/[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.50 - (show annotations) (download) (as text)
Sun May 5 15:19:11 2002 UTC (17 years, 5 months ago) by wingman
Branch: MAIN
Changes since 1.49: +10 -1 lines
File MIME type: text/x-chdr
Changes:

 * removed patch.h
 * added proper <filename>.h to (nearly) all <filename.h>
 * moved fixcolon to server.mod and irc.mod
 * moved ip2long to net.h
 * removed some unused function (forgot the name :-P)

Todo:

 * move config.h #include's away from main.h to files which
   needs them
 * clean up lib/eggdrop/module.h
   (now not just main.h is included but nearly all .h files from
    the core, but i guess this fixes itself when the global func
    table is abandon - then the modules must be revised too and
    we can clean up module.h)

And i'll bet i forgot something... ;-)

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23