static int check_tcl_pub(char *nick, char *from, char *chname, char *msg) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; int x; char buf[512], *args = buf, *cmd, host[161], *hand; struct userrec *u; strcpy(args, msg); cmd = newsplit(&args); simple_sprintf(host, "%s!%s", nick, from); u = get_user_by_host(host); hand = u ? u->handle : "*"; get_user_flagrec(u, &fr, chname); Tcl_SetVar(interp, "_pub1", nick, 0); Tcl_SetVar(interp, "_pub2", from, 0); Tcl_SetVar(interp, "_pub3", hand, 0); Tcl_SetVar(interp, "_pub4", chname, 0); Tcl_SetVar(interp, "_pub5", args, 0); x = check_tcl_bind(H_pub, cmd, &fr, " $_pub1 $_pub2 $_pub3 $_pub4 $_pub5", MATCH_EXACT | BIND_USE_ATTR | BIND_HAS_BUILTINS); if (x == BIND_NOMATCH) return 0; if (x == BIND_EXEC_LOG) putlog(LOG_CMDS, chname, "<<%s>> !%s! %s %s", nick, hand, cmd, args); return 1; }
static int check_tcl_pubm(char *nick, char *from, char *chname, char *msg) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; int x; char buf[1024], host[161]; struct userrec *u; simple_sprintf(buf, "%s %s", chname, msg); simple_sprintf(host, "%s!%s", nick, from); u = get_user_by_host(host); get_user_flagrec(u, &fr, chname); Tcl_SetVar(interp, "_pubm1", nick, 0); Tcl_SetVar(interp, "_pubm2", from, 0); Tcl_SetVar(interp, "_pubm3", u ? u->handle : "*", 0); Tcl_SetVar(interp, "_pubm4", chname, 0); Tcl_SetVar(interp, "_pubm5", msg, 0); x = check_tcl_bind(H_pubm, buf, &fr, " $_pubm1 $_pubm2 $_pubm3 $_pubm4 $_pubm5", MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE | BIND_STACKRET); /* * 0 - no match * 1 - match, log * 2 - match, don't log */ if (x == BIND_NOMATCH) return 0; if (x == BIND_EXEC_LOG) return 2; return 1; }
static void schan_members_update(struct stats_member *m, char *chan) { char *host; #ifndef NO_EGG struct userrec *u; #endif m->user = NULL; host = nmalloc(strlen(m->nick) + 1 + strlen(m->uhost) + 1); sprintf(host, "%s!%s", m->nick, m->uhost); #ifndef NO_EGG u = get_user_by_host(host); if (u) { m->user = findsuser_by_name(u->handle); if (!m->user) { m->user = addsuser(u->handle, now, now); debug1("Stats.Mod: Created suserrec for %s.", u->handle); } } else #endif m->user = findsuser(host); nfree(host); if (m->user) { m->stats = findlocstats(chan, m->user->user); if (!m->stats) m->stats = initstats(chan, m->user->user); } }
/* This is called after a mode bind is processed. It will check if the * channel still exists and will refresh the user and victim flag records, * in case users were also modified. */ struct chanset_t *modebind_refresh(char *chname, char *usrhost, struct flag_record *usr, char *vcrhost, struct flag_record *vcr) { struct userrec *u; struct chanset_t *chan; if (!chname || !(chan = findchan(chname))) return NULL; if (usrhost) { u = get_user_by_host(usrhost); get_user_flagrec(u, usr, chan->dname); } if (vcrhost) { u = get_user_by_host(vcrhost); get_user_flagrec(u, vcr, chan->dname); } return chan; }
static int hand_on_chan(struct chanset_t *chan, struct userrec *u) { char s[UHOSTLEN]; memberlist *m; for (m = chan->channel.member; m && m->nick[0]; m = m->next) { sprintf(s, "%s!%s", m->nick, m->userhost); if (u == get_user_by_host(s)) return 1; } return 0; }
/* Punishes bad guys under certain circumstances using methods as defined * by the revenge_mode flag. */ static void maybe_revenge(struct chanset_t *chan, char *whobad, char *whovictim, int type) { char *badnick, *victim; int mevictim; struct userrec *u, *u2; if (!chan || (type < 0)) return; /* Get info about offender */ u = get_user_by_host(whobad); badnick = splitnick(&whobad); /* Get info about victim */ u2 = get_user_by_host(whovictim); victim = splitnick(&whovictim); mevictim = match_my_nick(victim); /* Do we want to revenge? */ if (want_to_revenge(chan, u, u2, badnick, victim, mevictim)) punish_badguy(chan, whobad, u, badnick, victim, mevictim, type); }
/* Expire mask originally set by `who' on `chan'? * * We might not want to expire masks in all cases, as other bots * often tend to immediately reset masks they've listed in their * internal ban list, making it quite senseless for us to remove * them in the first place. * * Returns 1 if a mask on `chan' by `who' may be expired and 0 if * not. */ static int expired_mask(struct chanset_t *chan, char *who) { memberlist *m, *m2; char buf[UHOSTLEN], *snick, *sfrom; struct userrec *u; /* Always expire masks, regardless of who set it? */ if (force_expire) return 1; strcpy(buf, who); sfrom = buf; snick = splitnick(&sfrom); if (!snick[0]) return 1; m = ismember(chan, snick); if (!m) for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next) if (!egg_strcasecmp(sfrom, m2->userhost)) { m = m2; break; } if (!m || !chan_hasop(m) || !rfc_casecmp(m->nick, botname)) return 1; /* At this point we know the person/bot who set the mask is currently * present in the channel and has op. */ if (m->user) u = m->user; else { simple_sprintf(buf, "%s!%s", m->nick, m->userhost); u = get_user_by_host(buf); } /* Do not expire masks set by bots. */ if (u && u->flags & USER_BOT) return 0; else return 1; }
static void notes_hourly() { expire_notes(); if (notify_users) { register struct chanset_t *chan; register memberlist *m; int k; register int l; char s1[256]; struct userrec *u; for (chan = chanset; chan; chan = chan->next) { for (m = chan->channel.member; m && m->nick[0]; m = m->next) { sprintf(s1, "%s!%s", m->nick, m->userhost); u = get_user_by_host(s1); if (u) { k = num_notes(u->handle); for (l = 0; l < dcc_total; l++) if ((dcc[l].type->flags & DCT_CHAT) && !egg_strcasecmp(dcc[l].nick, u->handle)) { k = 0; /* They already know they have notes */ break; } if (k) { dprintf(DP_HELP, "NOTICE %s :You have %d note%s waiting on %s.\n", m->nick, k, k == 1 ? "" : "s", botname); dprintf(DP_HELP, "NOTICE %s :%s /MSG %s NOTES <pass> INDEX\n", m->nick, NOTES_FORLIST, botname); } } } } for (l = 0; l < dcc_total; l++) { k = num_notes(dcc[l].nick); if ((k > 0) && (dcc[l].type->flags & DCT_CHAT)) { dprintf(l, NOTES_WAITING2, k, (k == 1) ? "" : "s"); dprintf(l, "### %s\n", (k != 1) ? NOTES_DCC_USAGE_READ : NOTES_DCC_USAGE_READ2); } } } }
/* Got a private message. */ static int gotmsg(char *from, char *msg) { char *to, buf[UHOSTLEN], *nick, ctcpbuf[512], *uhost = buf, *ctcp, *p, *p1, *code; struct userrec *u; int ctcp_count = 0; int ignoring; /* Notice to a channel, not handled here */ if (msg[0] && ((strchr(CHANMETA, *msg) != NULL) || (*msg == '@'))) return 0; ignoring = match_ignore(from); to = newsplit(&msg); fixcolon(msg); strncpyz(uhost, from, sizeof(buf)); nick = splitnick(&uhost); /* Check for CTCP: */ ctcp_reply[0] = 0; p = strchr(msg, 1); while ((p != NULL) && (*p)) { p++; p1 = p; while ((*p != 1) && (*p != 0)) p++; if (*p == 1) { *p = 0; strncpyz(ctcpbuf, p1, sizeof(ctcpbuf)); ctcp = ctcpbuf; /* remove the ctcp in msg */ memmove(p1 - 1, p + 1, strlen(p + 1) + 1); if (!ignoring) detect_flood(nick, uhost, from, strncmp(ctcp, "ACTION ", 7) ? FLOOD_CTCP : FLOOD_PRIVMSG); /* Respond to the first answer_ctcp */ p = strchr(msg, 1); if (ctcp_count < answer_ctcp) { ctcp_count++; if (ctcp[0] != ' ') { code = newsplit(&ctcp); /* CTCP from oper, don't interpret */ if ((to[0] == '$') || strchr(to, '.')) { if (!ignoring) putlog(LOG_PUBLIC, to, "CTCP %s: %s from %s (%s) to %s", code, ctcp, nick, uhost, to); } else { u = get_user_by_host(from); if (!ignoring || trigger_on_ignore) { if (!check_tcl_ctcp(nick, uhost, u, to, code, ctcp) && !ignoring) { if ((lowercase_ctcp && !egg_strcasecmp(code, "DCC")) || (!lowercase_ctcp && !strcmp(code, "DCC"))) { /* If it gets this far unhandled, it means that * the user is totally unknown. */ code = newsplit(&ctcp); if (!strcmp(code, "CHAT")) { if (!quiet_reject) { if (u) dprintf(DP_HELP, "NOTICE %s :I'm not accepting calls " "at the moment.\n", nick); else dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_NOSTRANGERS); } putlog(LOG_MISC, "*", "%s: %s", DCC_REFUSED, from); } else putlog(LOG_MISC, "*", "Refused DCC %s: %s", code, from); } } if (!strcmp(code, "ACTION")) { putlog(LOG_MSGS, "*", "Action to %s: %s %s", to, nick, ctcp); } else { putlog(LOG_MSGS, "*", "CTCP %s: %s from %s (%s)", code, ctcp, nick, uhost); } /* I love a good close cascade ;) */ } } } } } } /* Send out possible ctcp responses */ if (ctcp_reply[0]) { if (ctcp_mode != 2) { dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply); } else { if (now - last_ctcp > flud_ctcp_time) { dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply); count_ctcp = 1; } else if (count_ctcp < flud_ctcp_thr) { dprintf(DP_HELP, "NOTICE %s :%s\n", nick, ctcp_reply); count_ctcp++; } last_ctcp = now; } } if (msg[0]) { int result = 0; /* Msg from oper, don't interpret */ if ((to[0] == '$') || (strchr(to, '.') != NULL)) { if (!ignoring) { detect_flood(nick, uhost, from, FLOOD_PRIVMSG); putlog(LOG_MSGS | LOG_SERV, "*", "[%s!%s to %s] %s", nick, uhost, to, msg); } return 0; } detect_flood(nick, uhost, from, FLOOD_PRIVMSG); u = get_user_by_host(from); code = newsplit(&msg); rmspace(msg); if (!ignoring || trigger_on_ignore) { result = check_tcl_msgm(code, nick, uhost, u, msg); if (!result || !exclusive_binds) if (check_tcl_msg(code, nick, uhost, u, msg)) return 0; } if (!ignoring && result != 2) putlog(LOG_MSGS, "*", "[%s] %s %s", from, code, msg); } return 0; }
/* Got a private notice. */ static int gotnotice(char *from, char *msg) { char *to, *nick, ctcpbuf[512], *p, *p1, buf[512], *uhost = buf, *ctcp; struct userrec *u; int ignoring; /* Notice to a channel, not handled here */ if (msg[0] && ((strchr(CHANMETA, *msg) != NULL) || (*msg == '@'))) return 0; ignoring = match_ignore(from); to = newsplit(&msg); fixcolon(msg); strcpy(uhost, from); nick = splitnick(&uhost); /* Check for CTCP: */ p = strchr(msg, 1); while ((p != NULL) && (*p)) { p++; p1 = p; while ((*p != 1) && (*p != 0)) p++; if (*p == 1) { *p = 0; ctcp = strcpy(ctcpbuf, p1); strcpy(p1 - 1, p + 1); if (!ignoring) detect_flood(nick, uhost, from, FLOOD_CTCP); p = strchr(msg, 1); if (ctcp[0] != ' ') { char *code = newsplit(&ctcp); /* CTCP reply from oper, don't interpret */ if ((to[0] == '$') || strchr(to, '.')) { if (!ignoring) putlog(LOG_PUBLIC, "*", "CTCP reply %s: %s from %s (%s) to %s", code, ctcp, nick, uhost, to); } else { u = get_user_by_host(from); if (!ignoring || trigger_on_ignore) { check_tcl_ctcr(nick, uhost, u, to, code, ctcp); if (!ignoring) /* Who cares? */ putlog(LOG_MSGS, "*", "CTCP reply %s: %s from %s (%s) to %s", code, ctcp, nick, uhost, to); } } } } } if (msg[0]) { /* Notice from oper, don't interpret */ if ((to[0] == '$') || (strchr(to, '.') != NULL)) { if (!ignoring) { detect_flood(nick, uhost, from, FLOOD_NOTICE); putlog(LOG_MSGS | LOG_SERV, "*", "-%s (%s) to %s- %s", nick, uhost, to, msg); } return 0; } /* Server notice? */ if ((nick[0] == 0) || (uhost[0] == 0)) { /* Hidden `250' connection count message from server */ if (strncmp(msg, "Highest connection count:", 25)) putlog(LOG_SERV, "*", "-NOTICE- %s", msg); return 0; } detect_flood(nick, uhost, from, FLOOD_NOTICE); u = get_user_by_host(from); if (!ignoring || trigger_on_ignore) if (check_tcl_notc(nick, uhost, u, botname, msg) == 2) return 0; if (!ignoring) putlog(LOG_MSGS, "*", "-%s (%s)- %s", nick, uhost, msg); } return 0; }
static void got_halfop(struct chanset_t *chan, char *nick, char *from, char *who, struct userrec *opu, struct flag_record *opper) { memberlist *m; char s[UHOSTLEN]; char ch[sizeof chan->name]; struct userrec *u; int check_chan = 0; int snm = chan->stopnethack_mode; m = ismember(chan, who); if (!m) { if (channel_pending(chan)) return; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); return; } /* Did *I* just get halfopped? */ if (!me_op(chan) && !me_halfop(chan) && match_my_nick(who)) check_chan = 1; strcpy(ch, chan->name); simple_sprintf(s, "%s!%s", m->nick, m->userhost); if (!m->user) u = get_user_by_host(s); else u = m->user; get_user_flagrec(u, &victim, chan->dname); /* Flags need to be set correctly right from the beginning now, so that * add_mode() doesn't get irritated. */ m->flags |= CHANHALFOP; check_tcl_mode(nick, from, opu, chan->dname, "+h", who); if (!(chan = modebind_refresh(ch, from, opper, s, &victim)) || !(m = ismember(chan, who))) return; m->flags &= ~SENTHALFOP; if (channel_pending(chan)) return; if (nick[0] && HALFOP_CANDOMODE('h') && !match_my_nick(who) && !match_my_nick(nick)) { if (channel_bitch(chan) && !(glob_master(*opper) || glob_bot(*opper)) && !chan_master(*opper) && !(glob_halfop(victim) || glob_op(victim) || glob_bot(victim)) && !chan_op(victim) && !chan_halfop(victim)) add_mode(chan, '-', 'h', who); else if ((chan_dehalfop(victim) || (glob_dehalfop(victim) && !chan_halfop(victim))) && !glob_master(*opper) && !chan_master(*opper)) add_mode(chan, '-', 'h', who); else if (reversing) add_mode(chan, '-', 'h', who); } else if (reversing && HALFOP_CANDOMODE('h') && !match_my_nick(who) && !match_my_nick(nick)) add_mode(chan, '-', 'h', who); if (!nick[0] && HALFOP_CANDOMODE('h') && !match_my_nick(who)) { if (chan_dehalfop(victim) || (glob_dehalfop(victim) && !chan_halfop(victim))) { m->flags |= FAKEHALFOP; add_mode(chan, '-', 'h', who); } else if (snm > 0 && snm < 7 && !((channel_autohalfop(chan) || glob_autohalfop(victim) || chan_autohalfop(victim)) && (chan_halfop(victim) || (glob_halfop(victim) && !chan_dehalfop(victim)))) && !glob_exempt(victim) && !chan_exempt(victim)) { if (snm == 5) snm = channel_bitch(chan) ? 1 : 3; if (snm == 6) snm = channel_bitch(chan) ? 4 : 2; if (chan_washalfoptest(victim) || glob_washalfoptest(victim) || snm == 2) { if (!chan_washalfop(m)) { m->flags |= FAKEHALFOP; add_mode(chan, '-', 'h', who); } } else if (!(chan_halfop(victim) || (glob_halfop(victim) && !chan_dehalfop(victim)))) { if (snm == 1 || snm == 4 || (snm == 3 && !chan_washalfop(m))) { add_mode(chan, '-', 'h', who); m->flags |= FAKEHALFOP; } } else if (snm == 4 && !chan_washalfop(m)) { add_mode(chan, '-', 'h', who); m->flags |= FAKEHALFOP; } } } m->flags |= WASHALFOP; if (check_chan) recheck_channel(chan, 1); }
/* Do on NICK, PRIVMSG, NOTICE and JOIN. */ static int detect_flood(char *floodnick, char *floodhost, char *from, int which) { char *p, ftype[10], h[1024]; struct userrec *u; int thr = 0, lapse = 0, atr; /* Okay, make sure i'm not flood-checking myself */ if (match_my_nick(floodnick)) return 0; /* My user@host (?) */ if (!egg_strcasecmp(floodhost, botuserhost)) return 0; u = get_user_by_host(from); atr = u ? u->flags : 0; if (atr & (USER_BOT | USER_FRIEND)) return 0; /* Determine how many are necessary to make a flood */ switch (which) { case FLOOD_PRIVMSG: case FLOOD_NOTICE: thr = flud_thr; lapse = flud_time; strcpy(ftype, "msg"); break; case FLOOD_CTCP: thr = flud_ctcp_thr; lapse = flud_ctcp_time; strcpy(ftype, "ctcp"); break; } if ((thr == 0) || (lapse == 0)) return 0; /* No flood protection */ p = strchr(floodhost, '@'); if (p) { p++; if (egg_strcasecmp(lastmsghost[which], p)) { /* New */ strcpy(lastmsghost[which], p); lastmsgtime[which] = now; lastmsgs[which] = 0; return 0; } } else return 0; /* Uh... whatever. */ if (lastmsgtime[which] < now - lapse) { /* Flood timer expired, reset it */ lastmsgtime[which] = now; lastmsgs[which] = 0; return 0; } lastmsgs[which]++; if (lastmsgs[which] >= thr) { /* FLOOD */ /* Reset counters */ lastmsgs[which] = 0; lastmsgtime[which] = 0; lastmsghost[which][0] = 0; u = get_user_by_host(from); if (check_tcl_flud(floodnick, floodhost, u, ftype, "*")) return 0; /* Private msg */ simple_sprintf(h, "*!*@%s", p); putlog(LOG_MISC, "*", IRC_FLOODIGNORE1, p); addignore(h, botnetnick, (which == FLOOD_CTCP) ? "CTCP flood" : "MSG/NOTICE flood", now + (60 * ignore_time)); } return 0; }
static void check_expired_chanstuff() { masklist *b, *e; memberlist *m, *n; char *key, s[UHOSTLEN]; struct chanset_t *chan; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; if (!server_online) return; for (chan = chanset; chan; chan = chan->next) { if (channel_active(chan)) { if (me_op(chan) || me_halfop(chan)) { if (channel_dynamicbans(chan) && chan->ban_time) for (b = chan->channel.ban; b->mask[0]; b = b->next) if (now - b->timer > 60 * chan->ban_time && !u_sticky_mask(chan->bans, b->mask) && !u_sticky_mask(global_bans, b->mask) && expired_mask(chan, b->who)) { putlog(LOG_MODES, chan->dname, "(%s) Channel ban on %s expired.", chan->dname, b->mask); add_mode(chan, '-', 'b', b->mask); b->timer = now; } if (use_exempts && channel_dynamicexempts(chan) && chan->exempt_time) for (e = chan->channel.exempt; e->mask[0]; e = e->next) if (now - e->timer > 60 * chan->exempt_time && !u_sticky_mask(chan->exempts, e->mask) && !u_sticky_mask(global_exempts, e->mask) && expired_mask(chan, e->who)) { /* Check to see if it matches a ban */ int match = 0; for (b = chan->channel.ban; b->mask[0]; b = b->next) if (mask_match(b->mask, e->mask)) { match = 1; break; } /* Leave this extra logging in for now. Can be removed later * Jason */ if (match) { putlog(LOG_MODES, chan->dname, "(%s) Channel exemption %s NOT expired. Exempt still set!", chan->dname, e->mask); } else { putlog(LOG_MODES, chan->dname, "(%s) Channel exemption on %s expired.", chan->dname, e->mask); add_mode(chan, '-', 'e', e->mask); } e->timer = now; } if (use_invites && channel_dynamicinvites(chan) && chan->invite_time && !(chan->channel.mode & CHANINV)) for (b = chan->channel.invite; b->mask[0]; b = b->next) if (now - b->timer > 60 * chan->invite_time && !u_sticky_mask(chan->invites, b->mask) && !u_sticky_mask(global_invites, b->mask) && expired_mask(chan, b->who)) { putlog(LOG_MODES, chan->dname, "(%s) Channel invitation on %s expired.", chan->dname, b->mask); add_mode(chan, '-', 'I', b->mask); b->timer = now; } if (chan->idle_kick) for (m = chan->channel.member; m && m->nick[0]; m = m->next) if (now - m->last >= chan->idle_kick * 60 && !match_my_nick(m->nick) && !chan_issplit(m)) { sprintf(s, "%s!%s", m->nick, m->userhost); get_user_flagrec(m->user ? m->user : get_user_by_host(s), &fr, chan->dname); if ((!(glob_bot(fr) || glob_friend(fr) || (glob_op(fr) && !chan_deop(fr)) || chan_friend(fr) || chan_op(fr))) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) { dprintf(DP_SERVER, "KICK %s %s :idle %d min\n", chan->name, m->nick, chan->idle_kick); m->flags |= SENTKICK; } } } for (m = chan->channel.member; m && m->nick[0]; m = n) { n = m->next; if (m->split && now - m->split > wait_split) { sprintf(s, "%s!%s", m->nick, m->userhost); check_tcl_sign(m->nick, m->userhost, m->user ? m->user : get_user_by_host(s), chan->dname, "lost in the netsplit"); putlog(LOG_JOIN, chan->dname, "%s (%s) got lost in the net-split.", m->nick, m->userhost); killmember(chan, m->nick); } m = n; } check_lonely_channel(chan); } else if (!channel_inactive(chan) && !channel_pending(chan)) { key = chan->channel.key[0] ? chan->channel.key : chan->key_prot; if (key[0]) dprintf(DP_SERVER, "JOIN %s %s\n", chan->name[0] ? chan->name : chan->dname, key); else dprintf(DP_SERVER, "JOIN %s\n", chan->name[0] ? chan->name : chan->dname); } } }
static void got_deop(struct chanset_t *chan, char *nick, char *from, char *who, struct userrec *opu) { memberlist *m; char ch[sizeof chan->name]; char s[UHOSTLEN], s1[UHOSTLEN]; struct userrec *u; int had_halfop; m = ismember(chan, who); if (!m) { if (channel_pending(chan)) return; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); return; } strcpy(ch, chan->name); simple_sprintf(s, "%s!%s", m->nick, m->userhost); simple_sprintf(s1, "%s!%s", nick, from); u = get_user_by_host(s); get_user_flagrec(u, &victim, chan->dname); had_halfop = chan_hasop(m); /* Flags need to be set correctly right from the beginning now, so that * add_mode() doesn't get irritated. */ m->flags &= ~(CHANOP | SENTDEOP | FAKEOP); check_tcl_mode(nick, from, opu, chan->dname, "-o", who); if (!(chan = modebind_refresh(ch, from, &user, s, &victim)) || !(m = ismember(chan, who))) return; m->flags &= ~WASOP; if (channel_pending(chan)) return; if (HALFOP_CANDOMODE('o')) { int ok = 1; if (!glob_deop(victim) && !chan_deop(victim)) { if (channel_protectops(chan) && (glob_master(victim) || chan_master(victim) || glob_op(victim) || chan_op(victim))) ok = 0; else if (channel_protectfriends(chan) && (glob_friend(victim) || chan_friend(victim))) ok = 0; } if ((reversing || !ok) && had_halfop && !match_my_nick(nick) && rfc_casecmp(who, nick) && !match_my_nick(who) && !glob_master(user) && !chan_master(user) && !glob_bot(user) && ((chan_op(victim) || (glob_op(victim) && !chan_deop(victim))) || !channel_bitch(chan))) add_mode(chan, '+', 'o', who); } if (!nick[0]) putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s", chan->dname, who, from); /* Check for mass deop */ if (nick[0]) detect_chan_flood(nick, from, s1, chan, FLOOD_DEOP, who, 0); /* Having op hides your +v and +h status -- so now that someone's lost ops, * check to see if they have +v or +h */ if (!(m->flags & (CHANVOICE | CHANHALFOP | STOPWHO))) { chan->status |= CHAN_PEND; refresh_who_chan(chan->name); m->flags |= STOPWHO; } /* Was the bot deopped? */ if (match_my_nick(who)) { /* Cancel any pending kicks and modes */ memberlist *m2; for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next) m2->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTVOICE | SENTDEVOICE); check_tcl_need(chan->dname, "op"); if (chan->need_op[0]) do_tcl("need-op", chan->need_op); if (!nick[0]) putlog(LOG_MODES, chan->dname, "TS resync deopped me on %s :(", chan->dname); } if (nick[0]) maybe_revenge(chan, s1, s, REVENGE_DEOP); }
/* If i'm the only person on the channel, and i'm not op'd, * might as well leave and rejoin. If i'm NOT the only person * on the channel, but i'm still not op'd, demand ops. */ static void check_lonely_channel(struct chanset_t *chan) { memberlist *m; char s[UHOSTLEN]; int i = 0; if (channel_pending(chan) || !channel_active(chan) || me_op(chan) || channel_inactive(chan) || (chan->channel.mode & CHANANON)) return; /* Count non-split channel members */ for (m = chan->channel.member; m && m->nick[0]; m = m->next) if (!chan_issplit(m)) i++; if (i == 1 && channel_cycle(chan) && !channel_stop_cycle(chan)) { if (chan->name[0] != '+') { /* Its pointless to cycle + chans for ops */ putlog(LOG_MISC, "*", "Trying to cycle %s to regain ops.", chan->dname); dprintf(DP_MODE, "PART %s\n", chan->name); /* If it's a !chan, we need to recreate the channel with !!chan <cybah> */ if (chan->key_prot[0]) dprintf(DP_MODE, "JOIN %s%s %s\n", (chan->dname[0] == '!') ? "!" : "", chan->dname, chan->key_prot); else dprintf(DP_MODE, "JOIN %s%s\n", (chan->dname[0] == '!') ? "!" : "", chan->dname); chan->status &= ~CHAN_WHINED; } } else if (any_ops(chan)) { chan->status &= ~CHAN_WHINED; check_tcl_need(chan->dname, "op"); if (chan->need_op[0]) do_tcl("need-op", chan->need_op); } else { /* Other people here, but none are ops. If there are other bots make * them LEAVE! */ int ok = 1; struct userrec *u; if (!channel_whined(chan)) { /* + is opless. Complaining about no ops when without special * help(services), we cant get them - Raist */ if (chan->name[0] != '+' && channel_logstatus(chan)) putlog(LOG_MISC, "*", "%s is active but has no ops :(", chan->dname); chan->status |= CHAN_WHINED; } for (m = chan->channel.member; m && m->nick[0]; m = m->next) { sprintf(s, "%s!%s", m->nick, m->userhost); u = get_user_by_host(s); if (!match_my_nick(m->nick) && (!u || !(u->flags & USER_BOT))) { ok = 0; break; } } if (ok && channel_cycle(chan)) { /* ALL bots! make them LEAVE!!! */ for (m = chan->channel.member; m && m->nick[0]; m = m->next) if (!match_my_nick(m->nick)) dprintf(DP_SERVER, "PRIVMSG %s :go %s\n", m->nick, chan->dname); } else { /* Some humans on channel, but still op-less */ check_tcl_need(chan->dname, "op"); if (chan->need_op[0]) do_tcl("need-op", chan->need_op); } } }
static void got_dehalfop(struct chanset_t *chan, char *nick, char *from, char *who, struct userrec *opu) { memberlist *m; char ch[sizeof chan->name]; char s[UHOSTLEN], s1[UHOSTLEN]; struct userrec *u; int had_halfop; m = ismember(chan, who); if (!m) { if (channel_pending(chan)) return; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); return; } strcpy(ch, chan->name); simple_sprintf(s, "%s!%s", m->nick, m->userhost); simple_sprintf(s1, "%s!%s", nick, from); u = get_user_by_host(s); get_user_flagrec(u, &victim, chan->dname); had_halfop = chan_hasop(m); /* Flags need to be set correctly right from the beginning now, so that * add_mode() doesn't get irritated. */ m->flags &= ~(CHANHALFOP | SENTDEHALFOP | FAKEHALFOP); check_tcl_mode(nick, from, opu, chan->dname, "-h", who); if (!(chan = modebind_refresh(ch, from, &user, s, &victim)) || !(m = ismember(chan, who))) return; /* Check comments in got_op() (drummer) */ m->flags &= ~WASHALFOP; if (channel_pending(chan)) return; /* Dehalfop'd someone on my oplist? */ if (HALFOP_CANDOMODE('h')) { int ok = 1; if (!glob_dehalfop(victim) && !chan_dehalfop(victim)) { if (channel_protecthalfops(chan) && (glob_master(victim) || chan_master(victim) || glob_halfop(victim) || chan_halfop(victim))) ok = 0; else if (channel_protectfriends(chan) && (glob_friend(victim) || chan_friend(victim))) ok = 0; } if ((reversing || !ok) && had_halfop && !match_my_nick(nick) && rfc_casecmp(who, nick) && !match_my_nick(who) && !glob_master(user) && !chan_master(user) && !glob_bot(user) && ((chan_halfop(victim) || (glob_halfop(victim) && !chan_dehalfop(victim))) || !channel_bitch(chan))) add_mode(chan, '+', 'h', who); } if (!nick[0]) putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s", chan->dname, who, from); if (!(m->flags & (CHANVOICE | STOPWHO))) { chan->status |= CHAN_PEND; refresh_who_chan(chan->name); m->flags |= STOPWHO; } }
static int gotmode(char *from, char *origmsg) { char *nick, *ch, *op, *chg, *msg; char s[UHOSTLEN], buf[511]; char ms2[3]; int z; struct userrec *u; memberlist *m; struct chanset_t *chan; strncpy(buf, origmsg, 510); buf[510] = 0; msg = buf; /* Usermode changes? */ if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) { ch = newsplit(&msg); chg = newsplit(&msg); reversing = 0; chan = findchan(ch); if (!chan) { putlog(LOG_MISC, "*", CHAN_FORCEJOIN, ch); dprintf(DP_SERVER, "PART %s\n", ch); } else if (channel_active(chan) || channel_pending(chan)) { z = strlen(msg); if (msg[--z] == ' ') /* I hate cosmetic bugs :P -poptix */ msg[z] = 0; putlog(LOG_MODES, chan->dname, "%s: mode change '%s %s' by %s", ch, chg, msg, from); u = get_user_by_host(from); get_user_flagrec(u, &user, ch); nick = splitnick(&from); m = ismember(chan, nick); if (m) m->last = now; if (m && channel_active(chan) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) && !(glob_friend(user) || chan_friend(user) || (channel_dontkickops(chan) && (chan_op(user) || (glob_op(user) && !chan_deop(user))))) && !match_my_nick(nick)) { if (chan_fakeop(m) || chan_fakehalfop(m)) { putlog(LOG_MODES, ch, CHAN_FAKEMODE, ch); dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_FAKEMODE_KICK); m->flags |= SENTKICK; reversing = 1; } else if (!chan_hasop(m) && !chan_hashalfop(m) && !channel_nodesynch(chan)) { putlog(LOG_MODES, ch, CHAN_DESYNCMODE, ch); dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_DESYNCMODE_KICK); m->flags |= SENTKICK; reversing = 1; } } ms2[0] = '+'; ms2[2] = 0; while ((ms2[1] = *chg)) { int todo = 0; switch (*chg) { case '+': ms2[0] = '+'; break; case '-': ms2[0] = '-'; break; case 'i': todo = CHANINV; if (!nick[0] && bounce_modes) reversing = 1; break; case 'p': todo = CHANPRIV; if (!nick[0] && bounce_modes) reversing = 1; break; case 's': todo = CHANSEC; if (!nick[0] && bounce_modes) reversing = 1; break; case 'm': todo = CHANMODER; if (!nick[0] && bounce_modes) reversing = 1; break; case 'c': todo = CHANNOCLR; if (!nick[0] && bounce_modes) reversing = 1; break; case 'C': todo = CHANNOCTCP; if (!nick[0] && bounce_modes) reversing = 1; break; case 'R': todo = CHANREGON; if (!nick[0] && bounce_modes) reversing = 1; break; case 'M': todo = CHANMODREG; if (!nick[0] && bounce_modes) reversing = 1; break; case 'r': todo = CHANLONLY; if (!nick[0] && bounce_modes) reversing = 1; break; case 'D': todo = CHANDELJN; if (!nick[0] && bounce_modes) reversing = 1; break; case 'u': todo = CHANSTRIP; if (!nick[0] && bounce_modes) reversing = 1; break; case 'N': todo = CHANNONOTC; if (!nick[0] && bounce_modes) reversing = 1; break; case 'T': todo = CHANNOAMSG; if (!nick[0] && bounce_modes) reversing = 1; break; case 'd': todo = CHANINVIS; break; case 't': todo = CHANTOPIC; if (!nick[0] && bounce_modes) reversing = 1; break; case 'n': todo = CHANNOMSG; if (!nick[0] && bounce_modes) reversing = 1; break; case 'a': todo = CHANANON; if (!nick[0] && bounce_modes) reversing = 1; break; case 'q': todo = CHANQUIET; if (!nick[0] && bounce_modes) reversing = 1; break; case 'l': if (!nick[0] && bounce_modes) reversing = 1; if (ms2[0] == '-') { check_tcl_mode(nick, from, u, chan->dname, ms2, ""); /* The Tcl proc might have modified/removed the chan or user */ if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (channel_active(chan)) { if (reversing && (chan->channel.maxmembers != 0)) { simple_sprintf(s, "%d", chan->channel.maxmembers); add_mode(chan, '+', 'l', s); } else if ((chan->limit_prot != 0) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) { simple_sprintf(s, "%d", chan->limit_prot); add_mode(chan, '+', 'l', s); } } chan->channel.maxmembers = 0; } else { op = newsplit(&msg); fixcolon(op); if (op == '\0') break; chan->channel.maxmembers = atoi(op); check_tcl_mode(nick, from, u, chan->dname, ms2, int_to_base10(chan->channel.maxmembers)); /* The Tcl proc might have modified/removed the chan or user */ if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (channel_pending(chan)) break; if ((reversing && !(chan->mode_pls_prot & CHANLIMIT)) || ((chan->mode_mns_prot & CHANLIMIT) && !glob_master(user) && !chan_master(user))) add_mode(chan, '-', 'l', ""); if ((chan->limit_prot != chan->channel.maxmembers) && (chan->mode_pls_prot & CHANLIMIT) && (chan->limit_prot != 0) && !glob_master(user) && !chan_master(user)) { simple_sprintf(s, "%d", chan->limit_prot); add_mode(chan, '+', 'l', s); } } break; case 'k': if (ms2[0] == '+') chan->channel.mode |= CHANKEY; else chan->channel.mode &= ~CHANKEY; op = newsplit(&msg); fixcolon(op); if (op == '\0') { break; } check_tcl_mode(nick, from, u, chan->dname, ms2, op); /* The Tcl proc might have modified/removed the chan or user */ if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (ms2[0] == '+') { set_key(chan, op); if (channel_active(chan)) got_key(chan, nick, from, op); } else { if (channel_active(chan)) { if (reversing && chan->channel.key[0]) add_mode(chan, '+', 'k', chan->channel.key); else if (chan->key_prot[0] && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) add_mode(chan, '+', 'k', chan->key_prot); } set_key(chan, NULL); } break; case 'o': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_op(chan, nick, from, op, u, &user); else got_deop(chan, nick, from, op, u); break; case 'h': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_halfop(chan, nick, from, op, u, &user); else got_dehalfop(chan, nick, from, op, u); break; case 'v': op = newsplit(&msg); fixcolon(op); m = ismember(chan, op); if (!m) { if (channel_pending(chan)) break; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, op); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); } else { simple_sprintf(s, "%s!%s", m->nick, m->userhost); get_user_flagrec(m->user ? m->user : get_user_by_host(s), &victim, chan->dname); if (ms2[0] == '+') { m->flags &= ~SENTVOICE; m->flags |= CHANVOICE; check_tcl_mode(nick, from, u, chan->dname, ms2, op); if (!(chan = modebind_refresh(ch, from, &user, s, &victim))) return 0; if (channel_active(chan) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) { if (chan_quiet(victim) || (glob_quiet(victim) && !chan_voice(victim))) add_mode(chan, '-', 'v', op); else if (reversing) add_mode(chan, '-', 'v', op); } } else { m->flags &= ~SENTDEVOICE; m->flags &= ~CHANVOICE; check_tcl_mode(nick, from, u, chan->dname, ms2, op); if (!(chan = modebind_refresh(ch, from, &user, s, &victim))) return 0; if (channel_active(chan) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) { if ((channel_autovoice(chan) && !chan_quiet(victim) && (chan_voice(victim) || glob_voice(victim))) || (!chan_quiet(victim) && (glob_gvoice(victim) || chan_gvoice(victim)))) add_mode(chan, '+', 'v', op); else if (reversing) add_mode(chan, '+', 'v', op); } } } break; case 'b': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_ban(chan, nick, from, op, ch, u); else got_unban(chan, nick, from, op, ch, u); break; case 'e': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_exempt(chan, nick, from, op, ch, u); else got_unexempt(chan, nick, from, op, ch, u); break; case 'I': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_invite(chan, nick, from, op, ch, u); else got_uninvite(chan, nick, from, op, ch, u); break; } if (todo) { check_tcl_mode(nick, from, u, chan->dname, ms2, ""); if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (ms2[0] == '+') chan->channel.mode |= todo; else chan->channel.mode &= ~todo; if (channel_active(chan)) { if ((((ms2[0] == '+') && (chan->mode_mns_prot & todo)) || ((ms2[0] == '-') && (chan->mode_pls_prot & todo))) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, ""); else if (reversing && ((ms2[0] == '+') || (chan->mode_pls_prot & todo)) && ((ms2[0] == '-') || (chan->mode_mns_prot & todo))) add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, ""); } } chg++; } if (!me_op(chan) && !nick[0]) chan->status |= CHAN_ASKEDMODES; } } return 0; }
static void do_seen(int idx, char *prefix, char *nick, char *hand, char *channel, char *text) { char stuff[512], word1[512], word2[512], whotarget[512], object[512], whoredirect[512], *oix, *lastonplace = 0; struct userrec *urec; struct chanset_t *chan; struct laston_info *li; struct chanuserrec *cr; memberlist *m = NULL; int onchan = 0, i; long tv; time_t laston = 0, work; whotarget[0] = 0; whoredirect[0] = 0; object[0] = 0; /* Was ANYONE specified */ if (!text[0]) { dprintf(idx, "%sUm, %s, it might help if you ask me about _someone_...\n", prefix, nick); return; } wordshift(word1, text); oix = strchr(word1, '\''); /* Have we got a NICK's target? */ if (oix == word1) return; /* Skip anything starting with ' */ if (oix && *oix && ((oix[1] && (oix[1] == 's' || oix[1] == 'S') && !oix[2]) || (!oix[1] && (oix[-1] == 's' || oix[-1] == 'z' || oix[-1] == 'x' || oix[-1] == 'S' || oix[-1] == 'Z' || oix[-1] == 'X')))) { strncpy(object, word1, oix - word1); object[oix - word1] = 0; wordshift(word1, text); if (!word1[0]) { dprintf(idx, "%s%s's what, %s?\n", prefix, object, nick); return; } urec = get_user_by_handle(userlist, object); if (!urec) { chan = chanset; while (chan) { onchan = 0; m = ismember(chan, object); if (m) { onchan = 1; sprintf(stuff, "%s!%s", object, m->userhost); urec = get_user_by_host(stuff); if (!urec || !egg_strcasecmp(object, urec->handle)) break; strcat(whoredirect, object); strcat(whoredirect, " is "); strcat(whoredirect, urec->handle); strcat(whoredirect, ", and "); strcpy(object, urec->handle); break; } chan = chan->next; } if (!onchan) { dprintf(idx, "%sI don't think I know who %s is, %s.\n", prefix, object, nick); return; } } if (!egg_strcasecmp(word1, "bf") || !egg_strcasecmp(word1, "boyfriend")) { strcpy(whotarget, getxtra(object, "BF")); if (whotarget[0]) { sprintf(whoredirect, "%s boyfriend is %s, and ", fixnick(object), whotarget); goto targetcont; } dprintf(idx, "%sI don't know who %s boyfriend is, %s.\n", prefix, fixnick(object), nick); return; } if (!egg_strcasecmp(word1, "gf") || !egg_strcasecmp(word1, "girlfriend")) { strcpy(whotarget, getxtra(object, "GF")); if (whotarget[0]) { sprintf(whoredirect, "%s girlfriend is %s, and ", fixnick(object), whotarget); goto targetcont; } dprintf(idx, "%sI don't know who %s girlfriend is, %s.\n", prefix, fixnick(object), nick); return; } dprintf(idx, "%sWhy are you bothering me with questions about %s %s, %s?\n", prefix, fixnick(object), word1, nick); return; } /* Keyword "my" */ if (!egg_strcasecmp(word1, "my")) { wordshift(word1, text); if (!word1[0]) { dprintf(idx, "%sYour what, %s?\n", prefix, nick); return; } /* Do I even KNOW the requestor? */ if (hand[0] == '*' || !hand[0]) { dprintf(idx, "%sI don't know you, %s, so I don't know about your %s.\n", prefix, nick, word1); return; } /* "my boyfriend" */ if (!egg_strcasecmp(word1, "boyfriend") || !egg_strcasecmp(word1, "bf")) { strcpy(whotarget, getxtra(hand, "BF")); if (whotarget[0]) { sprintf(whoredirect, "%s, your boyfriend is %s, and ", nick, whotarget); } else { dprintf(idx, "%sI didn't know you had a boyfriend, %s\n", prefix, nick); return; } } /* "my girlfriend" */ else if (!egg_strcasecmp(word1, "girlfriend") || !egg_strcasecmp(word1, "gf")) { strcpy(whotarget, getxtra(hand, "GF")); if (whotarget[0]) { sprintf(whoredirect, "%s, your girlfriend is %s, and ", nick, whotarget); } else { dprintf(idx, "%sI didn't know you had a girlfriend, %s\n", prefix, nick); return; } } else { dprintf(idx, "%sI don't know anything about your %s, %s.\n", prefix, word1, nick); return; } } /* "your" keyword */ else if (!egg_strcasecmp(word1, "your")) { wordshift(word1, text); /* "your admin" */ if (!egg_strcasecmp(word1, "owner") || !egg_strcasecmp(word1, "admin")) { if (admin[0]) { strcpy(word2, admin); wordshift(whotarget, word2); strcat(whoredirect, "My owner is "); strcat(whoredirect, whotarget); strcat(whoredirect, ", and "); if (!egg_strcasecmp(whotarget, hand)) { strcat(whoredirect, "that's YOU"); if (!egg_strcasecmp(hand, nick)) strcat(whoredirect, "!!!"); else { strcat(whoredirect, ", "); strcat(whoredirect, nick); strcat(whoredirect, "!"); } dprintf(idx, "%s%s\n", prefix, whoredirect); return; } } else { /* owner variable munged or not set */ dprintf(idx, "%sI don't seem to recall who my owner is right now...\n", prefix); return; } } else { /* no "your" target specified */ dprintf(idx, "%sLet's not get personal, %s.\n", prefix, nick); return; } } /* Check for keyword match in the internal table */ else if (match_trigger(word1)) { sprintf(word2, "%s%s\n", prefix, match_trigger(word1)); dprintf(idx, word2, nick); return; } /* Otherwise, make the target to the first word and continue */ else strcpy(whotarget, word1); targetcont: /* Looking for ones own nick? */ if (!rfc_casecmp(nick, whotarget)) { dprintf(idx, "%s%sLooking for yourself, eh %s?\n", prefix, whoredirect, nick); return; } /* Check if nick is on a channel */ chan = chanset; while (chan) { m = ismember(chan, whotarget); if (m) { onchan = 1; sprintf(word1, "%s!%s", whotarget, m->userhost); urec = get_user_by_host(word1); if (!urec || !egg_strcasecmp(whotarget, urec->handle)) break; strcat(whoredirect, whotarget); strcat(whoredirect, " is "); strcat(whoredirect, urec->handle); strcat(whoredirect, ", and "); break; } chan = chan->next; } /* Check if nick is on a channel by xref'ing to handle */ if (!onchan) { chan = chanset; while (chan) { m = chan->channel.member; while (m && m->nick[0]) { sprintf(word2, "%s!%s", m->nick, m->userhost); urec = get_user_by_host(word2); if (urec && !egg_strcasecmp(urec->handle, whotarget)) { onchan = 1; strcat(whoredirect, whotarget); strcat(whoredirect, " is "); strcat(whoredirect, m->nick); strcat(whoredirect, ", and "); strcpy(whotarget, m->nick); break; } m = m->next; } chan = chan->next; } } /* Check if the target was on the channel, but is netsplit */ chan = findchan_by_dname(channel); if (chan) { m = ismember(chan, whotarget); if (m && chan_issplit(m)) { dprintf(idx, "%s%s%s was just here, but got netsplit.\n", prefix, whoredirect, whotarget); return; } } /* Check if the target IS on the channel */ if (chan && m) { dprintf(idx, "%s%s%s is on the channel right now!\n", prefix, whoredirect, whotarget); return; } /* Target not on this channel. Check other channels */ chan = chanset; while (chan) { m = ismember(chan, whotarget); if (m && chan_issplit(m)) { dprintf(idx, "%s%s%s was just on %s, but got netsplit.\n", prefix, whoredirect, whotarget, chan->dname); return; } if (m) { dprintf(idx, "%s%s%s is on %s right now!\n", prefix, whoredirect, whotarget, chan->dname); return; } chan = chan->next; } /* Target isn't on any of my channels. */ /* See if target matches a handle in my userlist. */ urec = get_user_by_handle(userlist, whotarget); /* No match, then bail out */ if (!urec) { dprintf(idx, "%s%sI don't know who %s is.\n", prefix, whoredirect, whotarget); return; } /* We had a userlist match to a handle */ /* Is the target currently DCC CHAT to me on the botnet? */ for (i = 0; i < dcc_total; i++) { if (dcc[i].type->flags & DCT_CHAT) { if (!egg_strcasecmp(whotarget, dcc[i].nick)) { if (!rfc_casecmp(channel, dcc[i].u.chat->con_chan) && dcc[i].u.chat->con_flags & LOG_PUBLIC) { strcat(whoredirect, whotarget); strcat(whoredirect, " is 'observing' this channel right now from my party line!"); dprintf(idx, "%s%s\n", prefix, whoredirect); } else { dprintf(idx, "%s%s%s is linked to me via DCC CHAT right now!\n", prefix, whoredirect, whotarget); } return; } } } /* Target known, but nowhere to be seen. Give last IRC and botnet time */ wordshift(word1, text); if (!egg_strcasecmp(word1, "anywhere")) cr = NULL; else for (cr = urec->chanrec; cr; cr = cr->next) { if (!rfc_casecmp(cr->channel, channel)) { if (cr->laston) { laston = cr->laston; lastonplace = channel; break; } } } if (!cr) { li = get_user(&USERENTRY_LASTON, urec); if (!li || !li->lastonplace || !li->lastonplace[0]) { dprintf(idx, "%s%sI've never seen %s around.\n", prefix, whoredirect, whotarget); return; } lastonplace = li->lastonplace; laston = li->laston; } word1[0] = 0; word2[0] = 0; work = now - laston; if (work >= 86400) { tv = work / 86400; sprintf(word2, "%lu day%s, ", tv, (tv == 1) ? "" : "s"); work = work % 86400; } if (work >= 3600) { tv = work / 3600; sprintf(word2 + strlen(word2), "%lu hour%s, ", tv, (tv == 1) ? "" : "s"); work = work % 3600; } if (work >= 60) { tv = work / 60; sprintf(word2 + strlen(word2), "%lu minute%s, ", tv, (tv == 1) ? "" : "s"); } if (!word2[0] && (work < 60)) { strcpy(word2, "just moments ago!!"); } else { strcpy(word2 + strlen(word2) - 2, " ago."); } if (lastonplace[0] && (strchr(CHANMETA, lastonplace[0]) != NULL)) sprintf(word1, "on IRC channel %s", lastonplace); else if (lastonplace[0] == '@') sprintf(word1, "on %s", lastonplace + 1); else if (lastonplace[0] != 0) sprintf(word1, "on my %s", lastonplace); else strcpy(word1, "seen"); dprintf(idx, "%s%s%s was last %s %s\n", prefix, whoredirect, whotarget, word1, word2); }
static void got_ban(struct chanset_t *chan, char *nick, char *from, char *who, char *ch, struct userrec *u) { char me[UHOSTLEN], s[UHOSTLEN], s1[UHOSTLEN]; memberlist *m; struct userrec *targ; egg_snprintf(me, sizeof me, "%s!%s", botname, botuserhost); egg_snprintf(s, sizeof s, "%s!%s", nick, from); newban(chan, who, s); check_tcl_mode(nick, from, u, chan->dname, "+b", who); if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return; if (channel_pending(chan) || HALFOP_CANTDOMODE('b')) return; if (match_addr(who, me) && !isexempted(chan, me)) { add_mode(chan, '-', 'b', who); reversing = 1; return; } if (!match_my_nick(nick)) { if (nick[0] && channel_nouserbans(chan) && !glob_bot(user) && !glob_master(user) && !chan_master(user)) { add_mode(chan, '-', 'b', who); return; } for (m = chan->channel.member; m && m->nick[0]; m = m->next) { egg_snprintf(s1, sizeof s1, "%s!%s", m->nick, m->userhost); if (match_addr(who, s1)) { targ = get_user_by_host(s1); if (targ) { get_user_flagrec(targ, &victim, chan->dname); if ((glob_friend(victim) || (glob_op(victim) && !chan_deop(victim)) || chan_friend(victim) || chan_op(victim)) && !glob_master(user) && !glob_bot(user) && !chan_master(user) && !isexempted(chan, s1)) { add_mode(chan, '-', 'b', who); return; } } } } } refresh_exempt(chan, who); if (nick[0] && channel_enforcebans(chan)) { register maskrec *b; int cycle; char resn[512] = ""; for (cycle = 0; cycle < 2; cycle++) { for (b = cycle ? chan->bans : global_bans; b; b = b->next) { if (match_addr(b->mask, who)) { if (b->desc && b->desc[0] != '@') egg_snprintf(resn, sizeof resn, "%s %s", IRC_PREBANNED, b->desc); else resn[0] = 0; } } } kick_all(chan, who, resn[0] ? resn : IRC_BANNED, match_my_nick(nick) ? 0 : 1); } if (!nick[0] && (bounce_bans || bounce_modes) && (!u_equals_mask(global_bans, who) || !u_equals_mask(chan->bans, who))) add_mode(chan, '-', 'b', who); }