/* 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); }
/* If this user@host is in a channel, set it (it was null) */ void set_chanlist(const char *host, struct userrec *rec) { char *nick, *uhost, buf[UHOSTLEN]; register memberlist *m; register struct chanset_t *chan; strncpyz(buf, host, sizeof buf); uhost = buf; nick = splitnick(&uhost); for (chan = chanset; chan; chan = chan->next) for (m = chan->channel.member; m && m->nick[0]; m = m->next) if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost)) m->user = rec; }
/* WALLOPS: oper's nuisance */ static int gotwall(char *from, char *msg) { char *nick; fixcolon(msg); if (check_tcl_wall(from, msg) != 2) { if (strchr(from, '!')) { nick = splitnick(&from); putlog(LOG_WALL, "*", "!%s(%s)! %s", nick, from, msg); } else putlog(LOG_WALL, "*", "!%s! %s", from, msg); } return 0; }
/* Shortcut for get_user_by_host -- might have user record in one * of the channel caches. */ struct userrec *check_chanlist(const char *host) { char *nick = NULL, *uhost = NULL, buf[UHOSTLEN] = ""; register memberlist *m = NULL; register struct chanset_t *chan = NULL; strlcpy(buf, host, sizeof buf); uhost = buf; nick = splitnick(&uhost); for (chan = chanset; chan; chan = chan->next) for (m = chan->channel.member; m && m->nick[0]; m = m->next) if (!rfc_casecmp(nick, m->nick) && !strcasecmp(uhost, m->userhost)) return m->user; return NULL; }
/* 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; }
/* Got nick change. */ static int gotnick(char *from, char *msg) { char *nick, *alt = get_altbotnick(); nick = splitnick(&from); fixcolon(msg); check_queues(nick, msg); if (match_my_nick(nick)) { /* Regained nick! */ strncpyz(botname, msg, NICKLEN); altnick_char = 0; if (!strcmp(msg, origbotname)) { putlog(LOG_SERV | LOG_MISC, "*", "Regained nickname '%s'.", msg); nick_juped = 0; } else if (alt[0] && !strcmp(msg, alt)) putlog(LOG_SERV | LOG_MISC, "*", "Regained alternate nickname '%s'.", msg); else if (keepnick && strcmp(nick, msg)) { putlog(LOG_SERV | LOG_MISC, "*", "Nickname changed to '%s'???", msg); if (!rfc_casecmp(nick, origbotname)) { putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname); dprintf(DP_SERVER, "NICK %s\n", origbotname); } else if (alt[0] && !rfc_casecmp(nick, alt) && egg_strcasecmp(botname, origbotname)) { putlog(LOG_MISC, "*", IRC_GETALTNICK, alt); dprintf(DP_SERVER, "NICK %s\n", alt); } } else putlog(LOG_SERV | LOG_MISC, "*", "Nickname changed to '%s'???", msg); } else if ((keepnick) && (rfc_casecmp(nick, msg))) { /* Only do the below if there was actual nick change, case doesn't count */ if (!rfc_casecmp(nick, origbotname)) { putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname); dprintf(DP_SERVER, "NICK %s\n", origbotname); } else if (alt[0] && !rfc_casecmp(nick, alt) && egg_strcasecmp(botname, origbotname)) { putlog(LOG_MISC, "*", IRC_GETALTNICK, altnick); dprintf(DP_SERVER, "NICK %s\n", altnick); } } 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; }
/* 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; }
/* Dependant on revenge_mode, punish the offender. */ static void punish_badguy(struct chanset_t *chan, char *whobad, struct userrec *u, char *badnick, char *victim, int mevictim, int type) { char reason[1024], ct[81], *kick_msg; memberlist *m; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; m = ismember(chan, badnick); if (!m) return; get_user_flagrec(u, &fr, chan->dname); /* Get current time into a string */ egg_strftime(ct, 7, "%d %b", localtime(&now)); /* Put together log and kick messages */ reason[0] = 0; switch (type) { case REVENGE_KICK: kick_msg = IRC_KICK_PROTECT; simple_sprintf(reason, "kicked %s off %s", victim, chan->dname); break; case REVENGE_DEOP: simple_sprintf(reason, "deopped %s on %s", victim, chan->dname); kick_msg = IRC_DEOP_PROTECT; break; default: kick_msg = "revenge!"; } putlog(LOG_MISC, chan->dname, "Punishing %s (%s)", badnick, reason); /* Set the offender +d */ if ((chan->revenge_mode > 0) && !(chan_deop(fr) || glob_deop(fr))) { char s[UHOSTLEN], s1[UHOSTLEN]; memberlist *mx = NULL; /* Removing op */ if (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) { fr.match = FR_CHAN; if (chan_op(fr)) fr.chan &= ~USER_OP; else fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); putlog(LOG_MISC, "*", "No longer opping %s[%s] (%s)", u->handle, whobad, reason); } /* ... or just setting to deop */ else if (u) { /* In the user list already, cool :) */ fr.match = FR_CHAN; fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s", ct, reason); putlog(LOG_MISC, "*", "Now deopping %s[%s] (%s)", u->handle, whobad, s); } /* ... or creating new user and setting that to deop */ else { strcpy(s1, whobad); maskaddr(s1, s, chan->ban_type); strcpy(s1, badnick); /* If that handle exists use "badX" (where X is an increasing number) * instead. */ while (get_user_by_handle(userlist, s1)) { if (!strncmp(s1, "bad", 3)) { int i; i = atoi(s1 + 3); simple_sprintf(s1 + 3, "%d", i + 1); } else strcpy(s1, "bad1"); /* Start with '1' */ } userlist = adduser(userlist, s1, s, "-", 0); fr.match = FR_CHAN; fr.chan = USER_DEOP; fr.udef_chan = 0; u = get_user_by_handle(userlist, s1); if ((mx = ismember(chan, badnick))) mx->user = u; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s (%s)", ct, reason, whobad); set_user(&USERENTRY_COMMENT, u, (void *) s); putlog(LOG_MISC, "*", "Now deopping %s (%s)", whobad, reason); } } /* Always try to deop the offender */ if (!mevictim) add_mode(chan, '-', 'o', badnick); /* Ban. Should be done before kicking. */ if (chan->revenge_mode > 2) { char s[UHOSTLEN], s1[UHOSTLEN]; splitnick(&whobad); maskaddr(whobad, s1, chan->ban_type); simple_sprintf(s, "(%s) %s", ct, reason); u_addban(chan, s1, botnetnick, s, now + (60 * chan->ban_time), 0); if (!mevictim && HALFOP_CANDOMODE('b')) { add_mode(chan, '+', 'b', s1); flush_mode(chan, QUICK); } } /* Kick the offender */ if (!mevictim && (chan->revenge_mode > 1) && (!channel_dontkickops(chan) || (!chan_op(fr) && (!glob_op(fr) || chan_deop(fr)))) && !chan_sentkick(m) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m) && (strchr(NOHALFOPS_MODES, 'b') == NULL)))) { dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, badnick, kick_msg); m->flags |= SENTKICK; } }
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 tell_invites(int idx, int show_inact, char *match) { int k = 1; char *chname; struct chanset_t *chan = NULL; maskrec *u; /* Was a channel given? */ if (match[0]) { chname = newsplit(&match); if (chname[0] && strchr(CHANMETA, chname[0])) { chan = findchan_by_dname(chname); if (!chan) { dprintf(idx, "%s.\n", CHAN_NOSUCH); return; } } else match = chname; } /* don't return here, we want to show global invites even if no chan */ if (!chan && !(chan = findchan_by_dname(dcc[idx].u.chat->con_chan)) && !(chan = chanset)) chan = NULL; if (chan && show_inact) dprintf(idx, "%s: (! = %s %s)\n", INVITES_GLOBAL, MODES_NOTACTIVE, chan->dname); else dprintf(idx, "%s:\n", INVITES_GLOBAL); for (u = global_invites; u; u = u->next) { if (match[0]) { if ((match_addr(match, u->mask)) || (wild_match(match, u->desc)) || (wild_match(match, u->user))) display_invite(idx, k, u, chan, 1); k++; } else display_invite(idx, k++, u, chan, show_inact); } if (chan) { if (show_inact) dprintf(idx, "%s %s: (! = %s, * = %s)\n", INVITES_BYCHANNEL, chan->dname, MODES_NOTACTIVE2, MODES_NOTBYBOT); else dprintf(idx, "%s %s: (* = %s)\n", INVITES_BYCHANNEL, chan->dname, MODES_NOTBYBOT); for (u = chan->invites; u; u = u->next) { if (match[0]) { if ((match_addr(match, u->mask)) || (wild_match(match, u->desc)) || (wild_match(match, u->user))) display_invite(idx, k, u, chan, 1); k++; } else display_invite(idx, k++, u, chan, show_inact); } if (chan->status & CHAN_ACTIVE) { masklist *i; char s[UHOSTLEN], *s1, *s2, fill[256]; int min, sec; for (i = chan->channel.invite; i && i->mask[0]; i = i->next) { if ((!u_equals_mask(global_invites, i->mask)) && (!u_equals_mask(chan->invites, i->mask))) { strcpy(s, i->who); s2 = s; s1 = splitnick(&s2); if (s1[0]) sprintf(fill, "%s (%s!%s)", i->mask, s1, s2); else sprintf(fill, "%s (server %s)", i->mask, s2); if (i->timer != 0) { min = (now - i->timer) / 60; sec = (now - i->timer) - (min * 60); sprintf(s, " (active %02d:%02d)", min, sec); strcat(fill, s); } if ((!match[0]) || (match_addr(match, i->mask))) dprintf(idx, "* [%3d] %s\n", k, fill); k++; } } } } if (k == 1) dprintf(idx, "(There are no invites, permanent or otherwise.)\n"); if ((!show_inact) && (!match[0])) dprintf(idx, "%s.\n", INVITES_USEINVITESALL); }