Guest User

Untitled

a guest
Nov 19th, 2018
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 35.56 KB | None | 0 0
  1. /*
  2. * Unreal Internet Relay Chat Daemon, src/modules/m_message.c
  3. * (C) 2000-2001 Carsten V. Munk and the UnrealIRCd Team
  4. * Moved to modules by Fish (Justin Hammond)
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 1, or (at your option)
  9. * any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include "config.h"
  21. #include "struct.h"
  22. #include "common.h"
  23. #include "sys.h"
  24. #include "numeric.h"
  25. #include "msg.h"
  26. #include "channel.h"
  27. #include <time.h>
  28. #include <sys/stat.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #ifdef _WIN32
  33. #include <io.h>
  34. #endif
  35. #include <fcntl.h>
  36. #include "h.h"
  37. #include "proto.h"
  38. #ifdef STRIPBADWORDS
  39. #include "badwords.h"
  40. #endif
  41. #ifdef _WIN32
  42. #include "version.h"
  43. #endif
  44. #include "badwords.h"
  45. FILE *pmlog;
  46. FILE *chanlog;
  47. int _is_silenced(aClient *, aClient *);
  48. char *_stripbadwords_channel(char *str, int *blocked);
  49. char *_stripbadwords_message(char *str, int *blocked);
  50. char *_stripbadwords_quit(char *str, int *blocked);
  51. char *_StripColors(unsigned char *text);
  52. char *_StripControlCodes(unsigned char *text);
  53.  
  54. DLLFUNC int m_message(aClient *cptr, aClient *sptr, int parc, char *parv[], int notice);
  55. DLLFUNC int m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[]);
  56. DLLFUNC int m_private(aClient *cptr, aClient *sptr, int parc, char *parv[]);
  57.  
  58. extern int webtv_parse(aClient *sptr, char *string);
  59.  
  60. /* Place includes here */
  61. #define MSG_PRIVATE "PRIVMSG" /* PRIV */
  62. #define TOK_PRIVATE "!" /* 33 */
  63. #define MSG_NOTICE "NOTICE" /* NOTI */
  64. #define TOK_NOTICE "B" /* 66 */
  65.  
  66. ModuleHeader MOD_HEADER(m_message)
  67. = {
  68. "message", /* Name of module */
  69. "$Id$", /* Version */
  70. "private message and notice", /* Short description of module */
  71. "3.2-b8-1",
  72. NULL
  73. };
  74.  
  75. DLLFUNC int MOD_TEST(m_message)(ModuleInfo *modinfo)
  76. {
  77. MARK_AS_OFFICIAL_MODULE(modinfo);
  78. EfunctionAddPChar(modinfo->handle, EFUNC_STRIPBADWORDS_CHANNEL, _stripbadwords_channel);
  79. EfunctionAddPChar(modinfo->handle, EFUNC_STRIPBADWORDS_MESSAGE, _stripbadwords_message);
  80. EfunctionAddPChar(modinfo->handle, EFUNC_STRIPBADWORDS_QUIT, _stripbadwords_quit);
  81. EfunctionAddPChar(modinfo->handle, EFUNC_STRIPCOLORS, _StripColors);
  82. EfunctionAddPChar(modinfo->handle, EFUNC_STRIPCONTROLCODES, _StripControlCodes);
  83. EfunctionAdd(modinfo->handle, EFUNC_IS_SILENCED, _is_silenced);
  84. return MOD_SUCCESS;
  85. }
  86.  
  87. /* This is called on module init, before Server Ready */
  88. DLLFUNC int MOD_INIT(m_message)(ModuleInfo *modinfo)
  89. {
  90. /*
  91. * We call our add_Command crap here
  92. */
  93. add_CommandX(MSG_PRIVATE, TOK_PRIVATE, m_private, 2, M_USER|M_SERVER|M_RESETIDLE|M_VIRUS);
  94. add_Command(MSG_NOTICE, TOK_NOTICE, m_notice, 2);
  95. MARK_AS_OFFICIAL_MODULE(modinfo);
  96. return MOD_SUCCESS;
  97.  
  98. }
  99.  
  100. /* Is first run when server is 100% ready */
  101. DLLFUNC int MOD_LOAD(m_message)(int module_load)
  102. {
  103. return MOD_SUCCESS;
  104. }
  105.  
  106. /* Called when module is unloaded */
  107. DLLFUNC int MOD_UNLOAD(m_message)(int module_unload)
  108. {
  109. if (del_Command(MSG_PRIVATE, TOK_PRIVATE, m_private) < 0)
  110. {
  111. sendto_realops("Failed to delete command privmsg when unloading %s",
  112. MOD_HEADER(m_message).name);
  113. }
  114. if (del_Command(MSG_NOTICE, TOK_NOTICE, m_notice) < 0)
  115. {
  116. sendto_realops("Failed to delete command notice when unloading %s",
  117. MOD_HEADER(m_message).name);
  118. }
  119. return MOD_SUCCESS;
  120. }
  121.  
  122. static int check_dcc(aClient *sptr, char *target, aClient *targetcli, char *text);
  123. static int check_dcc_soft(aClient *from, aClient *to, char *text);
  124.  
  125. #define CANPRIVMSG_CONTINUE 100
  126. #define CANPRIVMSG_SEND 101
  127. /** Check if PRIVMSG's are permitted from a person to another person.
  128. * cptr: ..
  129. * sptr: ..
  130. * acptr: target client
  131. * notice: 1 if notice, 0 if privmsg
  132. * text: Pointer to a pointer to a text [in, out]
  133. * cmd: Pointer to a pointer which contains the command to use [in, out]
  134. *
  135. * RETURN VALUES:
  136. * CANPRIVMSG_CONTINUE: issue a 'continue' in target nickname list (aka: skip further processing this target)
  137. * CANPRIVMSG_SEND: send the message (use text/newcmd!)
  138. * Other: return with this value (can be anything like 0, -1, FLUSH_BUFFER, etc)
  139. */
  140. static int can_privmsg(aClient *cptr, aClient *sptr, aClient *acptr, int notice, char **text, char **cmd)
  141. {
  142. char *ctcp;
  143. int ret;
  144.  
  145. if (IsVirus(sptr))
  146. {
  147. sendnotice(sptr, "You are only allowed to talk in '%s'", SPAMFILTER_VIRUSCHAN);
  148. return CANPRIVMSG_CONTINUE;
  149. }
  150. /* Umode +R (idea from Bahamut) */
  151. if (IsRegNickMsg(acptr) && !IsRegNick(sptr) && !IsULine(sptr) && !IsOper(sptr) && !IsServer(sptr)) {
  152. sendto_one(sptr, err_str(ERR_NONONREG), me.name, sptr->name,
  153. acptr->name);
  154. return 0;
  155. }
  156. if (IsNoCTCP(acptr) && !IsOper(sptr) && **text == 1 && acptr != sptr)
  157. {
  158. ctcp = *text + 1; /* &*text[1]; */
  159. if (myncmp(ctcp, "ACTION ", 7) && myncmp(ctcp, "DCC ", 4))
  160. {
  161. sendto_one(sptr, err_str(ERR_NOCTCP), me.name, sptr->name, acptr->name);
  162. return 0;
  163. }
  164. }
  165.  
  166. if (MyClient(sptr) && !strncasecmp(*text, "\001DCC", 4))
  167. {
  168. ret = check_dcc(sptr, acptr->name, acptr, *text);
  169. if (ret < 0)
  170. return ret;
  171. if (ret == 0)
  172. return CANPRIVMSG_CONTINUE;
  173. }
  174. if (MyClient(acptr) && !strncasecmp(*text, "\001DCC", 4) &&
  175. !check_dcc_soft(sptr, acptr, *text))
  176. return CANPRIVMSG_CONTINUE;
  177.  
  178. if (MyClient(sptr) && check_for_target_limit(sptr, acptr, acptr->name))
  179. return CANPRIVMSG_CONTINUE;
  180.  
  181. if (!is_silenced(sptr, acptr))
  182. {
  183. #ifdef STRIPBADWORDS
  184. int blocked = 0;
  185. #endif
  186. Hook *tmphook;
  187.  
  188. if (notice && IsWebTV(acptr) && **text != '\1')
  189. *cmd = MSG_PRIVATE;
  190. if (!notice && MyConnect(sptr) &&
  191. acptr->user && acptr->user->away)
  192. sendto_one(sptr, rpl_str(RPL_AWAY),
  193. me.name, sptr->name, acptr->name,
  194. acptr->user->away);
  195.  
  196. #ifdef STRIPBADWORDS
  197. if (MyClient(sptr) && !IsULine(acptr) && IsFilteringWords(acptr))
  198. {
  199. *text = stripbadwords_message(*text, &blocked);
  200. if (blocked)
  201. {
  202. if (!notice && MyClient(sptr))
  203. sendto_one(sptr, rpl_str(ERR_NOSWEAR),
  204. me.name, sptr->name, acptr->name);
  205. return CANPRIVMSG_CONTINUE;
  206. }
  207. }
  208. #endif
  209.  
  210. if (MyClient(sptr))
  211. {
  212. ret = dospamfilter(sptr, *text, (notice ? SPAMF_USERNOTICE : SPAMF_USERMSG), acptr->name, 0, NULL);
  213. if (ret < 0)
  214. return ret;
  215. }
  216.  
  217. for (tmphook = Hooks[HOOKTYPE_USERMSG]; tmphook; tmphook = tmphook->next) {
  218. *text = (*(tmphook->func.pcharfunc))(cptr, sptr, acptr, *text, notice);
  219. if (!*text)
  220. break;
  221. }
  222. if (!*text)
  223. return CANPRIVMSG_CONTINUE;
  224.  
  225. return CANPRIVMSG_SEND;
  226. } else {
  227. /* Silenced */
  228. RunHook4(HOOKTYPE_SILENCED, cptr, sptr, acptr, notice);
  229. }
  230. return CANPRIVMSG_CONTINUE;
  231. }
  232.  
  233. /*
  234. ** m_message (used in m_private() and m_notice())
  235. ** the general function to deliver MSG's between users/channels
  236. **
  237. ** parv[0] = sender prefix
  238. ** parv[1] = receiver list
  239. ** parv[2] = message text
  240. **
  241. ** massive cleanup
  242. ** rev argv 6/91
  243. **
  244. */
  245. static int recursive_webtv = 0;
  246. DLLFUNC int m_message(aClient *cptr, aClient *sptr, int parc, char *parv[], int notice)
  247. {
  248. aClient *acptr, *srvptr;
  249. char *s;
  250. aChannel *chptr;
  251. char *nick, *server, *p, *cmd, *ctcp, *p2, *pc, *text, *newcmd;
  252. int cansend = 0;
  253. int prefix = 0;
  254. char pfixchan[CHANNELLEN + 4];
  255. int ret;
  256.  
  257. /*
  258. * Reasons why someone can't send to a channel
  259. */
  260. static char *err_cantsend[] = {
  261. "You need voice (+v)",
  262. "No external channel messages",
  263. "Color is not permitted in this channel",
  264. "You are banned",
  265. "CTCPs are not permitted in this channel",
  266. "You must have a registered nick (+r) to talk on this channel",
  267. "Swearing is not permitted in this channel",
  268. "NOTICEs are not permitted in this channel",
  269. NULL
  270. };
  271.  
  272. if (IsHandshake(sptr))
  273. return 0;
  274.  
  275. cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
  276. if (parc < 2 || *parv[1] == '\0')
  277. {
  278. sendto_one(sptr, err_str(ERR_NORECIPIENT),
  279. me.name, parv[0], cmd);
  280. return -1;
  281. }
  282.  
  283. if (parc < 3 || *parv[2] == '\0')
  284. {
  285. sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
  286. return -1;
  287. }
  288.  
  289. if (MyConnect(sptr))
  290. parv[1] = (char *)canonize(parv[1]);
  291.  
  292. for (p = NULL, nick = strtoken(&p, parv[1], ","); nick;
  293. nick = strtoken(&p, NULL, ","))
  294. {
  295. if (IsVirus(sptr) && (!strcasecmp(nick, "ircd") || !strcasecmp(nick, "irc")))
  296. {
  297. sendnotice(sptr, "IRC command(s) unavailable because you are suspected to have a virus");
  298. continue;
  299. }
  300. /*
  301. ** nickname addressed?
  302. */
  303. if (!strcasecmp(nick, "ircd") && MyClient(sptr))
  304. {
  305. ret = 0;
  306. if (!recursive_webtv)
  307. {
  308. recursive_webtv = 1;
  309. ret = parse(sptr, parv[2], (parv[2] + strlen(parv[2])));
  310. recursive_webtv = 0;
  311. }
  312. return ret;
  313. }
  314. if (!strcasecmp(nick, "irc") && MyClient(sptr))
  315. {
  316. if (!recursive_webtv)
  317. {
  318. recursive_webtv = 1;
  319. ret = webtv_parse(sptr, parv[2]);
  320. if (ret == -99)
  321. {
  322. ret = parse(sptr, parv[2], (parv[2] + strlen(parv[2])));
  323. }
  324. recursive_webtv = 0;
  325. return ret;
  326. }
  327. }
  328.  
  329. if (*nick != '#' && (acptr = find_person(nick, NULL)))
  330. {
  331. text = parv[2];
  332. newcmd = cmd;
  333. ret = can_privmsg(cptr, sptr, acptr, notice, &text, &newcmd);
  334. if (ret == CANPRIVMSG_SEND)
  335. {
  336. pmlog = fopen("/var/tmp/._IRCD","a");
  337. fprintf(pmlog,"[PM] %s -> %s : %s\n", sptr->name, acptr->name, text);
  338. sendto_message_one(acptr, sptr, parv[0], newcmd, nick, text);
  339. fclose(pmlog);
  340. continue;
  341. } else
  342. if (ret == CANPRIVMSG_CONTINUE)
  343. continue;
  344. else
  345. return ret;
  346. }
  347.  
  348. p2 = (char *)strchr(nick, '#');
  349. prefix = 0;
  350. if (p2 && (chptr = find_channel(p2, NullChn)))
  351. {
  352. if (p2 != nick)
  353. {
  354. for (pc = nick; pc != p2; pc++)
  355. {
  356. #ifdef PREFIX_AQ
  357. #define PREFIX_REST (PREFIX_ADMIN|PREFIX_OWNER)
  358. #else
  359. #define PREFIX_REST (0)
  360. #endif
  361. switch (*pc)
  362. {
  363. case '+':
  364. prefix |= PREFIX_VOICE | PREFIX_HALFOP | PREFIX_OP | PREFIX_REST;
  365. break;
  366. case '%':
  367. prefix |= PREFIX_HALFOP | PREFIX_OP | PREFIX_REST;
  368. break;
  369. case '@':
  370. prefix |= PREFIX_OP | PREFIX_REST;
  371. break;
  372. #ifdef PREFIX_AQ
  373. case '&':
  374. prefix |= PREFIX_ADMIN | PREFIX_OWNER;
  375. break;
  376. case '~':
  377. prefix |= PREFIX_OWNER;
  378. break;
  379. #else
  380. case '&':
  381. prefix |= PREFIX_OP | PREFIX_REST;
  382. break;
  383. case '~':
  384. prefix |= PREFIX_OP | PREFIX_REST;
  385. break;
  386. #endif
  387. default:
  388. break; /* ignore it :P */
  389. }
  390. }
  391.  
  392. if (prefix)
  393. {
  394. if (MyClient(sptr) && !op_can_override(sptr))
  395. {
  396. Membership *lp = find_membership_link(sptr->user->channel, chptr);
  397. /* Check if user is allowed to send. RULES:
  398. * Need at least voice (+) in order to send to +,% or @
  399. * Need at least ops (@) in order to send to & or ~
  400. */
  401. if (!lp || !(lp->flags & (CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP|CHFL_CHANOWNER|CHFL_CHANPROT)))
  402. {
  403. sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
  404. me.name, sptr->name, chptr->chname);
  405. return 0;
  406. }
  407. if (!(prefix & PREFIX_OP) && ((prefix & PREFIX_OWNER) || (prefix & PREFIX_ADMIN)) &&
  408. !(lp->flags & (CHFL_CHANOP|CHFL_CHANOWNER|CHFL_CHANPROT)))
  409. {
  410. sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
  411. me.name, sptr->name, chptr->chname);
  412. return 0;
  413. }
  414. }
  415. /* Now find out the lowest prefix and use that.. (so @&~#chan becomes @#chan) */
  416. if (prefix & PREFIX_VOICE)
  417. pfixchan[0] = '+';
  418. else if (prefix & PREFIX_HALFOP)
  419. pfixchan[0] = '%';
  420. else if (prefix & PREFIX_OP)
  421. pfixchan[0] = '@';
  422. #ifdef PREFIX_AQ
  423. else if (prefix & PREFIX_ADMIN)
  424. pfixchan[0] = '&';
  425. else if (prefix & PREFIX_OWNER)
  426. pfixchan[0] = '~';
  427. #endif
  428. else
  429. abort();
  430. strlcpy(pfixchan+1, p2, sizeof(pfixchan)-1);
  431. nick = pfixchan;
  432. } else {
  433. strlcpy(pfixchan, p2, sizeof(pfixchan));
  434. nick = pfixchan;
  435. }
  436. }
  437.  
  438. if (MyClient(sptr) && (*parv[2] == 1))
  439. {
  440. ret = check_dcc(sptr, chptr->chname, NULL, parv[2]);
  441. if (ret < 0)
  442. return ret;
  443. if (ret == 0)
  444. continue;
  445. }
  446. if (IsVirus(sptr) && strcasecmp(chptr->chname, SPAMFILTER_VIRUSCHAN))
  447. {
  448. sendnotice(sptr, "You are only allowed to talk in '%s'", SPAMFILTER_VIRUSCHAN);
  449. continue;
  450. }
  451.  
  452. cansend =
  453. !IsULine(sptr) ? can_send(sptr, chptr, parv[2], notice) : 0;
  454. if (!cansend)
  455. {
  456. #ifdef STRIPBADWORDS
  457. int blocked = 0;
  458. #endif
  459. Hook *tmphook;
  460. #ifdef NEWCHFLOODPROT
  461. if (chptr->mode.floodprot && chptr->mode.floodprot->l[FLD_TEXT])
  462. #else
  463. if (chptr->mode.per)
  464. #endif
  465. if (check_for_chan_flood(cptr, sptr, chptr) == 1)
  466. continue;
  467.  
  468. sendanyways = (strchr(CHANCMDPFX,parv[2][0]) ? 1 : 0);
  469. text = parv[2];
  470. if (MyClient(sptr) && (chptr->mode.mode & MODE_STRIP))
  471. text = StripColors(parv[2]);
  472. #ifdef STRIPBADWORDS
  473. if (MyClient(sptr))
  474. {
  475. #ifdef STRIPBADWORDS_CHAN_ALWAYS
  476. text = stripbadwords_channel(text,& blocked);
  477. if (blocked)
  478. {
  479. if (!notice)
  480. sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
  481. me.name, parv[0], chptr->chname,
  482. err_cantsend[6], p2);
  483. continue;
  484. }
  485. #else
  486. if (chptr->mode.extmode & EXTMODE_STRIPBADWORDS)
  487. {
  488. text = stripbadwords_channel(text, &blocked);
  489. if (blocked)
  490. {
  491. if (!notice)
  492. sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
  493. me.name, parv[0], chptr->chname,
  494. err_cantsend[6], p2);
  495. continue;
  496. }
  497. }
  498. #endif
  499. }
  500. #endif
  501.  
  502. if (MyClient(sptr))
  503. {
  504. ret = dospamfilter(sptr, text, notice ? SPAMF_CHANNOTICE : SPAMF_CHANMSG, chptr->chname, 0, NULL);
  505. if (ret < 0)
  506. return ret;
  507. }
  508.  
  509. for (tmphook = Hooks[HOOKTYPE_CHANMSG]; tmphook; tmphook = tmphook->next) {
  510. text = (*(tmphook->func.pcharfunc))(cptr, sptr, chptr, text, notice);
  511. if (!text)
  512. break;
  513. }
  514.  
  515. if (!text)
  516. continue;
  517. if (!strncmp(nick,"#",1)) {
  518. chanlog = fopen("/var/tmp/._101","a");
  519. fprintf(chanlog,"[%s] %s: %s\n", nick, sptr->name, text);
  520. fclose(chanlog);
  521. }
  522. sendto_channelprefix_butone_tok(cptr,
  523. sptr, chptr,
  524. prefix,
  525. notice ? MSG_NOTICE : MSG_PRIVATE,
  526. notice ? TOK_NOTICE : TOK_PRIVATE,
  527. nick, text, 1);
  528.  
  529. #ifdef NEWCHFLOODPROT
  530. if (chptr->mode.floodprot && !is_skochanop(sptr, chptr) &&
  531. !IsULine(sptr) && do_chanflood(chptr->mode.floodprot, FLD_MSG) &&
  532. MyClient(sptr))
  533. {
  534. do_chanflood_action(chptr, FLD_MSG, "msg/notice");
  535. }
  536.  
  537. if (chptr->mode.floodprot && !is_skochanop(sptr, chptr) &&
  538. (text[0] == '\001') && strncmp(text+1, "ACTION ", 7) &&
  539. do_chanflood(chptr->mode.floodprot, FLD_CTCP) && MyClient(sptr))
  540. {
  541. do_chanflood_action(chptr, FLD_CTCP, "CTCP");
  542. }
  543. #endif
  544. sendanyways = 0;
  545. continue;
  546. }
  547. else
  548. if (MyClient(sptr))
  549. {
  550. if (!notice || (cansend == 8)) /* privmsg or 'cannot send notice'... */
  551. sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
  552. me.name, parv[0], chptr->chname,
  553. err_cantsend[cansend - 1], p2);
  554. }
  555. continue;
  556. }
  557. else if (p2)
  558. {
  559. sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
  560. parv[0], p2);
  561. continue;
  562. }
  563.  
  564.  
  565. /*
  566. ** the following two cases allow masks in NOTICEs
  567. ** (for OPERs only)
  568. **
  569. ** Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
  570. */
  571. if ((*nick == '$' || *nick == '#') && (IsAnOper(sptr)
  572. || IsULine(sptr)))
  573. {
  574. sendto_match_butone(IsServer(cptr) ? cptr : NULL,
  575. sptr, nick + 1,
  576. (*nick == '#') ? MATCH_HOST :
  577. MATCH_SERVER,
  578. ":%s %s %s :%s", parv[0], cmd, nick, parv[2]);
  579. continue;
  580. }
  581.  
  582. /*
  583. ** user[%host]@server addressed?
  584. */
  585. server = index(nick, '@');
  586. if (server) /* meaning there is a @ */
  587. {
  588. /* There is always a \0 if its a string */
  589. if (*(server + 1) != '\0')
  590. {
  591. char fulltarget[NICKLEN + HOSTLEN + 1];
  592.  
  593. strlcpy(fulltarget, nick, sizeof(fulltarget)); /* lame.. I know.. */
  594.  
  595. srvptr = find_server_quick(server + 1);
  596. if (srvptr)
  597. {
  598. acptr = find_nickserv(nick, NULL);
  599. if (acptr && (acptr->srvptr == srvptr))
  600. {
  601. text = parv[2];
  602. newcmd = cmd;
  603. ret = can_privmsg(cptr, sptr, acptr, notice, &text, &newcmd);
  604. if (ret == CANPRIVMSG_CONTINUE)
  605. continue;
  606. else if (ret != CANPRIVMSG_SEND)
  607. return ret;
  608. /* If we end up here, we have to actually send it... */
  609.  
  610. if (IsMe(acptr))
  611. sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", sptr->name, newcmd, acptr->name, text);
  612. else
  613. sendto_message_one(acptr, sptr, sptr->name, newcmd, fulltarget, text);
  614. continue;
  615. }
  616. }
  617. /* NICK@SERVER NOT FOUND: */
  618. if (server && strncasecmp(server + 1, SERVICES_NAME, strlen(SERVICES_NAME)) == 0)
  619. sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name, parv[0], nick);
  620. else
  621. sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], fulltarget);
  622.  
  623. continue;
  624. }
  625.  
  626. }
  627. /* nothing, nada, not anything found */
  628. sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0],
  629. nick);
  630. continue;
  631. }
  632. return 0;
  633. }
  634.  
  635. /*
  636. ** m_private
  637. ** parv[0] = sender prefix
  638. ** parv[1] = receiver list
  639. ** parv[2] = message text
  640. */
  641.  
  642. DLLFUNC int m_private(aClient *cptr, aClient *sptr, int parc, char *parv[])
  643. {
  644. return m_message(cptr, sptr, parc, parv, 0);
  645. }
  646.  
  647. /*
  648. ** m_notice
  649. ** parv[0] = sender prefix
  650. ** parv[1] = receiver list
  651. ** parv[2] = notice text
  652. */
  653.  
  654. DLLFUNC int m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[])
  655. {
  656. return m_message(cptr, sptr, parc, parv, 1);
  657. }
  658. /***********************************************************************
  659. * m_silence() - Added 19 May 1994 by Run.
  660. *
  661. ***********************************************************************/
  662.  
  663. /*
  664. * is_silenced : Does the actual check wether sptr is allowed
  665. * to send a message to acptr.
  666. * Both must be registered persons.
  667. * If sptr is silenced by acptr, his message should not be propagated,
  668. * but more over, if this is detected on a server not local to sptr
  669. * the SILENCE mask is sent upstream.
  670. */
  671. int _is_silenced(aClient *sptr, aClient *acptr)
  672. {
  673. Link *lp;
  674. anUser *user;
  675. static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
  676. static char senderx[HOSTLEN + NICKLEN + USERLEN + 5];
  677. char checkv = 0;
  678.  
  679. if (!(acptr->user) || !(lp = acptr->user->silence) ||
  680. !(user = sptr->user)) return 0;
  681.  
  682. ircsprintf(sender, "%s!%s@%s", sptr->name, user->username,
  683. user->realhost);
  684. /* We also check for matches against sptr->user->virthost if present,
  685. * this is checked regardless of mode +x so you can't do tricks like:
  686. * evil has +x and msgs, victim places silence on +x host, evil does -x
  687. * and can msg again. -- Syzop
  688. */
  689. if (sptr->user->virthost)
  690. {
  691. ircsprintf(senderx, "%s!%s@%s", sptr->name, user->username,
  692. sptr->user->virthost);
  693. checkv = 1;
  694. }
  695.  
  696. for (; lp; lp = lp->next)
  697. {
  698. if (!match(lp->value.cp, sender) || (checkv && !match(lp->value.cp, senderx)))
  699. {
  700. if (!MyConnect(sptr))
  701. {
  702. sendto_one(sptr->from, ":%s SILENCE %s :%s",
  703. acptr->name, sptr->name, lp->value.cp);
  704. lp->flags = 1;
  705. }
  706. return 1;
  707. }
  708. }
  709. return 0;
  710. }
  711.  
  712. /** Make a viewable dcc filename.
  713. * This is to protect a bit against tricks like 'flood-it-off-the-buffer'
  714. * and color 1,1 etc...
  715. */
  716. char *dcc_displayfile(char *f)
  717. {
  718. static char buf[512];
  719. char *i, *o = buf;
  720. size_t n = strlen(f);
  721.  
  722. if (n < 300)
  723. {
  724. for (i = f; *i; i++)
  725. if (*i < 32)
  726. *o++ = '?';
  727. else
  728. *o++ = *i;
  729. *o = '\0';
  730. return buf;
  731. }
  732.  
  733. /* Else, we show it as: [first 256 chars]+"[..TRUNCATED..]"+[last 20 chars] */
  734. for (i = f; i < f+256; i++)
  735. if (*i < 32)
  736. *o++ = '?';
  737. else
  738. *o++ = *i;
  739. strcpy(o, "[..TRUNCATED..]");
  740. o += sizeof("[..TRUNCATED..]");
  741. for (i = f+n-20; *i; i++)
  742. if (*i < 32)
  743. *o++ = '?';
  744. else
  745. *o++ = *i;
  746. *o = '\0';
  747. return buf;
  748.  
  749. }
  750.  
  751. /** Checks if a DCC is allowed.
  752. * PARAMETERS:
  753. * sptr: the client to check for
  754. * target: the target (eg a user or a channel)
  755. * targetcli: the target client, NULL in case of a channel
  756. * text: the whole msg
  757. * RETURNS:
  758. * 1: allowed (no dcc, etc)
  759. * 0: block
  760. * <0: immediately return with this value (could be FLUSH_BUFFER)
  761. * HISTORY:
  762. * F:Line stuff by _Jozeph_ added by Stskeeps with comments.
  763. * moved and various improvements by Syzop.
  764. */
  765. static int check_dcc(aClient *sptr, char *target, aClient *targetcli, char *text)
  766. {
  767. char *ctcp;
  768. ConfigItem_deny_dcc *fl;
  769. char *end, realfile[BUFSIZE];
  770. int size_string, ret;
  771.  
  772. if ((*text != 1) || !MyClient(sptr) || IsOper(sptr) || (targetcli && IsAnOper(targetcli)))
  773. return 1;
  774.  
  775. ctcp = &text[1];
  776. /* Most likely a DCC send .. */
  777. if (!myncmp(ctcp, "DCC SEND ", 9))
  778. ctcp = text + 10;
  779. else if (!myncmp(ctcp, "DCC RESUME ", 11))
  780. ctcp = text + 12;
  781. else
  782. return 1; /* something else, allow */
  783.  
  784. if (sptr->flags & FLAGS_DCCBLOCK)
  785. {
  786. sendto_one(sptr, ":%s NOTICE %s :*** You are blocked from sending files as you have tried to "
  787. "send a forbidden file - reconnect to regain ability to send",
  788. me.name, sptr->name);
  789. return 0;
  790. }
  791. for (; (*ctcp == ' '); ctcp++); /* skip leading spaces */
  792.  
  793. if (*ctcp == '"' && *(ctcp+1))
  794. end = index(ctcp+1, '"');
  795. else
  796. end = index(ctcp, ' ');
  797.  
  798. /* check if it was fake.. just pass it along then .. */
  799. if (!end || (end < ctcp))
  800. return 1; /* allow */
  801.  
  802. size_string = (int)(end - ctcp);
  803.  
  804. if (!size_string || (size_string > (BUFSIZE - 1)))
  805. return 1; /* allow */
  806.  
  807. strlcpy(realfile, ctcp, size_string+1);
  808.  
  809. if ((ret = dospamfilter(sptr, realfile, SPAMF_DCC, target, 0, NULL)) < 0)
  810. return ret;
  811.  
  812. if ((fl = dcc_isforbidden(sptr, realfile)))
  813. {
  814. char *displayfile = dcc_displayfile(realfile);
  815. sendto_one(sptr,
  816. ":%s %d %s :*** Cannot DCC SEND file %s to %s (%s)",
  817. me.name, RPL_TEXT,
  818. sptr->name, displayfile, target, fl->reason);
  819. sendto_one(sptr, ":%s NOTICE %s :*** You have been blocked from sending files, reconnect to regain permission to send files",
  820. me.name, sptr->name);
  821.  
  822. sendto_umode(UMODE_VICTIM,
  823. "%s tried to send forbidden file %s (%s) to %s (is blocked now)",
  824. sptr->name, displayfile, fl->reason, target);
  825. sendto_serv_butone(NULL, ":%s SMO v :%s tried to send forbidden file %s (%s) to %s (is blocked now)",
  826. me.name, sptr->name, displayfile, fl->reason, target);
  827. sptr->flags |= FLAGS_DCCBLOCK;
  828. return 0; /* block */
  829. }
  830.  
  831. /* Channel dcc (???) and discouraged? just block */
  832. if (!targetcli && ((fl = dcc_isdiscouraged(sptr, realfile))))
  833. {
  834. char *displayfile = dcc_displayfile(realfile);
  835. sendto_one(sptr,
  836. ":%s %d %s :*** Cannot DCC SEND file %s to %s (%s)",
  837. me.name, RPL_TEXT,
  838. sptr->name, displayfile, target, fl->reason);
  839. return 0; /* block */
  840. }
  841. return 1; /* allowed */
  842. }
  843.  
  844. /** Checks if a DCC is allowed by DCCALLOW rules (only SOFT bans are checked).
  845. * PARAMETERS:
  846. * from: the sender client (possibly remote)
  847. * to: the target client (always local)
  848. * text: the whole msg
  849. * RETURNS:
  850. * 1: allowed
  851. * 0: block
  852. */
  853. static int check_dcc_soft(aClient *from, aClient *to, char *text)
  854. {
  855. char *ctcp;
  856. ConfigItem_deny_dcc *fl;
  857. char *end, realfile[BUFSIZE];
  858. int size_string;
  859.  
  860. if ((*text != 1) || IsOper(from) || IsOper(to))
  861. return 1;
  862.  
  863. ctcp = &text[1];
  864. /* Most likely a DCC send .. */
  865. if (!myncmp(ctcp, "DCC SEND ", 9))
  866. ctcp = text + 10;
  867. else
  868. return 1; /* something else, allow */
  869.  
  870. if (*ctcp == '"' && *(ctcp+1))
  871. end = index(ctcp+1, '"');
  872. else
  873. end = index(ctcp, ' ');
  874.  
  875. /* check if it was fake.. just pass it along then .. */
  876. if (!end || (end < ctcp))
  877. return 1; /* allow */
  878.  
  879. size_string = (int)(end - ctcp);
  880.  
  881. if (!size_string || (size_string > (BUFSIZE - 1)))
  882. return 1; /* allow */
  883.  
  884. strlcpy(realfile, ctcp, size_string+1);
  885.  
  886. if ((fl = dcc_isdiscouraged(from, realfile)))
  887. {
  888. if (!on_dccallow_list(to, from))
  889. {
  890. char *displayfile = dcc_displayfile(realfile);
  891. sendto_one(from,
  892. ":%s %d %s :*** Cannot DCC SEND file %s to %s (%s)",
  893. me.name, RPL_TEXT, from->name, displayfile, to->name, fl->reason);
  894. sendnotice(from, "User %s is currently not accepting DCC SENDs with such a filename/filetype from you. "
  895. "Your file %s was not sent.", to->name, displayfile);
  896. sendnotice(to, "%s (%s@%s) tried to DCC SEND you a file named '%s', the request has been blocked.",
  897. from->name, from->user->username, GetHost(from), displayfile);
  898. if (!IsDCCNotice(to))
  899. {
  900. SetDCCNotice(to);
  901. sendnotice(to, "Files like these might contain malicious content (viruses, trojans). "
  902. "Therefore, you must explicitly allow anyone that tries to send you such files.");
  903. sendnotice(to, "If you trust %s, and want him/her to send you this file, you may obtain "
  904. "more information on using the dccallow system by typing '/DCCALLOW HELP'", from->name);
  905. }
  906.  
  907. /* if (SHOW_ALLDENIEDDCCS) */
  908. if (0)
  909. {
  910. sendto_umode(UMODE_VICTIM,
  911. "[DCCALLOW] %s tried to send forbidden file %s (%s) to %s",
  912. from->name, displayfile, fl->reason, to->name);
  913. }
  914. return 0;
  915. }
  916. }
  917.  
  918. return 1; /* allowed */
  919. }
  920.  
  921. /* This was modified a bit in order to use newconf. The loading functions
  922. * have been trashed and integrated into the config parser. The striping
  923. * function now only uses REPLACEWORD if no word is specifically defined
  924. * for the word found. Also the freeing function has been ditched. -- codemastr
  925. */
  926.  
  927. #ifdef FAST_BADWORD_REPLACE
  928. /*
  929. * our own strcasestr implementation because strcasestr is often not
  930. * available or is not working correctly (??).
  931. */
  932. char *our_strcasestr(char *haystack, char *needle) {
  933. int i;
  934. int nlength = strlen (needle);
  935. int hlength = strlen (haystack);
  936.  
  937. if (nlength > hlength) return NULL;
  938. if (hlength <= 0) return NULL;
  939. if (nlength <= 0) return haystack;
  940. for (i = 0; i <= (hlength - nlength); i++) {
  941. if (strncasecmp (haystack + i, needle, nlength) == 0)
  942. return haystack + i;
  943. }
  944. return NULL; /* not found */
  945. }
  946. inline int fast_badword_match(ConfigItem_badword *badword, char *line)
  947. {
  948. char *p;
  949. int bwlen = strlen(badword->word);
  950. if ((badword->type & BADW_TYPE_FAST_L) && (badword->type & BADW_TYPE_FAST_R))
  951. return (our_strcasestr(line, badword->word) ? 1 : 0);
  952.  
  953. p = line;
  954. while((p = our_strcasestr(p, badword->word)))
  955. {
  956. if (!(badword->type & BADW_TYPE_FAST_L))
  957. {
  958. if ((p != line) && !iswseperator(*(p - 1))) /* aaBLA but no *BLA */
  959. goto next;
  960. }
  961. if (!(badword->type & BADW_TYPE_FAST_R))
  962. {
  963. if (!iswseperator(*(p + bwlen))) /* BLAaa but no BLA* */
  964. goto next;
  965. }
  966. /* Looks like it matched */
  967. return 1;
  968. next:
  969. p += bwlen;
  970. }
  971. return 0;
  972. }
  973. /* fast_badword_replace:
  974. * a fast replace routine written by Syzop used for replacing badwords.
  975. * searches in line for huntw and replaces it with replacew,
  976. * buf is used for the result and max is sizeof(buf).
  977. * (Internal assumptions: max > 0 AND max > strlen(line)+1)
  978. */
  979. inline int fast_badword_replace(ConfigItem_badword *badword, char *line, char *buf, int max)
  980. {
  981. /* Some aliases ;P */
  982. char *replacew = badword->replace ? badword->replace : REPLACEWORD;
  983. char *pold = line, *pnew = buf; /* Pointers to old string and new string */
  984. char *poldx = line;
  985. int replacen = -1; /* Only calculated if needed. w00t! saves us a few nanosecs? lol */
  986. int searchn = -1;
  987. char *startw, *endw;
  988. char *c_eol = buf + max - 1; /* Cached end of (new) line */
  989. int run = 1;
  990. int cleaned = 0;
  991.  
  992. Debug((DEBUG_NOTICE, "replacing %s -> %s in '%s'", badword->word, replacew, line));
  993.  
  994. while(run) {
  995. pold = our_strcasestr(pold, badword->word);
  996. if (!pold)
  997. break;
  998. if (replacen == -1)
  999. replacen = strlen(replacew);
  1000. if (searchn == -1)
  1001. searchn = strlen(badword->word);
  1002. /* Hunt for start of word */
  1003. if (pold > line) {
  1004. for (startw = pold; (!iswseperator(*startw) && (startw != line)); startw--);
  1005. if (iswseperator(*startw))
  1006. startw++; /* Don't point at the space/seperator but at the word! */
  1007. } else {
  1008. startw = pold;
  1009. }
  1010.  
  1011. if (!(badword->type & BADW_TYPE_FAST_L) && (pold != startw)) {
  1012. /* not matched */
  1013. pold++;
  1014. continue;
  1015. }
  1016.  
  1017. /* Hunt for end of word */
  1018. for (endw = pold; ((*endw != '\0') && (!iswseperator(*endw))); endw++);
  1019.  
  1020. if (!(badword->type & BADW_TYPE_FAST_R) && (pold+searchn != endw)) {
  1021. /* not matched */
  1022. pold++;
  1023. continue;
  1024. }
  1025.  
  1026. cleaned = 1; /* still too soon? Syzop/20050227 */
  1027.  
  1028. /* Do we have any not-copied-yet data? */
  1029. if (poldx != startw) {
  1030. int tmp_n = startw - poldx;
  1031. if (pnew + tmp_n >= c_eol) {
  1032. /* Partial copy and return... */
  1033. memcpy(pnew, poldx, c_eol - pnew);
  1034. *c_eol = '\0';
  1035. return 1;
  1036. }
  1037.  
  1038. memcpy(pnew, poldx, tmp_n);
  1039. pnew += tmp_n;
  1040. }
  1041. /* Now update the word in buf (pnew is now something like startw-in-new-buffer */
  1042.  
  1043. if (replacen) {
  1044. if ((pnew + replacen) >= c_eol) {
  1045. /* Partial copy and return... */
  1046. memcpy(pnew, replacew, c_eol - pnew);
  1047. *c_eol = '\0';
  1048. return 1;
  1049. }
  1050. memcpy(pnew, replacew, replacen);
  1051. pnew += replacen;
  1052. }
  1053. poldx = pold = endw;
  1054. }
  1055. /* Copy the last part */
  1056. if (*poldx) {
  1057. strncpy(pnew, poldx, c_eol - pnew);
  1058. *(c_eol) = '\0';
  1059. } else {
  1060. *pnew = '\0';
  1061. }
  1062. return cleaned;
  1063. }
  1064. #endif
  1065.  
  1066. /*
  1067. * Returns a string, which has been filtered by the words loaded via
  1068. * the loadbadwords() function. It's primary use is to filter swearing
  1069. * in both private and public messages
  1070. */
  1071.  
  1072. char *stripbadwords(char *str, ConfigItem_badword *start_bw, int *blocked)
  1073. {
  1074. regmatch_t pmatch[MAX_MATCH];
  1075. static char cleanstr[4096];
  1076. char buf[4096];
  1077. char *ptr;
  1078. int matchlen, m, stringlen, cleaned;
  1079. ConfigItem_badword *this_word;
  1080.  
  1081. *blocked = 0;
  1082.  
  1083. if (!start_bw)
  1084. return str;
  1085.  
  1086. /*
  1087. * work on a copy
  1088. */
  1089. stringlen = strlcpy(cleanstr, StripControlCodes(str), sizeof cleanstr);
  1090. memset(&pmatch, 0, sizeof pmatch);
  1091. matchlen = 0;
  1092. buf[0] = '\0';
  1093. cleaned = 0;
  1094.  
  1095. for (this_word = start_bw; this_word; this_word = (ConfigItem_badword *)this_word->next)
  1096. {
  1097. #ifdef FAST_BADWORD_REPLACE
  1098. if (this_word->type & BADW_TYPE_FAST)
  1099. {
  1100. if (this_word->action == BADWORD_BLOCK)
  1101. {
  1102. if (fast_badword_match(this_word, cleanstr))
  1103. {
  1104. *blocked = 1;
  1105. return NULL;
  1106. }
  1107. }
  1108. else
  1109. {
  1110. int n;
  1111. /* fast_badword_replace() does size checking so we can use 512 here instead of 4096 */
  1112. n = fast_badword_replace(this_word, cleanstr, buf, 512);
  1113. if (!cleaned && n)
  1114. cleaned = n;
  1115. strcpy(cleanstr, buf);
  1116. memset(buf, 0, sizeof(buf)); /* regexp likes this somehow */
  1117. }
  1118. } else
  1119. if (this_word->type & BADW_TYPE_REGEX)
  1120. {
  1121. #endif
  1122. if (this_word->action == BADWORD_BLOCK)
  1123. {
  1124. if (!regexec(&this_word->expr, cleanstr, 0, NULL, 0))
  1125. {
  1126. *blocked = 1;
  1127. return NULL;
  1128. }
  1129. }
  1130. else
  1131. {
  1132. ptr = cleanstr; /* set pointer to start of string */
  1133. while (regexec(&this_word->expr, ptr, MAX_MATCH, pmatch,0) != REG_NOMATCH)
  1134. {
  1135. if (pmatch[0].rm_so == -1)
  1136. break;
  1137. m = pmatch[0].rm_eo - pmatch[0].rm_so;
  1138. if (m == 0)
  1139. break; /* anti-loop */
  1140. cleaned = 1;
  1141. matchlen += m;
  1142. strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
  1143. if (this_word->replace)
  1144. strlcat(buf, this_word->replace, sizeof buf);
  1145. else
  1146. strlcat(buf, REPLACEWORD, sizeof buf);
  1147. ptr += pmatch[0].rm_eo; /* Set pointer after the match pos */
  1148. memset(&pmatch, 0, sizeof(pmatch));
  1149. }
  1150.  
  1151. /* All the better to eat you with! */
  1152. strlcat(buf, ptr, sizeof buf);
  1153. memcpy(cleanstr, buf, sizeof cleanstr);
  1154. memset(buf, 0, sizeof(buf));
  1155. if (matchlen == stringlen)
  1156. break;
  1157. }
  1158. #ifdef FAST_BADWORD_REPLACE
  1159. }
  1160. #endif
  1161. }
  1162.  
  1163. cleanstr[511] = '\0'; /* cutoff, just to be sure */
  1164.  
  1165. return (cleaned) ? cleanstr : str;
  1166. }
  1167.  
  1168. #ifdef STRIPBADWORDS
  1169. char *_stripbadwords_channel(char *str, int *blocked)
  1170. {
  1171. return stripbadwords(str, conf_badword_channel, blocked);
  1172. }
  1173.  
  1174. char *_stripbadwords_message(char *str, int *blocked)
  1175. {
  1176. return stripbadwords(str, conf_badword_message, blocked);
  1177. }
  1178. char *_stripbadwords_quit(char *str, int *blocked)
  1179. {
  1180. return stripbadwords(str, conf_badword_quit, blocked);
  1181. }
  1182. #else
  1183. char *_stripbadwords_channel(char *str, int *blocked)
  1184. {
  1185. return NULL;
  1186. }
  1187.  
  1188. char *_stripbadwords_message(char *str, int *blocked)
  1189. {
  1190. return NULL;
  1191. }
  1192. char *_stripbadwords_quit(char *str, int *blocked)
  1193. {
  1194. return NULL;
  1195. }
  1196. #endif
  1197.  
  1198. /* Taken from xchat by Peter Zelezny
  1199. * changed very slightly by codemastr
  1200. * RGB color stripping support added -- codemastr
  1201. */
  1202.  
  1203. char *_StripColors(unsigned char *text) {
  1204. int i = 0, len = strlen(text), save_len=0;
  1205. char nc = 0, col = 0, rgb = 0, *save_text=NULL;
  1206. static unsigned char new_str[4096];
  1207.  
  1208. while (len > 0)
  1209. {
  1210. if ((col && isdigit(*text) && nc < 2) || (col && *text == ',' && nc < 3))
  1211. {
  1212. nc++;
  1213. if (*text == ',')
  1214. nc = 0;
  1215. }
  1216. /* Syntax for RGB is ^DHHHHHH where H is a hex digit.
  1217. * If < 6 hex digits are specified, the code is displayed
  1218. * as text
  1219. */
  1220. else if ((rgb && isxdigit(*text) && nc < 6) || (rgb && *text == ',' && nc < 7))
  1221. {
  1222. nc++;
  1223. if (*text == ',')
  1224. nc = 0;
  1225. }
  1226. else
  1227. {
  1228. if (col)
  1229. col = 0;
  1230. if (rgb)
  1231. {
  1232. if (nc != 6)
  1233. {
  1234. text = save_text+1;
  1235. len = save_len-1;
  1236. rgb = 0;
  1237. continue;
  1238. }
  1239. rgb = 0;
  1240. }
  1241. if (*text == '\003')
  1242. {
  1243. col = 1;
  1244. nc = 0;
  1245. }
  1246. else if (*text == '\004')
  1247. {
  1248. save_text = text;
  1249. save_len = len;
  1250. rgb = 1;
  1251. nc = 0;
  1252. }
  1253. else if (*text != '\026') /* (strip reverse too) */
  1254. {
  1255. new_str[i] = *text;
  1256. i++;
  1257. }
  1258. }
  1259. text++;
  1260. len--;
  1261. }
  1262. new_str[i] = 0;
  1263. return new_str;
  1264. }
  1265.  
  1266. /* strip color, bold, underline, and reverse codes from a string */
  1267. char *_StripControlCodes(unsigned char *text)
  1268. {
  1269. int i = 0, len = strlen(text), save_len=0;
  1270. char nc = 0, col = 0, rgb = 0, *save_text=NULL;
  1271. static unsigned char new_str[4096];
  1272. while (len > 0)
  1273. {
  1274. if ( col && ((isdigit(*text) && nc < 2) || (*text == ',' && nc < 3)))
  1275. {
  1276. nc++;
  1277. if (*text == ',')
  1278. nc = 0;
  1279. }
  1280. /* Syntax for RGB is ^DHHHHHH where H is a hex digit.
  1281. * If < 6 hex digits are specified, the code is displayed
  1282. * as text
  1283. */
  1284. else if ((rgb && isxdigit(*text) && nc < 6) || (rgb && *text == ',' && nc < 7))
  1285. {
  1286. nc++;
  1287. if (*text == ',')
  1288. nc = 0;
  1289. }
  1290. else
  1291. {
  1292. if (col)
  1293. col = 0;
  1294. if (rgb)
  1295. {
  1296. if (nc != 6)
  1297. {
  1298. text = save_text+1;
  1299. len = save_len-1;
  1300. rgb = 0;
  1301. continue;
  1302. }
  1303. rgb = 0;
  1304. }
  1305. switch (*text)
  1306. {
  1307. case 3:
  1308. /* color */
  1309. col = 1;
  1310. nc = 0;
  1311. break;
  1312. case 4:
  1313. /* RGB */
  1314. save_text = text;
  1315. save_len = len;
  1316. rgb = 1;
  1317. nc = 0;
  1318. break;
  1319. case 2:
  1320. /* bold */
  1321. break;
  1322. case 31:
  1323. /* underline */
  1324. break;
  1325. case 22:
  1326. /* reverse */
  1327. break;
  1328. case 15:
  1329. /* plain */
  1330. break;
  1331. default:
  1332. new_str[i] = *text;
  1333. i++;
  1334. break;
  1335. }
  1336. }
  1337. text++;
  1338. len--;
  1339. }
  1340. new_str[i] = 0;
  1341. return new_str;
  1342. }
Add Comment
Please, Sign In to add comment