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

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

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


Revision 1.35 - (show 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 /*
2 * dccutil.c -- handles:
3 * 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 *
9 * $Id: dccutil.c,v 1.34 2001/08/10 23:51:20 ite Exp $
10 */
11 /*
12 * Copyright (C) 1997 Robey Pointer
13 * Copyright (C) 1999, 2000, 2001 Eggheads Development Team
14 *
15 * 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 *
20 * 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 *
25 * 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 */
29
30 #include <sys/stat.h>
31 #include "main.h"
32 #include <errno.h>
33 #include "chan.h"
34 #include "modules.h"
35 #include "tandem.h"
36
37 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 extern Tcl_Interp *interp;
43
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
48 int reserved_port_min = 0;
49 int reserved_port_max = 0;
50
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 /* Replace \n with \r\n */
87 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
103 void dprintf EGG_VARARGS_DEF(int, arg1)
104 {
105 static char buf[1024];
106 char *format;
107 int idx, len;
108 va_list va;
109
110 idx = EGG_VARARGS_START(int, arg1, va);
111 format = va_arg(va, char *);
112 egg_vsnprintf(buf, 1023, format, va);
113 va_end(va);
114 /* 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 /* 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
124 #if (TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >= 1) || (TCL_MAJOR_VERSION >= 9)
125 str_nutf8tounicode(buf, sizeof buf);
126 #endif
127 len = strlen(buf);
128
129 if (idx < 0) {
130 tputs(-idx, buf, len);
131 } else if (idx > 0x7FF0) {
132 switch (idx) {
133 case DP_LOG:
134 putlog(LOG_MISC, "*", "%s", buf);
135 break;
136 case DP_STDOUT:
137 tputs(STDOUT, buf, len);
138 break;
139 case DP_STDERR:
140 tputs(STDERR, buf, len);
141 break;
142 case DP_SERVER:
143 case DP_HELP:
144 case DP_MODE:
145 case DP_MODE_NEXT:
146 case DP_SERVER_NEXT:
147 case DP_HELP_NEXT:
148 qserver(idx, buf, len);
149 break;
150 }
151 return;
152 } else {
153 if (len > 500) { /* Truncate to fit */
154 buf[500] = 0;
155 strcat(buf, "\n");
156 len = 501;
157 }
158 if (dcc[idx].type && ((long) (dcc[idx].type->output) == 1)) {
159 char *p = add_cr(buf);
160
161 tputs(dcc[idx].sock, p, strlen(p));
162 } else if (dcc[idx].type && dcc[idx].type->output) {
163 dcc[idx].type->output(idx, buf, dcc[idx].u.other);
164 } else
165 tputs(dcc[idx].sock, buf, len);
166 }
167 }
168
169 void chatout EGG_VARARGS_DEF(char *, arg1)
170 {
171 int i, len;
172 char *format;
173 char s[601];
174 va_list va;
175
176 format = EGG_VARARGS_START(char *, arg1, va);
177 egg_vsnprintf(s, 511, format, va);
178 va_end(va);
179 len = strlen(s);
180 if (len > 511)
181 len = 511;
182 s[len + 1] = 0;
183
184 for (i = 0; i < dcc_total; i++)
185 if (dcc[i].type == &DCC_CHAT)
186 if (dcc[i].u.chat->channel >= 0)
187 dprintf(i, "%s", s);
188
189 }
190
191 /* Print to all on this channel but one.
192 */
193 void chanout_but EGG_VARARGS_DEF(int, arg1)
194 {
195 int i, x, chan, len;
196 char *format;
197 char s[601];
198 va_list va;
199
200 x = EGG_VARARGS_START(int, arg1, va);
201 chan = va_arg(va, int);
202 format = va_arg(va, char *);
203 egg_vsnprintf(s, 511, format, va);
204 va_end(va);
205 len = strlen(s);
206 if (len > 511)
207 len = 511;
208 s[len + 1] = 0;
209
210 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 dprintf(i, "%s", s);
214
215 }
216
217 void dcc_chatter(int idx)
218 {
219 int i, j;
220 struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
221
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 /* Still there? */
230 if ((idx >= dcc_total) || (dcc[idx].sock != j))
231 return; /* Nope */
232 /* Tcl script may have taken control */
233 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 /* If the chat channel has already been altered it's *highly*
238 * probably join/part messages have been broadcast everywhere,
239 * so dont bother sending them
240 */
241 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 check_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel, geticon(idx), dcc[idx].sock, dcc[idx].host);
252 }
253 /* But *do* bother with sending it locally */
254 if (!dcc[idx].u.chat->channel) {
255 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 /* 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 void lostdcc(int n)
267 {
268 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 egg_bzero(&dcc[n], sizeof(struct dcc_t));
273
274 dcc[n].sock = (-1);
275 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 *
282 * Note: The entry will be deconstructed if it was not deconstructed
283 * already. This case should normally not occur.
284 */
285 void removedcc(int n)
286 {
287 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 egg_memcpy(&dcc[n], &dcc[dcc_total], sizeof(struct dcc_t));
294 else
295 egg_bzero(&dcc[n], sizeof(struct dcc_t)); /* drummer */
296 }
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 dcc[i].type = NULL;
307 dcc[i].sock = (-1);
308 removedcc(i);
309 i--;
310 }
311 }
312 }
313
314 /* Show list of current dcc's to a dcc-chatter
315 * positive value: idx given -- negative value: sock given
316 */
317 void tell_dcc(int zidx)
318 {
319 int i, j, k;
320 char other[160];
321
322 spaces[HANDLEN - 9] = 0;
323 dprintf(zidx, "SOCK PORT NICK %s HOST TYPE\n"
324 ,spaces);
325 dprintf(zidx, "---- ----- ---------%s -------------------------- ----\n"
326 ,spaces);
327 spaces[HANDLEN - 9] = ' ';
328 /* Show server */
329 for (i = 0; i < dcc_total; i++) {
330 j = strlen(dcc[i].host);
331 if (j > 26)
332 j -= 26;
333 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 dprintf(zidx, "%-4d %5d %s%s %-26s %s\n", dcc[i].sock,
344 dcc[i].port, dcc[i].nick, spaces, dcc[i].host + j, other);
345 spaces[k] = ' ';
346 }
347 }
348
349 /* Mark someone on dcc chat as no longer away
350 */
351 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 /* This helps the memory debugging
396 */
397 void *_get_data_ptr(int size, char *file, int line)
398 {
399 char *p;
400 #ifdef DEBUG_MEM
401 char x[1024];
402
403 p = strrchr(file, '/');
404 egg_snprintf(x, sizeof x, "dccutil.c:%s", p ? p + 1 : file);
405 p = n_malloc(size, x, line);
406 #else
407 p = nmalloc(size);
408 #endif
409 egg_bzero(p, size);
410 return p;
411 }
412
413 /* Make a password, 10-15 random letters and digits
414 */
415 void makepass(char *s)
416 {
417 int i;
418
419 i = 10 + (random() % 6);
420 make_rand_str(s, i);
421 }
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 egg_bzero((char *) &dcc[i], sizeof(struct dcc_t));
455
456 dcc[i].type = type;
457 if (xtra_size) {
458 dcc[i].u.other = nmalloc(xtra_size);
459 egg_bzero(dcc[i].u.other, xtra_size);
460 }
461 return i;
462 }
463
464 /* Changes the given dcc entry to another type.
465 */
466 void changeover_dcc(int i, struct dcc_table *type, int xtra_size)
467 {
468 /* Free old structure. */
469 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 egg_bzero(dcc[i].u.other, xtra_size);
480 }
481 }
482
483 int detect_dcc_flood(time_t * timer, struct chat_info *chat, int idx)
484 {
485 time_t t;
486
487 if (!dcc_flood_thr)
488 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 dprintf(idx, "*** FLOOD: %s.\n", _("Goodbye"));
498 /* Evil assumption here that flags&DCT_CHAT implies chat type */
499 if ((dcc[idx].type->flags & DCT_CHAT) && chat &&
500 (chat->channel >= 0)) {
501 char x[1024];
502
503 egg_snprintf(x, sizeof x, _("%s has been forcibly removed for flooding.\n"), dcc[idx].nick);
504 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 /* Handle someone being booted from dcc chat.
523 */
524 void do_boot(int idx, char *by, char *reason)
525 {
526 int files = (dcc[idx].type != &DCC_CHAT);
527
528 dprintf(idx, _("-=- poof -=-\n"));
529 dprintf(idx, _("Youve been booted from the %s by %s%s%s\n"), files ? "file section" : "bot",
530 by, reason[0] ? ": " : ".", reason);
531 /* If it's a partyliner (chatterer :) */
532 /* Horrible assumption that DCT_CHAT using structure uses same format
533 * as DCC_CHAT */
534 if ((dcc[idx].type->flags & DCT_CHAT) &&
535 (dcc[idx].u.chat->channel >= 0)) {
536 char x[1024];
537
538 egg_snprintf(x, sizeof x, _("%s booted %s from the party line%s%s\n"), by, dcc[idx].nick,
539 reason[0] ? ": " : "", reason);
540 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 lostdcc(idx);
548 /* Entry must remain in the table so it can be logged by the caller */
549 } 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