X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fchannel.c;h=6e9e0f478c235040d502b38363115bb677acff5f;hb=8605e9c0fe7ffa42149271c9af31288bd4a0dfac;hp=7c3360acb088ebf4690f5796fa5287226473a961;hpb=2cc21caf32323ebd778c16c8a7b69cd12d6ff01f;p=ngircd-alex.git diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 7c3360ac..6e9e0f47 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "defines.h" @@ -39,6 +40,7 @@ #include "lists.h" #include "log.h" #include "messages.h" +#include "match.h" #include "exp.h" @@ -57,14 +59,24 @@ static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client )); static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer )); static CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan )); static CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan )); -static bool Delete_Channel PARAMS(( CHANNEL *Chan )); +static void Delete_Channel PARAMS(( CHANNEL *Chan )); +static void Free_Channel PARAMS(( CHANNEL *Chan )); +static void Set_KeyFile PARAMS((CHANNEL *Chan, const char *KeyFile)); GLOBAL void Channel_Init( void ) { + CHANNEL *sc; + My_Channels = NULL; My_Cl2Chan = NULL; + + sc = Channel_Create("&SERVER"); + if (sc) { + Channel_SetModes(sc, "mnPt"); + Channel_SetTopic(sc, Client_ThisServer(), "Server Messages"); + } } /* Channel_Init */ @@ -89,58 +101,70 @@ Channel_InitPredefined( void ) { /* Generate predefined persistent channels */ - CHANNEL *chan; - char *c; - unsigned int i; + CHANNEL *new_chan; + const struct Conf_Channel *conf_chan; + const char *c; + size_t i, channel_count = array_length(&Conf_Channels, sizeof(*conf_chan)); - for( i = 0; i < Conf_Channel_Count; i++ ) - { - /* Check for Name configuration */ - if( ! Conf_Channel[i].name[0] ) continue; + conf_chan = array_start(&Conf_Channels); - /* Check for invalid channel name */ - if( ! Channel_IsValidName( Conf_Channel[i].name )) - { - Log( LOG_ERR, "Can't create pre-defined channel: invalid name: \"%s\"!", Conf_Channel[i].name ); - array_free(&Conf_Channel[i].topic); + assert(channel_count == 0 || conf_chan != NULL); + + for (i = 0; i < channel_count; i++, conf_chan++) { + if (!conf_chan->name[0] || !Channel_IsValidName(conf_chan->name)) { + Log(LOG_ERR, "Can't create pre-defined channel: invalid name: \"%s\"", + conf_chan->name); continue; } - /* Check if the channel name is already in use */ - 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 ); - array_free(&Conf_Channel[i].topic); + new_chan = Channel_Search(conf_chan->name); + if (new_chan) { + Log(LOG_INFO, + "Can't create pre-defined channel \"%s\": name already in use.", + conf_chan->name); + Set_KeyFile(new_chan, conf_chan->keyfile); continue; } - /* Create channel */ - chan = Channel_Create(Conf_Channel[i].name); - if (chan) { - Channel_ModeAdd(chan, 'P'); + new_chan = Channel_Create(conf_chan->name); + if (!new_chan) { + Log(LOG_ERR, "Can't create pre-defined channel \"%s\"", + conf_chan->name); + continue; + } + Log(LOG_INFO, "Created pre-defined channel \"%s\"", + conf_chan->name); - if (array_start(&Conf_Channel[i].topic) != NULL) - Channel_SetTopic(chan, NULL, - array_start(&Conf_Channel[i].topic)); - array_free(&Conf_Channel[i].topic); + Channel_ModeAdd(new_chan, 'P'); - c = Conf_Channel[i].modes; - while (*c) - Channel_ModeAdd(chan, *c++); + if (conf_chan->topic[0]) + Channel_SetTopic(new_chan, NULL, conf_chan->topic); - Channel_SetKey(chan, Conf_Channel[i].key); - Channel_SetMaxUsers(chan, Conf_Channel[i].maxusers); + c = conf_chan->modes; + while (*c) + Channel_ModeAdd(new_chan, *c++); - Log(LOG_INFO, "Created pre-defined channel \"%s\".", - Conf_Channel[i].name ); - } - else Log(LOG_ERR, "Can't create pre-defined channel \"%s\"!", - Conf_Channel[i].name ); + Channel_SetKey(new_chan, conf_chan->key); + Channel_SetMaxUsers(new_chan, conf_chan->maxusers); + Set_KeyFile(new_chan, conf_chan->keyfile); } + if (channel_count) + array_free(&Conf_Channels); } /* Channel_InitPredefined */ +static void +Free_Channel(CHANNEL *chan) +{ + array_free(&chan->topic); + array_free(&chan->keyfile); + Lists_Free(&chan->list_bans); + Lists_Free(&chan->list_invites); + + free(chan); +} + + GLOBAL void Channel_Exit( void ) { @@ -149,20 +173,17 @@ Channel_Exit( void ) /* free struct Channel */ c = My_Channels; - while( c ) - { + while (c) { c_next = c->next; - array_free(&c->topic); - free( c ); + Free_Channel(c); c = c_next; } /* Free Channel allocation table */ cl2chan = My_Cl2Chan; - while( c ) - { + while (cl2chan) { cl2chan_next = cl2chan->next; - free( cl2chan ); + free(cl2chan); cl2chan = cl2chan_next; } } /* Channel_Exit */ @@ -177,7 +198,7 @@ Channel_Exit( void ) * Add_Client(). */ GLOBAL bool -Channel_Join( CLIENT *Client, char *Name ) +Channel_Join( CLIENT *Client, const char *Name ) { CHANNEL *chan; @@ -304,7 +325,7 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, GLOBAL void -Channel_Quit( CLIENT *Client, char *Reason ) +Channel_Quit( CLIENT *Client, const char *Reason ) { CHANNEL *c, *next_c; @@ -682,7 +703,7 @@ Channel_TopicWho(CHANNEL *Chan) GLOBAL void -Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, char *Topic) +Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, const char *Topic) { size_t len; assert( Chan != NULL ); @@ -710,7 +731,7 @@ Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, char *Topic) GLOBAL void -Channel_SetModes( CHANNEL *Chan, char *Modes ) +Channel_SetModes( CHANNEL *Chan, const char *Modes ) { assert( Chan != NULL ); assert( Modes != NULL ); @@ -720,7 +741,7 @@ Channel_SetModes( CHANNEL *Chan, char *Modes ) GLOBAL void -Channel_SetKey( CHANNEL *Chan, char *Key ) +Channel_SetKey( CHANNEL *Chan, const char *Key ) { assert( Chan != NULL ); assert( Key != NULL ); @@ -747,6 +768,10 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) is_member = has_voice = is_op = false; + /* The server itself always can send messages :-) */ + if (Client_ThisServer() == From) + return true; + if (Channel_IsMemberOf(Chan, From)) { is_member = true; if (strchr(Channel_UserModes(Chan, From), 'v')) @@ -794,7 +819,7 @@ Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command, GLOBAL CHANNEL * -Channel_Create( char *Name ) +Channel_Create( const char *Name ) { /* Create new CHANNEL structure and add it to linked list */ CHANNEL *c; @@ -858,7 +883,7 @@ Add_Client( CHANNEL *Chan, CLIENT *Client ) cl2chan->next = My_Cl2Chan; My_Cl2Chan = cl2chan; - Log( LOG_DEBUG, "User \"%s\" joined channel \"%s\".", Client_Mask( Client ), Chan->name ); + LogDebug("User \"%s\" joined channel \"%s\".", Client_Mask(Client), Chan->name); return cl2chan; } /* Add_Client */ @@ -1013,6 +1038,76 @@ Channel_ShowInvites( CLIENT *Client, CHANNEL *Channel ) } +/** + * Log a message to the local &SERVER channel, if it exists. + */ +GLOBAL void +Channel_LogServer(const char *msg) +{ + CHANNEL *sc; + CLIENT *c; + + assert(msg != NULL); + + sc = Channel_Search("&SERVER"); + if (!sc) + return; + + c = Client_ThisServer(); + Channel_Write(sc, c, c, "PRIVMSG", false, msg); +} /* Channel_LogServer */ + + +GLOBAL bool +Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key) +{ + char *file_name, line[COMMAND_LEN], *nick, *pass; + FILE *fd; + + assert(Chan != NULL); + assert(Client != NULL); + assert(Key != NULL); + + if (!strchr(Chan->modes, 'k')) + return true; + if (strcmp(Chan->key, Key) == 0) + return true; + if (*Key == '\0') + return false; + + file_name = array_start(&Chan->keyfile); + if (!file_name) + return false; + fd = fopen(file_name, "r"); + if (!fd) { + Log(LOG_ERR, "Can't open channel key file \"%s\" for %s: %s", + file_name, Chan->name, strerror(errno)); + return false; + } + + while (fgets(line, (int)sizeof(line), fd) != NULL) { + ngt_TrimStr(line); + if (! (nick = strchr(line, ':'))) + continue; + *nick++ = '\0'; + if (!Match(line, Client_User(Client))) + continue; + if (! (pass = strchr(nick, ':'))) + continue; + *pass++ = '\0'; + if (!Match(nick, Client_ID(Client))) + continue; + if (strcmp(Key, pass) != 0) + continue; + + fclose(fd); + return true; + } + fclose(fd); + return false; +} /* Channel_CheckKey */ + + static CL2CHAN * Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan ) { @@ -1038,35 +1133,64 @@ Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel ) } /* Get_Next_Cl2Chan */ -static bool -Delete_Channel( CHANNEL *Chan ) +/** + * Remove a channel and free all of its data structures. + */ +static void +Delete_Channel(CHANNEL *Chan) { - /* delete channel structure */ - CHANNEL *chan, *last_chan; last_chan = NULL; chan = My_Channels; - while( chan ) - { - if( chan == Chan ) break; + while (chan) { + if (chan == Chan) + break; last_chan = chan; chan = chan->next; } - if( ! chan ) return false; - - Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name ); - /* free invite and ban lists */ - Lists_Free( &chan->list_bans ); - Lists_Free( &chan->list_invites ); + assert(chan != NULL); + if (!chan) + return; /* maintain channel list */ - if( last_chan ) last_chan->next = chan->next; - else My_Channels = chan->next; - free( chan ); + if (last_chan) + last_chan->next = chan->next; + else + My_Channels = chan->next; - return true; + LogDebug("Freed channel structure for \"%s\".", Chan->name); + Free_Channel(Chan); } /* Delete_Channel */ + +static void +Set_KeyFile(CHANNEL *Chan, const char *KeyFile) +{ + size_t len; + + assert(Chan != NULL); + assert(KeyFile != NULL); + + len = strlen(KeyFile); + if (len < array_bytes(&Chan->keyfile)) { + Log(LOG_INFO, "Channel key file of %s removed.", Chan->name); + array_free(&Chan->keyfile); + } + + if (len < 1) + return; + + if (!array_copyb(&Chan->keyfile, KeyFile, len+1)) + Log(LOG_WARNING, + "Could not set new channel key file \"%s\" for %s: %s", + KeyFile, Chan->name, strerror(errno)); + else + Log(LOG_INFO|LOG_snotice, + "New local channel key file \"%s\" for %s activated.", + KeyFile, Chan->name); +} /* Set_KeyFile */ + + /* -eof- */