1 /* 2 * tcluser.c -- handles: 3 * Tcl stubs for the user-record-oriented commands 4 */ 5 /* 6 * Copyright (C) 1997 Robey Pointer 7 * Copyright (C) 1999 - 2021 Eggheads Development Team 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2 12 * of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 */ 23 24 #include "main.h" 25 #include "users.h" 26 #include "chan.h" 27 #include "tandem.h" 28 #include "modules.h" 29 #include "string.h" 30 31 extern Tcl_Interp *interp; 32 extern struct userrec *userlist; 33 extern int default_flags, dcc_total, ignore_time; 34 extern struct dcc_t *dcc; 35 extern char botnetnick[]; 36 extern time_t now; 37 extern struct user_entry_type *entry_type_list; 38 39 static int tcl_countusers STDVAR 40 { 41 BADARGS(1, 1, ""); 42 43 Tcl_AppendResult(irp, int_to_base10(count_users(userlist)), NULL); 44 return TCL_OK; 45 } 46 47 static int tcl_validuser STDVAR 48 { 49 BADARGS(2, 2, " handle"); 50 51 Tcl_AppendResult(irp, get_user_by_handle(userlist, argv[1]) ? "1" : "0", 52 NULL); 53 return TCL_OK; 54 } 55 56 static int tcl_finduser STDVAR 57 { 58 struct userrec *u; 59 60 BADARGS(2, 2, " nick!user@host"); 61 62 u = get_user_by_host(argv[1]); 63 Tcl_AppendResult(irp, u ? u->handle : "*", NULL); 64 return TCL_OK; 65 } 66 67 static int tcl_passwdOk STDVAR 68 { 69 struct userrec *u; 70 71 BADARGS(3, 3, " handle passwd"); 72 73 Tcl_AppendResult(irp, ((u = get_user_by_handle(userlist, argv[1])) && 74 u_pass_match(u, argv[2])) ? "1" : "0", NULL); 75 return TCL_OK; 76 } 77 78 static int tcl_chattr STDVAR 79 { 80 int of, ocf = 0; 81 char *chan, *chg, work[100]; 82 struct flag_record pls, mns, user; 83 struct userrec *u; 84 85 BADARGS(2, 4, " handle ?changes? ?channel?"); 86 87 if ((argv[1][0] == '*') || !(u = get_user_by_handle(userlist, argv[1]))) { 88 Tcl_AppendResult(irp, "*", NULL); 89 return TCL_OK; 90 } 91 if (argc == 4) { 92 user.match = FR_GLOBAL | FR_CHAN; 93 chan = argv[3]; 94 chg = argv[2]; 95 } else if (argc == 3 && argv[2][0]) { 96 int ischan = (findchan_by_dname(argv[2]) != NULL); 97 98 if (strchr(CHANMETA, argv[2][0]) && !ischan && argv[2][0] != '+' && 99 argv[2][0] != '-') { 100 Tcl_AppendResult(irp, "no such channel", NULL); 101 return TCL_ERROR; 102 } else if (ischan) { 103 /* Channel exists */ 104 user.match = FR_GLOBAL | FR_CHAN; 105 chan = argv[2]; 106 chg = NULL; 107 } else { 108 /* 3rd possibility... channel doesnt exist, does start with a +. 109 * In this case we assume the string is flags. 110 */ 111 user.match = FR_GLOBAL; 112 chan = NULL; 113 chg = argv[2]; 114 } 115 } else { 116 user.match = FR_GLOBAL; 117 chan = NULL; 118 chg = NULL; 119 } 120 if (chan && !findchan_by_dname(chan)) { 121 Tcl_AppendResult(irp, "no such channel", NULL); 122 return TCL_ERROR; 123 } 124 /* Retrieve current flags */ 125 get_user_flagrec(u, &user, chan); 126 /* Make changes */ 127 if (chg) { 128 of = user.global; 129 pls.match = user.match; 130 break_down_flags(chg, &pls, &mns); 131 /* No-one can change these flags on-the-fly */ 132 pls.global &=~(USER_BOT); 133 mns.global &=~(USER_BOT); 134 135 if (chan) { 136 pls.chan &= ~(BOT_AGGRESSIVE); 137 mns.chan &= ~(BOT_AGGRESSIVE); 138 } 139 user_sanity_check(&(user.global), pls.global, mns.global); 140 141 user.udef_global = (user.udef_global | pls.udef_global) 142 & ~mns.udef_global; 143 if (chan) { 144 ocf = user.chan; 145 chan_sanity_check(&(user.chan), pls.chan, mns.chan, user.global); 146 user.udef_chan = (user.udef_chan | pls.udef_chan) & ~mns.udef_chan; 147 148 } 149 set_user_flagrec(u, &user, chan); 150 check_dcc_attrs(u, of); 151 if (chan) 152 check_dcc_chanattrs(u, chan, user.chan, ocf); 153 } 154 user.chan &= ~BOT_AGGRESSIVE; /* actually not a user flag, hide it */ 155 /* Build flag string */ 156 build_flags(work, &user, NULL); 157 Tcl_AppendResult(irp, work, NULL); 158 return TCL_OK; 159 } 160 161 static int tcl_botattr STDVAR 162 { 163 char *chan, *chg, work[100]; 164 struct flag_record pls, mns, user; 165 struct userrec *u; 166 167 BADARGS(2, 4, " bot-handle ?changes? ?channel?"); 168 169 u = get_user_by_handle(userlist, argv[1]); 170 if ((argv[1][0] == '*') || !u || !(u->flags & USER_BOT)) { 171 Tcl_AppendResult(irp, "*", NULL); 172 return TCL_OK; 173 } 174 if (argc == 4) { 175 user.match = FR_BOT | FR_CHAN; 176 chan = argv[3]; 177 chg = argv[2]; 178 } else if (argc == 3 && argv[2][0] && strchr(CHANMETA, argv[2][0]) != NULL) { 179 /* We need todo extra checking here to stop us mixing up +channel's 180 * with flags. <cybah> 181 */ 182 if (!findchan_by_dname(argv[2]) && argv[2][0] != '+') { 183 /* Channel doesnt exist, and it cant possibly be flags as there 184 * is no + at the start of the string. 185 */ 186 Tcl_AppendResult(irp, "no such channel", NULL); 187 return TCL_ERROR; 188 } else if (findchan_by_dname(argv[2])) { 189 /* Channel exists */ 190 user.match = FR_BOT | FR_CHAN; 191 chan = argv[2]; 192 chg = NULL; 193 } else { 194 /* 3rd possibility... channel doesnt exist, does start with a +. 195 * In this case we assume the string is flags. 196 */ 197 user.match = FR_BOT; 198 chan = NULL; 199 chg = argv[2]; 200 } 201 } else { 202 user.match = FR_BOT; 203 chan = NULL; 204 if (argc < 3) 205 chg = NULL; 206 else 207 chg = argv[2]; 208 } 209 if (chan && !findchan_by_dname(chan)) { 210 Tcl_AppendResult(irp, "no such channel", NULL); 211 return TCL_ERROR; 212 } 213 /* Retrieve current flags */ 214 get_user_flagrec(u, &user, chan); 215 /* Make changes */ 216 if (chg) { 217 pls.match = user.match; 218 break_down_flags(chg, &pls, &mns); 219 /* No-one can change these flags on-the-fly */ 220 if (chan) { 221 pls.chan &= BOT_AGGRESSIVE; 222 mns.chan &= BOT_AGGRESSIVE; 223 } 224 /* this merges user.bot with pls.bot and mns.bot in user.bot 225 * squelch the msgids as this is the tcl version of botattr */ 226 bot_sanity_check(&(user.bot), pls.bot, mns.bot); 227 if (chan) { 228 user.chan = (user.chan | pls.chan) & ~mns.chan; 229 user.udef_chan = (user.udef_chan | pls.udef_chan) & ~mns.udef_chan; 230 } 231 set_user_flagrec(u, &user, chan); 232 } 233 /* Only user flags can be set per channel, not bot ones, 234 so BOT_AGGRESSIVE is a hack to allow botattr |+s */ 235 user.chan &= BOT_AGGRESSIVE; 236 user.udef_chan = 0; /* User definable bot flags are global only, 237 anything here is a regular flag, so hide it. */ 238 /* Build flag string */ 239 build_flags(work, &user, NULL); 240 Tcl_AppendResult(irp, work, NULL); 241 return TCL_OK; 242 } 243 244 static int tcl_matchattr STDVAR 245 { 246 struct userrec *u; 247 struct flag_record plus = {0}, minus = {0}, user = {0}; 248 int ok = 0, nom = 0; 249 250 BADARGS(3, 4, " handle flags ?channel?"); 251 252 if ((u = get_user_by_handle(userlist, argv[1]))) { 253 user.match = FR_GLOBAL | (argc == 4 ? FR_CHAN : 0) | FR_BOT; 254 get_user_flagrec(u, &user, argv[3]); 255 plus.match = user.match; 256 break_down_flags(argv[2], &plus, &minus); 257 minus.match = plus.match ^ (FR_AND | FR_OR); 258 if (!minus.global && !minus.udef_global && !minus.chan && 259 !minus.udef_chan && !minus.bot) { 260 nom = 1; 261 if (!plus.global && !plus.udef_global && !plus.chan && 262 !plus.udef_chan && !plus.bot) { 263 Tcl_AppendResult(irp, "Unknown flag specified for matching", NULL); 264 return TCL_ERROR; 265 } 266 } 267 if (flagrec_eq(&plus, &user)) { 268 if (nom || !flagrec_eq(&minus, &user)) { 269 ok = 1; 270 } 271 } 272 } 273 Tcl_AppendResult(irp, ok ? "1" : "0", NULL); 274 return TCL_OK; 275 } 276 277 static int tcl_adduser STDVAR 278 { 279 unsigned char *p; 280 281 BADARGS(2, 3, " handle ?hostmask?"); 282 283 if (strlen(argv[1]) > HANDLEN) 284 argv[1][HANDLEN] = 0; 285 for (p = (unsigned char *) argv[1]; *p; p++) 286 if (*p <= 32 || *p == '@') 287 *p = '?'; 288 289 if ((argv[1][0] == '*') || strchr(BADHANDCHARS, argv[1][0]) || 290 get_user_by_handle(userlist, argv[1])) 291 Tcl_AppendResult(irp, "0", NULL); 292 else { 293 userlist = adduser(userlist, argv[1], argv[2], "-", default_flags); 294 Tcl_AppendResult(irp, "1", NULL); 295 } 296 return TCL_OK; 297 } 298 299 static int tcl_addbot STDVAR 300 { 301 struct bot_addr *bi; 302 /* Max addr len is 60 ? (see cmd_pls_bot in cmds.c) + brackets + delims + ports + 0 */ 303 char *p, *q, addr[75], hand[HANDLEN + 1]; 304 int i, colon=0, braced = 0, ipv6 = 0, count = 0; 305 306 307 BADARGS(3, 5, " handle address ?telnet-port ?relay-port??"); 308 309 /* Copy to adjustable char*'s */ 310 strlcpy(hand, argv[1], sizeof hand); 311 strlcpy(addr, argv[2], sizeof addr); 312 313 for (p = hand; *p; p++) 314 if ((unsigned char) *p <= 32 || *p == '@') { 315 Tcl_AppendResult(irp, "Invalid character in handle", NULL); 316 return TCL_ERROR; 317 } 318 319 if ((argv[1][0] == '*') || strchr(BADHANDCHARS, argv[1][0]) || 320 get_user_by_handle(userlist, hand)) 321 Tcl_AppendResult(irp, "0", NULL); 322 else { 323 for (i=0; addr[i]; i++) { 324 if (addr[i] == ':') { 325 count++; 326 colon=i; 327 } 328 if (addr[i] == ']') { 329 braced = i; 330 } 331 } 332 if (count > 1) { 333 ipv6 = 1; 334 } 335 if ((!ipv6 && braced) 336 #ifndef IPV6 337 || (ipv6) 338 #endif 339 ) { 340 Tcl_AppendResult(irp, "0", NULL); 341 return TCL_OK; 342 } 343 /* Check that the char following the / is not null */ 344 if ((q = strrchr(addr, '/'))) { 345 if (!q[1]) { 346 *q = 0; 347 q = NULL; 348 } 349 } 350 351 /* Find ports, still allowing them in address for backward compat */ 352 if (!ipv6) { 353 q = strchr(addr, ':'); 354 } else if (braced && (colon > braced)) { 355 q = strrchr(addr, ':'); 356 } else { 357 /* IPv6 address with no braces or braces without port(s) after */ 358 q = NULL; 359 } 360 361 if (q) { 362 /* Split and count, ignore any following args */ 363 *q++ = 0; 364 p = strchr(q, '/'); 365 if (p) 366 *p++ = 0; 367 } else { 368 /* No port in address field, check next args */ 369 p = NULL; 370 if (argc == 4 || argc == 5) { 371 q = argv[3]; 372 } 373 if (argc == 5) { 374 p = argv[4]; 375 } 376 } 377 378 /* Verify ports */ 379 #ifndef TLS 380 /* Check TLS */ 381 if ((q && *q == '+') || (p && *p == '+')) { 382 Tcl_AppendResult(irp, "0", NULL); 383 return TCL_OK; 384 } 385 386 #endif 387 /* Verify */ 388 /* check_int_range returns 0 if q or p is NULL */ 389 if (q && !check_int_range(q, 0, 65536)) { 390 Tcl_AppendResult(irp, "0", NULL); 391 return TCL_OK; 392 } 393 if (p && !check_int_range(p, 0, 65536)) { 394 Tcl_AppendResult(irp, "0", NULL); 395 return TCL_OK; 396 } 397 398 userlist = adduser(userlist, hand, "none", "-", USER_BOT); 399 bi = user_malloc(sizeof(struct bot_addr)); 400 #ifdef TLS 401 bi->ssl = 0; 402 #endif 403 404 if ((count = strlen(addr)) > 60) { 405 count = 60; 406 addr[count] = 0; 407 } 408 /* Trim IPv6 []s out if present */ 409 if (braced) { 410 --count; 411 addr[count] = 0; 412 memmove(addr, addr + 1, count); 413 } 414 415 if (!q) { 416 bi->address = user_malloc(count + 1); 417 strcpy(bi->address, addr); 418 bi->telnet_port = 3333; 419 bi->relay_port = 3333; 420 } else { 421 bi->address = user_malloc(count + 1); 422 strcpy(bi->address, addr); 423 bi->telnet_port = atoi(q); 424 #ifdef TLS 425 if (*q == '+') 426 bi->ssl = TLS_BOT; 427 #endif 428 if (!p) { 429 bi->relay_port = bi->telnet_port; 430 #ifdef TLS 431 bi->ssl *= TLS_BOT + TLS_RELAY; 432 #endif 433 } else { 434 bi->relay_port = atoi(p); 435 #ifdef TLS 436 if (*p == '+') 437 bi->ssl |= TLS_RELAY; 438 #endif 439 } 440 } 441 set_user(&USERENTRY_BOTADDR, get_user_by_handle(userlist, hand), bi); 442 Tcl_AppendResult(irp, "1", NULL); 443 } 444 return TCL_OK; 445 } 446 447 static int tcl_deluser STDVAR 448 { 449 BADARGS(2, 2, " handle"); 450 451 Tcl_AppendResult(irp, (argv[1][0] == '*') ? "0" : 452 int_to_base10(deluser(argv[1])), NULL); 453 return TCL_OK; 454 } 455 456 static int tcl_delhost STDVAR 457 { 458 BADARGS(3, 3, " handle hostmask"); 459 460 if ((!get_user_by_handle(userlist, argv[1])) || (argv[1][0] == '*')) { 461 Tcl_AppendResult(irp, "non-existent user", NULL); 462 return TCL_ERROR; 463 } 464 Tcl_AppendResult(irp, delhost_by_handle(argv[1], argv[2]) ? "1" : "0", NULL); 465 return TCL_OK; 466 } 467 468 static int tcl_userlist STDVAR 469 { 470 struct userrec *u; 471 struct flag_record user, plus, minus; 472 int ok = 1, f = 0; 473 474 BADARGS(1, 3, " ?flags ?channel??"); 475 476 if (argc == 3 && !findchan_by_dname(argv[2])) { 477 Tcl_AppendResult(irp, "Invalid channel: ", argv[2], NULL); 478 return TCL_ERROR; 479 } 480 if (argc >= 2) { 481 plus.match = FR_GLOBAL | FR_CHAN | FR_BOT; 482 break_down_flags(argv[1], &plus, &minus); 483 f = (minus.global ||minus.udef_global || minus.chan || minus.udef_chan || 484 minus.bot); 485 minus.match = plus.match ^ (FR_AND | FR_OR); 486 } 487 for (u = userlist; u; u = u->next) { 488 if (argc >= 2) { 489 user.match = FR_GLOBAL | FR_CHAN | FR_BOT | (argc == 3 ? 0 : FR_ANYWH); 490 if (argc == 3) 491 get_user_flagrec(u, &user, argv[2]); 492 else 493 get_user_flagrec(u, &user, NULL); 494 if (flagrec_eq(&plus, &user) && !(f && flagrec_eq(&minus, &user))) 495 ok = 1; 496 else 497 ok = 0; 498 } 499 if (ok) 500 Tcl_AppendElement(interp, u->handle); 501 } 502 return TCL_OK; 503 } 504 505 static int tcl_save STDVAR 506 { 507 write_userfile(-1); 508 return TCL_OK; 509 } 510 511 static int tcl_reload STDVAR 512 { 513 reload(); 514 return TCL_OK; 515 } 516 517 static int tcl_chhandle STDVAR 518 { 519 struct userrec *u; 520 char newhand[HANDLEN + 1]; 521 int x = 1, i; 522 523 BADARGS(3, 3, " oldnick newnick"); 524 525 u = get_user_by_handle(userlist, argv[1]); 526 if (!u) 527 x = 0; 528 else { 529 strlcpy(newhand, argv[2], sizeof newhand); 530 for (i = 0; i < strlen(newhand); i++) 531 if (((unsigned char) newhand[i] <= 32) || (newhand[i] == '@')) 532 newhand[i] = '?'; 533 if (strchr(BADHANDCHARS, newhand[0]) != NULL) 534 x = 0; 535 else if (strlen(newhand) < 1) 536 x = 0; 537 else if (get_user_by_handle(userlist, newhand)) 538 x = 0; 539 else if (!strcasecmp(botnetnick, newhand) && (!(u->flags & USER_BOT) || 540 nextbot(argv[1]) != -1)) 541 x = 0; 542 else if (newhand[0] == '*') 543 x = 0; 544 } 545 if (x) 546 x = change_handle(u, newhand); 547 548 Tcl_AppendResult(irp, x ? "1" : "0", NULL); 549 return TCL_OK; 550 } 551 552 static int tcl_getting_users STDVAR 553 { 554 int i; 555 556 BADARGS(1, 1, ""); 557 558 for (i = 0; i < dcc_total; i++) { 559 if (dcc[i].type == &DCC_BOT && dcc[i].status & STAT_GETTING) { 560 Tcl_AppendResult(irp, "1", NULL); 561 return TCL_OK; 562 } 563 } 564 Tcl_AppendResult(irp, "0", NULL); 565 return TCL_OK; 566 } 567 568 static int tcl_isignore STDVAR 569 { 570 BADARGS(2, 2, " nick!user@host"); 571 572 Tcl_AppendResult(irp, match_ignore(argv[1]) ? "1" : "0", NULL); 573 return TCL_OK; 574 } 575 576 static int tcl_newignore STDVAR 577 { 578 time_t expire_time; 579 char ign[UHOSTLEN], cmt[66], from[HANDLEN + 1]; 580 581 BADARGS(4, 5, " hostmask creator comment ?lifetime?"); 582 583 strlcpy(ign, argv[1], sizeof ign); 584 strlcpy(from, argv[2], sizeof from); 585 strlcpy(cmt, argv[3], sizeof cmt); 586 if (argc == 4) 587 expire_time = now + 60 * ignore_time; 588 else if ((expire_time = get_expire_time(irp, argv[4])) == -1) 589 return TCL_ERROR; 590 addignore(ign, from, cmt, expire_time); 591 return TCL_OK; 592 } 593 594 static int tcl_killignore STDVAR 595 { 596 BADARGS(2, 2, " hostmask"); 597 598 Tcl_AppendResult(irp, delignore(argv[1]) ? "1" : "0", NULL); 599 return TCL_OK; 600 } 601 602 static int tcl_ignorelist STDVAR 603 { 604 char expire[11], added[11], *p; 605 long tv; 606 EGG_CONST char *list[5]; 607 struct igrec *i; 608 609 BADARGS(1, 1, ""); 610 611 for (i = global_ign; i; i = i->next) { 612 list[0] = i->igmask; 613 list[1] = i->msg; 614 615 tv = i->expire; 616 egg_snprintf(expire, sizeof expire, "%lu", tv); 617 list[2] = expire; 618 619 tv = i->added; 620 egg_snprintf(added, sizeof added, "%lu", tv); 621 list[3] = added; 622 623 list[4] = i->user; 624 p = Tcl_Merge(5, list); 625 Tcl_AppendElement(irp, p); 626 Tcl_Free((char *) p); 627 } 628 return TCL_OK; 629 } 630 631 static int tcl_getuser STDVAR 632 { 633 struct user_entry_type *et = NULL; 634 struct userrec *u; 635 struct user_entry *e; 636 637 BADARGS(2, -1, " handle ?type?"); 638 639 if (!(u = get_user_by_handle(userlist, argv[1]))) { 640 if (argv[1][0] != '*') { 641 Tcl_AppendResult(irp, "No such user.", NULL); 642 return TCL_ERROR; 643 } else 644 return TCL_OK; /* silently ignore user */ 645 } 646 if (argc >= 3) { 647 if (!(et = find_entry_type(argv[2])) && 648 strcasecmp(argv[2], "HANDLE")) { 649 Tcl_AppendResult(irp, "No such info type: ", argv[2], NULL); 650 return TCL_ERROR; 651 } 652 if (!strcasecmp(argv[2], "HANDLE")) 653 Tcl_AppendResult(irp, u->handle, NULL); 654 else { 655 e = find_user_entry(et, u); 656 if (e) 657 return et->tcl_get(irp, u, e, argc, argv); 658 } 659 } else { 660 for (et = entry_type_list; et; et = et->next) { 661 if (!et->tcl_append) 662 continue; 663 e = find_user_entry(et, u); 664 if (e && e->name) { 665 Tcl_AppendElement(irp, e->name); 666 } else if (et->name) { 667 Tcl_AppendElement(irp, et->name); 668 } else { 669 continue; 670 } 671 if (e) { 672 et->tcl_append(irp, u, e); 673 } else { 674 Tcl_AppendElement(irp, ""); 675 } 676 } 677 } 678 return TCL_OK; 679 } 680 681 static int tcl_setuser STDVAR 682 { 683 struct user_entry_type *et; 684 struct userrec *u; 685 struct user_entry *e; 686 int r; 687 module_entry *me; 688 689 BADARGS(3, -1, " handle type ?setting....?"); 690 691 if (!(et = find_entry_type(argv[2]))) { 692 Tcl_AppendResult(irp, "No such info type: ", argv[2], NULL); 693 return TCL_ERROR; 694 } 695 if (!(u = get_user_by_handle(userlist, argv[1]))) { 696 if (argv[1][0] != '*') { 697 Tcl_AppendResult(irp, "No such user.", NULL); 698 return TCL_ERROR; 699 } else 700 return TCL_OK; /* Silently ignore user * */ 701 } 702 me = module_find("irc", 0, 0); 703 if (me && !strcasecmp(argv[2], "hosts") && argc == 3) { 704 Function *func = me->funcs; 705 706 (func[IRC_CHECK_THIS_USER]) (argv[1], 1, NULL); 707 } 708 if (!(e = find_user_entry(et, u))) { 709 e = user_malloc(sizeof(struct user_entry)); 710 e->type = et; 711 e->name = NULL; 712 e->u.list = NULL; 713 list_insert((&(u->entries)), e); 714 } 715 r = et->tcl_set(irp, u, e, argc, argv); 716 /* Yeah... e is freed, and we read it... (tcl: setuser hand HOSTS none) */ 717 if ((!e->u.list) && (egg_list_delete((struct list_type **) &(u->entries), 718 (struct list_type *) e))) 719 nfree(e); 720 /* else maybe already freed... (entry_type==HOSTS) <drummer> */ 721 if (me && !strcasecmp(argv[2], "hosts") && argc == 4) { 722 Function *func = me->funcs; 723 724 (func[IRC_CHECK_THIS_USER]) (argv[1], 0, NULL); 725 } 726 return r; 727 } 728 729 tcl_cmds tcluser_cmds[] = { 730 {"countusers", tcl_countusers}, 731 {"validuser", tcl_validuser}, 732 {"finduser", tcl_finduser}, 733 {"passwdok", tcl_passwdOk}, 734 {"chattr", tcl_chattr}, 735 {"botattr", tcl_botattr}, 736 {"matchattr", tcl_matchattr}, 737 {"matchchanattr", tcl_matchattr}, 738 {"adduser", tcl_adduser}, 739 {"addbot", tcl_addbot}, 740 {"deluser", tcl_deluser}, 741 {"delhost", tcl_delhost}, 742 {"userlist", tcl_userlist}, 743 {"save", tcl_save}, 744 {"reload", tcl_reload}, 745 {"chhandle", tcl_chhandle}, 746 {"chnick", tcl_chhandle}, 747 {"getting-users", tcl_getting_users}, 748 {"isignore", tcl_isignore}, 749 {"newignore", tcl_newignore}, 750 {"killignore", tcl_killignore}, 751 {"ignorelist", tcl_ignorelist}, 752 {"getuser", tcl_getuser}, 753 {"setuser", tcl_setuser}, 754 {NULL, NULL} 755 }; 756