channels.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2014 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. * channels.c -- part of channels.mod
  22. * support for channels within the bot
  23. *
  24. */
  25. #define MAKING_CHANNELS
  26. #include "src/common.h"
  27. #include "src/mod/share.mod/share.h"
  28. #include "src/mod/irc.mod/irc.h"
  29. #include "src/mod/server.mod/server.h"
  30. #include "src/chanprog.h"
  31. #include "src/egg_timer.h"
  32. #include "src/misc.h"
  33. #include "src/main.h"
  34. #include "src/color.h"
  35. #include "src/userrec.h"
  36. #include "src/users.h"
  37. #include "src/set.h"
  38. #include "src/rfc1459.h"
  39. #include "src/match.h"
  40. #include "src/settings.h"
  41. #include "src/tandem.h"
  42. #include "src/botnet.h"
  43. #include "src/botmsg.h"
  44. #include "src/net.h"
  45. #include "src/binds.h"
  46. #include "src/cmds.h"
  47. #include <bdlib/src/String.h>
  48. #include <sys/stat.h>
  49. static bool use_info = 1;
  50. static char glob_chanmode[64] = "nt"; /* Default chanmode (drummer,990731) */
  51. static interval_t global_ban_time;
  52. static interval_t global_exempt_time;
  53. static interval_t global_invite_time;
  54. static char *lastdeletedmask = NULL;
  55. static int killed_bots = 0;
  56. #include "channels.h"
  57. #include "cmdschan.c"
  58. #include "chanmisc.c"
  59. #include "userchan.c"
  60. /* This will close channels if the HUB:leaf count is skewed from config setting */
  61. static void
  62. check_should_close()
  63. {
  64. int H = close_threshold.count, L = close_threshold.time;
  65. if ((H <= 0) || (L <= 0))
  66. return;
  67. int hc = 1, lc = 0;
  68. struct userrec *u = NULL;
  69. for (tand_t *bot = tandbot; bot; bot = bot->next) {
  70. if ((u = get_user_by_handle(userlist, bot->bot))) {
  71. if (bot_hublevel(u) < 999)
  72. hc++;
  73. else
  74. lc++;
  75. }
  76. }
  77. if ((hc >= H) && (lc <= L)) {
  78. for (struct chanset_t *chan = chanset; chan; chan = chan->next) {
  79. if (!channel_closed(chan)) {
  80. do_chanset(NULL, chan, "+closed chanmode +stni", DO_LOCAL | DO_NET);
  81. #ifdef G_BACKUP
  82. chan->channel.backup_time = now + 30;
  83. #endif /* G_BACKUP */
  84. }
  85. }
  86. }
  87. }
  88. static void got_cset(char *botnick, char *code, char *par)
  89. {
  90. if (!par || !par[0])
  91. return;
  92. bool all = 0, isdefault = 0;
  93. char *chname = NULL;
  94. struct chanset_t *chan = NULL;
  95. if (par[0] == '*' && par[1] == ' ') {
  96. all = 1;
  97. newsplit(&par);
  98. } else {
  99. chname = newsplit(&par);
  100. if (!strcasecmp(chname, "default"))
  101. isdefault = 1;
  102. else if (!strchr(CHANMETA, chname[0])) {
  103. putlog(LOG_ERROR, "*", "Got bad cset: bot: %s code: %s par: %s %s", botnick, code, chname, par);
  104. return;
  105. }
  106. if (isdefault)
  107. chan = chanset_default;
  108. else if (!(chan = findchan_by_dname(chname)))
  109. return;
  110. }
  111. if (all)
  112. chan = NULL;
  113. do_chanset(NULL, chan, par, DO_LOCAL);
  114. }
  115. /* returns 1 if botn is in bots */
  116. static int
  117. parsebots(char *bots, char *botn) {
  118. if (!strcmp(bots, "*")) {
  119. return 1;
  120. } else {
  121. char *list = strdup(bots), *bot = strtok(list, ",");
  122. while(bot && *bot) {
  123. if (!strcasecmp(bot, botn))
  124. return 1;
  125. bot = strtok((char*) NULL, ",");
  126. }
  127. free(list);
  128. }
  129. return 0;
  130. }
  131. static void got_cpart(char *botnick, char *code, char *par)
  132. {
  133. if (!par[0])
  134. return;
  135. char *chname = newsplit(&par);
  136. struct chanset_t *chan = NULL;
  137. if (!(chan = findchan_by_dname(chname)))
  138. return;
  139. char *bots = newsplit(&par);
  140. int match = 0;
  141. /* if bots is '*' just remove_channel */
  142. if (!strcmp(bots, "*"))
  143. match = 0;
  144. else
  145. match = parsebots(bots, conf.bot->nick);
  146. if (match)
  147. do_chanset(NULL, chan, "+inactive", DO_LOCAL);
  148. else
  149. remove_channel(chan);
  150. if (conf.bot->hub)
  151. write_userfile(-1);
  152. }
  153. void rcmd_chans(char *fbot, char *fhand, char *fidx) {
  154. if (conf.bot->hub)
  155. return;
  156. struct chanset_t *chan = NULL;
  157. char buf[1024] = "", reply[1024] = "";
  158. if (server_online) {
  159. for (chan = chanset; chan; chan = chan->next) {
  160. if (!channel_active(chan) && (shouldjoin(chan) || chan->channel.jointime)) {
  161. if (buf[0])
  162. strlcat(buf, " ", sizeof(buf));
  163. strlcat(buf, chan->dname, sizeof(buf));
  164. }
  165. }
  166. if (buf[0])
  167. simple_snprintf(reply, sizeof(reply), "[%s] I am not in: %s", cursrvname, buf);
  168. } else
  169. simple_snprintf(reply, sizeof(reply), "I am not online.");
  170. if (reply[0])
  171. botnet_send_cmdreply(conf.bot->nick, fbot, fhand, fidx, reply);
  172. }
  173. static void got_cjoin(char *botnick, char *code, char *par)
  174. {
  175. if (!par[0])
  176. return;
  177. char *chname = newsplit(&par), *options = NULL;
  178. struct chanset_t *chan = findchan_by_dname(chname);
  179. int match = 0;
  180. if (conf.bot->hub) {
  181. newsplit(&par); /* hubs ignore the botmatch param */
  182. options = par;
  183. } else {
  184. /* ALL hubs should add the channel, leaf should check the list for a match */
  185. bool inactive = 0;
  186. char *bots = newsplit(&par);
  187. match = parsebots(bots, conf.bot->nick);
  188. if (strstr(par, "+inactive"))
  189. inactive = 1;
  190. if (chan && !match)
  191. return;
  192. if (!match) {
  193. size_t size = strlen(par) + 12 + 1;
  194. options = (char *) my_calloc(1, size);
  195. simple_snprintf(options, size, "%s +inactive", par);
  196. } else if (match && chan && !shouldjoin(chan)) {
  197. if (!inactive)
  198. do_chanset(NULL, chan, "-inactive", DO_LOCAL);
  199. return;
  200. } else
  201. options = par;
  202. }
  203. if (chan)
  204. return;
  205. sdprintf("OPTIONS: %s", options);
  206. char result[RESULT_LEN] = "";
  207. if (channel_add(result, chname, options) == ERROR) /* drummer */
  208. putlog(LOG_BOTS, "@", "Invalid channel or channel options from %s for %s: %s", botnick, chname, result);
  209. if (conf.bot->hub)
  210. write_userfile(-1);
  211. if (!match && !conf.bot->hub)
  212. free(options);
  213. }
  214. static void got_cycle(char *botnick, char *code, char *par)
  215. {
  216. if (!par[0])
  217. return;
  218. char *chname = newsplit(&par);
  219. struct chanset_t *chan = NULL;
  220. if (!(chan = findchan_by_dname(chname)))
  221. return;
  222. interval_t delay = 10;
  223. if (par[0])
  224. delay = atoi(newsplit(&par));
  225. do_chanset(NULL, chan, "+inactive", DO_LOCAL);
  226. dprintf(DP_SERVER, "PART %s\n", chan->name);
  227. chan->channel.jointime = ((now + delay) - server_lag); /* rejoin in 10 seconds */
  228. }
  229. static void got_down(char *botnick, char *code, char *par)
  230. {
  231. if (!par[0])
  232. return;
  233. char *chname = newsplit(&par);
  234. struct chanset_t *chan = NULL;
  235. if (!(chan = findchan_by_dname(chname)))
  236. return;
  237. chan->channel.no_op = (now + 10);
  238. add_mode(chan, '-', 'o', botname);
  239. }
  240. void got_kl(char *botnick, char *code, char *par)
  241. {
  242. killed_bots++;
  243. if (kill_threshold && (killed_bots == kill_threshold)) {
  244. for (struct chanset_t *ch = chanset; ch; ch = ch->next)
  245. do_chanset(NULL, ch, "+closed +bitch +backup", DO_LOCAL | DO_NET);
  246. /* FIXME: we should randomize nick here ... */
  247. }
  248. }
  249. static int
  250. check_slowjoinpart(struct chanset_t *chan)
  251. {
  252. /* slowpart */
  253. if (chan->channel.parttime && (chan->channel.parttime < now)) {
  254. chan->channel.parttime = 0;
  255. dprintf(DP_MODE, "PART %s\n", chan->name);
  256. if (chan) /* this should NOT be necesary, but some unforseen bug requires it.. */
  257. remove_channel(chan);
  258. return 1; /* if we keep looping, we'll segfault. */
  259. /* slowjoin */
  260. } else if ((chan->channel.jointime) && (chan->channel.jointime < now)) {
  261. chan->status &= ~CHAN_INACTIVE;
  262. chan->channel.jointime = 0;
  263. if (shouldjoin(chan))
  264. join_chan(chan);
  265. } else if (channel_closed(chan)) {
  266. enforce_closed(chan);
  267. }
  268. return 0;
  269. }
  270. static void
  271. check_limitraise(struct chanset_t *chan) {
  272. /* only check every other time for now */
  273. chan->checklimit++;
  274. if (chan->checklimit == 2) {
  275. chan->checklimit = 0;
  276. if (chan->limitraise && dolimit(chan))
  277. raise_limit(chan);
  278. }
  279. }
  280. static void
  281. channels_timers()
  282. {
  283. static int cnt = 0;
  284. struct chanset_t *chan_n = NULL, *chan = NULL;
  285. bool reset = 0;
  286. cnt += 10; /* function is called every 10 seconds */
  287. for (chan = chanset; chan; chan = chan_n) {
  288. chan_n = chan->next;
  289. if ((cnt % 10) == 0) {
  290. /* 10 seconds */
  291. if (!conf.bot->hub && check_slowjoinpart(chan)) /* if 1 is returned, chan was removed. */
  292. continue;
  293. }
  294. if ((cnt % 60) == 0) {
  295. /* 60 seconds */
  296. reset = 1;
  297. if (!conf.bot->hub)
  298. check_limitraise(chan);
  299. }
  300. }
  301. if (reset)
  302. cnt = 0;
  303. }
  304. static void got_sj(int idx, char *code, char *par)
  305. {
  306. struct chanset_t *chan = findchan_by_dname(newsplit(&par));
  307. if (chan) {
  308. if (conf.bot->hub) {
  309. chan->status &= ~CHAN_INACTIVE;
  310. write_userfile(-1);
  311. } else
  312. chan->channel.jointime = ((atoi(par) + now) - server_lag);
  313. }
  314. }
  315. static void got_sp(int idx, char *code, char *par)
  316. {
  317. struct chanset_t *chan = findchan_by_dname(newsplit(&par));
  318. if (chan) {
  319. if (conf.bot->hub) {
  320. remove_channel(chan);
  321. write_userfile(-1);
  322. } else
  323. chan->channel.parttime = ((atoi(par) + now) - server_lag);
  324. }
  325. }
  326. #ifdef no
  327. /* got_jn
  328. * We get this when a bot is opped in a +take chan
  329. * we are to set -inactive, jointime = 0, and join.
  330. */
  331. static void got_jn(int idx, char *code, char *par)
  332. {
  333. char *chname = newsplit(&par);
  334. if (!chname || !chname[0])
  335. return;
  336. struct chanset_t *chan = NULL;
  337. if (!(chan = findchan_by_dname(chname))) return;
  338. if (chan->channel.jointime && channel_inactive(chan)) {
  339. chan->status &= ~CHAN_INACTIVE;
  340. chan->channel.jointime = 0;
  341. if (!conf.bot->hub && shouldjoin(chan))
  342. join_chan(chan);
  343. }
  344. }
  345. #endif
  346. static void set_mode_protect(struct chanset_t *chan, char *set)
  347. {
  348. int i, pos = 1;
  349. char *s = NULL, *s1 = NULL;
  350. /* Clear old modes */
  351. chan->mode_mns_prot = chan->mode_pls_prot = 0;
  352. chan->limit_prot = 0;
  353. chan->key_prot[0] = 0;
  354. for (s = newsplit(&set); *s; s++) {
  355. i = 0;
  356. switch (*s) {
  357. case '+':
  358. pos = 1;
  359. break;
  360. case '-':
  361. pos = 0;
  362. break;
  363. case 'i':
  364. i = CHANINV;
  365. break;
  366. case 'p':
  367. i = CHANPRIV;
  368. break;
  369. case 's':
  370. i = CHANSEC;
  371. break;
  372. case 'm':
  373. i = CHANMODER;
  374. break;
  375. case 'c':
  376. i = CHANNOCLR;
  377. break;
  378. case 'C':
  379. i = CHANNOCTCP;
  380. break;
  381. case 'R':
  382. i = CHANREGON;
  383. break;
  384. case 'M':
  385. i = CHANMODR;
  386. break;
  387. case 'r':
  388. i = CHANLONLY;
  389. break;
  390. case 't':
  391. i = CHANTOPIC;
  392. break;
  393. case 'n':
  394. i = CHANNOMSG;
  395. break;
  396. case 'a':
  397. i = CHANANON;
  398. break;
  399. case 'q':
  400. i = CHANQUIET;
  401. break;
  402. case 'l':
  403. i = CHANLIMIT;
  404. chan->limit_prot = 0;
  405. if (pos) {
  406. s1 = newsplit(&set);
  407. if (s1[0] && !chan->limitraise)
  408. chan->limit_prot = atoi(s1);
  409. }
  410. break;
  411. case 'k':
  412. i = CHANKEY;
  413. chan->key_prot[0] = 0;
  414. if (pos) {
  415. s1 = newsplit(&set);
  416. if (s1[0])
  417. strlcpy(chan->key_prot, s1, sizeof(chan->key_prot));
  418. }
  419. break;
  420. }
  421. if (i) {
  422. if (pos) {
  423. chan->mode_pls_prot |= i;
  424. chan->mode_mns_prot &= ~i;
  425. } else {
  426. chan->mode_pls_prot &= ~i;
  427. chan->mode_mns_prot |= i;
  428. }
  429. }
  430. }
  431. /* Prevents a +s-p +p-s flood (fixed by drummer) */
  432. if (chan->mode_pls_prot & CHANSEC)
  433. chan->mode_pls_prot &= ~CHANPRIV;
  434. if (chan->mode_mns_prot & CHANPRIV && chan->closed_private)
  435. chan->closed_private = 0;
  436. if (chan->mode_mns_prot & CHANINV && chan->closed_invite)
  437. chan->closed_invite = 0;
  438. if (chan->mode_mns_prot & CHANMODER && chan->voice_moderate)
  439. chan->voice_moderate = 0;
  440. }
  441. static void get_mode_protect(struct chanset_t *chan, char *s, size_t ssiz)
  442. {
  443. char *p = s, s1[121] = "";
  444. int tst;
  445. for (int i = 0; i < 2; i++) {
  446. if (i == 0) {
  447. tst = chan->mode_pls_prot;
  448. if ((tst) || (chan->limit_prot != 0) || (chan->key_prot[0]))
  449. *p++ = '+';
  450. if (chan->limit_prot != 0) {
  451. *p++ = 'l';
  452. simple_sprintf(&s1[strlen(s1)], "%d ", chan->limit_prot);
  453. }
  454. if (chan->key_prot[0]) {
  455. *p++ = 'k';
  456. simple_sprintf(&s1[strlen(s1)], "%s ", chan->key_prot);
  457. }
  458. } else {
  459. tst = chan->mode_mns_prot;
  460. if (tst)
  461. *p++ = '-';
  462. if (tst & CHANKEY)
  463. *p++ = 'k';
  464. if (tst & CHANLIMIT)
  465. *p++ = 'l';
  466. }
  467. if (tst & CHANINV)
  468. *p++ = 'i';
  469. if (tst & CHANPRIV)
  470. *p++ = 'p';
  471. if (tst & CHANSEC)
  472. *p++ = 's';
  473. if (tst & CHANMODER)
  474. *p++ = 'm';
  475. if (tst & CHANNOCLR)
  476. *p++ = 'c';
  477. if (tst & CHANNOCTCP)
  478. *p++ = 'C';
  479. if (tst & CHANREGON)
  480. *p++ = 'R';
  481. if (tst & CHANMODR)
  482. *p++ = 'M';
  483. if (tst & CHANLONLY)
  484. *p++ = 'r';
  485. if (tst & CHANTOPIC)
  486. *p++ = 't';
  487. if (tst & CHANNOMSG)
  488. *p++ = 'n';
  489. if (tst & CHANANON)
  490. *p++ = 'a';
  491. if (tst & CHANQUIET)
  492. *p++ = 'q';
  493. }
  494. *p = 0;
  495. if (s1[0]) {
  496. s1[strlen(s1) - 1] = 0;
  497. strlcat(s, " ", ssiz);
  498. strlcat(s, s1, ssiz);
  499. }
  500. }
  501. /* Returns true if this is one of the channel masks
  502. */
  503. bool ismodeline(masklist *m, const char *username)
  504. {
  505. for (; m && m->mask[0]; m = m->next)
  506. if (!rfc_casecmp(m->mask, username))
  507. return 1;
  508. return 0;
  509. }
  510. /* Returns true if user matches one of the masklist -- drummer
  511. */
  512. bool ismasked(masklist *m, const char *username)
  513. {
  514. for (; m && m->mask[0]; m = m->next)
  515. if (wild_match(m->mask, (char *) username))
  516. return 1;
  517. return 0;
  518. }
  519. /* Unlink chanset element from chanset list.
  520. */
  521. static inline bool chanset_unlink(struct chanset_t *chan)
  522. {
  523. struct chanset_t *c_old = NULL;
  524. for (struct chanset_t *c = chanset; c; c_old = c, c = c->next) {
  525. if (c == chan) {
  526. if (c_old)
  527. c_old->next = c->next;
  528. else
  529. chanset = c->next;
  530. return 1;
  531. }
  532. }
  533. return 0;
  534. }
  535. /* Completely removes a channel.
  536. *
  537. * This includes the removal of all channel-bans, -exempts and -invites, as
  538. * well as all user flags related to the channel.
  539. */
  540. void remove_channel(struct chanset_t *chan)
  541. {
  542. if (chan != chanset_default) {
  543. irc_log(chan, "Parting");
  544. /* Remove the channel from the list, so that noone can pull it
  545. away from under our feet during the check_part() call. */
  546. chanset_unlink(chan);
  547. /* Using chan->name is important here, especially for !chans <cybah> */
  548. if (!conf.bot->hub && shouldjoin(chan) && chan->name[0])
  549. dprintf(DP_SERVER, "PART %s\n", chan->name);
  550. clear_channel(chan, 0);
  551. noshare = 1;
  552. /* Remove channel-bans */
  553. while (chan->bans)
  554. u_delmask('b', chan, chan->bans->mask, 1);
  555. /* Remove channel-exempts */
  556. while (chan->exempts)
  557. u_delmask('e', chan, chan->exempts->mask, 1);
  558. /* Remove channel-invites */
  559. while (chan->invites)
  560. u_delmask('I', chan, chan->invites->mask, 1);
  561. /* Remove channel specific user flags */
  562. user_del_chan(chan->dname);
  563. noshare = 0;
  564. }
  565. free(chan->channel.key);
  566. if (chan->key)
  567. free(chan->key);
  568. if (chan->rmkey)
  569. free(chan->rmkey);
  570. if (chan->groups) {
  571. delete(chan->groups);
  572. }
  573. delete chan->bot_roles;
  574. delete chan->role_bots;
  575. delete chan->channel.floodtime;
  576. delete chan->channel.floodnum;
  577. free(chan);
  578. }
  579. /* Bind this to chon and *if* the users console channel == ***
  580. * then set it to a specific channel
  581. */
  582. static int channels_chon(char *handle, int idx)
  583. {
  584. struct flag_record fr = {FR_CHAN | FR_ANYWH | FR_GLOBAL, 0, 0, 0 };
  585. int find;
  586. bool found = 0;
  587. struct chanset_t *chan = chanset;
  588. if (dcc[idx].type == &DCC_CHAT) {
  589. if (!findchan_by_dname(dcc[idx].u.chat->con_chan) &&
  590. ((dcc[idx].u.chat->con_chan[0] != '*') ||
  591. (dcc[idx].u.chat->con_chan[1] != 0))) {
  592. get_user_flagrec(dcc[idx].user, &fr, NULL);
  593. if (glob_op(fr))
  594. found = 1;
  595. if (chan_owner(fr))
  596. find = USER_OWNER;
  597. else if (chan_master(fr))
  598. find = USER_MASTER;
  599. else
  600. find = USER_OP;
  601. fr.match = FR_CHAN;
  602. while (chan && !found) {
  603. get_user_flagrec(dcc[idx].user, &fr, chan->dname, chan);
  604. if (fr.chan & find)
  605. found = 1;
  606. else
  607. chan = chan->next;
  608. }
  609. if (!chan)
  610. chan = chanset;
  611. struct chat_info dummy;
  612. if (chan)
  613. strlcpy(dcc[idx].u.chat->con_chan, chan->dname, sizeof(dummy.con_chan));
  614. else
  615. strlcpy(dcc[idx].u.chat->con_chan, "*", 2);
  616. }
  617. }
  618. return 0;
  619. }
  620. static cmd_t my_chon[] =
  621. {
  622. {"*", "", (Function) channels_chon, "channels:chon", 0},
  623. {NULL, NULL, NULL, NULL, 0}
  624. };
  625. void channels_report(int idx, int details)
  626. {
  627. int i;
  628. char s[1024] = "", s2[100] = "";
  629. struct flag_record fr = {FR_CHAN | FR_GLOBAL, 0, 0, 0 };
  630. for (struct chanset_t *chan = chanset; chan; chan = chan->next) {
  631. if (idx != DP_STDOUT)
  632. get_user_flagrec(dcc[idx].user, &fr, chan->dname, chan);
  633. if (!privchan(fr, chan, PRIV_OP) && ((idx == DP_STDOUT) || glob_master(fr) || chan_master(fr))) {
  634. s[0] = 0;
  635. if (chan_bitch(chan))
  636. strlcat(s, "bitch, ", sizeof(s));
  637. if (s[0])
  638. s[strlen(s) - 2] = 0;
  639. if (!s[0])
  640. strlcpy(s, "lurking", sizeof(s));
  641. get_mode_protect(chan, s2, sizeof(s2));
  642. if (channel_closed(chan)) {
  643. if (chan->closed_invite)
  644. strlcat(s2, "i", sizeof(s2));
  645. if (chan->closed_private)
  646. strlcat(s2, "p", sizeof(s2));
  647. }
  648. if (channel_voice(chan) && chan->voice_moderate) {
  649. strlcat(s2, "m", sizeof(s2));
  650. }
  651. if (conf.bot->hub || shouldjoin(chan)) {
  652. if (channel_active(chan)) {
  653. /* If it's a !chan, we want to display it's unique name too <cybah> */
  654. if (chan->dname[0]=='!') {
  655. dprintf(idx, " %-20s: %2d member%s enforcing \"%s\" (%s), "
  656. "unique name %s\n", chan->dname, chan->channel.members,
  657. (chan->channel.members==1) ? "," : "s,", s2, s, chan->name);
  658. } else {
  659. dprintf(idx, " %-20s: %2d member%s enforcing \"%s\" (%s)\n",
  660. chan->dname, chan->channel.members,
  661. chan->channel.members == 1 ? "," : "s,", s2, s);
  662. }
  663. } else {
  664. if (!conf.bot->hub)
  665. dprintf(idx, " %-20s: (%s), enforcing \"%s\" (%s)\n", chan->dname,
  666. channel_pending(chan) ? "pending" : "not on channel", s2, s);
  667. else
  668. dprintf(idx, " %-20s: (%s), enforcing \"%s\" (%s)\n", chan->dname,
  669. "limbo", s2, s);
  670. }
  671. } else {
  672. dprintf(idx, " %-20s: channel is set +inactive\n",
  673. chan->dname);
  674. }
  675. if (details) {
  676. s[0] = 0;
  677. i = 0;
  678. i += my_strcpy(s + i, "dynamic ");
  679. if (channel_enforcebans(chan))
  680. i += my_strcpy(s + i, "enforcebans ");
  681. if (channel_dynamicbans(chan))
  682. i += my_strcpy(s + i, "dynamicbans ");
  683. if (!channel_nouserbans(chan))
  684. i += my_strcpy(s + i, "userbans ");
  685. if (channel_bitch(chan))
  686. i += my_strcpy(s + i, "bitch ");
  687. if (channel_secret(chan))
  688. i += my_strcpy(s + i, "secret ");
  689. if (channel_cycle(chan))
  690. i += my_strcpy(s + i, "cycle ");
  691. if (channel_dynamicexempts(chan))
  692. i += my_strcpy(s + i, "dynamicexempts ");
  693. if (!channel_nouserexempts(chan))
  694. i += my_strcpy(s + i, "userexempts ");
  695. if (channel_dynamicinvites(chan))
  696. i += my_strcpy(s + i, "dynamicinvites ");
  697. if (!channel_nouserinvites(chan))
  698. i += my_strcpy(s + i, "userinvites ");
  699. if (!shouldjoin(chan))
  700. i += my_strcpy(s + i, "inactive ");
  701. if (channel_nodesynch(chan))
  702. i += my_strcpy(s + i, "nodesynch ");
  703. if (channel_closed(chan))
  704. i += my_strcpy(s + i, "closed ");
  705. if (HAVE_TAKE && channel_take(chan))
  706. i += my_strcpy(s + i, "take ");
  707. if (channel_voice(chan))
  708. i += my_strcpy(s + i, "voice ");
  709. if (channel_autoop(chan))
  710. i += my_strcpy(s + i, "autoop ");
  711. if (channel_rbl(chan))
  712. i += my_strcpy(s + i, "rbl ");
  713. if (channel_voicebitch(chan))
  714. i += my_strcpy(s + i, "voicebitch ");
  715. if (channel_protect(chan))
  716. i += my_strcpy(s + i, "protect ");
  717. /* Chanflag template
  718. * if (channel_temp(chan))
  719. * i += my_strcpy(s + i, "temp ");
  720. */
  721. if (channel_botbitch(chan))
  722. i += my_strcpy(s + i, "botbitch ");
  723. if (channel_backup(chan))
  724. i += my_strcpy(s + i, "backup ");
  725. if (channel_fastop(chan))
  726. i += my_strcpy(s + i, "fastop ");
  727. if (channel_privchan(chan))
  728. i += my_strcpy(s + i, "private ");
  729. dprintf(idx, " Options: %s\n", s);
  730. if (chan->limitraise)
  731. dprintf(idx, " Raising limit +%d every 2 minutes\n", chan->limitraise);
  732. dprintf(idx, " Bans last %d mins.\n", chan->ban_time);
  733. dprintf(idx, " Exemptions last %d mins.\n", chan->exempt_time);
  734. dprintf(idx, " Invitations last %d mins.\n", chan->invite_time);
  735. }
  736. }
  737. }
  738. }
  739. cmd_t channels_bot[] = {
  740. {"cjoin", "", (Function) got_cjoin, NULL, 0},
  741. {"cpart", "", (Function) got_cpart, NULL, 0},
  742. {"cset", "", (Function) got_cset, NULL, 0},
  743. {"cycle", "", (Function) got_cycle, NULL, LEAF},
  744. {"down", "", (Function) got_down, NULL, LEAF},
  745. {"kl", "", (Function) got_kl, NULL, 0},
  746. {"sj", "", (Function) got_sj, NULL, 0},
  747. {"sp", "", (Function) got_sp, NULL, 0},
  748. // {"jn", "", (Function) got_jn, NULL, 0},
  749. /*
  750. #ifdef HUB
  751. {"o1", "", (Function) got_o1, NULL, 0},
  752. {"kl", "", (Function) got_kl, NULL, 0},
  753. #endif
  754. {"ltp", "", (Function) got_locktopic, NULL, 0},
  755. */
  756. {NULL, NULL, NULL, NULL, 0}
  757. };
  758. void channels_init()
  759. {
  760. timer_create_secs(60, "check_expired_masks", (Function) check_expired_masks);
  761. if (conf.bot->hub) {
  762. timer_create_secs(30, "check_should_close", (Function) check_should_close);
  763. #ifdef G_BACKUP
  764. timer_create_secs(30, "check_should_backup", (Function) check_should_backup);
  765. #endif /* G_BACKUP */
  766. }
  767. timer_create_secs(10, "channels_timers", (Function) channels_timers);
  768. add_builtins("dcc", C_dcc_channels);
  769. add_builtins("bot", channels_bot);
  770. add_builtins("chon", my_chon);
  771. }