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

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

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


Revision 1.1.1.1 - (show annotations) (download) (as text) (vendor branch)
Mon Jul 26 21:11:06 2010 UTC (8 years, 10 months ago) by simple
Branch: eggheads
CVS Tags: v1
Changes since 1.1: +0 -0 lines
File MIME type: text/x-chdr
Imported Eggdrop 1.6.20

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