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