channels.c 22 KB

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