/[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.11 - (show annotations) (download) (as text)
Thu Oct 2 19:27:43 2014 UTC (4 years, 7 months ago) by thommey
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +2 -2 lines
File MIME type: text/x-chdr
Remove length limit of info line. Fix stripcodes modifying the Tcl object in-place. Only permanent owners can
delete owners.

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.10 2013/07/31 01:09:33 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, *port, *relay, *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 port = newsplit(&par);
762 host = newsplit(&par);
763
764 if (strlen(handle) > HANDLEN)
765 handle[HANDLEN] = 0;
766
767 if (get_user_by_handle(userlist, handle)) {
768 dprintf(idx, "Someone already exists by that name.\n");
769 return;
770 }
771
772 if (strchr(BADHANDCHARS, handle[0]) != NULL) {
773 dprintf(idx, "You can't start a botnick with '%c'.\n", handle[0]);
774 return;
775 }
776
777 if (strlen(addr) > 60)
778 addr[60] = 0;
779
780 userlist = adduser(userlist, handle, "none", "-", USER_BOT);
781 u1 = get_user_by_handle(userlist, handle);
782 bi = user_malloc(sizeof(struct bot_addr));
783 bi->address = user_malloc(strlen(addr) + 1);
784 strcpy(bi->address, addr);
785
786 if (!port[0]) {
787 bi->telnet_port = 3333;
788 bi->relay_port = 3333;
789 } else {
790 #ifdef TLS
791 if (*port == '+')
792 bi->ssl |= TLS_BOT;
793 #endif
794 bi->telnet_port = atoi(port);
795 relay = strchr(port, '/');
796 if (!relay) {
797 bi->relay_port = bi->telnet_port;
798 #ifdef TLS
799 bi->ssl *= TLS_BOT + TLS_RELAY;
800 #endif
801 } else {
802 #ifdef TLS
803 if (relay[1] == '+')
804 bi->ssl |= TLS_RELAY;
805 #endif
806 bi->relay_port = atoi(relay + 1);
807 }
808 }
809
810 set_user(&USERENTRY_BOTADDR, u1, bi);
811 if (addr[0]) {
812 putlog(LOG_CMDS, "*", "#%s# +bot %s %s%s%s %s%s", dcc[idx].nick, handle,
813 addr, port[0] ? " " : "", port[0] ? port : "", host[0] ? " " : "",
814 host);
815 #ifdef TLS
816 dprintf(idx, "Added bot '%s' with address [%s]:%s%d/%s%d and %s%s%s.\n",
817 handle, addr, (bi->ssl & TLS_BOT) ? "+" : "", bi->telnet_port,
818 (bi->ssl & TLS_RELAY) ? "+" : "", bi->relay_port, host[0] ?
819 "hostmask '" : "no hostmask", host[0] ? host : "",
820 host[0] ? "'" : "");
821 #else
822 dprintf(idx, "Added bot '%s' with address [%s]:%d/%d and %s%s%s.\n", handle,
823 addr, bi->telnet_port, bi->relay_port, host[0] ? "hostmask '" :
824 "no hostmask", host[0] ? host : "", host[0] ? "'" : "");
825 #endif
826 } else {
827 putlog(LOG_CMDS, "*", "#%s# +bot %s %s%s", dcc[idx].nick, handle,
828 host[0] ? " " : "", host);
829 dprintf(idx, "Added bot '%s' with no address and %s%s%s.\n", handle,
830 host[0] ? "hostmask '" : "no hostmask", host[0] ? host : "",
831 host[0] ? "'" : "");
832 }
833 if (host[0]) {
834 addhost_by_handle(handle, host);
835 } else if (!add_bot_hostmask(idx, handle)) {
836 dprintf(idx, "You'll want to add a hostmask if this bot will ever be on "
837 "any channels that I'm on.\n");
838 }
839 }
840
841 static void cmd_chhandle(struct userrec *u, int idx, char *par)
842 {
843 char hand[HANDLEN + 1], newhand[HANDLEN + 1];
844 int i, atr = u ? u->flags : 0, atr2;
845 struct userrec *u2;
846
847 strncpyz(hand, newsplit(&par), sizeof hand);
848 strncpyz(newhand, newsplit(&par), sizeof newhand);
849
850 if (!hand[0] || !newhand[0]) {
851 dprintf(idx, "Usage: chhandle <oldhandle> <newhandle>\n");
852 return;
853 }
854 for (i = 0; i < strlen(newhand); i++)
855 if (((unsigned char) newhand[i] <= 32) || (newhand[i] == '@'))
856 newhand[i] = '?';
857 if (strchr(BADHANDCHARS, newhand[0]) != NULL)
858 dprintf(idx, "Bizarre quantum forces prevent nicknames from starting with "
859 "'%c'.\n", newhand[0]);
860 else if (get_user_by_handle(userlist, newhand) &&
861 egg_strcasecmp(hand, newhand))
862 dprintf(idx, "Somebody is already using %s.\n", newhand);
863 else {
864 u2 = get_user_by_handle(userlist, hand);
865 atr2 = u2 ? u2->flags : 0;
866 if ((atr & USER_BOTMAST) && !(atr & USER_MASTER) && !(atr2 & USER_BOT))
867 dprintf(idx, "You can't change handles for non-bots.\n");
868 else if ((bot_flags(u2) & BOT_SHARE) && !(atr & USER_OWNER))
869 dprintf(idx, "You can't change share bot's nick.\n");
870 else if ((atr2 & USER_OWNER) && !(atr & USER_OWNER) &&
871 egg_strcasecmp(dcc[idx].nick, hand))
872 dprintf(idx, "You can't change a bot owner's handle.\n");
873 else if (isowner(hand) && egg_strcasecmp(dcc[idx].nick, hand))
874 dprintf(idx, "You can't change a permanent bot owner's handle.\n");
875 else if (!egg_strcasecmp(newhand, botnetnick) && (!(atr2 & USER_BOT) ||
876 nextbot(hand) != -1))
877 dprintf(idx, "Hey! That's MY name!\n");
878 else if (change_handle(u2, newhand)) {
879 putlog(LOG_CMDS, "*", "#%s# chhandle %s %s", dcc[idx].nick,
880 hand, newhand);
881 dprintf(idx, "Changed.\n");
882 } else
883 dprintf(idx, "Failed.\n");
884 }
885 }
886
887 static void cmd_handle(struct userrec *u, int idx, char *par)
888 {
889 char oldhandle[HANDLEN + 1], newhandle[HANDLEN + 1];
890 int i;
891
892 strncpyz(newhandle, newsplit(&par), sizeof newhandle);
893
894 if (!newhandle[0]) {
895 dprintf(idx, "Usage: handle <new-handle>\n");
896 return;
897 }
898 for (i = 0; i < strlen(newhandle); i++)
899 if (((unsigned char) newhandle[i] <= 32) || (newhandle[i] == '@'))
900 newhandle[i] = '?';
901 if (strchr(BADHANDCHARS, newhandle[0]) != NULL)
902 dprintf(idx,
903 "Bizarre quantum forces prevent handle from starting with '%c'.\n",
904 newhandle[0]);
905 else if (get_user_by_handle(userlist, newhandle) &&
906 egg_strcasecmp(dcc[idx].nick, newhandle))
907 dprintf(idx, "Somebody is already using %s.\n", newhandle);
908 else if (!egg_strcasecmp(newhandle, botnetnick))
909 dprintf(idx, "Hey! That's MY name!\n");
910 else {
911 strncpyz(oldhandle, dcc[idx].nick, sizeof oldhandle);
912 if (change_handle(u, newhandle)) {
913 putlog(LOG_CMDS, "*", "#%s# handle %s", oldhandle, newhandle);
914 dprintf(idx, "Okay, changed.\n");
915 } else
916 dprintf(idx, "Failed.\n");
917 }
918 }
919
920 static void cmd_chpass(struct userrec *u, int idx, char *par)
921 {
922 char *handle, *new;
923 int atr = u ? u->flags : 0, l;
924
925 if (!par[0])
926 dprintf(idx, "Usage: chpass <handle> [password]\n");
927 else {
928 handle = newsplit(&par);
929 u = get_user_by_handle(userlist, handle);
930 if (!u)
931 dprintf(idx, "No such user.\n");
932 else if ((atr & USER_BOTMAST) && !(atr & USER_MASTER) &&
933 !(u->flags & USER_BOT))
934 dprintf(idx, "You can't change passwords for non-bots.\n");
935 else if ((bot_flags(u) & BOT_SHARE) && !(atr & USER_OWNER))
936 dprintf(idx, "You can't change a share bot's password.\n");
937 else if ((u->flags & USER_OWNER) && !(atr & USER_OWNER) &&
938 egg_strcasecmp(handle, dcc[idx].nick))
939 dprintf(idx, "You can't change a bot owner's password.\n");
940 else if (isowner(handle) && egg_strcasecmp(dcc[idx].nick, handle))
941 dprintf(idx, "You can't change a permanent bot owner's password.\n");
942 else if (!par[0]) {
943 putlog(LOG_CMDS, "*", "#%s# chpass %s [nothing]", dcc[idx].nick, handle);
944 set_user(&USERENTRY_PASS, u, NULL);
945 dprintf(idx, "Removed password.\n");
946 } else {
947 l = strlen(new = newsplit(&par));
948 if (l > 16)
949 new[16] = 0;
950 if (l < 6)
951 dprintf(idx, "Please use at least 6 characters.\n");
952 else {
953 set_user(&USERENTRY_PASS, u, new);
954 putlog(LOG_CMDS, "*", "#%s# chpass %s [something]", dcc[idx].nick,
955 handle);
956 dprintf(idx, "Changed password.\n");
957 }
958 }
959 }
960 }
961
962 #ifdef TLS
963 static void cmd_fprint(struct userrec *u, int idx, char *par)
964 {
965 char *new;
966
967 if (!par[0]) {
968 dprintf(idx, "Usage: fprint <newfingerprint|+>\n");
969 return;
970 }
971 new = newsplit(&par);
972 if (!strcmp(new, "+")) {
973 if (!dcc[idx].ssl) {
974 dprintf(idx, "You aren't connected with SSL. "
975 "Please set your fingerprint manually.\n");
976 return;
977 } else if (!(new = ssl_getfp(dcc[idx].sock))) {
978 dprintf(idx, "Can't get your current fingerprint. "
979 "Set up you client to send a certificate!\n");
980 return;
981 }
982 }
983 if (set_user(&USERENTRY_FPRINT, u, new)) {
984 putlog(LOG_CMDS, "*", "#%s# fprint...", dcc[idx].nick);
985 dprintf(idx, "Changed fingerprint to '%s'.\n", new);
986 } else
987 dprintf(idx, "Invalid fingerprint. Must be a hexadecimal string.\n");
988 }
989
990 static void cmd_chfinger(struct userrec *u, int idx, char *par)
991 {
992 char *handle, *new;
993 int atr = u ? u->flags : 0;
994
995 if (!par[0])
996 dprintf(idx, "Usage: chfinger <handle> [fingerprint]\n");
997 else {
998 handle = newsplit(&par);
999 u = get_user_by_handle(userlist, handle);
1000 if (!u)
1001 dprintf(idx, "No such user.\n");
1002 else if ((atr & USER_BOTMAST) && !(atr & USER_MASTER) &&
1003 !(u->flags & USER_BOT))
1004 dprintf(idx, "You can't change fingerprints for non-bots.\n");
1005 else if ((bot_flags(u) & BOT_SHARE) && !(atr & USER_OWNER))
1006 dprintf(idx, "You can't change a share bot's fingerprint.\n");
1007 else if ((u->flags & USER_OWNER) && !(atr & USER_OWNER) &&
1008 egg_strcasecmp(handle, dcc[idx].nick))
1009 dprintf(idx, "You can't change a bot owner's fingerprint.\n");
1010 else if (isowner(handle) && egg_strcasecmp(dcc[idx].nick, handle))
1011 dprintf(idx, "You can't change a permanent bot owner's fingerprint.\n");
1012 else if (!par[0]) {
1013 putlog(LOG_CMDS, "*", "#%s# chfinger %s [nothing]", dcc[idx].nick, handle);
1014 set_user(&USERENTRY_FPRINT, u, NULL);
1015 dprintf(idx, "Removed fingerprint.\n");
1016 } else {
1017 new = newsplit(&par);
1018 if (set_user(&USERENTRY_FPRINT, u, new)) {
1019 putlog(LOG_CMDS, "*", "#%s# chfinger %s %s", dcc[idx].nick,
1020 handle, new);
1021 dprintf(idx, "Changed fingerprint.\n");
1022 } else
1023 dprintf(idx, "Invalid fingerprint. Must be a hexadecimal string.\n");
1024 }
1025 }
1026 }
1027 #endif
1028
1029 static void cmd_chaddr(struct userrec *u, int idx, char *par)
1030 {
1031 #ifdef TLS
1032 int use_ssl = 0;
1033 #endif
1034 int telnet_port = 3333, relay_port = 3333;
1035 char *handle, *addr, *port, *relay;
1036 struct bot_addr *bi;
1037 struct userrec *u1;
1038
1039 handle = newsplit(&par);
1040 if (!par[0]) {
1041 dprintf(idx, "Usage: chaddr <botname> <address> "
1042 "[telnet-port[/relay-port]]>\n");
1043 return;
1044 }
1045 addr = newsplit(&par);
1046 port = newsplit(&par);
1047 if (strlen(addr) > UHOSTMAX)
1048 addr[UHOSTMAX] = 0;
1049 u1 = get_user_by_handle(userlist, handle);
1050 if (!u1 || !(u1->flags & USER_BOT)) {
1051 dprintf(idx, "This command is only useful for tandem bots.\n");
1052 return;
1053 }
1054 if ((bot_flags(u1) & BOT_SHARE) && (!u || !(u->flags & USER_OWNER))) {
1055 dprintf(idx, "You can't change a share bot's address.\n");
1056 return;
1057 }
1058 putlog(LOG_CMDS, "*", "#%s# chaddr %s %s%s%s", dcc[idx].nick, handle,
1059 addr, *port ? " " : "", port);
1060 dprintf(idx, "Changed bot's address.\n");
1061
1062 bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u1);
1063 if (bi) {
1064 telnet_port = bi->telnet_port;
1065 relay_port = bi->relay_port;
1066 #ifdef TLS
1067 use_ssl = bi->ssl;
1068 #endif
1069 }
1070
1071 bi = user_malloc(sizeof(struct bot_addr));
1072 bi->address = user_malloc(strlen(addr) + 1);
1073 strcpy(bi->address, addr);
1074
1075 if (!port[0]) {
1076 bi->telnet_port = telnet_port;
1077 bi->relay_port = relay_port;
1078 #ifdef TLS
1079 bi->ssl = use_ssl;
1080 } else {
1081 bi->ssl = 0;
1082 if (*port == '+')
1083 bi->ssl |= TLS_BOT;
1084 bi->telnet_port = atoi(port);
1085 relay = strchr(port, '/');
1086 if (!relay) {
1087 bi->relay_port = bi->telnet_port;
1088 bi->ssl *= TLS_BOT + TLS_RELAY;
1089 } else {
1090 relay++;
1091 if (*relay == '+')
1092 bi->ssl |= TLS_RELAY;
1093 #else
1094 } else {
1095 bi->telnet_port = atoi(port);
1096 relay = strchr(port, '/');
1097 if (!relay)
1098 bi->relay_port = bi->telnet_port;
1099 else {
1100 relay++;
1101 #endif
1102 bi->relay_port = atoi(relay);
1103 }
1104 }
1105 set_user(&USERENTRY_BOTADDR, u1, bi);
1106 }
1107
1108 static void cmd_comment(struct userrec *u, int idx, char *par)
1109 {
1110 char *handle;
1111 struct userrec *u1;
1112
1113 handle = newsplit(&par);
1114 if (!par[0]) {
1115 dprintf(idx, "Usage: comment <handle> <newcomment>\n");
1116 return;
1117 }
1118 u1 = get_user_by_handle(userlist, handle);
1119 if (!u1) {
1120 dprintf(idx, "No such user!\n");
1121 return;
1122 }
1123 if ((u1->flags & USER_OWNER) && !(u && (u->flags & USER_OWNER)) &&
1124 egg_strcasecmp(handle, dcc[idx].nick)) {
1125 dprintf(idx, "You can't change comment on a bot owner.\n");
1126 return;
1127 }
1128 putlog(LOG_CMDS, "*", "#%s# comment %s %s", dcc[idx].nick, handle, par);
1129 if (!egg_strcasecmp(par, "none")) {
1130 dprintf(idx, "Okay, comment blanked.\n");
1131 set_user(&USERENTRY_COMMENT, u1, NULL);
1132 return;
1133 }
1134 dprintf(idx, "Changed comment.\n");
1135 set_user(&USERENTRY_COMMENT, u1, par);
1136 }
1137
1138 static void cmd_restart(struct userrec *u, int idx, char *par)
1139 {
1140 putlog(LOG_CMDS, "*", "#%s# restart", dcc[idx].nick);
1141 if (!backgrd) {
1142 dprintf(idx, "You cannot .restart a bot when running -n (due to Tcl).\n");
1143 return;
1144 }
1145 dprintf(idx, "Restarting.\n");
1146 if (make_userfile) {
1147 putlog(LOG_MISC, "*", "Uh, guess you don't need to create a new userfile.");
1148 make_userfile = 0;
1149 }
1150 write_userfile(-1);
1151 putlog(LOG_MISC, "*", "Restarting ...");
1152 wipe_timers(interp, &utimer);
1153 wipe_timers(interp, &timer);
1154 do_restart = idx;
1155 }
1156
1157 static void cmd_rehash(struct userrec *u, int idx, char *par)
1158 {
1159 putlog(LOG_CMDS, "*", "#%s# rehash", dcc[idx].nick);
1160 dprintf(idx, "Rehashing.\n");
1161 if (make_userfile) {
1162 putlog(LOG_MISC, "*", "Uh, guess you don't need to create a new userfile.");
1163 make_userfile = 0;
1164 }
1165 write_userfile(-1);
1166 putlog(LOG_MISC, "*", "Rehashing ...");
1167 do_restart = -2;
1168 }
1169
1170 static void cmd_reload(struct userrec *u, int idx, char *par)
1171 {
1172 putlog(LOG_CMDS, "*", "#%s# reload", dcc[idx].nick);
1173 dprintf(idx, "Reloading user file...\n");
1174 reload();
1175 }
1176
1177 void cmd_die(struct userrec *u, int idx, char *par)
1178 {
1179 char s1[1024], s2[1024];
1180
1181 putlog(LOG_CMDS, "*", "#%s# die %s", dcc[idx].nick, par);
1182 if (par[0]) {
1183 egg_snprintf(s1, sizeof s1, "BOT SHUTDOWN (%s: %s)", dcc[idx].nick, par);
1184 egg_snprintf(s2, sizeof s2, "DIE BY %s!%s (%s)", dcc[idx].nick,
1185 dcc[idx].host, par);
1186 strncpyz(quit_msg, par, 1024);
1187 } else {
1188 egg_snprintf(s1, sizeof s1, "BOT SHUTDOWN (Authorized by %s)",
1189 dcc[idx].nick);
1190 egg_snprintf(s2, sizeof s2, "DIE BY %s!%s (request)", dcc[idx].nick,
1191 dcc[idx].host);
1192 strncpyz(quit_msg, dcc[idx].nick, 1024);
1193 }
1194 kill_bot(s1, s2);
1195 }
1196
1197 static void cmd_debug(struct userrec *u, int idx, char *par)
1198 {
1199 if (!egg_strcasecmp(par, "help")) {
1200 putlog(LOG_CMDS, "*", "#%s# debug help", dcc[idx].nick);
1201 debug_help(idx);
1202 } else {
1203 putlog(LOG_CMDS, "*", "#%s# debug", dcc[idx].nick);
1204 debug_mem_to_dcc(idx);
1205 }
1206 }
1207
1208 static void cmd_simul(struct userrec *u, int idx, char *par)
1209 {
1210 char *nick;
1211 int i, ok = 0;
1212
1213 nick = newsplit(&par);
1214 if (!par[0]) {
1215 dprintf(idx, "Usage: simul <hand> <text>\n");
1216 return;
1217 }
1218 if (isowner(nick)) {
1219 dprintf(idx, "Unable to '.simul' permanent owners.\n");
1220 return;
1221 }
1222 for (i = 0; i < dcc_total; i++)
1223 if (!egg_strcasecmp(nick, dcc[i].nick) && !ok &&
1224 (dcc[i].type->flags & DCT_SIMUL)) {
1225 putlog(LOG_CMDS, "*", "#%s# simul %s %s", dcc[idx].nick, nick, par);
1226 if (dcc[i].type && dcc[i].type->activity) {
1227 dcc[i].type->activity(i, par, strlen(par));
1228 ok = 1;
1229 }
1230 }
1231 if (!ok)
1232 dprintf(idx, "No such user on the party line.\n");
1233 }
1234
1235 static void cmd_link(struct userrec *u, int idx, char *par)
1236 {
1237 char *s;
1238 int i;
1239
1240 if (!par[0]) {
1241 dprintf(idx, "Usage: link [some-bot] <new-bot>\n");
1242 return;
1243 }
1244 putlog(LOG_CMDS, "*", "#%s# link %s", dcc[idx].nick, par);
1245 s = newsplit(&par);
1246 if (!par[0] || !egg_strcasecmp(par, botnetnick))
1247 botlink(dcc[idx].nick, idx, s);
1248 else {
1249 char x[40];
1250
1251 i = nextbot(s);
1252 if (i < 0) {
1253 dprintf(idx, "No such bot online.\n");
1254 return;
1255 }
1256 simple_sprintf(x, "%d:%s@%s", dcc[idx].sock, dcc[idx].nick, botnetnick);
1257 botnet_send_link(i, x, s, par);
1258 }
1259 }
1260
1261 static void cmd_unlink(struct userrec *u, int idx, char *par)
1262 {
1263 int i;
1264 char *bot;
1265
1266 if (!par[0]) {
1267 dprintf(idx, "Usage: unlink <bot> [reason]\n");
1268 return;
1269 }
1270 putlog(LOG_CMDS, "*", "#%s# unlink %s", dcc[idx].nick, par);
1271 bot = newsplit(&par);
1272 i = nextbot(bot);
1273 if (i < 0) {
1274 botunlink(idx, bot, par, dcc[idx].nick);
1275 return;
1276 }
1277 /* If we're directly connected to that bot, just do it
1278 * (is nike gunna sue?)
1279 */
1280 if (!egg_strcasecmp(dcc[i].nick, bot))
1281 botunlink(idx, bot, par, dcc[i].nick);
1282 else {
1283 char x[40];
1284
1285 simple_sprintf(x, "%d:%s@%s", dcc[idx].sock, dcc[idx].nick, botnetnick);
1286 botnet_send_unlink(i, x, lastbot(bot), bot, par);
1287 }
1288 }
1289
1290 static void cmd_relay(struct userrec *u, int idx, char *par)
1291 {
1292 if (!par[0]) {
1293 dprintf(idx, "Usage: relay <bot>\n");
1294 return;
1295 }
1296 putlog(LOG_CMDS, "*", "#%s# relay %s", dcc[idx].nick, par);
1297 tandem_relay(idx, par, 0);
1298 }
1299
1300 static void cmd_save(struct userrec *u, int idx, char *par)
1301 {
1302 putlog(LOG_CMDS, "*", "#%s# save", dcc[idx].nick);
1303 dprintf(idx, "Saving user file...\n");
1304 write_userfile(-1);
1305 }
1306
1307 static void cmd_backup(struct userrec *u, int idx, char *par)
1308 {
1309 putlog(LOG_CMDS, "*", "#%s# backup", dcc[idx].nick);
1310 dprintf(idx, "Backing up the channel & user files...\n");
1311 call_hook(HOOK_BACKUP);
1312 }
1313
1314 static void cmd_trace(struct userrec *u, int idx, char *par)
1315 {
1316 int i;
1317 char x[NOTENAMELEN + 11], y[12];
1318
1319 if (!par[0]) {
1320 dprintf(idx, "Usage: trace <botname>\n");
1321 return;
1322 }
1323 if (!egg_strcasecmp(par, botnetnick)) {
1324 dprintf(idx, "That's me! Hiya! :)\n");
1325 return;
1326 }
1327 i = nextbot(par);
1328 if (i < 0) {
1329 dprintf(idx, "Unreachable bot.\n");
1330 return;
1331 }
1332 putlog(LOG_CMDS, "*", "#%s# trace %s", dcc[idx].nick, par);
1333 simple_sprintf(x, "%d:%s@%s", dcc[idx].sock, dcc[idx].nick, botnetnick);
1334 simple_sprintf(y, ":%d", now);
1335 botnet_send_trace(i, x, par, y);
1336 }
1337
1338 static void cmd_binds(struct userrec *u, int idx, char *par)
1339 {
1340 putlog(LOG_CMDS, "*", "#%s# binds %s", dcc[idx].nick, par);
1341 tell_binds(idx, par);
1342 }
1343
1344 static void cmd_banner(struct userrec *u, int idx, char *par)
1345 {
1346 char s[1024];
1347 int i;
1348
1349 if (!par[0]) {
1350 dprintf(idx, "Usage: banner <message>\n");
1351 return;
1352 }
1353 simple_sprintf(s, "\007### Botwide: [%s] %s\n", dcc[idx].nick, par);
1354 for (i = 0; i < dcc_total; i++)
1355 if (dcc[i].type->flags & DCT_MASTER)
1356 dprintf(i, "%s", s);
1357 }
1358
1359 /* After messing with someone's user flags, make sure the dcc-chat flags
1360 * are set correctly.
1361 */
1362 int check_dcc_attrs(struct userrec *u, int oatr)
1363 {
1364 int i, stat;
1365 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
1366
1367 if (!u)
1368 return 0;
1369 /* Make sure default owners are +n */
1370 if (isowner(u->handle)) {
1371 u->flags = sanity_check(u->flags | USER_OWNER);
1372 }
1373 for (i = 0; i < dcc_total; i++) {
1374 if ((dcc[i].type->flags & DCT_MASTER) &&
1375 (!egg_strcasecmp(u->handle, dcc[i].nick))) {
1376 stat = dcc[i].status;
1377 if ((dcc[i].type == &DCC_CHAT) &&
1378 ((u->flags & (USER_OP | USER_MASTER | USER_OWNER | USER_BOTMAST)) !=
1379 (oatr & (USER_OP | USER_MASTER | USER_OWNER | USER_BOTMAST)))) {
1380 botnet_send_join_idx(i, -1);
1381 }
1382 if ((oatr & USER_MASTER) && !(u->flags & USER_MASTER)) {
1383 dprintf(i, "*** POOF! ***\n");
1384 dprintf(i, "You are no longer a master on this bot.\n");
1385 }
1386 if (!(oatr & USER_MASTER) && (u->flags & USER_MASTER)) {
1387 dcc[i].u.chat->con_flags |= conmask;
1388 dprintf(i, "*** POOF! ***\n");
1389 dprintf(i, "You are now a master on this bot.\n");
1390 }
1391 if (!(oatr & USER_BOTMAST) && (u->flags & USER_BOTMAST)) {
1392 dprintf(i, "### POOF! ###\n");
1393 dprintf(i, "You are now a botnet master on this bot.\n");
1394 }
1395 if ((oatr & USER_BOTMAST) && !(u->flags & USER_BOTMAST)) {
1396 dprintf(i, "### POOF! ###\n");
1397 dprintf(i, "You are no longer a botnet master on this bot.\n");
1398 }
1399 if (!(oatr & USER_OWNER) && (u->flags & USER_OWNER)) {
1400 dprintf(i, "@@@ POOF! @@@\n");
1401 dprintf(i, "You are now an OWNER of this bot.\n");
1402 }
1403 if ((oatr & USER_OWNER) && !(u->flags & USER_OWNER)) {
1404 dprintf(i, "@@@ POOF! @@@\n");
1405 dprintf(i, "You are no longer an owner of this bot.\n");
1406 }
1407 get_user_flagrec(u, &fr, dcc[i].u.chat->con_chan);
1408 dcc[i].u.chat->con_flags = check_conflags(&fr,
1409 dcc[i].u.chat->con_flags);
1410 if ((stat & STAT_PARTY) && (u->flags & USER_OP))
1411 stat &= ~STAT_PARTY;
1412 if (!(stat & STAT_PARTY) && !(u->flags & USER_OP) &&
1413 !(u->flags & USER_MASTER))
1414 stat |= STAT_PARTY;
1415 if ((stat & STAT_CHAT) && !(u->flags & USER_PARTY) &&
1416 !(u->flags & USER_MASTER) && (!(u->flags & USER_OP) || require_p))
1417 stat &= ~STAT_CHAT;
1418 if ((dcc[i].type->flags & DCT_FILES) && !(stat & STAT_CHAT) &&
1419 ((u->flags & USER_MASTER) || (u->flags & USER_PARTY) ||
1420 ((u->flags & USER_OP) && !require_p)))
1421 stat |= STAT_CHAT;
1422 dcc[i].status = stat;
1423 /* Check if they no longer have access to wherever they are.
1424 *
1425 * NOTE: DON'T kick someone off the party line just cuz they lost +p
1426 * (pinvite script removes +p after 5 mins automatically)
1427 */
1428 if ((dcc[i].type->flags & DCT_FILES) && !(u->flags & USER_XFER) &&
1429 !(u->flags & USER_MASTER)) {
1430 dprintf(i, "-+- POOF! -+-\n");
1431 dprintf(i, "You no longer have file area access.\n\n");
1432 putlog(LOG_MISC, "*", "DCC user [%s]%s removed from file system",
1433 dcc[i].nick, dcc[i].host);
1434 if (dcc[i].status & STAT_CHAT) {
1435 struct chat_info *ci;
1436
1437 ci = dcc[i].u.file->chat;
1438 nfree(dcc[i].u.file);
1439 dcc[i].u.chat = ci;
1440 dcc[i].status &= (~STAT_CHAT);
1441 dcc[i].type = &DCC_CHAT;
1442 if (dcc[i].u.chat->channel >= 0) {
1443 chanout_but(-1, dcc[i].u.chat->channel,
1444 "*** %s has returned.\n", dcc[i].nick);
1445 if (dcc[i].u.chat->channel < GLOBAL_CHANS)
1446 botnet_send_join_idx(i, -1);
1447 }
1448 } else {
1449 killsock(dcc[i].sock);
1450 lostdcc(i);
1451 }
1452 }
1453 }
1454
1455 if (dcc[i].type == &DCC_BOT && !egg_strcasecmp(u->handle, dcc[i].nick)) {
1456 if ((dcc[i].status & STAT_LEAF) && !(bot_flags(u) & BOT_LEAF))
1457 dcc[i].status &= ~(STAT_LEAF | STAT_WARNED);
1458 if (!(dcc[i].status & STAT_LEAF) && (bot_flags(u) & BOT_LEAF))
1459 dcc[i].status |= STAT_LEAF;
1460 }
1461 }
1462
1463 return u->flags;
1464 }
1465
1466 int check_dcc_chanattrs(struct userrec *u, char *chname, int chflags,
1467 int ochatr)
1468 {
1469 int i, found = 0;
1470 struct flag_record fr = { FR_CHAN, 0, 0, 0, 0, 0 };
1471 struct chanset_t *chan;
1472
1473 if (!u)
1474 return 0;
1475 for (i = 0; i < dcc_total; i++) {
1476 if ((dcc[i].type->flags & DCT_MASTER) &&
1477 !egg_strcasecmp(u->handle, dcc[i].nick)) {
1478 if ((dcc[i].type == &DCC_CHAT) &&
1479 ((chflags & (USER_OP | USER_MASTER | USER_OWNER)) !=
1480 (ochatr & (USER_OP | USER_MASTER | USER_OWNER))))
1481 botnet_send_join_idx(i, -1);
1482 if ((ochatr & USER_MASTER) && !(chflags & USER_MASTER)) {
1483 dprintf(i, "*** POOF! ***\n");
1484 dprintf(i, "You are no longer a master on %s.\n", chname);
1485 }
1486 if (!(ochatr & USER_MASTER) && (chflags & USER_MASTER)) {
1487 dcc[i].u.chat->con_flags |= conmask;
1488 dprintf(i, "*** POOF! ***\n");
1489 dprintf(i, "You are now a master on %s.\n", chname);
1490 }
1491 if (!(ochatr & USER_OWNER) && (chflags & USER_OWNER)) {
1492 dprintf(i, "@@@ POOF! @@@\n");
1493 dprintf(i, "You are now an OWNER of %s.\n", chname);
1494 }
1495 if ((ochatr & USER_OWNER) && !(chflags & USER_OWNER)) {
1496 dprintf(i, "@@@ POOF! @@@\n");
1497 dprintf(i, "You are no longer an owner of %s.\n", chname);
1498 }
1499 if (((ochatr & (USER_OP | USER_MASTER | USER_OWNER)) &&
1500 (!(chflags & (USER_OP | USER_MASTER | USER_OWNER)))) ||
1501 ((chflags & (USER_OP | USER_MASTER | USER_OWNER)) &&
1502 (!(ochatr & (USER_OP | USER_MASTER | USER_OWNER))))) {
1503
1504 for (chan = chanset; chan && !found; chan = chan->next) {
1505 get_user_flagrec(u, &fr, chan->dname);
1506 if (fr.chan & (USER_OP | USER_MASTER | USER_OWNER))
1507 found = 1;
1508 }
1509 if (!chan)
1510 chan = chanset;
1511 if (chan)
1512 strcpy(dcc[i].u.chat->con_chan, chan->dname);
1513 else
1514 strcpy(dcc[i].u.chat->con_chan, "*");
1515 }
1516 fr.match = (FR_CHAN | FR_GLOBAL);
1517 get_user_flagrec(u, &fr, dcc[i].u.chat->con_chan);
1518 dcc[i].u.chat->con_flags = check_conflags(&fr,
1519 dcc[i].u.chat->con_flags);
1520 }
1521 }
1522 return chflags;
1523 }
1524
1525 static void cmd_chattr(struct userrec *u, int idx, char *par)
1526 {
1527 char *hand, *arg = NULL, *tmpchg = NULL, *chg = NULL, work[1024];
1528 struct chanset_t *chan = NULL;
1529 struct userrec *u2;
1530 struct flag_record pls = { 0, 0, 0, 0, 0, 0 },
1531 mns = { 0, 0, 0, 0, 0, 0 },
1532 user = { 0, 0, 0, 0, 0, 0 };
1533 module_entry *me;
1534 int fl = -1, of = 0, ocf = 0;
1535
1536 if (!par[0]) {
1537 dprintf(idx, "Usage: chattr <handle> [changes] [channel]\n");
1538 return;
1539 }
1540 hand = newsplit(&par);
1541 u2 = get_user_by_handle(userlist, hand);
1542 if (!u2) {
1543 dprintf(idx, "No such user!\n");
1544 return;
1545 }
1546
1547 /* Parse args */
1548 if (par[0]) {
1549 arg = newsplit(&par);
1550 if (par[0]) {
1551 /* .chattr <handle> <changes> <channel> */
1552 chg = arg;
1553 arg = newsplit(&par);
1554 chan = findchan_by_dname(arg);
1555 } else {
1556 chan = findchan_by_dname(arg);
1557 /* Consider modeless channels, starting with '+' */
1558 if (!(arg[0] == '+' && chan) &&
1559 !(arg[0] != '+' && strchr(CHANMETA, arg[0]))) {
1560 /* .chattr <handle> <changes> */
1561 chg = arg;
1562 chan = NULL; /* uh, !strchr (CHANMETA, channel[0]) && channel found?? */
1563 arg = NULL;
1564 }
1565 /* .chattr <handle> <channel>: nothing to do... */
1566 }
1567 }
1568 /* arg: pointer to channel name, NULL if none specified
1569 * chan: pointer to channel structure, NULL if none found or none specified
1570 * chg: pointer to changes, NULL if none specified
1571 */
1572 Assert(!(!arg && chan));
1573 if (arg && !chan) {
1574 dprintf(idx, "No channel record for %s.\n", arg);
1575 return;
1576 }
1577 if (chg) {
1578 if (!arg && strpbrk(chg, "&|")) {
1579 /* .chattr <handle> *[&|]*: use console channel if found... */
1580 if (!strcmp((arg = dcc[idx].u.chat->con_chan), "*"))
1581 arg = NULL;
1582 else
1583 chan = findchan_by_dname(arg);
1584 if (arg && !chan) {
1585 dprintf(idx, "Invalid console channel %s.\n", arg);
1586 return;
1587 }
1588 } else if (arg && !strpbrk(chg, "&|")) {
1589 tmpchg = nmalloc(strlen(chg) + 2);
1590 strcpy(tmpchg, "|");
1591 strcat(tmpchg, chg);
1592 chg = tmpchg;
1593 }
1594 }
1595 par = arg;
1596 user.match = FR_GLOBAL;
1597 if (chan)
1598 user.match |= FR_CHAN;
1599 get_user_flagrec(u, &user, chan ? chan->dname : 0);
1600 if (!chan && !glob_botmast(user)) {
1601 dprintf(idx, "You do not have Bot Master privileges.\n");
1602 if (tmpchg)
1603 nfree(tmpchg);
1604 return;
1605 }
1606 if (chan && !glob_master(user) && !chan_master(user)) {
1607 dprintf(idx, "You do not have channel master privileges for channel %s.\n",
1608 par);
1609 if (tmpchg)
1610 nfree(tmpchg);
1611 return;
1612 }
1613 user.match &= fl;
1614 if (chg) {
1615 pls.match = user.match;
1616 break_down_flags(chg, &pls, &mns);
1617 /* No-one can change these flags on-the-fly */
1618 pls.global &=~(USER_BOT);
1619 mns.global &=~(USER_BOT);
1620
1621 if (chan) {
1622 pls.chan &= ~(BOT_SHARE);
1623 mns.chan &= ~(BOT_SHARE);
1624 }
1625 if (!glob_owner(user)) {
1626 pls.global &=~(USER_OWNER | USER_MASTER | USER_BOTMAST | USER_UNSHARED);
1627 mns.global &=~(USER_OWNER | USER_MASTER | USER_BOTMAST | USER_UNSHARED);
1628
1629 if (chan) {
1630 pls.chan &= ~USER_OWNER;
1631 mns.chan &= ~USER_OWNER;
1632 }
1633 if (!glob_master(user)) {
1634 pls.global &=USER_PARTY | USER_XFER;
1635 mns.global &=USER_PARTY | USER_XFER;
1636
1637 if (!glob_botmast(user)) {
1638 pls.global = 0;
1639 mns.global = 0;
1640 }
1641 }
1642 }
1643 if (chan && !chan_owner(user) && !glob_owner(user)) {
1644 pls.chan &= ~USER_MASTER;
1645 mns.chan &= ~USER_MASTER;
1646 if (!chan_master(user) && !glob_master(user)) {
1647 pls.chan = 0;
1648 mns.chan = 0;
1649 }
1650 }
1651 get_user_flagrec(u2, &user, par);
1652 if (user.match & FR_GLOBAL) {
1653 of = user.global;
1654 user.global = sanity_check((user.global |pls.global) &~mns.global);
1655
1656 user.udef_global = (user.udef_global | pls.udef_global)
1657 & ~mns.udef_global;
1658 }
1659 if (chan) {
1660 ocf = user.chan;
1661 user.chan = chan_sanity_check((user.chan | pls.chan) & ~mns.chan,
1662 user.global);
1663
1664 user.udef_chan = (user.udef_chan | pls.udef_chan) & ~mns.udef_chan;
1665 }
1666 set_user_flagrec(u2, &user, par);
1667 }
1668 if (chan)
1669 putlog(LOG_CMDS, "*", "#%s# (%s) chattr %s %s",
1670 dcc[idx].nick, chan ? chan->dname : "*", hand, chg ? chg : "");
1671 else
1672 putlog(LOG_CMDS, "*", "#%s# chattr %s %s", dcc[idx].nick, hand,
1673 chg ? chg : "");
1674 /* Get current flags and display them */
1675 if (user.match & FR_GLOBAL) {
1676 user.match = FR_GLOBAL;
1677 if (chg)
1678 check_dcc_attrs(u2, of);
1679 get_user_flagrec(u2, &user, NULL);
1680 build_flags(work, &user, NULL);
1681 if (work[0] != '-')
1682 dprintf(idx, "Global flags for %s are now +%s.\n", hand, work);
1683 else
1684 dprintf(idx, "No global flags for %s.\n", hand);
1685 }
1686 if (chan) {
1687 user.match = FR_CHAN;
1688 get_user_flagrec(u2, &user, par);
1689 user.chan &= ~BOT_SHARE;
1690 if (chg)
1691 check_dcc_chanattrs(u2, chan->dname, user.chan, ocf);
1692 build_flags(work, &user, NULL);
1693 if (work[0] != '-')
1694 dprintf(idx, "Channel flags for %s on %s are now +%s.\n", hand,
1695 chan->dname, work);
1696 else
1697 dprintf(idx, "No flags for %s on %s.\n", hand, chan->dname);
1698 }
1699 if (chg && (me = module_find("irc", 0, 0))) {
1700 Function *func = me->funcs;
1701 (func[IRC_CHECK_THIS_USER]) (hand, 0, NULL);
1702 }
1703 if (tmpchg)
1704 nfree(tmpchg);
1705 }
1706
1707 static void cmd_botattr(struct userrec *u, int idx, char *par)
1708 {
1709 char *hand, *chg = NULL, *arg = NULL, *tmpchg = NULL, work[1024];
1710 struct chanset_t *chan = NULL;
1711 struct userrec *u2;
1712 struct flag_record pls = { 0, 0, 0, 0, 0, 0 },
1713 mns = { 0, 0, 0, 0, 0, 0 },
1714 user = { 0, 0, 0, 0, 0, 0 };
1715 int idx2;
1716
1717 if (!par[0]) {
1718 dprintf(idx, "Usage: botattr <handle> [changes] [channel]\n");
1719 return;
1720 }
1721 hand = newsplit(&par);
1722 u2 = get_user_by_handle(userlist, hand);
1723 if (!u2 || !(u2->flags & USER_BOT)) {
1724 dprintf(idx, "No such bot!\n");
1725 return;
1726 }
1727 for (idx2 = 0; idx2 < dcc_total; idx2++)
1728 if (dcc[idx2].type != &DCC_RELAY && dcc[idx2].type != &DCC_FORK_BOT &&
1729 !egg_strcasecmp(dcc[idx2].nick, hand))
1730 break;
1731 if (idx2 != dcc_total) {
1732 dprintf(idx,
1733 "You may not change the attributes of a directly linked bot.\n");
1734 return;
1735 }
1736 /* Parse args */
1737 if (par[0]) {
1738 arg = newsplit(&par);
1739 if (par[0]) {
1740 /* .botattr <handle> <changes> <channel> */
1741 chg = arg;
1742 arg = newsplit(&par);
1743 chan = findchan_by_dname(arg);
1744 } else {
1745 chan = findchan_by_dname(arg);
1746 /* Consider modeless channels, starting with '+' */
1747 if (!(arg[0] == '+' && chan) &&
1748 !(arg[0] != '+' && strchr(CHANMETA, arg[0]))) {
1749 /* .botattr <handle> <changes> */
1750 chg = arg;
1751 chan = NULL; /* uh, !strchr (CHANMETA, channel[0]) && channel found?? */
1752 arg = NULL;
1753 }
1754 /* .botattr <handle> <channel>: nothing to do... */
1755 }
1756 }
1757 /* arg: pointer to channel name, NULL if none specified
1758 * chan: pointer to channel structure, NULL if none found or none specified
1759 * chg: pointer to changes, NULL if none specified
1760 */
1761 Assert(!(!arg && chan));
1762 if (arg && !chan) {
1763 dprintf(idx, "No channel record for %s.\n", arg);
1764 return;
1765 }
1766 if (chg) {
1767 if (!arg && strpbrk(chg, "&|")) {
1768 /* botattr <handle> *[&|]*: use console channel if found... */
1769 if (!strcmp((arg = dcc[idx].u.chat->con_chan), "*"))
1770 arg = NULL;
1771 else
1772 chan = findchan_by_dname(arg);
1773 if (arg && !chan) {
1774 dprintf(idx, "Invalid console channel %s.\n", arg);
1775 return;
1776 }
1777 } else if (arg && !strpbrk(chg, "&|")) {
1778 tmpchg = nmalloc(strlen(chg) + 2);
1779 strcpy(tmpchg, "|");
1780 strcat(tmpchg, chg);
1781 chg = tmpchg;
1782 }
1783 }
1784 par = arg;
1785
1786 user.match = FR_GLOBAL;
1787 get_user_flagrec(u, &user, chan ? chan->dname : 0);
1788 if (!glob_botmast(user)) {
1789 dprintf(idx, "You do not have Bot Master privileges.\n");
1790 if (tmpchg)
1791 nfree(tmpchg);
1792 return;
1793 }
1794 if (chg) {
1795 user.match = FR_BOT | (chan ? FR_CHAN : 0);
1796 pls.match = user.match;
1797 break_down_flags(chg, &pls, &mns);
1798 /* No-one can change these flags on-the-fly */
1799 pls.global &=~BOT_BOT;
1800 mns.global &=~BOT_BOT;
1801
1802 if (chan && glob_owner(user)) {
1803 pls.chan &= BOT_SHARE;
1804 mns.chan &= BOT_SHARE;
1805 } else {
1806 pls.chan = 0;
1807 mns.chan = 0;
1808 }
1809 if (!glob_owner(user)) {
1810 pls.bot &= ~(BOT_SHARE | BOT_GLOBAL);
1811 mns.bot &= ~(BOT_SHARE | BOT_GLOBAL);
1812 }
1813 user.match = FR_BOT | (chan ? FR_CHAN : 0);
1814 get_user_flagrec(u2, &user, par);
1815 user.bot = (user.bot | pls.bot) & ~mns.bot;
1816 if ((user.bot & BOT_SHARE) == BOT_SHARE)
1817 user.bot &= ~BOT_SHARE;
1818 if (chan)
1819 user.chan = (user.chan | pls.chan) & ~mns.chan;
1820 set_user_flagrec(u2, &user, par);
1821 }
1822 if (chan)
1823 putlog(LOG_CMDS, "*", "#%s# (%s) botattr %s %s",
1824 dcc[idx].nick, chan->dname, hand, chg ? chg : "");
1825 else
1826 putlog(LOG_CMDS, "*", "#%s# botattr %s %s", dcc[idx].nick, hand,
1827 chg ? chg : "");
1828 /* get current flags and display them */
1829 if (!chan || pls.bot || mns.bot) {
1830 user.match = FR_BOT;
1831 get_user_flagrec(u2, &user, NULL);
1832 build_flags(work, &user, NULL);
1833 if (work[0] != '-')
1834 dprintf(idx, "Bot flags for %s are now +%s.\n", hand, work);
1835 else
1836 dprintf(idx, "There are no bot flags for %s.\n", hand);
1837 }
1838 if (chan) {
1839 user.match = FR_CHAN;
1840 get_user_flagrec(u2, &user, par);
1841 user.chan &= BOT_SHARE;
1842 user.udef_chan = 0; /* udef chan flags are user only */
1843 build_flags(work, &user, NULL);
1844 if (work[0] != '-')
1845 dprintf(idx, "Bot flags for %s on %s are now +%s.\n", hand,
1846 chan->dname, work);
1847 else
1848 dprintf(idx, "There are no bot flags for %s on %s.\n", hand, chan->dname);
1849 }
1850 if (tmpchg)
1851 nfree(tmpchg);
1852 }
1853
1854 static void cmd_chat(struct userrec *u, int idx, char *par)
1855 {
1856 char *arg;
1857 int newchan, oldchan;
1858 module_entry *me;
1859
1860 arg = newsplit(&par);
1861 if (!egg_strcasecmp(arg, "off")) {
1862 /* Turn chat off */
1863 if (dcc[idx].u.chat->channel < 0) {
1864 dprintf(idx, "You weren't in chat anyway!\n");
1865 return;
1866 } else {
1867 dprintf(idx, "Leaving chat mode...\n");
1868 check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock,
1869 dcc[idx].u.chat->channel);
1870 chanout_but(-1, dcc[idx].u.chat->channel,
1871 "*** %s left the party line.\n", dcc[idx].nick);
1872 if (dcc[idx].u.chat->channel < GLOBAL_CHANS)
1873 botnet_send_part_idx(idx, "");
1874 }
1875 dcc[idx].u.chat->channel = -1;
1876 } else {
1877 if (arg[0] == '*') {
1878 if (((arg[1] < '0') || (arg[1] > '9'))) {
1879 if (!arg[1])
1880 newchan = 0;
1881 else {
1882 Tcl_SetVar(interp, "_chan", arg, 0);
1883 if ((Tcl_VarEval(interp, "assoc ", "$_chan", NULL) == TCL_OK) &&
1884 !tcl_resultempty())
1885 newchan = tcl_resultint();
1886 else
1887 newchan = -1;
1888 }
1889 if (newchan < 0) {
1890 dprintf(idx, "No channel exists by that name.\n");
1891 return;
1892 }
1893 } else
1894 newchan = GLOBAL_CHANS + atoi(arg + 1);
1895 if (newchan < GLOBAL_CHANS || newchan > 199999) {
1896 dprintf(idx, "Channel number out of range: local channels must be "
1897 "*0-*99999.\n");
1898 return;
1899 }
1900 } else {
1901 if (((arg[0] < '0') || (arg[0] > '9')) && (arg[0])) {
1902 if (!egg_strcasecmp(arg, "on"))
1903 newchan = 0;
1904 else {
1905 Tcl_SetVar(interp, "_chan", arg, 0);
1906 if ((Tcl_VarEval(interp, "assoc ", "$_chan", NULL) == TCL_OK) &&
1907 !tcl_resultempty())
1908 newchan = tcl_resultint();
1909 else
1910 newchan = -1;
1911 }
1912 if (newchan < 0) {
1913 dprintf(idx, "No channel exists by that name.\n");
1914 return;
1915 }
1916 } else
1917 newchan = atoi(arg);
1918 if ((newchan < 0) || (newchan >= GLOBAL_CHANS)) {
1919 dprintf(idx, "Channel number out of range: must be between 0 and %d."
1920 "\n", GLOBAL_CHANS);
1921 return;
1922 }
1923 }
1924 /* If coming back from being off the party line, make sure they're
1925 * not away.
1926 */
1927 if ((dcc[idx].u.chat->channel < 0) && (dcc[idx].u.chat->away != NULL))
1928 not_away(idx);
1929 if (dcc[idx].u.chat->channel == newchan) {
1930 if (!newchan) {
1931 dprintf(idx, "You're already on the party line!\n");
1932 return;
1933 } else {
1934 dprintf(idx, "You're already on channel %s%d!\n",
1935 (newchan < GLOBAL_CHANS) ? "" : "*", newchan % GLOBAL_CHANS);
1936 return;
1937 }
1938 } else {
1939 oldchan = dcc[idx].u.chat->channel;
1940 if (oldchan >= 0)
1941 check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock, oldchan);
1942 if (!oldchan)
1943 chanout_but(-1, 0, "*** %s left the party line.\n", dcc[idx].nick);
1944 else if (oldchan > 0)
1945 chanout_but(-1, oldchan, "*** %s left the channel.\n", dcc[idx].nick);
1946 dcc[idx].u.chat->channel = newchan;
1947 if (!newchan) {
1948 dprintf(idx, "Entering the party line...\n");
1949 chanout_but(-1, 0, "*** %s joined the party line.\n", dcc[idx].nick);
1950 } else {
1951 dprintf(idx, "Joining channel '%s'...\n", arg);
1952 chanout_but(-1, newchan, "*** %s joined the channel.\n", dcc[idx].nick);
1953 }
1954 check_tcl_chjn(botnetnick, dcc[idx].nick, newchan, geticon(idx),
1955 dcc[idx].sock, dcc[idx].host);
1956 if (newchan < GLOBAL_CHANS)
1957 botnet_send_join_idx(idx, oldchan);
1958 else if (oldchan < GLOBAL_CHANS)
1959 botnet_send_part_idx(idx, "");
1960 }
1961 }
1962 /* New style autosave here too -- rtc, 09/28/1999 */
1963 if ((me = module_find("console", 1, 1))) {
1964 Function *func = me->funcs;
1965
1966 (func[CONSOLE_DOSTORE]) (idx);
1967 }
1968 }
1969
1970 static void cmd_echo(struct userrec *u, int idx, char *par)
1971 {
1972 module_entry *me;
1973
1974 if (!par[0]) {
1975 dprintf(idx, "Echo is currently %s.\n", dcc[idx].status & STAT_ECHO ?
1976 "on" : "off");
1977 return;
1978 }
1979 if (!egg_strcasecmp(par, "on")) {
1980 dprintf(idx, "Echo turned on.\n");
1981 dcc[idx].status |= STAT_ECHO;
1982 } else if (!egg_strcasecmp(par, "off")) {
1983 dprintf(idx, "Echo turned off.\n");
1984 dcc[idx].status &= ~STAT_ECHO;
1985 } else {
1986 dprintf(idx, "Usage: echo <on/off>\n");
1987 return;
1988 }
1989 /* New style autosave here too -- rtc, 09/28/1999 */
1990 if ((me = module_find("console", 1, 1))) {
1991 Function *func = me->funcs;
1992
1993 (func[CONSOLE_DOSTORE]) (idx);
1994 }
1995 }
1996
1997 int stripmodes(char *s)
1998 {
1999 int res = 0;
2000
2001 for (; *s; s++)
2002 switch (tolower((unsigned) *s)) {
2003 case 'c':
2004 res |= STRIP_COLOR;
2005 break;
2006 case 'b':
2007 res |= STRIP_BOLD;
2008 break;
2009 case 'r':
2010 res |= STRIP_REVERSE;
2011 break;
2012 case 'u':
2013 res |= STRIP_UNDERLINE;
2014 break;
2015 case 'a':
2016 res |= STRIP_ANSI;
2017 break;
2018 case 'g':
2019 res |= STRIP_BELLS;
2020 break;
2021 case 'o':
2022 res |= STRIP_ORDINARY;
2023 break;
2024 case 'i':
2025 res |= STRIP_ITALICS;
2026 break;
2027 case '*':
2028 res |= STRIP_ALL;
2029 break;
2030 }
2031 return res;
2032 }
2033
2034 char *stripmasktype(int x)
2035 {
2036 static char s[20];
2037 char *p = s;
2038
2039 if (x & STRIP_COLOR)
2040 *p++ = 'c';
2041 if (x & STRIP_BOLD)
2042 *p++ = 'b';
2043 if (x & STRIP_REVERSE)
2044 *p++ = 'r';
2045 if (x & STRIP_UNDERLINE)
2046 *p++ = 'u';