channels.c 23 KB

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