tclchan.c 29 KB

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