channels.c 24 KB

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