channels.c 23 KB

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