/[cvs]/eggdrop1.9/src/dccutil.c
ViewVC logotype

Annotation of /eggdrop1.9/src/dccutil.c

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


Revision 1.35 - (hide annotations) (download) (as text)
Fri Sep 28 03:15:34 2001 UTC (18 years ago) by stdarg
Branch: MAIN
Changes since 1.34: +2 -1 lines
File MIME type: text/x-chdr

This is a big patch!
Created several new bind tables (raw, msg, msgm, pub, pubm) to see how it
would work. Seems to work well so far, although there could be bugs.
Added most of the new important bind table functions to the global table.

1 guppy 1.31 /*
2 segfault 1.1 * dccutil.c -- handles:
3 fabian 1.10 * lots of little functions to send formatted text to
4     * varying types of connections
5     * '.who', '.whom', and '.dccstat' code
6     * memory management for dcc structures
7     * timeout checking for dcc connections
8 guppy 1.31 *
9 stdarg 1.35 * $Id: dccutil.c,v 1.34 2001/08/10 23:51:20 ite Exp $
10 segfault 1.1 */
11 guppy 1.31 /*
12     * Copyright (C) 1997 Robey Pointer
13     * Copyright (C) 1999, 2000, 2001 Eggheads Development Team
14     *
15 fabian 1.10 * This program is free software; you can redistribute it and/or
16     * modify it under the terms of the GNU General Public License
17     * as published by the Free Software Foundation; either version 2
18     * of the License, or (at your option) any later version.
19 guppy 1.31 *
20 fabian 1.10 * This program is distributed in the hope that it will be useful,
21     * but WITHOUT ANY WARRANTY; without even the implied warranty of
22     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23     * GNU General Public License for more details.
24 guppy 1.31 *
25 fabian 1.10 * You should have received a copy of the GNU General Public License
26     * along with this program; if not, write to the Free Software
27     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 segfault 1.1 */
29    
30 fabian 1.17 #include <sys/stat.h>
31 segfault 1.1 #include "main.h"
32     #include <errno.h>
33     #include "chan.h"
34     #include "modules.h"
35     #include "tandem.h"
36    
37 fabian 1.17 extern struct dcc_t *dcc;
38     extern int dcc_total, max_dcc, dcc_flood_thr, backgrd, MAXSOCKS;
39     extern char botnetnick[], spaces[], version[];
40     extern time_t now;
41     extern sock_list *socklist;
42 guppy 1.28 extern Tcl_Interp *interp;
43 fabian 1.17
44     char motdfile[121] = "text/motd"; /* File where the motd is stored */
45     int connect_timeout = 15; /* How long to wait before a telnet
46     connection times out */
47 segfault 1.1
48 guppy 1.25 int reserved_port_min = 0;
49     int reserved_port_max = 0;
50 segfault 1.1
51     void init_dcc_max()
52     {
53     int osock = MAXSOCKS;
54    
55     if (max_dcc < 1)
56     max_dcc = 1;
57     if (dcc)
58     dcc = nrealloc(dcc, sizeof(struct dcc_t) * max_dcc);
59     else
60     dcc = nmalloc(sizeof(struct dcc_t) * max_dcc);
61    
62     MAXSOCKS = max_dcc + 10;
63     if (socklist)
64     socklist = (sock_list *) nrealloc((void *) socklist,
65     sizeof(sock_list) * MAXSOCKS);
66     else
67     socklist = (sock_list *) nmalloc(sizeof(sock_list) * MAXSOCKS);
68     for (; osock < MAXSOCKS; osock++)
69     socklist[osock].flags = SOCK_UNUSED;
70     }
71    
72     int expmem_dccutil()
73     {
74     int tot, i;
75    
76     tot = sizeof(struct dcc_t) * max_dcc + sizeof(sock_list) * MAXSOCKS;
77    
78     for (i = 0; i < dcc_total; i++) {
79     if (dcc[i].type && dcc[i].type->expmem)
80     tot += dcc[i].type->expmem(dcc[i].u.other);
81     }
82     return tot;
83     }
84    
85    
86 fabian 1.17 /* Replace \n with \r\n */
87 segfault 1.1 char *add_cr(char *buf)
88     {
89     static char WBUF[1024];
90     char *p, *q;
91    
92     for (p = buf, q = WBUF; *p; p++, q++) {
93     if (*p == '\n')
94     *q++ = '\r';
95     *q = *p;
96     }
97     *q = *p;
98     return WBUF;
99     }
100    
101     extern void (*qserver) (int, char *, int);
102 fabian 1.7
103 fabian 1.5 void dprintf EGG_VARARGS_DEF(int, arg1)
104 segfault 1.1 {
105 guppy 1.28 static char buf[1024];
106 segfault 1.1 char *format;
107     int idx, len;
108 fabian 1.17 va_list va;
109 segfault 1.1
110 fabian 1.5 idx = EGG_VARARGS_START(int, arg1, va);
111 segfault 1.1 format = va_arg(va, char *);
112 guppy 1.28 egg_vsnprintf(buf, 1023, format, va);
113 segfault 1.1 va_end(va);
114 guppy 1.28 /* We can not use the return value vsnprintf() to determine where
115     * to null terminate. The C99 standard specifies that vsnprintf()
116     * shall return the number of bytes that would be written if the
117     * buffer had been large enough, rather then -1.
118     */
119 poptix 1.32 /* We actually can, since if it's < 0 or >= sizeof(buf), we know it wrote
120     * sizeof(buf) bytes. But we're not doing that anyway.
121     */
122     buf[sizeof(buf)-1] = 0;
123 guppy 1.28
124 guppy 1.30 #if (TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >= 1) || (TCL_MAJOR_VERSION >= 9)
125 guppy 1.29 str_nutf8tounicode(buf, sizeof buf);
126 guppy 1.28 #endif
127 poptix 1.32 len = strlen(buf);
128 guppy 1.28
129 segfault 1.1 if (idx < 0) {
130 guppy 1.28 tputs(-idx, buf, len);
131 segfault 1.1 } else if (idx > 0x7FF0) {
132     switch (idx) {
133     case DP_LOG:
134 guppy 1.28 putlog(LOG_MISC, "*", "%s", buf);
135 segfault 1.1 break;
136     case DP_STDOUT:
137 guppy 1.28 tputs(STDOUT, buf, len);
138 segfault 1.1 break;
139     case DP_STDERR:
140 guppy 1.28 tputs(STDERR, buf, len);
141 segfault 1.1 break;
142     case DP_SERVER:
143     case DP_HELP:
144     case DP_MODE:
145 fabian 1.8 case DP_MODE_NEXT:
146     case DP_SERVER_NEXT:
147     case DP_HELP_NEXT:
148 guppy 1.28 qserver(idx, buf, len);
149 segfault 1.1 break;
150     }
151     return;
152     } else {
153 fabian 1.17 if (len > 500) { /* Truncate to fit */
154 guppy 1.28 buf[500] = 0;
155     strcat(buf, "\n");
156 segfault 1.1 len = 501;
157     }
158     if (dcc[idx].type && ((long) (dcc[idx].type->output) == 1)) {
159 guppy 1.28 char *p = add_cr(buf);
160 segfault 1.1
161     tputs(dcc[idx].sock, p, strlen(p));
162     } else if (dcc[idx].type && dcc[idx].type->output) {
163 guppy 1.28 dcc[idx].type->output(idx, buf, dcc[idx].u.other);
164 segfault 1.1 } else
165 guppy 1.28 tputs(dcc[idx].sock, buf, len);
166 segfault 1.1 }
167     }
168    
169 fabian 1.5 void chatout EGG_VARARGS_DEF(char *, arg1)
170 segfault 1.1 {
171 guppy 1.28 int i, len;
172 segfault 1.1 char *format;
173     char s[601];
174 fabian 1.17 va_list va;
175 segfault 1.1
176 fabian 1.5 format = EGG_VARARGS_START(char *, arg1, va);
177 guppy 1.28 egg_vsnprintf(s, 511, format, va);
178     va_end(va);
179     len = strlen(s);
180     if (len > 511)
181     len = 511;
182 guppy 1.31 s[len + 1] = 0;
183 guppy 1.28
184 segfault 1.1 for (i = 0; i < dcc_total; i++)
185     if (dcc[i].type == &DCC_CHAT)
186     if (dcc[i].u.chat->channel >= 0)
187 guppy 1.28 dprintf(i, "%s", s);
188 guppy 1.31
189 segfault 1.1 }
190    
191 fabian 1.17 /* Print to all on this channel but one.
192     */
193 fabian 1.5 void chanout_but EGG_VARARGS_DEF(int, arg1)
194 segfault 1.1 {
195 guppy 1.28 int i, x, chan, len;
196 segfault 1.1 char *format;
197     char s[601];
198 fabian 1.17 va_list va;
199 segfault 1.1
200 fabian 1.5 x = EGG_VARARGS_START(int, arg1, va);
201 segfault 1.1 chan = va_arg(va, int);
202     format = va_arg(va, char *);
203 guppy 1.28 egg_vsnprintf(s, 511, format, va);
204     va_end(va);
205     len = strlen(s);
206     if (len > 511)
207     len = 511;
208 guppy 1.31 s[len + 1] = 0;
209    
210 segfault 1.1 for (i = 0; i < dcc_total; i++)
211     if ((dcc[i].type == &DCC_CHAT) && (i != x))
212     if (dcc[i].u.chat->channel == chan)
213 guppy 1.28 dprintf(i, "%s", s);
214 guppy 1.31
215 segfault 1.1 }
216    
217     void dcc_chatter(int idx)
218     {
219     int i, j;
220 fabian 1.17 struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
221 segfault 1.1
222     get_user_flagrec(dcc[idx].user, &fr, NULL);
223     show_motd(idx);
224     i = dcc[idx].u.chat->channel;
225     dcc[idx].u.chat->channel = 234567;
226     j = dcc[idx].sock;
227     strcpy(dcc[idx].u.chat->con_chan, "***");
228     check_tcl_chon(dcc[idx].nick, dcc[idx].sock);
229 fabian 1.17 /* Still there? */
230 segfault 1.1 if ((idx >= dcc_total) || (dcc[idx].sock != j))
231 fabian 1.17 return; /* Nope */
232     /* Tcl script may have taken control */
233 segfault 1.1 if (dcc[idx].type == &DCC_CHAT) {
234     if (!strcmp(dcc[idx].u.chat->con_chan, "***"))
235     strcpy(dcc[idx].u.chat->con_chan, "*");
236     if (dcc[idx].u.chat->channel == 234567) {
237 fabian 1.17 /* If the chat channel has already been altered it's *highly*
238 segfault 1.1 * probably join/part messages have been broadcast everywhere,
239 fabian 1.17 * so dont bother sending them
240     */
241 segfault 1.1 if (i == -2)
242     i = 0;
243     dcc[idx].u.chat->channel = i;
244     if (dcc[idx].u.chat->channel >= 0) {
245     if (dcc[idx].u.chat->channel < 100000) {
246     botnet_send_join_idx(idx, -1);
247     }
248     }
249     check_tcl_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
250     geticon(idx), dcc[idx].sock, dcc[idx].host);
251 stdarg 1.35 check_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel, geticon(idx), dcc[idx].sock, dcc[idx].host);
252 segfault 1.1 }
253 fabian 1.17 /* But *do* bother with sending it locally */
254 guppy 1.24 if (!dcc[idx].u.chat->channel) {
255 segfault 1.1 chanout_but(-1, 0, "*** %s joined the party line.\n", dcc[idx].nick);
256     } else if (dcc[idx].u.chat->channel > 0) {
257     chanout_but(-1, dcc[idx].u.chat->channel,
258     "*** %s joined the channel.\n", dcc[idx].nick);
259     }
260     }
261     }
262    
263 fabian 1.14 /* Mark an entry as lost and deconstruct it's contents. It will be securely
264     * removed from the dcc list in the main loop.
265     */
266 segfault 1.1 void lostdcc(int n)
267     {
268 fabian 1.14 if (dcc[n].type && dcc[n].type->kill)
269     dcc[n].type->kill(n, dcc[n].u.other);
270     else if (dcc[n].u.other)
271     nfree(dcc[n].u.other);
272 fabian 1.19 egg_bzero(&dcc[n], sizeof(struct dcc_t));
273 fabian 1.14
274     dcc[n].sock = (-1);
275 fabian 1.11 dcc[n].type = &DCC_LOST;
276     }
277    
278     /* Remove entry from dcc list. Think twice before using this function,
279     * because it invalidates any variables that point to a specific dcc
280     * entry!
281 fabian 1.17 *
282     * Note: The entry will be deconstructed if it was not deconstructed
283     * already. This case should normally not occur.
284 fabian 1.11 */
285     void removedcc(int n)
286     {
287 segfault 1.1 if (dcc[n].type && dcc[n].type->kill)
288     dcc[n].type->kill(n, dcc[n].u.other);
289     else if (dcc[n].u.other)
290     nfree(dcc[n].u.other);
291     dcc_total--;
292     if (n < dcc_total)
293 fabian 1.19 egg_memcpy(&dcc[n], &dcc[dcc_total], sizeof(struct dcc_t));
294 segfault 1.1 else
295 fabian 1.19 egg_bzero(&dcc[n], sizeof(struct dcc_t)); /* drummer */
296 fabian 1.12 }
297    
298     /* Clean up sockets that were just left for dead.
299     */
300     void dcc_remove_lost(void)
301     {
302     int i;
303    
304     for (i = 0; i < dcc_total; i++) {
305     if (dcc[i].type == &DCC_LOST) {
306 fabian 1.14 dcc[i].type = NULL;
307 fabian 1.12 dcc[i].sock = (-1);
308     removedcc(i);
309     i--;
310     }
311     }
312 segfault 1.1 }
313    
314 fabian 1.17 /* Show list of current dcc's to a dcc-chatter
315     * positive value: idx given -- negative value: sock given
316     */
317 segfault 1.1 void tell_dcc(int zidx)
318     {
319     int i, j, k;
320     char other[160];
321    
322     spaces[HANDLEN - 9] = 0;
323 drummer 1.33 dprintf(zidx, "SOCK PORT NICK %s HOST TYPE\n"
324 segfault 1.1 ,spaces);
325 drummer 1.33 dprintf(zidx, "---- ----- ---------%s -------------------------- ----\n"
326 segfault 1.1 ,spaces);
327     spaces[HANDLEN - 9] = ' ';
328 fabian 1.17 /* Show server */
329 segfault 1.1 for (i = 0; i < dcc_total; i++) {
330     j = strlen(dcc[i].host);
331 drummer 1.33 if (j > 26)
332     j -= 26;
333 segfault 1.1 else
334     j = 0;
335     if (dcc[i].type && dcc[i].type->display)
336     dcc[i].type->display(i, other);
337     else {
338     sprintf(other, "?:%lX !! ERROR !!", (long) dcc[i].type);
339     break;
340     }
341     k = HANDLEN - strlen(dcc[i].nick);
342     spaces[k] = 0;
343 drummer 1.33 dprintf(zidx, "%-4d %5d %s%s %-26s %s\n", dcc[i].sock,
344 segfault 1.1 dcc[i].port, dcc[i].nick, spaces, dcc[i].host + j, other);
345     spaces[k] = ' ';
346     }
347     }
348    
349 fabian 1.17 /* Mark someone on dcc chat as no longer away
350     */
351 segfault 1.1 void not_away(int idx)
352     {
353     if (dcc[idx].u.chat->away == NULL) {
354     dprintf(idx, "You weren't away!\n");
355     return;
356     }
357     if (dcc[idx].u.chat->channel >= 0) {
358     chanout_but(-1, dcc[idx].u.chat->channel,
359     "*** %s is no longer away.\n", dcc[idx].nick);
360     if (dcc[idx].u.chat->channel < 100000) {
361     botnet_send_away(-1, botnetnick, dcc[idx].sock, NULL, idx);
362     }
363     }
364     dprintf(idx, "You're not away any more.\n");
365     nfree(dcc[idx].u.chat->away);
366     dcc[idx].u.chat->away = NULL;
367     check_tcl_away(botnetnick, dcc[idx].sock, NULL);
368     }
369    
370     void set_away(int idx, char *s)
371     {
372     if (s == NULL) {
373     not_away(idx);
374     return;
375     }
376     if (!s[0]) {
377     not_away(idx);
378     return;
379     }
380     if (dcc[idx].u.chat->away != NULL)
381     nfree(dcc[idx].u.chat->away);
382     dcc[idx].u.chat->away = (char *) nmalloc(strlen(s) + 1);
383     strcpy(dcc[idx].u.chat->away, s);
384     if (dcc[idx].u.chat->channel >= 0) {
385     chanout_but(-1, dcc[idx].u.chat->channel,
386     "*** %s is now away: %s\n", dcc[idx].nick, s);
387     if (dcc[idx].u.chat->channel < 100000) {
388     botnet_send_away(-1, botnetnick, dcc[idx].sock, s, idx);
389     }
390     }
391     dprintf(idx, "You are now away.\n");
392     check_tcl_away(botnetnick, dcc[idx].sock, s);
393     }
394    
395 fabian 1.17 /* This helps the memory debugging
396     */
397 segfault 1.1 void *_get_data_ptr(int size, char *file, int line)
398     {
399     char *p;
400 fabian 1.9 #ifdef DEBUG_MEM
401 segfault 1.1 char x[1024];
402    
403 fabian 1.20 p = strrchr(file, '/');
404 guppy 1.24 egg_snprintf(x, sizeof x, "dccutil.c:%s", p ? p + 1 : file);
405 segfault 1.1 p = n_malloc(size, x, line);
406     #else
407     p = nmalloc(size);
408     #endif
409 fabian 1.19 egg_bzero(p, size);
410 segfault 1.1 return p;
411     }
412    
413 fabian 1.17 /* Make a password, 10-15 random letters and digits
414     */
415 segfault 1.1 void makepass(char *s)
416     {
417 fabian 1.2 int i;
418 segfault 1.1
419     i = 10 + (random() % 6);
420 fabian 1.2 make_rand_str(s, i);
421 segfault 1.1 }
422    
423     void flush_lines(int idx, struct chat_info *ci)
424     {
425     int c = ci->line_count;
426     struct msgq *p = ci->buffer, *o;
427    
428     while (p && c < (ci->max_line)) {
429     ci->current_lines--;
430     tputs(dcc[idx].sock, p->msg, p->len);
431     nfree(p->msg);
432     o = p->next;
433     nfree(p);
434     p = o;
435     c++;
436     }
437     if (p != NULL) {
438     if (dcc[idx].status & STAT_TELNET)
439     tputs(dcc[idx].sock, "[More]: ", 8);
440     else
441     tputs(dcc[idx].sock, "[More]\n", 7);
442     }
443     ci->buffer = p;
444     ci->line_count = 0;
445     }
446    
447     int new_dcc(struct dcc_table *type, int xtra_size)
448     {
449     int i = dcc_total;
450    
451     if (dcc_total == max_dcc)
452     return -1;
453     dcc_total++;
454 fabian 1.19 egg_bzero((char *) &dcc[i], sizeof(struct dcc_t));
455 segfault 1.1
456     dcc[i].type = type;
457     if (xtra_size) {
458     dcc[i].u.other = nmalloc(xtra_size);
459 fabian 1.19 egg_bzero(dcc[i].u.other, xtra_size);
460 segfault 1.1 }
461     return i;
462     }
463    
464 fabian 1.22 /* Changes the given dcc entry to another type.
465     */
466 fabian 1.3 void changeover_dcc(int i, struct dcc_table *type, int xtra_size)
467     {
468 fabian 1.22 /* Free old structure. */
469 fabian 1.3 if (dcc[i].type && dcc[i].type->kill)
470     dcc[i].type->kill(i, dcc[i].u.other);
471     else if (dcc[i].u.other) {
472     nfree(dcc[i].u.other);
473     dcc[i].u.other = NULL;
474     }
475    
476     dcc[i].type = type;
477     if (xtra_size) {
478     dcc[i].u.other = nmalloc(xtra_size);
479 fabian 1.19 egg_bzero(dcc[i].u.other, xtra_size);
480 fabian 1.3 }
481     }
482    
483 segfault 1.1 int detect_dcc_flood(time_t * timer, struct chat_info *chat, int idx)
484     {
485     time_t t;
486    
487 guppy 1.24 if (!dcc_flood_thr)
488 segfault 1.1 return 0;
489     t = now;
490     if (*timer != t) {
491     *timer = t;
492     chat->msgs_per_sec = 0;
493     } else {
494     chat->msgs_per_sec++;
495     if (chat->msgs_per_sec > dcc_flood_thr) {
496     /* FLOOD */
497 ite 1.34 dprintf(idx, "*** FLOOD: %s.\n", _("Goodbye"));
498 fabian 1.17 /* Evil assumption here that flags&DCT_CHAT implies chat type */
499 segfault 1.1 if ((dcc[idx].type->flags & DCT_CHAT) && chat &&
500     (chat->channel >= 0)) {
501     char x[1024];
502    
503 ite 1.34 egg_snprintf(x, sizeof x, _("%s has been forcibly removed for flooding.\n"), dcc[idx].nick);
504 segfault 1.1 chanout_but(idx, chat->channel, "*** %s", x);
505     if (chat->channel < 100000)
506     botnet_send_part_idx(idx, x);
507     }
508     check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
509     if ((dcc[idx].sock != STDOUT) || backgrd) {
510     killsock(dcc[idx].sock);
511     lostdcc(idx);
512     } else {
513     dprintf(DP_STDOUT, "\n### SIMULATION RESET ###\n\n");
514     dcc_chatter(idx);
515     }
516     return 1; /* <- flood */
517     }
518     }
519     return 0;
520     }
521    
522 fabian 1.17 /* Handle someone being booted from dcc chat.
523     */
524 segfault 1.1 void do_boot(int idx, char *by, char *reason)
525     {
526     int files = (dcc[idx].type != &DCC_CHAT);
527    
528 ite 1.34 dprintf(idx, _("-=- poof -=-\n"));
529     dprintf(idx, _("Youve been booted from the %s by %s%s%s\n"), files ? "file section" : "bot",
530 fabian 1.23 by, reason[0] ? ": " : ".", reason);
531 fabian 1.17 /* If it's a partyliner (chatterer :) */
532     /* Horrible assumption that DCT_CHAT using structure uses same format
533 segfault 1.1 * as DCC_CHAT */
534     if ((dcc[idx].type->flags & DCT_CHAT) &&
535     (dcc[idx].u.chat->channel >= 0)) {
536     char x[1024];
537    
538 ite 1.34 egg_snprintf(x, sizeof x, _("%s booted %s from the party line%s%s\n"), by, dcc[idx].nick,
539 guppy 1.24 reason[0] ? ": " : "", reason);
540 segfault 1.1 chanout_but(idx, dcc[idx].u.chat->channel, "*** %s.\n", x);
541     if (dcc[idx].u.chat->channel < 100000)
542     botnet_send_part_idx(idx, x);
543     }
544     check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
545     if ((dcc[idx].sock != STDOUT) || backgrd) {
546     killsock(dcc[idx].sock);
547 fabian 1.11 lostdcc(idx);
548 fabian 1.17 /* Entry must remain in the table so it can be logged by the caller */
549 segfault 1.1 } else {
550     dprintf(DP_STDOUT, "\n### SIMULATION RESET\n\n");
551     dcc_chatter(idx);
552     }
553     return;
554     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23