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

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

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


Revision 1.51 - (show annotations) (download) (as text)
Fri Jun 1 22:03:15 2001 UTC (18 years, 6 months ago) by guppy
Branch: MAIN
Changes since 1.50: +12 -4 lines
File MIME type: text/x-chdr
here is sup's patch to fix .relay and .chaddr

1 /*
2 * cmds.c -- handles:
3 * commands from a user via dcc
4 * (split in 2, this portion contains no-irc commands)
5 *
6 * $Id: cmds.c,v 1.50 2001/05/20 00:25:58 guppy Exp $
7 */
8 /*
9 * Copyright (C) 1997 Robey Pointer
10 * Copyright (C) 1999, 2000, 2001 Eggheads Development Team
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #include "main.h"
28 #include "tandem.h"
29 #include "modules.h"
30 #include <ctype.h>
31
32 extern struct chanset_t *chanset;
33 extern struct dcc_t *dcc;
34 extern struct userrec *userlist;
35 extern tcl_timer_t *timer, *utimer;
36 extern int dcc_total, remote_boots, backgrd, make_userfile,
37 do_restart, conmask, require_p, must_be_owner,
38 strict_host;
39 extern unsigned long otraffic_irc, otraffic_irc_today,
40 itraffic_irc, itraffic_irc_today,
41 otraffic_bn, otraffic_bn_today,
42 itraffic_bn, itraffic_bn_today,
43 otraffic_dcc, otraffic_dcc_today,
44 itraffic_dcc, itraffic_dcc_today,
45 otraffic_trans, otraffic_trans_today,
46 itraffic_trans, itraffic_trans_today,
47 otraffic_unknown, otraffic_unknown_today,
48 itraffic_unknown, itraffic_unknown_today;
49 extern Tcl_Interp *interp;
50 extern char botnetnick[], origbotname[], ver[], network[],
51 owner[], spaces[];
52 extern time_t now, online_since;
53
54
55 static char *btos(unsigned long);
56
57
58 /* Add hostmask to a bot's record if possible.
59 */
60 static int add_bot_hostmask(int idx, char *nick)
61 {
62 struct chanset_t *chan;
63
64 for (chan = chanset; chan; chan = chan->next)
65 if (channel_active(chan)) {
66 memberlist *m = ismember(chan, nick);
67
68 if (m) {
69 char s[UHOSTLEN];
70 struct userrec *u;
71
72 egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost);
73 u = get_user_by_host(s);
74 if (u) {
75 dprintf(idx, "(Can't add hostmask for %s because it matches %s)\n",
76 nick, u->handle);
77 return 0;
78 }
79 if (strchr("~^+=-", m->userhost[0]))
80 egg_snprintf(s, sizeof s, "*!%s%s", strict_host ? "?" : "", m->userhost+1);
81 else
82 egg_snprintf(s, sizeof s, "*!%s", m->userhost);
83 dprintf(idx, "(Added hostmask for %s from %s)\n", nick, chan->dname);
84 addhost_by_handle(nick, s);
85 return 1;
86 }
87 }
88 return 0;
89 }
90
91 static void tell_who(struct userrec *u, int idx, int chan)
92 {
93 int i, k, ok = 0, atr = u ? u->flags : 0, len;
94 char s[1024]; /* temp fix - 1.4 has a better one */
95
96 if (!chan)
97 dprintf(idx, "Party line members: (* = owner, + = master, @ = op)\n");
98 else {
99 simple_sprintf(s, "assoc %d", chan);
100 if ((Tcl_Eval(interp, s) != TCL_OK) || !interp->result[0])
101 dprintf(idx,
102 "People on channel %s%d: (* = owner, + = master, @ = op)\n",
103 (chan < 100000) ? "" : "*", chan % 100000);
104 else
105 dprintf(idx,
106 "People on channel '%s' (%s%d): (* = owner, + = master, @ = op)\n",
107 interp->result, (chan < 100000) ? "" : "*", chan % 100000);
108 }
109 for (i = 0; i < dcc_total; i++)
110 if (dcc[i].type == &DCC_CHAT)
111 if (dcc[i].u.chat->channel == chan) {
112 spaces[len = HANDLEN - strlen(dcc[i].nick)] = 0;
113 if (atr & USER_OWNER) {
114 sprintf(s, " [%.2lu] %c%s%s %s",
115 dcc[i].sock, (geticon(i) == '-' ? ' ' : geticon(i)),
116 dcc[i].nick, spaces, dcc[i].host);
117 } else {
118 sprintf(s, " %c%s%s %s",
119 (geticon(i) == '-' ? ' ' : geticon(i)),
120 dcc[i].nick, spaces, dcc[i].host);
121 }
122 spaces[len] = ' ';
123 if (atr & USER_MASTER) {
124 if (dcc[i].u.chat->con_flags)
125 sprintf(&s[strlen(s)], " (con:%s)",
126 masktype(dcc[i].u.chat->con_flags));
127 }
128 if (now - dcc[i].timeval > 300) {
129 unsigned long days, hrs, mins;
130
131 days = (now - dcc[i].timeval) / 86400;
132 hrs = ((now - dcc[i].timeval) - (days * 86400)) / 3600;
133 mins = ((now - dcc[i].timeval) - (hrs * 3600)) / 60;
134 if (days > 0)
135 sprintf(&s[strlen(s)], " (idle %lud%luh)", days, hrs);
136 else if (hrs > 0)
137 sprintf(&s[strlen(s)], " (idle %luh%lum)", hrs, mins);
138 else
139 sprintf(&s[strlen(s)], " (idle %lum)", mins);
140 }
141 dprintf(idx, "%s\n", s);
142 if (dcc[i].u.chat->away != NULL)
143 dprintf(idx, " AWAY: %s\n", dcc[i].u.chat->away);
144 }
145 for (i = 0; i < dcc_total; i++)
146 if (dcc[i].type == &DCC_BOT) {
147 if (!ok) {
148 ok = 1;
149 dprintf(idx, "Bots connected:\n");
150 }
151 egg_strftime(s, 14, "%d %b %H:%M", localtime(&dcc[i].timeval));
152 spaces[len = HANDLEN - strlen(dcc[i].nick)] = 0;
153 if (atr & USER_OWNER) {
154 dprintf(idx, " [%.2lu] %s%c%s%s (%s) %s\n",
155 dcc[i].sock, dcc[i].status & STAT_CALLED ? "<-" : "->",
156 dcc[i].status & STAT_SHARE ? '+' : ' ',
157 dcc[i].nick, spaces, s, dcc[i].u.bot->version);
158 } else {
159 dprintf(idx, " %s%c%s%s (%s) %s\n",
160 dcc[i].status & STAT_CALLED ? "<-" : "->",
161 dcc[i].status & STAT_SHARE ? '+' : ' ',
162 dcc[i].nick, spaces, s, dcc[i].u.bot->version);
163 }
164 spaces[len] = ' ';
165 }
166 ok = 0;
167 for (i = 0; i < dcc_total; i++) {
168 if ((dcc[i].type == &DCC_CHAT) && (dcc[i].u.chat->channel != chan)) {
169 if (!ok) {
170 ok = 1;
171 dprintf(idx, "Other people on the bot:\n");
172 }
173 spaces[len = HANDLEN - strlen(dcc[i].nick)] = 0;
174 if (atr & USER_OWNER) {
175 sprintf(s, " [%.2lu] %c%s%s ",
176 dcc[i].sock,
177 (geticon(i) == '-' ? ' ' : geticon(i)), dcc[i].nick,
178 spaces);
179 } else {
180 sprintf(s, " %c%s%s ",
181 (geticon(i) == '-' ? ' ' : geticon(i)), dcc[i].nick,
182 spaces);
183 }
184 spaces[len] = ' ';
185 if (atr & USER_MASTER) {
186 if (dcc[i].u.chat->channel < 0)
187 strcat(s, "(-OFF-) ");
188 else if (!dcc[i].u.chat->channel)
189 strcat(s, "(party) ");
190 else
191 sprintf(&s[strlen(s)], "(%5d) ", dcc[i].u.chat->channel);
192 }
193 strcat(s, dcc[i].host);
194 if (atr & USER_MASTER) {
195 if (dcc[i].u.chat->con_flags)
196 sprintf(&s[strlen(s)], " (con:%s)",
197 masktype(dcc[i].u.chat->con_flags));
198 }
199 if (now - dcc[i].timeval > 300) {
200 k = (now - dcc[i].timeval) / 60;
201 if (k < 60)
202 sprintf(&s[strlen(s)], " (idle %dm)", k);
203 else
204 sprintf(&s[strlen(s)], " (idle %dh%dm)", k / 60, k % 60);
205 }
206 dprintf(idx, "%s\n", s);
207 if (dcc[i].u.chat->away != NULL)
208 dprintf(idx, " AWAY: %s\n", dcc[i].u.chat->away);
209 }
210 if ((atr & USER_MASTER) && (dcc[i].type->flags & DCT_SHOWWHO) &&
211 (dcc[i].type != &DCC_CHAT)) {
212 if (!ok) {
213 ok = 1;
214 dprintf(idx, "Other people on the bot:\n");
215 }
216 spaces[len = HANDLEN - strlen(dcc[i].nick)] = 0;
217 if (atr & USER_OWNER) {
218 sprintf(s, " [%.2lu] %c%s%s (files) %s",
219 dcc[i].sock, dcc[i].status & STAT_CHAT ? '+' : ' ',
220 dcc[i].nick, spaces, dcc[i].host);
221 } else {
222 sprintf(s, " %c%s%s (files) %s",
223 dcc[i].status & STAT_CHAT ? '+' : ' ',
224 dcc[i].nick, spaces, dcc[i].host);
225 }
226 spaces[len] = ' ';
227 dprintf(idx, "%s\n", s);
228 }
229 }
230 }
231
232 static void cmd_botinfo(struct userrec *u, int idx, char *par)
233 {
234 char s[512], s2[32];
235 struct chanset_t *chan;
236 time_t now2;
237 int hr, min;
238
239 chan = chanset;
240 now2 = now - online_since;
241 s2[0] = 0;
242 if (now2 > 86400) {
243 int days = now2 / 86400;
244
245 /* Days */
246 sprintf(s2, "%d day", days);
247 if (days >= 2)
248 strcat(s2, "s");
249 strcat(s2, ", ");
250 now2 -= days * 86400;
251 }
252 hr = (time_t) ((int) now2 / 3600);
253 now2 -= (hr * 3600);
254 min = (time_t) ((int) now2 / 60);
255 sprintf(&s2[strlen(s2)], "%02d:%02d", (int) hr, (int) min);
256 putlog(LOG_CMDS, "*", "#%s# botinfo", dcc[idx].nick);
257 simple_sprintf(s, "%d:%s@%s", dcc[idx].sock, dcc[idx].nick, botnetnick);
258 botnet_send_infoq(-1, s);
259 s[0] = 0;
260 if (module_find("server", 0, 0)) {
261 while (chan != NULL) {
262 if (!channel_secret(chan)) {
263 if ((strlen(s) + strlen(chan->dname) + strlen(network)
264 + strlen(botnetnick) + strlen(ver) + 1) >= 490) {
265 strcat(s,"++ ");
266 break; /* yeesh! */
267 }
268 strcat(s, chan->dname);
269 strcat(s, ", ");
270 }
271 chan = chan->next;
272 }
273
274 if (s[0]) {
275 s[strlen(s) - 2] = 0;
276 dprintf(idx, "*** [%s] %s <%s> (%s) [UP %s]\n", botnetnick,
277 ver, network, s, s2);
278 } else
279 dprintf(idx, "*** [%s] %s <%s> (%s) [UP %s]\n", botnetnick,
280 ver, network, BOT_NOCHANNELS, s2);
281 } else
282 dprintf(idx, "*** [%s] %s <NO_IRC> [UP %s]\n", botnetnick, ver, s2);
283 }
284
285 static void cmd_whom(struct userrec *u, int idx, char *par)
286 {
287 if (par[0] == '*') {
288 putlog(LOG_CMDS, "*", "#%s# whom %s", dcc[idx].nick, par);
289 answer_local_whom(idx, -1);
290 return;
291 } else if (dcc[idx].u.chat->channel < 0) {
292 dprintf(idx, "You have chat turned off.\n");
293 return;
294 }
295 putlog(LOG_CMDS, "*", "#%s# whom %s", dcc[idx].nick, par);
296 if (!par[0]) {
297 answer_local_whom(idx, dcc[idx].u.chat->channel);
298 } else {
299 int chan = -1;
300
301 if ((par[0] < '0') || (par[0] > '9')) {
302 Tcl_SetVar(interp, "chan", par, 0);
303 if ((Tcl_VarEval(interp, "assoc ", "$chan", NULL) == TCL_OK) &&
304 interp->result[0]) {
305 chan = atoi(interp->result);
306 }
307 if (chan <= 0) {
308 dprintf(idx, "No such channel.\n");
309 return;
310 }
311 } else
312 chan = atoi(par);
313 if ((chan < 0) || (chan > 99999)) {
314 dprintf(idx, "Channel # out of range: must be 0-99999\n");
315 return;
316 }
317 answer_local_whom(idx, chan);
318 }
319 }
320
321 static void cmd_me(struct userrec *u, int idx, char *par)
322 {
323 int i;
324
325 if (dcc[idx].u.chat->channel < 0) {
326 dprintf(idx, "You have chat turned off.\n");
327 return;
328 }
329 if (!par[0]) {
330 dprintf(idx, "Usage: me <action>\n");
331 return;
332 }
333 if (dcc[idx].u.chat->away != NULL)
334 not_away(idx);
335 for (i = 0; i < dcc_total; i++)
336 if ((dcc[i].type->flags & DCT_CHAT) &&
337 (dcc[i].u.chat->channel == dcc[idx].u.chat->channel) &&
338 ((i != idx) || (dcc[i].status & STAT_ECHO)))
339 dprintf(i, "* %s %s\n", dcc[idx].nick, par);
340 botnet_send_act(idx, botnetnick, dcc[idx].nick,
341 dcc[idx].u.chat->channel, par);
342 check_tcl_act(dcc[idx].nick, dcc[idx].u.chat->channel, par);
343 }
344
345 static void cmd_motd(struct userrec *u, int idx, char *par)
346 {
347 int i;
348
349 if (par[0]) {
350 putlog(LOG_CMDS, "*", "#%s# motd %s", dcc[idx].nick, par);
351 if (!egg_strcasecmp(par, botnetnick))
352 show_motd(idx);
353 else {
354 i = nextbot(par);
355 if (i < 0)
356 dprintf(idx, "That bot isn't connected.\n");
357 else {
358 char x[40];
359
360 simple_sprintf(x, "%s%d:%s@%s",
361 (u->flags & USER_HIGHLITE) ?
362 ((dcc[idx].status & STAT_TELNET) ? "#" : "!") : "",
363 dcc[idx].sock, dcc[idx].nick, botnetnick);
364 botnet_send_motd(i, x, par);
365 }
366 }
367 } else {
368 putlog(LOG_CMDS, "*", "#%s# motd", dcc[idx].nick);
369 show_motd(idx);
370 }
371 }
372
373 static void cmd_away(struct userrec *u, int idx, char *par)
374 {
375 if (strlen(par) > 60)
376 par[60] = 0;
377 set_away(idx, par);
378 }
379
380 static void cmd_back(struct userrec *u, int idx, char *par)
381 {
382 not_away(idx);
383 }
384
385 static void cmd_newpass(struct userrec *u, int idx, char *par)
386 {
387 char *new;
388
389 if (!par[0]) {
390 dprintf(idx, "Usage: newpass <newpassword>\n");
391 return;
392 }
393 new = newsplit(&par);
394 if (strlen(new) > 16)
395 new[16] = 0;
396 if (strlen(new) < 6) {
397 dprintf(idx, "Please use at least 6 characters.\n");
398 return;
399 }
400 set_user(&USERENTRY_PASS, u, new);
401 putlog(LOG_CMDS, "*", "#%s# newpass...", dcc[idx].nick);
402 dprintf(idx, "Changed password to '%s'\n", new);
403 }
404
405 static void cmd_bots(struct userrec *u, int idx, char *par)
406 {
407 putlog(LOG_CMDS, "*", "#%s# bots", dcc[idx].nick);
408 tell_bots(idx);
409 }
410
411 static void cmd_bottree(struct userrec *u, int idx, char *par)
412 {
413 putlog(LOG_CMDS, "*", "#%s# bottree", dcc[idx].nick);
414 tell_bottree(idx, 0);
415 }
416
417 static void cmd_vbottree(struct userrec *u, int idx, char *par)
418 {
419 putlog(LOG_CMDS, "*", "#%s# vbottree", dcc[idx].nick);
420 tell_bottree(idx, 1);
421 }
422
423 static void cmd_rehelp(struct userrec *u, int idx, char *par)
424 {
425 putlog(LOG_CMDS, "*", "#%s# rehelp", dcc[idx].nick);
426 dprintf(idx, "Reload help cache...\n");
427 reload_help_data();
428 }
429
430 static void cmd_help(struct userrec *u, int idx, char *par)
431 {
432 struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
433
434 get_user_flagrec(u, &fr, dcc[idx].u.chat->con_chan);
435 if (par[0]) {
436 putlog(LOG_CMDS, "*", "#%s# help %s", dcc[idx].nick, par);
437 if (!strcmp(par, "all"))
438 tellallhelp(idx, "all", &fr);
439 else if (strchr(par, '*') || strchr(par, '?')) {
440 char *p = par;
441
442 /* Check if the search pattern only consists of '*' and/or '?'
443 * If it does, show help for "all" instead of listing all help
444 * entries.
445 */
446 for (p = par; *p && ((*p == '*') || (*p == '?')); p++);
447 if (*p)
448 tellwildhelp(idx, par, &fr);
449 else
450 tellallhelp(idx, "all", &fr);
451 } else
452 tellhelp(idx, par, &fr, 0);
453 } else {
454 putlog(LOG_CMDS, "*", "#%s# help", dcc[idx].nick);
455 if (glob_op(fr) || glob_botmast(fr) || chan_op(fr))
456 tellhelp(idx, "help", &fr, 0);
457 else
458 tellhelp(idx, "helpparty", &fr, 0);
459 }
460 }
461
462 static void cmd_addlog(struct userrec *u, int idx, char *par)
463 {
464 if (!par[0]) {
465 dprintf(idx, "Usage: addlog <message>\n");
466 return;
467 }
468 dprintf(idx, "Placed entry in the log file.\n");
469 putlog(LOG_MISC, "*", "%s: %s", dcc[idx].nick, par);
470 }
471
472 static void cmd_who(struct userrec *u, int idx, char *par)
473 {
474 int i;
475
476 if (par[0]) {
477 if (dcc[idx].u.chat->channel < 0) {
478 dprintf(idx, "You have chat turned off.\n");
479 return;
480 }
481 putlog(LOG_CMDS, "*", "#%s# who %s", dcc[idx].nick, par);
482 if (!egg_strcasecmp(par, botnetnick))
483 tell_who(u, idx, dcc[idx].u.chat->channel);
484 else {
485 i = nextbot(par);
486 if (i < 0) {
487 dprintf(idx, "That bot isn't connected.\n");
488 } else if (dcc[idx].u.chat->channel > 99999)
489 dprintf(idx, "You are on a local channel\n");
490 else {
491 char s[40];
492
493 simple_sprintf(s, "%d:%s@%s", dcc[idx].sock,
494 dcc[idx].nick, botnetnick);
495 botnet_send_who(i, s, par, dcc[idx].u.chat->channel);
496 }
497 }
498 } else {
499 putlog(LOG_CMDS, "*", "#%s# who", dcc[idx].nick);
500 if (dcc[idx].u.chat->channel < 0)
501 tell_who(u, idx, 0);
502 else
503 tell_who(u, idx, dcc[idx].u.chat->channel);
504 }
505 }
506
507 static void cmd_whois(struct userrec *u, int idx, char *par)
508 {
509 if (!par[0]) {
510 dprintf(idx, "Usage: whois <handle>\n");
511 return;
512 }
513 putlog(LOG_CMDS, "*", "#%s# whois %s", dcc[idx].nick, par);
514 tell_user_ident(idx, par, u ? (u->flags & USER_MASTER) : 0);
515 }
516
517 static void cmd_match(struct userrec *u, int idx, char *par)
518 {
519 int start = 1, limit = 20;
520 char *s, *s1, *chname;
521
522 if (!par[0]) {
523 dprintf(idx, "Usage: match <nick/host> [[skip] count]\n");
524 return;
525 }
526 putlog(LOG_CMDS, "*", "#%s# match %s", dcc[idx].nick, par);
527 s = newsplit(&par);
528 if (strchr(CHANMETA, par[0]) != NULL)
529 chname = newsplit(&par);
530 else
531 chname = "";
532 if (atoi(par) > 0) {
533 s1 = newsplit(&par);
534 if (atoi(par) > 0) {
535 start = atoi(s1);
536 limit = atoi(par);
537 } else
538 limit = atoi(s1);
539 }
540 tell_users_match(idx, s, start, limit, u ? (u->flags & USER_MASTER) : 0,
541 chname);
542 }
543
544 static void cmd_uptime(struct userrec *u, int idx, char *par)
545 {
546 putlog(LOG_CMDS, "*", "#%s# uptime", dcc[idx].nick);
547 tell_verbose_uptime(idx);
548 }
549
550 static void cmd_status(struct userrec *u, int idx, char *par)
551 {
552 int atr = u ? u->flags : 0;
553
554 if (!egg_strcasecmp(par, "all")) {
555 if (!(atr & USER_MASTER)) {
556 dprintf(idx, "You do not have Bot Master privileges.\n");
557 return;
558 }
559 putlog(LOG_CMDS, "*", "#%s# status all", dcc[idx].nick);
560 tell_verbose_status(idx);
561 tell_mem_status_dcc(idx);
562 dprintf(idx, "\n");
563 tell_settings(idx);
564 do_module_report(idx, 1, NULL);
565 } else {
566 putlog(LOG_CMDS, "*", "#%s# status", dcc[idx].nick);
567 tell_verbose_status(idx);
568 tell_mem_status_dcc(idx);
569 do_module_report(idx, 0, NULL);
570 }
571 }
572
573 static void cmd_dccstat(struct userrec *u, int idx, char *par)
574 {
575 putlog(LOG_CMDS, "*", "#%s# dccstat", dcc[idx].nick);
576 tell_dcc(idx);
577 }
578
579 static void cmd_boot(struct userrec *u, int idx, char *par)
580 {
581 int i, files = 0, ok = 0;
582 char *who;
583 struct userrec *u2;
584
585 if (!par[0]) {
586 dprintf(idx, "Usage: boot nick[@bot]\n");
587 return;
588 }
589 who = newsplit(&par);
590 if (strchr(who, '@') != NULL) {
591 char whonick[HANDLEN + 1];
592
593 splitcn(whonick, who, '@', HANDLEN);
594 if (!egg_strcasecmp(who, botnetnick)) {
595 cmd_boot(u, idx, whonick);
596 return;
597 }
598 if (remote_boots > 0) {
599 i = nextbot(who);
600 if (i < 0) {
601 dprintf(idx, "No such bot connected.\n");
602 return;
603 }
604 botnet_send_reject(i, dcc[idx].nick, botnetnick, whonick,
605 who, par[0] ? par : dcc[idx].nick);
606 putlog(LOG_BOTS, "*", "#%s# boot %s@%s (%s)", dcc[idx].nick, whonick,
607 who, par[0] ? par : dcc[idx].nick);
608 } else
609 dprintf(idx, "Remote boots are disabled here.\n");
610 return;
611 }
612 for (i = 0; i < dcc_total; i++)
613 if (!egg_strcasecmp(dcc[i].nick, who)
614 && !ok && (dcc[i].type->flags & DCT_CANBOOT)) {
615 u2 = get_user_by_handle(userlist, dcc[i].nick);
616 if (u2 && (u2->flags & USER_OWNER)
617 && egg_strcasecmp(dcc[idx].nick, who)) {
618 dprintf(idx, "Can't boot the bot owner.\n");
619 return;
620 }
621 if (u2 && (u2->flags & USER_MASTER) && !(u && (u->flags & USER_MASTER))) {
622 dprintf(idx, "Can't boot a bot master.\n");
623 return;
624 }
625 files = (dcc[i].type->flags & DCT_FILES);
626 if (files)
627 dprintf(idx, "Booted %s from the file section.\n", dcc[i].nick);
628 else
629 dprintf(idx, "Booted %s from the bot.\n", dcc[i].nick);
630 putlog(LOG_CMDS, "*", "#%s# boot %s %s", dcc[idx].nick, who, par);
631 do_boot(i, dcc[idx].nick, par);
632 ok = 1;
633 }
634 if (!ok)
635 dprintf(idx, "Who? No such person on the party line.\n");
636 }
637
638 static void cmd_console(struct userrec *u, int idx, char *par)
639 {
640 char *nick, s[2], s1[512];
641 int dest = 0, i, ok = 0, pls, md;
642 struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
643 module_entry *me;
644
645 if (!par[0]) {
646 dprintf(idx, "Your console is %s: %s (%s)\n",
647 dcc[idx].u.chat->con_chan,
648 masktype(dcc[idx].u.chat->con_flags),
649 maskname(dcc[idx].u.chat->con_flags));
650 return;
651 }
652 get_user_flagrec(u, &fr, dcc[idx].u.chat->con_chan);
653 strcpy(s1, par);
654 nick = newsplit(&par);
655 /* Don't remove '+' as someone couldn't have '+' in CHANMETA cause
656 * he doesn't use IRCnet ++rtc.
657 */
658 if (nick[0] && !strchr(CHANMETA "+-*", nick[0]) && glob_master(fr)) {
659 for (i = 0; i < dcc_total; i++)
660 if (!egg_strcasecmp(nick, dcc[i].nick) &&
661 (dcc[i].type == &DCC_CHAT) && (!ok)) {
662 ok = 1;
663 dest = i;
664 }
665 if (!ok) {
666 dprintf(idx, "No such user on the party line!\n");
667 return;
668 }
669 nick[0] = 0;
670 } else
671 dest = idx;
672 if (!nick[0])
673 nick = newsplit(&par);
674 /* Consider modeless channels, starting with '+' */
675 if ((nick [0] == '+' && findchan_by_dname(nick)) ||
676 (nick [0] != '+' && strchr(CHANMETA "*", nick[0]))) {
677 if (strcmp(nick, "*") && !findchan_by_dname(nick)) {
678 dprintf(idx, "Invalid console channel: %s\n", nick);
679 return;
680 }
681 get_user_flagrec(u, &fr, nick);
682 if (!chan_op(fr) && !(glob_op(fr) && !chan_deop(fr))) {
683 dprintf(idx, "You don't have op or master access to channel %s\n",
684 nick);
685 return;
686 }
687 strncpyz(dcc[dest].u.chat->con_chan, nick, 81);
688 nick[0] = 0;
689 if ((dest == idx) && !glob_master(fr) && !chan_master(fr))
690 /* Consoling to another channel for self */
691 dcc[dest].u.chat->con_flags &= ~(LOG_MISC | LOG_CMDS | LOG_WALL);
692 }
693 if (!nick[0])
694 nick = newsplit(&par);
695 pls = 1;
696 if (nick[0]) {
697 if ((nick[0] != '+') && (nick[0] != '-'))
698 dcc[dest].u.chat->con_flags = 0;
699 for (; *nick; nick++) {
700 if (*nick == '+')
701 pls = 1;
702 else if (*nick == '-')
703 pls = 0;
704 else {
705 s[0] = *nick;
706 s[1] = 0;
707 md = logmodes(s);
708 if ((dest == idx) && !glob_master(fr) && pls) {
709 if (chan_master(fr))
710 md &= ~(LOG_FILES | LOG_LEV1 | LOG_LEV2 | LOG_LEV3 |
711 LOG_LEV4 | LOG_LEV5 | LOG_LEV6 | LOG_LEV7 |
712 LOG_LEV8 | LOG_DEBUG);
713 else
714 md &= ~(LOG_MISC | LOG_CMDS | LOG_FILES | LOG_LEV1 |
715 LOG_LEV2 | LOG_LEV3 | LOG_LEV4 | LOG_LEV5 |
716 LOG_LEV6 | LOG_LEV7 | LOG_LEV8 | LOG_WALL |
717 LOG_DEBUG);
718 }
719 if (!glob_owner(fr) && pls)
720 md &= ~(LOG_RAW | LOG_SRVOUT | LOG_BOTNET | LOG_BOTSHARE);
721 if (!glob_botmast(fr) && pls)
722 md &= ~LOG_BOTS;
723 if (pls)
724 dcc[dest].u.chat->con_flags |= md;
725 else
726 dcc[dest].u.chat->con_flags &= ~md;
727 }
728 }
729 }
730 putlog(LOG_CMDS, "*", "#%s# console %s", dcc[idx].nick, s1);
731 if (dest == idx) {
732 dprintf(idx, "Set your console to %s: %s (%s)\n",
733 dcc[idx].u.chat->con_chan,
734 masktype(dcc[idx].u.chat->con_flags),
735 maskname(dcc[idx].u.chat->con_flags));
736 } else {
737 dprintf(idx, "Set console of %s to %s: %s (%s)\n", dcc[dest].nick,
738 dcc[dest].u.chat->con_chan,
739 masktype(dcc[dest].u.chat->con_flags),
740 maskname(dcc[dest].u.chat->con_flags));
741 dprintf(dest, "%s set your console to %s: %s (%s)\n", dcc[idx].nick,
742 dcc[dest].u.chat->con_chan,
743 masktype(dcc[dest].u.chat->con_flags),
744 maskname(dcc[dest].u.chat->con_flags));
745 }
746 /* New style autosave -- drummer,07/25/1999*/
747 if ((me = module_find("console", 1, 1))) {
748 Function *func = me->funcs;
749 (func[CONSOLE_DOSTORE]) (dest);
750 }
751 }
752
753 static void cmd_pls_bot(struct userrec *u, int idx, char *par)
754 {
755 char *handle, *addr, *p, *q, *host;
756 struct userrec *u1;
757 struct bot_addr *bi;
758
759 if (!par[0])
760 dprintf(idx, "Usage: +bot <handle> <address[:telnet-port[/relay-port]]> [host]\n");
761 else {
762 handle = newsplit(&par);
763 addr = newsplit(&par);
764 if (strlen(handle) > HANDLEN)
765 handle[HANDLEN] = 0; /* max len = XX .. for the moment :) */
766 if (get_user_by_handle(userlist, handle))
767 dprintf(idx, "Someone already exists by that name.\n");
768 else if (strchr(BADHANDCHARS, handle[0]) != NULL)
769 dprintf(idx, "You can't start a botnick with '%c'.\n", handle[0]);
770 else {
771 if (strlen(addr) > 60)
772 addr[60] = 0;
773 putlog(LOG_CMDS, "*", "#%s# +bot %s %s", dcc[idx].nick, handle, addr);
774 userlist = adduser(userlist, handle, "none", "-", USER_BOT);
775 u1 = get_user_by_handle(userlist, handle);
776 bi = user_malloc(sizeof(struct bot_addr));
777
778 q = strchr(addr, ':');
779 if (!q) {
780 bi->address = user_malloc(strlen(addr) + 1);
781 strcpy(bi->address, addr);
782 bi->telnet_port = 3333;
783 bi->relay_port = 3333;
784 } else {
785 bi->address = user_malloc(q - addr + 1);
786 strncpy(bi->address, addr, q - addr);
787 bi->address[q - addr] = 0;
788 p = q + 1;
789 bi->telnet_port = atoi(p);
790 q = strchr(p, '/');
791 if (!q) {
792 bi->relay_port = bi->telnet_port;
793 } else {
794 bi->relay_port = atoi(q + 1);
795 }
796 }
797 set_user(&USERENTRY_BOTADDR, u1, bi);
798 dprintf(idx, "Added bot '%s' with address '%s' and no password.\n",
799 handle, addr);
800 host = newsplit(&par);
801 if (host[0]) {
802 addhost_by_handle(handle, host);
803 } else if (!add_bot_hostmask(idx, handle))
804 dprintf(idx, "You'll want to add a hostmask if this bot will ever %s",
805 "be on any channels that I'm on.\n");
806 }
807 }
808 }
809
810 static void cmd_chhandle(struct userrec *u, int idx, char *par)
811 {
812 char hand[HANDLEN + 1], newhand[HANDLEN + 1];
813 int i, atr = u ? u->flags : 0, atr2;
814 struct userrec *u2;
815
816 strncpyz(hand, newsplit(&par), sizeof hand);
817 strncpyz(newhand, newsplit(&par), sizeof newhand);
818
819 if (!hand[0] || !newhand[0]) {
820 dprintf(idx, "Usage: chhandle <oldhandle> <newhandle>\n");
821 return;
822 }
823 for (i = 0; i < strlen(newhand); i++)
824 if ((newhand[i] <= 32) || (newhand[i] >= 127) || (newhand[i] == '@'))
825 newhand[i] = '?';
826 if (strchr(BADHANDCHARS, newhand[0]) != NULL)
827 dprintf(idx, "Bizarre quantum forces prevent nicknames from starting with %c\n",
828 newhand[0]);
829 else if (get_user_by_handle(userlist, newhand) &&
830 egg_strcasecmp(hand, newhand))
831 dprintf(idx, "Somebody is already using %s.\n", newhand);
832 else {
833 u2 = get_user_by_handle(userlist, hand);
834 atr2 = u2 ? u2->flags : 0;
835 if ((atr & USER_BOTMAST) && !(atr & USER_MASTER) &&
836 !(atr2 & USER_BOT))
837 dprintf(idx, "You can't change nick for non-bots.\n");
838 else if ((bot_flags(u2) & BOT_SHARE) && !(atr & USER_OWNER))
839 dprintf(idx, "You can't change shared bot's nick.\n");
840 else if ((atr2 & USER_OWNER) && !(atr & USER_OWNER) &&
841 egg_strcasecmp(dcc[idx].nick, hand))
842 dprintf(idx, "Can't change the bot owner's handle.\n");
843 else if (isowner(hand) && egg_strcasecmp(dcc[idx].nick, hand))
844 dprintf(idx, "Can't change the permanent bot owner's handle.\n");
845 else if (!egg_strcasecmp(newhand, botnetnick) && (!(atr2 & USER_BOT) ||
846 nextbot(hand) != -1))
847 dprintf(idx, "Hey! That's MY name!\n");
848 else if (change_handle(u2, newhand)) {
849 putlog(LOG_CMDS, "*", "#%s# chhandle %s %s", dcc[idx].nick,
850 hand, newhand);
851 dprintf(idx, "Changed.\n");
852 } else
853 dprintf(idx, "Failed.\n");
854 }
855 }
856
857 static void cmd_handle(struct userrec *u, int idx, char *par)
858 {
859 char oldhandle[HANDLEN + 1], newhandle[HANDLEN + 1];
860 int i;
861
862 strncpyz(newhandle, newsplit(&par), sizeof newhandle);
863
864 if (!newhandle[0]) {
865 dprintf(idx, "Usage: handle <new-handle>\n");
866 return;
867 }
868 for (i = 0; i < strlen(newhandle); i++)
869 if ((newhandle[i] <= 32) || (newhandle[i] >= 127) || (newhandle[i] == '@'))
870 newhandle[i] = '?';
871 if (strchr(BADHANDCHARS, newhandle[0]) != NULL) {
872 dprintf(idx, "Bizarre quantum forces prevent handle from starting with '%c'\n",
873 newhandle[0]);
874 } else if (get_user_by_handle(userlist, newhandle) &&
875 egg_strcasecmp(dcc[idx].nick, newhandle)) {
876 dprintf(idx, "Somebody is already using %s.\n", newhandle);
877 } else if (!egg_strcasecmp(newhandle, botnetnick)) {
878 dprintf(idx, "Hey! That's MY name!\n");
879 } else {
880 strncpyz(oldhandle, dcc[idx].nick, sizeof oldhandle);
881 if (change_handle(u, newhandle)) {
882 putlog(LOG_CMDS, "*", "#%s# handle %s", oldhandle, newhandle);
883 dprintf(idx, "Okay, changed.\n");
884 } else
885 dprintf(idx, "Failed.\n");
886 }
887 }
888
889 static void cmd_chpass(struct userrec *u, int idx, char *par)
890 {
891 char *handle, *new;
892 int atr = u ? u->flags : 0, l;
893
894 if (!par[0])
895 dprintf(idx, "Usage: chpass <handle> [password]\n");
896 else {
897 handle = newsplit(&par);
898 u = get_user_by_handle(userlist, handle);
899 if (!u)
900 dprintf(idx, "No such user.\n");
901 else if ((atr & USER_BOTMAST) && !(atr & USER_MASTER) &&
902 !(u->flags & USER_BOT))
903 dprintf(idx, "You can't change password for non-bots.\n");
904 else if ((bot_flags(u) & BOT_SHARE) && !(atr & USER_OWNER))
905 dprintf(idx, "You can't change shared bot's password.\n");
906 else if ((u->flags & USER_OWNER) && !(atr & USER_OWNER) &&
907 egg_strcasecmp(handle, dcc[idx].nick))
908 dprintf(idx, "Can't change the bot owner's password.\n");
909 else if (isowner(handle) && egg_strcasecmp(dcc[idx].nick, handle))
910 dprintf(idx, "Can't change the permanent bot owner's password.\n");
911 else if (!par[0]) {
912 putlog(LOG_CMDS, "*", "#%s# chpass %s [nothing]", dcc[idx].nick,
913 handle);
914 set_user(&USERENTRY_PASS, u, NULL);
915 dprintf(idx, "Removed password.\n");
916 } else {
917 l = strlen(new = newsplit(&par));
918 if (l > 16)
919 new[16] = 0;
920 if (l < 6)
921 dprintf(idx, "Please use at least 6 characters.\n");
922 else {
923 set_user(&USERENTRY_PASS, u, new);
924 putlog(LOG_CMDS, "*", "#%s# chpass %s [something]", dcc[idx].nick,
925 handle);
926 dprintf(idx, "Changed password.\n");
927 }
928 }
929 }
930 }
931
932 static void cmd_chaddr(struct userrec *u, int idx, char *par)
933 {
934 int telnet_port = 3333, relay_port = 3333;
935 char *handle, *addr, *p, *q;
936 struct bot_addr *bi;
937 struct userrec *u1;
938
939 if (!par[0]) {
940 dprintf(idx, "Usage: chaddr <botname> <address[:telnet-port[/relay-port]]>\n");
941 return;
942 }
943 handle = newsplit(&par);
944 addr = newsplit(&par);
945 if (strlen(addr) > UHOSTMAX)
946 addr[UHOSTMAX] = 0;
947 u1 = get_user_by_handle(userlist, handle);
948 if (!u1 || !(u1->flags & USER_BOT)) {
949 dprintf(idx, "Useful only for tandem bots.\n");
950 return;
951 }
952 if ((bot_flags(u1) & BOT_SHARE) && (!u || !u->flags & USER_OWNER)) {
953 dprintf(idx, "You can't change shared bot's address.\n");
954 return;
955 }
956 putlog(LOG_CMDS, "*", "#%s# chaddr %s %s", dcc[idx].nick, handle, addr);
957 dprintf(idx, "Changed bot's address.\n");
958
959 bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u1);
960 if (bi) {
961 telnet_port = bi->telnet_port;
962 relay_port = bi->relay_port;
963 }
964
965 bi = user_malloc(sizeof(struct bot_addr));
966
967 q = strchr(addr, ':');
968 if (!q) {
969 bi->address = user_malloc(strlen(addr) + 1);
970 strcpy(bi->address, addr);
971 bi->telnet_port = telnet_port;
972 bi->relay_port = relay_port;
973 } else {
974 bi->address = user_malloc(q - addr + 1);
975 strncpyz(bi->address, addr, q - addr + 1);
976 p = q + 1;
977 bi->telnet_port = atoi(p);
978 q = strchr(p, '/');
979 if (!q) {
980 bi->relay_port = bi->telnet_port;
981 } else {
982 bi->relay_port = atoi(q + 1);
983 }
984 }
985 set_user(&USERENTRY_BOTADDR, u1, bi);
986 }
987
988 static void cmd_comment(struct userrec *u, int idx, char *par)
989 {
990 char *handle;
991 struct userrec *u1;
992
993 if (!par[0]) {
994 dprintf(idx, "Usage: comment <handle> <newcomment>\n");
995 return;
996 }
997 handle = newsplit(&par);
998 u1 = get_user_by_handle(userlist, handle);
999 if (!u1) {
1000 dprintf(idx, "No such user!\n");
1001 return;
1002 }
1003 if ((u1->flags & USER_OWNER) && !(u && (u->flags & USER_OWNER)) &&
1004 egg_strcasecmp(handle, dcc[idx].nick)) {
1005 dprintf(idx, "Can't change comment on the bot owner.\n");
1006 return;
1007 }
1008 putlog(LOG_CMDS, "*", "#%s# comment %s %s", dcc[idx].nick, handle, par);
1009 if (!egg_strcasecmp(par, "none")) {
1010 dprintf(idx, "Okay, comment blanked.\n");
1011 set_user(&USERENTRY_COMMENT, u1, NULL);
1012 return;
1013 }
1014 dprintf(idx, "Changed comment.\n");
1015 set_user(&USERENTRY_COMMENT, u1, par);
1016 }
1017
1018 static void cmd_restart(struct userrec *u, int idx, char *par)
1019 {
1020 putlog(LOG_CMDS, "*", "#%s# restart", dcc[idx].nick);
1021 if (!backgrd) {
1022 dprintf(idx, "You can not .restart a bot when running -n (due to tcl)\n");
1023 return;
1024 }
1025 dprintf(idx, "Restarting.\n");
1026 if (make_userfile) {
1027 putlog(LOG_MISC, "*",
1028 "Uh, guess you don't need to create a new userfile.");
1029 make_userfile = 0;
1030 }
1031 write_userfile(-1);
1032 putlog(LOG_MISC, "*", "Restarting ...");
1033 wipe_timers(interp, &utimer);
1034 wipe_timers(interp, &timer);
1035 do_restart = idx;
1036 }
1037
1038 static void cmd_rehash(struct userrec *u, int idx, char *par)
1039 {
1040 putlog(LOG_CMDS, "*", "#%s# rehash", dcc[idx].nick);
1041 dprintf(idx, "Rehashing.\n");
1042 if (make_userfile) {
1043 putlog(LOG_MISC, "*",
1044 "Uh, guess you don't need to create a new userfile.");
1045 make_userfile = 0;
1046 }
1047 write_userfile(-1);
1048 putlog(LOG_MISC, "*", "Rehashing ...");
1049 do_restart = -2;
1050 }
1051
1052 static void cmd_reload(struct userrec *u, int idx, char *par)
1053 {
1054 putlog(LOG_CMDS, "*", "#%s# reload", dcc[idx].nick);
1055 dprintf(idx, "Reloading user file...\n");
1056 reload();
1057 }
1058
1059 /* NOTE: This gets replaced in the server mod, with a version that handles
1060 * the server disconnect better.
1061 */
1062 void cmd_die(struct userrec *u, int idx, char *par)
1063 {
1064 char s[1024];
1065
1066 putlog(LOG_CMDS, "*", "#%s# die %s", dcc[idx].nick, par);
1067 if (par[0]) {
1068 simple_sprintf(s, "BOT SHUTDOWN (%s: %s)", dcc[idx].nick, par);
1069 } else {
1070 simple_sprintf(s, "BOT SHUTDOWN (authorized by %s)", dcc[idx].nick);
1071 }
1072 chatout("*** %s\n", s);
1073 botnet_send_chat(-1, botnetnick, s);
1074 botnet_send_bye();
1075 write_userfile(-1);
1076 simple_sprintf(s, "DIE BY %s!%s (%s)", dcc[idx].nick,
1077 dcc[idx].host, par[0] ? par : "request");
1078 fatal(s, 0);
1079 }
1080
1081 static void cmd_debug(struct userrec *u, int idx, char *par)
1082 {
1083 if (!egg_strcasecmp(par, "help")) {
1084 putlog(LOG_CMDS, "*", "#%s# debug help", dcc[idx].nick);
1085 debug_help(idx);
1086 } else {
1087 putlog(LOG_CMDS, "*", "#%s# debug", dcc[idx].nick);
1088 debug_mem_to_dcc(idx);
1089 }
1090 }
1091
1092 static void cmd_simul(struct userrec *u, int idx, char *par)
1093 {
1094 char *nick;
1095 int i, ok = 0;
1096
1097 nick = newsplit(&par);
1098 if (!par[0]) {
1099 dprintf(idx, "Usage: simul <hand> <text>\n");
1100 return;
1101 }
1102 if (isowner(nick)) {
1103 dprintf(idx, "Unable to '.simul' permanent owners.\n");
1104 return;
1105 }
1106 for (i = 0; i < dcc_total; i++)
1107 if (!egg_strcasecmp(nick, dcc[i].nick) && !ok &&
1108 (dcc[i].type->flags & DCT_SIMUL)) {
1109 putlog(LOG_CMDS, "*", "#%s# simul %s %s", dcc[idx].nick, nick, par);
1110 if (dcc[i].type && dcc[i].type->activity) {
1111 dcc[i].type->activity(i, par, strlen(par));
1112 ok = 1;
1113 }
1114 }
1115 if (!ok)
1116 dprintf(idx, "No such user on the party line.\n");
1117 }
1118
1119 static void cmd_link(struct userrec *u, int idx, char *par)
1120 {
1121 char *s;
1122 int i;
1123
1124 if (!par[0]) {
1125 dprintf(idx, "Usage: link [some-bot] <new-bot>\n");
1126 return;
1127 }
1128 putlog(LOG_CMDS, "*", "#%s# link %s", dcc[idx].nick, par);
1129 s = newsplit(&par);
1130 if (!par[0] || !egg_strcasecmp(par, botnetnick))
1131 botlink(dcc[idx].nick, idx, s);
1132 else {
1133 char x[40];
1134
1135 i = nextbot(s);
1136 if (i < 0) {
1137 dprintf(idx, "No such bot online.\n");
1138 return;
1139 }
1140 simple_sprintf(x, "%d:%s@%s", dcc[idx].sock, dcc[idx].nick, botnetnick);
1141 botnet_send_link(i, x, s, par);
1142 }
1143 }
1144
1145 static void cmd_unlink(struct userrec *u, int idx, char *par)
1146 {
1147 int i;
1148 char *bot;
1149
1150 if (!par[0]) {
1151 dprintf(idx, "Usage: unlink <bot> [reason]\n");
1152 return;
1153 }
1154 putlog(LOG_CMDS, "*", "#%s# unlink %s", dcc[idx].nick, par);
1155 bot = newsplit(&par);
1156 i = nextbot(bot);
1157 if (i < 0) {
1158 botunlink(idx, bot, par);
1159 return;
1160 }
1161 /* If we're directly connected to that bot, just do it
1162 * (is nike gunna sue?)
1163 */
1164 if (!egg_strcasecmp(dcc[i].nick, bot))
1165 botunlink(idx, bot, par);
1166 else {
1167 char x[40];
1168
1169 simple_sprintf(x, "%d:%s@%s", dcc[idx].sock, dcc[idx].nick, botnetnick);
1170 botnet_send_unlink(i, x, lastbot(bot), bot, par);
1171 }
1172 }
1173
1174 static void cmd_relay(struct userrec *u, int idx, char *par)
1175 {
1176 if (!par[0]) {
1177 dprintf(idx, "Usage: relay <bot>\n");
1178 return;
1179 }
1180 putlog(LOG_CMDS, "*", "#%s# relay %s", dcc[idx].nick, par);
1181 tandem_relay(idx, par, 0);
1182 }
1183
1184 static void cmd_save(struct userrec *u, int idx, char *par)
1185 {
1186 putlog(LOG_CMDS, "*", "#%s# save", dcc[idx].nick);
1187 dprintf(idx, "Saving user file...\n");
1188 write_userfile(-1);
1189 }
1190
1191 static void cmd_backup(struct userrec *u, int idx, char *par)
1192 {
1193 putlog(LOG_CMDS, "*", "#%s# backup", dcc[idx].nick);
1194 dprintf(idx, "Backing up the user file...\n");
1195 backup_userfile();
1196 }
1197
1198 static void cmd_trace(struct userrec *u, int idx, char *par)
1199 {
1200 int i;
1201 char x[NOTENAMELEN + 11], y[11];
1202
1203 if (!par[0]) {
1204 dprintf(idx, "Usage: trace <botname>\n");
1205 return;
1206 }
1207 if (!egg_strcasecmp(par, botnetnick)) {
1208 dprintf(idx, "That's me! Hiya! :)\n");
1209 return;
1210 }
1211 i = nextbot(par);
1212 if (i < 0) {
1213 dprintf(idx, "Unreachable bot.\n");
1214 return;
1215 }
1216 putlog(LOG_CMDS, "*", "#%s# trace %s", dcc[idx].nick, par);
1217 simple_sprintf(x, "%d:%s@%s", dcc[idx].sock, dcc[idx].nick, botnetnick);
1218 simple_sprintf(y, ":%d", now);
1219 botnet_send_trace(i, x, par, y);
1220 }
1221
1222 static void cmd_binds(struct userrec *u, int idx, char *par)
1223 {
1224 putlog(LOG_CMDS, "*", "#%s# binds %s", dcc[idx].nick, par);
1225 tell_binds(idx, par);
1226 }
1227
1228 static void cmd_banner(struct userrec *u, int idx, char *par)
1229 {
1230 char s[1024];
1231 int i;
1232
1233 if (!par[0]) {
1234 dprintf(idx, "Usage: banner <message>\n");
1235 return;
1236 }
1237 simple_sprintf(s, "\007### Botwide: [%s] %s\n", dcc[idx].nick, par);
1238 for (i = 0; i < dcc_total; i++)
1239 if (dcc[i].type->flags & DCT_MASTER)
1240 dprintf(i, "%s", s);
1241 }
1242
1243 /* After messing with someone's user flags, make sure the dcc-chat flags
1244 * are set correctly.
1245 */
1246 int check_dcc_attrs(struct userrec *u, int oatr)
1247 {
1248 int i, stat;
1249 char *p, *q, s[121];
1250
1251 /* If it matches someone in the owner list, make sure he/she has +n */
1252 if (!u)
1253 return 0;
1254 /* Make sure default owners are +n */
1255 if (owner[0]) {
1256 q = owner;
1257 p = strchr(q, ',');
1258 while (p) {
1259 strncpyz(s, q, p - q);
1260 rmspace(s);
1261 if (!egg_strcasecmp(u->handle, s))
1262 u->flags = sanity_check(u->flags | USER_OWNER);
1263 q = p + 1;
1264 p = strchr(q, ',');
1265 }
1266 strcpy(s, q);
1267 rmspace(s);
1268 if (!egg_strcasecmp(u->handle, s))
1269 u->flags = sanity_check(u->flags | USER_OWNER);
1270 }
1271 for (i = 0; i < dcc_total; i++) {
1272 if ((dcc[i].type->flags & DCT_MASTER) &&
1273 (!egg_strcasecmp(u->handle, dcc[i].nick))) {
1274 stat = dcc[i].status;
1275 if ((dcc[i].type == &DCC_CHAT) &&
1276 ((u->flags & (USER_OP | USER_MASTER | USER_OWNER |
1277 USER_BOTMAST))
1278 != (oatr & (USER_OP | USER_MASTER | USER_OWNER |
1279 USER_BOTMAST)))) {
1280 botnet_send_join_idx(i, -1);
1281 }
1282 if ((oatr & USER_MASTER) && !(u->flags & USER_MASTER)) {
1283 struct flag_record fr = {FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
1284
1285 dcc[i].u.chat->con_flags &= ~(LOG_MISC | LOG_CMDS | LOG_RAW |
1286 LOG_FILES | LOG_LEV1 | LOG_LEV2 |
1287 LOG_LEV3 | LOG_LEV4 | LOG_LEV5 |
1288 LOG_LEV6 | LOG_LEV7 | LOG_LEV8 |
1289 LOG_WALL | LOG_DEBUG);
1290 get_user_flagrec(u, &fr, NULL);
1291 if (!chan_master(fr))
1292 dcc[i].u.chat->con_flags |= (LOG_MISC | LOG_CMDS);
1293 dprintf(i, "*** POOF! ***\n");
1294 dprintf(i, "You are no longer a master on this bot.\n");
1295 }
1296 if (!(oatr & USER_MASTER) && (u->flags & USER_MASTER)) {
1297 dcc[i].u.chat->con_flags |= conmask;
1298 dprintf(i, "*** POOF! ***\n");
1299 dprintf(i, "You are now a master on this bot.\n");
1300 }
1301 if (!(oatr & USER_BOTMAST) && (u->flags & USER_BOTMAST)) {
1302 dprintf(i, "### POOF! ###\n");
1303 dprintf(i, "You are now a botnet master on this bot.\n");
1304 }
1305 if ((oatr & USER_BOTMAST) && !(u->flags & USER_BOTMAST)) {
1306 dprintf(i, "### POOF! ###\n");
1307 dprintf(i, "You are no longer a botnet master on this bot.\n");
1308 }
1309 if (!(oatr & USER_OWNER) && (u->flags & USER_OWNER)) {
1310 dprintf(i, "@@@ POOF! @@@\n");
1311 dprintf(i, "You are now an OWNER of this bot.\n");
1312 }
1313 if ((oatr & USER_OWNER) && !(u->flags & USER_OWNER)) {
1314 dprintf(i, "@@@ POOF! @@@\n");
1315 dprintf(i, "You are no longer an owner of this bot.\n");
1316 }
1317 if ((stat & STAT_PARTY) && (u->flags & USER_OP))
1318 stat &= ~STAT_PARTY;
1319 if (!(stat & STAT_PARTY) && !(u->flags & USER_OP) &&
1320 !(u->flags & USER_MASTER))
1321 stat |= STAT_PARTY;
1322 if ((stat & STAT_CHAT) && !(u->flags & USER_PARTY) &&
1323 !(u->flags & USER_MASTER) &&
1324 (!(u->flags & USER_OP) || require_p))
1325 stat &= ~STAT_CHAT;
1326 if ((dcc[i].type->flags & DCT_FILES) && !(stat & STAT_CHAT) &&
1327 ((u->flags & USER_MASTER) || (u->flags & USER_PARTY) ||
1328 ((u->flags & USER_OP) && !require_p)))
1329 stat |= STAT_CHAT;
1330 dcc[i].status = stat;
1331 /* Check if they no longer have access to wherever they are.
1332 *
1333 * NOTE: DON'T kick someone off the party line just cuz they lost +p
1334 * (pinvite script removes +p after 5 mins automatically)
1335 */
1336 if ((dcc[i].type->flags & DCT_FILES) && !(u->flags & USER_XFER) &&
1337 !(u->flags & USER_MASTER)) {
1338 dprintf(i, "-+- POOF! -+-\n");
1339 dprintf(i, "You no longer have file area access.\n\n");
1340 putlog(LOG_MISC, "*", "DCC user [%s]%s removed from file system",
1341 dcc[i].nick, dcc[i].host);
1342 if (dcc[i].status & STAT_CHAT) {
1343 struct chat_info *ci;
1344
1345 ci = dcc[i].u.file->chat;
1346 nfree(dcc[i].u.file);
1347 dcc[i].u.chat = ci;
1348 dcc[i].status &= (~STAT_CHAT);
1349 dcc[i].type = &DCC_CHAT;
1350 if (dcc[i].u.chat->channel >= 0) {
1351 chanout_but(-1, dcc[i].u.chat->channel,
1352 "*** %s has returned.\n", dcc[i].nick);
1353 if (dcc[i].u.chat->channel < 100000)
1354 botnet_send_join_idx(i, -1);
1355 }
1356 } else {
1357 killsock(dcc[i].sock);
1358 lostdcc(i);
1359 }
1360 }
1361 }
1362 if (dcc[i].type == &DCC_BOT && !egg_strcasecmp(u->handle, dcc[i].nick)) {
1363 if ((dcc[i].status & STAT_LEAF) && !(u->flags & BOT_LEAF))
1364 dcc[i].status &= ~(STAT_LEAF | STAT_WARNED);
1365 if (!(dcc[i].status & STAT_LEAF) && (u->flags & BOT_LEAF))
1366 dcc[i].status |= STAT_LEAF;
1367 }
1368 }
1369 return u->flags;
1370 }
1371
1372 int check_dcc_chanattrs(struct userrec *u, char *chname, int chflags,
1373 int ochatr)
1374 {
1375 int i, found = 0, atr = u ? u->flags : 0;
1376 struct chanset_t *chan;
1377
1378 if (!u)
1379 return 0;
1380 chan = chanset;
1381 for (i = 0; i < dcc_total; i++) {
1382 if ((dcc[i].type->flags & DCT_MASTER) &&
1383 !egg_strcasecmp(u->handle, dcc[i].nick)) {
1384 if ((dcc[i].type == &DCC_CHAT) &&
1385 ((chflags & (USER_OP | USER_MASTER | USER_OWNER))
1386 != (ochatr & (USER_OP | USER_MASTER | USER_OWNER))))
1387 botnet_send_join_idx(i, -1);
1388 if ((ochatr & USER_MASTER) && !(chflags & USER_MASTER)) {
1389 if (!(atr & USER_MASTER))
1390 dcc[i].u.chat->con_flags &= ~(LOG_MISC | LOG_CMDS);
1391 dprintf(i, "*** POOF! ***\n");
1392 dprintf(i, "You are no longer a master on %s.\n", chname);
1393 }
1394 if (!(ochatr & USER_MASTER) && (chflags & USER_MASTER)) {
1395 dcc[i].u.chat->con_flags |= conmask;
1396 if (!(atr & USER_MASTER))
1397 dcc[i].u.chat->con_flags &=
1398 ~(LOG_LEV1 | LOG_LEV2 | LOG_LEV3 | LOG_LEV4 |
1399 LOG_LEV5 | LOG_LEV6 | LOG_LEV7 | LOG_LEV8 |
1400 LOG_RAW | LOG_DEBUG | LOG_WALL | LOG_FILES | LOG_SRVOUT);
1401 dprintf(i, "*** POOF! ***\n");
1402 dprintf(i, "You are now a master on %s.\n", chname);
1403 }
1404 if (!(ochatr & USER_OWNER) && (chflags & USER_OWNER)) {
1405 dprintf(i, "@@@ POOF! @@@\n");
1406 dprintf(i, "You are now an OWNER of %s.\n", chname);
1407 }
1408 if ((ochatr & USER_OWNER) && !(chflags & USER_OWNER)) {
1409 dprintf(i, "@@@ POOF! @@@\n");
1410 dprintf(i, "You are no longer an owner of %s.\n", chname);
1411 }
1412 if (((ochatr & (USER_OP | USER_MASTER | USER_OWNER)) &&
1413 (!(chflags & (USER_OP | USER_MASTER | USER_OWNER)))) ||
1414 ((chflags & (USER_OP | USER_MASTER | USER_OWNER)) &&
1415 (!(ochatr & (USER_OP | USER_MASTER | USER_OWNER))))) {
1416 struct flag_record fr = {FR_CHAN, 0, 0, 0, 0, 0};
1417
1418 while (chan && !found) {
1419 get_user_flagrec(u, &fr, chan->dname);
1420 if (fr.chan & (USER_OP | USER_MASTER | USER_OWNER))
1421 found = 1;
1422 else
1423 chan = chan->next;
1424 }
1425 if (!chan)
1426 chan = chanset;
1427 if (chan)
1428 strcpy(dcc[i].u.chat->con_chan, chan->dname);
1429 else
1430 strcpy(dcc[i].u.chat->con_chan, "*");
1431 }
1432 }
1433 }
1434 return chflags;
1435 }
1436
1437 static void cmd_chattr(struct userrec *u, int idx, char *par)
1438 {
1439 char *hand, *arg = NULL, *tmpchg = NULL, *chg = NULL, work[1024];
1440 struct chanset_t *chan = NULL;
1441 struct userrec *u2;
1442 struct flag_record pls = {0, 0, 0, 0, 0, 0},
1443 mns = {0, 0, 0, 0, 0, 0},
1444 user = {0, 0, 0, 0, 0, 0};
1445 module_entry *me;
1446 int fl = -1, of = 0, ocf = 0;
1447
1448 if (!par[0]) {
1449 dprintf(idx, "Usage: chattr <handle> [changes] [channel]\n");
1450 return;
1451 }
1452 hand = newsplit(&par);
1453 u2 = get_user_by_handle(userlist, hand);
1454 if (!u2) {
1455 dprintf(idx, "No such user!\n");
1456 return;
1457 }
1458
1459 /* Parse args */
1460 if (par[0]) {
1461 arg = newsplit(&par);
1462 if (par[0]) {
1463 /* .chattr <handle> <changes> <channel> */
1464 chg = arg;
1465 arg = newsplit(&par);
1466 chan = findchan_by_dname(arg);
1467 } else {
1468 chan = findchan_by_dname(arg);
1469 /* Consider modeless channels, starting with '+' */
1470 if (!(arg[0] == '+' && chan) &&
1471 !(arg[0] != '+' && strchr (CHANMETA, arg[0]))) {
1472 /* .chattr <handle> <changes> */
1473 chg = arg;
1474 chan = NULL; /* uh, !strchr (CHANMETA, channel[0]) && channel found?? */
1475 arg = NULL;
1476 }
1477 /* .chattr <handle> <channel>: nothing to do... */
1478 }
1479 }
1480 /* arg: pointer to channel name, NULL if none specified
1481 * chan: pointer to channel structure, NULL if none found or none specified
1482 * chg: pointer to changes, NULL if none specified
1483 */
1484 Assert(!(!arg && chan));
1485 if (arg && !chan) {
1486 dprintf(idx, "No channel record for %s.\n", arg);
1487 return;
1488 }
1489 if (chg) {
1490 if (!arg && strpbrk(chg, "&|")) {
1491 /* .chattr <handle> *[&|]*: use console channel if found... */
1492 if (!strcmp ((arg = dcc[idx].u.chat->con_chan), "*"))
1493 arg = NULL;
1494 else
1495 chan = findchan_by_dname(arg);
1496 if (arg && !chan) {
1497 dprintf (idx, "Invalid console channel %s.\n", arg);
1498 return;
1499 }
1500 } else if (arg && !strpbrk(chg, "&|")) {
1501 tmpchg = nmalloc(strlen(chg) + 2);
1502 strcpy(tmpchg, "|");
1503 strcat(tmpchg, chg);
1504 chg = tmpchg;
1505 }
1506 }
1507 par = arg;
1508 user.match = FR_GLOBAL;
1509 if (chan)
1510 user.match |= FR_CHAN;
1511 get_user_flagrec(u, &user, chan ? chan->dname : 0);
1512 if (!chan && !glob_botmast(user)) {
1513 dprintf(idx, "You do not have Bot Master privileges.\n");
1514 if (tmpchg)
1515 nfree(tmpchg);
1516 return;
1517 }
1518 if (chan && !glob_master(user) && !chan_master(user)) {
1519 dprintf(idx, "You do not have channel master privileges for channel %s\n",
1520 par);
1521 if (tmpchg)
1522 nfree(tmpchg);
1523 return;
1524 }
1525 user.match &= fl;
1526 if (chg) {
1527 pls.match = user.match;
1528 break_down_flags(chg, &pls, &mns);
1529 /* No-one can change these flags on-the-fly */
1530 pls.global &= ~(USER_BOT);
1531 mns.global &= ~(USER_BOT);
1532
1533 if (chan) {
1534 pls.chan &= ~(BOT_SHARE);
1535 mns.chan &= ~(BOT_SHARE);
1536 }
1537 if (!glob_owner(user)) {
1538 pls.global &= ~(USER_OWNER | USER_MASTER | USER_BOTMAST | USER_UNSHARED);
1539 mns.global &= ~(USER_OWNER | USER_MASTER | USER_BOTMAST | USER_UNSHARED);
1540
1541 if (chan) {
1542 pls.chan &= ~USER_OWNER;
1543 mns.chan &= ~USER_OWNER;
1544 }
1545 if (!glob_master(user)) {
1546 pls.global &= USER_PARTY | USER_XFER;
1547 mns.global &= USER_PARTY | USER_XFER;
1548
1549 if (!glob_botmast(user)) {
1550 pls.global = 0;
1551 mns.global = 0;
1552 }
1553 }
1554 }
1555 if (chan && !chan_owner(user) && !glob_owner(user)) {
1556 pls.chan &= ~USER_MASTER;
1557 mns.chan &= ~USER_MASTER;
1558 if (!chan_master(user) && !glob_master(user)) {
1559 pls.chan = 0;
1560 mns.chan = 0;
1561 }
1562 }
1563 get_user_flagrec(u2, &user, par);
1564 if (user.match & FR_GLOBAL) {
1565 of = user.global;
1566 user.global = sanity_check((user.global |pls.global) &~mns.global);
1567
1568 user.udef_global = (user.udef_global | pls.udef_global)
1569 & ~mns.udef_global;
1570 }
1571 if (chan) {
1572 ocf = user.chan;
1573 user.chan = chan_sanity_check((user.chan | pls.chan) & ~mns.chan,
1574 user.global);
1575
1576 user.udef_chan = (user.udef_chan | pls.udef_chan) & ~mns.udef_chan;
1577 }
1578 set_user_flagrec(u2, &user, par);
1579 }
1580 if (chan)
1581 putlog(LOG_CMDS, "*", "#%s# (%s) chattr %s %s",
1582 dcc[idx].nick, chan ? chan->dname : "*", hand, chg ? chg : "");
1583 else
1584 putlog(LOG_CMDS, "*", "#%s# chattr %s %s", dcc[idx].nick, hand,
1585 chg ? chg : "");
1586 /* Get current flags and display them */
1587 if (user.match & FR_GLOBAL) {
1588 user.match = FR_GLOBAL;
1589 if (chg)
1590 check_dcc_attrs(u2, of);
1591 get_user_flagrec(u2, &user, NULL);
1592 build_flags(work, &user, NULL);
1593 if (work[0] != '-')
1594 dprintf(idx, "Global flags for %s are now +%s\n", hand, work);
1595 else
1596 dprintf(idx, "No global flags for %s.\n", hand);
1597 }
1598 if (chan) {
1599 user.match = FR_CHAN;
1600 get_user_flagrec(u2, &user, par);
1601 user.chan &= ~BOT_SHARE;
1602 if (chg)
1603 check_dcc_chanattrs(u2, chan->dname, user.chan, ocf);
1604 build_flags(work, &user, NULL);
1605 if (work[0] != '-')
1606 dprintf(idx, "Channel flags for %s on %s are now +%s\n", hand,
1607 chan->dname, work);
1608 else
1609 dprintf(idx, "No flags for %s on %s.\n", hand, chan->dname);
1610 if (chg && (me = module_find("irc", 0, 0))) {
1611 Function *func = me->funcs;
1612
1613 if (chan)
1614 (func[IRC_RECHECK_CHANNEL]) (chan, 0);
1615 }
1616 }
1617 if (tmpchg)
1618 nfree(tmpchg);
1619 }
1620
1621 static void cmd_botattr(struct userrec *u, int idx, char *par)
1622 {
1623 char *hand, *chg = NULL, *arg = NULL, *tmpchg = NULL, work[1024];
1624 struct chanset_t *chan = NULL;
1625 struct userrec *u2;
1626 struct flag_record pls = {0, 0, 0, 0, 0, 0},
1627 mns = {0, 0, 0, 0, 0, 0},
1628 user = {0, 0, 0, 0, 0, 0};
1629 int idx2;
1630
1631 if (!par[0]) {
1632 dprintf(idx, "Usage: botattr <handle> [changes] [channel]\n");
1633 return;
1634 }
1635 hand = newsplit(&par);
1636 u2 = get_user_by_handle(userlist, hand);
1637 if (!u2 || !(u2->flags & USER_BOT)) {
1638 dprintf(idx, "No such bot!\n");
1639 return;
1640 }
1641 for (idx2 = 0; idx2 < dcc_total; idx2++)
1642 if (dcc[idx2].type != &DCC_RELAY && dcc[idx2].type != &DCC_FORK_BOT &&
1643 !egg_strcasecmp(dcc[idx2].nick, hand))
1644 break;
1645 if (idx2 != dcc_total) {
1646 dprintf(idx, "You may not change the attributes of a directly linked bot.\n");
1647 return;
1648 }
1649 /* Parse args */
1650 if (par[0]) {
1651 arg = newsplit(&par);
1652 if (par[0]) {
1653 /* .botattr <handle> <changes> <channel> */
1654 chg = arg;
1655 arg = newsplit(&par);
1656 chan = findchan_by_dname(arg);
1657 } else {
1658 chan = findchan_by_dname(arg);
1659 /* Consider modeless channels, starting with '+' */
1660 if (!(arg[0] == '+' && chan) &&
1661 !(arg[0] != '+' && strchr (CHANMETA, arg[0]))) {
1662 /* .botattr <handle> <changes> */
1663 chg = arg;
1664 chan = NULL; /* uh, !strchr (CHANMETA, channel[0]) && channel found?? */
1665 arg = NULL;
1666 }
1667 /* .botattr <handle> <channel>: nothing to do... */
1668 }
1669 }
1670 /* arg: pointer to channel name, NULL if none specified
1671 * chan: pointer to channel structure, NULL if none found or none specified
1672 * chg: pointer to changes, NULL if none specified
1673 */
1674 Assert(!(!arg && chan));
1675 if (arg && !chan) {
1676 dprintf(idx, "No channel record for %s.\n", arg);
1677 return;
1678 }
1679 if (chg) {
1680 if (!arg && strpbrk(chg, "&|")) {
1681 /* botattr <handle> *[&|]*: use console channel if found... */
1682 if (!strcmp ((arg = dcc[idx].u.chat->con_chan), "*"))
1683 arg = NULL;
1684 else
1685 chan = findchan_by_dname(arg);
1686 if (arg && !chan) {
1687 dprintf (idx, "Invalid console channel %s.\n", arg);
1688 return;
1689 }
1690 } else if (arg && !strpbrk(chg, "&|")) {
1691 tmpchg = nmalloc(strlen(chg) + 2);
1692 strcpy (tmpchg, "|");
1693 strcat (tmpchg, chg);
1694 chg = tmpchg;
1695 }
1696 }
1697 par = arg;
1698
1699 user.match = FR_GLOBAL;
1700 get_user_flagrec(u, &user, chan ? chan->dname : 0);
1701 if (!glob_botmast(user)) {
1702 dprintf(idx, "You do not have Bot Master privileges.\n");
1703 if (tmpchg)
1704 nfree(tmpchg);
1705 return;
1706 }
1707 if (chg) {
1708 user.match = FR_BOT | (chan ? FR_CHAN : 0);
1709 pls.match = user.match;
1710 break_down_flags(chg, &pls, &mns);
1711 /* No-one can change these flags on-the-fly */
1712 pls.global &=~BOT_BOT;
1713 mns.global &=~BOT_BOT;
1714
1715 if (chan && glob_owner(user)) {
1716 pls.chan &= BOT_SHARE;
1717 mns.chan &= BOT_SHARE;
1718 } else {
1719 pls.chan = 0;
1720 mns.chan = 0;
1721 }
1722 if (!glob_owner(user)) {
1723 pls.bot &= ~(BOT_SHARE | BOT_GLOBAL);
1724 mns.bot &= ~(BOT_SHARE | BOT_GLOBAL);
1725 }
1726 user.match = FR_BOT | (chan ? FR_CHAN : 0);
1727 get_user_flagrec(u2, &user, par);
1728 user.bot = (user.bot | pls.bot) & ~mns.bot;
1729 if ((user.bot & BOT_SHARE) == BOT_SHARE)
1730 user.bot &= ~BOT_SHARE;
1731 if (chan)
1732 user.chan = (user.chan | pls.chan) & ~mns.chan;
1733 set_user_flagrec(u2, &user, par);
1734 }
1735 if (chan)
1736 putlog(LOG_CMDS, "*", "#%s# (%s) botattr %s %s",
1737 dcc[idx].nick, chan->dname, hand, chg ? chg : "");
1738 else
1739 putlog(LOG_CMDS, "*", "#%s# botattr %s %s", dcc[idx].nick, hand,
1740 chg ? chg : "");
1741 /* get current flags and display them */
1742 if (!chan || pls.bot || mns.bot) {
1743 user.match = FR_BOT;
1744 get_user_flagrec(u2, &user, NULL);
1745 build_flags(work, &user, NULL);
1746 if (work[0] != '-')
1747 dprintf(idx, "Bot flags for %s are now +%s\n", hand, work);
1748 else
1749 dprintf(idx, "No bot flags for %s.\n", hand);
1750 }
1751 if (chan) {
1752 user.match = FR_CHAN;
1753 get_user_flagrec(u2, &user, par);
1754 user.chan &= BOT_SHARE;
1755 build_flags(work, &user, NULL);
1756 if (work[0] != '-')
1757 dprintf(idx, "Bot flags for %s on %s are now +%s\n", hand,
1758 chan->dname, work);
1759 else
1760 dprintf(idx, "No bot flags for %s on %s.\n", hand, chan->dname);
1761 }
1762 if (tmpchg)
1763 nfree(tmpchg);
1764 }
1765
1766 static void cmd_chat(struct userrec *u, int idx, char *par)
1767 {
1768 char *arg;
1769 int newchan, oldchan;
1770 module_entry *me;
1771
1772 arg = newsplit(&par);
1773 if (!egg_strcasecmp(arg, "off")) {
1774 /* Turn chat off */
1775 if (dcc[idx].u.chat->channel < 0) {
1776 dprintf(idx, "You weren't in chat anyway!\n");
1777 return;
1778 } else {
1779 dprintf(idx, "Leaving chat mode...\n");
1780 check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock,
1781 dcc[idx].u.chat->channel);
1782 chanout_but(-1, dcc[idx].u.chat->channel,
1783 "*** %s left the party line.\n",
1784 dcc[idx].nick);
1785 if (dcc[idx].u.chat->channel < 100000)
1786 botnet_send_part_idx(idx, "");
1787 }
1788 dcc[idx].u.chat->channel = (-1);
1789 } else {
1790 if (arg[0] == '*') {
1791 if (((arg[1] < '0') || (arg[1] > '9'))) {
1792 if (!arg[1])
1793 newchan = 0;
1794 else {
1795 Tcl_SetVar(interp, "chan", arg, 0);
1796 if ((Tcl_VarEval(interp, "assoc ", "$chan", NULL) == TCL_OK) &&
1797 interp->result[0])
1798 newchan = atoi(interp->result);
1799 else
1800 newchan = -1;
1801 }
1802 if (newchan < 0) {
1803 dprintf(idx, "No channel by that name.\n");
1804 return;
1805 }
1806 } else
1807 newchan = 100000 + atoi(arg + 1);
1808 if (newchan < 100000 || newchan > 199999) {
1809 dprintf(idx, "Channel # out of range: local channels must be *0-*99999\n");
1810 return;
1811 }
1812 } else {
1813 if (((arg[0] < '0') || (arg[0] > '9')) && (arg[0])) {
1814 if (!egg_strcasecmp(arg, "on"))
1815 newchan = 0;
1816 else {
1817 Tcl_SetVar(interp, "chan", arg, 0);
1818 if ((Tcl_VarEval(interp, "assoc ", "$chan", NULL) == TCL_OK) &&
1819 interp->result[0])
1820 newchan = atoi(interp->result);
1821 else
1822 newchan = -1;
1823 }
1824 if (newchan < 0) {
1825 dprintf(idx, "No channel by that name.\n");
1826 return;
1827 }
1828 } else
1829 newchan = atoi(arg);
1830 if ((newchan < 0) || (newchan > 99999)) {
1831 dprintf(idx, "Channel # out of range: must be between 0 and 99999.\n");
1832 return;
1833 }
1834 }
1835 /* If coming back from being off the party line, make sure they're
1836 * not away.
1837 */
1838 if ((dcc[idx].u.chat->channel < 0) && (dcc[idx].u.chat->away != NULL))
1839 not_away(idx);
1840 if (dcc[idx].u.chat->channel == newchan) {
1841 if (!newchan) {
1842 dprintf(idx, "You're already on the party line!\n");
1843 return;
1844 } else {
1845 dprintf(idx, "You're already on channel %s%d!\n",
1846 (newchan < 100000) ? "" : "*", newchan % 100000);
1847 return;
1848 }
1849 } else {
1850 oldchan = dcc[idx].u.chat->channel;
1851 if (oldchan >= 0)
1852 check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock, oldchan);
1853 if (!oldchan) {
1854 chanout_but(-1, 0, "*** %s left the party line.\n", dcc[idx].nick);
1855 } else if (oldchan > 0) {
1856 chanout_but(-1, oldchan, "*** %s left the channel.\n", dcc[idx].nick);
1857 }
1858 dcc[idx].u.chat->channel = newchan;
1859 if (!newchan) {
1860 dprintf(idx, "Entering the party line...\n");
1861 chanout_but(-1, 0, "*** %s joined the party line.\n", dcc[idx].nick);
1862 } else {
1863 dprintf(idx, "Joining channel '%s'...\n", arg);
1864 chanout_but(-1, newchan, "*** %s joined the channel.\n", dcc[idx].nick);
1865 }
1866 check_tcl_chjn(botnetnick, dcc[idx].nick, newchan, geticon(idx),
1867 dcc[idx].sock, dcc[idx].host);
1868 if (newchan < 100000)
1869 botnet_send_join_idx(idx, oldchan);
1870 else if (oldchan < 100000)
1871 botnet_send_part_idx(idx, "");
1872 }
1873 }
1874 /* New style autosave here too -- rtc, 09/28/1999*/
1875 if ((me = module_find("console", 1, 1))) {
1876 Function *func = me->funcs;
1877 (func[CONSOLE_DOSTORE]) (idx);
1878 }
1879 }
1880
1881 static void cmd_echo(struct userrec *u, int idx, char *par)
1882 {
1883 module_entry *me;
1884
1885 if (!par[0]) {
1886 dprintf(idx, "Echo is currently %s.\n", dcc[idx].status & STAT_ECHO ?
1887 "on" : "off");
1888 return;
1889 }
1890 if (!egg_strcasecmp(par, "on")) {
1891 dprintf(idx, "Echo turned on.\n");
1892 dcc[idx].status |= STAT_ECHO;
1893 } else if (!egg_strcasecmp(par, "off")) {
1894 dprintf(idx, "Echo turned off.\n");
1895 dcc[idx].status &= ~STAT_ECHO;
1896 } else {
1897 dprintf(idx, "Usage: echo <on/off>\n");
1898 return;
1899 }
1900 /* New style autosave here too -- rtc, 09/28/1999*/
1901 if ((me = module_find("console", 1, 1))) {
1902 Function *func = me->funcs;
1903 (func[CONSOLE_DOSTORE]) (idx);
1904 }
1905 }
1906
1907 int stripmodes(char *s)
1908 {
1909 int res = 0;
1910
1911 for (; *s; s++)
1912 switch (tolower(*s)) {
1913 case 'b':
1914 res |= STRIP_BOLD;
1915 break;
1916 case 'c':
1917 res |= STRIP_COLOR;
1918 break;
1919 case 'r':
1920 res |= STRIP_REV;
1921 break;
1922 case 'u':
1923 res |= STRIP_UNDER;
1924 break;
1925 case 'a':
1926 res |= STRIP_ANSI;
1927 break;
1928 case 'g':
1929 res |= STRIP_BELLS;
1930 break;
1931 case '*':
1932 res |= STRIP_ALL;
1933 break;
1934 }
1935 return res;
1936 }
1937
1938 char *stripmasktype(int x)
1939 {
1940 static char s[20];
1941 char *p = s;
1942
1943 if (x & STRIP_BOLD)
1944 *p++ = 'b';
1945 if (x & STRIP_COLOR)
1946 *p++ = 'c';
1947 if (x & STRIP_REV)
1948 *p++ = 'r';
1949 if (x & STRIP_UNDER)
1950 *p++ = 'u';
1951 if (x & STRIP_ANSI)
1952 *p++ = 'a';
1953 if (x & STRIP_BELLS)
1954 *p++ = 'g';
1955 if (p == s)
1956 *p++ = '-';
1957 *p = 0;
1958 return s;
1959 }
1960
1961 static char *stripmaskname(int x)
1962 {
1963 static char s[161];
1964 int i = 0;
1965
1966 s[i] = 0;
1967 if (x & STRIP_BOLD)
1968 i += my_strcpy(s + i, "bold, ");
1969 if (x & STRIP_COLOR)
1970 i += my_strcpy(s + i, "color, ");
1971 if (x & STRIP_REV)
1972 i += my_strcpy(s + i, "reverse, ");
1973 if (x & STRIP_UNDER)
1974 i += my_strcpy(s + i, "underline, ");
1975 if (x & STRIP_ANSI)
1976 i += my_strcpy(s + i, "ansi, ");
1977 if (x & STRIP_BELLS)
1978 i += my_strcpy(s + i, "bells, ");
1979 if (!i)
1980 strcpy(s, "none");
1981 else
1982 s[i - 2] = 0;
1983 return s;
1984 }
1985
1986 static void cmd_strip(struct userrec *u, int idx, char *par)
1987 {
1988 char *nick, *changes, *c, s[2];
1989 int dest = 0, i, pls, md, ok = 0;
1990 module_entry *me;
1991
1992 if (!par[0]) {
1993 dprintf(idx, "Your current strip settings are: %s (%s)\n",
1994 stripmasktype(dcc[idx].u.chat->strip_flags),
1995 stripmaskname(dcc[idx].u.chat->strip_flags));
1996 return;
1997 }
1998 nick = newsplit(&par);
1999 if ((nick[0] != '+') && (nick[0] != '-') && u &&
2000 (u->flags & USER_MASTER)) {
2001 for (i = 0; i < dcc_total; i++)
2002 if (!egg_strcasecmp(nick, dcc[i].nick) && dcc[i].type == &DCC_CHAT &&
2003 !ok) {
2004 ok = 1;
2005 dest = i;
2006 }
2007 if (!ok) {
2008 dprintf(idx, "No such user on the party line!\n");
2009 return;
2010 }
2011 changes = par;
2012 } else {
2013 changes = nick;
2014 nick = "";
2015 dest = idx;
2016 }
2017 c = changes;
2018 if ((c[0] != '+') && (c[0] != '-'))
2019 dcc[dest].u.chat->strip_flags = 0;
2020 s[1] = 0;
2021 for (pls = 1; *c; c++) {
2022 switch (*c) {
2023 case '+':
2024 pls = 1;
2025 break;
2026 case '-':
2027 pls = 0;
2028 break;
2029 default:
2030 s[0] = *c;
2031 md = stripmodes(s);
2032 if (pls == 1)
2033 dcc[dest].u.chat->strip_flags |= md;
2034 else
2035 dcc[dest].u.chat->strip_flags &= ~md;
2036 }
2037 }
2038 if (nick[0])
2039 putlog(LOG_CMDS, "*", "#%s# strip %s %s", dcc[idx].nick, nick, changes);
2040 else