/[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.4.2.8 - (show annotations) (download) (as text)
Wed Jul 31 01:14:54 2013 UTC (5 years, 11 months ago) by thommey
Branch: gettext
Changes since 1.4.2.7: +1 -19 lines
File MIME type: text/x-chdr
apply two patches of guppy that were missing

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