]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc-info.c
Implemented IRC commands INFO, USERS (dummy), and SUMMON (dummy).
[ngircd-alex.git] / src / ngircd / irc-info.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2005 Alexander Barton (alex@barton.de)
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  * IRC info commands
12  */
13
14
15 #include "portab.h"
16
17 static char UNUSED id[] = "$Id: irc-info.c,v 1.44 2008/02/17 13:26:42 alex Exp $";
18
19 #include "imp.h"
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <strings.h>
26
27 #include "ngircd.h"
28 #include "cvs-version.h"
29 #include "conn-func.h"
30 #include "conn-zip.h"
31 #include "client.h"
32 #include "channel.h"
33 #include "resolve.h"
34 #include "conf.h"
35 #include "defines.h"
36 #include "log.h"
37 #include "messages.h"
38 #include "match.h"
39 #include "tool.h"
40 #include "parse.h"
41 #include "irc-write.h"
42
43 #include "exp.h"
44 #include "irc-info.h"
45
46
47 GLOBAL bool
48 IRC_ADMIN(CLIENT *Client, REQUEST *Req )
49 {
50         CLIENT *target, *prefix;
51
52         assert( Client != NULL );
53         assert( Req != NULL );
54
55         /* Falsche Anzahl Parameter? */
56         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
57
58         /* Ziel suchen */
59         if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
60         else target = Client_ThisServer( );
61
62         /* Prefix ermitteln */
63         if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
64         else prefix = Client;
65         if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
66
67         /* An anderen Server weiterleiten? */
68         if( target != Client_ThisServer( ))
69         {
70                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
71
72                 /* forwarden */
73                 IRC_WriteStrClientPrefix( target, prefix, "ADMIN %s", Req->argv[0] );
74                 return CONNECTED;
75         }
76
77         /* mit Versionsinfo antworten */
78         if( ! IRC_WriteStrClient( Client, RPL_ADMINME_MSG, Client_ID( prefix ), Conf_ServerName )) return DISCONNECTED;
79         if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC1_MSG, Client_ID( prefix ), Conf_ServerAdmin1 )) return DISCONNECTED;
80         if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC2_MSG, Client_ID( prefix ), Conf_ServerAdmin2 )) return DISCONNECTED;
81         if( ! IRC_WriteStrClient( Client, RPL_ADMINEMAIL_MSG, Client_ID( prefix ), Conf_ServerAdminMail )) return DISCONNECTED;
82
83         IRC_SetPenalty( Client, 1 );
84         return CONNECTED;
85 } /* IRC_ADMIN */
86
87
88 /**
89  * Handler for the IRC command "INFO".
90  * See RFC 2812 section 3.4.10.
91  */
92 GLOBAL bool
93 IRC_INFO(CLIENT * Client, REQUEST * Req)
94 {
95         CLIENT *target, *prefix;
96         char msg[510];
97
98         assert(Client != NULL);
99         assert(Req != NULL);
100
101         /* Wrong number of parameters? */
102         if (Req->argc > 1)
103                 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
104                                           Client_ID(Client), Req->command);
105
106         /* Determine prefix */
107         if (Client_Type(Client) == CLIENT_SERVER)
108                 prefix = Client_Search(Req->prefix);
109         else
110                 prefix = Client;
111         if (!prefix)
112                 return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
113                                           Client_ID(Client), Req->prefix);
114
115         /* Look for a target */
116         if (Req->argc > 0)
117                 target = Client_Search(Req->argv[0]);
118         else
119                 target = Client_ThisServer();
120         
121         /* Make sure that the target is a server */
122         if (target && Client_Type(target) != CLIENT_SERVER)
123                 target = Client_Introducer(target);
124
125         if (!target)
126                 return IRC_WriteStrClient(prefix, ERR_NOSUCHSERVER_MSG,
127                                           Client_ID(prefix), Req->argv[0]);
128
129         /* Pass on to another server? */
130         if (target != Client_ThisServer()) {
131                 IRC_WriteStrClientPrefix(target, prefix, "INFO %s",
132                                          Req->argv[0]);
133                 return CONNECTED;
134         }
135
136         if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix),
137                                 NGIRCd_Version))
138                 return DISCONNECTED;
139         
140         strlcpy(msg, "Server has been started ", sizeof(msg));
141         strlcat(msg, NGIRCd_StartStr, sizeof(msg));
142         if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
143                 return DISCONNECTED;
144
145         if (!IRC_WriteStrClient(Client, RPL_ENDOFINFO_MSG, Client_ID(prefix)))
146                 return DISCONNECTED;
147
148         IRC_SetPenalty(Client, 2);
149         return CONNECTED;
150 } /* IRC_INFO */
151
152
153 GLOBAL bool
154 IRC_ISON( CLIENT *Client, REQUEST *Req )
155 {
156         char rpl[COMMAND_LEN];
157         CLIENT *c;
158         char *ptr;
159         int i;
160
161         assert( Client != NULL );
162         assert( Req != NULL );
163
164         /* Falsche Anzahl Parameter? */
165         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
166
167         strlcpy( rpl, RPL_ISON_MSG, sizeof rpl );
168         for( i = 0; i < Req->argc; i++ )
169         {
170                 ptr = strtok( Req->argv[i], " " );
171                 while( ptr )
172                 {
173                         ngt_TrimStr( ptr );
174                         c = Client_Search( ptr );
175                         if( c && ( Client_Type( c ) == CLIENT_USER ))
176                         {
177                                 /* Dieser Nick ist "online" */
178                                 strlcat( rpl, ptr, sizeof( rpl ));
179                                 strlcat( rpl, " ", sizeof( rpl ));
180                         }
181                         ptr = strtok( NULL, " " );
182                 }
183         }
184         ngt_TrimLastChr(rpl, ' ');
185
186         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
187 } /* IRC_ISON */
188
189
190 GLOBAL bool
191 IRC_LINKS( CLIENT *Client, REQUEST *Req )
192 {
193         CLIENT *target, *from, *c;
194         char *mask;
195
196         assert( Client != NULL );
197         assert( Req != NULL );
198
199         /* Falsche Anzahl Parameter? */
200         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
201
202         /* Server-Mask ermitteln */
203         if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
204         else mask = "*";
205
206         /* Absender ermitteln */
207         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
208         else from = Client;
209         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
210
211         /* An anderen Server forwarden? */
212         if( Req->argc == 2 )
213         {
214                 target = Client_Search( Req->argv[0] );
215                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
216                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
217         }
218
219         /* Wer ist der Absender? */
220         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
221         else target = Client;
222         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
223
224         c = Client_First( );
225         while( c )
226         {
227                 if( Client_Type( c ) == CLIENT_SERVER )
228                 {
229                         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;
230                 }
231                 c = Client_Next( c );
232         }
233         
234         IRC_SetPenalty( target, 1 );
235         return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
236 } /* IRC_LINKS */
237
238
239 GLOBAL bool
240 IRC_LUSERS( CLIENT *Client, REQUEST *Req )
241 {
242         CLIENT *target, *from;
243
244         assert( Client != NULL );
245         assert( Req != NULL );
246
247         /* Falsche Anzahl Parameter? */
248         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
249
250         /* Absender ermitteln */
251         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
252         else from = Client;
253         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
254
255         /* An anderen Server forwarden? */
256         if( Req->argc == 2 )
257         {
258                 target = Client_Search( Req->argv[1] );
259                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
260                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
261         }
262
263         /* Wer ist der Absender? */
264         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
265         else target = Client;
266         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
267
268         IRC_Send_LUSERS( target );
269
270         IRC_SetPenalty( target, 1 );
271         return CONNECTED;
272 } /* IRC_LUSERS */
273
274
275 GLOBAL bool
276 IRC_MOTD( CLIENT *Client, REQUEST *Req )
277 {
278         CLIENT *from, *target;
279
280         assert( Client != NULL );
281         assert( Req != NULL );
282
283         /* Falsche Anzahl Parameter? */
284         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
285
286         /* From aus Prefix ermitteln */
287         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
288         else from = Client;
289         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
290
291         if( Req->argc == 1 )
292         {
293                 /* an anderen Server forwarden */
294                 target = Client_Search( Req->argv[0] );
295                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
296
297                 if( target != Client_ThisServer( ))
298                 {
299                         /* Ok, anderer Server ist das Ziel: forwarden */
300                         return IRC_WriteStrClientPrefix( target, from, "MOTD %s", Req->argv[0] );
301                 }
302         }
303
304         IRC_SetPenalty( from, 3 );
305         return IRC_Show_MOTD( from );
306 } /* IRC_MOTD */
307
308
309 GLOBAL bool
310 IRC_NAMES( CLIENT *Client, REQUEST *Req )
311 {
312         char rpl[COMMAND_LEN], *ptr;
313         CLIENT *target, *from, *c;
314         CHANNEL *chan;
315
316         assert( Client != NULL );
317         assert( Req != NULL );
318
319         /* Falsche Anzahl Parameter? */
320         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
321
322         /* From aus Prefix ermitteln */
323         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
324         else from = Client;
325         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
326
327         if( Req->argc == 2 )
328         {
329                 /* an anderen Server forwarden */
330                 target = Client_Search( Req->argv[1] );
331                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
332
333                 if( target != Client_ThisServer( ))
334                 {
335                         /* Ok, anderer Server ist das Ziel: forwarden */
336                         return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
337                 }
338         }
339
340         if( Req->argc > 0 )
341         {
342                 /* bestimmte Channels durchgehen */
343                 ptr = strtok( Req->argv[0], "," );
344                 while( ptr )
345                 {
346                         chan = Channel_Search( ptr );
347                         if( chan )
348                         {
349                                 /* Namen ausgeben */
350                                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
351                         }
352                         if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
353
354                         /* naechsten Namen ermitteln */
355                         ptr = strtok( NULL, "," );
356                 }
357                 return CONNECTED;
358         }
359
360         /* alle Channels durchgehen */
361         chan = Channel_First( );
362         while( chan )
363         {
364                 /* Namen ausgeben */
365                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
366
367                 /* naechster Channel */
368                 chan = Channel_Next( chan );
369         }
370
371         /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
372         c = Client_First( );
373         snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
374         while( c )
375         {
376                 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
377                 {
378                         /* Okay, das ist ein User: anhaengen */
379                         if( rpl[strlen( rpl ) - 1] != ':' ) strlcat( rpl, " ", sizeof( rpl ));
380                         strlcat( rpl, Client_ID( c ), sizeof( rpl ));
381
382                         if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
383                         {
384                                 /* Zeile wird zu lang: senden! */
385                                 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
386                                 snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
387                         }
388                 }
389
390                 /* naechster Client */
391                 c = Client_Next( c );
392         }
393         if( rpl[strlen( rpl ) - 1] != ':')
394         {
395                 /* es wurden User gefunden */
396                 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
397         }
398
399         IRC_SetPenalty( from, 1 );
400         return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
401 } /* IRC_NAMES */
402
403
404 static unsigned int
405 t_diff(time_t *t, const time_t div)
406 {
407         time_t diff, remain;
408
409         diff = *t / div;
410
411         remain = diff * div;
412         *t -= remain;
413
414         return diff;
415 }
416
417
418 static unsigned int
419 uptime_days(time_t *now)
420 {
421         return t_diff(now, 60 * 60 * 24);
422 }
423
424
425 static unsigned int
426 uptime_hrs(time_t *now)
427 {
428         return t_diff(now, 60 * 60);
429 }
430
431
432 static unsigned int
433 uptime_mins(time_t *now)
434 {
435          return t_diff(now, 60);
436 }
437
438
439 GLOBAL bool
440 IRC_STATS( CLIENT *Client, REQUEST *Req )
441 {
442         CLIENT *from, *target, *cl;
443         CONN_ID con;
444         char query;
445         COMMAND *cmd;
446         time_t time_now;
447         unsigned int days, hrs, mins;
448
449         assert( Client != NULL );
450         assert( Req != NULL );
451
452         /* Falsche Anzahl Parameter? */
453         if (Req->argc > 2)
454                 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
455
456         /* From aus Prefix ermitteln */
457         if (Client_Type(Client) == CLIENT_SERVER)
458                 from = Client_Search(Req->prefix);
459         else
460                 from = Client;
461
462         if (! from)
463                 return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix);
464
465         if (Req->argc == 2) {
466                 /* an anderen Server forwarden */
467                 target = Client_Search( Req->argv[1] );
468                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
469                         return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
470
471                 if( target != Client_ThisServer()) {
472                         /* Ok, anderer Server ist das Ziel: forwarden */
473                         return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] );
474                 }
475         }
476
477         if (Req->argc > 0)
478                 query = Req->argv[0][0] ? Req->argv[0][0] : '*';
479         else
480                 query = '*';
481
482         switch (query) {
483                 case 'l':       /* Links */
484                 case 'L':
485                         time_now = time(NULL);
486                         for (con = Conn_First(); con != NONE ;con = Conn_Next(con)) {
487                                 cl = Conn_GetClient(con);
488                                 if (!cl)
489                                         continue;
490                                 if ((Client_Type(cl) == CLIENT_SERVER) || (cl == Client)) {
491                                         /* Server link or our own connection */
492 #ifdef ZLIB
493                                         if (Conn_Options(con) & CONN_ZIP) {
494                                                 if (!IRC_WriteStrClient(from, RPL_STATSLINKINFOZIP_MSG,
495                                                         Client_ID(from), Client_Mask(cl), Conn_SendQ(con),
496                                                         Conn_SendMsg(con), Zip_SendBytes(con), Conn_SendBytes(con),
497                                                         Conn_RecvMsg(con), Zip_RecvBytes(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
498                                                                 return DISCONNECTED;
499                                                 continue;
500                                         }
501 #endif
502                                         if (!IRC_WriteStrClient(from, RPL_STATSLINKINFO_MSG, Client_ID(from),
503                                                 Client_Mask(cl), Conn_SendQ(con), Conn_SendMsg(con), Conn_SendBytes(con),
504                                                 Conn_RecvMsg(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
505                                                         return DISCONNECTED;
506                                 }
507                         }
508                         break;
509                 case 'm':       /* IRC-Commands */
510                 case 'M':
511                         cmd = Parse_GetCommandStruct( );
512                         for (; cmd->name ; cmd++) {
513                                 if (cmd->lcount == 0 && cmd->rcount == 0)
514                                         continue;
515                                 if (!IRC_WriteStrClient(from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
516                                                 cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
517                                                         return DISCONNECTED;
518                         }
519                         break;
520                 case 'u':       /* server uptime */
521                 case 'U':
522                         time_now = time(NULL) - NGIRCd_Start;
523                         days = uptime_days(&time_now);
524                         hrs = uptime_hrs(&time_now);
525                         mins = uptime_mins(&time_now);
526                         if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
527                                         days, hrs, mins, (unsigned int) time_now))
528                                                 return DISCONNECTED;
529                         break;
530         }
531
532         IRC_SetPenalty(from, 2);
533         return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, Client_ID(from), query);
534 } /* IRC_STATS */
535
536
537 /**
538  * Handler for the IRC command "SUMMON".
539  * See RFC 2812 section 4.5. ngIRCd doesn't implement this functionality and
540  * therefore answers with ERR_SUMMONDISABLED.
541  */
542 GLOBAL bool
543 IRC_SUMMON(CLIENT * Client, REQUEST * Req)
544 {
545         return IRC_WriteStrClient(Client, ERR_SUMMONDISABLED_MSG,
546                                   Client_ID(Client), Req->command);
547 } /* IRC_SUMMON */
548
549
550 GLOBAL bool
551 IRC_TIME( CLIENT *Client, REQUEST *Req )
552 {
553         CLIENT *from, *target;
554         char t_str[64];
555         time_t t;
556
557         assert( Client != NULL );
558         assert( Req != NULL );
559
560         /* Falsche Anzahl Parameter? */
561         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
562
563         /* From aus Prefix ermitteln */
564         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
565         else from = Client;
566         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
567
568         if( Req->argc == 1 )
569         {
570                 /* an anderen Server forwarden */
571                 target = Client_Search( Req->argv[0] );
572                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
573
574                 if( target != Client_ThisServer( ))
575                 {
576                         /* Ok, anderer Server ist das Ziel: forwarden */
577                         return IRC_WriteStrClientPrefix( target, from, "TIME %s", Req->argv[0] );
578                 }
579         }
580
581         t = time( NULL );
582         (void)strftime( t_str, 60, "%A %B %d %Y -- %H:%M %Z", localtime( &t ));
583         return IRC_WriteStrClient( from, RPL_TIME_MSG, Client_ID( from ), Client_ID( Client_ThisServer( )), t_str );
584 } /* IRC_TIME */
585
586
587 GLOBAL bool
588 IRC_USERHOST( CLIENT *Client, REQUEST *Req )
589 {
590         char rpl[COMMAND_LEN];
591         CLIENT *c;
592         int max, i;
593
594         assert( Client != NULL );
595         assert( Req != NULL );
596
597         /* Falsche Anzahl Parameter? */
598         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
599
600         if( Req->argc > 5 ) max = 5;
601         else max = Req->argc;
602
603         strlcpy( rpl, RPL_USERHOST_MSG, sizeof rpl );
604         for( i = 0; i < max; i++ )
605         {
606                 c = Client_Search( Req->argv[i] );
607                 if( c && ( Client_Type( c ) == CLIENT_USER ))
608                 {
609                         /* Dieser Nick ist "online" */
610                         strlcat( rpl, Client_ID( c ), sizeof( rpl ));
611                         if( Client_HasMode( c, 'o' )) strlcat( rpl, "*", sizeof( rpl ));
612                         strlcat( rpl, "=", sizeof( rpl ));
613                         if( Client_HasMode( c, 'a' )) strlcat( rpl, "-", sizeof( rpl ));
614                         else strlcat( rpl, "+", sizeof( rpl ));
615                         strlcat( rpl, Client_User( c ), sizeof( rpl ));
616                         strlcat( rpl, "@", sizeof( rpl ));
617                         strlcat( rpl, Client_Hostname( c ), sizeof( rpl ));
618                         strlcat( rpl, " ", sizeof( rpl ));
619                 }
620         }
621         ngt_TrimLastChr( rpl, ' ');
622
623         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
624 } /* IRC_USERHOST */
625
626
627 /**
628  * Handler for the IRC command "USERS".
629  * See RFC 2812 section 4.6. As suggested there the command is disabled.
630  */
631 GLOBAL bool
632 IRC_USERS(CLIENT * Client, REQUEST * Req)
633 {
634         return IRC_WriteStrClient(Client, ERR_USERSDISABLED_MSG,
635                                   Client_ID(Client), Req->command);
636 } /* IRC_USERS */
637
638
639 GLOBAL bool
640 IRC_VERSION( CLIENT *Client, REQUEST *Req )
641 {
642         CLIENT *target, *prefix;
643 #ifdef CVSDATE
644         char ver[12], vertxt[30];
645 #endif
646
647         assert( Client != NULL );
648         assert( Req != NULL );
649
650         /* Falsche Anzahl Parameter? */
651         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
652
653         /* Ziel suchen */
654         if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
655         else target = Client_ThisServer( );
656
657         /* Prefix ermitteln */
658         if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
659         else prefix = Client;
660         if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
661
662         /* An anderen Server weiterleiten? */
663         if( target != Client_ThisServer( ))
664         {
665                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
666
667                 /* forwarden */
668                 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
669                 return CONNECTED;
670         }
671
672         /* mit Versionsinfo antworten */
673         IRC_SetPenalty( Client, 1 );
674 #ifdef CVSDATE
675         strlcpy( ver, CVSDATE, sizeof( ver ));
676         strncpy( ver + 4, ver + 5, 2 );
677         strncpy( ver + 6, ver + 8, 3 );
678         snprintf( vertxt, sizeof( vertxt ), "%s(%s)", PACKAGE_VERSION, ver );
679         return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), PACKAGE_NAME, vertxt, NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition );
680 #else
681         return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition );
682 #endif
683 } /* IRC_VERSION */
684
685
686
687 static bool
688 write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
689 {
690         return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client), channelname,
691                         Client_User(c), Client_Hostname(c), Client_ID(Client_Introducer(c)), Client_ID(c),
692                         flags, Client_Hops(c), Client_Info(c));
693 }
694
695
696 static const char *
697 who_flags_status(const char *client_modes)
698 {
699         if (strchr(client_modes, 'a'))
700                 return "G"; /* away */
701         return "H";
702 }
703
704
705 static const char *
706 who_flags_qualifier(const char *chan_user_modes)
707 {
708         if (strchr(chan_user_modes, 'o'))
709                 return "@";
710         else if (strchr(chan_user_modes, 'v'))
711                 return "+";
712         return "";
713 }
714
715
716 static bool
717 IRC_Send_WHO(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
718 {
719         bool is_visible, is_member, is_ircop;
720         CL2CHAN *cl2chan;
721         const char *client_modes;
722         const char *chan_user_modes;
723         char flags[8];
724         CLIENT *c;
725
726         assert( Client != NULL );
727         assert( Chan != NULL );
728
729         is_member = Channel_IsMemberOf(Chan, Client);
730
731         /* Secret channel? */
732         if (!is_member && strchr(Channel_Modes(Chan), 's'))
733                 return CONNECTED;
734
735         cl2chan = Channel_FirstMember(Chan);
736         for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
737                 c = Channel_GetClient(cl2chan);
738
739                 client_modes = Client_Modes(c);
740                 is_ircop = strchr(client_modes, 'o') != NULL;
741                 if (OnlyOps && !is_ircop)
742                         continue;
743
744                 is_visible = strchr(client_modes, 'i') == NULL;
745                 if (is_member || is_visible) {
746                         strcpy(flags, who_flags_status(client_modes));
747                         if (is_ircop)
748                                 strlcat(flags, "*", sizeof(flags));
749
750                         chan_user_modes = Channel_UserModes(Chan, c);
751                         strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
752
753                         if (!write_whoreply(Client, c, Channel_Name(Chan), flags))
754                                 return DISCONNECTED;
755                 }
756         }
757         return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
758 } /* IRC_Send_WHO */
759
760
761
762 static bool
763 MatchCaseInsensitive(const char *pattern, const char *searchme)
764 {
765         char haystack[COMMAND_LEN];
766
767         strlcpy(haystack, searchme, sizeof(haystack));
768
769         ngt_LowerStr(haystack);
770
771         return Match(pattern, haystack);
772 }
773
774
775 GLOBAL bool
776 IRC_WHO( CLIENT *Client, REQUEST *Req )
777 {
778         bool only_ops, have_arg, client_match;
779         const char *channelname, *client_modes, *chan_user_modes;
780         char pattern[COMMAND_LEN];
781         char flags[4];
782         CL2CHAN *cl2chan;
783         CHANNEL *chan, *cn;
784         CLIENT *c;
785
786         assert( Client != NULL );
787         assert( Req != NULL );
788
789         if (Req->argc > 2)
790                 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
791
792         only_ops = false;
793         have_arg = false;
794
795         if (Req->argc == 2) {
796                 if (strcmp(Req->argv[1], "o") == 0)
797                         only_ops = true;
798 #ifdef STRICT_RFC
799                 else return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
800 #endif
801         }
802
803         IRC_SetPenalty(Client, 1);
804         if (Req->argc >= 1) { /* Channel or Mask. */
805                 chan = Channel_Search(Req->argv[0]);
806                 if (chan)
807                         return IRC_Send_WHO(Client, chan, only_ops);
808                 if (strcmp(Req->argv[0], "0") != 0) { /* RFC stupidity, same as no arguments */
809                         have_arg = true;
810                         strlcpy(pattern, Req->argv[0], sizeof(pattern));
811                         ngt_LowerStr(pattern);
812                         IRC_SetPenalty(Client, 3);
813                 }
814         }
815
816         for (c = Client_First(); c != NULL; c = Client_Next(c)) {
817                 if (Client_Type(c) != CLIENT_USER)
818                         continue;
819                  /*
820                   * RFC 2812, 3.6.1:
821                   * In the absence of the parameter, all visible (users who aren't
822                   * invisible (user mode +i) and who don't have a common channel
823                   * with the requesting client) are listed.
824                   *
825                   * The same result can be achieved by using a [sic] of "0"
826                   * or any wildcard which will end up matching every visible user.
827                   *
828                   * The [sic] passed to WHO is matched against users' host, server, real name and
829                   * nickname if the channel cannot be found.
830                   */
831                 client_modes = Client_Modes(c);
832                 if (strchr(client_modes, 'i'))
833                         continue;
834
835                 if (only_ops && !strchr(client_modes, 'o'))
836                         continue;
837
838                 if (have_arg) { /* match pattern against user host/server/name/nick */
839                         client_match = MatchCaseInsensitive(pattern, Client_Hostname(c)); /* user's host */
840                         if (!client_match)
841                                 client_match = MatchCaseInsensitive(pattern, Client_ID(Client_Introducer(c))); /* server */
842                         if (!client_match)
843                                 client_match = Match(Req->argv[0], Client_Info(c)); /* realname */
844                         if (!client_match)
845                                 client_match = MatchCaseInsensitive(pattern, Client_ID(c)); /* nick name */
846
847                         if (!client_match) /* This isn't the client you're looking for */
848                                 continue;
849                 }
850
851                 strcpy(flags, who_flags_status(client_modes));
852
853                 if (strchr(client_modes, 'o')) /* this client is an operator */
854                         strlcat(flags, "*", sizeof(flags));
855
856                 /* Search suitable channel */
857                 cl2chan = Channel_FirstChannelOf(c);
858                 while (cl2chan) {
859                         cn = Channel_GetChannel(cl2chan);
860                         if (Channel_IsMemberOf(cn, Client) ||
861                                     !strchr(Channel_Modes(cn), 's'))
862                         {
863                                 channelname = Channel_Name(cn);
864                                 break;
865                         }
866                         cl2chan = Channel_NextChannelOf(c, cl2chan);
867                 }
868                 if (cl2chan) {
869                         chan = Channel_GetChannel(cl2chan);
870                         chan_user_modes = Channel_UserModes(chan, c);
871                         strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
872                 } else
873                         channelname = "*";
874
875                 if (!write_whoreply(Client, c, channelname, flags))
876                         return DISCONNECTED;
877         }
878
879         if (Req->argc > 0)
880                 channelname = Req->argv[0];
881         else
882                 channelname = "*";
883
884         return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), channelname);
885 } /* IRC_WHO */
886
887
888 GLOBAL bool
889 IRC_WHOIS( CLIENT *Client, REQUEST *Req )
890 {
891         CLIENT *from, *target, *c;
892         char str[LINE_LEN + 1];
893         CL2CHAN *cl2chan;
894         CHANNEL *chan;
895
896         assert( Client != NULL );
897         assert( Req != NULL );
898
899         /* Bad number of parameters? */
900         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
901
902         /* Search client */
903         c = Client_Search( Req->argv[Req->argc - 1] );
904         if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
905
906         /* Search sender of the WHOIS */
907         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
908         else from = Client;
909         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
910
911         /* Forward to other server? */
912         if( Req->argc > 1 )
913         {
914                 /* Search target server (can be specified as nick of that server!) */
915                 target = Client_Search( Req->argv[0] );
916                 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
917         }
918         else target = Client_ThisServer( );
919
920         assert( target != NULL );
921
922         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] );
923
924         /* Nick, user and name */
925         if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
926
927         /* Server */
928         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;
929
930         /* Channels */
931         snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
932         cl2chan = Channel_FirstChannelOf( c );
933         while( cl2chan )
934         {
935                 chan = Channel_GetChannel( cl2chan );
936                 assert( chan != NULL );
937
938                 /* next */
939                 cl2chan = Channel_NextChannelOf( c, cl2chan );
940
941                 /* Secret channel? */
942                 if( strchr( Channel_Modes( chan ), 's' ) && ! Channel_IsMemberOf( chan, Client )) continue;
943
944                 /* Concatenate channel names */
945                 if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
946                 if( strchr( Channel_UserModes( chan, c ), 'o' )) strlcat( str, "@", sizeof( str ));
947                 else if( strchr( Channel_UserModes( chan, c ), 'v' )) strlcat( str, "+", sizeof( str ));
948                 strlcat( str, Channel_Name( chan ), sizeof( str ));
949
950                 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
951                 {
952                         /* Line becomes too long: send it! */
953                         if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
954                         snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
955                 }
956         }
957         if( str[strlen( str ) - 1] != ':')
958         {
959                 /* There is data left to send: */
960                 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
961         }
962
963         /* IRC-Operator? */
964         if( Client_HasMode( c, 'o' ))
965         {
966                 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
967         }
968
969         /* Idle and signon time (local clients only!) */
970         if (Client_Conn(c) > NONE ) {
971                 if (! IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
972                         Client_ID(from), Client_ID(c),
973                         (unsigned long)Conn_GetIdle(Client_Conn(c)),
974                         (unsigned long)Conn_GetSignon(Client_Conn(c))))
975                                 return DISCONNECTED;
976         }
977
978         /* Away? */
979         if( Client_HasMode( c, 'a' ))
980         {
981                 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
982         }
983
984         /* End of Whois */
985         return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
986 } /* IRC_WHOIS */
987
988
989 /**
990  * IRC "WHOWAS" function.
991  * This function implements the IRC command "WHOWHAS". It handles local
992  * requests and request that should be forwarded to other servers.
993  */
994 GLOBAL bool
995 IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
996 {
997         CLIENT *target, *prefix;
998         WHOWAS *whowas;
999         int max, last, count, i;
1000         char t_str[60];
1001         
1002         assert( Client != NULL );
1003         assert( Req != NULL );
1004
1005         /* Wrong number of parameters? */
1006         if(( Req->argc < 1 ) || ( Req->argc > 3 ))
1007                 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
1008                                            Client_ID( Client ), Req->command );
1009
1010         /* Search taget */
1011         if( Req->argc == 3 )
1012                 target = Client_Search( Req->argv[2] );
1013         else
1014                 target = Client_ThisServer( );
1015
1016         /* Get prefix */
1017         if( Client_Type( Client ) == CLIENT_SERVER )
1018                 prefix = Client_Search( Req->prefix );
1019         else
1020                 prefix = Client;
1021
1022         if( ! prefix )
1023                 return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG,
1024                                            Client_ID( Client ), Req->prefix );
1025
1026         /* Forward to other server? */
1027         if( target != Client_ThisServer( ))
1028         {
1029                 if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
1030                         return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG,
1031                                                    Client_ID( prefix ),
1032                                                    Req->argv[2] );
1033
1034                 /* Forward */
1035                 IRC_WriteStrClientPrefix( target, prefix, "WHOWAS %s %s %s",
1036                                           Req->argv[0], Req->argv[1],
1037                                           Req->argv[2] );
1038                 return CONNECTED;
1039         }
1040         
1041         whowas = Client_GetWhowas( );
1042         last = Client_GetLastWhowasIndex( );
1043         if( last < 0 ) last = 0;
1044         
1045         if( Req->argc > 1 )
1046         {
1047                 max = atoi( Req->argv[1] );
1048                 if( max < 1 ) max = MAX_WHOWAS;
1049         }
1050         else
1051                 max = DEFAULT_WHOWAS;
1052         
1053         i = last;
1054         count = 0;
1055         do
1056         {
1057                 /* Used entry? */
1058                 if( whowas[i].time > 0 &&
1059                     strcasecmp( Req->argv[0], whowas[i].id ) == 0 )
1060                 {
1061                         (void)strftime( t_str, sizeof(t_str),
1062                                         "%a %b %d %H:%M:%S %Y",
1063                                         localtime( &whowas[i].time ));
1064                 
1065                         if( ! IRC_WriteStrClient( prefix, RPL_WHOWASUSER_MSG,
1066                                                   Client_ID( prefix ),
1067                                                   whowas[i].id,
1068                                                   whowas[i].user,
1069                                                   whowas[i].host, 
1070                                                   whowas[i].info ))
1071                                 return DISCONNECTED;
1072                 
1073                         if( ! IRC_WriteStrClient( prefix, RPL_WHOISSERVER_MSG,
1074                                                   Client_ID( prefix ),
1075                                                   whowas[i].id,
1076                                                   whowas[i].server, t_str ))
1077                                 return DISCONNECTED;
1078                 
1079                         count++;
1080                         if( count >= max ) break;
1081                 }
1082                 
1083                 /* previos entry */
1084                 i--;
1085
1086                 /* "underflow", wrap around */
1087                 if( i < 0 ) i = MAX_WHOWAS - 1;
1088         } while( i != last );
1089         
1090         return IRC_WriteStrClient( prefix, RPL_ENDOFWHOWAS_MSG,
1091                                    Client_ID( prefix ), Req->argv[0] );
1092 } /* IRC_WHOWAS */
1093
1094
1095 GLOBAL bool
1096 IRC_Send_LUSERS( CLIENT *Client )
1097 {
1098         unsigned long cnt;
1099 #ifndef STRICT_RFC
1100         unsigned long max;
1101 #endif
1102
1103         assert( Client != NULL );
1104
1105         /* Users, services and serevers in the network */
1106         if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
1107
1108         /* Number of IRC operators */
1109         cnt = Client_OperCount( );
1110         if( cnt > 0 )
1111         {
1112                 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
1113         }
1114
1115         /* Unknown connections */
1116         cnt = Client_UnknownCount( );
1117         if( cnt > 0 )
1118         {
1119                 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
1120         }
1121
1122         /* Number of created channels */
1123         if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
1124
1125         /* Number of local users, services and servers */
1126         if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
1127
1128 #ifndef STRICT_RFC
1129         /* Maximum number of local users */
1130         cnt = Client_MyUserCount();
1131         max = Client_MyMaxUserCount();
1132         if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
1133                         cnt, max, cnt, max))
1134                 return DISCONNECTED;
1135         /* Maximum number of users in the network */
1136         cnt = Client_UserCount();
1137         max = Client_MaxUserCount();
1138         if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
1139                         cnt, max, cnt, max))
1140                 return DISCONNECTED;
1141 #endif
1142         
1143         return CONNECTED;
1144 } /* IRC_Send_LUSERS */
1145
1146
1147 static bool
1148 Show_MOTD_Start(CLIENT *Client)
1149 {
1150         return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
1151                 Client_ID( Client ), Client_ID( Client_ThisServer( )));
1152 }
1153
1154 static bool
1155 Show_MOTD_Sendline(CLIENT *Client, const char *msg)
1156 {
1157         return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
1158 }
1159
1160 static bool
1161 Show_MOTD_End(CLIENT *Client)
1162 {
1163         return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
1164 }
1165
1166
1167 GLOBAL bool
1168 IRC_Show_MOTD( CLIENT *Client )
1169 {
1170         char line[127];
1171         FILE *fd;
1172
1173         assert( Client != NULL );
1174
1175         if (Conf_MotdPhrase[0]) {
1176                 if (!Show_MOTD_Start(Client))
1177                         return DISCONNECTED;
1178                 if (!Show_MOTD_Sendline(Client, Conf_MotdPhrase))
1179                         return DISCONNECTED;
1180
1181                 return Show_MOTD_End(Client);
1182         }
1183
1184         fd = fopen( Conf_MotdFile, "r" );
1185         if( ! fd ) {
1186                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
1187                 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
1188         }
1189
1190         if (!Show_MOTD_Start( Client )) {
1191                 fclose(fd);
1192                 return false;
1193         }
1194
1195         while (fgets( line, (int)sizeof line, fd )) {
1196                 ngt_TrimLastChr( line, '\n');
1197
1198                 if( ! Show_MOTD_Sendline( Client, line)) {
1199                         fclose( fd );
1200                         return false;
1201                 }
1202         }
1203         fclose(fd);
1204         return Show_MOTD_End(Client);
1205 } /* IRC_Show_MOTD */
1206
1207
1208 GLOBAL bool
1209 IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
1210 {
1211         bool is_visible, is_member;
1212         char str[LINE_LEN + 1];
1213         CL2CHAN *cl2chan;
1214         CLIENT *cl;
1215
1216         assert( Client != NULL );
1217         assert( Chan != NULL );
1218
1219         if( Channel_IsMemberOf( Chan, Client )) is_member = true;
1220         else is_member = false;
1221
1222         /* Secret channel? */
1223         if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
1224
1225         /* Alle Mitglieder suchen */
1226         snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1227         cl2chan = Channel_FirstMember( Chan );
1228         while( cl2chan )
1229         {
1230                 cl = Channel_GetClient( cl2chan );
1231
1232                 if( strchr( Client_Modes( cl ), 'i' )) is_visible = false;
1233                 else is_visible = true;
1234
1235                 if( is_member || is_visible )
1236                 {
1237                         /* Nick anhaengen */
1238                         if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
1239                         if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
1240                         else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
1241                         strlcat( str, Client_ID( cl ), sizeof( str ));
1242
1243                         if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
1244                         {
1245                                 /* Zeile wird zu lang: senden! */
1246                                 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
1247                                 snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1248                         }
1249                 }
1250
1251                 /* naechstes Mitglied suchen */
1252                 cl2chan = Channel_NextMember( Chan, cl2chan );
1253         }
1254         if( str[strlen( str ) - 1] != ':')
1255         {
1256                 /* Es sind noch Daten da, die gesendet werden muessen */
1257                 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
1258         }
1259
1260         return CONNECTED;
1261 } /* IRC_Send_NAMES */
1262
1263
1264
1265 /**
1266  * Send the ISUPPORT numeric (005).
1267  * This numeric indicates the features that are supported by this server.
1268  * See <http://www.irc.org/tech_docs/005.html> for details.
1269  */
1270 GLOBAL bool
1271 IRC_Send_ISUPPORT PARAMS((CLIENT * Client))
1272 {
1273         if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
1274                                 Conf_MaxJoins))
1275                 return DISCONNECTED;
1276         return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
1277                                   CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
1278                                   COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
1279                                   COMMAND_LEN - 113);
1280 } /* IRC_Send_ISUPPORT */
1281
1282
1283 /* -eof- */