/[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.103 - (show annotations) (download) (as text)
Sat May 11 01:08:43 2002 UTC (17 years, 7 months ago) by stdarg
Branch: MAIN
Changes since 1.102: +226 -243 lines
File MIME type: text/x-chdr
* Fixed a lot of duplicate log messages from dcc commands.

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