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 IRC_MOTD( CLIENT *Client, REQUEST *Req )
275 CLIENT *from, *target;
277 assert( Client != NULL );
278 assert( Req != NULL );
280 /* Falsche Anzahl Parameter? */
281 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
283 /* From aus Prefix ermitteln */
284 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
286 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
290 /* an anderen Server forwarden */
291 target = Client_Search( Req->argv[0] );
292 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
294 if( target != Client_ThisServer( ))
296 /* Ok, anderer Server ist das Ziel: forwarden */
297 return IRC_WriteStrClientPrefix( target, from, "MOTD %s", Req->argv[0] );
301 IRC_SetPenalty( from, 3 );
302 return IRC_Show_MOTD( from );
307 IRC_NAMES( CLIENT *Client, REQUEST *Req )
309 char rpl[COMMAND_LEN], *ptr;
310 CLIENT *target, *from, *c;
313 assert( Client != NULL );
314 assert( Req != NULL );
316 /* Falsche Anzahl Parameter? */
317 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
319 /* From aus Prefix ermitteln */
320 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
322 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
326 /* an anderen Server forwarden */
327 target = Client_Search( Req->argv[1] );
328 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
330 if( target != Client_ThisServer( ))
332 /* Ok, anderer Server ist das Ziel: forwarden */
333 return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
339 /* bestimmte Channels durchgehen */
340 ptr = strtok( Req->argv[0], "," );
343 chan = Channel_Search( ptr );
347 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
349 if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
351 /* naechsten Namen ermitteln */
352 ptr = strtok( NULL, "," );
357 /* alle Channels durchgehen */
358 chan = Channel_First( );
362 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
364 /* naechster Channel */
365 chan = Channel_Next( chan );
368 /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
370 snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
373 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
375 /* Okay, das ist ein User: anhaengen */
376 if( rpl[strlen( rpl ) - 1] != ':' ) strlcat( rpl, " ", sizeof( rpl ));
377 strlcat( rpl, Client_ID( c ), sizeof( rpl ));
379 if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
381 /* Zeile wird zu lang: senden! */
382 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
383 snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
387 /* naechster Client */
388 c = Client_Next( c );
390 if( rpl[strlen( rpl ) - 1] != ':')
392 /* es wurden User gefunden */
393 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
396 IRC_SetPenalty( from, 1 );
397 return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
402 t_diff(time_t *t, const time_t div)
416 uptime_days(time_t *now)
418 return t_diff(now, 60 * 60 * 24);
423 uptime_hrs(time_t *now)
425 return t_diff(now, 60 * 60);
430 uptime_mins(time_t *now)
432 return t_diff(now, 60);
437 IRC_STATS( CLIENT *Client, REQUEST *Req )
439 CLIENT *from, *target, *cl;
444 unsigned int days, hrs, mins;
446 assert( Client != NULL );
447 assert( Req != NULL );
449 /* Falsche Anzahl Parameter? */
451 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
453 /* From aus Prefix ermitteln */
454 if (Client_Type(Client) == CLIENT_SERVER)
455 from = Client_Search(Req->prefix);
460 return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix);
462 if (Req->argc == 2) {
463 /* an anderen Server forwarden */
464 target = Client_Search( Req->argv[1] );
465 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
466 return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
468 if( target != Client_ThisServer()) {
469 /* Ok, anderer Server ist das Ziel: forwarden */
470 return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] );
475 query = Req->argv[0][0] ? Req->argv[0][0] : '*';
480 case 'l': /* Links */
482 time_now = time(NULL);
483 for (con = Conn_First(); con != NONE ;con = Conn_Next(con)) {
484 cl = Conn_GetClient(con);
487 if ((Client_Type(cl) == CLIENT_SERVER) || (cl == Client)) {
488 /* Server link or our own connection */
490 if (Conn_Options(con) & CONN_ZIP) {
491 if (!IRC_WriteStrClient(from, RPL_STATSLINKINFOZIP_MSG,
492 Client_ID(from), Client_Mask(cl), Conn_SendQ(con),
493 Conn_SendMsg(con), Zip_SendBytes(con), Conn_SendBytes(con),
494 Conn_RecvMsg(con), Zip_RecvBytes(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
499 if (!IRC_WriteStrClient(from, RPL_STATSLINKINFO_MSG, Client_ID(from),
500 Client_Mask(cl), Conn_SendQ(con), Conn_SendMsg(con), Conn_SendBytes(con),
501 Conn_RecvMsg(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
506 case 'm': /* IRC-Commands */
508 cmd = Parse_GetCommandStruct( );
509 for (; cmd->name ; cmd++) {
510 if (cmd->lcount == 0 && cmd->rcount == 0)
512 if (!IRC_WriteStrClient(from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
513 cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
517 case 'u': /* server uptime */
519 time_now = time(NULL) - NGIRCd_Start;
520 days = uptime_days(&time_now);
521 hrs = uptime_hrs(&time_now);
522 mins = uptime_mins(&time_now);
523 if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
524 days, hrs, mins, (unsigned int) time_now))
529 IRC_SetPenalty(from, 2);
530 return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, Client_ID(from), query);
535 * Handler for the IRC command "SUMMON".
536 * See RFC 2812 section 4.5. ngIRCd doesn't implement this functionality and
537 * therefore answers with ERR_SUMMONDISABLED.
540 IRC_SUMMON(CLIENT * Client, REQUEST * Req)
542 return IRC_WriteStrClient(Client, ERR_SUMMONDISABLED_MSG,
543 Client_ID(Client), Req->command);
548 IRC_TIME( CLIENT *Client, REQUEST *Req )
550 CLIENT *from, *target;
554 assert( Client != NULL );
555 assert( Req != NULL );
557 /* Falsche Anzahl Parameter? */
558 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
560 /* From aus Prefix ermitteln */
561 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
563 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
567 /* an anderen Server forwarden */
568 target = Client_Search( Req->argv[0] );
569 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
571 if( target != Client_ThisServer( ))
573 /* Ok, anderer Server ist das Ziel: forwarden */
574 return IRC_WriteStrClientPrefix( target, from, "TIME %s", Req->argv[0] );
579 (void)strftime( t_str, 60, "%A %B %d %Y -- %H:%M %Z", localtime( &t ));
580 return IRC_WriteStrClient( from, RPL_TIME_MSG, Client_ID( from ), Client_ID( Client_ThisServer( )), t_str );
585 IRC_USERHOST( CLIENT *Client, REQUEST *Req )
587 char rpl[COMMAND_LEN];
591 assert( Client != NULL );
592 assert( Req != NULL );
594 /* Falsche Anzahl Parameter? */
595 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
597 if( Req->argc > 5 ) max = 5;
598 else max = Req->argc;
600 strlcpy( rpl, RPL_USERHOST_MSG, sizeof rpl );
601 for( i = 0; i < max; i++ )
603 c = Client_Search( Req->argv[i] );
604 if( c && ( Client_Type( c ) == CLIENT_USER ))
606 /* Dieser Nick ist "online" */
607 strlcat( rpl, Client_ID( c ), sizeof( rpl ));
608 if( Client_HasMode( c, 'o' )) strlcat( rpl, "*", sizeof( rpl ));
609 strlcat( rpl, "=", sizeof( rpl ));
610 if( Client_HasMode( c, 'a' )) strlcat( rpl, "-", sizeof( rpl ));
611 else strlcat( rpl, "+", sizeof( rpl ));
612 strlcat( rpl, Client_User( c ), sizeof( rpl ));
613 strlcat( rpl, "@", sizeof( rpl ));
614 strlcat( rpl, Client_Hostname( c ), sizeof( rpl ));
615 strlcat( rpl, " ", sizeof( rpl ));
618 ngt_TrimLastChr( rpl, ' ');
620 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
625 * Handler for the IRC command "USERS".
626 * See RFC 2812 section 4.6. As suggested there the command is disabled.
629 IRC_USERS(CLIENT * Client, REQUEST * Req)
631 return IRC_WriteStrClient(Client, ERR_USERSDISABLED_MSG,
632 Client_ID(Client), Req->command);
637 IRC_VERSION( CLIENT *Client, REQUEST *Req )
639 CLIENT *target, *prefix;
641 assert( Client != NULL );
642 assert( Req != NULL );
644 /* Falsche Anzahl Parameter? */
645 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
648 if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
649 else target = Client_ThisServer( );
651 /* Prefix ermitteln */
652 if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
653 else prefix = Client;
654 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
656 /* An anderen Server weiterleiten? */
657 if( target != Client_ThisServer( ))
659 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
662 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
666 /* send version information */
667 IRC_SetPenalty(Client, 1);
668 return IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
669 PACKAGE_NAME, PACKAGE_VERSION,
670 NGIRCd_DebugLevel, Conf_ServerName,
671 NGIRCd_VersionAddition);
676 write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
678 return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client), channelname,
679 Client_User(c), Client_Hostname(c), Client_ID(Client_Introducer(c)), Client_ID(c),
680 flags, Client_Hops(c), Client_Info(c));
685 who_flags_status(const char *client_modes)
687 if (strchr(client_modes, 'a'))
688 return "G"; /* away */
694 who_flags_qualifier(const char *chan_user_modes)
696 if (strchr(chan_user_modes, 'o'))
698 else if (strchr(chan_user_modes, 'v'))
705 IRC_Send_WHO(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
707 bool is_visible, is_member, is_ircop;
709 const char *client_modes;
710 const char *chan_user_modes;
714 assert( Client != NULL );
715 assert( Chan != NULL );
717 is_member = Channel_IsMemberOf(Chan, Client);
719 /* Secret channel? */
720 if (!is_member && strchr(Channel_Modes(Chan), 's'))
723 cl2chan = Channel_FirstMember(Chan);
724 for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
725 c = Channel_GetClient(cl2chan);
727 client_modes = Client_Modes(c);
728 is_ircop = strchr(client_modes, 'o') != NULL;
729 if (OnlyOps && !is_ircop)
732 is_visible = strchr(client_modes, 'i') == NULL;
733 if (is_member || is_visible) {
734 strcpy(flags, who_flags_status(client_modes));
736 strlcat(flags, "*", sizeof(flags));
738 chan_user_modes = Channel_UserModes(Chan, c);
739 strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
741 if (!write_whoreply(Client, c, Channel_Name(Chan), flags))
745 return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
751 MatchCaseInsensitive(const char *pattern, const char *searchme)
753 char haystack[COMMAND_LEN];
755 strlcpy(haystack, searchme, sizeof(haystack));
757 ngt_LowerStr(haystack);
759 return Match(pattern, haystack);
764 IRC_WHO( CLIENT *Client, REQUEST *Req )
766 bool only_ops, have_arg, client_match;
767 const char *channelname, *client_modes, *chan_user_modes;
768 char pattern[COMMAND_LEN];
774 assert( Client != NULL );
775 assert( Req != NULL );
778 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
783 if (Req->argc == 2) {
784 if (strcmp(Req->argv[1], "o") == 0)
787 else return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
791 IRC_SetPenalty(Client, 1);
792 if (Req->argc >= 1) { /* Channel or Mask. */
793 chan = Channel_Search(Req->argv[0]);
795 return IRC_Send_WHO(Client, chan, only_ops);
796 if (strcmp(Req->argv[0], "0") != 0) { /* RFC stupidity, same as no arguments */
798 strlcpy(pattern, Req->argv[0], sizeof(pattern));
799 ngt_LowerStr(pattern);
800 IRC_SetPenalty(Client, 3);
804 for (c = Client_First(); c != NULL; c = Client_Next(c)) {
805 if (Client_Type(c) != CLIENT_USER)
809 * In the absence of the parameter, all visible (users who aren't
810 * invisible (user mode +i) and who don't have a common channel
811 * with the requesting client) are listed.
813 * The same result can be achieved by using a [sic] of "0"
814 * or any wildcard which will end up matching every visible user.
816 * The [sic] passed to WHO is matched against users' host, server, real name and
817 * nickname if the channel cannot be found.
819 client_modes = Client_Modes(c);
820 if (strchr(client_modes, 'i'))
823 if (only_ops && !strchr(client_modes, 'o'))
826 if (have_arg) { /* match pattern against user host/server/name/nick */
827 client_match = MatchCaseInsensitive(pattern, Client_Hostname(c)); /* user's host */
829 client_match = MatchCaseInsensitive(pattern, Client_ID(Client_Introducer(c))); /* server */
831 client_match = Match(Req->argv[0], Client_Info(c)); /* realname */
833 client_match = MatchCaseInsensitive(pattern, Client_ID(c)); /* nick name */
835 if (!client_match) /* This isn't the client you're looking for */
839 strcpy(flags, who_flags_status(client_modes));
841 if (strchr(client_modes, 'o')) /* this client is an operator */
842 strlcat(flags, "*", sizeof(flags));
844 /* Search suitable channel */
845 cl2chan = Channel_FirstChannelOf(c);
847 cn = Channel_GetChannel(cl2chan);
848 if (Channel_IsMemberOf(cn, Client) ||
849 !strchr(Channel_Modes(cn), 's'))
851 channelname = Channel_Name(cn);
854 cl2chan = Channel_NextChannelOf(c, cl2chan);
857 chan = Channel_GetChannel(cl2chan);
858 chan_user_modes = Channel_UserModes(chan, c);
859 strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
863 if (!write_whoreply(Client, c, channelname, flags))
868 channelname = Req->argv[0];
872 return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), channelname);
877 IRC_WHOIS( CLIENT *Client, REQUEST *Req )
879 CLIENT *from, *target, *c;
880 char str[LINE_LEN + 1];
884 assert( Client != NULL );
885 assert( Req != NULL );
887 /* Bad number of parameters? */
888 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
891 c = Client_Search( Req->argv[Req->argc - 1] );
892 if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
894 /* Search sender of the WHOIS */
895 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
897 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
899 /* Forward to other server? */
902 /* Search target server (can be specified as nick of that server!) */
903 target = Client_Search( Req->argv[0] );
904 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
906 else target = Client_ThisServer( );
908 assert( target != NULL );
910 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] );
912 /* Nick, user and name */
913 if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
916 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;
919 snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
920 cl2chan = Channel_FirstChannelOf( c );
923 chan = Channel_GetChannel( cl2chan );
924 assert( chan != NULL );
927 cl2chan = Channel_NextChannelOf( c, cl2chan );
929 /* Secret channel? */
930 if( strchr( Channel_Modes( chan ), 's' ) && ! Channel_IsMemberOf( chan, Client )) continue;
932 /* Concatenate channel names */
933 if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
934 if( strchr( Channel_UserModes( chan, c ), 'o' )) strlcat( str, "@", sizeof( str ));
935 else if( strchr( Channel_UserModes( chan, c ), 'v' )) strlcat( str, "+", sizeof( str ));
936 strlcat( str, Channel_Name( chan ), sizeof( str ));
938 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
940 /* Line becomes too long: send it! */
941 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
942 snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
945 if( str[strlen( str ) - 1] != ':')
947 /* There is data left to send: */
948 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
952 if( Client_HasMode( c, 'o' ))
954 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
957 /* Idle and signon time (local clients only!) */
958 if (Client_Conn(c) > NONE ) {
959 if (! IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
960 Client_ID(from), Client_ID(c),
961 (unsigned long)Conn_GetIdle(Client_Conn(c)),
962 (unsigned long)Conn_GetSignon(Client_Conn(c))))
967 if( Client_HasMode( c, 'a' ))
969 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
973 return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
978 * IRC "WHOWAS" function.
979 * This function implements the IRC command "WHOWHAS". It handles local
980 * requests and request that should be forwarded to other servers.
983 IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
985 CLIENT *target, *prefix;
987 int max, last, count, i;
990 assert( Client != NULL );
991 assert( Req != NULL );
993 /* Wrong number of parameters? */
994 if(( Req->argc < 1 ) || ( Req->argc > 3 ))
995 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
996 Client_ID( Client ), Req->command );
1000 target = Client_Search( Req->argv[2] );
1002 target = Client_ThisServer( );
1005 if( Client_Type( Client ) == CLIENT_SERVER )
1006 prefix = Client_Search( Req->prefix );
1011 return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG,
1012 Client_ID( Client ), Req->prefix );
1014 /* Forward to other server? */
1015 if( target != Client_ThisServer( ))
1017 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
1018 return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG,
1019 Client_ID( prefix ),
1023 IRC_WriteStrClientPrefix( target, prefix, "WHOWAS %s %s %s",
1024 Req->argv[0], Req->argv[1],
1029 whowas = Client_GetWhowas( );
1030 last = Client_GetLastWhowasIndex( );
1031 if( last < 0 ) last = 0;
1035 max = atoi( Req->argv[1] );
1036 if( max < 1 ) max = MAX_WHOWAS;
1039 max = DEFAULT_WHOWAS;
1046 if( whowas[i].time > 0 &&
1047 strcasecmp( Req->argv[0], whowas[i].id ) == 0 )
1049 (void)strftime( t_str, sizeof(t_str),
1050 "%a %b %d %H:%M:%S %Y",
1051 localtime( &whowas[i].time ));
1053 if( ! IRC_WriteStrClient( prefix, RPL_WHOWASUSER_MSG,
1054 Client_ID( prefix ),
1059 return DISCONNECTED;
1061 if( ! IRC_WriteStrClient( prefix, RPL_WHOISSERVER_MSG,
1062 Client_ID( prefix ),
1064 whowas[i].server, t_str ))
1065 return DISCONNECTED;
1068 if( count >= max ) break;
1074 /* "underflow", wrap around */
1075 if( i < 0 ) i = MAX_WHOWAS - 1;
1076 } while( i != last );
1078 return IRC_WriteStrClient( prefix, RPL_ENDOFWHOWAS_MSG,
1079 Client_ID( prefix ), Req->argv[0] );
1084 IRC_Send_LUSERS( CLIENT *Client )
1091 assert( Client != NULL );
1093 /* Users, services and serevers in the network */
1094 if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
1096 /* Number of IRC operators */
1097 cnt = Client_OperCount( );
1100 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
1103 /* Unknown connections */
1104 cnt = Client_UnknownCount( );
1107 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
1110 /* Number of created channels */
1111 if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
1113 /* Number of local users, services and servers */
1114 if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
1117 /* Maximum number of local users */
1118 cnt = Client_MyUserCount();
1119 max = Client_MyMaxUserCount();
1120 if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
1121 cnt, max, cnt, max))
1122 return DISCONNECTED;
1123 /* Maximum number of users in the network */
1124 cnt = Client_UserCount();
1125 max = Client_MaxUserCount();
1126 if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
1127 cnt, max, cnt, max))
1128 return DISCONNECTED;
1132 } /* IRC_Send_LUSERS */
1136 Show_MOTD_Start(CLIENT *Client)
1138 return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
1139 Client_ID( Client ), Client_ID( Client_ThisServer( )));
1143 Show_MOTD_Sendline(CLIENT *Client, const char *msg)
1145 return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
1149 Show_MOTD_End(CLIENT *Client)
1151 return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
1156 IRC_Show_MOTD( CLIENT *Client )
1161 assert( Client != NULL );
1163 if (Conf_MotdPhrase[0]) {
1164 if (!Show_MOTD_Start(Client))
1165 return DISCONNECTED;
1166 if (!Show_MOTD_Sendline(Client, Conf_MotdPhrase))
1167 return DISCONNECTED;
1169 return Show_MOTD_End(Client);
1172 fd = fopen( Conf_MotdFile, "r" );
1174 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
1175 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
1178 if (!Show_MOTD_Start( Client )) {
1183 while (fgets( line, (int)sizeof line, fd )) {
1184 ngt_TrimLastChr( line, '\n');
1186 if( ! Show_MOTD_Sendline( Client, line)) {
1192 return Show_MOTD_End(Client);
1193 } /* IRC_Show_MOTD */
1197 IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
1199 bool is_visible, is_member;
1200 char str[LINE_LEN + 1];
1204 assert( Client != NULL );
1205 assert( Chan != NULL );
1207 if( Channel_IsMemberOf( Chan, Client )) is_member = true;
1208 else is_member = false;
1210 /* Secret channel? */
1211 if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
1213 /* Alle Mitglieder suchen */
1214 snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1215 cl2chan = Channel_FirstMember( Chan );
1218 cl = Channel_GetClient( cl2chan );
1220 if( strchr( Client_Modes( cl ), 'i' )) is_visible = false;
1221 else is_visible = true;
1223 if( is_member || is_visible )
1225 /* Nick anhaengen */
1226 if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
1227 if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
1228 else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
1229 strlcat( str, Client_ID( cl ), sizeof( str ));
1231 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
1233 /* Zeile wird zu lang: senden! */
1234 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
1235 snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1239 /* naechstes Mitglied suchen */
1240 cl2chan = Channel_NextMember( Chan, cl2chan );
1242 if( str[strlen( str ) - 1] != ':')
1244 /* Es sind noch Daten da, die gesendet werden muessen */
1245 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
1249 } /* IRC_Send_NAMES */
1254 * Send the ISUPPORT numeric (005).
1255 * This numeric indicates the features that are supported by this server.
1256 * See <http://www.irc.org/tech_docs/005.html> for details.
1259 IRC_Send_ISUPPORT PARAMS((CLIENT * Client))
1261 if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
1263 return DISCONNECTED;
1264 return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
1265 CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
1266 COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
1268 } /* IRC_Send_ISUPPORT */