/[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.112 - (show annotations) (download) (as text)
Mon Feb 3 11:41:34 2003 UTC (16 years, 10 months ago) by wcc
Branch: MAIN
Changes since 1.111: +10 -12 lines
File MIME type: text/x-chdr
* More botnet removal.

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