X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fchannel.c;h=74c97a0a8dc41abe99c30981d0f840402f040df9;hp=46e42acd834ea9bcc7600e33406367ac74cd3ef3;hb=8fa92f0a24bb97a972ef82b8fa057d737c9f55b7;hpb=1c7b9dbe931ecbb0f355ab66c9b422f7e6001058 diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 46e42acd..74c97a0a 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -1,44 +1,45 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. - * - * Channel management */ - #define __channel_c__ - #include "portab.h" +/** + * @file + * Channel management + */ + #include "imp.h" #include #include #include #include +#include #include #include "defines.h" #include "conn-func.h" -#include "client.h" #include "exp.h" #include "channel.h" #include "imp.h" #include "irc-write.h" -#include "resolve.h" #include "conf.h" #include "hash.h" #include "lists.h" #include "log.h" #include "messages.h" +#include "match.h" #include "exp.h" @@ -59,6 +60,7 @@ static CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan )); static CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, 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 @@ -108,16 +110,21 @@ Channel_InitPredefined( void ) 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); + if (!conf_chan->name[0]) + continue; + if (!Channel_IsValidName(conf_chan->name)) { + Log(LOG_ERR, + "Can't create pre-defined channel: invalid name: \"%s\"", + conf_chan->name); continue; } 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); + 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; } @@ -127,6 +134,8 @@ Channel_InitPredefined( void ) conf_chan->name); continue; } + Log(LOG_INFO, "Created pre-defined channel \"%s\"", + conf_chan->name); Channel_ModeAdd(new_chan, 'P'); @@ -139,8 +148,7 @@ Channel_InitPredefined( void ) Channel_SetKey(new_chan, conf_chan->key); Channel_SetMaxUsers(new_chan, conf_chan->maxusers); - Log(LOG_INFO, "Created pre-defined channel \"%s\"", - conf_chan->name); + Set_KeyFile(new_chan, conf_chan->keyfile); } if (channel_count) array_free(&Conf_Channels); @@ -151,6 +159,7 @@ static void Free_Channel(CHANNEL *chan) { array_free(&chan->topic); + array_free(&chan->keyfile); Lists_Free(&chan->list_bans); Lists_Free(&chan->list_invites); @@ -191,7 +200,7 @@ Channel_Exit( void ) * Add_Client(). */ GLOBAL bool -Channel_Join( CLIENT *Client, char *Name ) +Channel_Join( CLIENT *Client, const char *Name ) { CHANNEL *chan; @@ -257,6 +266,9 @@ Channel_Part(CLIENT * Client, CLIENT * Origin, const char *Name, const char *Rea return false; } + if (Conf_MorePrivacy) + Reason = ""; + /* Part client from channel */ if (!Remove_Client(REMOVE_PART, chan, Client, Origin, Reason, true)) return false; @@ -318,13 +330,16 @@ 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; assert( Client != NULL ); assert( Reason != NULL ); + if (Conf_MorePrivacy) + Reason = ""; + IRC_WriteStrRelatedPrefix( Client, Client, false, "QUIT :%s", Reason ); c = My_Channels; @@ -692,6 +707,14 @@ Channel_TopicWho(CHANNEL *Chan) return Chan->topic_who; } /* Channel_TopicWho */ + +GLOBAL unsigned int +Channel_CreationTime(CHANNEL *Chan) +{ + assert(Chan != NULL); + return (unsigned int) Chan->creation_time; +} /* Channel_CreationTime */ + #endif @@ -724,7 +747,7 @@ Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, const char *Topic) GLOBAL void -Channel_SetModes( CHANNEL *Chan, char *Modes ) +Channel_SetModes( CHANNEL *Chan, const char *Modes ) { assert( Chan != NULL ); assert( Modes != NULL ); @@ -829,6 +852,9 @@ Channel_Create( const char *Name ) strlcpy( c->name, Name, sizeof( c->name )); c->hash = Hash( c->name ); c->next = My_Channels; +#ifndef STRICT_RFC + c->creation_time = time(NULL); +#endif My_Channels = c; LogDebug("Created new channel structure for \"%s\".", Name); return c; @@ -944,6 +970,9 @@ Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const ch Client_Mask( Client ), c->name, Client_ID(Origin), Reason); break; default: /* PART */ + if (Conf_MorePrivacy) + Reason = ""; + if (InformServer) IRC_WriteStrServersPrefix(Origin, Client, "PART %s :%s", c->name, Reason); @@ -973,6 +1002,7 @@ GLOBAL bool Channel_AddBan(CHANNEL *c, const char *mask ) { struct list_head *h = Channel_GetListBans(c); + LogDebug("Adding \"%s\" to \"%s\" %s list", mask, Channel_Name(c), "ban"); return Lists_Add(h, mask, false); } @@ -981,6 +1011,7 @@ GLOBAL bool Channel_AddInvite(CHANNEL *c, const char *mask, bool onlyonce) { struct list_head *h = Channel_GetListInvites(c); + LogDebug("Adding \"%s\" to \"%s\" %s list", mask, Channel_Name(c), "invite"); return Lists_Add(h, mask, onlyonce); } @@ -1035,7 +1066,7 @@ Channel_ShowInvites( CLIENT *Client, CHANNEL *Channel ) * Log a message to the local &SERVER channel, if it exists. */ GLOBAL void -Channel_LogServer(char *msg) +Channel_LogServer(const char *msg) { CHANNEL *sc; CLIENT *c; @@ -1051,6 +1082,114 @@ Channel_LogServer(char *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 (*Key == '\0') + return false; + if (strcmp(Chan->key, Key) == 0) + return true; + + 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 */ + + +/** + * Check wether a client is allowed to administer a channel or not. + * + * @param Chan The channel to test. + * @param Client The client from which the command has been received. + * @param Origin The originator of the command (or NULL). + * @param OnChannel Set to true if the originator is member of the channel. + * @param AdminOk Set to true if the client is allowed to do + * administrative tasks on this channel. + * @param UseServerMode Set to true if ngIRCd should emulate "server mode", + * that is send commands as if originating from a server + * and not the originator of the command. + */ +GLOBAL void +Channel_CheckAdminRights(CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, + bool *OnChannel, bool *AdminOk, bool *UseServerMode) +{ + assert (Chan != NULL); + assert (Client != NULL); + assert (OnChannel != NULL); + assert (AdminOk != NULL); + assert (UseServerMode != NULL); + + /* Use the client as origin, if no origin has been given (no prefix?) */ + if (!Origin) + Origin = Client; + + *OnChannel = false; + *AdminOk = false; + *UseServerMode = false; + + if (Client_Type(Client) != CLIENT_USER + && Client_Type(Client) != CLIENT_SERVER + && Client_Type(Client) != CLIENT_SERVICE) + return; + + /* Allow channel administration if the client is a server or service */ + if (Client_Type(Client) != CLIENT_USER) { + *AdminOk = true; + return; + } + + *OnChannel = Channel_IsMemberOf(Chan, Origin); + + if (*OnChannel && strchr(Channel_UserModes(Chan, Origin), 'o')) { + /* User is a channel operator */ + *AdminOk = true; + } else if (Conf_OperCanMode) { + /* IRC operators are allowed to administer channels as well */ + if (Client_OperByMe(Origin)) { + *AdminOk = true; + if (Conf_OperServerMode) + *UseServerMode = true; + } + } +} /* Channel_CheckAdminRights */ + + static CL2CHAN * Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan ) { @@ -1108,4 +1247,32 @@ Delete_Channel(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- */