#ifdef LEAF #define MODULE_NAME "server" #define MAKING_SERVER #include "src/mod/module.h" #include "server.h" static Function *global = NULL, *encryption_funcs; extern struct cfg_entry CFG_OPTIMESLACK; static int ctcp_mode; static int serv; static int strict_host; static char newserver[121]; static int newserverport; static char newserverpass[121]; static time_t trying_server; static int server_lag; static char altnick[NICKLEN]; static char raltnick[NICKLEN]; static int curserv; static int flud_thr; static int flud_time; static int flud_ctcp_thr; static int flud_ctcp_time; static char initserver[121]; static char botuserhost[121]; static int keepnick; static int nick_juped = 0; static int check_stoned; static int serverror_quit; static int quiet_reject; static int waiting_for_awake; static time_t server_online; static time_t server_cycle_wait; static char botrealname[121]; static int min_servs; static int server_timeout; static int never_give_up; static int strict_servernames; static struct server_list *serverlist; static int cycle_time; static int default_port; static char oldnick[NICKLEN]; static int trigger_on_ignore; static int answer_ctcp; static int lowercase_ctcp; static int check_mode_r; static int net_type; static char connectserver[121]; static int resolvserv; static int double_mode; static int double_server; static int double_help; static int double_warned; static int lastpingtime; static char stackablecmds[511]; static char stackable2cmds[511]; static time_t last_time; static int use_penalties; static int use_fastdeq; static int nick_len; static int kick_method; static int optimize_kicks; static p_tcl_bind_list H_wall, H_raw, H_notc, H_msgm, H_msg, H_flud, H_ctcr, H_ctcp; static void empty_msgq (void); static void next_server (int *, char *, unsigned int *, char *); static void disconnect_server (int); static char *get_altbotnick (void); static int calc_penalty (char *); static int fast_deq (int); static char *splitnicks (char **); static void check_queues (char *, char *); static void parse_q (struct msgq_head *, char *, char *); static void purge_kicks (struct msgq_head *); static int deq_kick (int); static void msgq_clear (struct msgq_head *qh); static int stack_limit; #include "servmsg.c" #define MAXPENALTY 10 #define msgrate 2 static int maxqmsg; static struct msgq_head mq, hq, modeq; static int burst; #include "cmdsserv.c" #include "tclserv.c" static void deq_msg () { struct msgq *q; int ok = 0; if ((now - last_time) >= msgrate || now < (last_time - 90)) { last_time = now; if (burst > 0) burst--; ok = 1; } if (serv < 0) return; if (modeq.head) { while (modeq.head && (burst < 4) && ((last_time - now) < MAXPENALTY)) { if (deq_kick (DP_MODE)) { burst++; continue; } if (!modeq.head) break; if (fast_deq (DP_MODE)) { burst++; continue; } tputs (serv, modeq.head->msg, modeq.head->len); if (debug_output) { modeq.head->msg[strlen (modeq.head->msg) - 1] = 0; putlog (LOG_SRVOUT, "@", "[m->] %s", modeq.head->msg); } modeq.tot--; last_time += calc_penalty (modeq.head->msg); q = modeq.head->next; nfree (modeq.head->msg); nfree (modeq.head); modeq.head = q; burst++; } if (!modeq.head) modeq.last = 0; return; } if (burst > 1) return; if (mq.head) { burst++; if (deq_kick (DP_SERVER)) return; if (fast_deq (DP_SERVER)) return; tputs (serv, mq.head->msg, mq.head->len); if (debug_output) { mq.head->msg[strlen (mq.head->msg) - 1] = 0; putlog (LOG_SRVOUT, "@", "[s->] %s", mq.head->msg); } mq.tot--; last_time += calc_penalty (mq.head->msg); q = mq.head->next; nfree (mq.head->msg); nfree (mq.head); mq.head = q; if (!mq.head) mq.last = NULL; return; } if (!hq.head || burst || !ok) return; if (deq_kick (DP_HELP)) return; if (fast_deq (DP_HELP)) return; tputs (serv, hq.head->msg, hq.head->len); if (debug_output) { hq.head->msg[strlen (hq.head->msg) - 1] = 0; putlog (LOG_SRVOUT, "*", "[h->] %s", hq.head->msg); } hq.tot--; last_time += calc_penalty (hq.head->msg); q = hq.head->next; nfree (hq.head->msg); nfree (hq.head); hq.head = q; if (!hq.head) hq.last = NULL; } static int calc_penalty (char *msg) { char *cmd, *par1, *par2, *par3; register int penalty, i, ii; if (!use_penalties && net_type != NETT_UNDERNET && net_type != NETT_HYBRID_EFNET) return 0; if (msg[strlen (msg) - 1] == '\n') msg[strlen (msg) - 1] = '\0'; cmd = newsplit (&msg); if (msg) i = strlen (msg); else i = strlen (cmd); last_time -= 2; if (net_type == NETT_UNDERNET || net_type == NETT_HYBRID_EFNET) { last_time += (2 + i / 120); return 0; } penalty = (1 + i / 100); if (!egg_strcasecmp (cmd, "KICK")) { par1 = newsplit (&msg); par2 = newsplit (&msg); par3 = splitnicks (&par2); penalty++; while (strlen (par3) > 0) { par3 = splitnicks (&par2); penalty++; } ii = penalty; par3 = splitnicks (&par1); while (strlen (par1) > 0) { par3 = splitnicks (&par1); penalty += ii; } } else if (!egg_strcasecmp (cmd, "MODE")) { i = 0; par1 = newsplit (&msg); par2 = newsplit (&msg); if (!strlen (par2)) i++; while (strlen (par2) > 0) { if (strchr ("ntimps", par2[0])) i += 3; else if (!strchr ("+-", par2[0])) i += 1; par2++; } while (strlen (msg) > 0) { newsplit (&msg); i += 2; } ii = 0; while (strlen (par1) > 0) { splitnicks (&par1); ii++; } penalty += (ii * i); } else if (!egg_strcasecmp (cmd, "TOPIC")) { penalty++; par1 = newsplit (&msg); par2 = newsplit (&msg); if (strlen (par2) > 0) { penalty += 2; par3 = splitnicks (&par1); while (strlen (par1) > 0) { par3 = splitnicks (&par1); penalty += 2; } } } else if (!egg_strcasecmp (cmd, "PRIVMSG") || !egg_strcasecmp (cmd, "NOTICE")) { par1 = newsplit (&msg); while (strlen (par1) > 0) { splitnicks (&par1); penalty++; } } else if (!egg_strcasecmp (cmd, "WHO")) { par1 = newsplit (&msg); par2 = par1; while (strlen (par1) > 0) { par2 = splitnicks (&par1); if (strlen (par2) > 4) penalty += 3; else penalty += 5; } } else if (!egg_strcasecmp (cmd, "AWAY")) { if (strlen (msg) > 0) penalty += 2; else penalty += 1; } else if (!egg_strcasecmp (cmd, "INVITE")) { penalty += 3; } else if (!egg_strcasecmp (cmd, "JOIN")) { penalty += 2; } else if (!egg_strcasecmp (cmd, "PART")) { penalty += 4; } else if (!egg_strcasecmp (cmd, "VERSION")) { penalty += 2; } else if (!egg_strcasecmp (cmd, "TIME")) { penalty += 2; } else if (!egg_strcasecmp (cmd, "TRACE")) { penalty += 2; } else if (!egg_strcasecmp (cmd, "NICK")) { penalty += 3; } else if (!egg_strcasecmp (cmd, "ISON")) { penalty += 1; } else if (!egg_strcasecmp (cmd, "WHOIS")) { penalty += 2; } else if (!egg_strcasecmp (cmd, "DNS")) { penalty += 2; } else penalty++; if (penalty > 99) penalty = 99; if (penalty < 2) { putlog (LOG_SRVOUT, "*", "Penalty < 2sec, that's impossible!"); penalty = 2; } if (debug_output && penalty != 0) putlog (LOG_SRVOUT, "*", "Adding penalty: %i", penalty); return penalty; } char * splitnicks (char **rest) { register char *o, *r; if (!rest) return *rest = ""; o = *rest; while (*o == ' ') o++; r = o; while (*o && *o != ',') o++; if (*o) *o++ = 0; *rest = o; return r; } static int fast_deq (int which) { struct msgq_head *h; struct msgq *m, *nm; char msgstr[511], nextmsgstr[511], tosend[511], victims[511], stackable[511], *msg, *nextmsg, *cmd, *nextcmd, *to, *nextto, *stckbl; int len, doit = 0, found = 0, cmd_count = 0, stack_method = 1; if (!use_fastdeq) return 0; switch (which) { case DP_MODE: h = &modeq; break; case DP_SERVER: h = &mq; break; case DP_HELP: h = &hq; break; default: return 0; } m = h->head; strncpyz (msgstr, m->msg, sizeof msgstr); msg = msgstr; cmd = newsplit (&msg); if (use_fastdeq > 1) { strncpyz (stackable, stackablecmds, sizeof stackable); stckbl = stackable; while (strlen (stckbl) > 0) if (!egg_strcasecmp (newsplit (&stckbl), cmd)) { found = 1; break; } if (use_fastdeq == 2 && !found) return 0; if (use_fastdeq == 3 && found) return 0; strncpyz (stackable, stackable2cmds, sizeof stackable); stckbl = stackable; while (strlen (stckbl) > 0) if (!egg_strcasecmp (newsplit (&stckbl), cmd)) { stack_method = 2; break; } } to = newsplit (&msg); len = strlen (to); if (to[len - 1] == '\n') to[len - 1] = 0; simple_sprintf (victims, "%s", to); while (m) { nm = m->next; if (!nm) break; strncpyz (nextmsgstr, nm->msg, sizeof nextmsgstr); nextmsg = nextmsgstr; nextcmd = newsplit (&nextmsg); nextto = newsplit (&nextmsg); len = strlen (nextto); if (nextto[len - 1] == '\n') nextto[len - 1] = 0; if (strcmp (to, nextto) && !strcmp (cmd, nextcmd) && !strcmp (msg, nextmsg) && ((strlen (cmd) + strlen (victims) + strlen (nextto) + strlen (msg) + 2) < 510) && (!stack_limit || cmd_count < stack_limit - 1)) { cmd_count++; if (stack_method == 1) simple_sprintf (victims, "%s,%s", victims, nextto); else simple_sprintf (victims, "%s %s", victims, nextto); doit = 1; m->next = nm->next; if (!nm->next) h->last = m; nfree (nm->msg); nfree (nm); h->tot--; } else m = m->next; } if (doit) { simple_sprintf (tosend, "%s %s %s", cmd, victims, msg); len = strlen (tosend); tosend[len - 1] = '\n'; tputs (serv, tosend, len); m = h->head->next; nfree (h->head->msg); nfree (h->head); h->head = m; if (!h->head) h->last = 0; h->tot--; if (debug_output) { tosend[len - 1] = 0; switch (which) { case DP_MODE: putlog (LOG_SRVOUT, "*", "[m=>] %s", tosend); break; case DP_SERVER: putlog (LOG_SRVOUT, "*", "[s=>] %s", tosend); break; case DP_HELP: putlog (LOG_SRVOUT, "*", "[h=>] %s", tosend); break; } } last_time += calc_penalty (tosend); return 1; } return 0; } static void check_queues (char *oldnick, char *newnick) { if (optimize_kicks == 2) { if (modeq.head) parse_q (&modeq, oldnick, newnick); if (mq.head) parse_q (&mq, oldnick, newnick); if (hq.head) parse_q (&hq, oldnick, newnick); } } static void parse_q (struct msgq_head *q, char *oldnick, char *newnick) { struct msgq *m, *lm = NULL; char buf[511], *msg, *nicks, *nick, *chan, newnicks[511], newmsg[511]; int changed; for (m = q->head; m;) { changed = 0; if (optimize_kicks == 2 && !egg_strncasecmp (m->msg, "KICK ", 5)) { newnicks[0] = 0; strncpyz (buf, m->msg, sizeof buf); if (buf[0] && (buf[strlen (buf) - 1] == '\n')) buf[strlen (buf) - 1] = '\0'; msg = buf; newsplit (&msg); chan = newsplit (&msg); nicks = newsplit (&msg); while (strlen (nicks) > 0) { nick = splitnicks (&nicks); if (!egg_strcasecmp (nick, oldnick) && ((9 + strlen (chan) + strlen (newnicks) + strlen (newnick) + strlen (nicks) + strlen (msg)) < 510)) { if (newnick) egg_snprintf (newnicks, sizeof newnicks, "%s,%s", newnicks, newnick); changed = 1; } else egg_snprintf (newnicks, sizeof newnicks, ",%s", nick); } egg_snprintf (newmsg, sizeof newmsg, "KICK %s %s %s\n", chan, newnicks + 1, msg); } if (changed) { if (newnicks[0] == 0) { if (!lm) q->head = m->next; else lm->next = m->next; nfree (m->msg); nfree (m); m = lm; q->tot--; if (!q->head) q->last = 0; } else { nfree (m->msg); m->msg = nmalloc (strlen (newmsg) + 1); m->len = strlen (newmsg); strcpy (m->msg, newmsg); } } lm = m; if (m) m = m->next; else m = q->head; } } static void purge_kicks (struct msgq_head *q) { struct msgq *m, *lm = NULL; char buf[511], *reason, *nicks, *nick, *chan, newnicks[511], newmsg[511], chans[511], *chns, *ch; int changed, found; struct chanset_t *cs; for (m = q->head; m;) { if (!egg_strncasecmp (m->msg, "KICK", 4)) { newnicks[0] = 0; changed = 0; strncpyz (buf, m->msg, sizeof buf); if (buf[0] && (buf[strlen (buf) - 1] == '\n')) buf[strlen (buf) - 1] = '\0'; reason = buf; newsplit (&reason); chan = newsplit (&reason); nicks = newsplit (&reason); while (strlen (nicks) > 0) { found = 0; nick = splitnicks (&nicks); strncpyz (chans, chan, sizeof chans); chns = chans; while (strlen (chns) > 0) { ch = newsplit (&chns); cs = findchan (ch); if (!cs) continue; if (ismember (cs, nick)) found = 1; } if (found) egg_snprintf (newnicks, sizeof newnicks, "%s,%s", newnicks, nick); else { putlog (LOG_SRVOUT, "*", "%s isn't on any target channel, removing " "kick...", nick); changed = 1; } } if (changed) { if (newnicks[0] == 0) { if (!lm) q->head = m->next; else lm->next = m->next; nfree (m->msg); nfree (m); m = lm; q->tot--; if (!q->head) q->last = 0; } else { nfree (m->msg); egg_snprintf (newmsg, sizeof newmsg, "KICK %s %s %s\n", chan, newnicks + 1, reason); m->msg = nmalloc (strlen (newmsg) + 1); m->len = strlen (newmsg); strcpy (m->msg, newmsg); } } } lm = m; if (m) m = m->next; else m = q->head; } } static int deq_kick (int which) { struct msgq_head *h; struct msgq *msg, *m, *lm; char buf[511], buf2[511], *reason2, *nicks, *chan, *chan2, *reason, *nick, newnicks[511], newnicks2[511], newmsg[511]; int changed = 0, nr = 0; if (!optimize_kicks) return 0; newnicks[0] = 0; switch (which) { case DP_MODE: h = &modeq; break; case DP_SERVER: h = &mq; break; case DP_HELP: h = &hq; break; default: return 0; } if (egg_strncasecmp (h->head->msg, "KICK", 4)) return 0; if (optimize_kicks == 2) { purge_kicks (h); if (!h->head) return 1; } if (egg_strncasecmp (h->head->msg, "KICK", 4)) return 0; msg = h->head; strncpyz (buf, msg->msg, sizeof buf); reason = buf; newsplit (&reason); chan = newsplit (&reason); nicks = newsplit (&reason); while (strlen (nicks) > 0) { egg_snprintf (newnicks, sizeof newnicks, "%s,%s", newnicks, newsplit (&nicks)); nr++; } for (m = msg->next, lm = NULL; m && (nr < kick_method);) { if (!egg_strncasecmp (m->msg, "KICK", 4)) { changed = 0; newnicks2[0] = 0; strncpyz (buf2, m->msg, sizeof buf2); if (buf2[0] && (buf2[strlen (buf2) - 1] == '\n')) buf2[strlen (buf2) - 1] = '\0'; reason2 = buf2; newsplit (&reason2); chan2 = newsplit (&reason2); nicks = newsplit (&reason2); if (!egg_strcasecmp (chan, chan2) && !egg_strcasecmp (reason, reason2)) { while (strlen (nicks) > 0) { nick = splitnicks (&nicks); if ((nr < kick_method) && ((9 + strlen (chan) + strlen (newnicks) + strlen (nick) + strlen (reason)) < 510)) { egg_snprintf (newnicks, sizeof newnicks, "%s,%s", newnicks, nick); nr++; changed = 1; } else egg_snprintf (newnicks2, sizeof newnicks2, "%s,%s", newnicks2, nick); } } if (changed) { if (newnicks2[0] == 0) { if (!lm) h->head->next = m->next; else lm->next = m->next; nfree (m->msg); nfree (m); m = lm; h->tot--; if (!h->head) h->last = 0; } else { nfree (m->msg); egg_snprintf (newmsg, sizeof newmsg, "KICK %s %s %s\n", chan2, newnicks2 + 1, reason); m->msg = nmalloc (strlen (newmsg) + 1); m->len = strlen (newmsg); strcpy (m->msg, newmsg); } } } lm = m; if (m) m = m->next; else m = h->head->next; } egg_snprintf (newmsg, sizeof newmsg, "KICK %s %s %s\n", chan, newnicks + 1, reason); tputs (serv, newmsg, strlen (newmsg)); if (debug_output) { newmsg[strlen (newmsg) - 1] = 0; switch (which) { case DP_MODE: putlog (LOG_SRVOUT, "@", "[m->] %s", newmsg); break; case DP_SERVER: putlog (LOG_SRVOUT, "@", "[s->] %s", newmsg); break; case DP_HELP: putlog (LOG_SRVOUT, "@", "[h->] %s", newmsg); break; } debug3 ("Changed: %d, kick-method: %d, nr: %d", changed, kick_method, nr); } h->tot--; last_time += calc_penalty (newmsg); m = h->head->next; nfree (h->head->msg); nfree (h->head); h->head = m; if (!h->head) h->last = 0; return 1; } static void empty_msgq () { msgq_clear (&modeq); msgq_clear (&mq); msgq_clear (&hq); burst = 0; } static void queue_server (int which, char *buf, int len) { struct msgq_head *h = NULL, tempq; struct msgq *q, *tq, *tqq; int doublemsg = 0, qnext = 0; if (serv < 0) return; if (!egg_strncasecmp (buf, "PING", 4) || !egg_strncasecmp (buf, "PONG", 4)) { if (buf[1] == 'I' || buf[1] == 'i') lastpingtime = now; tputs (serv, buf, len); if (debug_output) { if (buf[len - 1] == '\n') buf[len - 1] = 0; putlog (LOG_SRVOUT, "@", "[m->] %s", buf); } return; } switch (which) { case DP_MODE_NEXT: qnext = 1; case DP_MODE: h = &modeq; tempq = modeq; if (double_mode) doublemsg = 1; break; case DP_SERVER_NEXT: qnext = 1; case DP_SERVER: h = &mq; tempq = mq; if (double_server) doublemsg = 1; break; case DP_HELP_NEXT: qnext = 1; case DP_HELP: h = &hq; tempq = hq; if (double_help) doublemsg = 1; break; default: putlog (LOG_MISC, "*", "!!! queuing unknown type to server!!"); return; } if (h->tot < maxqmsg) { if (!doublemsg) for (tq = tempq.head; tq; tq = tqq) { tqq = tq->next; if (!egg_strcasecmp (tq->msg, buf)) { if (!double_warned) { if (buf[len - 1] == '\n') buf[len - 1] = 0; debug1 ("msg already queued. skipping: %s", buf); double_warned = 1; } return; } } q = nmalloc (sizeof (struct msgq)); if (qnext) q->next = h->head; else q->next = NULL; if (h->head) { if (!qnext) h->last->next = q; } else h->head = q; if (qnext) h->head = q; h->last = q; q->len = len; q->msg = nmalloc (len + 1); strncpyz (q->msg, buf, len + 1); h->tot++; h->warned = 0; double_warned = 0; } else { if (!h->warned) { switch (which) { case DP_MODE_NEXT: case DP_MODE: putlog (LOG_MISC, "*", "!!! OVER MAXIMUM MODE QUEUE"); break; case DP_SERVER_NEXT: case DP_SERVER: putlog (LOG_MISC, "*", "!!! OVER MAXIMUM SERVER QUEUE"); break; case DP_HELP_NEXT: case DP_HELP: putlog (LOG_MISC, "*", "!!! OVER MAXIMUM HELP QUEUE"); break; } } h->warned = 1; } if (debug_output && !h->warned) { if (buf[len - 1] == '\n') buf[len - 1] = 0; switch (which) { case DP_MODE: putlog (LOG_SRVOUT, "@", "[!m] %s", buf); break; case DP_SERVER: putlog (LOG_SRVOUT, "@", "[!s] %s", buf); break; case DP_HELP: putlog (LOG_SRVOUT, "@", "[!h] %s", buf); break; case DP_MODE_NEXT: putlog (LOG_SRVOUT, "@", "[!!m] %s", buf); break; case DP_SERVER_NEXT: putlog (LOG_SRVOUT, "@", "[!!s] %s", buf); break; case DP_HELP_NEXT: putlog (LOG_SRVOUT, "@", "[!!h] %s", buf); break; } } if (which == DP_MODE || which == DP_MODE_NEXT) deq_msg (); } static void add_server (char *ss) { struct server_list *x, *z; char *p, *q; for (z = serverlist; z && z->next; z = z->next); while (ss) { p = strchr (ss, ','); if (p) *p++ = 0; x = nmalloc (sizeof (struct server_list)); x->next = 0; x->realname = 0; x->port = 0; if (z) z->next = x; else serverlist = x; z = x; q = strchr (ss, ':'); if (!q) { x->port = default_port; x->pass = 0; x->name = nmalloc (strlen (ss) + 1); strcpy (x->name, ss); } else { *q++ = 0; x->name = nmalloc (q - ss); strcpy (x->name, ss); ss = q; q = strchr (ss, ':'); if (!q) { x->pass = 0; } else { *q++ = 0; x->pass = nmalloc (strlen (q) + 1); strcpy (x->pass, q); } x->port = atoi (ss); } ss = p; } } static void clearq (struct server_list *xx) { struct server_list *x; while (xx) { x = xx->next; if (xx->name) nfree (xx->name); if (xx->pass) nfree (xx->pass); if (xx->realname) nfree (xx->realname); nfree (xx); xx = x; } } void servers_describe (struct cfg_entry *entry, int idx) { } void servers6_describe (struct cfg_entry *entry, int idx) { } int count (const char *s) { char *ele; int i = 0; char count[1000]; strcpy (count, s); ele = strtok (count, ","); while (ele && *ele) { i++; ele = strtok ((char *) NULL, ","); } return i - 1; } int rrand (int a, int b) { b++; return ((random () % (b - a)) + a); } char * randomize (char *line, char **new) { char *str, *words[1000], *bak; int i, o, b, r, u = 0; Context; bak = line; i = count (line); b = i + 1; str = strtok (line, ","); o = 0; while (str && *str) { words[o] = str; o++; str = strtok ((char *) NULL, ","); } while (b) { if (u > 200) { sprintf (*new, "%s", bak); return *new; } r = rrand (0, i); if (strstr (*new, words[r]) == NULL) { if (b == i + 1) sprintf (*new, "%s", words[r]); else sprintf (*new, "%s,%s", *new, words[r]); b--; } else u++; } return *new; } void servers_changed (struct cfg_entry *entry, char *olddata, int *valid) { #ifdef LEAF char *slist, *p; #ifdef S_RANDSERVERS char *new; if (hostname6[0]) return; #endif slist = (char *) (entry->ldata ? entry-> ldata : (entry->gdata ? entry->gdata : "")); if (serverlist) { clearq (serverlist); serverlist = NULL; } p = nmalloc (strlen (slist) + 1); strcpy (p, slist); #ifdef S_RANDSERVERS new = nmalloc (strlen (slist) + 1); randomize (p, &new); strcpy (p, new); #endif add_server (p); nfree (p); nfree (new); #endif } void servers6_changed (struct cfg_entry *entry, char *olddata, int *valid) { #ifdef LEAF char *slist, *p; #ifdef S_RANDSERVERS char *new; if (!hostname6[0]) return; #endif slist = (char *) (entry->ldata ? entry-> ldata : (entry->gdata ? entry->gdata : "")); if (serverlist) { clearq (serverlist); serverlist = NULL; } p = nmalloc (strlen (slist) + 1); strcpy (p, slist); #ifdef S_RANDSERVERS new = nmalloc (strlen (slist) + 1); randomize (p, &new); strcpy (p, new); #endif add_server (p); nfree (p); nfree (new); #endif } void nick_describe (struct cfg_entry *entry, int idx) { } void nick_changed (struct cfg_entry *entry, char *olddata, int *valid) { #ifdef LEAF char *p; if (entry->ldata) p = entry->ldata; else if (entry->gdata) p = entry->gdata; else p = NULL; if (p && p[0]) { strncpy0 (origbotname, p, NICKMAX + 1); } else { strncpy0 (origbotname, botnetnick, NICKMAX + 1); } #endif } void realname_describe (struct cfg_entry *entry, int idx) { } void realname_changed (struct cfg_entry *entry, char *olddata, int *valid) { #ifdef LEAF if (entry->ldata) { strncpy0 (botrealname, (char *) entry->ldata, 120); } else if (entry->gdata) { strncpy0 (botrealname, (char *) entry->gdata, 120); } #endif } struct cfg_entry CFG_SERVERS = { "servers", CFGF_LOCAL | CFGF_GLOBAL, NULL, NULL, servers_changed, servers_changed, servers_describe }; struct cfg_entry CFG_SERVERS6 = { "servers6", CFGF_LOCAL | CFGF_GLOBAL, NULL, NULL, servers6_changed, servers6_changed, servers6_describe }; struct cfg_entry CFG_NICK = { "nick", CFGF_LOCAL | CFGF_GLOBAL, NULL, NULL, nick_changed, nick_changed, nick_describe }; struct cfg_entry CFG_REALNAME = { "realname", CFGF_LOCAL | CFGF_GLOBAL, NULL, NULL, realname_changed, realname_changed, realname_describe }; static void next_server (int *ptr, char *serv, unsigned int *port, char *pass) { struct server_list *x = serverlist; int i = 0; if (x == NULL) return; if (*ptr == (-1)) { for (; x; x = x->next) { if (x->port == *port) { if (!egg_strcasecmp (x->name, serv)) { *ptr = i; return; } else if (x->realname && !egg_strcasecmp (x->realname, serv)) { *ptr = i; strncpyz (serv, x->realname, sizeof serv); return; } } i++; } x = nmalloc (sizeof (struct server_list)); x->next = 0; x->realname = 0; x->name = nmalloc (strlen (serv) + 1); strcpy (x->name, serv); x->port = *port ? *port : default_port; if (pass && pass[0]) { x->pass = nmalloc (strlen (pass) + 1); strcpy (x->pass, pass); } else x->pass = NULL; list_append ((struct list_type **) (&serverlist), (struct list_type *) x); *ptr = i; return; } i = (*ptr); while (i > 0 && x != NULL) { x = x->next; i--; } if (x != NULL) { x = x->next; (*ptr)++; } if (x == NULL) { x = serverlist; *ptr = 0; } strcpy (serv, x->name); *port = x->port ? x->port : default_port; if (x->pass) strcpy (pass, x->pass); else pass[0] = 0; } static int server_6char STDVAR { Function F = (Function) cd; char x[20]; BADARGS (7, 7, " nick user@host handle desto/chan keyword/nick text"); CHECKVALIDITY (server_6char); egg_snprintf (x, sizeof x, "%d", F (argv[1], argv[2], argv[3], argv[4], argv[5], argv[6])); Tcl_AppendResult (irp, x, NULL); return TCL_OK; } static int server_5char STDVAR { Function F = (Function) cd; BADARGS (6, 6, " nick user@host handle channel text"); CHECKVALIDITY (server_5char); F (argv[1], argv[2], argv[3], argv[4], argv[5]); return TCL_OK; } static int server_2char STDVAR { Function F = (Function) cd; BADARGS (3, 3, " nick msg"); CHECKVALIDITY (server_2char); F (argv[1], argv[2]); return TCL_OK; } static int server_msg STDVAR { Function F = (Function) cd; BADARGS (5, 5, " nick uhost hand buffer"); CHECKVALIDITY (server_msg); F (argv[1], argv[2], get_user_by_handle (userlist, argv[3]), argv[4]); return TCL_OK; } static int server_raw STDVAR { Function F = (Function) cd; BADARGS (4, 4, " from code args"); CHECKVALIDITY (server_raw); Tcl_AppendResult (irp, int_to_base10 (F (argv[1], argv[3])), NULL); return TCL_OK; } #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) static char * nick_change (ClientData cdata, Tcl_Interp * irp, CONST char *name1, CONST char *name2, int flags) #else static char * nick_change (ClientData cdata, Tcl_Interp * irp, char *name1, char *name2, int flags) #endif { #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) CONST char *new; #else char *new; #endif if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) { Tcl_SetVar2 (interp, name1, name2, origbotname, TCL_GLOBAL_ONLY); if (flags & TCL_TRACE_UNSETS) Tcl_TraceVar (irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, nick_change, cdata); } else { new = Tcl_GetVar2 (interp, name1, name2, TCL_GLOBAL_ONLY); if (rfc_casecmp (origbotname, (char *) new)) { if (origbotname[0]) { putlog (LOG_MISC, "*", "* IRC NICK CHANGE: %s -> %s", origbotname, new); nick_juped = 0; } strncpyz (origbotname, new, NICKLEN); if (server_online) dprintf (DP_SERVER, "NICK %s\n", origbotname); } } return NULL; } static void rand_nick (char *nick) { register char *p = nick; while ((p = strchr (p, '?')) != NULL) { *p = '0' + random () % 10; p++; } } static char * get_altbotnick (void) { if (strchr (altnick, '?')) { if (!raltnick[0]) { strncpyz (raltnick, altnick, NICKLEN); rand_nick (raltnick); } return raltnick; } else return altnick; } #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) static char * altnick_change (ClientData cdata, Tcl_Interp * irp, CONST char *name1, CONST char *name2, int flags) #else static char * altnick_change (ClientData cdata, Tcl_Interp * irp, char *name1, char *name2, int flags) #endif { raltnick[0] = 0; return NULL; } #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) static char * traced_server (ClientData cdata, Tcl_Interp * irp, CONST char *name1, CONST char *name2, int flags) #else static char * traced_server (ClientData cdata, Tcl_Interp * irp, char *name1, char *name2, int flags) #endif { char s[1024]; if (server_online) { int servidx = findanyidx (serv); simple_sprintf (s, "%s:%u", dcc[servidx].host, dcc[servidx].port); } else s[0] = 0; Tcl_SetVar2 (interp, name1, name2, s, TCL_GLOBAL_ONLY); if (flags & TCL_TRACE_UNSETS) Tcl_TraceVar (irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_server, cdata); return NULL; } #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) static char * traced_botname (ClientData cdata, Tcl_Interp * irp, CONST char *name1, CONST char *name2, int flags) #else static char * traced_botname (ClientData cdata, Tcl_Interp * irp, char *name1, char *name2, int flags) #endif { char s[1024]; simple_sprintf (s, "%s%s%s", botname, botuserhost[0] ? "!" : "", botuserhost[0] ? botuserhost : ""); Tcl_SetVar2 (interp, name1, name2, s, TCL_GLOBAL_ONLY); if (flags & TCL_TRACE_UNSETS) Tcl_TraceVar (irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_botname, cdata); return NULL; } static void do_nettype (void) { switch (net_type) { case NETT_EFNET: check_mode_r = 0; nick_len = 9; break; case NETT_IRCNET: check_mode_r = 1; use_penalties = 1; use_fastdeq = 3; nick_len = 9; simple_sprintf (stackablecmds, "INVITE AWAY VERSION NICK"); kick_method = 4; break; case NETT_UNDERNET: check_mode_r = 0; use_fastdeq = 2; nick_len = 9; simple_sprintf (stackablecmds, "PRIVMSG NOTICE TOPIC PART WHOIS USERHOST USERIP ISON"); simple_sprintf (stackable2cmds, "USERHOST USERIP ISON"); break; case NETT_DALNET: check_mode_r = 0; use_fastdeq = 2; nick_len = 32; simple_sprintf (stackablecmds, "PRIVMSG NOTICE PART WHOIS WHOWAS USERHOST ISON WATCH DCCALLOW"); simple_sprintf (stackable2cmds, "USERHOST ISON WATCH"); break; case NETT_HYBRID_EFNET: check_mode_r = 0; nick_len = 9; break; } } #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) static char * traced_nettype (ClientData cdata, Tcl_Interp * irp, CONST char *name1, CONST char *name2, int flags) #else static char * traced_nettype (ClientData cdata, Tcl_Interp * irp, char *name1, char *name2, int flags) #endif { do_nettype (); return NULL; } #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) static char * traced_nicklen (ClientData cdata, Tcl_Interp * irp, CONST char *name1, CONST char *name2, int flags) #else static char * traced_nicklen (ClientData cdata, Tcl_Interp * irp, char *name1, char *name2, int flags) #endif { if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) { char s[40]; egg_snprintf (s, sizeof s, "%d", nick_len); Tcl_SetVar2 (interp, name1, name2, s, TCL_GLOBAL_ONLY); if (flags & TCL_TRACE_UNSETS) Tcl_TraceVar (irp, name1, TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_nicklen, cdata); } else { #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) CONST char *cval = Tcl_GetVar2 (interp, name1, name2, TCL_GLOBAL_ONLY); #else char *cval = Tcl_GetVar2 (interp, name1, name2, TCL_GLOBAL_ONLY); #endif long lval = 0; Context; if (cval && Tcl_ExprLong (interp, cval, &lval) != TCL_ERROR) { if (lval > NICKMAX) lval = NICKMAX; nick_len = (int) lval; } } return NULL; } static tcl_strings my_tcl_strings[] = { {"botnick", NULL, 0, STR_PROTECT}, {"altnick", altnick, NICKMAX, 0}, {"realname", botrealname, 80, 0}, {"init-server", initserver, 120, 0}, {"connect-server", connectserver, 120, 0}, {"stackable-commands", stackablecmds, 510, 0}, {"stackable2-commands", stackable2cmds, 510, 0}, {NULL, NULL, 0, 0} }; static tcl_coups my_tcl_coups[] = { {"flood-msg", &flud_thr, &flud_time}, {"flood-ctcp", &flud_ctcp_thr, &flud_ctcp_time}, {NULL, NULL, NULL} }; static tcl_ints my_tcl_ints[] = { {"use-console-r", NULL, 1}, {"servlimit", &min_servs, 0}, {"server-timeout", &server_timeout, 0}, {"lowercase-ctcp", &lowercase_ctcp, 0}, {"server-online", (int *) &server_online, 2}, {"never-give-up", &never_give_up, 0}, {"keep-nick", &keepnick, 0}, {"strict-servernames", &strict_servernames, 0}, {"check-stoned", &check_stoned, 0}, {"serverror-quit", &serverror_quit, 0}, {"quiet-reject", &quiet_reject, 0}, {"max-queue-msg", &maxqmsg, 0}, {"trigger-on-ignore", &trigger_on_ignore, 0}, {"answer-ctcp", &answer_ctcp, 0}, {"server-cycle-wait", (int *) &server_cycle_wait, 0}, {"default-port", &default_port, 0}, {"check-mode-r", &check_mode_r, 0}, {"net-type", &net_type, 0}, {"ctcp-mode", &ctcp_mode, 0}, {"double-mode", &double_mode, 0}, {"double-server", &double_server, 0}, {"double-help", &double_help, 0}, {"use-penalties", &use_penalties, 0}, {"use-fastdeq", &use_fastdeq, 0}, {"nicklen", &nick_len, 0}, {"nick-len", &nick_len, 0}, {"optimize-kicks", &optimize_kicks, 0}, {"isjuped", &nick_juped, 0}, {"stack-limit", &stack_limit, 0}, {NULL, NULL, 0} }; static void dcc_chat_hostresolved (int); static int ctcp_DCC_CHAT (char *nick, char *from, char *handle, char *object, char *keyword, char *text) { char *action, *param, *ip, *prt, buf[512], *msg = buf; int i, ok; struct userrec *u = get_user_by_handle (userlist, handle); struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 }; if (!ischanhub () && !issechub ()) return 0; strcpy (msg, text); action = newsplit (&msg); param = newsplit (&msg); ip = newsplit (&msg); prt = newsplit (&msg); if (egg_strcasecmp (action, "CHAT") || egg_strcasecmp (object, botname) || !u) return 0; get_user_flagrec (u, &fr, 0); ok = 1; if (issechub () && !glob_huba (fr)) ok = 0; if (ischanhub () && !glob_chuba (fr)) ok = 0; if (dcc_total == max_dcc) { if (!quiet_reject) dprintf (DP_HELP, "NOTICE %s :%s\n", nick, DCC_TOOMANYDCCS1); putlog (LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT", param, nick, from); } else if (!ok) { if (!quiet_reject) dprintf (DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED2); putlog (LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED, nick, from); } else if (u_pass_match (u, "-")) { if (!quiet_reject) dprintf (DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED3); putlog (LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED4, nick, from); } else if (atoi (prt) < 1024 || atoi (prt) > 65535) { if (!quiet_reject) dprintf (DP_HELP, "NOTICE %s :%s (invalid port)\n", nick, DCC_CONNECTFAILED1); putlog (LOG_MISC, "*", "%s: CHAT (%s!%s)", DCC_CONNECTFAILED3, nick, from); } else { if (!sanitycheck_dcc (nick, from, ip, prt)) return 1; i = new_dcc (&DCC_DNSWAIT, sizeof (struct dns_info)); if (i < 0) { putlog (LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", dcc[i].nick, ip); return 1; } dcc[i].addr = my_atoul (ip); dcc[i].port = atoi (prt); dcc[i].sock = -1; strcpy (dcc[i].nick, u->handle); strcpy (dcc[i].host, from); dcc[i].timeval = now; dcc[i].user = u; dcc[i].u.dns->ip = dcc[i].addr; dcc[i].u.dns->dns_type = RES_HOSTBYIP; dcc[i].u.dns->dns_success = dcc_chat_hostresolved; dcc[i].u.dns->dns_failure = dcc_chat_hostresolved; dcc[i].u.dns->type = &DCC_CHAT_PASS; dcc_dnshostbyip (dcc[i].addr); } return 1; } static void dcc_chat_hostresolved (int i) { char buf[512], ip[512]; int ok; struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 }; egg_snprintf (buf, sizeof buf, "%d", dcc[i].port); if (!hostsanitycheck_dcc (dcc[i].nick, dcc[i].host, dcc[i].addr, dcc[i].u.dns->host, buf)) { lostdcc (i); return; } egg_snprintf (ip, sizeof ip, "%lu", iptolong (htonl (dcc[i].addr))); dcc[i].sock = getsock (0, getprotocol (ip)); if (dcc[i].sock < 0 || open_telnet_dcc (dcc[i].sock, ip, buf) < 0) { neterror (buf); if (!quiet_reject) dprintf (DP_HELP, "NOTICE %s :%s (%s)\n", dcc[i].nick, DCC_CONNECTFAILED1, buf); putlog (LOG_MISC, "*", "%s: CHAT (%s!%s)", DCC_CONNECTFAILED2, dcc[i].nick, dcc[i].host); putlog (LOG_MISC, "*", " (%s)", buf); killsock (dcc[i].sock); lostdcc (i); } else { changeover_dcc (i, &DCC_CHAT_PASS, sizeof (struct chat_info)); dcc[i].status = STAT_ECHO; get_user_flagrec (dcc[i].user, &fr, 0); ok = 1; if (issechub () && !glob_huba (fr)) ok = 0; if (ischanhub () && !glob_chuba (fr)) ok = 0; if (ok) dcc[i].status |= STAT_PARTY; strcpy (dcc[i].u.chat->con_chan, (chanset) ? chanset->dname : "*"); dcc[i].timeval = now; putlog (LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", dcc[i].nick, dcc[i].host); dprintf (i, "%s", rand_dccresp ()); } return; } static void server_secondly () { if (cycle_time) cycle_time--; deq_msg (); if (!resolvserv && serv < 0) connect_server (); } static void server_5minutely () { if (check_stoned && server_online) { if (waiting_for_awake) { int servidx = findanyidx (serv); disconnect_server (servidx); lostdcc (servidx); putlog (LOG_SERV, "*", IRC_SERVERSTONED); } else if (!trying_server) { dprintf (DP_MODE, "PING :%lu\n", (unsigned long) now); waiting_for_awake = 1; } } } static void server_prerehash () { strcpy (oldnick, botname); } static void server_postrehash () { strncpyz (botname, origbotname, NICKLEN); if (oldnick[0] && !rfc_casecmp (oldnick, botname) && !rfc_casecmp (oldnick, get_altbotnick ())) { strcpy (botname, oldnick); dprintf (DP_SERVER, "NICK %s\n", origbotname); } else if (oldnick[0]) strcpy (botname, oldnick); } static void server_die () { cycle_time = 100; if (server_online) { dprintf (-serv, "QUIT :%s\n", quit_msg[0] ? quit_msg : ""); sleep (3); } nuke_server (NULL); } static void server_report (int idx, int details) { char s1[64], s[128]; int servidx; if (server_online) { dprintf (idx, " Online as: %s%s%s (%s)\n", botname, botuserhost[0] ? "!" : "", botuserhost[0] ? botuserhost : "", botrealname); if (nick_juped) dprintf (idx, " NICK IS JUPED: %s %s\n", origbotname, keepnick ? "(trying)" : ""); nick_juped = 0; daysdur (now, server_online, s1); egg_snprintf (s, sizeof s, "(connected %s)", s1); if (server_lag && !waiting_for_awake) { if (server_lag == (-1)) egg_snprintf (s1, sizeof s1, " (bad pong replies)"); else egg_snprintf (s1, sizeof s1, " (lag: %ds)", server_lag); strcat (s, s1); } } if ((trying_server || server_online) && ((servidx = findanyidx (serv)) != (-1))) { dprintf (idx, " Server %s:%d %s\n", dcc[servidx].host, dcc[servidx].port, trying_server ? "(trying)" : s); } else dprintf (idx, " %s\n", IRC_NOSERVER); if (modeq.tot) dprintf (idx, " %s %d%%, %d msgs\n", IRC_MODEQUEUE, (int) ((float) (modeq.tot * 100.0) / (float) maxqmsg), (int) modeq.tot); if (mq.tot) dprintf (idx, " %s %d%%, %d msgs\n", IRC_SERVERQUEUE, (int) ((float) (mq.tot * 100.0) / (float) maxqmsg), (int) mq.tot); if (hq.tot) dprintf (idx, " %s %d%%, %d msgs\n", IRC_HELPQUEUE, (int) ((float) (hq.tot * 100.0) / (float) maxqmsg), (int) hq.tot); if (details) { if (min_servs) dprintf (idx, " Requiring a net of at least %d server(s)\n", min_servs); if (initserver[0]) dprintf (idx, " On connect, I do: %s\n", initserver); if (connectserver[0]) dprintf (idx, " Before connect, I do: %s\n", connectserver); dprintf (idx, " Flood is: %d msg/%ds, %d ctcp/%ds\n", flud_thr, flud_time, flud_ctcp_thr, flud_ctcp_time); } } static void msgq_clear (struct msgq_head *qh) { register struct msgq *q, *qq; for (q = qh->head; q; q = qq) { qq = q->next; nfree (q->msg); nfree (q); } qh->head = qh->last = NULL; qh->tot = qh->warned = 0; } static int msgq_expmem (struct msgq_head *qh) { register int tot = 0; register struct msgq *m; for (m = qh->head; m; m = m->next) { tot += m->len + 1; tot += sizeof (struct msgq); } return tot; } static int server_expmem () { int tot = 0; struct server_list *s = serverlist; for (; s; s = s->next) { if (s->name) tot += strlen (s->name) + 1; if (s->pass) tot += strlen (s->pass) + 1; if (s->realname) tot += strlen (s->realname) + 1; tot += sizeof (struct server_list); } tot += msgq_expmem (&mq) + msgq_expmem (&hq) + msgq_expmem (&modeq); return tot; } static cmd_t my_ctcps[] = { {"DCC", "", ctcp_DCC_CHAT, "server:DCC"}, {NULL, NULL, NULL, NULL} }; static char * server_close () { cycle_time = 100; nuke_server ("Connection reset by peer"); clearq (serverlist); rem_builtins_dcc (H_dcc, C_dcc_serv); rem_builtins (H_raw, my_raw_binds); rem_builtins (H_ctcp, my_ctcps); del_bind_table (H_wall); del_bind_table (H_raw); del_bind_table (H_notc); del_bind_table (H_msgm); del_bind_table (H_msg); del_bind_table (H_flud); del_bind_table (H_ctcr); del_bind_table (H_ctcp); rem_tcl_coups (my_tcl_coups); rem_tcl_strings (my_tcl_strings); rem_tcl_ints (my_tcl_ints); rem_tcl_commands (my_tcl_cmds); Tcl_UntraceVar (interp, "nick", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, nick_change, NULL); Tcl_UntraceVar (interp, "altnick", TCL_TRACE_WRITES | TCL_TRACE_UNSETS, altnick_change, NULL); Tcl_UntraceVar (interp, "botname", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_botname, NULL); Tcl_UntraceVar (interp, "server", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_server, NULL); Tcl_UntraceVar (interp, "net-type", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_nettype, NULL); Tcl_UntraceVar (interp, "nick-len", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_nicklen, NULL); empty_msgq (); del_hook (HOOK_SECONDLY, (Function) server_secondly); del_hook (HOOK_5MINUTELY, (Function) server_5minutely); del_hook (HOOK_QSERV, (Function) queue_server); del_hook (HOOK_MINUTELY, (Function) minutely_checks); del_hook (HOOK_PRE_REHASH, (Function) server_prerehash); del_hook (HOOK_REHASH, (Function) server_postrehash); del_hook (HOOK_DIE, (Function) server_die); module_undepend (MODULE_NAME); return NULL; } EXPORT_SCOPE char *server_start (); static Function server_table[] = { (Function) server_start, (Function) server_close, (Function) server_expmem, (Function) server_report, (Function) NULL, (Function) botuserhost, (Function) & quiet_reject, (Function) & serv, (Function) & flud_thr, (Function) & flud_time, (Function) & flud_ctcp_thr, (Function) & flud_ctcp_time, (Function) match_my_nick, (Function) check_tcl_flud, (Function) NULL, (Function) & answer_ctcp, (Function) & trigger_on_ignore, (Function) check_tcl_ctcpr, (Function) detect_avalanche, (Function) nuke_server, (Function) newserver, (Function) & newserverport, (Function) newserverpass, (Function) & cycle_time, (Function) & default_port, (Function) & server_online, (Function) & min_servs, (Function) & H_raw, (Function) & H_wall, (Function) & H_msg, (Function) & H_msgm, (Function) & H_notc, (Function) & H_flud, (Function) & H_ctcp, (Function) & H_ctcr, (Function) ctcp_reply, (Function) get_altbotnick, (Function) & nick_len, (Function) check_tcl_notc, (Function) & server_lag, (Function) & curserv, (Function) cursrvname, (Function) botrealname, }; char * server_start (Function * global_funcs) { #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8)) CONST char *s; #else char *s; #endif global = global_funcs; serv = -1; strict_host = 1; botname[0] = 0; trying_server = 0L; server_lag = 0; altnick[0] = 0; raltnick[0] = 0; curserv = 0; flud_thr = 5; flud_time = 60; flud_ctcp_thr = 3; flud_ctcp_time = 60; initserver[0] = 0; connectserver[0] = 0; botuserhost[0] = 0; keepnick = 1; check_stoned = 1; serverror_quit = 1; quiet_reject = 1; waiting_for_awake = 0; server_online = 0; server_cycle_wait = 15; strcpy (botrealname, "A deranged product of evil coders"); min_servs = 0; server_timeout = 15; never_give_up = 1; strict_servernames = 1; serverlist = NULL; cycle_time = 0; default_port = 6667; oldnick[0] = 0; trigger_on_ignore = 0; answer_ctcp = 1; lowercase_ctcp = 0; check_mode_r = 0; maxqmsg = 300; burst = 0; net_type = NETT_EFNET; double_mode = 0; double_server = 0; double_help = 0; use_penalties = 0; use_fastdeq = 0; stackablecmds[0] = 0; strcpy (stackable2cmds, "USERHOST ISON"); resolvserv = 0; lastpingtime = 0; last_time = 0; nick_len = 9; kick_method = 1; optimize_kicks = 0; stack_limit = 4; server_table[4] = (Function) botname; module_register (MODULE_NAME, server_table, 1, 2); if (!(encryption_funcs = module_depend (MODULE_NAME, "encryption", 0, 0))) { module_undepend (MODULE_NAME); return "This module requires an encryption modules."; } s = Tcl_GetVar (interp, "nick", TCL_GLOBAL_ONLY); if (s) strncpyz (origbotname, s, NICKLEN); Tcl_TraceVar (interp, "nick", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, nick_change, NULL); Tcl_TraceVar (interp, "altnick", TCL_TRACE_WRITES | TCL_TRACE_UNSETS, altnick_change, NULL); Tcl_TraceVar (interp, "botname", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_botname, NULL); Tcl_TraceVar (interp, "server", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_server, NULL); Tcl_TraceVar (interp, "net-type", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_nettype, NULL); Tcl_TraceVar (interp, "nick-len", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_nicklen, NULL); H_wall = add_bind_table ("wall", HT_STACKABLE, server_2char); H_raw = add_bind_table ("raw", HT_STACKABLE, server_raw); H_notc = add_bind_table ("notc", HT_STACKABLE, server_6char); H_msgm = add_bind_table ("msgm", HT_STACKABLE, server_msg); H_msg = add_bind_table ("msg", 0, server_msg); H_flud = add_bind_table ("flud", HT_STACKABLE, server_5char); H_ctcr = add_bind_table ("ctcr", HT_STACKABLE, server_6char); H_ctcp = add_bind_table ("ctcp", HT_STACKABLE, server_6char); add_builtins (H_raw, my_raw_binds); add_builtins_dcc (H_dcc, C_dcc_serv); add_builtins (H_ctcp, my_ctcps); my_tcl_strings[0].buf = botname; add_tcl_strings (my_tcl_strings); my_tcl_ints[0].val = &use_console_r; add_tcl_ints (my_tcl_ints); add_tcl_commands (my_tcl_cmds); add_tcl_coups (my_tcl_coups); add_hook (HOOK_SECONDLY, (Function) server_secondly); add_hook (HOOK_10SECONDLY, (Function) server_10secondly); add_hook (HOOK_5MINUTELY, (Function) server_5minutely); add_hook (HOOK_MINUTELY, (Function) minutely_checks); add_hook (HOOK_QSERV, (Function) queue_server); add_hook (HOOK_PRE_REHASH, (Function) server_prerehash); add_hook (HOOK_REHASH, (Function) server_postrehash); add_hook (HOOK_DIE, (Function) server_die); mq.head = hq.head = modeq.head = NULL; mq.last = hq.last = modeq.last = NULL; mq.tot = hq.tot = modeq.tot = 0; mq.warned = hq.warned = modeq.warned = 0; double_warned = 0; newserver[0] = 0; newserverport = 0; curserv = 999; do_nettype (); add_cfg (&CFG_NICK); add_cfg (&CFG_SERVERS); add_cfg (&CFG_SERVERS6); add_cfg (&CFG_REALNAME); set_cfg_str (NULL, STR ("realname"), "A deranged product of evil coders"); return NULL; } #endif