/* This is a reply on ISON :<current> <orig> [<alt>] */ static void got303(char *from, char *msg) { char *tmp, *alt; int ison_orig = 0, ison_alt = 0; if (!keepnick || !strncmp(botname, origbotname, strlen(botname))) { return; } newsplit(&msg); fixcolon(msg); alt = get_altbotnick(); tmp = newsplit(&msg); if (tmp[0] && !rfc_casecmp(botname, tmp)) { while ((tmp = newsplit(&msg))[0]) { /* no, it's NOT == */ if (!rfc_casecmp(tmp, origbotname)) ison_orig = 1; else if (alt[0] && !rfc_casecmp(tmp, alt)) ison_alt = 1; } if (!ison_orig) { if (!nick_juped) putlog(LOG_MISC, "*", IRC_GETORIGNICK, origbotname); dprintf(DP_SERVER, "NICK %s\n", origbotname); } else if (alt[0] && !ison_alt && rfc_casecmp(botname, alt)) { putlog(LOG_MISC, "*", IRC_GETALTNICK, alt); dprintf(DP_SERVER, "NICK %s\n", alt); } } }
/* 438 : Nick change too fast */ static int got438(char *from, char *msg) { newsplit(&msg); newsplit(&msg); fixcolon(msg); putlog(LOG_MISC, "*", "%s", msg); return 0; }
/* 001: welcome to IRC (use it to fix the server name) */ static int got001(char *from, char *msg) { int i; char *key; struct chanset_t *chan; struct server_list *x = serverlist; /* FIXME - x should never be NULL anywhere in this function, but * apparently it sometimes is. */ if (x) { for (i = curserv; i > 0 && x; i--) x = x->next; if (!x) { putlog(LOG_MISC, "*", "Invalid server list!"); } else { if (x->realname) nfree(x->realname); x->realname = nmalloc(strlen(from) + 1); strcpy(x->realname, from); } if (realservername) nfree(realservername); realservername = nmalloc(strlen(from) + 1); strcpy(realservername, from); } else putlog(LOG_MISC, "*", "No server list!"); server_online = now; fixcolon(msg); strncpyz(botname, msg, NICKLEN); altnick_char = 0; dprintf(DP_SERVER, "WHOIS %s\n", botname); /* get user@host */ if (initserver[0]) do_tcl("init-server", initserver); /* Call Tcl init-server */ check_tcl_event("init-server"); if (!x) return 0; if (module_find("irc", 0, 0)) { /* Only join if the IRC module is loaded. */ for (chan = chanset; chan; chan = chan->next) { chan->status &= ~(CHAN_ACTIVE | CHAN_PEND); if (!channel_inactive(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); } } } return 0; }
/* Pong from server. */ static int gotpong(char *from, char *msg) { newsplit(&msg); fixcolon(msg); /* Scrap server name */ server_lag = now - my_atoul(msg); if (server_lag > 99999) { /* IRCnet lagmeter support by drummer */ server_lag = now - lastpingtime; } return 0; }
/* * 465 ERR_YOUREBANNEDCREEP :You are banned from this server */ static int got465(char *from, char *msg) { newsplit(&msg); /* 465 */ fixcolon(msg); putlog(LOG_SERV, "*", "Server (%s) says I'm banned: %s", from, msg); putlog(LOG_SERV, "*", "Disconnecting from server."); nuke_server("Banned from server."); return 1; }
/* 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; }
/* 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; }
static int gotmode(char *from, char *msg) { char *ch; ch = newsplit(&msg); /* Usermode changes? */ if (strchr(CHANMETA, ch[0]) == NULL) { if (match_my_nick(ch) && check_mode_r) { /* umode +r? - D0H dalnet uses it to mean something different */ fixcolon(msg); if ((msg[0] == '+') && strchr(msg, 'r')) { int servidx = findanyidx(serv); putlog(LOG_MISC | LOG_JOIN, "*", "%s has me i-lined (jumping)", dcc[servidx].host); nuke_server("i-lines suck"); } } } return 0; }
/* got 251: lusers * <server> 251 <to> :there are 2258 users and 805 invisible on 127 servers */ static int got251(char *from, char *msg) { int i; char *servs; if (min_servs == 0) return 0; /* No minimum limit on servers */ newsplit(&msg); fixcolon(msg); /* NOTE!!! If servlimit is not set or is 0 */ for (i = 0; i < 8; i++) newsplit(&msg); /* lusers IS NOT SENT AT ALL!! */ servs = newsplit(&msg); if (strncmp(msg, "servers", 7)) return 0; /* Was invalid format */ while (*servs && (*servs < 32)) servs++; /* I've seen some lame nets put bolds & * stuff in here :/ */ i = atoi(servs); if (i < min_servs) { putlog(LOG_SERV, "*", IRC_AUTOJUMP, min_servs, i); nuke_server(IRC_CHANGINGSERV); } 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; }
static int gotping(char *from, char *msg) { fixcolon(msg); dprintf(DP_MODE, "PONG :%s\n", msg); return 0; }
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; }