/[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.36 - (show annotations) (download) (as text)
Sun Oct 7 04:02:54 2001 UTC (18 years ago) by stdarg
Branch: MAIN
Changes since 1.35: +1 -2 lines
File MIME type: text/x-chdr
Got rid of bind tables in the exported irc function table. They're not used anywhere in the core or other normal modules. Other people should use find_bind_table(), not #define's.
Got rid of H_* bind tables in irc module. All are BT_* now.
Integrated the new bind tables in with the normal bind/unbind command.
Made tcl callbacks work with the normal data types (string, int, user (handle)).
Got rid of old bind tables in server.mod
Made ctcp.mod use the new bind tables.
Wrote down most of the stuff I did so that ITE could see a detailed report :) hehe (although I have a feeling I've left something out)

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.35 2001/09/28 03:15:34 stdarg 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 }
252 /* But *do* bother with sending it locally */
253 if (!dcc[idx].u.chat->channel) {
254 chanout_but(-1, 0, "*** %s joined the party line.\n", dcc[idx].nick);
255 } else if (dcc[idx].u.chat->channel > 0) {
256 chanout_but(-1, dcc[idx].u.chat->channel,
257 "*** %s joined the channel.\n", dcc[idx].nick);
258 }
259 }
260 }
261
262 /* Mark an entry as lost and deconstruct it's contents. It will be securely
263 * removed from the dcc list in the main loop.
264 */
265 void lostdcc(int n)
266 {
267 if (dcc[n].type && dcc[n].type->kill)
268 dcc[n].type->kill(n, dcc[n].u.other);
269 else if (dcc[n].u.other)
270 nfree(dcc[n].u.other);
271 egg_bzero(&dcc[n], sizeof(struct dcc_t));
272
273 dcc[n].sock = (-1);
274 dcc[n].type = &DCC_LOST;
275 }
276
277 /* Remove entry from dcc list. Think twice before using this function,
278 * because it invalidates any variables that point to a specific dcc
279 * entry!
280 *
281 * Note: The entry will be deconstructed if it was not deconstructed
282 * already. This case should normally not occur.
283 */
284 void removedcc(int n)
285 {
286 if (dcc[n].type && dcc[n].type->kill)
287 dcc[n].type->kill(n, dcc[n].u.other);
288 else if (dcc[n].u.other)
289 nfree(dcc[n].u.other);
290 dcc_total--;
291 if (n < dcc_total)
292 egg_memcpy(&dcc[n], &dcc[dcc_total], sizeof(struct dcc_t));
293 else
294 egg_bzero(&dcc[n], sizeof(struct dcc_t)); /* drummer */
295 }
296
297 /* Clean up sockets that were just left for dead.
298 */
299 void dcc_remove_lost(void)
300 {
301 int i;
302
303 for (i = 0; i < dcc_total; i++) {
304 if (dcc[i].type == &DCC_LOST) {
305 dcc[i].type = NULL;
306 dcc[i].sock = (-1);
307 removedcc(i);
308 i--;
309 }
310 }
311 }
312
313 /* Show list of current dcc's to a dcc-chatter
314 * positive value: idx given -- negative value: sock given
315 */
316 void tell_dcc(int zidx)
317 {
318 int i, j, k;
319 char other[160];
320
321 spaces[HANDLEN - 9] = 0;
322 dprintf(zidx, "SOCK PORT NICK %s HOST TYPE\n"
323 ,spaces);
324 dprintf(zidx, "---- ----- ---------%s -------------------------- ----\n"
325 ,spaces);
326 spaces[HANDLEN - 9] = ' ';
327 /* Show server */
328 for (i = 0; i < dcc_total; i++) {
329 j = strlen(dcc[i].host);
330 if (j > 26)
331 j -= 26;
332 else
333 j = 0;
334 if (dcc[i].type && dcc[i].type->display)
335 dcc[i].type->display(i, other);
336 else {
337 sprintf(other, "?:%lX !! ERROR !!", (long) dcc[i].type);
338 break;
339 }
340 k = HANDLEN - strlen(dcc[i].nick);
341 spaces[k] = 0;
342 dprintf(zidx, "%-4d %5d %s%s %-26s %s\n", dcc[i].sock,
343 dcc[i].port, dcc[i].nick, spaces, dcc[i].host + j, other);
344 spaces[k] = ' ';
345 }
346 }
347
348 /* Mark someone on dcc chat as no longer away
349 */
350 void not_away(int idx)
351 {
352 if (dcc[idx].u.chat->away == NULL) {
353 dprintf(idx, "You weren't away!\n");
354 return;
355 }
356 if (dcc[idx].u.chat->channel >= 0) {
357 chanout_but(-1, dcc[idx].u.chat->channel,
358 "*** %s is no longer away.\n", dcc[idx].nick);
359 if (dcc[idx].u.chat->channel < 100000) {
360 botnet_send_away(-1, botnetnick, dcc[idx].sock, NULL, idx);
361 }
362 }
363 dprintf(idx, "You're not away any more.\n");
364 nfree(dcc[idx].u.chat->away);
365 dcc[idx].u.chat->away = NULL;
366 check_tcl_away(botnetnick, dcc[idx].sock, NULL);
367 }
368
369 void set_away(int idx, char *s)
370 {
371 if (s == NULL) {
372 not_away(idx);
373 return;
374 }
375 if (!s[0]) {
376 not_away(idx);
377 return;
378 }
379 if (dcc[idx].u.chat->away != NULL)
380 nfree(dcc[idx].u.chat->away);
381 dcc[idx].u.chat->away = (char *) nmalloc(strlen(s) + 1);
382 strcpy(dcc[idx].u.chat->away, s);
383 if (dcc[idx].u.chat->channel >= 0) {
384 chanout_but(-1, dcc[idx].u.chat->channel,
385 "*** %s is now away: %s\n", dcc[idx].nick, s);
386 if (dcc[idx].u.chat->channel < 100000) {
387 botnet_send_away(-1, botnetnick, dcc[idx].sock, s, idx);
388 }
389 }
390 dprintf(idx, "You are now away.\n");
391 check_tcl_away(botnetnick, dcc[idx].sock, s);
392 }
393
394 /* This helps the memory debugging
395 */
396 void *_get_data_ptr(int size, char *file, int line)
397 {
398 char *p;
399 #ifdef DEBUG_MEM
400 char x[1024];
401
402 p = strrchr(file, '/');
403 egg_snprintf(x, sizeof x, "dccutil.c:%s", p ? p + 1 : file);
404 p = n_malloc(size, x, line);
405 #else
406 p = nmalloc(size);
407 #endif
408 egg_bzero(p, size);
409 return p;
410 }
411
412 /* Make a password, 10-15 random letters and digits
413 */
414 void makepass(char *s)
415 {
416 int i;
417
418 i = 10 + (random() % 6);
419 make_rand_str(s, i);
420 }
421
422 void flush_lines(int idx, struct chat_info *ci)
423 {
424 int c = ci->line_count;
425 struct msgq *p = ci->buffer, *o;
426
427 while (p && c < (ci->max_line)) {
428 ci->current_lines--;
429 tputs(dcc[idx].sock, p->msg, p->len);
430 nfree(p->msg);
431 o = p->next;
432 nfree(p);
433 p = o;
434 c++;
435 }
436 if (p != NULL) {
437 if (dcc[idx].status & STAT_TELNET)
438 tputs(dcc[idx].sock, "[More]: ", 8);
439 else
440 tputs(dcc[idx].sock, "[More]\n", 7);
441 }
442 ci->buffer = p;
443 ci->line_count = 0;
444 }
445
446 int new_dcc(struct dcc_table *type, int xtra_size)
447 {
448 int i = dcc_total;
449
450 if (dcc_total == max_dcc)
451 return -1;
452 dcc_total++;
453 egg_bzero((char *) &dcc[i], sizeof(struct dcc_t));
454
455 dcc[i].type = type;
456 if (xtra_size) {
457 dcc[i].u.other = nmalloc(xtra_size);
458 egg_bzero(dcc[i].u.other, xtra_size);
459 }
460 return i;
461 }
462
463 /* Changes the given dcc entry to another type.
464 */
465 void changeover_dcc(int i, struct dcc_table *type, int xtra_size)
466 {
467 /* Free old structure. */
468 if (dcc[i].type && dcc[i].type->kill)
469 dcc[i].type->kill(i, dcc[i].u.other);
470 else if (dcc[i].u.other) {
471 nfree(dcc[i].u.other);
472 dcc[i].u.other = NULL;
473 }
474
475 dcc[i].type = type;
476 if (xtra_size) {
477 dcc[i].u.other = nmalloc(xtra_size);
478 egg_bzero(dcc[i].u.other, xtra_size);
479 }
480 }
481
482 int detect_dcc_flood(time_t * timer, struct chat_info *chat, int idx)
483 {
484 time_t t;
485
486 if (!dcc_flood_thr)
487 return 0;
488 t = now;
489 if (*timer != t) {
490 *timer = t;
491 chat->msgs_per_sec = 0;
492 } else {
493 chat->msgs_per_sec++;
494 if (chat->msgs_per_sec > dcc_flood_thr) {
495 /* FLOOD */
496 dprintf(idx, "*** FLOOD: %s.\n", _("Goodbye"));
497 /* Evil assumption here that flags&DCT_CHAT implies chat type */
498 if ((dcc[idx].type->flags & DCT_CHAT) && chat &&
499 (chat->channel >= 0)) {
500 char x[1024];
501
502 egg_snprintf(x, sizeof x, _("%s has been forcibly removed for flooding.\n"), dcc[idx].nick);
503 chanout_but(idx, chat->channel, "*** %s", x);
504 if (chat->channel < 100000)
505 botnet_send_part_idx(idx, x);
506 }
507 check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
508 if ((dcc[idx].sock != STDOUT) || backgrd) {
509 killsock(dcc[idx].sock);
510 lostdcc(idx);
511 } else {
512 dprintf(DP_STDOUT, "\n### SIMULATION RESET ###\n\n");
513 dcc_chatter(idx);
514 }
515 return 1; /* <- flood */
516 }
517 }
518 return 0;
519 }
520
521 /* Handle someone being booted from dcc chat.
522 */
523 void do_boot(int idx, char *by, char *reason)
524 {
525 int files = (dcc[idx].type != &DCC_CHAT);
526
527 dprintf(idx, _("-=- poof -=-\n"));
528 dprintf(idx, _("Youve been booted from the %s by %s%s%s\n"), files ? "file section" : "bot",
529 by, reason[0] ? ": " : ".", reason);
530 /* If it's a partyliner (chatterer :) */
531 /* Horrible assumption that DCT_CHAT using structure uses same format
532 * as DCC_CHAT */
533 if ((dcc[idx].type->flags & DCT_CHAT) &&
534 (dcc[idx].u.chat->channel >= 0)) {
535 char x[1024];
536
537 egg_snprintf(x, sizeof x, _("%s booted %s from the party line%s%s\n"), by, dcc[idx].nick,
538 reason[0] ? ": " : "", reason);
539 chanout_but(idx, dcc[idx].u.chat->channel, "*** %s.\n", x);
540 if (dcc[idx].u.chat->channel < 100000)
541 botnet_send_part_idx(idx, x);
542 }
543 check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
544 if ((dcc[idx].sock != STDOUT) || backgrd) {
545 killsock(dcc[idx].sock);
546 lostdcc(idx);
547 /* Entry must remain in the table so it can be logged by the caller */
548 } else {
549 dprintf(DP_STDOUT, "\n### SIMULATION RESET\n\n");
550 dcc_chatter(idx);
551 }
552 return;
553 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23