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

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

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


Revision 1.4.2.1 - (show annotations) (download) (as text)
Wed Nov 10 13:39:19 2010 UTC (8 years, 8 months ago) by pseudo
Branch: gettext
Changes since 1.4: +97 -110 lines
File MIME type: text/x-chdr
Converted remaining lang #defines in the core to english strings from core.english.lang. Gettextified most of the hardcoded strings.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23