PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/src/mod/irc.mod/chan.c

https://github.com/eggheads/eggdrop-1.8
C | 2520 lines | 1998 code | 207 blank | 315 comment | 814 complexity | ab83eea5a5047790e94db76b5e59760c MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * chan.c -- part of irc.mod
  3. * almost everything to do with channel manipulation
  4. * telling channel status
  5. * 'who' response
  6. * user kickban, kick, op, deop
  7. * idle kicking
  8. *
  9. * $Id: chan.c,v 1.2 2010/10/24 13:22:40 pseudo Exp $
  10. */
  11. /*
  12. * Copyright (C) 1997 Robey Pointer
  13. * Copyright (C) 1999 - 2010 Eggheads Development Team
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * as published by the Free Software Foundation; either version 2
  18. * of the License, or (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, write to the Free Software
  27. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  28. */
  29. static time_t last_ctcp = (time_t) 0L;
  30. static int count_ctcp = 0;
  31. static time_t last_invtime = (time_t) 0L;
  32. static char last_invchan[300] = "";
  33. /* ID length for !channels.
  34. */
  35. #define CHANNEL_ID_LEN 5
  36. /* Returns a pointer to a new channel member structure.
  37. */
  38. static memberlist *newmember(struct chanset_t *chan)
  39. {
  40. memberlist *x;
  41. for (x = chan->channel.member; x && x->nick[0]; x = x->next);
  42. x->next = (memberlist *) channel_malloc(sizeof(memberlist));
  43. x->next->next = NULL;
  44. x->next->nick[0] = 0;
  45. x->next->split = 0L;
  46. x->next->last = 0L;
  47. x->next->delay = 0L;
  48. chan->channel.members++;
  49. return x;
  50. }
  51. /* Remove channel members for which no WHO reply was received */
  52. static inline void sync_members(struct chanset_t *chan)
  53. {
  54. memberlist *m, *next, *prev;
  55. for (m = chan->channel.member, prev = 0; m && m->nick[0]; m = next) {
  56. next = m->next;
  57. if (!chan_whosynced(m)) {
  58. if (prev)
  59. prev->next = next;
  60. else
  61. chan->channel.member = next;
  62. nfree(m);
  63. chan->channel.members--;
  64. } else
  65. prev = m;
  66. }
  67. }
  68. /* Always pass the channel dname (display name) to this function <cybah>
  69. */
  70. static void update_idle(char *chname, char *nick)
  71. {
  72. memberlist *m;
  73. struct chanset_t *chan;
  74. chan = findchan_by_dname(chname);
  75. if (chan) {
  76. m = ismember(chan, nick);
  77. if (m)
  78. m->last = now;
  79. }
  80. }
  81. /* Returns the current channel mode.
  82. */
  83. static char *getchanmode(struct chanset_t *chan)
  84. {
  85. static char s[121];
  86. int atr, i;
  87. s[0] = '+';
  88. i = 1;
  89. atr = chan->channel.mode;
  90. if (atr & CHANINV)
  91. s[i++] = 'i';
  92. if (atr & CHANPRIV)
  93. s[i++] = 'p';
  94. if (atr & CHANSEC)
  95. s[i++] = 's';
  96. if (atr & CHANMODER)
  97. s[i++] = 'm';
  98. if (atr & CHANNOCLR)
  99. s[i++] = 'c';
  100. if (atr & CHANNOCTCP)
  101. s[i++] = 'C';
  102. if (atr & CHANREGON)
  103. s[i++] = 'R';
  104. if (atr & CHANTOPIC)
  105. s[i++] = 't';
  106. if (atr & CHANMODREG)
  107. s[i++] = 'M';
  108. if (atr & CHANLONLY)
  109. s[i++] = 'r';
  110. if (atr & CHANDELJN)
  111. s[i++] = 'D';
  112. if (atr & CHANSTRIP)
  113. s[i++] = 'u';
  114. if (atr & CHANNONOTC)
  115. s[i++] = 'N';
  116. if (atr & CHANNOAMSG)
  117. s[i++] = 'T';
  118. if (atr & CHANINVIS)
  119. s[i++] = 'd';
  120. if (atr & CHANNOMSG)
  121. s[i++] = 'n';
  122. if (atr & CHANANON)
  123. s[i++] = 'a';
  124. if (atr & CHANKEY)
  125. s[i++] = 'k';
  126. if (chan->channel.maxmembers != 0)
  127. s[i++] = 'l';
  128. s[i] = 0;
  129. if (chan->channel.key[0])
  130. i += sprintf(s + i, " %s", chan->channel.key);
  131. if (chan->channel.maxmembers != 0)
  132. sprintf(s + i, " %d", chan->channel.maxmembers);
  133. return s;
  134. }
  135. static void check_exemptlist(struct chanset_t *chan, char *from)
  136. {
  137. masklist *e;
  138. int ok = 0;
  139. if (!use_exempts)
  140. return;
  141. for (e = chan->channel.exempt; e->mask[0]; e = e->next)
  142. if (match_addr(e->mask, from)) {
  143. add_mode(chan, '-', 'e', e->mask);
  144. ok = 1;
  145. }
  146. if (prevent_mixing && ok)
  147. flush_mode(chan, QUICK);
  148. }
  149. /* Check a channel and clean-out any more-specific matching masks.
  150. *
  151. * Moved all do_ban(), do_exempt() and do_invite() into this single function
  152. * as the code bloat is starting to get rediculous <cybah>
  153. */
  154. static void do_mask(struct chanset_t *chan, masklist *m, char *mask, char mode)
  155. {
  156. for (; m && m->mask[0]; m = m->next)
  157. if (cmp_masks(mask, m->mask) && rfc_casecmp(mask, m->mask))
  158. add_mode(chan, '-', mode, m->mask);
  159. add_mode(chan, '+', mode, mask);
  160. flush_mode(chan, QUICK);
  161. }
  162. /* This is a clone of detect_flood, but works for channel specificity now
  163. * and handles kick & deop as well.
  164. */
  165. static int detect_chan_flood(char *floodnick, char *floodhost, char *from,
  166. struct chanset_t *chan, int which, char *victim)
  167. {
  168. char h[UHOSTLEN], ftype[12], *p;
  169. struct userrec *u;
  170. memberlist *m;
  171. int thr = 0, lapse = 0;
  172. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  173. if (!chan || (which < 0) || (which >= FLOOD_CHAN_MAX))
  174. return 0;
  175. /* Okay, make sure i'm not flood-checking myself */
  176. if (match_my_nick(floodnick))
  177. return 0;
  178. /* My user@host (?) */
  179. if (!egg_strcasecmp(floodhost, botuserhost))
  180. return 0;
  181. m = ismember(chan, floodnick);
  182. /* Do not punish non-existant channel members and IRC services like
  183. * ChanServ
  184. */
  185. if (!m && (which != FLOOD_JOIN))
  186. return 0;
  187. get_user_flagrec(get_user_by_host(from), &fr, chan->dname);
  188. if (glob_bot(fr) || ((which == FLOOD_DEOP) && (glob_master(fr) ||
  189. chan_master(fr)) && (glob_friend(fr) || chan_friend(fr))) ||
  190. ((which == FLOOD_KICK) && (glob_master(fr) || chan_master(fr)) &&
  191. (glob_friend(fr) || chan_friend(fr))) || ((which != FLOOD_DEOP) &&
  192. (which != FLOOD_KICK) && (glob_friend(fr) || chan_friend(fr))) ||
  193. (channel_dontkickops(chan) && (chan_op(fr) || (glob_op(fr) &&
  194. !chan_deop(fr)))))
  195. return 0;
  196. /* Determine how many are necessary to make a flood. */
  197. switch (which) {
  198. case FLOOD_PRIVMSG:
  199. case FLOOD_NOTICE:
  200. thr = chan->flood_pub_thr;
  201. lapse = chan->flood_pub_time;
  202. strcpy(ftype, "pub");
  203. break;
  204. case FLOOD_CTCP:
  205. thr = chan->flood_ctcp_thr;
  206. lapse = chan->flood_ctcp_time;
  207. strcpy(ftype, "pub");
  208. break;
  209. case FLOOD_NICK:
  210. thr = chan->flood_nick_thr;
  211. lapse = chan->flood_nick_time;
  212. strcpy(ftype, "nick");
  213. break;
  214. case FLOOD_JOIN:
  215. thr = chan->flood_join_thr;
  216. lapse = chan->flood_join_time;
  217. strcpy(ftype, "join");
  218. break;
  219. case FLOOD_DEOP:
  220. thr = chan->flood_deop_thr;
  221. lapse = chan->flood_deop_time;
  222. strcpy(ftype, "deop");
  223. break;
  224. case FLOOD_KICK:
  225. thr = chan->flood_kick_thr;
  226. lapse = chan->flood_kick_time;
  227. strcpy(ftype, "kick");
  228. break;
  229. }
  230. if ((thr == 0) || (lapse == 0))
  231. return 0; /* no flood protection */
  232. if ((which == FLOOD_KICK) || (which == FLOOD_DEOP))
  233. p = floodnick;
  234. else {
  235. p = strchr(floodhost, '@');
  236. if (p) {
  237. p++;
  238. }
  239. if (!p)
  240. return 0;
  241. }
  242. if (rfc_casecmp(chan->floodwho[which], p)) { /* new */
  243. strncpy(chan->floodwho[which], p, 80);
  244. chan->floodwho[which][80] = 0;
  245. chan->floodtime[which] = now;
  246. chan->floodnum[which] = 1;
  247. return 0;
  248. }
  249. if (chan->floodtime[which] < now - lapse) {
  250. /* Flood timer expired, reset it */
  251. chan->floodtime[which] = now;
  252. chan->floodnum[which] = 1;
  253. return 0;
  254. }
  255. /* Deop'n the same person, sillyness ;) - so just ignore it */
  256. if (which == FLOOD_DEOP) {
  257. if (!rfc_casecmp(chan->deopd, victim))
  258. return 0;
  259. else
  260. strcpy(chan->deopd, victim);
  261. }
  262. chan->floodnum[which]++;
  263. if (chan->floodnum[which] >= thr) { /* FLOOD */
  264. /* Reset counters */
  265. chan->floodnum[which] = 0;
  266. chan->floodtime[which] = 0;
  267. chan->floodwho[which][0] = 0;
  268. if (which == FLOOD_DEOP)
  269. chan->deopd[0] = 0;
  270. u = get_user_by_host(from);
  271. if (check_tcl_flud(floodnick, floodhost, u, ftype, chan->dname))
  272. return 0;
  273. switch (which) {
  274. case FLOOD_PRIVMSG:
  275. case FLOOD_NOTICE:
  276. case FLOOD_CTCP:
  277. /* Flooding chan! either by public or notice */
  278. if (!chan_sentkick(m) &&
  279. (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) {
  280. putlog(LOG_MODES, chan->dname, IRC_FLOODKICK, floodnick);
  281. dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, floodnick, CHAN_FLOOD);
  282. m->flags |= SENTKICK;
  283. }
  284. return 1;
  285. case FLOOD_JOIN:
  286. case FLOOD_NICK:
  287. if (use_exempts && (u_match_mask(global_exempts, from) ||
  288. u_match_mask(chan->exempts, from)))
  289. return 1;
  290. simple_sprintf(h, "*!*@%s", p);
  291. if (!isbanned(chan, h) && (me_op(chan) || me_halfop(chan))) {
  292. check_exemptlist(chan, from);
  293. do_mask(chan, chan->channel.ban, h, 'b');
  294. }
  295. if ((u_match_mask(global_bans, from)) ||
  296. (u_match_mask(chan->bans, from)))
  297. return 1; /* Already banned */
  298. if (which == FLOOD_JOIN)
  299. putlog(LOG_MISC | LOG_JOIN, chan->dname, IRC_FLOODIGNORE3, p);
  300. else
  301. putlog(LOG_MISC | LOG_JOIN, chan->dname, IRC_FLOODIGNORE4, p);
  302. strcpy(ftype + 4, " flood");
  303. u_addban(chan, h, botnetnick, ftype, now + (60 * chan->ban_time), 0);
  304. if (!channel_enforcebans(chan) && (me_op(chan) || me_halfop(chan))) {
  305. char s[UHOSTLEN];
  306. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  307. sprintf(s, "%s!%s", m->nick, m->userhost);
  308. if (wild_match(h, s) && (m->joined >= chan->floodtime[which]) &&
  309. !chan_sentkick(m) && !match_my_nick(m->nick) && (me_op(chan) ||
  310. (me_halfop(chan) && !chan_hasop(m)))) {
  311. m->flags |= SENTKICK;
  312. if (which == FLOOD_JOIN)
  313. dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, m->nick,
  314. IRC_JOIN_FLOOD);
  315. else
  316. dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, m->nick,
  317. IRC_NICK_FLOOD);
  318. }
  319. }
  320. }
  321. return 1;
  322. case FLOOD_KICK:
  323. if ((me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) &&
  324. !chan_sentkick(m)) {
  325. putlog(LOG_MODES, chan->dname, "Kicking %s, for mass kick.", floodnick);
  326. dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, floodnick,
  327. IRC_MASSKICK);
  328. m->flags |= SENTKICK;
  329. }
  330. return 1;
  331. case FLOOD_DEOP:
  332. if ((me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) &&
  333. !chan_sentkick(m)) {
  334. putlog(LOG_MODES, chan->dname, CHAN_MASSDEOP, chan->dname, from);
  335. dprintf(DP_MODE, "KICK %s %s :%s\n",
  336. chan->name, floodnick, CHAN_MASSDEOP_KICK);
  337. m->flags |= SENTKICK;
  338. }
  339. return 1;
  340. }
  341. }
  342. return 0;
  343. }
  344. /* Given a [nick!]user@host, place a quick ban on them on a chan.
  345. */
  346. static char *quickban(struct chanset_t *chan, char *uhost)
  347. {
  348. static char s1[512];
  349. maskaddr(uhost, s1, chan->ban_type);
  350. do_mask(chan, chan->channel.ban, s1, 'b');
  351. return s1;
  352. }
  353. /* Kick any user (except friends/masters) with certain mask from channel
  354. * with a specified comment. Ernst 18/3/1998
  355. */
  356. static void kick_all(struct chanset_t *chan, char *hostmask, char *comment,
  357. int bantype)
  358. {
  359. memberlist *m;
  360. char kicknick[512], s[UHOSTLEN];
  361. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  362. int k, l, flushed;
  363. if (!me_op(chan) && !me_halfop(chan))
  364. return;
  365. k = 0;
  366. flushed = 0;
  367. kicknick[0] = 0;
  368. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  369. sprintf(s, "%s!%s", m->nick, m->userhost);
  370. get_user_flagrec(m->user ? m->user : get_user_by_host(s), &fr, chan->dname);
  371. if ((me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) &&
  372. match_addr(hostmask, s) && !chan_sentkick(m) &&
  373. !match_my_nick(m->nick) && !chan_issplit(m) &&
  374. !glob_friend(fr) && !chan_friend(fr) && !(use_exempts && ((bantype &&
  375. isexempted(chan, s)) || (u_match_mask(global_exempts, s) ||
  376. u_match_mask(chan->exempts, s)))) && !(channel_dontkickops(chan) &&
  377. (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))))) {
  378. if (!flushed) {
  379. /* We need to kick someone, flush eventual bans first */
  380. flush_mode(chan, QUICK);
  381. flushed += 1;
  382. }
  383. m->flags |= SENTKICK; /* Mark as pending kick */
  384. if (kicknick[0])
  385. strcat(kicknick, ",");
  386. strcat(kicknick, m->nick);
  387. k += 1;
  388. l = strlen(chan->name) + strlen(kicknick) + strlen(comment) + 5;
  389. if ((kick_method != 0 && k == kick_method) || (l > 480)) {
  390. dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, kicknick, comment);
  391. k = 0;
  392. kicknick[0] = 0;
  393. }
  394. }
  395. }
  396. if (k > 0)
  397. dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, kicknick, comment);
  398. }
  399. /* If any bans match this wildcard expression, refresh them on the channel.
  400. */
  401. static void refresh_ban_kick(struct chanset_t *chan, char *user, char *nick)
  402. {
  403. register maskrec *b;
  404. memberlist *m;
  405. int cycle;
  406. m = ismember(chan, nick);
  407. if (!m || chan_sentkick(m))
  408. return;
  409. /* Check global bans in first cycle and channel bans in second cycle. */
  410. for (cycle = 0; cycle < 2; cycle++) {
  411. for (b = cycle ? chan->bans : global_bans; b; b = b->next) {
  412. if (match_addr(b->mask, user)) {
  413. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  414. char c[512]; /* The ban comment. */
  415. char s[UHOSTLEN];
  416. sprintf(s, "%s!%s", m->nick, m->userhost);
  417. get_user_flagrec(m->user ? m->user : get_user_by_host(s), &fr,
  418. chan->dname);
  419. if (!glob_friend(fr) && !chan_friend(fr)) {
  420. add_mode(chan, '-', 'o', nick); /* Guess it can't hurt. */
  421. check_exemptlist(chan, user);
  422. do_mask(chan, chan->channel.ban, b->mask, 'b');
  423. b->lastactive = now;
  424. if (b->desc && b->desc[0] != '@')
  425. egg_snprintf(c, sizeof c, "%s %s", IRC_PREBANNED, b->desc);
  426. else
  427. c[0] = 0;
  428. kick_all(chan, b->mask, c[0] ? c : IRC_YOUREBANNED, 0);
  429. return; /* Drop out on 1st ban. */
  430. }
  431. }
  432. }
  433. }
  434. }
  435. /* This is a bit cumbersome at the moment, but it works... Any improvements
  436. * then feel free to have a go.. Jason
  437. */
  438. static void refresh_exempt(struct chanset_t *chan, char *user)
  439. {
  440. maskrec *e;
  441. masklist *b;
  442. int cycle;
  443. /* Check global exempts in first cycle and channel exempts in second cycle. */
  444. for (cycle = 0; cycle < 2; cycle++) {
  445. for (e = cycle ? chan->exempts : global_exempts; e; e = e->next) {
  446. if (mask_match(user, e->mask)) {
  447. for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
  448. if (mask_match(b->mask, user)) {
  449. if (e->lastactive < now - 60 && !isexempted(chan, e->mask)) {
  450. do_mask(chan, chan->channel.exempt, e->mask, 'e');
  451. e->lastactive = now;
  452. }
  453. }
  454. }
  455. }
  456. }
  457. }
  458. }
  459. static void refresh_invite(struct chanset_t *chan, char *user)
  460. {
  461. maskrec *i;
  462. int cycle;
  463. /* Check global invites in first cycle and channel invites in second cycle. */
  464. for (cycle = 0; cycle < 2; cycle++) {
  465. for (i = cycle ? chan->invites : global_invites; i; i = i->next) {
  466. if (match_addr(i->mask, user) &&
  467. ((i->flags & MASKREC_STICKY) || (chan->channel.mode & CHANINV))) {
  468. if (i->lastactive < now - 60 && !isinvited(chan, i->mask)) {
  469. do_mask(chan, chan->channel.invite, i->mask, 'I');
  470. i->lastactive = now;
  471. return;
  472. }
  473. }
  474. }
  475. }
  476. }
  477. /* Enforce all channel bans in a given channel. Ernst 18/3/1998
  478. */
  479. static void enforce_bans(struct chanset_t *chan)
  480. {
  481. char me[UHOSTLEN];
  482. masklist *b;
  483. if (HALFOP_CANTDOMODE('b'))
  484. return;
  485. simple_sprintf(me, "%s!%s", botname, botuserhost);
  486. /* Go through all bans, kicking the users. */
  487. for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
  488. if (!match_addr(b->mask, me))
  489. if (!isexempted(chan, b->mask))
  490. kick_all(chan, b->mask, IRC_YOUREBANNED, 1);
  491. }
  492. }
  493. /* Make sure that all who are 'banned' on the userlist are actually in fact
  494. * banned on the channel.
  495. *
  496. * Note: Since i was getting a ban list, i assume i'm chop.
  497. */
  498. static void recheck_bans(struct chanset_t *chan)
  499. {
  500. maskrec *u;
  501. int cycle;
  502. /* Check global bans in first cycle and channel bans in second cycle. */
  503. for (cycle = 0; cycle < 2; cycle++) {
  504. for (u = cycle ? chan->bans : global_bans; u; u = u->next)
  505. if (!isbanned(chan, u->mask) && (!channel_dynamicbans(chan) ||
  506. (u->flags & MASKREC_STICKY)))
  507. add_mode(chan, '+', 'b', u->mask);
  508. }
  509. }
  510. /* Make sure that all who are exempted on the userlist are actually in fact
  511. * exempted on the channel.
  512. *
  513. * Note: Since i was getting an excempt list, i assume i'm chop.
  514. */
  515. static void recheck_exempts(struct chanset_t *chan)
  516. {
  517. maskrec *e;
  518. masklist *b;
  519. int cycle;
  520. /* Check global exempts in first cycle and channel exempts in second cycle. */
  521. for (cycle = 0; cycle < 2; cycle++) {
  522. for (e = cycle ? chan->exempts : global_exempts; e; e = e->next) {
  523. if (!isexempted(chan, e->mask) &&
  524. (!channel_dynamicexempts(chan) || (e->flags & MASKREC_STICKY)))
  525. add_mode(chan, '+', 'e', e->mask);
  526. for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
  527. if (mask_match(b->mask, e->mask) &&
  528. !isexempted(chan, e->mask))
  529. add_mode(chan, '+', 'e', e->mask);
  530. /* do_mask(chan, chan->channel.exempt, e->mask, 'e'); */
  531. }
  532. }
  533. }
  534. }
  535. /* Make sure that all who are invited on the userlist are actually in fact
  536. * invited on the channel.
  537. *
  538. * Note: Since i was getting an invite list, i assume i'm chop.
  539. */
  540. static void recheck_invites(struct chanset_t *chan)
  541. {
  542. maskrec *ir;
  543. int cycle;
  544. /* Check global invites in first cycle and channel invites in second cycle. */
  545. for (cycle = 0; cycle < 2; cycle++) {
  546. for (ir = cycle ? chan->invites : global_invites; ir; ir = ir->next) {
  547. /* If invite isn't set and (channel is not dynamic invites and not invite
  548. * only) or invite is sticky.
  549. */
  550. if (!isinvited(chan, ir->mask) && ((!channel_dynamicinvites(chan) &&
  551. !(chan->channel.mode & CHANINV)) || ir->flags & MASKREC_STICKY))
  552. add_mode(chan, '+', 'I', ir->mask);
  553. /* do_mask(chan, chan->channel.invite, ir->mask, 'I'); */
  554. }
  555. }
  556. }
  557. /* Resets the masks on the channel.
  558. */
  559. static void resetmasks(struct chanset_t *chan, masklist *m, maskrec *mrec,
  560. maskrec *global_masks, char mode)
  561. {
  562. if (!me_op(chan) && (!me_halfop(chan) ||
  563. (strchr(NOHALFOPS_MODES, 'b') != NULL) ||
  564. (strchr(NOHALFOPS_MODES, 'e') != NULL) ||
  565. (strchr(NOHALFOPS_MODES, 'I') != NULL)))
  566. return;
  567. /* Remove masks we didn't put there */
  568. for (; m && m->mask[0]; m = m->next) {
  569. if (!u_equals_mask(global_masks, m->mask) && !u_equals_mask(mrec, m->mask))
  570. add_mode(chan, '-', mode, m->mask);
  571. }
  572. /* Make sure the intended masks are still there */
  573. switch (mode) {
  574. case 'b':
  575. recheck_bans(chan);
  576. break;
  577. case 'e':
  578. recheck_exempts(chan);
  579. break;
  580. case 'I':
  581. recheck_invites(chan);
  582. break;
  583. default:
  584. putlog(LOG_MISC, "*", "(!) Invalid mode '%c' in resetmasks()", mode);
  585. break;
  586. }
  587. }
  588. static void check_this_ban(struct chanset_t *chan, char *banmask, int sticky)
  589. {
  590. memberlist *m;
  591. char user[UHOSTLEN];
  592. if (HALFOP_CANTDOMODE('b'))
  593. return;
  594. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  595. sprintf(user, "%s!%s", m->nick, m->userhost);
  596. if (match_addr(banmask, user) &&
  597. !(use_exempts &&
  598. (u_match_mask(global_exempts, user) ||
  599. u_match_mask(chan->exempts, user))))
  600. refresh_ban_kick(chan, user, m->nick);
  601. }
  602. if (!isbanned(chan, banmask) && (!channel_dynamicbans(chan) || sticky))
  603. add_mode(chan, '+', 'b', banmask);
  604. }
  605. static void recheck_channel_modes(struct chanset_t *chan)
  606. {
  607. int cur = chan->channel.mode, mns = chan->mode_mns_prot,
  608. pls = chan->mode_pls_prot;
  609. if (!(chan->status & CHAN_ASKEDMODES)) {
  610. if (pls & CHANINV && !(cur & CHANINV))
  611. add_mode(chan, '+', 'i', "");
  612. else if (mns & CHANINV && cur & CHANINV)
  613. add_mode(chan, '-', 'i', "");
  614. if (pls & CHANPRIV && !(cur & CHANPRIV))
  615. add_mode(chan, '+', 'p', "");
  616. else if (mns & CHANPRIV && cur & CHANPRIV)
  617. add_mode(chan, '-', 'p', "");
  618. if (pls & CHANSEC && !(cur & CHANSEC))
  619. add_mode(chan, '+', 's', "");
  620. else if (mns & CHANSEC && cur & CHANSEC)
  621. add_mode(chan, '-', 's', "");
  622. if (pls & CHANMODER && !(cur & CHANMODER))
  623. add_mode(chan, '+', 'm', "");
  624. else if (mns & CHANMODER && cur & CHANMODER)
  625. add_mode(chan, '-', 'm', "");
  626. if (pls & CHANNOCLR && !(cur & CHANNOCLR))
  627. add_mode(chan, '+', 'c', "");
  628. else if (mns & CHANNOCLR && cur & CHANNOCLR)
  629. add_mode(chan, '-', 'c', "");
  630. if (pls & CHANNOCTCP && !(cur & CHANNOCTCP))
  631. add_mode(chan, '+', 'C', "");
  632. else if (mns & CHANNOCTCP && cur & CHANNOCTCP)
  633. add_mode(chan, '-', 'C', "");
  634. if (pls & CHANREGON && !(cur & CHANREGON))
  635. add_mode(chan, '+', 'R', "");
  636. else if (mns & CHANREGON && cur & CHANREGON)
  637. add_mode(chan, '-', 'R', "");
  638. if (pls & CHANMODREG && !(cur & CHANMODREG))
  639. add_mode(chan, '+', 'M', "");
  640. else if (mns & CHANMODREG && cur & CHANMODREG)
  641. add_mode(chan, '-', 'M', "");
  642. if (pls & CHANLONLY && !(cur & CHANLONLY))
  643. add_mode(chan, '+', 'r', "");
  644. else if (mns & CHANLONLY && cur & CHANLONLY)
  645. add_mode(chan, '-', 'r', "");
  646. if (pls & CHANDELJN && !(cur & CHANDELJN))
  647. add_mode(chan, '+', 'D', "");
  648. else if (mns & CHANDELJN && cur & CHANDELJN)
  649. add_mode(chan, '-', 'D', "");
  650. if (pls & CHANSTRIP && !(cur & CHANSTRIP))
  651. add_mode(chan, '+', 'u', "");
  652. else if (mns & CHANSTRIP && cur & CHANSTRIP)
  653. add_mode(chan, '-', 'u', "");
  654. if (pls & CHANNONOTC && !(cur & CHANNONOTC))
  655. add_mode(chan, '+', 'N', "");
  656. else if (mns & CHANNONOTC && cur & CHANNONOTC)
  657. add_mode(chan, '-', 'N', "");
  658. if (pls & CHANNOAMSG && !(cur & CHANNOAMSG))
  659. add_mode(chan, '+', 'T', "");
  660. else if (mns & CHANNOAMSG && cur & CHANNOAMSG)
  661. add_mode(chan, '-', 'T', "");
  662. if (pls & CHANTOPIC && !(cur & CHANTOPIC))
  663. add_mode(chan, '+', 't', "");
  664. else if (mns & CHANTOPIC && cur & CHANTOPIC)
  665. add_mode(chan, '-', 't', "");
  666. if (pls & CHANNOMSG && !(cur & CHANNOMSG))
  667. add_mode(chan, '+', 'n', "");
  668. else if ((mns & CHANNOMSG) && (cur & CHANNOMSG))
  669. add_mode(chan, '-', 'n', "");
  670. if ((pls & CHANANON) && !(cur & CHANANON))
  671. add_mode(chan, '+', 'a', "");
  672. else if ((mns & CHANANON) && (cur & CHANANON))
  673. add_mode(chan, '-', 'a', "");
  674. if ((pls & CHANQUIET) && !(cur & CHANQUIET))
  675. add_mode(chan, '+', 'q', "");
  676. else if ((mns & CHANQUIET) && (cur & CHANQUIET))
  677. add_mode(chan, '-', 'q', "");
  678. if ((chan->limit_prot != 0) && (chan->channel.maxmembers == 0)) {
  679. char s[50];
  680. sprintf(s, "%d", chan->limit_prot);
  681. add_mode(chan, '+', 'l', s);
  682. } else if ((mns & CHANLIMIT) && (chan->channel.maxmembers != 0))
  683. add_mode(chan, '-', 'l', "");
  684. if (chan->key_prot[0]) {
  685. if (rfc_casecmp(chan->channel.key, chan->key_prot) != 0) {
  686. if (chan->channel.key[0])
  687. add_mode(chan, '-', 'k', chan->channel.key);
  688. add_mode(chan, '+', 'k', chan->key_prot);
  689. }
  690. } else if ((mns & CHANKEY) && (chan->channel.key[0]))
  691. add_mode(chan, '-', 'k', chan->channel.key);
  692. }
  693. }
  694. static void check_this_member(struct chanset_t *chan, char *nick,
  695. struct flag_record *fr)
  696. {
  697. memberlist *m;
  698. char s[UHOSTLEN], *p;
  699. m = ismember(chan, nick);
  700. if (!m || match_my_nick(nick) || (!me_op(chan) && !me_halfop(chan)))
  701. return;
  702. #ifdef NO_HALFOP_CHANMODES
  703. if (me_op(chan)) {
  704. #else
  705. if (me_op(chan) || me_halfop(chan)) {
  706. #endif
  707. if (HALFOP_CANDOMODE('o')) {
  708. if (chan_hasop(m) && ((chan_deop(*fr) || (glob_deop(*fr) &&
  709. !chan_op(*fr))) || (channel_bitch(chan) && (!chan_op(*fr) &&
  710. !(glob_op(*fr) && !chan_deop(*fr)))))) {
  711. add_mode(chan, '-', 'o', m->nick);
  712. }
  713. if (!chan_hasop(m) && (chan_op(*fr) || (glob_op(*fr) &&
  714. !chan_deop(*fr))) && (channel_autoop(chan) || glob_autoop(*fr) ||
  715. chan_autoop(*fr))) {
  716. if (!chan->aop_min)
  717. add_mode(chan, '+', 'o', m->nick);
  718. else {
  719. set_delay(chan, m->nick);
  720. m->flags |= SENTOP;
  721. }
  722. }
  723. }
  724. if (HALFOP_CANDOMODE('h')) {
  725. if (chan_hashalfop(m) && ((chan_dehalfop(*fr) || (glob_dehalfop(*fr) &&
  726. !chan_halfop(*fr)) || (channel_bitch(chan) && (!chan_halfop(*fr) &&
  727. !(glob_halfop(*fr) && !chan_dehalfop(*fr)))))))
  728. add_mode(chan, '-', 'h', m->nick);
  729. if (!chan_sentop(m) && !chan_hasop(m) && !chan_hashalfop(m) &&
  730. (chan_halfop(*fr) || (glob_halfop(*fr) && !chan_dehalfop(*fr))) &&
  731. (channel_autohalfop(chan) || glob_autohalfop(*fr) ||
  732. chan_autohalfop(*fr))) {
  733. if (!chan->aop_min)
  734. add_mode(chan, '+', 'h', m->nick);
  735. else {
  736. set_delay(chan, m->nick);
  737. m->flags |= SENTHALFOP;
  738. }
  739. }
  740. }
  741. if (HALFOP_CANDOMODE('v')) {
  742. if (chan_hasvoice(m) && (chan_quiet(*fr) || (glob_quiet(*fr) &&
  743. !chan_voice(*fr))))
  744. add_mode(chan, '-', 'v', m->nick);
  745. if (!chan_hasvoice(m) && !chan_hasop(m) && !chan_hashalfop(m) &&
  746. (chan_voice(*fr) || (glob_voice(*fr) && !chan_quiet(*fr))) &&
  747. (channel_autovoice(chan) || glob_gvoice(*fr) || chan_gvoice(*fr))) {
  748. if (!chan->aop_min)
  749. add_mode(chan, '+', 'v', m->nick);
  750. else {
  751. set_delay(chan, m->nick);
  752. m->flags |= SENTVOICE;
  753. }
  754. }
  755. }
  756. }
  757. if (!me_op(chan) && (!me_halfop(chan) ||
  758. (strchr(NOHALFOPS_MODES, 'b') != NULL) ||
  759. (strchr(NOHALFOPS_MODES, 'e') != NULL) ||
  760. (strchr(NOHALFOPS_MODES, 'I') != NULL)))
  761. return;
  762. sprintf(s, "%s!%s", m->nick, m->userhost);
  763. if (use_invites && (u_match_mask(global_invites, s) ||
  764. u_match_mask(chan->invites, s)))
  765. refresh_invite(chan, s);
  766. if (!(use_exempts && (u_match_mask(global_exempts, s) ||
  767. u_match_mask(chan->exempts, s)))) {
  768. if (u_match_mask(global_bans, s) || u_match_mask(chan->bans, s))
  769. refresh_ban_kick(chan, s, m->nick);
  770. if (!chan_sentkick(m) && (chan_kick(*fr) || glob_kick(*fr)) &&
  771. (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) {
  772. check_exemptlist(chan, s);
  773. quickban(chan, m->userhost);
  774. p = get_user(&USERENTRY_COMMENT, m->user);
  775. dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, m->nick,
  776. p ? p : IRC_POLITEKICK);
  777. m->flags |= SENTKICK;
  778. }
  779. }
  780. }
  781. static void check_this_user(char *hand, int delete, char *host)
  782. {
  783. char s[UHOSTLEN];
  784. memberlist *m;
  785. struct userrec *u;
  786. struct chanset_t *chan;
  787. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  788. for (chan = chanset; chan; chan = chan->next)
  789. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  790. sprintf(s, "%s!%s", m->nick, m->userhost);
  791. u = m->user ? m->user : get_user_by_host(s);
  792. if ((u && !egg_strcasecmp(u->handle, hand) && delete < 2) ||
  793. (!u && delete == 2 && match_addr(host, fixfrom(s)))) {
  794. u = delete ? NULL : u;
  795. get_user_flagrec(u, &fr, chan->dname);
  796. check_this_member(chan, m->nick, &fr);
  797. }
  798. }
  799. }
  800. /* Things to do when i just became a chanop:
  801. */
  802. static void recheck_channel(struct chanset_t *chan, int dobans)
  803. {
  804. memberlist *m;
  805. char s[UHOSTLEN];
  806. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  807. static int stacking = 0;
  808. int stop_reset = 0;
  809. if (stacking || !userlist)
  810. return;
  811. stacking++;
  812. /* Okay, sort through who needs to be deopped. */
  813. for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
  814. sprintf(s, "%s!%s", m->nick, m->userhost);
  815. if (!m->user && !m->tried_getuser) {
  816. m->tried_getuser = 1;
  817. m->user = get_user_by_host(s);
  818. }
  819. get_user_flagrec(m->user, &fr, chan->dname);
  820. if (glob_bot(fr) && chan_hasop(m) && !match_my_nick(m->nick))
  821. stop_reset = 1;
  822. /* Perhaps we were halfop and tried to halfop/kick the user earlier but
  823. * the server rejected the request, so let's try again. */
  824. m->flags &= ~(SENTHALFOP | SENTKICK);
  825. check_this_member(chan, m->nick, &fr);
  826. }
  827. /* Most IRCDs nowadays require +h/+o for getting e/I lists,
  828. * so if we're still waiting for these, we'll request them here.
  829. * In case we got them on join, nothing will be done */
  830. if (chan->ircnet_status & (CHAN_ASKED_EXEMPTS | CHAN_ASKED_INVITED)) {
  831. chan->ircnet_status &= ~(CHAN_ASKED_EXEMPTS | CHAN_ASKED_INVITED);
  832. reset_chan_info(chan, CHAN_RESETEXEMPTS | CHAN_RESETINVITED);
  833. }
  834. if (dobans) {
  835. if (channel_nouserbans(chan) && !stop_reset)
  836. resetbans(chan);
  837. else
  838. recheck_bans(chan);
  839. if (use_invites) {
  840. if (channel_nouserinvites(chan) && !stop_reset)
  841. resetinvites(chan);
  842. else
  843. recheck_invites(chan);
  844. }
  845. if (use_exempts) {
  846. if (channel_nouserexempts(chan) && !stop_reset)
  847. resetexempts(chan);
  848. else
  849. recheck_exempts(chan);
  850. }
  851. if (channel_enforcebans(chan))
  852. enforce_bans(chan);
  853. if ((chan->status & CHAN_ASKEDMODES) && !channel_inactive(chan))
  854. dprintf(DP_MODE, "MODE %s\n", chan->name);
  855. recheck_channel_modes(chan);
  856. }
  857. stacking--;
  858. }
  859. /* got 324: mode status
  860. * <server> 324 <to> <channel> <mode>
  861. */
  862. static int got324(char *from, char *msg)
  863. {
  864. int i = 1, ok = 0;
  865. char *p, *q, *chname;
  866. struct chanset_t *chan;
  867. newsplit(&msg);
  868. chname = newsplit(&msg);
  869. chan = findchan(chname);
  870. if (!chan) {
  871. putlog(LOG_MISC, "*", "%s: %s", IRC_UNEXPECTEDMODE, chname);
  872. dprintf(DP_SERVER, "PART %s\n", chname);
  873. return 0;
  874. }
  875. if (chan->status & CHAN_ASKEDMODES)
  876. ok = 1;
  877. chan->status &= ~CHAN_ASKEDMODES;
  878. chan->channel.mode = 0;
  879. while (msg[i] != 0) {
  880. if (msg[i] == 'i')
  881. chan->channel.mode |= CHANINV;
  882. if (msg[i] == 'p')
  883. chan->channel.mode |= CHANPRIV;
  884. if (msg[i] == 's')
  885. chan->channel.mode |= CHANSEC;
  886. if (msg[i] == 'm')
  887. chan->channel.mode |= CHANMODER;
  888. if (msg[i] == 'c')
  889. chan->channel.mode |= CHANNOCLR;
  890. if (msg[i] == 'C')
  891. chan->channel.mode |= CHANNOCTCP;
  892. if (msg[i] == 'R')
  893. chan->channel.mode |= CHANREGON;
  894. if (msg[i] == 'M')
  895. chan->channel.mode |= CHANMODREG;
  896. if (msg[i] == 'r')
  897. chan->channel.mode |= CHANLONLY;
  898. if (msg[i] == 'D')
  899. chan->channel.mode |= CHANDELJN;
  900. if (msg[i] == 'u')
  901. chan->channel.mode |= CHANSTRIP;
  902. if (msg[i] == 'N')
  903. chan->channel.mode |= CHANNONOTC;
  904. if (msg[i] == 'T')
  905. chan->channel.mode |= CHANNOAMSG;
  906. if (msg[i] == 'd')
  907. chan->channel.mode |= CHANINVIS;
  908. if (msg[i] == 't')
  909. chan->channel.mode |= CHANTOPIC;
  910. if (msg[i] == 'n')
  911. chan->channel.mode |= CHANNOMSG;
  912. if (msg[i] == 'a')
  913. chan->channel.mode |= CHANANON;
  914. if (msg[i] == 'q')
  915. chan->channel.mode |= CHANQUIET;
  916. if (msg[i] == 'k') {
  917. chan->channel.mode |= CHANKEY;
  918. p = strchr(msg, ' ');
  919. if (p != NULL) { /* Test for null key assignment */
  920. p++;
  921. q = strchr(p, ' ');
  922. if (q != NULL) {
  923. *q = 0;
  924. set_key(chan, p);
  925. strcpy(p, q + 1);
  926. } else {
  927. set_key(chan, p);
  928. *p = 0;
  929. }
  930. }
  931. if ((chan->channel.mode & CHANKEY) && (!chan->channel.key[0] ||
  932. !strcmp("*", chan->channel.key)))
  933. /* Undernet use to show a blank channel key if one was set when
  934. * you first joined a channel; however, this has been replaced by
  935. * an asterisk and this has been agreed upon by other major IRC
  936. * networks so we'll check for an asterisk here as well
  937. * (guppy 22Dec2001) */
  938. chan->status |= CHAN_ASKEDMODES;
  939. }
  940. if (msg[i] == 'l') {
  941. p = strchr(msg, ' ');
  942. if (p != NULL) { /* test for null limit assignment */
  943. p++;
  944. q = strchr(p, ' ');
  945. if (q != NULL) {
  946. *q = 0;
  947. chan->channel.maxmembers = atoi(p);
  948. strcpy(p, q + 1);
  949. } else {
  950. chan->channel.maxmembers = atoi(p);
  951. *p = 0;
  952. }
  953. }
  954. }
  955. i++;
  956. }
  957. if (ok)
  958. recheck_channel_modes(chan);
  959. return 0;
  960. }
  961. static int got352or4(struct chanset_t *chan, char *user, char *host,
  962. char *nick, char *flags)
  963. {
  964. char userhost[UHOSTLEN];
  965. memberlist *m;
  966. m = ismember(chan, nick); /* In my channel list copy? */
  967. if (!m) { /* Nope, so update */
  968. m = newmember(chan); /* Get a new channel entry */
  969. m->joined = m->split = m->delay = 0L; /* Don't know when he joined */
  970. m->flags = 0; /* No flags for now */
  971. m->last = now; /* Last time I saw him */
  972. }
  973. strcpy(m->nick, nick); /* Store the nick in list */
  974. /* Store the userhost */
  975. simple_sprintf(m->userhost, "%s@%s", user, host);
  976. simple_sprintf(userhost, "%s!%s", nick, m->userhost);
  977. /* Combine n!u@h */
  978. m->user = NULL; /* No handle match (yet) */
  979. if (match_my_nick(nick)) /* Is it me? */
  980. strcpy(botuserhost, m->userhost); /* Yes, save my own userhost */
  981. m->flags |= WHO_SYNCED;
  982. if (strpbrk(flags, opchars) != NULL)
  983. m->flags |= (CHANOP | WASOP);
  984. else
  985. m->flags &= ~(CHANOP | WASOP);
  986. if (strchr(flags, '%') != NULL)
  987. m->flags |= (CHANHALFOP | WASHALFOP);
  988. else
  989. m->flags &= ~(CHANHALFOP | WASHALFOP);
  990. if (strchr(flags, '+') != NULL)
  991. m->flags |= CHANVOICE;
  992. else
  993. m->flags &= ~CHANVOICE;
  994. if (!(m->flags & (CHANVOICE | CHANOP | CHANHALFOP)))
  995. m->flags |= STOPWHO;
  996. if (match_my_nick(nick) && any_ops(chan) && !me_op(chan)) {
  997. check_tcl_need(chan->dname, "op");
  998. if (chan->need_op[0])
  999. do_tcl("need-op", chan->need_op);
  1000. }
  1001. m->user = get_user_by_host(userhost);
  1002. return 0;
  1003. }
  1004. /* got a 352: who info!
  1005. */
  1006. static int got352(char *from, char *msg)
  1007. {
  1008. char *nick, *user, *host, *chname, *flags;
  1009. struct chanset_t *chan;
  1010. newsplit(&msg); /* Skip my nick - effeciently */
  1011. chname = newsplit(&msg); /* Grab the channel */
  1012. chan = findchan(chname); /* See if I'm on channel */
  1013. if (chan) { /* Am I? */
  1014. user = newsplit(&msg); /* Grab the user */
  1015. host = newsplit(&msg); /* Grab the host */
  1016. newsplit(&msg); /* Skip the server */
  1017. nick = newsplit(&msg); /* Grab the nick */
  1018. flags = newsplit(&msg); /* Grab the flags */
  1019. got352or4(chan, user, host, nick, flags);
  1020. }
  1021. return 0;
  1022. }
  1023. /* got a 354: who info! - iru style
  1024. */
  1025. static int got354(char *from, char *msg)
  1026. {
  1027. char *nick, *user, *host, *chname, *flags;
  1028. struct chanset_t *chan;
  1029. if (use_354) {
  1030. newsplit(&msg); /* Skip my nick - effeciently */
  1031. if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) {
  1032. chname = newsplit(&msg); /* Grab the channel */
  1033. chan = findchan(chname); /* See if I'm on channel */
  1034. if (chan) { /* Am I? */
  1035. user = newsplit(&msg); /* Grab the user */
  1036. host = newsplit(&msg); /* Grab the host */
  1037. nick = newsplit(&msg); /* Grab the nick */
  1038. flags = newsplit(&msg); /* Grab the flags */
  1039. got352or4(chan, user, host, nick, flags);
  1040. }
  1041. }
  1042. }
  1043. return 0;
  1044. }
  1045. /* got 315: end of who
  1046. * <server> 315 <to> <chan> :End of /who
  1047. */
  1048. static int got315(char *from, char *msg)
  1049. {
  1050. char *chname, *key;
  1051. struct chanset_t *chan;
  1052. newsplit(&msg);
  1053. chname = newsplit(&msg);
  1054. chan = findchan(chname);
  1055. if (!chan || !channel_pending(chan)) /* Left channel before we got a 315? */
  1056. return 0;
  1057. sync_members(chan);
  1058. chan->status |= CHAN_ACTIVE;
  1059. chan->status &= ~CHAN_PEND;
  1060. if (!ismember(chan, botname)) { /* Am I on the channel now? */
  1061. putlog(LOG_MISC | LOG_JOIN, chan->dname, "Oops, I'm not really on %s.",
  1062. chan->dname);
  1063. clear_channel(chan, 1);
  1064. chan->status &= ~CHAN_ACTIVE;
  1065. key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
  1066. if (key[0])
  1067. dprintf(DP_SERVER, "JOIN %s %s\n",
  1068. chan->name[0] ? chan->name : chan->dname, key);
  1069. else
  1070. dprintf(DP_SERVER, "JOIN %s\n",
  1071. chan->name[0] ? chan->name : chan->dname);
  1072. } else if (me_op(chan))
  1073. recheck_channel(chan, 1);
  1074. else if (chan->channel.members == 1)
  1075. chan->status |= CHAN_STOP_CYCLE;
  1076. return 0; /* Don't check for I-Lines here. */
  1077. }
  1078. /* got 367: ban info
  1079. * <server> 367 <to> <chan> <ban> [placed-by] [timestamp]
  1080. */
  1081. static int got367(char *from, char *origmsg)
  1082. {
  1083. char *ban, *who, *chname, buf[511], *msg;
  1084. struct chanset_t *chan;
  1085. strncpy(buf, origmsg, 510);
  1086. buf[510] = 0;
  1087. msg = buf;
  1088. newsplit(&msg);
  1089. chname = newsplit(&msg);
  1090. chan = findchan(chname);
  1091. if (!chan || !(channel_pending(chan) || channel_active(chan)))
  1092. return 0;
  1093. ban = newsplit(&msg);
  1094. who = newsplit(&msg);
  1095. /* Extended timestamp format? */
  1096. if (who[0])
  1097. newban(chan, ban, who);
  1098. else
  1099. newban(chan, ban, "existent");
  1100. return 0;
  1101. }
  1102. /* got 368: end of ban list
  1103. * <server> 368 <to> <chan> :etc
  1104. */
  1105. static int got368(char *from, char *msg)
  1106. {
  1107. struct chanset_t *chan;
  1108. char *chname;
  1109. /* Okay, now add bans that i want, which aren't set yet */
  1110. newsplit(&msg);
  1111. chname = newsplit(&msg);
  1112. chan = findchan(chname);
  1113. if (chan)
  1114. chan->status &= ~CHAN_ASKEDBANS;
  1115. /* If i sent a mode -b on myself (deban) in got367, either
  1116. * resetbans() or recheck_bans() will flush that.
  1117. */
  1118. return 0;
  1119. }
  1120. /* got 348: ban exemption info
  1121. * <server> 348 <to> <chan> <exemption>
  1122. */
  1123. static int got348(char *from, char *origmsg)
  1124. {
  1125. char *exempt, *who, *chname, buf[511], *msg;
  1126. struct chanset_t *chan;
  1127. if (use_exempts == 0)
  1128. return 0;
  1129. strncpy(buf, origmsg, 510);
  1130. buf[510] = 0;
  1131. msg = buf;
  1132. newsplit(&msg);
  1133. chname = newsplit(&msg);
  1134. chan = findchan(chname);
  1135. if (!chan || !(channel_pending(chan) || channel_active(chan)))
  1136. return 0;
  1137. exempt = newsplit(&msg);
  1138. who = newsplit(&msg);
  1139. /* Extended timestamp format? */
  1140. if (who[0])
  1141. newexempt(chan, exempt, who);
  1142. else
  1143. newexempt(chan, exempt, "existent");
  1144. return 0;
  1145. }
  1146. /* got 349: end of ban exemption list
  1147. * <server> 349 <to> <chan> :etc
  1148. */
  1149. static int got349(char *from, char *msg)
  1150. {
  1151. struct chanset_t *chan;
  1152. char *chname;
  1153. if (use_exempts == 1) {
  1154. newsplit(&msg);
  1155. chname = newsplit(&msg);
  1156. chan = findchan(chname);
  1157. if (chan)
  1158. chan->ircnet_status &= ~CHAN_ASKED_EXEMPTS;
  1159. }
  1160. return 0;
  1161. }
  1162. /* got 346: invite exemption info
  1163. * <server> 346 <to> <chan> <exemption>
  1164. */
  1165. static int got346(char *from, char *origmsg)
  1166. {
  1167. char *invite, *who, *chname, buf[511], *msg;
  1168. struct chanset_t *chan;
  1169. strncpy(buf, origmsg, 510);
  1170. buf[510] = 0;
  1171. msg = buf;
  1172. if (use_invites == 0)
  1173. return 0;
  1174. newsplit(&msg);
  1175. chname = newsplit(&msg);
  1176. chan = findchan(chname);
  1177. if (!chan || !(channel_pending(chan) || channel_active(chan)))
  1178. return 0;
  1179. invite = newsplit(&msg);
  1180. who = newsplit(&msg);
  1181. /* Extended timestamp format? */
  1182. if (who[0])
  1183. newinvite(chan, invite, who);
  1184. else
  1185. newinvite(chan, invite, "existent");
  1186. return 0;
  1187. }
  1188. /* got 347: end of invite exemption list
  1189. * <server> 347 <to> <chan> :etc
  1190. */
  1191. static int got347(char *from, char *msg)
  1192. {
  1193. struct chanset_t *chan;
  1194. char *chname;
  1195. if (use_invites == 1) {
  1196. newsplit(&msg);
  1197. chname = newsplit(&msg);
  1198. chan = findchan(chname);
  1199. if (chan)
  1200. chan->ircnet_status &= ~CHAN_ASKED_INVITED;
  1201. }
  1202. return 0;
  1203. }
  1204. /* Too many channels.
  1205. */
  1206. static int got405(char *from, char *msg)
  1207. {
  1208. char *chname;
  1209. newsplit(&msg);
  1210. chname = newsplit(&msg);
  1211. putlog(LOG_MISC, "*", IRC_TOOMANYCHANS, chname);
  1212. return 0;
  1213. }
  1214. /* This is only of use to us with !channels. We get this message when
  1215. * attempting to join a non-existant !channel... The channel must be
  1216. * created by sending 'JOIN !!<channel>'. <cybah>
  1217. *
  1218. * 403 - ERR_NOSUCHCHANNEL
  1219. */
  1220. static int got403(char *from, char *msg)
  1221. {
  1222. char *chname;
  1223. struct chanset_t *chan;
  1224. newsplit(&msg);
  1225. chname = newsplit(&msg);
  1226. if (chname && chname[0] == '!') {
  1227. chan = findchan_by_dname(chname);
  1228. if (!chan) {
  1229. chan = findchan(chname);
  1230. if (!chan)
  1231. return 0; /* Ignore it */
  1232. /* We have the channel unique name, so we have attempted to join
  1233. * a specific !channel that doesnt exist. Now attempt to join the
  1234. * channel using it's short name.
  1235. */
  1236. putlog(LOG_MISC, "*",
  1237. "Unique channel %s does not exist... Attempting to join with "
  1238. "short name.", chname);
  1239. dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
  1240. } else {
  1241. /* We have found the channel, so the server has given us the short
  1242. * name. Prefix another '!' to it, and attempt the join again...
  1243. */
  1244. putlog(LOG_MISC, "*",
  1245. "Channel %s does not exist... Attempting to create it.", chname);
  1246. dprintf(DP_SERVER, "JOIN !%s\n", chan->dname);
  1247. }
  1248. }
  1249. return 0;
  1250. }
  1251. /* got 471: can't join channel, full
  1252. */
  1253. static int got471(char *from, char *msg)
  1254. {
  1255. char *chname;
  1256. struct chanset_t *chan;
  1257. newsplit(&msg);
  1258. chname = newsplit(&msg);
  1259. /* !channel short names (also referred to as 'description names'
  1260. * can be received by skipping over the unique ID.
  1261. */
  1262. if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
  1263. chname += CHANNEL_ID_LEN;
  1264. chname[0] = '!';
  1265. }
  1266. /* We use dname because name is first set on JOIN and we might not
  1267. * have joined the channel yet.
  1268. */
  1269. chan = findchan_by_dname(chname);
  1270. if (chan) {
  1271. putlog(LOG_JOIN, chan->dname, IRC_CHANFULL, chan->dname);
  1272. check_tcl_need(chan->dname, "limit");
  1273. chan = findchan_by_dname(chname);
  1274. if (!chan)
  1275. return 0;
  1276. if (chan->need_limit[0])
  1277. do_tcl("need-limit", chan->need_limit);
  1278. } else
  1279. putlog(LOG_JOIN, chname, IRC_CHANFULL, chname);
  1280. return 0;
  1281. }
  1282. /* got 473: can't join channel, invite only
  1283. */
  1284. static int got473(char *from, char *msg)
  1285. {
  1286. char *chname;
  1287. struct chanset_t *chan;
  1288. newsplit(&msg);
  1289. chname = newsplit(&msg);
  1290. /* !channel short names (also referred to as 'description names'
  1291. * can be received by skipping over the unique ID.
  1292. */
  1293. if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
  1294. chname += CHANNEL_ID_LEN;
  1295. chname[0] = '!';
  1296. }
  1297. /* We use dname because name is first set on JOIN and we might not
  1298. * have joined the channel yet.
  1299. */
  1300. chan = findchan_by_dname(chname);
  1301. if (chan) {
  1302. putlog(LOG_JOIN, chan->dname, IRC_CHANINVITEONLY, chan->dname);
  1303. check_tcl_need(chan->dname, "invite");
  1304. chan = findchan_by_dname(chname);
  1305. if (!chan)
  1306. return 0;
  1307. if (chan->need_invite[0])
  1308. do_tcl("need-invite", chan->need_invite);
  1309. } else
  1310. putlog(LOG_JOIN, chname, IRC_CHANINVITEONLY, chname);
  1311. return 0;
  1312. }
  1313. /* got 474: can't join channel, banned
  1314. */
  1315. static int got474(char *from, char *msg)
  1316. {
  1317. char *chname;
  1318. struct chanset_t *chan;
  1319. newsplit(&msg);
  1320. chname = newsplit(&msg);
  1321. /* !channel short names (also referred to as 'description names'
  1322. * can be received by skipping over the unique ID.
  1323. */
  1324. if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
  1325. chname += CHANNEL_ID_LEN;
  1326. chname[0] = '!';
  1327. }
  1328. /* We use dname because name is first set on JOIN and we might not
  1329. * have joined the channel yet.
  1330. */
  1331. chan = findchan_by_dname(chname);
  1332. if (chan) {
  1333. putlog(LOG_JOIN, chan->dname, IRC_BANNEDFROMCHAN, chan->dname);
  1334. check_tcl_need(chan->dname, "unban");
  1335. chan = findchan_by_dname(chname);
  1336. if (!chan)
  1337. return 0;
  1338. if (chan->need_unban[0])
  1339. do_tcl("need-unban", chan->need_unban);
  1340. } else
  1341. putlog(LOG_JOIN, chname, IRC_BANNEDFROMCHAN, chname);
  1342. return 0;
  1343. }
  1344. /* got 475: can't join channel, bad key
  1345. */
  1346. static int got475(char *from, char *msg)
  1347. {
  1348. char *chname;
  1349. struct chanset_t *chan;
  1350. newsplit(&msg);
  1351. chname = newsplit(&msg);
  1352. /* !channel short names (also referred to as 'description names'
  1353. * can be received by skipping over the unique ID.
  1354. */
  1355. if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
  1356. chname += CHANNEL_ID_LEN;
  1357. chname[0] = '!';
  1358. }
  1359. /* We use dname because name is first set on JOIN and we might not
  1360. * have joined the channel yet.
  1361. */
  1362. chan = findchan_by_dname(chname);
  1363. if (chan) {
  1364. putlog(LOG_JOIN, chan->dname, IRC_BADCHANKEY, chan->dname);
  1365. if (chan->channel.key[0]) {
  1366. nfree(chan->channel.key);
  1367. chan->channel.key = (char *) channel_malloc(1);
  1368. chan->channel.key[0] = 0;
  1369. if (chan->key_prot[0])
  1370. dprintf(DP_SERVER, "JOIN %s %s\n", chan->dname, chan->key_prot);
  1371. else
  1372. dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
  1373. } else {
  1374. check_tcl_need(chan->dname, "key");
  1375. chan = findchan_by_dname(chname);
  1376. if (!chan)
  1377. return 0;
  1378. if (chan->need_key[0])
  1379. do_tcl("need-key", chan->need_key);
  1380. }
  1381. } else
  1382. putlog(LOG_JOIN, chname, IRC_BADCHANKEY, chname);
  1383. return 0;
  1384. }
  1385. /* got invitation
  1386. */
  1387. static int gotinvite(char *from, char *msg)
  1388. {
  1389. char *nick, *key;
  1390. struct chanset_t *chan;
  1391. newsplit(&msg);
  1392. fixcolon(msg);
  1393. nick = splitnick(&from);
  1394. if (!rfc_casecmp(last_invchan, msg))
  1395. if (now - last_invtime < 30)
  1396. return 0; /* Two invites to the same channel in 30 seconds? */
  1397. putlog(LOG_MISC, "*", "%s!%s invited me to %s", nick, from, msg);
  1398. strncpy(last_invchan, msg, 299);
  1399. last_invchan[299] = 0;
  1400. last_invtime = now;
  1401. chan = findchan(msg);
  1402. if (!chan)
  1403. /* Might be a short-name */
  1404. chan = findchan_by_dname(msg);
  1405. if (chan && (channel_pending(chan) || channel_active(chan)))
  1406. dprintf(DP_HELP, "NOTICE %s :I'm already here.\n", nick);
  1407. else if (chan && !channel_inactive(chan)) {
  1408. key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
  1409. if (key[0])
  1410. dprintf(DP_SERVER, "JOIN %s %s\n",
  1411. chan->name[0] ? chan->name : chan->dname, key);
  1412. else
  1413. dprintf(DP_SERVER, "JOIN %s\n",
  1414. chan->name[0] ? chan->name : chan->dname);
  1415. }
  1416. return 0;
  1417. }
  1418. /* Set the topic.
  1419. */
  1420. static void set_topic(struct chanset_t *chan, char *k)
  1421. {
  1422. if (chan->channel.topic)
  1423. nfree(chan->channel.topic);
  1424. if (k && k[0]) {
  1425. chan->channel.topic = (char *) channel_malloc(strlen(k) + 1);
  1426. strcpy(chan->channel.topic, k);
  1427. } else
  1428. chan->channel.topic = NULL;
  1429. }
  1430. /* Topic change.
  1431. */
  1432. static int gottopic(char *from, char *msg)
  1433. {
  1434. char *nick, *chname;
  1435. memberlist *m;
  1436. struct chanset_t *chan;
  1437. struct userrec *u;
  1438. chname = newsplit(&msg);
  1439. fixcolon(msg);
  1440. u = get_user_by_host(from);
  1441. nick = splitnick(&from);
  1442. chan = findchan(chname);
  1443. if (chan) {
  1444. putlog(LOG_JOIN, chan->dname, "Topic changed on %s by %s!%s: %s",
  1445. chan->dname, nick, from, msg);
  1446. m = ismember(chan, nick);
  1447. if (m != NULL)
  1448. m->last = now;
  1449. set_topic(chan, msg);
  1450. check_tcl_topc(nick, from, u, chan->dname, msg);
  1451. }
  1452. return 0;
  1453. }
  1454. /* 331: no current topic for this channel
  1455. * <server> 331 <to> <chname> :etc
  1456. */
  1457. static int got331(char *from, char *msg)
  1458. {
  1459. char *chname;
  1460. struct chanset_t *chan;
  1461. newsplit(&msg);
  1462. chname = newsplit(&msg);
  1463. chan = findchan(chname);
  1464. if (chan) {
  1465. set_topic(chan, NULL);
  1466. check_tcl_topc("*", "*", NULL, chan->dname, "");
  1467. }
  1468. return 0;
  1469. }
  1470. /* 332: topic on a channel i've just joined
  1471. * <server> 332 <to> <chname> :topic goes here
  1472. */
  1473. static int got332(char *from, char *msg)
  1474. {
  1475. struct chanset_t *chan;
  1476. char *chname;
  1477. newsplit(&msg);
  1478. chname = newsplit(&msg);
  1479. chan = findchan(chname);
  1480. if (chan) {
  1481. fixcolon(msg);
  1482. set_topic(chan, msg);
  1483. check_tcl_topc("*", "*", NULL, chan->dname, msg);
  1484. }
  1485. return 0;
  1486. }
  1487. /* Set delay for +o, +h, or +v channel modes
  1488. */
  1489. static void set_delay(struct chanset_t *chan, char *nick)
  1490. {
  1491. time_t a_delay;
  1492. int aop_min, aop_max, aop_diff, count = 0;
  1493. memberlist *m, *m2;
  1494. m = ismember(chan, nick);
  1495. if (!m)
  1496. return;
  1497. /* aop-delay 5:30 -- aop_min:aop_max */
  1498. aop_min = chan->aop_min;
  1499. aop_max = chan->aop_max;
  1500. aop_diff = aop_max - aop_min;
  1501. /* If either min or max is less than or equal to 0 we don't delay. */
  1502. if ((aop_min <= 0) || (aop_max <= 0)) {
  1503. a_delay = now + 1;
  1504. /* Use min value for delay if min greater then or equal to max or if the
  1505. * difference of max and min is greater than RANDOM_MAX (sanity check).
  1506. */
  1507. } else if ((aop_min >= aop_max) || (aop_diff > RANDOM_MAX)) {
  1508. a_delay = now + aop_min;
  1509. /* Set a random delay based on the difference of max and min */
  1510. } else {
  1511. a_delay = now + randint(aop_diff) + aop_min + 1;
  1512. }
  1513. for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next)
  1514. if (m2->delay && !(m2->flags & FULL_DELAY))
  1515. count++;
  1516. if (count) {
  1517. for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next) {
  1518. if (m2->delay && !(m2->flags & FULL_DELAY)) {
  1519. m2->delay = a_delay;
  1520. if (count + 1 >= modesperline)
  1521. m2->flags |= FULL_DELAY;
  1522. }
  1523. }
  1524. }
  1525. if (count + 1 >= modesperline)
  1526. m->flags |= FULL_DELAY;
  1527. m->delay = a_delay;
  1528. }
  1529. /* Got a join
  1530. */
  1531. static int gotjoin(char *from, char *chname)
  1532. {
  1533. char *nick, *p, buf[UHOSTLEN], *uhost = buf;
  1534. char *ch_dname = NULL;
  1535. struct chanset_t *chan;
  1536. memberlist *m;
  1537. masklist *b;
  1538. struct userrec *u;
  1539. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  1540. fixcolon(chname);
  1541. chan = findchan(chname);
  1542. if (!chan && chname[0] == '!') {
  1543. /* As this is a !channel, we need to search for it by display (short)
  1544. * name now. This will happen when we initially join the channel, as we
  1545. * dont know the unique channel name that the server has made up. <cybah>
  1546. */
  1547. int l_chname = strlen(chname);
  1548. if (l_chname > (CHANNEL_ID_LEN + 1)) {
  1549. ch_dname = nmalloc(l_ch

Large files files are truncated, but you can click here to view the full file