2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
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.
12 * $Id: irc.c,v 1.82 2002/02/27 23:26:36 alex Exp $
17 * Revision 1.82 2002/02/27 23:26:36 alex
18 * - einige Funktionen in irc-xxx-Module ausgegliedert.
20 * Revision 1.81 2002/02/27 20:55:44 alex
21 * - Channel-Topics werden nun auch korrekt von anderen Server angenommen.
23 * Revision 1.80 2002/02/27 20:33:13 alex
24 * - Channel-Topics implementiert.
26 * Revision 1.79 2002/02/27 18:57:21 alex
27 * - PRIVMSG zeugt nun bei Texten an User an, wenn diese "away" sind.
29 * Revision 1.78 2002/02/27 18:23:45 alex
30 * - IRC-Befehl "AWAY" implementert.
32 * Revision 1.77 2002/02/27 17:05:41 alex
33 * - PRIVMSG beachtet nun die Channel-Modes "n" und "m".
35 * Revision 1.76 2002/02/27 16:04:14 alex
36 * - Bug bei belegtem Nickname bei User-Registrierung (NICK-Befehl) behoben.
38 * Revision 1.75 2002/02/27 15:23:27 alex
39 * - NAMES beachtet nun das "invisible" Flag ("i") von Usern.
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.
45 * Revision 1.73 2002/02/27 03:08:05 alex
46 * - Log-Meldungen bei SQUIT erneut ueberarbeitet ...
48 * Revision 1.72 2002/02/27 02:26:58 alex
49 * - SQUIT wird auf jeden Fall geforwarded, zudem besseres Logging.
51 * Revision 1.71 2002/02/27 00:50:05 alex
52 * - einige unnoetige Client_NextHop()-Aufrufe entfernt.
53 * - NAMES korrigiert und komplett implementiert.
55 * Revision 1.70 2002/02/26 22:06:40 alex
56 * - Nick-Aenderungen werden nun wieder korrekt ins Logfile geschrieben.
75 #include "irc-write.h"
84 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
86 assert( Client != NULL );
87 assert( Req != NULL );
89 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
91 /* Falsche Anzahl Parameter? */
92 if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
94 return IRC_Show_MOTD( Client );
98 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
100 BOOLEAN is_member, has_voice, is_op, ok;
104 assert( Client != NULL );
105 assert( Req != NULL );
107 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
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 );
114 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
116 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
118 cl = Client_Search( Req->argv[0] );
121 /* Okay, Ziel ist ein User */
122 if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' )))
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;
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] );
133 chan = Channel_Search( Req->argv[0] );
136 /* Okay, Ziel ist ein Channel */
137 is_member = has_voice = is_op = FALSE;
138 if( Channel_IsMemberOf( chan, from ))
141 if( strchr( Channel_UserModes( chan, from ), 'v' )) has_voice = TRUE;
142 if( strchr( Channel_UserModes( chan, from ), 'o' )) is_op = TRUE;
145 /* pruefen, ob Client in Channel schreiben darf */
147 if( strchr( Channel_Modes( chan ), 'n' ) && ( ! is_member )) ok = FALSE;
148 if( strchr( Channel_Modes( chan ), 'm' ) && ( ! is_op ) && ( ! has_voice )) ok = FALSE;
150 if( ! ok ) return IRC_WriteStrClient( from, ERR_CANNOTSENDTOCHAN_MSG, Client_ID( from ), Req->argv[0] );
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] );
157 return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
161 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
165 assert( Client != NULL );
166 assert( Req != NULL );
168 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
170 /* Falsche Anzahl Parameter? */
171 if( Req->argc != 2 ) return CONNECTED;
173 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
175 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
177 to = Client_Search( Req->argv[0] );
180 /* Okay, Ziel ist ein User */
181 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
183 else return CONNECTED;
187 GLOBAL BOOLEAN IRC_OPER( CLIENT *Client, REQUEST *Req )
191 assert( Client != NULL );
192 assert( Req != NULL );
194 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
196 /* Falsche Anzahl Parameter? */
197 if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
199 /* Operator suchen */
200 for( i = 0; i < Conf_Oper_Count; i++)
202 if( Conf_Oper[i].name[0] && Conf_Oper[i].pwd[0] && ( strcmp( Conf_Oper[i].name, Req->argv[0] ) == 0 )) break;
204 if( i >= Conf_Oper_Count )
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 ));
210 /* Stimmt das Passwort? */
211 if( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 )
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 ));
217 if( ! Client_HasMode( Client, 'o' ))
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 ));
225 if( ! Client_OperByMe( Client )) Log( LOG_NOTICE, "Got valid OPER from \"%s\", user is an IRC operator now.", Client_Mask( Client ));
227 Client_SetOperByMe( Client, TRUE );
228 return IRC_WriteStrClient( Client, RPL_YOUREOPER_MSG, Client_ID( Client ));
232 GLOBAL BOOLEAN IRC_DIE( CLIENT *Client, REQUEST *Req )
234 assert( Client != NULL );
235 assert( Req != NULL );
237 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
239 /* Falsche Anzahl Parameter? */
240 if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
242 if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
244 Log( LOG_NOTICE, "Got DIE command from \"%s\", going down!", Client_Mask( Client ));
250 GLOBAL BOOLEAN IRC_RESTART( CLIENT *Client, REQUEST *Req )
252 assert( Client != NULL );
253 assert( Req != NULL );
255 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
257 /* Falsche Anzahl Parameter? */
258 if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
260 if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
262 Log( LOG_NOTICE, "Got RESTART command from \"%s\", going down!", Client_Mask( Client ));
263 NGIRCd_Restart = TRUE;
268 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
270 CHAR rpl[COMMAND_LEN], *ptr;
271 CLIENT *target, *from, *c;
274 assert( Client != NULL );
275 assert( Req != NULL );
277 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
279 /* Falsche Anzahl Parameter? */
280 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
282 /* From aus Prefix ermitteln */
283 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
285 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
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] );
293 if( target != Client_ThisServer( ))
295 /* Ok, anderer Server ist das Ziel: forwarden */
296 return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
302 /* bestimmte Channels durchgehen */
303 ptr = strtok( Req->argv[0], "," );
306 chan = Channel_Search( ptr );
310 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
312 if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
314 /* naechsten Namen ermitteln */
315 ptr = strtok( NULL, "," );
320 /* alle Channels durchgehen */
321 chan = Channel_First( );
325 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
327 /* naechster Channel */
328 chan = Channel_Next( chan );
331 /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
333 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
336 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
338 /* Okay, das ist ein User: anhaengen */
339 if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " );
340 strcat( rpl, Client_ID( c ));
342 if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
344 /* Zeile wird zu lang: senden! */
345 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
346 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
350 /* naechster Client */
351 c = Client_Next( c );
353 if( rpl[strlen( rpl ) - 1] != ':')
355 /* es wurden User gefunden */
356 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
359 return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
363 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
365 CHAR rpl[COMMAND_LEN];
370 assert( Client != NULL );
371 assert( Req != NULL );
373 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
375 /* Falsche Anzahl Parameter? */
376 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
378 strcpy( rpl, RPL_ISON_MSG );
379 for( i = 0; i < Req->argc; i++ )
381 ptr = strtok( Req->argv[i], " " );
385 c = Client_GetFromID( ptr );
386 if( c && ( Client_Type( c ) == CLIENT_USER ))
388 /* Dieser Nick ist "online" */
392 ptr = strtok( NULL, " " );
395 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
397 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
401 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
403 CLIENT *from, *target, *c;
404 CHAR str[LINE_LEN + 1], *ptr = NULL;
408 assert( Client != NULL );
409 assert( Req != NULL );
411 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
413 /* Falsche Anzahl Parameter? */
414 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
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] );
420 /* Empfaenger des WHOIS suchen */
421 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
423 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
425 /* Forwarden an anderen Server? */
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] );
433 else target = Client_ThisServer( );
435 assert( target != NULL );
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 );
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;
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;
446 sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
447 cl2chan = Channel_FirstChannelOf( c );
450 chan = Channel_GetChannel( cl2chan );
451 assert( chan != NULL );
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 ));
459 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
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 ));
466 /* naechstes Mitglied suchen */
467 cl2chan = Channel_NextChannelOf( c, cl2chan );
469 if( str[strlen( str ) - 1] != ':')
471 /* Es sind noch Daten da, die gesendet werden muessen */
472 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
476 if( Client_HasMode( c, 'o' ))
478 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
481 /* Idle (nur lokale Clients) */
482 if( Client_Conn( c ) > NONE )
484 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
488 if( Client_HasMode( c, 'a' ))
490 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
494 return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
498 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
500 CHAR rpl[COMMAND_LEN];
504 assert( Client != NULL );
505 assert( Req != NULL );
507 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
509 /* Falsche Anzahl Parameter? */
510 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
512 if( Req->argc > 5 ) max = 5;
513 else max = Req->argc;
515 strcpy( rpl, RPL_USERHOST_MSG );
516 for( i = 0; i < max; i++ )
518 c = Client_GetFromID( Req->argv[i] );
519 if( c && ( Client_Type( c ) == CLIENT_USER ))
521 /* Dieser Nick ist "online" */
522 strcat( rpl, Client_ID( c ));
523 if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
525 if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
526 else strcat( rpl, "+" );
527 strcat( rpl, Client_User( c ));
529 strcat( rpl, Client_Hostname( c ));
533 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
535 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
539 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
541 assert( Client != NULL );
542 assert( Req != NULL );
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] );
551 GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req )
553 CLIENT *target, *from;
555 assert( Client != NULL );
556 assert( Req != NULL );
558 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
560 /* Falsche Anzahl Parameter? */
561 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
563 /* Absender ermitteln */
564 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
566 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
568 /* An anderen Server forwarden? */
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] );
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 );
581 IRC_Send_LUSERS( target );
587 GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
589 CLIENT *target, *from, *c;
592 assert( Client != NULL );
593 assert( Req != NULL );
595 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
597 /* Falsche Anzahl Parameter? */
598 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
600 /* Server-Mask ermitteln */
601 if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
604 /* Absender ermitteln */
605 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
607 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
609 /* An anderen Server forwarden? */
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] );
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 );
625 if( Client_Type( c ) == CLIENT_SERVER )
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;
629 c = Client_Next( c );
632 return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
636 GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req )
638 CHAR *channame, *flags, *topic, modes[8];
643 assert( Client != NULL );
644 assert( Req != NULL );
646 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
648 /* Falsche Anzahl Parameter? */
649 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
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 );
656 /* Channel-Namen durchgehen */
657 channame = strtok( Req->argv[0], "," );
660 /* wird der Channel neu angelegt? */
663 if( Channel_Search( channame )) is_new_chan = FALSE;
664 else is_new_chan = TRUE;
666 /* Hat ein Server Channel-User-Modes uebergeben? */
667 if( Client_Type( Client ) == CLIENT_SERVER )
669 /* Channel-Flags extrahieren */
670 flags = strchr( channame, 0x7 );
671 if( flags ) *flags++ = '\0';
674 /* neuer Channel udn lokaler Client? */
675 if( is_new_chan && ( Client_Type( Client ) == CLIENT_USER ))
677 /* Dann soll der Client Channel-Operator werden! */
681 /* Channel joinen (und ggf. anlegen) */
682 if( ! Channel_Join( target, channame ))
684 /* naechsten Namen ermitteln */
685 channame = strtok( NULL, "," );
688 chan = Channel_Search( channame );
689 assert( chan != NULL );
691 /* Modes setzen (wenn vorhanden) */
692 while( flags && *flags )
694 Channel_UserModeAdd( chan, target, *flags );
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';
703 /* An andere Server weiterleiten */
704 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
706 /* im Channel bekannt machen */
707 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
710 /* Modes im Channel bekannt machen */
711 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s %s :%s", channame, modes, Client_ID( target ));
714 if( Client_Type( Client ) == CLIENT_USER )
716 /* an Client bestaetigen */
717 IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
719 /* Topic an Client schicken */
720 topic = Channel_Topic( chan );
721 if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
723 /* Mitglieder an Client Melden */
724 IRC_Send_NAMES( Client, chan );
725 IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
728 /* naechsten Namen ermitteln */
729 channame = strtok( NULL, "," );
735 GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req )
740 assert( Client != NULL );
741 assert( Req != NULL );
743 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
745 /* Falsche Anzahl Parameter? */
746 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
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 );
753 /* Channel-Namen durchgehen */
754 chan = strtok( Req->argv[0], "," );
757 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
759 /* naechsten Namen ermitteln */
760 chan = strtok( NULL, "," );
764 /* naechsten Namen ermitteln */
765 chan = strtok( NULL, "," );
771 GLOBAL BOOLEAN IRC_TOPIC( CLIENT *Client, REQUEST *Req )
777 assert( Client != NULL );
778 assert( Req != NULL );
780 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
782 /* Falsche Anzahl Parameter? */
783 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
785 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
787 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
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] );
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] );
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 ));
804 if( strchr( Channel_Modes( chan ), 't' ))
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 ));
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>" );
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] );
820 GLOBAL BOOLEAN IRC_VERSION( CLIENT *Client, REQUEST *Req )
822 CLIENT *target, *prefix;
824 assert( Client != NULL );
825 assert( Req != NULL );
827 /* Falsche Anzahl Parameter? */
828 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
831 if( Req->argc == 1 ) target = Client_GetFromID( Req->argv[0] );
832 else target = Client_ThisServer( );
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 );
839 /* An anderen Server weiterleiten? */
840 if( target != Client_ThisServer( ))
842 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
845 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
849 /* mit Versionsinfo antworten */
850 return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( ));
854 GLOBAL BOOLEAN IRC_KILL( CLIENT *Client, REQUEST *Req )
858 assert( Client != NULL );
859 assert( Req != NULL );
861 if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
863 /* Falsche Anzahl Parameter? */
864 if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
866 prefix = Client_GetFromID( Req->prefix );
869 Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix );
870 prefix = Client_ThisServer( );
873 Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
875 /* andere Server benachrichtigen */
876 IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] );
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 );
886 GLOBAL BOOLEAN IRC_Show_MOTD( CLIENT *Client )
892 assert( Client != NULL );
894 fd = fopen( Conf_MotdFile, "r" );
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 ) );
901 IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
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 ))
912 ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
917 } /* IRC_Show_MOTD */
920 GLOBAL BOOLEAN IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
922 BOOLEAN is_visible, is_member;
923 CHAR str[LINE_LEN + 1];
927 assert( Client != NULL );
928 assert( Chan != NULL );
930 if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
931 else is_member = FALSE;
933 /* Alle Mitglieder suchen */
934 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
935 cl2chan = Channel_FirstMember( Chan );
938 cl = Channel_GetClient( cl2chan );
940 if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE;
941 else is_visible = TRUE;
943 if( is_member || is_visible )
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 ));
951 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
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 ));
959 /* naechstes Mitglied suchen */
960 cl2chan = Channel_NextMember( Chan, cl2chan );
962 if( str[strlen( str ) - 1] != ':')
964 /* Es sind noch Daten da, die gesendet werden muessen */
965 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
969 } /* IRC_Send_NAMES */
972 GLOBAL BOOLEAN IRC_Send_LUSERS( CLIENT *Client )
976 assert( Client != NULL );
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;
981 /* IRC-Operatoren im Netz */
982 cnt = Client_OperCount( );
985 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
988 /* Unbekannt Verbindungen */
989 cnt = Client_UnknownCount( );
992 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
995 /* Channels im Netz */
996 if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
998 /* Channels im Netz */
999 if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
1002 } /* IRC_Send_LUSERS */