- neuer IRC-Befehl "TIME".
[ngircd-alex.git] / src / ngircd / irc.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4  *
5  * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6  * der GNU General Public License (GPL), wie von der Free Software Foundation
7  * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8  * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10  * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: irc.c,v 1.101 2002/11/24 16:36:03 alex Exp $
13  *
14  * irc.c: IRC-Befehle
15  */
16
17
18 #include "portab.h"
19
20 #include "imp.h"
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "ngircd.h"
28 #include "conn.h"
29 #include "client.h"
30 #include "channel.h"
31 #include "resolve.h"
32 #include "conf.h"
33 #include "conn.h"
34 #include "irc-write.h"
35 #include "log.h"
36 #include "messages.h"
37 #include "parse.h"
38 #include "tool.h"
39
40 #include "exp.h"
41 #include "irc.h"
42
43
44 GLOBAL BOOLEAN
45 IRC_MOTD( CLIENT *Client, REQUEST *Req )
46 {
47         CLIENT *from, *target;
48
49         assert( Client != NULL );
50         assert( Req != NULL );
51
52         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
53
54         /* Falsche Anzahl Parameter? */
55         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
56
57         /* From aus Prefix ermitteln */
58         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
59         else from = Client;
60         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
61         
62         if( Req->argc == 1 )
63         {
64                 /* an anderen Server forwarden */
65                 target = Client_Search( Req->argv[0] );
66                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
67
68                 if( target != Client_ThisServer( ))
69                 {
70                         /* Ok, anderer Server ist das Ziel: forwarden */
71                         return IRC_WriteStrClientPrefix( target, from, "MOTD %s", Req->argv[0] );
72                 }
73         }
74
75         return IRC_Show_MOTD( from );
76 } /* IRC_MOTD */
77
78
79 GLOBAL BOOLEAN
80 IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
81 {
82         CLIENT *cl, *from;
83         CHANNEL *chan;
84         
85         assert( Client != NULL );
86         assert( Req != NULL );
87
88         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
89
90         /* Falsche Anzahl Parameter? */
91         if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
92         if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
93         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
94
95         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
96         else from = Client;
97         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
98
99         cl = Client_Search( Req->argv[0] );
100         if( cl )
101         {
102                 /* Okay, Ziel ist ein Client. Aber ist es auch ein User? */
103                 if( Client_Type( cl ) != CLIENT_USER ) return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
104
105                 /* Okay, Ziel ist ein User */
106                 if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' )))
107                 {
108                         /* Ziel-User ist AWAY: Meldung verschicken */
109                         if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( cl ), Client_Away( cl ))) return DISCONNECTED;
110                 }
111
112                 /* Text senden */
113                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
114                 return IRC_WriteStrClientPrefix( cl, from, "PRIVMSG %s :%s", Client_ID( cl ), Req->argv[1] );
115         }
116
117         chan = Channel_Search( Req->argv[0] );
118         if( chan ) return Channel_Write( chan, from, Client, Req->argv[1] );
119
120         return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
121 } /* IRC_PRIVMSG */
122
123
124 GLOBAL BOOLEAN
125 IRC_NOTICE( CLIENT *Client, REQUEST *Req )
126 {
127         CLIENT *to, *from;
128
129         assert( Client != NULL );
130         assert( Req != NULL );
131
132         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return CONNECTED;
133
134         /* Falsche Anzahl Parameter? */
135         if( Req->argc != 2 ) return CONNECTED;
136
137         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
138         else from = Client;
139         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
140
141         to = Client_Search( Req->argv[0] );
142         if(( to ) && ( Client_Type( to ) == CLIENT_USER ))
143         {
144                 /* Okay, Ziel ist ein User */
145                 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
146         }
147         else return CONNECTED;
148 } /* IRC_NOTICE */
149
150
151 GLOBAL BOOLEAN
152 IRC_NAMES( CLIENT *Client, REQUEST *Req )
153 {
154         CHAR rpl[COMMAND_LEN], *ptr;
155         CLIENT *target, *from, *c;
156         CHANNEL *chan;
157         
158         assert( Client != NULL );
159         assert( Req != NULL );
160
161         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
162
163         /* Falsche Anzahl Parameter? */
164         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
165
166         /* From aus Prefix ermitteln */
167         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
168         else from = Client;
169         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
170         
171         if( Req->argc == 2 )
172         {
173                 /* an anderen Server forwarden */
174                 target = Client_Search( Req->argv[1] );
175                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
176
177                 if( target != Client_ThisServer( ))
178                 {
179                         /* Ok, anderer Server ist das Ziel: forwarden */
180                         return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
181                 }
182         }
183
184         if( Req->argc > 0 )
185         {
186                 /* bestimmte Channels durchgehen */
187                 ptr = strtok( Req->argv[0], "," );
188                 while( ptr )
189                 {
190                         chan = Channel_Search( ptr );
191                         if( chan )
192                         {
193                                 /* Namen ausgeben */
194                                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
195                         }
196                         if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
197                         
198                         /* naechsten Namen ermitteln */
199                         ptr = strtok( NULL, "," );
200                 }
201                 return CONNECTED;
202         }
203         
204         /* alle Channels durchgehen */
205         chan = Channel_First( );
206         while( chan )
207         {
208                 /* Namen ausgeben */
209                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
210
211                 /* naechster Channel */
212                 chan = Channel_Next( chan );
213         }
214
215         /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
216         c = Client_First( );
217         sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
218         while( c )
219         {
220                 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
221                 {
222                         /* Okay, das ist ein User: anhaengen */
223                         if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " );
224                         strcat( rpl, Client_ID( c ));
225
226                         if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
227                         {
228                                 /* Zeile wird zu lang: senden! */
229                                 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
230                                 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
231                         }
232                 }
233
234                 /* naechster Client */
235                 c = Client_Next( c );
236         }
237         if( rpl[strlen( rpl ) - 1] != ':')
238         {
239                 /* es wurden User gefunden */
240                 if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
241         }
242         
243         return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
244 } /* IRC_NAMES */
245
246
247 GLOBAL BOOLEAN
248 IRC_ISON( CLIENT *Client, REQUEST *Req )
249 {
250         CHAR rpl[COMMAND_LEN];
251         CLIENT *c;
252         CHAR *ptr;
253         INT i;
254         
255         assert( Client != NULL );
256         assert( Req != NULL );
257
258         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
259
260         /* Falsche Anzahl Parameter? */
261         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
262
263         strcpy( rpl, RPL_ISON_MSG );
264         for( i = 0; i < Req->argc; i++ )
265         {
266                 ptr = strtok( Req->argv[i], " " );
267                 while( ptr )
268                 {
269                         ngt_TrimStr( ptr );
270                         c = Client_Search( ptr );
271                         if( c && ( Client_Type( c ) == CLIENT_USER ))
272                         {
273                                 /* Dieser Nick ist "online" */
274                                 strcat( rpl, ptr );
275                                 strcat( rpl, " " );
276                         }
277                         ptr = strtok( NULL, " " );
278                 }
279         }
280         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
281
282         return IRC_WriteStrClient( Client, "%s", rpl, Client_ID( Client ) );
283 } /* IRC_ISON */
284
285
286 GLOBAL BOOLEAN
287 IRC_WHOIS( CLIENT *Client, REQUEST *Req )
288 {
289         CLIENT *from, *target, *c;
290         CHAR str[LINE_LEN + 1], *ptr = NULL;
291         CL2CHAN *cl2chan;
292         CHANNEL *chan;
293         
294         assert( Client != NULL );
295         assert( Req != NULL );
296
297         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
298
299         /* Falsche Anzahl Parameter? */
300         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
301
302         /* Client suchen */
303         c = Client_Search( Req->argv[Req->argc - 1] );
304         if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
305
306         /* Empfaenger des WHOIS suchen */
307         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
308         else from = Client;
309         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
310         
311         /* Forwarden an anderen Server? */
312         if( Req->argc > 1 )
313         {
314                 /* angegebenen Ziel-Server suchen */
315                 target = Client_Search( Req->argv[1] );
316                 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
317                 ptr = Req->argv[1];
318         }
319         else target = Client_ThisServer( );
320
321         assert( target != NULL );
322         
323         if(( Client_NextHop( target ) != Client_ThisServer( )) && ( Client_Type( Client_NextHop( target )) == CLIENT_SERVER )) return IRC_WriteStrClientPrefix( target, from, "WHOIS %s :%s", Req->argv[0], ptr );
324         
325         /* Nick, User und Name */
326         if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
327
328         /* Server */
329         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;
330
331         /* Channels */
332         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
333         cl2chan = Channel_FirstChannelOf( c );
334         while( cl2chan )
335         {
336                 chan = Channel_GetChannel( cl2chan );
337                 assert( chan != NULL );
338                 
339                 /* Channel-Name anhaengen */
340                 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
341                 if( strchr( Channel_UserModes( chan, c ), 'o' )) strcat( str, "@" );
342                 else if( strchr( Channel_UserModes( chan, c ), 'v' )) strcat( str, "+" );
343                 strcat( str, Channel_Name( chan ));
344
345                 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
346                 {
347                         /* Zeile wird zu lang: senden! */
348                         if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
349                         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
350                 }
351
352                 /* naechstes Mitglied suchen */
353                 cl2chan = Channel_NextChannelOf( c, cl2chan );
354         }
355         if( str[strlen( str ) - 1] != ':')
356         {
357                 /* Es sind noch Daten da, die gesendet werden muessen */
358                 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
359         }
360         
361         /* IRC-Operator? */
362         if( Client_HasMode( c, 'o' ))
363         {
364                 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
365         }
366
367         /* Idle (nur lokale Clients) */
368         if( Client_Conn( c ) > NONE )
369         {
370                 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
371         }
372
373         /* Away? */
374         if( Client_HasMode( c, 'a' ))
375         {
376                 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
377         }
378
379         /* End of Whois */
380         return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
381 } /* IRC_WHOIS */
382
383
384 GLOBAL BOOLEAN
385 IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
386 {
387         assert( Client != NULL );
388         assert( Req != NULL );
389
390         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
391
392         /* Falsche Anzahl Parameter? */
393         if(( Req->argc < 1 ) || ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
394
395         /* ... */
396
397         return CONNECTED;
398 } /* IRC_WHOWAS */
399
400
401 GLOBAL BOOLEAN
402 IRC_WHO( CLIENT *Client, REQUEST *Req )
403 {
404         BOOLEAN ok, only_ops;
405         CHAR flags[8], *ptr;
406         CL2CHAN *cl2chan;
407         CHANNEL *chan;
408         CLIENT *c;
409         
410         assert( Client != NULL );
411         assert( Req != NULL );
412
413         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
414
415         /* Falsche Anzahl Parameter? */
416         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
417
418         only_ops = FALSE;
419         chan = NULL;
420
421         if( Req->argc == 2 )
422         {
423                 /* Nur OPs anzeigen? */
424                 if( strcmp( Req->argv[1], "o" ) == 0 ) only_ops = TRUE;
425 #ifdef STRICT_RFC
426                 else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
427 #endif
428         }
429         
430         if( Req->argc >= 1 )
431         {
432                 /* wurde ein Channel oder Nick-Mask angegeben? */
433                 chan = Channel_Search( Req->argv[0] );
434         }
435
436         if( chan )
437         {
438                 /* User eines Channels ausgeben */
439                 if( ! IRC_Send_WHO( Client, chan, only_ops )) return DISCONNECTED;
440         }
441
442         c = Client_First( );
443         while( c )
444         {
445                 if(( Client_Type( c ) == CLIENT_USER ) && ( ! strchr( Client_Modes( c ), 'i' )))
446                 {
447                         ok = FALSE;
448                         if( Req->argc == 0 ) ok = TRUE;
449                         else
450                         {
451                                 if( strcasecmp( Req->argv[0], Client_ID( c )) == 0 ) ok = TRUE;
452                                 else if( strcmp( Req->argv[0], "0" ) == 0 ) ok = TRUE;
453                         }
454                                 
455                         if( ok && (( ! only_ops ) || ( strchr( Client_Modes( c ), 'o' ))))
456                         {
457                                 /* Flags zusammenbasteln */
458                                 strcpy( flags, "H" );
459                                 if( strchr( Client_Modes( c ), 'o' )) strcat( flags, "*" );
460
461                                 /* ausgeben */
462                                 cl2chan = Channel_FirstChannelOf( c );
463                                 if( cl2chan ) ptr = Channel_Name( Channel_GetChannel( cl2chan ));
464                                 else ptr = "*";
465                                 if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), ptr, Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
466                         }
467                 }
468
469                 /* naechster Client */
470                 c = Client_Next( c );
471         }
472
473         if( chan ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Channel_Name( chan ));
474         else if( Req->argc == 0 ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), "*" );
475         else return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Req->argv[0] );
476 } /* IRC_WHO */
477
478
479 GLOBAL BOOLEAN
480 IRC_USERHOST( CLIENT *Client, REQUEST *Req )
481 {
482         CHAR rpl[COMMAND_LEN];
483         CLIENT *c;
484         INT max, i;
485
486         assert( Client != NULL );
487         assert( Req != NULL );
488
489         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
490
491         /* Falsche Anzahl Parameter? */
492         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
493
494         if( Req->argc > 5 ) max = 5;
495         else max = Req->argc;
496         
497         strcpy( rpl, RPL_USERHOST_MSG );
498         for( i = 0; i < max; i++ )
499         {
500                 c = Client_Search( Req->argv[i] );
501                 if( c && ( Client_Type( c ) == CLIENT_USER ))
502                 {
503                         /* Dieser Nick ist "online" */
504                         strcat( rpl, Client_ID( c ));
505                         if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
506                         strcat( rpl, "=" );
507                         if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
508                         else strcat( rpl, "+" );
509                         strcat( rpl, Client_User( c ));
510                         strcat( rpl, "@" );
511                         strcat( rpl, Client_Hostname( c ));
512                         strcat( rpl, " " );
513                 }
514         }
515         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
516
517         return IRC_WriteStrClient( Client, "%s", rpl, Client_ID( Client ) );
518 } /* IRC_USERHOST */
519
520
521 GLOBAL BOOLEAN
522 IRC_ERROR( CLIENT *Client, REQUEST *Req )
523 {
524         assert( Client != NULL );
525         assert( Req != NULL );
526
527         if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
528         else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
529
530         return CONNECTED;
531 } /* IRC_ERROR */
532
533
534 GLOBAL BOOLEAN
535 IRC_LUSERS( CLIENT *Client, REQUEST *Req )
536 {
537         CLIENT *target, *from;
538         
539         assert( Client != NULL );
540         assert( Req != NULL );
541
542         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
543
544         /* Falsche Anzahl Parameter? */
545         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
546
547         /* Absender ermitteln */
548         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
549         else from = Client;
550         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
551
552         /* An anderen Server forwarden? */
553         if( Req->argc == 2 )
554         {
555                 target = Client_Search( Req->argv[1] );
556                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
557                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
558         }
559
560         /* Wer ist der Absender? */
561         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
562         else target = Client;
563         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
564         
565         IRC_Send_LUSERS( target );
566
567         return CONNECTED;
568 } /* IRC_LUSERS */
569
570
571 GLOBAL BOOLEAN
572 IRC_LINKS( CLIENT *Client, REQUEST *Req )
573 {
574         CLIENT *target, *from, *c;
575         CHAR *mask;
576         
577         assert( Client != NULL );
578         assert( Req != NULL );
579
580         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
581
582         /* Falsche Anzahl Parameter? */
583         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
584
585         /* Server-Mask ermitteln */
586         if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
587         else mask = "*";
588
589         /* Absender ermitteln */
590         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
591         else from = Client;
592         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
593         
594         /* An anderen Server forwarden? */
595         if( Req->argc == 2 )
596         {
597                 target = Client_Search( Req->argv[0] );
598                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
599                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
600         }
601
602         /* Wer ist der Absender? */
603         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
604         else target = Client;
605         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
606         
607         c = Client_First( );
608         while( c )
609         {
610                 if( Client_Type( c ) == CLIENT_SERVER )
611                 {
612                         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;
613                 }
614                 c = Client_Next( c );
615         }
616         
617         return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
618 } /* IRC_LINKS */
619
620
621 GLOBAL BOOLEAN
622 IRC_VERSION( CLIENT *Client, REQUEST *Req )
623 {
624         CLIENT *target, *prefix;
625         
626         assert( Client != NULL );
627         assert( Req != NULL );
628
629         /* Falsche Anzahl Parameter? */
630         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
631
632         /* Ziel suchen */
633         if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
634         else target = Client_ThisServer( );
635
636         /* Prefix ermitteln */
637         if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
638         else prefix = Client;
639         if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
640         
641         /* An anderen Server weiterleiten? */
642         if( target != Client_ThisServer( ))
643         {
644                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
645
646                 /* forwarden */
647                 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
648                 return CONNECTED;
649         }
650
651         /* mit Versionsinfo antworten */
652         return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), PACKAGE, VERSION, NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( ));
653 } /* IRC_VERSION */
654
655
656 GLOBAL BOOLEAN
657 IRC_KILL( CLIENT *Client, REQUEST *Req )
658 {
659         CLIENT *prefix, *c;
660         
661         assert( Client != NULL );
662         assert( Req != NULL );
663
664         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
665
666         /* Falsche Anzahl Parameter? */
667         if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
668
669         prefix = Client_Search( Req->prefix );
670         if( ! prefix )
671         {
672                 Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix );
673                 prefix = Client_ThisServer( );
674         }
675         
676         Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
677         
678         /* andere Server benachrichtigen */
679         IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] );
680
681         /* haben wir selber einen solchen Client? */
682         c = Client_Search( Req->argv[0] );
683         if( c )
684         {
685                 /* Ja, wir haben einen solchen Client */
686                 if( Client_Conn( c ) != NONE ) Conn_Close( Client_Conn( c ), NULL, Req->argv[1], TRUE );
687                 else Client_Destroy( c, NULL, Req->argv[1], TRUE );
688         }
689         else Log( LOG_NOTICE, "Client with nick \"%s\" is unknown here.", Req->argv[0] );
690
691         return CONNECTED;
692 } /* IRC_KILL */
693
694
695 GLOBAL BOOLEAN
696 IRC_ADMIN(CLIENT *Client, REQUEST *Req )
697 {
698         CLIENT *target, *prefix;
699
700         assert( Client != NULL );
701         assert( Req != NULL );
702
703         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
704
705         /* Falsche Anzahl Parameter? */
706         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
707
708         /* Ziel suchen */
709         if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
710         else target = Client_ThisServer( );
711
712         /* Prefix ermitteln */
713         if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
714         else prefix = Client;
715         if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
716
717         /* An anderen Server weiterleiten? */
718         if( target != Client_ThisServer( ))
719         {
720                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
721
722                 /* forwarden */
723                 IRC_WriteStrClientPrefix( target, prefix, "ADMIN %s", Req->argv[0] );
724                 return CONNECTED;
725         }
726
727         /* mit Versionsinfo antworten */
728         if( ! IRC_WriteStrClient( Client, RPL_ADMINME_MSG, Client_ID( prefix ), Conf_ServerName )) return DISCONNECTED;
729         if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC1_MSG, Client_ID( prefix ), Conf_ServerAdmin1 )) return DISCONNECTED;
730         if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC2_MSG, Client_ID( prefix ), Conf_ServerAdmin2 )) return DISCONNECTED;
731         if( ! IRC_WriteStrClient( Client, RPL_ADMINEMAIL_MSG, Client_ID( prefix ), Conf_ServerAdminMail )) return DISCONNECTED;
732
733         return CONNECTED;
734 } /* IRC_ADMIN */
735
736
737
738 GLOBAL BOOLEAN
739 IRC_Show_MOTD( CLIENT *Client )
740 {
741         BOOLEAN ok;
742         CHAR line[127];
743         FILE *fd;
744         
745         assert( Client != NULL );
746
747         fd = fopen( Conf_MotdFile, "r" );
748         if( ! fd )
749         {
750                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
751                 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
752         }
753         
754         IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
755         while( TRUE )
756         {
757                 if( ! fgets( line, 126, fd )) break;
758                 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
759                 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
760                 {
761                         fclose( fd );
762                         return FALSE;
763                 }
764         }
765         ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
766
767         fclose( fd );
768         
769         return ok;
770 } /* IRC_Show_MOTD */
771
772
773 GLOBAL BOOLEAN
774 IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
775 {
776         BOOLEAN is_visible, is_member;
777         CHAR str[LINE_LEN + 1];
778         CL2CHAN *cl2chan;
779         CLIENT *cl;
780         
781         assert( Client != NULL );
782         assert( Chan != NULL );
783
784         if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
785         else is_member = FALSE;
786                          
787         /* Alle Mitglieder suchen */
788         sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
789         cl2chan = Channel_FirstMember( Chan );
790         while( cl2chan )
791         {
792                 cl = Channel_GetClient( cl2chan );
793
794                 if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE;
795                 else is_visible = TRUE;
796
797                 if( is_member || is_visible )
798                 {
799                         /* Nick anhaengen */
800                         if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
801                         if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" );
802                         else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" );
803                         strcat( str, Client_ID( cl ));
804         
805                         if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
806                         {
807                                 /* Zeile wird zu lang: senden! */
808                                 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
809                                 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
810                         }
811                 }
812
813                 /* naechstes Mitglied suchen */
814                 cl2chan = Channel_NextMember( Chan, cl2chan );
815         }
816         if( str[strlen( str ) - 1] != ':')
817         {
818                 /* Es sind noch Daten da, die gesendet werden muessen */
819                 if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
820         }
821
822         return CONNECTED;
823 } /* IRC_Send_NAMES */
824
825
826 GLOBAL BOOLEAN
827 IRC_Send_WHO( CLIENT *Client, CHANNEL *Chan, BOOLEAN OnlyOps )
828 {
829         BOOLEAN is_visible, is_member;
830         CL2CHAN *cl2chan;
831         CHAR flags[8];
832         CLIENT *c;
833
834         assert( Client != NULL );
835         assert( Chan != NULL );
836
837         if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
838         else is_member = FALSE;
839
840         /* Alle Mitglieder suchen */
841         cl2chan = Channel_FirstMember( Chan );
842         while( cl2chan )
843         {
844                 c = Channel_GetClient( cl2chan );
845
846                 if( strchr( Client_Modes( c ), 'i' )) is_visible = FALSE;
847                 else is_visible = TRUE;
848
849                 if( is_member || is_visible )
850                 {
851                         /* Flags zusammenbasteln */
852                         strcpy( flags, "H" );
853                         if( strchr( Client_Modes( c ), 'o' )) strcat( flags, "*" );
854                         if( strchr( Channel_UserModes( Chan, c ), 'o' )) strcat( flags, "@" );
855                         else if( strchr( Channel_UserModes( Chan, c ), 'v' )) strcat( flags, "+" );
856                         
857                         /* ausgeben */
858                         if(( ! OnlyOps ) || ( strchr( Client_Modes( c ), 'o' )))
859                         {
860                                 if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), Channel_Name( Chan ), Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
861                         }
862                 }
863
864                 /* naechstes Mitglied suchen */
865                 cl2chan = Channel_NextMember( Chan, cl2chan );
866         }
867         return CONNECTED;
868 } /* IRC_Send_WHO */
869
870
871 GLOBAL BOOLEAN
872 IRC_Send_LUSERS( CLIENT *Client )
873 {
874         LONG cnt;
875
876         assert( Client != NULL );
877
878         /* Users, Services und Serevr im Netz */
879         if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
880
881         /* IRC-Operatoren im Netz */
882         cnt = Client_OperCount( );
883         if( cnt > 0 )
884         {
885                 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
886         }
887
888         /* Unbekannt Verbindungen */
889         cnt = Client_UnknownCount( );
890         if( cnt > 0 )
891         {
892                 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
893         }
894
895         /* Channels im Netz */
896         if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
897
898         /* Channels im Netz */
899         if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
900         
901         return CONNECTED;
902 } /* IRC_Send_LUSERS */
903
904
905 /* -eof- */