2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
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.
26 #include "conn-func.h"
38 #include "irc-write.h"
45 IRC_ADMIN(CLIENT *Client, REQUEST *Req )
47 CLIENT *target, *prefix;
49 assert( Client != NULL );
50 assert( Req != NULL );
52 /* Falsche Anzahl Parameter? */
53 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
56 if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
57 else target = Client_ThisServer( );
59 /* Prefix ermitteln */
60 if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
62 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
64 /* An anderen Server weiterleiten? */
65 if( target != Client_ThisServer( ))
67 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
70 IRC_WriteStrClientPrefix( target, prefix, "ADMIN %s", Req->argv[0] );
74 /* mit Versionsinfo antworten */
75 if( ! IRC_WriteStrClient( Client, RPL_ADMINME_MSG, Client_ID( prefix ), Conf_ServerName )) return DISCONNECTED;
76 if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC1_MSG, Client_ID( prefix ), Conf_ServerAdmin1 )) return DISCONNECTED;
77 if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC2_MSG, Client_ID( prefix ), Conf_ServerAdmin2 )) return DISCONNECTED;
78 if( ! IRC_WriteStrClient( Client, RPL_ADMINEMAIL_MSG, Client_ID( prefix ), Conf_ServerAdminMail )) return DISCONNECTED;
80 IRC_SetPenalty( Client, 1 );
86 * Handler for the IRC command "INFO".
87 * See RFC 2812 section 3.4.10.
90 IRC_INFO(CLIENT * Client, REQUEST * Req)
92 CLIENT *target, *prefix;
95 assert(Client != NULL);
98 /* Wrong number of parameters? */
100 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
101 Client_ID(Client), Req->command);
103 /* Determine prefix */
104 if (Client_Type(Client) == CLIENT_SERVER)
105 prefix = Client_Search(Req->prefix);
109 return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
110 Client_ID(Client), Req->prefix);
112 /* Look for a target */
114 target = Client_Search(Req->argv[0]);
116 target = Client_ThisServer();
118 /* Make sure that the target is a server */
119 if (target && Client_Type(target) != CLIENT_SERVER)
120 target = Client_Introducer(target);
123 return IRC_WriteStrClient(prefix, ERR_NOSUCHSERVER_MSG,
124 Client_ID(prefix), Req->argv[0]);
126 /* Pass on to another server? */
127 if (target != Client_ThisServer()) {
128 IRC_WriteStrClientPrefix(target, prefix, "INFO %s",
133 if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix),
137 strlcpy(msg, "Server has been started ", sizeof(msg));
138 strlcat(msg, NGIRCd_StartStr, sizeof(msg));
139 if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
142 if (!IRC_WriteStrClient(Client, RPL_ENDOFINFO_MSG, Client_ID(prefix)))
145 IRC_SetPenalty(Client, 2);
151 IRC_ISON( CLIENT *Client, REQUEST *Req )
153 char rpl[COMMAND_LEN];
158 assert( Client != NULL );
159 assert( Req != NULL );
161 /* Falsche Anzahl Parameter? */
162 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
164 strlcpy( rpl, RPL_ISON_MSG, sizeof rpl );
165 for( i = 0; i < Req->argc; i++ )
167 ptr = strtok( Req->argv[i], " " );
171 c = Client_Search( ptr );
172 if( c && ( Client_Type( c ) == CLIENT_USER ))
174 /* Dieser Nick ist "online" */
175 strlcat( rpl, ptr, sizeof( rpl ));
176 strlcat( rpl, " ", sizeof( rpl ));
178 ptr = strtok( NULL, " " );
181 ngt_TrimLastChr(rpl, ' ');
183 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
188 IRC_LINKS( CLIENT *Client, REQUEST *Req )
190 CLIENT *target, *from, *c;
193 assert( Client != NULL );
194 assert( Req != NULL );
196 /* Falsche Anzahl Parameter? */
197 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
199 /* Server-Mask ermitteln */
200 if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
203 /* Absender ermitteln */
204 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
206 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
208 /* An anderen Server forwarden? */
211 target = Client_Search( Req->argv[0] );
212 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
213 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
216 /* Wer ist der Absender? */
217 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
218 else target = Client;
219 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
224 if( Client_Type( c ) == CLIENT_SERVER )
226 if( ! IRC_WriteStrClient( target, RPL_LINKS_MSG, Client_ID( target ), Client_ID( c ), Client_ID( Client_TopServer( c ) ? Client_TopServer( c ) : Client_ThisServer( )), Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
228 c = Client_Next( c );
231 IRC_SetPenalty( target, 1 );
232 return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
237 IRC_LUSERS( CLIENT *Client, REQUEST *Req )
239 CLIENT *target, *from;
241 assert( Client != NULL );
242 assert( Req != NULL );
244 /* Falsche Anzahl Parameter? */
245 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
247 /* Absender ermitteln */
248 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
250 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
252 /* An anderen Server forwarden? */
255 target = Client_Search( Req->argv[1] );
256 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
257 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
260 /* Wer ist der Absender? */
261 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
262 else target = Client;
263 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
265 IRC_Send_LUSERS( target );
267 IRC_SetPenalty( target, 1 );
273 * List registered services.
274 * This function is a dummy that immediately returns RPL_SERVLISTEND.
277 IRC_SERVLIST(CLIENT *Client, REQUEST *Req)
279 assert(Client != NULL);
283 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
284 Client_ID(Client), Req->command);
286 return IRC_WriteStrClient(Client, RPL_SERVLISTEND_MSG, Client_ID(Client),
287 Req->argc > 0 ? Req->argv[0] : "*",
288 Req->argc > 1 ? Req->argv[1] : "0");
293 IRC_MOTD( CLIENT *Client, REQUEST *Req )
295 CLIENT *from, *target;
297 assert( Client != NULL );
298 assert( Req != NULL );
300 /* Falsche Anzahl Parameter? */
301 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
303 /* From aus Prefix ermitteln */
304 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
306 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
310 /* an anderen Server forwarden */
311 target = Client_Search( Req->argv[0] );
312 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
314 if( target != Client_ThisServer( ))
316 /* Ok, anderer Server ist das Ziel: forwarden */
317 return IRC_WriteStrClientPrefix( target, from, "MOTD %s", Req->argv[0] );
321 IRC_SetPenalty( from, 3 );
322 return IRC_Show_MOTD( from );
327 IRC_NAMES( CLIENT *Client, REQUEST *Req )
329 char rpl[COMMAND_LEN], *ptr;
330 CLIENT *target, *from, *c;
333 assert( Client != NULL );
334 assert( Req != NULL );
336 /* Falsche Anzahl Parameter? */
337 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
339 /* From aus Prefix ermitteln */
340 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
342 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
346 /* an anderen Server forwarden */
347 target = Client_Search( Req->argv[1] );
348 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
350 if( target != Client_ThisServer( ))
352 /* Ok, anderer Server ist das Ziel: forwarden */
353 return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
359 /* bestimmte Channels durchgehen */
360 ptr = strtok( Req->argv[0], "," );
363 chan = Channel_Search( ptr );
367 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
369 if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
371 /* naechsten Namen ermitteln */
372 ptr = strtok( NULL, "," );
377 /* alle Channels durchgehen */
378 chan = Channel_First( );
382 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
384 /* naechster Channel */
385 chan = Channel_Next( chan );
388 /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
390 snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
393 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
395 /* Okay, das ist ein User: anhaengen */
396 if( rpl[strlen( rpl ) - 1] != ':' ) strlcat( rpl, " ", sizeof( rpl ));
397 strlcat( rpl, Client_ID( c ), sizeof( rpl ));
399 if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
401 /* Zeile wird zu lang: senden! */
402 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
403 snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
407 /* naechster Client */
408 c = Client_Next( c );
410 if( rpl[strlen( rpl ) - 1] != ':')
412 /* es wurden User gefunden */
413 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
416 IRC_SetPenalty( from, 1 );
417 return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
422 t_diff(time_t *t, const time_t div)
436 uptime_days(time_t *now)
438 return t_diff(now, 60 * 60 * 24);
443 uptime_hrs(time_t *now)
445 return t_diff(now, 60 * 60);
450 uptime_mins(time_t *now)
452 return t_diff(now, 60);
457 IRC_STATS( CLIENT *Client, REQUEST *Req )
459 CLIENT *from, *target, *cl;
464 unsigned int days, hrs, mins;
466 assert( Client != NULL );
467 assert( Req != NULL );
469 /* Falsche Anzahl Parameter? */
471 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
473 /* From aus Prefix ermitteln */
474 if (Client_Type(Client) == CLIENT_SERVER)
475 from = Client_Search(Req->prefix);
480 return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix);
482 if (Req->argc == 2) {
483 /* an anderen Server forwarden */
484 target = Client_Search( Req->argv[1] );
485 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
486 return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
488 if( target != Client_ThisServer()) {
489 /* Ok, anderer Server ist das Ziel: forwarden */
490 return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] );
495 query = Req->argv[0][0] ? Req->argv[0][0] : '*';
500 case 'l': /* Links */
502 time_now = time(NULL);
503 for (con = Conn_First(); con != NONE ;con = Conn_Next(con)) {
504 cl = Conn_GetClient(con);
507 if ((Client_Type(cl) == CLIENT_SERVER) || (cl == Client)) {
508 /* Server link or our own connection */
510 if (Conn_Options(con) & CONN_ZIP) {
511 if (!IRC_WriteStrClient(from, RPL_STATSLINKINFOZIP_MSG,
512 Client_ID(from), Client_Mask(cl), Conn_SendQ(con),
513 Conn_SendMsg(con), Zip_SendBytes(con), Conn_SendBytes(con),
514 Conn_RecvMsg(con), Zip_RecvBytes(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
519 if (!IRC_WriteStrClient(from, RPL_STATSLINKINFO_MSG, Client_ID(from),
520 Client_Mask(cl), Conn_SendQ(con), Conn_SendMsg(con), Conn_SendBytes(con),
521 Conn_RecvMsg(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
526 case 'm': /* IRC-Commands */
528 cmd = Parse_GetCommandStruct( );
529 for (; cmd->name ; cmd++) {
530 if (cmd->lcount == 0 && cmd->rcount == 0)
532 if (!IRC_WriteStrClient(from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
533 cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
537 case 'u': /* server uptime */
539 time_now = time(NULL) - NGIRCd_Start;
540 days = uptime_days(&time_now);
541 hrs = uptime_hrs(&time_now);
542 mins = uptime_mins(&time_now);
543 if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
544 days, hrs, mins, (unsigned int) time_now))
549 IRC_SetPenalty(from, 2);
550 return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, Client_ID(from), query);
555 * Handler for the IRC command "SUMMON".
556 * See RFC 2812 section 4.5. ngIRCd doesn't implement this functionality and
557 * therefore answers with ERR_SUMMONDISABLED.
560 IRC_SUMMON(CLIENT * Client, REQUEST * Req)
562 return IRC_WriteStrClient(Client, ERR_SUMMONDISABLED_MSG,
563 Client_ID(Client), Req->command);
568 IRC_TIME( CLIENT *Client, REQUEST *Req )
570 CLIENT *from, *target;
574 assert( Client != NULL );
575 assert( Req != NULL );
577 /* Falsche Anzahl Parameter? */
578 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
580 /* From aus Prefix ermitteln */
581 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
583 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
587 /* an anderen Server forwarden */
588 target = Client_Search( Req->argv[0] );
589 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
591 if( target != Client_ThisServer( ))
593 /* Ok, anderer Server ist das Ziel: forwarden */
594 return IRC_WriteStrClientPrefix( target, from, "TIME %s", Req->argv[0] );
599 (void)strftime( t_str, 60, "%A %B %d %Y -- %H:%M %Z", localtime( &t ));
600 return IRC_WriteStrClient( from, RPL_TIME_MSG, Client_ID( from ), Client_ID( Client_ThisServer( )), t_str );
605 IRC_USERHOST( CLIENT *Client, REQUEST *Req )
607 char rpl[COMMAND_LEN];
611 assert( Client != NULL );
612 assert( Req != NULL );
614 /* Falsche Anzahl Parameter? */
615 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
617 if( Req->argc > 5 ) max = 5;
618 else max = Req->argc;
620 strlcpy( rpl, RPL_USERHOST_MSG, sizeof rpl );
621 for( i = 0; i < max; i++ )
623 c = Client_Search( Req->argv[i] );
624 if( c && ( Client_Type( c ) == CLIENT_USER ))
626 /* Dieser Nick ist "online" */
627 strlcat( rpl, Client_ID( c ), sizeof( rpl ));
628 if( Client_HasMode( c, 'o' )) strlcat( rpl, "*", sizeof( rpl ));
629 strlcat( rpl, "=", sizeof( rpl ));
630 if( Client_HasMode( c, 'a' )) strlcat( rpl, "-", sizeof( rpl ));
631 else strlcat( rpl, "+", sizeof( rpl ));
632 strlcat( rpl, Client_User( c ), sizeof( rpl ));
633 strlcat( rpl, "@", sizeof( rpl ));
634 strlcat( rpl, Client_Hostname( c ), sizeof( rpl ));
635 strlcat( rpl, " ", sizeof( rpl ));
638 ngt_TrimLastChr( rpl, ' ');
640 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
645 * Handler for the IRC command "USERS".
646 * See RFC 2812 section 4.6. As suggested there the command is disabled.
649 IRC_USERS(CLIENT * Client, REQUEST * Req)
651 return IRC_WriteStrClient(Client, ERR_USERSDISABLED_MSG,
652 Client_ID(Client), Req->command);
657 IRC_VERSION( CLIENT *Client, REQUEST *Req )
659 CLIENT *target, *prefix;
661 assert( Client != NULL );
662 assert( Req != NULL );
664 /* Falsche Anzahl Parameter? */
665 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
668 if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
669 else target = Client_ThisServer( );
671 /* Prefix ermitteln */
672 if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
673 else prefix = Client;
674 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
676 /* An anderen Server weiterleiten? */
677 if( target != Client_ThisServer( ))
679 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
682 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
686 /* send version information */
687 IRC_SetPenalty(Client, 1);
688 return IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
689 PACKAGE_NAME, PACKAGE_VERSION,
690 NGIRCd_DebugLevel, Conf_ServerName,
691 NGIRCd_VersionAddition);
696 write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
698 return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client), channelname,
699 Client_User(c), Client_Hostname(c), Client_ID(Client_Introducer(c)), Client_ID(c),
700 flags, Client_Hops(c), Client_Info(c));
705 who_flags_status(const char *client_modes)
707 if (strchr(client_modes, 'a'))
708 return "G"; /* away */
714 who_flags_qualifier(const char *chan_user_modes)
716 if (strchr(chan_user_modes, 'o'))
718 else if (strchr(chan_user_modes, 'v'))
725 IRC_Send_WHO(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
727 bool is_visible, is_member, is_ircop;
729 const char *client_modes;
730 const char *chan_user_modes;
734 assert( Client != NULL );
735 assert( Chan != NULL );
737 is_member = Channel_IsMemberOf(Chan, Client);
739 /* Secret channel? */
740 if (!is_member && strchr(Channel_Modes(Chan), 's'))
741 return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
743 cl2chan = Channel_FirstMember(Chan);
744 for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
745 c = Channel_GetClient(cl2chan);
747 client_modes = Client_Modes(c);
748 is_ircop = strchr(client_modes, 'o') != NULL;
749 if (OnlyOps && !is_ircop)
752 is_visible = strchr(client_modes, 'i') == NULL;
753 if (is_member || is_visible) {
754 strcpy(flags, who_flags_status(client_modes));
756 strlcat(flags, "*", sizeof(flags));
758 chan_user_modes = Channel_UserModes(Chan, c);
759 strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
761 if (!write_whoreply(Client, c, Channel_Name(Chan), flags))
765 return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
771 MatchCaseInsensitive(const char *pattern, const char *searchme)
773 char haystack[COMMAND_LEN];
775 strlcpy(haystack, searchme, sizeof(haystack));
777 ngt_LowerStr(haystack);
779 return Match(pattern, haystack);
784 IRC_WHO( CLIENT *Client, REQUEST *Req )
786 bool only_ops, have_arg, client_match;
787 const char *channelname, *client_modes, *chan_user_modes;
788 char pattern[COMMAND_LEN];
794 assert( Client != NULL );
795 assert( Req != NULL );
798 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
803 if (Req->argc == 2) {
804 if (strcmp(Req->argv[1], "o") == 0)
807 else return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
811 IRC_SetPenalty(Client, 1);
812 if (Req->argc >= 1) { /* Channel or Mask. */
813 chan = Channel_Search(Req->argv[0]);
815 return IRC_Send_WHO(Client, chan, only_ops);
816 if (strcmp(Req->argv[0], "0") != 0) { /* RFC stupidity, same as no arguments */
818 strlcpy(pattern, Req->argv[0], sizeof(pattern));
819 ngt_LowerStr(pattern);
820 IRC_SetPenalty(Client, 3);
824 for (c = Client_First(); c != NULL; c = Client_Next(c)) {
825 if (Client_Type(c) != CLIENT_USER)
829 * In the absence of the parameter, all visible (users who aren't
830 * invisible (user mode +i) and who don't have a common channel
831 * with the requesting client) are listed.
833 * The same result can be achieved by using a [sic] of "0"
834 * or any wildcard which will end up matching every visible user.
836 * The [sic] passed to WHO is matched against users' host, server, real name and
837 * nickname if the channel cannot be found.
839 client_modes = Client_Modes(c);
840 if (strchr(client_modes, 'i'))
843 if (only_ops && !strchr(client_modes, 'o'))
846 if (have_arg) { /* match pattern against user host/server/name/nick */
847 client_match = MatchCaseInsensitive(pattern, Client_Hostname(c)); /* user's host */
849 client_match = MatchCaseInsensitive(pattern, Client_ID(Client_Introducer(c))); /* server */
851 client_match = Match(Req->argv[0], Client_Info(c)); /* realname */
853 client_match = MatchCaseInsensitive(pattern, Client_ID(c)); /* nick name */
855 if (!client_match) /* This isn't the client you're looking for */
859 strcpy(flags, who_flags_status(client_modes));
861 if (strchr(client_modes, 'o')) /* this client is an operator */
862 strlcat(flags, "*", sizeof(flags));
864 /* Search suitable channel */
865 cl2chan = Channel_FirstChannelOf(c);
867 cn = Channel_GetChannel(cl2chan);
868 if (Channel_IsMemberOf(cn, Client) ||
869 !strchr(Channel_Modes(cn), 's'))
871 channelname = Channel_Name(cn);
874 cl2chan = Channel_NextChannelOf(c, cl2chan);
877 chan = Channel_GetChannel(cl2chan);
878 chan_user_modes = Channel_UserModes(chan, c);
879 strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
883 if (!write_whoreply(Client, c, channelname, flags))
888 channelname = Req->argv[0];
892 return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), channelname);
897 IRC_WHOIS( CLIENT *Client, REQUEST *Req )
899 CLIENT *from, *target, *c;
900 char str[LINE_LEN + 1];
904 assert( Client != NULL );
905 assert( Req != NULL );
907 /* Bad number of parameters? */
908 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
911 c = Client_Search( Req->argv[Req->argc - 1] );
912 if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
914 /* Search sender of the WHOIS */
915 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
917 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
919 /* Forward to other server? */
922 /* Search target server (can be specified as nick of that server!) */
923 target = Client_Search( Req->argv[0] );
924 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
926 else target = Client_ThisServer( );
928 assert( target != NULL );
930 if(( Client_NextHop( target ) != Client_ThisServer( )) && ( Client_Type( Client_NextHop( target )) == CLIENT_SERVER )) return IRC_WriteStrClientPrefix( target, from, "WHOIS %s :%s", Req->argv[0], Req->argv[1] );
932 /* Nick, user and name */
933 if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
936 if( ! IRC_WriteStrClient( from, RPL_WHOISSERVER_MSG, Client_ID( from ), Client_ID( c ), Client_ID( Client_Introducer( c )), Client_Info( Client_Introducer( c )))) return DISCONNECTED;
939 snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
940 cl2chan = Channel_FirstChannelOf( c );
943 chan = Channel_GetChannel( cl2chan );
944 assert( chan != NULL );
947 cl2chan = Channel_NextChannelOf( c, cl2chan );
949 /* Secret channel? */
950 if( strchr( Channel_Modes( chan ), 's' ) && ! Channel_IsMemberOf( chan, Client )) continue;
952 /* Concatenate channel names */
953 if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
954 if( strchr( Channel_UserModes( chan, c ), 'o' )) strlcat( str, "@", sizeof( str ));
955 else if( strchr( Channel_UserModes( chan, c ), 'v' )) strlcat( str, "+", sizeof( str ));
956 strlcat( str, Channel_Name( chan ), sizeof( str ));
958 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
960 /* Line becomes too long: send it! */
961 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
962 snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
965 if( str[strlen( str ) - 1] != ':')
967 /* There is data left to send: */
968 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
972 if( Client_HasMode( c, 'o' ))
974 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
977 /* Idle and signon time (local clients only!) */
978 if (Client_Conn(c) > NONE ) {
979 if (! IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
980 Client_ID(from), Client_ID(c),
981 (unsigned long)Conn_GetIdle(Client_Conn(c)),
982 (unsigned long)Conn_GetSignon(Client_Conn(c))))
987 if( Client_HasMode( c, 'a' ))
989 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
993 return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
998 WHOWAS_EntryWrite(CLIENT *prefix, WHOWAS *entry)
1002 (void)strftime(t_str, sizeof(t_str), "%a %b %d %H:%M:%S %Y",
1003 localtime(&entry->time));
1005 if (!IRC_WriteStrClient(prefix, RPL_WHOWASUSER_MSG, Client_ID(prefix),
1006 entry->id, entry->user, entry->host, entry->info))
1007 return DISCONNECTED;
1009 return IRC_WriteStrClient(prefix, RPL_WHOISSERVER_MSG, Client_ID(prefix),
1010 entry->id, entry->server, t_str);
1014 * IRC "WHOWAS" function.
1015 * This function implements the IRC command "WHOWHAS". It handles local
1016 * requests and request that should be forwarded to other servers.
1019 IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
1021 CLIENT *target, *prefix;
1023 char tok_buf[COMMAND_LEN];
1024 int max, last, count, i, nc;
1027 assert( Client != NULL );
1028 assert( Req != NULL );
1030 /* Wrong number of parameters? */
1032 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
1033 Client_ID(Client), Req->command);
1035 return IRC_WriteStrClient(Client, ERR_NONICKNAMEGIVEN_MSG, Client_ID(Client));
1039 target = Client_Search(Req->argv[2]);
1041 target = Client_ThisServer();
1044 if (Client_Type(Client) == CLIENT_SERVER)
1045 prefix = Client_Search(Req->prefix);
1050 return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
1051 Client_ID(Client), Req->prefix);
1053 /* Forward to other server? */
1054 if (target != Client_ThisServer()) {
1055 if (!target || (Client_Type(target) != CLIENT_SERVER))
1056 return IRC_WriteStrClient(prefix, ERR_NOSUCHSERVER_MSG,
1057 Client_ID(prefix), Req->argv[2]);
1060 IRC_WriteStrClientPrefix( target, prefix, "WHOWAS %s %s %s",
1061 Req->argv[0], Req->argv[1],
1066 whowas = Client_GetWhowas( );
1067 last = Client_GetLastWhowasIndex( );
1071 max = DEFAULT_WHOWAS;
1072 if (Req->argc > 1) {
1073 max = atoi(Req->argv[1]);
1079 * Break up the nick argument into a list of nicks, if applicable
1080 * Can't modify Req->argv[0] because we need it for RPL_ENDOFWHOWAS_MSG.
1082 strlcpy(tok_buf, Req->argv[0], sizeof(tok_buf));
1083 nick = strtok(tok_buf, ",");
1085 for (i=last, count=0; nick != NULL ; nick = strtok(NULL, ",")) {
1089 if (whowas[i].time > 0 && strcasecmp(nick, whowas[i].id) == 0) {
1090 if (!WHOWAS_EntryWrite(prefix, &whowas[i]))
1091 return DISCONNECTED;
1095 /* previous entry */
1098 /* "underflow", wrap around */
1102 if (nc && count >= max)
1104 } while (i != last);
1106 if (nc == 0 && !IRC_WriteStrClient(prefix, ERR_WASNOSUCHNICK_MSG,
1107 Client_ID(prefix), nick))
1108 return DISCONNECTED;
1110 return IRC_WriteStrClient(prefix, RPL_ENDOFWHOWAS_MSG, Client_ID(prefix), Req->argv[0]);
1115 IRC_Send_LUSERS( CLIENT *Client )
1122 assert( Client != NULL );
1124 /* Users, services and serevers in the network */
1125 if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
1127 /* Number of IRC operators */
1128 cnt = Client_OperCount( );
1131 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
1134 /* Unknown connections */
1135 cnt = Client_UnknownCount( );
1138 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
1141 /* Number of created channels */
1142 if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
1144 /* Number of local users, services and servers */
1145 if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
1148 /* Maximum number of local users */
1149 cnt = Client_MyUserCount();
1150 max = Client_MyMaxUserCount();
1151 if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
1152 cnt, max, cnt, max))
1153 return DISCONNECTED;
1154 /* Maximum number of users in the network */
1155 cnt = Client_UserCount();
1156 max = Client_MaxUserCount();
1157 if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
1158 cnt, max, cnt, max))
1159 return DISCONNECTED;
1163 } /* IRC_Send_LUSERS */
1167 Show_MOTD_Start(CLIENT *Client)
1169 return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
1170 Client_ID( Client ), Client_ID( Client_ThisServer( )));
1174 Show_MOTD_Sendline(CLIENT *Client, const char *msg)
1176 return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
1180 Show_MOTD_End(CLIENT *Client)
1182 return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
1187 IRC_Show_MOTD( CLIENT *Client )
1192 assert( Client != NULL );
1194 if (Conf_MotdPhrase[0]) {
1195 if (!Show_MOTD_Start(Client))
1196 return DISCONNECTED;
1197 if (!Show_MOTD_Sendline(Client, Conf_MotdPhrase))
1198 return DISCONNECTED;
1200 return Show_MOTD_End(Client);
1203 fd = fopen( Conf_MotdFile, "r" );
1205 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
1206 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
1209 if (!Show_MOTD_Start( Client )) {
1214 while (fgets( line, (int)sizeof line, fd )) {
1215 ngt_TrimLastChr( line, '\n');
1217 if( ! Show_MOTD_Sendline( Client, line)) {
1223 return Show_MOTD_End(Client);
1224 } /* IRC_Show_MOTD */
1228 IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
1230 bool is_visible, is_member;
1231 char str[LINE_LEN + 1];
1235 assert( Client != NULL );
1236 assert( Chan != NULL );
1238 if( Channel_IsMemberOf( Chan, Client )) is_member = true;
1239 else is_member = false;
1241 /* Secret channel? */
1242 if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
1244 /* Alle Mitglieder suchen */
1245 snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1246 cl2chan = Channel_FirstMember( Chan );
1249 cl = Channel_GetClient( cl2chan );
1251 if( strchr( Client_Modes( cl ), 'i' )) is_visible = false;
1252 else is_visible = true;
1254 if( is_member || is_visible )
1256 /* Nick anhaengen */
1257 if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
1258 if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
1259 else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
1260 strlcat( str, Client_ID( cl ), sizeof( str ));
1262 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
1264 /* Zeile wird zu lang: senden! */
1265 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
1266 snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1270 /* naechstes Mitglied suchen */
1271 cl2chan = Channel_NextMember( Chan, cl2chan );
1273 if( str[strlen( str ) - 1] != ':')
1275 /* Es sind noch Daten da, die gesendet werden muessen */
1276 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
1280 } /* IRC_Send_NAMES */
1285 * Send the ISUPPORT numeric (005).
1286 * This numeric indicates the features that are supported by this server.
1287 * See <http://www.irc.org/tech_docs/005.html> for details.
1290 IRC_Send_ISUPPORT PARAMS((CLIENT * Client))
1292 if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
1294 return DISCONNECTED;
1295 return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
1296 CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
1297 COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
1299 } /* IRC_Send_ISUPPORT */