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