]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/irc.c
- neue Funktionen Channel_ModeAdd(), Channel_ModeDel(), Channel_UserModes(),
[ngircd-alex.git] / src / ngircd / irc.c
index 3f818155aa97d5bee3f01e4d8e4bd88c02f0b645..ce06f069b72194b4dfad655f5634f1780634722b 100644 (file)
@@ -9,11 +9,39 @@
  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
  * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
  *
- * $Id: irc.c,v 1.41 2002/01/27 17:15:49 alex Exp $
+ * $Id: irc.c,v 1.49 2002/02/06 16:51:22 alex Exp $
  *
  * irc.c: IRC-Befehle
  *
  * $Log: irc.c,v $
+ * Revision 1.49  2002/02/06 16:51:22  alex
+ * - neue Funktion zur MODE-Behandlung, fuer Channel-Modes vorbereitet.
+ *
+ * Revision 1.48  2002/01/29 00:13:45  alex
+ * - WHOIS zeigt nun auch die Channels an, in denen der jeweilige User Mitglied ist.
+ * - zu jedem Server wird nun der "Top-Server" gespeichert, somit funktioniert
+ *   LINKS wieder korrekt.
+ *
+ * Revision 1.47  2002/01/28 13:05:48  alex
+ * - nach einem JOIN wird die Liste der Mitglieder an den Client geschickt.
+ * - MODE fuer Channels wird nun komplett ignoriert (keine Fehlermeldung mehr).
+ *
+ * Revision 1.46  2002/01/28 01:45:43  alex
+ * - SERVER-Meldungen an neue Server sind nun in der richtigen Reihenfolge.
+ *
+ * Revision 1.45  2002/01/28 01:18:14  alex
+ * - connectierenden Servern werden Channels nun mit NJOIN bekannt gemacht.
+ *
+ * Revision 1.44  2002/01/28 00:55:08  alex
+ * - ein neu connectierender Server wird nun korrekt im Netz bekannt gemacht.
+ *
+ * Revision 1.43  2002/01/27 21:56:39  alex
+ * - IRC_WriteStrServersPrefixID() und IRC_WriteStrClientPrefixID() wieder entfernt.
+ * - einige kleinere Fixes bezueglich Channels ...
+ *
+ * Revision 1.42  2002/01/27 18:28:01  alex
+ * - bei NICK wurde das falsche Prefix an andere Server weitergegeben.
+ *
  * Revision 1.41  2002/01/27 17:15:49  alex
  * - anderungen an den Funktions-Prototypen von IRC_WriteStrChannel() und
  *   IRC_WriteStrChannelPrefix(),
@@ -197,6 +225,8 @@ LOCAL BOOLEAN Show_MOTD( CLIENT *Client );
 
 LOCAL VOID Kill_Nick( CHAR *Nick );
 
+LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan );
+
 
 GLOBAL VOID IRC_Init( VOID )
 {
@@ -243,27 +273,8 @@ GLOBAL BOOLEAN IRC_WriteStrClientPrefix( CLIENT *Client, CLIENT *Prefix, CHAR *F
        vsnprintf( buffer, 1000, Format, ap );
        va_end( ap );
 
-       return Conn_WriteStr( Client_Conn( Client_NextHop( Client )), ":%s %s", Client_Mask( Prefix ), buffer );
-} /* IRC_WriteStrClientPrefix */
-
-
-GLOBAL BOOLEAN IRC_WriteStrClientPrefixID( CLIENT *Client, CLIENT *Prefix, CHAR *Format, ... )
-{
-       /* Text an Clients, lokal bzw. remote, senden. */
-
-       CHAR buffer[1000];
-       va_list ap;
-
-       assert( Client != NULL );
-       assert( Format != NULL );
-       assert( Prefix != NULL );
-
-       va_start( ap, Format );
-       vsnprintf( buffer, 1000, Format, ap );
-       va_end( ap );
-
        return Conn_WriteStr( Client_Conn( Client_NextHop( Client )), ":%s %s", Client_ID( Prefix ), buffer );
-} /* IRC_WriteStrClientPrefixID */
+} /* IRC_WriteStrClientPrefix */
 
 
 GLOBAL BOOLEAN IRC_WriteStrChannel( CLIENT *Client, CHANNEL *Chan, BOOLEAN Remote, CHAR *Format, ... )
