channels.c 23 KB

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