X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fchannel.c;h=c30d4d555189b67a0bc895f8c69e9d929e0b8522;hp=bf3e5a7951f4b439834ac8a50815f6059e961daa;hb=f86bbd718d4a439509c290b62722f4aa96c00abb;hpb=f7327524fce6a7db28850c8b8b8f0e99d0b2402b diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index bf3e5a79..c30d4d55 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -9,7 +9,7 @@ * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. * - * $Id: channel.c,v 1.24 2002/05/30 16:52:21 alex Exp $ + * $Id: channel.c,v 1.34 2002/11/22 17:57:15 alex Exp $ * * channel.c: Management der Channels */ @@ -36,20 +36,25 @@ #include "resolve.h" #include "conf.h" #include "hash.h" +#include "lists.h" #include "log.h" #include "messages.h" #include "exp.h" +#define REMOVE_PART 0 +#define REMOVE_QUIT 1 +#define REMOVE_KICK 2 + + LOCAL CHANNEL *My_Channels; LOCAL CL2CHAN *My_Cl2Chan; -LOCAL CHANNEL *New_Chan PARAMS(( CHAR *Name )); LOCAL CL2CHAN *Get_Cl2Chan PARAMS(( CHANNEL *Chan, CLIENT *Client )); LOCAL CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client )); -LOCAL BOOLEAN Remove_Client PARAMS(( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN ServerPART )); +LOCAL BOOLEAN Remove_Client PARAMS(( INT Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN InformServer )); LOCAL CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan )); LOCAL CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan )); LOCAL BOOLEAN Delete_Channel PARAMS(( CHANNEL *Chan )); @@ -58,18 +63,24 @@ LOCAL BOOLEAN Delete_Channel PARAMS(( CHANNEL *Chan )); GLOBAL VOID Channel_Init( VOID ) { - CHANNEL *chan; - CHAR *c; - INT i; - My_Channels = NULL; My_Cl2Chan = NULL; +} /* Channel_Init */ + +GLOBAL VOID +Channel_InitPredefined( VOID ) +{ /* Vordefinierte persistente Channels erzeugen */ + + CHANNEL *chan; + CHAR *c; + INT i; + for( i = 0; i < Conf_Channel_Count; i++ ) { /* Ist ein Name konfiguriert? */ - if( ! Conf_Channel[i].name ) continue; + if( ! Conf_Channel[i].name[0] ) continue; /* Gueltiger Channel-Name? */ if( ! Channel_IsValidName( Conf_Channel[i].name )) @@ -77,14 +88,19 @@ Channel_Init( VOID ) Log( LOG_ERR, "Can't create pre-defined channel: invalid name: \"%s\"!", Conf_Channel[i].name ); continue; } + + /* Gibt es den Channel bereits? */ + chan = Channel_Search( Conf_Channel[i].name ); + if( chan ) + { + Log( LOG_INFO, "Can't create pre-defined channel \"%s\": name already in use.", Conf_Channel[i].name ); + continue; + } /* Channel anlegen */ - chan = New_Chan( Conf_Channel[i].name ); + chan = Channel_Create( Conf_Channel[i].name ); if( chan ) { - /* Verketten */ - chan->next = My_Channels; - My_Channels = chan; Channel_ModeAdd( chan, 'P' ); Channel_SetTopic( chan, Conf_Channel[i].topic ); c = Conf_Channel[i].modes; @@ -93,7 +109,7 @@ Channel_Init( VOID ) } else Log( LOG_ERR, "Can't create pre-defined channel \"%s\"!", Conf_Channel[i].name ); } -} /* Channel_Init */ +} /* Channel_InitPredefined */ GLOBAL VOID @@ -147,12 +163,8 @@ Channel_Join( CLIENT *Client, CHAR *Name ) else { /* Gibt es noch nicht? Dann neu anlegen: */ - chan = New_Chan( Name ); + chan = Channel_Create( Name ); if( ! chan ) return FALSE; - - /* Verketten */ - chan->next = My_Channels; - My_Channels = chan; } /* User dem Channel hinzufuegen */ @@ -168,6 +180,7 @@ Channel_Part( CLIENT *Client, CLIENT *Origin, CHAR *Name, CHAR *Reason ) assert( Client != NULL ); assert( Name != NULL ); + assert( Reason != NULL ); /* Channel suchen */ chan = Channel_Search( Name ); @@ -178,33 +191,77 @@ Channel_Part( CLIENT *Client, CLIENT *Origin, CHAR *Name, CHAR *Reason ) } /* User aus Channel entfernen */ - if( ! Remove_Client( chan, Client, Origin, Reason, TRUE )) return FALSE; + if( ! Remove_Client( REMOVE_PART, chan, Client, Origin, Reason, TRUE )) return FALSE; else return TRUE; } /* Channel_Part */ GLOBAL VOID -Channel_RemoveClient( CLIENT *Client, CHAR *Reason ) +Channel_Kick( CLIENT *Client, CLIENT *Origin, CHAR *Name, CHAR *Reason ) +{ + CHANNEL *chan; + + assert( Client != NULL ); + assert( Origin != NULL ); + assert( Name != NULL ); + assert( Reason != NULL ); + + /* Channel suchen */ + chan = Channel_Search( Name ); + if( ! chan ) + { + IRC_WriteStrClient( Origin, ERR_NOSUCHCHANNEL_MSG, Client_ID( Origin ), Name ); + return; + } + + /* Ist der User Mitglied in dem Channel? */ + if( ! Channel_IsMemberOf( chan, Origin )) + { + IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG, Client_ID( Origin ), Name ); + return; + } + + /* Ist der User Channel-Operator? */ + if( ! strchr( Channel_UserModes( chan, Origin ), 'o' )) + { + IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Name); + return; + } + + /* Ist der Ziel-User Mitglied im Channel? */ + if( ! Channel_IsMemberOf( chan, Client )) + { + IRC_WriteStrClient( Origin, ERR_USERNOTINCHANNEL_MSG, Client_ID( Origin ), Client_ID( Client ), Name ); + return; + } + + Remove_Client( REMOVE_KICK, chan, Client, Origin, Reason, TRUE ); +} /* Channel_Kick */ + + +GLOBAL VOID +Channel_Quit( CLIENT *Client, CHAR *Reason ) { CHANNEL *c, *next_c; assert( Client != NULL ); + assert( Reason != NULL ); c = My_Channels; while( c ) { next_c = c->next; - Remove_Client( c, Client, Client_ThisServer( ), Reason, FALSE ); + Remove_Client( REMOVE_QUIT, c, Client, Client, Reason, FALSE ); c = next_c; } -} /* Channel_RemoveClient */ +} /* Channel_Quit */ -GLOBAL INT +GLOBAL LONG Channel_Count( VOID ) { CHANNEL *c; - INT count; + LONG count; count = 0; c = My_Channels; @@ -217,11 +274,11 @@ Channel_Count( VOID ) } /* Channel_Count */ -GLOBAL INT +GLOBAL LONG Channel_MemberCount( CHANNEL *Chan ) { CL2CHAN *cl2chan; - INT count; + LONG count; assert( Chan != NULL ); @@ -520,6 +577,18 @@ Channel_SetTopic( CHANNEL *Chan, CHAR *Topic ) } /* Channel_SetTopic */ +GLOBAL VOID +Channel_SetModes( CHANNEL *Chan, CHAR *Modes ) +{ + assert( Chan != NULL ); + assert( Modes != NULL ); + + strncpy( Chan->modes, Modes, CHANNEL_MODE_LEN - 1 ); + Chan->topic[CHANNEL_MODE_LEN - 1] = '\0'; +} /* Channel_SetModes */ + + + GLOBAL BOOLEAN Channel_Write( CHANNEL *Chan, CLIENT *From, CLIENT *Client, CHAR *Text ) { @@ -547,9 +616,8 @@ Channel_Write( CHANNEL *Chan, CLIENT *From, CLIENT *Client, CHAR *Text ) } /* Channel_Write */ - -LOCAL CHANNEL * -New_Chan( CHAR *Name ) +GLOBAL CHANNEL * +Channel_Create( CHAR *Name ) { /* Neue Channel-Struktur anlegen */ @@ -560,7 +628,7 @@ New_Chan( CHAR *Name ) c = malloc( sizeof( CHANNEL )); if( ! c ) { - Log( LOG_EMERG, "Can't allocate memory!" ); + Log( LOG_EMERG, "Can't allocate memory! [New_Chan]" ); return NULL; } c->next = NULL; @@ -570,10 +638,14 @@ New_Chan( CHAR *Name ) strcpy( c->topic, "" ); c->hash = Hash( c->name ); + /* Verketten */ + c->next = My_Channels; + My_Channels = c; + Log( LOG_DEBUG, "Created new channel structure for \"%s\".", Name ); return c; -} /* New_Chan */ +} /* Channel_Create */ LOCAL CL2CHAN * @@ -606,7 +678,7 @@ Add_Client( CHANNEL *Chan, CLIENT *Client ) cl2chan = malloc( sizeof( CL2CHAN )); if( ! cl2chan ) { - Log( LOG_EMERG, "Can't allocate memory!" ); + Log( LOG_EMERG, "Can't allocate memory! [Add_Client]" ); return NULL; } cl2chan->channel = Chan; @@ -624,7 +696,7 @@ Add_Client( CHANNEL *Chan, CLIENT *Client ) LOCAL BOOLEAN -Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN ServerPART ) +Remove_Client( INT Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN InformServer ) { CL2CHAN *cl2chan, *last_cl2chan; CHANNEL *c; @@ -652,11 +724,30 @@ Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOL else My_Cl2Chan = cl2chan->next; free( cl2chan ); - if( ServerPART ) IRC_WriteStrServersPrefix( Origin, Client, "PART %s :%s", c->name, Reason ); - IRC_WriteStrChannelPrefix( Origin, c, Client, FALSE, "PART %s :%s", c->name, Reason ); - if(( Client_Conn( Origin ) > NONE ) && ( Client_Type( Origin ) == CLIENT_USER )) IRC_WriteStrClientPrefix( Origin, Client, "PART %s :%s", c->name, Reason ); - - Log( LOG_DEBUG, "User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason ); + switch( Type ) + { + case REMOVE_QUIT: + /* QUIT: andere Server wurden bereits informiert, vgl. Client_Destroy(); + * hier also "nur" noch alle User in betroffenen Channeln infomieren */ + assert( InformServer == FALSE ); + IRC_WriteStrChannelPrefix( Origin, c, Origin, FALSE, "QUIT :%s", Reason ); + Log( LOG_DEBUG, "User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason ); + break; + case REMOVE_KICK: + /* User wurde geKICKed: ggf. andere Server sowie alle betroffenen User + * im entsprechenden Channel informieren */ + if( InformServer ) IRC_WriteStrServersPrefix( Client_NextHop( Origin ), Origin, "KICK %s %s :%s", c->name, Client_ID( Client ), Reason ); + IRC_WriteStrChannelPrefix( Client, c, Origin, FALSE, "KICK %s %s :%s", c->name, Client_ID( Client ), Reason ); + if(( Client_Conn( Client ) > NONE ) && ( Client_Type( Client ) == CLIENT_USER )) IRC_WriteStrClientPrefix( Client, Origin, "KICK %s %s :%s", c->name, Client_ID( Client ), Reason ); + Log( LOG_DEBUG, "User \"%s\" has been kicked of \"%s\" by \"%s\": %s.", Client_Mask( Client ), c->name, Client_ID( Origin ), Reason ); + break; + default: + /* PART */ + if( InformServer ) IRC_WriteStrServersPrefix( Origin, Client, "PART %s :%s", c->name, Reason ); + IRC_WriteStrChannelPrefix( Origin, c, Client, FALSE, "PART %s :%s", c->name, Reason ); + if(( Client_Conn( Origin ) > NONE ) && ( Client_Type( Origin ) == CLIENT_USER )) IRC_WriteStrClientPrefix( Origin, Client, "PART %s :%s", c->name, Reason ); + Log( LOG_DEBUG, "User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason ); + } /* Wenn Channel nun leer und nicht pre-defined: loeschen */ if( ! strchr( Channel_Modes( Chan ), 'P' )) @@ -712,6 +803,9 @@ Delete_Channel( CHANNEL *Chan ) Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name ); + /* Invite- und Ban-Lists aufraeumen */ + Lists_DeleteChannel( chan ); + /* Neu verketten und freigeben */ if( last_chan ) last_chan->next = chan->next; else My_Channels = chan->next;