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

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

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


Revision 1.107 - (show annotations) (download) (as text)
Fri Sep 20 21:41:49 2002 UTC (17 years, 2 months ago) by stdarg
Branch: MAIN
Changes since 1.106: +14 -482 lines
File MIME type: text/x-chdr
* Mo-Ize removed the botnet code, thanks

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