chanmisc.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2010 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, changed_groups = false;
  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], "groups")) {
  294. i++;
  295. if (i >= items) {
  296. if (result)
  297. strlcpy(result, "channel groups needs argument", RESULT_LEN);
  298. return ERROR;
  299. }
  300. // Get string into right format
  301. bd::String changroups(item[i]);
  302. // Replace commas with spaces to be in proper format
  303. changroups.sub(",", " ");
  304. changroups.trim();
  305. *(chan->groups) = changroups.split(" ");
  306. changed_groups = true;
  307. } else if (!strcmp(item[i], "topic")) {
  308. char *p = NULL;
  309. i++;
  310. if (i >= items) {
  311. if (result)
  312. strlcpy(result, "topic needs argument", RESULT_LEN);
  313. return ERROR;
  314. }
  315. p = replace(item[i], "{", "[");
  316. p = replace(p, "}", "]");
  317. strlcpy(chan->topic, p, sizeof(chan->topic));
  318. } else if (!cmd && !strcmp(item[i], "addedby")) {
  319. i++;
  320. if (i >= items) {
  321. if (result)
  322. strlcpy(result, "addedby needs argument", RESULT_LEN);
  323. return ERROR;
  324. }
  325. strlcpy(chan->added_by, item[i], sizeof(chan->added_by));
  326. } else if (!cmd && !strcmp(item[i], "addedts")) {
  327. i++;
  328. if (i >= items) {
  329. if (result)
  330. strlcpy(result, "addedts needs argument", RESULT_LEN);
  331. return ERROR;
  332. }
  333. chan->added_ts = atoi(item[i]);
  334. } else if (!strcmp(item[i], "limit")) {
  335. i++;
  336. if (i >= items) {
  337. if (result)
  338. strlcpy(result, "channel limit needs argument", RESULT_LEN);
  339. return ERROR;
  340. }
  341. chan->limitraise = atoi(item[i]);
  342. chan->limit_prot = 0;
  343. /*
  344. } else if (!strcmp(item[i], "revenge-mode")) {
  345. i++;
  346. if (i >= items) {
  347. if (result)
  348. strlcpy(result, "channel revenge-mode needs argument", RESULT_LEN);
  349. return ERROR;
  350. }
  351. chan->revenge_mode = atoi(item[i]);
  352. */
  353. } else if (!strcmp(item[i], "ban-time")) {
  354. i++;
  355. if (i >= items) {
  356. if (result)
  357. strlcpy(result, "channel ban-time needs argument", RESULT_LEN);
  358. return ERROR;
  359. }
  360. chan->ban_time = atoi(item[i]);
  361. } else if (!strcmp(item[i], "exempt-time")) {
  362. i++;
  363. if (i >= items) {
  364. if (result)
  365. strlcpy(result, "channel exempt-time needs argument", RESULT_LEN);
  366. return ERROR;
  367. }
  368. chan->exempt_time = atoi(item[i]);
  369. } else if (!strcmp(item[i], "invite-time")) {
  370. i++;
  371. if (i >= items) {
  372. if (result)
  373. strlcpy(result, "channel invite-time needs argument", RESULT_LEN);
  374. return ERROR;
  375. }
  376. chan->invite_time = atoi(item[i]);
  377. } else if (!strcmp(item[i], "closed-ban")) {
  378. i++;
  379. if (i >= items) {
  380. if (result)
  381. strlcpy(result, "channel closed-ban needs argument", RESULT_LEN);
  382. return ERROR;
  383. }
  384. chan->closed_ban = atoi(item[i]);
  385. } else if (!strcmp(item[i], "closed-invite")) {
  386. i++;
  387. if (i >= items) {
  388. if (result)
  389. strlcpy(result, "channel closed-invite needs argument", RESULT_LEN);
  390. return ERROR;
  391. }
  392. chan->closed_invite = atoi(item[i]);
  393. if (chan->mode_mns_prot & CHANINV && chan->closed_invite)
  394. chan->closed_invite = 0;
  395. } else if (!strcmp(item[i], "closed-private")) {
  396. i++;
  397. if (i >= items) {
  398. if (result)
  399. strlcpy(result, "channel closed-private needs argument", RESULT_LEN);
  400. return ERROR;
  401. }
  402. chan->closed_private = atoi(item[i]);
  403. if (chan->mode_mns_prot & CHANPRIV && chan->closed_private)
  404. chan->closed_private = 0;
  405. } else if (!strcmp(item[i], "voice-non-ident")) {
  406. i++;
  407. if (i >= items) {
  408. if (result)
  409. strlcpy(result, "channel voice-ident needs argument", RESULT_LEN);
  410. return ERROR;
  411. }
  412. chan->voice_non_ident = atoi(item[i]);
  413. } else if (!strcmp(item[i], "bad-cookie")) {
  414. i++;
  415. if (i >= items) {
  416. if (result)
  417. strlcpy(result, "channel bad-cookie needs argument", RESULT_LEN);
  418. return ERROR;
  419. }
  420. chan->bad_cookie = deflag_translate(item[i]);
  421. } else if (!strcmp(item[i], "manop")) {
  422. i++;
  423. if (i >= items) {
  424. if (result)
  425. strlcpy(result, "channel manop needs argument", RESULT_LEN);
  426. return ERROR;
  427. }
  428. chan->manop = deflag_translate(item[i]);
  429. } else if (!strcmp(item[i], "mdop")) {
  430. i++;
  431. if (i >= items) {
  432. if (result)
  433. strlcpy(result, "channel mdop needs argument", RESULT_LEN);
  434. return ERROR;
  435. }
  436. chan->mdop = deflag_translate(item[i]);
  437. } else if (!strcmp(item[i], "mop")) {
  438. i++;
  439. if (i >= items) {
  440. if (result)
  441. strlcpy(result, "channel mop needs argument", RESULT_LEN);
  442. return ERROR;
  443. }
  444. chan->mop = deflag_translate(item[i]);
  445. } else if (!strcmp(item[i], "knock")) {
  446. i++;
  447. if (i >= items) {
  448. if (result)
  449. strlcpy(result, "channel knock needs argument", RESULT_LEN);
  450. return ERROR;
  451. }
  452. if (!str_isdigit(item[i])) {
  453. if (!strcasecmp("Op", item[i]))
  454. chan->knock_flags = CHAN_FLAG_OP;
  455. else if (!strcasecmp("Voice", item[i]))
  456. chan->knock_flags = CHAN_FLAG_VOICE;
  457. else if (!strcasecmp("User", item[i]))
  458. chan->knock_flags = CHAN_FLAG_USER;
  459. else if (!strcasecmp("None", item[i]))
  460. chan->knock_flags = 0;
  461. else {
  462. if (result)
  463. strlcpy(result, "channel knock only accepts Op|Voice|User|None", RESULT_LEN);
  464. return ERROR;
  465. }
  466. } else
  467. chan->knock_flags = atoi(item[i]);
  468. } else if (!strcmp(item[i], "flood-exempt")) {
  469. i++;
  470. if (i >= items) {
  471. if (result)
  472. strlcpy(result, "channel flood-exempt needs argument", RESULT_LEN);
  473. return ERROR;
  474. }
  475. if (!str_isdigit(item[i])) {
  476. if (!strcasecmp("Op", item[i]))
  477. chan->flood_exempt_mode = CHAN_FLAG_OP;
  478. else if (!strcasecmp("Voice", item[i]))
  479. chan->flood_exempt_mode = CHAN_FLAG_VOICE;
  480. else if (!strcasecmp("None", item[i]))
  481. chan->flood_exempt_mode = 0;
  482. else {
  483. if (result)
  484. strlcpy(result, "channel flood-exempt only accepts Op|Voice|None", RESULT_LEN);
  485. return ERROR;
  486. }
  487. } else
  488. chan->flood_exempt_mode = atoi(item[i]);
  489. } else if (!strcmp(item[i], "closed-exempt")) {
  490. i++;
  491. if (i >= items) {
  492. if (result)
  493. strlcpy(result, "channel closed-exempt needs argument", RESULT_LEN);
  494. return ERROR;
  495. }
  496. if (!str_isdigit(item[i])) {
  497. if (!strcasecmp("Op", item[i]))
  498. chan->closed_exempt_mode = CHAN_FLAG_OP;
  499. else if (!strcasecmp("Voice", item[i]))
  500. chan->closed_exempt_mode = CHAN_FLAG_VOICE;
  501. else if (!strcasecmp("None", item[i]))
  502. chan->closed_exempt_mode = 0;
  503. else {
  504. if (result)
  505. strlcpy(result, "channel closed-exempt only accepts Op|Voice|None", RESULT_LEN);
  506. return ERROR;
  507. }
  508. } else
  509. chan->closed_exempt_mode = atoi(item[i]);
  510. } else if (!strcmp(item[i], "flood-lock-time")) {
  511. i++;
  512. if (i >= items) {
  513. if (result)
  514. strlcpy(result, "channel flood-lock-time needs argument", RESULT_LEN);
  515. return ERROR;
  516. }
  517. chan->flood_lock_time = atoi(item[i]);
  518. } else if (!strcmp(item[i], "auto-delay")) {
  519. i++;
  520. if (i >= items) {
  521. if (result)
  522. strlcpy(result, "channel auto-delay needs argument", RESULT_LEN);
  523. return ERROR;
  524. }
  525. chan->auto_delay = atoi(item[i]);
  526. } else if (!strcmp(item[i], "ban-type")) {
  527. i++;
  528. if (i >= items) {
  529. if (result)
  530. strlcpy(result, "channel ban-type needs argument", RESULT_LEN);
  531. return ERROR;
  532. }
  533. chan->ban_type = atoi(item[i]);
  534. } else if (!strcmp(item[i], "protect-backup")) {
  535. i++;
  536. if (i >= items) {
  537. if (result)
  538. strlcpy(result, "channel protect-backup needs argument", RESULT_LEN);
  539. return ERROR;
  540. }
  541. chan->protect_backup = atoi(item[i]);
  542. } else if (!strcmp(item[i], "fish-key")) {
  543. i++;
  544. if (i >= items) {
  545. set_fish_key(chan->dname, "");
  546. return ERROR;
  547. }
  548. set_fish_key(chan->dname, item[i]);
  549. strlcpy(chan->fish_key, item[i], sizeof(chan->fish_key));
  550. }
  551. /* Chanint template
  552. * } else if (!strcmp(item[i], "temp")) {
  553. * i++;
  554. * if (i >= items) {
  555. * if (result)
  556. * strlcpy(result, "channel temp needs argument", RESULT_LEN);
  557. * return ERROR;
  558. * }
  559. * chan->temp = atoi(item[i]);
  560. */
  561. else if (!strcmp(item[i], "+enforcebans"))
  562. chan->status |= CHAN_ENFORCEBANS;
  563. else if (!strcmp(item[i], "-enforcebans"))
  564. chan->status &= ~CHAN_ENFORCEBANS;
  565. else if (!strcmp(item[i], "+dynamicbans"))
  566. chan->status |= CHAN_DYNAMICBANS;
  567. else if (!strcmp(item[i], "-dynamicbans"))
  568. chan->status &= ~CHAN_DYNAMICBANS;
  569. else if (!strcmp(item[i], "-userbans"))
  570. chan->status |= CHAN_NOUSERBANS;
  571. else if (!strcmp(item[i], "+userbans"))
  572. chan->status &= ~CHAN_NOUSERBANS;
  573. else if (!strcmp(item[i], "+bitch"))
  574. chan->status |= CHAN_BITCH;
  575. else if (!strcmp(item[i], "-bitch"))
  576. chan->status &= ~CHAN_BITCH;
  577. else if (!strcmp(item[i], "+nodesynch"))
  578. chan->status |= CHAN_NODESYNCH;
  579. else if (!strcmp(item[i], "-nodesynch"))
  580. chan->status &= ~CHAN_NODESYNCH;
  581. else if (!strcmp(item[i], "+inactive"))
  582. chan->status |= CHAN_INACTIVE;
  583. else if (!strcmp(item[i], "-inactive"))
  584. chan->status&= ~CHAN_INACTIVE;
  585. else if (!strcmp(item[i], "+secret"))
  586. chan->status |= CHAN_SECRET;
  587. else if (!strcmp(item[i], "-secret"))
  588. chan->status &= ~CHAN_SECRET;
  589. else if (!strcmp(item[i], "+cycle"))
  590. chan->status |= CHAN_CYCLE;
  591. else if (!strcmp(item[i], "-cycle"))
  592. chan->status &= ~CHAN_CYCLE;
  593. else if (!strcmp(item[i], "+dynamicexempts"))
  594. chan->status |= CHAN_DYNAMICEXEMPTS;
  595. else if (!strcmp(item[i], "-dynamicexempts"))
  596. chan->status &= ~CHAN_DYNAMICEXEMPTS;
  597. else if (!strcmp(item[i], "-userexempts"))
  598. chan->status |= CHAN_NOUSEREXEMPTS;
  599. else if (!strcmp(item[i], "+userexempts"))
  600. chan->status &= ~CHAN_NOUSEREXEMPTS;
  601. else if (!strcmp(item[i], "+dynamicinvites"))
  602. chan->status |= CHAN_DYNAMICINVITES;
  603. else if (!strcmp(item[i], "-dynamicinvites"))
  604. chan->status &= ~CHAN_DYNAMICINVITES;
  605. else if (!strcmp(item[i], "-userinvites"))
  606. chan->status |= CHAN_NOUSERINVITES;
  607. else if (!strcmp(item[i], "+userinvites"))
  608. chan->status &= ~CHAN_NOUSERINVITES;
  609. else if (!strcmp(item[i], "+closed"))
  610. chan->status |= CHAN_CLOSED;
  611. else if (!strcmp(item[i], "-closed"))
  612. chan->status &= ~CHAN_CLOSED;
  613. else if (HAVE_TAKE && !strcmp(item[i], "+take"))
  614. chan->status |= CHAN_TAKE;
  615. else if (HAVE_TAKE && !strcmp(item[i], "-take"))
  616. chan->status &= ~CHAN_TAKE;
  617. else if (!HAVE_TAKE && !strcmp(item[i], "+take"))
  618. chan->status |= CHAN_BITCH;
  619. else if (!HAVE_TAKE && !strcmp(item[i], "-take"))
  620. chan->status &= ~CHAN_BITCH;
  621. else if (!strcmp(item[i], "+voice"))
  622. chan->status |= CHAN_VOICE;
  623. else if (!strcmp(item[i], "-voice"))
  624. chan->status &= ~CHAN_VOICE;
  625. else if (!strcmp(item[i], "+autoop"))
  626. chan->status |= CHAN_AUTOOP;
  627. else if (!strcmp(item[i], "-autoop"))
  628. chan->status &= ~CHAN_AUTOOP;
  629. else if (!strcmp(item[i], "+botbitch"))
  630. chan->status |= CHAN_BOTBITCH;
  631. else if (!strcmp(item[i], "-botbitch"))
  632. chan->status &= ~CHAN_BOTBITCH;
  633. else if (!strcmp(item[i], "+nomassjoin"))
  634. chan->status |= CHAN_NOMASSJOIN;
  635. else if (!strcmp(item[i], "-nomassjoin"))
  636. chan->status &= ~CHAN_NOMASSJOIN;
  637. else if (!strcmp(item[i], "+meankicks"))
  638. chan->status |= CHAN_MEANKICKS;
  639. else if (!strcmp(item[i], "-meankicks"))
  640. chan->status &= ~CHAN_MEANKICKS;
  641. else if (!strcmp(item[i], "+rbl"))
  642. chan->status |= CHAN_RBL;
  643. else if (!strcmp(item[i], "-rbl"))
  644. chan->status &= ~CHAN_RBL;
  645. else if (!strcmp(item[i], "+voicebitch"))
  646. chan->status |= CHAN_VOICEBITCH;
  647. else if (!strcmp(item[i], "-voicebitch"))
  648. chan->status &= ~CHAN_VOICEBITCH;
  649. else if (!strcmp(item[i], "+protect"))
  650. chan->status |= CHAN_PROTECT;
  651. else if (!strcmp(item[i], "-protect"))
  652. chan->status &= ~CHAN_PROTECT;
  653. /* Chanflag template
  654. * else if (!strcmp(item[i], "+temp"))
  655. * chan->status |= CHAN_TEMP;
  656. * else if (!strcmp(item[i], "-temp"))
  657. * chan->status &= ~CHAN_TEMP;
  658. */
  659. else if (!strcmp(item[i], "+fastop"))
  660. chan->status |= CHAN_FASTOP;
  661. else if (!strcmp(item[i], "-fastop"))
  662. chan->status &= ~CHAN_FASTOP;
  663. else if (!strcmp(item[i], "+private"))
  664. chan->status |= CHAN_PRIVATE;
  665. else if (!strcmp(item[i], "-private"))
  666. chan->status &= ~CHAN_PRIVATE;
  667. else if (!strcmp(item[i], "+backup"))
  668. chan->status |= CHAN_BACKUP;
  669. else if (!strcmp(item[i], "-backup"))
  670. chan->status &= ~CHAN_BACKUP;
  671. /* ignore wasoptest, stopnethack and clearbans in chanfile, remove
  672. this later */
  673. else if (!cmd && !HAVE_TAKE && !strcmp(item[i], "+take")) ;
  674. else if (!cmd && !HAVE_TAKE && !strcmp(item[i], "-take")) ;
  675. else if (!cmd && !strcmp(item[i], "stopnethack-mode")) ;
  676. else if (!cmd && !strcmp(item[i], "revenge-mode")) ;
  677. else if (!cmd && !strcmp(item[i], "+revenge")) ;
  678. else if (!cmd && !strcmp(item[i], "-revenge")) ;
  679. else if (!cmd && !strcmp(item[i], "+revengebot")) ;
  680. else if (!cmd && !strcmp(item[i], "-revengebot")) ;
  681. else if (!cmd && !strcmp(item[i], "+manop")) ;
  682. else if (!cmd && !strcmp(item[i], "-manop")) ;
  683. else if (!cmd && !strcmp(item[i], "+dontkickops")) ;
  684. else if (!cmd && !strcmp(item[i], "-dontkickops")) ;
  685. else if (!cmd && !strcmp(item[i], "+nomdop")) ;
  686. else if (!cmd && !strcmp(item[i], "-nomdop")) ;
  687. else if (!cmd && !strcmp(item[i], "+protectfriends")) ;
  688. else if (!cmd && !strcmp(item[i], "-protectfriends")) ;
  689. else if (!cmd && !strcmp(item[i], "+protectops")) ;
  690. else if (!cmd && !strcmp(item[i], "-protectops")) ;
  691. else if (!cmd && !strcmp(item[i], "+punish")) ;
  692. else if (!cmd && !strcmp(item[i], "-punish")) ;
  693. else if (!cmd && !strcmp(item[i], "+seen")) ;
  694. else if (!cmd && !strcmp(item[i], "-seen")) ;
  695. else if (!cmd && !strcmp(item[i], "+secret")) ;
  696. else if (!cmd && !strcmp(item[i], "-secret")) ;
  697. else if (!cmd && !strcmp(item[i], "-stopnethack")) ;
  698. else if (!cmd && !strcmp(item[i], "+stopnethack")) ;
  699. else if (!cmd && !strcmp(item[i], "-wasoptest")) ;
  700. else if (!cmd && !strcmp(item[i], "+wasoptest")) ; /* Eule 01.2000 */
  701. else if (!cmd && !strcmp(item[i], "+clearbans")) ;
  702. else if (!cmd && !strcmp(item[i], "-clearbans")) ;
  703. else if (!cmd && !strncmp(item[i], "need-", 5)) ;
  704. else if (!strncmp(item[i], "flood-", 6)) {
  705. int *pthr = NULL;
  706. interval_t *ptime = NULL;
  707. char *p = NULL;
  708. if (!strcmp(item[i] + 6, "*")) {
  709. i++;
  710. if (i >= items) {
  711. if (result)
  712. simple_snprintf(result, RESULT_LEN, "%s needs argument", item[i - 1]);
  713. return ERROR;
  714. }
  715. p = strchr(item[i], ':');
  716. int thr = 0;
  717. interval_t time = 0;
  718. if (p) {
  719. *p++ = 0;
  720. thr = atoi(item[i]);
  721. time = atoi(p);
  722. *--p = ':';
  723. } else {
  724. thr = atoi(item[i]);
  725. time = 1;
  726. }
  727. chan->flood_pub_thr = thr;
  728. chan->flood_pub_time = time;
  729. chan->flood_join_thr = thr;
  730. chan->flood_join_time = time;
  731. chan->flood_ctcp_thr = thr;
  732. chan->flood_ctcp_time = time;
  733. chan->flood_kick_thr = thr;
  734. chan->flood_kick_time = time;
  735. chan->flood_deop_thr = thr;
  736. chan->flood_deop_time = time;
  737. chan->flood_nick_thr = thr;
  738. chan->flood_nick_time = time;
  739. chan->flood_mjoin_thr = thr;
  740. chan->flood_mjoin_time = time;
  741. } else if (!strcmp(item[i] + 6, "chan")) {
  742. pthr = &chan->flood_pub_thr;
  743. ptime = &chan->flood_pub_time;
  744. } else if (!strcmp(item[i] + 6, "join")) {
  745. pthr = &chan->flood_join_thr;
  746. ptime = &chan->flood_join_time;
  747. } else if (!strcmp(item[i] + 6, "ctcp")) {
  748. pthr = &chan->flood_ctcp_thr;
  749. ptime = &chan->flood_ctcp_time;
  750. } else if (!strcmp(item[i] + 6, "kick")) {
  751. pthr = &chan->flood_kick_thr;
  752. ptime = &chan->flood_kick_time;
  753. } else if (!strcmp(item[i] + 6, "deop")) {
  754. pthr = &chan->flood_deop_thr;
  755. ptime = &chan->flood_deop_time;
  756. } else if (!strcmp(item[i] + 6, "nick")) {
  757. pthr = &chan->flood_nick_thr;
  758. ptime = &chan->flood_nick_time;
  759. } else if (!strcmp(item[i] + 6, "mjoin")) {
  760. pthr = &chan->flood_mjoin_thr;
  761. ptime = &chan->flood_mjoin_time;
  762. } else { /* Ignore for optimal forward compatibility */
  763. i++;
  764. continue;
  765. }
  766. if (pthr && ptime) { //Ignore flood-*
  767. i++;
  768. if (i >= items) {
  769. if (result)
  770. simple_snprintf(result, RESULT_LEN, "%s needs argument", item[i - 1]);
  771. return ERROR;
  772. }
  773. p = strchr(item[i], ':');
  774. if (p) {
  775. *p++ = 0;
  776. *pthr = atoi(item[i]);
  777. *ptime = atoi(p);
  778. *--p = ':';
  779. } else {
  780. *pthr = atoi(item[i]);
  781. *ptime = 1;
  782. }
  783. }
  784. } else {
  785. if (result && item[i][0]) { /* ignore "" */
  786. if (!result[0])
  787. strlcpy(result, "illegal channel option: ", RESULT_LEN);
  788. if (result_extra[0])
  789. strlcat(result_extra, " ", sizeof(result_extra));
  790. strlcat(result_extra, item[i], sizeof(result_extra));
  791. }
  792. error = 1;
  793. }
  794. }
  795. if ((chan->status ^ old_status) & CHAN_TAKE)
  796. chan->status |= CHAN_BITCH; // to avoid bots still mass opping from +take from not using cookies
  797. if (!conf.bot->hub && (chan != chanset_default)) {
  798. // Check if groups changed or +/-backup set
  799. if (!restarting && !loading && (changed_groups || ((old_status ^ chan->status) & (CHAN_INACTIVE | CHAN_BACKUP)))) {
  800. check_shouldjoin(chan);
  801. }
  802. if (me_op(chan)) {
  803. if ((old_status ^ chan->status) & (CHAN_ENFORCEBANS|CHAN_NOUSERBANS|CHAN_DYNAMICBANS|CHAN_NOUSEREXEMPTS|CHAN_NOUSERINVITES|CHAN_DYNAMICEXEMPTS|CHAN_DYNAMICINVITES)) {
  804. recheck_channel(chan, 1);
  805. /* Does a change in channel flag affect client status in the channel? */
  806. } else if ((chan->status ^ old_status) & (CHAN_BITCH | CHAN_BOTBITCH | CHAN_PRIVATE | CHAN_CLOSED | CHAN_VOICE | CHAN_VOICEBITCH )) {
  807. recheck_channel(chan, 0);
  808. } else if ((old_status & CHAN_TAKE) && !(chan->status & CHAN_TAKE)) {
  809. //Set -take, fetch bans/exempts/invites
  810. recheck_channel(chan, 2);
  811. } else if (old_mode_pls_prot != chan->mode_pls_prot || old_mode_mns_prot != chan->mode_mns_prot) {
  812. recheck_channel_modes(chan);
  813. }
  814. }
  815. }
  816. if (result && result[0] && result_extra[0])
  817. strlcat(result, result_extra, RESULT_LEN);
  818. if (error)
  819. return ERROR;
  820. return OK;
  821. }
  822. static void init_masklist(masklist *m)
  823. {
  824. m->mask = (char *) my_calloc(1, 1);
  825. m->who = NULL;
  826. m->next = NULL;
  827. }
  828. /* Initialize out the channel record.
  829. */
  830. static void init_channel(struct chanset_t *chan, bool reset)
  831. {
  832. chan->channel.maxmembers = 0;
  833. chan->channel.mode = 0;
  834. chan->channel.members = 0;
  835. chan->channel.splitmembers = 0;
  836. if (!reset)
  837. my_setkey(chan, NULL);
  838. chan->channel.ban = (masklist *) my_calloc(1, sizeof(masklist));
  839. init_masklist(chan->channel.ban);
  840. chan->channel.exempt = (masklist *) my_calloc(1, sizeof(masklist));
  841. init_masklist(chan->channel.exempt);
  842. chan->channel.invite = (masklist *) my_calloc(1, sizeof(masklist));
  843. init_masklist(chan->channel.invite);
  844. chan->channel.member = (memberlist *) my_calloc(1, sizeof(memberlist));
  845. chan->channel.member->nick[0] = 0;
  846. chan->channel.member->next = NULL;
  847. chan->channel.topic = NULL;
  848. }
  849. static void clear_masklist(masklist *m)
  850. {
  851. masklist *temp = NULL;
  852. for (; m; m = temp) {
  853. temp = m->next;
  854. if (m->mask)
  855. free(m->mask);
  856. if (m->who)
  857. free(m->who);
  858. free(m);
  859. }
  860. }
  861. /* Clear out channel data from memory.
  862. */
  863. void clear_channel(struct chanset_t *chan, bool reset)
  864. {
  865. memberlist *m = NULL, *m1 = NULL;
  866. if (chan->channel.topic)
  867. free(chan->channel.topic);
  868. for (m = chan->channel.member; m; m = m1) {
  869. m1 = m->next;
  870. free(m);
  871. }
  872. clear_masklist(chan->channel.ban);
  873. chan->channel.ban = NULL;
  874. clear_masklist(chan->channel.exempt);
  875. chan->channel.exempt = NULL;
  876. clear_masklist(chan->channel.invite);
  877. chan->channel.invite = NULL;
  878. chan->channel.last_eI = 0;
  879. chan->ircnet_status = 0;
  880. // chan->ircnet_status &= ~CHAN_HAVEBANS;
  881. if (reset)
  882. init_channel(chan, 1);
  883. for (size_t i = 0; i < MODES_PER_LINE_MAX; ++i) {
  884. if (chan->cmode[i].op) {
  885. free(chan->cmode[i].op);
  886. chan->cmode[i].op = NULL;
  887. }
  888. if (chan->ccmode[i].op) {
  889. free(chan->ccmode[i].op);
  890. chan->ccmode[i].op = NULL;
  891. }
  892. }
  893. }
  894. /* Create new channel and parse commands.
  895. */
  896. int channel_add(char *result, const char *newname, char *options, bool isdefault)
  897. {
  898. /* When loading userfile */
  899. if (newname && newname[0] && loading && !strcmp(newname, "default"))
  900. isdefault = 1;
  901. if (!newname || !newname[0] || (!isdefault && !strchr(CHANMETA, newname[0]))) {
  902. if (result)
  903. strlcpy(result, "invalid channel prefix", RESULT_LEN);
  904. return ERROR;
  905. }
  906. if (strchr(newname, ',') != NULL) {
  907. if (result)
  908. strlcpy(result, "invalid channel name", RESULT_LEN);
  909. return ERROR;
  910. }
  911. const char **item = NULL;
  912. int items = 0;
  913. char buf[3001] = "";
  914. simple_snprintf(buf, sizeof(buf), "chanmode { %s }", glob_chanmode);
  915. if (!isdefault) { // These are passed in in 'options'
  916. strlcat(buf, " ", sizeof(buf));
  917. strlcat(buf, def_chanset, sizeof(buf));
  918. }
  919. // Add in 'default' channel options
  920. if (!isdefault && chanset_default) {
  921. bd::String default_chan_options = channel_to_string(chanset_default);
  922. strlcat(buf, " ", sizeof(buf));
  923. strlcat(buf, default_chan_options.c_str(), sizeof(buf));
  924. }
  925. if (options && options[0]) {
  926. strlcat(buf, " ", sizeof(buf));
  927. strlcat(buf, options, sizeof(buf));
  928. }
  929. if (SplitList(result, buf, &items, &item) != OK)
  930. return ERROR;
  931. bool join = 0;
  932. struct chanset_t *chan = NULL;
  933. int ret = OK;
  934. if ((chan = findchan_by_dname(newname))) {
  935. /* Already existing channel, maybe a reload of the channel file */
  936. chan->status &= ~CHAN_FLAGGED; /* don't delete me! :) */
  937. } else {
  938. chan = (struct chanset_t *) my_calloc(1, sizeof(struct chanset_t));
  939. /* These are defaults, bzero already set them 0, but we set them for future reference */
  940. chan->limit_prot = 0;
  941. chan->limit = 0;
  942. chan->closed_ban = 0;
  943. chan->closed_private = 1;
  944. chan->closed_invite = 1;
  945. chan->voice_non_ident = 1;
  946. chan->auto_delay = 5;
  947. chan->ban_type = 3;
  948. /* Chanint template
  949. * chan->temp = 0;
  950. */
  951. chan->groups = new bd::Array<bd::String>;
  952. *(chan->groups) << "main";
  953. chan->protect_backup = 1;
  954. chan->fish_key[0] = 0;
  955. chan->knock_flags = 0;
  956. chan->flood_lock_time = 120;
  957. chan->flood_exempt_mode = 0;
  958. chan->flood_pub_thr = gfld_chan_thr;
  959. chan->flood_pub_time = gfld_chan_time;
  960. chan->flood_ctcp_thr = gfld_ctcp_thr;
  961. chan->flood_ctcp_time = gfld_ctcp_time;
  962. chan->flood_join_thr = gfld_join_thr;
  963. chan->flood_join_time = gfld_join_time;
  964. chan->flood_deop_thr = gfld_deop_thr;
  965. chan->flood_deop_time = gfld_deop_time;
  966. chan->flood_kick_thr = gfld_kick_thr;
  967. chan->flood_kick_time = gfld_kick_time;
  968. chan->flood_nick_thr = gfld_nick_thr;
  969. chan->flood_nick_time = gfld_nick_time;
  970. chan->flood_mjoin_thr = 6;
  971. chan->flood_mjoin_time = 1;
  972. // chan->revenge_mode = global_revenge_mode;
  973. chan->limitraise = 20;
  974. chan->ban_time = global_ban_time;
  975. chan->exempt_time = global_exempt_time;
  976. chan->invite_time = global_invite_time;
  977. chan->channel.jointime = 0;
  978. chan->channel.parttime = 0;
  979. chan->channel.fighting = 0;
  980. chan->channel.drone_set_mode = 0;
  981. chan->channel.drone_jointime = 0;
  982. chan->channel.drone_joins = 0;
  983. chan->channel.last_eI = 0;
  984. /* We _only_ put the dname (display name) in here so as not to confuse
  985. * any code later on. chan->name gets updated with the channel name as
  986. * the server knows it, when we join the channel. <cybah>
  987. */
  988. strlcpy(chan->dname, newname, sizeof(chan->dname));
  989. /* Initialize chan->channel info */
  990. if (isdefault) {
  991. if (chanset_default)
  992. remove_channel(chanset_default);
  993. chanset_default = chan;
  994. } else {
  995. init_channel(chan, 0);
  996. list_append((struct list_type **) &chanset, (struct list_type *) chan);
  997. /* Channel name is stored in xtra field for sharebot stuff */
  998. if (!conf.bot->hub && !isdefault)
  999. join = 1;
  1000. }
  1001. }
  1002. /* If loading is set, we're loading the userfile. Ignore errors while
  1003. * reading userfile and just return OK. This is for compatability
  1004. * if a user goes back to an eggdrop that no-longer supports certain
  1005. * (channel) options.
  1006. */
  1007. if ((channel_modify(result, chan, items, (char **) item, 0) != OK)) {
  1008. putlog(LOG_ERROR, "*", "Error parsing channel options for %s: %s", chan->dname, result);
  1009. if (!loading)
  1010. ret = ERROR;
  1011. }
  1012. free(item);
  1013. if (join && shouldjoin(chan))
  1014. join_chan(chan);
  1015. return ret;
  1016. }