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

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

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


Revision 1.2 - (show annotations) (download) (as text)
Tue Oct 19 12:13:32 2010 UTC (8 years, 8 months ago) by pseudo
Branch: MAIN
Branch point for: gettext
Changes since 1.1: +41 -1 lines
File MIME type: text/x-chdr
Added full SSL support including Tcl commands.
Added support for certificate authentication.
Added support for botnet and partyline encryption using ssl.
Documented the new features and commands.
Fixed add_server() problems with IPv6 addresses in the server list.

1 /*
2 * botcmd.c -- handles:
3 * commands that comes across the botnet
4 * userfile transfer and update commands from sharebots
5 *
6 * $Id: botcmd.c,v 1.1.1.1 2010/07/26 21:11:06 simple Exp $
7 */
8 /*
9 * Copyright (C) 1997 Robey Pointer
10 * Copyright (C) 1999 - 2010 Eggheads Development Team
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #include "main.h"
28 #include "tandem.h"
29 #include "users.h"
30 #include "chan.h"
31 #include "modules.h"
32
33 extern char botnetnick[], ver[], admin[], network[], motdfile[];
34 extern int dcc_total, remote_boots, noshare;
35 #ifdef TLS
36 extern int tls_vfybots;
37 extern int tls_vfyclients;
38 extern SSL_CTX *ssl_ctx;
39 #endif
40 extern struct dcc_t *dcc;
41 extern struct chanset_t *chanset;
42 extern struct userrec *userlist;
43 extern Tcl_Interp *interp;
44 extern time_t now, online_since;
45 extern party_t *party;
46 extern module_entry *module_list;
47
48 static char TBUF[1024]; /* Static buffer for goofy bot stuff */
49
50 static char base64to[256] = {
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0,
54 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
55 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 62, 0, 63, 0, 0, 0, 26, 27, 28,
56 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
57 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
64 };
65
66
67 int base64_to_int(char *buf)
68 {
69 int i = 0;
70
71 while (*buf) {
72 i = i << 6;
73 i += base64to[(int) *buf];
74 buf++;
75 }
76 return i;
77 }
78
79 /* Used for 1.0 compatibility: if a join message arrives with no sock#,
80 * i'll just grab the next "fakesock" # (incrementing to assure uniqueness)
81 */
82 static int fakesock = 2300;
83
84 static void fake_alert(int idx, char *item, char *extra)
85 {
86 static unsigned long lastfake; /* The last time fake_alert was used */
87
88 if (now - lastfake > 10) {
89 #ifndef NO_OLD_BOTNET
90 if (b_numver(idx) < NEAT_BOTNET)
91 dprintf(idx, "chat %s NOTICE: %s (%s != %s).\n",
92 botnetnick, NET_FAKEREJECT, item, extra);
93 else
94 #endif
95 dprintf(idx, "ct %s NOTICE: %s (%s != %s).\n",
96 botnetnick, NET_FAKEREJECT, item, extra);
97 putlog(LOG_BOTS, "*", "%s %s (%s != %s).", dcc[idx].nick, NET_FAKEREJECT,
98 item, extra);
99 lastfake = now;
100 }
101 }
102
103 /* chan <from> <chan> <text>
104 */
105 static void bot_chan2(int idx, char *msg)
106 {
107 char *from, *p, *s;
108 int i, chan;
109
110 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
111 return;
112 from = newsplit(&msg);
113 p = newsplit(&msg);
114 #ifndef NO_OLD_BOTNET
115 if (b_numver(idx) < NEAT_BOTNET)
116 chan = atoi(p);
117 else
118 #endif
119 chan = base64_to_int(p);
120 /* Strip annoying control chars */
121 for (p = s = from; *s; s++)
122 if ((*s > 31) && (*s != 127))
123 *p++ = *s;
124 if (*p)
125 *p = 0;
126 p = strchr(from, '@');
127 if (p) {
128 snprintf(TBUF, sizeof(TBUF), "<%s> %s", from, msg);
129 *p = 0;
130 if (!partyidle(p + 1, from)) {
131 *p = '@';
132 fake_alert(idx, "user", from);
133 return;
134 }
135 *p = '@';
136 p++;
137 } else {
138 sprintf(TBUF, "*** (%s) %s", from, msg);
139 p = from;
140 }
141 i = nextbot(p);
142 if (i != idx) {
143 fake_alert(idx, "direction", p);
144 } else {
145 chanout_but(-1, chan, "%s\n", TBUF);
146 /* Send to new version bots */
147 if (i >= 0)
148 botnet_send_chan(idx, from, NULL, chan, msg);
149 if (strchr(from, '@') != NULL)
150 check_tcl_chat(from, chan, msg);
151 else
152 check_tcl_bcst(from, chan, msg);
153 }
154 }
155
156 /* chat <from> <notice> -- only from bots
157 */
158 static void bot_chat(int idx, char *par)
159 {
160 char *from;
161 int i;
162
163 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
164 return;
165 from = newsplit(&par);
166 if (strchr(from, '@') != NULL) {
167 fake_alert(idx, "bot", from);
168 return;
169 }
170 /* Make sure the bot is valid */
171 i = nextbot(from);
172 if (i != idx) {
173 fake_alert(idx, "direction", from);
174 return;
175 }
176 chatout("*** (%s) %s\n", from, par);
177 botnet_send_chat(idx, from, par);
178 check_tcl_bcst(from, -1, par);
179 }
180
181 /* actchan <from> <chan> <text>
182 */
183 static void bot_actchan(int idx, char *par)
184 {
185 char *from, *p, *s;
186 int i, chan;
187
188 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
189 return;
190 from = newsplit(&par);
191 p = strchr(from, '@');
192 if (p == NULL) {
193 /* How can a bot do an action? */
194 fake_alert(idx, "user@bot", from);
195 return;
196 }
197 *p = 0;
198 if (!partyidle(p + 1, from)) {
199 *p = '@';
200 fake_alert(idx, "user", from);
201 return;
202 }
203 *p = '@';
204 p++;
205 i = nextbot(p);
206 if (i != idx) {
207 fake_alert(idx, "direction", p);
208 return;
209 }
210 p = newsplit(&par);
211 #ifndef NO_OLD_BOTNET
212 if (b_numver(idx) < NEAT_BOTNET)
213 chan = atoi(p);
214 else
215 #endif
216 chan = base64_to_int(p);
217 for (p = s = from; *s; s++)
218 if ((*s > 31) && (*s != 127))
219 *p++ = *s;
220 if (*p)
221 *p = 0;
222 chanout_but(-1, chan, "* %s %s\n", from, par);
223 botnet_send_act(idx, from, NULL, chan, par);
224 check_tcl_act(from, chan, par);
225 }
226
227 /* priv <from> <to> <message>
228 */
229 static void bot_priv(int idx, char *par)
230 {
231 char *from, *p, *to = TBUF, *tobot;
232 int i;
233
234 from = newsplit(&par);
235 tobot = newsplit(&par);
236 splitc(to, tobot, '@');
237 p = strchr(from, '@');
238 if (p != NULL)
239 p++;
240 else
241 p = from;
242 i = nextbot(p);
243 if (i != idx) {
244 fake_alert(idx, "direction", p);
245 return;
246 }
247 if (!to[0])
248 return; /* Silently ignore notes to '@bot' */
249 if (!egg_strcasecmp(tobot, botnetnick)) { /* For me! */
250 if (p == from)
251 add_note(to, from, par, -2, 0);
252 else {
253 i = add_note(to, from, par, -1, 0);
254 if (from[0] != '@')
255 switch (i) {
256 case NOTE_ERROR:
257 botnet_send_priv(idx, botnetnick, from, NULL,
258 "%s %s.", BOT_NOSUCHUSER, to);
259 break;
260 case NOTE_STORED:
261 botnet_send_priv(idx, botnetnick, from, NULL, "%s", BOT_NOTESTORED2);
262 break;
263 case NOTE_FULL:
264 botnet_send_priv(idx, botnetnick, from, NULL, "%s", BOT_NOTEBOXFULL);
265 break;
266 case NOTE_AWAY:
267 botnet_send_priv(idx, botnetnick, from, NULL,
268 "%s %s", to, BOT_NOTEISAWAY);
269 break;
270 case NOTE_FWD:
271 botnet_send_priv(idx, botnetnick, from, NULL,
272 "%s %s", "Not online; note forwarded to:", to);
273 break;
274 case NOTE_REJECT:
275 botnet_send_priv(idx, botnetnick, from, NULL,
276 "%s %s", to, "rejected your note.");
277 break;
278 case NOTE_TCL:
279 break; /* Do nothing */
280 case NOTE_OK:
281 botnet_send_priv(idx, botnetnick, from, NULL,
282 "%s %s.", BOT_NOTESENTTO, to);
283 break;
284 }
285 }
286 } else { /* Pass it on */
287 i = nextbot(tobot);
288 if (i >= 0)
289 botnet_send_priv(i, from, to, tobot, "%s", par);
290 }
291 }
292
293 static void bot_bye(int idx, char *par)
294 {
295 char s[1024];
296 int users, bots;
297
298 bots = bots_in_subtree(findbot(dcc[idx].nick));
299 users = users_in_subtree(findbot(dcc[idx].nick));
300 simple_sprintf(s, "%s %s. %s (lost %d bot%s and %d user%s)",
301 BOT_DISCONNECTED, dcc[idx].nick, par[0] ?
302 par : "No reason", bots, (bots != 1) ?
303 "s" : "", users, (users != 1) ? "s" : "");
304 putlog(LOG_BOTS, "*", "%s", s);
305 chatout("*** %s\n", s);
306 botnet_send_unlinked(idx, dcc[idx].nick, s);
307 dprintf(idx, "*bye\n");
308 killsock(dcc[idx].sock);
309 lostdcc(idx);
310 }
311
312 static void remote_tell_who(int idx, char *nick, int chan)
313 {
314 int i = 10, k, l, ok = 0;
315 char s[1024], *realnick;
316 struct chanset_t *c;
317
318 realnick = strchr(nick, ':');
319 if (realnick)
320 realnick++;
321 else
322 realnick = nick;
323 putlog(LOG_BOTS, "*", "#%s# who", realnick);
324 strcpy(s, "Channels: ");
325 for (c = chanset; c; c = c->next)
326 if (!channel_secret(c) && !channel_inactive(c)) {
327 l = strlen(c->dname);
328 if (i + l < 1021) {
329 if (i > 10)
330 sprintf(s, "%s, %s", s, c->dname);
331 else {
332 strcpy(s, c->dname);
333 i += (l + 2);
334 }
335 }
336 }
337 if (i > 10) {
338 botnet_send_priv(idx, botnetnick, nick, NULL, "%s (%s)", s, ver);
339 } else
340 botnet_send_priv(idx, botnetnick, nick, NULL, "%s (%s)", BOT_NOCHANNELS,
341 ver);
342 if (admin[0])
343 botnet_send_priv(idx, botnetnick, nick, NULL, "Admin: %s", admin);
344 if (chan == 0)
345 botnet_send_priv(idx, botnetnick, nick, NULL, "%s (* = owner, + = master,"
346 " %% = botmaster, @ = op, ^ = halfop)", BOT_PARTYMEMBS);
347 else {
348 simple_sprintf(s, "assoc %d", chan);
349 if ((Tcl_Eval(interp, s) != TCL_OK) || tcl_resultempty())
350 botnet_send_priv(idx, botnetnick, nick, NULL, "%s %s%d: (* = owner, + ="
351 " master, %% = botmaster, @ = op, ^ = halfop)\n",
352 BOT_PEOPLEONCHAN, (chan < GLOBAL_CHANS) ? "" : "*",
353 chan % GLOBAL_CHANS);
354 else
355 botnet_send_priv(idx, botnetnick, nick, NULL, "%s '%s' (%s%d): (* = "
356 "owner, + = master, %% = botmaster, @ = op, ^ = halfop)\n",
357 BOT_PEOPLEONCHAN, tcl_resultstring(), (chan < GLOBAL_CHANS) ?
358 "" : "*", chan % GLOBAL_CHANS);
359 }
360 for (i = 0; i < dcc_total; i++)
361 if (dcc[i].type->flags & DCT_REMOTEWHO)
362 if (dcc[i].u.chat->channel == chan) {
363 k = sprintf(s, " %c%-15s %s", (geticon(i) == '-' ? ' ' : geticon(i)),
364 dcc[i].nick, dcc[i].host);
365 if (now - dcc[i].timeval > 300) {
366 unsigned long days, hrs, mins;
367
368 days = (now - dcc[i].timeval) / 86400;
369 hrs = ((now - dcc[i].timeval) - (days * 86400)) / 3600;
370 mins = ((now - dcc[i].timeval) - (hrs * 3600)) / 60;
371 if (days > 0)
372 sprintf(s + k, " (%s %lud%luh)", MISC_IDLE, days, hrs);
373 else if (hrs > 0)
374 sprintf(s + k, " (%s %luh%lum)", MISC_IDLE, hrs, mins);
375 else
376 sprintf(s + k, " (%s %lum)", MISC_IDLE, mins);
377 }
378 botnet_send_priv(idx, botnetnick, nick, NULL, "%s", s);
379 if (dcc[i].u.chat->away != NULL)
380 botnet_send_priv(idx, botnetnick, nick, NULL, " %s: %s",
381 MISC_AWAY, dcc[i].u.chat->away);
382 }
383 for (i = 0; i < dcc_total; i++)
384 if (dcc[i].type == &DCC_BOT) {
385 if (!ok) {
386 ok = 1;
387 botnet_send_priv(idx, botnetnick, nick, NULL, "%s:", BOT_BOTSCONNECTED);
388 }
389 sprintf(s, " %s%c%-15s %s",
390 dcc[i].status & STAT_CALLED ? "<-" : "->",
391 dcc[i].status & STAT_SHARE ? '+' : ' ',
392 dcc[i].nick, dcc[i].u.bot->version);
393 botnet_send_priv(idx, botnetnick, nick, NULL, "%s", s);
394 }
395 ok = 0;
396 for (i = 0; i < dcc_total; i++)
397 if (dcc[i].type->flags & DCT_REMOTEWHO)
398 if (dcc[i].u.chat->channel != chan) {
399 if (!ok) {
400 ok = 1;
401 botnet_send_priv(idx, botnetnick, nick, NULL, "%s:", BOT_OTHERPEOPLE);
402 }
403 l = sprintf(s, " %c%-15s %s", (geticon(i) == '-' ? ' ' : geticon(i)),
404 dcc[i].nick, dcc[i].host);
405 if (now - dcc[i].timeval > 300) {
406 k = (now - dcc[i].timeval) / 60;
407 if (k < 60)
408 sprintf(s + l, " (%s %dm)", MISC_IDLE, k);
409 else
410 sprintf(s + l, " (%s %dh%dm)", MISC_IDLE, k / 60, k % 60);
411 }
412 botnet_send_priv(idx, botnetnick, nick, NULL, "%s", s);
413 if (dcc[i].u.chat->away != NULL)
414 botnet_send_priv(idx, botnetnick, nick, NULL,
415 " %s: %s", MISC_AWAY, dcc[i].u.chat->away);
416 }
417 }
418
419 /* who <from@bot> <tobot> <chan#>
420 */
421 static void bot_who(int idx, char *par)
422 {
423 char *from, *to, *p;
424 int i, chan;
425
426 from = newsplit(&par);
427 p = strchr(from, '@');
428 if (!p) {
429 sprintf(TBUF, "%s@%s", from, dcc[idx].nick);
430 from = TBUF;
431 }
432 to = newsplit(&par);
433 if (!egg_strcasecmp(to, botnetnick))
434 to[0] = 0;
435 #ifndef NO_OLD_BOTNET
436 if (b_numver(idx) < NEAT_BOTNET)
437 chan = atoi(par);
438 else
439 #endif
440 chan = base64_to_int(par);
441 if (to[0]) {
442 i = nextbot(to);
443 if (i >= 0)
444 botnet_send_who(i, from, to, chan);
445 } else
446 remote_tell_who(idx, from, chan);
447 }
448
449 static void bot_endlink(int idx, char *par)
450 {
451 dcc[idx].status &= ~STAT_LINKING;
452 }
453
454 /* info? <from@bot> -> send priv
455 */
456 static void bot_infoq(int idx, char *par)
457 {
458 char s[200], s2[32], *realnick;
459 struct chanset_t *chan;
460 time_t now2;
461 int hr, min;
462
463 /* Strip the idx from user@bot */
464 realnick = strchr(par, ':');
465 if (realnick)
466 realnick++;
467 else
468 realnick = par;
469 putlog(LOG_BOTS, "*", "#%s# botinfo", realnick);
470
471 now2 = now - online_since;
472 s2[0] = 0;
473 if (now2 > 86400) {
474 int days = now2 / 86400;
475
476 /* Days */
477 sprintf(s2, "%d day", days);
478 if (days >= 2)
479 strcat(s2, "s");
480 strcat(s2, ", ");
481 now2 -= days * 86400;
482 }
483 hr = (time_t) ((int) now2 / 3600);
484 now2 -= (hr * 3600);
485 min = (time_t) ((int) now2 / 60);
486 sprintf(&s2[strlen(s2)], "%02d:%02d", (int) hr, (int) min);
487 if (module_find("server", 0, 0)) {
488 s[0] = 0;
489 for (chan = chanset; chan; chan = chan->next) {
490 if (!channel_secret(chan)) {
491 if ((strlen(s) + strlen(chan->dname) + strlen(network)
492 + strlen(botnetnick) + strlen(ver) + 1) >= 200) {
493 strcat(s, "++ ");
494 break; /* Yegads..! */
495 }
496 strcat(s, chan->dname);
497 strcat(s, ", ");
498 }
499 }
500 if (s[0]) {
501 s[strlen(s) - 2] = 0;
502 botnet_send_priv(idx, botnetnick, par, NULL,
503 "%s <%s> (%s) [UP %s]", ver, network, s, s2);
504 } else
505 botnet_send_priv(idx, botnetnick, par, NULL, "%s <%s> (%s) [UP %s]", ver,
506 network, BOT_NOCHANNELS, s2);
507 } else
508 botnet_send_priv(idx, botnetnick, par, NULL,
509 "%s <NO_IRC> [UP %s]", ver, s2);
510 botnet_send_infoq(idx, par);
511 }
512
513 static void bot_ping(int idx, char *par)
514 {
515 botnet_send_pong(idx);
516 }
517
518 static void bot_pong(int idx, char *par)
519 {
520 dcc[idx].status &= ~STAT_PINGED;
521 }
522
523 /* link <from@bot> <who> <to-whom>
524 */
525 static void bot_link(int idx, char *par)
526 {
527 char *from, *bot, *rfrom;
528 int i;
529
530 from = newsplit(&par);
531 bot = newsplit(&par);
532
533 if (!egg_strcasecmp(bot, botnetnick)) {
534 if ((rfrom = strchr(from, ':')))
535 rfrom++;
536 else
537 rfrom = from;
538 putlog(LOG_CMDS, "*", "#%s# link %s", rfrom, par);
539 if (botlink(from, -1, par))
540 botnet_send_priv(idx, botnetnick, from, NULL, "%s %s ...",
541 BOT_LINKATTEMPT, par);
542 else
543 botnet_send_priv(idx, botnetnick, from, NULL, "%s.", BOT_CANTLINKTHERE);
544 } else {
545 i = nextbot(bot);
546 if (i >= 0)
547 botnet_send_link(i, from, bot, par);
548 }
549 }
550
551 /* unlink <from@bot> <linking-bot> <undesired-bot> <reason>
552 */
553 static void bot_unlink(int idx, char *par)
554 {
555 char *from, *bot, *rfrom, *p, *undes;
556 int i;
557
558 from = newsplit(&par);
559 bot = newsplit(&par);
560 undes = newsplit(&par);
561 if (!egg_strcasecmp(bot, botnetnick)) {
562 if ((rfrom = strchr(from, ':')))
563 rfrom++;
564 else
565 rfrom = from;
566 putlog(LOG_CMDS, "*", "#%s# unlink %s (%s)", rfrom, undes, par[0] ? par :
567 "No reason");
568 i = botunlink(-3, undes, par[0] ? par : NULL, rfrom);
569 if (i == 1) {
570 p = strchr(from, '@');
571 if (p) {
572 /* idx will change after unlink -- get new idx
573 *
574 * TODO: This has changed with the new lostdcc() behaviour. Check
575 * if we can optimise the situation.
576 */
577 i = nextbot(p + 1);
578 if (i >= 0)
579 botnet_send_priv(i, botnetnick, from, NULL,
580 "Unlinked from %s.", undes);
581 }
582 } else if (i == 0) {
583 botnet_send_unlinked(-1, undes, "");
584 p = strchr(from, '@');
585 if (p) {
586 /* Ditto above, about idx */
587 i = nextbot(p + 1);
588 if (i >= 0)
589 botnet_send_priv(i, botnetnick, from, NULL,
590 "%s %s.", BOT_CANTUNLINK, undes);
591 }
592 } else {
593 p = strchr(from, '@');
594 if (p) {
595 i = nextbot(p + 1);
596 if (i >= 0)
597 botnet_send_priv(i, botnetnick, from, NULL,
598 "Can't remotely unlink sharebots.");
599 }
600 }
601 } else {
602 i = nextbot(bot);
603 if (i >= 0)
604 botnet_send_unlink(i, from, bot, undes, par);
605 }
606 }
607
608 /* Bot next share?
609 */
610 static void bot_update(int idx, char *par)
611 {
612 char *bot, x;
613 int vnum;
614
615 bot = newsplit(&par);
616 x = par[0];
617 if (x)
618 par++;
619 #ifndef NO_OLD_BOTNET
620 if (b_numver(idx) < NEAT_BOTNET)
621 vnum = atoi(par);
622 else
623 #endif
624 vnum = base64_to_int(par);
625 if (in_chain(bot))
626 updatebot(idx, bot, x, vnum);
627 }
628
629 /* Newbot next share?
630 */
631 static void bot_nlinked(int idx, char *par)
632 {
633 char *newbot, *next, *p, s[1024], x;
634 int bogus = 0, i;
635 struct userrec *u;
636
637 newbot = newsplit(&par);
638 next = newsplit(&par);
639 s[0] = 0;
640 if (!next[0]) {
641 putlog(LOG_BOTS, "*", "Invalid eggnet protocol from %s (zapfing)",
642 dcc[idx].nick);
643 simple_sprintf(s, "%s %s (%s)", MISC_DISCONNECTED, dcc[idx].nick,
644 MISC_INVALIDBOT);
645 dprintf(idx, "error invalid eggnet protocol for 'nlinked'\n");
646 } else if ((in_chain(newbot)) || (!egg_strcasecmp(newbot, botnetnick))) {
647 /* Loop! */
648 putlog(LOG_BOTS, "*", "%s %s (mutual: %s)",
649 BOT_LOOPDETECT, dcc[idx].nick, newbot);
650 simple_sprintf(s, "%s %s: disconnecting %s", MISC_LOOP, newbot,
651 dcc[idx].nick);
652 dprintf(idx, "error Loop (%s)\n", newbot);
653 }
654 if (!s[0]) {
655 for (p = newbot; *p; p++)
656 if ((*p < 32) || (*p == 127) || ((p - newbot) >= HANDLEN))
657 bogus = 1;
658 i = nextbot(next);
659 if (i != idx)
660 bogus = 1;
661 }
662 if (bogus) {
663 putlog(LOG_BOTS, "*", "%s %s! (%s -> %s)", BOT_BOGUSLINK, dcc[idx].nick,
664 next, newbot);
665 simple_sprintf(s, "%s: %s %s", BOT_BOGUSLINK, dcc[idx].nick,
666 MISC_DISCONNECTED);
667 dprintf(idx, "error %s (%s -> %s)\n", BOT_BOGUSLINK, next, newbot);
668 }
669 if (bot_flags(dcc[idx].user) & BOT_LEAF) {
670 putlog(LOG_BOTS, "*", "%s %s (%s %s)",
671 BOT_DISCONNLEAF, dcc[idx].nick, newbot, BOT_LINKEDTO);
672 simple_sprintf(s, "%s %s (to %s): %s",
673 BOT_ILLEGALLINK, dcc[idx].nick, newbot, MISC_DISCONNECTED);
674 dprintf(idx, "error %s\n", BOT_YOUREALEAF);
675 }
676 if (s[0]) {
677 chatout("*** %s\n", s);
678 botnet_send_unlinked(idx, dcc[idx].nick, s);
679 dprintf(idx, "bye %s\n", BOT_ILLEGALLINK);
680 killsock(dcc[idx].sock);
681 lostdcc(idx);
682 return;
683 }
684 x = par[0];
685 if (x)
686 par++;
687 else
688 x = '-';
689 #ifndef NO_OLD_BOTNET
690 if (b_numver(idx) < NEAT_BOTNET)
691 i = atoi(par);
692 else
693 #endif
694 i = base64_to_int(par);
695 botnet_send_nlinked(idx, newbot, next, x, i);
696 if (x == '!') {
697 chatout("*** (%s) %s %s.\n", next, NET_LINKEDTO, newbot);
698 x = '-';
699 }
700 addbot(newbot, dcc[idx].nick, next, x, i);
701 check_tcl_link(newbot, next);
702 u = get_user_by_handle(userlist, newbot);
703 if (bot_flags(u) & BOT_REJECT) {
704 botnet_send_reject(idx, botnetnick, NULL, newbot, NULL, NULL);
705 putlog(LOG_BOTS, "*", "%s %s %s %s", BOT_REJECTING,
706 newbot, MISC_FROM, dcc[idx].nick);
707 }
708 }
709
710 #ifndef NO_OLD_BOTNET
711 static void bot_linked(int idx, char *par)
712 {
713 char s[1024];
714 int bots, users;
715
716 bots = bots_in_subtree(findbot(dcc[idx].nick));
717 users = users_in_subtree(findbot(dcc[idx].nick));
718 putlog(LOG_BOTS, "*", "%s", BOT_OLDBOT);
719 simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s",
720 MISC_DISCONNECTED, dcc[idx].nick, MISC_OUTDATED,
721 bots, (bots != 1) ? "s" : "", users, (users != 1) ? "s" : "");
722 chatout("*** %s\n", s);
723 botnet_send_unlinked(idx, dcc[idx].nick, s);
724 killsock(dcc[idx].sock);
725 lostdcc(idx);
726 }
727 #endif /* !NO_OLD_BOTNET */
728
729 static void bot_unlinked(int idx, char *par)
730 {
731 int i;
732 char *bot;
733
734 bot = newsplit(&par);
735 i = nextbot(bot);
736 if ((i >= 0) && (i != idx)) /* Bot is NOT downstream along idx, so
737 * BOGUS! */
738 fake_alert(idx, "direction", bot);
739 else if (i >= 0) { /* Valid bot downstream of idx */
740 if (par[0])
741 chatout("*** (%s) %s\n", lastbot(bot), par);
742 botnet_send_unlinked(idx, bot, par);
743 unvia(idx, findbot(bot));
744 rembot(bot);
745 }
746 /* Otherwise it's not even a valid bot, so just ignore! */
747 }
748
749 /* trace <from@bot> <dest> <chain:chain..>
750 */
751 static void bot_trace(int idx, char *par)
752 {
753 char *from, *dest;
754 int i;
755
756 from = newsplit(&par);
757 dest = newsplit(&par);
758 simple_sprintf(TBUF, "%s:%s", par, botnetnick);
759 botnet_send_traced(idx, from, TBUF);
760 if (egg_strcasecmp(dest, botnetnick) && ((i = nextbot(dest)) > 0))
761 botnet_send_trace(i, from, dest, par);
762 }
763
764 /* traced <to@bot> <chain:chain..>
765 */
766 static void bot_traced(int idx, char *par)
767 {
768 char *to, *p;
769 int i, sock;
770
771 to = newsplit(&par);
772 p = strchr(to, '@');
773 if (p == NULL)
774 p = to;
775 else {
776 *p = 0;
777 p++;
778 }
779 if (!egg_strcasecmp(p, botnetnick)) {
780 time_t t = 0;
781 char *p = par, *ss = TBUF;
782
783 splitc(ss, to, ':');
784 if (ss[0])
785 sock = atoi(ss);
786 else
787 sock = -1;
788 if (par[0] == ':') {
789 t = atoi(par + 1);
790 p = strchr(par + 1, ':');
791 if (p)
792 p++;
793 else
794 p = par + 1;
795 }
796 for (i = 0; i < dcc_total; i++)
797 if ((dcc[i].type->flags & DCT_CHAT) &&
798 (!egg_strcasecmp(dcc[i].nick, to)) &&
799 ((sock == -1) || (sock == dcc[i].sock))) {
800 if (t) {
801 int j = 0;
802
803 {
804 register char *c = p;
805
806 for (; *c != '\0'; c++)
807 if (*c == ':')
808 j++;
809 }
810 dprintf(i, "%s -> %s (%lu secs, %d hop%s)\n", BOT_TRACERESULT, p,
811 now - t, j, (j != 1) ? "s" : "");
812 } else
813 dprintf(i, "%s -> %s\n", BOT_TRACERESULT, p);
814 }
815 } else {
816 i = nextbot(p);
817 if (p != to)
818 *--p = '@';
819 if (i >= 0)
820 botnet_send_traced(i, to, par);
821 }
822 }
823
824 /* reject <from> <bot>
825 */
826 static void bot_reject(int idx, char *par)
827 {
828 char *from, *who, *destbot, *frombot;
829 struct userrec *u;
830 int i;
831
832 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
833 return;
834 from = newsplit(&par);
835 frombot = strchr(from, '@');
836 if (frombot)
837 frombot++;
838 else
839 frombot = from;
840 i = nextbot(frombot);
841 if (i != idx) {
842 fake_alert(idx, "direction", frombot);
843 return;
844 }
845 who = newsplit(&par);
846 if (!(destbot = strchr(who, '@'))) {
847 /* Rejecting a bot */
848 i = nextbot(who);
849 if (i < 0) {
850 botnet_send_priv(idx, botnetnick, from, NULL, "%s %s (%s)",
851 BOT_CANTUNLINK, who, BOT_DOESNTEXIST);
852 } else if (!egg_strcasecmp(dcc[i].nick, who)) {
853 char s[1024];
854
855 /* I'm the connection to the rejected bot */
856 putlog(LOG_BOTS, "*", "%s %s %s", from, MISC_REJECTED, dcc[i].nick);
857 dprintf(i, "bye %s\n", par[0] ? par : MISC_REJECTED);
858 simple_sprintf(s, "%s %s (%s: %s)",
859 MISC_DISCONNECTED, dcc[i].nick, from,
860 par[0] ? par : MISC_REJECTED);
861 chatout("*** %s\n", s);
862 botnet_send_unlinked(i, dcc[i].nick, s);
863 killsock(dcc[i].sock);
864 lostdcc(i);
865 } else {
866 if (i >= 0)
867 botnet_send_reject(i, from, NULL, who, NULL, par);
868 }
869 } else { /* Rejecting user */
870 *destbot++ = 0;
871 if (!egg_strcasecmp(destbot, botnetnick)) {
872 /* Kick someone here! */
873 int ok = 0;
874
875 if (remote_boots == 1) {
876 frombot = strchr(from, '@');
877 if (frombot == NULL)
878 frombot = from;
879 else
880 frombot++;
881 u = get_user_by_handle(userlist, frombot);
882 if (!(bot_flags(u) & BOT_SHARE)) {
883 add_note(from, botnetnick, "No non sharebot boots.", -1, 0);
884 ok = 1;
885 }
886 } else if (remote_boots == 0) {
887 botnet_send_priv(idx, botnetnick, from, NULL, "%s", BOT_NOREMOTEBOOT);
888 ok = 1;
889 }
890 for (i = 0; (i < dcc_total) && (!ok); i++)
891 if ((!egg_strcasecmp(who, dcc[i].nick)) &&
892 (dcc[i].type->flags & DCT_CHAT)) {
893 u = get_user_by_handle(userlist, dcc[i].nick);
894 if (u && (u->flags & USER_OWNER)) {
895 add_note(from, botnetnick, BOT_NOOWNERBOOT, -1, 0);
896 return;
897 }
898 do_boot(i, from, par);
899 ok = 1;
900 putlog(LOG_CMDS, "*", "#%s# boot %s (%s)", from, who,
901 par[0] ? par : "No reason");
902 }
903 } else {
904 i = nextbot(destbot);
905 *--destbot = '@';
906 if (i >= 0)
907 botnet_send_reject(i, from, NULL, who, NULL, par);
908 }
909 }
910 }
911
912 static void bot_thisbot(int idx, char *par)
913 {
914 if (egg_strcasecmp(par, dcc[idx].nick)) {
915 char s[1024];
916
917 putlog(LOG_BOTS, "*", NET_WRONGBOT, dcc[idx].nick, par);
918 dprintf(idx, "bye %s\n", MISC_IMPOSTER);
919 simple_sprintf(s, "%s %s (%s)", MISC_DISCONNECTED, dcc[idx].nick,
920 MISC_IMPOSTER);
921 chatout("*** %s\n", s);
922 botnet_send_unlinked(idx, dcc[idx].nick, s);
923 unvia(idx, findbot(dcc[idx].nick));
924 killsock(dcc[idx].sock);
925 lostdcc(idx);
926 return;
927 }
928 if (bot_flags(dcc[idx].user) & BOT_LEAF)
929 dcc[idx].status |= STAT_LEAF;
930 /* Set capitalization the way they want it */
931 noshare = 1;
932 change_handle(dcc[idx].user, par);
933 noshare = 0;
934 strcpy(dcc[idx].nick, par);
935 }
936
937 static void bot_handshake(int idx, char *par)
938 {
939 struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick);
940
941 /* We *don't* want botnet passwords migrating */
942 noshare = 1;
943 set_user(&USERENTRY_PASS, u, par);
944 noshare = 0;
945 }
946
947 /* Used to send a direct msg from Tcl on one bot to Tcl on another
948 * zapf <frombot> <tobot> <code [param]>
949 */
950 static void bot_zapf(int idx, char *par)
951 {
952 char *from, *to;
953 int i;
954
955 from = newsplit(&par);
956 to = newsplit(&par);
957 i = nextbot(from);
958 if (i != idx) {
959 fake_alert(idx, "direction", from);
960 return;
961 }
962 if (!egg_strcasecmp(to, botnetnick)) {
963 /* For me! */
964 char *opcode;
965
966 opcode = newsplit(&par);
967 check_tcl_bot(from, opcode, par);
968 return;
969 }
970 i = nextbot(to);
971 if (i >= 0)
972 botnet_send_zapf(i, from, to, par);
973 }
974
975 /* Used to send a global msg from Tcl on one bot to every other bot
976 * zapf-broad <frombot> <code [param]>
977 */
978 static void bot_zapfbroad(int idx, char *par)
979 {
980 char *from, *opcode;
981 int i;
982
983 from = newsplit(&par);
984 opcode = newsplit(&par);
985
986 i = nextbot(from);
987 if (i != idx) {
988 fake_alert(idx, "direction", from);
989 return;
990 }
991 check_tcl_bot(from, opcode, par);
992 botnet_send_zapf_broad(idx, from, opcode, par);
993 }
994
995 /* Show motd to someone
996 */
997 static void bot_motd(int idx, char *par)
998 {
999 FILE *vv;
1000 char *s = TBUF, *who, *p;
1001 int i;
1002 struct flag_record fr = { FR_BOT, USER_BOT, 0, 0, 0, 0 };
1003
1004 who = newsplit(&par);
1005 if (!par[0] || !egg_strcasecmp(par, botnetnick)) {
1006 int irc = 0;
1007
1008 p = strchr(who, ':');
1009 if (p)
1010 p++;
1011 else
1012 p = who;
1013 if (who[0] == '!') {
1014 irc = HELP_IRC;
1015 fr.global |=USER_HIGHLITE;
1016
1017 who++;
1018 } else if (who[0] == '#') {
1019 fr.global |=USER_HIGHLITE;
1020
1021 who++;
1022 }
1023 putlog(LOG_CMDS, "*", "#%s# motd", p);
1024 vv = fopen(motdfile, "r");
1025 if (vv != NULL) {
1026 botnet_send_priv(idx, botnetnick, who, NULL, "--- %s\n", MISC_MOTDFILE);
1027 help_subst(NULL, NULL, 0, irc, NULL);
1028 while (!feof(vv)) {
1029 fgets(s, 120, vv);
1030 if (!feof(vv)) {
1031 if (s[strlen(s) - 1] == '\n')
1032 s[strlen(s) - 1] = 0;
1033 if (!s[0])
1034 strcpy(s, " ");
1035 help_subst(s, who, &fr, HELP_DCC, dcc[idx].nick);
1036 if (s[0])
1037 botnet_send_priv(idx, botnetnick, who, NULL, "%s", s);
1038 }
1039 }
1040 fclose(vv);
1041 } else
1042 botnet_send_priv(idx, botnetnick, who, NULL, "%s :(", MISC_NOMOTDFILE);
1043 } else {
1044 /* Pass it on */
1045 i = nextbot(par);
1046 if (i >= 0)
1047 botnet_send_motd(i, who, par);
1048 }
1049 }
1050
1051 /* These are still here, so that they will pass the relevant
1052 * requests through even if no filesys is loaded.
1053 *
1054 * filereject <bot:filepath> <sock:nick@bot> <reason...>
1055 */
1056 static void bot_filereject(int idx, char *par)
1057 {
1058 char *path, *to, *tobot, *p;
1059 int i;
1060
1061 path = newsplit(&par);
1062 to = newsplit(&par);
1063 if ((tobot = strchr(to, '@')))
1064 tobot++;
1065 else
1066 tobot = to; /* Bot wants a file?! :) */
1067 if (egg_strcasecmp(tobot, botnetnick)) { /* for me! */
1068 p = strchr(to, ':');
1069 if (p != NULL) {
1070 *p = 0;
1071 for (i = 0; i < dcc_total; i++) {
1072 if (dcc[i].sock == atoi(to))
1073 dprintf(i, "%s (%s): %s\n", BOT_XFERREJECTED, path, par);
1074 }
1075 *p = ':';
1076 }
1077 /* No ':'? malformed */
1078 putlog(LOG_FILES, "*", "%s %s: %s", path, MISC_REJECTED, par);
1079 } else { /* Pass it on */
1080 i = nextbot(tobot);
1081 if (i >= 0)
1082 botnet_send_filereject(i, path, to, par);
1083 }
1084 }
1085
1086 /* filereq <sock:nick@bot> <bot:file>
1087 */
1088 static void bot_filereq(int idx, char *tobot)
1089 {
1090 char *from, *path;
1091 int i;
1092
1093 from = newsplit(&tobot);
1094 if ((path = strchr(tobot, ':'))) {
1095 *path++ = 0;
1096
1097 if (!egg_strcasecmp(tobot, botnetnick)) { /* For me! */
1098 /* Process this */
1099 module_entry *fs = module_find("filesys", 0, 0);
1100
1101 if (fs == NULL)
1102 botnet_send_priv(idx, botnetnick, from, NULL, MOD_NOFILESYSMOD);
1103 else {
1104 Function f = fs->funcs[FILESYS_REMOTE_REQ];
1105
1106 f(idx, from, path);
1107 }
1108 } else { /* Pass it on */
1109 i = nextbot(tobot);
1110 if (i >= 0)
1111 botnet_send_filereq(i, from, tobot, path);
1112 }
1113 }
1114 }
1115
1116 /* filesend <bot:path> <sock:nick@bot> <IP#> <port> <size>
1117 */
1118 static void bot_filesend(int idx, char *par)
1119 {
1120 char *botpath, *to, *tobot, *nick;
1121 int i;
1122 char *nfn;
1123
1124 botpath = newsplit(&par);
1125 to = newsplit(&par);
1126 if ((tobot = strchr(to, '@'))) {
1127 *tobot = 0;
1128 tobot++;
1129 } else
1130 tobot = to;
1131 if (!egg_strcasecmp(tobot, botnetnick)) { /* For me! */
1132 nfn = strrchr(botpath, '/');
1133 if (nfn == NULL) {
1134 nfn = strrchr(botpath, ':');
1135 if (nfn == NULL)
1136 nfn = botpath; /* That's odd. */
1137 else
1138 nfn++;
1139 } else
1140 nfn++;
1141 if ((nick = strchr(to, ':')))
1142 nick++;
1143 else
1144 nick = to;
1145 /* Send it to 'nick' as if it's from me */
1146 dprintf(DP_SERVER, "PRIVMSG %s :\001DCC SEND %s %s\001\n", nick, nfn, par);
1147 } else {
1148 i = nextbot(tobot);
1149 if (i >= 0) {
1150 *--tobot = '@';
1151 botnet_send_filesend(i, botpath, to, par);
1152 }
1153 }
1154 }
1155
1156 static void bot_error(int idx, char *par)
1157 {
1158 putlog(LOG_MISC | LOG_BOTS, "*", "%s: %s", dcc[idx].nick, par);
1159 }
1160
1161 /* nc <bot> <sock> <newnick>
1162 */
1163 static void bot_nickchange(int idx, char *par)
1164 {
1165 char *bot, *ssock, *newnick;
1166 int sock, i;
1167
1168 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
1169 return;
1170 bot = newsplit(&par);
1171 #ifndef NO_OLD_BOTNET
1172 if (b_numver(idx) < NEAT_BOTNET) {
1173 fake_alert(idx, "botversion", "NEAT_BOTNET");
1174 return;
1175 }
1176 #endif
1177 i = nextbot(bot);
1178 if (i != idx) {
1179 fake_alert(idx, "direction", bot);
1180 return;
1181 }
1182 ssock = newsplit(&par);
1183 sock = base64_to_int(ssock);
1184 newnick = newsplit(&par);
1185 i = partynick(bot, sock, newnick);
1186 if (i < 0) {
1187 fake_alert(idx, "sock#", ssock);
1188 return;
1189 }
1190 chanout_but(-1, party[i].chan, "*** (%s) Nick change: %s -> %s\n",
1191 bot, newnick, party[i].nick);
1192 botnet_send_nkch_part(idx, i, newnick);
1193 }
1194
1195 /* join <bot> <nick> <chan> <flag><sock> <from>
1196 */
1197 static void bot_join(int idx, char *par)
1198 {
1199 char *bot, *nick, *x, *y;
1200 struct userrec *u;
1201 int i, sock, chan, i2, linking = 0;
1202
1203 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
1204 return;
1205 bot = newsplit(&par);
1206 #ifndef NO_OLD_BOTNET
1207 if (b_numver(idx) >= NEAT_BOTNET)
1208 #endif
1209 if (bot[0] == '!') {
1210 linking = 1;
1211 bot++;
1212 }
1213 if (b_status(idx) & STAT_LINKING) {
1214 linking = 1;
1215 }
1216 nick = newsplit(&par);
1217 x = newsplit(&par);
1218 #ifndef NO_OLD_BOTNET
1219 if (b_numver(idx) < NEAT_BOTNET)
1220 chan = atoi(x);
1221 else
1222 #endif
1223 chan = base64_to_int(x);
1224 y = newsplit(&par);
1225 if ((chan < 0) || !y[0])
1226 return; /* Woops! pre 1.2.1's send .chat off'ers
1227 * too!! */
1228 if (!y[0]) {
1229 y[0] = '-';
1230 sock = 0;
1231 } else {
1232 #ifndef NO_OLD_BOTNET
1233 if (b_numver(idx) < NEAT_BOTNET)
1234 sock = atoi(y + 1);
1235 else
1236 #endif
1237 sock = base64_to_int(y + 1);
1238 }
1239 /* 1.1 bots always send a sock#, even on a channel change
1240 * so if sock# is 0, this is from an old bot and we must tread softly
1241 * grab old sock# if there is one, otherwise make up one.
1242 */
1243 if (sock == 0)
1244 sock = partysock(bot, nick);
1245 if (sock == 0)
1246 sock = fakesock++;
1247 i = nextbot(bot);
1248 if (i != idx) { /* Ok, garbage from a 1.0g (who uses that
1249 * now?) OR raistlin being evil :) */
1250 fake_alert(idx, "direction", bot);
1251 return;
1252 }
1253 u = get_user_by_handle(userlist, nick);
1254 if (u) {
1255 sprintf(TBUF, "@%s", bot);
1256 touch_laston(u, TBUF, now);
1257 }
1258 i = addparty(bot, nick, chan, y[0], sock, par, &i2);
1259 botnet_send_join_party(idx, linking, i2, i);
1260 if (i != chan) {
1261 if (i >= 0) {
1262 if (b_numver(idx) >= NEAT_BOTNET)
1263 chanout_but(-1, i, "*** (%s) %s %s %s.\n", bot, nick, NET_LEFTTHE,
1264 i ? "channel" : "party line");
1265 check_tcl_chpt(bot, nick, sock, i);
1266 }
1267 if ((b_numver(idx) >= NEAT_BOTNET) && !linking)
1268 chanout_but(-1, chan, "*** (%s) %s %s %s.\n", bot, nick, NET_JOINEDTHE,
1269 chan ? "channel" : "party line");
1270 check_tcl_chjn(bot, nick, chan, y[0], sock, par);
1271 }
1272 }
1273
1274 /* part <bot> <nick> <sock> [etc..]
1275 */
1276 static void bot_part(int idx, char *par)
1277 {
1278 char *bot, *nick, *etc;
1279 struct userrec *u;
1280 int sock, partyidx;
1281 int silent = 0;
1282
1283 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
1284 return;
1285 bot = newsplit(&par);
1286 if (bot[0] == '!') {
1287 silent = 1;
1288 bot++;
1289 }
1290 nick = newsplit(&par);
1291 etc = newsplit(&par);
1292 #ifndef NO_OLD_BOTNET
1293 if (b_numver(idx) < NEAT_BOTNET) {
1294 sock = atoi(etc);
1295 silent = 1;
1296 } else
1297 #endif
1298 sock = base64_to_int(etc);
1299 if (sock == 0)
1300 sock = partysock(bot, nick);
1301 u = get_user_by_handle(userlist, nick);
1302 if (u) {
1303 sprintf(TBUF, "@%s", bot);
1304 touch_laston(u, TBUF, now);
1305 }
1306 if ((partyidx = getparty(bot, sock)) != -1) {
1307 if (party[partyidx].chan >= 0)
1308 check_tcl_chpt(bot, nick, sock, party[partyidx].chan);
1309 if ((b_numver(idx) >= NEAT_BOTNET) && !silent) {
1310 register int chan = party[partyidx].chan;
1311
1312 if (par[0])
1313 chanout_but(-1, chan, "*** (%s) %s %s %s (%s).\n", bot, nick,
1314 NET_LEFTTHE, chan ? "channel" : "party line", par);
1315 else
1316 chanout_but(-1, chan, "*** (%s) %s %s %s.\n", bot, nick,
1317 NET_LEFTTHE, chan ? "channel" : "party line");
1318 }
1319 botnet_send_part_party(idx, partyidx, par, silent);
1320 remparty(bot, sock);
1321 }
1322 }
1323
1324 /* away <bot> <sock> <message>
1325 * null message = unaway
1326 */
1327 static void bot_away(int idx, char *par)
1328 {
1329 char *bot, *etc;
1330 int sock, partyidx, linking = 0;
1331
1332 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
1333 return;
1334 bot = newsplit(&par);
1335 #ifndef NO_OLD_BOTNET
1336 if (b_numver(idx) >= NEAT_BOTNET)
1337 #endif
1338 if (bot[0] == '!') {
1339 linking = 1;
1340 bot++;
1341 }
1342 if (b_status(idx) & STAT_LINKING) {
1343 linking = 1;
1344 }
1345 etc = newsplit(&par);
1346 #ifndef NO_OLD_BOTNET
1347 if (b_numver(idx) < NEAT_BOTNET)
1348 sock = atoi(etc);
1349 else
1350 #endif
1351 sock = base64_to_int(etc);
1352 if (sock == 0)
1353 sock = partysock(bot, etc);
1354 check_tcl_away(bot, sock, par);
1355 if (par[0]) {
1356 partystat(bot, sock, PLSTAT_AWAY, 0);
1357 partyaway(bot, sock, par);
1358 } else
1359 partystat(bot, sock, 0, PLSTAT_AWAY);
1360 partyidx = getparty(bot, sock);
1361 if ((b_numver(idx) >= NEAT_BOTNET) && !linking) {
1362 if (par[0])
1363 chanout_but(-1, party[partyidx].chan,
1364 "*** (%s) %s %s: %s.\n", bot,
1365 party[partyidx].nick, NET_AWAY, par);
1366 else
1367 chanout_but(-1, party[partyidx].chan,
1368 "*** (%s) %s %s.\n", bot, party[partyidx].nick, NET_UNAWAY);
1369 }
1370 botnet_send_away(idx, bot, sock, par, linking);
1371 }
1372
1373 /* (a courtesy info to help during connect bursts)
1374 * idle <bot> <sock> <#secs> [away msg]
1375 */
1376 static void bot_idle(int idx, char *par)
1377 {
1378 char *bot, *work;
1379 int sock, idle;
1380
1381 if (bot_flags(dcc[idx].user) & BOT_ISOLATE)
1382 return;
1383 bot = newsplit(&par);
1384 work = newsplit(&par);
1385 #ifndef NO_OLD_BOTNET
1386 if (b_numver(idx) < NEAT_BOTNET)
1387 sock = atoi(work);
1388 else
1389 #endif
1390 sock = base64_to_int(work);
1391 if (sock == 0)
1392 sock = partysock(bot, work);
1393 work = newsplit(&par);
1394 #ifndef NO_OLD_BOTNET
1395 if (b_numver(idx) < NEAT_BOTNET)
1396 idle = atoi(work);
1397 else
1398 #endif
1399 idle = base64_to_int(work);
1400 partysetidle(bot, sock, idle);
1401 if (par[0]) {
1402 partystat(bot, sock, PLSTAT_AWAY, 0);
1403 partyaway(bot, sock, par);
1404 }
1405 botnet_send_idle(idx, bot, sock, idle, par);
1406 }
1407
1408 #ifndef NO_OLD_BOTNET
1409
1410 static void bot_ufno(int idx, char *par)
1411 {
1412 putlog(LOG_BOTS, "*", "%s %s: %s", USERF_REJECTED, dcc[idx].nick, par);
1413 dcc[idx].status &= ~STAT_OFFERED;
1414 if (!(dcc[idx].status & STAT_GETTING))
1415 dcc[idx].status &= ~STAT_SHARE;
1416 }
1417
1418 static void bot_old_userfile(int idx, char *par)
1419 {
1420 putlog(LOG_BOTS, "*", "%s %s", USERF_OLDSHARE, dcc[idx].nick);
1421 dprintf(idx, "uf-no %s\n", USERF_ANTIQUESHARE);
1422 }
1423
1424 #endif /* !NO_OLD_BOTNET */
1425
1426 void bot_share(int idx, char *par)
1427 {
1428 sharein(idx, par);
1429 }
1430
1431 /* v <frombot> <tobot> <idx:nick>
1432 */
1433 static void bot_versions(int sock, char *par)
1434 {
1435 char *frombot = newsplit(&par), *tobot, *from;
1436 module_entry *me;
1437
1438 if (nextbot(frombot) != sock)
1439 fake_alert(sock, "versions-direction", frombot);
1440 else if (egg_strcasecmp(tobot = newsplit(&par), botnetnick)) {
1441 if ((sock = nextbot(tobot)) >= 0)
1442 dprintf(sock, "v %s %s %s\n", frombot, tobot, par);
1443 } else {
1444 from = newsplit(&par);
1445 botnet_send_priv(sock, botnetnick, from, frombot, "Modules loaded:\n");
1446 for (me = module_list; me; me = me->next)
1447 botnet_send_priv(sock, botnetnick, from, frombot,
1448 " Module: %s (v%d.%d)\n", me->name, me->major,
1449 me->minor);
1450 botnet_send_priv(sock, botnetnick, from, frombot, "End of module list.\n");
1451 }
1452 }
1453
1454 #ifdef TLS
1455 /* Negotiate an encrypted session over the existing link
1456 * starttls
1457 */
1458 static void bot_starttls(int idx, char *par)
1459 {
1460 /* We're already using ssl, ignore the request */
1461 if (dcc[idx].ssl)
1462 return;
1463
1464 if (dcc[idx].status & STAT_STARTTLS) {
1465 /* we requested ssl, now we got the reply */
1466 dcc[idx].status &= ~STAT_STARTTLS;
1467 ssl_handshake(dcc[idx].sock, TLS_CONNECT, tls_vfybots, LOG_BOTS,
1468 dcc[idx].host, NULL);
1469 } else {
1470 /* the peer requests ssl, tell it to go on */
1471 /*
1472 if (!SSL_CTX_check_private_key(ssl_ctx)) {
1473 putlog(LOG_BOTS, "*", "%s", ERR_error_string(ERR_get_error()));
1474 return;
1475 }
1476 */
1477 dprintf(idx, "starttls\n");
1478 putlog(LOG_BOTS, "*", "Got STARTTLS from %s. Replying...", dcc[idx].nick);
1479 ssl_handshake(dcc[idx].sock, TLS_LISTEN, tls_vfybots, LOG_BOTS,
1480 dcc[idx].host, NULL);
1481 }
1482 dcc[idx].ssl = 1;
1483 }
1484 #endif
1485
1486 /* BOT COMMANDS
1487 *
1488 * function call should be:
1489 * int bot_whatever(idx,"parameters");
1490 *
1491 * SORT these, dcc_bot uses a shortcut which requires them sorted
1492 *
1493 * yup, those are tokens there to allow a more efficient botnet as
1494 * time goes on (death to slowly upgrading llama's)
1495 */
1496 botcmd_t C_bot[] =
1497 {
1498 {"a", (IntFunc) bot_actchan},
1499 #ifndef NO_OLD_BOTNET
1500 {"actchan", (IntFunc) bot_actchan},
1501 #endif
1502 {"aw", (IntFunc) bot_away},
1503 {"away", (IntFunc) bot_away},
1504 {"bye", (IntFunc) bot_bye},
1505 {"c", (IntFunc) bot_chan2},
1506 #ifndef NO_OLD_BOTNET
1507 {"chan", (IntFunc) bot_chan2},
1508 {"chat", (IntFunc) bot_chat},
1509 #endif
1510 {"ct", (IntFunc) bot_chat},
1511 {"e", (IntFunc) bot_error},
1512 {"el", (IntFunc) bot_endlink},
1513 #ifndef NO_OLD_BOTNET
1514 {"error", (IntFunc) bot_error},
1515 #endif
1516 {"f!", (IntFunc) bot_filereject},
1517 #ifndef NO_OLD_BOTNET
1518 {"filereject", (IntFunc) bot_filereject},
1519 {"filereq", (IntFunc) bot_filereq},
1520 {"filesend", (IntFunc) bot_filesend},
1521 #endif
1522 {"fr", (IntFunc) bot_filereq},
1523 {"fs", (IntFunc) bot_filesend},
1524 {"h", (IntFunc) bot_handshake},
1525 #ifndef NO_OLD_BOTNET
1526 {"handshake", (IntFunc) bot_handshake},
1527 #endif
1528 {"i", (IntFunc) bot_idle},
1529 {"i?", (IntFunc) bot_infoq},
1530 #ifndef NO_OLD_BOTNET
1531 {"idle", (IntFunc) bot_idle},
1532 {"info?", (IntFunc) bot_infoq},
1533 #endif
1534 {"j", (IntFunc) bot_join},
1535 #ifndef NO_OLD_BOTNET
1536 {"join", (IntFunc) bot_join},
1537 #endif
1538 {"l", (IntFunc) bot_link},
1539 #ifndef NO_OLD_BOTNET
1540 {"link", (IntFunc) bot_link},
1541 {"linked", (IntFunc) bot_linked},
1542 #endif
1543 {"m", (IntFunc) bot_motd},
1544 #ifndef NO_OLD_BOTNET
1545 {"motd", (IntFunc) bot_motd},
1546 #endif
1547 {"n", (IntFunc) bot_nlinked},
1548 {"nc", (IntFunc) bot_nickchange},
1549 #ifndef NO_OLD_BOTNET
1550 {"nlinked", (IntFunc) bot_nlinked},
1551 #endif
1552 {"p", (IntFunc) bot_priv},
1553 #ifndef NO_OLD_BOTNET
1554 {"part", (IntFunc) bot_part},
1555 #endif
1556 {"pi", (IntFunc) bot_ping},
1557 #ifndef NO_OLD_BOTNET
1558 {"ping", (IntFunc) bot_ping},
1559 #endif
1560 {"po", (IntFunc) bot_pong},
1561 #ifndef NO_OLD_BOTNET
1562 {"pong", (IntFunc) bot_pong},
1563 {"priv", (IntFunc) bot_priv},
1564 #endif
1565 {"pt", (IntFunc) bot_part},
1566 {"r", (IntFunc) bot_reject},
1567 #ifndef NO_OLD_BOTNET
1568 {"reject", (IntFunc) bot_reject},
1569 #endif
1570 {"s", (IntFunc) bot_share},
1571 #ifdef TLS
1572 {"starttls", (IntFunc) bot_starttls},
1573 #endif
1574 {"t", (IntFunc) bot_trace},
1575 {"tb", (IntFunc) bot_thisbot},
1576 {"td", (IntFunc) bot_traced},
1577 #ifndef NO_OLD_BOTNET
1578 {"thisbot", (IntFunc) bot_thisbot},
1579 {"trace", (IntFunc) bot_trace},
1580 {"traced", (IntFunc) bot_traced},
1581 #endif
1582 {"u", (IntFunc) bot_update},
1583 #ifndef NO_OLD_BOTNET
1584 {"uf-no", (IntFunc) bot_ufno},
1585 #endif
1586 {"ul", (IntFunc) bot_unlink},
1587 {"un", (IntFunc) bot_unlinked},
1588 #ifndef NO_OLD_BOTNET
1589 {"unaway", (IntFunc) bot_away},
1590 {"unlink", (IntFunc) bot_unlink},
1591 {"unlinked", (IntFunc) bot_unlinked},
1592 {"update", (IntFunc) bot_update},
1593 {"userfile?", (IntFunc) bot_old_userfile},
1594 #endif
1595 {"v", (IntFunc) bot_versions},
1596 {"w", (IntFunc) bot_who},
1597 #ifndef NO_OLD_BOTNET
1598 {"who", (IntFunc) bot_who},
1599 #endif
1600 {"z", (IntFunc) bot_zapf},
1601 #ifndef NO_OLD_BOTNET
1602 {"zapf", (IntFunc) bot_zapf},
1603 {"zapf-broad", (IntFunc) bot_zapfbroad},
1604 #endif
1605 {"zb", (IntFunc) bot_zapfbroad},
1606 {NULL, NULL}
1607 };

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23