]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc.c
- einige Funktionen in irc-xxx-Module ausgegliedert.
[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.82 2002/02/27 23:26:36 alex Exp $
13  *
14  * irc.c: IRC-Befehle
15  *
16  * $Log: irc.c,v $
17  * Revision 1.82  2002/02/27 23:26:36  alex
18  * - einige Funktionen in irc-xxx-Module ausgegliedert.
19  *
20  * Revision 1.81  2002/02/27 20:55:44  alex
21  * - Channel-Topics werden nun auch korrekt von anderen Server angenommen.
22  *
23  * Revision 1.80  2002/02/27 20:33:13  alex
24  * - Channel-Topics implementiert.
25  *
26  * Revision 1.79  2002/02/27 18:57:21  alex
27  * - PRIVMSG zeugt nun bei Texten an User an, wenn diese "away" sind.
28  *
29  * Revision 1.78  2002/02/27 18:23:45  alex
30  * - IRC-Befehl "AWAY" implementert.
31  *
32  * Revision 1.77  2002/02/27 17:05:41  alex
33  * - PRIVMSG beachtet nun die Channel-Modes "n" und "m".
34  *
35  * Revision 1.76  2002/02/27 16:04:14  alex
36  * - Bug bei belegtem Nickname bei User-Registrierung (NICK-Befehl) behoben.
37  *
38  * Revision 1.75  2002/02/27 15:23:27  alex
39  * - NAMES beachtet nun das "invisible" Flag ("i") von Usern.
40  *
41  * Revision 1.74  2002/02/27 03:44:53  alex
42  * - gerade eben in SQUIT eingefuehrten Bug behoben: entfernte Server werden nun
43  *   nur noch geloescht, die Verbindung, von der SQUIT kam, bleibt wieder offen.
44  *
45  * Revision 1.73  2002/02/27 03:08:05  alex
46  * - Log-Meldungen bei SQUIT erneut ueberarbeitet ...
47  *
48  * Revision 1.72  2002/02/27 02:26:58  alex
49  * - SQUIT wird auf jeden Fall geforwarded, zudem besseres Logging.
50  *
51  * Revision 1.71  2002/02/27 00:50:05  alex
52  * - einige unnoetige Client_NextHop()-Aufrufe entfernt.
53  * - NAMES korrigiert und komplett implementiert.
54  *
55  * Revision 1.70  2002/02/26 22:06:40  alex
56  * - Nick-Aenderungen werden nun wieder korrekt ins Logfile geschrieben.
57  */
58
59
60 #include <portab.h>
61 #include "global.h"
62
63 #include <imp.h>
64 #include <assert.h>
65 #include <errno.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69
70 #include "ngircd.h"
71 #include "channel.h"
72 #include "client.h"
73 #include "conf.h"
74 #include "conn.h"
75 #include "irc-write.h"
76 #include "log.h"
77 #include "messages.h"
78 #include "tool.h"
79
80 #include <exp.h>
81 #include "irc.h"
82
83
84 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
85 {
86         assert( Client != NULL );
87         assert( Req != NULL );
88
89         if( Client_Type( Client ) != CLIENT_USER ) 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_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
93
94         return IRC_Show_MOTD( Client );
95 } /* IRC_MOTD */
96
97
98 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
99 {
100         BOOLEAN is_member, has_voice, is_op, ok;
101         CLIENT *cl, *from;
102         CHANNEL *chan;
103         
104         assert( Client != NULL );
105         assert( Req != NULL );
106
107         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
108
109         /* Falsche Anzahl Parameter? */
110         if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
111         if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
112         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
113
114         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
115         else from = Client;
116         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
117
118         cl = Client_Search( Req->argv[0] );
119         if( cl )
120         {
121                 /* Okay, Ziel ist ein User */
122                 if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' )))
123                 {
124                         /* Ziel-User ist AWAY: Meldung verschicken */
125                         if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( cl ), Client_Away( cl ))) return DISCONNECTED;
126                 }
127
128                 /* Text senden */
129                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
130                 return IRC_WriteStrClientPrefix( cl, from, "PRIVMSG %s :%s", Client_ID( cl ), Req->argv[1] );
131         }
132
133         chan = Channel_Search( Req->argv[0] );
134         if( chan )
135         {
136                 /* Okay, Ziel ist ein Channel */
137                 is_member = has_voice = is_op = FALSE;
138                 if( Channel_IsMemberOf( chan, from ))
139                 {
140                         is_member = TRUE;
141                         if( strchr( Channel_UserModes( chan, from ), 'v' )) has_voice = TRUE;
142                         if( strchr( Channel_UserModes( chan, from ), 'o' )) is_op = TRUE;
143                 }
144                 
145                 /* pruefen, ob Client in Channel schreiben darf */
146                 ok = TRUE;
147                 if( strchr( Channel_Modes( chan ), 'n' ) && ( ! is_member )) ok = FALSE;
148                 if( strchr( Channel_Modes( chan ), 'm' ) && ( ! is_op ) && ( ! has_voice )) ok = FALSE;
149
150                 if( ! ok ) return IRC_WriteStrClient( from, ERR_CANNOTSENDTOCHAN_MSG, Client_ID( from ), Req->argv[0] );
151
152                 /* Text senden */
153                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
154                 return IRC_WriteStrChannelPrefix( Client, chan, from, TRUE, "PRIVMSG %s :%s", Req->argv[0], Req->argv[1] );
155         }
156
157         return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
158 } /* IRC_PRIVMSG */
159
160
161 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
162 {
163         CLIENT *to, *from;
164
165         assert( Client != NULL );
166         assert( Req != NULL );
167
168         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
169
170         /* Falsche Anzahl Parameter? */
171         if( Req->argc != 2 ) return CONNECTED;
172
173         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
174         else from = Client;
175         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
176
177         to = Client_Search( Req->argv[0] );
178         if( to )
179         {
180                 /* Okay, Ziel ist ein User */
181                 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
182         }
183         else return CONNECTED;
184 } /* IRC_NOTICE */
185
186
187 GLOBAL BOOLEAN IRC_OPER( CLIENT *Client, REQUEST *Req )
188 {
189         INT i;
190         
191         assert( Client != NULL );
192         assert( Req != NULL );
193
194         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
195         
196         /* Falsche Anzahl Parameter? */
197         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
198
199         /* Operator suchen */
200         for( i = 0; i < Conf_Oper_Count; i++)
201         {
202                 if( Conf_Oper[i].name[0] && Conf_Oper[i].pwd[0] && ( strcmp( Conf_Oper[i].name, Req->argv[0] ) == 0 )) break;
203         }
204         if( i >= Conf_Oper_Count )
205         {
206                 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Name \"%s\" not configured!", Client_Mask( Client ), Req->argv[0] );
207                 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
208         }
209
210         /* Stimmt das Passwort? */
211         if( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 )
212         {
213                 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Bad password for \"%s\"!", Client_Mask( Client ), Conf_Oper[i].name );
214                 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
215         }
216         
217         if( ! Client_HasMode( Client, 'o' ))
218         {
219                 /* noch kein o-Mode gesetzt */
220                 Client_ModeAdd( Client, 'o' );
221                 if( ! IRC_WriteStrClient( Client, "MODE %s :+o", Client_ID( Client ))) return DISCONNECTED;
222                 IRC_WriteStrServersPrefix( NULL, Client, "MODE %s :+o", Client_ID( Client ));
223         }
224
225         if( ! Client_OperByMe( Client )) Log( LOG_NOTICE, "Got valid OPER from \"%s\", user is an IRC operator now.", Client_Mask( Client ));
226
227         Client_SetOperByMe( Client, TRUE );
228         return IRC_WriteStrClient( Client, RPL_YOUREOPER_MSG, Client_ID( Client ));
229 } /* IRC_OPER */
230
231
232 GLOBAL BOOLEAN IRC_DIE( CLIENT *Client, REQUEST *Req )
233 {
234         assert( Client != NULL );
235         assert( Req != NULL );
236
237         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
238
239         /* Falsche Anzahl Parameter? */
240         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
241
242         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
243
244         Log( LOG_NOTICE, "Got DIE command from \"%s\", going down!", Client_Mask( Client ));
245         NGIRCd_Quit = TRUE;
246         return CONNECTED;
247 } /* IRC_DIE */
248
249
250 GLOBAL BOOLEAN IRC_RESTART( CLIENT *Client, REQUEST *Req )
251 {
252         assert( Client != NULL );
253         assert( Req != NULL );
254
255         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
256
257         /* Falsche Anzahl Parameter? */
258         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
259
260         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
261
262         Log( LOG_NOTICE, "Got RESTART command from \"%s\", going down!", Client_Mask( Client ));
263         NGIRCd_Restart = TRUE;
264         return CONNECTED;
265 } /* IRC_RESTART */
266
267
268 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
269 {
270         CHAR rpl[COMMAND_LEN], *ptr;
271         CLIENT *target, *from, *c;
272         CHANNEL *chan;
273         
274         assert( Client != NULL );
275         assert( Req != NULL );
276
277         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
278
279         /* Falsche Anzahl Parameter? */
280         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
281
282         /* From aus Prefix ermitteln */
283         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
284         else from = Client;
285         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
286         
287         if( Req->argc == 2 )
288         {
289                 /* an anderen Server forwarden */
290                 target = Client_GetFromID( Req->argv[1] );
291                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
292
293                 if( target != Client_ThisServer( ))
294                 {
295                         /* Ok, anderer Server ist das Ziel: forwarden */
296                         return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
297                 }
298         }
299
300         if( Req->argc > 0 )
301         {
302                 /* bestimmte Channels durchgehen */
303                 ptr = strtok( Req->argv[0], "," );
304                 while( ptr )
305                 {
306                         chan = Channel_Search( ptr );
307                         if( chan )
308                         {
309                                 /* Namen ausgeben */
310                                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
311                         }
312                         if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
313                         
314                         /* naechsten Namen ermitteln */
315                         ptr = strtok( NULL, "," );
316                 }
317                 return CONNECTED;
318         }
319         
320         /* alle Channels durchgehen */
321         chan = Channel_First( );
322         while( chan )
323         {
324                 /* Namen ausgeben */
325                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
326
327                 /* naechster Channel */
328                 chan = Channel_Next( chan );
329         }
330
331         /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
332         c = Client_First( );
333         sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
334         while( c )
335         {
336                 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
337                 {
338                         /* Okay, das ist ein User: anhaengen */
339                         if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " );
340                         strcat( rpl, Client_ID( c ));
341
342                         if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
343                         {
344                                 /* Zeile wird zu lang: senden! */
345                                 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
346                                 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
347                         }
348                 }
349
350                 /* naechster Client */
351                 c = Client_Next( c );
352         }
353         if( rpl[strlen( rpl ) - 1] != ':')
354         {
355                 /* es wurden User gefunden */
356                 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
357         }
358         
359         return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
360 } /* IRC_NAMES */
361
362
363 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
364 {
365         CHAR rpl[COMMAND_LEN];
366         CLIENT *c;
367         CHAR *ptr;
368         INT i;
369         
370         assert( Client != NULL );
371         assert( Req != NULL );
372
373         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
374
375         /* Falsche Anzahl Parameter? */
376         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
377
378         strcpy( rpl, RPL_ISON_MSG );
379         for( i = 0; i < Req->argc; i++ )
380         {
381                 ptr = strtok( Req->argv[i], " " );
382                 while( ptr )
383                 {
384                         ngt_TrimStr( ptr );
385                         c = Client_GetFromID( ptr );
386                         if( c && ( Client_Type( c ) == CLIENT_USER ))
387                         {
388                                 /* Dieser Nick ist "online" */
389                                 strcat( rpl, ptr );
390                                 strcat( rpl, " " );
391                         }
392                         ptr = strtok( NULL, " " );
393                 }
394         }
395         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
396
397         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
398 } /* IRC_ISON */
399
400
401 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
402 {
403         CLIENT *from, *target, *c;
404         CHAR str[LINE_LEN + 1], *ptr = NULL;
405         CL2CHAN *cl2chan;
406         CHANNEL *chan;
407         
408         assert( Client != NULL );
409         assert( Req != NULL );
410
411         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
412
413         /* Falsche Anzahl Parameter? */
414         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
415
416         /* Client suchen */
417         c = Client_GetFromID( Req->argv[Req->argc - 1] );
418         if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
419
420         /* Empfaenger des WHOIS suchen */
421         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
422         else from = Client;
423         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
424         
425         /* Forwarden an anderen Server? */
426         if( Req->argc > 1 )
427         {
428                 /* angegebenen Ziel-Server suchen */
429                 target = Client_GetFromID( Req->argv[1] );
430                 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
431                 ptr = Req->argv[1];
432         }
433         else target = Client_ThisServer( );
434
435         assert( target != NULL );
436         
437         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 );
438         
439         /* Nick, User und Name */
440         if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
441
442         /* Server */
443         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;
444
445         /* Channels */
446         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
447         cl2chan = Channel_FirstChannelOf( c );
448         while( cl2chan )
449         {
450                 chan = Channel_GetChannel( cl2chan );
451                 assert( chan != NULL );
452                 
453                 /* Channel-Name anhaengen */
454                 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
455                 if( strchr( Channel_UserModes( chan, c ), 'v' )) strcat( str, "+" );
456                 if( strchr( Channel_UserModes( chan, c ), 'o' )) strcat( str, "@" );
457                 strcat( str, Channel_Name( chan ));
458
459                 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
460                 {
461                         /* Zeile wird zu lang: senden! */
462                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
463                         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
464                 }
465
466                 /* naechstes Mitglied suchen */
467                 cl2chan = Channel_NextChannelOf( c, cl2chan );
468         }
469         if( str[strlen( str ) - 1] != ':')
470         {
471                 /* Es sind noch Daten da, die gesendet werden muessen */
472                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
473         }
474         
475         /* IRC-Operator? */
476         if( Client_HasMode( c, 'o' ))
477         {
478                 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
479         }
480
481         /* Idle (nur lokale Clients) */
482         if( Client_Conn( c ) > NONE )
483         {
484                 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
485         }
486
487         /* Away? */
488         if( Client_HasMode( c, 'a' ))
489         {
490                 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
491         }
492
493         /* End of Whois */
494         return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
495 } /* IRC_WHOIS */
496
497
498 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
499 {
500         CHAR rpl[COMMAND_LEN];
501         CLIENT *c;
502         INT max, i;
503
504         assert( Client != NULL );
505         assert( Req != NULL );
506
507         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
508
509         /* Falsche Anzahl Parameter? */
510         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
511
512         if( Req->argc > 5 ) max = 5;
513         else max = Req->argc;
514         
515         strcpy( rpl, RPL_USERHOST_MSG );
516         for( i = 0; i < max; i++ )
517         {
518                 c = Client_GetFromID( Req->argv[i] );
519                 if( c && ( Client_Type( c ) == CLIENT_USER ))
520                 {
521                         /* Dieser Nick ist "online" */
522                         strcat( rpl, Client_ID( c ));
523                         if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
524                         strcat( rpl, "=" );
525                         if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
526                         else strcat( rpl, "+" );
527                         strcat( rpl, Client_User( c ));
528                         strcat( rpl, "@" );
529                         strcat( rpl, Client_Hostname( c ));
530                         strcat( rpl, " " );
531                 }
532         }
533         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
534
535         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
536 } /* IRC_USERHOST */
537
538
539 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
540 {
541         assert( Client != NULL );
542         assert( Req != NULL );
543
544         if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
545         else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
546
547         return CONNECTED;
548 } /* IRC_ERROR */
549
550
551 GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req )
552 {
553         CLIENT *target, *from;
554         
555         assert( Client != NULL );
556         assert( Req != NULL );
557
558         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
559
560         /* Falsche Anzahl Parameter? */
561         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
562
563         /* Absender ermitteln */
564         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
565         else from = Client;
566         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
567
568         /* An anderen Server forwarden? */
569         if( Req->argc == 2 )
570         {
571                 target = Client_GetFromID( Req->argv[1] );
572                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
573                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
574         }
575
576         /* Wer ist der Absender? */
577         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
578         else target = Client;
579         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
580         
581         IRC_Send_LUSERS( target );
582
583         return CONNECTED;
584 } /* IRC_LUSERS */
585
586
587 GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
588 {
589         CLIENT *target, *from, *c;
590         CHAR *mask;
591         
592         assert( Client != NULL );
593         assert( Req != NULL );
594
595         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
596
597         /* Falsche Anzahl Parameter? */
598         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
599
600         /* Server-Mask ermitteln */
601         if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
602         else mask = "*";
603
604         /* Absender ermitteln */
605         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
606         else from = Client;
607         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
608         
609         /* An anderen Server forwarden? */
610         if( Req->argc == 2 )
611         {
612                 target = Client_GetFromID( Req->argv[0] );
613                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
614                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
615         }
616
617         /* Wer ist der Absender? */
618         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
619         else target = Client;
620         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
621         
622         c = Client_First( );
623         while( c )
624         {
625                 if( Client_Type( c ) == CLIENT_SERVER )
626                 {
627                         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;
628                 }
629                 c = Client_Next( c );
630         }
631         
632         return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
633 } /* IRC_LINKS */
634
635
636 GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req )
637 {
638         CHAR *channame, *flags, *topic, modes[8];
639         BOOLEAN is_new_chan;
640         CLIENT *target;
641         CHANNEL *chan;
642         
643         assert( Client != NULL );
644         assert( Req != NULL );
645
646         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
647
648         /* Falsche Anzahl Parameter? */
649         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
650
651         /* Wer ist der Absender? */
652         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
653         else target = Client;
654         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
655         
656         /* Channel-Namen durchgehen */
657         channame = strtok( Req->argv[0], "," );
658         while( channame )
659         {
660                 /* wird der Channel neu angelegt? */
661                 flags = NULL;
662
663                 if( Channel_Search( channame )) is_new_chan = FALSE;
664                 else is_new_chan = TRUE;
665
666                 /* Hat ein Server Channel-User-Modes uebergeben? */
667                 if( Client_Type( Client ) == CLIENT_SERVER )
668                 {
669                         /* Channel-Flags extrahieren */
670                         flags = strchr( channame, 0x7 );
671                         if( flags ) *flags++ = '\0';
672                 }
673
674                 /* neuer Channel udn lokaler Client? */
675                 if( is_new_chan && ( Client_Type( Client ) == CLIENT_USER ))
676                 {
677                         /* Dann soll der Client Channel-Operator werden! */
678                         flags = "o";
679                 }
680
681                 /* Channel joinen (und ggf. anlegen) */
682                 if( ! Channel_Join( target, channame ))
683                 {
684                         /* naechsten Namen ermitteln */
685                         channame = strtok( NULL, "," );
686                         continue;
687                 }
688                 chan = Channel_Search( channame );
689                 assert( chan != NULL );
690
691                 /* Modes setzen (wenn vorhanden) */
692                 while( flags && *flags )
693                 {
694                         Channel_UserModeAdd( chan, target, *flags );
695                         flags++;
696                 }
697
698                 /* Muessen Modes an andere Server gemeldet werden? */
699                 strcpy( &modes[1], Channel_UserModes( chan, target ));
700                 if( modes[1] ) modes[0] = 0x7;
701                 else modes[0] = '\0';
702
703                 /* An andere Server weiterleiten */
704                 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
705
706                 /* im Channel bekannt machen */
707                 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
708                 if( modes[1] )
709                 {
710                         /* Modes im Channel bekannt machen */
711                         IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s %s :%s", channame, modes, Client_ID( target ));
712                 }
713
714                 if( Client_Type( Client ) == CLIENT_USER )
715                 {
716                         /* an Client bestaetigen */
717                         IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
718
719                         /* Topic an Client schicken */
720                         topic = Channel_Topic( chan );
721                         if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
722
723                         /* Mitglieder an Client Melden */
724                         IRC_Send_NAMES( Client, chan );
725                         IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
726                 }
727                 
728                 /* naechsten Namen ermitteln */
729                 channame = strtok( NULL, "," );
730         }
731         return CONNECTED;
732 } /* IRC_JOIN */
733
734
735 GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req )
736 {
737         CLIENT *target;
738         CHAR *chan;
739
740         assert( Client != NULL );
741         assert( Req != NULL );
742
743         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
744
745         /* Falsche Anzahl Parameter? */
746         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
747
748         /* Wer ist der Absender? */
749         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
750         else target = Client;
751         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
752
753         /* Channel-Namen durchgehen */
754         chan = strtok( Req->argv[0], "," );
755         while( chan )
756         {
757                 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
758                 {
759                         /* naechsten Namen ermitteln */
760                         chan = strtok( NULL, "," );
761                         continue;
762                 }
763
764                 /* naechsten Namen ermitteln */
765                 chan = strtok( NULL, "," );
766         }
767         return CONNECTED;
768 } /* IRC_PART */
769
770
771 GLOBAL BOOLEAN IRC_TOPIC( CLIENT *Client, REQUEST *Req )
772 {
773         CHANNEL *chan;
774         CLIENT *from;
775         CHAR *topic;
776         
777         assert( Client != NULL );
778         assert( Req != NULL );
779
780         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
781
782         /* Falsche Anzahl Parameter? */
783         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
784
785         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
786         else from = Client;
787         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
788
789         /* Welcher Channel? */
790         chan = Channel_Search( Req->argv[0] );
791         if( ! chan ) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
792
793         /* Ist der User Mitglied in dem Channel? */
794         if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
795
796         if( Req->argc == 1 )
797         {
798                 /* Topic erfragen */
799                 topic = Channel_Topic( chan );
800                 if( *topic ) return IRC_WriteStrClient( from, RPL_TOPIC_MSG, Client_ID( from ), Channel_Name( chan ), topic );
801                 else return IRC_WriteStrClient( from, RPL_NOTOPIC_MSG, Client_ID( from ), Channel_Name( chan ));
802         }
803
804         if( strchr( Channel_Modes( chan ), 't' ))
805         {
806                 /* Topic Lock. Ist der User ein Channel Operator? */
807                 if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
808         }
809
810         /* Topic setzen */
811         Channel_SetTopic( chan, Req->argv[1] );
812         Log( LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s", Client_Mask( from ), Channel_Name( chan ), Req->argv[1][0] ? Req->argv[1] : "<none>" );
813
814         /* im Channel bekannt machen */
815         IRC_WriteStrChannelPrefix( Client, chan, from, TRUE, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
816         return IRC_WriteStrClientPrefix( from, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
817 } /* IRC_TOPIC */
818
819
820 GLOBAL BOOLEAN IRC_VERSION( CLIENT *Client, REQUEST *Req )
821 {
822         CLIENT *target, *prefix;
823         
824         assert( Client != NULL );
825         assert( Req != NULL );
826
827         /* Falsche Anzahl Parameter? */
828         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
829
830         /* Ziel suchen */
831         if( Req->argc == 1 ) target = Client_GetFromID( Req->argv[0] );
832         else target = Client_ThisServer( );
833
834         /* Prefix ermitteln */
835         if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_GetFromID( Req->prefix );
836         else prefix = Client;
837         if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
838         
839         /* An anderen Server weiterleiten? */
840         if( target != Client_ThisServer( ))
841         {
842                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
843
844                 /* forwarden */
845                 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
846                 return CONNECTED;
847         }
848
849         /* mit Versionsinfo antworten */
850         return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( ));
851 } /* IRC_VERSION */
852
853
854 GLOBAL BOOLEAN IRC_KILL( CLIENT *Client, REQUEST *Req )
855 {
856         CLIENT *prefix, *c;
857         
858         assert( Client != NULL );
859         assert( Req != NULL );
860
861         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
862
863         /* Falsche Anzahl Parameter? */
864         if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
865
866         prefix = Client_GetFromID( Req->prefix );
867         if( ! prefix )
868         {
869                 Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix );
870                 prefix = Client_ThisServer( );
871         }
872         
873         Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
874         
875         /* andere Server benachrichtigen */
876         IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] );
877
878         /* haben wir selber einen solchen Client? */
879         c = Client_GetFromID( Req->argv[0] );
880         if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Req->argv[1], TRUE );
881         
882         return CONNECTED;
883 } /* IRC_KILL */
884
885
886 GLOBAL BOOLEAN IRC_Show_MOTD( CLIENT *Client )
887 {
888         BOOLEAN ok;
889         CHAR line[127];
890         FILE *fd;
891         
892         assert( Client != NULL );
893
894         fd = fopen( Conf_MotdFile, "r" );
895         if( ! fd )
896         {
897                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
898                 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
899         }
900         
901         IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
902         while( TRUE )
903         {
904                 if( ! fgets( line, 126, fd )) break;
905                 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
906                 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
907                 {
908                         fclose( fd );
909                         return FALSE;
910                 }
911         }
912         ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
913
914         fclose( fd );
915         
916         return ok;
917 } /* IRC_Show_MOTD */
918
919
920 GLOBAL BOOLEAN IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
921 {
922         BOOLEAN is_visible, is_member;
923         CHAR str[LINE_LEN + 1];
924         CL2CHAN *cl2chan;
925         CLIENT *cl;
926         
927         assert( Client != NULL );
928         assert( Chan != NULL );
929
930         if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
931         else is_member = FALSE;
932                          
933         /* Alle Mitglieder suchen */
934         sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
935         cl2chan = Channel_FirstMember( Chan );
936         while( cl2chan )
937         {
938                 cl = Channel_GetClient( cl2chan );
939
940                 if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE;
941                 else is_visible = TRUE;
942
943                 if( is_member || is_visible )
944                 {
945                         /* Nick anhaengen */
946                         if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
947                         if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" );
948                         if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" );
949                         strcat( str, Client_ID( cl ));
950         
951                         if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
952                         {
953                                 /* Zeile wird zu lang: senden! */
954                                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
955                                 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
956                         }
957                 }
958
959                 /* naechstes Mitglied suchen */
960                 cl2chan = Channel_NextMember( Chan, cl2chan );
961         }
962         if( str[strlen( str ) - 1] != ':')
963         {
964                 /* Es sind noch Daten da, die gesendet werden muessen */
965                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
966         }
967
968         return CONNECTED;
969 } /* IRC_Send_NAMES */
970
971
972 GLOBAL BOOLEAN IRC_Send_LUSERS( CLIENT *Client )
973 {
974         INT cnt;
975
976         assert( Client != NULL );
977
978         /* Users, Services und Serevr im Netz */
979         if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
980
981         /* IRC-Operatoren im Netz */
982         cnt = Client_OperCount( );
983         if( cnt > 0 )
984         {
985                 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
986         }
987
988         /* Unbekannt Verbindungen */
989         cnt = Client_UnknownCount( );
990         if( cnt > 0 )
991         {
992                 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
993         }
994
995         /* Channels im Netz */
996         if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
997
998         /* Channels im Netz */
999         if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
1000         
1001         return CONNECTED;
1002 } /* IRC_Send_LUSERS */
1003
1004
1005 /* -eof- */