/[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.69 - (show annotations) (download) (as text)
Sun Oct 7 04:02:54 2001 UTC (18 years, 2 months ago) by stdarg
Branch: MAIN
Changes since 1.68: +2 -2 lines
File MIME type: text/x-chdr
Got rid of bind tables in the exported irc function table. They're not used anywhere in the core or other normal modules. Other people should use find_bind_table(), not #define's.
Got rid of H_* bind tables in irc module. All are BT_* now.
Integrated the new bind tables in with the normal bind/unbind command.
Made tcl callbacks work with the normal data types (string, int, user (handle)).
Got rid of old bind tables in server.mod
Made ctcp.mod use the new bind tables.
Wrote down most of the stuff I did so that ITE could see a detailed report :) hehe (although I have a feeling I've left something out)

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