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.83 2002/02/28 00:48:26 alex Exp $
17 * Revision 1.83 2002/02/28 00:48:26 alex
18 * - Forwarding von TOPIC an andere Server gefixed. Hoffentlich ;-)
20 * Revision 1.82 2002/02/27 23:26:36 alex
21 * - einige Funktionen in irc-xxx-Module ausgegliedert.
23 * Revision 1.81 2002/02/27 20:55:44 alex
24 * - Channel-Topics werden nun auch korrekt von anderen Server angenommen.
26 * Revision 1.80 2002/02/27 20:33:13 alex
27 * - Channel-Topics implementiert.
29 * Revision 1.79 2002/02/27 18:57:21 alex
30 * - PRIVMSG zeugt nun bei Texten an User an, wenn diese "away" sind.
32 * Revision 1.78 2002/02/27 18:23:45 alex
33 * - IRC-Befehl "AWAY" implementert.
35 * Revision 1.77 2002/02/27 17:05:41 alex
36 * - PRIVMSG beachtet nun die Channel-Modes "n" und "m".
38 * Revision 1.76 2002/02/27 16:04:14 alex
39 * - Bug bei belegtem Nickname bei User-Registrierung (NICK-Befehl) behoben.
41 * Revision 1.75 2002/02/27 15:23:27 alex
42 * - NAMES beachtet nun das "invisible" Flag ("i") von Usern.
44 * Revision 1.74 2002/02/27 03:44:53 alex
45 * - gerade eben in SQUIT eingefuehrten Bug behoben: entfernte Server werden nun
46 * nur noch geloescht, die Verbindung, von der SQUIT kam, bleibt wieder offen.
48 * Revision 1.73 2002/02/27 03:08:05 alex
49 * - Log-Meldungen bei SQUIT erneut ueberarbeitet ...
51 * Revision 1.72 2002/02/27 02:26:58 alex
52 * - SQUIT wird auf jeden Fall geforwarded, zudem besseres Logging.
54 * Revision 1.71 2002/02/27 00:50:05 alex
55 * - einige unnoetige Client_NextHop()-Aufrufe entfernt.
56 * - NAMES korrigiert und komplett implementiert.
58 * Revision 1.70 2002/02/26 22:06:40 alex
59 * - Nick-Aenderungen werden nun wieder korrekt ins Logfile geschrieben.
78 #include "irc-write.h"
87 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
89 assert( Client != NULL );
90 assert( Req != NULL );
92 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
94 /* Falsche Anzahl Parameter? */
95 if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
97 return IRC_Show_MOTD( Client );
101 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
103 BOOLEAN is_member, has_voice, is_op, ok;
107 assert( Client != NULL );
108 assert( Req != NULL );
110 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
112 /* Falsche Anzahl Parameter? */
113 if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
114 if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
115 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
117 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
119 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
121 cl = Client_Search( Req->argv[0] );
124 /* Okay, Ziel ist ein User */
125 if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' )))
127 /* Ziel-User ist AWAY: Meldung verschicken */
128 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( cl ), Client_Away( cl ))) return DISCONNECTED;
132 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
133 return IRC_WriteStrClientPrefix( cl, from, "PRIVMSG %s :%s", Client_ID( cl ), Req->argv[1] );
136 chan = Channel_Search( Req->argv[0] );
139 /* Okay, Ziel ist ein Channel */
140 is_member = has_voice = is_op = FALSE;
141 if( Channel_IsMemberOf( chan, from ))
144 if( strchr( Channel_UserModes( chan, from ), 'v' )) has_voice = TRUE;
145 if( strchr( Channel_UserModes( chan, from ), 'o' )) is_op = TRUE;
148 /* pruefen, ob Client in Channel schreiben darf */
150 if( strchr( Channel_Modes( chan ), 'n' ) && ( ! is_member )) ok = FALSE;
151 if( strchr( Channel_Modes( chan ), 'm' ) && ( ! is_op ) && ( ! has_voice )) ok = FALSE;
153 if( ! ok ) return IRC_WriteStrClient( from, ERR_CANNOTSENDTOCHAN_MSG, Client_ID( from ), Req->argv[0] );
156 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
157 return IRC_WriteStrChannelPrefix( Client, chan, from, TRUE, "PRIVMSG %s :%s", Req->argv[0], Req->argv[1] );
160 return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
164 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
168 assert( Client != NULL );
169 assert( Req != NULL );
171 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
173 /* Falsche Anzahl Parameter? */
174 if( Req->argc != 2 ) return CONNECTED;
176 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
178 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
180 to = Client_Search( Req->argv[0] );
183 /* Okay, Ziel ist ein User */
184 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
186 else return CONNECTED;
190 GLOBAL BOOLEAN IRC_OPER( CLIENT *Client, REQUEST *Req )
194 assert( Client != NULL );
195 assert( Req != NULL );
197 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
199 /* Falsche Anzahl Parameter? */
200 if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
202 /* Operator suchen */
203 for( i = 0; i < Conf_Oper_Count; i++)
205 if( Conf_Oper[i].name[0] && Conf_Oper[i].pwd[0] && ( strcmp( Conf_Oper[i].name, Req->argv[0] ) == 0 )) break;
207 if( i >= Conf_Oper_Count )
209 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Name \"%s\" not configured!", Client_Mask( Client ), Req->argv[0] );
210 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
213 /* Stimmt das Passwort? */
214 if( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 )
216 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Bad password for \"%s\"!", Client_Mask( Client ), Conf_Oper[i].name );
217 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
220 if( ! Client_HasMode( Client, 'o' ))
222 /* noch kein o-Mode gesetzt */
223 Client_ModeAdd( Client, 'o' );
224 if( ! IRC_WriteStrClient( Client, "MODE %s :+o", Client_ID( Client ))) return DISCONNECTED;
225 IRC_WriteStrServersPrefix( NULL, Client, "MODE %s :+o", Client_ID( Client ));
228 if( ! Client_OperByMe( Client )) Log( LOG_NOTICE, "Got valid OPER from \"%s\", user is an IRC operator now.", Client_Mask( Client ));
230 Client_SetOperByMe( Client, TRUE );
231 return IRC_WriteStrClient( Client, RPL_YOUREOPER_MSG, Client_ID( Client ));
235 GLOBAL BOOLEAN IRC_DIE( CLIENT *Client, REQUEST *Req )
237 assert( Client != NULL );
238 assert( Req != NULL );
240 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
242 /* Falsche Anzahl Parameter? */
243 if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
245 if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
247 Log( LOG_NOTICE, "Got DIE command from \"%s\", going down!", Client_Mask( Client ));
253 GLOBAL BOOLEAN IRC_RESTART( CLIENT *Client, REQUEST *Req )
255 assert( Client != NULL );
256 assert( Req != NULL );
258 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
260 /* Falsche Anzahl Parameter? */
261 if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
263 if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
265 Log( LOG_NOTICE, "Got RESTART command from \"%s\", going down!", Client_Mask( Client ));
266 NGIRCd_Restart = TRUE;
271 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
273 CHAR rpl[COMMAND_LEN], *ptr;
274 CLIENT *target, *from, *c;
277 assert( Client != NULL );
278 assert( Req != NULL );
280 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
282 /* Falsche Anzahl Parameter? */
283 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
285 /* From aus Prefix ermitteln */
286 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
288 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
292 /* an anderen Server forwarden */
293 target = Client_GetFromID( Req->argv[1] );
294 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
296 if( target != Client_ThisServer( ))
298 /* Ok, anderer Server ist das Ziel: forwarden */
299 return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
305 /* bestimmte Channels durchgehen */
306 ptr = strtok( Req->argv[0], "," );
309 chan = Channel_Search( ptr );
313 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
315 if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
317 /* naechsten Namen ermitteln */
318 ptr = strtok( NULL, "," );
323 /* alle Channels durchgehen */
324 chan = Channel_First( );
328 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
330 /* naechster Channel */
331 chan = Channel_Next( chan );
334 /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
336 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
339 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
341 /* Okay, das ist ein User: anhaengen */
342 if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " );
343 strcat( rpl, Client_ID( c ));
345 if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
347 /* Zeile wird zu lang: senden! */
348 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
349 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
353 /* naechster Client */
354 c = Client_Next( c );
356 if( rpl[strlen( rpl ) - 1] != ':')
358 /* es wurden User gefunden */
359 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
362 return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
366 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
368 CHAR rpl[COMMAND_LEN];
373 assert( Client != NULL );
374 assert( Req != NULL );
376 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
378 /* Falsche Anzahl Parameter? */
379 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
381 strcpy( rpl, RPL_ISON_MSG );
382 for( i = 0; i < Req->argc; i++ )
384 ptr = strtok( Req->argv[i], " " );
388 c = Client_GetFromID( ptr );
389 if( c && ( Client_Type( c ) == CLIENT_USER ))
391 /* Dieser Nick ist "online" */
395 ptr = strtok( NULL, " " );
398 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
400 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
404 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
406 CLIENT *from, *target, *c;
407 CHAR str[LINE_LEN + 1], *ptr = NULL;
411 assert( Client != NULL );
412 assert( Req != NULL );
414 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
416 /* Falsche Anzahl Parameter? */
417 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
420 c = Client_GetFromID( Req->argv[Req->argc - 1] );
421 if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
423 /* Empfaenger des WHOIS suchen */
424 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
426 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
428 /* Forwarden an anderen Server? */
431 /* angegebenen Ziel-Server suchen */
432 target = Client_GetFromID( Req->argv[1] );
433 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
436 else target = Client_ThisServer( );
438 assert( target != NULL );
440 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 );
442 /* Nick, User und Name */
443 if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
446 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;
449 sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
450 cl2chan = Channel_FirstChannelOf( c );
453 chan = Channel_GetChannel( cl2chan );
454 assert( chan != NULL );
456 /* Channel-Name anhaengen */
457 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
458 if( strchr( Channel_UserModes( chan, c ), 'v' )) strcat( str, "+" );
459 if( strchr( Channel_UserModes( chan, c ), 'o' )) strcat( str, "@" );
460 strcat( str, Channel_Name( chan ));
462 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
464 /* Zeile wird zu lang: senden! */
465 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
466 sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
469 /* naechstes Mitglied suchen */
470 cl2chan = Channel_NextChannelOf( c, cl2chan );
472 if( str[strlen( str ) - 1] != ':')
474 /* Es sind noch Daten da, die gesendet werden muessen */
475 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
479 if( Client_HasMode( c, 'o' ))
481 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
484 /* Idle (nur lokale Clients) */
485 if( Client_Conn( c ) > NONE )
487 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
491 if( Client_HasMode( c, 'a' ))
493 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
497 return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
501 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
503 CHAR rpl[COMMAND_LEN];
507 assert( Client != NULL );
508 assert( Req != NULL );
510 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
512 /* Falsche Anzahl Parameter? */
513 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
515 if( Req->argc > 5 ) max = 5;
516 else max = Req->argc;
518 strcpy( rpl, RPL_USERHOST_MSG );
519 for( i = 0; i < max; i++ )
521 c = Client_GetFromID( Req->argv[i] );
522 if( c && ( Client_Type( c ) == CLIENT_USER ))
524 /* Dieser Nick ist "online" */
525 strcat( rpl, Client_ID( c ));
526 if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
528 if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
529 else strcat( rpl, "+" );
530 strcat( rpl, Client_User( c ));
532 strcat( rpl, Client_Hostname( c ));
536 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
538 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
542 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
544 assert( Client != NULL );
545 assert( Req != NULL );
547 if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
548 else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
554 GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req )
556 CLIENT *target, *from;
558 assert( Client != NULL );
559 assert( Req != NULL );
561 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
563 /* Falsche Anzahl Parameter? */
564 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
566 /* Absender ermitteln */
567 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
569 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
571 /* An anderen Server forwarden? */
574 target = Client_GetFromID( Req->argv[1] );
575 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
576 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
579 /* Wer ist der Absender? */
580 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
581 else target = Client;
582 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
584 IRC_Send_LUSERS( target );
590 GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
592 CLIENT *target, *from, *c;
595 assert( Client != NULL );
596 assert( Req != NULL );
598 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
600 /* Falsche Anzahl Parameter? */
601 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
603 /* Server-Mask ermitteln */
604 if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
607 /* Absender ermitteln */
608 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
610 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
612 /* An anderen Server forwarden? */
615 target = Client_GetFromID( Req->argv[0] );
616 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
617 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
620 /* Wer ist der Absender? */
621 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
622 else target = Client;
623 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
628 if( Client_Type( c ) == CLIENT_SERVER )
630 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;
632 c = Client_Next( c );
635 return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
639 GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req )
641 CHAR *channame, *flags, *topic, modes[8];
646 assert( Client != NULL );
647 assert( Req != NULL );
649 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
651 /* Falsche Anzahl Parameter? */
652 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
654 /* Wer ist der Absender? */
655 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
656 else target = Client;
657 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
659 /* Channel-Namen durchgehen */
660 channame = strtok( Req->argv[0], "," );
663 /* wird der Channel neu angelegt? */
666 if( Channel_Search( channame )) is_new_chan = FALSE;
667 else is_new_chan = TRUE;
669 /* Hat ein Server Channel-User-Modes uebergeben? */
670 if( Client_Type( Client ) == CLIENT_SERVER )
672 /* Channel-Flags extrahieren */
673 flags = strchr( channame, 0x7 );
674 if( flags ) *flags++ = '\0';
677 /* neuer Channel udn lokaler Client? */
678 if( is_new_chan && ( Client_Type( Client ) == CLIENT_USER ))
680 /* Dann soll der Client Channel-Operator werden! */
684 /* Channel joinen (und ggf. anlegen) */
685 if( ! Channel_Join( target, channame ))
687 /* naechsten Namen ermitteln */
688 channame = strtok( NULL, "," );
691 chan = Channel_Search( channame );
692 assert( chan != NULL );
694 /* Modes setzen (wenn vorhanden) */
695 while( flags && *flags )
697 Channel_UserModeAdd( chan, target, *flags );
701 /* Muessen Modes an andere Server gemeldet werden? */
702 strcpy( &modes[1], Channel_UserModes( chan, target ));
703 if( modes[1] ) modes[0] = 0x7;
704 else modes[0] = '\0';
706 /* An andere Server weiterleiten */
707 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
709 /* im Channel bekannt machen */
710 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
713 /* Modes im Channel bekannt machen */
714 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s %s :%s", channame, modes, Client_ID( target ));
717 if( Client_Type( Client ) == CLIENT_USER )
719 /* an Client bestaetigen */
720 IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
722 /* Topic an Client schicken */
723 topic = Channel_Topic( chan );
724 if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
726 /* Mitglieder an Client Melden */
727 IRC_Send_NAMES( Client, chan );
728 IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
731 /* naechsten Namen ermitteln */
732 channame = strtok( NULL, "," );
738 GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req )
743 assert( Client != NULL );
744 assert( Req != NULL );
746 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
748 /* Falsche Anzahl Parameter? */
749 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
751 /* Wer ist der Absender? */
752 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
753 else target = Client;
754 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
756 /* Channel-Namen durchgehen */
757 chan = strtok( Req->argv[0], "," );
760 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
762 /* naechsten Namen ermitteln */
763 chan = strtok( NULL, "," );
767 /* naechsten Namen ermitteln */
768 chan = strtok( NULL, "," );
774 GLOBAL BOOLEAN IRC_TOPIC( CLIENT *Client, REQUEST *Req )
780 assert( Client != NULL );
781 assert( Req != NULL );
783 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
785 /* Falsche Anzahl Parameter? */
786 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
788 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
790 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
792 /* Welcher Channel? */
793 chan = Channel_Search( Req->argv[0] );
794 if( ! chan ) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
796 /* Ist der User Mitglied in dem Channel? */
797 if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
802 topic = Channel_Topic( chan );
803 if( *topic ) return IRC_WriteStrClient( from, RPL_TOPIC_MSG, Client_ID( from ), Channel_Name( chan ), topic );
804 else return IRC_WriteStrClient( from, RPL_NOTOPIC_MSG, Client_ID( from ), Channel_Name( chan ));
807 if( strchr( Channel_Modes( chan ), 't' ))
809 /* Topic Lock. Ist der User ein Channel Operator? */
810 if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
814 Channel_SetTopic( chan, Req->argv[1] );
815 Log( LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s", Client_Mask( from ), Channel_Name( chan ), Req->argv[1][0] ? Req->argv[1] : "<none>" );
817 /* im Channel bekannt machen und an Server weiterleiten */
818 IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
819 IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
821 if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
822 else return CONNECTED;
826 GLOBAL BOOLEAN IRC_VERSION( CLIENT *Client, REQUEST *Req )
828 CLIENT *target, *prefix;
830 assert( Client != NULL );
831 assert( Req != NULL );
833 /* Falsche Anzahl Parameter? */
834 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
837 if( Req->argc == 1 ) target = Client_GetFromID( Req->argv[0] );
838 else target = Client_ThisServer( );
840 /* Prefix ermitteln */
841 if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_GetFromID( Req->prefix );
842 else prefix = Client;
843 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
845 /* An anderen Server weiterleiten? */
846 if( target != Client_ThisServer( ))
848 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
851 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
855 /* mit Versionsinfo antworten */
856 return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( ));
860 GLOBAL BOOLEAN IRC_KILL( CLIENT *Client, REQUEST *Req )
864 assert( Client != NULL );
865 assert( Req != NULL );
867 if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
869 /* Falsche Anzahl Parameter? */
870 if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
872 prefix = Client_GetFromID( Req->prefix );
875 Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix );
876 prefix = Client_ThisServer( );
879 Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
881 /* andere Server benachrichtigen */
882 IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] );
884 /* haben wir selber einen solchen Client? */
885 c = Client_GetFromID( Req->argv[0] );
886 if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Req->argv[1], TRUE );
892 GLOBAL BOOLEAN IRC_Show_MOTD( CLIENT *Client )
898 assert( Client != NULL );
900 fd = fopen( Conf_MotdFile, "r" );
903 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
904 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
907 IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
910 if( ! fgets( line, 126, fd )) break;
911 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
912 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
918 ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
923 } /* IRC_Show_MOTD */
926 GLOBAL BOOLEAN IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
928 BOOLEAN is_visible, is_member;
929 CHAR str[LINE_LEN + 1];
933 assert( Client != NULL );
934 assert( Chan != NULL );
936 if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
937 else is_member = FALSE;
939 /* Alle Mitglieder suchen */
940 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
941 cl2chan = Channel_FirstMember( Chan );
944 cl = Channel_GetClient( cl2chan );
946 if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE;
947 else is_visible = TRUE;
949 if( is_member || is_visible )
952 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
953 if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" );
954 if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" );
955 strcat( str, Client_ID( cl ));
957 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
959 /* Zeile wird zu lang: senden! */
960 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
961 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
965 /* naechstes Mitglied suchen */
966 cl2chan = Channel_NextMember( Chan, cl2chan );
968 if( str[strlen( str ) - 1] != ':')
970 /* Es sind noch Daten da, die gesendet werden muessen */
971 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
975 } /* IRC_Send_NAMES */
978 GLOBAL BOOLEAN IRC_Send_LUSERS( CLIENT *Client )
982 assert( Client != NULL );
984 /* Users, Services und Serevr im Netz */
985 if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
987 /* IRC-Operatoren im Netz */
988 cnt = Client_OperCount( );
991 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
994 /* Unbekannt Verbindungen */
995 cnt = Client_UnknownCount( );
998 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
1001 /* Channels im Netz */
1002 if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
1004 /* Channels im Netz */
1005 if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
1008 } /* IRC_Send_LUSERS */