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