/[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.34 - (show annotations) (download) (as text)
Fri Aug 10 23:51:20 2001 UTC (18 years, 4 months ago) by ite
Branch: MAIN
Changes since 1.33: +6 -6 lines
File MIME type: text/x-chdr
Gettext phase 1: created a dummy _() macro, replaced old get_lang #defines with the respective string entries in english.*.lang and removed them.

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.33 2001/07/26 17:04:33 drummer 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