@@ -307,12 +318,13 @@ GLOBAL BOOLEAN IRC_WriteStrChannelPrefix( CLIENT *Client, CHANNEL *Chan, CLIENT
        cl2chan = Channel_FirstMember( Chan );
        while( cl2chan )
        {
-               if( Remote ) c = Client_NextHop( Channel_GetClient( cl2chan ));
-               else
+               c = Channel_GetClient( cl2chan );
+               if( ! Remote )
                {
-                       c = Channel_GetClient( cl2chan );
                        if( Client_Conn( c ) <= NONE ) c = NULL;
+                       else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
                }
+               if( c ) c = Client_NextHop( c );
                        
                if( c && ( c != Client ))
                {
@@ -380,32 +392,6 @@ GLOBAL VOID IRC_WriteStrServersPrefix( CLIENT *ExceptOf, CLIENT *Prefix, CHAR *F
 } /* IRC_WriteStrServersPrefix */
 
 
-GLOBAL VOID IRC_WriteStrServersPrefixID( CLIENT *ExceptOf, CLIENT *Prefix, CHAR *Format, ... )
-{
-       CHAR buffer[1000];
-       CLIENT *c;
-       va_list ap;
-
-       assert( Format != NULL );
-       assert( Prefix != NULL );
-
-       va_start( ap, Format );
-       vsnprintf( buffer, 1000, Format, ap );
-       va_end( ap );
-
-       c = Client_First( );
-       while( c )
-       {
-               if(( Client_Type( c ) == CLIENT_SERVER ) && ( Client_Conn( c ) > NONE ) && ( c != Client_ThisServer( )) && ( c != ExceptOf ))
-               {
-                       /* Ziel-Server gefunden */
-                       IRC_WriteStrClientPrefixID( c, Prefix, buffer );
-               }
-               c = Client_Next( c );
-       }
-} /* IRC_WriteStrServersPrefixID */
-
-
 GLOBAL BOOLEAN IRC_PASS( CLIENT *Client, REQUEST *Req )
 {
        assert( Client != NULL );
@@ -449,8 +435,10 @@ GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
 {
        CHAR str[LINE_LEN], *ptr;
        BOOLEAN ok;
-       CLIENT *c;
-       INT i;
+       CLIENT *from, *c;
+       CHANNEL *chan;
+       CL2CHAN *cl2chan;
+       INT max_hops, i;
        
        assert( Client != NULL );
        assert( Req != NULL );
@@ -512,24 +500,36 @@ GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
 
                Client_SetType( Client, CLIENT_SERVER );
 
-               /* Alle bisherigen Server dem neuen Server bekannt machen,
-                * die bisherigen Server ueber den neuen informierenn */
+               /* maximalen Hop Count ermitteln */
+               max_hops = 0;
                c = Client_First( );
                while( c )
                {
-                       if(( Client_Type( c ) == CLIENT_SERVER ) && ( c != Client ) && ( c != Client_ThisServer( )))
+                       if( Client_Hops( c ) > max_hops ) max_hops = Client_Hops( c );
+                       c = Client_Next( c );
+               }
+               
+               /* Alle bisherigen Server dem neuen Server bekannt machen,
+                * die bisherigen Server ueber den neuen informierenn */
+               for( i = 0; i < ( max_hops + 1 ); i++ )
+               {
+                       c = Client_First( );
+                       while( c )
                        {
-                               if( Client_Conn( c ) > NONE )
+                               if(( Client_Type( c ) == CLIENT_SERVER ) && ( c != Client ) && ( c != Client_ThisServer( )) && ( Client_Hops( c ) == i ))
                                {
-                                       /* Dem gefundenen Server gleich den neuen
-                                       * Server bekannt machen */
-                                       if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED;
+                                       if( Client_Conn( c ) > NONE )
+                                       {
+                                               /* Dem gefundenen Server gleich den neuen
+                                               * Server bekannt machen */
+                                               if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED;
+                                       }
+                                       
+                                       /* Den neuen Server ueber den alten informieren */
+                                       if( ! IRC_WriteStrClientPrefix( Client, Client_Hops( c ) == 1 ? Client_ThisServer( ) : Client_Introducer( c ), "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ))) return DISCONNECTED;
                                }
-                               
-                               /* Den neuen Server ueber den alten informieren */
-                               if( ! IRC_WriteStrClientPrefix( Client, Client_Introducer( c ), "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ))) return DISCONNECTED;
+                               c = Client_Next( c );
                        }
-                       c = Client_Next( c );
                }
 
                /* alle User dem neuen Server bekannt machen */
@@ -543,6 +543,40 @@ GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
                        }
                        c = Client_Next( c );
                }
+
+               /* Channels dem neuen Server bekannt machen */
+               chan = Channel_First( );
+               while( chan )
+               {
+                       sprintf( str, "NJOIN %s :", Channel_Name( chan ));
+
+                       /* alle Member suchen */
+                       cl2chan = Channel_FirstMember( chan );
+                       while( cl2chan )
+                       {
+                               if( str[strlen( str ) - 1] != ':' ) strcat( str, "," );
+                               strcat( str, Client_ID( Channel_GetClient( cl2chan )));
+
+                               if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
+                               {
+                                       /* Zeile senden */
+                                       if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
+                                       sprintf( str, "NJOIN %s :", Channel_Name( chan ));
+                               }
+                               
+                               cl2chan = Channel_NextMember( chan, cl2chan );
+                       }
+
+                       /* noch Daten da? */
+                       if( str[strlen( str ) - 1] != ':')
+                       {
+                               /* Ja; Also senden ... */
+                               if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
+                       }
+
+                       /* naechsten Channel suchen */
+                       chan = Channel_Next( chan );
+               }
                
                return CONNECTED;
        }
@@ -560,8 +594,17 @@ GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
                ptr = strchr( Req->argv[3] + 2, '[' );
                if( ! ptr ) ptr = Req->argv[3];
 
+               from = Client_GetFromID( Req->prefix );
+               if( ! from )
+               {
+                       /* Hm, Server, der diesen einfuehrt, ist nicht bekannt!? */
+                       Log( LOG_ALERT, "Unknown ID in prefix of SERVER: \"%s\"! (on connection %d)", Req->prefix, Client_Conn( Client ));
+                       Conn_Close( Client_Conn( Client ), NULL, "Unknown ID in prefix of SERVER", TRUE );
+                       return DISCONNECTED;
+               }
+
                /* Neue Client-Struktur anlegen */
-               c = Client_NewRemoteServer( Client, Req->argv[0], atoi( Req->argv[1] ), atoi( Req->argv[2] ), ptr, TRUE );
+               c = Client_NewRemoteServer( Client, Req->argv[0], from, atoi( Req->argv[1] ), atoi( Req->argv[2] ), ptr, TRUE );
                if( ! c )
                {
                        /* Neue Client-Struktur konnte nicht angelegt werden */
@@ -571,10 +614,13 @@ GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
                }
 
                /* Log-Meldung zusammenbauen und ausgeben */
-               if(( Client_Hops( c ) > 1 ) && ( Req->prefix[0] )) sprintf( str, "connected to %s, ", Req->prefix );
+               if(( Client_Hops( c ) > 1 ) && ( Req->prefix[0] )) sprintf( str, "connected to %s, ", Client_ID( from ));
                else strcpy( str, "" );
                Log( LOG_NOTICE, "Server \"%s\" registered (via %s, %s%d hop%s).", Client_ID( c ), Client_ID( Client ), str, Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
-               
+
+               /* Andere Server informieren */
+               IRC_WriteStrServersPrefix( Client, from, "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ));
+
                return CONNECTED;
        }
        else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
@@ -672,7 +718,7 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req )
                {
                        /* Nick-Aenderung: allen mitteilen! */
                        Log( LOG_DEBUG, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] );
-                       IRC_WriteStrServersPrefix( Client, Client, "NICK :%s", Req->argv[0] );
+                       IRC_WriteStrServersPrefix( Client, target, "NICK :%s", Req->argv[0] );
                }
        
                /* Client-Nick registrieren */
@@ -968,119 +1014,161 @@ GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
 
 GLOBAL BOOLEAN IRC_MODE( CLIENT *Client, REQUEST *Req )
 {
-       CHAR x[2], new_modes[CLIENT_MODE_LEN], *ptr;
+       CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
        BOOLEAN set, ok;
-       CLIENT *target;
+       CHANNEL *chan;
+       CLIENT *cl;
        
        assert( Client != NULL );
        assert( Req != NULL );
 
+       cl = NULL;
+       chan = NULL;
+
+       /* Valider Client? */
        if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
 
-       /* Falsche Anzahl Parameter? */
-       if(( Req->argc > 2 ) || ( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+       /* Keine Parameter? */
+       if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
 
-       /* "Ziel-Client" suchen */
-       target = Client_Search( Req->argv[0] );
+       /* Ziel suchen: Client bzw. Channel */
+       if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
+       if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
 
-       /* Wer ist der Anfragende? */
+       /* Kein Ziel gefunden? */
+       if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
+
+       /* Falsche Anzahl Parameter? */
+       if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+       if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+       
+       /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
        if( Client_Type( Client ) == CLIENT_USER )
        {
-               /* User: MODE ist nur fuer sich selber zulaessig */
-               if( target != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
-       }
-       else
-       {
-               /* Server: gibt es den Client ueberhaupt? */
-               if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
+               if( cl )
+               {
+                       /* MODE ist nur fuer sich selber zulaessig! */
+                       if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
+               }
+               if( chan )
+               {
+                       /* Darf der User die Channel-Modes ermitteln? */
+               }
        }
 
-       /* Werden die Modes erfragt? */
-       if( Req->argc == 1 ) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( Client ));
+       /* Werden die Modes "nur" erfragt? */
+       if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
+       if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEISCHAN_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
 
-       ptr = Req->argv[1];
+       mode_ptr = Req->argv[1];
 
        /* Sollen Modes gesetzt oder geloescht werden? */
-       if( *ptr == '+' ) set = TRUE;
-       else if( *ptr == '-' ) set = FALSE;
+       if( *mode_ptr == '+' ) set = TRUE;
+       else if( *mode_ptr == '-' ) set = FALSE;
        else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
 
        /* Reply-String mit Aenderungen vorbereiten */
-       if( set ) strcpy( new_modes, "+" );
-       else strcpy( new_modes, "-" );
+       if( set ) strcpy( the_modes, "+" );
+       else strcpy( the_modes, "-" );
 
-       ptr++;
+       mode_ptr++;
        ok = TRUE;
        x[1] = '\0';
-       while( *ptr )
+       while( *mode_ptr )
        {
                x[0] = '\0';
                if( Client_Type( Client ) == CLIENT_SERVER )
                {
-                       x[0] = *ptr;
-                       ok = TRUE;
+                       /* Befehl kommt von einem Server, daher
+                        * trauen wir ihm "unbesehen" ... */
+                       x[0] = *mode_ptr;
                }
                else
                {
-                       switch( *ptr )
+                       /* Modes validieren */
+                       if( cl )
                        {
-                               case 'i':
-                                       /* invisible */
-                                       x[0] = 'i';
-                                       break;
-                               case 'r':
-                                       /* restricted (kann nur gesetzt werden) */
-                                       if( set ) x[0] = 'r';
-                                       else ok = IRC_WriteStrClient( target, ERR_RESTRICTED_MSG, Client_ID( target ));
-                                       break;
-                               case 'o':
-                                       /* operator (kann nur geloescht werden) */
-                                       if( ! set )
-                                       {
-                                               Client_SetOperByMe( target, FALSE );
-                                               x[0] = 'o';
-                                       }
-                                       else ok = IRC_WriteStrClient( target, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( target ));
-                                       break;
-                               default:
-                                       ok = IRC_WriteStrClient( target, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( target ));
-                                       x[0] = '\0';
+                               /* User-Modes */
+                               switch( *mode_ptr )
+                               {
+                                       case 'i':
+                                               /* invisible */
+                                               x[0] = 'i';
+                                               break;
+                                       case 'r':
+                                               /* restricted (kann nur gesetzt werden) */
+                                               if( set ) x[0] = 'r';
+                                               else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
+                                               break;
+                                       case 'o':
+                                               /* operator (kann nur geloescht werden) */
+                                               if( ! set )
+                                               {
+                                                       Client_SetOperByMe( Client, FALSE );
+                                                       x[0] = 'o';
+                                               }
+                                               else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
+                                               break;
+                                       default:
+                                               ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
+                                               x[0] = '\0';
+                               }
+                       }
+                       if( chan )
+                       {
+                               /* Channel-Modes */
+                               Log( LOG_DEBUG, "Channel-Mode '%c' not supported ...", *mode_ptr );
                        }
                }
                if( ! ok ) break;
-
-               ptr++;
+               
+               mode_ptr++;
                if( ! x[0] ) continue;
 
                /* Okay, gueltigen Mode gefunden */
-               if( set )
+               if( cl )
                {
-                       /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
-                       if( Client_ModeAdd( target, x[0] )) strcat( new_modes, x );
+                       /* Es geht um User-Modes */
+                       if( set )
+                       {
+                               /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
+                               if( Client_ModeAdd( Client, x[0] )) strcat( the_modes, x );
+                       }
+                       else
+                       {
+                               /* Modes geloescht. Wenn der Client ihn hatte: merken */
+                               if( Client_ModeDel( Client, x[0] )) strcat( the_modes, x );
+                       }
                }
-               else
+               if( chan )
                {
-                       /* Modes geloescht. Wenn der Client ihn hatte: merken */
-                       if( Client_ModeDel( target, x[0] )) strcat( new_modes, x );
+                       /* Es geht um Channel-Modes */
                }
        }
-       
-       /* Geanderte Modes? */
-       if( new_modes[1] )
+
+       /* Wurden Modes geaendert? */
+       if( the_modes[1] )
        {
-               if( Client_Type( Client ) == CLIENT_SERVER )
+               if( cl )
                {
-                       /* Modes an andere Server forwarden */
-                       IRC_WriteStrServersPrefix( Client, Client, "MODE %s :%s", Client_ID( target ), new_modes );
+                       if( Client_Type( Client ) == CLIENT_SERVER )
+                       {
+                               /* Modes an andere Server forwarden */
+                               IRC_WriteStrServersPrefix( Client, Client, "MODE %s :%s", Client_ID( cl ), the_modes );
+                       }
+                       else
+                       {
+                               /* Bestaetigung an Client schicken & andere Server informieren */
+                               ok = IRC_WriteStrClient( Client, "MODE %s :%s", Client_ID( cl ), the_modes );
+                               IRC_WriteStrServers( Client, "MODE %s :%s", Client_ID( cl ), the_modes );
+                       }
+                       Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
                }
-               else
+               if( chan )
                {
-                       /* Bestaetigung an Client schicken & andere Server informieren */
-                       ok = IRC_WriteStrClient( Client, "MODE %s :%s", Client_ID( target ), new_modes );
-                       IRC_WriteStrServers( Client, "MODE %s :%s", Client_ID( target ), new_modes );
                }
-               Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( target ), Client_Modes( target ));
        }
+
        return ok;
 } /* IRC_MODE */
 
@@ -1252,7 +1340,8 @@ GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
 {
        CLIENT *from, *target, *c;
-       CHAR *ptr = NULL;
+       CHAR str[LINE_LEN + 1], *ptr = NULL;
+       CL2CHAN *cl2chan;
        
        assert( Client != NULL );
        assert( Req != NULL );
@@ -1297,6 +1386,31 @@ GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
        /* Server */
        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;
 
+       /* Channels */
+       sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
+       cl2chan = Channel_FirstChannelOf( c );
+       while( cl2chan )
+       {
+               /* Channel-Name anhaengen */
+               if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
+               strcat( str, Channel_Name( Channel_GetChannel( cl2chan )));
+
+               if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
+               {
+                       /* Zeile wird zu lang: senden! */
+                       if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
+                       sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
+               }
+
+               /* naechstes Mitglied suchen */
+               cl2chan = Channel_NextChannelOf( c, cl2chan );
+       }
+       if( str[strlen( str ) - 1] != ':')
+       {
+               /* Es sind noch Daten da, die gesendet werden muessen */
+               if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
+       }
+       
        /* IRC-Operator? */
        if( Client_HasMode( c, 'o' ))
        {
@@ -1465,7 +1579,7 @@ GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
        {
                if( Client_Type( c ) == CLIENT_SERVER )
                {
-                       if( ! IRC_WriteStrClient( target, RPL_LINKS_MSG, Client_ID( target ), Client_ID( c ), Client_ID( Client_Introducer( c )), Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
+                       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;
                }
                c = Client_Next( c );
        }
@@ -1511,15 +1625,18 @@ GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req )
                        continue;
                }
 
-               /* An andere Server weiterleiten, an Client bestaetigen */
-               IRC_WriteStrServersPrefixID( Client, target, "JOIN :%s", chan );
-               IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", chan );
+               /* An andere Server weiterleiten */
+               IRC_WriteStrServersPrefix( Client, target, "JOIN :%s", chan );
                IRC_WriteStrChannelPrefix( Client, Channel_Search( chan ), target, FALSE, "JOIN :%s", chan );
 
                if( Client_Type( Client ) == CLIENT_USER )
                {
+                       /* an Client bestaetigen */
+                       IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", chan );
                        /* Topic an Client schicken */
                        IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), chan, "What a wonderful channel!" );
+                       /* Mitglieder an Client Melden */
+                       Send_NAMES( Client, Channel_Search( chan ));
                }
                
                /* naechsten Namen ermitteln */
@@ -1636,4 +1753,44 @@ LOCAL VOID Kill_Nick( CHAR *Nick )
 } /* Kill_Nick */
 
 
+LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan )
+{
+       CHAR str[LINE_LEN + 1];
+       CL2CHAN *cl2chan;
+       
+       assert( Client != NULL );
+       assert( Chan != NULL );
+
+       /* Alle Mitglieder suchen */
+       sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
+       cl2chan = Channel_FirstMember( Chan );
+       while( cl2chan )
+       {
+               /* Nick anhaengen */
+               if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
+               strcat( str, Client_ID( Channel_GetClient( cl2chan )));
+
+               if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
+               {
+                       /* Zeile wird zu lang: senden! */
+                       if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
+                       sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
+               }
+
+               /* naechstes Mitglied suchen */
+               cl2chan = Channel_NextMember( Chan, cl2chan );
+       }
+       if( str[strlen( str ) - 1] != ':')
+       {
+               /* Es sind noch Daten da, die gesendet werden muessen */
+               if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
+       }
+
+       /* Ende anzeigen */
+       IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( Chan ));
+       
+       return CONNECTED;
+} /* Send_NAMES */
+
+
 /* -eof- */