00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 static time_t last_ctcp = (time_t) 0L;
00031 static int count_ctcp = 0;
00032 static time_t last_invtime = (time_t) 0L;
00033 static char last_invchan[300] = "";
00034
00035
00036
00037 #define CHANNEL_ID_LEN 5
00038
00039
00040
00041
00042 static memberlist *newmember(struct chanset_t *chan)
00043 {
00044 memberlist *x;
00045
00046 for (x = chan->channel.member; x && x->nick[0]; x = x->next);
00047 x->next = (memberlist *) channel_malloc(sizeof(memberlist));
00048 x->next->next = NULL;
00049 x->next->nick[0] = 0;
00050 x->next->split = 0L;
00051 x->next->last = 0L;
00052 x->next->delay = 0L;
00053 chan->channel.members++;
00054 return x;
00055 }
00056
00057
00058 static inline void sync_members(struct chanset_t *chan)
00059 {
00060 memberlist *m, *next, *prev;
00061
00062 for (m = chan->channel.member, prev = 0; m && m->nick[0]; m = next) {
00063 next = m->next;
00064 if (!chan_whosynced(m)) {
00065 if (prev)
00066 prev->next = next;
00067 else
00068 chan->channel.member = next;
00069 nfree(m);
00070 chan->channel.members--;
00071 } else
00072 prev = m;
00073 }
00074 }
00075
00076
00077
00078 static void update_idle(char *chname, char *nick)
00079 {
00080 memberlist *m;
00081 struct chanset_t *chan;
00082
00083 chan = findchan_by_dname(chname);
00084 if (chan) {
00085 m = ismember(chan, nick);
00086 if (m)
00087 m->last = now;
00088 }
00089 }
00090
00091
00092
00093 static char *getchanmode(struct chanset_t *chan)
00094 {
00095 static char s[121];
00096 int atr, i;
00097
00098 s[0] = '+';
00099 i = 1;
00100 atr = chan->channel.mode;
00101 if (atr & CHANINV)
00102 s[i++] = 'i';
00103 if (atr & CHANPRIV)
00104 s[i++] = 'p';
00105 if (atr & CHANSEC)
00106 s[i++] = 's';
00107 if (atr & CHANMODER)
00108 s[i++] = 'm';
00109 if (atr & CHANNOCLR)
00110 s[i++] = 'c';
00111 if (atr & CHANNOCTCP)
00112 s[i++] = 'C';
00113 if (atr & CHANREGON)
00114 s[i++] = 'R';
00115 if (atr & CHANTOPIC)
00116 s[i++] = 't';
00117 if (atr & CHANMODREG)
00118 s[i++] = 'M';
00119 if (atr & CHANLONLY)
00120 s[i++] = 'r';
00121 if (atr & CHANDELJN)
00122 s[i++] = 'D';
00123 if (atr & CHANSTRIP)
00124 s[i++] = 'u';
00125 if (atr & CHANNONOTC)
00126 s[i++] = 'N';
00127 if (atr & CHANNOAMSG)
00128 s[i++] = 'T';
00129 if (atr & CHANINVIS)
00130 s[i++] = 'd';
00131 if (atr & CHANNOMSG)
00132 s[i++] = 'n';
00133 if (atr & CHANANON)
00134 s[i++] = 'a';
00135 if (atr & CHANKEY)
00136 s[i++] = 'k';
00137 if (chan->channel.maxmembers != 0)
00138 s[i++] = 'l';
00139 s[i] = 0;
00140 if (chan->channel.key[0])
00141 i += sprintf(s + i, " %s", chan->channel.key);
00142 if (chan->channel.maxmembers != 0)
00143 sprintf(s + i, " %d", chan->channel.maxmembers);
00144 return s;
00145 }
00146
00147 static void check_exemptlist(struct chanset_t *chan, char *from)
00148 {
00149 masklist *e;
00150 int ok = 0;
00151
00152 if (!use_exempts)
00153 return;
00154
00155 for (e = chan->channel.exempt; e->mask[0]; e = e->next)
00156 if (match_addr(e->mask, from)) {
00157 add_mode(chan, '-', 'e', e->mask);
00158 ok = 1;
00159 }
00160 if (prevent_mixing && ok)
00161 flush_mode(chan, QUICK);
00162 }
00163
00164
00165
00166
00167
00168
00169 static void do_mask(struct chanset_t *chan, masklist *m, char *mask, char mode)
00170 {
00171 for (; m && m->mask[0]; m = m->next)
00172 if (cmp_masks(mask, m->mask) && rfc_casecmp(mask, m->mask))
00173 add_mode(chan, '-', mode, m->mask);
00174 add_mode(chan, '+', mode, mask);
00175 flush_mode(chan, QUICK);
00176 }
00177
00178
00179
00180
00181 static int detect_chan_flood(char *floodnick, char *floodhost, char *from,
00182 struct chanset_t *chan, int which, char *victim)
00183 {
00184 char h[UHOSTLEN], ftype[12], *p;
00185 struct userrec *u;
00186 memberlist *m;
00187 int thr = 0, lapse = 0;
00188 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00189
00190 if (!chan || (which < 0) || (which >= FLOOD_CHAN_MAX))
00191 return 0;
00192
00193
00194 if (match_my_nick(floodnick))
00195 return 0;
00196
00197
00198 if (!egg_strcasecmp(floodhost, botuserhost))
00199 return 0;
00200
00201 m = ismember(chan, floodnick);
00202
00203
00204
00205
00206 if (!m && (which != FLOOD_JOIN))
00207 return 0;
00208
00209 get_user_flagrec(get_user_by_host(from), &fr, chan->dname);
00210 if (glob_bot(fr) || ((which == FLOOD_DEOP) && (glob_master(fr) ||
00211 chan_master(fr)) && (glob_friend(fr) || chan_friend(fr))) ||
00212 ((which == FLOOD_KICK) && (glob_master(fr) || chan_master(fr)) &&
00213 (glob_friend(fr) || chan_friend(fr))) || ((which != FLOOD_DEOP) &&
00214 (which != FLOOD_KICK) && (glob_friend(fr) || chan_friend(fr))) ||
00215 (channel_dontkickops(chan) && (chan_op(fr) || (glob_op(fr) &&
00216 !chan_deop(fr)))))
00217 return 0;
00218
00219
00220 switch (which) {
00221 case FLOOD_PRIVMSG:
00222 case FLOOD_NOTICE:
00223 thr = chan->flood_pub_thr;
00224 lapse = chan->flood_pub_time;
00225 strcpy(ftype, "pub");
00226 break;
00227 case FLOOD_CTCP:
00228 thr = chan->flood_ctcp_thr;
00229 lapse = chan->flood_ctcp_time;
00230 strcpy(ftype, "pub");
00231 break;
00232 case FLOOD_NICK:
00233 thr = chan->flood_nick_thr;
00234 lapse = chan->flood_nick_time;
00235 strcpy(ftype, "nick");
00236 break;
00237 case FLOOD_JOIN:
00238 thr = chan->flood_join_thr;
00239 lapse = chan->flood_join_time;
00240 strcpy(ftype, "join");
00241 break;
00242 case FLOOD_DEOP:
00243 thr = chan->flood_deop_thr;
00244 lapse = chan->flood_deop_time;
00245 strcpy(ftype, "deop");
00246 break;
00247 case FLOOD_KICK:
00248 thr = chan->flood_kick_thr;
00249 lapse = chan->flood_kick_time;
00250 strcpy(ftype, "kick");
00251 break;
00252 }
00253 if ((thr == 0) || (lapse == 0))
00254 return 0;
00255
00256 if ((which == FLOOD_KICK) || (which == FLOOD_DEOP))
00257 p = floodnick;
00258 else {
00259 p = strchr(floodhost, '@');
00260 if (p) {
00261 p++;
00262 }
00263 if (!p)
00264 return 0;
00265 }
00266 if (rfc_casecmp(chan->floodwho[which], p)) {
00267 strncpy(chan->floodwho[which], p, 80);
00268 chan->floodwho[which][80] = 0;
00269 chan->floodtime[which] = now;
00270 chan->floodnum[which] = 1;
00271 return 0;
00272 }
00273 if (chan->floodtime[which] < now - lapse) {
00274
00275 chan->floodtime[which] = now;
00276 chan->floodnum[which] = 1;
00277 return 0;
00278 }
00279
00280 if (which == FLOOD_DEOP) {
00281 if (!rfc_casecmp(chan->deopd, victim))
00282 return 0;
00283 else
00284 strcpy(chan->deopd, victim);
00285 }
00286 chan->floodnum[which]++;
00287 if (chan->floodnum[which] >= thr) {
00288
00289 chan->floodnum[which] = 0;
00290 chan->floodtime[which] = 0;
00291 chan->floodwho[which][0] = 0;
00292 if (which == FLOOD_DEOP)
00293 chan->deopd[0] = 0;
00294 u = get_user_by_host(from);
00295 if (check_tcl_flud(floodnick, floodhost, u, ftype, chan->dname))
00296 return 0;
00297 switch (which) {
00298 case FLOOD_PRIVMSG:
00299 case FLOOD_NOTICE:
00300 case FLOOD_CTCP:
00301
00302 if (!chan_sentkick(m) &&
00303 (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) {
00304 putlog(LOG_MODES, chan->dname, IRC_FLOODKICK, floodnick);
00305 dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, floodnick, CHAN_FLOOD);
00306 m->flags |= SENTKICK;
00307 }
00308 return 1;
00309 case FLOOD_JOIN:
00310 case FLOOD_NICK:
00311 if (use_exempts && (u_match_mask(global_exempts, from) ||
00312 u_match_mask(chan->exempts, from)))
00313 return 1;
00314 simple_sprintf(h, "*!*@%s", p);
00315 if (!isbanned(chan, h) && (me_op(chan) || me_halfop(chan))) {
00316 check_exemptlist(chan, from);
00317 do_mask(chan, chan->channel.ban, h, 'b');
00318 }
00319 if ((u_match_mask(global_bans, from)) ||
00320 (u_match_mask(chan->bans, from)))
00321 return 1;
00322 if (which == FLOOD_JOIN)
00323 putlog(LOG_MISC | LOG_JOIN, chan->dname, IRC_FLOODIGNORE3, p);
00324 else
00325 putlog(LOG_MISC | LOG_JOIN, chan->dname, IRC_FLOODIGNORE4, p);
00326 strcpy(ftype + 4, " flood");
00327 u_addban(chan, h, botnetnick, ftype, now + (60 * chan->ban_time), 0);
00328 if (!channel_enforcebans(chan) && (me_op(chan) || me_halfop(chan))) {
00329 char s[UHOSTLEN];
00330
00331 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00332 sprintf(s, "%s!%s", m->nick, m->userhost);
00333 if (wild_match(h, s) && (m->joined >= chan->floodtime[which]) &&
00334 !chan_sentkick(m) && !match_my_nick(m->nick) && (me_op(chan) ||
00335 (me_halfop(chan) && !chan_hasop(m)))) {
00336 m->flags |= SENTKICK;
00337 if (which == FLOOD_JOIN)
00338 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, m->nick,
00339 IRC_JOIN_FLOOD);
00340 else
00341 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, m->nick,
00342 IRC_NICK_FLOOD);
00343 }
00344 }
00345 }
00346 return 1;
00347 case FLOOD_KICK:
00348 if ((me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) &&
00349 !chan_sentkick(m)) {
00350 putlog(LOG_MODES, chan->dname, "Kicking %s, for mass kick.", floodnick);
00351 dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, floodnick,
00352 IRC_MASSKICK);
00353 m->flags |= SENTKICK;
00354 }
00355 return 1;
00356 case FLOOD_DEOP:
00357 if ((me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) &&
00358 !chan_sentkick(m)) {
00359 putlog(LOG_MODES, chan->dname, CHAN_MASSDEOP, chan->dname, from);
00360 dprintf(DP_MODE, "KICK %s %s :%s\n",
00361 chan->name, floodnick, CHAN_MASSDEOP_KICK);
00362 m->flags |= SENTKICK;
00363 }
00364 return 1;
00365 }
00366 }
00367 return 0;
00368 }
00369
00370
00371
00372 static char *quickban(struct chanset_t *chan, char *uhost)
00373 {
00374 static char s1[512];
00375
00376 maskaddr(uhost, s1, chan->ban_type);
00377 do_mask(chan, chan->channel.ban, s1, 'b');
00378 return s1;
00379 }
00380
00381
00382
00383
00384 static void kick_all(struct chanset_t *chan, char *hostmask, char *comment,
00385 int bantype)
00386 {
00387 memberlist *m;
00388 char kicknick[512], s[UHOSTLEN];
00389 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00390 int k, l, flushed;
00391
00392 if (!me_op(chan) && !me_halfop(chan))
00393 return;
00394
00395 k = 0;
00396 flushed = 0;
00397 kicknick[0] = 0;
00398 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00399 sprintf(s, "%s!%s", m->nick, m->userhost);
00400 get_user_flagrec(m->user ? m->user : get_user_by_host(s), &fr, chan->dname);
00401 if ((me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) &&
00402 match_addr(hostmask, s) && !chan_sentkick(m) &&
00403 !match_my_nick(m->nick) && !chan_issplit(m) &&
00404 !glob_friend(fr) && !chan_friend(fr) && !(use_exempts && ((bantype &&
00405 isexempted(chan, s)) || (u_match_mask(global_exempts, s) ||
00406 u_match_mask(chan->exempts, s)))) && !(channel_dontkickops(chan) &&
00407 (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))))) {
00408 if (!flushed) {
00409
00410 flush_mode(chan, QUICK);
00411 flushed += 1;
00412 }
00413 m->flags |= SENTKICK;
00414 if (kicknick[0])
00415 strcat(kicknick, ",");
00416 strcat(kicknick, m->nick);
00417 k += 1;
00418 l = strlen(chan->name) + strlen(kicknick) + strlen(comment) + 5;
00419 if ((kick_method != 0 && k == kick_method) || (l > 480)) {
00420 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, kicknick, comment);
00421 k = 0;
00422 kicknick[0] = 0;
00423 }
00424 }
00425 }
00426 if (k > 0)
00427 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, kicknick, comment);
00428 }
00429
00430
00431
00432 static void refresh_ban_kick(struct chanset_t *chan, char *user, char *nick)
00433 {
00434 register maskrec *b;
00435 memberlist *m;
00436 int cycle;
00437
00438 m = ismember(chan, nick);
00439 if (!m || chan_sentkick(m))
00440 return;
00441
00442
00443 for (cycle = 0; cycle < 2; cycle++) {
00444 for (b = cycle ? chan->bans : global_bans; b; b = b->next) {
00445 if (match_addr(b->mask, user)) {
00446 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00447 char c[512];
00448 char s[UHOSTLEN];
00449
00450 sprintf(s, "%s!%s", m->nick, m->userhost);
00451 get_user_flagrec(m->user ? m->user : get_user_by_host(s), &fr,
00452 chan->dname);
00453 if (!glob_friend(fr) && !chan_friend(fr)) {
00454 add_mode(chan, '-', 'o', nick);
00455 check_exemptlist(chan, user);
00456 do_mask(chan, chan->channel.ban, b->mask, 'b');
00457 b->lastactive = now;
00458 if (b->desc && b->desc[0] != '@')
00459 egg_snprintf(c, sizeof c, "%s %s", IRC_PREBANNED, b->desc);
00460 else
00461 c[0] = 0;
00462 kick_all(chan, b->mask, c[0] ? c : IRC_YOUREBANNED, 0);
00463 return;
00464 }
00465 }
00466 }
00467 }
00468 }
00469
00470
00471
00472
00473 static void refresh_exempt(struct chanset_t *chan, char *user)
00474 {
00475 maskrec *e;
00476 masklist *b;
00477 int cycle;
00478
00479
00480 for (cycle = 0; cycle < 2; cycle++) {
00481 for (e = cycle ? chan->exempts : global_exempts; e; e = e->next) {
00482 if (mask_match(user, e->mask)) {
00483 for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
00484 if (mask_match(b->mask, user)) {
00485 if (e->lastactive < now - 60 && !isexempted(chan, e->mask)) {
00486 do_mask(chan, chan->channel.exempt, e->mask, 'e');
00487 e->lastactive = now;
00488 }
00489 }
00490 }
00491 }
00492 }
00493 }
00494 }
00495
00496 static void refresh_invite(struct chanset_t *chan, char *user)
00497 {
00498 maskrec *i;
00499 int cycle;
00500
00501
00502 for (cycle = 0; cycle < 2; cycle++) {
00503 for (i = cycle ? chan->invites : global_invites; i; i = i->next) {
00504 if (match_addr(i->mask, user) &&
00505 ((i->flags & MASKREC_STICKY) || (chan->channel.mode & CHANINV))) {
00506 if (i->lastactive < now - 60 && !isinvited(chan, i->mask)) {
00507 do_mask(chan, chan->channel.invite, i->mask, 'I');
00508 i->lastactive = now;
00509 return;
00510 }
00511 }
00512 }
00513 }
00514 }
00515
00516
00517
00518 static void enforce_bans(struct chanset_t *chan)
00519 {
00520 char me[UHOSTLEN];
00521 masklist *b;
00522
00523 if (HALFOP_CANTDOMODE('b'))
00524 return;
00525
00526 simple_sprintf(me, "%s!%s", botname, botuserhost);
00527
00528 for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
00529 if (!match_addr(b->mask, me))
00530 if (!isexempted(chan, b->mask))
00531 kick_all(chan, b->mask, IRC_YOUREBANNED, 1);
00532 }
00533 }
00534
00535
00536
00537
00538
00539
00540 static void recheck_bans(struct chanset_t *chan)
00541 {
00542 maskrec *u;
00543 int cycle;
00544
00545
00546 for (cycle = 0; cycle < 2; cycle++) {
00547 for (u = cycle ? chan->bans : global_bans; u; u = u->next)
00548 if (!isbanned(chan, u->mask) && (!channel_dynamicbans(chan) ||
00549 (u->flags & MASKREC_STICKY)))
00550 add_mode(chan, '+', 'b', u->mask);
00551 }
00552 }
00553
00554
00555
00556
00557
00558
00559 static void recheck_exempts(struct chanset_t *chan)
00560 {
00561 maskrec *e;
00562 masklist *b;
00563 int cycle;
00564
00565
00566 for (cycle = 0; cycle < 2; cycle++) {
00567 for (e = cycle ? chan->exempts : global_exempts; e; e = e->next) {
00568 if (!isexempted(chan, e->mask) &&
00569 (!channel_dynamicexempts(chan) || (e->flags & MASKREC_STICKY)))
00570 add_mode(chan, '+', 'e', e->mask);
00571 for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
00572 if (mask_match(b->mask, e->mask) &&
00573 !isexempted(chan, e->mask))
00574 add_mode(chan, '+', 'e', e->mask);
00575
00576 }
00577 }
00578 }
00579 }
00580
00581
00582
00583
00584
00585
00586 static void recheck_invites(struct chanset_t *chan)
00587 {
00588 maskrec *ir;
00589 int cycle;
00590
00591
00592 for (cycle = 0; cycle < 2; cycle++) {
00593 for (ir = cycle ? chan->invites : global_invites; ir; ir = ir->next) {
00594
00595
00596
00597 if (!isinvited(chan, ir->mask) && ((!channel_dynamicinvites(chan) &&
00598 !(chan->channel.mode & CHANINV)) || ir->flags & MASKREC_STICKY))
00599 add_mode(chan, '+', 'I', ir->mask);
00600
00601 }
00602 }
00603 }
00604
00605
00606
00607 static void resetmasks(struct chanset_t *chan, masklist *m, maskrec *mrec,
00608 maskrec *global_masks, char mode)
00609 {
00610 if (!me_op(chan) && (!me_halfop(chan) ||
00611 (strchr(NOHALFOPS_MODES, 'b') != NULL) ||
00612 (strchr(NOHALFOPS_MODES, 'e') != NULL) ||
00613 (strchr(NOHALFOPS_MODES, 'I') != NULL)))
00614 return;
00615
00616
00617 for (; m && m->mask[0]; m = m->next) {
00618 if (!u_equals_mask(global_masks, m->mask) && !u_equals_mask(mrec, m->mask))
00619 add_mode(chan, '-', mode, m->mask);
00620 }
00621
00622
00623 switch (mode) {
00624 case 'b':
00625 recheck_bans(chan);
00626 break;
00627 case 'e':
00628 recheck_exempts(chan);
00629 break;
00630 case 'I':
00631 recheck_invites(chan);
00632 break;
00633 default:
00634 putlog(LOG_MISC, "*", "(!) Invalid mode '%c' in resetmasks()", mode);
00635 break;
00636 }
00637 }
00638 static void check_this_ban(struct chanset_t *chan, char *banmask, int sticky)
00639 {
00640 memberlist *m;
00641 char user[UHOSTLEN];
00642
00643 if (HALFOP_CANTDOMODE('b'))
00644 return;
00645
00646 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00647 sprintf(user, "%s!%s", m->nick, m->userhost);
00648 if (match_addr(banmask, user) &&
00649 !(use_exempts &&
00650 (u_match_mask(global_exempts, user) ||
00651 u_match_mask(chan->exempts, user))))
00652 refresh_ban_kick(chan, user, m->nick);
00653 }
00654 if (!isbanned(chan, banmask) && (!channel_dynamicbans(chan) || sticky))
00655 add_mode(chan, '+', 'b', banmask);
00656 }
00657
00658 static void recheck_channel_modes(struct chanset_t *chan)
00659 {
00660 int cur = chan->channel.mode, mns = chan->mode_mns_prot,
00661 pls = chan->mode_pls_prot;
00662
00663 if (!(chan->status & CHAN_ASKEDMODES)) {
00664 if (pls & CHANINV && !(cur & CHANINV))
00665 add_mode(chan, '+', 'i', "");
00666 else if (mns & CHANINV && cur & CHANINV)
00667 add_mode(chan, '-', 'i', "");
00668 if (pls & CHANPRIV && !(cur & CHANPRIV))
00669 add_mode(chan, '+', 'p', "");
00670 else if (mns & CHANPRIV && cur & CHANPRIV)
00671 add_mode(chan, '-', 'p', "");
00672 if (pls & CHANSEC && !(cur & CHANSEC))
00673 add_mode(chan, '+', 's', "");
00674 else if (mns & CHANSEC && cur & CHANSEC)
00675 add_mode(chan, '-', 's', "");
00676 if (pls & CHANMODER && !(cur & CHANMODER))
00677 add_mode(chan, '+', 'm', "");
00678 else if (mns & CHANMODER && cur & CHANMODER)
00679 add_mode(chan, '-', 'm', "");
00680 if (pls & CHANNOCLR && !(cur & CHANNOCLR))
00681 add_mode(chan, '+', 'c', "");
00682 else if (mns & CHANNOCLR && cur & CHANNOCLR)
00683 add_mode(chan, '-', 'c', "");
00684 if (pls & CHANNOCTCP && !(cur & CHANNOCTCP))
00685 add_mode(chan, '+', 'C', "");
00686 else if (mns & CHANNOCTCP && cur & CHANNOCTCP)
00687 add_mode(chan, '-', 'C', "");
00688 if (pls & CHANREGON && !(cur & CHANREGON))
00689 add_mode(chan, '+', 'R', "");
00690 else if (mns & CHANREGON && cur & CHANREGON)
00691 add_mode(chan, '-', 'R', "");
00692 if (pls & CHANMODREG && !(cur & CHANMODREG))
00693 add_mode(chan, '+', 'M', "");
00694 else if (mns & CHANMODREG && cur & CHANMODREG)
00695 add_mode(chan, '-', 'M', "");
00696 if (pls & CHANLONLY && !(cur & CHANLONLY))
00697 add_mode(chan, '+', 'r', "");
00698 else if (mns & CHANLONLY && cur & CHANLONLY)
00699 add_mode(chan, '-', 'r', "");
00700 if (pls & CHANDELJN && !(cur & CHANDELJN))
00701 add_mode(chan, '+', 'D', "");
00702 else if (mns & CHANDELJN && cur & CHANDELJN)
00703 add_mode(chan, '-', 'D', "");
00704 if (pls & CHANSTRIP && !(cur & CHANSTRIP))
00705 add_mode(chan, '+', 'u', "");
00706 else if (mns & CHANSTRIP && cur & CHANSTRIP)
00707 add_mode(chan, '-', 'u', "");
00708 if (pls & CHANNONOTC && !(cur & CHANNONOTC))
00709 add_mode(chan, '+', 'N', "");
00710 else if (mns & CHANNONOTC && cur & CHANNONOTC)
00711 add_mode(chan, '-', 'N', "");
00712 if (pls & CHANNOAMSG && !(cur & CHANNOAMSG))
00713 add_mode(chan, '+', 'T', "");
00714 else if (mns & CHANNOAMSG && cur & CHANNOAMSG)
00715 add_mode(chan, '-', 'T', "");
00716 if (pls & CHANTOPIC && !(cur & CHANTOPIC))
00717 add_mode(chan, '+', 't', "");
00718 else if (mns & CHANTOPIC && cur & CHANTOPIC)
00719 add_mode(chan, '-', 't', "");
00720 if (pls & CHANNOMSG && !(cur & CHANNOMSG))
00721 add_mode(chan, '+', 'n', "");
00722 else if ((mns & CHANNOMSG) && (cur & CHANNOMSG))
00723 add_mode(chan, '-', 'n', "");
00724 if ((pls & CHANANON) && !(cur & CHANANON))
00725 add_mode(chan, '+', 'a', "");
00726 else if ((mns & CHANANON) && (cur & CHANANON))
00727 add_mode(chan, '-', 'a', "");
00728 if ((pls & CHANQUIET) && !(cur & CHANQUIET))
00729 add_mode(chan, '+', 'q', "");
00730 else if ((mns & CHANQUIET) && (cur & CHANQUIET))
00731 add_mode(chan, '-', 'q', "");
00732 if ((chan->limit_prot != 0) && (chan->channel.maxmembers == 0)) {
00733 char s[50];
00734
00735 sprintf(s, "%d", chan->limit_prot);
00736 add_mode(chan, '+', 'l', s);
00737 } else if ((mns & CHANLIMIT) && (chan->channel.maxmembers != 0))
00738 add_mode(chan, '-', 'l', "");
00739 if (chan->key_prot[0]) {
00740 if (rfc_casecmp(chan->channel.key, chan->key_prot) != 0) {
00741 if (chan->channel.key[0])
00742 add_mode(chan, '-', 'k', chan->channel.key);
00743 add_mode(chan, '+', 'k', chan->key_prot);
00744 }
00745 } else if ((mns & CHANKEY) && (chan->channel.key[0]))
00746 add_mode(chan, '-', 'k', chan->channel.key);
00747 }
00748 }
00749
00750 static void check_this_member(struct chanset_t *chan, char *nick,
00751 struct flag_record *fr)
00752 {
00753 memberlist *m;
00754 char s[UHOSTLEN], *p;
00755
00756 m = ismember(chan, nick);
00757 if (!m || match_my_nick(nick) || (!me_op(chan) && !me_halfop(chan)))
00758 return;
00759
00760
00761 #ifdef NO_HALFOP_CHANMODES
00762 if (me_op(chan)) {
00763 #else
00764 if (me_op(chan) || me_halfop(chan)) {
00765 #endif
00766 if (HALFOP_CANDOMODE('o')) {
00767 if (chan_hasop(m) && ((chan_deop(*fr) || (glob_deop(*fr) &&
00768 !chan_op(*fr))) || (channel_bitch(chan) && (!chan_op(*fr) &&
00769 !(glob_op(*fr) && !chan_deop(*fr)))))) {
00770 add_mode(chan, '-', 'o', m->nick);
00771 }
00772 if (!chan_hasop(m) && (chan_op(*fr) || (glob_op(*fr) &&
00773 !chan_deop(*fr))) && (channel_autoop(chan) || glob_autoop(*fr) ||
00774 chan_autoop(*fr))) {
00775 if (!chan->aop_min)
00776 add_mode(chan, '+', 'o', m->nick);
00777 else {
00778 set_delay(chan, m->nick);
00779 m->flags |= SENTOP;
00780 }
00781 }
00782 }
00783
00784 if (HALFOP_CANDOMODE('h')) {
00785 if (chan_hashalfop(m) && ((chan_dehalfop(*fr) || (glob_dehalfop(*fr) &&
00786 !chan_halfop(*fr)) || (channel_bitch(chan) && (!chan_halfop(*fr) &&
00787 !(glob_halfop(*fr) && !chan_dehalfop(*fr)))))))
00788 add_mode(chan, '-', 'h', m->nick);
00789 if (!chan_sentop(m) && !chan_hasop(m) && !chan_hashalfop(m) &&
00790 (chan_halfop(*fr) || (glob_halfop(*fr) && !chan_dehalfop(*fr))) &&
00791 (channel_autohalfop(chan) || glob_autohalfop(*fr) ||
00792 chan_autohalfop(*fr))) {
00793 if (!chan->aop_min)
00794 add_mode(chan, '+', 'h', m->nick);
00795 else {
00796 set_delay(chan, m->nick);
00797 m->flags |= SENTHALFOP;
00798 }
00799 }
00800 }
00801
00802 if (HALFOP_CANDOMODE('v')) {
00803 if (chan_hasvoice(m) && (chan_quiet(*fr) || (glob_quiet(*fr) &&
00804 !chan_voice(*fr))))
00805 add_mode(chan, '-', 'v', m->nick);
00806 if (!chan_hasvoice(m) && !chan_hasop(m) && !chan_hashalfop(m) &&
00807 (chan_voice(*fr) || (glob_voice(*fr) && !chan_quiet(*fr))) &&
00808 (channel_autovoice(chan) || glob_gvoice(*fr) || chan_gvoice(*fr))) {
00809 if (!chan->aop_min)
00810 add_mode(chan, '+', 'v', m->nick);
00811 else {
00812 set_delay(chan, m->nick);
00813 m->flags |= SENTVOICE;
00814 }
00815 }
00816 }
00817 }
00818
00819 if (!me_op(chan) && (!me_halfop(chan) ||
00820 (strchr(NOHALFOPS_MODES, 'b') != NULL) ||
00821 (strchr(NOHALFOPS_MODES, 'e') != NULL) ||
00822 (strchr(NOHALFOPS_MODES, 'I') != NULL)))
00823 return;
00824
00825 sprintf(s, "%s!%s", m->nick, m->userhost);
00826 if (use_invites && (u_match_mask(global_invites, s) ||
00827 u_match_mask(chan->invites, s)))
00828 refresh_invite(chan, s);
00829 if (!(use_exempts && (u_match_mask(global_exempts, s) ||
00830 u_match_mask(chan->exempts, s)))) {
00831 if (u_match_mask(global_bans, s) || u_match_mask(chan->bans, s))
00832 refresh_ban_kick(chan, s, m->nick);
00833 if (!chan_sentkick(m) && (chan_kick(*fr) || glob_kick(*fr)) &&
00834 (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) {
00835 check_exemptlist(chan, s);
00836 quickban(chan, m->userhost);
00837 p = get_user(&USERENTRY_COMMENT, m->user);
00838 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, m->nick,
00839 p ? p : IRC_POLITEKICK);
00840 m->flags |= SENTKICK;
00841 }
00842 }
00843 }
00844
00845 static void check_this_user(char *hand, int delete, char *host)
00846 {
00847 char s[UHOSTLEN];
00848 memberlist *m;
00849 struct userrec *u;
00850 struct chanset_t *chan;
00851 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00852
00853 for (chan = chanset; chan; chan = chan->next)
00854 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00855 sprintf(s, "%s!%s", m->nick, m->userhost);
00856 u = m->user ? m->user : get_user_by_host(s);
00857 if ((u && !egg_strcasecmp(u->handle, hand) && delete < 2) ||
00858 (!u && delete == 2 && match_addr(host, fixfrom(s)))) {
00859 u = delete ? NULL : u;
00860 get_user_flagrec(u, &fr, chan->dname);
00861 check_this_member(chan, m->nick, &fr);
00862 }
00863 }
00864 }
00865
00866
00867
00868 static void recheck_channel(struct chanset_t *chan, int dobans)
00869 {
00870 memberlist *m;
00871 char s[UHOSTLEN];
00872 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00873 static int stacking = 0;
00874 int stop_reset = 0;
00875
00876 if (stacking || !userlist)
00877 return;
00878
00879 stacking++;
00880
00881 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00882 sprintf(s, "%s!%s", m->nick, m->userhost);
00883 if (!m->user && !m->tried_getuser) {
00884 m->tried_getuser = 1;
00885 m->user = get_user_by_host(s);
00886 }
00887 get_user_flagrec(m->user, &fr, chan->dname);
00888 if (glob_bot(fr) && chan_hasop(m) && !match_my_nick(m->nick))
00889 stop_reset = 1;
00890
00891
00892 m->flags &= ~(SENTHALFOP | SENTKICK);
00893 check_this_member(chan, m->nick, &fr);
00894 }
00895
00896
00897
00898 if (chan->ircnet_status & (CHAN_ASKED_EXEMPTS | CHAN_ASKED_INVITED)) {
00899 chan->ircnet_status &= ~(CHAN_ASKED_EXEMPTS | CHAN_ASKED_INVITED);
00900 reset_chan_info(chan, CHAN_RESETEXEMPTS | CHAN_RESETINVITED);
00901 }
00902 if (dobans) {
00903 if (channel_nouserbans(chan) && !stop_reset)
00904 resetbans(chan);
00905 else
00906 recheck_bans(chan);
00907 if (use_invites) {
00908 if (channel_nouserinvites(chan) && !stop_reset)
00909 resetinvites(chan);
00910 else
00911 recheck_invites(chan);
00912 }
00913 if (use_exempts) {
00914 if (channel_nouserexempts(chan) && !stop_reset)
00915 resetexempts(chan);
00916 else
00917 recheck_exempts(chan);
00918 }
00919 if (channel_enforcebans(chan))
00920 enforce_bans(chan);
00921 if ((chan->status & CHAN_ASKEDMODES) && !channel_inactive(chan))
00922 dprintf(DP_MODE, "MODE %s\n", chan->name);
00923 recheck_channel_modes(chan);
00924 }
00925 stacking--;
00926 }
00927
00928
00929
00930
00931 static int got324(char *from, char *msg)
00932 {
00933 int i = 1, ok = 0;
00934 char *p, *q, *chname;
00935 struct chanset_t *chan;
00936
00937 newsplit(&msg);
00938 chname = newsplit(&msg);
00939 chan = findchan(chname);
00940 if (!chan) {
00941 putlog(LOG_MISC, "*", "%s: %s", IRC_UNEXPECTEDMODE, chname);
00942 dprintf(DP_SERVER, "PART %s\n", chname);
00943 return 0;
00944 }
00945 if (chan->status & CHAN_ASKEDMODES)
00946 ok = 1;
00947 chan->status &= ~CHAN_ASKEDMODES;
00948 chan->channel.mode = 0;
00949 while (msg[i] != 0) {
00950 if (msg[i] == 'i')
00951 chan->channel.mode |= CHANINV;
00952 if (msg[i] == 'p')
00953 chan->channel.mode |= CHANPRIV;
00954 if (msg[i] == 's')
00955 chan->channel.mode |= CHANSEC;
00956 if (msg[i] == 'm')
00957 chan->channel.mode |= CHANMODER;
00958 if (msg[i] == 'c')
00959 chan->channel.mode |= CHANNOCLR;
00960 if (msg[i] == 'C')
00961 chan->channel.mode |= CHANNOCTCP;
00962 if (msg[i] == 'R')
00963 chan->channel.mode |= CHANREGON;
00964 if (msg[i] == 'M')
00965 chan->channel.mode |= CHANMODREG;
00966 if (msg[i] == 'r')
00967 chan->channel.mode |= CHANLONLY;
00968 if (msg[i] == 'D')
00969 chan->channel.mode |= CHANDELJN;
00970 if (msg[i] == 'u')
00971 chan->channel.mode |= CHANSTRIP;
00972 if (msg[i] == 'N')
00973 chan->channel.mode |= CHANNONOTC;
00974 if (msg[i] == 'T')
00975 chan->channel.mode |= CHANNOAMSG;
00976 if (msg[i] == 'd')
00977 chan->channel.mode |= CHANINVIS;
00978 if (msg[i] == 't')
00979 chan->channel.mode |= CHANTOPIC;
00980 if (msg[i] == 'n')
00981 chan->channel.mode |= CHANNOMSG;
00982 if (msg[i] == 'a')
00983 chan->channel.mode |= CHANANON;
00984 if (msg[i] == 'q')
00985 chan->channel.mode |= CHANQUIET;
00986 if (msg[i] == 'k') {
00987 chan->channel.mode |= CHANKEY;
00988 p = strchr(msg, ' ');
00989 if (p != NULL) {
00990 p++;
00991 q = strchr(p, ' ');
00992 if (q != NULL) {
00993 *q = 0;
00994 set_key(chan, p);
00995 strcpy(p, q + 1);
00996 } else {
00997 set_key(chan, p);
00998 *p = 0;
00999 }
01000 }
01001 if ((chan->channel.mode & CHANKEY) && (!chan->channel.key[0] ||
01002 !strcmp("*", chan->channel.key)))
01003
01004
01005
01006
01007
01008 chan->status |= CHAN_ASKEDMODES;
01009 }
01010 if (msg[i] == 'l') {
01011 p = strchr(msg, ' ');
01012 if (p != NULL) {
01013 p++;
01014 q = strchr(p, ' ');
01015 if (q != NULL) {
01016 *q = 0;
01017 chan->channel.maxmembers = atoi(p);
01018 strcpy(p, q + 1);
01019 } else {
01020 chan->channel.maxmembers = atoi(p);
01021 *p = 0;
01022 }
01023 }
01024 }
01025 i++;
01026 }
01027 if (ok)
01028 recheck_channel_modes(chan);
01029 return 0;
01030 }
01031
01032 static int got352or4(struct chanset_t *chan, char *user, char *host,
01033 char *nick, char *flags)
01034 {
01035 char userhost[UHOSTLEN];
01036 memberlist *m;
01037
01038 m = ismember(chan, nick);
01039 if (!m) {
01040 m = newmember(chan);
01041 m->joined = m->split = m->delay = 0L;
01042 m->flags = 0;
01043 m->last = now;
01044 }
01045 strcpy(m->nick, nick);
01046
01047 simple_sprintf(m->userhost, "%s@%s", user, host);
01048 simple_sprintf(userhost, "%s!%s", nick, m->userhost);
01049
01050 m->user = NULL;
01051 if (match_my_nick(nick))
01052 strcpy(botuserhost, m->userhost);
01053 m->flags |= WHO_SYNCED;
01054 if (strpbrk(flags, opchars) != NULL)
01055 m->flags |= (CHANOP | WASOP);
01056 else
01057 m->flags &= ~(CHANOP | WASOP);
01058 if (strchr(flags, '%') != NULL)
01059 m->flags |= (CHANHALFOP | WASHALFOP);
01060 else
01061 m->flags &= ~(CHANHALFOP | WASHALFOP);
01062 if (strchr(flags, '+') != NULL)
01063 m->flags |= CHANVOICE;
01064 else
01065 m->flags &= ~CHANVOICE;
01066 if (!(m->flags & (CHANVOICE | CHANOP | CHANHALFOP)))
01067 m->flags |= STOPWHO;
01068 if (match_my_nick(nick) && any_ops(chan) && !me_op(chan)) {
01069 check_tcl_need(chan->dname, "op");
01070 if (chan->need_op[0])
01071 do_tcl("need-op", chan->need_op);
01072 }
01073 m->user = get_user_by_host(userhost);
01074 return 0;
01075 }
01076
01077
01078
01079 static int got352(char *from, char *msg)
01080 {
01081 char *nick, *user, *host, *chname, *flags;
01082 struct chanset_t *chan;
01083
01084 newsplit(&msg);
01085 chname = newsplit(&msg);
01086 chan = findchan(chname);
01087 if (chan) {
01088 user = newsplit(&msg);
01089 host = newsplit(&msg);
01090 newsplit(&msg);
01091 nick = newsplit(&msg);
01092 flags = newsplit(&msg);
01093 got352or4(chan, user, host, nick, flags);
01094 }
01095 return 0;
01096 }
01097
01098
01099
01100 static int got354(char *from, char *msg)
01101 {
01102 char *nick, *user, *host, *chname, *flags;
01103 struct chanset_t *chan;
01104
01105 if (use_354) {
01106 newsplit(&msg);
01107 if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) {
01108 chname = newsplit(&msg);
01109 chan = findchan(chname);
01110 if (chan) {
01111 user = newsplit(&msg);
01112 host = newsplit(&msg);
01113 nick = newsplit(&msg);
01114 flags = newsplit(&msg);
01115 got352or4(chan, user, host, nick, flags);
01116 }
01117 }
01118 }
01119 return 0;
01120 }
01121
01122
01123
01124
01125
01126 static int got315(char *from, char *msg)
01127 {
01128 char *chname, *key;
01129 struct chanset_t *chan;
01130
01131 newsplit(&msg);
01132 chname = newsplit(&msg);
01133 chan = findchan(chname);
01134 if (!chan || !channel_pending(chan))
01135 return 0;
01136
01137 sync_members(chan);
01138 chan->status |= CHAN_ACTIVE;
01139 chan->status &= ~CHAN_PEND;
01140 if (!ismember(chan, botname)) {
01141 putlog(LOG_MISC | LOG_JOIN, chan->dname, "Oops, I'm not really on %s.",
01142 chan->dname);
01143 clear_channel(chan, 1);
01144 chan->status &= ~CHAN_ACTIVE;
01145
01146 key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
01147 if (key[0])
01148 dprintf(DP_SERVER, "JOIN %s %s\n",
01149 chan->name[0] ? chan->name : chan->dname, key);
01150 else
01151 dprintf(DP_SERVER, "JOIN %s\n",
01152 chan->name[0] ? chan->name : chan->dname);
01153 } else if (me_op(chan))
01154 recheck_channel(chan, 1);
01155 else if (chan->channel.members == 1)
01156 chan->status |= CHAN_STOP_CYCLE;
01157 return 0;
01158 }
01159
01160
01161
01162
01163 static int got367(char *from, char *origmsg)
01164 {
01165 char *ban, *who, *chname, buf[511], *msg;
01166 struct chanset_t *chan;
01167
01168 strncpy(buf, origmsg, 510);
01169 buf[510] = 0;
01170 msg = buf;
01171 newsplit(&msg);
01172 chname = newsplit(&msg);
01173 chan = findchan(chname);
01174 if (!chan || !(channel_pending(chan) || channel_active(chan)))
01175 return 0;
01176 ban = newsplit(&msg);
01177 who = newsplit(&msg);
01178
01179 if (who[0])
01180 newban(chan, ban, who);
01181 else
01182 newban(chan, ban, "existent");
01183 return 0;
01184 }
01185
01186
01187
01188
01189 static int got368(char *from, char *msg)
01190 {
01191 struct chanset_t *chan;
01192 char *chname;
01193
01194
01195 newsplit(&msg);
01196 chname = newsplit(&msg);
01197 chan = findchan(chname);
01198 if (chan)
01199 chan->status &= ~CHAN_ASKEDBANS;
01200
01201
01202
01203 return 0;
01204 }
01205
01206
01207
01208
01209 static int got348(char *from, char *origmsg)
01210 {
01211 char *exempt, *who, *chname, buf[511], *msg;
01212 struct chanset_t *chan;
01213
01214 if (use_exempts == 0)
01215 return 0;
01216
01217 strncpy(buf, origmsg, 510);
01218 buf[510] = 0;
01219 msg = buf;
01220 newsplit(&msg);
01221 chname = newsplit(&msg);
01222 chan = findchan(chname);
01223 if (!chan || !(channel_pending(chan) || channel_active(chan)))
01224 return 0;
01225 exempt = newsplit(&msg);
01226 who = newsplit(&msg);
01227
01228 if (who[0])
01229 newexempt(chan, exempt, who);
01230 else
01231 newexempt(chan, exempt, "existent");
01232 return 0;
01233 }
01234
01235
01236
01237
01238 static int got349(char *from, char *msg)
01239 {
01240 struct chanset_t *chan;
01241 char *chname;
01242
01243 if (use_exempts == 1) {
01244 newsplit(&msg);
01245 chname = newsplit(&msg);
01246 chan = findchan(chname);
01247 if (chan)
01248 chan->ircnet_status &= ~CHAN_ASKED_EXEMPTS;
01249 }
01250 return 0;
01251 }
01252
01253
01254
01255
01256 static int got346(char *from, char *origmsg)
01257 {
01258 char *invite, *who, *chname, buf[511], *msg;
01259 struct chanset_t *chan;
01260
01261 strncpy(buf, origmsg, 510);
01262 buf[510] = 0;
01263 msg = buf;
01264 if (use_invites == 0)
01265 return 0;
01266 newsplit(&msg);
01267 chname = newsplit(&msg);
01268 chan = findchan(chname);
01269 if (!chan || !(channel_pending(chan) || channel_active(chan)))
01270 return 0;
01271 invite = newsplit(&msg);
01272 who = newsplit(&msg);
01273
01274 if (who[0])
01275 newinvite(chan, invite, who);
01276 else
01277 newinvite(chan, invite, "existent");
01278 return 0;
01279 }
01280
01281
01282
01283
01284 static int got347(char *from, char *msg)
01285 {
01286 struct chanset_t *chan;
01287 char *chname;
01288
01289 if (use_invites == 1) {
01290 newsplit(&msg);
01291 chname = newsplit(&msg);
01292 chan = findchan(chname);
01293 if (chan)
01294 chan->ircnet_status &= ~CHAN_ASKED_INVITED;
01295 }
01296 return 0;
01297 }
01298
01299
01300
01301 static int got405(char *from, char *msg)
01302 {
01303 char *chname;
01304
01305 newsplit(&msg);
01306 chname = newsplit(&msg);
01307 putlog(LOG_MISC, "*", IRC_TOOMANYCHANS, chname);
01308 return 0;
01309 }
01310
01311
01312
01313
01314
01315
01316
01317 static int got403(char *from, char *msg)
01318 {
01319 char *chname;
01320 struct chanset_t *chan;
01321
01322 newsplit(&msg);
01323 chname = newsplit(&msg);
01324 if (chname && chname[0] == '!') {
01325 chan = findchan_by_dname(chname);
01326 if (!chan) {
01327 chan = findchan(chname);
01328 if (!chan)
01329 return 0;
01330
01331
01332
01333
01334 putlog(LOG_MISC, "*",
01335 "Unique channel %s does not exist... Attempting to join with "
01336 "short name.", chname);
01337 dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
01338 } else {
01339
01340
01341
01342 putlog(LOG_MISC, "*",
01343 "Channel %s does not exist... Attempting to create it.", chname);
01344 dprintf(DP_SERVER, "JOIN !%s\n", chan->dname);
01345 }
01346 }
01347 return 0;
01348 }
01349
01350
01351
01352 static int got471(char *from, char *msg)
01353 {
01354 char *chname;
01355 struct chanset_t *chan;
01356
01357 newsplit(&msg);
01358 chname = newsplit(&msg);
01359
01360
01361
01362 if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
01363 chname += CHANNEL_ID_LEN;
01364 chname[0] = '!';
01365 }
01366
01367
01368
01369 chan = findchan_by_dname(chname);
01370 if (chan) {
01371 putlog(LOG_JOIN, chan->dname, IRC_CHANFULL, chan->dname);
01372 check_tcl_need(chan->dname, "limit");
01373
01374 chan = findchan_by_dname(chname);
01375 if (!chan)
01376 return 0;
01377
01378 if (chan->need_limit[0])
01379 do_tcl("need-limit", chan->need_limit);
01380 } else
01381 putlog(LOG_JOIN, chname, IRC_CHANFULL, chname);
01382 return 0;
01383 }
01384
01385
01386
01387 static int got473(char *from, char *msg)
01388 {
01389 char *chname;
01390 struct chanset_t *chan;
01391
01392 newsplit(&msg);
01393 chname = newsplit(&msg);
01394
01395
01396
01397 if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
01398 chname += CHANNEL_ID_LEN;
01399 chname[0] = '!';
01400 }
01401
01402
01403
01404 chan = findchan_by_dname(chname);
01405 if (chan) {
01406 putlog(LOG_JOIN, chan->dname, IRC_CHANINVITEONLY, chan->dname);
01407 check_tcl_need(chan->dname, "invite");
01408
01409 chan = findchan_by_dname(chname);
01410 if (!chan)
01411 return 0;
01412
01413 if (chan->need_invite[0])
01414 do_tcl("need-invite", chan->need_invite);
01415 } else
01416 putlog(LOG_JOIN, chname, IRC_CHANINVITEONLY, chname);
01417 return 0;
01418 }
01419
01420
01421
01422 static int got474(char *from, char *msg)
01423 {
01424 char *chname;
01425 struct chanset_t *chan;
01426
01427 newsplit(&msg);
01428 chname = newsplit(&msg);
01429
01430
01431
01432 if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
01433 chname += CHANNEL_ID_LEN;
01434 chname[0] = '!';
01435 }
01436
01437
01438
01439 chan = findchan_by_dname(chname);
01440 if (chan) {
01441 putlog(LOG_JOIN, chan->dname, IRC_BANNEDFROMCHAN, chan->dname);
01442 check_tcl_need(chan->dname, "unban");
01443
01444 chan = findchan_by_dname(chname);
01445 if (!chan)
01446 return 0;
01447
01448 if (chan->need_unban[0])
01449 do_tcl("need-unban", chan->need_unban);
01450 } else
01451 putlog(LOG_JOIN, chname, IRC_BANNEDFROMCHAN, chname);
01452 return 0;
01453 }
01454
01455
01456
01457 static int got475(char *from, char *msg)
01458 {
01459 char *chname;
01460 struct chanset_t *chan;
01461
01462 newsplit(&msg);
01463 chname = newsplit(&msg);
01464
01465
01466
01467 if ((chname[0] == '!') && (strlen(chname) > CHANNEL_ID_LEN)) {
01468 chname += CHANNEL_ID_LEN;
01469 chname[0] = '!';
01470 }
01471
01472
01473
01474 chan = findchan_by_dname(chname);
01475 if (chan) {
01476 putlog(LOG_JOIN, chan->dname, IRC_BADCHANKEY, chan->dname);
01477 if (chan->channel.key[0]) {
01478 nfree(chan->channel.key);
01479 chan->channel.key = (char *) channel_malloc(1);
01480 chan->channel.key[0] = 0;
01481
01482 if (chan->key_prot[0])
01483 dprintf(DP_SERVER, "JOIN %s %s\n", chan->dname, chan->key_prot);
01484 else
01485 dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
01486 } else {
01487 check_tcl_need(chan->dname, "key");
01488
01489 chan = findchan_by_dname(chname);
01490 if (!chan)
01491 return 0;
01492
01493 if (chan->need_key[0])
01494 do_tcl("need-key", chan->need_key);
01495 }
01496 } else
01497 putlog(LOG_JOIN, chname, IRC_BADCHANKEY, chname);
01498 return 0;
01499 }
01500
01501
01502
01503 static int gotinvite(char *from, char *msg)
01504 {
01505 char *nick, *key;
01506 struct chanset_t *chan;
01507
01508 newsplit(&msg);
01509 fixcolon(msg);
01510 nick = splitnick(&from);
01511 if (!rfc_casecmp(last_invchan, msg))
01512 if (now - last_invtime < 30)
01513 return 0;
01514 putlog(LOG_MISC, "*", "%s!%s invited me to %s", nick, from, msg);
01515 strncpy(last_invchan, msg, 299);
01516 last_invchan[299] = 0;
01517 last_invtime = now;
01518 chan = findchan(msg);
01519 if (!chan)
01520
01521 chan = findchan_by_dname(msg);
01522
01523 if (chan && (channel_pending(chan) || channel_active(chan)))
01524 dprintf(DP_HELP, "NOTICE %s :I'm already here.\n", nick);
01525 else if (chan && !channel_inactive(chan)) {
01526
01527 key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
01528 if (key[0])
01529 dprintf(DP_SERVER, "JOIN %s %s\n",
01530 chan->name[0] ? chan->name : chan->dname, key);
01531 else
01532 dprintf(DP_SERVER, "JOIN %s\n",
01533 chan->name[0] ? chan->name : chan->dname);
01534 }
01535 return 0;
01536 }
01537
01538
01539
01540 static void set_topic(struct chanset_t *chan, char *k)
01541 {
01542 if (chan->channel.topic)
01543 nfree(chan->channel.topic);
01544 if (k && k[0]) {
01545 chan->channel.topic = (char *) channel_malloc(strlen(k) + 1);
01546 strcpy(chan->channel.topic, k);
01547 } else
01548 chan->channel.topic = NULL;
01549 }
01550
01551
01552
01553 static int gottopic(char *from, char *msg)
01554 {
01555 char *nick, *chname;
01556 memberlist *m;
01557 struct chanset_t *chan;
01558 struct userrec *u;
01559
01560 chname = newsplit(&msg);
01561 fixcolon(msg);
01562 u = get_user_by_host(from);
01563 nick = splitnick(&from);
01564 chan = findchan(chname);
01565 if (chan) {
01566 putlog(LOG_JOIN, chan->dname, "Topic changed on %s by %s!%s: %s",
01567 chan->dname, nick, from, msg);
01568 m = ismember(chan, nick);
01569 if (m != NULL)
01570 m->last = now;
01571 set_topic(chan, msg);
01572 check_tcl_topc(nick, from, u, chan->dname, msg);
01573 }
01574 return 0;
01575 }
01576
01577
01578
01579
01580 static int got331(char *from, char *msg)
01581 {
01582 char *chname;
01583 struct chanset_t *chan;
01584
01585 newsplit(&msg);
01586 chname = newsplit(&msg);
01587 chan = findchan(chname);
01588 if (chan) {
01589 set_topic(chan, NULL);
01590 check_tcl_topc("*", "*", NULL, chan->dname, "");
01591 }
01592 return 0;
01593 }
01594
01595
01596
01597
01598 static int got332(char *from, char *msg)
01599 {
01600 struct chanset_t *chan;
01601 char *chname;
01602
01603 newsplit(&msg);
01604 chname = newsplit(&msg);
01605 chan = findchan(chname);
01606 if (chan) {
01607 fixcolon(msg);
01608 set_topic(chan, msg);
01609 check_tcl_topc("*", "*", NULL, chan->dname, msg);
01610 }
01611 return 0;
01612 }
01613
01614
01615
01616 static void set_delay(struct chanset_t *chan, char *nick)
01617 {
01618 time_t a_delay;
01619 int aop_min, aop_max, aop_diff, count = 0;
01620 memberlist *m, *m2;
01621
01622 m = ismember(chan, nick);
01623 if (!m)
01624 return;
01625
01626
01627 aop_min = chan->aop_min;
01628 aop_max = chan->aop_max;
01629 aop_diff = aop_max - aop_min;
01630
01631
01632 if ((aop_min <= 0) || (aop_max <= 0)) {
01633 a_delay = now + 1;
01634
01635
01636
01637
01638 } else if ((aop_min >= aop_max) || (aop_diff > RANDOM_MAX)) {
01639 a_delay = now + aop_min;
01640
01641
01642 } else {
01643 a_delay = now + randint(aop_diff) + aop_min + 1;
01644 }
01645
01646 for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next)
01647 if (m2->delay && !(m2->flags & FULL_DELAY))
01648 count++;
01649
01650 if (count) {
01651 for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next) {
01652 if (m2->delay && !(m2->flags & FULL_DELAY)) {
01653 m2->delay = a_delay;
01654
01655 if (count + 1 >= modesperline)
01656 m2->flags |= FULL_DELAY;
01657
01658 }
01659 }
01660 }
01661
01662 if (count + 1 >= modesperline)
01663 m->flags |= FULL_DELAY;
01664
01665 m->delay = a_delay;
01666 }
01667
01668
01669
01670 static int gotjoin(char *from, char *chname)
01671 {
01672 char *nick, *p, buf[UHOSTLEN], *uhost = buf;
01673 char *ch_dname = NULL;
01674 struct chanset_t *chan;
01675 memberlist *m;
01676 masklist *b;
01677 struct userrec *u;
01678 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
01679
01680 fixcolon(chname);
01681 chan = findchan(chname);
01682 if (!chan && chname[0] == '!') {
01683
01684
01685
01686
01687 int l_chname = strlen(chname);
01688
01689 if (l_chname > (CHANNEL_ID_LEN + 1)) {
01690 ch_dname = nmalloc(l_chname + 1);
01691 if (ch_dname) {
01692 egg_snprintf(ch_dname, l_chname + 2, "!%s",
01693 chname + (CHANNEL_ID_LEN + 1));
01694 chan = findchan_by_dname(ch_dname);
01695 if (!chan) {
01696
01697
01698
01699
01700 chan = findchan_by_dname(chname);
01701 if (chan) {
01702
01703
01704
01705 chan->status |= CHAN_INACTIVE;
01706 putlog(LOG_MISC, "*", "Deactivated channel %s, because it uses "
01707 "an ID channel-name. Use the descriptive name instead.",
01708 chname);
01709 dprintf(DP_SERVER, "PART %s\n", chname);
01710 goto exit;
01711 }
01712 }
01713 }
01714 }
01715 } else if (!chan) {
01716
01717
01718
01719 chan = findchan_by_dname(chname);
01720 }
01721
01722 if (!chan || channel_inactive(chan)) {
01723 strcpy(uhost, from);
01724 nick = splitnick(&uhost);
01725 if (match_my_nick(nick)) {
01726 putlog(LOG_MISC, "*", "joined %s but didn't want to!", chname);
01727 dprintf(DP_MODE, "PART %s\n", chname);
01728 }
01729 } else if (!channel_pending(chan)) {
01730 chan->status &= ~CHAN_STOP_CYCLE;
01731 strcpy(uhost, from);
01732 nick = splitnick(&uhost);
01733 detect_chan_flood(nick, uhost, from, chan, FLOOD_JOIN, NULL);
01734
01735 chan = findchan(chname);
01736 if (!chan) {
01737 if (ch_dname)
01738 chan = findchan_by_dname(ch_dname);
01739 else
01740 chan = findchan_by_dname(chname);
01741 }
01742 if (!chan)
01743
01744 goto exit;
01745
01746
01747 u = get_user_by_host(from);
01748 get_user_flagrec(u, &fr, chan->dname);
01749 if (!channel_active(chan) && !match_my_nick(nick)) {
01750
01751 putlog(LOG_MISC, chan->dname,
01752 "confused bot: guess I'm on %s and didn't realize it",
01753 chan->dname);
01754 chan->status |= CHAN_ACTIVE;
01755 chan->status &= ~CHAN_PEND;
01756 reset_chan_info(chan, CHAN_RESETALL);
01757 } else {
01758 m = ismember(chan, nick);
01759 if (m && m->split && !egg_strcasecmp(m->userhost, uhost)) {
01760 check_tcl_rejn(nick, uhost, u, chan->dname);
01761
01762 chan = findchan(chname);
01763 if (!chan) {
01764 if (ch_dname)
01765 chan = findchan_by_dname(ch_dname);
01766 else
01767 chan = findchan_by_dname(chname);
01768 }
01769 if (!chan)
01770
01771 goto exit;
01772
01773
01774 u = get_user_by_host(from);
01775 m->split = 0;
01776 m->last = now;
01777 m->delay = 0L;
01778 m->flags = (chan_hasop(m) ? WASOP : 0) | (chan_hashalfop(m) ? WASHALFOP : 0);
01779 m->user = u;
01780 set_handle_laston(chan->dname, u, now);
01781 m->flags |= STOPWHO;
01782 putlog(LOG_JOIN, chan->dname, "%s (%s) returned to %s.", nick, uhost,
01783 chan->dname);
01784 } else {
01785 if (m)
01786 killmember(chan, nick);
01787 m = newmember(chan);
01788 m->joined = now;
01789 m->split = 0L;
01790 m->flags = 0;
01791 m->last = now;
01792 m->delay = 0L;
01793 strcpy(m->nick, nick);
01794 strcpy(m->userhost, uhost);
01795 m->user = u;
01796 m->flags |= STOPWHO;
01797
01798 check_tcl_join(nick, uhost, u, chan->dname);
01799
01800
01801
01802
01803
01804 chan = findchan(chname);
01805 if (!chan) {
01806 if (ch_dname)
01807 chan = findchan_by_dname(ch_dname);
01808 else
01809 chan = findchan_by_dname(chname);
01810 }
01811 if (!chan)
01812
01813 goto exit;
01814
01815
01816
01817 u = m->user;
01818
01819 if (match_my_nick(nick)) {
01820
01821
01822
01823 strncpy(chan->name, chname, 81);
01824 chan->name[80] = 0;
01825 chan->status &= ~CHAN_JUPED;
01826
01827
01828
01829
01830
01831 if (chname[0] == '!')
01832 putlog(LOG_JOIN | LOG_MISC, chan->dname, "%s joined %s (%s)",
01833 nick, chan->dname, chname);
01834 else
01835 putlog(LOG_JOIN | LOG_MISC, chan->dname, "%s joined %s.", nick,
01836 chname);
01837 reset_chan_info(chan, (CHAN_RESETALL & ~CHAN_RESETTOPIC));
01838 } else {
01839 struct chanuserrec *cr;
01840
01841 putlog(LOG_JOIN, chan->dname,
01842 "%s (%s) joined %s.", nick, uhost, chan->dname);
01843
01844
01845
01846 if (u) {
01847 struct laston_info *li = 0;
01848
01849 cr = get_chanrec(m->user, chan->dname);
01850 if (!cr && no_chanrec_info)
01851 li = get_user(&USERENTRY_LASTON, m->user);
01852 if (channel_greet(chan) && use_info &&
01853 ((cr && now - cr->laston > wait_info) ||
01854 (no_chanrec_info && (!li || now - li->laston > wait_info)))) {
01855 char s1[512], *s;
01856
01857 if (!(u->flags & USER_BOT)) {
01858 s = get_user(&USERENTRY_INFO, u);
01859 get_handle_chaninfo(u->handle, chan->dname, s1);
01860
01861
01862
01863 if (!s || (s1[0] && (s[0] != '@' || s1[0] == '@')))
01864 s = s1;
01865 if (s[0] == '@')
01866 s++;
01867 if (s && s[0])
01868 dprintf(DP_HELP, "PRIVMSG %s :[%s] %s\n", chan->name, nick,
01869 s);
01870 }
01871 }
01872 }
01873 set_handle_laston(chan->dname, u, now);
01874 }
01875 }
01876 if (me_op(chan) || me_halfop(chan)) {
01877
01878
01879
01880
01881
01882 if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'I') == NULL)) &&
01883 (u_match_mask(global_invites, from) ||
01884 u_match_mask(chan->invites, from)))
01885 refresh_invite(chan, from);
01886 if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'b') == NULL)) &&
01887 (!use_exempts || (!u_match_mask(global_exempts, from) &&
01888 !u_match_mask(chan->exempts, from)))) {
01889 if (channel_enforcebans(chan) && !chan_op(fr) && !glob_op(fr) &&
01890 !glob_friend(fr) && !chan_friend(fr) && !chan_sentkick(m) &&
01891 (!use_exempts || !isexempted(chan, from)) && (me_op(chan) ||
01892 (me_halfop(chan) && !chan_hasop(m)))) {
01893 for (b = chan->channel.ban; b->mask[0]; b = b->next) {
01894 if (match_addr(b->mask, from)) {
01895 dprintf(DP_SERVER, "KICK %s %s :%s\n", chname, m->nick,
01896 IRC_YOUREBANNED);
01897 m->flags |= SENTKICK;
01898 goto exit;
01899 }
01900 }
01901 }
01902
01903 if (u_match_mask(global_bans, from) || u_match_mask(chan->bans, from))
01904 refresh_ban_kick(chan, from, nick);
01905 else if (!chan_sentkick(m) && (glob_kick(fr) || chan_kick(fr)) &&
01906 (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) {
01907 check_exemptlist(chan, from);
01908 quickban(chan, from);
01909 p = get_user(&USERENTRY_COMMENT, m->user);
01910 dprintf(DP_MODE, "KICK %s %s :%s\n", chname, nick,
01911 (p && (p[0] != '@')) ? p : IRC_COMMENTKICK);
01912 m->flags |= SENTKICK;
01913 }
01914 }
01915 #ifdef NO_HALFOP_CHANMODES
01916 if (me_op(chan)) {
01917 #endif
01918 if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'o') == NULL)) &&
01919 (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) &&
01920 (channel_autoop(chan) || glob_autoop(fr) || chan_autoop(fr))) {
01921 if (!chan->aop_min)
01922 add_mode(chan, '+', 'o', nick);
01923 else {
01924 set_delay(chan, nick);
01925 m->flags |= SENTOP;
01926 }
01927 } else if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'h') == NULL)) &&
01928 (chan_halfop(fr) || (glob_halfop(fr) &&
01929 !chan_dehalfop(fr))) && (channel_autohalfop(chan) ||
01930 glob_autohalfop(fr) || chan_autohalfop(fr))) {
01931 if (!chan->aop_min)
01932 add_mode(chan, '+', 'h', nick);
01933 else {
01934 set_delay(chan, nick);
01935 m->flags |= SENTHALFOP;
01936 }
01937 } else if ((me_op(chan) || (strchr(NOHALFOPS_MODES, 'v') == NULL)) &&
01938 ((channel_autovoice(chan) && (chan_voice(fr) ||
01939 (glob_voice(fr) && !chan_quiet(fr)))) ||
01940 ((glob_gvoice(fr) || chan_gvoice(fr)) &&
01941 !chan_quiet(fr)))) {
01942 if (!chan->aop_min)
01943 add_mode(chan, '+', 'v', nick);
01944 else {
01945 set_delay(chan, nick);
01946 m->flags |= SENTVOICE;
01947 }
01948 }
01949 #ifdef NO_HALFOP_CHANMODES
01950 }
01951 #endif
01952 }
01953 }
01954 }
01955
01956 exit:
01957 if (ch_dname)
01958 nfree(ch_dname);
01959 return 0;
01960 }
01961
01962
01963
01964 static int gotpart(char *from, char *msg)
01965 {
01966 char *nick, *chname, *key;
01967 struct chanset_t *chan;
01968 struct userrec *u;
01969
01970 chname = newsplit(&msg);
01971 fixcolon(chname);
01972 fixcolon(msg);
01973 chan = findchan(chname);
01974 if (chan && channel_inactive(chan)) {
01975 clear_channel(chan, 1);
01976 chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
01977 return 0;
01978 }
01979 if (chan && !channel_pending(chan)) {
01980 u = get_user_by_host(from);
01981 nick = splitnick(&from);
01982 if (!channel_active(chan)) {
01983
01984 putlog(LOG_MISC, chan->dname,
01985 "confused bot: guess I'm on %s and didn't realize it",
01986 chan->dname);
01987 chan->status |= CHAN_ACTIVE;
01988 chan->status &= ~CHAN_PEND;
01989 reset_chan_info(chan, CHAN_RESETALL);
01990 }
01991 set_handle_laston(chan->dname, u, now);
01992
01993
01994 check_tcl_part(nick, from, u, chan->dname, msg);
01995
01996 chan = findchan(chname);
01997 if (!chan)
01998 return 0;
01999
02000 killmember(chan, nick);
02001 if (msg[0])
02002 putlog(LOG_JOIN, chan->dname, "%s (%s) left %s (%s).", nick, from,
02003 chan->dname, msg);
02004 else
02005 putlog(LOG_JOIN, chan->dname, "%s (%s) left %s.", nick, from,
02006 chan->dname);
02007
02008 if (match_my_nick(nick)) {
02009 clear_channel(chan, 1);
02010 chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
02011 if (!channel_inactive(chan)) {
02012
02013 key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
02014 if (key[0])
02015 dprintf(DP_SERVER, "JOIN %s %s\n",
02016 chan->name[0] ? chan->name : chan->dname, key);
02017 else
02018 dprintf(DP_SERVER, "JOIN %s\n",
02019 chan->name[0] ? chan->name : chan->dname);
02020 }
02021 } else
02022 check_lonely_channel(chan);
02023 }
02024 return 0;
02025 }
02026
02027
02028
02029 static int gotkick(char *from, char *origmsg)
02030 {
02031 char *nick, *whodid, *chname, s1[UHOSTLEN], buf[UHOSTLEN], *uhost = buf;
02032 char buf2[511], *msg, *key;
02033 memberlist *m;
02034 struct chanset_t *chan;
02035 struct userrec *u;
02036 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
02037
02038 strncpy(buf2, origmsg, 510);
02039 buf2[510] = 0;
02040 msg = buf2;
02041 chname = newsplit(&msg);
02042 chan = findchan(chname);
02043 if (!chan)
02044 return 0;
02045 nick = newsplit(&msg);
02046 if (match_my_nick(nick) && channel_pending(chan) &&
02047 !channel_inactive(chan)) {
02048 chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
02049
02050 key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
02051 if (key[0])
02052 dprintf(DP_SERVER, "JOIN %s %s\n",
02053 chan->name[0] ? chan->name : chan->dname, key);
02054 else
02055 dprintf(DP_SERVER, "JOIN %s\n",
02056 chan->name[0] ? chan->name : chan->dname);
02057 clear_channel(chan, 1);
02058 return 0;
02059 }
02060 if (channel_active(chan)) {
02061 fixcolon(msg);
02062 u = get_user_by_host(from);
02063 strcpy(uhost, from);
02064 whodid = splitnick(&uhost);
02065 detect_chan_flood(whodid, uhost, from, chan, FLOOD_KICK, nick);
02066
02067 chan = findchan(chname);
02068 if (!chan)
02069 return 0;
02070
02071 m = ismember(chan, whodid);
02072 if (m)
02073 m->last = now;
02074
02075 get_user_flagrec(u, &fr, chan->dname);
02076 set_handle_laston(chan->dname, u, now);
02077 check_tcl_kick(whodid, uhost, u, chan->dname, nick, msg);
02078
02079 chan = findchan(chname);
02080 if (!chan)
02081 return 0;
02082
02083 m = ismember(chan, nick);
02084 if (m) {
02085 struct userrec *u2;
02086
02087 simple_sprintf(s1, "%s!%s", m->nick, m->userhost);
02088 u2 = get_user_by_host(s1);
02089 set_handle_laston(chan->dname, u2, now);
02090 maybe_revenge(chan, from, s1, REVENGE_KICK);
02091 }
02092 putlog(LOG_MODES, chan->dname, "%s kicked from %s by %s: %s", s1,
02093 chan->dname, from, msg);
02094
02095 if (match_my_nick(nick) && !channel_inactive(chan)) {
02096 chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
02097
02098 key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
02099 if (key[0])
02100 dprintf(DP_SERVER, "JOIN %s %s\n",
02101 chan->name[0] ? chan->name : chan->dname, key);
02102 else
02103 dprintf(DP_SERVER, "JOIN %s\n",
02104 chan->name[0] ? chan->name : chan->dname);
02105 clear_channel(chan, 1);
02106 } else {
02107 killmember(chan, nick);
02108 check_lonely_channel(chan);
02109 }
02110 }
02111 return 0;
02112 }
02113
02114
02115
02116 static int gotnick(char *from, char *msg)
02117 {
02118 char *nick, *chname, s1[UHOSTLEN], buf[UHOSTLEN], *uhost = buf;
02119 unsigned char found = 0;
02120 memberlist *m, *mm;
02121 struct chanset_t *chan, *oldchan = NULL;
02122 struct userrec *u;
02123 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
02124
02125 strcpy(uhost, from);
02126 nick = splitnick(&uhost);
02127 fixcolon(msg);
02128 clear_chanlist_member(nick);
02129 for (chan = chanset; chan; chan = chan->next) {
02130 oldchan = chan;
02131 chname = chan->dname;
02132 m = ismember(chan, nick);
02133 if (m) {
02134 putlog(LOG_JOIN, chan->dname, "Nick change: %s -> %s", nick, msg);
02135 m->last = now;
02136 if (rfc_casecmp(nick, msg)) {
02137
02138 mm = ismember(chan, msg);
02139 if (mm) {
02140
02141 if (mm->split)
02142 putlog(LOG_JOIN, chan->dname,
02143 "Possible future nick collision: %s", mm->nick);
02144 else
02145 putlog(LOG_MISC, chan->dname,
02146 "* Bug: nick change to existing nick");
02147 killmember(chan, mm->nick);
02148 }
02149 }
02150
02151
02152
02153
02154 sprintf(s1, "%s!%s", msg, uhost);
02155 strcpy(m->nick, msg);
02156 detect_chan_flood(msg, uhost, from, chan, FLOOD_NICK, NULL);
02157
02158 if (!findchan_by_dname(chname)) {
02159 chan = oldchan;
02160 continue;
02161 }
02162
02163 if (chan_sentkick(m) || chan_sentdeop(m) || chan_sentop(m) ||
02164 chan_sentdehalfop(m) || chan_senthalfop(m) || chan_sentdevoice(m) ||
02165 chan_sentvoice(m))
02166 m->flags |= STOPCHECK;
02167
02168 m->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTDEHALFOP | SENTHALFOP |
02169 SENTVOICE | SENTDEVOICE);
02170
02171 if (!chan_stopcheck(m)) {
02172 get_user_flagrec(m->user ? m->user : get_user_by_host(s1), &fr,
02173 chan->dname);
02174 check_this_member(chan, m->nick, &fr);
02175 }
02176
02177
02178 u = get_user_by_host(from);
02179 found = 1;
02180 check_tcl_nick(nick, uhost, u, chan->dname, msg);
02181
02182 if (!findchan_by_dname(chname)) {
02183 chan = oldchan;
02184 continue;
02185 }
02186 }
02187 }
02188 if (!found) {
02189 u = get_user_by_host(from);
02190 s1[0] = '*';
02191 s1[1] = 0;
02192 check_tcl_nick(nick, uhost, u, s1, msg);
02193 }
02194 return 0;
02195 }
02196
02197
02198
02199 static int gotquit(char *from, char *msg)
02200 {
02201 char *nick, *chname, *p, *alt;
02202 int split = 0;
02203 char from2[NICKMAX + UHOSTMAX + 1];
02204 memberlist *m;
02205 struct chanset_t *chan, *oldchan = NULL;
02206 struct userrec *u;
02207
02208 strcpy(from2, from);
02209 u = get_user_by_host(from2);
02210 nick = splitnick(&from);
02211 fixcolon(msg);
02212
02213
02214
02215
02216 p = strchr(msg, ' ');
02217 if (p && (p == strrchr(msg, ' '))) {
02218 char *z1, *z2;
02219
02220 *p = 0;
02221 z1 = strchr(p + 1, '.');
02222 z2 = strchr(msg, '.');
02223 if (z1 && z2 && (*(z1 + 1) != 0) && (z1 - 1 != p) &&
02224 (z2 + 1 != p) && (z2 != msg)) {
02225
02226
02227
02228 split = 1;
02229 } else
02230 *p = ' ';
02231 }
02232 for (chan = chanset; chan; chan = chan->next) {
02233 oldchan = chan;
02234 chname = chan->dname;
02235 m = ismember(chan, nick);
02236 if (m) {
02237 u = get_user_by_host(from2);
02238 if (u)
02239
02240
02241
02242 set_handle_laston(chan->dname, u, now);
02243 if (split) {
02244 m->split = now;
02245 check_tcl_splt(nick, from, u, chan->dname);
02246
02247 if (!findchan_by_dname(chname)) {
02248 chan = oldchan;
02249 continue;
02250 }
02251 putlog(LOG_JOIN, chan->dname, "%s (%s) got netsplit.", nick, from);
02252 } else {
02253 check_tcl_sign(nick, from, u, chan->dname, msg);
02254
02255 if (!findchan_by_dname(chname)) {
02256 chan = oldchan;
02257 continue;
02258 }
02259 putlog(LOG_JOIN, chan->dname, "%s (%s) left irc: %s", nick, from, msg);
02260 killmember(chan, nick);
02261 check_lonely_channel(chan);
02262 }
02263 }
02264 }
02265
02266
02267
02268 if (keepnick) {
02269 alt = get_altbotnick();
02270 if (!rfc_casecmp(nick, origbotname)) {
02271 putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname);
02272 dprintf(DP_SERVER, "NICK %s\n", origbotname);
02273 } else if (alt[0]) {
02274 if (!rfc_casecmp(nick, alt) && strcmp(botname, origbotname)) {
02275 putlog(LOG_MISC, "*", IRC_GETALTNICK, alt);
02276 dprintf(DP_SERVER, "NICK %s\n", alt);
02277 }
02278 }
02279 }
02280 return 0;
02281 }
02282
02283
02284
02285 static int gotmsg(char *from, char *msg)
02286 {
02287 char *to, *realto, buf[UHOSTLEN], *nick, buf2[512], *uhost = buf, *p, *p1,
02288 *code, *ctcp;
02289 int ctcp_count = 0, ignoring;
02290 struct chanset_t *chan;
02291 struct userrec *u;
02292 memberlist *m;
02293 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
02294
02295
02296
02297 if (!strchr(CHANMETA "@", msg[0]))
02298 return 0;
02299
02300 to = newsplit(&msg);
02301 realto = (to[0] == '@') ? to + 1 : to;
02302 chan = findchan(realto);
02303 if (!chan)
02304 return 0;
02305
02306 fixcolon(msg);
02307 strcpy(uhost, from);
02308 nick = splitnick(&uhost);
02309 ignoring = match_ignore(from);
02310
02311 if (flud_ctcp_thr && detect_avalanche(msg)) {
02312 u = get_user_by_host(from);
02313 get_user_flagrec(u, &fr, chan->dname);
02314 m = ismember(chan, nick);
02315
02316 if (m && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) &&
02317 !chan_sentkick(m) && !chan_friend(fr) && !glob_friend(fr) &&
02318 !(channel_dontkickops(chan) && (chan_op(fr) || (glob_op(fr) &&
02319 !chan_deop(fr)))) && !(use_exempts && ban_fun &&
02320 (u_match_mask(global_exempts, from) ||
02321 u_match_mask(chan->exempts, from)))) {
02322 if (ban_fun) {
02323 check_exemptlist(chan, from);
02324 u_addban(chan, quickban(chan, uhost), botnetnick, IRC_FUNKICK,
02325 now + (60 * chan->ban_time), 0);
02326 }
02327 if (kick_fun) {
02328
02329 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, nick, IRC_FUNKICK);
02330 m->flags |= SENTKICK;
02331 }
02332 }
02333 if (!ignoring) {
02334 putlog(LOG_MODES, "*", "Avalanche from %s!%s in %s - ignoring",
02335 nick, uhost, chan->dname);
02336 p = strchr(uhost, '@');
02337 if (p)
02338 p++;
02339 else
02340 p = uhost;
02341 simple_sprintf(buf2, "*!*@%s", p);
02342 addignore(buf2, botnetnick, "ctcp avalanche", now + (60 * ignore_time));
02343 }
02344 return 0;
02345 }
02346
02347 ctcp_reply[0] = 0;
02348 p = strchr(msg, 1);
02349 while (p && *p) {
02350 p++;
02351 p1 = p;
02352 while ((*p != 1) && *p)
02353 p++;
02354 if (*p == 1) {
02355 *p = 0;
02356 ctcp = buf2;
02357 strcpy(ctcp, p1);
02358 strcpy(p1 - 1, p + 1);
02359 detect_chan_flood(nick, uhost, from, chan, strncmp(ctcp, "ACTION ", 7) ?
02360 FLOOD_CTCP : FLOOD_PRIVMSG, NULL);
02361
02362 chan = findchan(realto);
02363 if (!chan)
02364 return 0;
02365
02366
02367 p = strchr(msg, 1);
02368 if (ctcp_count < answer_ctcp) {
02369 ctcp_count++;
02370 if (ctcp[0] != ' ') {
02371 code = newsplit(&ctcp);
02372 u = get_user_by_host(from);
02373 if (!ignoring || trigger_on_ignore) {
02374 if (!check_tcl_ctcp(nick, uhost, u, to, code, ctcp)) {
02375 chan = findchan(realto);
02376 if (!chan)
02377 return 0;
02378
02379 update_idle(chan->dname, nick);
02380 }
02381 if (!ignoring) {
02382
02383 if (!strcmp(code, "ACTION")) {
02384 putlog(LOG_PUBLIC, chan->dname, "Action: %s %s", nick, ctcp);
02385 } else {
02386 putlog(LOG_PUBLIC, chan->dname,
02387 "CTCP %s: %s from %s (%s) to %s", code, ctcp, nick,
02388 from, to);
02389 }
02390 }
02391 }
02392 }
02393 }
02394 }
02395 }
02396
02397
02398 if (ctcp_reply[0]) {
02399 if (ctcp_mode != 2) {
02400 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
02401 } else {
02402 if (now - last_ctcp > flud_ctcp_time) {
02403 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
02404 count_ctcp = 1;
02405 } else if (count_ctcp < flud_ctcp_thr) {
02406 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply);
02407 count_ctcp++;
02408 }
02409 last_ctcp = now;
02410 }
02411 }
02412
02413 if (msg[0]) {
02414 int result = 0;
02415
02416
02417 detect_chan_flood(nick, uhost, from, chan, FLOOD_PRIVMSG, NULL);
02418
02419 chan = findchan(realto);
02420 if (!chan)
02421 return 0;
02422
02423 update_idle(chan->dname, nick);
02424
02425 if (!ignoring || trigger_on_ignore) {
02426 result = check_tcl_pubm(nick, uhost, chan->dname, msg);
02427
02428 if (!result || !exclusive_binds)
02429 if (check_tcl_pub(nick, uhost, chan->dname, msg))
02430 return 0;
02431 }
02432
02433 if (!ignoring && result != 2) {
02434 if (to[0] == '@')
02435 putlog(LOG_PUBLIC, chan->dname, "@<%s> %s", nick, msg);
02436 else
02437 putlog(LOG_PUBLIC, chan->dname, "<%s> %s", nick, msg);
02438 }
02439 }
02440 return 0;
02441 }
02442
02443
02444
02445 static int gotnotice(char *from, char *msg)
02446 {
02447 char *to, *realto, *nick, buf2[512], *p, *p1, buf[512], *uhost = buf;
02448 char *ctcp, *code;
02449 struct userrec *u;
02450 memberlist *m;
02451 struct chanset_t *chan;
02452 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
02453 int ignoring;
02454
02455 if (!strchr(CHANMETA "@", *msg))
02456 return 0;
02457 ignoring = match_ignore(from);
02458 to = newsplit(&msg);
02459 realto = (*to == '@') ? to + 1 : to;
02460 chan = findchan(realto);
02461 if (!chan)
02462 return 0;
02463 fixcolon(msg);
02464 strcpy(uhost, from);
02465 nick = splitnick(&uhost);
02466 u = get_user_by_host(from);
02467 if (flud_ctcp_thr && detect_avalanche(msg)) {
02468 get_user_flagrec(u, &fr, chan->dname);
02469 m = ismember(chan, nick);
02470
02471 if (me_op(chan) && m && !chan_sentkick(m) && !chan_friend(fr) &&
02472 !glob_friend(fr) && !(channel_dontkickops(chan) && (chan_op(fr) ||
02473 (glob_op(fr) && !chan_deop(fr)))) && !(use_exempts && ban_fun &&
02474 (u_match_mask(global_exempts, from) ||
02475 u_match_mask(chan->exempts, from)))) {
02476 if (ban_fun) {
02477 check_exemptlist(chan, from);
02478 u_addban(chan, quickban(chan, uhost), botnetnick,
02479 IRC_FUNKICK, now + (60 * chan->ban_time), 0);
02480 }
02481 if (kick_fun) {
02482
02483 dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, nick, IRC_FUNKICK);
02484 m->flags |= SENTKICK;
02485 }
02486 }
02487 if (!ignoring)
02488 putlog(LOG_MODES, "*", "Avalanche from %s", from);
02489 return 0;
02490 }
02491
02492 p = strchr(msg, 1);
02493 while (p && *p) {
02494 p++;
02495 p1 = p;
02496 while ((*p != 1) && *p)
02497 p++;
02498 if (*p == 1) {
02499 *p = 0;
02500 ctcp = buf2;
02501 strcpy(ctcp, p1);
02502 strcpy(p1 - 1, p + 1);
02503 p = strchr(msg, 1);
02504 detect_chan_flood(nick, uhost, from, chan,
02505 strncmp(ctcp, "ACTION ", 7) ?
02506 FLOOD_CTCP : FLOOD_PRIVMSG, NULL);
02507
02508 chan = findchan(realto);
02509 if (!chan)
02510 return 0;
02511
02512 if (ctcp[0] != ' ') {
02513 code = newsplit(&ctcp);
02514 if (!ignoring || trigger_on_ignore) {
02515 check_tcl_ctcr(nick, uhost, u, chan->dname, code, msg);
02516
02517 chan = findchan(realto);
02518 if (!chan)
02519 return 0;
02520
02521 if (!ignoring) {
02522 putlog(LOG_PUBLIC, chan->dname,
02523 "CTCP reply %s: %s from %s (%s) to %s", code, msg, nick,
02524 from, chan->dname);
02525 update_idle(chan->dname, nick);
02526 }
02527 }
02528 }
02529 }
02530 }
02531 if (msg[0]) {
02532
02533
02534 detect_chan_flood(nick, uhost, from, chan, FLOOD_NOTICE, NULL);
02535
02536 chan = findchan(realto);
02537 if (!chan)
02538 return 0;
02539
02540 update_idle(chan->dname, nick);
02541
02542 if (!ignoring || trigger_on_ignore)
02543 if (check_tcl_notc(nick, uhost, u, to, msg) == 2)
02544 return 0;
02545
02546 if (!ignoring)
02547 putlog(LOG_PUBLIC, chan->dname, "-%s:%s- %s", nick, to, msg);
02548 }
02549 return 0;
02550 }
02551
02552 static cmd_t irc_raw[] = {
02553 {"324", "", (IntFunc) got324, "irc:324"},
02554 {"352", "", (IntFunc) got352, "irc:352"},
02555 {"354", "", (IntFunc) got354, "irc:354"},
02556 {"315", "", (IntFunc) got315, "irc:315"},
02557 {"367", "", (IntFunc) got367, "irc:367"},
02558 {"368", "", (IntFunc) got368, "irc:368"},
02559 {"403", "", (IntFunc) got403, "irc:403"},
02560 {"405", "", (IntFunc) got405, "irc:405"},
02561 {"471", "", (IntFunc) got471, "irc:471"},
02562 {"473", "", (IntFunc) got473, "irc:473"},
02563 {"474", "", (IntFunc) got474, "irc:474"},
02564 {"475", "", (IntFunc) got475, "irc:475"},
02565 {"INVITE", "", (IntFunc) gotinvite, "irc:invite"},
02566 {"TOPIC", "", (IntFunc) gottopic, "irc:topic"},
02567 {"331", "", (IntFunc) got331, "irc:331"},
02568 {"332", "", (IntFunc) got332, "irc:332"},
02569 {"JOIN", "", (IntFunc) gotjoin, "irc:join"},
02570 {"PART", "", (IntFunc) gotpart, "irc:part"},
02571 {"KICK", "", (IntFunc) gotkick, "irc:kick"},
02572 {"NICK", "", (IntFunc) gotnick, "irc:nick"},
02573 {"QUIT", "", (IntFunc) gotquit, "irc:quit"},
02574 {"PRIVMSG", "", (IntFunc) gotmsg, "irc:msg"},
02575 {"NOTICE", "", (IntFunc) gotnotice, "irc:notice"},
02576 {"MODE", "", (IntFunc) gotmode, "irc:mode"},
02577 {"346", "", (IntFunc) got346, "irc:346"},
02578 {"347", "", (IntFunc) got347, "irc:347"},
02579 {"348", "", (IntFunc) got348, "irc:348"},
02580 {"349", "", (IntFunc) got349, "irc:349"},
02581 {NULL, NULL, NULL, NULL}
02582 };