/* Check timers, execute the ones that have expired. */ void do_check_timers(tcl_timer_t ** stack) { tcl_timer_t *mark = *stack, *old = NULL; char x[16]; /* New timers could be added by a Tcl script inside a current timer * so i'll just clear out the timer list completely, and add any * unexpired timers back on. */ *stack = NULL; while (mark) { if (mark->mins > 0) mark->mins--; old = mark; mark = mark->next; if (!old->mins) { egg_snprintf(x, sizeof x, "timer%lu", old->id); do_tcl(x, old->cmd); if (old->count == 1) { nfree(old->cmd); nfree(old); continue; } else { old->mins = old->interval; if (old->count > 1) old->count--; } } old->next = *stack; *stack = old; } }
/* 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; }
/* 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); } } }
/* Hook up to a server */ static void connect_server(void) { char pass[121], botserver[UHOSTLEN]; int servidx; unsigned int botserverport = 0; lastpingcheck = 0; trying_server = now; empty_msgq(); if (newserverport) { /* Jump to specified server */ curserv = -1; /* Reset server list */ strcpy(botserver, newserver); botserverport = newserverport; strcpy(pass, newserverpass); newserver[0] = 0; newserverport = 0; newserverpass[0] = 0; } else { if (curserv == -1) curserv = 999; pass[0] = 0; } if (!cycle_time) { struct chanset_t *chan; struct server_list *x = serverlist; if (!x && !botserverport) { putlog(LOG_SERV, "*", "No servers in server list"); cycle_time = 300; return; } servidx = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info)); if (servidx < 0) { putlog(LOG_SERV, "*", "NO MORE DCC CONNECTIONS -- Can't create server connection."); return; } if (connectserver[0]) /* drummer */ do_tcl("connect-server", connectserver); check_tcl_event("connect-server"); next_server(&curserv, botserver, &botserverport, pass); #ifdef TLS putlog(LOG_SERV, "*", "%s [%s]:%s%d", IRC_SERVERTRY, botserver, use_ssl ? "+" : "", botserverport); dcc[servidx].ssl = use_ssl; #else putlog(LOG_SERV, "*", "%s [%s]:%d", IRC_SERVERTRY, botserver, botserverport); #endif dcc[servidx].port = botserverport; strcpy(dcc[servidx].nick, "(server)"); strncpyz(dcc[servidx].host, botserver, UHOSTLEN); botuserhost[0] = 0; nick_juped = 0; for (chan = chanset; chan; chan = chan->next) chan->status &= ~CHAN_JUPED; dcc[servidx].timeval = now; dcc[servidx].sock = -1; dcc[servidx].u.dns->host = get_data_ptr(strlen(dcc[servidx].host) + 1); strcpy(dcc[servidx].u.dns->host, dcc[servidx].host); dcc[servidx].u.dns->cbuf = get_data_ptr(strlen(pass) + 1); strcpy(dcc[servidx].u.dns->cbuf, pass); dcc[servidx].u.dns->dns_success = server_resolve_success; dcc[servidx].u.dns->dns_failure = server_resolve_failure; dcc[servidx].u.dns->dns_type = RES_IPBYHOST; dcc[servidx].u.dns->type = &SERVER_SOCKET; if (server_cycle_wait) /* Back to 1st server & set wait time. * Note: Put it here, just in case the server quits on us quickly */ cycle_time = server_cycle_wait; else cycle_time = 0; /* I'm resolving... don't start another server connect request */ resolvserv = 1; /* Resolve the hostname. */ dcc_dnsipbyhost(dcc[servidx].host); } }
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); }