PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/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
  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_chname + 1);
  1550. if (ch_dname) {
  1551. egg_snprintf(ch_dname, l_chname + 2, "!%s",
  1552. chname + (CHANNEL_ID_LEN + 1));
  1553. chan = findchan_by_dname(ch_dname);
  1554. if (!chan) {
  1555. /* Hmm.. okay. Maybe the admin's a genius and doesn't know the
  1556. * difference between id and descriptive channel names. Search
  1557. * the channel name in the dname list using the id-name.
  1558. */
  1559. chan = findchan_by_dname(chname);
  1560. if (chan) {
  1561. /* Duh, I was right. Mark this channel as inactive and log
  1562. * the incident.
  1563. */
  1564. chan->status |= CHAN_INACTIVE;
  1565. putlog(LOG_MISC, "*", "Deactivated channel %s, because it uses "
  1566. "an ID channel-name. Use the descriptive name instead.",
  1567. chname);
  1568. dprintf(DP_SERVER, "PART %s\n", chname);
  1569. goto exit;
  1570. }
  1571. }
  1572. }
  1573. }
  1574. } else if (!chan) {
  1575. /* As this is not a !chan, we need to search for it by display name now.
  1576. * Unlike !chan's, we dont need to remove the unique part.
  1577. */
  1578. chan = findchan_by_dname(chname);
  1579. }
  1580. if (!chan || channel_inactive(chan)) {
  1581. strcpy(uhost, from);
  1582. nick = splitnick(&uhost);
  1583. if (match_my_nick(nick)) {
  1584. putlog(LOG_MISC, "*", "joined %s but didn't want to!", chname);
  1585. dprintf(DP_MODE, "PART %s\n", chname);
  1586. }
  1587. } else if (!channel_pending(chan)) {
  1588. chan->status &= ~CHAN_STOP_CYCLE;
  1589. strcpy(uhost, from);
  1590. nick = splitnick(&uhost);
  1591. detect_chan_flood(nick, uhost, from, chan, FLOOD_JOIN, NULL);
  1592. chan = findchan(chname);
  1593. if (!chan) {
  1594. if (ch_dname)
  1595. chan = findchan_by_dname(ch_dname);
  1596. else
  1597. chan = findchan_by_dname(chname);
  1598. }
  1599. if (!chan)
  1600. /* The channel doesn't exist anymore, so get out of here. */
  1601. goto exit;
  1602. /* Grab last time joined before we update it */
  1603. u = get_user_by_host(from);
  1604. get_user_flagrec(u, &fr, chan->dname); /* Lam: fix to work with !channels */
  1605. if (!channel_active(chan) && !match_my_nick(nick)) {
  1606. /* uh, what?! i'm on the channel?! */
  1607. putlog(LOG_MISC, chan->dname,
  1608. "confused bot: guess I'm on %s and didn't realize it",
  1609. chan->dname);
  1610. chan->status |= CHAN_ACTIVE;
  1611. chan->status &= ~CHAN_PEND;
  1612. reset_chan_info(chan, CHAN_RESETALL);
  1613. } else {
  1614. m = ismember(chan, nick);
  1615. if (m && m->split && !egg_strcasecmp(m->userhost, uhost)) {
  1616. check_tcl_rejn(nick, uhost, u, chan->dname);
  1617. chan = findchan(chname);
  1618. if (!chan) {
  1619. if (ch_dname)
  1620. chan = findchan_by_dname(ch_dname);
  1621. else
  1622. chan = findchan_by_dname(chname);
  1623. }
  1624. if (!chan)
  1625. /* The channel doesn't exist anymore, so get out of here. */
  1626. goto exit;
  1627. /* The tcl binding might have deleted the current user. Recheck. */
  1628. u = get_user_by_host(from);
  1629. m->split = 0;
  1630. m->last = now;
  1631. m->delay = 0L;
  1632. m->flags = (chan_hasop(m) ? WASOP : 0) | (chan_hashalfop(m) ? WASHALFOP : 0);
  1633. m->user = u;
  1634. set_handle_laston(chan->dname, u, now);
  1635. m->flags |= STOPWHO;
  1636. putlog(LOG_JOIN, chan->dname, "%s (%s) returned to %s.", nick, uhost,
  1637. chan->dname);
  1638. } else {
  1639. if (m)
  1640. killmember(chan, nick);
  1641. m = newmember(chan);
  1642. m->joined = now;
  1643. m->split = 0L;
  1644. m->flags = 0;
  1645. m->last = now;
  1646. m->delay = 0L;
  1647. strcpy(m->nick, nick);
  1648. strcpy(m->userhost, uhost);
  1649. m->user = u;
  1650. m->flags |= STOPWHO;
  1651. check_tcl_join(nick, uhost, u, chan->dname);
  1652. /* The tcl binding might have deleted the current user and the
  1653. * current channel, so we'll now have to re-check whether they
  1654. * both still exist.
  1655. */
  1656. chan = findchan(chname);
  1657. if (!chan) {
  1658. if (ch_dname)
  1659. chan = findchan_by_dname(ch_dname);
  1660. else
  1661. chan = findchan_by_dname(chname);
  1662. }
  1663. if (!chan)
  1664. /* The channel doesn't exist anymore, so get out of here. */
  1665. goto exit;
  1666. /* The record saved in the channel record always gets updated,
  1667. * so we can use that. */
  1668. u = m->user;
  1669. if (match_my_nick(nick)) {
  1670. /* It was me joining! Need to update the channel record with the
  1671. * unique name for the channel (as the server see's it). <cybah>
  1672. */
  1673. strncpy(chan->name, chname, 81);
  1674. chan->name[80] = 0;
  1675. chan->status &= ~CHAN_JUPED;
  1676. /* ... and log us joining. Using chan->dname for the channel is
  1677. * important in this case. As the config file will never contain
  1678. * logs with the unique name.
  1679. */
  1680. if (chname[0] == '!')
  1681. putlog(LOG_JOIN | LOG_MISC, chan->dname, "%s joined %s (%s)",
  1682. nick, chan->dname, chname);
  1683. else
  1684. putlog(LOG_JOIN | LOG_MISC, chan->dname, "%s joined %s.", nick,
  1685. chname);
  1686. reset_chan_info(chan, (CHAN_RESETALL & ~CHAN_RESETTOPIC));
  1687. } else {
  1688. struct chanuserrec *cr;
  1689. putlog(LOG_JOIN, chan->dname,
  1690. "%s (%s) joined %s.", nick, uhost, chan->dname);
  1691. /* Don't re-display greeting if they've been on the channel
  1692. * recently.
  1693. */
  1694. if (u) {
  1695. struct laston_info *li = 0;
  1696. cr = get_chanrec(m->user, chan->dname);
  1697. if (!cr && no_chanrec_info)
  1698. li = get_user(&USERENTRY_LASTON, m->user);
  1699. if (channel_greet(chan) && use_info &&
  1700. ((cr && now - cr->laston > wait_info) ||
  1701. (no_chanrec_info && (!li || now - li->laston > wait_info)))) {
  1702. char s1[512], *s;
  1703. if (!(u->flags & USER_BOT)) {
  1704. s = get_user(&USERENTRY_INFO, u);
  1705. get_handle_chaninfo(u->handle, chan->dname, s1);
  1706. /* Locked info line overides non-locked channel specific
  1707. * info line.
  1708. */
  1709. if (!s || (s1[0] && (s[0] != '@' || s1[0] == '@')))
  1710. s = s1;
  1711. if (s[0] == '@')
  1712. s++;
  1713. if (s && s[0])
  1714. dprintf(DP_HELP, "PRIVMSG %s :[%s] %s\n", chan->name, nick,
  1715. s);
  1716. }
  1717. }
  1718. }
  1719. set_handle_laston(chan->dname, u, now);
  1720. }
  1721. }
  1722. if (me_op(chan) || me_halfop(chan)) {
  1723. /* Check for and reset exempts and invites.
  1724. *
  1725. * This will require further checking to account for when to use the
  1726. * various modes.
  1727. */
  1728. if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'I') == NULL)) &&
  1729. (u_match_mask(global_invites, from) ||
  1730. u_match_mask(chan->invites, from)))
  1731. refresh_invite(chan, from);
  1732. if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'b') == NULL)) &&
  1733. (!use_exempts || (!u_match_mask(global_exempts, from) &&
  1734. !u_match_mask(chan->exempts, from)))) {
  1735. if (channel_enforcebans(chan) && !chan_op(fr) && !glob_op(fr) &&
  1736. !glob_friend(fr) && !chan_friend(fr) && !chan_sentkick(m) &&
  1737. (!use_exempts || !isexempted(chan, from)) && (me_op(chan) ||
  1738. (me_halfop(chan) && !chan_hasop(m)))) {
  1739. for (b = chan->channel.ban; b->mask[0]; b = b->next) {
  1740. if (match_addr(b->mask, from)) {
  1741. dprintf(DP_SERVER, "KICK %s %s :%s\n", chname, m->nick,
  1742. IRC_YOUREBANNED);
  1743. m->flags |= SENTKICK;
  1744. goto exit;
  1745. }
  1746. }
  1747. }
  1748. /* If it matches a ban, dispose of them. */
  1749. if (u_match_mask(global_bans, from) || u_match_mask(chan->bans, from))
  1750. refresh_ban_kick(chan, from, nick);
  1751. else if (!chan_sentkick(m) && (glob_kick(fr) || chan_kick(fr)) &&
  1752. (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) {
  1753. check_exemptlist(chan, from);
  1754. quickban(chan, from);
  1755. p = get_user(&USERENTRY_COMMENT, m->user);
  1756. dprintf(DP_MODE, "KICK %s %s :%s\n", chname, nick,
  1757. (p && (p[0] != '@')) ? p : IRC_COMMENTKICK);
  1758. m->flags |= SENTKICK;
  1759. }
  1760. }
  1761. #ifdef NO_HALFOP_CHANMODES
  1762. if (me_op(chan)) {
  1763. #endif
  1764. if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'o') == NULL)) &&
  1765. (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) &&
  1766. (channel_autoop(chan) || glob_autoop(fr) || chan_autoop(fr))) {
  1767. if (!chan->aop_min)
  1768. add_mode(chan, '+', 'o', nick);
  1769. else {
  1770. set_delay(chan, nick);
  1771. m->flags |= SENTOP;
  1772. }
  1773. } else if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'h') == NULL)) &&
  1774. (chan_halfop(fr) || (glob_halfop(fr) &&
  1775. !chan_dehalfop(fr))) && (channel_autohalfop(chan) ||
  1776. glob_autohalfop(fr) || chan_autohalfop(fr))) {
  1777. if (!chan->aop_min)
  1778. add_mode(chan, '+', 'h', nick);
  1779. else {
  1780. set_delay(chan, nick);
  1781. m->flags |= SENTHALFOP;
  1782. }
  1783. } else if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'v') == NULL)) &&
  1784. ((channel_autovoice(chan) && (chan_voice(fr) ||
  1785. (glob_voice(fr) && !chan_quiet(fr)))) ||
  1786. ((glob_gvoice(fr) || chan_gvoice(fr)) &&
  1787. !chan_quiet(fr)))) {
  1788. if (!chan->aop_min)
  1789. add_mode(chan, '+', 'v', nick);
  1790. else {
  1791. set_delay(chan, nick);
  1792. m->flags |= SENTVOICE;
  1793. }
  1794. }
  1795. #ifdef NO_HALFOP_CHANMODES
  1796. }
  1797. #endif
  1798. }
  1799. }
  1800. }
  1801. exit:
  1802. if (ch_dname)
  1803. nfree(ch_dname);
  1804. return 0;
  1805. }
  1806. /* Got a part
  1807. */
  1808. static int gotpart(char *from, char *msg)
  1809. {
  1810. char *nick, *chname, *key;
  1811. struct chanset_t *chan;
  1812. struct userrec *u;
  1813. chname = newsplit(&msg);
  1814. fixcolon(chname);
  1815. fixcolon(msg);
  1816. chan = findchan(chname);
  1817. if (chan && channel_inactive(chan)) {
  1818. clear_channel(chan, 1);
  1819. chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
  1820. return 0;
  1821. }
  1822. if (chan && !channel_pending(chan)) {
  1823. u = get_user_by_host(from);
  1824. nick = splitnick(&from);
  1825. if (!channel_active(chan)) {
  1826. /* whoa! */
  1827. putlog(LOG_MISC, chan->dname,
  1828. "confused bot: guess I'm on %s and didn't realize it",
  1829. chan->dname);
  1830. chan->status |= CHAN_ACTIVE;
  1831. chan->status &= ~CHAN_PEND;
  1832. reset_chan_info(chan, CHAN_RESETALL);
  1833. }
  1834. set_handle_laston(chan->dname, u, now);
  1835. /* This must be directly above the killmember, in case we're doing anything
  1836. * to the record that would affect the above */
  1837. check_tcl_part(nick, from, u, chan->dname, msg);
  1838. chan = findchan(chname);
  1839. if (!chan)
  1840. return 0;
  1841. killmember(chan, nick);
  1842. if (msg[0])
  1843. putlog(LOG_JOIN, chan->dname, "%s (%s) left %s (%s).", nick, from,
  1844. chan->dname, msg);
  1845. else
  1846. putlog(LOG_JOIN, chan->dname, "%s (%s) left %s.", nick, from,
  1847. chan->dname);
  1848. /* If it was me, all hell breaks loose... */
  1849. if (match_my_nick(nick)) {
  1850. clear_channel(chan, 1);
  1851. chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
  1852. if (!channel_inactive(chan)) {
  1853. key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
  1854. if (key[0])
  1855. dprintf(DP_SERVER, "JOIN %s %s\n",
  1856. chan->name[0] ? chan->name : chan->dname, key);
  1857. else
  1858. dprintf(DP_SERVER, "JOIN %s\n",
  1859. chan->name[0] ? chan->name : chan->dname);
  1860. }
  1861. } else
  1862. check_lonely_channel(chan);
  1863. }
  1864. return 0;
  1865. }
  1866. /* Got a kick
  1867. */
  1868. static int gotkick(char *from, char *origmsg)
  1869. {
  1870. char *nick, *whodid, *chname, s1[UHOSTLEN], buf[UHOSTLEN], *uhost = buf;
  1871. char buf2[511], *msg, *key;
  1872. memberlist *m;
  1873. struct chanset_t *chan;
  1874. struct userrec *u;
  1875. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  1876. strncpy(buf2, origmsg, 510);
  1877. buf2[510] = 0;
  1878. msg = buf2;
  1879. chname = newsplit(&msg);
  1880. chan = findchan(chname);
  1881. if (!chan)
  1882. return 0;
  1883. nick = newsplit(&msg);
  1884. if (match_my_nick(nick) && channel_pending(chan) &&
  1885. !channel_inactive(chan)) {
  1886. chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
  1887. key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
  1888. if (key[0])
  1889. dprintf(DP_SERVER, "JOIN %s %s\n",
  1890. chan->name[0] ? chan->name : chan->dname, key);
  1891. else
  1892. dprintf(DP_SERVER, "JOIN %s\n",
  1893. chan->name[0] ? chan->name : chan->dname);
  1894. clear_channel(chan, 1);
  1895. return 0; /* rejoin if kicked before getting needed info <Wcc[08/08/02]> */
  1896. }
  1897. if (channel_active(chan)) {
  1898. fixcolon(msg);
  1899. u = get_user_by_host(from);
  1900. strcpy(uhost, from);
  1901. whodid = splitnick(&uhost);
  1902. detect_chan_flood(whodid, uhost, from, chan, FLOOD_KICK, nick);
  1903. chan = findchan(chname);
  1904. if (!chan)
  1905. return 0;
  1906. m = ismember(chan, whodid);
  1907. if (m)
  1908. m->last = now;
  1909. /* This _needs_ to use chan->dname <cybah> */
  1910. get_user_flagrec(u, &fr, chan->dname);
  1911. set_handle_laston(chan->dname, u, now);
  1912. check_tcl_kick(whodid, uhost, u, chan->dname, nick, msg);
  1913. chan = findchan(chname);
  1914. if (!chan)
  1915. return 0;
  1916. m = ismember(chan, nick);
  1917. if (m) {
  1918. struct userrec *u2;
  1919. simple_sprintf(s1, "%s!%s", m->nick, m->userhost);
  1920. u2 = get_user_by_host(s1);
  1921. set_handle_laston(chan->dname, u2, now);
  1922. maybe_revenge(chan, from, s1, REVENGE_KICK);
  1923. }
  1924. putlog(LOG_MODES, chan->dname, "%s kicked from %s by %s: %s", s1,
  1925. chan->dname, from, msg);
  1926. /* Kicked ME?!? the sods! */
  1927. if (match_my_nick(nick) && !channel_inactive(chan)) {
  1928. chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
  1929. key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
  1930. if (key[0])
  1931. dprintf(DP_SERVER, "JOIN %s %s\n",
  1932. chan->name[0] ? chan->name : chan->dname, key);
  1933. else
  1934. dprintf(DP_SERVER, "JOIN %s\n",
  1935. chan->name[0] ? chan->name : chan->dname);
  1936. clear_channel(chan, 1);
  1937. } else {
  1938. killmember(chan, nick);
  1939. check_lonely_channel(chan);
  1940. }
  1941. }
  1942. return 0;
  1943. }
  1944. /* Got a nick change
  1945. */
  1946. static int gotnick(char *from, char *msg)
  1947. {
  1948. char *nick, *chname, s1[UHOSTLEN], buf[UHOSTLEN], *uhost = buf;
  1949. unsigned char found = 0;
  1950. memberlist *m, *mm;
  1951. struct chanset_t *chan, *oldchan = NULL;
  1952. struct userrec *u;
  1953. struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
  1954. strcpy(uhost, from);
  1955. nick = splitnick(&uhost);
  1956. fixcolon(msg);
  1957. clear_chanlist_member(nick); /* Cache for nick 'nick' is meaningless now. */
  1958. for (chan = chanset; chan; chan = chan->next) {
  1959. oldchan = chan;
  1960. chname = chan->dname;
  1961. m = ismember(chan, nick);
  1962. if (m) {
  1963. putlog(LOG_JOIN, chan->dname, "Nick change: %s -> %s", nick, msg);
  1964. m->last = now;
  1965. if (rfc_casecmp(nick, msg)) {
  1966. /* Not just a capitalization change */
  1967. mm = ismember(chan, msg);
  1968. if (mm) {
  1969. /* Someone on channel with old nick?! */
  1970. if (mm->split)
  1971. putlog(LOG_JOIN, chan->dname,
  1972. "Possible future nick collision: %s", mm->nick);
  1973. else
  1974. putlog(LOG_MISC, chan->dname,
  1975. "* Bug: nick change to existing nick");
  1976. killmember(chan, mm->nick);
  1977. }
  1978. }
  1979. /*
  1980. * Banned?
  1981. */
  1982. /* Compose a nick!user@host for the new nick */
  1983. sprintf(s1, "%s!%s", msg, uhost);
  1984. strcpy(m->nick, msg);
  1985. detect_chan_flood(msg, uhost, from, chan, FLOOD_NICK, NULL);
  1986. if (!findchan_by_dname(chname)) {
  1987. chan = oldchan;
  1988. continue;
  1989. }
  1990. /* don't fill the serverqueue with modes or kicks in a nickflood */
  1991. if (chan_sentkick(m) || chan_sentdeop(m) || chan_sentop(m) ||
  1992. chan_sentdehalfop(m) || chan_senthalfop(m) || chan_sentdevoice(m) ||
  1993. chan_sentvoice(m))
  1994. m->flags |= STOPCHECK;
  1995. /* Any pending kick or mode to the old nick is lost. */
  1996. m->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTDEHALFOP | SENTHALFOP |
  1997. SENTVOICE | SENTDEVOICE);
  1998. /* nick-ban or nick is +k or something? */
  1999. if (!chan_stopcheck(m)) {
  2000. get_user_flagrec(m->user ? m->user : get_user_by_host(s1), &fr,
  2001. chan->dname);
  2002. check_this_member(chan, m->nick, &fr);
  2003. }
  2004. /* Make sure this is in the loop, someone could have changed the record
  2005. * in an earlier iteration of the loop. */
  2006. u = get_user_by_host(from);
  2007. found = 1;
  2008. check_tcl_nick(nick, uhost, u, chan->dname, msg);
  2009. if (!findchan_by_dname(chname)) {
  2010. chan = oldchan;
  2011. continue;
  2012. }
  2013. }
  2014. }
  2015. if (!found) {
  2016. u = get_user_by_host(from);
  2017. s1[0] = '*';
  2018. s1[1] = 0;
  2019. check_tcl_nick(nick, uhost, u, s1, msg);
  2020. }
  2021. return 0;
  2022. }
  2023. /* Signoff, similar to part.
  2024. */
  2025. static int gotquit(char *from, char *msg)
  2026. {
  2027. char *nick, *chname, *p, *alt;
  2028. int split = 0;
  2029. char from2[NICKMAX + UHOSTMAX + 1];
  2030. memberlist *m;
  2031. struct chanset_t *chan, *oldchan = NULL;
  2032. struct userrec *u;
  2033. strcpy(from2, from);
  2034. u = get_user_by_host(from2);
  2035. nick = splitnick(&from);
  2036. fixcolon(msg);
  2037. /* Fred1: Instead of expensive wild_match on signoff, quicker method.
  2038. * Determine if signoff string matches "%.% %.%", and only one
  2039. * space.
  2040. */
  2041. p = strchr(msg, ' ');
  2042. if (p && (p == strrchr(msg, ' '))) {
  2043. char *z1, *z2;
  2044. *p = 0;
  2045. z1 = strchr(p + 1, '.');
  2046. z2 = strchr(msg, '.');
  2047. if (z1 && z2 && (*(z1 + 1) != 0) && (z1 - 1 != p) &&
  2048. (z2 + 1 != p) && (z2 != msg)) {
  2049. /* Server split, or else it looked like it anyway (no harm in
  2050. * assuming)
  2051. */
  2052. split = 1;
  2053. } else
  2054. *p = ' ';
  2055. }
  2056. for (chan = chanset; chan; chan = chan->next) {
  2057. oldchan = chan;
  2058. chname = chan->dname;
  2059. m = ismember(chan, nick);
  2060. if (m) {
  2061. u = get_user_by_host(from2);
  2062. if (u)
  2063. /* If you remove this, the bot will crash when the user record in
  2064. * question is removed/modified during the tcl binds below, and the
  2065. * users was on more than one monitored channel */
  2066. set_handle_laston(chan->dname, u, now);
  2067. if (split) {
  2068. m->split = now;
  2069. check_tcl_splt(nick, from, u, chan->dname);
  2070. if (!findchan_by_dname(chname)) {
  2071. chan = oldchan;
  2072. continue;
  2073. }
  2074. putlog(LOG_JOIN, chan->dname, "%s (%s) got netsplit.", nick, from);
  2075. } else {
  2076. check_tcl_sign(nick, from, u, chan->dname, msg);
  2077. if (!findchan_by_dname(chname)) {
  2078. chan = oldchan;
  2079. continue;
  2080. }
  2081. putlog(LOG_JOIN, chan->dname, "%s (%s) left irc: %s", nick, from, msg);
  2082. killmember(chan, nick);
  2083. check_lonely_channel(chan);
  2084. }
  2085. }
  2086. }
  2087. /* Our nick quit? if so, grab it. Heck, our altnick quit maybe, maybe
  2088. * we want it.
  2089. */
  2090. if (keepnick) {
  2091. alt = get_altbotnick();
  2092. if (!rfc_casecmp(nick, origbotname)) {
  2093. putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname);
  2094. dprintf(DP_SERVER, "NICK %s\n", origbotname);
  2095. } else if (alt[0]) {
  2096. if (!rfc_casecmp(nick, alt) && strcmp(botname, origbotname)) {
  2097. putlog(LOG_MISC, "*", IRC_GETALTNICK, alt);
  2098. dprintf(DP_SERVER, "NICK %s\n", alt);
  2099. }
  2100. }
  2101. }
  2102. return 0;
  2103. }
  2104. /* Got a private message.
  2105. */
  2106. static int gotmsg(char *from, char *msg)
  2107. {
  2108. char *to, *realto, buf[UHOSTLEN], *nick, buf2[512], *uhost = buf, *p, *p1,
  2109. *code, *ctcp;
  2110. int ctcp_count = 0, ignoring;
  2111. struct chanset_t *chan;
  2112. struct userrec *u;
  2113. /* Only handle if message is to a channel, or to @#channel. */
  2114. /* FIXME: Properly handle ovNotices (@+#channel), vNotices (+#channel), etc. */
  2115. if (!strchr(CHANMETA "@", msg[0]))
  2116. return 0;
  2117. to = newsplit(&msg);
  2118. realto = (to[0] == '@') ? to + 1 : to;
  2119. chan = findchan(realto);
  2120. if (!chan)
  2121. return 0; /* Unknown channel; don't process. */
  2122. fixcolon(msg);
  2123. strcpy(uhost, from);
  2124. nick = splitnick(&uhost);
  2125. ignoring = match_ignore(from);
  2126. /* Check for CTCP: */
  2127. ctcp_reply[0] = 0;
  2128. p = strchr(msg, 1);
  2129. while (p && *p) {
  2130. p++;
  2131. p1 = p;
  2132. while ((*p != 1) && *p)
  2133. p++;
  2134. if (*p == 1) {
  2135. *p = 0;
  2136. ctcp = buf2;
  2137. strcpy(ctcp, p1);
  2138. strcpy(p1 - 1, p + 1);
  2139. detect_chan_flood(nick, uhost, from, chan, strncmp(ctcp, "ACTION ", 7) ?
  2140. FLOOD_CTCP : FLOOD_PRIVMSG, NULL);
  2141. chan = findchan(realto);
  2142. if (!chan)
  2143. return 0;
  2144. /* Respond to the first answer_ctcp */
  2145. p = strchr(msg, 1);
  2146. if (ctcp_count < answer_ctcp) {
  2147. ctcp_count++;
  2148. if (ctcp[0] != ' ') {
  2149. code = newsplit(&ctcp);
  2150. u = get_user_by_host(from);
  2151. if (!ignoring || trigger_on_ignore) {
  2152. if (!check_tcl_ctcp(nick, uhost, u, to, code, ctcp)) {
  2153. chan = findchan(realto);
  2154. if (!chan)
  2155. return 0;
  2156. update_idle(chan->dname, nick);
  2157. }
  2158. if (!ignoring) {
  2159. /* Log DCC, it's to a channel damnit! */
  2160. if (!strcmp(code, "ACTION")) {
  2161. putlog(LOG_PUBLIC, chan->dname, "Action: %s %s", nick, ctcp);
  2162. } else {
  2163. putlog(LOG_PUBLIC, chan->dname,
  2164. "CTCP %s: %s from %s (%s) to %s", code, ctcp, nick,
  2165. from, to);
  2166. }
  2167. }
  2168. }
  2169. }
  2170. }
  2171. }
  2172. }
  2173. /* Send out possible ctcp responses. */
  2174. if (ctcp_reply[0]) {
  2175. if (ctcp_mode != 2) {
  2176. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
  2177. } else {
  2178. if (now - last_ctcp > flud_ctcp_time) {
  2179. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
  2180. count_ctcp = 1;
  2181. } else if (count_ctcp < flud_ctcp_thr) {
  2182. dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
  2183. count_ctcp++;
  2184. }
  2185. last_ctcp = now;
  2186. }
  2187. }
  2188. if (msg[0]) {
  2189. int result = 0;
  2190. /* Check even if we're ignoring the host. (modified by Eule 17.7.99) */
  2191. detect_chan_flood(nick, uhost, from, chan, FLOOD_PRIVMSG, NULL);
  2192. chan = findchan(realto);
  2193. if (!chan)
  2194. return 0;
  2195. update_idle(chan->dname, nick);
  2196. if (!ignoring || trigger_on_ignore) {
  2197. result = check_tcl_pubm(nick, uhost, chan->dname, msg);
  2198. if (!result || !exclusive_binds)
  2199. if (check_tcl_pub(nick, uhost, chan->dname, msg))
  2200. return 0;
  2201. }
  2202. if (!ignoring && result != 2) {
  2203. if (to[0] == '@')
  2204. putlog(LOG_PUBLIC, chan->dname, "@<%s> %s", nick, msg);
  2205. else
  2206. putlog(LOG_PUBLIC, chan->dname, "<%s> %s", nick, msg);
  2207. }
  2208. }
  2209. return 0;
  2210. }
  2211. /* Got a private notice.
  2212. */
  2213. static int gotnotice(char *from, char *msg)
  2214. {
  2215. char *to, *realto, *nick, buf2[512], *p, *p1, buf[512], *uhost = buf;
  2216. char *ctcp, *code;
  2217. struct userrec *u;
  2218. struct chanset_t *chan;
  2219. int ignoring;
  2220. if (!strchr(CHANMETA "@", *msg))
  2221. return 0;
  2222. ignoring = match_ignore(from);
  2223. to = newsplit(&msg);
  2224. realto = (*to == '@') ? to + 1 : to;
  2225. chan = findchan(realto);
  2226. if (!chan)
  2227. return 0; /* Notice to an unknown channel?? */
  2228. fixcolon(msg);
  2229. strcpy(uhost, from);
  2230. nick = splitnick(&uhost);
  2231. u = get_user_by_host(from);
  2232. /* Check for CTCP: */
  2233. p = strchr(msg, 1);
  2234. while (p && *p) {
  2235. p++;
  2236. p1 = p;
  2237. while ((*p != 1) && *p)
  2238. p++;
  2239. if (*p == 1) {
  2240. *p = 0;
  2241. ctcp = buf2;
  2242. strcpy(ctcp, p1);
  2243. strcpy(p1 - 1, p + 1);
  2244. p = strchr(msg, 1);
  2245. detect_chan_flood(nick, uhost, from, chan,
  2246. strncmp(ctcp, "ACTION ", 7) ?
  2247. FLOOD_CTCP : FLOOD_PRIVMSG, NULL);
  2248. chan = findchan(realto);
  2249. if (!chan)
  2250. return 0;
  2251. if (ctcp[0] != ' ') {
  2252. code = newsplit(&ctcp);
  2253. if (!ignoring || trigger_on_ignore) {
  2254. check_tcl_ctcr(nick, uhost, u, chan->dname, code, msg);
  2255. chan = findchan(realto);
  2256. if (!chan)
  2257. return 0;
  2258. if (!ignoring) {
  2259. putlog(LOG_PUBLIC, chan->dname,
  2260. "CTCP reply %s: %s from %s (%s) to %s", code, msg, nick,
  2261. from, chan->dname);
  2262. update_idle(chan->dname, nick);
  2263. }
  2264. }
  2265. }
  2266. }
  2267. }
  2268. if (msg[0]) {
  2269. /* Check even if we're ignoring the host. (modified by Eule 17.7.99) */
  2270. detect_chan_flood(nick, uhost, from, chan, FLOOD_NOTICE, NULL);
  2271. chan = findchan(realto);
  2272. if (!chan)
  2273. return 0;
  2274. update_idle(chan->dname, nick);
  2275. if (!ignoring || trigger_on_ignore)
  2276. if (check_tcl_notc(nick, uhost, u, to, msg) == 2)
  2277. return 0;
  2278. if (!ignoring)
  2279. putlog(LOG_PUBLIC, chan->dname, "-%s:%s- %s", nick, to, msg);
  2280. }
  2281. return 0;
  2282. }
  2283. static cmd_t irc_raw[] = {
  2284. {"324", "", (IntFunc) got324, "irc:324"},
  2285. {"352", "", (IntFunc) got352, "irc:352"},
  2286. {"354", "", (IntFunc) got354, "irc:354"},
  2287. {"315", "", (IntFunc) got315, "irc:315"},
  2288. {"367", "", (IntFunc) got367, "irc:367"},
  2289. {"368", "", (IntFunc) got368, "irc:368"},
  2290. {"403", "", (IntFunc) got403, "irc:403"},
  2291. {"405", "", (IntFunc) got405, "irc:405"},
  2292. {"471", "", (IntFunc) got471, "irc:471"},
  2293. {"473", "", (IntFunc) got473, "irc:473"},
  2294. {"474", "", (IntFunc) got474, "irc:474"},
  2295. {"475", "", (IntFunc) got475, "irc:475"},
  2296. {"INVITE", "", (IntFunc) gotinvite, "irc:invite"},
  2297. {"TOPIC", "", (IntFunc) gottopic, "irc:topic"},
  2298. {"331", "", (IntFunc) got331, "irc:331"},
  2299. {"332", "", (IntFunc) got332, "irc:332"},
  2300. {"JOIN", "", (IntFunc) gotjoin, "irc:join"},
  2301. {"PART", "", (IntFunc) gotpart, "irc:part"},
  2302. {"KICK", "", (IntFunc) gotkick, "irc:kick"},
  2303. {"NICK", "", (IntFunc) gotnick, "irc:nick"},
  2304. {"QUIT", "", (IntFunc) gotquit, "irc:quit"},
  2305. {"PRIVMSG", "", (IntFunc) gotmsg, "irc:msg"},
  2306. {"NOTICE", "", (IntFunc) gotnotice, "irc:notice"},
  2307. {"MODE", "", (IntFunc) gotmode, "irc:mode"},
  2308. {"346", "", (IntFunc) got346, "irc:346"},
  2309. {"347", "", (IntFunc) got347, "irc:347"},
  2310. {"348", "", (IntFunc) got348, "irc:348"},
  2311. {"349", "", (IntFunc) got349, "irc:349"},
  2312. {NULL, NULL, NULL, NULL}
  2313. };