Annotation of ircnowd/src/ngircd/irc-info.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
! 9: * Please read the file COPYING, README and AUTHORS for more information.
! 10: */
! 11:
! 12: #include "portab.h"
! 13:
! 14: /**
! 15: * @file
! 16: * IRC info commands
! 17: */
! 18:
! 19: #include <assert.h>
! 20: #include <stdio.h>
! 21: #include <stdlib.h>
! 22: #include <string.h>
! 23: #include <strings.h>
! 24: #include <time.h>
! 25:
! 26: #include "ngircd.h"
! 27: #include "conn-func.h"
! 28: #include "conn-zip.h"
! 29: #include "channel.h"
! 30: #include "class.h"
! 31: #include "conf.h"
! 32: #include "lists.h"
! 33: #include "messages.h"
! 34: #include "match.h"
! 35: #include "parse.h"
! 36: #include "irc.h"
! 37: #include "irc-macros.h"
! 38: #include "irc-write.h"
! 39: #include "client-cap.h"
! 40: #include "op.h"
! 41:
! 42: #include "irc-info.h"
! 43:
! 44: /* Local functions */
! 45:
! 46: static unsigned int
! 47: t_diff(time_t *t, const time_t d)
! 48: {
! 49: time_t diff, remain;
! 50:
! 51: diff = *t / d;
! 52: remain = diff * d;
! 53: *t -= remain;
! 54:
! 55: return (unsigned int)diff;
! 56: }
! 57:
! 58: static unsigned int
! 59: uptime_days(time_t *now)
! 60: {
! 61: return t_diff(now, 60 * 60 * 24);
! 62: }
! 63:
! 64: static unsigned int
! 65: uptime_hrs(time_t *now)
! 66: {
! 67: return t_diff(now, 60 * 60);
! 68: }
! 69:
! 70: static unsigned int
! 71: uptime_mins(time_t *now)
! 72: {
! 73: return t_diff(now, 60);
! 74: }
! 75:
! 76: static bool
! 77: write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
! 78: {
! 79: return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client),
! 80: channelname, Client_User(c),
! 81: Client_HostnameDisplayed(c),
! 82: Client_ID(Client_Introducer(c)), Client_ID(c),
! 83: flags, Client_Hops(c), Client_Info(c));
! 84: }
! 85:
! 86: /**
! 87: * Return channel user mode prefix(es).
! 88: *
! 89: * @param Client The client requesting the mode prefixes.
! 90: * @param chan_user_modes String with channel user modes.
! 91: * @param str String buffer to which the prefix(es) will be appended.
! 92: * @param len Size of "str" buffer.
! 93: * @return Pointer to "str".
! 94: */
! 95: static char *
! 96: who_flags_qualifier(CLIENT *Client, const char *chan_user_modes,
! 97: char *str, size_t len)
! 98: {
! 99: assert(Client != NULL);
! 100:
! 101: if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
! 102: if (strchr(chan_user_modes, 'q'))
! 103: strlcat(str, "~", len);
! 104: if (strchr(chan_user_modes, 'a'))
! 105: strlcat(str, "&", len);
! 106: if (strchr(chan_user_modes, 'o'))
! 107: strlcat(str, "@", len);
! 108: if (strchr(chan_user_modes, 'h'))
! 109: strlcat(str, "%", len);
! 110: if (strchr(chan_user_modes, 'v'))
! 111: strlcat(str, "+", len);
! 112:
! 113: return str;
! 114: }
! 115:
! 116: if (strchr(chan_user_modes, 'q'))
! 117: strlcat(str, "~", len);
! 118: else if (strchr(chan_user_modes, 'a'))
! 119: strlcat(str, "&", len);
! 120: else if (strchr(chan_user_modes, 'o'))
! 121: strlcat(str, "@", len);
! 122: else if (strchr(chan_user_modes, 'h'))
! 123: strlcat(str, "%", len);
! 124: else if (strchr(chan_user_modes, 'v'))
! 125: strlcat(str, "+", len);
! 126:
! 127: return str;
! 128: }
! 129:
! 130: /**
! 131: * Send WHO reply for a "channel target" ("WHO #channel").
! 132: *
! 133: * @param Client Client requesting the information.
! 134: * @param Chan Channel being requested.
! 135: * @param OnlyOps Only display IRC operators.
! 136: * @return CONNECTED or DISCONNECTED.
! 137: */
! 138: static bool
! 139: IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
! 140: {
! 141: bool is_visible, is_member, is_ircop;
! 142: CL2CHAN *cl2chan;
! 143: char flags[10];
! 144: CLIENT *c;
! 145: int count = 0;
! 146:
! 147: assert( Client != NULL );
! 148: assert( Chan != NULL );
! 149:
! 150: is_member = Channel_IsMemberOf(Chan, Client);
! 151:
! 152: /* Secret channel? */
! 153: if (!is_member && Channel_HasMode(Chan, 's'))
! 154: return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG,
! 155: Client_ID(Client), Channel_Name(Chan));
! 156:
! 157: cl2chan = Channel_FirstMember(Chan);
! 158: for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
! 159: c = Channel_GetClient(cl2chan);
! 160:
! 161: is_ircop = Client_HasMode(c, 'o');
! 162: if (OnlyOps && !is_ircop)
! 163: continue;
! 164:
! 165: is_visible = !Client_HasMode(c, 'i');
! 166: if (is_member || is_visible) {
! 167: memset(flags, 0, sizeof(flags));
! 168:
! 169: if (Client_HasMode(c, 'a'))
! 170: flags[0] = 'G'; /* away */
! 171: else
! 172: flags[0] = 'H';
! 173:
! 174: if (is_ircop)
! 175: flags[1] = '*';
! 176:
! 177: who_flags_qualifier(Client, Channel_UserModes(Chan, c),
! 178: flags, sizeof(flags));
! 179:
! 180: if (!write_whoreply(Client, c, Channel_Name(Chan),
! 181: flags))
! 182: return DISCONNECTED;
! 183: count++;
! 184: }
! 185: }
! 186:
! 187: /* If there are a lot of clients, increase the penalty a bit */
! 188: if (count > MAX_RPL_WHO)
! 189: IRC_SetPenalty(Client, 1);
! 190:
! 191: return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
! 192: Channel_Name(Chan));
! 193: }
! 194:
! 195: /**
! 196: * Send WHO reply for a "mask target" ("WHO m*sk").
! 197: *
! 198: * @param Client Client requesting the information.
! 199: * @param Mask Mask being requested or NULL for "all" clients.
! 200: * @param OnlyOps Only display IRC operators.
! 201: * @return CONNECTED or DISCONNECTED.
! 202: */
! 203: static bool
! 204: IRC_WHO_Mask(CLIENT *Client, char *Mask, bool OnlyOps)
! 205: {
! 206: CLIENT *c;
! 207: CL2CHAN *cl2chan;
! 208: CHANNEL *chan;
! 209: bool client_match, is_visible;
! 210: char flags[3];
! 211: int count = 0;
! 212:
! 213: assert (Client != NULL);
! 214:
! 215: if (Mask)
! 216: ngt_LowerStr(Mask);
! 217:
! 218: IRC_SetPenalty(Client, 3);
! 219: for (c = Client_First(); c != NULL; c = Client_Next(c)) {
! 220: if (Client_Type(c) != CLIENT_USER)
! 221: continue;
! 222:
! 223: if (OnlyOps && !Client_HasMode(c, 'o'))
! 224: continue;
! 225:
! 226: if (Mask) {
! 227: /* Match pattern against user host/server/name/nick */
! 228: client_match = MatchCaseInsensitive(Mask,
! 229: Client_Hostname(c));
! 230: if (!client_match)
! 231: client_match = MatchCaseInsensitive(Mask,
! 232: Client_ID(Client_Introducer(c)));
! 233: if (!client_match)
! 234: client_match = MatchCaseInsensitive(Mask,
! 235: Client_Info(c));
! 236: if (!client_match)
! 237: client_match = MatchCaseInsensitive(Mask,
! 238: Client_ID(c));
! 239: if (!client_match)
! 240: continue; /* no match: skip this client */
! 241: }
! 242:
! 243: is_visible = !Client_HasMode(c, 'i');
! 244:
! 245: /* Target client is invisible, but mask matches exactly? */
! 246: if (!is_visible && Mask && strcasecmp(Client_ID(c), Mask) == 0)
! 247: is_visible = true;
! 248:
! 249: /* Target still invisible, but are both on the same channel? */
! 250: if (!is_visible) {
! 251: cl2chan = Channel_FirstChannelOf(Client);
! 252: while (cl2chan && !is_visible) {
! 253: chan = Channel_GetChannel(cl2chan);
! 254: if (Channel_IsMemberOf(chan, c))
! 255: is_visible = true;
! 256: cl2chan = Channel_NextChannelOf(Client, cl2chan);
! 257: }
! 258: }
! 259:
! 260: if (!is_visible) /* target user is not visible */
! 261: continue;
! 262:
! 263: if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO"))
! 264: break;
! 265:
! 266: memset(flags, 0, sizeof(flags));
! 267:
! 268: if (Client_HasMode(c, 'a'))
! 269: flags[0] = 'G'; /* away */
! 270: else
! 271: flags[0] = 'H';
! 272:
! 273: if (Client_HasMode(c, 'o'))
! 274: flags[1] = '*';
! 275:
! 276: if (!write_whoreply(Client, c, "*", flags))
! 277: return DISCONNECTED;
! 278: count++;
! 279: }
! 280:
! 281: return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
! 282: Mask ? Mask : "*");
! 283: }
! 284:
! 285: /**
! 286: * Generate WHOIS reply of one actual client.
! 287: *
! 288: * @param Client The client from which this command has been received.
! 289: * @param from The client requesting the information ("originator").
! 290: * @param c The client of which information should be returned.
! 291: * @return CONNECTED or DISCONNECTED.
! 292: */
! 293: static bool
! 294: IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
! 295: {
! 296: char str[COMMAND_LEN];
! 297: CL2CHAN *cl2chan;
! 298: CHANNEL *chan;
! 299:
! 300: assert(Client != NULL);
! 301: assert(from != NULL);
! 302: assert(c != NULL);
! 303:
! 304: /* Nick, user, hostname and client info */
! 305: if (!IRC_WriteStrClient(from, RPL_WHOISUSER_MSG, Client_ID(from),
! 306: Client_ID(c), Client_User(c),
! 307: Client_HostnameDisplayed(c), Client_Info(c)))
! 308: return DISCONNECTED;
! 309:
! 310: /* Server */
! 311: if (!IRC_WriteStrClient(from, RPL_WHOISSERVER_MSG, Client_ID(from),
! 312: Client_ID(c), Client_ID(Client_Introducer(c)),
! 313: Client_Info(Client_Introducer(c))))
! 314: return DISCONNECTED;
! 315:
! 316: /* Channels, show only if client has no +I or if from is oper */
! 317: if(!(Client_HasMode(c, 'I')) || Client_HasMode(from, 'o')) {
! 318: snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
! 319: Client_ID(from), Client_ID(c));
! 320: cl2chan = Channel_FirstChannelOf(c);
! 321: while (cl2chan) {
! 322: chan = Channel_GetChannel(cl2chan);
! 323: assert(chan != NULL);
! 324:
! 325: /* next */
! 326: cl2chan = Channel_NextChannelOf(c, cl2chan);
! 327:
! 328: /* Secret channel? */
! 329: if (Channel_HasMode(chan, 's')
! 330: && !Channel_IsMemberOf(chan, Client))
! 331: continue;
! 332:
! 333: /* Local channel and request is not from a user? */
! 334: if (Client_Type(Client) == CLIENT_SERVER
! 335: && Channel_IsLocal(chan))
! 336: continue;
! 337:
! 338: /* Concatenate channel names */
! 339: if (str[strlen(str) - 1] != ':')
! 340: strlcat(str, " ", sizeof(str));
! 341:
! 342: who_flags_qualifier(Client, Channel_UserModes(chan, c),
! 343: str, sizeof(str));
! 344: strlcat(str, Channel_Name(chan), sizeof(str));
! 345:
! 346: if (strlen(str) > (COMMAND_LEN - CHANNEL_NAME_LEN - 4)) {
! 347: /* Line becomes too long: send it! */
! 348: if (!IRC_WriteStrClient(Client, "%s", str))
! 349: return DISCONNECTED;
! 350: snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
! 351: Client_ID(from), Client_ID(c));
! 352: }
! 353: }
! 354: if(str[strlen(str) - 1] != ':') {
! 355: /* There is data left to send: */
! 356: if (!IRC_WriteStrClient(Client, "%s", str))
! 357: return DISCONNECTED;
! 358: }
! 359: }
! 360:
! 361: /* IRC-Services? */
! 362: if (Client_Type(c) == CLIENT_SERVICE &&
! 363: !IRC_WriteStrClient(from, RPL_WHOISSERVICE_MSG,
! 364: Client_ID(from), Client_ID(c)))
! 365: return DISCONNECTED;
! 366:
! 367: /* IRC-Operator? */
! 368: if (Client_Type(c) != CLIENT_SERVICE &&
! 369: Client_HasMode(c, 'o') &&
! 370: !IRC_WriteStrClient(from, RPL_WHOISOPERATOR_MSG,
! 371: Client_ID(from), Client_ID(c)))
! 372: return DISCONNECTED;
! 373:
! 374: /* IRC-Bot? */
! 375: if (Client_HasMode(c, 'B') &&
! 376: !IRC_WriteStrClient(from, RPL_WHOISBOT_MSG,
! 377: Client_ID(from), Client_ID(c)))
! 378: return DISCONNECTED;
! 379:
! 380: /* Connected using SSL? */
! 381: if (Conn_UsesSSL(Client_Conn(c))) {
! 382: if (!IRC_WriteStrClient(from, RPL_WHOISSSL_MSG, Client_ID(from),
! 383: Client_ID(c)))
! 384: return DISCONNECTED;
! 385:
! 386: /* Certificate fingerprint? */
! 387: if (Conn_GetCertFp(Client_Conn(c)) &&
! 388: from == c &&
! 389: !IRC_WriteStrClient(from, RPL_WHOISCERTFP_MSG,
! 390: Client_ID(from), Client_ID(c),
! 391: Conn_GetCertFp(Client_Conn(c))))
! 392: return DISCONNECTED;
! 393: }
! 394:
! 395: /* Registered nickname? */
! 396: if (Client_HasMode(c, 'R') &&
! 397: !IRC_WriteStrClient(from, RPL_WHOISREGNICK_MSG,
! 398: Client_ID(from), Client_ID(c)))
! 399: return DISCONNECTED;
! 400:
! 401: /* Account name metadata? */
! 402: if (Client_AccountName(c) &&
! 403: !IRC_WriteStrClient(from, RPL_WHOISLOGGEDIN_MSG,
! 404: Client_ID(from), Client_ID(c),
! 405: Client_AccountName(c)))
! 406: return DISCONNECTED;
! 407:
! 408: /* Local client and requester is the user itself or an IRC Op? */
! 409: if (Client_Conn(c) > NONE &&
! 410: (from == c || Client_HasMode(from, 'o'))) {
! 411: /* Client hostname */
! 412: if (!IRC_WriteStrClient(from, RPL_WHOISHOST_MSG,
! 413: Client_ID(from), Client_ID(c),
! 414: Client_Hostname(c), Client_IPAText(c)))
! 415: return DISCONNECTED;
! 416: /* Client modes */
! 417: if (!IRC_WriteStrClient(from, RPL_WHOISMODES_MSG,
! 418: Client_ID(from), Client_ID(c), Client_Modes(c)))
! 419: return DISCONNECTED;
! 420: }
! 421:
! 422: /* Idle and signon time (local clients only!) */
! 423: if (!Conf_MorePrivacy && Client_Conn(c) > NONE &&
! 424: !IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
! 425: Client_ID(from), Client_ID(c),
! 426: (unsigned long)Conn_GetIdle(Client_Conn(c)),
! 427: (unsigned long)Conn_GetSignon(Client_Conn(c))))
! 428: return DISCONNECTED;
! 429:
! 430: /* Away? */
! 431: if (Client_HasMode(c, 'a') &&
! 432: !IRC_WriteStrClient(from, RPL_AWAY_MSG,
! 433: Client_ID(from), Client_ID(c), Client_Away(c)))
! 434: return DISCONNECTED;
! 435:
! 436: return CONNECTED;
! 437: }
! 438:
! 439: static bool
! 440: WHOWAS_EntryWrite(CLIENT *prefix, WHOWAS *entry)
! 441: {
! 442: char t_str[60];
! 443:
! 444: (void)strftime(t_str, sizeof(t_str), "%a %b %d %H:%M:%S %Y",
! 445: localtime(&entry->time));
! 446:
! 447: if (!IRC_WriteStrClient(prefix, RPL_WHOWASUSER_MSG, Client_ID(prefix),
! 448: entry->id, entry->user, entry->host, entry->info))
! 449: return DISCONNECTED;
! 450:
! 451: return IRC_WriteStrClient(prefix, RPL_WHOISSERVER_MSG, Client_ID(prefix),
! 452: entry->id, entry->server, t_str);
! 453: }
! 454:
! 455: #ifdef SSL_SUPPORT
! 456: static bool
! 457: Show_MOTD_SSLInfo(CLIENT *Client)
! 458: {
! 459: char buf[COMMAND_LEN];
! 460: char c_str[128];
! 461:
! 462: if (Conn_GetCipherInfo(Client_Conn(Client), c_str, sizeof(c_str))) {
! 463: snprintf(buf, sizeof(buf), "Connected using Cipher %s", c_str);
! 464: if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG,
! 465: Client_ID(Client), buf))
! 466: return false;
! 467: }
! 468:
! 469: if (Conn_GetCertFp(Client_Conn(Client))) {
! 470: snprintf(buf, sizeof(buf),
! 471: "Your client certificate fingerprint is: %s",
! 472: Conn_GetCertFp(Client_Conn(Client)));
! 473: if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG,
! 474: Client_ID(Client), buf))
! 475: return false;
! 476: }
! 477:
! 478: return true;
! 479: }
! 480: #else
! 481: static bool
! 482: Show_MOTD_SSLInfo(UNUSED CLIENT *c)
! 483: {
! 484: return true;
! 485: }
! 486: #endif
! 487:
! 488: /* Global functions */
! 489:
! 490: /**
! 491: * Handler for the IRC command "ADMIN".
! 492: *
! 493: * @param Client The client from which this command has been received.
! 494: * @param Req Request structure with prefix and all parameters.
! 495: * @return CONNECTED or DISCONNECTED.
! 496: */
! 497: GLOBAL bool
! 498: IRC_ADMIN(CLIENT *Client, REQUEST *Req )
! 499: {
! 500: CLIENT *target, *prefix;
! 501:
! 502: assert( Client != NULL );
! 503: assert( Req != NULL );
! 504:
! 505: _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
! 506: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
! 507:
! 508: /* Forward? */
! 509: if(target != Client_ThisServer()) {
! 510: IRC_WriteStrClientPrefix(target, prefix,
! 511: "ADMIN %s", Client_ID(target));
! 512: return CONNECTED;
! 513: }
! 514:
! 515: if (!IRC_WriteStrClient(Client, RPL_ADMINME_MSG, Client_ID(prefix),
! 516: Conf_ServerName))
! 517: return DISCONNECTED;
! 518: if (!IRC_WriteStrClient(Client, RPL_ADMINLOC1_MSG, Client_ID(prefix),
! 519: Conf_ServerAdmin1))
! 520: return DISCONNECTED;
! 521: if (!IRC_WriteStrClient(Client, RPL_ADMINLOC2_MSG, Client_ID(prefix),
! 522: Conf_ServerAdmin2))
! 523: return DISCONNECTED;
! 524: if (!IRC_WriteStrClient(Client, RPL_ADMINEMAIL_MSG, Client_ID(prefix),
! 525: Conf_ServerAdminMail))
! 526: return DISCONNECTED;
! 527:
! 528: return CONNECTED;
! 529: } /* IRC_ADMIN */
! 530:
! 531: /**
! 532: * Handler for the IRC command "INFO".
! 533: *
! 534: * @param Client The client from which this command has been received.
! 535: * @param Req Request structure with prefix and all parameters.
! 536: * @return CONNECTED or DISCONNECTED.
! 537: */
! 538: GLOBAL bool
! 539: IRC_INFO(CLIENT * Client, REQUEST * Req)
! 540: {
! 541: CLIENT *target, *prefix;
! 542: char msg[510];
! 543:
! 544: assert(Client != NULL);
! 545: assert(Req != NULL);
! 546:
! 547: _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
! 548: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
! 549:
! 550: /* Forward? */
! 551: if (target != Client_ThisServer()) {
! 552: IRC_WriteStrClientPrefix(target, prefix, "INFO %s",
! 553: Client_ID(target));
! 554: return CONNECTED;
! 555: }
! 556:
! 557: if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix),
! 558: NGIRCd_Version))
! 559: return DISCONNECTED;
! 560:
! 561: #if defined(BIRTHDATE)
! 562: char t_str[60];
! 563: time_t t = BIRTHDATE;
! 564: (void)strftime(t_str, sizeof(t_str), "%a %b %d %Y at %H:%M:%S (%Z)",
! 565: localtime(&t));
! 566: snprintf(msg, sizeof(msg), "Birth Date: %s", t_str);
! 567: if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
! 568: return DISCONNECTED;
! 569: #elif defined(__DATE__) && defined(__TIME__)
! 570: snprintf(msg, sizeof(msg), "Birth Date: %s at %s", __DATE__, __TIME__);
! 571: if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
! 572: return DISCONNECTED;
! 573: #endif
! 574:
! 575: strlcpy(msg, "On-line since ", sizeof(msg));
! 576: strlcat(msg, NGIRCd_StartStr, sizeof(msg));
! 577: if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
! 578: return DISCONNECTED;
! 579:
! 580: if (!IRC_WriteStrClient(Client, RPL_ENDOFINFO_MSG, Client_ID(prefix)))
! 581: return DISCONNECTED;
! 582:
! 583: return CONNECTED;
! 584: } /* IRC_INFO */
! 585:
! 586: /**
! 587: * Handler for the IRC "ISON" command.
! 588: *
! 589: * @param Client The client from which this command has been received.
! 590: * @param Req Request structure with prefix and all parameters.
! 591: * @return CONNECTED or DISCONNECTED.
! 592: */
! 593: GLOBAL bool
! 594: IRC_ISON( CLIENT *Client, REQUEST *Req )
! 595: {
! 596: char rpl[COMMAND_LEN];
! 597: CLIENT *c;
! 598: char *ptr;
! 599: int i;
! 600:
! 601: assert(Client != NULL);
! 602: assert(Req != NULL);
! 603:
! 604: strlcpy(rpl, RPL_ISON_MSG, sizeof rpl);
! 605: for (i = 0; i < Req->argc; i++) {
! 606: /* "All" ircd even parse ":<x> <y> ..." arguments and split
! 607: * them up; so we do the same ... */
! 608: ptr = strtok(Req->argv[i], " ");
! 609: while (ptr) {
! 610: ngt_TrimStr(ptr);
! 611: c = Client_Search(ptr);
! 612: if (c && Client_Type(c) == CLIENT_USER) {
! 613: strlcat(rpl, Client_ID(c), sizeof(rpl));
! 614: strlcat(rpl, " ", sizeof(rpl));
! 615: }
! 616: ptr = strtok(NULL, " ");
! 617: }
! 618: }
! 619: ngt_TrimLastChr(rpl, ' ');
! 620:
! 621: return IRC_WriteStrClient(Client, rpl, Client_ID(Client));
! 622: } /* IRC_ISON */
! 623:
! 624: /**
! 625: * Handler for the IRC "LINKS" command.
! 626: *
! 627: * @param Client The client from which this command has been received.
! 628: * @param Req Request structure with prefix and all parameters.
! 629: * @return CONNECTED or DISCONNECTED.
! 630: */
! 631: GLOBAL bool
! 632: IRC_LINKS(CLIENT *Client, REQUEST *Req)
! 633: {
! 634: CLIENT *target, *from, *c;
! 635: char *mask;
! 636:
! 637: assert(Client != NULL);
! 638: assert(Req != NULL);
! 639:
! 640: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 641:
! 642: /* Get pointer to server mask or "*", if none given */
! 643: if (Req->argc > 0)
! 644: mask = Req->argv[Req->argc - 1];
! 645: else
! 646: mask = "*";
! 647:
! 648: /* Forward? */
! 649: if (Req->argc == 2) {
! 650: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
! 651: if (target != Client_ThisServer()) {
! 652: IRC_WriteStrClientPrefix(target, from,
! 653: "LINKS %s %s", Client_ID(target),
! 654: Req->argv[1]);
! 655: return CONNECTED;
! 656: }
! 657: }
! 658:
! 659: c = Client_First();
! 660: while (c) {
! 661: if (Client_Type(c) == CLIENT_SERVER
! 662: && MatchCaseInsensitive(mask, Client_ID(c))) {
! 663: if (!IRC_WriteStrClient(from, RPL_LINKS_MSG,
! 664: Client_ID(from), Client_ID(c),
! 665: Client_ID(Client_TopServer(c)
! 666: ? Client_TopServer(c)
! 667: : Client_ThisServer()),
! 668: Client_Hops(c), Client_Info(c)))
! 669: return DISCONNECTED;
! 670: }
! 671: c = Client_Next(c);
! 672: }
! 673: return IRC_WriteStrClient(from, RPL_ENDOFLINKS_MSG,
! 674: Client_ID(from), mask);
! 675: } /* IRC_LINKS */
! 676:
! 677: /**
! 678: * Handler for the IRC "LUSERS" command.
! 679: *
! 680: * @param Client The client from which this command has been received.
! 681: * @param Req Request structure with prefix and all parameters.
! 682: * @return CONNECTED or DISCONNECTED.
! 683: */
! 684: GLOBAL bool
! 685: IRC_LUSERS( CLIENT *Client, REQUEST *Req )
! 686: {
! 687: CLIENT *target, *from;
! 688:
! 689: assert( Client != NULL );
! 690: assert( Req != NULL );
! 691:
! 692: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 693: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
! 694:
! 695: /* Forward? */
! 696: if (target != Client_ThisServer()) {
! 697: IRC_WriteStrClientPrefix(target, from,
! 698: "LUSERS %s %s", Req->argv[0],
! 699: Client_ID(target));
! 700: return CONNECTED;
! 701: }
! 702:
! 703: return IRC_Send_LUSERS(from);
! 704: } /* IRC_LUSERS */
! 705:
! 706: /**
! 707: * Handler for the IRC command "SERVLIST".
! 708: *
! 709: * @param Client The client from which this command has been received.
! 710: * @param Req Request structure with prefix and all parameters.
! 711: * @return CONNECTED or DISCONNECTED.
! 712: */
! 713: GLOBAL bool
! 714: IRC_SERVLIST(CLIENT *Client, REQUEST *Req)
! 715: {
! 716: CLIENT *c;
! 717:
! 718: assert(Client != NULL);
! 719: assert(Req != NULL);
! 720:
! 721: if (Req->argc < 2 || strcmp(Req->argv[1], "0") == 0) {
! 722: for (c = Client_First(); c!= NULL; c = Client_Next(c)) {
! 723: if (Client_Type(c) != CLIENT_SERVICE)
! 724: continue;
! 725: if (Req->argc > 0 && !MatchCaseInsensitive(Req->argv[0],
! 726: Client_ID(c)))
! 727: continue;
! 728: if (!IRC_WriteStrClient(Client, RPL_SERVLIST_MSG,
! 729: Client_ID(Client), Client_Mask(c),
! 730: Client_Mask(Client_Introducer(c)), "*",
! 731: 0, Client_Hops(c), Client_Info(c)))
! 732: return DISCONNECTED;
! 733: }
! 734: }
! 735:
! 736: return IRC_WriteStrClient(Client, RPL_SERVLISTEND_MSG, Client_ID(Client),
! 737: Req->argc > 0 ? Req->argv[0] : "*",
! 738: Req->argc > 1 ? Req->argv[1] : "0");
! 739: } /* IRC_SERVLIST */
! 740:
! 741: /**
! 742: * Handler for the IRC command "MOTD".
! 743: *
! 744: * @param Client The client from which this command has been received.
! 745: * @param Req Request structure with prefix and all parameters.
! 746: * @return CONNECTED or DISCONNECTED.
! 747: */
! 748: GLOBAL bool
! 749: IRC_MOTD( CLIENT *Client, REQUEST *Req )
! 750: {
! 751: CLIENT *from, *target;
! 752:
! 753: assert( Client != NULL );
! 754: assert( Req != NULL );
! 755:
! 756: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 757: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
! 758:
! 759: /* Forward? */
! 760: if (target != Client_ThisServer()) {
! 761: IRC_WriteStrClientPrefix(target, from, "MOTD %s",
! 762: Client_ID(target));
! 763: return CONNECTED;
! 764: }
! 765:
! 766: return IRC_Show_MOTD(from);
! 767: } /* IRC_MOTD */
! 768:
! 769: /**
! 770: * Handler for the IRC command "NAMES".
! 771: *
! 772: * @param Client The client from which this command has been received.
! 773: * @param Req Request structure with prefix and all parameters.
! 774: * @return CONNECTED or DISCONNECTED.
! 775: */
! 776: GLOBAL bool
! 777: IRC_NAMES( CLIENT *Client, REQUEST *Req )
! 778: {
! 779: char rpl[COMMAND_LEN], *ptr;
! 780: CLIENT *target, *from, *c;
! 781: CHANNEL *chan;
! 782:
! 783: assert( Client != NULL );
! 784: assert( Req != NULL );
! 785:
! 786: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 787: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
! 788:
! 789: /* Forward? */
! 790: if (target != Client_ThisServer()) {
! 791: IRC_WriteStrClientPrefix(target, from, "NAMES %s :%s",
! 792: Req->argv[0], Client_ID(target));
! 793: return CONNECTED;
! 794: }
! 795:
! 796: if (Req->argc > 0) {
! 797: /* Return NAMES list for specific channels */
! 798: ptr = strtok(Req->argv[0], ",");
! 799: while(ptr) {
! 800: chan = Channel_Search(ptr);
! 801: if (chan && !IRC_Send_NAMES(from, chan))
! 802: return DISCONNECTED;
! 803: if (!IRC_WriteStrClient(from, RPL_ENDOFNAMES_MSG,
! 804: Client_ID(from), ptr))
! 805: return DISCONNECTED;
! 806: ptr = strtok( NULL, "," );
! 807: }
! 808: return CONNECTED;
! 809: }
! 810:
! 811: chan = Channel_First();
! 812: while (chan) {
! 813: if (!IRC_Send_NAMES(from, chan))
! 814: return DISCONNECTED;
! 815: chan = Channel_Next(chan);
! 816: }
! 817:
! 818: /* Now print all clients which are not in any channel */
! 819: c = Client_First();
! 820: snprintf(rpl, sizeof(rpl), RPL_NAMREPLY_MSG, Client_ID(from), "*", "*");
! 821: while (c) {
! 822: if (Client_Type(c) == CLIENT_USER
! 823: && Channel_FirstChannelOf(c) == NULL
! 824: && !Client_HasMode(c, 'i'))
! 825: {
! 826: /* its a user, concatenate ... */
! 827: if (rpl[strlen(rpl) - 1] != ':')
! 828: strlcat(rpl, " ", sizeof(rpl));
! 829: strlcat(rpl, Client_ID(c), sizeof(rpl));
! 830:
! 831: if (strlen(rpl) > COMMAND_LEN - CLIENT_NICK_LEN - 4) {
! 832: /* Line is gwoing too long, send now */
! 833: if (!IRC_WriteStrClient(from, "%s", rpl))
! 834: return DISCONNECTED;
! 835: snprintf(rpl, sizeof(rpl), RPL_NAMREPLY_MSG,
! 836: Client_ID(from), "*", "*");
! 837: }
! 838: }
! 839: c = Client_Next(c);
! 840: }
! 841: if (rpl[strlen(rpl) - 1] != ':' && !IRC_WriteStrClient(from, "%s", rpl))
! 842: return DISCONNECTED;
! 843:
! 844: return IRC_WriteStrClient(from, RPL_ENDOFNAMES_MSG, Client_ID(from), "*");
! 845: } /* IRC_NAMES */
! 846:
! 847: /**
! 848: * Handler for the IRC command "STATS".
! 849: *
! 850: * @param Client The client from which this command has been received.
! 851: * @param Req Request structure with prefix and all parameters.
! 852: * @return CONNECTED or DISCONNECTED.
! 853: */
! 854: GLOBAL bool
! 855: IRC_STATS( CLIENT *Client, REQUEST *Req )
! 856: {
! 857: CLIENT *from, *target, *cl;
! 858: CONN_ID con;
! 859: char query;
! 860: COMMAND *cmd;
! 861: time_t time_now;
! 862: unsigned int days, hrs, mins;
! 863: struct list_head *list;
! 864: struct list_elem *list_item;
! 865: bool more_links = false;
! 866:
! 867: assert(Client != NULL);
! 868: assert(Req != NULL);
! 869:
! 870: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 871: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
! 872:
! 873: /* Forward? */
! 874: if (target != Client_ThisServer()) {
! 875: IRC_WriteStrClientPrefix(target, from, "STATS %s %s",
! 876: Req->argv[0], Client_ID(target));
! 877: return CONNECTED;
! 878: }
! 879:
! 880: if (Req->argc > 0)
! 881: query = Req->argv[0][0] ? Req->argv[0][0] : '*';
! 882: else
! 883: query = '*';
! 884:
! 885: switch (query) {
! 886: case 'g': /* Network-wide bans ("G-Lines") */
! 887: case 'G':
! 888: case 'k': /* Server-local bans ("K-Lines") */
! 889: case 'K':
! 890: if (!Client_HasMode(from, 'o'))
! 891: return IRC_WriteErrClient(from, ERR_NOPRIVILEGES_MSG,
! 892: Client_ID(from));
! 893: if (query == 'g' || query == 'G')
! 894: list = Class_GetList(CLASS_GLINE);
! 895: else
! 896: list = Class_GetList(CLASS_KLINE);
! 897: list_item = Lists_GetFirst(list);
! 898: while (list_item) {
! 899: if (!IRC_WriteStrClient(from, RPL_STATSXLINE_MSG,
! 900: Client_ID(from), query,
! 901: Lists_GetMask(list_item),
! 902: Lists_GetValidity(list_item),
! 903: Lists_GetReason(list_item)))
! 904: return DISCONNECTED;
! 905: list_item = Lists_GetNext(list_item);
! 906: }
! 907: break;
! 908: case 'L': /* Link status (servers and user links) */
! 909: if (!Op_Check(from, Req))
! 910: return Op_NoPrivileges(from, Req);
! 911: more_links = true;
! 912:
! 913: case 'l': /* Link status (servers and own link) */
! 914: time_now = time(NULL);
! 915: for (con = Conn_First(); con != NONE; con = Conn_Next(con)) {
! 916: cl = Conn_GetClient(con);
! 917: if (!cl)
! 918: continue;
! 919: if (Client_Type(cl) == CLIENT_SERVER ||
! 920: cl == Client ||
! 921: (more_links && Client_Type(cl) == CLIENT_USER)) {
! 922: #ifdef ZLIB
! 923: if (Conn_Options(con) & CONN_ZIP) {
! 924: if (!IRC_WriteStrClient
! 925: (from, RPL_STATSLINKINFOZIP_MSG,
! 926: Client_ID(from), Client_Mask(cl),
! 927: Conn_SendQ(con), Conn_SendMsg(con),
! 928: Zip_SendBytes(con),
! 929: Conn_SendBytes(con),
! 930: Conn_RecvMsg(con),
! 931: Zip_RecvBytes(con),
! 932: Conn_RecvBytes(con),
! 933: (long)(time_now - Conn_StartTime(con))))
! 934: return DISCONNECTED;
! 935: continue;
! 936: }
! 937: #endif
! 938: if (!IRC_WriteStrClient
! 939: (from, RPL_STATSLINKINFO_MSG,
! 940: Client_ID(from), Client_Mask(cl),
! 941: Conn_SendQ(con), Conn_SendMsg(con),
! 942: Conn_SendBytes(con), Conn_RecvMsg(con),
! 943: Conn_RecvBytes(con),
! 944: (long)(time_now - Conn_StartTime(con))))
! 945: return DISCONNECTED;
! 946: }
! 947: }
! 948: break;
! 949: case 'm': /* IRC command status (usage count) */
! 950: case 'M':
! 951: cmd = Parse_GetCommandStruct();
! 952: for (; cmd->name; cmd++) {
! 953: if (cmd->lcount == 0 && cmd->rcount == 0)
! 954: continue;
! 955: if (!IRC_WriteStrClient
! 956: (from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
! 957: cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
! 958: return DISCONNECTED;
! 959: }
! 960: break;
! 961: case 'u': /* Server uptime */
! 962: case 'U':
! 963: time_now = time(NULL) - NGIRCd_Start;
! 964: days = uptime_days(&time_now);
! 965: hrs = uptime_hrs(&time_now);
! 966: mins = uptime_mins(&time_now);
! 967: if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
! 968: days, hrs, mins, (unsigned int)time_now))
! 969: return DISCONNECTED;
! 970: break;
! 971: }
! 972:
! 973: return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG,
! 974: Client_ID(from), query);
! 975: } /* IRC_STATS */
! 976:
! 977: /**
! 978: * Handler for the IRC command "SUMMON".
! 979: *
! 980: * @param Client The client from which this command has been received.
! 981: * @param Req Request structure with prefix and all parameters.
! 982: * @return CONNECTED or DISCONNECTED.
! 983: */
! 984: GLOBAL bool
! 985: IRC_SUMMON(CLIENT * Client, UNUSED REQUEST * Req)
! 986: {
! 987: assert(Client != NULL);
! 988:
! 989: return IRC_WriteErrClient(Client, ERR_SUMMONDISABLED_MSG,
! 990: Client_ID(Client));
! 991: } /* IRC_SUMMON */
! 992:
! 993: /**
! 994: * Handler for the IRC command "TIME".
! 995: *
! 996: * @param Client The client from which this command has been received.
! 997: * @param Req Request structure with prefix and all parameters.
! 998: * @return CONNECTED or DISCONNECTED.
! 999: */
! 1000: GLOBAL bool
! 1001: IRC_TIME( CLIENT *Client, REQUEST *Req )
! 1002: {
! 1003: CLIENT *from, *target;
! 1004: char t_str[64];
! 1005: time_t t;
! 1006:
! 1007: assert(Client != NULL);
! 1008: assert(Req != NULL);
! 1009:
! 1010: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 1011: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
! 1012:
! 1013: /* Forward? */
! 1014: if (target != Client_ThisServer()) {
! 1015: IRC_WriteStrClientPrefix(target, from, "TIME %s",
! 1016: Client_ID(target));
! 1017: return CONNECTED;
! 1018: }
! 1019:
! 1020: t = time( NULL );
! 1021: (void)strftime(t_str, 60, "%A %B %d %Y -- %H:%M %Z", localtime(&t));
! 1022: return IRC_WriteStrClient(from, RPL_TIME_MSG, Client_ID(from),
! 1023: Client_ID(Client_ThisServer()), t_str);
! 1024: } /* IRC_TIME */
! 1025:
! 1026: /**
! 1027: * Handler for the IRC command "USERHOST".
! 1028: *
! 1029: * @param Client The client from which this command has been received.
! 1030: * @param Req Request structure with prefix and all parameters.
! 1031: * @return CONNECTED or DISCONNECTED.
! 1032: */
! 1033: GLOBAL bool
! 1034: IRC_USERHOST(CLIENT *Client, REQUEST *Req)
! 1035: {
! 1036: char rpl[COMMAND_LEN];
! 1037: CLIENT *c;
! 1038: int max, i;
! 1039:
! 1040: assert(Client != NULL);
! 1041: assert(Req != NULL);
! 1042:
! 1043: if (Req->argc > 5)
! 1044: max = 5;
! 1045: else
! 1046: max = Req->argc;
! 1047:
! 1048: strlcpy(rpl, RPL_USERHOST_MSG, sizeof rpl);
! 1049: for (i = 0; i < max; i++) {
! 1050: c = Client_Search(Req->argv[i]);
! 1051: if (c && (Client_Type(c) == CLIENT_USER)) {
! 1052: /* This Nick is "online" */
! 1053: strlcat(rpl, Client_ID(c), sizeof(rpl));
! 1054: if (Client_HasMode(c, 'o'))
! 1055: strlcat(rpl, "*", sizeof(rpl));
! 1056: strlcat(rpl, "=", sizeof(rpl));
! 1057: if (Client_HasMode(c, 'a'))
! 1058: strlcat(rpl, "-", sizeof(rpl));
! 1059: else
! 1060: strlcat(rpl, "+", sizeof(rpl));
! 1061: strlcat(rpl, Client_User(c), sizeof(rpl));
! 1062: strlcat(rpl, "@", sizeof(rpl));
! 1063: strlcat(rpl, Client_HostnameDisplayed(c), sizeof(rpl));
! 1064: strlcat(rpl, " ", sizeof(rpl));
! 1065: }
! 1066: }
! 1067: ngt_TrimLastChr(rpl, ' ');
! 1068:
! 1069: return IRC_WriteStrClient(Client, rpl, Client_ID(Client));
! 1070: } /* IRC_USERHOST */
! 1071:
! 1072: /**
! 1073: * Handler for the IRC command "USERS".
! 1074: *
! 1075: * @param Client The client from which this command has been received.
! 1076: * @param Req Request structure with prefix and all parameters.
! 1077: * @return CONNECTED or DISCONNECTED.
! 1078: */
! 1079: GLOBAL bool
! 1080: IRC_USERS(CLIENT * Client, UNUSED REQUEST * Req)
! 1081: {
! 1082: assert(Client != NULL);
! 1083:
! 1084: return IRC_WriteErrClient(Client, ERR_USERSDISABLED_MSG,
! 1085: Client_ID(Client));
! 1086: } /* IRC_USERS */
! 1087:
! 1088: /**
! 1089: * Handler for the IRC command "VERSION".
! 1090: *
! 1091: * @param Client The client from which this command has been received.
! 1092: * @param Req Request structure with prefix and all parameters.
! 1093: * @return CONNECTED or DISCONNECTED.
! 1094: */
! 1095: GLOBAL bool
! 1096: IRC_VERSION( CLIENT *Client, REQUEST *Req )
! 1097: {
! 1098: CLIENT *target, *prefix;
! 1099:
! 1100: assert( Client != NULL );
! 1101: assert( Req != NULL );
! 1102:
! 1103: _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
! 1104: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
! 1105:
! 1106: /* Forward? */
! 1107: if (target != Client_ThisServer()) {
! 1108: IRC_WriteStrClientPrefix(target, prefix, "VERSION %s",
! 1109: Client_ID(target));
! 1110: return CONNECTED;
! 1111: }
! 1112:
! 1113: /* send version information */
! 1114: if (!IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
! 1115: PACKAGE_NAME, PACKAGE_VERSION,
! 1116: NGIRCd_DebugLevel, Conf_ServerName,
! 1117: NGIRCd_VersionAddition))
! 1118: return DISCONNECTED;
! 1119:
! 1120: #ifndef STRICT_RFC
! 1121: /* send RPL_ISUPPORT(005) numerics */
! 1122: if (!IRC_Send_ISUPPORT(prefix))
! 1123: return DISCONNECTED;
! 1124: #endif
! 1125:
! 1126: return CONNECTED;
! 1127: } /* IRC_VERSION */
! 1128:
! 1129: /**
! 1130: * Handler for the IRC "WHO" command.
! 1131: *
! 1132: * @param Client The client from which this command has been received.
! 1133: * @param Req Request structure with prefix and all parameters.
! 1134: * @return CONNECTED or DISCONNECTED.
! 1135: */
! 1136: GLOBAL bool
! 1137: IRC_WHO(CLIENT *Client, REQUEST *Req)
! 1138: {
! 1139: bool only_ops;
! 1140: CHANNEL *chan;
! 1141:
! 1142: assert (Client != NULL);
! 1143: assert (Req != NULL);
! 1144:
! 1145: only_ops = false;
! 1146: if (Req->argc == 2) {
! 1147: if (strcmp(Req->argv[1], "o") == 0)
! 1148: only_ops = true;
! 1149: #ifdef STRICT_RFC
! 1150: else {
! 1151: return IRC_WriteErrClient(Client,
! 1152: ERR_NEEDMOREPARAMS_MSG,
! 1153: Client_ID(Client),
! 1154: Req->command);
! 1155: }
! 1156: #endif
! 1157: }
! 1158:
! 1159: if (Req->argc >= 1) {
! 1160: /* Channel or mask given */
! 1161: chan = Channel_Search(Req->argv[0]);
! 1162: if (chan) {
! 1163: /* Members of a channel have been requested */
! 1164: return IRC_WHO_Channel(Client, chan, only_ops);
! 1165: }
! 1166: if (strcmp(Req->argv[0], "0") != 0) {
! 1167: /* A mask has been given. But please note this RFC
! 1168: * stupidity: "0" is same as no arguments ... */
! 1169: return IRC_WHO_Mask(Client, Req->argv[0], only_ops);
! 1170: }
! 1171: }
! 1172:
! 1173: /* No channel or (valid) mask given */
! 1174: return IRC_WHO_Mask(Client, NULL, only_ops);
! 1175: } /* IRC_WHO */
! 1176:
! 1177: /**
! 1178: * Handler for the IRC "WHOIS" command.
! 1179: *
! 1180: * @param Client The client from which this command has been received.
! 1181: * @param Req Request structure with prefix and all parameters.
! 1182: * @return CONNECTED or DISCONNECTED.
! 1183: */
! 1184: GLOBAL bool
! 1185: IRC_WHOIS( CLIENT *Client, REQUEST *Req )
! 1186: {
! 1187: CLIENT *from, *target, *c;
! 1188: unsigned int match_count = 0, found = 0;
! 1189: bool has_wildcards, is_remote;
! 1190: bool got_wildcard = false;
! 1191: char mask[COMMAND_LEN], *query;
! 1192:
! 1193: assert( Client != NULL );
! 1194: assert( Req != NULL );
! 1195:
! 1196: /* Wrong number of parameters? */
! 1197: if (Req->argc < 1)
! 1198: return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
! 1199: Client_ID(Client));
! 1200:
! 1201: _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
! 1202: _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
! 1203:
! 1204: /* Get target server for this command */
! 1205: if (Req->argc > 1) {
! 1206: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, Client)
! 1207: } else
! 1208: target = Client_ThisServer();
! 1209:
! 1210: assert(target != NULL);
! 1211:
! 1212: /* Forward? */
! 1213: if (target != Client_ThisServer()) {
! 1214: IRC_WriteStrClientPrefix(target, from, "WHOIS %s :%s",
! 1215: Req->argv[0], Req->argv[1]);
! 1216: return CONNECTED;
! 1217: }
! 1218:
! 1219: is_remote = Client_Conn(from) < 0;
! 1220: strlcpy(mask, Req->argv[Req->argc - 1], sizeof(mask));
! 1221: for (query = strtok(ngt_LowerStr(mask), ",");
! 1222: query && found < 3;
! 1223: query = strtok(NULL, ","), found++)
! 1224: {
! 1225: has_wildcards = query[strcspn(query, "*?")] != 0;
! 1226: /*
! 1227: * follows ircd 2.10 implementation:
! 1228: * - handle up to 3 targets
! 1229: * - no wildcards for remote clients
! 1230: * - only one wildcard target per local client
! 1231: *
! 1232: * Also, at most MAX_RPL_WHOIS matches are returned.
! 1233: */
! 1234: if (!has_wildcards || is_remote) {
! 1235: c = Client_Search(query);
! 1236: if (c && (Client_Type(c) == CLIENT_USER
! 1237: || Client_Type(c) == CLIENT_SERVICE)) {
! 1238: if (!IRC_WHOIS_SendReply(Client, from, c))
! 1239: return DISCONNECTED;
! 1240: } else {
! 1241: if (!IRC_WriteErrClient(Client,
! 1242: ERR_NOSUCHNICK_MSG,
! 1243: Client_ID(Client),
! 1244: query))
! 1245: return DISCONNECTED;
! 1246: }
! 1247: continue;
! 1248: }
! 1249: if (got_wildcard) {
! 1250: /* we already handled one wildcard query */
! 1251: if (!IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
! 1252: Client_ID(Client), query))
! 1253: return DISCONNECTED;
! 1254: continue;
! 1255: }
! 1256: got_wildcard = true;
! 1257: /* Increase penalty for wildcard queries */
! 1258: IRC_SetPenalty(Client, 3);
! 1259:
! 1260: for (c = Client_First(); c; c = Client_Next(c)) {
! 1261: if (IRC_CheckListTooBig(Client, match_count,
! 1262: MAX_RPL_WHOIS, "WHOIS"))
! 1263: break;
! 1264:
! 1265: if (Client_Type(c) != CLIENT_USER)
! 1266: continue;
! 1267: if (!MatchCaseInsensitive(query, Client_ID(c)))
! 1268: continue;
! 1269: if (!IRC_WHOIS_SendReply(Client, from, c))
! 1270: return DISCONNECTED;
! 1271:
! 1272: match_count++;
! 1273: }
! 1274:
! 1275: if (match_count == 0)
! 1276: IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
! 1277: Client_ID(Client),
! 1278: Req->argv[Req->argc - 1]);
! 1279: }
! 1280: return IRC_WriteStrClient(from, RPL_ENDOFWHOIS_MSG,
! 1281: Client_ID(from), Req->argv[Req->argc - 1]);
! 1282: } /* IRC_WHOIS */
! 1283:
! 1284: /**
! 1285: * Handler for the IRC "WHOWAS" command.
! 1286: *
! 1287: * @param Client The client from which this command has been received.
! 1288: * @param Req Request structure with prefix and all parameters.
! 1289: * @return CONNECTED or DISCONNECTED.
! 1290: */
! 1291: GLOBAL bool
! 1292: IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
! 1293: {
! 1294: CLIENT *target, *prefix;
! 1295: WHOWAS *whowas;
! 1296: char tok_buf[COMMAND_LEN];
! 1297: int max, last, count, i, nc;
! 1298: const char *nick;
! 1299:
! 1300: assert( Client != NULL );
! 1301: assert( Req != NULL );
! 1302:
! 1303: /* Wrong number of parameters? */
! 1304: if (Req->argc < 1)
! 1305: return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
! 1306: Client_ID(Client));
! 1307:
! 1308: _IRC_ARGC_LE_OR_RETURN_(Client, Req, 3)
! 1309: _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
! 1310: _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 2, prefix)
! 1311:
! 1312: /* Do not reveal any info on disconnected users? */
! 1313: if (Conf_MorePrivacy)
! 1314: return CONNECTED;
! 1315:
! 1316: /* Forward? */
! 1317: if (target != Client_ThisServer()) {
! 1318: IRC_WriteStrClientPrefix(target, prefix, "WHOWAS %s %s %s",
! 1319: Req->argv[0], Req->argv[1],
! 1320: Client_ID(target));
! 1321: return CONNECTED;
! 1322: }
! 1323:
! 1324: whowas = Client_GetWhowas( );
! 1325: last = Client_GetLastWhowasIndex( );
! 1326: if (last < 0)
! 1327: last = 0;
! 1328:
! 1329: max = DEF_RPL_WHOWAS;
! 1330: if (Req->argc > 1) {
! 1331: max = atoi(Req->argv[1]);
! 1332: if (max < 1)
! 1333: max = MAX_RPL_WHOWAS;
! 1334: }
! 1335:
! 1336: /*
! 1337: * Break up the nick argument into a list of nicks, if applicable
! 1338: * Can't modify Req->argv[0] because we need it for RPL_ENDOFWHOWAS_MSG.
! 1339: */
! 1340: strlcpy(tok_buf, Req->argv[0], sizeof(tok_buf));
! 1341: nick = strtok(tok_buf, ",");
! 1342:
! 1343: for (i=last, count=0; nick != NULL ; nick = strtok(NULL, ",")) {
! 1344: nc = 0;
! 1345: do {
! 1346: /* Used entry? */
! 1347: if (whowas[i].time > 0 && strcasecmp(nick, whowas[i].id) == 0) {
! 1348: if (!WHOWAS_EntryWrite(prefix, &whowas[i]))
! 1349: return DISCONNECTED;
! 1350: nc++;
! 1351: count++;
! 1352: }
! 1353: /* previous entry */
! 1354: i--;
! 1355:
! 1356: /* "underflow", wrap around */
! 1357: if (i < 0)
! 1358: i = MAX_WHOWAS - 1;
! 1359:
! 1360: if (nc && count >= max)
! 1361: break;
! 1362: } while (i != last);
! 1363:
! 1364: if (nc == 0 && !IRC_WriteErrClient(prefix, ERR_WASNOSUCHNICK_MSG,
! 1365: Client_ID(prefix), nick))
! 1366: return DISCONNECTED;
! 1367: }
! 1368: return IRC_WriteStrClient(prefix, RPL_ENDOFWHOWAS_MSG,
! 1369: Client_ID(prefix), Req->argv[0]);
! 1370: } /* IRC_WHOWAS */
! 1371:
! 1372: /**
! 1373: * Send LUSERS reply to a client.
! 1374: *
! 1375: * @param Client The receipient of the information.
! 1376: * @return CONNECTED or DISCONNECTED.
! 1377: */
! 1378: GLOBAL bool
! 1379: IRC_Send_LUSERS(CLIENT *Client)
! 1380: {
! 1381: unsigned long cnt;
! 1382: #ifndef STRICT_RFC
! 1383: unsigned long max;
! 1384: #endif
! 1385:
! 1386: assert(Client != NULL);
! 1387:
! 1388: /* Users, services and servers in the network */
! 1389: if (!IRC_WriteStrClient(Client, RPL_LUSERCLIENT_MSG, Client_ID(Client),
! 1390: Client_UserCount(), Client_ServiceCount(),
! 1391: Client_ServerCount()))
! 1392: return DISCONNECTED;
! 1393:
! 1394: /* Number of IRC operators */
! 1395: cnt = Client_OperCount( );
! 1396: if (cnt > 0) {
! 1397: if (!IRC_WriteStrClient(Client, RPL_LUSEROP_MSG,
! 1398: Client_ID(Client), cnt))
! 1399: return DISCONNECTED;
! 1400: }
! 1401:
! 1402: /* Unknown connections */
! 1403: cnt = Client_UnknownCount( );
! 1404: if (cnt > 0) {
! 1405: if (!IRC_WriteStrClient(Client, RPL_LUSERUNKNOWN_MSG,
! 1406: Client_ID(Client), cnt))
! 1407: return DISCONNECTED;
! 1408: }
! 1409:
! 1410: /* Number of created channels */
! 1411: if (!IRC_WriteStrClient(Client, RPL_LUSERCHANNELS_MSG,
! 1412: Client_ID(Client),
! 1413: Channel_CountVisible(Client)))
! 1414: return DISCONNECTED;
! 1415:
! 1416: /* Number of local users, services and servers */
! 1417: if (!IRC_WriteStrClient(Client, RPL_LUSERME_MSG, Client_ID(Client),
! 1418: Client_MyUserCount(), Client_MyServiceCount(),
! 1419: Client_MyServerCount()))
! 1420: return DISCONNECTED;
! 1421:
! 1422: #ifndef STRICT_RFC
! 1423: /* Maximum number of local users */
! 1424: cnt = Client_MyUserCount();
! 1425: max = Client_MyMaxUserCount();
! 1426: if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
! 1427: cnt, max, cnt, max))
! 1428: return DISCONNECTED;
! 1429: /* Maximum number of users in the network */
! 1430: cnt = Client_UserCount();
! 1431: max = Client_MaxUserCount();
! 1432: if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
! 1433: cnt, max, cnt, max))
! 1434: return DISCONNECTED;
! 1435: /* Connection counters */
! 1436: if (! IRC_WriteStrClient(Client, RPL_STATSCONN_MSG, Client_ID(Client),
! 1437: Conn_CountMax(), Conn_CountAccepted()))
! 1438: return DISCONNECTED;
! 1439: #endif
! 1440:
! 1441: return CONNECTED;
! 1442: } /* IRC_Send_LUSERS */
! 1443:
! 1444: GLOBAL bool
! 1445: IRC_Show_MOTD( CLIENT *Client )
! 1446: {
! 1447: const char *line;
! 1448: size_t len_tot, len_str;
! 1449:
! 1450: assert( Client != NULL );
! 1451:
! 1452: len_tot = array_bytes(&Conf_Motd);
! 1453: if (len_tot == 0 && !Conn_UsesSSL(Client_Conn(Client)))
! 1454: return IRC_WriteErrClient(Client, ERR_NOMOTD_MSG, Client_ID(Client));
! 1455:
! 1456: if (!IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG, Client_ID(Client),
! 1457: Client_ID(Client_ThisServer())))
! 1458: return DISCONNECTED;
! 1459:
! 1460: line = array_start(&Conf_Motd);
! 1461: while (len_tot > 0) {
! 1462: len_str = strlen(line) + 1;
! 1463:
! 1464: assert(len_tot >= len_str);
! 1465: len_tot -= len_str;
! 1466:
! 1467: if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID(Client), line))
! 1468: return DISCONNECTED;
! 1469: line += len_str;
! 1470: }
! 1471:
! 1472: if (!Show_MOTD_SSLInfo(Client))
! 1473: return DISCONNECTED;
! 1474:
! 1475: if (!IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG, Client_ID(Client)))
! 1476: return DISCONNECTED;
! 1477:
! 1478: if (*Conf_CloakHost)
! 1479: return IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
! 1480: Client_ID(Client),
! 1481: Client_Hostname(Client));
! 1482:
! 1483: return CONNECTED;
! 1484: } /* IRC_Show_MOTD */
! 1485:
! 1486: /**
! 1487: * Send NAMES reply for a specific client and channel.
! 1488: *
! 1489: * @param Client The client requesting the NAMES information.
! 1490: * @param Chan The channel
! 1491: * @return CONNECTED or DISCONNECTED.
! 1492: */
! 1493: GLOBAL bool
! 1494: IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
! 1495: {
! 1496: bool is_visible, is_member;
! 1497: char str[COMMAND_LEN];
! 1498: CL2CHAN *cl2chan;
! 1499: CLIENT *cl;
! 1500:
! 1501: assert(Client != NULL);
! 1502: assert(Chan != NULL);
! 1503:
! 1504: if (Channel_IsMemberOf(Chan, Client))
! 1505: is_member = true;
! 1506: else
! 1507: is_member = false;
! 1508:
! 1509: /* Do not print info on channel memberships to anyone that is not member? */
! 1510: if (Conf_MorePrivacy && !is_member)
! 1511: return CONNECTED;
! 1512:
! 1513: /* Secret channel? */
! 1514: if (!is_member && Channel_HasMode(Chan, 's'))
! 1515: return CONNECTED;
! 1516:
! 1517: snprintf(str, sizeof(str), RPL_NAMREPLY_MSG, Client_ID(Client), "=",
! 1518: Channel_Name(Chan));
! 1519: cl2chan = Channel_FirstMember(Chan);
! 1520: while (cl2chan) {
! 1521: cl = Channel_GetClient(cl2chan);
! 1522:
! 1523: if (Client_HasMode(cl, 'i'))
! 1524: is_visible = false;
! 1525: else
! 1526: is_visible = true;
! 1527:
! 1528: if (is_member || is_visible) {
! 1529: if (str[strlen(str) - 1] != ':')
! 1530: strlcat(str, " ", sizeof(str));
! 1531:
! 1532: who_flags_qualifier(Client, Channel_UserModes(Chan, cl),
! 1533: str, sizeof(str));
! 1534: strlcat(str, Client_ID(cl), sizeof(str));
! 1535:
! 1536: if (strlen(str) > (COMMAND_LEN - CLIENT_NICK_LEN - 4)) {
! 1537: if (!IRC_WriteStrClient(Client, "%s", str))
! 1538: return DISCONNECTED;
! 1539: snprintf(str, sizeof(str), RPL_NAMREPLY_MSG,
! 1540: Client_ID(Client), "=",
! 1541: Channel_Name(Chan));
! 1542: }
! 1543: }
! 1544:
! 1545: cl2chan = Channel_NextMember(Chan, cl2chan);
! 1546: }
! 1547: if (str[strlen(str) - 1] != ':') {
! 1548: if (!IRC_WriteStrClient(Client, "%s", str))
! 1549: return DISCONNECTED;
! 1550: }
! 1551:
! 1552: return CONNECTED;
! 1553: } /* IRC_Send_NAMES */
! 1554:
! 1555: /**
! 1556: * Send the ISUPPORT numeric (005).
! 1557: * This numeric indicates the features that are supported by this server.
! 1558: * See <http://www.irc.org/tech_docs/005.html> for details.
! 1559: */
! 1560: GLOBAL bool
! 1561: IRC_Send_ISUPPORT(CLIENT * Client)
! 1562: {
! 1563: if (Conf_Network[0] && !IRC_WriteStrClient(Client, RPL_ISUPPORTNET_MSG,
! 1564: Client_ID(Client),
! 1565: Conf_Network))
! 1566: return DISCONNECTED;
! 1567: if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
! 1568: CHANTYPES, CHANTYPES, Conf_MaxJoins))
! 1569: return DISCONNECTED;
! 1570: return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
! 1571: CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
! 1572: COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
! 1573: COMMAND_LEN - 113, MAX_HNDL_MODES_ARG,
! 1574: MAX_HNDL_CHANNEL_LISTS);
! 1575: } /* IRC_Send_ISUPPORT */
! 1576:
! 1577: /* -eof- */
CVSweb