unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
who_old.c (22238B)
1 /* src/modules/who_old.c 2 * Copyright (C) 1990 Jarkko Oikarinen and 3 * University of Oulu, Computing Center 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free softwmare; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 /* rewritten 06/02 by larne, the old one was unreadable. */ 24 /* changed indentation + some parts rewritten by Syzop. */ 25 26 #include "unrealircd.h" 27 28 CMD_FUNC(cmd_who); 29 30 /* Place includes here */ 31 #define MSG_WHO "WHO" 32 33 ModuleHeader MOD_HEADER 34 = { 35 "who_old", /* Name of module */ 36 "5.0", /* Version */ 37 "command /who (old version)", /* Short description of module */ 38 "UnrealIRCd Team", 39 "unrealircd-6", 40 }; 41 42 /* This is called on module init, before Server Ready */ 43 MOD_INIT() 44 { 45 if (!CommandAdd(modinfo->handle, MSG_WHO, cmd_who, MAXPARA, CMD_USER)) 46 { 47 config_warn("You cannot load both the cmd_whox and cmd_who module. You should ONLY load the cmd_whox module."); 48 return MOD_FAILED; 49 } 50 MARK_AS_OFFICIAL_MODULE(modinfo); 51 return MOD_SUCCESS; 52 } 53 54 /* Is first run when server is 100% ready */ 55 MOD_LOAD() 56 { 57 return MOD_SUCCESS; 58 } 59 60 61 /* Called when module is unloaded */ 62 MOD_UNLOAD() 63 { 64 return MOD_SUCCESS; 65 } 66 67 static void do_channel_who(Client *client, Channel *channel, const char *mask); 68 static void make_who_status(Client *, Client *, Channel *, Member *, char *, int); 69 static void do_other_who(Client *client, const char *mask); 70 static void send_who_reply(Client *, Client *, const char *, const char *, const char *); 71 static const char *first_visible_channel(Client *, Client *, int *); 72 static int parse_who_options(Client *, int, const char **); 73 static void who_sendhelp(Client *); 74 75 #define WF_OPERONLY 0x01 /**< only show opers */ 76 #define WF_ONCHANNEL 0x02 /**< we're on the channel we're /who'ing */ 77 #define WF_WILDCARD 0x04 /**< a wildcard /who */ 78 #define WF_REALHOST 0x08 /**< want real hostnames */ 79 #define WF_IP 0x10 /**< want IP addresses */ 80 81 static int who_flags; 82 83 #define WHO_CANTSEE 0x01 /**< set if we can't see them */ 84 #define WHO_CANSEE 0x02 /**< set if we can */ 85 #define WHO_OPERSEE 0x04 /**< set if we only saw them because we're an oper */ 86 87 #define FVC_HIDDEN 0x01 88 89 #define WHO_WANT 1 90 #define WHO_DONTWANT 2 91 #define WHO_DONTCARE 0 92 93 struct { 94 int want_away; 95 int want_channel; 96 const char *channel; /**< if they want one */ 97 int want_gecos; 98 const char *gecos; 99 int want_server; 100 const char *server; 101 int want_host; 102 const char *host; 103 int want_nick; 104 const char *nick; 105 int want_user; 106 const char *user; 107 int want_ip; 108 const char *ip; 109 int want_port; 110 int port; 111 int want_umode; 112 int umodes_dontwant; 113 int umodes_want; 114 int common_channels_only; 115 } wfl; 116 117 /** The /who command: retrieves information from users. */ 118 CMD_FUNC(cmd_who) 119 { 120 Channel *target_channel; 121 const char *mask = parv[1]; 122 char maskbuf[512]; 123 int i = 0; 124 125 if (!MyUser(client)) 126 return; 127 128 who_flags = 0; 129 memset(&wfl, 0, sizeof(wfl)); 130 131 if (parc > 1) 132 { 133 i = parse_who_options(client, parc - 1, parv + 1); 134 if (i < 0) 135 { 136 sendnumeric(client, RPL_ENDOFWHO, mask); 137 return; 138 } 139 } 140 141 if (parc-i < 2 || strcmp(parv[1 + i], "0") == 0) 142 mask = "*"; 143 else 144 mask = parv[1 + i]; 145 146 if (!i && parc > 2 && *parv[2] == 'o') 147 who_flags |= WF_OPERONLY; 148 149 /* Pfff... collapse... hate it! */ 150 strlcpy(maskbuf, mask, sizeof(maskbuf)); 151 collapse(maskbuf); 152 mask = maskbuf; 153 154 if (*mask == '\0') 155 { 156 /* no mask given */ 157 sendnumeric(client, RPL_ENDOFWHO, "*"); 158 return; 159 } 160 161 if ((target_channel = find_channel(mask)) != NULL) 162 { 163 do_channel_who(client, target_channel, mask); 164 sendnumeric(client, RPL_ENDOFWHO, mask); 165 return; 166 } 167 168 if (wfl.channel && wfl.want_channel == WHO_WANT && 169 (target_channel = find_channel(wfl.channel)) != NULL) 170 { 171 do_channel_who(client, target_channel, mask); 172 sendnumeric(client, RPL_ENDOFWHO, mask); 173 return; 174 } 175 else 176 { 177 do_other_who(client, mask); 178 sendnumeric(client, RPL_ENDOFWHO, mask); 179 return; 180 } 181 182 return; 183 } 184 185 static void who_sendhelp(Client *client) 186 { 187 char *who_help[] = { 188 "/WHO [+|-][achmnsuM] [args]", 189 "Flags are specified like channel modes, the flags chmnsu all have arguments", 190 "Flags are set to a positive check by +, a negative check by -", 191 "The flags work as follows:", 192 "Flag a: user is away", 193 "Flag c <channel>: user is on <channel>,", 194 " no wildcards accepted", 195 "Flag h <host>: user has string <host> in their hostname,", 196 " wildcards accepted", 197 "Flag m <usermodes>: user has <usermodes> set, only", 198 " O/o/C/A/a/N/B are allowed", 199 "Flag n <nick>: user has string <nick> in their nickname,", 200 " wildcards accepted", 201 "Flag s <server>: user is on server <server>,", 202 " wildcards not accepted", 203 "Flag u <user>: user has string <user> in their username,", 204 " wildcards accepted", 205 "Behavior flags:", 206 "Flag M: check for user in channels I am a member of", 207 NULL 208 }; 209 210 char *who_oper_help[] = { 211 "/WHO [+|-][acghimnsuMRI] [args]", 212 "Flags are specified like channel modes, the flags chigmnsu all have arguments", 213 "Flags are set to a positive check by +, a negative check by -", 214 "The flags work as follows:", 215 "Flag a: user is away", 216 "Flag c <channel>: user is on <channel>,", 217 " no wildcards accepted", 218 "Flag g <gcos/realname>: user has string <gcos> in their GCOS,", 219 " wildcards accepted", 220 "Flag h <host>: user has string <host> in their hostname,", 221 " wildcards accepted", 222 "Flag i <ip>: user has string <ip> in their IP address,", 223 " wildcards accepted", 224 "Flag p <port>: user is connecting on port <port>,", 225 " local connections only", 226 "Flag m <usermodes>: user has <usermodes> set", 227 "Flag n <nick>: user has string <nick> in their nickname,", 228 " wildcards accepted", 229 "Flag s <server>: user is on server <server>,", 230 " wildcards not accepted", 231 "Flag u <user>: user has string <user> in their username,", 232 " wildcards accepted", 233 "Behavior flags:", 234 "Flag M: check for user in channels I am a member of", 235 "Flag R: show users' real hostnames", 236 "Flag I: show users' IP addresses", 237 NULL 238 }; 239 char **s; 240 241 if (IsOper(client)) 242 s = who_oper_help; 243 else 244 s = who_help; 245 246 for (; *s; s++) 247 sendnumeric(client, RPL_LISTSYNTAX, *s); 248 } 249 250 #define WHO_ADD 1 251 #define WHO_DEL 2 252 253 static int parse_who_options(Client *client, int argc, const char **argv) 254 { 255 const char *s = argv[0]; 256 int what = WHO_ADD; 257 int i = 1; 258 259 /* A few helper macro's because this is used a lot, added during recode by Syzop. */ 260 261 /** function requiress a parameter: check if there's one, if not: return -1. */ 262 #define REQUIRE_PARAM() { if (i >= argc) { \ 263 who_sendhelp(client); \ 264 return -1; \ 265 } } while(0); 266 /** set option 'x' depending on 'what' (add/want or del/dontwant) */ 267 #define SET_OPTION(x) { if (what == WHO_ADD) \ 268 x = WHO_WANT; \ 269 else \ 270 x = WHO_DONTWANT; \ 271 } while(0); 272 /** Eat a param, set the param in memory and set the option to want or dontwant */ 273 #define DOIT(x,y) { REQUIRE_PARAM(); x = argv[i]; SET_OPTION(y); i++; } while(0); 274 275 if (*s != '-' && *s != '+') 276 return 0; 277 278 while (*s) 279 { 280 switch (*s) 281 { 282 case '+': 283 what = WHO_ADD; 284 break; 285 case '-': 286 what = WHO_DEL; 287 break; 288 case 'a': 289 SET_OPTION(wfl.want_away); 290 break; 291 case 'c': 292 DOIT(wfl.channel, wfl.want_channel); 293 break; 294 case 'g': 295 REQUIRE_PARAM() 296 if (!IsOper(client)) 297 break; /* oper-only */ 298 wfl.gecos = argv[i]; 299 SET_OPTION(wfl.want_gecos); 300 i++; 301 break; 302 case 's': 303 DOIT(wfl.server, wfl.want_server); 304 break; 305 case 'h': 306 DOIT(wfl.host, wfl.want_host); 307 break; 308 case 'i': 309 REQUIRE_PARAM() 310 if (!IsOper(client)) 311 break; /* oper-only */ 312 wfl.ip = argv[i]; 313 SET_OPTION(wfl.want_ip); 314 i++; 315 break; 316 case 'n': 317 DOIT(wfl.nick, wfl.want_nick); 318 break; 319 case 'u': 320 DOIT(wfl.user, wfl.want_user); 321 break; 322 case 'm': 323 REQUIRE_PARAM() 324 { 325 const char *s = argv[i]; 326 int *umodes; 327 328 if (what == WHO_ADD) 329 umodes = &wfl.umodes_want; 330 else 331 umodes = &wfl.umodes_dontwant; 332 333 *umodes = set_usermode(s); 334 335 if (!IsOper(client)) 336 *umodes = *umodes & UMODE_OPER; /* these are usermodes regular users may search for. just oper now. */ 337 if (*umodes == 0) 338 return -1; 339 } 340 i++; 341 break; 342 case 'p': 343 REQUIRE_PARAM() 344 if (!IsOper(client)) 345 break; /* oper-only */ 346 wfl.port = atoi(argv[i]); 347 SET_OPTION(wfl.want_port); 348 i++; 349 break; 350 case 'M': 351 SET_OPTION(wfl.common_channels_only); 352 break; 353 case 'R': 354 if (!IsOper(client)) 355 break; 356 if (what == WHO_ADD) 357 who_flags |= WF_REALHOST; 358 else 359 who_flags &= ~WF_REALHOST; 360 break; 361 case 'I': 362 if (!IsOper(client)) 363 break; 364 if (what == WHO_ADD) 365 who_flags |= WF_IP; 366 367 else 368 who_flags &= ~WF_IP; 369 break; 370 default: 371 who_sendhelp(client); 372 return -1; 373 } 374 s++; 375 } 376 377 return i; 378 #undef REQUIRE_PARAM 379 #undef SET_OPTION 380 #undef DOIT 381 } 382 383 static int can_see(Client *requester, Client *target, Channel *channel) 384 { 385 int ret = 0; 386 char has_common_chan = 0; 387 388 do { 389 /* can only see people */ 390 if (!IsUser(target)) 391 return WHO_CANTSEE; 392 393 /* can only see opers if thats what they want */ 394 if (who_flags & WF_OPERONLY) 395 { 396 if (!IsOper(target)) 397 return ret | WHO_CANTSEE; 398 if (IsHideOper(target)) { 399 if (IsOper(requester)) 400 ret |= WHO_OPERSEE; 401 else 402 return ret | WHO_CANTSEE; 403 } 404 } 405 406 /* if they only want people who are away */ 407 if ((wfl.want_away == WHO_WANT && !target->user->away) || 408 (wfl.want_away == WHO_DONTWANT && target->user->away)) 409 return WHO_CANTSEE; 410 411 /* if they only want people on a certain channel. */ 412 if (wfl.want_channel != WHO_DONTCARE) 413 { 414 Channel *chan = find_channel(wfl.channel); 415 if (!chan && wfl.want_channel == WHO_WANT) 416 return WHO_CANTSEE; 417 if ((wfl.want_channel == WHO_WANT) && !IsMember(target, chan)) 418 return WHO_CANTSEE; 419 if ((wfl.want_channel == WHO_DONTWANT) && IsMember(target, chan)) 420 return WHO_CANTSEE; 421 } 422 423 /* if they only want people with a certain gecos */ 424 if (wfl.want_gecos != WHO_DONTCARE) 425 { 426 if (((wfl.want_gecos == WHO_WANT) && !match_simple(wfl.gecos, target->info)) || 427 ((wfl.want_gecos == WHO_DONTWANT) && match_simple(wfl.gecos, target->info))) 428 { 429 return WHO_CANTSEE; 430 } 431 } 432 433 /* if they only want people with a certain server */ 434 if (wfl.want_server != WHO_DONTCARE) 435 { 436 if (((wfl.want_server == WHO_WANT) && strcasecmp(wfl.server, target->user->server)) || 437 ((wfl.want_server == WHO_DONTWANT) && !strcasecmp(wfl.server, target->user->server))) 438 { 439 return WHO_CANTSEE; 440 } 441 } 442 443 /* if they only want people with a certain host */ 444 if (wfl.want_host != WHO_DONTCARE) 445 { 446 char *host; 447 448 if (IsOper(requester)) 449 host = target->user->realhost; 450 else 451 host = GetHost(target); 452 453 if (((wfl.want_host == WHO_WANT) && !match_simple(wfl.host, host)) || 454 ((wfl.want_host == WHO_DONTWANT) && match_simple(wfl.host, host))) 455 { 456 return WHO_CANTSEE; 457 } 458 } 459 460 /* if they only want people with a certain IP */ 461 if (wfl.want_ip != WHO_DONTCARE) 462 { 463 char *ip; 464 465 ip = target->ip; 466 if (!ip) 467 return WHO_CANTSEE; 468 469 if (((wfl.want_ip == WHO_WANT) && !match_simple(wfl.ip, ip)) || 470 ((wfl.want_ip == WHO_DONTWANT) && match_simple(wfl.ip, ip))) 471 { 472 return WHO_CANTSEE; 473 } 474 } 475 476 /* if they only want people connecting on a certain port */ 477 if (wfl.want_port != WHO_DONTCARE) 478 { 479 int port; 480 481 if (!MyUser(target)) 482 return WHO_CANTSEE; 483 484 port = target->local->listener->port; 485 486 if (((wfl.want_port == WHO_WANT) && wfl.port != port) || 487 ((wfl.want_port == WHO_DONTWANT) && wfl.port == port)) 488 { 489 return WHO_CANTSEE; 490 } 491 } 492 493 /* if they only want people with a certain nick.. */ 494 if (wfl.want_nick != WHO_DONTCARE) 495 { 496 if (((wfl.want_nick == WHO_WANT) && !match_simple(wfl.nick, target->name)) || 497 ((wfl.want_nick == WHO_DONTWANT) && match_simple(wfl.nick, target->name))) 498 { 499 return WHO_CANTSEE; 500 } 501 } 502 503 /* if they only want people with a certain username */ 504 if (wfl.want_user != WHO_DONTCARE) 505 { 506 if (((wfl.want_user == WHO_WANT) && !match_simple(wfl.user, target->user->username)) || 507 ((wfl.want_user == WHO_DONTWANT) && match_simple(wfl.user, target->user->username))) 508 { 509 return WHO_CANTSEE; 510 } 511 } 512 513 /* if they only want people with a certain umode */ 514 if (wfl.umodes_want) 515 { 516 if (!(target->umodes & wfl.umodes_want) || (!IsOper(requester) && (target->umodes & UMODE_HIDEOPER))) 517 return WHO_CANTSEE; 518 } 519 520 if (wfl.umodes_dontwant) 521 { 522 if ((target->umodes & wfl.umodes_dontwant) && (!(target->umodes & UMODE_HIDEOPER) || IsOper(requester))) 523 return WHO_CANTSEE; 524 } 525 526 /* if they only want common channels */ 527 if (wfl.common_channels_only) 528 { 529 if (!has_common_channels(requester, target)) 530 return WHO_CANTSEE; 531 has_common_chan = 1; 532 } 533 534 if (channel) 535 { 536 int member = who_flags & WF_ONCHANNEL; 537 538 if (SecretChannel(channel) || HiddenChannel(channel)) 539 { 540 /* if they aren't on it.. they can't see it */ 541 if (!(who_flags & WF_ONCHANNEL)) 542 break; 543 } 544 if (IsInvisible(target) && !member) 545 break; 546 547 if (!user_can_see_member(requester, target, channel)) 548 break; /* invisible (eg: due to delayjoin) */ 549 } 550 else 551 { 552 /* a user/mask who */ 553 554 /* If the common channel info hasn't been set, set it now */ 555 if (!wfl.common_channels_only) 556 has_common_chan = has_common_channels(requester, target); 557 558 if (IsInvisible(target) && !has_common_chan) 559 { 560 /* don't show them unless it's an exact match 561 or it is the user requesting the /who */ 562 if ((who_flags & WF_WILDCARD) && requester != target) 563 break; 564 } 565 } 566 567 /* phew.. show them. */ 568 return WHO_CANSEE; 569 } while (0); 570 571 /* if we get here, it's oper-dependant. */ 572 if (IsOper(requester)) 573 return ret | WHO_OPERSEE | WHO_CANSEE; 574 else 575 { 576 if (requester == target) 577 return ret | WHO_CANSEE; 578 else 579 return ret | WHO_CANTSEE; 580 } 581 } 582 583 static void do_channel_who(Client *client, Channel *channel, const char *mask) 584 { 585 Member *cm = channel->members; 586 if (IsMember(client, channel) || ValidatePermissionsForPath("channel:see:who:onchannel",client,NULL,channel,NULL)) 587 who_flags |= WF_ONCHANNEL; 588 589 for (cm = channel->members; cm; cm = cm->next) 590 { 591 Client *acptr = cm->client; 592 char status[32]; 593 int cansee; 594 if ((cansee = can_see(client, acptr, channel)) & WHO_CANTSEE) 595 continue; 596 597 make_who_status(client, acptr, channel, cm, status, cansee); 598 send_who_reply(client, acptr, channel->name, status, ""); 599 } 600 } 601 602 static void make_who_status(Client *client, Client *acptr, Channel *channel, 603 Member *cm, char *status, int cansee) 604 { 605 int i = 0; 606 Hook *h; 607 608 if (acptr->user->away) 609 status[i++] = 'G'; 610 else 611 status[i++] = 'H'; 612 613 if (IsRegNick(acptr)) 614 status[i++] = 'r'; 615 616 if (IsSecureConnect(acptr)) 617 status[i++] = 's'; 618 619 for (h = Hooks[HOOKTYPE_WHO_STATUS]; h; h = h->next) 620 { 621 int ret = (*(h->func.intfunc))(client, acptr, channel, cm, status, cansee); 622 if (ret != 0) 623 status[i++] = (char)ret; 624 } 625 626 if (IsOper(acptr) && (!IsHideOper(acptr) || client == acptr || IsOper(client))) 627 status[i++] = '*'; 628 629 if (IsOper(acptr) && (IsHideOper(acptr) && client != acptr && IsOper(client))) 630 status[i++] = '!'; 631 632 if (cansee & WHO_OPERSEE) 633 status[i++] = '?'; 634 635 if (cm) 636 { 637 if (HasCapability(client, "multi-prefix")) 638 { 639 /* Standard NAMES reply (single character) */ 640 char c = mode_to_prefix(*cm->member_modes); 641 if (c) 642 status[i++] = c; 643 } 644 else 645 { 646 /* NAMES reply with all rights included (multi-prefix / NAMESX) */ 647 strcpy(&status[i], modes_to_prefix(cm->member_modes)); 648 i += strlen(&status[i]); 649 } 650 } 651 652 status[i] = '\0'; 653 } 654 655 static void do_other_who(Client *client, const char *mask) 656 { 657 int oper = IsOper(client); 658 659 if (strchr(mask, '*') || strchr(mask, '?')) 660 { 661 int i = 0; 662 /* go through all users.. */ 663 Client *acptr; 664 who_flags |= WF_WILDCARD; 665 666 list_for_each_entry(acptr, &client_list, client_node) 667 { 668 int cansee; 669 char status[20]; 670 const char *channel; 671 int flg; 672 673 if (!IsUser(acptr)) 674 continue; 675 if (!oper) { 676 /* non-opers can only search on nick here */ 677 if (!match_simple(mask, acptr->name)) 678 continue; 679 } else { 680 /* opers can search on name, ident, virthost, ip and realhost. 681 * Yes, I like readable if's -- Syzop. 682 */ 683 if (match_simple(mask, acptr->name) || match_simple(mask, acptr->user->realhost) || 684 match_simple(mask, acptr->user->username)) 685 goto matchok; 686 if (IsHidden(acptr) && match_simple(mask, acptr->user->virthost)) 687 goto matchok; 688 if (acptr->ip && match_simple(mask, acptr->ip)) 689 goto matchok; 690 /* nothing matched... */ 691 continue; 692 } 693 matchok: 694 if ((cansee = can_see(client, acptr, NULL)) & WHO_CANTSEE) 695 continue; 696 if (WHOLIMIT && !IsOper(client) && ++i > WHOLIMIT) 697 { 698 sendnumeric(client, ERR_WHOLIMEXCEED, WHOLIMIT); 699 return; 700 } 701 702 channel = first_visible_channel(client, acptr, &flg); 703 make_who_status(client, acptr, NULL, NULL, status, cansee); 704 send_who_reply(client, acptr, channel, status, (flg & FVC_HIDDEN) ? "~" : ""); 705 } 706 } 707 else 708 { 709 /* just a single client (no wildcards detected) */ 710 Client *acptr = find_client(mask, NULL); 711 int cansee; 712 char status[20]; 713 const char *channel; 714 int flg; 715 716 if (!acptr) 717 return; 718 719 if ((cansee = can_see(client, acptr, NULL)) == WHO_CANTSEE) 720 return; 721 722 channel = first_visible_channel(client, acptr, &flg); 723 make_who_status(client, acptr, NULL, NULL, status, cansee); 724 send_who_reply(client, acptr, channel, status, (flg & FVC_HIDDEN) ? "~" : ""); 725 } 726 } 727 728 static void send_who_reply(Client *client, Client *acptr, 729 const char *channel, const char *status, const char *xstat) 730 { 731 char *stat; 732 const char *host; 733 int flat = (FLAT_MAP && !IsOper(client)) ? 1 : 0; 734 735 stat = safe_alloc(strlen(status) + strlen(xstat) + 1); 736 sprintf(stat, "%s%s", status, xstat); 737 738 if (IsOper(client)) 739 { 740 if (who_flags & WF_REALHOST) 741 host = acptr->user->realhost; 742 else if (who_flags & WF_IP) 743 host = (acptr->ip ? acptr->ip : acptr->user->realhost); 744 else 745 host = GetHost(acptr); 746 } 747 else 748 host = GetHost(acptr); 749 750 751 if (IsULine(acptr) && !IsOper(client) && !ValidatePermissionsForPath("server:info:map:ulines",client,acptr,NULL,NULL) && HIDE_ULINES) 752 { 753 sendnumeric(client, RPL_WHOREPLY, 754 channel, /* channel name */ 755 acptr->user->username, /* user name */ 756 host, /* hostname */ 757 "hidden", /* let's hide the server from normal users if the server is a uline and HIDE_ULINES is on */ 758 acptr->name, /* nick */ 759 stat, /* status */ 760 0, /* hops (hidden) */ 761 acptr->info /* realname */ 762 ); 763 764 } else { 765 sendnumeric(client, RPL_WHOREPLY, 766 channel, /* channel name */ 767 acptr->user->username, /* user name */ 768 host, /* hostname */ 769 acptr->user->server, /* server name */ 770 acptr->name, /* nick */ 771 stat, /* status */ 772 flat ? 0 : acptr->hopcount, /* hops */ 773 acptr->info /* realname */ 774 ); 775 } 776 safe_free(stat); 777 } 778 779 static const char *first_visible_channel(Client *client, Client *acptr, int *flg) 780 { 781 Membership *lp; 782 783 *flg = 0; 784 785 for (lp = acptr->user->channel; lp; lp = lp->next) 786 { 787 Channel *channel = lp->channel; 788 Hook *h; 789 int ret = EX_ALLOW; 790 int operoverride = 0; 791 int showchannel = 0; 792 793 /* Note that the code below is almost identical to the one in /WHOIS */ 794 795 if (ShowChannel(client, channel)) 796 showchannel = 1; 797 798 for (h = Hooks[HOOKTYPE_SEE_CHANNEL_IN_WHOIS]; h; h = h->next) 799 { 800 int n = (*(h->func.intfunc))(client, acptr, channel); 801 /* Hook return values: 802 * EX_ALLOW means 'yes is ok, as far as modules are concerned' 803 * EX_DENY means 'hide this channel, unless oper overriding' 804 * EX_ALWAYS_DENY means 'hide this channel, always' 805 * ... with the exception that we always show the channel if you /WHOIS yourself 806 */ 807 if (n == EX_DENY) 808 { 809 ret = EX_DENY; 810 } 811 else if (n == EX_ALWAYS_DENY) 812 { 813 ret = EX_ALWAYS_DENY; 814 break; 815 } 816 } 817 818 if (ret == EX_DENY) 819 showchannel = 0; 820 821 if (!showchannel && (ValidatePermissionsForPath("channel:see:who:secret",client,NULL,channel,NULL) || ValidatePermissionsForPath("channel:see:whois",client,NULL,channel,NULL))) 822 { 823 showchannel = 1; /* OperOverride */ 824 operoverride = 1; 825 } 826 827 if ((ret == EX_ALWAYS_DENY) && (acptr != client)) 828 continue; /* a module asked us to really not expose this channel, so we don't (except target==ourselves). */ 829 830 if (acptr == client) 831 showchannel = 1; 832 833 if (operoverride) 834 *flg |= FVC_HIDDEN; 835 836 if (showchannel) 837 return channel->name; 838 } 839 840 /* no channels that they can see */ 841 return "*"; 842 }