PageRenderTime 73ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/src/mod/channels.mod/tclchan.c

https://github.com/eggheads/eggdrop-1.8
C | 2379 lines | 2110 code | 197 blank | 72 comment | 771 complexity | c437212badc04d68b47227fb7974a2e3 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * tclchan.c -- part of channels.mod
  3. *
  4. * $Id: tclchan.c,v 1.4 2014/09/06 23:49:32 thommey Exp $
  5. */
  6. /*
  7. * Copyright (C) 1997 Robey Pointer
  8. * Copyright (C) 1999 - 2010 Eggheads Development Team
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24. static int tcl_killban STDVAR
  25. {
  26. struct chanset_t *chan;
  27. BADARGS(2, 2, " ban");
  28. if (u_delban(NULL, argv[1], 1) > 0) {
  29. for (chan = chanset; chan; chan = chan->next)
  30. add_mode(chan, '-', 'b', argv[1]);
  31. Tcl_AppendResult(irp, "1", NULL);
  32. } else
  33. Tcl_AppendResult(irp, "0", NULL);
  34. return TCL_OK;
  35. }
  36. static int tcl_killchanban STDVAR
  37. {
  38. struct chanset_t *chan;
  39. BADARGS(3, 3, " channel ban");
  40. chan = findchan_by_dname(argv[1]);
  41. if (!chan) {
  42. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  43. return TCL_ERROR;
  44. }
  45. if (u_delban(chan, argv[2], 1) > 0) {
  46. add_mode(chan, '-', 'b', argv[2]);
  47. Tcl_AppendResult(irp, "1", NULL);
  48. } else
  49. Tcl_AppendResult(irp, "0", NULL);
  50. return TCL_OK;
  51. }
  52. static int tcl_killexempt STDVAR
  53. {
  54. struct chanset_t *chan;
  55. BADARGS(2, 2, " exempt");
  56. if (u_delexempt(NULL, argv[1], 1) > 0) {
  57. for (chan = chanset; chan; chan = chan->next)
  58. add_mode(chan, '-', 'e', argv[1]);
  59. Tcl_AppendResult(irp, "1", NULL);
  60. } else
  61. Tcl_AppendResult(irp, "0", NULL);
  62. return TCL_OK;
  63. }
  64. static int tcl_killchanexempt STDVAR
  65. {
  66. struct chanset_t *chan;
  67. BADARGS(3, 3, " channel exempt");
  68. chan = findchan_by_dname(argv[1]);
  69. if (!chan) {
  70. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  71. return TCL_ERROR;
  72. }
  73. if (u_delexempt(chan, argv[2], 1) > 0) {
  74. add_mode(chan, '-', 'e', argv[2]);
  75. Tcl_AppendResult(irp, "1", NULL);
  76. } else
  77. Tcl_AppendResult(irp, "0", NULL);
  78. return TCL_OK;
  79. }
  80. static int tcl_killinvite STDVAR
  81. {
  82. struct chanset_t *chan;
  83. BADARGS(2, 2, " invite");
  84. if (u_delinvite(NULL, argv[1], 1) > 0) {
  85. for (chan = chanset; chan; chan = chan->next)
  86. add_mode(chan, '-', 'I', argv[1]);
  87. Tcl_AppendResult(irp, "1", NULL);
  88. } else
  89. Tcl_AppendResult(irp, "0", NULL);
  90. return TCL_OK;
  91. }
  92. static int tcl_killchaninvite STDVAR
  93. {
  94. struct chanset_t *chan;
  95. BADARGS(3, 3, " channel invite");
  96. chan = findchan_by_dname(argv[1]);
  97. if (!chan) {
  98. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  99. return TCL_ERROR;
  100. }
  101. if (u_delinvite(chan, argv[2], 1) > 0) {
  102. add_mode(chan, '-', 'I', argv[2]);
  103. Tcl_AppendResult(irp, "1", NULL);
  104. } else
  105. Tcl_AppendResult(irp, "0", NULL);
  106. return TCL_OK;
  107. }
  108. static int tcl_stick STDVAR
  109. {
  110. struct chanset_t *chan;
  111. int ok = 0;
  112. BADARGS(2, 3, " ban ?channel?");
  113. if (argc == 3) {
  114. chan = findchan_by_dname(argv[2]);
  115. if (!chan) {
  116. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  117. return TCL_ERROR;
  118. }
  119. if (u_setsticky_ban(chan, argv[1], !strncmp(argv[0], "un", 2) ? 0 : 1))
  120. ok = 1;
  121. }
  122. if (!ok && u_setsticky_ban(NULL, argv[1], !strncmp(argv[0], "un", 2) ?
  123. 0 : 1))
  124. ok = 1;
  125. if (ok)
  126. Tcl_AppendResult(irp, "1", NULL);
  127. else
  128. Tcl_AppendResult(irp, "0", NULL);
  129. return TCL_OK;
  130. }
  131. static int tcl_stickinvite STDVAR
  132. {
  133. struct chanset_t *chan;
  134. int ok = 0;
  135. BADARGS(2, 3, " invite ?channel?");
  136. if (argc == 3) {
  137. chan = findchan_by_dname(argv[2]);
  138. if (!chan) {
  139. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  140. return TCL_ERROR;
  141. }
  142. if (u_setsticky_invite(chan, argv[1], !strncmp(argv[0], "un", 2) ? 0 : 1))
  143. ok = 1;
  144. }
  145. if (!ok && u_setsticky_invite(NULL, argv[1], !strncmp(argv[0], "un", 2) ?
  146. 0 : 1))
  147. ok = 1;
  148. if (ok)
  149. Tcl_AppendResult(irp, "1", NULL);
  150. else
  151. Tcl_AppendResult(irp, "0", NULL);
  152. return TCL_OK;
  153. }
  154. static int tcl_stickexempt STDVAR
  155. {
  156. struct chanset_t *chan;
  157. int ok = 0;
  158. BADARGS(2, 3, " exempt ?channel?");
  159. if (argc == 3) {
  160. chan = findchan_by_dname(argv[2]);
  161. if (!chan) {
  162. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  163. return TCL_ERROR;
  164. }
  165. if (u_setsticky_exempt(chan, argv[1], !strncmp(argv[0], "un", 2) ? 0 : 1))
  166. ok = 1;
  167. }
  168. if (!ok && u_setsticky_exempt(NULL, argv[1], !strncmp(argv[0], "un", 2) ?
  169. 0 : 1))
  170. ok = 1;
  171. if (ok)
  172. Tcl_AppendResult(irp, "1", NULL);
  173. else
  174. Tcl_AppendResult(irp, "0", NULL);
  175. return TCL_OK;
  176. }
  177. static int tcl_isban STDVAR
  178. {
  179. struct chanset_t *chan;
  180. int ok = 0;
  181. BADARGS(2, 3, " ban ?channel?");
  182. if (argc == 3) {
  183. chan = findchan_by_dname(argv[2]);
  184. if (!chan) {
  185. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  186. return TCL_ERROR;
  187. }
  188. if (u_equals_mask(chan->bans, argv[1]))
  189. ok = 1;
  190. }
  191. if (u_equals_mask(global_bans, argv[1]))
  192. ok = 1;
  193. if (ok)
  194. Tcl_AppendResult(irp, "1", NULL);
  195. else
  196. Tcl_AppendResult(irp, "0", NULL);
  197. return TCL_OK;
  198. }
  199. static int tcl_isexempt STDVAR
  200. {
  201. struct chanset_t *chan;
  202. int ok = 0;
  203. BADARGS(2, 3, " exempt ?channel?");
  204. if (argc == 3) {
  205. chan = findchan_by_dname(argv[2]);
  206. if (!chan) {
  207. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  208. return TCL_ERROR;
  209. }
  210. if (u_equals_mask(chan->exempts, argv[1]))
  211. ok = 1;
  212. }
  213. if (u_equals_mask(global_exempts, argv[1]))
  214. ok = 1;
  215. if (ok)
  216. Tcl_AppendResult(irp, "1", NULL);
  217. else
  218. Tcl_AppendResult(irp, "0", NULL);
  219. return TCL_OK;
  220. }
  221. static int tcl_isinvite STDVAR
  222. {
  223. struct chanset_t *chan;
  224. int ok = 0;
  225. BADARGS(2, 3, " invite ?channel?");
  226. if (argc == 3) {
  227. chan = findchan_by_dname(argv[2]);
  228. if (!chan) {
  229. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  230. return TCL_ERROR;
  231. }
  232. if (u_equals_mask(chan->invites, argv[1]))
  233. ok = 1;
  234. }
  235. if (u_equals_mask(global_invites, argv[1]))
  236. ok = 1;
  237. if (ok)
  238. Tcl_AppendResult(irp, "1", NULL);
  239. else
  240. Tcl_AppendResult(irp, "0", NULL);
  241. return TCL_OK;
  242. }
  243. static int tcl_isbansticky STDVAR
  244. {
  245. struct chanset_t *chan;
  246. int ok = 0;
  247. BADARGS(2, 3, " ban ?channel?");
  248. if (argc == 3) {
  249. chan = findchan_by_dname(argv[2]);
  250. if (!chan) {
  251. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  252. return TCL_ERROR;
  253. }
  254. if (u_sticky_mask(chan->bans, argv[1]))
  255. ok = 1;
  256. }
  257. if (u_sticky_mask(global_bans, argv[1]))
  258. ok = 1;
  259. if (ok)
  260. Tcl_AppendResult(irp, "1", NULL);
  261. else
  262. Tcl_AppendResult(irp, "0", NULL);
  263. return TCL_OK;
  264. }
  265. static int tcl_isexemptsticky STDVAR
  266. {
  267. struct chanset_t *chan;
  268. int ok = 0;
  269. BADARGS(2, 3, " exempt ?channel?");
  270. if (argc == 3) {
  271. chan = findchan_by_dname(argv[2]);
  272. if (!chan) {
  273. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  274. return TCL_ERROR;
  275. }
  276. if (u_sticky_mask(chan->exempts, argv[1]))
  277. ok = 1;
  278. }
  279. if (u_sticky_mask(global_exempts, argv[1]))
  280. ok = 1;
  281. if (ok)
  282. Tcl_AppendResult(irp, "1", NULL);
  283. else
  284. Tcl_AppendResult(irp, "0", NULL);
  285. return TCL_OK;
  286. }
  287. static int tcl_isinvitesticky STDVAR
  288. {
  289. struct chanset_t *chan;
  290. int ok = 0;
  291. BADARGS(2, 3, " invite ?channel?");
  292. if (argc == 3) {
  293. chan = findchan_by_dname(argv[2]);
  294. if (!chan) {
  295. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  296. return TCL_ERROR;
  297. }
  298. if (u_sticky_mask(chan->invites, argv[1]))
  299. ok = 1;
  300. }
  301. if (u_sticky_mask(global_invites, argv[1]))
  302. ok = 1;
  303. if (ok)
  304. Tcl_AppendResult(irp, "1", NULL);
  305. else
  306. Tcl_AppendResult(irp, "0", NULL);
  307. return TCL_OK;
  308. }
  309. static int tcl_ispermban STDVAR
  310. {
  311. struct chanset_t *chan;
  312. int ok = 0;
  313. BADARGS(2, 3, " ban ?channel?");
  314. if (argc == 3) {
  315. chan = findchan_by_dname(argv[2]);
  316. if (chan == NULL) {
  317. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  318. return TCL_ERROR;
  319. }
  320. if (u_equals_mask(chan->bans, argv[1]) == 2)
  321. ok = 1;
  322. }
  323. if (u_equals_mask(global_bans, argv[1]) == 2)
  324. ok = 1;
  325. if (ok)
  326. Tcl_AppendResult(irp, "1", NULL);
  327. else
  328. Tcl_AppendResult(irp, "0", NULL);
  329. return TCL_OK;
  330. }
  331. static int tcl_ispermexempt STDVAR
  332. {
  333. struct chanset_t *chan;
  334. int ok = 0;
  335. BADARGS(2, 3, " exempt ?channel?");
  336. if (argc == 3) {
  337. chan = findchan_by_dname(argv[2]);
  338. if (chan == NULL) {
  339. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  340. return TCL_ERROR;
  341. }
  342. if (u_equals_mask(chan->exempts, argv[1]) == 2)
  343. ok = 1;
  344. }
  345. if (u_equals_mask(global_exempts, argv[1]) == 2)
  346. ok = 1;
  347. if (ok)
  348. Tcl_AppendResult(irp, "1", NULL);
  349. else
  350. Tcl_AppendResult(irp, "0", NULL);
  351. return TCL_OK;
  352. }
  353. static int tcl_isperminvite STDVAR
  354. {
  355. struct chanset_t *chan;
  356. int ok = 0;
  357. BADARGS(2, 3, " invite ?channel?");
  358. if (argc == 3) {
  359. chan = findchan_by_dname(argv[2]);
  360. if (chan == NULL) {
  361. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  362. return TCL_ERROR;
  363. }
  364. if (u_equals_mask(chan->invites, argv[1]) == 2)
  365. ok = 1;
  366. }
  367. if (u_equals_mask(global_invites, argv[1]) == 2)
  368. ok = 1;
  369. if (ok)
  370. Tcl_AppendResult(irp, "1", NULL);
  371. else
  372. Tcl_AppendResult(irp, "0", NULL);
  373. return TCL_OK;
  374. }
  375. static int tcl_matchban STDVAR
  376. {
  377. struct chanset_t *chan;
  378. int ok = 0;
  379. BADARGS(2, 3, " user!nick@host ?channel?");
  380. if (argc == 3) {
  381. chan = findchan_by_dname(argv[2]);
  382. if (chan == NULL) {
  383. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  384. return TCL_ERROR;
  385. }
  386. if (u_match_mask(chan->bans, argv[1]))
  387. ok = 1;
  388. }
  389. if (u_match_mask(global_bans, argv[1]))
  390. ok = 1;
  391. if (ok)
  392. Tcl_AppendResult(irp, "1", NULL);
  393. else
  394. Tcl_AppendResult(irp, "0", NULL);
  395. return TCL_OK;
  396. }
  397. static int tcl_matchexempt STDVAR
  398. {
  399. struct chanset_t *chan;
  400. int ok = 0;
  401. BADARGS(2, 3, " user!nick@host ?channel?");
  402. if (argc == 3) {
  403. chan = findchan_by_dname(argv[2]);
  404. if (chan == NULL) {
  405. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  406. return TCL_ERROR;
  407. }
  408. if (u_match_mask(chan->exempts, argv[1]))
  409. ok = 1;
  410. }
  411. if (u_match_mask(global_exempts, argv[1]))
  412. ok = 1;
  413. if (ok)
  414. Tcl_AppendResult(irp, "1", NULL);
  415. else
  416. Tcl_AppendResult(irp, "0", NULL);
  417. return TCL_OK;
  418. }
  419. static int tcl_matchinvite STDVAR
  420. {
  421. struct chanset_t *chan;
  422. int ok = 0;
  423. BADARGS(2, 3, " user!nick@host ?channel?");
  424. if (argc == 3) {
  425. chan = findchan_by_dname(argv[2]);
  426. if (chan == NULL) {
  427. Tcl_AppendResult(irp, "invalid channel: ", argv[2], NULL);
  428. return TCL_ERROR;
  429. }
  430. if (u_match_mask(chan->invites, argv[1]))
  431. ok = 1;
  432. }
  433. if (u_match_mask(global_invites, argv[1]))
  434. ok = 1;
  435. if (ok)
  436. Tcl_AppendResult(irp, "1", NULL);
  437. else
  438. Tcl_AppendResult(irp, "0", NULL);
  439. return TCL_OK;
  440. }
  441. static int tcl_newchanban STDVAR
  442. {
  443. time_t expire_time;
  444. struct chanset_t *chan;
  445. char ban[161], cmt[MASKREASON_LEN], from[HANDLEN + 1];
  446. int sticky = 0;
  447. module_entry *me;
  448. BADARGS(5, 7, " channel ban creator comment ?lifetime? ?options?");
  449. chan = findchan_by_dname(argv[1]);
  450. if (chan == NULL) {
  451. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  452. return TCL_ERROR;
  453. }
  454. if (argc == 7) {
  455. if (!egg_strcasecmp(argv[6], "none"));
  456. else if (!egg_strcasecmp(argv[6], "sticky"))
  457. sticky = 1;
  458. else {
  459. Tcl_AppendResult(irp, "invalid option ", argv[6], " (must be one of: ",
  460. "sticky, none)", NULL);
  461. return TCL_ERROR;
  462. }
  463. }
  464. strncpyz(ban, argv[2], sizeof ban);
  465. strncpyz(from, argv[3], sizeof from);
  466. strncpyz(cmt, argv[4], sizeof cmt);
  467. if (argc == 5) {
  468. if (chan->ban_time == 0)
  469. expire_time = 0L;
  470. else
  471. expire_time = now + (60 * chan->ban_time);
  472. } else {
  473. if (atoi(argv[5]) == 0)
  474. expire_time = 0L;
  475. else
  476. expire_time = now + (atoi(argv[5]) * 60);
  477. }
  478. if (u_addban(chan, ban, from, cmt, expire_time, sticky))
  479. if ((me = module_find("irc", 0, 0)))
  480. (me->funcs[IRC_CHECK_THIS_BAN]) (chan, ban, sticky);
  481. return TCL_OK;
  482. }
  483. static int tcl_newban STDVAR
  484. {
  485. time_t expire_time;
  486. struct chanset_t *chan;
  487. char ban[UHOSTLEN], cmt[MASKREASON_LEN], from[HANDLEN + 1];
  488. int sticky = 0;
  489. module_entry *me;
  490. BADARGS(4, 6, " ban creator comment ?lifetime? ?options?");
  491. if (argc == 6) {
  492. if (!egg_strcasecmp(argv[5], "none"));
  493. else if (!egg_strcasecmp(argv[5], "sticky"))
  494. sticky = 1;
  495. else {
  496. Tcl_AppendResult(irp, "invalid option ", argv[5], " (must be one of: ",
  497. "sticky, none)", NULL);
  498. return TCL_ERROR;
  499. }
  500. }
  501. strncpyz(ban, argv[1], sizeof ban);
  502. strncpyz(from, argv[2], sizeof from);
  503. strncpyz(cmt, argv[3], sizeof cmt);
  504. if (argc == 4) {
  505. if (global_ban_time == 0)
  506. expire_time = 0L;
  507. else
  508. expire_time = now + (60 * global_ban_time);
  509. } else {
  510. if (atoi(argv[4]) == 0)
  511. expire_time = 0L;
  512. else
  513. expire_time = now + (atoi(argv[4]) * 60);
  514. }
  515. if (u_addban(NULL, ban, from, cmt, expire_time, sticky))
  516. if ((me = module_find("irc", 0, 0)))
  517. for (chan = chanset; chan != NULL; chan = chan->next)
  518. (me->funcs[IRC_CHECK_THIS_BAN]) (chan, ban, sticky);
  519. return TCL_OK;
  520. }
  521. static int tcl_newchanexempt STDVAR
  522. {
  523. time_t expire_time;
  524. struct chanset_t *chan;
  525. char exempt[161], cmt[MASKREASON_LEN], from[HANDLEN + 1];
  526. int sticky = 0;
  527. BADARGS(5, 7, " channel exempt creator comment ?lifetime? ?options?");
  528. chan = findchan_by_dname(argv[1]);
  529. if (chan == NULL) {
  530. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  531. return TCL_ERROR;
  532. }
  533. if (argc == 7) {
  534. if (!egg_strcasecmp(argv[6], "none"));
  535. else if (!egg_strcasecmp(argv[6], "sticky"))
  536. sticky = 1;
  537. else {
  538. Tcl_AppendResult(irp, "invalid option ", argv[6], " (must be one of: ",
  539. "sticky, none)", NULL);
  540. return TCL_ERROR;
  541. }
  542. }
  543. strncpyz(exempt, argv[2], sizeof exempt);
  544. strncpyz(from, argv[3], sizeof from);
  545. strncpyz(cmt, argv[4], sizeof cmt);
  546. if (argc == 5) {
  547. if (chan->exempt_time == 0)
  548. expire_time = 0L;
  549. else
  550. expire_time = now + (60 * chan->exempt_time);
  551. } else {
  552. if (atoi(argv[5]) == 0)
  553. expire_time = 0L;
  554. else
  555. expire_time = now + (atoi(argv[5]) * 60);
  556. }
  557. if (u_addexempt(chan, exempt, from, cmt, expire_time, sticky))
  558. add_mode(chan, '+', 'e', exempt);
  559. return TCL_OK;
  560. }
  561. static int tcl_newexempt STDVAR
  562. {
  563. time_t expire_time;
  564. struct chanset_t *chan;
  565. char exempt[UHOSTLEN], cmt[MASKREASON_LEN], from[HANDLEN + 1];
  566. int sticky = 0;
  567. BADARGS(4, 6, " exempt creator comment ?lifetime? ?options?");
  568. if (argc == 6) {
  569. if (!egg_strcasecmp(argv[5], "none"));
  570. else if (!egg_strcasecmp(argv[5], "sticky"))
  571. sticky = 1;
  572. else {
  573. Tcl_AppendResult(irp, "invalid option ", argv[5], " (must be one of: ",
  574. "sticky, none)", NULL);
  575. return TCL_ERROR;
  576. }
  577. }
  578. strncpyz(exempt, argv[1], sizeof exempt);
  579. strncpyz(from, argv[2], sizeof from);
  580. strncpyz(cmt, argv[3], sizeof cmt);
  581. if (argc == 4) {
  582. if (global_exempt_time == 0)
  583. expire_time = 0L;
  584. else
  585. expire_time = now + (60 * global_exempt_time);
  586. } else {
  587. if (atoi(argv[4]) == 0)
  588. expire_time = 0L;
  589. else
  590. expire_time = now + (atoi(argv[4]) * 60);
  591. }
  592. u_addexempt(NULL, exempt, from, cmt, expire_time, sticky);
  593. for (chan = chanset; chan; chan = chan->next)
  594. add_mode(chan, '+', 'e', exempt);
  595. return TCL_OK;
  596. }
  597. static int tcl_newchaninvite STDVAR
  598. {
  599. time_t expire_time;
  600. struct chanset_t *chan;
  601. char invite[161], cmt[MASKREASON_LEN], from[HANDLEN + 1];
  602. int sticky = 0;
  603. BADARGS(5, 7, " channel invite creator comment ?lifetime? ?options?");
  604. chan = findchan_by_dname(argv[1]);
  605. if (chan == NULL) {
  606. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  607. return TCL_ERROR;
  608. }
  609. if (argc == 7) {
  610. if (!egg_strcasecmp(argv[6], "none"));
  611. else if (!egg_strcasecmp(argv[6], "sticky"))
  612. sticky = 1;
  613. else {
  614. Tcl_AppendResult(irp, "invalid option ", argv[6], " (must be one of: ",
  615. "sticky, none)", NULL);
  616. return TCL_ERROR;
  617. }
  618. }
  619. strncpyz(invite, argv[2], sizeof invite);
  620. strncpyz(from, argv[3], sizeof from);
  621. strncpyz(cmt, argv[4], sizeof cmt);
  622. if (argc == 5) {
  623. if (chan->invite_time == 0)
  624. expire_time = 0L;
  625. else
  626. expire_time = now + (60 * chan->invite_time);
  627. } else {
  628. if (atoi(argv[5]) == 0)
  629. expire_time = 0L;
  630. else
  631. expire_time = now + (atoi(argv[5]) * 60);
  632. }
  633. if (u_addinvite(chan, invite, from, cmt, expire_time, sticky))
  634. add_mode(chan, '+', 'I', invite);
  635. return TCL_OK;
  636. }
  637. static int tcl_newinvite STDVAR
  638. {
  639. time_t expire_time;
  640. struct chanset_t *chan;
  641. char invite[UHOSTLEN], cmt[MASKREASON_LEN], from[HANDLEN + 1];
  642. int sticky = 0;
  643. BADARGS(4, 6, " invite creator comment ?lifetime? ?options?");
  644. if (argc == 6) {
  645. if (!egg_strcasecmp(argv[5], "none"));
  646. else if (!egg_strcasecmp(argv[5], "sticky"))
  647. sticky = 1;
  648. else {
  649. Tcl_AppendResult(irp, "invalid option ", argv[5], " (must be one of: ",
  650. "sticky, none)", NULL);
  651. return TCL_ERROR;
  652. }
  653. }
  654. strncpyz(invite, argv[1], sizeof invite);
  655. strncpyz(from, argv[2], sizeof from);
  656. strncpyz(cmt, argv[3], sizeof cmt);
  657. if (argc == 4) {
  658. if (global_invite_time == 0)
  659. expire_time = 0L;
  660. else
  661. expire_time = now + (60 * global_invite_time);
  662. } else {
  663. if (atoi(argv[4]) == 0)
  664. expire_time = 0L;
  665. else
  666. expire_time = now + (atoi(argv[4]) * 60);
  667. }
  668. u_addinvite(NULL, invite, from, cmt, expire_time, sticky);
  669. for (chan = chanset; chan; chan = chan->next)
  670. add_mode(chan, '+', 'I', invite);
  671. return TCL_OK;
  672. }
  673. static int tcl_channel_info(Tcl_Interp *irp, struct chanset_t *chan)
  674. {
  675. char a[121], b[121], s[121];
  676. EGG_CONST char *args[2];
  677. struct udef_struct *ul;
  678. get_mode_protect(chan, s);
  679. Tcl_AppendElement(irp, s);
  680. simple_sprintf(s, "%d", chan->idle_kick);
  681. Tcl_AppendElement(irp, s);
  682. simple_sprintf(s, "%d", chan->stopnethack_mode);
  683. Tcl_AppendElement(irp, s);
  684. simple_sprintf(s, "%d", chan->revenge_mode);
  685. Tcl_AppendElement(irp, s);
  686. Tcl_AppendElement(irp, chan->need_op);
  687. Tcl_AppendElement(irp, chan->need_invite);
  688. Tcl_AppendElement(irp, chan->need_key);
  689. Tcl_AppendElement(irp, chan->need_unban);
  690. Tcl_AppendElement(irp, chan->need_limit);
  691. simple_sprintf(s, "%d:%d", chan->flood_pub_thr, chan->flood_pub_time);
  692. Tcl_AppendElement(irp, s);
  693. simple_sprintf(s, "%d:%d", chan->flood_ctcp_thr, chan->flood_ctcp_time);
  694. Tcl_AppendElement(irp, s);
  695. simple_sprintf(s, "%d:%d", chan->flood_join_thr, chan->flood_join_time);
  696. Tcl_AppendElement(irp, s);
  697. simple_sprintf(s, "%d:%d", chan->flood_kick_thr, chan->flood_kick_time);
  698. Tcl_AppendElement(irp, s);
  699. simple_sprintf(s, "%d:%d", chan->flood_deop_thr, chan->flood_deop_time);
  700. Tcl_AppendElement(irp, s);
  701. simple_sprintf(s, "%d:%d", chan->flood_nick_thr, chan->flood_nick_time);
  702. Tcl_AppendElement(irp, s);
  703. simple_sprintf(s, "%d:%d", chan->aop_min, chan->aop_max);
  704. Tcl_AppendElement(irp, s);
  705. simple_sprintf(s, "%d", chan->ban_type);
  706. Tcl_AppendElement(irp, s);
  707. simple_sprintf(s, "%d", chan->ban_time);
  708. Tcl_AppendElement(irp, s);
  709. simple_sprintf(s, "%d", chan->exempt_time);
  710. Tcl_AppendElement(irp, s);
  711. simple_sprintf(s, "%d", chan->invite_time);
  712. Tcl_AppendElement(irp, s);
  713. if (chan->status & CHAN_ENFORCEBANS)
  714. Tcl_AppendElement(irp, "+enforcebans");
  715. else
  716. Tcl_AppendElement(irp, "-enforcebans");
  717. if (chan->status & CHAN_DYNAMICBANS)
  718. Tcl_AppendElement(irp, "+dynamicbans");
  719. else
  720. Tcl_AppendElement(irp, "-dynamicbans");
  721. if (chan->status & CHAN_NOUSERBANS)
  722. Tcl_AppendElement(irp, "-userbans");
  723. else
  724. Tcl_AppendElement(irp, "+userbans");
  725. if (chan->status & CHAN_OPONJOIN)
  726. Tcl_AppendElement(irp, "+autoop");
  727. else
  728. Tcl_AppendElement(irp, "-autoop");
  729. if (chan->status & CHAN_AUTOHALFOP)
  730. Tcl_AppendElement(irp, "+autohalfop");
  731. else
  732. Tcl_AppendElement(irp, "-autohalfop");
  733. if (chan->status & CHAN_BITCH)
  734. Tcl_AppendElement(irp, "+bitch");
  735. else
  736. Tcl_AppendElement(irp, "-bitch");
  737. if (chan->status & CHAN_GREET)
  738. Tcl_AppendElement(irp, "+greet");
  739. else
  740. Tcl_AppendElement(irp, "-greet");
  741. if (chan->status & CHAN_PROTECTOPS)
  742. Tcl_AppendElement(irp, "+protectops");
  743. else
  744. Tcl_AppendElement(irp, "-protectops");
  745. if (chan->status & CHAN_PROTECTHALFOPS)
  746. Tcl_AppendElement(irp, "+protecthalfops");
  747. else
  748. Tcl_AppendElement(irp, "-protecthalfops");
  749. if (chan->status & CHAN_PROTECTFRIENDS)
  750. Tcl_AppendElement(irp, "+protectfriends");
  751. else
  752. Tcl_AppendElement(irp, "-protectfriends");
  753. if (chan->status & CHAN_DONTKICKOPS)
  754. Tcl_AppendElement(irp, "+dontkickops");
  755. else
  756. Tcl_AppendElement(irp, "-dontkickops");
  757. if (chan->status & CHAN_INACTIVE)
  758. Tcl_AppendElement(irp, "+inactive");
  759. else
  760. Tcl_AppendElement(irp, "-inactive");
  761. if (chan->status & CHAN_LOGSTATUS)
  762. Tcl_AppendElement(irp, "+statuslog");
  763. else
  764. Tcl_AppendElement(irp, "-statuslog");
  765. if (chan->status & CHAN_REVENGE)
  766. Tcl_AppendElement(irp, "+revenge");
  767. else
  768. Tcl_AppendElement(irp, "-revenge");
  769. if (chan->status & CHAN_REVENGEBOT)
  770. Tcl_AppendElement(irp, "+revengebot");
  771. else
  772. Tcl_AppendElement(irp, "-revengebot");
  773. if (chan->status & CHAN_SECRET)
  774. Tcl_AppendElement(irp, "+secret");
  775. else
  776. Tcl_AppendElement(irp, "-secret");
  777. if (chan->status & CHAN_SHARED)
  778. Tcl_AppendElement(irp, "+shared");
  779. else
  780. Tcl_AppendElement(irp, "-shared");
  781. if (chan->status & CHAN_AUTOVOICE)
  782. Tcl_AppendElement(irp, "+autovoice");
  783. else
  784. Tcl_AppendElement(irp, "-autovoice");
  785. if (chan->status & CHAN_CYCLE)
  786. Tcl_AppendElement(irp, "+cycle");
  787. else
  788. Tcl_AppendElement(irp, "-cycle");
  789. if (chan->status & CHAN_SEEN)
  790. Tcl_AppendElement(irp, "+seen");
  791. else
  792. Tcl_AppendElement(irp, "-seen");
  793. if (chan->ircnet_status & CHAN_DYNAMICEXEMPTS)
  794. Tcl_AppendElement(irp, "+dynamicexempts");
  795. else
  796. Tcl_AppendElement(irp, "-dynamicexempts");
  797. if (chan->ircnet_status & CHAN_NOUSEREXEMPTS)
  798. Tcl_AppendElement(irp, "-userexempts");
  799. else
  800. Tcl_AppendElement(irp, "+userexempts");
  801. if (chan->ircnet_status & CHAN_DYNAMICINVITES)
  802. Tcl_AppendElement(irp, "+dynamicinvites");
  803. else
  804. Tcl_AppendElement(irp, "-dynamicinvites");
  805. if (chan->ircnet_status & CHAN_NOUSERINVITES)
  806. Tcl_AppendElement(irp, "-userinvites");
  807. else
  808. Tcl_AppendElement(irp, "+userinvites");
  809. if (chan->status & CHAN_NODESYNCH)
  810. Tcl_AppendElement(irp, "+nodesynch");
  811. else
  812. Tcl_AppendElement(irp, "-nodesynch");
  813. if (chan->status & CHAN_STATIC)
  814. Tcl_AppendElement(irp, "+static");
  815. else
  816. Tcl_AppendElement(irp, "-static");
  817. for (ul = udef; ul; ul = ul->next) {
  818. /* If it's undefined, skip it. */
  819. if (!ul->defined || !ul->name)
  820. continue;
  821. if (ul->type == UDEF_FLAG) {
  822. simple_sprintf(s, "%c%s", getudef(ul->values, chan->dname) ? '+' : '-',
  823. ul->name);
  824. Tcl_AppendElement(irp, s);
  825. } else if (ul->type == UDEF_INT) {
  826. char *x;
  827. egg_snprintf(a, sizeof a, "%s", ul->name);
  828. egg_snprintf(b, sizeof b, "%d", getudef(ul->values, chan->dname));
  829. args[0] = a;
  830. args[1] = b;
  831. x = Tcl_Merge(2, args);
  832. egg_snprintf(s, sizeof s, "%s", x);
  833. Tcl_Free((char *) x);
  834. Tcl_AppendElement(irp, s);
  835. } else if (ul->type == UDEF_STR) {
  836. char *p = (char *) getudef(ul->values, chan->dname), *buf;
  837. if (!p)
  838. p = "{}";
  839. buf = nmalloc(strlen(ul->name) + strlen(p) + 2);
  840. simple_sprintf(buf, "%s %s", ul->name, p);
  841. Tcl_AppendElement(irp, buf);
  842. nfree(buf);
  843. } else
  844. debug1("UDEF-ERROR: unknown type %d", ul->type);
  845. }
  846. return TCL_OK;
  847. }
  848. #define APPEND_KEYVAL(x, y) { \
  849. Tcl_AppendElement(irp, x); \
  850. Tcl_AppendElement(irp, y); \
  851. }
  852. static int tcl_channel_getlist(Tcl_Interp *irp, struct chanset_t *chan)
  853. {
  854. char s[121], *str;
  855. EGG_CONST char **argv = NULL;
  856. int argc = 0;
  857. struct udef_struct *ul;
  858. /* String values first */
  859. get_mode_protect(chan, s);
  860. APPEND_KEYVAL("chanmode", s);
  861. APPEND_KEYVAL("need-op", chan->need_op);
  862. APPEND_KEYVAL("need-invite", chan->need_invite);
  863. APPEND_KEYVAL("need-key", chan->need_key);
  864. APPEND_KEYVAL("need-unban", chan->need_unban);
  865. APPEND_KEYVAL("need-limit", chan->need_limit);
  866. /* Integers now */
  867. simple_sprintf(s, "%d", chan->idle_kick);
  868. APPEND_KEYVAL("idle-kick", s);
  869. simple_sprintf(s, "%d", chan->stopnethack_mode);
  870. APPEND_KEYVAL("stopnethack-mode", s);
  871. simple_sprintf(s, "%d", chan->revenge_mode);
  872. APPEND_KEYVAL("revenge-mode", s);
  873. simple_sprintf(s, "%d", chan->ban_type);
  874. APPEND_KEYVAL("ban-type", s);
  875. simple_sprintf(s, "%d", chan->ban_time);
  876. APPEND_KEYVAL("ban-time", s);
  877. simple_sprintf(s, "%d", chan->exempt_time);
  878. APPEND_KEYVAL("exempt-time", s);
  879. simple_sprintf(s, "%d", chan->invite_time);
  880. APPEND_KEYVAL("invite-time", s);
  881. simple_sprintf(s, "%d %d", chan->flood_pub_thr, chan->flood_pub_time);
  882. APPEND_KEYVAL("flood-chan", s);
  883. simple_sprintf(s, "%d %d", chan->flood_ctcp_thr, chan->flood_ctcp_time);
  884. APPEND_KEYVAL("flood-ctcp", s);
  885. simple_sprintf(s, "%d %d", chan->flood_join_thr, chan->flood_join_time);
  886. APPEND_KEYVAL("flood-join", s);
  887. simple_sprintf(s, "%d %d", chan->flood_kick_thr, chan->flood_kick_time);
  888. APPEND_KEYVAL("flood-kick", s);
  889. simple_sprintf(s, "%d %d", chan->flood_deop_thr, chan->flood_deop_time);
  890. APPEND_KEYVAL("flood-deop", s);
  891. simple_sprintf(s, "%d %d", chan->flood_nick_thr, chan->flood_nick_time);
  892. APPEND_KEYVAL("flood-nick", s);
  893. simple_sprintf(s, "%d %d", chan->aop_min, chan->aop_max);
  894. APPEND_KEYVAL("aop-delay", s);
  895. /* Last, but not least - flags */
  896. APPEND_KEYVAL("enforcebans",
  897. channel_enforcebans(chan) ? "1" : "0");
  898. APPEND_KEYVAL("dynamicbans",
  899. channel_dynamicbans(chan) ? "1" : "0");
  900. APPEND_KEYVAL("userbans",
  901. channel_nouserbans(chan) ? "1" : "0");
  902. APPEND_KEYVAL("autoop",
  903. channel_autoop(chan) ? "1" : "0");
  904. APPEND_KEYVAL("autohalfop",
  905. channel_autohalfop(chan) ? "1" : "0");
  906. APPEND_KEYVAL("bitch",
  907. channel_bitch(chan) ? "1" : "0");
  908. APPEND_KEYVAL("greet",
  909. channel_greet(chan) ? "1" : "0");
  910. APPEND_KEYVAL("protectops",
  911. channel_protectops(chan) ? "1" : "0");
  912. APPEND_KEYVAL("protecthalfops",
  913. channel_protecthalfops(chan) ? "1" : "0");
  914. APPEND_KEYVAL("protectfriends",
  915. channel_protectfriends(chan) ? "1" : "0");
  916. APPEND_KEYVAL("dontkickops",
  917. channel_dontkickops(chan) ? "1" : "0");
  918. APPEND_KEYVAL("inactive",
  919. channel_inactive(chan) ? "1" : "0");
  920. APPEND_KEYVAL("statuslog",
  921. channel_logstatus(chan) ? "1" : "0");
  922. APPEND_KEYVAL("revenge",
  923. channel_revenge(chan) ? "1" : "0");
  924. APPEND_KEYVAL("revengebot",
  925. channel_revengebot(chan) ? "1" : "0");
  926. APPEND_KEYVAL("secret",
  927. channel_secret(chan) ? "1" : "0");
  928. APPEND_KEYVAL("shared",
  929. channel_shared(chan) ? "1" : "0");
  930. APPEND_KEYVAL("autovoice",
  931. channel_autovoice(chan) ? "1" : "0");
  932. APPEND_KEYVAL("cycle",
  933. channel_cycle(chan) ? "1" : "0");
  934. APPEND_KEYVAL("seen",
  935. channel_seen(chan) ? "1" : "0");
  936. APPEND_KEYVAL("nodesynch",
  937. channel_nodesynch(chan) ? "1" : "0");
  938. APPEND_KEYVAL("static",
  939. channel_static(chan) ? "1" : "0");
  940. APPEND_KEYVAL("dynamicexempts",
  941. channel_dynamicexempts(chan) ? "1" : "0");
  942. APPEND_KEYVAL("userexempts",
  943. channel_nouserexempts(chan) ? "1" : "0");
  944. APPEND_KEYVAL("dynamicinvites",
  945. channel_dynamicinvites(chan) ? "1" : "0");
  946. APPEND_KEYVAL("userinvites",
  947. channel_nouserinvites(chan) ? "1" : "0");
  948. /* User defined settings */
  949. for (ul = udef; ul && ul->name; ul = ul->next) {
  950. if (ul->type == UDEF_STR) {
  951. str = (char *) getudef(ul->values, chan->dname);
  952. if (!str)
  953. str = "{}";
  954. Tcl_SplitList(irp, str, &argc, &argv);
  955. if (argc > 0)
  956. APPEND_KEYVAL(ul->name, argv[0]);
  957. Tcl_Free((char *) argv);
  958. } else {
  959. simple_sprintf(s, "%d", getudef(ul->values, chan->dname));
  960. APPEND_KEYVAL(ul->name, s);
  961. }
  962. }
  963. return TCL_OK;
  964. }
  965. static int tcl_channel_get(Tcl_Interp *irp, struct chanset_t *chan,
  966. char *setting)
  967. {
  968. char s[121], *str = NULL;
  969. EGG_CONST char **argv = NULL;
  970. int argc = 0;
  971. struct udef_struct *ul;
  972. if (!strcmp(setting, "chanmode"))
  973. get_mode_protect(chan, s);
  974. else if (!strcmp(setting, "need-op")) {
  975. strncpy(s, chan->need_op, 120);
  976. s[120] = 0;
  977. } else if (!strcmp(setting, "need-invite")) {
  978. strncpy(s, chan->need_invite, 120);
  979. s[120] = 0;
  980. } else if (!strcmp(setting, "need-key")) {
  981. strncpy(s, chan->need_key, 120);
  982. s[120] = 0;
  983. } else if (!strcmp(setting, "need-unban")) {
  984. strncpy(s, chan->need_unban, 120);
  985. s[120] = 0;
  986. } else if (!strcmp(setting, "need-limit")) {
  987. strncpy(s, chan->need_limit, 120);
  988. s[120] = 0;
  989. } else if (!strcmp(setting, "idle-kick"))
  990. simple_sprintf(s, "%d", chan->idle_kick);
  991. else if (!strcmp(setting, "stopnethack-mode") || !strcmp(setting, "stop-net-hack"))
  992. simple_sprintf(s, "%d", chan->stopnethack_mode);
  993. else if (!strcmp(setting, "revenge-mode"))
  994. simple_sprintf(s, "%d", chan->revenge_mode);
  995. else if (!strcmp(setting, "ban-type"))
  996. simple_sprintf(s, "%d", chan->ban_type);
  997. else if (!strcmp(setting, "ban-time"))
  998. simple_sprintf(s, "%d", chan->ban_time);
  999. else if (!strcmp(setting, "exempt-time"))
  1000. simple_sprintf(s, "%d", chan->exempt_time);
  1001. else if (!strcmp(setting, "invite-time"))
  1002. simple_sprintf(s, "%d", chan->invite_time);
  1003. else if (!strcmp(setting, "flood-chan"))
  1004. simple_sprintf(s, "%d %d", chan->flood_pub_thr, chan->flood_pub_time);
  1005. else if (!strcmp(setting, "flood-ctcp"))
  1006. simple_sprintf(s, "%d %d", chan->flood_ctcp_thr, chan->flood_ctcp_time);
  1007. else if (!strcmp(setting, "flood-join"))
  1008. simple_sprintf(s, "%d %d", chan->flood_join_thr, chan->flood_join_time);
  1009. else if (!strcmp(setting, "flood-kick"))
  1010. simple_sprintf(s, "%d %d", chan->flood_kick_thr, chan->flood_kick_time);
  1011. else if (!strcmp(setting, "flood-deop"))
  1012. simple_sprintf(s, "%d %d", chan->flood_deop_thr, chan->flood_deop_time);
  1013. else if (!strcmp(setting, "flood-nick"))
  1014. simple_sprintf(s, "%d %d", chan->flood_nick_thr, chan->flood_nick_time);
  1015. else if (!strcmp(setting, "aop-delay"))
  1016. simple_sprintf(s, "%d %d", chan->aop_min, chan->aop_max);
  1017. else if CHKFLAG_POS(CHAN_ENFORCEBANS, "enforcebans", chan->status)
  1018. else if CHKFLAG_POS(CHAN_DYNAMICBANS, "dynamicbans", chan->status)
  1019. else if CHKFLAG_NEG(CHAN_NOUSERBANS, "userbans", chan->status)
  1020. else if CHKFLAG_POS(CHAN_OPONJOIN, "autoop", chan->status)
  1021. else if CHKFLAG_POS(CHAN_AUTOHALFOP, "autohalfop", chan->status)
  1022. else if CHKFLAG_POS(CHAN_BITCH, "bitch", chan->status)
  1023. else if CHKFLAG_POS(CHAN_GREET, "greet", chan->status)
  1024. else if CHKFLAG_POS(CHAN_PROTECTOPS, "protectops", chan->status)
  1025. else if CHKFLAG_POS(CHAN_PROTECTHALFOPS, "protecthalfops", chan->status)
  1026. else if CHKFLAG_POS(CHAN_PROTECTFRIENDS, "protectfriends", chan->status)
  1027. else if CHKFLAG_POS(CHAN_DONTKICKOPS, "dontkickops", chan->status)
  1028. else if CHKFLAG_POS(CHAN_INACTIVE, "inactive", chan->status)
  1029. else if CHKFLAG_POS(CHAN_LOGSTATUS, "statuslog", chan->status)
  1030. else if CHKFLAG_POS(CHAN_REVENGE, "revenge", chan->status)
  1031. else if CHKFLAG_POS(CHAN_REVENGEBOT, "revengebot", chan->status)
  1032. else if CHKFLAG_POS(CHAN_SECRET, "secret", chan->status)
  1033. else if CHKFLAG_POS(CHAN_SHARED, "shared", chan->status)
  1034. else if CHKFLAG_POS(CHAN_AUTOVOICE, "autovoice", chan->status)
  1035. else if CHKFLAG_POS(CHAN_CYCLE, "cycle", chan->status)
  1036. else if CHKFLAG_POS(CHAN_SEEN, "seen", chan->status)
  1037. else if CHKFLAG_POS(CHAN_NODESYNCH, "nodesynch", chan->status)
  1038. else if CHKFLAG_POS(CHAN_STATIC, "static", chan->status)
  1039. else if CHKFLAG_POS(CHAN_DYNAMICEXEMPTS, "dynamicexempts",
  1040. chan->ircnet_status)
  1041. else if CHKFLAG_NEG(CHAN_NOUSEREXEMPTS, "userexempts",
  1042. chan->ircnet_status)
  1043. else if CHKFLAG_POS(CHAN_DYNAMICINVITES, "dynamicinvites",
  1044. chan->ircnet_status)
  1045. else if CHKFLAG_NEG(CHAN_NOUSERINVITES, "userinvites",
  1046. chan->ircnet_status)
  1047. else {
  1048. /* Hopefully it's a user-defined flag. */
  1049. for (ul = udef; ul && ul->name; ul = ul->next) {
  1050. if (!strcmp(setting, ul->name))
  1051. break;
  1052. }
  1053. if (!ul || !ul->name) {
  1054. /* Error if it wasn't found. */
  1055. Tcl_AppendResult(irp, "Unknown channel setting.", NULL);
  1056. return TCL_ERROR;
  1057. }
  1058. if (ul->type == UDEF_STR) {
  1059. str = (char *) getudef(ul->values, chan->dname);
  1060. if (!str)
  1061. str = "{}";
  1062. Tcl_SplitList(irp, str, &argc, &argv);
  1063. if (argc > 0)
  1064. Tcl_AppendResult(irp, argv[0], NULL);
  1065. Tcl_Free((char *) argv);
  1066. } else {
  1067. /* Flag or int, all the same. */
  1068. simple_sprintf(s, "%d", getudef(ul->values, chan->dname));
  1069. Tcl_AppendResult(irp, s, NULL);
  1070. }
  1071. return TCL_OK;
  1072. }
  1073. /* Ok, if we make it this far, the result is "s". */
  1074. Tcl_AppendResult(irp, s, NULL);
  1075. return TCL_OK;
  1076. }
  1077. static int tcl_channel STDVAR
  1078. {
  1079. struct chanset_t *chan;
  1080. BADARGS(2, -1, " command ?options?");
  1081. if (!strcmp(argv[1], "add")) {
  1082. BADARGS(3, 4, " add channel-name ?options-list?");
  1083. if (argc == 3)
  1084. return tcl_channel_add(irp, argv[2], "");
  1085. return tcl_channel_add(irp, argv[2], argv[3]);
  1086. }
  1087. if (!strcmp(argv[1], "set")) {
  1088. BADARGS(3, -1, " set channel-name ?options?");
  1089. chan = findchan_by_dname(argv[2]);
  1090. if (chan == NULL) {
  1091. if (chan_hack == 1)
  1092. return TCL_OK; /* Ignore channel settings for a static
  1093. * channel which has been removed from
  1094. * the config */
  1095. Tcl_AppendResult(irp, "no such channel record", NULL);
  1096. return TCL_ERROR;
  1097. }
  1098. return tcl_channel_modify(irp, chan, argc - 3, &argv[3]);
  1099. }
  1100. if (!strcmp(argv[1], "get")) {
  1101. BADARGS(3, 4, " get channel-name ?setting-name?");
  1102. chan = findchan_by_dname(argv[2]);
  1103. if (chan == NULL) {
  1104. Tcl_AppendResult(irp, "no such channel record", NULL);
  1105. return TCL_ERROR;
  1106. }
  1107. if (argc == 4)
  1108. return tcl_channel_get(irp, chan, argv[3]);
  1109. else
  1110. return tcl_channel_getlist(irp, chan);
  1111. }
  1112. if (!strcmp(argv[1], "info")) {
  1113. BADARGS(3, 3, " info channel-name");
  1114. chan = findchan_by_dname(argv[2]);
  1115. if (chan == NULL) {
  1116. Tcl_AppendResult(irp, "no such channel record", NULL);
  1117. return TCL_ERROR;
  1118. }
  1119. return tcl_channel_info(irp, chan);
  1120. }
  1121. if (!strcmp(argv[1], "remove")) {
  1122. BADARGS(3, 3, " remove channel-name");
  1123. chan = findchan_by_dname(argv[2]);
  1124. if (chan == NULL) {
  1125. Tcl_AppendResult(irp, "no such channel record", NULL);
  1126. return TCL_ERROR;
  1127. }
  1128. remove_channel(chan);
  1129. return TCL_OK;
  1130. }
  1131. Tcl_AppendResult(irp, "unknown channel command: should be one of: ",
  1132. "add, set, get, info, remove", NULL);
  1133. return TCL_ERROR;
  1134. }
  1135. /* Parse options for a channel. */
  1136. static int tcl_channel_modify(Tcl_Interp *irp, struct chanset_t *chan,
  1137. int items, char **item)
  1138. {
  1139. int i, x = 0, found, old_status = chan->status,
  1140. old_mode_mns_prot = chan->mode_mns_prot,
  1141. old_mode_pls_prot = chan->mode_pls_prot;
  1142. struct udef_struct *ul = udef;
  1143. char s[121];
  1144. module_entry *me;
  1145. for (i = 0; i < items; i++) {
  1146. if (!strcmp(item[i], "need-op")) {
  1147. i++;
  1148. if (i >= items) {
  1149. if (irp)
  1150. Tcl_AppendResult(irp, "channel need-op needs argument", NULL);
  1151. return TCL_ERROR;
  1152. }
  1153. strncpy(chan->need_op, item[i], 120);
  1154. chan->need_op[120] = 0;
  1155. } else if (!strcmp(item[i], "need-invite")) {
  1156. i++;
  1157. if (i >= items) {
  1158. if (irp)
  1159. Tcl_AppendResult(irp, "channel need-invite needs argument", NULL);
  1160. return TCL_ERROR;
  1161. }
  1162. strncpy(chan->need_invite, item[i], 120);
  1163. chan->need_invite[120] = 0;
  1164. } else if (!strcmp(item[i], "need-key")) {
  1165. i++;
  1166. if (i >= items) {
  1167. if (irp)
  1168. Tcl_AppendResult(irp, "channel need-key needs argument", NULL);
  1169. return TCL_ERROR;
  1170. }
  1171. strncpy(chan->need_key, item[i], 120);
  1172. chan->need_key[120] = 0;
  1173. } else if (!strcmp(item[i], "need-limit")) {
  1174. i++;
  1175. if (i >= items) {
  1176. if (irp)
  1177. Tcl_AppendResult(irp, "channel need-limit needs argument", NULL);
  1178. return TCL_ERROR;
  1179. }
  1180. strncpy(chan->need_limit, item[i], 120);
  1181. chan->need_limit[120] = 0;
  1182. } else if (!strcmp(item[i], "need-unban")) {
  1183. i++;
  1184. if (i >= items) {
  1185. if (irp)
  1186. Tcl_AppendResult(irp, "channel need-unban needs argument", NULL);
  1187. return TCL_ERROR;
  1188. }
  1189. strncpy(chan->need_unban, item[i], 120);
  1190. chan->need_unban[120] = 0;
  1191. } else if (!strcmp(item[i], "chanmode")) {
  1192. i++;
  1193. if (i >= items) {
  1194. if (irp)
  1195. Tcl_AppendResult(irp, "channel chanmode needs argument", NULL);
  1196. return TCL_ERROR;
  1197. }
  1198. strncpy(s, item[i], 120);
  1199. s[120] = 0;
  1200. set_mode_protect(chan, s);
  1201. } else if (!strcmp(item[i], "idle-kick")) {
  1202. i++;
  1203. if (i >= items) {
  1204. if (irp)
  1205. Tcl_AppendResult(irp, "channel idle-kick needs argument", NULL);
  1206. return TCL_ERROR;
  1207. }
  1208. chan->idle_kick = atoi(item[i]);
  1209. } else if (!strcmp(item[i], "dont-idle-kick"))
  1210. chan->idle_kick = 0;
  1211. else if (!strcmp(item[i], "stopnethack-mode")) {
  1212. i++;
  1213. if (i >= items) {
  1214. if (irp)
  1215. Tcl_AppendResult(irp, "channel stopnethack-mode needs argument",
  1216. NULL);
  1217. return TCL_ERROR;
  1218. }
  1219. chan->stopnethack_mode = atoi(item[i]);
  1220. } else if (!strcmp(item[i], "revenge-mode")) {
  1221. i++;
  1222. if (i >= items) {
  1223. if (irp)
  1224. Tcl_AppendResult(irp, "channel revenge-mode needs argument", NULL);
  1225. return TCL_ERROR;
  1226. }
  1227. chan->revenge_mode = atoi(item[i]);
  1228. } else if (!strcmp(item[i], "ban-type")) {
  1229. i++;
  1230. if (i >= items) {
  1231. if (irp)
  1232. Tcl_AppendResult(irp, "channel ban-type needs argument", NULL);
  1233. return TCL_ERROR;
  1234. }
  1235. chan->ban_type = atoi(item[i]);
  1236. } else if (!strcmp(item[i], "ban-time")) {
  1237. i++;
  1238. if (i >= items) {
  1239. if (irp)
  1240. Tcl_AppendResult(irp, "channel ban-time needs argument", NULL);
  1241. return TCL_ERROR;
  1242. }
  1243. chan->ban_time = atoi(item[i]);
  1244. } else if (!strcmp(item[i], "exempt-time")) {
  1245. i++;
  1246. if (i >= items) {
  1247. if (irp)
  1248. Tcl_AppendResult(irp, "channel exempt-time needs argument", NULL);
  1249. return TCL_ERROR;
  1250. }
  1251. chan->exempt_time = atoi(item[i]);
  1252. } else if (!strcmp(item[i], "invite-time")) {
  1253. i++;
  1254. if (i >= items) {
  1255. if (irp)
  1256. Tcl_AppendResult(irp, "channel invite-time needs argument", NULL);
  1257. return TCL_ERROR;
  1258. }
  1259. chan->invite_time = atoi(item[i]);
  1260. } else if (!strcmp(item[i], "+enforcebans"))
  1261. chan->status |= CHAN_ENFORCEBANS;
  1262. else if (!strcmp(item[i], "-enforcebans"))
  1263. chan->status &= ~CHAN_ENFORCEBANS;
  1264. else if (!strcmp(item[i], "+dynamicbans"))
  1265. chan->status |= CHAN_DYNAMICBANS;
  1266. else if (!strcmp(item[i], "-dynamicbans"))
  1267. chan->status &= ~CHAN_DYNAMICBANS;
  1268. else if (!strcmp(item[i], "-userbans"))
  1269. chan->status |= CHAN_NOUSERBANS;
  1270. else if (!strcmp(item[i], "+userbans"))
  1271. chan->status &= ~CHAN_NOUSERBANS;
  1272. else if (!strcmp(item[i], "+autoop"))
  1273. chan->status |= CHAN_OPONJOIN;
  1274. else if (!strcmp(item[i], "-autoop"))
  1275. chan->status &= ~CHAN_OPONJOIN;
  1276. else if (!strcmp(item[i], "+autohalfop"))
  1277. chan->status |= CHAN_AUTOHALFOP;
  1278. else if (!strcmp(item[i], "-autohalfop"))
  1279. chan->status &= ~CHAN_AUTOHALFOP;
  1280. else if (!strcmp(item[i], "+bitch"))
  1281. chan->status |= CHAN_BITCH;
  1282. else if (!strcmp(item[i], "-bitch"))
  1283. chan->status &= ~CHAN_BITCH;
  1284. else if (!strcmp(item[i], "+nodesynch"))
  1285. chan->status |= CHAN_NODESYNCH;
  1286. else if (!strcmp(item[i], "-nodesynch"))
  1287. chan->status &= ~CHAN_NODESYNCH;
  1288. else if (!strcmp(item[i], "+greet"))
  1289. chan->status |= CHAN_GREET;
  1290. else if (!strcmp(item[i], "-greet"))
  1291. chan->status &= ~CHAN_GREET;
  1292. else if (!strcmp(item[i], "+protectops"))
  1293. chan->status |= CHAN_PROTECTOPS;
  1294. else if (!strcmp(item[i], "-protectops"))
  1295. chan->status &= ~CHAN_PROTECTOPS;
  1296. else if (!strcmp(item[i], "+protecthalfops"))
  1297. chan->status |= CHAN_PROTECTHALFOPS;
  1298. else if (!strcmp(item[i], "-protecthalfops"))
  1299. chan->status &= ~CHAN_PROTECTHALFOPS;
  1300. else if (!strcmp(item[i], "+protectfriends"))
  1301. chan->status |= CHAN_PROTECTFRIENDS;
  1302. else if (!strcmp(item[i], "-protectfriends"))
  1303. chan->status &= ~CHAN_PROTECTFRIENDS;
  1304. else if (!strcmp(item[i], "+dontkickops"))
  1305. chan->status |= CHAN_DONTKICKOPS;
  1306. else if (!strcmp(item[i], "-dontkickops"))
  1307. chan->status &= ~CHAN_DONTKICKOPS;
  1308. else if (!strcmp(item[i], "+inactive"))
  1309. chan->status |= CHAN_INACTIVE;
  1310. else if (!strcmp(item[i], "-inactive"))
  1311. chan->status &= ~CHAN_INACTIVE;
  1312. else if (!strcmp(item[i], "+statuslog"))
  1313. chan->status |= CHAN_LOGSTATUS;
  1314. else if (!strcmp(item[i], "-statuslog"))
  1315. chan->status &= ~CHAN_LOGSTATUS;
  1316. else if (!strcmp(item[i], "+revenge"))
  1317. chan->status |= CHAN_REVENGE;
  1318. else if (!strcmp(item[i], "-revenge"))
  1319. chan->status &= ~CHAN_REVENGE;
  1320. else if (!strcmp(item[i], "+revengebot"))
  1321. chan->status |= CHAN_REVENGEBOT;
  1322. else if (!strcmp(item[i], "-revengebot"))
  1323. chan->status &= ~CHAN_REVENGEBOT;
  1324. else if (!strcmp(item[i], "+secret"))
  1325. chan->status |= CHAN_SECRET;
  1326. else if (!strcmp(item[i], "-secret"))
  1327. chan->status &= ~CHAN_SECRET;
  1328. else if (!strcmp(item[i], "+shared"))
  1329. chan->status |= CHAN_SHARED;
  1330. else if (!strcmp(item[i], "-shared"))
  1331. chan->status &= ~CHAN_SHARED;
  1332. else if (!strcmp(item[i], "+autovoice"))
  1333. chan->status |= CHAN_AUTOVOICE;
  1334. else if (!strcmp(item[i], "-autovoice"))
  1335. chan->status &= ~CHAN_AUTOVOICE;
  1336. else if (!strcmp(item[i], "+cycle"))
  1337. chan->status |= CHAN_CYCLE;
  1338. else if (!strcmp(item[i], "-cycle"))
  1339. chan->status &= ~CHAN_CYCLE;
  1340. else if (!strcmp(item[i], "+seen"))
  1341. chan->status |= CHAN_SEEN;
  1342. else if (!strcmp(item[i], "-seen"))
  1343. chan->status &= ~CHAN_SEEN;
  1344. else if (!strcmp(item[i], "+static"))
  1345. chan->status |= CHAN_STATIC;
  1346. else if (!strcmp(item[i], "-static"))
  1347. chan->status &= ~CHAN_STATIC;
  1348. else if (!strcmp(item[i], "+dynamicexempts"))
  1349. chan->ircnet_status |= CHAN_DYNAMICEXEMPTS;
  1350. else if (!strcmp(item[i], "-dynamicexempts"))
  1351. chan->ircnet_status &= ~CHAN_DYNAMICEXEMPTS;
  1352. else if (!strcmp(item[i], "-userexempts"))
  1353. chan->ircnet_status |= CHAN_NOUSEREXEMPTS;
  1354. else if (!strcmp(item[i], "+userexempts"))
  1355. chan->ircnet_status &= ~CHAN_NOUSEREXEMPTS;
  1356. else if (!strcmp(item[i], "+dynamicinvites"))
  1357. chan->ircnet_status |= CHAN_DYNAMICINVITES;
  1358. else if (!strcmp(item[i], "-dynamicinvites"))
  1359. chan->ircnet_status &= ~CHAN_DYNAMICINVITES;
  1360. else if (!strcmp(item[i], "-userinvites"))
  1361. chan->ircnet_status |= CHAN_NOUSERINVITES;
  1362. else if (!strcmp(item[i], "+userinvites"))
  1363. chan->ircnet_status &= ~CHAN_NOUSERINVITES;
  1364. /* ignore wasoptest, stopnethack and clearbans in chanfile, remove
  1365. * this later */
  1366. else if (!strcmp(item[i], "-stopnethack"));
  1367. else if (!strcmp(item[i], "+stopnethack"));
  1368. else if (!strcmp(item[i], "-wasoptest"));
  1369. else if (!strcmp(item[i], "+wasoptest")); /* Eule 01.2000 */
  1370. else if (!strcmp(item[i], "+clearbans"));
  1371. else if (!strcmp(item[i], "-clearbans"));
  1372. else if (!strncmp(item[i], "flood-", 6)) {
  1373. int *pthr = 0, *ptime;
  1374. char *p;
  1375. if (!strcmp(item[i] + 6, "chan")) {
  1376. pthr = &chan->flood_pub_thr;
  1377. ptime = &chan->flood_pub_time;
  1378. } else if (!strcmp(item[i] + 6, "join")) {
  1379. pthr = &chan->flood_join_thr;
  1380. ptime = &chan->flood_join_time;
  1381. } else if (!strcmp(item[i] + 6, "ctcp")) {
  1382. pthr = &chan->flood_ctcp_thr;
  1383. ptime = &chan->flood_ctcp_time;
  1384. } else if (!strcmp(item[i] + 6, "kick")) {
  1385. pthr = &chan->flood_kick_thr;
  1386. ptime = &chan->flood_kick_time;
  1387. } else if (!strcmp(item[i] + 6, "deop")) {
  1388. pthr = &chan->flood_deop_thr;
  1389. ptime = &chan->flood_deop_time;
  1390. } else if (!strcmp(item[i] + 6, "nick")) {
  1391. pthr = &chan->flood_nick_thr;
  1392. ptime = &chan->flood_nick_time;
  1393. } else {
  1394. if (irp)
  1395. Tcl_AppendResult(irp, "illegal channel flood type: ", item[i], NULL);
  1396. return TCL_ERROR;
  1397. }
  1398. i++;
  1399. if (i >= items) {
  1400. if (irp)
  1401. Tcl_AppendResult(irp, item[i - 1], " needs argument", NULL);
  1402. return TCL_ERROR;
  1403. }
  1404. p = strchr(item[i], ':');
  1405. if (p) {
  1406. *p++ = 0;
  1407. *pthr = atoi(item[i]);
  1408. *ptime = atoi(p);
  1409. *--p = ':';
  1410. } else {
  1411. *pthr = atoi(item[i]);
  1412. *ptime = 1;
  1413. }
  1414. } else if (!strncmp(item[i], "aop-delay", 9)) {
  1415. char *p;
  1416. i++;
  1417. if (i >= items) {
  1418. if (irp)
  1419. Tcl_AppendResult(irp, item[i - 1], " needs argument", NULL);
  1420. return TCL_ERROR;
  1421. }
  1422. p = strchr(item[i], ':');
  1423. if (p) {
  1424. p++;
  1425. chan->aop_min = atoi(item[i]);
  1426. chan->aop_max = atoi(p);
  1427. } else {
  1428. chan->aop_min = atoi(item[i]);
  1429. chan->aop_max = chan->aop_min;
  1430. }
  1431. } else {
  1432. if (!strncmp(item[i] + 1, "udef-flag-", 10))
  1433. /* 10th position for the +/- sign */
  1434. initudef(UDEF_FLAG, item[i] + 11, 0);
  1435. else if (!strncmp(item[i], "udef-int-", 9))
  1436. initudef(UDEF_INT, item[i] + 9, 0);
  1437. else if (!strncmp(item[i], "udef-str-", 9))
  1438. initudef(UDEF_STR, item[i] + 9, 0);
  1439. found = 0;
  1440. for (ul = udef; ul; ul = ul->next) {
  1441. if (ul->type == UDEF_FLAG && (!egg_strcasecmp(item[i] + 1, ul->name) ||
  1442. (!strncmp(item[i] + 1, "udef-flag-", 10) &&
  1443. !egg_strcasecmp(item[i] + 11, ul->name)))) {
  1444. if (item[i][0] == '+')
  1445. setudef(ul, chan->dname, 1);
  1446. else
  1447. setudef(ul, chan->dname, 0);
  1448. found = 1;
  1449. break;
  1450. } else if (ul->type == UDEF_INT && (!egg_strcasecmp(item[i], ul->name) ||
  1451. (!strncmp(item[i], "udef-int-", 9) &&
  1452. !egg_strcasecmp(item[i] + 9, ul->name)))) {
  1453. i++;
  1454. if (i >= items) {
  1455. if (irp)
  1456. Tcl_AppendResult(irp, "this setting needs an argument", NULL);
  1457. return TCL_ERROR;
  1458. }
  1459. setudef(ul, chan->dname, atoi(item[i]));
  1460. found = 1;
  1461. break;
  1462. } else if (ul->type == UDEF_STR &&
  1463. (!egg_strcasecmp(item[i], ul->name) ||
  1464. (!strncmp(item[i], "udef-str-", 9) &&
  1465. !egg_strcasecmp(item[i] + 9, ul->name)))) {
  1466. char *val;
  1467. i++;
  1468. if (i >= items) {
  1469. if (irp)
  1470. Tcl_AppendResult(irp, "this setting needs an argument", NULL);
  1471. return TCL_ERROR;
  1472. }
  1473. val = (char *) getudef(ul->values, chan->dname);
  1474. if (val)
  1475. nfree(val);
  1476. /* Get extra room for new braces, etc */
  1477. val = nmalloc(3 * strlen(item[i]) + 10);
  1478. convert_element(item[i], val);
  1479. val = nrealloc(val, strlen(val) + 1);
  1480. setudef(ul, chan->dname, (intptr_t) val);
  1481. found = 1;
  1482. break;
  1483. }
  1484. }
  1485. if (!found) {
  1486. if (irp && item[i][0]) /* ignore "" */
  1487. Tcl_AppendResult(irp, "illegal channel option: ", item[i], "\n", NULL);
  1488. x++;
  1489. }
  1490. }
  1491. }
  1492. /* If protect_readonly == 0 and chan_hack == 0 then
  1493. * bot is now processing the configfile, so dont do anything,
  1494. * we've to wait the channelfile that maybe override these settings
  1495. * (note: it may cause problems if there is no chanfile!)
  1496. * <drummer/1999/10/21>
  1497. */
  1498. if (protect_readonly || chan_hack) {
  1499. if (((old_status ^ chan->status) & CHAN_INACTIVE) &&
  1500. module_find("irc", 0, 0)) {
  1501. if (channel_inactive(chan) && (chan->status & (CHAN_ACTIVE | CHAN_PEND)))
  1502. dprintf(DP_SERVER, "PART %s\n", chan->name);
  1503. if (!channel_inactive(chan) &&
  1504. !(chan->status & (CHAN_ACTIVE | CHAN_PEND))) {
  1505. char *key;
  1506. key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
  1507. if (key[0])
  1508. dprintf(DP_SERVER, "JOIN %s %s\n",
  1509. chan->name[0] ? chan->name : chan->dname, key);
  1510. else
  1511. dprintf(DP_SERVER, "JOIN %s\n",
  1512. chan->name[0] ? chan->name : chan->dname);
  1513. }
  1514. }
  1515. if ((old_status ^ chan->status) & (CHAN_ENFORCEBANS | CHAN_OPONJOIN |
  1516. CHAN_BITCH | CHAN_AUTOVOICE |
  1517. CHAN_AUTOHALFOP)) {
  1518. if ((me = module_find("irc", 0, 0)))
  1519. (me->funcs[IRC_RECHECK_CHANNEL]) (chan, 1);
  1520. } else if (old_mode_pls_prot != chan->mode_pls_prot ||
  1521. old_mode_mns_prot != chan->mode_mns_prot)
  1522. if ((me = module_find("irc", 1, 2)))
  1523. (me->funcs[IRC_RECHECK_CHANNEL_MODES]) (chan);
  1524. }
  1525. if (x > 0)
  1526. return TCL_ERROR;
  1527. return TCL_OK;
  1528. }
  1529. static int tcl_do_masklist(maskrec *m, Tcl_Interp *irp)
  1530. {
  1531. char ts[21], ts1[21], ts2[21], *p;
  1532. long tv;
  1533. EGG_CONST char *list[6];
  1534. for (; m; m = m->next) {
  1535. list[0] = m->mask;
  1536. list[1] = m->desc;
  1537. tv = m->expire;
  1538. sprintf(ts, "%lu", tv);
  1539. list[2] = ts;
  1540. tv = m->added;
  1541. sprintf(ts1, "%lu", tv);
  1542. list[3] = ts1;
  1543. tv = m->lastactive;
  1544. sprintf(ts2, "%lu", tv);
  1545. list[4] = ts2;
  1546. list[5] = m->user;
  1547. p = Tcl_Merge(6, list);
  1548. Tcl_AppendElement(irp, p);
  1549. Tcl_Free((char *) p);
  1550. }
  1551. return TCL_OK;
  1552. }
  1553. static int tcl_banlist STDVAR
  1554. {
  1555. struct chanset_t *chan;
  1556. BADARGS(1, 2, " ?channel?");
  1557. if (argc == 2) {
  1558. chan = findchan_by_dname(argv[1]);
  1559. if (chan == NULL) {
  1560. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  1561. return TCL_ERROR;
  1562. }
  1563. return tcl_do_masklist(chan->bans, irp);
  1564. }
  1565. return tcl_do_masklist(global_bans, irp);
  1566. }
  1567. static int tcl_exemptlist STDVAR
  1568. {
  1569. struct chanset_t *chan;
  1570. BADARGS(1, 2, " ?channel?");
  1571. if (argc == 2) {
  1572. chan = findchan_by_dname(argv[1]);
  1573. if (chan == NULL) {
  1574. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  1575. return TCL_ERROR;
  1576. }
  1577. return tcl_do_masklist(chan->exempts, irp);
  1578. }
  1579. return tcl_do_masklist(global_exempts, irp);
  1580. }
  1581. static int tcl_invitelist STDVAR
  1582. {
  1583. struct chanset_t *chan;
  1584. BADARGS(1, 2, " ?channel?");
  1585. if (argc == 2) {
  1586. chan = findchan_by_dname(argv[1]);
  1587. if (chan == NULL) {
  1588. Tcl_AppendResult(irp, "invalid channel: ", argv[1], NULL);
  1589. return TCL_ERROR;
  1590. }
  1591. return tcl_do_masklist(chan->invites, irp);
  1592. }
  1593. return tcl_do_masklist(global_invites, irp);
  1594. }
  1595. static int tcl_channels STDVAR
  1596. {
  1597. struct chanset_t *chan;
  1598. BADARGS(1, 1, "");
  1599. for (chan = chanset; chan; chan = chan->next)
  1600. Tcl_AppendElement(irp, chan->dname);
  1601. return TCL_OK;
  1602. }
  1603. static int tcl_savechannels STDVAR
  1604. {
  1605. BADARGS(1, 1, "");
  1606. if (!chanfile[0]) {
  1607. Tcl_AppendResult(irp, "no channel file", NULL);
  1608. return TCL_ERROR;
  1609. }
  1610. write_channels();
  1611. return TCL_OK;
  1612. }
  1613. static int tcl_loadchannels STDVAR
  1614. {
  1615. BADARGS(1, 1, "");
  1616. if (!chanfile[0]) {
  1617. Tcl_AppendResult(irp, "no channel file", NULL);
  1618. return TCL_ERROR;
  1619. }
  1620. read_channels(1, 1);
  1621. return TCL_OK;
  1622. }
  1623. static int tcl_validchan STDVAR
  1624. {
  1625. struct chanset_t *chan;
  1626. BADARGS(2, 2, " channel");
  1627. chan = findchan_by_dname(argv[1]);
  1628. if (chan == NULL)
  1629. Tcl_AppendResult(irp, "0", NULL);
  1630. else
  1631. Tcl_AppendResult(irp, "1", NULL);
  1632. return TCL_OK;
  1633. }
  1634. static int tcl_isdynamic STDVAR
  1635. {
  1636. struct chanset_t *chan;
  1637. BADARGS(2, 2, " channel");
  1638. chan = findchan_by_dname(argv[1]);
  1639. if (chan != NULL)
  1640. if (!channel_static(chan)) {
  1641. Tcl_AppendResult(irp, "1", NULL);
  1642. return TCL_OK;
  1643. }
  1644. Tcl_AppendResult(irp, "0", NULL);
  1645. return TCL_OK;
  1646. }
  1647. static int tcl_getchaninfo STDVAR
  1648. {
  1649. char s[161];
  1650. struct userrec *u;
  1651. BADARGS(3, 3, " handle channel");
  1652. u = get_user_by_handle(userlist, argv[1]);
  1653. if (!u || (u->flags & USER_BOT))
  1654. return TCL_OK;
  1655. get_handle_chaninfo(argv[1], argv[2], s);
  1656. Tcl_AppendResult(irp, s, NULL);
  1657. return TCL_OK;
  1658. }
  1659. static int tcl_setchaninfo STDVAR
  1660. {
  1661. struct chanset_t *chan;
  1662. BADARGS(4, 4, " handle channel info");
  1663. chan = findchan_by_dname(argv[2]);
  1664. if (chan == NULL) {
  1665. Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
  1666. return TCL_ERROR;
  1667. }
  1668. if (!egg_strcasecmp(argv[3], "none")) {
  1669. set_handle_chaninfo(userlist, argv[1], argv[2], NULL);
  1670. return TCL_OK;
  1671. }
  1672. set_handle_chaninfo(userlist, argv[1], argv[2], argv[3]);
  1673. return TCL_OK;
  1674. }
  1675. static int tcl_setlaston STDVAR
  1676. {
  1677. time_t t = now;
  1678. struct userrec *u;
  1679. BADARGS(2, 4, " handle ?channel? ?timestamp?");
  1680. u = get_user_by_handle(userlist, argv[1]);
  1681. if (!u) {
  1682. Tcl_AppendResult(irp, "No such user: ", argv[1], NULL);
  1683. return TCL_ERROR;
  1684. }
  1685. if (argc == 4)
  1686. t = (time_t) atoi(argv[3]);
  1687. if (argc == 3 && ((argv[2][0] != '#') && (argv[2][0] != '&')))
  1688. t = (time_t) atoi(argv[2]);
  1689. if (argc == 2 || (argc == 3 && ((argv[2][0] != '#') && (argv[2][0] != '&'))))
  1690. set_handle_laston("*", u, t);
  1691. else
  1692. set_handle_laston(argv[2], u, t);
  1693. return TCL_OK;
  1694. }
  1695. static int tcl_addchanrec STDVAR
  1696. {
  1697. struct userrec *u;
  1698. BADARGS(3, 3, " handle channel");
  1699. u = get_user_by_handle(userlist, argv[1]);
  1700. if (!u) {
  1701. Tcl_AppendResult(irp, "0", NULL);
  1702. return TCL_OK;
  1703. }
  1704. if (!findchan_by_dname(argv[2])) {
  1705. Tcl_AppendResult(irp, "0", NULL);
  1706. return TCL_OK;
  1707. }
  1708. if (get_chanrec(u, argv[2]) != NULL) {
  1709. Tcl_AppendResult(irp, "0", NULL);
  1710. return TCL_OK;
  1711. }
  1712. add_chanrec(u, argv[2]);
  1713. Tcl_AppendResult(irp, "1", NULL);
  1714. return TCL_OK;
  1715. }
  1716. static int tcl_delchanrec STDVAR
  1717. {
  1718. struct userrec *u;
  1719. BADARGS(3, 3, " handle channel");
  1720. u = get_user_by_handle(userlist, argv[1]);
  1721. if (!u) {
  1722. Tcl_AppendResult(irp, "0", NULL);
  1723. return TCL_OK;
  1724. }
  1725. if (get_chanrec(u, argv[2]) == NULL) {
  1726. Tcl_AppendResult(irp, "0", NULL);
  1727. return TCL_OK;
  1728. }
  1729. del_chanrec(u, argv[2]);
  1730. Tcl_AppendResult(irp, "1", NULL);
  1731. return TCL_OK;
  1732. }
  1733. static int tcl_haschanrec STDVAR
  1734. {
  1735. struct userrec *u;
  1736. struct chanset_t *chan;
  1737. struct chanuserrec *chanrec;
  1738. BADARGS(3, 3, " handle channel");
  1739. chan = findchan_by_dname(argv[2]);
  1740. if (chan == NULL) {
  1741. Tcl_AppendResult(irp, "illegal channel: ", argv[2], NULL);
  1742. return TCL_ERROR;
  1743. }
  1744. u = get_user_by_handle(userlist, argv[1]);
  1745. if (!u) {
  1746. Tcl_AppendResult(irp, "No such user: ", argv[1], NULL);
  1747. return TCL_ERROR;
  1748. }
  1749. chanrec = get_chanrec(u, chan->dname);
  1750. if (chanrec) {
  1751. Tcl_AppendResult(irp, "1", NULL);
  1752. return TCL_OK;
  1753. }
  1754. Tcl_AppendResult(irp, "0", NULL);
  1755. return TCL_OK;
  1756. }
  1757. static void init_masklist(masklist *m)
  1758. {
  1759. m->mask = nmalloc(1);
  1760. m->mask[0] = 0;
  1761. m->who = NULL;
  1762. m->next = NULL;
  1763. }
  1764. /* Initialize out the channel record.
  1765. */
  1766. static void init_channel(struct chanset_t *chan, int reset)
  1767. {
  1768. int flags = reset ? reset : CHAN_RESETALL;
  1769. if (!reset) {
  1770. chan->channel.key = nmalloc(1);
  1771. chan->channel.key[0] = 0;
  1772. chan->channel.members = 0;
  1773. chan->channel.member = nmalloc(sizeof(memberlist));
  1774. chan->channel.member->nick[0] = 0;
  1775. chan->channel.member->next = NULL;
  1776. }
  1777. if (flags & CHAN_RESETMODES) {
  1778. if (!reset)
  1779. chan->channel.mode = 0;
  1780. chan->channel.maxmembers = 0;
  1781. }
  1782. if (flags & CHAN_RESETBANS) {
  1783. chan->channel.ban = nmalloc(sizeof(masklist));
  1784. init_masklist(chan->channel.ban);
  1785. }
  1786. if (flags & CHAN_RESETEXEMPTS) {
  1787. chan->channel.exempt = nmalloc(sizeof(masklist));
  1788. init_masklist(chan->channel.exempt);
  1789. }
  1790. if (flags & CHAN_RESETINVITED) {
  1791. chan->channel.invite = nmalloc(sizeof(masklist));
  1792. init_masklist(chan->channel.invite);
  1793. }
  1794. if (flags & CHAN_RESETTOPIC)
  1795. chan->channel.topic = NULL;
  1796. }
  1797. static void clear_masklist(masklist *m)
  1798. {
  1799. masklist *temp;
  1800. for (; m; m = temp) {
  1801. temp = m->next;
  1802. if (m->mask)
  1803. nfree(m->mask);
  1804. if (m->who)
  1805. nfree(m->who);
  1806. nfree(m);
  1807. }
  1808. }
  1809. /* Clear out channel data from memory.
  1810. */
  1811. static void clear_channel(struct chanset_t *chan, int reset)
  1812. {
  1813. int flags = reset ? reset : CHAN_RESETALL;
  1814. memberlist *m, *m1;
  1815. if (flags & CHAN_RESETWHO) {
  1816. for (m = chan->channel.member; m; m = m1) {
  1817. m1 = m->next;
  1818. if (reset)
  1819. m->flags &= ~WHO_SYNCED;
  1820. else
  1821. nfree(m);
  1822. }
  1823. }
  1824. if (flags & CHAN_RESETBANS) {
  1825. clear_masklist(chan->channel.ban);
  1826. chan->channel.ban = NULL;
  1827. }
  1828. if (flags & CHAN_RESETEXEMPTS) {
  1829. clear_masklist(chan->channel.exempt);
  1830. chan->channel.exempt = NULL;
  1831. }
  1832. if (flags & CHAN_RESETINVITED) {
  1833. clear_masklist(chan->channel.invite);
  1834. chan->channel.invite = NULL;
  1835. }
  1836. if ((flags & CHAN_RESETTOPIC) && chan->channel.topic)
  1837. nfree(chan->channel.topic);
  1838. if (reset)
  1839. init_channel(chan, reset);
  1840. }
  1841. /* Create new channel and parse commands.
  1842. */
  1843. static int tcl_channel_add(Tcl_Interp *irp, char *newname, char *options)
  1844. {
  1845. int items;
  1846. int ret = TCL_OK;
  1847. int join = 0;
  1848. char buf[2048], buf2[256];
  1849. EGG_CONST char **item;
  1850. struct chanset_t *chan;
  1851. if (!newname || !newname[0] || (strchr(CHANMETA, newname[0]) == NULL)) {
  1852. if (irp)
  1853. Tcl_AppendResult(irp, "invalid channel prefix", NULL);
  1854. return TCL_ERROR;
  1855. }
  1856. if (strchr(newname, ',') != NULL) {
  1857. if (irp)
  1858. Tcl_AppendResult(irp, "invalid channel name", NULL);
  1859. return TCL_ERROR;
  1860. }
  1861. convert_element(glob_chanmode, buf2);
  1862. simple_sprintf(buf, "chanmode %s ", buf2);
  1863. strncat(buf, glob_chanset, 2047 - strlen(buf));
  1864. strncat(buf, options, 2047 - strlen(buf));
  1865. buf[2047] = 0;
  1866. if (Tcl_SplitList(NULL, buf, &items, &item) != TCL_OK)
  1867. return TCL_ERROR;
  1868. if ((chan = findchan_by_dname(newname))) {
  1869. /* Already existing channel, maybe a reload of the channel file */
  1870. chan->status &= ~CHAN_FLAGGED; /* don't delete me! :) */
  1871. } else {
  1872. chan = nmalloc(sizeof *chan);
  1873. /* Hells bells, why set *every* variable to 0 when we have bzero? */
  1874. egg_bzero(chan, sizeof(struct chanset_t));
  1875. chan->limit_prot = 0;
  1876. chan->limit = 0;
  1877. chan->flood_pub_thr = gfld_chan_thr;
  1878. chan->flood_pub_time = gfld_chan_time;
  1879. chan->flood_ctcp_thr = gfld_ctcp_thr;
  1880. chan->flood_ctcp_time = gfld_ctcp_time;
  1881. chan->flood_join_thr = gfld_join_thr;
  1882. chan->flood_join_time = gfld_join_time;
  1883. chan->flood_deop_thr = gfld_deop_thr;
  1884. chan->flood_deop_time = gfld_deop_time;
  1885. chan->flood_kick_thr = gfld_kick_thr;
  1886. chan->flood_kick_time = gfld_kick_time;
  1887. chan->flood_nick_thr = gfld_nick_thr;
  1888. chan->flood_nick_time = gfld_nick_time;
  1889. chan->stopnethack_mode = global_stopnethack_mode;
  1890. chan->revenge_mode = global_revenge_mode;
  1891. chan->ban_type = global_ban_type;
  1892. chan->ban_time = global_ban_time;
  1893. chan->exempt_time = global_exempt_time;
  1894. chan->invite_time = global_invite_time;
  1895. chan->idle_kick = global_idle_kick;
  1896. chan->aop_min = global_aop_min;
  1897. chan->aop_max = global_aop_max;
  1898. /* We _only_ put the dname (display name) in here so as not to confuse
  1899. * any code later on. chan->name gets updated with the channel name as
  1900. * the server knows it, when we join the channel. <cybah>
  1901. */
  1902. strncpy(chan->dname, newname, 81);
  1903. chan->dname[80] = 0;
  1904. /* Initialize chan->channel info */
  1905. init_channel(chan, 0);
  1906. egg_list_append((struct list_type **) &chanset, (struct list_type *) chan);
  1907. /* Channel name is stored in xtra field for sharebot stuff */
  1908. join = 1;
  1909. }
  1910. /* If chan_hack is set, we're loading the userfile. Ignore errors while
  1911. * reading userfile and just return TCL_OK. This is for compatability
  1912. * if a user goes back to an eggdrop that no-longer supports certain
  1913. * (channel) options.
  1914. */
  1915. if ((tcl_channel_modify(irp, chan, items, (char **) item) != TCL_OK) &&
  1916. !chan_hack) {
  1917. ret = TCL_ERROR;
  1918. }
  1919. Tcl_Free((char *) item);
  1920. if (join && !channel_inactive(chan) && module_find("irc", 0, 0)) {
  1921. if (chan->key_prot[0])
  1922. dprintf(DP_SERVER, "JOIN %s %s\n", chan->dname, chan->key_prot);
  1923. else
  1924. dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
  1925. }
  1926. return ret;
  1927. }
  1928. static int tcl_setudef STDVAR
  1929. {
  1930. int type;
  1931. BADARGS(3, 3, " type name");
  1932. if (!egg_strcasecmp(argv[1], "flag"))
  1933. type = UDEF_FLAG;
  1934. else if (!egg_strcasecmp(argv[1], "int"))
  1935. type = UDEF_INT;
  1936. else if (!egg_strcasecmp(argv[1], "str"))
  1937. type = UDEF_STR;
  1938. else {
  1939. Tcl_AppendResult(irp, "invalid type. Must be one of: flag, int, str",
  1940. NULL);
  1941. return TCL_ERROR;
  1942. }
  1943. initudef(type, argv[2], 1);
  1944. return TCL_OK;
  1945. }
  1946. static int tcl_renudef STDVAR
  1947. {
  1948. struct udef_struct *ul;
  1949. int type, found = 0;
  1950. BADARGS(4, 4, " type oldname newname");
  1951. if (!egg_strcasecmp(argv[1], "flag"))
  1952. type = UDEF_FLAG;
  1953. else if (!egg_strcasecmp(argv[1], "int"))
  1954. type = UDEF_INT;
  1955. else if (!egg_strcasecmp(argv[1], "str"))
  1956. type = UDEF_STR;
  1957. else {
  1958. Tcl_AppendResult(irp, "invalid type. Must be one of: flag, int, str",
  1959. NULL);
  1960. return TCL_ERROR;
  1961. }
  1962. for (ul = udef; ul; ul = ul->next) {
  1963. if (ul->type == type && !egg_strcasecmp(ul->name, argv[2])) {
  1964. nfree(ul->name);
  1965. ul->name = nmalloc(strlen(argv[3]) + 1);
  1966. strcpy(ul->name, argv[3]);
  1967. found = 1;
  1968. }
  1969. }
  1970. if (!found) {
  1971. Tcl_AppendResult(irp, "not found", NULL);
  1972. return TCL_ERROR;
  1973. } else
  1974. return TCL_OK;
  1975. }
  1976. static int tcl_deludef STDVAR
  1977. {
  1978. struct udef_struct *ul, *ull;
  1979. int type, found = 0;
  1980. BADARGS(3, 3, " type name");
  1981. if (!egg_strcasecmp(argv[1], "flag"))
  1982. type = UDEF_FLAG;
  1983. else if (!egg_strcasecmp(argv[1], "int"))
  1984. type = UDEF_INT;
  1985. else if (!egg_strcasecmp(argv[1], "str"))
  1986. type = UDEF_STR;
  1987. else {
  1988. Tcl_AppendResult(irp, "invalid type. Must be one of: flag, int, str",
  1989. NULL);
  1990. return TCL_ERROR;
  1991. }
  1992. for (ul = udef; ul; ul = ul->next) {
  1993. ull = ul->next;
  1994. if (!ull)
  1995. break;
  1996. if (ull->type == type && !egg_strcasecmp(ull->name, argv[2])) {
  1997. ul->next = ull->next;
  1998. nfree(ull->name);
  1999. free_udef_chans(ull->values, ull->type);
  2000. nfree(ull);
  2001. found = 1;
  2002. }
  2003. }
  2004. if (udef) {
  2005. if (udef->type == type && !egg_strcasecmp(udef->name, argv[2])) {
  2006. ul = udef->next;
  2007. nfree(udef->name);
  2008. free_udef_chans(udef->values, udef->type);
  2009. nfree(udef);
  2010. udef = ul;
  2011. found = 1;
  2012. }
  2013. }
  2014. if (!found) {
  2015. Tcl_AppendResult(irp, "not found", NULL);
  2016. return TCL_ERROR;
  2017. } else
  2018. return TCL_OK;
  2019. }
  2020. static int tcl_getudefs STDVAR
  2021. {
  2022. struct udef_struct *ul;
  2023. int type = 0, count = 0;
  2024. BADARGS(1, 2, " ?type?");
  2025. if (argc > 1) {
  2026. if (!egg_strcasecmp(argv[1], "flag"))
  2027. type = UDEF_FLAG;
  2028. else if (!egg_strcasecmp(argv[1], "int"))
  2029. type = UDEF_INT;
  2030. else if (!egg_strcasecmp(argv[1], "str"))
  2031. type = UDEF_STR;
  2032. else {
  2033. Tcl_AppendResult(irp, "invalid type. Valid types are: flag, int, str",
  2034. NULL);
  2035. return TCL_ERROR;
  2036. }
  2037. }
  2038. for (ul = udef; ul; ul = ul->next)
  2039. if (!type || (ul->type == type)) {
  2040. Tcl_AppendElement(irp, ul->name);
  2041. count++;
  2042. }
  2043. return TCL_OK;
  2044. }
  2045. static int tcl_chansettype STDVAR
  2046. {
  2047. struct udef_struct *ul;
  2048. BADARGS(2, 2, " setting");
  2049. /* String values first */
  2050. if (!strcmp(argv[1], "chanmode") ||
  2051. !strcmp(argv[1], "need-op") ||
  2052. !strcmp(argv[1], "need-invite") ||
  2053. !strcmp(argv[1], "need-key") ||
  2054. !strcmp(argv[1], "need-unban") ||
  2055. !strcmp(argv[1], "need-limit")) {
  2056. Tcl_AppendResult(irp, "str", NULL);
  2057. /* Couplets */
  2058. } else if (!strcmp(argv[1], "flood-chan") ||
  2059. !strcmp(argv[1], "flood-ctcp") ||
  2060. !strcmp(argv[1], "flood-join") ||
  2061. !strcmp(argv[1], "flood-kick") ||
  2062. !strcmp(argv[1], "flood-deop") ||
  2063. !strcmp(argv[1], "flood-nick") ||
  2064. !strcmp(argv[1], "flood-nick") ||
  2065. !strcmp(argv[1], "aop-delay")) {
  2066. Tcl_AppendResult(irp, "pair", NULL);
  2067. /* Integers now */
  2068. } else if (!strcmp(argv[1], "idle-kick") ||
  2069. !strcmp(argv[1], "stopnethack-mode") ||
  2070. !strcmp(argv[1], "revenge-mode") ||
  2071. !strcmp(argv[1], "ban-type") ||
  2072. !strcmp(argv[1], "ban-time") ||
  2073. !strcmp(argv[1], "exempt-time") ||
  2074. !strcmp(argv[1], "invite-time")) {
  2075. Tcl_AppendResult(irp, "int", NULL);
  2076. /* Last, but not least - flags */
  2077. } else if (!strcmp(argv[1], "enforcebans") ||
  2078. !strcmp(argv[1], "dynamicbans") ||
  2079. !strcmp(argv[1], "userbans") ||
  2080. !strcmp(argv[1], "autoop") ||
  2081. !strcmp(argv[1], "autohalfop") ||
  2082. !strcmp(argv[1], "bitch") ||
  2083. !strcmp(argv[1], "greet") ||
  2084. !strcmp(argv[1], "protectops") ||
  2085. !strcmp(argv[1], "protecthalfops") ||
  2086. !strcmp(argv[1], "protectfriends") ||
  2087. !strcmp(argv[1], "dontkickops") ||
  2088. !strcmp(argv[1], "inactive") ||
  2089. !strcmp(argv[1], "statuslog") ||
  2090. !strcmp(argv[1], "revenge") ||
  2091. !strcmp(argv[1], "revengebot") ||
  2092. !strcmp(argv[1], "secret") ||
  2093. !strcmp(argv[1], "shared") ||
  2094. !strcmp(argv[1], "autovoice") ||
  2095. !strcmp(argv[1], "cycle") ||
  2096. !strcmp(argv[1], "seen") ||
  2097. !strcmp(argv[1], "nodesynch") ||
  2098. !strcmp(argv[1], "static") ||
  2099. !strcmp(argv[1], "dynamicexempts") ||
  2100. !strcmp(argv[1], "userexempts") ||
  2101. !strcmp(argv[1], "dynamicinvites") ||
  2102. !strcmp(argv[1], "userinvites")) {
  2103. Tcl_AppendResult(irp, "flag", NULL);
  2104. } else {
  2105. /* Must be a UDEF. */
  2106. for (ul = udef; ul && ul->name; ul = ul->next) {
  2107. if (!strcmp(argv[1], ul->name))
  2108. break;
  2109. }
  2110. if (!ul || !ul->name) {
  2111. Tcl_AppendResult(irp, "unknown channel setting.", NULL);
  2112. return TCL_ERROR;
  2113. }
  2114. if (ul->type == UDEF_STR)
  2115. Tcl_AppendResult(irp, "str", NULL);
  2116. else if (ul->type == UDEF_INT)
  2117. Tcl_AppendResult(irp, "int", NULL);
  2118. else if (ul->type == UDEF_FLAG)
  2119. Tcl_AppendResult(irp, "flag", NULL);
  2120. else
  2121. /* won't happen unless some day we create
  2122. * a new type and forget to add it here
  2123. */
  2124. Tcl_AppendResult(irp, "unknown", NULL);
  2125. }
  2126. return TCL_OK;
  2127. }
  2128. static tcl_cmds channels_cmds[] = {
  2129. {"killban", tcl_killban},
  2130. {"killchanban", tcl_killchanban},
  2131. {"isbansticky", tcl_isbansticky},
  2132. {"isban", tcl_isban},
  2133. {"ispermban", tcl_ispermban},
  2134. {"matchban", tcl_matchban},
  2135. {"newchanban", tcl_newchanban},
  2136. {"newban", tcl_newban},
  2137. {"killexempt", tcl_killexempt},
  2138. {"killchanexempt", tcl_killchanexempt},
  2139. {"isexemptsticky", tcl_isexemptsticky},
  2140. {"isexempt", tcl_isexempt},
  2141. {"ispermexempt", tcl_ispermexempt},
  2142. {"matchexempt", tcl_matchexempt},
  2143. {"newchanexempt", tcl_newchanexempt},
  2144. {"newexempt", tcl_newexempt},
  2145. {"killinvite", tcl_killinvite},
  2146. {"killchaninvite", tcl_killchaninvite},
  2147. {"isinvitesticky", tcl_isinvitesticky},
  2148. {"isinvite", tcl_isinvite},
  2149. {"isperminvite", tcl_isperminvite},
  2150. {"matchinvite", tcl_matchinvite},
  2151. {"newchaninvite", tcl_newchaninvite},
  2152. {"newinvite", tcl_newinvite},
  2153. {"channel", tcl_channel},
  2154. {"channels", tcl_channels},
  2155. {"exemptlist", tcl_exemptlist},
  2156. {"invitelist", tcl_invitelist},
  2157. {"banlist", tcl_banlist},
  2158. {"savechannels", tcl_savechannels},
  2159. {"loadchannels", tcl_loadchannels},
  2160. {"validchan", tcl_validchan},
  2161. {"isdynamic", tcl_isdynamic},
  2162. {"getchaninfo", tcl_getchaninfo},
  2163. {"setchaninfo", tcl_setchaninfo},
  2164. {"setlaston", tcl_setlaston},
  2165. {"addchanrec", tcl_addchanrec},
  2166. {"delchanrec", tcl_delchanrec},
  2167. {"stick", tcl_stick},
  2168. {"unstick", tcl_stick},
  2169. {"stickban", tcl_stick},
  2170. {"unstickban", tcl_stick},
  2171. {"stickinvite", tcl_stickinvite},
  2172. {"unstickinvite", tcl_stickinvite},
  2173. {"stickexempt", tcl_stickexempt},
  2174. {"unstickexempt", tcl_stickexempt},
  2175. {"setudef", tcl_setudef},
  2176. {"renudef", tcl_renudef},
  2177. {"deludef", tcl_deludef},
  2178. {"getudefs", tcl_getudefs},
  2179. {"chansettype", tcl_chansettype},
  2180. {"haschanrec", tcl_haschanrec},
  2181. {NULL, NULL}
  2182. };