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

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

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


Revision 1.73 - (show annotations) (download) (as text)
Tue Feb 25 06:52:19 2003 UTC (16 years, 3 months ago) by stdarg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.72: +1 -1 lines
File MIME type: text/x-chdr
FILE REMOVED
* Well, I think Tcl is finally removed from the core (except for detection/configuration).

1 /*
2 * tcldcc.c --
3 *
4 * Tcl stubs for the dcc commands
5 */
6 /*
7 * Copyright (C) 1997 Robey Pointer
8 * Copyright (C) 1999, 2000, 2001, 2002, 2003 Eggheads Development Team
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25 #ifndef lint
26 static const char rcsid[] = "$Id: tcldcc.c,v 1.72 2003/02/15 00:23:51 wcc Exp $";
27 #endif
28
29 #include "main.h"
30 #include "modules.h"
31 #include "logfile.h"
32 #include "misc.h"
33 #include "cmdt.h" /* cmd_t */
34 #include "chanprog.h" /* masktype, logmodes */
35 #include "dccutil.h" /* chatout, chanout_but, lostdcc
36 not_away, set_away, new_dcc */
37 #include "net.h" /* tputs, sockoptions, killsock,
38 getsock, open_telnet_raw, neterror,
39 open_listen */
40 #include "userrec.h" /* write_userfile */
41 #include "traffic.h" /* egg_traffic_t */
42
43 extern struct dcc_t *dcc;
44 extern int dcc_total, backgrd, parties, make_userfile, do_restart, max_dcc;
45 extern char myname[];
46 extern time_t now;
47
48 /* Traffic stuff. */
49 extern egg_traffic_t traffic;
50
51 #ifndef MAKING_MODS
52 extern struct dcc_table DCC_CHAT, DCC_SCRIPT, DCC_TELNET, DCC_SOCKET;
53 #endif /* MAKING_MODS */
54
55 /***********************************************************************/
56
57 static int script_putdcc(int idx, char *text)
58 {
59 if (idx < 0 || idx >= dcc_total || !dcc[idx].type) return(1);
60 dumplots(-(dcc[idx].sock), "", text);
61 return(0);
62 }
63
64 /* Allows tcl scripts to send out raw data. Can be used for fast server
65 * write (idx=-1)
66 *
67 * usage:
68 * putdccraw <idx> <size> <rawdata>
69 * example:
70 * putdccraw 6 13 "eggdrop rulz\n"
71 *
72 * (added by drummer@sophia.jpte.hu)
73 */
74
75 static int script_putdccraw(int idx, int len, char *text)
76 {
77 int i;
78
79 if (idx == -1) {
80 /* -1 means search for the server's idx. */
81 for (i = 0; i < dcc_total; i++) {
82 if (dcc[i].type && !strcmp(dcc[i].nick, "(server)")) {
83 idx = i;
84 break;
85 }
86 }
87 }
88 if (idx < 0 || idx >= dcc_total || !dcc[idx].type) return(1);
89 tputs(dcc[idx].sock, text, len);
90 return(0);
91 }
92
93 static int script_dccsimul(int idx, char *cmd)
94 {
95 int len;
96 if (idx < 0 || !dcc->type || !(dcc[idx].type->flags & DCT_SIMUL)
97 || !(dcc[idx].type->activity)) return(1);
98
99 len = strlen(cmd);
100 if (len > 510) len = 510;
101
102 dcc[idx].type->activity(idx, cmd, len);
103 return(0);
104 }
105
106 static int script_dccbroadcast(char *msg)
107 {
108 chatout("*** %s\n", msg);
109 return(0);
110 }
111
112 static int script_hand2idx(char *nick)
113 {
114 int i;
115
116 for (i = 0; i < dcc_total; i++) {
117 if ((dcc[i].type) && (dcc[i].type->flags & DCT_SIMUL) &&
118 !strcasecmp(nick, dcc[i].nick)) {
119 return(i);
120 }
121 }
122 return(-1);
123 }
124
125 static int script_console(script_var_t *retval, int nargs, int idx, char *what)
126 {
127 static char *view[2];
128 char str[2];
129 int plus;
130
131 str[1] = 0;
132
133 if (idx < 0 || idx >= dcc_total || !dcc[idx].type || dcc[idx].type != &DCC_CHAT) {
134 retval->value = "invalid idx";
135 retval->len = 10;
136 retval->type = SCRIPT_ERROR | SCRIPT_STRING;
137 }
138
139 retval->type = SCRIPT_ARRAY | SCRIPT_STRING;
140 retval->len = 2;
141 view[0] = dcc[idx].u.chat->con_chan;
142 view[1] = masktype(dcc[idx].u.chat->con_flags);
143 retval->value = (void *)view;
144
145 if (nargs != 2) {
146 view[1] = masktype(dcc[idx].u.chat->con_flags);
147 return(0); /* Done. */
148 }
149
150 /* They want to change something. */
151 if (strchr(CHANMETA, what[0]) != NULL) {
152 /* The channel. */
153 strlcpy(dcc[idx].u.chat->con_chan, what, 80);
154 return(0);
155 }
156
157 /* The flags. */
158 if (*what != '+' && *what != '-') dcc[idx].u.chat->con_flags = 0;
159 for (plus = 1; *what; what++) {
160 if (*what == '-') plus = 0;
161 else if (*what == '+') plus = 1;
162 else {
163 str[0] = *what;
164 if (plus) dcc[idx].u.chat->con_flags |= logmodes(str);
165 else dcc[idx].u.chat->con_flags &= (~logmodes(str));
166 }
167 }
168 view[1] = masktype(dcc[idx].u.chat->con_flags);
169 return(0);
170 }
171
172 static int script_echo(int nargs, int idx, int status)
173 {
174 if (idx < 0 || idx >= dcc_total || !dcc[idx].type || dcc[idx].type != &DCC_CHAT) return(0);
175 if (nargs == 2) {
176 if (status) dcc[idx].status |= STAT_ECHO;
177 else dcc[idx].status &= (~STAT_ECHO);
178 }
179
180 if (dcc[idx].status & STAT_ECHO) return(1);
181 return(0);
182 }
183
184 static int script_page(int nargs, int idx, int status)
185 {
186 if (idx < 0 || idx >= dcc_total || !dcc[idx].type || dcc[idx].type != &DCC_CHAT) return(0);
187
188 if (nargs == 2) {
189 if (status) {
190 dcc[idx].status |= STAT_PAGE;
191 dcc[idx].u.chat->max_line = status;
192 }
193 else dcc[idx].status &= (~STAT_PAGE);
194 }
195 if (dcc[idx].status & STAT_PAGE) return(dcc[idx].u.chat->max_line);
196 return(0);
197 }
198
199 static int script_control(int idx, script_callback_t *callback)
200 {
201 void *hold;
202
203 if (idx < 0 || idx >= max_dcc) {
204 callback->syntax = strdup("");
205 callback->del(callback);
206 return(-1);
207 }
208
209 if (dcc[idx].type && dcc[idx].type->flags & DCT_CHAT) {
210 if (dcc[idx].u.chat->channel >= 0) {
211 chanout_but(idx, dcc[idx].u.chat->channel, "*** %s has gone.\n",
212 dcc[idx].nick);
213 }
214 }
215
216 if (dcc[idx].type == &DCC_SCRIPT) {
217 script_callback_t *old_callback;
218
219 /* If it's already controlled, overwrite the old handler. */
220 old_callback = dcc[idx].u.script->callback;
221 if (old_callback) old_callback->del(old_callback);
222 dcc[idx].u.script->callback = callback;
223 }
224 else {
225 /* Otherwise we have to save the old handler. */
226 hold = dcc[idx].u.other;
227 dcc[idx].u.script = calloc(1, sizeof(struct script_info));
228 dcc[idx].u.script->u.other = hold;
229 dcc[idx].u.script->type = dcc[idx].type;
230 dcc[idx].u.script->callback = callback;
231 dcc[idx].type = &DCC_SCRIPT;
232
233 /* Do not buffer data anymore. All received and stored data
234 is passed over to the dcc functions from now on. */
235 sockoptions(dcc[idx].sock, EGG_OPTION_UNSET, SOCK_BUFFER);
236 }
237
238 callback->syntax = strdup("is");
239 return(0);
240 }
241
242 static int script_valididx(int idx)
243 {
244 if (idx < 0 || idx >= dcc_total || !dcc[idx].type || !(dcc[idx].type->flags & DCT_VALIDIDX)) return(0);
245 return(1);
246 }
247
248 /*
249 idx - idx to kill
250 reason - optional message to send with the kill
251 */
252 static int script_killdcc(int idx, char *reason)
253 {
254 if (idx < 0 || idx >= dcc_total || !dcc[idx].type || !(dcc[idx].type->flags & DCT_VALIDIDX)) return(-1);
255
256 /* Don't kill terminal socket */
257 if ((dcc[idx].sock == STDOUT) && !backgrd) return(0);
258
259 /* Make sure 'whom' info is updated for other bots */
260 if (dcc[idx].type->flags & DCT_CHAT) chanout_but(idx, dcc[idx].u.chat->channel, "*** %s has left the %s%s%s\n", dcc[idx].nick, dcc[idx].u.chat ? "channel" : "partyline", reason ? ": " : "", reason ? reason : "");
261 /* Notice is sent to the party line, the script can add a reason. */
262
263 killsock(dcc[idx].sock);
264 killtransfer(idx);
265 lostdcc(idx);
266 return(TCL_OK);
267 }
268
269 static char *script_idx2hand(int idx)
270 {
271 if (idx < 0 || idx >= dcc_total || !(dcc[idx].type) || !(dcc[idx].nick)) return("");
272 return(dcc[idx].nick);
273 }
274
275 /* list of { idx nick host type {other} timestamp}
276 */
277 static int script_dcclist(script_var_t *retval, char *match)
278 {
279 int i;
280 script_var_t *sublist, *idx, *nick, *host, *type, *othervar, *timestamp;
281 char other[160];
282
283 retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR;
284 retval->len = 0;
285 retval->value = NULL;
286 for (i = 0; i < dcc_total; i++) {
287 if (!(dcc[i].type)) continue;
288 if (match && strcasecmp(dcc[i].type->name, match)) continue;
289
290 idx = script_int(i);
291 nick = script_string(dcc[i].nick, -1);
292 host = script_string(dcc[i].host, -1);
293 type = script_string(dcc[i].type->name, -1);
294 if (dcc[i].type->display) dcc[i].type->display(i, other);
295 else sprintf(other, "?:%X !! ERROR !!", (int) dcc[i].type);
296 othervar = script_copy_string(other, -1);
297 othervar->type |= SCRIPT_FREE;
298 timestamp = script_int(dcc[i].timeval);
299
300 sublist = script_list(6, idx, nick, host, type, othervar, timestamp);
301 script_list_append(retval, sublist);
302 }
303 return(0);
304 }
305
306 static int script_dccused()
307 {
308 return(dcc_total);
309 }
310
311 static int script_getdccidle(int idx)
312 {
313 if (idx < 0 || idx >= dcc_total || !(dcc->type)) return(-1);
314 return(now - dcc[idx].timeval);
315 }
316
317 static char *script_getdccaway(int idx)
318 {
319 if (idx < 0 || idx >= dcc_total || !(dcc[idx].type) || dcc[idx].type != &DCC_CHAT) return("");
320 if (dcc[idx].u.chat->away == NULL) return("");
321 return(dcc[idx].u.chat->away);
322 }
323
324 static int script_setdccaway(int idx, char *text)
325 {
326 if (idx < 0 || idx >= dcc_total || !(dcc[idx].type) || dcc[idx].type != &DCC_CHAT) return(1);
327 if (!text || !text[0]) {
328 /* un-away */
329 if (dcc[idx].u.chat->away != NULL) not_away(idx);
330 }
331 else set_away(idx, text);
332 return(0);
333 }
334
335 static int script_connect(char *hostname, int port)
336 {
337 int i, z, sock;
338
339 sock = getsock(0);
340 if (sock < 0) return(-1);
341 z = open_telnet_raw(sock, hostname, port);
342 if (z < 0) {
343 killsock(sock);
344 return(-1);
345 }
346
347 /* Well well well... it worked! */
348 i = new_dcc(&DCC_SOCKET, 0);
349 dcc[i].sock = sock;
350 dcc[i].port = port;
351 strcpy(dcc[i].nick, "*");
352 strlcpy(dcc[i].host, hostname, UHOSTMAX);
353 return(i);
354 }
355
356 /* Create a new listening port (or destroy one)
357 *
358 * listen <port> bots/all/users [mask]
359 * listen <port> script <proc> [flag]
360 * listen <port> off
361 */
362 /* These multi-purpose commands are silly. Let's break it up. */
363
364 static int find_idx_by_port(int port)
365 {
366 int idx;
367 for (idx = 0; idx < dcc_total; idx++) {
368 if ((dcc[idx].type == &DCC_TELNET) && (dcc[idx].port == port)) break;
369 }
370 if (idx == dcc_total) return(-1);
371 return(idx);
372 }
373
374 static int script_listen_off(int port)
375 {
376 int idx;
377
378 idx = find_idx_by_port(port);
379 if (idx < 0) return(-1);
380 killsock(dcc[idx].sock);
381 lostdcc(idx);
382 return(0);
383 }
384
385 static int get_listen_dcc(char *port)
386 {
387 int af = AF_INET;
388 int portnum;
389 int sock;
390 int idx;
391
392 if (!strncasecmp(port, "ipv6%", 5)) {
393 #ifdef AF_INET6
394 port += 5;
395 af = AF_INET6;
396 #else
397 return(-1);
398 #endif
399 }
400 else if (!strncasecmp(port, "ipv4%", 5)) {
401 port += 5;
402 }
403
404 portnum = atoi(port);
405
406 idx = find_idx_by_port(portnum);
407
408 if (idx == -1) {
409 sock = open_listen(&portnum, af);
410 if (sock == -1) {
411 putlog(LOG_MISC, "*", "Requested port is in use.");
412 return(-1);
413 }
414 else if (sock == -2) {
415 putlog(LOG_MISC, "*", "Couldn't assign the requested IP. Please make sure 'my_ip' and/or 'my_ip6' are set properly.");
416 return(-1);
417 }
418
419 idx = new_dcc(&DCC_TELNET, 0);
420 strcpy(dcc[idx].addr, "*"); /* who cares? */
421 dcc[idx].port = portnum;
422 dcc[idx].sock = sock;
423 dcc[idx].timeval = now;
424 }
425 return(idx);
426 }
427
428 static int script_listen_script(char *port, script_callback_t *callback, char *flags)
429 {
430 int idx;
431
432 if (flags && strcasecmp(flags, "pub")) return(-1);
433
434 idx = get_listen_dcc(port);
435 if (idx < 0) return(idx);
436
437 strcpy(dcc[idx].nick, "(script)");
438 if (flags) dcc[idx].status = LSTN_PUBLIC;
439 strlcpy(dcc[idx].host, callback->name, UHOSTMAX);
440
441 return(dcc[idx].port);
442 }
443
444 static int script_listen(char *port, char *type, char *mask)
445 {
446 int idx;
447
448 if (strcmp(type, "bots") && strcmp(type, "users") && strcmp(type, "all")) return(-1);
449
450 idx = get_listen_dcc(port);
451 if (idx < 0) return(idx);
452
453 /* bots/users/all */
454 sprintf(dcc[idx].nick, "(%s)", type);
455
456 if (mask) strlcpy(dcc[idx].host, mask, UHOSTMAX);
457 else strcpy(dcc[idx].host, "*");
458
459 putlog(LOG_MISC, "*", "Listening at telnet port %d (%s)", dcc[idx].port, type);
460 return(dcc[idx].port);
461 }
462
463 static int script_boot(char *user_bot, char *reason)
464 {
465 char who[NOTENAMELEN + 1];
466 int i;
467
468 strlcpy(who, user_bot, sizeof who);
469 if (strchr(who, '@') != NULL) {
470 char whonick[HANDLEN + 1];
471
472 splitc(whonick, who, '@');
473 whonick[HANDLEN] = 0;
474 if (!strcasecmp(who, myname))
475 strlcpy(who, whonick, sizeof who);
476 else
477 return(0);
478 }
479 for (i = 0; i < dcc_total; i++)
480 if ((dcc[i].type) && (dcc[i].type->flags & DCT_CANBOOT) &&
481 !strcasecmp(dcc[i].nick, who)) {
482 do_boot(i, myname, reason ? reason : "");
483 break;
484 }
485 return(0);
486 }
487
488 static int script_rehash()
489 {
490 if (make_userfile) {
491 putlog(LOG_MISC, "*", _("Userfile creation not necessary--skipping"));
492 make_userfile = 0;
493 }
494 write_userfile(-1);
495 putlog(LOG_MISC, "*", _("Rehashing..."));
496 do_restart = -2;
497 return(0);
498 }
499
500 static int script_restart()
501 {
502 if (!backgrd) return(1);
503 if (make_userfile) {
504 putlog(LOG_MISC, "*", _("Userfile creation not necessary--skipping"));
505 make_userfile = 0;
506 }
507 write_userfile(-1);
508 putlog(LOG_MISC, "*", _("Restarting..."));
509 do_restart = -1;
510 return(0);
511 }
512
513 static int script_traffic(script_var_t *retval)
514 {
515 unsigned long out_total_today, out_total;
516 unsigned long in_total_today, in_total;
517 script_var_t *sublist;
518
519 retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR;
520 retval->len = 0;
521 retval->value = NULL;
522
523 sublist = script_list(5, script_string("irc", -1),
524 script_int(traffic.in_today.irc),
525 script_int(traffic.in_today.irc + traffic.in_total.irc),
526 script_int(traffic.out_today.irc),
527 script_int(traffic.out_today.irc + traffic.out_total.irc));
528 script_list_append(retval, sublist);
529 /*
530 sublist = script_list(5, script_string("botnet", -1),
531 script_int(traffic.in_today.bn),
532 script_int(traffic.in_today.bn + traffic.in_total.bn),
533 script_int(traffic.out_today.bn),
534 script_int(traffic.out_today.bn + traffic.out_total.bn));
535 script_list_append(retval, sublist);
536 */
537 sublist = script_list(5, script_string("dcc", -1),
538 script_int(traffic.in_today.dcc),
539 script_int(traffic.in_today.dcc + traffic.in_total.dcc),
540 script_int(traffic.out_today.dcc),
541 script_int(traffic.out_today.dcc + traffic.out_total.dcc));
542 script_list_append(retval, sublist);
543
544 sublist = script_list(5, script_string("filesys", -1),
545 script_int(traffic.in_today.filesys),
546 script_int(traffic.in_today.filesys + traffic.in_total.filesys),
547 script_int(traffic.out_today.filesys),
548 script_int(traffic.out_today.filesys + traffic.out_total.filesys));
549 script_list_append(retval, sublist);
550
551 sublist = script_list(5, script_string("unknown", -1),
552 script_int(traffic.in_today.unknown),
553 script_int(traffic.in_today.unknown + traffic.in_total.unknown),
554 script_int(traffic.out_today.unknown),
555 script_int(traffic.out_today.unknown + traffic.out_total.unknown));
556 script_list_append(retval, sublist);
557
558 /* Totals */
559 in_total_today = traffic.in_today.irc + traffic.in_today.bn + traffic.in_today.dcc + traffic.in_today.unknown;
560
561 in_total = in_total_today + traffic.in_total.irc + traffic.in_total.bn + traffic.in_total.dcc + traffic.in_total.unknown;
562
563 out_total_today = traffic.out_today.irc + traffic.out_today.bn + traffic.out_today.dcc + traffic.out_today.unknown;
564
565 out_total = out_total_today + traffic.out_total.irc + traffic.out_total.bn + traffic.out_total.dcc + traffic.out_total.unknown;
566
567 sublist = script_list(5, script_string("total", -1),
568 script_int(in_total_today),
569 script_int(in_total),
570 script_int(out_total_today),
571 script_int(out_total));
572 script_list_append(retval, sublist);
573
574 return(0);
575 }
576
577 script_command_t script_dcc_cmds[] = {
578 {"", "putdcc", script_putdcc, NULL, 2, "is", "idx text", SCRIPT_INTEGER, 0},
579 {"", "putdccraw", script_putdccraw, NULL, 3, "iis", "idx len text", SCRIPT_INTEGER, 0},
580 {"", "dccsimul", script_dccsimul, NULL, 2, "is", "idx command", SCRIPT_INTEGER, 0},
581 {"", "dccbroadcast", script_dccbroadcast, NULL, 1, "s", "text", SCRIPT_INTEGER, 0},
582 {"", "hand2idx", script_hand2idx, NULL, 1, "s", "handle", SCRIPT_INTEGER, 0},
583 {"", "valididx", script_valididx, NULL, 1, "i", "idx", SCRIPT_INTEGER, 0},
584 {"", "idx2hand", script_idx2hand, NULL, 1, "i", "idx", SCRIPT_INTEGER, 0},
585 {"", "dccused", script_dccused, NULL, 0, "", "", SCRIPT_INTEGER, 0},
586 {"", "getdccidle", script_getdccidle, NULL, 1, "i", "idx", SCRIPT_INTEGER, 0},
587 {"", "getdccaway", script_getdccaway, NULL, 1, "i", "idx", SCRIPT_STRING, 0},
588 {"", "setdccaway", script_setdccaway, NULL, 2, "is", "idx msg", SCRIPT_INTEGER, 0},
589 {"", "boot", script_boot, NULL, 2,"ss", "user@bot reason", SCRIPT_INTEGER, 0},
590 {"", "rehash", script_rehash, NULL, 0,"", "", SCRIPT_INTEGER, 0},
591 {"", "restart", script_restart, NULL, 0, "", "", SCRIPT_INTEGER, 0},
592 {"", "console", script_console, NULL, 1, "is", "idx ?changes?", 0, SCRIPT_PASS_RETVAL|SCRIPT_PASS_COUNT|SCRIPT_VAR_ARGS},
593 {"", "echo", script_echo, NULL, 1, "ii", "idx ?status?", SCRIPT_INTEGER, SCRIPT_PASS_COUNT|SCRIPT_VAR_ARGS},
594 {"", "page", script_page, NULL, 1, "ii", "idx ?status?", SCRIPT_INTEGER, SCRIPT_PASS_COUNT|SCRIPT_VAR_ARGS},
595 {"", "dcclist", script_dcclist, NULL, 0, "s", "?match?", 0, SCRIPT_PASS_RETVAL|SCRIPT_VAR_ARGS},
596 {"", "control", script_control, NULL, 1, "ic", "idx ?callback?", SCRIPT_INTEGER, SCRIPT_VAR_ARGS},
597 {"", "killdcc", script_killdcc, NULL, 1, "i", "idx", SCRIPT_INTEGER, 0},
598 {"", "connect", script_connect, NULL, 2, "si", "host port", SCRIPT_INTEGER, 0},
599 {"", "listen_off", script_listen_off, NULL, 1, "i", "port", SCRIPT_INTEGER, 0},
600 {"", "listen_script", script_listen_script, NULL, 2, "scs", "port callback ?flags?", SCRIPT_INTEGER, SCRIPT_VAR_ARGS},
601 {"", "listen", script_listen, NULL, 2, "sss", "port type ?mask?", SCRIPT_INTEGER, SCRIPT_VAR_ARGS},
602 {"", "traffic", script_traffic, NULL, 0, "", "", 0, SCRIPT_PASS_RETVAL},
603 {0}
604 };

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23