/[cvs]/eggdrop1.4/src/dcc.c
ViewVC logotype

Annotation of /eggdrop1.4/src/dcc.c

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


Revision 1.18 - (hide annotations) (download) (as text)
Fri Nov 5 21:54:33 1999 UTC (19 years, 11 months ago) by guppy
Branch: MAIN
Changes since 1.17: +2 -0 lines
File MIME type: text/x-chdr
minor patches

1 segfault 1.1 /*
2     * dcc.c -- handles:
3     * activity on a dcc socket
4     * disconnect on a dcc socket
5     * ...and that's it! (but it's a LOT)
6     * dprintf'ized, 27oct1995
7     */
8     /*
9     * This file is part of the eggdrop source code
10     * copyright (c) 1997 Robey Pointer
11     * and is distributed according to the GNU general public license.
12     * For full details, read the top of 'main.c' or the file called
13     * COPYING that was distributed with this code.
14     */
15    
16     #include "main.h"
17     #include <ctype.h>
18     #include <errno.h>
19     #include "modules.h"
20     #include "tandem.h"
21    
22 guppy 1.7 /* includes for botnet md5 challenge/response code <cybah> */
23     #include "md5/global.h"
24     #include "md5/md5.h"
25    
26 segfault 1.1 extern struct userrec *userlist;
27     extern struct chanset_t *chanset;
28     extern Tcl_Interp *interp;
29     extern time_t now;
30     extern int egg_numver, connect_timeout, conmask, backgrd, max_dcc;
31     extern int make_userfile, default_flags, debug_output, ignore_time;
32     extern char botnetnick[], ver[], origbotname[], notify_new[];
33    
34     struct dcc_t *dcc = 0; /* dcc list */
35     int dcc_total = 0; /* total dcc's */
36     char tempdir[121] = ""; /* temporary directory (default: current dir) */
37     int require_p = 0; /* require 'p' access to get on the party line? */
38     int allow_new_telnets = 0; /* allow people to introduce themselves via telnet */
39 guppy 1.6 int stealth_telnets = 0; /* be paranoid? <cybah> */
40     int use_telnet_banner = 0; /* display telnet banner? [seC] */
41 segfault 1.1 char network[41] = "unknown-net"; /* name of the IRC network you're on */
42     int password_timeout = 180; /* time to wait for a password from a user */
43     int bot_timeout = 60; /* bot timeout value */
44     int identtimeout = 5; /* timeout value for ident lookups */
45     int protect_telnet = 1; /* even bother with ident lookups :) */
46     int flood_telnet_thr = 5; /* number of telnet connections to be considered a flood */
47     int flood_telnet_time = 60; /* in how many seconds? */
48     extern int min_dcc_port, max_dcc_port; /* valid portrange for telnets */
49 segfault 1.2 extern int par_telnet_flood; /* trigger telnet flood for +f ppl? */
50 guppy 1.5 char bannerfile[121] = "telnet-banner"; /* file displayed on telnet login */
51 segfault 1.1
52     static void strip_telnet(int sock, char *buf, int *len)
53     {
54     unsigned char *p = (unsigned char *) buf, *o = (unsigned char *) buf;
55     int mark;
56    
57     while (*p != 0) {
58     while ((*p != 255) && (*p != 0))
59     *o++ = *p++;
60     if (*p == 255) {
61     p++;
62     mark = 2;
63     if (!*p)
64     mark = 1; /* bogus */
65     if ((*p >= 251) && (*p <= 254)) {
66     mark = 3;
67     if (!*(p + 1))
68     mark = 2; /* bogus */
69     }
70     if (*p == 251) {
71     /* WILL X -> response: DONT X */
72     /* except WILL ECHO which we just smile and ignore */
73     if (!(*(p + 1) == 1)) {
74     write(sock, "\377\376", 2);
75     write(sock, p + 1, 1);
76     }
77     }
78     if (*p == 253) {
79     /* DO X -> response: WONT X */
80     /* except DO ECHO which we just smile and ignore */
81     if (!(*(p + 1) == 1)) {
82     write(sock, "\377\374", 2);
83     write(sock, p + 1, 1);
84     }
85     }
86     if (*p == 246) {
87     /* "are you there?" */
88     /* response is: "hell yes!" */
89     write(sock, "\r\nHell, yes!\r\n", 14);
90     }
91     /* anything else can probably be ignored */
92     p += mark - 1;
93     *len = *len - mark;
94     }
95     }
96     *o = *p;
97     }
98    
99     static void greet_new_bot(int idx)
100     {
101     int bfl = bot_flags(dcc[idx].user);
102     int i;
103    
104     dcc[idx].timeval = now;
105     dcc[idx].u.bot->version[0] = 0;
106     dcc[idx].u.bot->numver = 0;
107     if (bfl & BOT_REJECT) {
108     putlog(LOG_BOTS, "*", DCC_REJECT, dcc[idx].nick);
109     dprintf(idx, "error You are being rejected.\n");
110     dprintf(idx, "bye\n");
111     killsock(dcc[idx].sock);
112     lostdcc(idx);
113     return;
114     }
115     if (bfl & BOT_LEAF)
116     dcc[idx].status |= STAT_LEAF;
117     dcc[idx].status |= STAT_LINKING;
118     #ifndef NO_OLD_BOTNET
119     dprintf(idx, "version %d %d %s <%s>\n", egg_numver, HANDLEN, ver, network);
120     #else
121     dprintf(idx, "v %d %d %s <%s>\n", egg_numver, HANDLEN, ver, network);
122     #endif
123     for (i = 0; i < dcc_total; i++)
124     if (dcc[i].type == &DCC_FORK_BOT) {
125     killsock(dcc[i].sock);
126     lostdcc(i);
127     i--;
128     }
129     }
130    
131     static void bot_version(int idx, char *par)
132     {
133     char x[1024];
134     int l;
135    
136     context;
137     dcc[idx].timeval = now;
138     if ((par[0] >= '0') && (par[0] <= '9')) {
139     char *work;
140    
141     work = newsplit(&par);
142     dcc[idx].u.bot->numver = atoi(work);
143     } else
144     dcc[idx].u.bot->numver = 0;
145    
146     #ifndef NO_OLD_BOTNET
147     if (b_numver(idx) < NEAT_BOTNET) {
148     #if HANDLEN != 9
149     dprintf(idx, "error Non-matching handle length: mine %d, yours 9\n",
150     HANDLEN);
151     dprintf(idx, "bye\n");
152     killsock(dcc[idx].sock);
153     lostdcc(idx);
154     return;
155     #else
156     dprintf(idx, "thisbot %s\n", botnetnick);
157     #endif
158     } else {
159     #endif
160     dprintf(idx, "tb %s\n", botnetnick);
161     l = atoi(newsplit(&par));
162     if (l != HANDLEN) {
163     dprintf(idx, "error Non-matching handle length: mine %d, yours %d\n",
164     HANDLEN, l);
165     dprintf(idx, "bye\n");
166     killsock(dcc[idx].sock);
167     lostdcc(idx);
168     return;
169     }
170     #ifndef NO_OLD_BOTNET
171     }
172     #endif
173     strncpy(dcc[idx].u.bot->version, par, 120);
174     dcc[idx].u.bot->version[120] = 0;
175     putlog(LOG_BOTS, "*", DCC_LINKED, dcc[idx].nick);
176     chatout("*** Linked to %s\n", dcc[idx].nick);
177     botnet_send_nlinked(idx, dcc[idx].nick, botnetnick, '!',
178     dcc[idx].u.bot->numver);
179     dump_links(idx);
180     dcc[idx].type = &DCC_BOT;
181     addbot(dcc[idx].nick, dcc[idx].nick, botnetnick, '-',
182     dcc[idx].u.bot->numver);
183     check_tcl_link(dcc[idx].nick, botnetnick);
184     simple_sprintf(x, "v %d", dcc[idx].u.bot->numver);
185     bot_share(idx, x);
186     dprintf(idx, "el\n");
187     }
188    
189     void failed_link(int idx)
190     {
191     char s[81], s1[512];
192    
193     if (dcc[idx].port >= dcc[idx].u.bot->port + 3) {
194     if (dcc[idx].u.bot->linker[0]) {
195     sprintf(s, "Couldn't link to %s.", dcc[idx].nick);
196     strcpy(s1, dcc[idx].u.bot->linker);
197     add_note(s1, botnetnick, s, -2, 0);
198     }
199     if (dcc[idx].u.bot->numver >= (-1))
200     putlog(LOG_BOTS, "*", DCC_LINKFAIL, dcc[idx].nick);
201     killsock(dcc[idx].sock);
202     strcpy(s, dcc[idx].nick);
203     lostdcc(idx);
204     autolink_cycle(s); /* check for more auto-connections */
205     return;
206     }
207     /* try next port */
208     killsock(dcc[idx].sock);
209     dcc[idx].sock = getsock(SOCK_STRONGCONN);
210     dcc[idx].port++;
211     dcc[idx].timeval = now;
212     if (open_telnet_raw(dcc[idx].sock, dcc[idx].host, dcc[idx].port) < 0) {
213     failed_link(idx);
214     }
215     }
216    
217     static void cont_link(int idx, char *buf, int i)
218     {
219 guppy 1.7 char x[1024];
220 segfault 1.1 int atr = bot_flags(dcc[idx].user);
221    
222     context;
223     if (atr & BOT_HUB) {
224     /* disconnect all +a bots because we just got a hub */
225     for (i = 0; i < dcc_total; i++) {
226     if ((i != idx) && (bot_flags(dcc[i].user) & BOT_ALT)) {
227 guppy 1.12 if ((dcc[i].type == &DCC_FORK_BOT) ||
228     (dcc[i].type == &DCC_BOT_NEW)) {
229 segfault 1.1 killsock(dcc[i].sock);
230     lostdcc(i);
231     }
232     }
233     }
234     /* just those currently in the process of linking */
235     if (in_chain(dcc[idx].nick)) {
236     i = nextbot(dcc[idx].nick);
237     if (i > 0) {
238     simple_sprintf(x, "Unlinked %s (restructure)", dcc[i].nick);
239     chatout("*** %s\n", x);
240     botnet_send_unlinked(i, dcc[i].nick, x);
241     dprintf(i, "bye\n");
242     killsock(dcc[i].sock);
243     lostdcc(i);
244     }
245     }
246     }
247     dcc[idx].type = &DCC_BOT_NEW;
248     dcc[idx].u.bot->numver = 0;
249 guppy 1.7
250     /* Don't send our password here, just the username. The code later on
251     * will determine if the password needs to be sent in cleartext or if we
252     * can send an MD5 digest. <cybah>
253     */
254    
255     dprintf(idx, "%s\n", botnetnick);
256 segfault 1.1 return;
257     }
258    
259 guppy 1.7 /* This function generates a digest by combining 'challenge' with
260     * 'password' and then sends it to the other bot. <Cybah>
261     */
262     static void dcc_bot_digest(int idx, char *challenge, char *password)
263     {
264     MD5_CTX Context;
265     char DigestString[33]; /* 32 for digest in hex + null */
266     unsigned char Digest[16];
267     int i;
268    
269     MD5Init(&Context);
270     MD5Update(&Context, (unsigned char *)challenge, strlen(challenge));
271     MD5Update(&Context, (unsigned char *)password, strlen(password));
272     MD5Final(Digest, &Context);
273    
274     for(i=0;i<16;i++)
275     sprintf(DigestString + (i*2), "%.2x", Digest[i]);
276     dprintf(idx, "digest %s\n", DigestString);
277     putlog(LOG_BOTS, "*", "Received challenge from %s... sending response ...", dcc[idx].nick);
278     }
279    
280 segfault 1.1 static void dcc_bot_new(int idx, char *buf, int x)
281     {
282     struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick);
283     char *code;
284    
285     strip_telnet(dcc[idx].sock, buf, &x);
286     code = newsplit(&buf);
287     if (!strcasecmp(code, "*hello!")) {
288     greet_new_bot(idx);
289     } else if (!strcasecmp(code, "version") || !strcasecmp(code, "v")) {
290     bot_version(idx, buf);
291     } else if (!strcasecmp(code, "badpass")) {
292     /* we entered the wrong password */
293     putlog(LOG_BOTS, "*", DCC_BADPASS, dcc[idx].nick);
294     } else if (!strcasecmp(code, "passreq")) {
295 guppy 1.7 char *pass = get_user(&USERENTRY_PASS, u);
296    
297     if (!pass || !strcmp(pass, "-")) {
298 segfault 1.1 putlog(LOG_BOTS, "*", DCC_PASSREQ, dcc[idx].nick);
299     dprintf(idx, "-\n");
300 guppy 1.7 } else {
301     /* Determine if the other end supports an MD5 digest instead of a
302     * cleartext password. <Cybah>
303     */
304     if(buf && buf[0] && strchr(buf, '<') && strchr(buf+1, '>')) {
305     dcc_bot_digest(idx, buf, pass);
306     } else {
307     dprintf(idx, "%s\n", pass);
308     }
309 segfault 1.1 }
310     } else if (!strcasecmp(code, "error")) {
311     putlog(LOG_BOTS, "*", DCC_LINKERROR, dcc[idx].nick, buf);
312     }
313     /* ignore otherwise */
314     }
315    
316     static void eof_dcc_bot_new(int idx)
317     {
318     context;
319     putlog(LOG_BOTS, "*", DCC_LOSTBOT, dcc[idx].nick, dcc[idx].port);
320     killsock(dcc[idx].sock);
321     lostdcc(idx);
322     }
323    
324     static void timeout_dcc_bot_new(int idx)
325     {
326     putlog(LOG_BOTS, "*", DCC_TIMEOUT, dcc[idx].nick,
327     dcc[idx].host, dcc[idx].port);
328     killsock(dcc[idx].sock);
329     lostdcc(idx);
330     }
331    
332     static void display_dcc_bot_new(int idx, char *buf)
333     {
334     sprintf(buf, "bot* waited %lus", now - dcc[idx].timeval);
335     }
336    
337     static int expmem_dcc_bot_(void *x)
338     {
339     return sizeof(struct bot_info);
340     }
341    
342     static void free_dcc_bot_(int n, void *x)
343     {
344     if (dcc[n].type == &DCC_BOT) {
345     unvia(n, findbot(dcc[n].nick));
346     rembot(dcc[n].nick);
347     }
348     nfree(x);
349     }
350    
351     struct dcc_table DCC_BOT_NEW =
352     {
353     "BOT_NEW",
354     0,
355     eof_dcc_bot_new,
356     dcc_bot_new,
357     &bot_timeout,
358     timeout_dcc_bot_new,
359     display_dcc_bot_new,
360     expmem_dcc_bot_,
361     free_dcc_bot_,
362     0
363     };
364    
365     /* hash function for tandem bot commands */
366     extern botcmd_t C_bot[];
367    
368     static void dcc_bot(int idx, char *code, int i)
369     {
370     char *msg;
371     int f;
372    
373     context;
374     strip_telnet(dcc[idx].sock, code, &i);
375     if (debug_output) {
376     if (code[0] == 's')
377     putlog(LOG_BOTSHARE, "*", "{%s} %s", dcc[idx].nick, code + 2);
378     else
379     putlog(LOG_BOTNET, "*", "[%s] %s", dcc[idx].nick, code);
380     }
381     msg = strchr(code, ' ');
382     if (msg) {
383     *msg = 0;
384     msg++;
385     } else
386     msg = "";
387     f = 0;
388     i = 0;
389     while ((C_bot[i].name != NULL) && (!f)) {
390     int y = strcasecmp(code, C_bot[i].name);
391    
392     if (y == 0) {
393     /* found a match */
394     (C_bot[i].func) (idx, msg);
395     f = 1;
396     } else if (y < 0)
397     return;
398     i++;
399     }
400     }
401    
402     static void eof_dcc_bot(int idx)
403     {
404     char x[1024];
405    
406     simple_sprintf(x, "Lost bot: %s", dcc[idx].nick);
407     putlog(LOG_BOTS, "*", "%s.", x);
408     chatout("*** %s\n", x);
409     botnet_send_unlinked(idx, dcc[idx].nick, x);
410     killsock(dcc[idx].sock);
411     lostdcc(idx);
412     }
413    
414     static void display_dcc_bot(int idx, char *buf)
415     {
416     int i = simple_sprintf(buf, "bot flags: ");
417    
418     buf[i++] = b_status(idx) & STAT_PINGED ? 'P' : 'p';
419     buf[i++] = b_status(idx) & STAT_SHARE ? 'U' : 'u';
420     buf[i++] = b_status(idx) & STAT_CALLED ? 'C' : 'c';
421     buf[i++] = b_status(idx) & STAT_OFFERED ? 'O' : 'o';
422     buf[i++] = b_status(idx) & STAT_SENDING ? 'S' : 's';
423     buf[i++] = b_status(idx) & STAT_GETTING ? 'G' : 'g';
424     buf[i++] = b_status(idx) & STAT_WARNED ? 'W' : 'w';
425     buf[i++] = b_status(idx) & STAT_LEAF ? 'L' : 'l';
426     buf[i++] = b_status(idx) & STAT_LINKING ? 'I' : 'i';
427     buf[i++] = b_status(idx) & STAT_AGGRESSIVE ? 'a' : 'A';
428     buf[i++] = 0;
429     }
430    
431     static void display_dcc_fork_bot(int idx, char *buf)
432     {
433     sprintf(buf, "conn bot");
434     }
435    
436     struct dcc_table DCC_BOT =
437     {
438     "BOT",
439     DCT_BOT,
440     eof_dcc_bot,
441     dcc_bot,
442     0,
443     0,
444     display_dcc_bot,
445     expmem_dcc_bot_,
446     free_dcc_bot_,
447     0
448     };
449    
450     struct dcc_table DCC_FORK_BOT =
451     {
452     "FORK_BOT",
453     0,
454     failed_link,
455     cont_link,
456     &connect_timeout,
457     failed_link,
458     display_dcc_fork_bot,
459     expmem_dcc_bot_,
460     free_dcc_bot_,
461     0
462     };
463    
464 guppy 1.7 /* This function generates a digest by combining a challenge consisting of
465     * our process id + connection time + botnetnick. The digest is then compared
466     * to the one given by the remote bot. Returns 1 if the digest matches,
467     * otherwise returns 0. <Cybah>
468     */
469     static int dcc_bot_check_digest(int idx, char *digest)
470     {
471     MD5_CTX Context;
472     char DigestString[33]; /* 32 for digest in hex + null */
473     unsigned char Digest[16];
474     int i;
475     char *password = get_user(&USERENTRY_PASS, dcc[idx].user);
476    
477     MD5Init(&Context);
478    
479 guppy 1.13 #ifdef HAVE_SNPRINTF
480 guppy 1.7 snprintf(DigestString, 33, "<%x%x@", getpid(), (unsigned int)dcc[idx].timeval);
481 guppy 1.13 #else
482     sprintf(DigestString, "<%x%x@", getpid(), (unsigned int)dcc[idx].timeval);
483     #endif
484 guppy 1.7 MD5Update(&Context, (unsigned char *)DigestString, strlen(DigestString));
485     MD5Update(&Context, (unsigned char *)botnetnick, strlen(botnetnick));
486     MD5Update(&Context, (unsigned char *)">", 1);
487     MD5Update(&Context, (unsigned char *)password, strlen(password));
488    
489     MD5Final(Digest, &Context);
490    
491     for(i=0;i<16;i++)
492     sprintf(DigestString + (i*2), "%.2x", Digest[i]);
493    
494     if(!strcmp(DigestString, digest)) {
495     return 1;
496     }
497     putlog(LOG_BOTS, "*", "Response (password hash) from %s incorrect", dcc[idx].nick);
498     return 0;
499     }
500    
501 segfault 1.1 static void dcc_chat_pass(int idx, char *buf, int atr)
502     {
503     if (!atr)
504     return;
505     strip_telnet(dcc[idx].sock, buf, &atr);
506     atr = dcc[idx].user ? dcc[idx].user->flags : 0;
507 guppy 1.7
508     /* Check for MD5 digest from remote _bot_. <cybah> */
509     if ((atr & USER_BOT) && !strncasecmp(buf, "digest ", 7)) {
510     if(dcc_bot_check_digest(idx, buf+7)) {
511     nfree(dcc[idx].u.chat);
512     dcc[idx].type = &DCC_BOT_NEW;
513     dcc[idx].u.bot = get_data_ptr(sizeof(struct bot_info));
514     dcc[idx].status = STAT_CALLED;
515     dprintf(idx, "*hello!\n");
516     greet_new_bot(idx);
517     return;
518     } else {
519     /* invalid password/digest */
520     dprintf(idx, "badpass\n");
521     putlog(LOG_MISC, "*", DCC_BADLOGIN, dcc[idx].nick, dcc[idx].host,
522     dcc[idx].port);
523     killsock(dcc[idx].sock);
524     lostdcc(idx);
525     return;
526     }
527     }
528    
529 segfault 1.1 if (u_pass_match(dcc[idx].user, buf)) {
530     if (atr & USER_BOT) {
531     nfree(dcc[idx].u.chat);
532     dcc[idx].type = &DCC_BOT_NEW;
533     dcc[idx].u.bot = get_data_ptr(sizeof(struct bot_info));
534    
535     dcc[idx].status = STAT_CALLED;
536     dprintf(idx, "*hello!\n");
537     greet_new_bot(idx);
538     } else {
539     /* log entry for successful login -slennox 3/28/1999 */
540     putlog(LOG_MISC, "*", DCC_LOGGEDIN, dcc[idx].nick,
541     dcc[idx].host, dcc[idx].port);
542     if (dcc[idx].u.chat->away) {
543     nfree(dcc[idx].u.chat->away);
544     dcc[idx].u.chat->away = NULL;
545     }
546     dcc[idx].type = &DCC_CHAT;
547     dcc[idx].status &= ~STAT_CHAT;
548     dcc[idx].u.chat->con_flags = (atr & USER_MASTER) ? conmask : 0;
549     dcc[idx].u.chat->channel = -2;
550     if (dcc[idx].status & STAT_TELNET)
551     dprintf(idx, "\377\374\001\n"); /* turn echo back on */
552     dcc_chatter(idx);
553     }
554     } else {
555     if (atr & USER_BOT)
556     dprintf(idx, "badpass\n");
557     else
558     dprintf(idx, DCC_HOUSTON);
559     putlog(LOG_MISC, "*", DCC_BADLOGIN, dcc[idx].nick,
560     dcc[idx].host, dcc[idx].port);
561     if (dcc[idx].u.chat->away) { /* su from a dumb user */
562     if (dcc[idx].status & STAT_TELNET)
563     dprintf(idx, "\377\374\001\n"); /* turn echo back on */
564     dcc[idx].user = get_user_by_handle(userlist, dcc[idx].u.chat->away);
565     strcpy(dcc[idx].nick, dcc[idx].u.chat->away);
566     nfree(dcc[idx].u.chat->away);
567     nfree(dcc[idx].u.chat->su_nick);
568     dcc[idx].u.chat->away = NULL;
569     dcc[idx].u.chat->su_nick = NULL;
570     dcc[idx].type = &DCC_CHAT;
571     if (dcc[idx].u.chat->channel < 100000)
572     botnet_send_join_idx(idx, -1);
573     chanout_but(-1, dcc[idx].u.chat->channel, DCC_JOIN, dcc[idx].nick);
574     } else {
575     killsock(dcc[idx].sock);
576     lostdcc(idx);
577     }
578     }
579     }
580    
581     static void eof_dcc_general(int idx)
582     {
583 arthur2 1.15 putlog(LOG_MISC, "*", DCC_LOSTDCC, dcc[idx].nick,
584 segfault 1.1 dcc[idx].host, dcc[idx].port);
585     killsock(dcc[idx].sock);
586     lostdcc(idx);
587     }
588    
589     static void tout_dcc_chat_pass(int idx)
590     {
591     dprintf(idx, "Timeout.\n");
592 arthur2 1.15 putlog(LOG_MISC, "*", DCC_PWDTIMEOUT, dcc[idx].nick,
593 segfault 1.1 dcc[idx].host);
594     killsock(dcc[idx].sock);
595     lostdcc(idx);
596     }
597    
598     static void display_dcc_chat_pass(int idx, char *buf)
599     {
600     sprintf(buf, "pass waited %lus", now - dcc[idx].timeval);
601     }
602    
603     static int expmem_dcc_general(void *x)
604     {
605     register struct chat_info *p = (struct chat_info *) x;
606     int tot = sizeof(struct chat_info);
607    
608     if (p->away)
609     tot += strlen(p->away) + 1;
610     if (p->buffer) {
611     struct msgq *q = p->buffer;
612    
613     while (q) {
614     tot += sizeof(struct list_type);
615    
616     tot += q->len + 1;
617     q = q->next;
618     }
619     }
620 guppy 1.18 if (p->su_nick)
621     tot += strlen(p->su_nick) + 1;
622 segfault 1.1 return tot;
623     }
624    
625     static void kill_dcc_general(int idx, void *x)
626     {
627     register struct chat_info *p = (struct chat_info *) x;
628    
629     if (p) {
630     if (p->buffer) {
631     struct msgq *r = dcc[idx].u.chat->buffer, *q;
632    
633     while (r) {
634     q = r->next;
635     nfree(r->msg);
636     nfree(r);
637     r = q;
638     }
639     }
640     if (p->away) {
641     nfree(p->away);
642     }
643     nfree(p);
644     }
645     }
646    
647     /* Remove the color control codes that mIRC,pIRCh etc use to make
648     * their client seem so fecking cool! (Sorry, Khaled, you are a nice
649     * guy, but when you added this feature you forced people to either
650     * use your *SHAREWARE* client or face screenfulls of crap!) */
651     static void strip_mirc_codes(int flags, char *text)
652     {
653     char *dd = text;
654    
655     while (*text) {
656     switch (*text) {
657     case 2: /* Bold text */
658     if (flags & STRIP_BOLD) {
659     text++;
660     continue;
661     }
662     break;
663     case 3: /* mIRC colors? */
664     if (flags & STRIP_COLOR) {
665     if (isdigit(text[1])) { /* Is the first char a number? */
666     text += 2; /* Skip over the ^C and the first digit */
667     if (isdigit(*text))
668     text++; /* Is this a double digit number? */
669     if (*text == ',') { /* Do we have a background color next? */
670     if (isdigit(text[1]))
671     text += 2; /* Skip over the first background digit */
672     if (isdigit(*text))
673     text++; /* Is it a double digit? */
674     }
675     } else
676     text++;
677     continue;
678     }
679     break;
680     case 7:
681     if (flags & STRIP_BELLS) {
682     text++;
683     continue;
684     }
685     break;
686     case 0x16: /* Reverse video */
687     if (flags & STRIP_REV) {
688     text++;
689     continue;
690     }
691     break;
692     case 0x1f: /* Underlined text */
693     if (flags & STRIP_UNDER) {
694     text++;
695     continue;
696     }
697     break;
698     case 033:
699     if (flags & STRIP_ANSI) {
700     text++;
701     if (*text == '[') {
702     text++;
703     while ((*text == ';') || isdigit(*text))
704     text++;
705     if (*text)
706     text++; /* also kill the following char */
707     }
708     continue;
709     }
710     break;
711     }
712     *dd++ = *text++; /* Move on to the next char */
713     }
714     *dd = 0;
715     }
716    
717     static void append_line(int idx, char *line)
718     {
719     int l = strlen(line);
720     struct msgq *p, *q;
721     struct chat_info *c = (dcc[idx].type == &DCC_CHAT) ? dcc[idx].u.chat :
722     dcc[idx].u.file->chat;
723    
724     if (c->current_lines > 1000) {
725     p = c->buffer;
726     /* they're probably trying to fill up the bot nuke the sods :) */
727     while (p) { /* flush their queue */
728     q = p->next;
729     nfree(p->msg);
730     nfree(p);
731     p = q;
732     }
733     c->buffer = 0;
734     dcc[idx].status &= ~STAT_PAGE;
735     do_boot(idx, botnetnick, "too many pages - senq full");
736     return;
737     }
738     if ((c->line_count < c->max_line) && (c->buffer == NULL)) {
739     c->line_count++;
740     tputs(dcc[idx].sock, line, l);
741     } else {
742     c->current_lines++;
743     if (c->buffer == NULL)
744     q = NULL;
745     else {
746     q = c->buffer;
747     while (q->next != NULL)
748     q = q->next;
749     }
750     p = get_data_ptr(sizeof(struct msgq));
751    
752     p->len = l;
753     p->msg = get_data_ptr(l + 1);
754     p->next = NULL;
755     strcpy(p->msg, line);
756     if (q == NULL)
757     c->buffer = p;
758     else
759     q->next = p;
760     }
761     }
762    
763     static void out_dcc_general(int idx, char *buf, void *x)
764     {
765     register struct chat_info *p = (struct chat_info *) x;
766     char *y = buf;
767    
768     strip_mirc_codes(p->strip_flags, buf);
769     if (dcc[idx].status & STAT_TELNET)
770     y = add_cr(buf);
771     if (dcc[idx].status & STAT_PAGE)
772     append_line(idx, y);
773     else
774     tputs(dcc[idx].sock, y, strlen(y));
775     }
776    
777     struct dcc_table DCC_CHAT_PASS =
778     {
779     "CHAT_PASS",
780     0,
781     eof_dcc_general,
782     dcc_chat_pass,
783     &password_timeout,
784     tout_dcc_chat_pass,
785     display_dcc_chat_pass,
786     expmem_dcc_general,
787     kill_dcc_general,
788     out_dcc_general
789     };
790    
791     /* make sure ansi code is just for color-changing */
792     static int check_ansi(char *v)
793     {
794     int count = 2;
795    
796     if (*v++ != '\033')
797     return 1;
798     if (*v++ != '[')
799     return 1;
800     while (*v) {
801     if (*v == 'm')
802     return 0;
803     if ((*v != ';') && ((*v < '0') || (*v > '9')))
804     return count;
805     v++;
806     count++;
807     }
808     return count;
809     }
810    
811     static void eof_dcc_chat(int idx)
812     {
813     context;
814     putlog(LOG_MISC, "*", DCC_LOSTDCC, dcc[idx].nick,
815     dcc[idx].host, dcc[idx].port);
816     context;
817     if (dcc[idx].u.chat->channel >= 0) {
818     chanout_but(idx, dcc[idx].u.chat->channel, "*** %s lost dcc link.\n",
819     dcc[idx].nick);
820     context;
821     if (dcc[idx].u.chat->channel < 100000)
822     botnet_send_part_idx(idx, "lost dcc link");
823     check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock,
824     dcc[idx].u.chat->channel);
825     }
826     context;
827     check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
828     context;
829     killsock(dcc[idx].sock);
830     context;
831     lostdcc(idx);
832     context;
833     }
834    
835     static void dcc_chat(int idx, char *buf, int i)
836     {
837     int nathan = 0, doron = 0, fixed = 0;
838     char *v, *d;
839    
840     context;
841     strip_telnet(dcc[idx].sock, buf, &i);
842     if (buf[0] && (buf[0] != '.') &&
843     detect_dcc_flood(&dcc[idx].timeval, dcc[idx].u.chat, idx))
844     return;
845     dcc[idx].timeval = now;
846     if (buf[0])
847     strcpy(buf, check_tcl_filt(idx, buf));
848     if (buf[0]) {
849     /* check for beeps and cancel annoying ones */
850     v = buf;
851     d = buf;
852     while (*v)
853     switch (*v) {
854     case 7: /* beep - no more than 3 */
855     nathan++;
856     if (nathan > 3)
857     v++;
858     else
859     *d++ = *v++;
860     break;
861     case 8: /* backspace - for lame telnet's :) */
862     if (d > buf) {
863     d--;
864     }
865     v++;
866     break;
867     case 27: /* ESC - ansi code? */
868     doron = check_ansi(v);
869     /* if it's valid, append a return-to-normal code at the end */
870     if (!doron) {
871     *d++ = *v++;
872     fixed = 1;
873     } else
874     v += doron;
875     break;
876     case '\r': /* weird pseudo-linefeed */
877     v++;
878     break;
879     default:
880     *d++ = *v++;
881     }
882     if (fixed)
883     strcpy(d, "\033[0m");
884     else
885     *d = 0;
886     if (buf[0]) { /* nothing to say - maybe paging... */
887     if ((buf[0] == '.') || (dcc[idx].u.chat->channel < 0)) {
888     if (buf[0] == '.')
889     buf++;
890     v = newsplit(&buf);
891 poptix 1.8 rmspace(buf);
892 segfault 1.1 if (check_tcl_dcc(v, idx, buf)) {
893 guppy 1.14 if (dcc[idx].u.chat->channel >= 0)
894     check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock,
895     dcc[idx].u.chat->channel);
896 segfault 1.1 check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
897     dprintf(idx, "*** Ja mata!\n");
898     flush_lines(idx, dcc[idx].u.chat);
899     putlog(LOG_MISC, "*", DCC_CLOSED, dcc[idx].nick,
900     dcc[idx].host);
901     if (dcc[idx].u.chat->channel >= 0) {
902     chanout_but(-1, dcc[idx].u.chat->channel,
903     "*** %s left the party line%s%s\n",
904     dcc[idx].nick, buf[0] ? ": " : ".", buf);
905     if (dcc[idx].u.chat->channel < 100000)
906     botnet_send_part_idx(idx, buf);
907     }
908     if (dcc[idx].u.chat->su_nick) {
909     dcc[idx].user = get_user_by_handle(userlist, dcc[idx].u.chat->su_nick);
910     strcpy(dcc[idx].nick, dcc[idx].u.chat->su_nick);
911     dcc[idx].type = &DCC_CHAT;
912     if (dcc[idx].u.chat->channel < 100000)
913     botnet_send_join_idx(idx, -1);
914     dprintf(idx, "Returning to real nick %s!\r\n", dcc[idx].u.chat->su_nick);
915     nfree(dcc[idx].u.chat->su_nick);
916     dcc[idx].u.chat->su_nick = NULL;
917     /* chanout_but(-1, dcc[idx].u.chat->channel, "*** %s has rejoined the party line.\n", dcc[idx].nick); */
918     dcc_chatter(idx);
919     return;
920     } else if ((dcc[idx].sock != STDOUT) || backgrd) {
921     killsock(dcc[idx].sock);
922     lostdcc(idx);
923     return;
924     } else {
925     dprintf(DP_STDOUT, "\n### SIMULATION RESET\n\n");
926     dcc_chatter(idx);
927     return;
928     }
929     }
930     } else if (buf[0] == ',') {
931     int me = 0;
932    
933     if ((buf[1] == 'm') && (buf[2] == 'e') && buf[3] == ' ')
934     me = 1;
935     for (i = 0; i < dcc_total; i++) {
936     int ok = 0;
937    
938     if (dcc[i].type->flags & DCT_MASTER) {
939     if ((dcc[i].type != &DCC_CHAT) ||
940     (dcc[i].u.chat->channel >= 0))
941     if ((i != idx) || (dcc[idx].status & STAT_ECHO))
942     ok = 1;
943     }
944     if (ok) {
945     struct userrec *u = get_user_by_handle(userlist, dcc[i].nick);
946    
947     if (u && (u->flags & USER_MASTER)) {
948     if (me)
949     dprintf(i, "-> %s%s\n", dcc[idx].nick, buf + 3);
950     else
951     dprintf(i, "-%s-> %s\n", dcc[idx].nick, buf + 1);
952     }
953     }
954     }
955     } else if (buf[0] == '\'') {
956     int me = 0;
957    
958     if ((buf[1] == 'm') && (buf[2] == 'e') &&
959     ((buf[3] == ' ') || (buf[3] == '\'') || (buf[3] == ',')))
960     me = 1;
961     for (i = 0; i < dcc_total; i++) {
962     if (dcc[i].type->flags & DCT_CHAT) {
963     if (me)
964     dprintf(i, "=> %s%s\n", dcc[idx].nick, buf + 3);
965     else
966     dprintf(i, "=%s=> %s\n", dcc[idx].nick, buf + 1);
967     }
968     }
969     } else {
970     if (dcc[idx].u.chat->away != NULL)
971     not_away(idx);
972     if (dcc[idx].status & STAT_ECHO)
973     chanout_but(-1, dcc[idx].u.chat->channel,
974     "<%s> %s\n", dcc[idx].nick, buf);
975     else
976     chanout_but(idx, dcc[idx].u.chat->channel, "<%s> %s\n",
977     dcc[idx].nick, buf);
978     botnet_send_chan(-1, botnetnick, dcc[idx].nick,
979     dcc[idx].u.chat->channel, buf);
980     check_tcl_chat(dcc[idx].nick, dcc[idx].u.chat->channel, buf);
981     }
982     }
983     }
984     if (dcc[idx].type == &DCC_CHAT) /* could have change to files */
985     if (dcc[idx].status & STAT_PAGE)
986     flush_lines(idx, dcc[idx].u.chat);
987     }
988    
989     static void display_dcc_chat(int idx, char *buf)
990     {
991     int i = simple_sprintf(buf, "chat flags: ");
992    
993     buf[i++] = dcc[idx].status & STAT_CHAT ? 'C' : 'c';
994     buf[i++] = dcc[idx].status & STAT_PARTY ? 'P' : 'p';
995     buf[i++] = dcc[idx].status & STAT_TELNET ? 'T' : 't';
996     buf[i++] = dcc[idx].status & STAT_ECHO ? 'E' : 'e';
997     buf[i++] = dcc[idx].status & STAT_PAGE ? 'P' : 'p';
998     simple_sprintf(buf + i, "/%d", dcc[idx].u.chat->channel);
999     }
1000    
1001     struct dcc_table DCC_CHAT =
1002     {
1003     "CHAT",
1004     DCT_CHAT | DCT_MASTER | DCT_SHOWWHO | DCT_VALIDIDX | DCT_SIMUL |
1005     DCT_CANBOOT | DCT_REMOTEWHO,
1006     eof_dcc_chat,
1007     dcc_chat,
1008     0,
1009     0,
1010     display_dcc_chat,
1011     expmem_dcc_general,
1012     kill_dcc_general,
1013     out_dcc_general
1014     };
1015    
1016     static int lasttelnets;
1017     static char lasttelnethost[81];
1018     static time_t lasttelnettime;
1019    
1020     /* a modified detect_flood for incoming telnet flood protection */
1021     static int detect_telnet_flood(char *floodhost)
1022     {
1023 segfault 1.2 struct flag_record fr =
1024     {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
1025 segfault 1.1 context;
1026 segfault 1.2 get_user_flagrec(get_user_by_host(floodhost), &fr, NULL);
1027     context;
1028     if (flood_telnet_thr == 0 || (glob_friend(fr) && !par_telnet_flood))
1029 segfault 1.1 return 0; /* no flood protection */
1030     if (strcasecmp(lasttelnethost, floodhost) != 0) { /* new */
1031     strcpy(lasttelnethost, floodhost);
1032     lasttelnettime = now;
1033     lasttelnets = 0;
1034     return 0;
1035     }
1036     if (lasttelnettime < now - flood_telnet_time) {
1037     /* flood timer expired, reset it */
1038     lasttelnettime = now;
1039     lasttelnets = 0;
1040     return 0;
1041     }
1042     lasttelnets++;
1043     if (lasttelnets >= flood_telnet_thr) { /* FLOOD */
1044     /* reset counters */
1045     lasttelnets = 0;
1046     lasttelnettime = 0;
1047     lasttelnethost[0] = 0;
1048     putlog(LOG_MISC, "*", IRC_TELNETFLOOD, floodhost);
1049     addignore(floodhost, origbotname, "Telnet connection flood",
1050     now + (60 * ignore_time));
1051     return 1;
1052     }
1053     return 0;
1054     }
1055    
1056     static void dcc_telnet_got_ident(int, char *);
1057    
1058     static void dcc_telnet(int idx, char *buf, int i)
1059     {
1060     unsigned long ip;
1061     unsigned short port;
1062     int j = 0, sock;
1063 guppy 1.13 char s[UHOSTLEN], s2[UHOSTLEN + 20];
1064 segfault 1.1
1065     context;
1066     if (dcc_total + 1 > max_dcc) {
1067     j = answer(dcc[idx].sock, s, &ip, &port, 0);
1068     if (j != -1) {
1069     dprintf(-j, "Sorry, too many connections already.\r\n");
1070     killsock(j);
1071     }
1072     return;
1073     }
1074     context;
1075     sock = answer(dcc[idx].sock, s, &ip, &port, 0);
1076     while ((sock == -1) && (errno == EAGAIN))
1077     sock = answer(sock, s, &ip, &port, 0);
1078     if (sock < 0) {
1079     neterror(s);
1080     putlog(LOG_MISC, "*", DCC_FAILED, s);
1081     killsock(sock);
1082     return;
1083     }
1084     /* <bindle> [09:37] Telnet connection: 168.246.255.191/0
1085     * <bindle> [09:37] Lost connection while identing [168.246.255.191/0]
1086     */
1087     context;
1088 arthur2 1.15 /* use dcc-portrange x:x on incoming telnets too, dw */
1089 segfault 1.1 if ((port < min_dcc_port) || (port > max_dcc_port)) {
1090     putlog(LOG_BOTS, "*", DCC_BADSRC, s, port);
1091     killsock(sock);
1092     return;
1093     }
1094     context;
1095     /* deny ips that ends with 0 or 255, dw */
1096     if ((ip & 0xff) == 0 || (ip & 0xff) == 0xff) {
1097     putlog(LOG_BOTS, "*", DCC_BADIP, s, port);
1098     killsock(sock);
1099     return;
1100     }
1101     if (dcc[idx].host[0] == '@') {
1102     /* restrict by hostname */
1103     if (!wild_match(dcc[idx].host + 1, s)) {
1104     putlog(LOG_BOTS, "*", DCC_BADHOST, s);
1105     killsock(sock);
1106     return;
1107     }
1108     }
1109     context;
1110     sprintf(s2, "telnet!telnet@%s", s);
1111     if (match_ignore(s2) || detect_telnet_flood(s2)) {
1112     killsock(sock);
1113     return;
1114     }
1115     context;
1116     i = new_dcc(&DCC_IDENTWAIT, 0);
1117     dcc[i].sock = sock;
1118     dcc[i].addr = ip;
1119     dcc[i].port = port;
1120     dcc[i].timeval = now;
1121     dcc[i].u.ident_sock = dcc[idx].sock;
1122 guppy 1.13 strncpy(dcc[i].host, s, UHOSTMAX);
1123     dcc[i].host[UHOSTMAX] = 0;
1124 segfault 1.1 strcpy(dcc[i].nick, "*");
1125     sock = open_telnet(s, 113);
1126     putlog(LOG_MISC, "*", DCC_TELCONN, s, port);
1127     s[0] = 0;
1128     context;
1129     if (sock < 0) {
1130     if (sock == -2)
1131     strcpy(s, "DNS lookup failed for ident");
1132     else
1133     neterror(s);
1134     } else {
1135     j = new_dcc(&DCC_IDENT, 0);
1136     if (j < 0) {
1137     killsock(sock);
1138     strcpy(s, "No Free DCC's");
1139     }
1140     }
1141     context;
1142     if (s[0]) {
1143     putlog(LOG_MISC, "*", DCC_IDENTFAIL, dcc[i].host, s);
1144     sprintf(s, "telnet@%s", dcc[i].host);
1145     dcc_telnet_got_ident(i, s);
1146     return;
1147     }
1148     context;
1149     dcc[j].sock = sock;
1150     dcc[j].port = 113;
1151     dcc[j].addr = ip;
1152     strcpy(dcc[j].host, dcc[i].host);
1153     strcpy(dcc[j].nick, "*");
1154     dcc[j].u.ident_sock = dcc[i].sock;
1155     dcc[j].timeval = now;
1156     dprintf(j, "%d, %d\n", dcc[i].port, dcc[idx].port);
1157     }
1158    
1159     static void eof_dcc_telnet(int idx)
1160     {
1161     putlog(LOG_MISC, "*", DCC_PORTDIE,
1162     dcc[idx].port);
1163     killsock(dcc[idx].sock);
1164     lostdcc(idx);
1165     }
1166    
1167     static void display_telnet(int idx, char *buf)
1168     {
1169 guppy 1.17 sprintf(buf, "lstn %d", dcc[idx].port);
1170 segfault 1.1 }
1171    
1172     struct dcc_table DCC_TELNET =
1173     {
1174     "TELNET",
1175     DCT_LISTEN,
1176     eof_dcc_telnet,
1177     dcc_telnet,
1178     0,
1179     0,
1180     display_telnet,
1181     0,
1182     0,
1183     0
1184     };
1185    
1186     static void dcc_telnet_id(int idx, char *buf, int atr)
1187     {
1188     int ok = 0;
1189     struct flag_record fr =
1190     {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
1191    
1192     context;
1193     strip_telnet(dcc[idx].sock, buf, &atr);
1194     buf[HANDLEN] = 0;
1195     /* toss out bad nicknames */
1196     if ((dcc[idx].nick[0] != '@') && (!wild_match(dcc[idx].nick, buf))) {
1197     dprintf(idx, "Sorry, that nickname format is invalid.\r\n");
1198 arthur2 1.15 putlog(LOG_BOTS, "*", DCC_BADNICK, dcc[idx].host);
1199 segfault 1.1 killsock(dcc[idx].sock);
1200     lostdcc(idx);
1201     return;
1202     }
1203     dcc[idx].user = get_user_by_handle(userlist, buf);
1204     get_user_flagrec(dcc[idx].user, &fr, NULL);
1205     /* make sure users-only/bots-only connects are honored */
1206     if ((dcc[idx].status & STAT_BOTONLY) && !glob_bot(fr)) {
1207     dprintf(idx, "This telnet port is for bots only.\r\n");
1208     putlog(LOG_BOTS, "*", DCC_NONBOT, dcc[idx].host);
1209     killsock(dcc[idx].sock);
1210     lostdcc(idx);
1211     return;
1212     }
1213     if ((dcc[idx].status & STAT_USRONLY) && glob_bot(fr)) {
1214     dprintf(idx, "error Only users may connect at this port.\n");
1215     putlog(LOG_BOTS, "*", DCC_NONUSER, dcc[idx].host);
1216     killsock(dcc[idx].sock);
1217     lostdcc(idx);
1218     return;
1219     }
1220     dcc[idx].status &= ~(STAT_BOTONLY | STAT_USRONLY);
1221     if ((!strcasecmp(buf, "NEW")) &&
1222     ((allow_new_telnets) || (make_userfile))) {
1223     dcc[idx].type = &DCC_TELNET_NEW;
1224     dcc[idx].timeval = now;
1225     dprintf(idx, "\r\n");
1226     dprintf(idx, IRC_TELNET, IRC_TELNET_ARGS);
1227     dprintf(idx, IRC_TELNET1);
1228     dprintf(idx, "\r\nEnter the nickname you would like to use.\r\n");
1229     return;
1230     }
1231     if (chan_op(fr)) {
1232     if (!require_p)
1233     ok = 1;
1234     }
1235     if (glob_party(fr) || glob_bot(fr))
1236     ok = 1;
1237     if (glob_xfer(fr)) {
1238     module_entry *me = module_find("filesys", 0, 0);
1239    
1240     if (me && me->funcs[FILESYS_ISVALID] && (me->funcs[FILESYS_ISVALID]) ())
1241     ok = 1;
1242     }
1243     if (!ok) {
1244     dprintf(idx, "You don't have access.\r\n");
1245 arthur2 1.15 putlog(LOG_BOTS, "*", DCC_INVHANDLE, dcc[idx].host, buf);
1246 segfault 1.1 killsock(dcc[idx].sock);
1247     lostdcc(idx);
1248     return;
1249     }
1250     if (glob_bot(fr)) {
1251 guppy 1.9 if (!strcasecmp(botnetnick, buf)) {
1252     dprintf(idx, "error You cannot link using my botnetnick.\n");
1253     putlog(LOG_BOTS, "*", DCC_MYBOTNETNICK, dcc[idx].host);
1254     killsock(dcc[idx].sock);
1255     lostdcc(idx);
1256     return;
1257     } else if (in_chain(buf)) {
1258 segfault 1.1 dprintf(idx, "error Already connected.\n");
1259     putlog(LOG_BOTS, "*", DCC_DUPLICATE,
1260     dcc[idx].host);
1261     killsock(dcc[idx].sock);
1262     lostdcc(idx);
1263     return;
1264     }
1265     }
1266     /* no password set? */
1267     if (u_pass_match(dcc[idx].user, "-")) {
1268     if (glob_bot(fr)) {
1269     char ps[20];
1270    
1271     makepass(ps);
1272     set_user(&USERENTRY_PASS, dcc[idx].user, ps);
1273     correct_handle(buf);
1274     strcpy(dcc[idx].nick, buf);
1275     nfree(dcc[idx].u.chat);
1276     dcc[idx].u.bot = get_data_ptr(sizeof(struct bot_info));
1277    
1278     dcc[idx].type = &DCC_BOT_NEW;
1279     dcc[idx].status = STAT_CALLED;
1280     dprintf(idx, "*hello!\n");
1281     greet_new_bot(idx);
1282     #ifdef NO_OLD_BOTNET
1283     dprintf(idx, "h %s\n", ps);
1284     #else
1285     dprintf(idx, "handshake %s\n", ps);
1286     #endif
1287     return;
1288     }
1289     dprintf(idx, "Can't telnet until you have a password set.\r\n");
1290     putlog(LOG_MISC, "*", DCC_NOPASS, buf, dcc[idx].host);
1291     killsock(dcc[idx].sock);
1292     lostdcc(idx);
1293     return;
1294     }
1295     ok = 0;
1296     dcc[idx].type = &DCC_CHAT_PASS;
1297     dcc[idx].timeval = now;
1298     if (glob_botmast(fr))
1299     ok = 1;
1300     else if (chan_op(fr)) {
1301     if (!require_p)
1302     ok = 1;
1303     else if (glob_party(fr))
1304     ok = 1;
1305     } else if (glob_party(fr)) {
1306     ok = 1;
1307     dcc[idx].status |= STAT_PARTY;
1308     }
1309     if (glob_bot(fr))
1310     ok = 1;
1311     if (!ok) {
1312     struct chat_info *ci;
1313    
1314     ci = dcc[idx].u.chat;
1315     dcc[idx].u.file = get_data_ptr(sizeof(struct file_info));
1316    
1317     dcc[idx].u.file->chat = ci;
1318     }
1319     correct_handle(buf);
1320     strcpy(dcc[idx].nick, buf);
1321 guppy 1.7
1322     if (glob_bot(fr)) {
1323     /* Must generate a string consisting of our process ID and the current
1324     * time. The bot will add it's password to the end and use it to generate
1325     * an MD5 checksum (always 128bit). The checksum is sent back and this
1326     * end does the same. The remote bot is only allowed access if the
1327     * checksums match. Please don't fuck with 'timeval', or the digest we
1328     * generate later for authentication will not be correct - you've been
1329     * warned ;) <Cybah>
1330     */
1331     putlog(LOG_BOTS, "*", "Challenging %s...", dcc[idx].nick);
1332     dprintf(idx, "passreq <%x%x@%s>\n", getpid(), dcc[idx].timeval, botnetnick);
1333     } else {
1334     /* *note* The MD5 digest used above to prevent cleartext passwords
1335     * being sent across the net will _only_ work when we have the cleartext
1336     * password. User passwords are encrypted (with blowfish usually) so the
1337     * same thing cant be done. Botnet passwords are always stored in
1338     * cleartext, or at least something that can be reversed. <Cybah>
1339     */
1340 guppy 1.9 dprintf(idx, "\n%s\377\373\001\n",DCC_ENTERPASS);
1341 segfault 1.1 /* turn off remote telnet echo: IAC WILL ECHO */
1342     }
1343     }
1344    
1345     static void eof_dcc_telnet_id(int idx)
1346     {
1347     putlog(LOG_MISC, "*", DCC_LOSTCON, dcc[idx].host,
1348     dcc[idx].port);
1349     killsock(dcc[idx].sock);
1350     lostdcc(idx);
1351     }
1352    
1353     static void timeout_dcc_telnet_id(int idx)
1354     {
1355     dprintf(idx, "Timeout.\n");
1356     putlog(LOG_MISC, "*", DCC_TTIMEOUT, dcc[idx].host);
1357     killsock(dcc[idx].sock);
1358     lostdcc(idx);
1359     }
1360    
1361     static void display_dcc_telnet_id(int idx, char *buf)
1362     {
1363     sprintf(buf, "t-in waited %lus", now - dcc[idx].timeval);
1364     }
1365    
1366     struct dcc_table DCC_TELNET_ID =
1367     {
1368     "TELNET_ID",
1369     0,
1370     eof_dcc_telnet_id,
1371     dcc_telnet_id,
1372     &password_timeout,
1373     timeout_dcc_telnet_id,
1374     display_dcc_telnet_id,
1375     expmem_dcc_general,
1376     kill_dcc_general,
1377     out_dcc_general
1378     };
1379    
1380     static void dcc_telnet_new(int idx, char *buf, int x)
1381     {
1382     int ok = 1;
1383     char work[1024], *p, *q, *r;
1384    
1385     buf[HANDLEN] = 0;
1386     strip_telnet(dcc[idx].sock, buf, &x);
1387     strcpy(dcc[idx].nick, buf);
1388     dcc[idx].timeval = now;
1389     for (x = 0; x < strlen(buf); x++)
1390     if ((buf[x] <= 32) || (buf[x] >= 127))
1391     ok = 0;
1392     if (!ok) {
1393     dprintf(idx, "\nYou can't use weird symbols in your nick.\n");
1394     dprintf(idx, "Try another one please:\n");
1395     } else if (strchr("-,+*=:!.@#;$", buf[0]) != NULL) {
1396     dprintf(idx, "\nYou can't start your nick with the character '%c'\n", buf[0]);
1397     dprintf(idx, "Try another one please:\n");
1398     } else if (get_user_by_handle(userlist, buf)) {
1399     dprintf(idx, "\nSorry, that nickname is taken already.\n");
1400     dprintf(idx, "Try another one please:\n");
1401     return;
1402     } else if (!strcasecmp(buf, origbotname) || !strcasecmp(buf, botnetnick)) {
1403     dprintf(idx, "Sorry, can't use my name for a nick.\n");
1404     } else {
1405     if (make_userfile)
1406     userlist = adduser(userlist, buf, "telnet!*@*", "-",
1407     sanity_check(default_flags | USER_PARTY |
1408     USER_MASTER | USER_OWNER));
1409     else {
1410     p = strchr(dcc[idx].host, '@');
1411     if (p) {
1412     q = p;
1413     *q = 0;
1414     p++;
1415     r = strchr(p, '.');
1416     if (!r)
1417     simple_sprintf(work, "telnet!%s@%s", dcc[idx].host, p);
1418     else
1419     simple_sprintf(work, "telnet!%s@*%s", dcc[idx].host, r);
1420     *q = '@';
1421     } else
1422     simple_sprintf(work, "telnet!*@*%s", dcc[idx].host);
1423     userlist = adduser(userlist, buf, work, "-",
1424     sanity_check(USER_PARTY | default_flags));
1425     }
1426     reaffirm_owners();
1427     dcc[idx].status = STAT_ECHO | STAT_TELNET;
1428     dcc[idx].type = &DCC_CHAT; /* just so next line will work */
1429     dcc[idx].user = get_user_by_handle(userlist, buf);
1430     check_dcc_attrs(dcc[idx].user, USER_PARTY | default_flags);
1431     dcc[idx].type = &DCC_TELNET_PW;
1432     if (make_userfile) {
1433     dprintf(idx, "\nYOU ARE THE MASTER/OWNER ON THIS BOT NOW\n");
1434     dprintf(idx, IRC_LIMBO);
1435 arthur2 1.15 putlog(LOG_MISC, "*", DCC_INSTCOMPL, buf);
1436 segfault 1.1 make_userfile = 0;
1437     write_userfile(-1);
1438     add_note(buf, botnetnick, "Welcome to eggdrop! :)", -1, 0);
1439     }
1440     dprintf(idx, "\nOkay, now choose and enter a password:\n");
1441     dprintf(idx, "(Only the first 15 letters are significant.)\n");
1442     }
1443     }
1444    
1445     static void dcc_telnet_pw(int idx, char *buf, int x)
1446     {
1447     char *newpass;
1448     int ok;
1449    
1450     strip_telnet(dcc[idx].sock, buf, &x);
1451     buf[16] = 0;
1452     ok = 1;
1453     if (strlen(buf) < 4) {
1454     dprintf(idx, "\nTry to use at least 4 characters in your password.\n");
1455     dprintf(idx, "Choose and enter a password:\n");
1456     return;
1457     }
1458     for (x = 0; x < strlen(buf); x++)
1459     if ((buf[x] <= 32) || (buf[x] == 127))
1460     ok = 0;
1461     if (!ok) {
1462     dprintf(idx, "\nYou can't use weird symbols in your password.\n");
1463     dprintf(idx, "Try another one please:\n");
1464     return;
1465     }
1466 arthur2 1.15 putlog(LOG_MISC, "*", DCC_NEWUSER, dcc[idx].nick, dcc[idx].host,
1467     dcc[idx].port);
1468 segfault 1.1 if (notify_new[0]) {
1469     char s[121], s1[121], s2[121];
1470    
1471     sprintf(s, "Introduced to %s, %s", dcc[idx].nick, dcc[idx].host);
1472     strcpy(s1, notify_new);
1473     splitc(s2, s1, ',');
1474     while (s2[0]) {
1475     rmspace(s2);
1476     add_note(s2, botnetnick, s, -1, 0);
1477     splitc(s2, s1, ',');
1478     }
1479     rmspace(s1);
1480     add_note(s1, botnetnick, s, -1, 0);
1481     }
1482     newpass = newsplit(&buf);
1483     set_user(&USERENTRY_PASS, dcc[idx].user, newpass);
1484     dprintf(idx, "\nRemember that! You'll need it next time you log in.\n");
1485     dprintf(idx, "You now have an account on %s...\n\n\n", botnetnick);
1486     dcc[idx].type = &DCC_CHAT;
1487     dcc[idx].u.chat->channel = -2;
1488     dcc_chatter(idx);
1489     }
1490    
1491     static void eof_dcc_telnet_new(int idx)
1492     {
1493 arthur2 1.15 putlog(LOG_MISC, "*", DCC_LOSTNEWUSER, dcc[idx].host, dcc[idx].port);
1494 segfault 1.1 killsock(dcc[idx].sock);
1495     lostdcc(idx);
1496     }
1497    
1498     static void eof_dcc_telnet_pw(int idx)
1499     {
1500 arthur2 1.15 putlog(LOG_MISC, "*", DCC_LOSTNEWUSR2, dcc[idx].nick, dcc[idx].host,
1501     dcc[idx].port);
1502 segfault 1.1 deluser(dcc[idx].nick);
1503     killsock(dcc[idx].sock);
1504     lostdcc(idx);
1505     }
1506    
1507     static void tout_dcc_telnet_new(int idx)
1508     {
1509     dprintf(idx, "Guess you're not there. Bye.\n");
1510     putlog(LOG_MISC, "*", DCC_TIMEOUTUSER, dcc[idx].host,
1511     dcc[idx].port);
1512     killsock(dcc[idx].sock);
1513     lostdcc(idx);
1514     }
1515    
1516     static void tout_dcc_telnet_pw(int idx)
1517     {
1518     dprintf(idx, "Guess you're not there. Bye.\n");
1519 arthur2 1.15 putlog(LOG_MISC, "*", DCC_TIMEOUTUSR2, dcc[idx].nick,
1520     dcc[idx].host, dcc[idx].port);
1521 segfault 1.1 killsock(dcc[idx].sock);
1522     lostdcc(idx);
1523     }
1524    
1525     static void display_dcc_telnet_new(int idx, char *buf)
1526     {
1527     sprintf(buf, "new waited %lus", now - dcc[idx].timeval);
1528     }
1529    
1530     static void display_dcc_telnet_pw(int idx, char *buf)
1531     {
1532     sprintf(buf, "newp waited %lus", now - dcc[idx].timeval);
1533     }
1534    
1535     struct dcc_table DCC_TELNET_NEW =
1536     {
1537     "TELNET_NEW",
1538     0,
1539     eof_dcc_telnet_new,
1540     dcc_telnet_new,
1541     &password_timeout,
1542     tout_dcc_telnet_new,
1543     display_dcc_telnet_new,
1544     expmem_dcc_general,
1545     kill_dcc_general,
1546     out_dcc_general
1547     };
1548    
1549     struct dcc_table DCC_TELNET_PW =
1550     {
1551     "TELNET_PW",
1552     0,
1553     eof_dcc_telnet_pw,
1554     dcc_telnet_pw,
1555     &password_timeout,
1556     tout_dcc_telnet_pw,
1557     display_dcc_telnet_pw,
1558     expmem_dcc_general,
1559     kill_dcc_general,
1560     out_dcc_general
1561     };
1562    
1563     static int call_tcl_func(char *name, int idx, char *args)
1564     {
1565     char s[11];
1566    
1567     sprintf(s, "%d", idx);
1568     Tcl_SetVar(interp, "_n", s, 0);
1569     Tcl_SetVar(interp, "_a", args, 0);
1570     if (Tcl_VarEval(interp, name, " $_n $_a", NULL) == TCL_ERROR) {
1571     putlog(LOG_MISC, "*", DCC_TCLERROR, name, interp->result);
1572     return -1;
1573     }
1574     return (atoi(interp->result));
1575     }
1576    
1577     static void dcc_script(int idx, char *buf, int len)
1578     {
1579 segfault 1.4 void *old = NULL;
1580     long oldsock = dcc[idx].sock;
1581 segfault 1.1
1582     strip_telnet(dcc[idx].sock, buf, &len);
1583     if (!len)
1584     return;
1585     dcc[idx].timeval = now;
1586     if (call_tcl_func(dcc[idx].u.script->command, dcc[idx].sock, buf)) {
1587 segfault 1.4 context;
1588     if ((dcc[idx].sock != oldsock) || (idx>max_dcc))
1589     return; /* drummer: this happen after killdcc */
1590 segfault 1.1 old = dcc[idx].u.script->u.other;
1591     dcc[idx].type = dcc[idx].u.script->type;
1592     nfree(dcc[idx].u.script);
1593     dcc[idx].u.other = old;
1594     if (dcc[idx].type == &DCC_SOCKET) {
1595     /* kill the whole thing off */
1596     killsock(dcc[idx].sock);
1597     lostdcc(idx);
1598     return;
1599     }
1600     if (dcc[idx].type == &DCC_CHAT) {
1601     if (dcc[idx].u.chat->channel >= 0) {
1602     chanout_but(-1, dcc[idx].u.chat->channel,DCC_JOIN, dcc[idx].nick);
1603     context;
1604     if (dcc[idx].u.chat->channel < 10000)
1605     botnet_send_join_idx(idx, -1);
1606     check_tcl_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
1607     geticon(idx), dcc[idx].sock, dcc[idx].host);
1608     }
1609     check_tcl_chon(dcc[idx].nick, dcc[idx].sock);
1610     }
1611     }
1612     }
1613    
1614     static void eof_dcc_script(int idx)
1615     {
1616     void *old;
1617     int oldflags;
1618    
1619     context;
1620     /* This will stop a killdcc from working, incase the script tries
1621     * to kill it's controlling socket while handling an EOF <cybah> */
1622     oldflags = dcc[idx].type->flags;
1623     dcc[idx].type->flags &= ~(DCT_VALIDIDX);
1624     /* tell the script they're gone: */
1625     call_tcl_func(dcc[idx].u.script->command, dcc[idx].sock, "");
1626     /* restore the flags */
1627     dcc[idx].type->flags = oldflags;
1628     context;
1629     old = dcc[idx].u.script->u.other;
1630     dcc[idx].type = dcc[idx].u.script->type;
1631     nfree(dcc[idx].u.script);
1632     dcc[idx].u.other = old;
1633     /* then let it fall thru to the real one */
1634     if (dcc[idx].type && dcc[idx].type->eof)
1635     dcc[idx].type->eof(idx);
1636     else {
1637 arthur2 1.15 putlog(LOG_MISC, "*", DCC_DEADSOCKET, dcc[idx].sock,
1638     dcc[idx].type->name);
1639 segfault 1.1 killsock(dcc[idx].sock);
1640     lostdcc(idx);
1641     }
1642     }
1643    
1644     static void display_dcc_script(int idx, char *buf)
1645     {
1646     sprintf(buf, "scri %s", dcc[idx].u.script->command);
1647     }
1648    
1649     static int expmem_dcc_script(void *x)
1650     {
1651     register struct script_info *p = (struct script_info *) x;
1652     int tot = sizeof(struct script_info);
1653    
1654     if (p->type && p->u.other)
1655     tot += p->type->expmem(p->u.other);
1656     return tot;
1657     }
1658    
1659     static void kill_dcc_script(int idx, void *x)
1660     {
1661     register struct script_info *p = (struct script_info *) x;
1662    
1663     if (p->type && p->u.other)
1664     p->type->kill(idx, p->u.other);
1665     nfree(p);
1666     }
1667    
1668     static void out_dcc_script(int idx, char *buf, void *x)
1669     {
1670     register struct script_info *p = (struct script_info *) x;
1671    
1672     if (p && p->type && p->u.other)
1673     p->type->output(idx, buf, p->u.other);
1674     else
1675     tputs(dcc[idx].sock, buf, strlen(buf));
1676     }
1677    
1678     struct dcc_table DCC_SCRIPT =
1679     {
1680     "SCRIPT",
1681     DCT_VALIDIDX,
1682     eof_dcc_script,
1683     dcc_script,
1684     0,
1685     0,
1686     display_dcc_script,
1687     expmem_dcc_script,
1688     kill_dcc_script,
1689     out_dcc_script
1690     };
1691    
1692     static void dcc_socket(int idx, char *buf, int len)
1693     {
1694     }
1695    
1696     static void eof_dcc_socket(int idx)
1697     {
1698     killsock(dcc[idx].sock);
1699     lostdcc(idx);
1700     }
1701    
1702     static void display_dcc_socket(int idx, char *buf)
1703     {
1704     strcpy(buf, "sock (stranded)");
1705     }
1706    
1707     struct dcc_table DCC_SOCKET =
1708     {
1709     "SOCKET",
1710     DCT_VALIDIDX,
1711     eof_dcc_socket,
1712     dcc_socket,
1713     0,
1714     0,
1715     display_dcc_socket,
1716     0,
1717     0,
1718     0
1719     };
1720    
1721     static void display_dcc_lost(int idx, char *buf)
1722     {
1723     strcpy(buf, "lost");
1724     }
1725    
1726     struct dcc_table DCC_LOST =
1727     {
1728     "LOST",
1729     0,
1730     0,
1731     dcc_socket,
1732     0,
1733     0,
1734     display_dcc_lost,
1735     0,
1736     0,
1737     0
1738     };
1739    
1740     void dcc_identwait(int idx, char *buf, int len)
1741     {
1742     /* ignore anything now */
1743     context;
1744     }
1745    
1746     void eof_dcc_identwait(int idx)
1747     {
1748     int i;
1749    
1750 arthur2 1.15 putlog(LOG_MISC, "*", DCC_LOSTCONN, dcc[idx].host, dcc[idx].port);
1751 segfault 1.1 for (i = 0; i < dcc_total; i++)
1752     if ((dcc[i].type == &DCC_IDENT) &&
1753     (dcc[i].u.ident_sock == dcc[idx].sock)) {
1754 guppy 1.12 killsock(dcc[i].sock); /* cleanup ident socket */
1755 segfault 1.1 dcc[i].u.other = 0;
1756 guppy 1.12 lostdcc(i);
1757     break;
1758 segfault 1.1 }
1759     killsock(dcc[idx].sock); /* cleanup waiting socket */
1760     dcc[idx].u.other = 0;
1761     lostdcc(idx);
1762     }
1763    
1764     static void display_dcc_identwait(int idx, char *buf)
1765     {
1766     sprintf(buf, "idtw waited %lus", now - dcc[idx].timeval);
1767     }
1768    
1769     struct dcc_table DCC_IDENTWAIT =
1770     {
1771     "IDENTWAIT",
1772     0,
1773     eof_dcc_identwait,
1774     dcc_identwait,
1775     0,
1776     0,
1777     display_dcc_identwait,
1778     0,
1779     0,
1780     0
1781     };
1782    
1783     void dcc_ident(int idx, char *buf, int len)
1784     {
1785     char response[512], uid[512], buf1[UHOSTLEN];
1786     int i, sock = dcc[idx].sock;
1787    
1788     context;
1789     sscanf(buf, "%*[^:]:%[^:]:%*[^:]:%[^\n]\n", response, uid);
1790     rmspace(response);
1791     if (response[0] != 'U') {
1792     dcc[idx].timeval = now;
1793     return;
1794     }
1795     rmspace(uid);
1796     uid[20] = 0; /* 20 character ident max */
1797     for (i = 0; i < dcc_total; i++)
1798     if ((dcc[i].type == &DCC_IDENTWAIT) &&
1799     (dcc[i].sock == dcc[idx].u.ident_sock)) {
1800     simple_sprintf(buf1, "%s@%s", uid, dcc[idx].host);
1801     dcc_telnet_got_ident(i, buf1);
1802     }
1803     idx = findanyidx(sock);
1804     dcc[idx].u.other = 0;
1805     killsock(dcc[idx].sock);
1806     lostdcc(idx);
1807     }
1808    
1809     void eof_dcc_ident(int idx)
1810     {
1811     char buf[UHOSTLEN];
1812     int i, sock = dcc[idx].sock;
1813    
1814     for (i = 0; i < dcc_total; i++)
1815     if ((dcc[i].type == &DCC_IDENTWAIT) &&
1816     (dcc[i].sock == dcc[idx].u.ident_sock)) {
1817     putlog(LOG_MISC, "*", DCC_EOFIDENT);
1818     simple_sprintf(buf, "telnet@%s", dcc[idx].host);
1819     dcc_telnet_got_ident(i, buf);
1820     }
1821     idx = findanyidx(sock); /* sanity */
1822 guppy 1.12 if (idx >= 0) {
1823     killsock(dcc[idx].sock);
1824     dcc[idx].u.other = 0;
1825     lostdcc(idx);
1826     }
1827 segfault 1.1 }
1828    
1829     static void display_dcc_ident(int idx, char *buf)
1830     {
1831     sprintf(buf, "idnt (sock %d)", dcc[idx].u.ident_sock);
1832     }
1833    
1834     struct dcc_table DCC_IDENT =
1835     {
1836     "IDENT",
1837     0,
1838     eof_dcc_ident,
1839     dcc_ident,
1840     &identtimeout,
1841     eof_dcc_ident,
1842     display_dcc_ident,
1843     0,
1844     0,
1845     0
1846     };
1847    
1848     void dcc_telnet_got_ident(int i, char *host)
1849     {
1850     int idx;
1851     char x[1024];
1852    
1853     for (idx = 0; idx < dcc_total; idx++)
1854     if ((dcc[idx].type == &DCC_TELNET) &&
1855     (dcc[idx].sock == dcc[i].u.ident_sock))
1856     break;
1857     dcc[i].u.other = 0;
1858 guppy 1.12 if (dcc_total == idx) {
1859 segfault 1.1 putlog(LOG_MISC, "*", DCC_LOSTIDENT);
1860 guppy 1.12 killsock(dcc[i].sock);
1861     lostdcc(i);
1862     return;
1863     }
1864 guppy 1.13 strncpy(dcc[i].host, host, UHOSTMAX);
1865     dcc[i].host[UHOSTMAX] = 0;
1866 segfault 1.1 simple_sprintf(x, "telnet!%s", dcc[i].host);
1867     if (protect_telnet && !make_userfile) {
1868     struct userrec *u;
1869     int ok = 1;
1870    
1871     context;
1872     u = get_user_by_host(x);
1873     /* not a user or +p & require p OR +o */
1874     if (!u)
1875     ok = 0;
1876     else if (require_p && !(u->flags & USER_PARTY))
1877     ok = 0;
1878     else if (!require_p && !(u->flags & USER_OP))
1879     ok = 0;
1880     if (!ok && u && (u->flags & USER_BOT))
1881     ok = 1;
1882     if (!ok) {
1883     putlog(LOG_MISC, "*", DCC_NOACCESS, dcc[i].host);
1884     killsock(dcc[i].sock);
1885     lostdcc(i);
1886     return;
1887     }
1888     }
1889     context;
1890     if (match_ignore(x)) {
1891     killsock(dcc[i].sock);
1892     lostdcc(i);
1893     return;
1894     }
1895     /* script? */
1896     if (!strcmp(dcc[idx].nick, "(script)")) {
1897     dcc[i].type = &DCC_SOCKET;
1898     dcc[i].u.other = NULL;
1899     strcpy(dcc[i].nick, "*");
1900     check_tcl_listen(dcc[idx].host, dcc[i].sock);
1901     return;
1902     }
1903     dcc[i].type = &DCC_TELNET_ID;
1904     dcc[i].u.chat = get_data_ptr(sizeof(struct chat_info));
1905     bzero(dcc[i].u.chat, sizeof(struct chat_info));
1906    
1907     /* copy acceptable-nick/host mask */
1908     dcc[i].status = STAT_TELNET | STAT_ECHO;
1909     if (!strcmp(dcc[idx].nick, "(bots)"))
1910     dcc[i].status |= STAT_BOTONLY;
1911     if (!strcmp(dcc[idx].nick, "(users)"))
1912     dcc[i].status |= STAT_USRONLY;
1913     /* copy acceptable-nick/host mask */
1914     strncpy(dcc[i].nick, dcc[idx].host, HANDLEN);
1915     dcc[i].nick[HANDLEN] = 0;
1916     dcc[i].timeval = now;
1917     strcpy(dcc[i].u.chat->con_chan, chanset ? chanset->name : "*");