/[cvs]/eggdrop1.9/src/botnet.c
ViewVC logotype

Contents of /eggdrop1.9/src/botnet.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.63 - (show annotations) (download) (as text)
Sun Sep 22 01:25:19 2002 UTC (16 years, 7 months ago) by stdarg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.62: +1 -1 lines
File MIME type: text/x-chdr
FILE REMOVED
* Remove unnecessary files (botnet stuff)

1 /*
2 * botnet.c --
3 *
4 * keeping track of which bot's connected where in the chain
5 * dumping a list of bots or a bot tree to a user
6 * rejecting a bot
7 * linking, unlinking, and relaying to another bot
8 * pinging the bots periodically and checking leaf status
9 */
10 /*
11 * Copyright (C) 1997 Robey Pointer
12 * Copyright (C) 1999, 2000, 2001, 2002 Eggheads Development Team
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 #ifndef lint
30 static const char rcsid[] = "$Id: botnet.c,v 1.62 2002/05/26 08:34:13 stdarg Exp $";
31 #endif
32
33 #include "main.h"
34 #include "tandem.h"
35 #include "modules.h"
36 #include "logfile.h"
37 #include "misc.h"
38 #include "dns.h"
39 #include "cmdt.h" /* cmd_t */
40 #include "tclhash.h" /* add_builtins2 */
41 #include "core_binds.h" /* check_bind_disc, check_bind_chpt,
42 check_bind_chof, check_bind_chon,
43 check_bind_chjn */
44 #include "users.h" /* getuser, get_user_by_handle, is_bot */
45 #include "botmsg.h" /* tandout_bot */
46 #include "botnet.h" /* bot_idle, bot_away, bot_join */
47 #include "dcc.h" /* dupwait_notify, failed_link */
48 #include "dccutil.h" /* dprintf_eggdrop, lostdcc, chatout,
49 new_dcc, changeover_dcc */
50 #include "net.h" /* tputs, killsock, getsock,
51 open_telnet_raw */
52 #include "userrec.h" /* touch_laston, correct_handle */
53 #include "botnet.h" /* prototypes */
54
55 extern char spaces[], spaces2[];
56 extern int dcc_total, backgrd, connect_timeout, max_dcc,
57 egg_numver;
58 extern struct userrec *userlist;
59 extern struct dcc_t *dcc;
60 extern time_t now;
61
62 tand_t *tandbot; /* Keep track of tandem bots on the
63 botnet */
64 party_t *party; /* Keep track of people on the botnet */
65 static int maxparty = 50; /* Maximum space for party line members
66 currently */
67 int tands = 0; /* Number of bots on the botnet */
68 int parties = 0; /* Number of people on the botnet */
69 char botnetnick[HANDLEN + 1] = ""; /* Botnet nickname */
70 int share_unlinks = 0; /* Allow remote unlinks of my
71 sharebots? */
72
73 /* From main.c */
74 extern int die_on_sigterm;
75 extern int die_on_sighup;
76
77 #ifndef MAKING_MODS
78 extern struct dcc_table DCC_CHAT, DCC_BOT, DCC_PRE_RELAY, DCC_FORK_RELAY,
79 DCC_RELAYING, DCC_DNSWAIT, DCC_FORK_BOT, DCC_BOT_NEW,
80 DCC_RELAY;
81 #endif /* MAKING_MODS */
82
83 static void botnet_sigterm(char *);
84 static void botnet_sighup(char *);
85
86 /* We want to listen to the sigterm event. */
87 static cmd_t botnet_events[] = {
88 {"botnet_sigterm", "", (Function) botnet_sigterm, NULL},
89 {"botnet_sighup", "", (Function) botnet_sighup, NULL},
90 {0}
91 };
92
93 static void init_bots();
94
95 void botnet_init()
96 {
97 init_bots();
98
99 /* Add our event handlers */
100 add_hook(HOOK_5MINUTELY, (Function) check_botnet_pings);
101 add_builtins("event", botnet_events);
102 }
103
104 /* Handle TERM signal */
105 static void botnet_sigterm(char *event)
106 {
107 if (die_on_sigterm) botnet_send_chat(-1, botnetnick, "ACK, I've been terminated! (SIGTERM)");
108 }
109
110 static void botnet_sighup(char *event)
111 {
112 if (die_on_sighup) botnet_send_chat(-1, botnetnick, "ACK, I've been terminated! (SIGHUP)");
113 }
114
115 static void init_bots()
116 {
117 tandbot = NULL;
118 /* Grab space for 50 bots for now -- expand later as needed */
119 maxparty = 50;
120 party = (party_t *) malloc(maxparty * sizeof(party_t));
121 }
122
123 tand_t *findbot(char *who)
124 {
125 tand_t *ptr;
126
127 for (ptr = tandbot; ptr; ptr = ptr->next)
128 if (!strcasecmp(ptr->bot, who))
129 return ptr;
130 return NULL;
131 }
132
133 /* Add a tandem bot to our chain list
134 */
135 void addbot(char *who, char *from, char *next, char flag, int vernum)
136 {
137 tand_t **ptr = &tandbot, *ptr2;
138
139 while (*ptr) {
140 if (!strcasecmp((*ptr)->bot, who))
141 putlog(LOG_BOTS, "*", "!!! Duplicate botnet bot entry!!");
142 ptr = &((*ptr)->next);
143 }
144 ptr2 = malloc(sizeof(tand_t));
145 strncpy(ptr2->bot, who, HANDLEN);
146 ptr2->bot[HANDLEN] = 0;
147 ptr2->share = flag;
148 ptr2->ver = vernum;
149 ptr2->next = *ptr;
150 *ptr = ptr2;
151 /* May be via itself */
152 ptr2->via = findbot(from);
153 if (!strcasecmp(next, botnetnick))
154 ptr2->uplink = (tand_t *) 1;
155 else
156 ptr2->uplink = findbot(next);
157 tands++;
158 }
159
160 void updatebot(int idx, char *who, char share, int vernum)
161 {
162 tand_t *ptr = findbot(who);
163
164 if (ptr) {
165 if (share)
166 ptr->share = share;
167 if (vernum)
168 ptr->ver = vernum;
169 botnet_send_update(idx, ptr);
170 }
171 }
172
173 /* For backward 1.0 compatibility:
174 * grab the (first) sock# for a user on another bot
175 */
176 int partysock(char *bot, char *nick)
177 {
178 int i;
179
180 for (i = 0; i < parties; i++) {
181 if ((!strcasecmp(party[i].bot, bot)) &&
182 (!strcasecmp(party[i].nick, nick)))
183 return party[i].sock;
184 }
185 return 0;
186 }
187
188 /* New botnet member
189 */
190 int addparty(char *bot, char *nick, int chan, char flag, int sock,
191 char *from, int *idx)
192 {
193 int i;
194
195 for (i = 0; i < parties; i++) {
196 /* Just changing the channel of someone already on? */
197 if (!strcasecmp(party[i].bot, bot) &&
198 (party[i].sock == sock)) {
199 int oldchan = party[i].chan;
200
201 party[i].chan = chan;
202 party[i].timer = now;
203 if (from[0]) {
204 if (flag == ' ')
205 flag = '-';
206 party[i].flag = flag;
207 if (party[i].from)
208 free(party[i].from);
209 party[i].from = strdup(from);
210 }
211 *idx = i;
212 return oldchan;
213 }
214 }
215 /* New member */
216 if (parties == maxparty) {
217 maxparty += 50;
218 party = (party_t *) realloc((void *) party, maxparty * sizeof(party_t));
219 }
220 strncpy(party[parties].nick, nick, HANDLEN);
221 party[parties].nick[HANDLEN] = 0;
222 strncpy(party[parties].bot, bot, HANDLEN);
223 party[parties].bot[HANDLEN] = 0;
224 party[parties].chan = chan;
225 party[parties].sock = sock;
226 party[parties].status = 0;
227 party[parties].away = 0;
228 party[parties].timer = now; /* cope. */
229 if (from[0]) {
230 if (flag == ' ')
231 flag = '-';
232 party[parties].flag = flag;
233 party[parties].from = strdup(from);
234 } else {
235 party[parties].flag = ' ';
236 party[parties].from = strdup("(unknown)");
237 }
238 *idx = parties;
239 parties++;
240 return -1;
241 }
242
243 /* Alter status flags for remote party-line user.
244 */
245 void partystat(char *bot, int sock, int add, int rem)
246 {
247 int i;
248
249 for (i = 0; i < parties; i++) {
250 if ((!strcasecmp(party[i].bot, bot)) &&
251 (party[i].sock == sock)) {
252 party[i].status |= add;
253 party[i].status &= ~rem;
254 }
255 }
256 }
257
258 /* Other bot is sharing idle info.
259 */
260 void partysetidle(char *bot, int sock, int secs)
261 {
262 int i;
263
264 for (i = 0; i < parties; i++) {
265 if ((!strcasecmp(party[i].bot, bot)) &&
266 (party[i].sock == sock)) {
267 party[i].timer = (now - (time_t) secs);
268 }
269 }
270 }
271
272 /* Return someone's chat channel.
273 */
274 int getparty(char *bot, int sock)
275 {
276 int i;
277
278 for (i = 0; i < parties; i++) {
279 if (!strcasecmp(party[i].bot, bot) &&
280 (party[i].sock == sock)) {
281 return i;
282 }
283 }
284 return -1;
285 }
286
287 /* Un-idle someone
288 */
289 int partyidle(char *bot, char *nick)
290 {
291 int i, ok = 0;
292
293 for (i = 0; i < parties; i++) {
294 if ((!strcasecmp(party[i].bot, bot)) &&
295 (!strcasecmp(party[i].nick, nick))) {
296 party[i].timer = now;
297 ok = 1;
298 }
299 }
300 return ok;
301 }
302
303 /* Change someone's nick
304 */
305 int partynick(char *bot, int sock, char *nick)
306 {
307 char work[HANDLEN + 1];
308 int i;
309
310 for (i = 0; i < parties; i++) {
311 if (!strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
312 strcpy(work, party[i].nick);
313 strncpy(party[i].nick, nick, HANDLEN);
314 party[i].nick[HANDLEN] = 0;
315 strcpy(nick, work);
316 return i;
317 }
318 }
319 return -1;
320 }
321
322 /* Set away message
323 */
324 void partyaway(char *bot, int sock, char *msg)
325 {
326 int i;
327
328 for (i = 0; i < parties; i++) {
329 if ((!strcasecmp(party[i].bot, bot)) &&
330 (party[i].sock == sock)) {
331 if (party[i].away)
332 free(party[i].away);
333 if (msg[0])
334 party[i].away = strdup(msg);
335 else
336 party[i].away = 0;
337 }
338 }
339 }
340
341 /* Remove a tandem bot from the chain list
342 */
343 void rembot(char *who)
344 {
345 tand_t **ptr = &tandbot, *ptr2;
346 struct userrec *u;
347
348 while (*ptr) {
349 if (!strcasecmp((*ptr)->bot, who))
350 break;
351 ptr = &((*ptr)->next);
352 }
353 if (!*ptr)
354 /* May have just .unlink *'d */
355 return;
356 check_bind_disc(who);
357
358 u = get_user_by_handle(userlist, who);
359 if (u != NULL)
360 touch_laston(u, "unlinked", now);
361
362 ptr2 = *ptr;
363 *ptr = ptr2->next;
364 free(ptr2);
365 tands--;
366
367 dupwait_notify(who);
368 }
369
370 void remparty(char *bot, int sock)
371 {
372 int i;
373
374 for (i = 0; i < parties; i++)
375 if ((!strcasecmp(party[i].bot, bot)) &&
376 (party[i].sock == sock)) {
377 parties--;
378 if (party[i].from)
379 free(party[i].from);
380 if (party[i].away)
381 free(party[i].away);
382 if (i < parties) {
383 strcpy(party[i].bot, party[parties].bot);
384 strcpy(party[i].nick, party[parties].nick);
385 party[i].chan = party[parties].chan;
386 party[i].sock = party[parties].sock;
387 party[i].flag = party[parties].flag;
388 party[i].status = party[parties].status;
389 party[i].timer = party[parties].timer;
390 party[i].from = party[parties].from;
391 party[i].away = party[parties].away;
392 }
393 }
394 }
395
396 /* Cancel every user that was on a certain bot
397 */
398 void rempartybot(char *bot)
399 {
400 int i;
401
402 for (i = 0; i < parties; i++)
403 if (!strcasecmp(party[i].bot, bot)) {
404 if (party[i].chan >= 0) {
405 check_bind_chpt(bot, party[i].nick, party[i].sock, party[i].chan);
406 }
407 remparty(bot, party[i].sock);
408 i--;
409 }
410 }
411
412 /* Remove every bot linked 'via' bot <x>
413 */
414 void unvia(int idx, tand_t * who)
415 {
416 tand_t *bot, *bot2;
417
418 if (!who)
419 return; /* Safety */
420 rempartybot(who->bot);
421 bot = tandbot;
422 while (bot) {
423 if (bot->uplink == who) {
424 unvia(idx, bot);
425 bot2 = bot->next;
426 rembot(bot->bot);
427 bot = bot2;
428 } else
429 bot = bot->next;
430 }
431 #ifndef NO_OLD_BOTNET
432 /* Every bot unvia's bots behind anyway, so why send msg's for
433 * EVERY one? - will this break things?!
434 */
435 tandout_but(idx, "unlinked %s\n", who->bot);
436 #endif
437 }
438
439 /* Return index into dcc list of the bot that connects us to bot <x>
440 */
441 int nextbot(char *who)
442 {
443 int j;
444 tand_t *bot = findbot(who);
445
446 if (!bot)
447 return -1;
448
449 for (j = 0; j < dcc_total; j++)
450 if (bot->via && !strcasecmp(bot->via->bot, dcc[j].nick) &&
451 (dcc[j].type == &DCC_BOT))
452 return j;
453 return -1; /* We're not connected to 'via' */
454 }
455
456 /* Return name of the bot that is directly connected to bot X
457 */
458 char *lastbot(char *who)
459 {
460 tand_t *bot = findbot(who);
461
462 if (!bot)
463 return "*";
464 else if (bot->uplink == (tand_t *) 1)
465 return botnetnick;
466 else
467 return bot->uplink->bot;
468 }
469
470 /* Modern version of 'whom' (use local data)
471 */
472 void answer_local_whom(int idx, int chan)
473 {
474 char c, idle[40], spaces2[33] = " ";
475 int i, len, len2, t, nicklen, botnicklen, total = 0;
476
477 if (chan == (-1))
478 dprintf(idx, "%s (+: %s, *: %s)\n", _("Users across the botnet"), _("Party line"),
479 _("Local channel"));
480 else if (chan > 0) {
481 dprintf(idx, "%s %s%d:\n", _("Users on channel"),
482 (chan < 100000) ? "" : "*", chan % 100000);
483 }
484 /* Find longest nick and botnick */
485 nicklen = botnicklen = 0;
486 for (i = 0; i < dcc_total; i++)
487 if (dcc[i].type == &DCC_CHAT) {
488 if ((chan == (-1)) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
489 t = strlen(dcc[i].nick); if(t > nicklen) nicklen = t;
490 t = strlen(botnetnick); if(t > botnicklen) botnicklen = t;
491 }
492 }
493 for (i = 0; i < parties; i++) {
494 if ((chan == (-1)) || ((chan >= 0) && (party[i].chan == chan))) {
495 t = strlen(party[i].nick); if(t > nicklen) nicklen = t;
496 t = strlen(party[i].bot); if(t > botnicklen) botnicklen = t;
497 }
498 }
499 if(nicklen < 9) nicklen = 9;
500 if(botnicklen < 9) botnicklen = 9;
501
502 spaces[nicklen - 9] = 0;
503 spaces2[botnicklen - 9] = 0;
504 dprintf(idx, " Nick %s Bot %s Host\n", spaces, spaces2);
505 dprintf(idx, "----------%s ---------%s --------------------\n",
506 spaces, spaces2);
507 spaces[nicklen - 9] = ' ';
508 spaces2[botnicklen - 9] = ' ';
509 for (i = 0; i < dcc_total; i++)
510 if (dcc[i].type == &DCC_CHAT) {
511 if ((chan == (-1)) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
512 c = geticon(dcc[i].user);
513 if (c == '-')
514 c = ' ';
515 if (now - dcc[i].timeval > 300) {
516 unsigned long days, hrs, mins;
517
518 days = (now - dcc[i].timeval) / 86400;
519 hrs = ((now - dcc[i].timeval) - (days * 86400)) / 3600;
520 mins = ((now - dcc[i].timeval) - (hrs * 3600)) / 60;
521 if (days > 0)
522 sprintf(idle, " [idle %lud%luh]", days, hrs);
523 else if (hrs > 0)
524 sprintf(idle, " [idle %luh%lum]", hrs, mins);
525 else
526 sprintf(idle, " [idle %lum]", mins);
527 } else
528 idle[0] = 0;
529 spaces[len = nicklen - strlen(dcc[i].nick)] = 0;
530 spaces2[len2 = botnicklen - strlen(botnetnick)] = 0;
531 total++;
532 dprintf(idx, "%c%s%s %c %s%s %s%s\n", c, dcc[i].nick, spaces,
533 (dcc[i].u.chat->channel == 0) && (chan == (-1)) ? '+' :
534 (dcc[i].u.chat->channel > 100000) &&
535 (chan == (-1)) ? '*' : ' ',
536 botnetnick, spaces2, dcc[i].host, idle);
537 spaces[len] = ' ';
538 spaces2[len2] = ' ';
539 if (dcc[i].u.chat->away != NULL)
540 dprintf(idx, " AWAY: %s\n", dcc[i].u.chat->away);
541 }
542 }
543 for (i = 0; i < parties; i++) {
544 if ((chan == (-1)) || ((chan >= 0) && (party[i].chan == chan))) {
545 c = party[i].flag;
546 if (c == '-')
547 c = ' ';
548 if (party[i].timer == 0L)
549 strcpy(idle, " [idle?]");
550 else if (now - party[i].timer > 300) {
551 unsigned long days, hrs, mins;
552
553 days = (now - party[i].timer) / 86400;
554 hrs = ((now - party[i].timer) - (days * 86400)) / 3600;
555 mins = ((now - party[i].timer) - (hrs * 3600)) / 60;
556 if (days > 0)
557 sprintf(idle, " [idle %lud%luh]", days, hrs);
558 else if (hrs > 0)
559 sprintf(idle, " [idle %luh%lum]", hrs, mins);
560 else
561 sprintf(idle, " [idle %lum]", mins);
562 } else
563 idle[0] = 0;
564 spaces[len = nicklen - strlen(party[i].nick)] = 0;
565 spaces2[len2 = botnicklen - strlen(party[i].bot)] = 0;
566 total++;
567 dprintf(idx, "%c%s%s %c %s%s %s%s\n", c, party[i].nick, spaces,
568 (party[i].chan == 0) && (chan == (-1)) ? '+' : ' ',
569 party[i].bot, spaces2, party[i].from, idle);
570 spaces[len] = ' ';
571 spaces2[len2] = ' ';
572 if (party[i].status & PLSTAT_AWAY)
573 dprintf(idx, " %s: %s\n", _("AWAY"),
574 party[i].away ? party[i].away : "");
575 }
576 }
577 dprintf(idx, "Total users: %d\n", total);
578 }
579
580 /* Show z a list of all bots connected
581 */
582 void tell_bots(int idx)
583 {
584 char s[512];
585 int i;
586 tand_t *bot;
587
588 if (!tands) {
589 dprintf(idx, "%s\n", _("No bots linked."));
590 return;
591 }
592 strcpy(s, botnetnick);
593 i = strlen(botnetnick);
594
595 for (bot = tandbot; bot; bot = bot->next) {
596 if (i > (500 - HANDLEN)) {
597 dprintf(idx, "Bots: %s\n", s);
598 s[0] = 0;
599 i = 0;
600 }
601 if (i) {
602 s[i++] = ',';
603 s[i++] = ' ';
604 }
605 strcpy(s + i, bot->bot);
606 i += strlen(bot->bot);
607 }
608 if (s[0])
609 dprintf(idx, "Bots: %s\n", s);
610 dprintf(idx, "(%s: %d)\n", _("total"), tands + 1);
611 }
612
613 /* Show a simpleton bot tree
614 */
615 void tell_bottree(int idx, int showver)
616 {
617 char s[161];
618 tand_t *last[20], *this, *bot, *bot2 = NULL;
619 int lev = 0, more = 1, mark[20], ok, cnt, i, imark;
620 char work[1024];
621 int tothops = 0;
622
623 if (tands == 0) {
624 dprintf(idx, "%s\n", _("No bots linked."));
625 return;
626 }
627 s[0] = 0;
628 i = 0;
629
630 for (bot = tandbot; bot; bot = bot->next)
631 if (!bot->uplink) {
632 if (i) {
633 s[i++] = ',';
634 s[i++] = ' ';
635 }
636 strcpy(s + i, bot->bot);
637 i += strlen(bot->bot);
638 }
639 if (s[0])
640 dprintf(idx, "(%s %s)\n", _("No trace info for:"), s);
641 if (showver)
642 dprintf(idx, "%s (%d.%d.%d.%d)\n", botnetnick,
643 egg_numver / 1000000,
644 egg_numver % 1000000 / 10000,
645 egg_numver % 10000 / 100,
646 egg_numver % 100);
647 else
648 dprintf(idx, "%s\n", botnetnick);
649 this = (tand_t *) 1;
650 work[0] = 0;
651 while (more) {
652 if (lev == 20) {
653 dprintf(idx, "\n%s\n", _("Tree too complex!"));
654 return;
655 }
656 cnt = 0;
657 tothops += lev;
658 for (bot = tandbot; bot; bot = bot->next)
659 if (bot->uplink == this)
660 cnt++;
661 if (cnt) {
662 imark = 0;
663 for (i = 0; i < lev; i++) {
664 if (mark[i])
665 strcpy(work + imark, " | ");
666 else
667 strcpy(work + imark, " ");
668 imark += 5;
669 }
670 if (cnt > 1)
671 strcpy(work + imark, " |-");
672 else
673 strcpy(work + imark, " `-");
674 s[0] = 0;
675 bot = tandbot;
676 while (!s[0]) {
677 if (bot->uplink == this) {
678 if (bot->ver) {
679 i = sprintf(s, "%c%s", bot->share, bot->bot);
680 if (showver)
681 sprintf(s + i, " (%d.%d.%d.%d)",
682 bot->ver / 1000000,
683 bot->ver % 1000000 / 10000,
684 bot->ver % 10000 / 100,
685 bot->ver % 100);
686 } else {
687 sprintf(s, "-%s", bot->bot);
688 }
689 } else
690 bot = bot->next;
691 }
692 dprintf(idx, "%s%s\n", work, s);
693 if (cnt > 1)
694 mark[lev] = 1;
695 else
696 mark[lev] = 0;
697 work[0] = 0;
698 last[lev] = this;
699 this = bot;
700 lev++;
701 more = 1;
702 } else {
703 while (cnt == 0) {
704 /* No subtrees from here */
705 if (lev == 0) {
706 dprintf(idx, "(( tree error ))\n");
707 return;
708 }
709 ok = 0;
710 for (bot = tandbot; bot; bot = bot->next) {
711 if (bot->uplink == last[lev - 1]) {
712 if (this == bot)
713 ok = 1;
714 else if (ok) {
715 cnt++;
716 if (cnt == 1) {
717 bot2 = bot;
718 if (bot->ver) {
719 i = sprintf(s, "%c%s", bot->share, bot->bot);
720 if (showver)
721 sprintf(s + i, " (%d.%d.%d.%d)",
722 bot->ver / 1000000,
723 bot->ver % 1000000 / 10000,
724 bot->ver % 10000 / 100,
725 bot->ver % 100);
726 } else {
727 sprintf(s, "-%s", bot->bot);
728 }
729 }
730 }
731 }
732 }
733 if (cnt) {
734 imark = 0;
735 for (i = 1; i < lev; i++) {
736 if (mark[i - 1])
737 strcpy(work + imark, " | ");
738 else
739 strcpy(work + imark, " ");
740 imark += 5;
741 }
742 more = 1;
743 if (cnt > 1)
744 dprintf(idx, "%s |-%s\n", work, s);
745 else
746 dprintf(idx, "%s `-%s\n", work, s);
747 this = bot2;
748 work[0] = 0;
749 if (cnt > 1)
750 mark[lev - 1] = 1;
751 else
752 mark[lev - 1] = 0;
753 } else {
754 /* This was the last child */
755 lev--;
756 if (lev == 0) {
757 more = 0;
758 cnt = 999;
759 } else {
760 more = 1;
761 this = last[lev];
762 }
763 }
764 }
765 }
766 }
767 /* Hop information: (9d) */
768 dprintf(idx, "Average hops: %3.1f, total bots: %d\n",
769 ((float) tothops) / ((float) tands), tands + 1);
770 }
771
772 /* Dump list of links to a new bot
773 */
774 void dump_links(int z)
775 {
776 register int i, l;
777 char x[1024];
778 tand_t *bot;
779
780 for (bot = tandbot; bot; bot = bot->next) {
781 char *p;
782
783 if (bot->uplink == (tand_t *) 1)
784 p = botnetnick;
785 else
786 p = bot->uplink->bot;
787 #ifndef NO_OLD_BOTNET
788 if (b_numver(z) < NEAT_BOTNET)
789 l = simple_sprintf(x, "nlinked %s %s %c%d\n", bot->bot,
790 p, bot->share, bot->ver);
791 else
792 #endif
793 l = simple_sprintf(x, "n %s %s %c%D\n", bot->bot, p,
794 bot->share, bot->ver);
795 tputs(dcc[z].sock, x, l);
796 }
797 if (!(bot_flags(dcc[z].user) & BOT_ISOLATE)) {
798 /* Dump party line members */
799 for (i = 0; i < dcc_total; i++) {
800 if (dcc[i].type == &DCC_CHAT) {
801 if ((dcc[i].u.chat->channel >= 0) &&
802 (dcc[i].u.chat->channel < 100000)) {
803 #ifndef NO_OLD_BOTNET
804 if (b_numver(z) < NEAT_BOTNET)
805 l = simple_sprintf(x, "join %s %s %d %c%d %s\n",
806 botnetnick, dcc[i].nick,
807 dcc[i].u.chat->channel, geticon(dcc[i].user),
808 dcc[i].sock, dcc[i].host);
809 else
810 #endif
811 l = simple_sprintf(x, "j !%s %s %D %c%D %s\n",
812 botnetnick, dcc[i].nick,
813 dcc[i].u.chat->channel, geticon(dcc[i].user),
814 dcc[i].sock, dcc[i].host);
815 tputs(dcc[z].sock, x, l);
816 #ifndef NO_OLD_BOTNET
817 if (b_numver(z) < NEAT_BOTNET) {
818 if (dcc[i].u.chat->away) {
819 l = simple_sprintf(x, "away %s %d %s\n", botnetnick,
820 dcc[i].sock, dcc[i].u.chat->away);
821 tputs(dcc[z].sock, x, l);
822 }
823 l = simple_sprintf(x, "idle %s %d %d\n", botnetnick,
824 dcc[i].sock, now - dcc[i].timeval);
825 } else
826 #endif
827 l = simple_sprintf(x, "i %s %D %D %s\n", botnetnick,
828 dcc[i].sock, now - dcc[i].timeval,
829 dcc[i].u.chat->away ? dcc[i].u.chat->away : "");
830 tputs(dcc[z].sock, x, l);
831 }
832 }
833 }
834 for (i = 0; i < parties; i++) {
835 #ifndef NO_OLD_BOTNET
836 if (b_numver(z) < NEAT_BOTNET)
837 l = simple_sprintf(x, "join %s %s %d %c%d %s\n",
838 party[i].bot, party[i].nick,
839 party[i].chan, party[i].flag,
840 party[i].sock, party[i].from);
841 else
842 #endif
843 l = simple_sprintf(x, "j %s %s %D %c%D %s\n",
844 party[i].bot, party[i].nick,
845 party[i].chan, party[i].flag,
846 party[i].sock, party[i].from);
847 tputs(dcc[z].sock, x, l);
848 if ((party[i].status & PLSTAT_AWAY) || (party[i].timer != 0)) {
849 #ifndef NO_OLD_BOTNET
850 if (b_numver(z) < NEAT_BOTNET) {
851 if (party[i].status & PLSTAT_AWAY) {
852 l = simple_sprintf(x, "away %s %d %s\n", party[i].bot,
853 party[i].sock, party[i].away);
854 tputs(dcc[z].sock, x, l);
855 }
856 l = simple_sprintf(x, "idle %s %d %d\n", party[i].bot,
857 party[i].sock, now - party[i].timer);
858 } else
859 #endif
860 l = simple_sprintf(x, "i %s %D %D %s\n", party[i].bot,
861 party[i].sock, now - party[i].timer,
862 party[i].away ? party[i].away : "");
863 tputs(dcc[z].sock, x, l);
864 }
865 }
866 }
867 }
868
869 int in_chain(char *who)
870 {
871 if (findbot(who))
872 return 1;
873 if (!strcasecmp(who, botnetnick))
874 return 1;
875 return 0;
876 }
877
878 int bots_in_subtree(tand_t *bot)
879 {
880 int nr = 1;
881 tand_t *b;
882
883 if (!bot)
884 return 0;
885 for (b = tandbot; b; b = b->next) {
886 if (b->bot && (b->uplink == bot)) {
887 nr += bots_in_subtree(b);
888 }
889 }
890 return nr;
891 }
892
893 int users_in_subtree(tand_t *bot)
894 {
895 int i, nr;
896 tand_t *b;
897
898 nr = 0;
899 if (!bot)
900 return 0;
901 for (i = 0; i < parties; i++)
902 if (!strcasecmp(party[i].bot, bot->bot))
903 nr++;
904 for (b = tandbot; b; b = b->next)
905 if (b->bot && (b->uplink == bot))
906 nr += users_in_subtree(b);
907 return nr;
908 }
909
910 /* Break link with a tandembot
911 */
912 int botunlink(int idx, char *nick, char *reason)
913 {
914 register int i;
915 int bots, users;
916 tand_t *bot;
917
918 if (nick[0] == '*')
919 dprintf(idx, "%s\n", _("Unlinking all bots..."));
920 for (i = 0; i < dcc_total; i++) {
921 if ((nick[0] == '*') || !strcasecmp(dcc[i].nick, nick)) {
922 if (dcc[i].type == &DCC_FORK_BOT) {
923 if (idx >= 0)
924 dprintf(idx, "%s: %s -> %s.\n", _("Killed link attempt to"),
925 dcc[i].nick, dcc[i].host);
926 putlog(LOG_BOTS, "*", "%s: %s -> %s:%d",
927 _("Killed link attempt to"), dcc[i].nick,
928 dcc[i].host, dcc[i].port);
929 killsock(dcc[i].sock);
930 lostdcc(i);
931 if (nick[0] != '*')
932 return 1;
933 } else if (dcc[i].type == &DCC_BOT_NEW) {
934 if (idx >= 0)
935 dprintf(idx, "%s %s.\n", _("No longer trying to link:"),
936 dcc[i].nick);
937 putlog(LOG_BOTS, "*", "%s %s @ %s:%d",
938 "Stopped trying to link", dcc[i].nick,
939 dcc[i].host, dcc[i].port);
940 killsock(dcc[i].sock);
941 lostdcc(i);
942 if (nick[0] != '*')
943 return 1;
944 } else if (dcc[i].type == &DCC_BOT) {
945 char s[1024];
946
947 if (idx >= 0)
948 dprintf(idx, "%s %s.\n", _("Breaking link with"), dcc[i].nick);
949 else if ((idx == -3) && (b_status(i) & STAT_SHARE) && !share_unlinks)
950 return -1;
951 bot = findbot(dcc[i].nick);
952 bots = bots_in_subtree(bot);
953 users = users_in_subtree(bot);
954 if (reason && reason[0]) {
955 /* FIXME PLURAL: handle this correctly with gettext */
956 simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
957 _("Unlinked from:"), dcc[i].nick, reason, bots,
958 (bots != 1) ? "s" : "", users, (users != 1) ?
959 "s" : "");
960 dprintf(i, "bye %s\n", reason);
961 } else {
962 /* FIXME PLURAL: handle this correctly with gettext */
963 simple_sprintf(s, "%s %s (lost %d bot%s and %d user%s)",
964 _("Unlinked from:"), dcc[i].nick, bots, (bots > 1) ?
965 "s" : "", users, (users != 1) ? "s" : "");
966 dprintf(i, "bye No reason\n");
967 }
968 chatout("*** %s\n", s);
969 botnet_send_unlinked(i, dcc[i].nick, s);
970 killsock(dcc[i].sock);
971 lostdcc(i);
972 if (nick[0] != '*')
973 return 1;
974 }
975 }
976 }
977 if (idx >= 0 && nick[0] != '*')
978 dprintf(idx, "%s\n", _("Not connected to that bot."));
979 if (nick[0] != '*') {
980 bot = findbot(nick);
981 if (bot) {
982 /* The internal bot list is desynched from the dcc list
983 sometimes. While we still search for the bug, provide
984 an easy way to clear out those `ghost'-bots.
985 Fabian (2000-08-02) */
986 char *ghost = "BUG!!: Found bot `%s' in internal bot list, but it\n"
987 " shouldn't have been there! Removing.\n"
988 " This is a known bug we haven't fixed yet. If this\n"
989 " bot is the newest eggdrop version available and you\n"
990 " know a *reliable* way to reproduce the bug, please\n"
991 " contact us - we need your help!\n";
992 if (idx >= 0)
993 dprintf(idx, ghost, nick);
994 else
995 putlog(LOG_MISC, "*", ghost, nick);
996 rembot(bot->bot);
997 return 1;
998 }
999 }
1000 if (nick[0] == '*') {
1001 dprintf(idx, "%s\n", _("Smooshing bot tables..."));
1002 while (tandbot)
1003 rembot(tandbot->bot);
1004 while (parties) {
1005 parties--;
1006 /* assert? */
1007 if (party[i].chan >= 0) {
1008 check_bind_chpt(party[i].bot, party[i].nick, party[i].sock,
1009 party[i].chan);
1010 }
1011 }
1012 }
1013 return 0;
1014 }
1015
1016 static void botlink_resolve_success(int);
1017 static void botlink_resolve_failure(int);
1018
1019 /* Link to another bot
1020 */
1021 int botlink(char *linker, int idx, char *nick)
1022 {
1023 struct bot_addr *bi;
1024 struct userrec *u;
1025 register int i;
1026
1027 u = get_user_by_handle(userlist, nick);
1028 if (!u || !(u->flags & USER_BOT)) {
1029 if (idx >= 0)
1030 dprintf(idx, _("%s is not a known bot.\n"), nick);
1031 } else if (!strcasecmp(nick, botnetnick)) {
1032 if (idx >= 0)
1033 dprintf(idx, _("Link to myself? Oh boy, Freud would have a field day.\n"));
1034 } else if (in_chain(nick) && (idx != -3)) {
1035 if (idx >= 0)
1036 dprintf(idx, _("That bot is already connected up.\n"));
1037 } else {
1038 for (i = 0; i < dcc_total; i++)
1039 if ((dcc[i].user == u) &&
1040 ((dcc[i].type == &DCC_FORK_BOT) ||
1041 (dcc[i].type == &DCC_BOT_NEW))) {
1042 if (idx >= 0)
1043 dprintf(idx, _("Already linking to that bot.\n"));
1044 return 0;
1045 }
1046 /* Address to connect to is in 'info' */
1047 bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
1048 if (!bi || !strlen(bi->address) || !bi->telnet_port || (bi->telnet_port <= 0)) {
1049 if (idx >= 0) {
1050 dprintf(idx, _("Invalid telnet address:port stored for '%s'.\n"), nick);
1051 dprintf(idx, _("Use: .chaddr %s <address>:<port#>[/<relay-port#>]\n"),
1052 nick);
1053 }
1054 } else if (dcc_total == max_dcc) {
1055 if (idx >= 0)
1056 dprintf(idx, _("Sorry, too many DCC connections.\n"));
1057 } else {
1058 correct_handle(nick);
1059
1060 if (idx > -2)
1061 putlog(LOG_BOTS, "*", _("Linking to %s at %s:%d ..."), nick,
1062 bi->address, bi->telnet_port);
1063
1064 i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
1065 dcc[i].timeval = now;
1066 dcc[i].port = bi->telnet_port;
1067 dcc[i].user = u;
1068 strcpy(dcc[i].nick, nick);
1069 strcpy(dcc[i].host, bi->address);
1070 dcc[i].u.dns->ibuf = idx;
1071 dcc[i].u.dns->cptr = strdup(linker);
1072 dcc[i].u.dns->host = strdup(dcc[i].host);
1073 dcc[i].u.dns->dns_success = botlink_resolve_success;
1074 dcc[i].u.dns->dns_failure = botlink_resolve_failure;
1075 dcc[i].u.dns->dns_type = RES_IPBYHOST;
1076 dcc[i].u.dns->type = &DCC_FORK_BOT;
1077 dcc_dnsipbyhost(bi->address);
1078 return 1;
1079 }
1080 }
1081 return 0;
1082 }
1083
1084 static void botlink_resolve_failure(int i)
1085 {
1086 char s[81];
1087
1088 putlog(LOG_BOTS, "*", _("Failed link to %s."), dcc[i].nick);
1089 strcpy(s, dcc[i].nick);
1090 free(dcc[i].u.dns->cptr);
1091 lostdcc(i);
1092 autolink_cycle(s); /* Check for more auto-connections */
1093 }
1094
1095 static void botlink_resolve_success(int i)
1096 {
1097 int idx = dcc[i].u.dns->ibuf;
1098 char *linker = dcc[i].u.dns->cptr;
1099
1100 strcpy(dcc[i].addr, dcc[i].u.dns->host);
1101 changeover_dcc(i, &DCC_FORK_BOT, sizeof(struct bot_info));
1102 dcc[i].timeval = now;
1103 strcpy(dcc[i].u.bot->linker, linker);
1104 strcpy(dcc[i].u.bot->version, "(primitive bot)");
1105 dcc[i].u.bot->numver = idx;
1106 dcc[i].u.bot->port = dcc[i].port; /* Remember where i started */
1107 dcc[i].sock = getsock(SOCK_STRONGCONN);
1108 free(linker);
1109 if (dcc[i].sock < 0 ||
1110 open_telnet_raw(dcc[i].sock, dcc[i].addr,
1111 dcc[i].port) < 0)
1112 failed_link(i);
1113 }
1114
1115 static void failed_tandem_relay(int idx)
1116 {
1117 int uidx = (-1), i;
1118
1119 for (i = 0; i < dcc_total; i++)
1120 if ((dcc[i].type == &DCC_PRE_RELAY) &&
1121 (dcc[i].u.relay->sock == dcc[idx].sock))
1122 uidx = i;
1123 if (uidx < 0) {
1124 putlog(LOG_MISC, "*", "%s %d -> %d", _("Cant find user for relay!"),
1125 dcc[idx].sock, dcc[idx].u.relay->sock);
1126 killsock(dcc[idx].sock);
1127 lostdcc(idx);
1128 return;
1129 }
1130 if (dcc[idx].port >= dcc[idx].u.relay->port + 3) {
1131 struct chat_info *ci = dcc[uidx].u.relay->chat;
1132
1133 dprintf(uidx, "%s %s.\n", _("Could not link to"), dcc[idx].nick);
1134 dcc[uidx].status = dcc[uidx].u.relay->old_status;
1135 free(dcc[uidx].u.relay);
1136 dcc[uidx].u.chat = ci;
1137 dcc[uidx].type = &DCC_CHAT;
1138 killsock(dcc[idx].sock);
1139 lostdcc(idx);
1140 return;
1141 }
1142 killsock(dcc[idx].sock);
1143 dcc[idx].sock = getsock(SOCK_STRONGCONN);
1144 dcc[uidx].u.relay->sock = dcc[idx].sock;
1145 dcc[idx].port++;
1146 dcc[idx].timeval = now;
1147 if (dcc[idx].sock < 0 ||
1148 open_telnet_raw(dcc[idx].sock, dcc[idx].addr[0] ?
1149 dcc[idx].addr :
1150 dcc[idx].host, dcc[idx].port) < 0)
1151 failed_tandem_relay(idx);
1152 }
1153
1154
1155 static void tandem_relay_resolve_failure(int);
1156 static void tandem_relay_resolve_success(int);
1157
1158 /* Relay to another tandembot
1159 */
1160 void tandem_relay(int idx, char *nick, register int i)
1161 {
1162 struct userrec *u;
1163 struct bot_addr *bi;
1164 struct chat_info *ci;
1165
1166 u = get_user_by_handle(userlist, nick);
1167 if (!u || !(u->flags & USER_BOT)) {
1168 dprintf(idx, "%s %s\n", nick, _("is not a known bot."));
1169 return;
1170 }
1171 if (!strcasecmp(nick, botnetnick)) {
1172 dprintf(idx, "%s\n", _("Relay to myself? What on EARTH would be the point?!"));
1173 return;
1174 }
1175 /* Address to connect to is in 'info' */
1176 bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
1177 if (!bi || !strlen(bi->address) || !bi->relay_port || (bi->relay_port <= 0)) {
1178 dprintf(idx, _("Invalid telnet address:port stored for '%s'.\n"), nick);
1179 dprintf(idx, _("Use: .chaddr %s <address>:<port#>[/<relay-port#>]\n"),
1180 nick);
1181
1182 return;
1183 }
1184 i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
1185 if (i < 0) {
1186 dprintf(idx, _("Sorry, too many DCC connections.\n"));
1187 return;
1188 }
1189
1190 dcc[i].sock = getsock(SOCK_STRONGCONN | SOCK_VIRTUAL);
1191 if (dcc[i].sock < 0) {
1192 lostdcc(i);
1193 dprintf(idx, _("No free sockets available.\n"));
1194 return;
1195 }
1196
1197 dcc[i].port = bi->relay_port;
1198 dcc[i].addr[0] = '\0';
1199 strcpy(dcc[i].nick, nick);
1200 dcc[i].user = u;
1201 strcpy(dcc[i].host, bi->address);
1202 dprintf(idx, "Connecting to %s @ %s:%d ...\n", nick,
1203 bi->address, bi->relay_port);
1204 dprintf(idx, _("(Type *BYE* on a line by itself to abort.)\n"));
1205 dcc[idx].type = &DCC_PRE_RELAY;
1206 ci = dcc[idx].u.chat;
1207 dcc[idx].u.relay = calloc(1, sizeof(struct relay_info));
1208 dcc[idx].u.relay->chat = ci;
1209 dcc[idx].u.relay->old_status = dcc[idx].status;
1210 dcc[idx].u.relay->sock = dcc[i].sock;
1211 dcc[i].timeval = now;
1212 dcc[i].u.dns->ibuf = dcc[idx].sock;
1213 dcc[i].u.dns->host = strdup(bi->address);
1214 dcc[i].u.dns->dns_success = tandem_relay_resolve_success;
1215 dcc[i].u.dns->dns_failure = tandem_relay_resolve_failure;
1216 dcc[i].u.dns->dns_type = RES_IPBYHOST;
1217 dcc[i].u.dns->type = &DCC_FORK_RELAY;
1218 dcc_dnsipbyhost(bi->address);
1219 }
1220
1221 static void tandem_relay_resolve_failure(int idx)
1222 {
1223 struct chat_info *ci;
1224 register int uidx = (-1), i;
1225
1226 for (i = 0; i < dcc_total; i++)
1227 if ((dcc[i].type == &DCC_PRE_RELAY) &&
1228 (dcc[i].u.relay->sock == dcc[idx].sock)) {
1229 uidx = i;
1230 break;
1231 }
1232 if (uidx < 0) {
1233 putlog(LOG_MISC, "*", _("Cant find user for relay! %d -> %d"),
1234 dcc[idx].sock, dcc[idx].u.relay->sock);
1235 killsock(dcc[idx].sock);
1236 lostdcc(idx);
1237 return;
1238 }
1239 ci = dcc[uidx].u.relay->chat;
1240 dprintf(uidx, _("Could not link to %s.\n"), dcc[idx].nick);
1241 dcc[uidx].status = dcc[uidx].u.relay->old_status;
1242 free(dcc[uidx].u.relay);
1243 dcc[uidx].u.chat = ci;
1244 dcc[uidx].type = &DCC_CHAT;
1245 killsock(dcc[idx].sock);
1246 lostdcc(idx);
1247 }
1248
1249 static void tandem_relay_resolve_success(int i)
1250 {
1251 int sock = dcc[i].u.dns->ibuf;
1252
1253 strcpy(dcc[i].addr, dcc[i].u.dns->host);
1254 changeover_dcc(i, &DCC_FORK_RELAY, sizeof(struct relay_info));
1255 dcc[i].u.relay->chat = calloc(1, sizeof(struct chat_info));
1256
1257 dcc[i].u.relay->sock = sock;
1258 dcc[i].u.relay->port = dcc[i].port;
1259 dcc[i].u.relay->chat->away = NULL;
1260 dcc[i].u.relay->chat->msgs_per_sec = 0;
1261 dcc[i].u.relay->chat->con_flags = 0;
1262 dcc[i].u.relay->chat->buffer = NULL;
1263 dcc[i].u.relay->chat->max_line = 0;
1264 dcc[i].u.relay->chat->line_count = 0;
1265 dcc[i].u.relay->chat->current_lines = 0;
1266 dcc[i].timeval = now;
1267 if (open_telnet_raw(dcc[i].sock, dcc[i].addr,
1268 dcc[i].port) < 0)
1269 failed_tandem_relay(i);
1270 }
1271
1272 /* Input from user before connect is ready
1273 */
1274 static void pre_relay(int idx, char *buf, register int i)
1275 {
1276 register int tidx = (-1);
1277
1278 for (i = 0; i < dcc_total; i++)
1279 if ((dcc[i].type == &DCC_FORK_RELAY) &&
1280 (dcc[i].u.relay->sock == dcc[idx].sock)) {
1281 tidx = i;
1282 break;
1283 }
1284 if (tidx < 0) {
1285 /* Now try to find it among the DNSWAIT sockets instead. */
1286 for (i = 0; i < dcc_total; i++)
1287 if ((dcc[i].type == &DCC_DNSWAIT) &&
1288 (dcc[i].sock == dcc[idx].u.relay->sock)) {
1289 tidx = i;
1290 break;
1291 }
1292 }
1293 if (tidx < 0) {
1294 putlog(LOG_MISC, "*", _("Cant find user for relay! %d -> %d"),
1295 dcc[idx].sock, dcc[idx].u.relay->sock);
1296 killsock(dcc[idx].sock);
1297 lostdcc(idx);
1298 return;
1299 }
1300 if (!strcasecmp(buf, "*bye*")) {
1301 /* Disconnect */
1302 struct chat_info *ci = dcc[idx].u.relay->chat;
1303
1304 dprintf(idx, _("Aborting relay attempt to %s.\n"), dcc[tidx].nick);
1305 dprintf(idx, _("You are now back on %s.\n\n"), botnetnick);
1306 putlog(LOG_MISC, "*", _("Relay aborted: %s -> %s"), dcc[idx].nick,
1307 dcc[tidx].nick);
1308 dcc[idx].status = dcc[idx].u.relay->old_status;
1309 free(dcc[idx].u.relay);
1310 dcc[idx].u.chat = ci;
1311 dcc[idx].type = &DCC_CHAT;
1312 killsock(dcc[tidx].sock);
1313 lostdcc(tidx);
1314 return;
1315 }
1316 }
1317
1318 /* User disconnected before her relay had finished connecting
1319 */
1320 static void failed_pre_relay(int idx)
1321 {
1322 register int tidx = (-1), i;
1323
1324 for (i = 0; i < dcc_total; i++)
1325 if ((dcc[i].type == &DCC_FORK_RELAY) &&
1326 (dcc[i].u.relay->sock == dcc[idx].sock)) {
1327 tidx = i;
1328 break;
1329 }
1330 if (tidx < 0) {
1331 /* Now try to find it among the DNSWAIT sockets instead. */
1332 for (i = 0; i < dcc_total; i++)
1333 if ((dcc[i].type == &DCC_DNSWAIT) &&
1334 (dcc[i].sock == dcc[idx].u.relay->sock)) {
1335 tidx = i;
1336 break;
1337 }
1338 }
1339 if (tidx < 0) {
1340 putlog(LOG_MISC, "*", _("Cant find user for relay! %d -> %d"),
1341 dcc[idx].sock, dcc[idx].u.relay->sock);
1342 killsock(dcc[idx].sock);
1343 lostdcc(idx);
1344 return;
1345 }
1346 putlog(LOG_MISC, "*", _("Lost dcc connection to [%s]%s/%d"), dcc[idx].nick,
1347 dcc[idx].host, dcc[idx].port);
1348 putlog(LOG_MISC, "*", _("(Dropping relay attempt to %s)"), dcc[tidx].nick);
1349 if ((dcc[tidx].sock != STDOUT) || backgrd) {
1350 if (idx > tidx) {
1351 int t = tidx;
1352
1353 tidx = idx;
1354 idx = t;
1355 }
1356 killsock(dcc[tidx].sock);
1357 lostdcc(tidx);
1358 } else {
1359 fatal("Lost my terminal?!", 0);
1360 }
1361 killsock(dcc[idx].sock);
1362 lostdcc(idx);
1363 }
1364
1365 static void cont_tandem_relay(int idx, char *buf, register int i)
1366 {
1367 register int uidx = (-1);
1368 struct relay_info *ri;
1369
1370 for (i = 0; i < dcc_total; i++)
1371 if ((dcc[i].type == &DCC_PRE_RELAY) &&
1372 (dcc[i].u.relay->sock == dcc[idx].sock))
1373 uidx = i;
1374 if (uidx < 0) {
1375 putlog(LOG_MISC, "*", "%s %d -> %d", _("Cant find user for relay!"),
1376 dcc[i].sock, dcc[i].u.relay->sock);
1377 killsock(dcc[i].sock);
1378 lostdcc(i);
1379 return;
1380 }
1381 dcc[idx].type = &DCC_RELAY;
1382 dcc[idx].u.relay->sock = dcc[uidx].sock;
1383 dcc[uidx].u.relay->sock = dcc[idx].sock;
1384 dprintf(uidx, "%s %s ...\n", _("Success!\n\nNOW CONNECTED TO RELAY BOT"), dcc[idx].nick);
1385 dprintf(uidx, "%s\n\n", _("(You can type *BYE* to prematurely close the connection.)"));
1386 putlog(LOG_MISC, "*", "%s %s -> %s", _("Relay link:"),
1387 dcc[uidx].nick, dcc[idx].nick);
1388 ri = dcc[uidx].u.relay; /* YEAH */
1389 dcc[uidx].type = &DCC_CHAT;
1390 dcc[uidx].u.chat = ri->chat;
1391 if (dcc[uidx].u.chat->channel >= 0) {
1392 chanout_but(-1, dcc[uidx].u.chat->channel, "*** %s %s\n",
1393 dcc[uidx].nick, _("left the party line."));
1394 if (dcc[uidx].u.chat->channel < 100000)
1395 botnet_send_part_idx(uidx, NULL);
1396 check_bind_chpt(botnetnick, dcc[uidx].nick, dcc[uidx].sock,
1397 dcc[uidx].u.chat->channel);
1398 }
1399 check_bind_chof(dcc[uidx].nick, uidx);
1400 dcc[uidx].type = &DCC_RELAYING;
1401 dcc[uidx].u.relay = ri;
1402 }
1403
1404 static void eof_dcc_relay(int idx)
1405 {
1406 register int j;
1407 struct chat_info *ci;
1408
1409 for (j = 0; j < dcc_total; j++)
1410 if (dcc[j].sock == dcc[idx].u.relay->sock)
1411 break;
1412 if (j == dcc_total) {
1413 killsock(dcc[idx].sock);
1414 lostdcc(idx);
1415 return;
1416 }
1417 dcc[j].status = dcc[j].u.relay->old_status;
1418 /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
1419 if (dcc[j].status & STAT_TELNET)
1420 dprintf(j, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
1421 putlog(LOG_MISC, "*", "%s: %s -> %s", _("Ended relay link"), dcc[j].nick,
1422 dcc[idx].nick);
1423 dprintf(j, "\n\n*** %s %s\n", _("RELAY CONNECTION DROPPED.\nYou are now back on"), botnetnick);
1424 ci = dcc[j].u.relay->chat;
1425 free(dcc[j].u.relay);
1426 dcc[j].u.chat = ci;
1427 dcc[j].type = &DCC_CHAT;
1428 if (dcc[j].u.chat->channel >= 0) {
1429 chanout_but(-1, dcc[j].u.chat->channel, "*** %s %s.\n",
1430 dcc[j].nick, _("rejoined the party line."));
1431 if (dcc[j].u.chat->channel < 100000)
1432 botnet_send_join_idx(j, -1);
1433 }
1434 check_bind_chon(dcc[j].nick, j);
1435 check_bind_chjn(botnetnick, dcc[j].nick, dcc[j].u.chat->channel,
1436 geticon(dcc[j].user), dcc[j].sock, dcc[j].host);
1437 killsock(dcc[idx].sock);
1438 lostdcc(idx);
1439 }
1440
1441 static void eof_dcc_relaying(int idx)
1442 {
1443 register int j, x = dcc[idx].u.relay->sock;
1444
1445 putlog(LOG_MISC, "*", "%s [%s]%s/%d", _("Lost dcc connection to"), dcc[idx].nick,
1446 dcc[idx].host, dcc[idx].port);
1447 killsock(dcc[idx].sock);
1448 lostdcc(idx);
1449 for (j = 0; (dcc[j].sock != x) || (dcc[j].type == &DCC_FORK_RELAY); j++);
1450 putlog(LOG_MISC, "*", "(%s %s)", _("Dropping relay link to"), dcc[j].nick);
1451 killsock(dcc[j].sock);
1452 lostdcc(j); /* Drop connection to the bot */
1453 }
1454
1455 static void dcc_relay(int idx, char *buf, int j)
1456 {
1457 unsigned char *p = (unsigned char *) buf;
1458 int mark;
1459
1460 for (j = 0; dcc[j].sock != dcc[idx].u.relay->sock ||
1461 dcc[j].type != &DCC_RELAYING; j++);
1462 /* If redirecting to a non-telnet user, swallow telnet codes and
1463 escape sequences. */
1464 if (!(dcc[j].status & STAT_TELNET)) {
1465 while (*p != 0) {
1466 while (*p != 255 && (*p != '\033' || *(p + 1) != '[') && *p != '\r' && *p)
1467 p++; /* Search for IAC, escape sequences and CR. */
1468 if (*p == 255) {
1469 mark = 2;
1470 if (!*(p + 1))
1471 mark = 1; /* Bogus */
1472 if ((*(p + 1) >= 251) || (*(p + 1) <= 254)) {
1473 mark = 3;
1474 if (!*(p + 2))
1475 mark = 2; /* Bogus */
1476 }
1477 strcpy((char *) p, (char *) (p + mark));
1478 } else if (*p == '\033') {
1479 unsigned char *e;
1480
1481 /* Search for the end of the escape sequence. */
1482 for (e = p + 2; *e != 'm' && *e; e++)
1483 ;
1484 strcpy((char *) p, (char *) (e + 1));
1485 } else if (*p == '\r')
1486 strcpy((char *) p, (char *) (p + 1));
1487 }
1488 if (!buf[0])
1489 dprintf(-dcc[idx].u.relay->sock, " \n");
1490 else
1491 dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
1492 return;
1493 }
1494 /* Telnet user */
1495 if (!buf[0])
1496 dprintf(-dcc[idx].u.relay->sock, " \r\n");
1497 else
1498 dprintf(-dcc[idx].u.relay->sock, "%s\r\n", buf);
1499 }
1500
1501 static void dcc_relaying(int idx, char *buf, int j)
1502 {
1503 struct chat_info *ci;
1504
1505 if (strcasecmp(buf, "*bye*")) {
1506 dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
1507 return;
1508 }
1509 for (j = 0; (dcc[j].sock != dcc[idx].u.relay->sock) ||
1510 (dcc[j].type != &DCC_RELAY); j++);
1511 dcc[idx].status = dcc[idx].u.relay->old_status;
1512 /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
1513 if (dcc[idx].status & STAT_TELNET)
1514 dprintf(idx, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
1515 dprintf(idx, "\n(%s %s.)\n", _("Breaking connection to"), dcc[j].nick);
1516 dprintf(idx, "%s %s.\n\n", _("You are now back on"), botnetnick);
1517 putlog(LOG_MISC, "*", "%s: %s -> %s", _("Relay broken"),
1518 dcc[idx].nick, dcc[j].nick);
1519 if (dcc[idx].u.relay->chat->channel >= 0) {
1520 chanout_but(-1, dcc[idx].u.relay->chat->channel,
1521 "*** %s joined the party line.\n", dcc[idx].nick);
1522 if (dcc[idx].u.relay->chat->channel < 100000)
1523 botnet_send_join_idx(idx, -1);
1524 }
1525 ci = dcc[idx].u.relay->chat;
1526 free(dcc[idx].u.relay);
1527 dcc[idx].u.chat = ci;
1528 dcc[idx].type = &DCC_CHAT;
1529 check_bind_chon(dcc[idx].nick, idx);
1530 if (dcc[idx].u.chat->channel >= 0) {
1531 check_bind_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
1532 geticon(dcc[idx].user), dcc[idx].sock, dcc[idx].host);
1533 }
1534 killsock(dcc[j].sock);
1535 lostdcc(j);
1536 }
1537
1538 static void display_relay(int i, char *other)
1539 {
1540 sprintf(other, "rela -> sock %d", dcc[i].u.relay->sock);
1541 }
1542
1543 static void display_relaying(int i, char *other)
1544 {
1545 sprintf(other, ">rly -> sock %d", dcc[i].u.relay->sock);
1546 }
1547
1548 static void display_tandem_relay(int i, char *other)
1549 {
1550 strcpy(other, "other rela");
1551 }
1552
1553 static void display_pre_relay(int i, char *other)
1554 {
1555 strcpy(other, "other >rly");
1556 }
1557
1558 static void kill_relay(int idx, void *x)
1559 {
1560 register struct relay_info *p = (struct relay_info *) x;
1561
1562 if (p->chat)
1563 DCC_CHAT.kill(idx, p->chat);
1564 free(p);
1565 }
1566
1567 struct dcc_table DCC_RELAY =
1568 {
1569 "RELAY",
1570 0, /* Flags */
1571 eof_dcc_relay,
1572 dcc_relay,
1573 NULL,
1574 NULL,
1575 display_relay,
1576 kill_relay,
1577 NULL
1578 };
1579
1580 static void out_relay(int idx, char *buf, void *x)
1581 {
1582 register struct relay_info *p = (struct relay_info *) x;
1583
1584 if (p && p->chat)
1585 DCC_CHAT.output(idx, buf, p->chat);
1586 else
1587 tputs(dcc[idx].sock, buf, strlen(buf));
1588 }
1589
1590 struct dcc_table DCC_RELAYING =
1591 {
1592 "RELAYING",
1593 0, /* Flags */
1594 eof_dcc_relaying,
1595 dcc_relaying,
1596 NULL,
1597 NULL,
1598 display_relaying,
1599 kill_relay,
1600 out_relay
1601 };
1602
1603 struct dcc_table DCC_FORK_RELAY =
1604 {
1605 "FORK_RELAY",
1606 0, /* Flags */
1607 failed_tandem_relay,
1608 cont_tandem_relay,
1609 &connect_timeout,
1610 failed_tandem_relay,
1611 display_tandem_relay,
1612 kill_relay,
1613 NULL
1614 };
1615
1616 struct dcc_table DCC_PRE_RELAY =
1617 {
1618 "PRE_RELAY",
1619 0, /* Flags */
1620 failed_pre_relay,
1621 pre_relay,
1622 NULL,
1623 NULL,
1624 display_pre_relay,
1625 kill_relay,
1626 NULL
1627 };
1628
1629 /* Once a minute, send 'ping' to each bot -- no exceptions
1630 */
1631 void check_botnet_pings()
1632 {
1633 int i;
1634 int bots, users;
1635 tand_t *bot;
1636
1637 for (i = 0; i < dcc_total; i++)
1638 if (dcc[i].type == &DCC_BOT)
1639 if (dcc[i].status & STAT_PINGED) {
1640 char s[1024];
1641
1642 putlog(LOG_BOTS, "*", "%s: %s", _("Ping timeout"), dcc[i].nick);
1643 bot = findbot(dcc[i].nick);
1644 bots = bots_in_subtree(bot);
1645 users = users_in_subtree(bot);
1646 simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)", _("Ping timeout"),
1647 dcc[i].nick, bots, (bots != 1) ? "s" : "",
1648 users, (users != 1) ? "s" : "");
1649 chatout("*** %s\n", s);
1650 botnet_send_unlinked(i, dcc[i].nick, s);
1651 killsock(dcc[i].sock);
1652 lostdcc(i);
1653 }
1654 for (i = 0; i < dcc_total; i++)
1655 if (dcc[i].type == &DCC_BOT) {
1656 botnet_send_ping(i);
1657 dcc[i].status |= STAT_PINGED;
1658 }
1659 for (i = 0; i < dcc_total; i++)
1660 if ((dcc[i].type == &DCC_BOT) && (dcc[i].status & STAT_LEAF)) {
1661 tand_t *bot, *via = findbot(dcc[i].nick);
1662
1663 for (bot = tandbot; bot; bot = bot->next) {
1664 if ((via == bot->via) && (bot != via)) {
1665 /* Not leaflike behavior */
1666 if (dcc[i].status & STAT_WARNED) {
1667 char s[1024];
1668
1669 putlog(LOG_BOTS, "*", "%s %s (%s).", _("Disconnected from:"),
1670 dcc[i].nick, _("unleaflike behavior"));
1671 dprintf(i, "bye %s\n", _("unleaflike behavior"));
1672 bot = findbot(dcc[i].nick);
1673 bots = bots_in_subtree(bot);
1674 users = users_in_subtree(bot);
1675 simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
1676 _("Disconnected from:"), dcc[i].nick, _("unleaflike behavior"),
1677 bots, (bots != 1) ? "s" : "", users, (users != 1) ?
1678 "s" : "");
1679 chatout("*** %s\n", s);
1680 botnet_send_unlinked(i, dcc[i].nick, s);
1681 killsock(dcc[i].sock);
1682 lostdcc(i);
1683 } else {
1684 botnet_send_reject(i, botnetnick, NULL, bot->bot,
1685 NULL, NULL);
1686 dcc[i].status |= STAT_WARNED;
1687 }
1688 } else
1689 dcc[i].status &= ~STAT_WARNED;
1690 }
1691 }
1692 }
1693
1694 void zapfbot(int idx)
1695 {
1696 char s[1024];
1697 int bots, users;
1698 tand_t *bot;
1699
1700 bot = findbot(dcc[idx].nick);
1701 bots = bots_in_subtree(bot);
1702 users = users_in_subtree(bot);
1703 simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)", _("Dropped bot"),
1704 dcc[idx].nick, bots, (bots != 1) ? "s" : "", users,
1705 (users != 1) ? "s" : "");
1706 chatout("*** %s\n", s);
1707 botnet_send_unlinked(idx, dcc[idx].nick, s);
1708 killsock(dcc[idx].sock);
1709 lostdcc(idx);
1710 }
1711
1712 void restart_chons()
1713 {
1714 int i;
1715
1716 /* Dump party line members */
1717 for (i = 0; i < dcc_total; i++) {
1718 if (dcc[i].type == &DCC_CHAT) {
1719 check_bind_chon(dcc[i].nick, i);
1720 check_bind_chjn(botnetnick, dcc[i].nick, dcc[i].u.chat->channel,
1721 geticon(dcc[i].user), dcc[i].sock, dcc[i].host);
1722 }
1723 }
1724 for (i = 0; i < parties; i++) {
1725 check_bind_chjn(party[i].bot, party[i].nick, party[i].chan,
1726 party[i].flag, party[i].sock, party[i].from);
1727 }
1728 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23