tclchan.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2008 Bryan Drewery
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. /*
  21. * tclchan.c -- part of channels.mod
  22. *
  23. */
  24. static int FindElement(char *resultBuf, const char *list, size_t listLength,
  25. const char **elementPtr, const char **nextPtr,
  26. size_t *sizePtr, int *bracePtr)
  27. {
  28. const char *p = list;
  29. const char *elemStart = NULL; /* Points to first byte of first element. */
  30. const char *limit = (list + listLength); /* Points just after list's last byte. */
  31. int openBraces = 0; /* Brace nesting level during parse. */
  32. int inQuotes = 0;
  33. size_t size = 0; /* lint. */
  34. const char *p2 = NULL;
  35. /*
  36. * Skim off leading white space and check for an opening brace or
  37. * quote. We treat embedded NULLs in the list as bytes belonging to
  38. * a list element.
  39. */
  40. while ((p < limit) && egg_isspace(*p)) { /* INTL: ISO space. */
  41. p++;
  42. }
  43. if (p == limit) { /* no element found */
  44. elemStart = limit;
  45. goto done;
  46. }
  47. if (*p == '{') {
  48. openBraces = 1;
  49. p++;
  50. } else if (*p == '"') {
  51. inQuotes = 1;
  52. p++;
  53. }
  54. elemStart = p;
  55. if (bracePtr != 0) {
  56. *bracePtr = openBraces;
  57. }
  58. /*
  59. * Find element's end (a space, close brace, or the end of the string).
  60. */
  61. while (p < limit) {
  62. switch (*p) {
  63. /*
  64. * Open brace: don't treat specially unless the element is in
  65. * braces. In this case, keep a nesting count.
  66. */
  67. case '{':
  68. if (openBraces != 0) {
  69. openBraces++;
  70. }
  71. break;
  72. /*
  73. * Close brace: if element is in braces, keep nesting count and
  74. * quit when the last close brace is seen.
  75. */
  76. case '}':
  77. if (openBraces > 1) {
  78. openBraces--;
  79. } else if (openBraces == 1) {
  80. size = (p - elemStart);
  81. p++;
  82. if ((p >= limit) || egg_isspace(*p)) { /* INTL: ISO space. */
  83. goto done;
  84. }
  85. /*
  86. * Garbage after the closing brace; return an error.
  87. */
  88. if (resultBuf) {
  89. p2 = p;
  90. while ((p2 < limit)
  91. && (!egg_isspace(*p2)) /* INTL: ISO space. */
  92. && (p2 < p+20)) {
  93. p2++;
  94. }
  95. // snprintf(resultBuf, RESULT_LEN, "list element in braces followed by \"%.*s\" instead of space", (int) (p2-p), p);
  96. }
  97. return ERROR;
  98. }
  99. break;
  100. /*
  101. * Backslash: skip over everything up to the end of the
  102. * backslash sequence.
  103. */
  104. /* case '\\': {
  105. Tcl_UtfBackslash(p, &numChars, NULL);
  106. p += (numChars - 1);
  107. break;
  108. }
  109. */
  110. /*
  111. * Space: ignore if element is in braces or quotes; otherwise
  112. * terminate element.
  113. */
  114. case ' ':
  115. case '\f':
  116. case '\n':
  117. case '\r':
  118. case '\t':
  119. case '\v':
  120. if ((openBraces == 0) && !inQuotes) {
  121. size = (p - elemStart);
  122. goto done;
  123. }
  124. break;
  125. /*
  126. * Double-quote: if element is in quotes then terminate it.
  127. */
  128. case '"':
  129. if (inQuotes) {
  130. size = (p - elemStart);
  131. p++;
  132. if ((p >= limit) || egg_isspace(*p)) { /* INTL: ISO space */
  133. goto done;
  134. }
  135. /*
  136. * Garbage after the closing quote; return an error.
  137. */
  138. if (resultBuf) {
  139. p2 = p;
  140. while ((p2 < limit)
  141. && (!egg_isspace(*p2)) /* INTL: ISO space */
  142. && (p2 < p+20)) {
  143. p2++;
  144. }
  145. // sprintf(resultBuf, "list element in quotes followed by \"%.*s\" %s", (int) (p2-p), p, "instead of space");
  146. }
  147. return ERROR;
  148. }
  149. break;
  150. }
  151. p++;
  152. }
  153. /*
  154. * End of list: terminate element.
  155. */
  156. if (p == limit) {
  157. if (openBraces != 0) {
  158. if (resultBuf) {
  159. simple_snprintf(resultBuf, RESULT_LEN, "unmatched open brace in list");
  160. }
  161. return ERROR;
  162. } else if (inQuotes) {
  163. if (resultBuf) {
  164. simple_snprintf(resultBuf, RESULT_LEN, "unmatched open quote in list");
  165. }
  166. return ERROR;
  167. }
  168. size = (p - elemStart);
  169. }
  170. done:
  171. while ((p < limit) && (egg_isspace(*p))) { /* INTL: ISO space. */
  172. p++;
  173. }
  174. *elementPtr = elemStart;
  175. *nextPtr = p;
  176. if (sizePtr != 0) {
  177. *sizePtr = size;
  178. }
  179. return OK;
  180. }
  181. /* unneeded?
  182. int CopyAndCollapse(int count, const char *src, char *dst)
  183. {
  184. register char c;
  185. int numRead;
  186. int newCount = 0;
  187. int backslashCount;
  188. for (c = *src; count > 0; src++, c = *src, count--) {
  189. if (c == '\\') {
  190. backslashCount = Tcl_UtfBackslash(src, &numRead, dst);
  191. dst += backslashCount;
  192. newCount += backslashCount;
  193. src += numRead-1;
  194. count -= numRead-1;
  195. } else {
  196. *dst = c;
  197. dst++;
  198. newCount++;
  199. }
  200. }
  201. *dst = 0;
  202. return newCount;
  203. }
  204. */
  205. int SplitList(char *resultBuf, const char *list, int *argcPtr, const char ***argvPtr)
  206. {
  207. const char **argv = NULL;
  208. const char *l = NULL;
  209. const char *element = NULL;
  210. char *p = NULL;
  211. int result, brace = 0;
  212. size_t size = 2; /* initialized to 1 for NULL pointer */
  213. size_t length, elSize, i = 0;
  214. /*
  215. * Figure out how much space to allocate. There must be enough
  216. * space for both the array of pointers and also for a copy of
  217. * the list. To estimate the number of pointers needed, count
  218. * the number of space characters in the list.
  219. */
  220. for (l = list; *l != 0; l++) {
  221. if (egg_isspace(*l)) { /* INTL: ISO space. */
  222. size++;
  223. }
  224. }
  225. argv = (const char **) my_calloc(1, (unsigned) ((size * sizeof(char *)) + (l - list) + 1 + 15)); /* 15 cuz the tcl src is hard to follow */
  226. length = strlen(list);
  227. for (p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) {
  228. const char *prevList = list;
  229. result = FindElement(resultBuf, list, length, &element, &list, &elSize, &brace);
  230. length -= (list - prevList);
  231. if (result != OK) {
  232. free((char *) argv);
  233. return result;
  234. }
  235. if (*element == 0) {
  236. break;
  237. }
  238. if (i >= size) {
  239. free((char *) argv);
  240. if (resultBuf)
  241. strlcpy(resultBuf, "internal error in SplitList", RESULT_LEN);
  242. return ERROR;
  243. }
  244. argv[i] = p;
  245. if (brace) {
  246. memcpy(p, element, elSize);
  247. p += elSize;
  248. *p = 0;
  249. p++;
  250. } else {
  251. /* CopyAndCollapse(elSize, element, p); */
  252. memcpy(p, element, elSize);
  253. p += elSize + 1;
  254. }
  255. }
  256. argv[i] = NULL;
  257. *argvPtr = argv;
  258. *argcPtr = i;
  259. return OK;
  260. }
  261. /* Parse options for a channel.
  262. */
  263. int channel_modify(char *result, struct chanset_t *chan, int items, char **item, bool cmd)
  264. {
  265. bool error = 0;
  266. int old_status = chan->status,
  267. old_mode_mns_prot = chan->mode_mns_prot,
  268. old_mode_pls_prot = chan->mode_pls_prot;
  269. char s[121] = "", result_extra[RESULT_LEN / 2] = "";
  270. if (result)
  271. result[0] = 0;
  272. for (register int i = 0; i < items; i++) {
  273. /* Chanchar template
  274. } else if (!strcmp(item[i], "temp")) {
  275. i++;
  276. if (i >= items) {
  277. if (result)
  278. strlcpy(result, "channel temp needs argument", RESULT_LEN);
  279. return ERROR;
  280. }
  281. strlcpy(chan->temp, item[i], sizeof(chan->temp));
  282. check_temp(chan);
  283. */
  284. if (!strcmp(item[i], "chanmode")) {
  285. i++;
  286. if (i >= items) {
  287. if (result)
  288. strlcpy(result, "channel chanmode needs argument", RESULT_LEN);
  289. return ERROR;
  290. }
  291. strlcpy(s, item[i], sizeof(s));
  292. set_mode_protect(chan, s);
  293. } else if (!strcmp(item[i], "topic")) {
  294. char *p = NULL;
  295. i++;
  296. if (i >= items) {
  297. if (result)
  298. strlcpy(result, "topic needs argument", RESULT_LEN);
  299. return ERROR;
  300. }
  301. p = replace(item[i], "{", "[");
  302. p = replace(p, "}", "]");
  303. strlcpy(chan->topic, p, sizeof(chan->topic));
  304. } else if (!cmd && !strcmp(item[i], "addedby")) {
  305. i++;
  306. if (i >= items) {
  307. if (result)
  308. strlcpy(result, "addedby needs argument", RESULT_LEN);
  309. return ERROR;
  310. }
  311. strlcpy(chan->added_by, item[i], NICKLEN);
  312. } else if (!cmd && !strcmp(item[i], "addedts")) {
  313. i++;
  314. if (i >= items) {
  315. if (result)
  316. strlcpy(result, "addedts needs argument", RESULT_LEN);
  317. return ERROR;
  318. }
  319. chan->added_ts = atoi(item[i]);
  320. } else if (!strcmp(item[i], "limit")) {
  321. i++;
  322. if (i >= items) {
  323. if (result)
  324. strlcpy(result, "channel limit needs argument", RESULT_LEN);
  325. return ERROR;
  326. }
  327. chan->limitraise = atoi(item[i]);
  328. chan->limit_prot = 0;
  329. /*
  330. } else if (!strcmp(item[i], "revenge-mode")) {
  331. i++;
  332. if (i >= items) {
  333. if (result)
  334. strlcpy(result, "channel revenge-mode needs argument", RESULT_LEN);
  335. return ERROR;
  336. }
  337. chan->revenge_mode = atoi(item[i]);
  338. */
  339. } else if (!strcmp(item[i], "ban-time")) {
  340. i++;
  341. if (i >= items) {
  342. if (result)
  343. strlcpy(result, "channel ban-time needs argument", RESULT_LEN);
  344. return ERROR;
  345. }
  346. chan->ban_time = atoi(item[i]);
  347. } else if (!strcmp(item[i], "exempt-time")) {
  348. i++;
  349. if (i >= items) {
  350. if (result)
  351. strlcpy(result, "channel exempt-time needs argument", RESULT_LEN);
  352. return ERROR;
  353. }
  354. chan->exempt_time = atoi(item[i]);
  355. } else if (!strcmp(item[i], "invite-time")) {
  356. i++;
  357. if (i >= items) {
  358. if (result)
  359. strlcpy(result, "channel invite-time needs argument", RESULT_LEN);
  360. return ERROR;
  361. }
  362. chan->invite_time = atoi(item[i]);
  363. } else if (!strcmp(item[i], "closed-ban")) {
  364. i++;
  365. if (i >= items) {
  366. if (result)
  367. strlcpy(result, "channel closed-ban needs argument", RESULT_LEN);
  368. return ERROR;
  369. }
  370. chan->closed_ban = atoi(item[i]);
  371. } else if (!strcmp(item[i], "closed-invite")) {
  372. i++;
  373. if (i >= items) {
  374. if (result)
  375. strlcpy(result, "channel closed-invite needs argument", RESULT_LEN);
  376. return ERROR;
  377. }
  378. chan->closed_invite = atoi(item[i]);
  379. if (chan->mode_mns_prot & CHANINV && chan->closed_invite)
  380. chan->closed_invite = 0;
  381. } else if (!strcmp(item[i], "closed-private")) {
  382. i++;
  383. if (i >= items) {
  384. if (result)
  385. strlcpy(result, "channel closed-private needs argument", RESULT_LEN);
  386. return ERROR;
  387. }
  388. chan->closed_private = atoi(item[i]);
  389. if (chan->mode_mns_prot & CHANPRIV && chan->closed_private)
  390. chan->closed_private = 0;
  391. } else if (!strcmp(item[i], "voice-non-ident")) {
  392. i++;
  393. if (i >= items) {
  394. if (result)
  395. strlcpy(result, "channel voice-ident needs argument", RESULT_LEN);
  396. return ERROR;
  397. }
  398. chan->voice_non_ident = atoi(item[i]);
  399. } else if (!strcmp(item[i], "bad-cookie")) {
  400. i++;
  401. if (i >= items) {
  402. if (result)
  403. strlcpy(result, "channel bad-cookie needs argument", RESULT_LEN);
  404. return ERROR;
  405. }
  406. chan->bad_cookie = deflag_translate(item[i]);
  407. } else if (!strcmp(item[i], "manop")) {
  408. i++;
  409. if (i >= items) {
  410. if (result)
  411. strlcpy(result, "channel manop needs argument", RESULT_LEN);
  412. return ERROR;
  413. }
  414. chan->manop = deflag_translate(item[i]);
  415. } else if (!strcmp(item[i], "mdop")) {
  416. i++;
  417. if (i >= items) {
  418. if (result)
  419. strlcpy(result, "channel mdop needs argument", RESULT_LEN);
  420. return ERROR;
  421. }
  422. chan->mdop = deflag_translate(item[i]);
  423. } else if (!strcmp(item[i], "mop")) {
  424. i++;
  425. if (i >= items) {
  426. if (result)
  427. strlcpy(result, "channel mop needs argument", RESULT_LEN);
  428. return ERROR;
  429. }
  430. chan->mop = deflag_translate(item[i]);
  431. } else if (!strcmp(item[i], "knock")) {
  432. i++;
  433. if (i >= items) {
  434. if (result)
  435. strlcpy(result, "channel knock needs argument", RESULT_LEN);
  436. return ERROR;
  437. }
  438. if (!str_isdigit(item[i])) {
  439. if (!strcasecmp("Op", item[i]))
  440. chan->knock_flags = FLOOD_EXEMPT_OP;
  441. else if (!strcasecmp("Voice", item[i]))
  442. chan->knock_flags = FLOOD_EXEMPT_VOICE;
  443. else if (!strcasecmp("User", item[i]))
  444. chan->knock_flags = FLOOD_EXEMPT_USER;
  445. else if (!strcasecmp("None", item[i]))
  446. chan->knock_flags = 0;
  447. else {
  448. if (result)
  449. strlcpy(result, "channel knock only accepts Op|Voice|User|None", RESULT_LEN);
  450. return ERROR;
  451. }
  452. } else
  453. chan->knock_flags = atoi(item[i]);
  454. } else if (!strcmp(item[i], "flood-exempt")) {
  455. i++;
  456. if (i >= items) {
  457. if (result)
  458. strlcpy(result, "channel flood-exempt needs argument", RESULT_LEN);
  459. return ERROR;
  460. }
  461. if (!str_isdigit(item[i])) {
  462. if (!strcasecmp("Op", item[i]))
  463. chan->flood_exempt_mode = FLOOD_EXEMPT_OP;
  464. else if (!strcasecmp("Voice", item[i]))
  465. chan->flood_exempt_mode = FLOOD_EXEMPT_VOICE;
  466. else if (!strcasecmp("None", item[i]))
  467. chan->flood_exempt_mode = 0;
  468. else {
  469. if (result)
  470. strlcpy(result, "channel flood-exempt only accepts Op|Voice|None", RESULT_LEN);
  471. return ERROR;
  472. }
  473. } else
  474. chan->flood_exempt_mode = atoi(item[i]);
  475. } else if (!strcmp(item[i], "flood-lock-time")) {
  476. i++;
  477. if (i >= items) {
  478. if (result)
  479. strlcpy(result, "channel flood-lock-time needs argument", RESULT_LEN);
  480. return ERROR;
  481. }
  482. chan->flood_lock_time = atoi(item[i]);
  483. } else if (!strcmp(item[i], "auto-delay")) {
  484. i++;
  485. if (i >= items) {
  486. if (result)
  487. strlcpy(result, "channel auto-delay needs argument", RESULT_LEN);
  488. return ERROR;
  489. }
  490. chan->auto_delay = atoi(item[i]);
  491. } else if (!strcmp(item[i], "ban-type")) {
  492. i++;
  493. if (i >= items) {
  494. if (result)
  495. strlcpy(result, "channel ban-type needs argument", RESULT_LEN);
  496. return ERROR;
  497. }
  498. chan->ban_type = atoi(item[i]);
  499. /* Chanint template
  500. * } else if (!strcmp(item[i], "temp")) {
  501. * i++;
  502. * if (i >= items) {
  503. * if (result)
  504. * strlcpy(result, "channel temp needs argument", RESULT_LEN);
  505. * return ERROR;
  506. * }
  507. * chan->temp = atoi(item[i]);
  508. */
  509. }
  510. else if (!strcmp(item[i], "+enforcebans"))
  511. chan->status |= CHAN_ENFORCEBANS;
  512. else if (!strcmp(item[i], "-enforcebans"))
  513. chan->status &= ~CHAN_ENFORCEBANS;
  514. else if (!strcmp(item[i], "+dynamicbans"))
  515. chan->status |= CHAN_DYNAMICBANS;
  516. else if (!strcmp(item[i], "-dynamicbans"))
  517. chan->status &= ~CHAN_DYNAMICBANS;
  518. else if (!strcmp(item[i], "-userbans"))
  519. chan->status |= CHAN_NOUSERBANS;
  520. else if (!strcmp(item[i], "+userbans"))
  521. chan->status &= ~CHAN_NOUSERBANS;
  522. else if (!strcmp(item[i], "+bitch"))
  523. chan->status |= CHAN_BITCH;
  524. else if (!strcmp(item[i], "-bitch"))
  525. chan->status &= ~CHAN_BITCH;
  526. else if (!strcmp(item[i], "+nodesynch"))
  527. chan->status |= CHAN_NODESYNCH;
  528. else if (!strcmp(item[i], "-nodesynch"))
  529. chan->status &= ~CHAN_NODESYNCH;
  530. else if (!strcmp(item[i], "+inactive"))
  531. chan->status |= CHAN_INACTIVE;
  532. else if (!strcmp(item[i], "-inactive"))
  533. chan->status&= ~CHAN_INACTIVE;
  534. else if (!strcmp(item[i], "+secret"))
  535. chan->status |= CHAN_SECRET;
  536. else if (!strcmp(item[i], "-secret"))
  537. chan->status &= ~CHAN_SECRET;
  538. else if (!strcmp(item[i], "+cycle"))
  539. chan->status |= CHAN_CYCLE;
  540. else if (!strcmp(item[i], "-cycle"))
  541. chan->status &= ~CHAN_CYCLE;
  542. else if (!strcmp(item[i], "+dynamicexempts"))
  543. chan->status |= CHAN_DYNAMICEXEMPTS;
  544. else if (!strcmp(item[i], "-dynamicexempts"))
  545. chan->status &= ~CHAN_DYNAMICEXEMPTS;
  546. else if (!strcmp(item[i], "-userexempts"))
  547. chan->status |= CHAN_NOUSEREXEMPTS;
  548. else if (!strcmp(item[i], "+userexempts"))
  549. chan->status &= ~CHAN_NOUSEREXEMPTS;
  550. else if (!strcmp(item[i], "+dynamicinvites"))
  551. chan->status |= CHAN_DYNAMICINVITES;
  552. else if (!strcmp(item[i], "-dynamicinvites"))
  553. chan->status &= ~CHAN_DYNAMICINVITES;
  554. else if (!strcmp(item[i], "-userinvites"))
  555. chan->status |= CHAN_NOUSERINVITES;
  556. else if (!strcmp(item[i], "+userinvites"))
  557. chan->status &= ~CHAN_NOUSERINVITES;
  558. else if (!strcmp(item[i], "+closed"))
  559. chan->status |= CHAN_CLOSED;
  560. else if (!strcmp(item[i], "-closed"))
  561. chan->status &= ~CHAN_CLOSED;
  562. else if (HAVE_TAKE && !strcmp(item[i], "+take"))
  563. chan->status |= CHAN_TAKE;
  564. else if (HAVE_TAKE && !strcmp(item[i], "-take"))
  565. chan->status &= ~CHAN_TAKE;
  566. else if (!HAVE_TAKE && !strcmp(item[i], "+take"))
  567. chan->status |= CHAN_BITCH;
  568. else if (!HAVE_TAKE && !strcmp(item[i], "-take"))
  569. chan->status &= ~CHAN_BITCH;
  570. else if (!strcmp(item[i], "+voice"))
  571. chan->status |= CHAN_VOICE;
  572. else if (!strcmp(item[i], "-voice"))
  573. chan->status &= ~CHAN_VOICE;
  574. else if (!strcmp(item[i], "+autoop"))
  575. chan->status |= CHAN_AUTOOP;
  576. else if (!strcmp(item[i], "-autoop"))
  577. chan->status &= ~CHAN_AUTOOP;
  578. else if (!strcmp(item[i], "+botbitch"))
  579. chan->status |= CHAN_BOTBITCH;
  580. else if (!strcmp(item[i], "-botbitch"))
  581. chan->status &= ~CHAN_BOTBITCH;
  582. else if (!strcmp(item[i], "+nomassjoin"))
  583. chan->status |= CHAN_NOMASSJOIN;
  584. else if (!strcmp(item[i], "-nomassjoin"))
  585. chan->status &= ~CHAN_NOMASSJOIN;
  586. else if (!strcmp(item[i], "+meankicks"))
  587. chan->status |= CHAN_MEANKICKS;
  588. else if (!strcmp(item[i], "-meankicks"))
  589. chan->status &= ~CHAN_MEANKICKS;
  590. else if (!strcmp(item[i], "+rbl"))
  591. chan->status |= CHAN_RBL;
  592. else if (!strcmp(item[i], "-rbl"))
  593. chan->status &= ~CHAN_RBL;
  594. else if (!strcmp(item[i], "+voicebitch"))
  595. chan->status |= CHAN_VOICEBITCH;
  596. else if (!strcmp(item[i], "-voicebitch"))
  597. chan->status &= ~CHAN_VOICEBITCH;
  598. /* Chanflag template
  599. * else if (!strcmp(item[i], "+temp"))
  600. * chan->status |= CHAN_TEMP;
  601. * else if (!strcmp(item[i], "-temp"))
  602. * chan->status &= ~CHAN_TEMP;
  603. */
  604. else if (!strcmp(item[i], "+fastop"))
  605. chan->status |= CHAN_FASTOP;
  606. else if (!strcmp(item[i], "-fastop"))
  607. chan->status &= ~CHAN_FASTOP;
  608. else if (!strcmp(item[i], "+private"))
  609. chan->status |= CHAN_PRIVATE;
  610. else if (!strcmp(item[i], "-private"))
  611. chan->status &= ~CHAN_PRIVATE;
  612. else if (!strcmp(item[i], "+backup"))
  613. chan->status |= CHAN_BACKUP;
  614. else if (!strcmp(item[i], "-backup"))
  615. chan->status &= ~CHAN_BACKUP;
  616. /* ignore wasoptest, stopnethack and clearbans in chanfile, remove
  617. this later */
  618. else if (!cmd && !HAVE_TAKE && !strcmp(item[i], "+take")) ;
  619. else if (!cmd && !HAVE_TAKE && !strcmp(item[i], "-take")) ;
  620. else if (!cmd && !strcmp(item[i], "stopnethack-mode")) ;
  621. else if (!cmd && !strcmp(item[i], "revenge-mode")) ;
  622. else if (!cmd && !strcmp(item[i], "+revenge")) ;
  623. else if (!cmd && !strcmp(item[i], "-revenge")) ;
  624. else if (!cmd && !strcmp(item[i], "+revengebot")) ;
  625. else if (!cmd && !strcmp(item[i], "-revengebot")) ;
  626. else if (!cmd && !strcmp(item[i], "+manop")) ;
  627. else if (!cmd && !strcmp(item[i], "-manop")) ;
  628. else if (!cmd && !strcmp(item[i], "+dontkickops")) ;
  629. else if (!cmd && !strcmp(item[i], "-dontkickops")) ;
  630. else if (!cmd && !strcmp(item[i], "+nomdop")) ;
  631. else if (!cmd && !strcmp(item[i], "-nomdop")) ;
  632. else if (!cmd && !strcmp(item[i], "+protectfriends")) ;
  633. else if (!cmd && !strcmp(item[i], "-protectfriends")) ;
  634. else if (!cmd && !strcmp(item[i], "+protectops")) ;
  635. else if (!cmd && !strcmp(item[i], "-protectops")) ;
  636. else if (!cmd && !strcmp(item[i], "+punish")) ;
  637. else if (!cmd && !strcmp(item[i], "-punish")) ;
  638. else if (!cmd && !strcmp(item[i], "+seen")) ;
  639. else if (!cmd && !strcmp(item[i], "-seen")) ;
  640. else if (!cmd && !strcmp(item[i], "+secret")) ;
  641. else if (!cmd && !strcmp(item[i], "-secret")) ;
  642. else if (!cmd && !strcmp(item[i], "-stopnethack")) ;
  643. else if (!cmd && !strcmp(item[i], "+stopnethack")) ;
  644. else if (!cmd && !strcmp(item[i], "-wasoptest")) ;
  645. else if (!cmd && !strcmp(item[i], "+wasoptest")) ; /* Eule 01.2000 */
  646. else if (!cmd && !strcmp(item[i], "+clearbans")) ;
  647. else if (!cmd && !strcmp(item[i], "-clearbans")) ;
  648. else if (!cmd && !strncmp(item[i], "need-", 5)) ;
  649. else if (!strncmp(item[i], "flood-", 6)) {
  650. int *pthr = NULL;
  651. interval_t *ptime = NULL;
  652. char *p = NULL;
  653. if (!strcmp(item[i] + 6, "*")) {
  654. i++;
  655. if (i >= items) {
  656. if (result)
  657. simple_snprintf(result, RESULT_LEN, "%s needs argument", item[i - 1]);
  658. return ERROR;
  659. }
  660. p = strchr(item[i], ':');
  661. int thr = 0;
  662. interval_t time = 0;
  663. if (p) {
  664. *p++ = 0;
  665. thr = atoi(item[i]);
  666. time = atoi(p);
  667. *--p = ':';
  668. } else {
  669. thr = atoi(item[i]);
  670. time = 1;
  671. }
  672. chan->flood_pub_thr = thr;
  673. chan->flood_pub_time = time;
  674. chan->flood_join_thr = thr;
  675. chan->flood_join_time = time;
  676. chan->flood_ctcp_thr = thr;
  677. chan->flood_ctcp_time = time;
  678. chan->flood_kick_thr = thr;
  679. chan->flood_kick_time = time;
  680. chan->flood_deop_thr = thr;
  681. chan->flood_deop_time = time;
  682. chan->flood_nick_thr = thr;
  683. chan->flood_nick_time = time;
  684. chan->flood_mjoin_thr = thr;
  685. chan->flood_mjoin_time = time;
  686. } else if (!strcmp(item[i] + 6, "chan")) {
  687. pthr = &chan->flood_pub_thr;
  688. ptime = &chan->flood_pub_time;
  689. } else if (!strcmp(item[i] + 6, "join")) {
  690. pthr = &chan->flood_join_thr;
  691. ptime = &chan->flood_join_time;
  692. } else if (!strcmp(item[i] + 6, "ctcp")) {
  693. pthr = &chan->flood_ctcp_thr;
  694. ptime = &chan->flood_ctcp_time;
  695. } else if (!strcmp(item[i] + 6, "kick")) {
  696. pthr = &chan->flood_kick_thr;
  697. ptime = &chan->flood_kick_time;
  698. } else if (!strcmp(item[i] + 6, "deop")) {
  699. pthr = &chan->flood_deop_thr;
  700. ptime = &chan->flood_deop_time;
  701. } else if (!strcmp(item[i] + 6, "nick")) {
  702. pthr = &chan->flood_nick_thr;
  703. ptime = &chan->flood_nick_time;
  704. } else if (!strcmp(item[i] + 6, "mjoin")) {
  705. pthr = &chan->flood_mjoin_thr;
  706. ptime = &chan->flood_mjoin_time;
  707. } else { /* Ignore for optimal forward compatibility */
  708. i++;
  709. continue;
  710. }
  711. if (pthr && ptime) { //Ignore flood-*
  712. i++;
  713. if (i >= items) {
  714. if (result)
  715. simple_snprintf(result, RESULT_LEN, "%s needs argument", item[i - 1]);
  716. return ERROR;
  717. }
  718. p = strchr(item[i], ':');
  719. if (p) {
  720. *p++ = 0;
  721. *pthr = atoi(item[i]);
  722. *ptime = atoi(p);
  723. *--p = ':';
  724. } else {
  725. *pthr = atoi(item[i]);
  726. *ptime = 1;
  727. }
  728. }
  729. } else {
  730. if (result && item[i][0]) { /* ignore "" */
  731. if (!result[0])
  732. strlcpy(result, "illegal channel option: ", RESULT_LEN);
  733. if (result_extra[0])
  734. strlcat(result_extra, " ", sizeof(result_extra));
  735. strlcat(result_extra, item[i], sizeof(result_extra));
  736. }
  737. error = 1;
  738. }
  739. }
  740. if ((chan->status ^ old_status) & CHAN_TAKE)
  741. chan->status |= (CHAN_FASTOP|CHAN_BITCH); // to avoid bots still mass opping from +take from not using cookies
  742. if (!conf.bot->hub && (chan != chanset_default)) {
  743. if ((old_status ^ chan->status) & (CHAN_INACTIVE | CHAN_BACKUP)) {
  744. if (!shouldjoin(chan) && (chan->ircnet_status & (CHAN_ACTIVE | CHAN_PEND)))
  745. dprintf(DP_SERVER, "PART %s\n", chan->name);
  746. if (shouldjoin(chan) && !(chan->ircnet_status & (CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING))) {
  747. dprintf(DP_SERVER, "JOIN %s %s\n", (chan->name[0]) ?
  748. chan->name : chan->dname,
  749. chan->channel.key[0] ?
  750. chan->channel.key : chan->key_prot);
  751. chan->ircnet_status |= CHAN_JOINING;
  752. }
  753. }
  754. if (me_op(chan)) {
  755. if ((old_status ^ chan->status) & (CHAN_ENFORCEBANS|CHAN_NOUSERBANS|CHAN_DYNAMICBANS|CHAN_NOUSEREXEMPTS|CHAN_NOUSERINVITES|CHAN_DYNAMICEXEMPTS|CHAN_DYNAMICINVITES)) {
  756. recheck_channel(chan, 1);
  757. /* if we -take, recheck the chan for modes and shit */
  758. /* also -[bot]bitch/-private might allow for auto-opping users */
  759. } else if ((chan->status ^ old_status) & (CHAN_BITCH | CHAN_BOTBITCH | CHAN_PRIVATE | CHAN_CLOSED)) {
  760. recheck_channel(chan, 0);
  761. } else if ((old_status & CHAN_TAKE) && !(chan->status & CHAN_TAKE)) {
  762. //Set -take, fetch bans/exempts/invites
  763. recheck_channel(chan, 2);
  764. } else if (old_mode_pls_prot != chan->mode_pls_prot || old_mode_mns_prot != chan->mode_mns_prot) {
  765. recheck_channel_modes(chan);
  766. }
  767. }
  768. }
  769. if (result && result[0] && result_extra[0])
  770. strlcat(result, result_extra, RESULT_LEN);
  771. if (error)
  772. return ERROR;
  773. return OK;
  774. }
  775. static void init_masklist(masklist *m)
  776. {
  777. m->mask = (char *) my_calloc(1, 1);
  778. m->who = NULL;
  779. m->next = NULL;
  780. }
  781. /* Initialize out the channel record.
  782. */
  783. static void init_channel(struct chanset_t *chan, bool reset)
  784. {
  785. chan->channel.maxmembers = 0;
  786. chan->channel.mode = 0;
  787. chan->channel.members = 0;
  788. if (!reset)
  789. chan->channel.key = (char *) my_calloc(1, 1);
  790. chan->channel.ban = (masklist *) my_calloc(1, sizeof(masklist));
  791. init_masklist(chan->channel.ban);
  792. chan->channel.exempt = (masklist *) my_calloc(1, sizeof(masklist));
  793. init_masklist(chan->channel.exempt);
  794. chan->channel.invite = (masklist *) my_calloc(1, sizeof(masklist));
  795. init_masklist(chan->channel.invite);
  796. chan->channel.member = (memberlist *) my_calloc(1, sizeof(memberlist));
  797. chan->channel.member->nick[0] = 0;
  798. chan->channel.member->next = NULL;
  799. chan->channel.topic = NULL;
  800. }
  801. static void clear_masklist(masklist *m)
  802. {
  803. masklist *temp = NULL;
  804. for (; m; m = temp) {
  805. temp = m->next;
  806. if (m->mask)
  807. free(m->mask);
  808. if (m->who)
  809. free(m->who);
  810. free(m);
  811. }
  812. }
  813. /* Clear out channel data from memory.
  814. */
  815. void clear_channel(struct chanset_t *chan, bool reset)
  816. {
  817. memberlist *m = NULL, *m1 = NULL;
  818. if (chan->channel.topic)
  819. free(chan->channel.topic);
  820. for (m = chan->channel.member; m; m = m1) {
  821. m1 = m->next;
  822. free(m);
  823. }
  824. clear_masklist(chan->channel.ban);
  825. chan->channel.ban = NULL;
  826. clear_masklist(chan->channel.exempt);
  827. chan->channel.exempt = NULL;
  828. clear_masklist(chan->channel.invite);
  829. chan->channel.invite = NULL;
  830. chan->channel.last_eI = 0;
  831. chan->ircnet_status &= ~CHAN_HAVEBANS;
  832. if (reset)
  833. init_channel(chan, 1);
  834. }
  835. /* Create new channel and parse commands.
  836. */
  837. int channel_add(char *result, char *newname, char *options, bool isdefault)
  838. {
  839. /* When loading userfile */
  840. if (newname && newname[0] && loading && !strcmp(newname, "default"))
  841. isdefault = 1;
  842. if (!newname || !newname[0] || (!isdefault && !strchr(CHANMETA, newname[0]))) {
  843. if (result)
  844. strlcpy(result, "invalid channel prefix", RESULT_LEN);
  845. return ERROR;
  846. }
  847. if (strchr(newname, ',') != NULL) {
  848. if (result)
  849. strlcpy(result, "invalid channel name", RESULT_LEN);
  850. return ERROR;
  851. }
  852. const char **item = NULL;
  853. int items = 0;
  854. char buf[3001] = "";
  855. simple_snprintf(buf, sizeof(buf), "chanmode { %s }", glob_chanmode);
  856. if (!isdefault) { // These are passed in in 'options'
  857. strlcat(buf, " ", sizeof(buf));
  858. strlcat(buf, def_chanset, sizeof(buf));
  859. }
  860. // Add in 'default' channel options
  861. if (!isdefault && chanset_default) {
  862. bd::String default_chan_options = channel_to_string(chanset_default);
  863. strlcat(buf, " ", sizeof(buf));
  864. strlcat(buf, default_chan_options.c_str(), sizeof(buf));
  865. }
  866. if (options && options[0]) {
  867. strlcat(buf, " ", sizeof(buf));
  868. strlcat(buf, options, sizeof(buf));
  869. }
  870. if (SplitList(result, buf, &items, &item) != OK)
  871. return ERROR;
  872. bool join = 0;
  873. struct chanset_t *chan = NULL;
  874. int ret = OK;
  875. if ((chan = findchan_by_dname(newname))) {
  876. /* Already existing channel, maybe a reload of the channel file */
  877. chan->status &= ~CHAN_FLAGGED; /* don't delete me! :) */
  878. } else {
  879. chan = (struct chanset_t *) my_calloc(1, sizeof(struct chanset_t));
  880. /* These are defaults, bzero already set them 0, but we set them for future reference */
  881. chan->limit_prot = 0;
  882. chan->limit = 0;
  883. chan->closed_ban = 0;
  884. chan->closed_private = 1;
  885. chan->closed_invite = 1;
  886. chan->voice_non_ident = 1;
  887. chan->auto_delay = 5;
  888. chan->ban_type = 3;
  889. /* Chanint template
  890. * chan->temp = 0;
  891. */
  892. chan->knock_flags = 0;
  893. chan->flood_lock_time = 120;
  894. chan->flood_exempt_mode = 0;
  895. chan->flood_pub_thr = gfld_chan_thr;
  896. chan->flood_pub_time = gfld_chan_time;
  897. chan->flood_ctcp_thr = gfld_ctcp_thr;
  898. chan->flood_ctcp_time = gfld_ctcp_time;
  899. chan->flood_join_thr = gfld_join_thr;
  900. chan->flood_join_time = gfld_join_time;
  901. chan->flood_deop_thr = gfld_deop_thr;
  902. chan->flood_deop_time = gfld_deop_time;
  903. chan->flood_kick_thr = gfld_kick_thr;
  904. chan->flood_kick_time = gfld_kick_time;
  905. chan->flood_nick_thr = gfld_nick_thr;
  906. chan->flood_nick_time = gfld_nick_time;
  907. chan->flood_mjoin_thr = 6;
  908. chan->flood_mjoin_time = 1;
  909. // chan->revenge_mode = global_revenge_mode;
  910. chan->limitraise = 20;
  911. chan->ban_time = global_ban_time;
  912. chan->exempt_time = global_exempt_time;
  913. chan->invite_time = global_invite_time;
  914. chan->channel.jointime = 0;
  915. chan->channel.parttime = 0;
  916. chan->channel.fighting = 0;
  917. chan->channel.drone_set_mode = 0;
  918. chan->channel.drone_jointime = 0;
  919. chan->channel.drone_joins = 0;
  920. chan->channel.last_eI = 0;
  921. /* We _only_ put the dname (display name) in here so as not to confuse
  922. * any code later on. chan->name gets updated with the channel name as
  923. * the server knows it, when we join the channel. <cybah>
  924. */
  925. strlcpy(chan->dname, newname, 81);
  926. /* Initialize chan->channel info */
  927. if (isdefault) {
  928. if (chanset_default)
  929. remove_channel(chanset_default);
  930. chanset_default = chan;
  931. } else {
  932. init_channel(chan, 0);
  933. list_append((struct list_type **) &chanset, (struct list_type *) chan);
  934. /* Channel name is stored in xtra field for sharebot stuff */
  935. if (!conf.bot->hub && !isdefault)
  936. join = 1;
  937. }
  938. }
  939. /* If loading is set, we're loading the userfile. Ignore errors while
  940. * reading userfile and just return OK. This is for compatability
  941. * if a user goes back to an eggdrop that no-longer supports certain
  942. * (channel) options.
  943. */
  944. if ((channel_modify(result, chan, items, (char **) item, 0) != OK)) {
  945. putlog(LOG_ERROR, "*", "Error parsing channel options for %s: %s", chan->dname, result);
  946. if (!loading)
  947. ret = ERROR;
  948. }
  949. free(item);
  950. if (join && shouldjoin(chan))
  951. dprintf(DP_SERVER, "JOIN %s %s\n", chan->dname, chan->key_prot);
  952. return ret;
  953. }