1 /*
2 * botmsg.c -- handles:
3 * formatting of messages to be sent on the botnet
4 * sending different messages to different versioned bots
5 *
6 * by Darrin Smith (beldin@light.iinet.net.au)
7 */
8 /*
9 * Copyright (C) 1997 Robey Pointer
10 * Copyright (C) 1999 - 2021 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
30 extern struct dcc_t *dcc;
31 extern int dcc_total, tands;
32 extern char botnetnick[];
33 extern party_t *party;
34 extern Tcl_Interp *interp;
35 extern struct userrec *userlist;
36
37 static char OBUF[1024];
38
39
40 #ifndef NO_OLD_BOTNET
41 /* Ditto for tandem bots
42 */
EGG_VARARGS_DEF(int,arg1)43 void tandout_but EGG_VARARGS_DEF(int, arg1)
44 {
45 int i, x, len;
46 char *format;
47 char s[511];
48 va_list va;
49
50 x = EGG_VARARGS_START(int, arg1, va);
51 format = va_arg(va, char *);
52
53 len = egg_vsnprintf(s, sizeof s, format, va);
54 va_end(va);
55 if (len >= sizeof s) {
56 len = sizeof s - 1;
57 s[len] = 0;
58 }
59
60 for (i = 0; i < dcc_total; i++)
61 if ((dcc[i].type == &DCC_BOT) && (i != x) && (b_numver(i) < NEAT_BOTNET))
62 dprint(i, s, len);
63 }
64 #endif
65
66 /* Thank you ircu :) */
67 static char tobase64array[64] = {
68 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
69 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
70 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
71 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
72 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
73 '[', ']'
74 };
75
int_to_base64(unsigned int val)76 char *int_to_base64(unsigned int val)
77 {
78 static char buf_base64[12];
79 int i = 11;
80
81 buf_base64[11] = 0;
82 if (!val) {
83 buf_base64[10] = 'A';
84 return buf_base64 + 10;
85 }
86 while (val) {
87 i--;
88 buf_base64[i] = tobase64array[val & 0x3f];
89 val = val >> 6;
90 }
91 return buf_base64 + i;
92 }
93
int_to_base10(int val)94 char *int_to_base10(int val)
95 {
96 static char buf_base10[17];
97 int p = 0;
98 int i = 16;
99
100 buf_base10[16] = 0;
101 if (!val) {
102 buf_base10[15] = '0';
103 return buf_base10 + 15;
104 }
105 if (val < 0) {
106 p = 1;
107 val *= -1;
108 }
109 while (val) {
110 i--;
111 buf_base10[i] = '0' + (val % 10);
112 val /= 10;
113 }
114 if (p) {
115 i--;
116 buf_base10[i] = '-';
117 }
118 return buf_base10 + i;
119 }
120
unsigned_int_to_base10(unsigned int val)121 char *unsigned_int_to_base10(unsigned int val)
122 {
123 static char buf_base10[16];
124 int i = 15;
125
126 buf_base10[15] = 0;
127 if (!val) {
128 buf_base10[14] = '0';
129 return buf_base10 + 14;
130 }
131 while (val) {
132 i--;
133 buf_base10[i] = '0' + (val % 10);
134 val /= 10;
135 }
136 return buf_base10 + i;
137 }
138
EGG_VARARGS_DEF(char *,arg1)139 int simple_sprintf EGG_VARARGS_DEF(char *, arg1)
140 {
141 char *buf, *format, *s;
142 int c = 0, i;
143 va_list va;
144
145 buf = EGG_VARARGS_START(char *, arg1, va);
146 format = va_arg(va, char *);
147
148 while (*format && c < 1023) {
149 if (*format == '%') {
150 format++;
151 switch (*format) {
152 case 's':
153 s = va_arg(va, char *);
154
155 break;
156 case 'd':
157 case 'i':
158 i = va_arg(va, int);
159
160 s = int_to_base10(i);
161 break;
162 case 'D':
163 i = va_arg(va, int);
164
165 s = int_to_base64((unsigned int) i);
166 break;
167 case 'u':
168 i = va_arg(va, unsigned int);
169
170 s = unsigned_int_to_base10(i);
171 break;
172 case '%':
173 buf[c++] = *format++;
174 continue;
175 case 'c':
176 buf[c++] = (char) va_arg(va, int);
177
178 format++;
179 continue;
180 default:
181 continue;
182 }
183 if (s)
184 while (*s && c < 1023)
185 buf[c++] = *s++;
186 format++;
187 } else
188 buf[c++] = *format++;
189 }
190 va_end(va);
191 buf[c] = 0;
192 return c;
193 }
194
195 /* Ditto for tandem bots
196 */
send_tand_but(int x,char * buf,int len)197 void send_tand_but(int x, char *buf, int len)
198 {
199 int i, iso = 0;
200
201 if (len < 0) {
202 /* Very unlikely len would be INT_MIN */
203 len = -len;
204 iso = 1;
205 }
206 for (i = 0; i < dcc_total; i++)
207 if ((dcc[i].type == &DCC_BOT) && (i != x) &&
208 (b_numver(i) >= NEAT_BOTNET) &&
209 (!iso || !(bot_flags(dcc[i].user) & BOT_ISOLATE)))
210 dprint(i, buf, len);
211 }
212
botnet_send_bye()213 void botnet_send_bye()
214 {
215 if (tands > 0) {
216 send_tand_but(-1, "bye\n", 4);
217 #ifndef NO_OLD_BOTNET
218 tandout_but(-1, "bye\n");
219 #endif
220 }
221 }
222
botnet_send_chan(int idx,char * botnick,char * user,int chan,char * data)223 void botnet_send_chan(int idx, char *botnick, char *user, int chan, char *data)
224 {
225 int i;
226
227 if ((tands > 0) && (chan < GLOBAL_CHANS)) {
228 if (user) {
229 i = simple_sprintf(OBUF, "c %s@%s %D %s\n", user, botnick, chan, data);
230 } else {
231 i = simple_sprintf(OBUF, "c %s %D %s\n", botnick, chan, data);
232 }
233 send_tand_but(idx, OBUF, -i);
234 #ifndef NO_OLD_BOTNET
235 tandout_but(idx, "chan %s%s%s %d %s\n", user ? user : "",
236 user ? "@" : "", botnick, chan, data);
237 #endif
238 }
239 }
240
botnet_send_act(int idx,char * botnick,char * user,int chan,char * data)241 void botnet_send_act(int idx, char *botnick, char *user, int chan, char *data)
242 {
243 int i;
244
245 if ((tands > 0) && (chan < GLOBAL_CHANS)) {
246 if (user) {
247 i = simple_sprintf(OBUF, "a %s@%s %D %s\n", user, botnick, chan, data);
248 } else {
249 i = simple_sprintf(OBUF, "a %s %D %s\n", botnick, chan, data);
250 }
251 send_tand_but(idx, OBUF, -i);
252 #ifndef NO_OLD_BOTNET
253 tandout_but(idx, "actchan %s%s%s %d %s\n", user ? user : "",
254 user ? "@" : "", botnick, chan, data);
255 #endif
256 }
257 }
258
botnet_send_chat(int idx,char * botnick,char * data)259 void botnet_send_chat(int idx, char *botnick, char *data)
260 {
261 int i;
262
263 if (tands > 0) {
264 i = simple_sprintf(OBUF, "ct %s %s\n", botnick, data);
265 send_tand_but(idx, OBUF, -i);
266 #ifndef NO_OLD_BOTNET
267 tandout_but(idx, "chat %s %s\n", botnick, data);
268 #endif
269 }
270 }
271
botnet_send_ping(int idx)272 void botnet_send_ping(int idx)
273 {
274 #ifndef NO_OLD_BOTNET
275 if (b_numver(idx) < NEAT_BOTNET)
276 dprintf(idx, "ping\n");
277 else
278 #endif
279 dprintf(idx, "pi\n");
280 }
281
botnet_send_pong(int idx)282 void botnet_send_pong(int idx)
283 {
284 #ifndef NO_OLD_BOTNET
285 if (b_numver(idx) < NEAT_BOTNET)
286 dprintf(idx, "pong\n");
287 else
288 #endif
289 dprintf(idx, "po\n");
290 }
291
EGG_VARARGS_DEF(int,arg1)292 void botnet_send_priv EGG_VARARGS_DEF(int, arg1)
293 {
294 int idx, l;
295 char *from, *to, *tobot, *format;
296 char tbuf[1024];
297 va_list va;
298
299 idx = EGG_VARARGS_START(int, arg1, va);
300 from = va_arg(va, char *);
301 to = va_arg(va, char *);
302 tobot = va_arg(va, char *);
303 format = va_arg(va, char *);
304
305 egg_vsnprintf(tbuf, 450, format, va);
306 va_end(va);
307 tbuf[sizeof(tbuf) - 1] = 0;
308
309 if (tobot) {
310 #ifndef NO_OLD_BOTNET
311 if (b_numver(idx) < NEAT_BOTNET)
312 l = simple_sprintf(OBUF, "priv %s %s@%s %s\n", from, to, tobot, tbuf);
313 else
314 #endif
315 l = simple_sprintf(OBUF, "p %s %s@%s %s\n", from, to, tobot, tbuf);
316 } else {
317 #ifndef NO_OLD_BOTNET
318 if (b_numver(idx) < NEAT_BOTNET)
319 l = simple_sprintf(OBUF, "priv %s %s %s\n", from, to, tbuf);
320 else
321 #endif
322 l = simple_sprintf(OBUF, "p %s %s %s\n", from, to, tbuf);
323 }
324 dprint(idx, OBUF, l);
325 }
326
botnet_send_who(int idx,char * from,char * to,int chan)327 void botnet_send_who(int idx, char *from, char *to, int chan)
328 {
329 int l;
330
331 #ifndef NO_OLD_BOTNET
332 if (b_numver(idx) < NEAT_BOTNET)
333 l = simple_sprintf(OBUF, "who %s %s %d\n", from, to, chan);
334 else
335 #endif
336 l = simple_sprintf(OBUF, "w %s %s %D\n", from, to, chan);
337 dprint(idx, OBUF, l);
338 }
339
botnet_send_infoq(int idx,char * par)340 void botnet_send_infoq(int idx, char *par)
341 {
342 int i = simple_sprintf(OBUF, "i? %s\n", par);
343
344 send_tand_but(idx, OBUF, i);
345 #ifndef NO_OLD_BOTNET
346 tandout_but(idx, "info? %s\n", par);
347 #endif
348 }
349
botnet_send_unlink(int idx,char * who,char * via,char * bot,char * reason)350 void botnet_send_unlink(int idx, char *who, char *via, char *bot, char *reason)
351 {
352 int l;
353
354 #ifndef NO_OLD_BOTNET
355 if (b_numver(idx) < NEAT_BOTNET)
356 l = simple_sprintf(OBUF, "unlink %s %s %s %s\n", who, via, bot, reason);
357 else
358 #endif
359 l = simple_sprintf(OBUF, "ul %s %s %s %s\n", who, via, bot, reason);
360 dprint(idx, OBUF, l);
361 }
362
botnet_send_link(int idx,char * who,char * via,char * bot)363 void botnet_send_link(int idx, char *who, char *via, char *bot)
364 {
365 int l;
366 #ifndef NO_OLD_BOTNET
367 if (b_numver(idx) < NEAT_BOTNET)
368 l = simple_sprintf(OBUF, "link %s %s %s\n", who, via, bot);
369 else
370 #endif
371 l = simple_sprintf(OBUF, "l %s %s %s\n", who, via, bot);
372 dprint(idx, OBUF, l);
373 }
374
botnet_send_unlinked(int idx,char * bot,char * args)375 void botnet_send_unlinked(int idx, char *bot, char *args)
376 {
377 int l;
378
379 if (tands > 0) {
380 l = simple_sprintf(OBUF, "un %s %s\n", bot, args ? args : "");
381 send_tand_but(idx, OBUF, l);
382 #ifndef NO_OLD_BOTNET
383 if ((idx >= 0) && (b_numver(idx) >= NEAT_BOTNET) && args && args[0])
384 tandout_but(idx, "chat %s %s\n", lastbot(bot), args);
385 tandout_but(idx, "unlinked %s\n", bot);
386 #endif
387 }
388 }
389
botnet_send_nlinked(int idx,char * bot,char * next,char flag,int vernum)390 void botnet_send_nlinked(int idx, char *bot, char *next, char flag, int vernum)
391 {
392 int l;
393
394 if (tands > 0) {
395 l = simple_sprintf(OBUF, "n %s %s %c%D\n", bot, next, flag, vernum);
396 send_tand_but(idx, OBUF, l);
397 #ifndef NO_OLD_BOTNET
398 if (flag == '!') {
399 flag = '-';
400 tandout_but(idx, "chat %s %s %s\n", next, NET_LINKEDTO, bot);
401 }
402 tandout_but(idx, "nlinked %s %s %c%d\n", bot, next, flag, vernum);
403 #endif
404 }
405 }
406
botnet_send_traced(int idx,char * bot,char * buf)407 void botnet_send_traced(int idx, char *bot, char *buf)
408 {
409 int l;
410
411 #ifndef NO_OLD_BOTNET
412 if (b_numver(idx) < NEAT_BOTNET)
413 l = simple_sprintf(OBUF, "traced %s %s\n", bot, buf);
414 else
415 #endif
416 l = simple_sprintf(OBUF, "td %s %s\n", bot, buf);
417 dprint(idx, OBUF, l);
418 }
419
botnet_send_trace(int idx,char * to,char * from,char * buf)420 void botnet_send_trace(int idx, char *to, char *from, char *buf)
421 {
422 int l;
423
424 #ifndef NO_OLD_BOTNET
425 if (b_numver(idx) < NEAT_BOTNET)
426 l = simple_sprintf(OBUF, "trace %s %s %s:%s\n", to, from, buf, botnetnick);
427 else
428 #endif
429 l = simple_sprintf(OBUF, "t %s %s %s:%s\n", to, from, buf, botnetnick);
430 dprint(idx, OBUF, l);
431 }
432
botnet_send_update(int idx,tand_t * ptr)433 void botnet_send_update(int idx, tand_t *ptr)
434 {
435 int l;
436
437 if (tands > 0) {
438 l = simple_sprintf(OBUF, "u %s %c%D\n", ptr->bot, ptr->share, ptr->ver);
439 send_tand_but(idx, OBUF, l);
440 #ifndef NO_OLD_BOTNET
441 tandout_but(idx, "update %s %c%d\n", ptr->bot, ptr->share, ptr->ver);
442 #endif
443 }
444 }
445
botnet_send_reject(int idx,char * fromp,char * frombot,char * top,char * tobot,char * reason)446 void botnet_send_reject(int idx, char *fromp, char *frombot, char *top,
447 char *tobot, char *reason)
448 {
449 int l;
450 char to[NOTENAMELEN + 1], from[NOTENAMELEN + 1];
451
452 if (!(bot_flags(dcc[idx].user) & BOT_ISOLATE)) {
453 if (tobot) {
454 simple_sprintf(to, "%s@%s", top, tobot);
455 top = to;
456 }
457 if (frombot) {
458 simple_sprintf(from, "%s@%s", fromp, frombot);
459 fromp = from;
460 }
461 if (!reason)
462 reason = "";
463 #ifndef NO_OLD_BOTNET
464 if (b_numver(idx) < NEAT_BOTNET)
465 l = simple_sprintf(OBUF, "reject %s %s %s\n", fromp, top, reason);
466 else
467 #endif
468 l = simple_sprintf(OBUF, "r %s %s %s\n", fromp, top, reason);
469 dprint(idx, OBUF, l);
470 }
471 }
472
botnet_send_zapf(int idx,char * a,char * b,char * c)473 void botnet_send_zapf(int idx, char *a, char *b, char *c)
474 {
475 int l;
476
477 #ifndef NO_OLD_BOTNET
478 if (b_numver(idx) < NEAT_BOTNET)
479 l = simple_sprintf(OBUF, "zapf %s %s %s\n", a, b, c);
480 else
481 #endif
482 l = simple_sprintf(OBUF, "z %s %s %s\n", a, b, c);
483 dprint(idx, OBUF, l);
484 }
485
botnet_send_zapf_broad(int idx,char * a,char * b,char * c)486 void botnet_send_zapf_broad(int idx, char *a, char *b, char *c)
487 {
488 int l;
489
490 if (tands > 0) {
491 l = simple_sprintf(OBUF, "zb %s %s%s%s\n", a, b ? b : "", b ? " " : "", c);
492 send_tand_but(idx, OBUF, l);
493 #ifndef NO_OLD_BOTNET
494 tandout_but(idx, "zapf-broad %s\n", OBUF + 3);
495 #endif
496 }
497 }
498
botnet_send_motd(int idx,char * from,char * to)499 void botnet_send_motd(int idx, char *from, char *to)
500 {
501 int l;
502
503 #ifndef NO_OLD_BOTNET
504 if (b_numver(idx) < NEAT_BOTNET)
505 l = simple_sprintf(OBUF, "motd %s %s\n", from, to);
506 else
507 #endif
508 l = simple_sprintf(OBUF, "m %s %s\n", from, to);
509 dprint(idx, OBUF, l);
510 }
511
botnet_send_filereject(int idx,char * path,char * from,char * reason)512 void botnet_send_filereject(int idx, char *path, char *from, char *reason)
513 {
514 int l;
515
516 #ifndef NO_OLD_BOTNET
517 if (b_numver(idx) < NEAT_BOTNET)
518 l = simple_sprintf(OBUF, "filereject %s %s %s\n", path, from, reason);
519 else
520 #endif
521 l = simple_sprintf(OBUF, "f! %s %s %s\n", path, from, reason);
522 dprint(idx, OBUF, l);
523 }
524
botnet_send_filesend(int idx,char * path,char * from,char * data)525 void botnet_send_filesend(int idx, char *path, char *from, char *data)
526 {
527 int l;
528
529 #ifndef NO_OLD_BOTNET
530 if (b_numver(idx) < NEAT_BOTNET)
531 l = simple_sprintf(OBUF, "filesend %s %s %s\n", path, from, data);
532 else
533 #endif
534 l = simple_sprintf(OBUF, "fs %s %s %s\n", path, from, data);
535 dprint(idx, OBUF, l);
536 }
537
botnet_send_filereq(int idx,char * from,char * bot,char * path)538 void botnet_send_filereq(int idx, char *from, char *bot, char *path)
539 {
540 int l;
541
542 #ifndef NO_OLD_BOTNET
543 if (b_numver(idx) < NEAT_BOTNET)
544 l = simple_sprintf(OBUF, "filereq %s %s:%s\n", from, bot, path);
545 else
546 #endif
547 l = simple_sprintf(OBUF, "fr %s %s:%s\n", from, bot, path);
548 dprint(idx, OBUF, l);
549 }
550
botnet_send_idle(int idx,char * bot,int sock,int idle,char * away)551 void botnet_send_idle(int idx, char *bot, int sock, int idle, char *away)
552 {
553 int l;
554
555 if (tands > 0) {
556 l = simple_sprintf(OBUF, "i %s %D %D %s\n", bot, sock, idle,
557 away ? away : "");
558 send_tand_but(idx, OBUF, -l);
559 #ifndef NO_OLD_BOTNET
560 if (away && away[0])
561 tandout_but(idx, "away %s %d %s\n", bot, sock, away);
562 tandout_but(idx, "idle %s %d %d\n", bot, sock, idle);
563 #endif
564 }
565 }
566
botnet_send_away(int idx,char * bot,int sock,char * msg,int linking)567 void botnet_send_away(int idx, char *bot, int sock, char *msg, int linking)
568 {
569 int l;
570
571 if (tands > 0) {
572 l = simple_sprintf(OBUF, "aw %s%s %D %s\n",
573 ((idx >= 0) && linking) ? "!" : "",
574 bot, sock, msg ? msg : "");
575 send_tand_but(idx, OBUF, -l);
576 #ifndef NO_OLD_BOTNET
577 if (msg) {
578 if (idx < 0) {
579 tandout_but(idx, "chan %s %d %s is now away: %s.\n", bot,
580 dcc[linking].u.chat->channel, dcc[linking].nick, msg);
581 } else if ((b_numver(idx) >= NEAT_BOTNET)) {
582 int partyidx = getparty(bot, sock);
583
584 if (partyidx >= 0)
585 tandout_but(idx, "chan %s %d %s %s: %s.\n", bot,
586 party[partyidx].chan, party[partyidx].nick,
587 NET_AWAY, msg);
588 }
589 tandout_but(idx, "away %s %d %s\n", bot, sock, msg);
590 } else {
591 if (idx < 0) {
592 tandout_but(idx, "chan %s %d %s %s.\n", bot,
593 dcc[linking].u.chat->channel, dcc[linking].nick,
594 NET_UNAWAY);
595 } else if (b_numver(idx) >= NEAT_BOTNET) {
596 int partyidx = getparty(bot, sock);
597
598 if (partyidx >= 0)
599 tandout_but(idx, "chan %s %d %s %s.\n", bot,
600 party[partyidx].chan, party[partyidx].nick, NET_UNAWAY);
601 }
602 tandout_but(idx, "unaway %s %d\n", bot, sock);
603 }
604 #endif
605 }
606 }
607
botnet_send_join_idx(int useridx,int oldchan)608 void botnet_send_join_idx(int useridx, int oldchan)
609 {
610 int l;
611
612 if (tands > 0) {
613 l = simple_sprintf(OBUF, "j %s %s %D %c%D %s\n",
614 botnetnick, dcc[useridx].nick,
615 dcc[useridx].u.chat->channel, geticon(useridx),
616 dcc[useridx].sock, dcc[useridx].host);
617 send_tand_but(-1, OBUF, -l);
618 #ifndef NO_OLD_BOTNET
619 tandout_but(-1, "join %s %s %d %c%d %s\n", botnetnick,
620 dcc[useridx].nick, dcc[useridx].u.chat->channel,
621 geticon(useridx), dcc[useridx].sock, dcc[useridx].host);
622 tandout_but(-1, "chan %s %d %s %s %s.\n",
623 botnetnick, dcc[useridx].u.chat->channel,
624 dcc[useridx].nick, NET_JOINEDTHE,
625 dcc[useridx].u.chat->channel ? "channel" : "party line");
626 if ((oldchan >= 0) && (oldchan < GLOBAL_CHANS)) {
627 tandout_but(-1, "chan %s %d %s %s %s.\n",
628 botnetnick, oldchan,
629 dcc[useridx].nick, NET_LEFTTHE,
630 oldchan ? "channel" : "party line");
631 }
632 #endif
633 }
634 }
635
botnet_send_join_party(int idx,int linking,int useridx,int oldchan)636 void botnet_send_join_party(int idx, int linking, int useridx, int oldchan)
637 {
638 int l;
639
640 if (tands > 0) {
641 l = simple_sprintf(OBUF, "j %s%s %s %D %c%D %s\n", linking ? "!" : "",
642 party[useridx].bot, party[useridx].nick,
643 party[useridx].chan, party[useridx].flag,
644 party[useridx].sock,
645 party[useridx].from ? party[useridx].from : "");
646 send_tand_but(idx, OBUF, -l);
647 #ifndef NO_OLD_BOTNET
648 tandout_but(idx, "join %s %s %d %c%d %s\n", party[useridx].bot,
649 party[useridx].nick, party[useridx].chan,
650 party[useridx].flag, party[useridx].sock,
651 party[useridx].from ? party[useridx].from : "");
652 if ((idx < 0) || (!linking && (b_numver(idx) >= NEAT_BOTNET))) {
653 tandout_but(idx, "chan %s %d %s %s %s.\n",
654 party[useridx].bot, party[useridx].chan,
655 party[useridx].nick, NET_JOINEDTHE,
656 party[useridx].chan ? "channel" : "party line");
657 }
658 if ((oldchan >= 0) && (oldchan < GLOBAL_CHANS) &&
659 ((idx < 0) || (b_numver(idx) >= NEAT_BOTNET))) {
660 tandout_but(idx, "chan %s %d %s %s %s.\n",
661 party[useridx].bot, oldchan, party[useridx].nick,
662 NET_LEFTTHE, party[useridx].chan ? "channel" : "party line");
663 }
664 #endif
665 }
666 }
667
botnet_send_part_idx(int useridx,char * reason)668 void botnet_send_part_idx(int useridx, char *reason)
669 {
670 int l = simple_sprintf(OBUF, "pt %s %s %D %s\n", botnetnick,
671 dcc[useridx].nick, dcc[useridx].sock,
672 reason ? reason : "");
673
674 if (tands > 0) {
675 send_tand_but(-1, OBUF, -l);
676 #ifndef NO_OLD_BOTNET
677 tandout_but(-1, "part %s %s %d\n", botnetnick,
678 dcc[useridx].nick, dcc[useridx].sock);
679 tandout_but(-1, "chan %s %d %s has left the %s%s%s.\n",
680 botnetnick, dcc[useridx].u.chat->channel,
681 dcc[useridx].nick,
682 dcc[useridx].u.chat->channel ? "channel" : "party line",
683 reason ? ": " : "", reason ? reason : "");
684 #endif
685 }
686 }
687
botnet_send_part_party(int idx,int partyidx,char * reason,int silent)688 void botnet_send_part_party(int idx, int partyidx, char *reason, int silent)
689 {
690 int l;
691
692 if (tands > 0) {
693 l = simple_sprintf(OBUF, "pt %s%s %s %D %s\n",
694 silent ? "!" : "", party[partyidx].bot,
695 party[partyidx].nick, party[partyidx].sock,
696 reason ? reason : "");
697 send_tand_but(idx, OBUF, -l);
698 #ifndef NO_OLD_BOTNET
699 tandout_but(idx, "part %s %s %d\n", party[partyidx].bot,
700 party[partyidx].nick, party[partyidx].sock);
701 if (((idx < 0) || (b_numver(idx) >= NEAT_BOTNET)) && !silent) {
702 tandout_but(idx, "chan %s %d %s has left the %s%s%s.\n",
703 party[partyidx].bot, party[partyidx].chan,
704 party[partyidx].nick,
705 party[partyidx].chan ? "channel" : "party line",
706 reason ? ": " : "", reason ? reason : "");
707 }
708 #endif
709 }
710 }
711
botnet_send_nkch(int useridx,char * oldnick)712 void botnet_send_nkch(int useridx, char *oldnick)
713 {
714 int l;
715
716 if (tands > 0) {
717 l = simple_sprintf(OBUF, "nc %s %D %s\n", botnetnick,
718 dcc[useridx].sock, dcc[useridx].nick);
719 send_tand_but(-1, OBUF, -l);
720 #ifndef NO_OLD_BOTNET
721 tandout_but(-1, "part %s %s %d\n", botnetnick,
722 dcc[useridx].nick, dcc[useridx].sock);
723 tandout_but(-1, "join %s %s %d %c%d %s\n", botnetnick,
724 dcc[useridx].nick, dcc[useridx].u.chat->channel,
725 geticon(useridx), dcc[useridx].sock, dcc[useridx].host);
726 tandout_but(-1, "chan %s %d %s: %s -> %s.\n",
727 botnetnick, dcc[useridx].u.chat->channel,
728 oldnick, NET_NICKCHANGE, dcc[useridx].nick);
729 #endif
730 }
731 }
732
botnet_send_nkch_part(int butidx,int useridx,char * oldnick)733 void botnet_send_nkch_part(int butidx, int useridx, char *oldnick)
734 {
735 int l;
736
737 if (tands > 0) {
738 l = simple_sprintf(OBUF, "nc %s %D %s\n", party[useridx].bot,
739 party[useridx].sock, party[useridx].nick);
740 send_tand_but(butidx, OBUF, -l);
741 #ifndef NO_OLD_BOTNET
742 tandout_but(butidx, "part %s %s %d\n", party[useridx].bot,
743 party[useridx].nick, party[useridx].sock);
744 tandout_but(butidx, "join %s %s %d %c%d %s\n", party[useridx].bot,
745 party[useridx].nick, party[useridx].chan,
746 party[useridx].flag, party[useridx].sock,
747 party[useridx].from ? party[useridx].from : "");
748 tandout_but(butidx, "chan %s %d %s : %s -> %s.\n",
749 party[useridx].bot, party[useridx].chan,
750 NET_NICKCHANGE, oldnick, party[useridx].nick);
751 #endif
752 }
753 }
754
755 /* This part of add_note is more relevant to the botnet than
756 * to the notes file.
757 */
add_note(char * to,char * from,char * msg,int idx,int echo)758 int add_note(char *to, char *from, char *msg, int idx, int echo)
759 {
760 #define FROMLEN 40
761 int status, i, iaway, sock;
762 char *p, botf[FROMLEN + 1 + HANDLEN + 1], ss[81], ssf[81];
763 struct userrec *u;
764
765 /* Notes have a length limit. Note + PRIVMSG header + nick + date must
766 * be less than 512.
767 */
768 if (strlen(msg) > 450)
769 msg[450] = 0;
770
771 /* Is this a cross-bot note? If it is, 'to' will be of the format
772 * 'user@bot'.
773 */
774 p = strchr(to, '@');
775 if (p != NULL) {
776 char x[21];
777
778 *p = 0;
779 strlcpy(x, to, sizeof x);
780 *p = '@';
781 p++;
782
783 if (!strcasecmp(p, botnetnick)) /* To me?? */
784 return add_note(x, from, msg, idx, echo); /* Start over, dimwit. */
785
786 if (strcasecmp(from, botnetnick)) {
787 if (strlen(from) > FROMLEN)
788 from[FROMLEN] = 0;
789
790 if (strchr(from, '@')) {
791 strcpy(botf, from);
792 } else
793 sprintf(botf, "%s@%s", from, botnetnick);
794
795 } else
796 strcpy(botf, botnetnick);
797
798 i = nextbot(p);
799 if (i < 0) {
800 if (idx >= 0)
801 dprintf(idx, BOT_NOTHERE);
802
803 return NOTE_ERROR;
804 }
805
806 if (idx >= 0 && echo)
807 dprintf(idx, "-> %s@%s: %s\n", x, p, msg);
808
809 if (idx >= 0) {
810 sprintf(ssf, "%lu:%s", dcc[idx].sock, botf);
811 botnet_send_priv(i, ssf, x, p, "%s", msg);
812 } else
813 botnet_send_priv(i, botf, x, p, "%s", msg);
814
815 return NOTE_OK; /* Forwarded to the right bot */
816 }
817
818 /* Might be form "sock:nick" */
819 splitc(ssf, from, ':');
820 rmspace(ssf);
821 splitc(ss, to, ':');
822 rmspace(ss);
823 if (!ss[0])
824 sock = -1;
825 else
826 sock = atoi(ss);
827
828 /* Don't process if there's a note binding for it */
829 if (idx != -2) { /* Notes from bots don't trigger it */
830 if (check_tcl_note(from, to, msg)) {
831 if (idx >= 0 && echo)
832 dprintf(idx, "-> %s: %s\n", to, msg);
833
834 return NOTE_TCL;
835 }
836 }
837
838 /* Valid user? */
839 u = get_user_by_handle(userlist, to);
840 if (!u) {
841 if (idx >= 0)
842 dprintf(idx, USERF_UNKNOWN);
843
844 return NOTE_ERROR;
845 }
846
847 /* Is the note to a bot? */
848 if (is_bot(u)) {
849 if (idx >= 0)
850 dprintf(idx, BOT_NONOTES);
851
852 return NOTE_ERROR;
853 }
854
855 /* Is user rejecting notes from this source? */
856 if (match_noterej(u, from)) {
857 if (idx >= 0)
858 dprintf(idx, "%s rejected your note.\n", u->handle);
859
860 return NOTE_REJECT;
861 }
862
863 status = NOTE_STORED;
864 iaway = 0;
865
866 /* Online right now? */
867 for (i = 0; i < dcc_total; i++) {
868 if ((dcc[i].type->flags & DCT_GETNOTES) &&
869 (sock == -1 || sock == dcc[i].sock) &&
870 !strcasecmp(dcc[i].nick, to)) {
871 int aok = 1;
872
873 if (dcc[i].type == &DCC_CHAT) {
874
875 /* Only check away if it's not from a bot. */
876 if (dcc[i].u.chat->away != NULL && idx != -2) {
877 aok = 0;
878
879 if (idx >= 0)
880 dprintf(idx, "%s %s: %s\n", dcc[i].nick, BOT_USERAWAY,
881 dcc[i].u.chat->away);
882
883 if (!iaway)
884 iaway = i;
885 status = NOTE_AWAY;
886 }
887 }
888
889 if (aok) {
890 char *p, *fr = from, work[1024];
891 int l = 0;
892
893 while (*msg == '<' || *msg == '>') {
894 p = newsplit(&msg);
895
896 if (*p == '<')
897 l += simple_sprintf(work + l, "via %s, ", p + 1);
898 else if (*from == '@')
899 fr = p + 1;
900 }
901
902 if (idx == -2 || !strcasecmp(from, botnetnick))
903 dprintf(i, "*** [%s] %s%s\n", fr, l ? work : "", msg);
904 else
905 dprintf(i, "%cNote [%s]: %s%s\n", 7, fr, l ? work : "", msg);
906
907 if (idx >= 0 && echo)
908 dprintf(idx, "-> %s: %s\n", to, msg);
909
910 return NOTE_OK;
911 }
912 }
913 }
914
915 if (idx == -2)
916 return NOTE_OK; /* Error msg from a tandembot: don't store. */
917
918 /* Call 'storenote' Tcl command. */
919 snprintf(ss, sizeof ss, "%ld", (idx >= 0) ? dcc[idx].sock : -1);
920 Tcl_SetVar(interp, "_from", from, 0);
921 Tcl_SetVar(interp, "_to", to, 0);
922 Tcl_SetVar(interp, "_data", msg, 0);
923 Tcl_SetVar(interp, "_idx", ss, 0);
924 if (Tcl_VarEval(interp, "storenote", " $_from $_to $_data $_idx", NULL) ==
925 TCL_OK) {
926
927 if (!tcl_resultempty())
928 status = NOTE_FWD;
929
930 /* User is away in all sessions -- just notify the user that a
931 * message arrived and was stored (only oldest session is notified).
932 */
933 if (status == NOTE_AWAY)
934 dprintf(iaway, "*** %s.\n", BOT_NOTEARRIVED);
935
936 return status;
937 }
938
939 /* If we haven't returned anything else by now, assume an error occurred. */
940 return NOTE_ERROR;
941 }
942