00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #define MODULE_NAME "server"
00027 #define MAKING_SERVER
00028
00029 #include "src/mod/module.h"
00030 #include "server.h"
00031
00032 static Function *global = NULL;
00033
00034 static int ctcp_mode;
00035 static int serv;
00036 static char newserver[121];
00037 static int newserverport;
00038 static char newserverpass[121];
00039 static time_t trying_server;
00040 static int server_lag;
00041 static char altnick[NICKLEN];
00042 static char raltnick[NICKLEN];
00043 static int curserv;
00044 static int flud_thr;
00045 static int flud_time;
00046 static int flud_ctcp_thr;
00047 static int flud_ctcp_time;
00048 static char initserver[121];
00049
00050 static char botuserhost[121];
00051
00052
00053
00054 static int keepnick;
00055
00056 static int nick_juped = 0;
00057 static int check_stoned;
00058 static int serverror_quit;
00059
00060 static time_t lastpingcheck;
00061
00062 static time_t server_online;
00063 static time_t server_cycle_wait;
00064
00065 static char botrealname[121];
00066 static int min_servs;
00067 static int server_timeout;
00068 static int never_give_up;
00069 static struct server_list *serverlist;
00070
00071 static int cycle_time;
00072 static int default_port;
00073 static char oldnick[NICKLEN];
00074 static int trigger_on_ignore;
00075 static int exclusive_binds;
00076
00077 static int answer_ctcp;
00078 static int lowercase_ctcp;
00079 static int check_mode_r;
00080 static int net_type;
00081 static char connectserver[121];
00082
00083 static int resolvserv;
00084 static int double_mode;
00085 static int double_server;
00086 static int double_help;
00087 static int double_warned;
00088 static int lastpingtime;
00089 static char stackablecmds[511];
00090 static char stackable2cmds[511];
00091 static time_t last_time;
00092 static int use_penalties;
00093 static int use_fastdeq;
00094 static int nick_len;
00095
00096 static int kick_method;
00097 static int optimize_kicks;
00098 static int msgrate;
00099
00100
00101 static p_tcl_bind_list H_wall, H_raw, H_notc, H_msgm, H_msg, H_flud, H_ctcr,
00102 H_ctcp, H_out;
00103
00104 static void empty_msgq(void);
00105 static void next_server(int *, char *, unsigned int *, char *);
00106 static void disconnect_server(int);
00107 static char *get_altbotnick(void);
00108 static int calc_penalty(char *);
00109 static int fast_deq(int);
00110 static char *splitnicks(char **);
00111 static void check_queues(char *, char *);
00112 static void parse_q(struct msgq_head *, char *, char *);
00113 static void purge_kicks(struct msgq_head *);
00114 static int deq_kick(int);
00115 static void msgq_clear(struct msgq_head *qh);
00116 static int stack_limit;
00117 static char *realservername;
00118
00119 #include "servmsg.c"
00120
00121 #define MAXPENALTY 10
00122
00123
00124 static int maxqmsg;
00125 static struct msgq_head mq, hq, modeq;
00126 static int burst;
00127
00128 #include "cmdsserv.c"
00129 #include "tclserv.c"
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 static void deq_msg()
00147 {
00148 struct msgq *q;
00149 int ok = 0;
00150
00151
00152 if ((now - last_time) >= msgrate || now < (last_time - 90)) {
00153 last_time = now;
00154 if (burst > 0)
00155 burst--;
00156 ok = 1;
00157 }
00158
00159 if (serv < 0)
00160 return;
00161
00162
00163 if (modeq.head) {
00164 while (modeq.head && (burst < 4) && ((last_time - now) < MAXPENALTY)) {
00165 if (deq_kick(DP_MODE)) {
00166 burst++;
00167 continue;
00168 }
00169 if (!modeq.head)
00170 break;
00171 if (fast_deq(DP_MODE)) {
00172 burst++;
00173 continue;
00174 }
00175 check_tcl_out(DP_MODE, modeq.head->msg, 1);
00176 write_to_server(modeq.head->msg, modeq.head->len);
00177 if (raw_log)
00178 putlog(LOG_SRVOUT, "*", "[m->] %s", modeq.head->msg);
00179 modeq.tot--;
00180 last_time += calc_penalty(modeq.head->msg);
00181 q = modeq.head->next;
00182 nfree(modeq.head->msg);
00183 nfree(modeq.head);
00184 modeq.head = q;
00185 burst++;
00186 }
00187 if (!modeq.head)
00188 modeq.last = 0;
00189 return;
00190 }
00191
00192
00193 if (burst > 1)
00194 return;
00195
00196 if (mq.head) {
00197 burst++;
00198
00199 if (deq_kick(DP_SERVER))
00200 return;
00201
00202 if (fast_deq(DP_SERVER))
00203 return;
00204
00205 check_tcl_out(DP_SERVER, mq.head->msg, 1);
00206 write_to_server(mq.head->msg, mq.head->len);
00207 if (raw_log)
00208 putlog(LOG_SRVOUT, "*", "[s->] %s", mq.head->msg);
00209 mq.tot--;
00210 last_time += calc_penalty(mq.head->msg);
00211 q = mq.head->next;
00212 nfree(mq.head->msg);
00213 nfree(mq.head);
00214 mq.head = q;
00215 if (!mq.head)
00216 mq.last = NULL;
00217 return;
00218 }
00219
00220
00221
00222
00223 if (!hq.head || burst || !ok)
00224 return;
00225
00226 if (deq_kick(DP_HELP))
00227 return;
00228
00229 if (fast_deq(DP_HELP))
00230 return;
00231
00232 check_tcl_out(DP_HELP, hq.head->msg, 1);
00233 write_to_server(hq.head->msg, hq.head->len);
00234 if (raw_log)
00235 putlog(LOG_SRVOUT, "*", "[h->] %s", hq.head->msg);
00236 hq.tot--;
00237 last_time += calc_penalty(hq.head->msg);
00238 q = hq.head->next;
00239 nfree(hq.head->msg);
00240 nfree(hq.head);
00241 hq.head = q;
00242 if (!hq.head)
00243 hq.last = NULL;
00244 }
00245
00246 static int calc_penalty(char *msg)
00247 {
00248 char *cmd, *par1, *par2, *par3;
00249 register int penalty, i, ii;
00250
00251 if (!use_penalties && net_type != NETT_UNDERNET &&
00252 net_type != NETT_HYBRID_EFNET)
00253 return 0;
00254
00255 cmd = newsplit(&msg);
00256 if (msg)
00257 i = strlen(msg);
00258 else
00259 i = strlen(cmd);
00260 last_time -= 2;
00261 if (net_type == NETT_UNDERNET || net_type == NETT_HYBRID_EFNET) {
00262 last_time += (2 + i / 120);
00263 return 0;
00264 }
00265 penalty = (1 + i / 100);
00266 if (!egg_strcasecmp(cmd, "KICK")) {
00267 par1 = newsplit(&msg);
00268 par2 = newsplit(&msg);
00269 par3 = splitnicks(&par2);
00270 penalty++;
00271 while (strlen(par3) > 0) {
00272 par3 = splitnicks(&par2);
00273 penalty++;
00274 }
00275 ii = penalty;
00276 par3 = splitnicks(&par1);
00277 while (strlen(par1) > 0) {
00278 par3 = splitnicks(&par1);
00279 penalty += ii;
00280 }
00281 } else if (!egg_strcasecmp(cmd, "MODE")) {
00282 i = 0;
00283 par1 = newsplit(&msg);
00284 par2 = newsplit(&msg);
00285 if (!strlen(par2))
00286 i++;
00287 while (strlen(par2) > 0) {
00288 if (strchr("ntimps", par2[0]))
00289 i += 3;
00290 else if (!strchr("+-", par2[0]))
00291 i += 1;
00292 par2++;
00293 }
00294 while (strlen(msg) > 0) {
00295 newsplit(&msg);
00296 i += 2;
00297 }
00298 ii = 0;
00299 while (strlen(par1) > 0) {
00300 splitnicks(&par1);
00301 ii++;
00302 }
00303 penalty += (ii * i);
00304 } else if (!egg_strcasecmp(cmd, "TOPIC")) {
00305 penalty++;
00306 par1 = newsplit(&msg);
00307 par2 = newsplit(&msg);
00308 if (strlen(par2) > 0) {
00309 penalty += 2;
00310 par3 = splitnicks(&par1);
00311 while (strlen(par1) > 0) {
00312 par3 = splitnicks(&par1);
00313 penalty += 2;
00314 }
00315 }
00316 } else if (!egg_strcasecmp(cmd, "PRIVMSG") ||
00317 !egg_strcasecmp(cmd, "NOTICE")) {
00318 par1 = newsplit(&msg);
00319
00320 while (strlen(par1) > 0) {
00321 splitnicks(&par1);
00322 penalty++;
00323 }
00324 } else if (!egg_strcasecmp(cmd, "WHO")) {
00325 par1 = newsplit(&msg);
00326 par2 = par1;
00327 while (strlen(par1) > 0) {
00328 par2 = splitnicks(&par1);
00329 if (strlen(par2) > 4)
00330 penalty += 3;
00331 else
00332 penalty += 5;
00333 }
00334 } else if (!egg_strcasecmp(cmd, "AWAY")) {
00335 if (strlen(msg) > 0)
00336 penalty += 2;
00337 else
00338 penalty += 1;
00339 } else if (!egg_strcasecmp(cmd, "INVITE")) {
00340
00341
00342
00343 penalty += 3;
00344 } else if (!egg_strcasecmp(cmd, "JOIN")) {
00345 penalty += 2;
00346 } else if (!egg_strcasecmp(cmd, "PART")) {
00347 penalty += 4;
00348 } else if (!egg_strcasecmp(cmd, "VERSION")) {
00349 penalty += 2;
00350 } else if (!egg_strcasecmp(cmd, "TIME")) {
00351 penalty += 2;
00352 } else if (!egg_strcasecmp(cmd, "TRACE")) {
00353 penalty += 2;
00354 } else if (!egg_strcasecmp(cmd, "NICK")) {
00355 penalty += 3;
00356 } else if (!egg_strcasecmp(cmd, "ISON")) {
00357 penalty += 1;
00358 } else if (!egg_strcasecmp(cmd, "WHOIS")) {
00359 penalty += 2;
00360 } else if (!egg_strcasecmp(cmd, "DNS")) {
00361 penalty += 2;
00362 } else
00363 penalty++;
00364
00365 if (penalty > 99)
00366 penalty = 99;
00367 if (penalty < 2) {
00368 putlog(LOG_SRVOUT, "*", "Penalty < 2sec; that's impossible!");
00369 penalty = 2;
00370 }
00371 if (raw_log && penalty != 0)
00372 putlog(LOG_SRVOUT, "*", "Adding penalty: %i", penalty);
00373 return penalty;
00374 }
00375
00376 char *splitnicks(char **rest)
00377 {
00378 register char *o, *r;
00379
00380 if (!rest)
00381 return *rest = "";
00382 o = *rest;
00383 while (*o == ' ')
00384 o++;
00385 r = o;
00386 while (*o && *o != ',')
00387 o++;
00388 if (*o)
00389 *o++ = 0;
00390 *rest = o;
00391 return r;
00392 }
00393
00394 static int fast_deq(int which)
00395 {
00396 struct msgq_head *h;
00397 struct msgq *m, *nm;
00398 char msgstr[511], nextmsgstr[511], tosend[511], victims[511], stackable[511],
00399 *msg, *nextmsg, *cmd, *nextcmd, *to, *nextto, *stckbl;
00400 int len, doit = 0, found = 0, cmd_count = 0, stack_method = 1;
00401
00402 if (!use_fastdeq)
00403 return 0;
00404
00405 switch (which) {
00406 case DP_MODE:
00407 h = &modeq;
00408 break;
00409 case DP_SERVER:
00410 h = &mq;
00411 break;
00412 case DP_HELP:
00413 h = &hq;
00414 break;
00415 default:
00416 return 0;
00417 }
00418
00419 m = h->head;
00420 strncpyz(msgstr, m->msg, sizeof msgstr);
00421 msg = msgstr;
00422 cmd = newsplit(&msg);
00423 if (use_fastdeq > 1) {
00424 strncpyz(stackable, stackablecmds, sizeof stackable);
00425 stckbl = stackable;
00426 while (strlen(stckbl) > 0) {
00427 if (!egg_strcasecmp(newsplit(&stckbl), cmd)) {
00428 found = 1;
00429 break;
00430 }
00431 }
00432
00433
00434 if (use_fastdeq == 2 && !found)
00435 return 0;
00436
00437
00438 if (use_fastdeq == 3 && found)
00439 return 0;
00440
00441
00442 strncpyz(stackable, stackable2cmds, sizeof stackable);
00443 stckbl = stackable;
00444 while (strlen(stckbl) > 0)
00445 if (!egg_strcasecmp(newsplit(&stckbl), cmd)) {
00446 stack_method = 2;
00447 break;
00448 }
00449 }
00450 to = newsplit(&msg);
00451 len = strlen(to);
00452 simple_sprintf(victims, "%s", to);
00453 while (m) {
00454 nm = m->next;
00455 if (!nm)
00456 break;
00457 strncpyz(nextmsgstr, nm->msg, sizeof nextmsgstr);
00458 nextmsg = nextmsgstr;
00459 nextcmd = newsplit(&nextmsg);
00460 nextto = newsplit(&nextmsg);
00461 len = strlen(nextto);
00462 if (strcmp(to, nextto) && !strcmp(cmd, nextcmd) && !strcmp(msg, nextmsg) &&
00463 ((strlen(cmd) + strlen(victims) + strlen(nextto) + strlen(msg) + 2) <
00464 510) && (!stack_limit || cmd_count < stack_limit - 1)) {
00465 cmd_count++;
00466 if (stack_method == 1)
00467 simple_sprintf(victims, "%s,%s", victims, nextto);
00468 else
00469 simple_sprintf(victims, "%s %s", victims, nextto);
00470 doit = 1;
00471 m->next = nm->next;
00472 if (!nm->next)
00473 h->last = m;
00474 nfree(nm->msg);
00475 nfree(nm);
00476 h->tot--;
00477 } else
00478 m = m->next;
00479 }
00480 if (doit) {
00481 simple_sprintf(tosend, "%s %s %s", cmd, victims, msg);
00482 len = strlen(tosend);
00483 check_tcl_out(which, tosend, 1);
00484 write_to_server(tosend, len);
00485 if (raw_log) {
00486 switch (which) {
00487 case DP_MODE:
00488 putlog(LOG_SRVOUT, "*", "[m=>] %s", tosend);
00489 break;
00490 case DP_SERVER:
00491 putlog(LOG_SRVOUT, "*", "[s=>] %s", tosend);
00492 break;
00493 case DP_HELP:
00494 putlog(LOG_SRVOUT, "*", "[h=>] %s", tosend);
00495 break;
00496 }
00497 }
00498 m = h->head->next;
00499 nfree(h->head->msg);
00500 nfree(h->head);
00501 h->head = m;
00502 if (!h->head)
00503 h->last = 0;
00504 h->tot--;
00505 last_time += calc_penalty(tosend);
00506 return 1;
00507 }
00508 return 0;
00509 }
00510
00511 static void check_queues(char *oldnick, char *newnick)
00512 {
00513 if (optimize_kicks != 2)
00514 return;
00515 if (modeq.head)
00516 parse_q(&modeq, oldnick, newnick);
00517 if (mq.head)
00518 parse_q(&mq, oldnick, newnick);
00519 if (hq.head)
00520 parse_q(&hq, oldnick, newnick);
00521 }
00522
00523 static void parse_q(struct msgq_head *q, char *oldnick, char *newnick)
00524 {
00525 struct msgq *m, *lm = NULL;
00526 char buf[511], *msg, *nicks, *nick, *chan, newnicks[511], newmsg[511];
00527 int changed;
00528
00529 for (m = q->head; m;) {
00530 changed = 0;
00531 if (optimize_kicks == 2 && !egg_strncasecmp(m->msg, "KICK ", 5)) {
00532 newnicks[0] = 0;
00533 strncpyz(buf, m->msg, sizeof buf);
00534 msg = buf;
00535 newsplit(&msg);
00536 chan = newsplit(&msg);
00537 nicks = newsplit(&msg);
00538 while (strlen(nicks) > 0) {
00539 nick = splitnicks(&nicks);
00540 if (!egg_strcasecmp(nick, oldnick) &&
00541 ((9 + strlen(chan) + strlen(newnicks) + strlen(newnick) +
00542 strlen(nicks) + strlen(msg)) < 510)) {
00543 if (newnick)
00544 egg_snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks, newnick);
00545 changed = 1;
00546 } else
00547 egg_snprintf(newnicks, sizeof newnicks, ",%s", nick);
00548 }
00549 egg_snprintf(newmsg, sizeof newmsg, "KICK %s %s %s", chan,
00550 newnicks + 1, msg);
00551 }
00552 if (changed) {
00553 if (newnicks[0] == 0) {
00554 if (!lm)
00555 q->head = m->next;
00556 else
00557 lm->next = m->next;
00558 nfree(m->msg);
00559 nfree(m);
00560 m = lm;
00561 q->tot--;
00562 if (!q->head)
00563 q->last = 0;
00564 } else {
00565 nfree(m->msg);
00566 m->msg = nmalloc(strlen(newmsg) + 1);
00567 m->len = strlen(newmsg);
00568 strcpy(m->msg, newmsg);
00569 }
00570 }
00571 lm = m;
00572 if (m)
00573 m = m->next;
00574 else
00575 m = q->head;
00576 }
00577 }
00578
00579 static void purge_kicks(struct msgq_head *q)
00580 {
00581 struct msgq *m, *lm = NULL;
00582 char buf[511], *reason, *nicks, *nick, *chan, newnicks[511],
00583 newmsg[511], chans[511], *chns, *ch;
00584 int changed, found;
00585 struct chanset_t *cs;
00586
00587 for (m = q->head; m;) {
00588 if (!egg_strncasecmp(m->msg, "KICK", 4)) {
00589 newnicks[0] = 0;
00590 changed = 0;
00591 strncpyz(buf, m->msg, sizeof buf);
00592 reason = buf;
00593 newsplit(&reason);
00594 chan = newsplit(&reason);
00595 nicks = newsplit(&reason);
00596 while (strlen(nicks) > 0) {
00597 found = 0;
00598 nick = splitnicks(&nicks);
00599 strncpyz(chans, chan, sizeof chans);
00600 chns = chans;
00601 while (strlen(chns) > 0) {
00602 ch = newsplit(&chns);
00603 cs = findchan(ch);
00604 if (!cs)
00605 continue;
00606 if (ismember(cs, nick))
00607 found = 1;
00608 }
00609 if (found)
00610 egg_snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks, nick);
00611 else {
00612 putlog(LOG_SRVOUT, "*", "%s isn't on any target channel; removing "
00613 "kick.", nick);
00614 changed = 1;
00615 }
00616 }
00617 if (changed) {
00618 if (newnicks[0] == 0) {
00619 if (!lm)
00620 q->head = m->next;
00621 else
00622 lm->next = m->next;
00623 nfree(m->msg);
00624 nfree(m);
00625 m = lm;
00626 q->tot--;
00627 if (!q->head)
00628 q->last = 0;
00629 } else {
00630 nfree(m->msg);
00631 egg_snprintf(newmsg, sizeof newmsg, "KICK %s %s %s", chan,
00632 newnicks + 1, reason);
00633 m->msg = nmalloc(strlen(newmsg) + 1);
00634 m->len = strlen(newmsg);
00635 strcpy(m->msg, newmsg);
00636 }
00637 }
00638 }
00639 lm = m;
00640 if (m)
00641 m = m->next;
00642 else
00643 m = q->head;
00644 }
00645 }
00646
00647 static int deq_kick(int which)
00648 {
00649 struct msgq_head *h;
00650 struct msgq *msg, *m, *lm;
00651 char buf[511], buf2[511], *reason2, *nicks, *chan, *chan2, *reason, *nick,
00652 newnicks[511], newnicks2[511], newmsg[511];
00653 int changed = 0, nr = 0;
00654
00655 if (!optimize_kicks)
00656 return 0;
00657
00658 newnicks[0] = 0;
00659 switch (which) {
00660 case DP_MODE:
00661 h = &modeq;
00662 break;
00663 case DP_SERVER:
00664 h = &mq;
00665 break;
00666 case DP_HELP:
00667 h = &hq;
00668 break;
00669 default:
00670 return 0;
00671 }
00672
00673 if (egg_strncasecmp(h->head->msg, "KICK", 4))
00674 return 0;
00675
00676 if (optimize_kicks == 2) {
00677 purge_kicks(h);
00678 if (!h->head)
00679 return 1;
00680 }
00681
00682 if (egg_strncasecmp(h->head->msg, "KICK", 4))
00683 return 0;
00684
00685 msg = h->head;
00686 strncpyz(buf, msg->msg, sizeof buf);
00687 reason = buf;
00688 newsplit(&reason);
00689 chan = newsplit(&reason);
00690 nicks = newsplit(&reason);
00691 while (strlen(nicks) > 0) {
00692 egg_snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks,
00693 newsplit(&nicks));
00694 nr++;
00695 }
00696 for (m = msg->next, lm = NULL; m && (nr < kick_method);) {
00697 if (!egg_strncasecmp(m->msg, "KICK", 4)) {
00698 changed = 0;
00699 newnicks2[0] = 0;
00700 strncpyz(buf2, m->msg, sizeof buf2);
00701 reason2 = buf2;
00702 newsplit(&reason2);
00703 chan2 = newsplit(&reason2);
00704 nicks = newsplit(&reason2);
00705 if (!egg_strcasecmp(chan, chan2) && !egg_strcasecmp(reason, reason2)) {
00706 while (strlen(nicks) > 0) {
00707 nick = splitnicks(&nicks);
00708 if ((nr < kick_method) && ((9 + strlen(chan) + strlen(newnicks) +
00709 strlen(nick) + strlen(reason)) < 510)) {
00710 egg_snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks, nick);
00711 nr++;
00712 changed = 1;
00713 } else
00714 egg_snprintf(newnicks2, sizeof newnicks2, "%s,%s", newnicks2, nick);
00715 }
00716 }
00717 if (changed) {
00718 if (newnicks2[0] == 0) {
00719 if (!lm)
00720 h->head->next = m->next;
00721 else
00722 lm->next = m->next;
00723 nfree(m->msg);
00724 nfree(m);
00725 m = lm;
00726 h->tot--;
00727 if (!h->head)
00728 h->last = 0;
00729 } else {
00730 nfree(m->msg);
00731 egg_snprintf(newmsg, sizeof newmsg, "KICK %s %s %s", chan2,
00732 newnicks2 + 1, reason);
00733 m->msg = nmalloc(strlen(newmsg) + 1);
00734 m->len = strlen(newmsg);
00735 strcpy(m->msg, newmsg);
00736 }
00737 }
00738 }
00739 lm = m;
00740 if (m)
00741 m = m->next;
00742 else
00743 m = h->head->next;
00744 }
00745 egg_snprintf(newmsg, sizeof newmsg, "KICK %s %s %s", chan, newnicks + 1,
00746 reason);
00747 check_tcl_out(which, newmsg, 1);
00748 write_to_server(newmsg, strlen(newmsg));
00749 if (raw_log) {
00750 switch (which) {
00751 case DP_MODE:
00752 putlog(LOG_SRVOUT, "*", "[m->] %s", newmsg);
00753 break;
00754 case DP_SERVER:
00755 putlog(LOG_SRVOUT, "*", "[s->] %s", newmsg);
00756 break;
00757 case DP_HELP:
00758 putlog(LOG_SRVOUT, "*", "[h->] %s", newmsg);
00759 break;
00760 }
00761 debug3("Changed: %d, kick-method: %d, nr: %d", changed, kick_method, nr);
00762 }
00763 h->tot--;
00764 last_time += calc_penalty(newmsg);
00765 m = h->head->next;
00766 nfree(h->head->msg);
00767 nfree(h->head);
00768 h->head = m;
00769 if (!h->head)
00770 h->last = 0;
00771 return 1;
00772 }
00773
00774
00775
00776 static void empty_msgq()
00777 {
00778 msgq_clear(&modeq);
00779 msgq_clear(&mq);
00780 msgq_clear(&hq);
00781 burst = 0;
00782 }
00783
00784
00785
00786 static void queue_server(int which, char *msg, int len)
00787 {
00788 struct msgq_head *h = NULL, tempq;
00789 struct msgq *q, *tq, *tqq;
00790 int doublemsg = 0, qnext = 0;
00791 char buf[511];
00792
00793
00794 if (serv < 0)
00795 return;
00796
00797
00798
00799
00800 strncpy(buf, msg, sizeof buf);
00801 msg = buf;
00802 remove_crlf(&msg);
00803 buf[510] = 0;
00804 len = strlen(buf);
00805
00806
00807 if (!egg_strncasecmp(buf, "PING", 4) || !egg_strncasecmp(buf, "PONG", 4)) {
00808 if (buf[1] == 'I' || buf[1] == 'i')
00809 lastpingtime = now;
00810 check_tcl_out(which, buf, 1);
00811 write_to_server(buf, len);
00812 if (raw_log)
00813 putlog(LOG_SRVOUT, "*", "[m->] %s", buf);
00814 return;
00815 }
00816
00817 switch (which) {
00818 case DP_MODE_NEXT:
00819 qnext = 1;
00820
00821
00822 case DP_MODE:
00823 h = &modeq;
00824 tempq = modeq;
00825 if (double_mode)
00826 doublemsg = 1;
00827 break;
00828
00829 case DP_SERVER_NEXT:
00830 qnext = 1;
00831
00832
00833 case DP_SERVER:
00834 h = &mq;
00835 tempq = mq;
00836 if (double_server)
00837 doublemsg = 1;
00838 break;
00839
00840 case DP_HELP_NEXT:
00841 qnext = 1;
00842
00843
00844 case DP_HELP:
00845 h = &hq;
00846 tempq = hq;
00847 if (double_help)
00848 doublemsg = 1;
00849 break;
00850
00851 default:
00852 putlog(LOG_MISC, "*", "Warning: queuing unknown type to server!");
00853 return;
00854 }
00855
00856 if (h->tot < maxqmsg) {
00857
00858 if (!doublemsg) {
00859 for (tq = tempq.head; tq; tq = tqq) {
00860 tqq = tq->next;
00861 if (!egg_strcasecmp(tq->msg, buf)) {
00862 if (!double_warned) {
00863 debug1("Message already queued; skipping: %s", buf);
00864 double_warned = 1;
00865 }
00866 return;
00867 }
00868 }
00869 }
00870
00871 if (check_tcl_out(which, buf, 0))
00872 return;
00873
00874 q = nmalloc(sizeof(struct msgq));
00875
00876
00877 if (qnext) {
00878 q->next = h->head;
00879 h->head = q;
00880 if (!h->last)
00881 h->last = q;
00882 }
00883 else {
00884 q->next = NULL;
00885 if (h->last)
00886 h->last->next = q;
00887 else
00888 h->head = q;
00889 h->last = q;
00890 }
00891
00892 q->len = len;
00893 q->msg = nmalloc(len + 1);
00894 egg_memcpy(q->msg, buf, len);
00895 q->msg[len] = 0;
00896 h->tot++;
00897 h->warned = 0;
00898 double_warned = 0;
00899
00900 if (raw_log) {
00901 switch (which) {
00902 case DP_MODE:
00903 putlog(LOG_SRVOUT, "*", "[!m] %s", buf);
00904 break;
00905 case DP_SERVER:
00906 putlog(LOG_SRVOUT, "*", "[!s] %s", buf);
00907 break;
00908 case DP_HELP:
00909 putlog(LOG_SRVOUT, "*", "[!h] %s", buf);
00910 break;
00911 case DP_MODE_NEXT:
00912 putlog(LOG_SRVOUT, "*", "[!!m] %s", buf);
00913 break;
00914 case DP_SERVER_NEXT:
00915 putlog(LOG_SRVOUT, "*", "[!!s] %s", buf);
00916 break;
00917 case DP_HELP_NEXT:
00918 putlog(LOG_SRVOUT, "*", "[!!h] %s", buf);
00919 break;
00920 }
00921 }
00922 } else {
00923 if (!h->warned) {
00924 switch (which) {
00925 case DP_MODE_NEXT:
00926
00927 case DP_MODE:
00928 putlog(LOG_MISC, "*", "Warning: over maximum mode queue!");
00929 break;
00930
00931 case DP_SERVER_NEXT:
00932
00933 case DP_SERVER:
00934 putlog(LOG_MISC, "*", "Warning: over maximum server queue!");
00935 break;
00936
00937 case DP_HELP_NEXT:
00938
00939 case DP_HELP:
00940 putlog(LOG_MISC, "*", "Warning: over maximum help queue!");
00941 break;
00942 }
00943 }
00944 h->warned = 1;
00945 }
00946
00947 if (which == DP_MODE || which == DP_MODE_NEXT)
00948 deq_msg();
00949 }
00950
00951
00952
00953 static void add_server(const char *ss)
00954 {
00955 struct server_list *x, *z;
00956 char *p, *q;
00957
00958 for (z = serverlist; z && z->next; z = z->next);
00959 while (ss) {
00960 p = strchr(ss, ',');
00961 if (p)
00962 *p++ = 0;
00963 x = nmalloc(sizeof(struct server_list));
00964
00965 x->next = 0;
00966 x->realname = 0;
00967 x->port = 0;
00968 if (z)
00969 z->next = x;
00970 else
00971 serverlist = x;
00972 z = x;
00973 q = strchr(ss, ':');
00974 if (!q) {
00975 x->port = default_port;
00976 x->pass = 0;
00977 x->name = nmalloc(strlen(ss) + 1);
00978 strcpy(x->name, ss);
00979 } else {
00980 *q++ = 0;
00981 x->name = nmalloc(q - ss);
00982 strcpy(x->name, ss);
00983 ss = q;
00984 q = strchr(ss, ':');
00985 if (!q) {
00986 x->pass = 0;
00987 } else {
00988 *q++ = 0;
00989 x->pass = nmalloc(strlen(q) + 1);
00990 strcpy(x->pass, q);
00991 }
00992 x->port = atoi(ss);
00993 }
00994 ss = p;
00995 }
00996 }
00997
00998
00999
01000
01001 static void clearq(struct server_list *xx)
01002 {
01003 struct server_list *x;
01004
01005 while (xx) {
01006 x = xx->next;
01007 if (xx->name)
01008 nfree(xx->name);
01009 if (xx->pass)
01010 nfree(xx->pass);
01011 if (xx->realname)
01012 nfree(xx->realname);
01013 nfree(xx);
01014 xx = x;
01015 }
01016 }
01017
01018
01019
01020
01021
01022 static void next_server(int *ptr, char *serv, unsigned int *port, char *pass)
01023 {
01024 struct server_list *x = serverlist;
01025 int i = 0;
01026
01027
01028 if (*ptr == -1) {
01029 for (; x; x = x->next) {
01030 if (x->port == *port) {
01031 if (!egg_strcasecmp(x->name, serv)) {
01032 *ptr = i;
01033 return;
01034 } else if (x->realname && !egg_strcasecmp(x->realname, serv)) {
01035 *ptr = i;
01036 strncpyz(serv, x->realname, sizeof serv);
01037 return;
01038 }
01039 }
01040 i++;
01041 }
01042
01043 x = nmalloc(sizeof(struct server_list));
01044
01045 x->next = 0;
01046 x->realname = 0;
01047 x->name = nmalloc(strlen(serv) + 1);
01048 strcpy(x->name, serv);
01049 x->port = *port ? *port : default_port;
01050 if (pass && pass[0]) {
01051 x->pass = nmalloc(strlen(pass) + 1);
01052 strcpy(x->pass, pass);
01053 } else
01054 x->pass = NULL;
01055 egg_list_append((struct list_type **) (&serverlist),
01056 (struct list_type *) x);
01057 *ptr = i;
01058 return;
01059 }
01060
01061 if (x == NULL)
01062 return;
01063 i = (*ptr);
01064 while (i > 0 && x != NULL) {
01065 x = x->next;
01066 i--;
01067 }
01068 if (x != NULL) {
01069 x = x->next;
01070 (*ptr)++;
01071 }
01072 if (x == NULL) {
01073 x = serverlist;
01074 *ptr = 0;
01075 }
01076 strcpy(serv, x->name);
01077 *port = x->port ? x->port : default_port;
01078 if (x->pass)
01079 strcpy(pass, x->pass);
01080 else
01081 pass[0] = 0;
01082 }
01083
01084 static int server_6char STDVAR
01085 {
01086 Function F = (Function) cd;
01087 char x[20];
01088
01089 BADARGS(7, 7, " nick user@host handle dest/chan keyword text");
01090
01091 CHECKVALIDITY(server_6char);
01092 egg_snprintf(x, sizeof x, "%d",
01093 F(argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]));
01094 Tcl_AppendResult(irp, x, NULL);
01095 return TCL_OK;
01096 }
01097
01098 static int server_5char STDVAR
01099 {
01100 Function F = (Function) cd;
01101
01102 BADARGS(6, 6, " nick user@host handle dest/channel text");
01103
01104 CHECKVALIDITY(server_5char);
01105 F(argv[1], argv[2], argv[3], argv[4], argv[5]);
01106 return TCL_OK;
01107 }
01108
01109 static int server_2char STDVAR
01110 {
01111 Function F = (Function) cd;
01112
01113 BADARGS(3, 3, " nick msg");
01114
01115 CHECKVALIDITY(server_2char);
01116 F(argv[1], argv[2]);
01117 return TCL_OK;
01118 }
01119
01120 static int server_msg STDVAR
01121 {
01122 Function F = (Function) cd;
01123
01124 BADARGS(5, 5, " nick uhost hand buffer");
01125
01126 CHECKVALIDITY(server_msg);
01127 F(argv[1], argv[2], get_user_by_handle(userlist, argv[3]), argv[4]);
01128 return TCL_OK;
01129 }
01130
01131 static int server_raw STDVAR
01132 {
01133 Function F = (Function) cd;
01134
01135 BADARGS(4, 4, " from code args");
01136
01137 CHECKVALIDITY(server_raw);
01138 Tcl_AppendResult(irp, int_to_base10(F(argv[1], argv[3])), NULL);
01139 return TCL_OK;
01140 }
01141
01142 static int server_out STDVAR
01143 {
01144 Function F = (Function) cd;
01145
01146 BADARGS(4, 4, " queue message sent");
01147
01148 CHECKVALIDITY(server_out);
01149 F(argv[1], argv[2], argv[3]);
01150 return TCL_OK;
01151 }
01152
01153
01154
01155 static char *nick_change(ClientData cdata, Tcl_Interp *irp,
01156 EGG_CONST char *name1,
01157 EGG_CONST char *name2, int flags)
01158 {
01159 EGG_CONST char *new;
01160
01161 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
01162 Tcl_SetVar2(interp, name1, name2, origbotname, TCL_GLOBAL_ONLY);
01163 if (flags & TCL_TRACE_UNSETS)
01164 Tcl_TraceVar(irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
01165 TCL_TRACE_UNSETS, nick_change, cdata);
01166 } else {
01167 new = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
01168 if (strcmp(origbotname, (char *) new)) {
01169 if (origbotname[0]) {
01170 putlog(LOG_MISC, "*", "* IRC NICK CHANGE: %s -> %s", origbotname, new);
01171 nick_juped = 0;
01172 }
01173 strncpyz(origbotname, new, NICKLEN);
01174 if (server_online)
01175 dprintf(DP_SERVER, "NICK %s\n", origbotname);
01176 }
01177 }
01178 return NULL;
01179 }
01180
01181
01182
01183 static void rand_nick(char *nick)
01184 {
01185 register char *p = nick;
01186
01187 while ((p = strchr(p, '?')) != NULL) {
01188 *p = '0' + randint(10);
01189 p++;
01190 }
01191 }
01192
01193
01194
01195 static char *get_altbotnick(void)
01196 {
01197
01198 if (strchr(altnick, '?')) {
01199 if (!raltnick[0]) {
01200 strncpyz(raltnick, altnick, NICKLEN);
01201 rand_nick(raltnick);
01202 }
01203 return raltnick;
01204 } else
01205 return altnick;
01206 }
01207
01208 static char *altnick_change(ClientData cdata, Tcl_Interp *irp,
01209 EGG_CONST char *name1,
01210 EGG_CONST char *name2, int flags)
01211 {
01212
01213 raltnick[0] = 0;
01214 return NULL;
01215 }
01216
01217 static char *traced_serveraddress(ClientData cdata, Tcl_Interp *irp,
01218 EGG_CONST char *name1,
01219 EGG_CONST char *name2, int flags)
01220 {
01221 char s[1024];
01222
01223 if (server_online) {
01224 int servidx = findanyidx(serv);
01225
01226 simple_sprintf(s, "%s:%u", dcc[servidx].host, dcc[servidx].port);
01227 } else
01228 s[0] = 0;
01229 Tcl_SetVar2(interp, name1, name2, s, TCL_GLOBAL_ONLY);
01230 if (flags & TCL_TRACE_UNSETS)
01231 Tcl_TraceVar(irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
01232 TCL_TRACE_UNSETS, traced_serveraddress, cdata);
01233 return NULL;
01234 }
01235
01236 static char *traced_server(ClientData cdata, Tcl_Interp *irp,
01237 EGG_CONST char *name1,
01238 EGG_CONST char *name2, int flags)
01239 {
01240 char s[1024];
01241
01242 if (server_online && realservername) {
01243 int servidx = findanyidx(serv);
01244
01245
01246 simple_sprintf(s, "%s:%u", realservername, dcc[servidx].port);
01247 } else
01248 s[0] = 0;
01249 Tcl_SetVar2(interp, name1, name2, s, TCL_GLOBAL_ONLY);
01250 if (flags & TCL_TRACE_UNSETS)
01251 Tcl_TraceVar(irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
01252 TCL_TRACE_UNSETS, traced_server, cdata);
01253 return NULL;
01254 }
01255
01256 static char *traced_botname(ClientData cdata, Tcl_Interp *irp,
01257 EGG_CONST char *name1,
01258 EGG_CONST char *name2, int flags)
01259 {
01260 char s[1024];
01261
01262 simple_sprintf(s, "%s%s%s", botname,
01263 botuserhost[0] ? "!" : "", botuserhost[0] ? botuserhost : "");
01264 Tcl_SetVar2(interp, name1, name2, s, TCL_GLOBAL_ONLY);
01265 if (flags & TCL_TRACE_UNSETS)
01266 Tcl_TraceVar(irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
01267 TCL_TRACE_UNSETS, traced_botname, cdata);
01268 return NULL;
01269 }
01270
01271 static void do_nettype(void)
01272 {
01273 switch (net_type) {
01274 case NETT_EFNET:
01275 check_mode_r = 0;
01276 nick_len = 9;
01277 break;
01278 case NETT_IRCNET:
01279 check_mode_r = 1;
01280 use_penalties = 1;
01281 use_fastdeq = 3;
01282 nick_len = 9;
01283 simple_sprintf(stackablecmds, "INVITE AWAY VERSION NICK");
01284 kick_method = 4;
01285 break;
01286 case NETT_UNDERNET:
01287 check_mode_r = 0;
01288 use_fastdeq = 2;
01289 nick_len = 12;
01290 simple_sprintf(stackablecmds,
01291 "PRIVMSG NOTICE TOPIC PART WHOIS USERHOST USERIP ISON");
01292 simple_sprintf(stackable2cmds, "USERHOST USERIP ISON");
01293 break;
01294 case NETT_DALNET:
01295 check_mode_r = 0;
01296 use_fastdeq = 2;
01297 nick_len = 32;
01298 simple_sprintf(stackablecmds,
01299 "PRIVMSG NOTICE PART WHOIS WHOWAS USERHOST ISON WATCH DCCALLOW");
01300 simple_sprintf(stackable2cmds, "USERHOST ISON WATCH");
01301 break;
01302 case NETT_HYBRID_EFNET:
01303 check_mode_r = 0;
01304 nick_len = 9;
01305 break;
01306 }
01307 }
01308
01309 static char *traced_nettype(ClientData cdata, Tcl_Interp *irp,
01310 EGG_CONST char *name1,
01311 EGG_CONST char *name2, int flags)
01312 {
01313 do_nettype();
01314 return NULL;
01315 }
01316
01317 static char *traced_nicklen(ClientData cdata, Tcl_Interp *irp,
01318 EGG_CONST char *name1,
01319 EGG_CONST char *name2, int flags)
01320 {
01321 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
01322 char s[40];
01323
01324 egg_snprintf(s, sizeof s, "%d", nick_len);
01325 Tcl_SetVar2(interp, name1, name2, s, TCL_GLOBAL_ONLY);
01326 if (flags & TCL_TRACE_UNSETS)
01327 Tcl_TraceVar(irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
01328 TCL_TRACE_UNSETS, traced_nicklen, cdata);
01329 } else {
01330 EGG_CONST char *cval = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
01331 long lval = 0;
01332
01333 if (cval && Tcl_ExprLong(interp, cval, &lval) != TCL_ERROR) {
01334 if (lval > NICKMAX)
01335 lval = NICKMAX;
01336 nick_len = (int) lval;
01337 }
01338 }
01339 return NULL;
01340 }
01341
01342 static tcl_strings my_tcl_strings[] = {
01343 {"botnick", NULL, 0, STR_PROTECT},
01344 {"altnick", altnick, NICKMAX, 0},
01345 {"realname", botrealname, 80, 0},
01346 {"init-server", initserver, 120, 0},
01347 {"connect-server", connectserver, 120, 0},
01348 {"stackable-commands", stackablecmds, 510, 0},
01349 {"stackable2-commands", stackable2cmds, 510, 0},
01350 {NULL, NULL, 0, 0}
01351 };
01352
01353 static tcl_coups my_tcl_coups[] = {
01354 {"flood-ctcp", &flud_ctcp_thr, &flud_ctcp_time},
01355 {"flood-msg", &flud_thr, &flud_time},
01356 {NULL, NULL, NULL}
01357 };
01358
01359 static tcl_ints my_tcl_ints[] = {
01360 {"servlimit", &min_servs, 0},
01361 {"server-timeout", &server_timeout, 0},
01362 {"lowercase-ctcp", &lowercase_ctcp, 0},
01363 {"server-online", (int *) &server_online, 2},
01364 {"never-give-up", &never_give_up, 0},
01365 {"keep-nick", &keepnick, 0},
01366 {"check-stoned", &check_stoned, 0},
01367 {"serverror-quit", &serverror_quit, 0},
01368 {"max-queue-msg", &maxqmsg, 0},
01369 {"trigger-on-ignore", &trigger_on_ignore, 0},
01370 {"answer-ctcp", &answer_ctcp, 0},
01371 {"server-cycle-wait", (int *) &server_cycle_wait, 0},
01372 {"default-port", &default_port, 0},
01373 {"check-mode-r", &check_mode_r, 0},
01374 {"net-type", &net_type, 0},
01375 {"ctcp-mode", &ctcp_mode, 0},
01376 {"double-mode", &double_mode, 0},
01377 {"double-server", &double_server, 0},
01378 {"double-help", &double_help, 0},
01379 {"use-penalties", &use_penalties, 0},
01380 {"use-fastdeq", &use_fastdeq, 0},
01381 {"nicklen", &nick_len, 0},
01382 {"nick-len", &nick_len, 0},
01383 {"optimize-kicks", &optimize_kicks, 0},
01384 {"isjuped", &nick_juped, 0},
01385 {"stack-limit", &stack_limit, 0},
01386 {"exclusive-binds", &exclusive_binds, 0},
01387 {"msg-rate", &msgrate, 0},
01388 {NULL, NULL, 0}
01389 };
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399 static char *tcl_eggserver(ClientData cdata, Tcl_Interp *irp,
01400 EGG_CONST char *name1,
01401 EGG_CONST char *name2, int flags)
01402 {
01403 int lc, code, i;
01404 char x[1024];
01405 EGG_CONST char **list, *slist;
01406 struct server_list *q;
01407 Tcl_DString ds;
01408
01409 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
01410
01411 Tcl_DStringInit(&ds);
01412 for (q = serverlist; q; q = q->next) {
01413 egg_snprintf(x, sizeof x, "%s:%d%s%s %s", q->name,
01414 q->port ? q->port : default_port, q->pass ? ":" : "",
01415 q->pass ? q->pass : "", q->realname ? q->realname : "");
01416 Tcl_DStringAppendElement(&ds, x);
01417 }
01418 slist = Tcl_DStringValue(&ds);
01419 Tcl_SetVar2(interp, name1, name2, slist, TCL_GLOBAL_ONLY);
01420 Tcl_DStringFree(&ds);
01421 } else {
01422 if (serverlist) {
01423 clearq(serverlist);
01424 serverlist = NULL;
01425 }
01426 slist = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
01427 if (slist != NULL) {
01428 code = Tcl_SplitList(interp, slist, &lc, &list);
01429 if (code == TCL_ERROR)
01430 return "variable must be a list";
01431 for (i = 0; i < lc && i < 50; i++)
01432 add_server((char *) list[i]);
01433
01434
01435
01436
01437 if (server_online) {
01438 int servidx = findanyidx(serv);
01439
01440 curserv = -1;
01441 if (serverlist)
01442 next_server(&curserv, dcc[servidx].host, &dcc[servidx].port, "");
01443 }
01444 Tcl_Free((char *) list);
01445 }
01446 }
01447 return NULL;
01448 }
01449
01450
01451 #define tcl_traceserver(name, ptr) \
01452 Tcl_TraceVar(interp, name, TCL_TRACE_READS | TCL_TRACE_WRITES | \
01453 TCL_TRACE_UNSETS, tcl_eggserver, (ClientData) ptr)
01454
01455 #define tcl_untraceserver(name, ptr) \
01456 Tcl_UntraceVar(interp, name, TCL_TRACE_READS | TCL_TRACE_WRITES | \
01457 TCL_TRACE_UNSETS, tcl_eggserver, (ClientData) ptr)
01458
01459
01460
01461
01462
01463
01464 static void dcc_chat_hostresolved(int);
01465
01466
01467
01468 static int ctcp_DCC_CHAT(char *nick, char *from, char *handle,
01469 char *object, char *keyword, char *text)
01470 {
01471 char *action, *param, *ip, *prt, buf[512], *msg = buf;
01472 int i;
01473 struct userrec *u = get_user_by_handle(userlist, handle);
01474 struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
01475
01476 strcpy(msg, text);
01477 action = newsplit(&msg);
01478 param = newsplit(&msg);
01479 ip = newsplit(&msg);
01480 prt = newsplit(&msg);
01481 if (egg_strcasecmp(action, "CHAT") || egg_strcasecmp(object, botname) || !u)
01482 return 0;
01483 get_user_flagrec(u, &fr, 0);
01484 if (dcc_total == max_dcc && increase_socks_max()) {
01485 if (!quiet_reject)
01486 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_TOOMANYDCCS1);
01487 putlog(LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT", param, nick, from);
01488 } else if (!(glob_party(fr) || (!require_p && chan_op(fr)))) {
01489 if (glob_xfer(fr))
01490 return 0;
01491 if (!quiet_reject)
01492 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED2);
01493 putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED, nick, from);
01494 } else if (u_pass_match(u, "-")) {
01495 if (!quiet_reject)
01496 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED3);
01497 putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED4, nick, from);
01498 } else if (atoi(prt) < 1024 || atoi(prt) > 65535) {
01499
01500 if (!quiet_reject)
01501 dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick,
01502 DCC_CONNECTFAILED1);
01503 putlog(LOG_MISC, "*", "%s: CHAT (%s!%s)", DCC_CONNECTFAILED3, nick, from);
01504 } else {
01505 if (!sanitycheck_dcc(nick, from, ip, prt))
01506 return 1;
01507 i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
01508 if (i < 0) {
01509 putlog(LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", nick, ip);
01510 return 1;
01511 }
01512 dcc[i].addr = my_atoul(ip);
01513 dcc[i].port = atoi(prt);
01514 dcc[i].sock = -1;
01515 strcpy(dcc[i].nick, u->handle);
01516 strcpy(dcc[i].host, from);
01517 dcc[i].timeval = now;
01518 dcc[i].user = u;
01519 dcc[i].u.dns->ip = dcc[i].addr;
01520 dcc[i].u.dns->dns_type = RES_HOSTBYIP;
01521 dcc[i].u.dns->dns_success = dcc_chat_hostresolved;
01522 dcc[i].u.dns->dns_failure = dcc_chat_hostresolved;
01523 dcc[i].u.dns->type = &DCC_CHAT_PASS;
01524 dcc_dnshostbyip(dcc[i].addr);
01525 }
01526 return 1;
01527 }
01528
01529 static void dcc_chat_hostresolved(int i)
01530 {
01531 char buf[512], ip[512];
01532 struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
01533
01534 egg_snprintf(buf, sizeof buf, "%d", dcc[i].port);
01535 if (!hostsanitycheck_dcc(dcc[i].nick, dcc[i].host, dcc[i].addr,
01536 dcc[i].u.dns->host, buf)) {
01537 lostdcc(i);
01538 return;
01539 }
01540 egg_snprintf(ip, sizeof ip, "%lu", iptolong(htonl(dcc[i].addr)));
01541 dcc[i].sock = getsock(0);
01542 if (dcc[i].sock < 0 || open_telnet_dcc(dcc[i].sock, ip, buf) < 0) {
01543 neterror(buf);
01544 if (!quiet_reject)
01545 dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", dcc[i].nick,
01546 DCC_CONNECTFAILED1, buf);
01547 putlog(LOG_MISC, "*", "%s: CHAT (%s!%s)", DCC_CONNECTFAILED2,
01548 dcc[i].nick, dcc[i].host);
01549 putlog(LOG_MISC, "*", " (%s)", buf);
01550 killsock(dcc[i].sock);
01551 lostdcc(i);
01552 } else {
01553 changeover_dcc(i, &DCC_CHAT_PASS, sizeof(struct chat_info));
01554 dcc[i].status = STAT_ECHO;
01555 get_user_flagrec(dcc[i].user, &fr, 0);
01556 if (glob_party(fr))
01557 dcc[i].status |= STAT_PARTY;
01558 strcpy(dcc[i].u.chat->con_chan, (chanset) ? chanset->dname : "*");
01559 dcc[i].timeval = now;
01560
01561 putlog(LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", dcc[i].nick,
01562 dcc[i].host);
01563 dprintf(i, "%s\n", DCC_ENTERPASS);
01564 }
01565 return;
01566 }
01567
01568
01569
01570
01571
01572
01573 static void server_secondly()
01574 {
01575 if (cycle_time)
01576 cycle_time--;
01577 deq_msg();
01578 if (!resolvserv && serv < 0)
01579 connect_server();
01580 }
01581
01582 static void server_5minutely()
01583 {
01584 if (check_stoned && server_online) {
01585 if (lastpingcheck && (now - lastpingcheck >= 240)) {
01586
01587
01588
01589 int servidx = findanyidx(serv);
01590
01591 disconnect_server(servidx);
01592 lostdcc(servidx);
01593 putlog(LOG_SERV, "*", IRC_SERVERSTONED);
01594 } else if (!trying_server) {
01595
01596 dprintf(DP_MODE, "PING :%li\n", now);
01597 lastpingcheck = now;
01598 }
01599 }
01600 }
01601
01602 static void server_prerehash()
01603 {
01604 strcpy(oldnick, botname);
01605 }
01606
01607 static void server_postrehash()
01608 {
01609 strncpyz(botname, origbotname, NICKLEN);
01610 if (!botname[0])
01611 fatal("NO BOT NAME.", 0);
01612 if (serverlist == NULL)
01613 fatal("NO SERVER.", 0);
01614 if (oldnick[0] && !rfc_casecmp(oldnick, botname) &&
01615 !rfc_casecmp(oldnick, get_altbotnick())) {
01616
01617 strcpy(botname, oldnick);
01618 dprintf(DP_SERVER, "NICK %s\n", origbotname);
01619 }
01620
01621 else if (oldnick[0])
01622 strcpy(botname, oldnick);
01623 }
01624
01625 static void server_die()
01626 {
01627 cycle_time = 100;
01628 if (server_online) {
01629 dprintf(-serv, "QUIT :%s\n", quit_msg[0] ? quit_msg : "");
01630 sleep(3);
01631 }
01632 nuke_server(NULL);
01633 }
01634
01635
01636 static void msgq_clear(struct msgq_head *qh)
01637 {
01638 register struct msgq *q, *qq;
01639
01640 for (q = qh->head; q; q = qq) {
01641 qq = q->next;
01642 nfree(q->msg);
01643 nfree(q);
01644 }
01645 qh->head = qh->last = NULL;
01646 qh->tot = qh->warned = 0;
01647 }
01648
01649 static int msgq_expmem(struct msgq_head *qh)
01650 {
01651 register int tot = 0;
01652 register struct msgq *m;
01653
01654 for (m = qh->head; m; m = m->next) {
01655 tot += m->len + 1;
01656 tot += sizeof(struct msgq);
01657 }
01658 return tot;
01659 }
01660
01661 static int server_expmem()
01662 {
01663 int tot = 0;
01664 struct server_list *s = serverlist;
01665
01666 for (; s; s = s->next) {
01667 if (s->name)
01668 tot += strlen(s->name) + 1;
01669 if (s->pass)
01670 tot += strlen(s->pass) + 1;
01671 if (s->realname)
01672 tot += strlen(s->realname) + 1;
01673 tot += sizeof(struct server_list);
01674 }
01675
01676 if (realservername)
01677 tot += strlen(realservername) + 1;
01678 tot += msgq_expmem(&mq) + msgq_expmem(&hq) + msgq_expmem(&modeq);
01679
01680 return tot;
01681 }
01682
01683 static void server_report(int idx, int details)
01684 {
01685 char s1[64], s[128];
01686 int servidx;
01687
01688 if (server_online) {
01689 dprintf(idx, " Online as: %s%s%s (%s)\n", botname, botuserhost[0] ?
01690 "!" : "", botuserhost[0] ? botuserhost : "", botrealname);
01691 if (nick_juped)
01692 dprintf(idx, " NICK IS JUPED: %s%s\n", origbotname,
01693 keepnick ? " (trying)" : "");
01694 daysdur(now, server_online, s1);
01695 egg_snprintf(s, sizeof s, "(connected %s)", s1);
01696 if (server_lag && !lastpingcheck) {
01697 if (server_lag == -1)
01698 egg_snprintf(s1, sizeof s1, " (bad pong replies)");
01699 else
01700 egg_snprintf(s1, sizeof s1, " (lag: %ds)", server_lag);
01701 strcat(s, s1);
01702 }
01703 }
01704
01705 if ((trying_server || server_online) &&
01706 ((servidx = findanyidx(serv)) != -1)) {
01707 dprintf(idx, " Server %s:%d %s\n", dcc[servidx].host, dcc[servidx].port,
01708 trying_server ? "(trying)" : s);
01709 } else
01710 dprintf(idx, " %s\n", IRC_NOSERVER);
01711
01712 if (modeq.tot)
01713 dprintf(idx, " %s %d%% (%d msgs)\n", IRC_MODEQUEUE,
01714 (int) ((float) (modeq.tot * 100.0) / (float) maxqmsg),
01715 (int) modeq.tot);
01716 if (mq.tot)
01717 dprintf(idx, " %s %d%% (%d msgs)\n", IRC_SERVERQUEUE,
01718 (int) ((float) (mq.tot * 100.0) / (float) maxqmsg), (int) mq.tot);
01719 if (hq.tot)
01720 dprintf(idx, " %s %d%% (%d msgs)\n", IRC_HELPQUEUE,
01721 (int) ((float) (hq.tot * 100.0) / (float) maxqmsg), (int) hq.tot);
01722
01723 if (details) {
01724 int size = server_expmem();
01725
01726 if (min_servs)
01727 dprintf(idx, " Requiring a network with at least %d server%s\n",
01728 min_servs, (min_servs != 1) ? "s" : "");
01729 if (initserver[0])
01730 dprintf(idx, " On connect, I do: %s\n", initserver);
01731 if (connectserver[0])
01732 dprintf(idx, " Before connect, I do: %s\n", connectserver);
01733 dprintf(idx, " Msg flood: %d msg%s/%d second%s\n", flud_thr,
01734 (flud_thr != 1) ? "s" : "", flud_time,
01735 (flud_time != 1) ? "s" : "");
01736 dprintf(idx, " CTCP flood: %d msg%s/%d second%s\n", flud_ctcp_thr,
01737 (flud_ctcp_thr != 1) ? "s" : "", flud_ctcp_time,
01738 (flud_ctcp_time != 1) ? "s" : "");
01739 dprintf(idx, " Using %d byte%s of memory\n", size,
01740 (size != 1) ? "s" : "");
01741 }
01742 }
01743
01744 static cmd_t my_ctcps[] = {
01745 {"DCC", "", ctcp_DCC_CHAT, "server:DCC"},
01746 {NULL, NULL, NULL, NULL}
01747 };
01748
01749 static char *server_close()
01750 {
01751 cycle_time = 100;
01752 nuke_server("Connection reset by peer");
01753 clearq(serverlist);
01754 rem_builtins(H_dcc, C_dcc_serv);
01755 rem_builtins(H_raw, my_raw_binds);
01756 rem_builtins(H_ctcp, my_ctcps);
01757
01758 del_bind_table(H_wall);
01759 del_bind_table(H_raw);
01760 del_bind_table(H_notc);
01761 del_bind_table(H_msgm);
01762 del_bind_table(H_msg);
01763 del_bind_table(H_flud);
01764 del_bind_table(H_ctcr);
01765 del_bind_table(H_ctcp);
01766 del_bind_table(H_out);
01767 rem_tcl_coups(my_tcl_coups);
01768 rem_tcl_strings(my_tcl_strings);
01769 rem_tcl_ints(my_tcl_ints);
01770 rem_help_reference("server.help");
01771 rem_tcl_commands(my_tcl_cmds);
01772 Tcl_UntraceVar(interp, "nick",
01773 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01774 nick_change, NULL);
01775 Tcl_UntraceVar(interp, "altnick",
01776 TCL_TRACE_WRITES | TCL_TRACE_UNSETS, altnick_change, NULL);
01777 Tcl_UntraceVar(interp, "botname",
01778 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01779 traced_botname, NULL);
01780 Tcl_UntraceVar(interp, "server",
01781 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01782 traced_server, NULL);
01783 Tcl_UntraceVar(interp, "serveraddress",
01784 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01785 traced_serveraddress, NULL);
01786 Tcl_UntraceVar(interp, "net-type",
01787 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01788 traced_nettype, NULL);
01789 Tcl_UntraceVar(interp, "nick-len",
01790 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01791 traced_nicklen, NULL);
01792 tcl_untraceserver("servers", NULL);
01793 empty_msgq();
01794 del_hook(HOOK_SECONDLY, (Function) server_secondly);
01795 del_hook(HOOK_5MINUTELY, (Function) server_5minutely);
01796 del_hook(HOOK_QSERV, (Function) queue_server);
01797 del_hook(HOOK_MINUTELY, (Function) minutely_checks);
01798 del_hook(HOOK_PRE_REHASH, (Function) server_prerehash);
01799 del_hook(HOOK_REHASH, (Function) server_postrehash);
01800 del_hook(HOOK_DIE, (Function) server_die);
01801 module_undepend(MODULE_NAME);
01802 return NULL;
01803 }
01804
01805 EXPORT_SCOPE char *server_start();
01806
01807 static Function server_table[] = {
01808 (Function) server_start,
01809 (Function) server_close,
01810 (Function) server_expmem,
01811 (Function) server_report,
01812
01813 (Function) NULL,
01814 (Function) botuserhost,
01815 (Function) NULL,
01816 (Function) & serv,
01817
01818 (Function) & flud_thr,
01819 (Function) & flud_time,
01820 (Function) & flud_ctcp_thr,
01821 (Function) & flud_ctcp_time,
01822
01823 (Function) match_my_nick,
01824 (Function) check_tcl_flud,
01825 (Function) NULL,
01826 (Function) & answer_ctcp,
01827
01828 (Function) & trigger_on_ignore,
01829 (Function) check_tcl_ctcpr,
01830 (Function) detect_avalanche,
01831 (Function) nuke_server,
01832
01833 (Function) newserver,
01834 (Function) & newserverport,
01835 (Function) newserverpass,
01836 (Function) & cycle_time,
01837
01838 (Function) & default_port,
01839 (Function) & server_online,
01840 (Function) & min_servs,
01841 (Function) & H_raw,
01842
01843 (Function) & H_wall,
01844 (Function) & H_msg,
01845 (Function) & H_msgm,
01846 (Function) & H_notc,
01847
01848 (Function) & H_flud,
01849 (Function) & H_ctcp,
01850 (Function) & H_ctcr,
01851 (Function) ctcp_reply,
01852
01853 (Function) get_altbotnick,
01854 (Function) & nick_len,
01855 (Function) check_tcl_notc,
01856 (Function) & exclusive_binds,
01857
01858 (Function) & H_out
01859 };
01860
01861 char *server_start(Function *global_funcs)
01862 {
01863 EGG_CONST char *s;
01864
01865 global = global_funcs;
01866
01867
01868
01869
01870
01871 serv = -1;
01872 botname[0] = 0;
01873 trying_server = 0L;
01874 server_lag = 0;
01875 altnick[0] = 0;
01876 raltnick[0] = 0;
01877 curserv = 0;
01878 flud_thr = 5;
01879 flud_time = 60;
01880 flud_ctcp_thr = 3;
01881 flud_ctcp_time = 60;
01882 initserver[0] = 0;
01883 connectserver[0] = 0;
01884 botuserhost[0] = 0;
01885 keepnick = 1;
01886 check_stoned = 1;
01887 serverror_quit = 1;
01888 lastpingcheck = 0;
01889 server_online = 0;
01890 server_cycle_wait = 60;
01891 strcpy(botrealname, "A deranged product of evil coders");
01892 min_servs = 0;
01893 server_timeout = 60;
01894 never_give_up = 0;
01895 serverlist = NULL;
01896 cycle_time = 0;
01897 default_port = 6667;
01898 oldnick[0] = 0;
01899 trigger_on_ignore = 0;
01900 exclusive_binds = 0;
01901 answer_ctcp = 1;
01902 lowercase_ctcp = 0;
01903 check_mode_r = 0;
01904 maxqmsg = 300;
01905 burst = 0;
01906 net_type = NETT_EFNET;
01907 double_mode = 0;
01908 double_server = 0;
01909 double_help = 0;
01910 use_penalties = 0;
01911 use_fastdeq = 0;
01912 stackablecmds[0] = 0;
01913 strcpy(stackable2cmds, "USERHOST ISON");
01914 resolvserv = 0;
01915 lastpingtime = 0;
01916 last_time = 0;
01917 nick_len = 9;
01918 kick_method = 1;
01919 optimize_kicks = 0;
01920 stack_limit = 4;
01921 realservername = 0;
01922 msgrate = 2;
01923
01924 server_table[4] = (Function) botname;
01925 module_register(MODULE_NAME, server_table, 1, 3);
01926 if (!module_depend(MODULE_NAME, "eggdrop", 106, 7)) {
01927 module_undepend(MODULE_NAME);
01928 return "This module requires Eggdrop 1.6.7 or later.";
01929 }
01930
01931
01932 tcl_eggserver(NULL, interp, "servers", NULL, 0);
01933 tcl_traceserver("servers", NULL);
01934 s = Tcl_GetVar(interp, "nick", TCL_GLOBAL_ONLY);
01935 if (s)
01936 strncpyz(origbotname, s, NICKLEN);
01937 Tcl_TraceVar(interp, "nick",
01938 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01939 nick_change, NULL);
01940 Tcl_TraceVar(interp, "altnick",
01941 TCL_TRACE_WRITES | TCL_TRACE_UNSETS, altnick_change, NULL);
01942 Tcl_TraceVar(interp, "botname",
01943 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01944 traced_botname, NULL);
01945 Tcl_TraceVar(interp, "server",
01946 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01947 traced_server, NULL);
01948 Tcl_TraceVar(interp, "serveraddress",
01949 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01950 traced_serveraddress, NULL);
01951 Tcl_TraceVar(interp, "net-type",
01952 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01953 traced_nettype, NULL);
01954 Tcl_TraceVar(interp, "nick-len",
01955 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01956 traced_nicklen, NULL);
01957
01958 H_wall = add_bind_table("wall", HT_STACKABLE, server_2char);
01959 H_raw = add_bind_table("raw", HT_STACKABLE, server_raw);
01960 H_notc = add_bind_table("notc", HT_STACKABLE, server_5char);
01961 H_msgm = add_bind_table("msgm", HT_STACKABLE, server_msg);
01962 H_msg = add_bind_table("msg", 0, server_msg);
01963 H_flud = add_bind_table("flud", HT_STACKABLE, server_5char);
01964 H_ctcr = add_bind_table("ctcr", HT_STACKABLE, server_6char);
01965 H_ctcp = add_bind_table("ctcp", HT_STACKABLE, server_6char);
01966 H_out = add_bind_table("out", HT_STACKABLE, server_out);
01967 add_builtins(H_raw, my_raw_binds);
01968 add_builtins(H_dcc, C_dcc_serv);
01969 add_builtins(H_ctcp, my_ctcps);
01970 add_help_reference("server.help");
01971 my_tcl_strings[0].buf = botname;
01972 add_tcl_strings(my_tcl_strings);
01973 add_tcl_ints(my_tcl_ints);
01974 add_tcl_commands(my_tcl_cmds);
01975 add_tcl_coups(my_tcl_coups);
01976 add_hook(HOOK_SECONDLY, (Function) server_secondly);
01977 add_hook(HOOK_5MINUTELY, (Function) server_5minutely);
01978 add_hook(HOOK_MINUTELY, (Function) minutely_checks);
01979 add_hook(HOOK_QSERV, (Function) queue_server);
01980 add_hook(HOOK_PRE_REHASH, (Function) server_prerehash);
01981 add_hook(HOOK_REHASH, (Function) server_postrehash);
01982 add_hook(HOOK_DIE, (Function) server_die);
01983 mq.head = hq.head = modeq.head = NULL;
01984 mq.last = hq.last = modeq.last = NULL;
01985 mq.tot = hq.tot = modeq.tot = 0;
01986 mq.warned = hq.warned = modeq.warned = 0;
01987 double_warned = 0;
01988 newserver[0] = 0;
01989 newserverport = 0;
01990 curserv = 999;
01991 do_nettype();
01992 return NULL;
01993 }