diff options
Diffstat (limited to 'src/modules')
154 files changed, 154 insertions, 33856 deletions
diff --git a/src/modules/extra/README b/src/modules/extra/README index 7e3096b34..4c4beef9d 100644 --- a/src/modules/extra/README +++ b/src/modules/extra/README @@ -1,7 +1 @@ -This directory stores modules which require external libraries to compile. -For example, m_filter_pcre requires the PCRE libraries. - -To compile any of these modules first ensure you have the required dependencies -(read the online documentation at http://www.inspircd.org/wiki/) and then cp -the .cpp file from this directory into the parent directory (src/modules/) and -re-configure your inspircd with ./configure -update to detect the new module. +This directory stores modules which require external libraries to compile.
For example, m_filter_pcre requires the PCRE libraries.
To compile any of these modules first ensure you have the required dependencies
(read the online documentation at http://www.inspircd.org/wiki/) and then cp
the .cpp file from this directory into the parent directory (src/modules/) and
re-configure your inspircd with ./configure -update to detect the new module.
\ No newline at end of file diff --git a/src/modules/extra/m_filter_pcre.cpp b/src/modules/extra/m_filter_pcre.cpp index 6fe79a981..0c6c05c8c 100644 --- a/src/modules/extra/m_filter_pcre.cpp +++ b/src/modules/extra/m_filter_pcre.cpp @@ -1,182 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <pcre.h> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_filter.h" - -/* $ModDesc: m_filter with regexps */ -/* $CompileFlags: exec("pcre-config --cflags") */ -/* $LinkerFlags: exec("pcre-config --libs") rpath("pcre-config --libs") -lpcre */ -/* $ModDep: m_filter.h */ - -#ifdef WINDOWS -#pragma comment(lib, "pcre.lib") -#endif - -class PCREFilter : public FilterResult -{ - public: - pcre* regexp; - - PCREFilter(pcre* r, const std::string &rea, const std::string &act, long gline_time, const std::string &pat, const std::string &flags) - : FilterResult(pat, rea, act, gline_time, flags), regexp(r) - { - } - - PCREFilter() - { - } -}; - -class ModuleFilterPCRE : public FilterBase -{ - std::vector<PCREFilter> filters; - pcre *re; - const char *error; - int erroffset; - PCREFilter fr; - - public: - ModuleFilterPCRE(InspIRCd* Me) - : FilterBase(Me, "m_filter_pcre.so") - { - OnRehash(NULL,""); - } - - virtual ~ModuleFilterPCRE() - { - } - - virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags) - { - for (std::vector<PCREFilter>::iterator index = filters.begin(); index != filters.end(); index++) - { - /* Skip ones that dont apply to us */ - - if (!FilterBase::AppliesToMe(user, dynamic_cast<FilterResult*>(&(*index)), flags)) - continue; - - if (pcre_exec(index->regexp, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) > -1) - { - fr = *index; - if (index != filters.begin()) - { - filters.erase(index); - filters.insert(filters.begin(), fr); - } - return &fr; - } - } - return NULL; - } - - virtual bool DeleteFilter(const std::string &freeform) - { - for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++) - { - if (i->freeform == freeform) - { - pcre_free((*i).regexp); - filters.erase(i); - return true; - } - } - return false; - } - - virtual void SyncFilters(Module* proto, void* opaque) - { - for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++) - { - this->SendFilter(proto, opaque, &(*i)); - } - } - - virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags) - { - for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++) - { - if (i->freeform == freeform) - { - return std::make_pair(false, "Filter already exists"); - } - } - - re = pcre_compile(freeform.c_str(),0,&error,&erroffset,NULL); - - if (!re) - { - ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", freeform.c_str(), erroffset, error); - ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", freeform.c_str()); - return std::make_pair(false, "Error in regular expression at offset " + ConvToStr(erroffset) + ": "+error); - } - else - { - filters.push_back(PCREFilter(re, reason, type, duration, freeform, flags)); - return std::make_pair(true, ""); - } - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader MyConf(ServerInstance); - - for (int index = 0; index < MyConf.Enumerate("keyword"); index++) - { - this->DeleteFilter(MyConf.ReadValue("keyword", "pattern", index)); - - std::string pattern = MyConf.ReadValue("keyword", "pattern", index); - std::string reason = MyConf.ReadValue("keyword", "reason", index); - std::string action = MyConf.ReadValue("keyword", "action", index); - std::string flags = MyConf.ReadValue("keyword", "flags", index); - long gline_time = ServerInstance->Duration(MyConf.ReadValue("keyword", "duration", index)); - if (action.empty()) - action = "none"; - if (flags.empty()) - flags = "*"; - - re = pcre_compile(pattern.c_str(),0,&error,&erroffset,NULL); - - if (!re) - { - ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", pattern.c_str(), erroffset, error); - ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", pattern.c_str()); - } - else - { - filters.push_back(PCREFilter(re, reason, action, gline_time, pattern, flags)); - ServerInstance->Log(DEFAULT,"Regular expression %s loaded.", pattern.c_str()); - } - } - } - - virtual int OnStats(char symbol, userrec* user, string_list &results) - { - if (symbol == 's') - { - std::string sn = ServerInstance->Config->ServerName; - for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++) - { - results.push_back(sn+" 223 "+user->nick+" :REGEXP:"+i->freeform+" "+i->flags+" "+i->action+" "+ConvToStr(i->gline_time)+" :"+i->reason); - } - } - return 0; - } -}; - -MODULE_INIT(ModuleFilterPCRE); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <pcre.h>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_filter.h"
/* $ModDesc: m_filter with regexps */
/* $CompileFlags: exec("pcre-config --cflags") */
/* $LinkerFlags: exec("pcre-config --libs") rpath("pcre-config --libs") -lpcre */
/* $ModDep: m_filter.h */
#ifdef WINDOWS
#pragma comment(lib, "pcre.lib")
#endif
class PCREFilter : public FilterResult
{
public:
pcre* regexp;
PCREFilter(pcre* r, const std::string &rea, const std::string &act, long gline_time, const std::string &pat, const std::string &flags)
: FilterResult(pat, rea, act, gline_time, flags), regexp(r)
{
}
PCREFilter()
{
}
};
class ModuleFilterPCRE : public FilterBase
{
std::vector<PCREFilter> filters;
pcre *re;
const char *error;
int erroffset;
PCREFilter fr;
public:
ModuleFilterPCRE(InspIRCd* Me)
: FilterBase(Me, "m_filter_pcre.so")
{
OnRehash(NULL,"");
}
virtual ~ModuleFilterPCRE()
{
}
virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags)
{
for (std::vector<PCREFilter>::iterator index = filters.begin(); index != filters.end(); index++)
{
/* Skip ones that dont apply to us */
if (!FilterBase::AppliesToMe(user, dynamic_cast<FilterResult*>(&(*index)), flags))
continue;
if (pcre_exec(index->regexp, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) > -1)
{
fr = *index;
if (index != filters.begin())
{
filters.erase(index);
filters.insert(filters.begin(), fr);
}
return &fr;
}
}
return NULL;
}
virtual bool DeleteFilter(const std::string &freeform)
{
for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
{
if (i->freeform == freeform)
{
pcre_free((*i).regexp);
filters.erase(i);
return true;
}
}
return false;
}
virtual void SyncFilters(Module* proto, void* opaque)
{
for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
{
this->SendFilter(proto, opaque, &(*i));
}
}
virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags)
{
for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
{
if (i->freeform == freeform)
{
return std::make_pair(false, "Filter already exists");
}
}
re = pcre_compile(freeform.c_str(),0,&error,&erroffset,NULL);
if (!re)
{
ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", freeform.c_str(), erroffset, error);
ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", freeform.c_str());
return std::make_pair(false, "Error in regular expression at offset " + ConvToStr(erroffset) + ": "+error);
}
else
{
filters.push_back(PCREFilter(re, reason, type, duration, freeform, flags));
return std::make_pair(true, "");
}
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader MyConf(ServerInstance);
for (int index = 0; index < MyConf.Enumerate("keyword"); index++)
{
this->DeleteFilter(MyConf.ReadValue("keyword", "pattern", index));
std::string pattern = MyConf.ReadValue("keyword", "pattern", index);
std::string reason = MyConf.ReadValue("keyword", "reason", index);
std::string action = MyConf.ReadValue("keyword", "action", index);
std::string flags = MyConf.ReadValue("keyword", "flags", index);
long gline_time = ServerInstance->Duration(MyConf.ReadValue("keyword", "duration", index));
if (action.empty())
action = "none";
if (flags.empty())
flags = "*";
re = pcre_compile(pattern.c_str(),0,&error,&erroffset,NULL);
if (!re)
{
ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", pattern.c_str(), erroffset, error);
ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", pattern.c_str());
}
else
{
filters.push_back(PCREFilter(re, reason, action, gline_time, pattern, flags));
ServerInstance->Log(DEFAULT,"Regular expression %s loaded.", pattern.c_str());
}
}
}
virtual int OnStats(char symbol, userrec* user, string_list &results)
{
if (symbol == 's')
{
std::string sn = ServerInstance->Config->ServerName;
for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
{
results.push_back(sn+" 223 "+user->nick+" :REGEXP:"+i->freeform+" "+i->flags+" "+i->action+" "+ConvToStr(i->gline_time)+" :"+i->reason);
}
}
return 0;
}
};
MODULE_INIT(ModuleFilterPCRE);
\ No newline at end of file diff --git a/src/modules/extra/m_httpclienttest.cpp b/src/modules/extra/m_httpclienttest.cpp index 90e7a5159..3f74b549b 100644 --- a/src/modules/extra/m_httpclienttest.cpp +++ b/src/modules/extra/m_httpclienttest.cpp @@ -1,81 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "httpclient.h" - -/* $ModDep: httpclient.h */ - -class MyModule : public Module -{ - -public: - - MyModule(InspIRCd* Me) - : Module::Module(Me) - { - } - - virtual ~MyModule() - { - } - - virtual void Implements(char* List) - { - List[I_OnRequest] = List[I_OnUserJoin] = List[I_OnUserPart] = 1; - } - - virtual Version GetVersion() - { - return Version(1,0,0,1,VF_VENDOR,API_VERSION); - } - - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - // method called when a user joins a channel - - std::string chan = channel->name; - std::string nick = user->nick; - ServerInstance->Log(DEBUG,"User " + nick + " joined " + chan); - - Module* target = ServerInstance->FindModule("m_http_client.so"); - if(target) - { - HTTPClientRequest req(ServerInstance, this, target, "http://znc.in/~psychon"); - req.Send(); - } - else - ServerInstance->Log(DEBUG,"module not found, load it!!"); - } - - char* OnRequest(Request* req) - { - HTTPClientResponse* resp = (HTTPClientResponse*)req; - if(!strcmp(resp->GetId(), HTTP_CLIENT_RESPONSE)) - { - ServerInstance->Log(DEBUG, resp->GetData()); - } - return NULL; - } - - virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent) - { - } - -}; - -MODULE_INIT(MyModule); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "httpclient.h"
/* $ModDep: httpclient.h */
class MyModule : public Module
{
public:
MyModule(InspIRCd* Me)
: Module::Module(Me)
{
}
virtual ~MyModule()
{
}
virtual void Implements(char* List)
{
List[I_OnRequest] = List[I_OnUserJoin] = List[I_OnUserPart] = 1;
}
virtual Version GetVersion()
{
return Version(1,0,0,1,VF_VENDOR,API_VERSION);
}
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
// method called when a user joins a channel
std::string chan = channel->name;
std::string nick = user->nick;
ServerInstance->Log(DEBUG,"User " + nick + " joined " + chan);
Module* target = ServerInstance->FindModule("m_http_client.so");
if(target)
{
HTTPClientRequest req(ServerInstance, this, target, "http://znc.in/~psychon");
req.Send();
}
else
ServerInstance->Log(DEBUG,"module not found, load it!!");
}
char* OnRequest(Request* req)
{
HTTPClientResponse* resp = (HTTPClientResponse*)req;
if(!strcmp(resp->GetId(), HTTP_CLIENT_RESPONSE))
{
ServerInstance->Log(DEBUG, resp->GetData());
}
return NULL;
}
virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
{
}
};
MODULE_INIT(MyModule);
\ No newline at end of file diff --git a/src/modules/extra/m_mysql.cpp b/src/modules/extra/m_mysql.cpp index 6605bed3c..eeabe5d48 100644 --- a/src/modules/extra/m_mysql.cpp +++ b/src/modules/extra/m_mysql.cpp @@ -1,889 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <mysql.h> -#include <pthread.h> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_sqlv2.h" - -/* VERSION 2 API: With nonblocking (threaded) requests */ - -/* $ModDesc: SQL Service Provider module for all other m_sql* modules */ -/* $CompileFlags: exec("mysql_config --include") */ -/* $LinkerFlags: exec("mysql_config --libs_r") rpath("mysql_config --libs_r") */ -/* $ModDep: m_sqlv2.h */ - -/* THE NONBLOCKING MYSQL API! - * - * MySQL provides no nonblocking (asyncronous) API of its own, and its developers recommend - * that instead, you should thread your program. This is what i've done here to allow for - * asyncronous SQL requests via mysql. The way this works is as follows: - * - * The module spawns a thread via pthreads, and performs its mysql queries in this thread, - * using a queue with priorities. There is a mutex on either end which prevents two threads - * adjusting the queue at the same time, and crashing the ircd. Every 50 milliseconds, the - * worker thread wakes up, and checks if there is a request at the head of its queue. - * If there is, it processes this request, blocking the worker thread but leaving the ircd - * thread to go about its business as usual. During this period, the ircd thread is able - * to insert futher pending requests into the queue. - * - * Once the processing of a request is complete, it is removed from the incoming queue to - * an outgoing queue, and initialized as a 'response'. The worker thread then signals the - * ircd thread (via a loopback socket) of the fact a result is available, by sending the - * connection ID through the connection. - * - * The ircd thread then mutexes the queue once more, reads the outbound response off the head - * of the queue, and sends it on its way to the original calling module. - * - * XXX: You might be asking "why doesnt he just send the response from within the worker thread?" - * The answer to this is simple. The majority of InspIRCd, and in fact most ircd's are not - * threadsafe. This module is designed to be threadsafe and is careful with its use of threads, - * however, if we were to call a module's OnRequest even from within a thread which was not the - * one the module was originally instantiated upon, there is a chance of all hell breaking loose - * if a module is ever put in a re-enterant state (stack corruption could occur, crashes, data - * corruption, and worse, so DONT think about it until the day comes when InspIRCd is 100% - * gauranteed threadsafe!) - * - * For a diagram of this system please see http://www.inspircd.org/wiki/Mysql2 - */ - - -class SQLConnection; -class Notifier; - - -typedef std::map<std::string, SQLConnection*> ConnMap; -bool giveup = false; -static Module* SQLModule = NULL; -static Notifier* MessagePipe = NULL; -int QueueFD = -1; - - -#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224 -#define mysql_field_count mysql_num_fields -#endif - -typedef std::deque<SQLresult*> ResultQueue; - -/* A mutex to wrap around queue accesses */ -pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; - -pthread_mutex_t results_mutex = PTHREAD_MUTEX_INITIALIZER; - -pthread_mutex_t logging_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** Represents a mysql result set - */ -class MySQLresult : public SQLresult -{ - int currentrow; - std::vector<std::string> colnames; - std::vector<SQLfieldList> fieldlists; - SQLfieldMap* fieldmap; - SQLfieldMap fieldmap2; - SQLfieldList emptyfieldlist; - int rows; - public: - - MySQLresult(Module* self, Module* to, MYSQL_RES* res, int affected_rows, unsigned int id) : SQLresult(self, to, id), currentrow(0), fieldmap(NULL) - { - /* A number of affected rows from from mysql_affected_rows. - */ - fieldlists.clear(); - rows = 0; - if (affected_rows >= 1) - { - rows = affected_rows; - fieldlists.resize(rows); - } - unsigned int field_count = 0; - if (res) - { - MYSQL_ROW row; - int n = 0; - while ((row = mysql_fetch_row(res))) - { - if (fieldlists.size() < (unsigned int)rows+1) - { - fieldlists.resize(fieldlists.size()+1); - } - field_count = 0; - MYSQL_FIELD *fields = mysql_fetch_fields(res); - if(mysql_num_fields(res) == 0) - break; - if (fields && mysql_num_fields(res)) - { - colnames.clear(); - while (field_count < mysql_num_fields(res)) - { - std::string a = (fields[field_count].name ? fields[field_count].name : ""); - std::string b = (row[field_count] ? row[field_count] : ""); - SQLfield sqlf(b, !row[field_count]); - colnames.push_back(a); - fieldlists[n].push_back(sqlf); - field_count++; - } - n++; - } - rows++; - } - mysql_free_result(res); - } - } - - MySQLresult(Module* self, Module* to, SQLerror e, unsigned int id) : SQLresult(self, to, id), currentrow(0) - { - rows = 0; - error = e; - } - - ~MySQLresult() - { - } - - virtual int Rows() - { - return rows; - } - - virtual int Cols() - { - return colnames.size(); - } - - virtual std::string ColName(int column) - { - if (column < (int)colnames.size()) - { - return colnames[column]; - } - else - { - throw SQLbadColName(); - } - return ""; - } - - virtual int ColNum(const std::string &column) - { - for (unsigned int i = 0; i < colnames.size(); i++) - { - if (column == colnames[i]) - return i; - } - throw SQLbadColName(); - return 0; - } - - virtual SQLfield GetValue(int row, int column) - { - if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols())) - { - return fieldlists[row][column]; - } - - throw SQLbadColName(); - - /* XXX: We never actually get here because of the throw */ - return SQLfield("",true); - } - - virtual SQLfieldList& GetRow() - { - if (currentrow < rows) - return fieldlists[currentrow]; - else - return emptyfieldlist; - } - - virtual SQLfieldMap& GetRowMap() - { - fieldmap2.clear(); - - if (currentrow < rows) - { - for (int i = 0; i < Cols(); i++) - { - fieldmap2.insert(std::make_pair(colnames[i],GetValue(currentrow, i))); - } - currentrow++; - } - - return fieldmap2; - } - - virtual SQLfieldList* GetRowPtr() - { - SQLfieldList* fieldlist = new SQLfieldList(); - - if (currentrow < rows) - { - for (int i = 0; i < Rows(); i++) - { - fieldlist->push_back(fieldlists[currentrow][i]); - } - currentrow++; - } - return fieldlist; - } - - virtual SQLfieldMap* GetRowMapPtr() - { - fieldmap = new SQLfieldMap(); - - if (currentrow < rows) - { - for (int i = 0; i < Cols(); i++) - { - fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i))); - } - currentrow++; - } - - return fieldmap; - } - - virtual void Free(SQLfieldMap* fm) - { - delete fm; - } - - virtual void Free(SQLfieldList* fl) - { - delete fl; - } -}; - -class SQLConnection; - -void NotifyMainThread(SQLConnection* connection_with_new_result); - -/** Represents a connection to a mysql database - */ -class SQLConnection : public classbase -{ - protected: - - MYSQL connection; - MYSQL_RES *res; - MYSQL_ROW row; - SQLhost host; - std::map<std::string,std::string> thisrow; - bool Enabled; - - public: - - QueryQueue queue; - ResultQueue rq; - - // This constructor creates an SQLConnection object with the given credentials, but does not connect yet. - SQLConnection(const SQLhost &hi) : host(hi), Enabled(false) - { - } - - ~SQLConnection() - { - Close(); - } - - // This method connects to the database using the credentials supplied to the constructor, and returns - // true upon success. - bool Connect() - { - unsigned int timeout = 1; - mysql_init(&connection); - mysql_options(&connection,MYSQL_OPT_CONNECT_TIMEOUT,(char*)&timeout); - return mysql_real_connect(&connection, host.host.c_str(), host.user.c_str(), host.pass.c_str(), host.name.c_str(), host.port, NULL, 0); - } - - void DoLeadingQuery() - { - if (!CheckConnection()) - return; - - /* Parse the command string and dispatch it to mysql */ - SQLrequest& req = queue.front(); - - /* Pointer to the buffer we screw around with substitution in */ - char* query; - - /* Pointer to the current end of query, where we append new stuff */ - char* queryend; - - /* Total length of the unescaped parameters */ - unsigned long paramlen; - - /* Total length of query, used for binary-safety in mysql_real_query */ - unsigned long querylength = 0; - - paramlen = 0; - - for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++) - { - paramlen += i->size(); - } - - /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be. - * sizeofquery + (totalparamlength*2) + 1 - * - * The +1 is for null-terminating the string for mysql_real_escape_string - */ - - query = new char[req.query.q.length() + (paramlen*2) + 1]; - queryend = query; - - /* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting - * the parameters into it... - */ - - for(unsigned long i = 0; i < req.query.q.length(); i++) - { - if(req.query.q[i] == '?') - { - /* We found a place to substitute..what fun. - * use mysql calls to escape and write the - * escaped string onto the end of our query buffer, - * then we "just" need to make sure queryend is - * pointing at the right place. - */ - if(req.query.p.size()) - { - unsigned long len = mysql_real_escape_string(&connection, queryend, req.query.p.front().c_str(), req.query.p.front().length()); - - queryend += len; - req.query.p.pop_front(); - } - else - break; - } - else - { - *queryend = req.query.q[i]; - queryend++; - } - querylength++; - } - - *queryend = 0; - - pthread_mutex_lock(&queue_mutex); - req.query.q = query; - pthread_mutex_unlock(&queue_mutex); - - if (!mysql_real_query(&connection, req.query.q.data(), req.query.q.length())) - { - /* Successfull query */ - res = mysql_use_result(&connection); - unsigned long rows = mysql_affected_rows(&connection); - MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), res, rows, req.id); - r->dbid = this->GetID(); - r->query = req.query.q; - /* Put this new result onto the results queue. - * XXX: Remember to mutex the queue! - */ - pthread_mutex_lock(&results_mutex); - rq.push_back(r); - pthread_mutex_unlock(&results_mutex); - } - else - { - /* XXX: See /usr/include/mysql/mysqld_error.h for a list of - * possible error numbers and error messages */ - SQLerror e(QREPLY_FAIL, ConvToStr(mysql_errno(&connection)) + std::string(": ") + mysql_error(&connection)); - MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), e, req.id); - r->dbid = this->GetID(); - r->query = req.query.q; - - pthread_mutex_lock(&results_mutex); - rq.push_back(r); - pthread_mutex_unlock(&results_mutex); - } - - /* Now signal the main thread that we've got a result to process. - * Pass them this connection id as what to examine - */ - - delete[] query; - - NotifyMainThread(this); - } - - bool ConnectionLost() - { - if (&connection) { - return (mysql_ping(&connection) != 0); - } - else return false; - } - - bool CheckConnection() - { - if (ConnectionLost()) { - return Connect(); - } - else return true; - } - - std::string GetError() - { - return mysql_error(&connection); - } - - const std::string& GetID() - { - return host.id; - } - - std::string GetHost() - { - return host.host; - } - - void SetEnable(bool Enable) - { - Enabled = Enable; - } - - bool IsEnabled() - { - return Enabled; - } - - void Close() - { - mysql_close(&connection); - } - - const SQLhost& GetConfHost() - { - return host; - } - -}; - -ConnMap Connections; - -bool HasHost(const SQLhost &host) -{ - for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); iter++) - { - if (host == iter->second->GetConfHost()) - return true; - } - return false; -} - -bool HostInConf(ConfigReader* conf, const SQLhost &h) -{ - for(int i = 0; i < conf->Enumerate("database"); i++) - { - SQLhost host; - host.id = conf->ReadValue("database", "id", i); - host.host = conf->ReadValue("database", "hostname", i); - host.port = conf->ReadInteger("database", "port", i, true); - host.name = conf->ReadValue("database", "name", i); - host.user = conf->ReadValue("database", "username", i); - host.pass = conf->ReadValue("database", "password", i); - host.ssl = conf->ReadFlag("database", "ssl", i); - if (h == host) - return true; - } - return false; -} - -void ClearOldConnections(ConfigReader* conf) -{ - ConnMap::iterator i,safei; - for (i = Connections.begin(); i != Connections.end(); i++) - { - if (!HostInConf(conf, i->second->GetConfHost())) - { - DELETE(i->second); - safei = i; - --i; - Connections.erase(safei); - } - } -} - -void ClearAllConnections() -{ - ConnMap::iterator i; - while ((i = Connections.begin()) != Connections.end()) - { - Connections.erase(i); - DELETE(i->second); - } -} - -void ConnectDatabases(InspIRCd* ServerInstance) -{ - for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++) - { - if (i->second->IsEnabled()) - continue; - - i->second->SetEnable(true); - if (!i->second->Connect()) - { - /* XXX: MUTEX */ - pthread_mutex_lock(&logging_mutex); - ServerInstance->Log(DEFAULT,"SQL: Failed to connect database "+i->second->GetHost()+": Error: "+i->second->GetError()); - i->second->SetEnable(false); - pthread_mutex_unlock(&logging_mutex); - } - } -} - -void LoadDatabases(ConfigReader* conf, InspIRCd* ServerInstance) -{ - ClearOldConnections(conf); - for (int j =0; j < conf->Enumerate("database"); j++) - { - SQLhost host; - host.id = conf->ReadValue("database", "id", j); - host.host = conf->ReadValue("database", "hostname", j); - host.port = conf->ReadInteger("database", "port", j, true); - host.name = conf->ReadValue("database", "name", j); - host.user = conf->ReadValue("database", "username", j); - host.pass = conf->ReadValue("database", "password", j); - host.ssl = conf->ReadFlag("database", "ssl", j); - - if (HasHost(host)) - continue; - - if (!host.id.empty() && !host.host.empty() && !host.name.empty() && !host.user.empty() && !host.pass.empty()) - { - SQLConnection* ThisSQL = new SQLConnection(host); - Connections[host.id] = ThisSQL; - } - } - ConnectDatabases(ServerInstance); -} - -char FindCharId(const std::string &id) -{ - char i = 1; - for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i) - { - if (iter->first == id) - { - return i; - } - } - return 0; -} - -ConnMap::iterator GetCharId(char id) -{ - char i = 1; - for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i) - { - if (i == id) - return iter; - } - return Connections.end(); -} - -void NotifyMainThread(SQLConnection* connection_with_new_result) -{ - /* Here we write() to the socket the main thread has open - * and we connect()ed back to before our thread became active. - * The main thread is using a nonblocking socket tied into - * the socket engine, so they wont block and they'll receive - * nearly instant notification. Because we're in a seperate - * thread, we can just use standard connect(), and we can - * block if we like. We just send the connection id of the - * connection back. - * - * NOTE: We only send a single char down the connection, this - * way we know it wont get a partial read at the other end if - * the system is especially congested (see bug #263). - * The function FindCharId translates a connection name into a - * one character id, and GetCharId translates a character id - * back into an iterator. - */ - char id = FindCharId(connection_with_new_result->GetID()); - send(QueueFD, &id, 1, 0); -} - -void* DispatcherThread(void* arg); - -/** Used by m_mysql to notify one thread when the other has a result - */ -class Notifier : public InspSocket -{ - insp_sockaddr sock_us; - socklen_t uslen; - - - public: - - /* Create a socket on a random port. Let the tcp stack allocate us an available port */ -#ifdef IPV6 - Notifier(InspIRCd* SI) : InspSocket(SI, "::1", 0, true, 3000) -#else - Notifier(InspIRCd* SI) : InspSocket(SI, "127.0.0.1", 0, true, 3000) -#endif - { - uslen = sizeof(sock_us); - if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen)) - { - throw ModuleException("Could not create random listening port on localhost"); - } - } - - Notifier(InspIRCd* SI, int newfd, char* ip) : InspSocket(SI, newfd, ip) - { - } - - /* Using getsockname and ntohs, we can determine which port number we were allocated */ - int GetPort() - { -#ifdef IPV6 - return ntohs(sock_us.sin6_port); -#else - return ntohs(sock_us.sin_port); -#endif - } - - virtual int OnIncomingConnection(int newsock, char* ip) - { - Notifier* n = new Notifier(this->Instance, newsock, ip); - n = n; /* Stop bitching at me, GCC */ - return true; - } - - virtual bool OnDataReady() - { - char data = 0; - /* NOTE: Only a single character is read so we know we - * cant get a partial read. (We've been told that theres - * data waiting, so we wont ever get EAGAIN) - * The function GetCharId translates a single character - * back into an iterator. - */ - if (read(this->GetFd(), &data, 1) > 0) - { - ConnMap::iterator iter = GetCharId(data); - if (iter != Connections.end()) - { - /* Lock the mutex, send back the data */ - pthread_mutex_lock(&results_mutex); - ResultQueue::iterator n = iter->second->rq.begin(); - (*n)->Send(); - iter->second->rq.pop_front(); - pthread_mutex_unlock(&results_mutex); - return true; - } - /* No error, but unknown id */ - return true; - } - - /* Erk, error on descriptor! */ - return false; - } -}; - -/** MySQL module - */ -class ModuleSQL : public Module -{ - public: - - ConfigReader *Conf; - InspIRCd* PublicServerInstance; - pthread_t Dispatcher; - int currid; - bool rehashing; - - ModuleSQL(InspIRCd* Me) - : Module::Module(Me), rehashing(false) - { - ServerInstance->UseInterface("SQLutils"); - - Conf = new ConfigReader(ServerInstance); - PublicServerInstance = ServerInstance; - currid = 0; - SQLModule = this; - - MessagePipe = new Notifier(ServerInstance); - - pthread_attr_t attribs; - pthread_attr_init(&attribs); - pthread_attr_setdetachstate(&attribs, PTHREAD_CREATE_DETACHED); - if (pthread_create(&this->Dispatcher, &attribs, DispatcherThread, (void *)this) != 0) - { - throw ModuleException("m_mysql: Failed to create dispatcher thread: " + std::string(strerror(errno))); - } - - if (!ServerInstance->PublishFeature("SQL", this)) - { - /* Tell worker thread to exit NOW */ - giveup = true; - throw ModuleException("m_mysql: Unable to publish feature 'SQL'"); - } - - ServerInstance->PublishInterface("SQL", this); - } - - virtual ~ModuleSQL() - { - giveup = true; - ClearAllConnections(); - DELETE(Conf); - ServerInstance->UnpublishInterface("SQL", this); - ServerInstance->UnpublishFeature("SQL"); - ServerInstance->DoneWithInterface("SQLutils"); - } - - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnRequest] = 1; - } - - unsigned long NewID() - { - if (currid+1 == 0) - currid++; - return ++currid; - } - - char* OnRequest(Request* request) - { - if(strcmp(SQLREQID, request->GetId()) == 0) - { - SQLrequest* req = (SQLrequest*)request; - - /* XXX: Lock */ - pthread_mutex_lock(&queue_mutex); - - ConnMap::iterator iter; - - char* returnval = NULL; - - if((iter = Connections.find(req->dbid)) != Connections.end()) - { - req->id = NewID(); - iter->second->queue.push(*req); - returnval = SQLSUCCESS; - } - else - { - req->error.Id(BAD_DBID); - } - - pthread_mutex_unlock(&queue_mutex); - /* XXX: Unlock */ - - return returnval; - } - - return NULL; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - rehashing = true; - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION); - } - -}; - -void* DispatcherThread(void* arg) -{ - ModuleSQL* thismodule = (ModuleSQL*)arg; - LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance); - - /* Connect back to the Notifier */ - - if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1) - { - /* crap, we're out of sockets... */ - return NULL; - } - - insp_sockaddr addr; - -#ifdef IPV6 - insp_aton("::1", &addr.sin6_addr); - addr.sin6_family = AF_FAMILY; - addr.sin6_port = htons(MessagePipe->GetPort()); -#else - insp_inaddr ia; - insp_aton("127.0.0.1", &ia); - addr.sin_family = AF_FAMILY; - addr.sin_addr = ia; - addr.sin_port = htons(MessagePipe->GetPort()); -#endif - - if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1) - { - /* wtf, we cant connect to it, but we just created it! */ - return NULL; - } - - while (!giveup) - { - if (thismodule->rehashing) - { - /* XXX: Lock */ - pthread_mutex_lock(&queue_mutex); - thismodule->rehashing = false; - LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance); - pthread_mutex_unlock(&queue_mutex); - /* XXX: Unlock */ - } - - SQLConnection* conn = NULL; - /* XXX: Lock here for safety */ - pthread_mutex_lock(&queue_mutex); - for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++) - { - if (i->second->queue.totalsize()) - { - conn = i->second; - break; - } - } - pthread_mutex_unlock(&queue_mutex); - /* XXX: Unlock */ - - /* Theres an item! */ - if (conn) - { - conn->DoLeadingQuery(); - - /* XXX: Lock */ - pthread_mutex_lock(&queue_mutex); - conn->queue.pop(); - pthread_mutex_unlock(&queue_mutex); - /* XXX: Unlock */ - } - - usleep(50); - } - - return NULL; -} - -MODULE_INIT(ModuleSQL); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <mysql.h>
#include <pthread.h>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_sqlv2.h"
/* VERSION 2 API: With nonblocking (threaded) requests */
/* $ModDesc: SQL Service Provider module for all other m_sql* modules */
/* $CompileFlags: exec("mysql_config --include") */
/* $LinkerFlags: exec("mysql_config --libs_r") rpath("mysql_config --libs_r") */
/* $ModDep: m_sqlv2.h */
/* THE NONBLOCKING MYSQL API!
*
* MySQL provides no nonblocking (asyncronous) API of its own, and its developers recommend
* that instead, you should thread your program. This is what i've done here to allow for
* asyncronous SQL requests via mysql. The way this works is as follows:
*
* The module spawns a thread via pthreads, and performs its mysql queries in this thread,
* using a queue with priorities. There is a mutex on either end which prevents two threads
* adjusting the queue at the same time, and crashing the ircd. Every 50 milliseconds, the
* worker thread wakes up, and checks if there is a request at the head of its queue.
* If there is, it processes this request, blocking the worker thread but leaving the ircd
* thread to go about its business as usual. During this period, the ircd thread is able
* to insert futher pending requests into the queue.
*
* Once the processing of a request is complete, it is removed from the incoming queue to
* an outgoing queue, and initialized as a 'response'. The worker thread then signals the
* ircd thread (via a loopback socket) of the fact a result is available, by sending the
* connection ID through the connection.
*
* The ircd thread then mutexes the queue once more, reads the outbound response off the head
* of the queue, and sends it on its way to the original calling module.
*
* XXX: You might be asking "why doesnt he just send the response from within the worker thread?"
* The answer to this is simple. The majority of InspIRCd, and in fact most ircd's are not
* threadsafe. This module is designed to be threadsafe and is careful with its use of threads,
* however, if we were to call a module's OnRequest even from within a thread which was not the
* one the module was originally instantiated upon, there is a chance of all hell breaking loose
* if a module is ever put in a re-enterant state (stack corruption could occur, crashes, data
* corruption, and worse, so DONT think about it until the day comes when InspIRCd is 100%
* gauranteed threadsafe!)
*
* For a diagram of this system please see http://www.inspircd.org/wiki/Mysql2
*/
class SQLConnection;
class Notifier;
typedef std::map<std::string, SQLConnection*> ConnMap;
bool giveup = false;
static Module* SQLModule = NULL;
static Notifier* MessagePipe = NULL;
int QueueFD = -1;
#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224
#define mysql_field_count mysql_num_fields
#endif
typedef std::deque<SQLresult*> ResultQueue;
/* A mutex to wrap around queue accesses */
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t results_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t logging_mutex = PTHREAD_MUTEX_INITIALIZER;
/** Represents a mysql result set
*/
class MySQLresult : public SQLresult
{
int currentrow;
std::vector<std::string> colnames;
std::vector<SQLfieldList> fieldlists;
SQLfieldMap* fieldmap;
SQLfieldMap fieldmap2;
SQLfieldList emptyfieldlist;
int rows;
public:
MySQLresult(Module* self, Module* to, MYSQL_RES* res, int affected_rows, unsigned int id) : SQLresult(self, to, id), currentrow(0), fieldmap(NULL)
{
/* A number of affected rows from from mysql_affected_rows.
*/
fieldlists.clear();
rows = 0;
if (affected_rows >= 1)
{
rows = affected_rows;
fieldlists.resize(rows);
}
unsigned int field_count = 0;
if (res)
{
MYSQL_ROW row;
int n = 0;
while ((row = mysql_fetch_row(res)))
{
if (fieldlists.size() < (unsigned int)rows+1)
{
fieldlists.resize(fieldlists.size()+1);
}
field_count = 0;
MYSQL_FIELD *fields = mysql_fetch_fields(res);
if(mysql_num_fields(res) == 0)
break;
if (fields && mysql_num_fields(res))
{
colnames.clear();
while (field_count < mysql_num_fields(res))
{
std::string a = (fields[field_count].name ? fields[field_count].name : "");
std::string b = (row[field_count] ? row[field_count] : "");
SQLfield sqlf(b, !row[field_count]);
colnames.push_back(a);
fieldlists[n].push_back(sqlf);
field_count++;
}
n++;
}
rows++;
}
mysql_free_result(res);
}
}
MySQLresult(Module* self, Module* to, SQLerror e, unsigned int id) : SQLresult(self, to, id), currentrow(0)
{
rows = 0;
error = e;
}
~MySQLresult()
{
}
virtual int Rows()
{
return rows;
}
virtual int Cols()
{
return colnames.size();
}
virtual std::string ColName(int column)
{
if (column < (int)colnames.size())
{
return colnames[column];
}
else
{
throw SQLbadColName();
}
return "";
}
virtual int ColNum(const std::string &column)
{
for (unsigned int i = 0; i < colnames.size(); i++)
{
if (column == colnames[i])
return i;
}
throw SQLbadColName();
return 0;
}
virtual SQLfield GetValue(int row, int column)
{
if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))
{
return fieldlists[row][column];
}
throw SQLbadColName();
/* XXX: We never actually get here because of the throw */
return SQLfield("",true);
}
virtual SQLfieldList& GetRow()
{
if (currentrow < rows)
return fieldlists[currentrow];
else
return emptyfieldlist;
}
virtual SQLfieldMap& GetRowMap()
{
fieldmap2.clear();
if (currentrow < rows)
{
for (int i = 0; i < Cols(); i++)
{
fieldmap2.insert(std::make_pair(colnames[i],GetValue(currentrow, i)));
}
currentrow++;
}
return fieldmap2;
}
virtual SQLfieldList* GetRowPtr()
{
SQLfieldList* fieldlist = new SQLfieldList();
if (currentrow < rows)
{
for (int i = 0; i < Rows(); i++)
{
fieldlist->push_back(fieldlists[currentrow][i]);
}
currentrow++;
}
return fieldlist;
}
virtual SQLfieldMap* GetRowMapPtr()
{
fieldmap = new SQLfieldMap();
if (currentrow < rows)
{
for (int i = 0; i < Cols(); i++)
{
fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i)));
}
currentrow++;
}
return fieldmap;
}
virtual void Free(SQLfieldMap* fm)
{
delete fm;
}
virtual void Free(SQLfieldList* fl)
{
delete fl;
}
};
class SQLConnection;
void NotifyMainThread(SQLConnection* connection_with_new_result);
/** Represents a connection to a mysql database
*/
class SQLConnection : public classbase
{
protected:
MYSQL connection;
MYSQL_RES *res;
MYSQL_ROW row;
SQLhost host;
std::map<std::string,std::string> thisrow;
bool Enabled;
public:
QueryQueue queue;
ResultQueue rq;
// This constructor creates an SQLConnection object with the given credentials, but does not connect yet.
SQLConnection(const SQLhost &hi) : host(hi), Enabled(false)
{
}
~SQLConnection()
{
Close();
}
// This method connects to the database using the credentials supplied to the constructor, and returns
// true upon success.
bool Connect()
{
unsigned int timeout = 1;
mysql_init(&connection);
mysql_options(&connection,MYSQL_OPT_CONNECT_TIMEOUT,(char*)&timeout);
return mysql_real_connect(&connection, host.host.c_str(), host.user.c_str(), host.pass.c_str(), host.name.c_str(), host.port, NULL, 0);
}
void DoLeadingQuery()
{
if (!CheckConnection())
return;
/* Parse the command string and dispatch it to mysql */
SQLrequest& req = queue.front();
/* Pointer to the buffer we screw around with substitution in */
char* query;
/* Pointer to the current end of query, where we append new stuff */
char* queryend;
/* Total length of the unescaped parameters */
unsigned long paramlen;
/* Total length of query, used for binary-safety in mysql_real_query */
unsigned long querylength = 0;
paramlen = 0;
for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)
{
paramlen += i->size();
}
/* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.
* sizeofquery + (totalparamlength*2) + 1
*
* The +1 is for null-terminating the string for mysql_real_escape_string
*/
query = new char[req.query.q.length() + (paramlen*2) + 1];
queryend = query;
/* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting
* the parameters into it...
*/
for(unsigned long i = 0; i < req.query.q.length(); i++)
{
if(req.query.q[i] == '?')
{
/* We found a place to substitute..what fun.
* use mysql calls to escape and write the
* escaped string onto the end of our query buffer,
* then we "just" need to make sure queryend is
* pointing at the right place.
*/
if(req.query.p.size())
{
unsigned long len = mysql_real_escape_string(&connection, queryend, req.query.p.front().c_str(), req.query.p.front().length());
queryend += len;
req.query.p.pop_front();
}
else
break;
}
else
{
*queryend = req.query.q[i];
queryend++;
}
querylength++;
}
*queryend = 0;
pthread_mutex_lock(&queue_mutex);
req.query.q = query;
pthread_mutex_unlock(&queue_mutex);
if (!mysql_real_query(&connection, req.query.q.data(), req.query.q.length()))
{
/* Successfull query */
res = mysql_use_result(&connection);
unsigned long rows = mysql_affected_rows(&connection);
MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), res, rows, req.id);
r->dbid = this->GetID();
r->query = req.query.q;
/* Put this new result onto the results queue.
* XXX: Remember to mutex the queue!
*/
pthread_mutex_lock(&results_mutex);
rq.push_back(r);
pthread_mutex_unlock(&results_mutex);
}
else
{
/* XXX: See /usr/include/mysql/mysqld_error.h for a list of
* possible error numbers and error messages */
SQLerror e(QREPLY_FAIL, ConvToStr(mysql_errno(&connection)) + std::string(": ") + mysql_error(&connection));
MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), e, req.id);
r->dbid = this->GetID();
r->query = req.query.q;
pthread_mutex_lock(&results_mutex);
rq.push_back(r);
pthread_mutex_unlock(&results_mutex);
}
/* Now signal the main thread that we've got a result to process.
* Pass them this connection id as what to examine
*/
delete[] query;
NotifyMainThread(this);
}
bool ConnectionLost()
{
if (&connection) {
return (mysql_ping(&connection) != 0);
}
else return false;
}
bool CheckConnection()
{
if (ConnectionLost()) {
return Connect();
}
else return true;
}
std::string GetError()
{
return mysql_error(&connection);
}
const std::string& GetID()
{
return host.id;
}
std::string GetHost()
{
return host.host;
}
void SetEnable(bool Enable)
{
Enabled = Enable;
}
bool IsEnabled()
{
return Enabled;
}
void Close()
{
mysql_close(&connection);
}
const SQLhost& GetConfHost()
{
return host;
}
};
ConnMap Connections;
bool HasHost(const SQLhost &host)
{
for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); iter++)
{
if (host == iter->second->GetConfHost())
return true;
}
return false;
}
bool HostInConf(ConfigReader* conf, const SQLhost &h)
{
for(int i = 0; i < conf->Enumerate("database"); i++)
{
SQLhost host;
host.id = conf->ReadValue("database", "id", i);
host.host = conf->ReadValue("database", "hostname", i);
host.port = conf->ReadInteger("database", "port", i, true);
host.name = conf->ReadValue("database", "name", i);
host.user = conf->ReadValue("database", "username", i);
host.pass = conf->ReadValue("database", "password", i);
host.ssl = conf->ReadFlag("database", "ssl", i);
if (h == host)
return true;
}
return false;
}
void ClearOldConnections(ConfigReader* conf)
{
ConnMap::iterator i,safei;
for (i = Connections.begin(); i != Connections.end(); i++)
{
if (!HostInConf(conf, i->second->GetConfHost()))
{
DELETE(i->second);
safei = i;
--i;
Connections.erase(safei);
}
}
}
void ClearAllConnections()
{
ConnMap::iterator i;
while ((i = Connections.begin()) != Connections.end())
{
Connections.erase(i);
DELETE(i->second);
}
}
void ConnectDatabases(InspIRCd* ServerInstance)
{
for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++)
{
if (i->second->IsEnabled())
continue;
i->second->SetEnable(true);
if (!i->second->Connect())
{
/* XXX: MUTEX */
pthread_mutex_lock(&logging_mutex);
ServerInstance->Log(DEFAULT,"SQL: Failed to connect database "+i->second->GetHost()+": Error: "+i->second->GetError());
i->second->SetEnable(false);
pthread_mutex_unlock(&logging_mutex);
}
}
}
void LoadDatabases(ConfigReader* conf, InspIRCd* ServerInstance)
{
ClearOldConnections(conf);
for (int j =0; j < conf->Enumerate("database"); j++)
{
SQLhost host;
host.id = conf->ReadValue("database", "id", j);
host.host = conf->ReadValue("database", "hostname", j);
host.port = conf->ReadInteger("database", "port", j, true);
host.name = conf->ReadValue("database", "name", j);
host.user = conf->ReadValue("database", "username", j);
host.pass = conf->ReadValue("database", "password", j);
host.ssl = conf->ReadFlag("database", "ssl", j);
if (HasHost(host))
continue;
if (!host.id.empty() && !host.host.empty() && !host.name.empty() && !host.user.empty() && !host.pass.empty())
{
SQLConnection* ThisSQL = new SQLConnection(host);
Connections[host.id] = ThisSQL;
}
}
ConnectDatabases(ServerInstance);
}
char FindCharId(const std::string &id)
{
char i = 1;
for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i)
{
if (iter->first == id)
{
return i;
}
}
return 0;
}
ConnMap::iterator GetCharId(char id)
{
char i = 1;
for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i)
{
if (i == id)
return iter;
}
return Connections.end();
}
void NotifyMainThread(SQLConnection* connection_with_new_result)
{
/* Here we write() to the socket the main thread has open
* and we connect()ed back to before our thread became active.
* The main thread is using a nonblocking socket tied into
* the socket engine, so they wont block and they'll receive
* nearly instant notification. Because we're in a seperate
* thread, we can just use standard connect(), and we can
* block if we like. We just send the connection id of the
* connection back.
*
* NOTE: We only send a single char down the connection, this
* way we know it wont get a partial read at the other end if
* the system is especially congested (see bug #263).
* The function FindCharId translates a connection name into a
* one character id, and GetCharId translates a character id
* back into an iterator.
*/
char id = FindCharId(connection_with_new_result->GetID());
send(QueueFD, &id, 1, 0);
}
void* DispatcherThread(void* arg);
/** Used by m_mysql to notify one thread when the other has a result
*/
class Notifier : public InspSocket
{
insp_sockaddr sock_us;
socklen_t uslen;
public:
/* Create a socket on a random port. Let the tcp stack allocate us an available port */
#ifdef IPV6
Notifier(InspIRCd* SI) : InspSocket(SI, "::1", 0, true, 3000)
#else
Notifier(InspIRCd* SI) : InspSocket(SI, "127.0.0.1", 0, true, 3000)
#endif
{
uslen = sizeof(sock_us);
if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen))
{
throw ModuleException("Could not create random listening port on localhost");
}
}
Notifier(InspIRCd* SI, int newfd, char* ip) : InspSocket(SI, newfd, ip)
{
}
/* Using getsockname and ntohs, we can determine which port number we were allocated */
int GetPort()
{
#ifdef IPV6
return ntohs(sock_us.sin6_port);
#else
return ntohs(sock_us.sin_port);
#endif
}
virtual int OnIncomingConnection(int newsock, char* ip)
{
Notifier* n = new Notifier(this->Instance, newsock, ip);
n = n; /* Stop bitching at me, GCC */
return true;
}
virtual bool OnDataReady()
{
char data = 0;
/* NOTE: Only a single character is read so we know we
* cant get a partial read. (We've been told that theres
* data waiting, so we wont ever get EAGAIN)
* The function GetCharId translates a single character
* back into an iterator.
*/
if (read(this->GetFd(), &data, 1) > 0)
{
ConnMap::iterator iter = GetCharId(data);
if (iter != Connections.end())
{
/* Lock the mutex, send back the data */
pthread_mutex_lock(&results_mutex);
ResultQueue::iterator n = iter->second->rq.begin();
(*n)->Send();
iter->second->rq.pop_front();
pthread_mutex_unlock(&results_mutex);
return true;
}
/* No error, but unknown id */
return true;
}
/* Erk, error on descriptor! */
return false;
}
};
/** MySQL module
*/
class ModuleSQL : public Module
{
public:
ConfigReader *Conf;
InspIRCd* PublicServerInstance;
pthread_t Dispatcher;
int currid;
bool rehashing;
ModuleSQL(InspIRCd* Me)
: Module::Module(Me), rehashing(false)
{
ServerInstance->UseInterface("SQLutils");
Conf = new ConfigReader(ServerInstance);
PublicServerInstance = ServerInstance;
currid = 0;
SQLModule = this;
MessagePipe = new Notifier(ServerInstance);
pthread_attr_t attribs;
pthread_attr_init(&attribs);
pthread_attr_setdetachstate(&attribs, PTHREAD_CREATE_DETACHED);
if (pthread_create(&this->Dispatcher, &attribs, DispatcherThread, (void *)this) != 0)
{
throw ModuleException("m_mysql: Failed to create dispatcher thread: " + std::string(strerror(errno)));
}
if (!ServerInstance->PublishFeature("SQL", this))
{
/* Tell worker thread to exit NOW */
giveup = true;
throw ModuleException("m_mysql: Unable to publish feature 'SQL'");
}
ServerInstance->PublishInterface("SQL", this);
}
virtual ~ModuleSQL()
{
giveup = true;
ClearAllConnections();
DELETE(Conf);
ServerInstance->UnpublishInterface("SQL", this);
ServerInstance->UnpublishFeature("SQL");
ServerInstance->DoneWithInterface("SQLutils");
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnRequest] = 1;
}
unsigned long NewID()
{
if (currid+1 == 0)
currid++;
return ++currid;
}
char* OnRequest(Request* request)
{
if(strcmp(SQLREQID, request->GetId()) == 0)
{
SQLrequest* req = (SQLrequest*)request;
/* XXX: Lock */
pthread_mutex_lock(&queue_mutex);
ConnMap::iterator iter;
char* returnval = NULL;
if((iter = Connections.find(req->dbid)) != Connections.end())
{
req->id = NewID();
iter->second->queue.push(*req);
returnval = SQLSUCCESS;
}
else
{
req->error.Id(BAD_DBID);
}
pthread_mutex_unlock(&queue_mutex);
/* XXX: Unlock */
return returnval;
}
return NULL;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
rehashing = true;
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
}
};
void* DispatcherThread(void* arg)
{
ModuleSQL* thismodule = (ModuleSQL*)arg;
LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance);
/* Connect back to the Notifier */
if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1)
{
/* crap, we're out of sockets... */
return NULL;
}
insp_sockaddr addr;
#ifdef IPV6
insp_aton("::1", &addr.sin6_addr);
addr.sin6_family = AF_FAMILY;
addr.sin6_port = htons(MessagePipe->GetPort());
#else
insp_inaddr ia;
insp_aton("127.0.0.1", &ia);
addr.sin_family = AF_FAMILY;
addr.sin_addr = ia;
addr.sin_port = htons(MessagePipe->GetPort());
#endif
if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1)
{
/* wtf, we cant connect to it, but we just created it! */
return NULL;
}
while (!giveup)
{
if (thismodule->rehashing)
{
/* XXX: Lock */
pthread_mutex_lock(&queue_mutex);
thismodule->rehashing = false;
LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance);
pthread_mutex_unlock(&queue_mutex);
/* XXX: Unlock */
}
SQLConnection* conn = NULL;
/* XXX: Lock here for safety */
pthread_mutex_lock(&queue_mutex);
for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++)
{
if (i->second->queue.totalsize())
{
conn = i->second;
break;
}
}
pthread_mutex_unlock(&queue_mutex);
/* XXX: Unlock */
/* Theres an item! */
if (conn)
{
conn->DoLeadingQuery();
/* XXX: Lock */
pthread_mutex_lock(&queue_mutex);
conn->queue.pop();
pthread_mutex_unlock(&queue_mutex);
/* XXX: Unlock */
}
usleep(50);
}
return NULL;
}
MODULE_INIT(ModuleSQL);
\ No newline at end of file diff --git a/src/modules/extra/m_pgsql.cpp b/src/modules/extra/m_pgsql.cpp index 5d267fc1a..9e85a40de 100644 --- a/src/modules/extra/m_pgsql.cpp +++ b/src/modules/extra/m_pgsql.cpp @@ -1,984 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <cstdlib> -#include <sstream> -#include <libpq-fe.h> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" -#include "m_sqlv2.h" - -/* $ModDesc: PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API */ -/* $CompileFlags: -Iexec("pg_config --includedir") eval("my $s = `pg_config --version`;$s =~ /^.*?(\d+)\.(\d+)\.(\d+).*?$/;my $v = hex(sprintf("0x%02x%02x%02x", $1, $2, $3));print "-DPGSQL_HAS_ESCAPECONN" if(($v >= 0x080104) || ($v >= 0x07030F && $v < 0x070400) || ($v >= 0x07040D && $v < 0x080000) || ($v >= 0x080008 && $v < 0x080100));") */ -/* $LinkerFlags: -Lexec("pg_config --libdir") -lpq */ -/* $ModDep: m_sqlv2.h */ - - -/* SQLConn rewritten by peavey to - * use EventHandler instead of - * InspSocket. This is much neater - * and gives total control of destroy - * and delete of resources. - */ - -/* Forward declare, so we can have the typedef neatly at the top */ -class SQLConn; - -typedef std::map<std::string, SQLConn*> ConnMap; - -/* CREAD, Connecting and wants read event - * CWRITE, Connecting and wants write event - * WREAD, Connected/Working and wants read event - * WWRITE, Connected/Working and wants write event - * RREAD, Resetting and wants read event - * RWRITE, Resetting and wants write event - */ -enum SQLstatus { CREAD, CWRITE, WREAD, WWRITE, RREAD, RWRITE }; - -/** SQLhost::GetDSN() - Overload to return correct DSN for PostgreSQL - */ -std::string SQLhost::GetDSN() -{ - std::ostringstream conninfo("connect_timeout = '2'"); - - if (ip.length()) - conninfo << " hostaddr = '" << ip << "'"; - - if (port) - conninfo << " port = '" << port << "'"; - - if (name.length()) - conninfo << " dbname = '" << name << "'"; - - if (user.length()) - conninfo << " user = '" << user << "'"; - - if (pass.length()) - conninfo << " password = '" << pass << "'"; - - if (ssl) - { - conninfo << " sslmode = 'require'"; - } - else - { - conninfo << " sslmode = 'disable'"; - } - - return conninfo.str(); -} - -class ReconnectTimer : public InspTimer -{ - private: - Module* mod; - public: - ReconnectTimer(InspIRCd* SI, Module* m) - : InspTimer(5, SI->Time(), false), mod(m) - { - } - virtual void Tick(time_t TIME); -}; - - -/** Used to resolve sql server hostnames - */ -class SQLresolver : public Resolver -{ - private: - SQLhost host; - Module* mod; - public: - SQLresolver(Module* m, InspIRCd* Instance, const SQLhost& hi, bool &cached) - : Resolver(Instance, hi.host, DNS_QUERY_FORWARD, cached, (Module*)m), host(hi), mod(m) - { - } - - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); - - virtual void OnError(ResolverError e, const std::string &errormessage) - { - ServerInstance->Log(DEBUG, "PgSQL: DNS lookup failed (%s), dying horribly", errormessage.c_str()); - } -}; - -/** PgSQLresult is a subclass of the mostly-pure-virtual class SQLresult. - * All SQL providers must create their own subclass and define it's methods using that - * database library's data retriveal functions. The aim is to avoid a slow and inefficient process - * of converting all data to a common format before it reaches the result structure. This way - * data is passes to the module nearly as directly as if it was using the API directly itself. - */ - -class PgSQLresult : public SQLresult -{ - PGresult* res; - int currentrow; - int rows; - int cols; - - SQLfieldList* fieldlist; - SQLfieldMap* fieldmap; -public: - PgSQLresult(Module* self, Module* to, unsigned long id, PGresult* result) - : SQLresult(self, to, id), res(result), currentrow(0), fieldlist(NULL), fieldmap(NULL) - { - rows = PQntuples(res); - cols = PQnfields(res); - } - - ~PgSQLresult() - { - /* If we allocated these, free them... */ - if(fieldlist) - DELETE(fieldlist); - - if(fieldmap) - DELETE(fieldmap); - - PQclear(res); - } - - virtual int Rows() - { - if(!cols && !rows) - { - return atoi(PQcmdTuples(res)); - } - else - { - return rows; - } - } - - virtual int Cols() - { - return PQnfields(res); - } - - virtual std::string ColName(int column) - { - char* name = PQfname(res, column); - - return (name) ? name : ""; - } - - virtual int ColNum(const std::string &column) - { - int n = PQfnumber(res, column.c_str()); - - if(n == -1) - { - throw SQLbadColName(); - } - else - { - return n; - } - } - - virtual SQLfield GetValue(int row, int column) - { - char* v = PQgetvalue(res, row, column); - - if(v) - { - return SQLfield(std::string(v, PQgetlength(res, row, column)), PQgetisnull(res, row, column)); - } - else - { - throw SQLbadColName(); - } - } - - virtual SQLfieldList& GetRow() - { - /* In an effort to reduce overhead we don't actually allocate the list - * until the first time it's needed...so... - */ - if(fieldlist) - { - fieldlist->clear(); - } - else - { - fieldlist = new SQLfieldList; - } - - if(currentrow < PQntuples(res)) - { - int cols = PQnfields(res); - - for(int i = 0; i < cols; i++) - { - fieldlist->push_back(GetValue(currentrow, i)); - } - - currentrow++; - } - - return *fieldlist; - } - - virtual SQLfieldMap& GetRowMap() - { - /* In an effort to reduce overhead we don't actually allocate the map - * until the first time it's needed...so... - */ - if(fieldmap) - { - fieldmap->clear(); - } - else - { - fieldmap = new SQLfieldMap; - } - - if(currentrow < PQntuples(res)) - { - int cols = PQnfields(res); - - for(int i = 0; i < cols; i++) - { - fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i))); - } - - currentrow++; - } - - return *fieldmap; - } - - virtual SQLfieldList* GetRowPtr() - { - SQLfieldList* fl = new SQLfieldList; - - if(currentrow < PQntuples(res)) - { - int cols = PQnfields(res); - - for(int i = 0; i < cols; i++) - { - fl->push_back(GetValue(currentrow, i)); - } - - currentrow++; - } - - return fl; - } - - virtual SQLfieldMap* GetRowMapPtr() - { - SQLfieldMap* fm = new SQLfieldMap; - - if(currentrow < PQntuples(res)) - { - int cols = PQnfields(res); - - for(int i = 0; i < cols; i++) - { - fm->insert(std::make_pair(ColName(i), GetValue(currentrow, i))); - } - - currentrow++; - } - - return fm; - } - - virtual void Free(SQLfieldMap* fm) - { - DELETE(fm); - } - - virtual void Free(SQLfieldList* fl) - { - DELETE(fl); - } -}; - -/** SQLConn represents one SQL session. - */ -class SQLConn : public EventHandler -{ - private: - InspIRCd* Instance; - SQLhost confhost; /* The <database> entry */ - Module* us; /* Pointer to the SQL provider itself */ - PGconn* sql; /* PgSQL database connection handle */ - SQLstatus status; /* PgSQL database connection status */ - bool qinprog; /* If there is currently a query in progress */ - QueryQueue queue; /* Queue of queries waiting to be executed on this connection */ - time_t idle; /* Time we last heard from the database */ - - public: - SQLConn(InspIRCd* SI, Module* self, const SQLhost& hi) - : EventHandler(), Instance(SI), confhost(hi), us(self), sql(NULL), status(CWRITE), qinprog(false) - { - idle = this->Instance->Time(); - if(!DoConnect()) - { - Instance->Log(DEFAULT, "WARNING: Could not connect to database with id: " + ConvToStr(hi.id)); - DelayReconnect(); - } - } - - ~SQLConn() - { - Close(); - } - - virtual void HandleEvent(EventType et, int errornum) - { - switch (et) - { - case EVENT_READ: - OnDataReady(); - break; - - case EVENT_WRITE: - OnWriteReady(); - break; - - case EVENT_ERROR: - DelayReconnect(); - break; - - default: - break; - } - } - - bool DoConnect() - { - if(!(sql = PQconnectStart(confhost.GetDSN().c_str()))) - return false; - - if(PQstatus(sql) == CONNECTION_BAD) - return false; - - if(PQsetnonblocking(sql, 1) == -1) - return false; - - /* OK, we've initalised the connection, now to get it hooked into the socket engine - * and then start polling it. - */ - this->fd = PQsocket(sql); - - if(this->fd <= -1) - return false; - - if (!this->Instance->SE->AddFd(this)) - { - Instance->Log(DEBUG, "BUG: Couldn't add pgsql socket to socket engine"); - return false; - } - - /* Socket all hooked into the engine, now to tell PgSQL to start connecting */ - return DoPoll(); - } - - bool DoPoll() - { - switch(PQconnectPoll(sql)) - { - case PGRES_POLLING_WRITING: - Instance->SE->WantWrite(this); - status = CWRITE; - return true; - case PGRES_POLLING_READING: - status = CREAD; - return true; - case PGRES_POLLING_FAILED: - return false; - case PGRES_POLLING_OK: - status = WWRITE; - return DoConnectedPoll(); - default: - return true; - } - } - - bool DoConnectedPoll() - { - if(!qinprog && queue.totalsize()) - { - /* There's no query currently in progress, and there's queries in the queue. */ - SQLrequest& query = queue.front(); - DoQuery(query); - } - - if(PQconsumeInput(sql)) - { - /* We just read stuff from the server, that counts as it being alive - * so update the idle-since time :p - */ - idle = this->Instance->Time(); - - if (PQisBusy(sql)) - { - /* Nothing happens here */ - } - else if (qinprog) - { - /* Grab the request we're processing */ - SQLrequest& query = queue.front(); - - /* Get a pointer to the module we're about to return the result to */ - Module* to = query.GetSource(); - - /* Fetch the result.. */ - PGresult* result = PQgetResult(sql); - - /* PgSQL would allow a query string to be sent which has multiple - * queries in it, this isn't portable across database backends and - * we don't want modules doing it. But just in case we make sure we - * drain any results there are and just use the last one. - * If the module devs are behaving there will only be one result. - */ - while (PGresult* temp = PQgetResult(sql)) - { - PQclear(result); - result = temp; - } - - if(to) - { - /* ..and the result */ - PgSQLresult reply(us, to, query.id, result); - - /* Fix by brain, make sure the original query gets sent back in the reply */ - reply.query = query.query.q; - - switch(PQresultStatus(result)) - { - case PGRES_EMPTY_QUERY: - case PGRES_BAD_RESPONSE: - case PGRES_FATAL_ERROR: - reply.error.Id(QREPLY_FAIL); - reply.error.Str(PQresultErrorMessage(result)); - default:; - /* No action, other values are not errors */ - } - - reply.Send(); - - /* PgSQLresult's destructor will free the PGresult */ - } - else - { - /* If the client module is unloaded partway through a query then the provider will set - * the pointer to NULL. We cannot just cancel the query as the result will still come - * through at some point...and it could get messy if we play with invalid pointers... - */ - PQclear(result); - } - qinprog = false; - queue.pop(); - DoConnectedPoll(); - } - return true; - } - else - { - /* I think we'll assume this means the server died...it might not, - * but I think that any error serious enough we actually get here - * deserves to reconnect [/excuse] - * Returning true so the core doesn't try and close the connection. - */ - DelayReconnect(); - return true; - } - } - - bool DoResetPoll() - { - switch(PQresetPoll(sql)) - { - case PGRES_POLLING_WRITING: - Instance->SE->WantWrite(this); - status = CWRITE; - return DoPoll(); - case PGRES_POLLING_READING: - status = CREAD; - return true; - case PGRES_POLLING_FAILED: - return false; - case PGRES_POLLING_OK: - status = WWRITE; - return DoConnectedPoll(); - default: - return true; - } - } - - bool OnDataReady() - { - /* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */ - return DoEvent(); - } - - bool OnWriteReady() - { - /* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */ - return DoEvent(); - } - - bool OnConnected() - { - return DoEvent(); - } - - void DelayReconnect(); - - bool DoEvent() - { - bool ret; - - if((status == CREAD) || (status == CWRITE)) - { - ret = DoPoll(); - } - else if((status == RREAD) || (status == RWRITE)) - { - ret = DoResetPoll(); - } - else - { - ret = DoConnectedPoll(); - } - return ret; - } - - SQLerror DoQuery(SQLrequest &req) - { - if((status == WREAD) || (status == WWRITE)) - { - if(!qinprog) - { - /* Parse the command string and dispatch it */ - - /* Pointer to the buffer we screw around with substitution in */ - char* query; - /* Pointer to the current end of query, where we append new stuff */ - char* queryend; - /* Total length of the unescaped parameters */ - unsigned int paramlen; - - paramlen = 0; - - for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++) - { - paramlen += i->size(); - } - - /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be. - * sizeofquery + (totalparamlength*2) + 1 - * - * The +1 is for null-terminating the string for PQsendQuery() - */ - - query = new char[req.query.q.length() + (paramlen*2) + 1]; - queryend = query; - - /* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting - * the parameters into it... - */ - - for(unsigned int i = 0; i < req.query.q.length(); i++) - { - if(req.query.q[i] == '?') - { - /* We found a place to substitute..what fun. - * Use the PgSQL calls to escape and write the - * escaped string onto the end of our query buffer, - * then we "just" need to make sure queryend is - * pointing at the right place. - */ - - if(req.query.p.size()) - { - int error = 0; - size_t len = 0; - -#ifdef PGSQL_HAS_ESCAPECONN - len = PQescapeStringConn(sql, queryend, req.query.p.front().c_str(), req.query.p.front().length(), &error); -#else - len = PQescapeString (queryend, req.query.p.front().c_str(), req.query.p.front().length()); -#endif - if(error) - { - Instance->Log(DEBUG, "BUG: Apparently PQescapeStringConn() failed somehow...don't know how or what to do..."); - } - - /* Incremenet queryend to the end of the newly escaped parameter */ - queryend += len; - - /* Remove the parameter we just substituted in */ - req.query.p.pop_front(); - } - else - { - Instance->Log(DEBUG, "BUG: Found a substitution location but no parameter to substitute :|"); - break; - } - } - else - { - *queryend = req.query.q[i]; - queryend++; - } - } - - /* Null-terminate the query */ - *queryend = 0; - req.query.q = query; - - if(PQsendQuery(sql, query)) - { - qinprog = true; - delete[] query; - return SQLerror(); - } - else - { - delete[] query; - return SQLerror(QSEND_FAIL, PQerrorMessage(sql)); - } - } - } - return SQLerror(BAD_CONN, "Can't query until connection is complete"); - } - - SQLerror Query(const SQLrequest &req) - { - queue.push(req); - - if(!qinprog && queue.totalsize()) - { - /* There's no query currently in progress, and there's queries in the queue. */ - SQLrequest& query = queue.front(); - return DoQuery(query); - } - else - { - return SQLerror(); - } - } - - void OnUnloadModule(Module* mod) - { - queue.PurgeModule(mod); - } - - const SQLhost GetConfHost() - { - return confhost; - } - - void Close() { - if (!this->Instance->SE->DelFd(this)) - { - if (sql && PQstatus(sql) == CONNECTION_BAD) - { - this->Instance->SE->DelFd(this, true); - } - else - { - Instance->Log(DEBUG, "BUG: PQsocket cant be removed from socket engine!"); - } - } - - if(sql) - { - PQfinish(sql); - sql = NULL; - } - } - -}; - -class ModulePgSQL : public Module -{ - private: - ConnMap connections; - unsigned long currid; - char* sqlsuccess; - ReconnectTimer* retimer; - - public: - ModulePgSQL(InspIRCd* Me) - : Module::Module(Me), currid(0) - { - ServerInstance->UseInterface("SQLutils"); - - sqlsuccess = new char[strlen(SQLSUCCESS)+1]; - - strlcpy(sqlsuccess, SQLSUCCESS, strlen(SQLSUCCESS)); - - if (!ServerInstance->PublishFeature("SQL", this)) - { - throw ModuleException("BUG: PgSQL Unable to publish feature 'SQL'"); - } - - ReadConf(); - - ServerInstance->PublishInterface("SQL", this); - } - - virtual ~ModulePgSQL() - { - if (retimer) - ServerInstance->Timers->DelTimer(retimer); - ClearAllConnections(); - delete[] sqlsuccess; - ServerInstance->UnpublishInterface("SQL", this); - ServerInstance->UnpublishFeature("SQL"); - ServerInstance->DoneWithInterface("SQLutils"); - } - - void Implements(char* List) - { - List[I_OnUnloadModule] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ReadConf(); - } - - bool HasHost(const SQLhost &host) - { - for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++) - { - if (host == iter->second->GetConfHost()) - return true; - } - return false; - } - - bool HostInConf(const SQLhost &h) - { - ConfigReader conf(ServerInstance); - for(int i = 0; i < conf.Enumerate("database"); i++) - { - SQLhost host; - host.id = conf.ReadValue("database", "id", i); - host.host = conf.ReadValue("database", "hostname", i); - host.port = conf.ReadInteger("database", "port", i, true); - host.name = conf.ReadValue("database", "name", i); - host.user = conf.ReadValue("database", "username", i); - host.pass = conf.ReadValue("database", "password", i); - host.ssl = conf.ReadFlag("database", "ssl", "0", i); - if (h == host) - return true; - } - return false; - } - - void ReadConf() - { - ClearOldConnections(); - - ConfigReader conf(ServerInstance); - for(int i = 0; i < conf.Enumerate("database"); i++) - { - SQLhost host; - int ipvalid; - - host.id = conf.ReadValue("database", "id", i); - host.host = conf.ReadValue("database", "hostname", i); - host.port = conf.ReadInteger("database", "port", i, true); - host.name = conf.ReadValue("database", "name", i); - host.user = conf.ReadValue("database", "username", i); - host.pass = conf.ReadValue("database", "password", i); - host.ssl = conf.ReadFlag("database", "ssl", "0", i); - - if (HasHost(host)) - continue; - -#ifdef IPV6 - if (strchr(host.host.c_str(),':')) - { - in6_addr blargle; - ipvalid = inet_pton(AF_INET6, host.host.c_str(), &blargle); - } - else -#endif - { - in_addr blargle; - ipvalid = inet_aton(host.host.c_str(), &blargle); - } - - if(ipvalid > 0) - { - /* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */ - host.ip = host.host; - this->AddConn(host); - } - else if(ipvalid == 0) - { - /* Conversion failed, assume it's a host */ - SQLresolver* resolver; - - try - { - bool cached; - resolver = new SQLresolver(this, ServerInstance, host, cached); - ServerInstance->AddResolver(resolver, cached); - } - catch(...) - { - /* THE WORLD IS COMING TO AN END! */ - } - } - else - { - /* Invalid address family, die horribly. */ - ServerInstance->Log(DEBUG, "BUG: insp_aton failed returning -1, oh noes."); - } - } - } - - void ClearOldConnections() - { - ConnMap::iterator iter,safei; - for (iter = connections.begin(); iter != connections.end(); iter++) - { - if (!HostInConf(iter->second->GetConfHost())) - { - DELETE(iter->second); - safei = iter; - --iter; - connections.erase(safei); - } - } - } - - void ClearAllConnections() - { - ConnMap::iterator i; - while ((i = connections.begin()) != connections.end()) - { - connections.erase(i); - DELETE(i->second); - } - } - - void AddConn(const SQLhost& hi) - { - if (HasHost(hi)) - { - ServerInstance->Log(DEFAULT, "WARNING: A pgsql connection with id: %s already exists, possibly due to DNS delay. Aborting connection attempt.", hi.id.c_str()); - return; - } - - SQLConn* newconn; - - /* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */ - newconn = new SQLConn(ServerInstance, this, hi); - - connections.insert(std::make_pair(hi.id, newconn)); - } - - void ReconnectConn(SQLConn* conn) - { - for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++) - { - if (conn == iter->second) - { - DELETE(iter->second); - connections.erase(iter); - break; - } - } - retimer = new ReconnectTimer(ServerInstance, this); - ServerInstance->Timers->AddTimer(retimer); - } - - virtual char* OnRequest(Request* request) - { - if(strcmp(SQLREQID, request->GetId()) == 0) - { - SQLrequest* req = (SQLrequest*)request; - ConnMap::iterator iter; - if((iter = connections.find(req->dbid)) != connections.end()) - { - /* Execute query */ - req->id = NewID(); - req->error = iter->second->Query(*req); - - return (req->error.Id() == NO_ERROR) ? sqlsuccess : NULL; - } - else - { - req->error.Id(BAD_DBID); - return NULL; - } - } - return NULL; - } - - virtual void OnUnloadModule(Module* mod, const std::string& name) - { - /* When a module unloads we have to check all the pending queries for all our connections - * and set the Module* specifying where the query came from to NULL. If the query has already - * been dispatched then when it is processed it will be dropped if the pointer is NULL. - * - * If the queries we find are not already being executed then we can simply remove them immediately. - */ - for(ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++) - { - iter->second->OnUnloadModule(mod); - } - } - - unsigned long NewID() - { - if (currid+1 == 0) - currid++; - - return ++currid; - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION); - } -}; - -/* move this here to use AddConn, rather that than having the whole - * module above SQLConn, since this is buggin me right now :/ - */ -void SQLresolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) -{ - host.ip = result; - ((ModulePgSQL*)mod)->AddConn(host); - ((ModulePgSQL*)mod)->ClearOldConnections(); -} - -void ReconnectTimer::Tick(time_t time) -{ - ((ModulePgSQL*)mod)->ReadConf(); -} - -void SQLConn::DelayReconnect() -{ - ((ModulePgSQL*)us)->ReconnectConn(this); -} - -MODULE_INIT(ModulePgSQL); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <cstdlib>
#include <sstream>
#include <libpq-fe.h>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
#include "m_sqlv2.h"
/* $ModDesc: PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API */
/* $CompileFlags: -Iexec("pg_config --includedir") eval("my $s = `pg_config --version`;$s =~ /^.*?(\d+)\.(\d+)\.(\d+).*?$/;my $v = hex(sprintf("0x%02x%02x%02x", $1, $2, $3));print "-DPGSQL_HAS_ESCAPECONN" if(($v >= 0x080104) || ($v >= 0x07030F && $v < 0x070400) || ($v >= 0x07040D && $v < 0x080000) || ($v >= 0x080008 && $v < 0x080100));") */
/* $LinkerFlags: -Lexec("pg_config --libdir") -lpq */
/* $ModDep: m_sqlv2.h */
/* SQLConn rewritten by peavey to
* use EventHandler instead of
* InspSocket. This is much neater
* and gives total control of destroy
* and delete of resources.
*/
/* Forward declare, so we can have the typedef neatly at the top */
class SQLConn;
typedef std::map<std::string, SQLConn*> ConnMap;
/* CREAD, Connecting and wants read event
* CWRITE, Connecting and wants write event
* WREAD, Connected/Working and wants read event
* WWRITE, Connected/Working and wants write event
* RREAD, Resetting and wants read event
* RWRITE, Resetting and wants write event
*/
enum SQLstatus { CREAD, CWRITE, WREAD, WWRITE, RREAD, RWRITE };
/** SQLhost::GetDSN() - Overload to return correct DSN for PostgreSQL
*/
std::string SQLhost::GetDSN()
{
std::ostringstream conninfo("connect_timeout = '2'");
if (ip.length())
conninfo << " hostaddr = '" << ip << "'";
if (port)
conninfo << " port = '" << port << "'";
if (name.length())
conninfo << " dbname = '" << name << "'";
if (user.length())
conninfo << " user = '" << user << "'";
if (pass.length())
conninfo << " password = '" << pass << "'";
if (ssl)
{
conninfo << " sslmode = 'require'";
}
else
{
conninfo << " sslmode = 'disable'";
}
return conninfo.str();
}
class ReconnectTimer : public InspTimer
{
private:
Module* mod;
public:
ReconnectTimer(InspIRCd* SI, Module* m)
: InspTimer(5, SI->Time(), false), mod(m)
{
}
virtual void Tick(time_t TIME);
};
/** Used to resolve sql server hostnames
*/
class SQLresolver : public Resolver
{
private:
SQLhost host;
Module* mod;
public:
SQLresolver(Module* m, InspIRCd* Instance, const SQLhost& hi, bool &cached)
: Resolver(Instance, hi.host, DNS_QUERY_FORWARD, cached, (Module*)m), host(hi), mod(m)
{
}
virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);
virtual void OnError(ResolverError e, const std::string &errormessage)
{
ServerInstance->Log(DEBUG, "PgSQL: DNS lookup failed (%s), dying horribly", errormessage.c_str());
}
};
/** PgSQLresult is a subclass of the mostly-pure-virtual class SQLresult.
* All SQL providers must create their own subclass and define it's methods using that
* database library's data retriveal functions. The aim is to avoid a slow and inefficient process
* of converting all data to a common format before it reaches the result structure. This way
* data is passes to the module nearly as directly as if it was using the API directly itself.
*/
class PgSQLresult : public SQLresult
{
PGresult* res;
int currentrow;
int rows;
int cols;
SQLfieldList* fieldlist;
SQLfieldMap* fieldmap;
public:
PgSQLresult(Module* self, Module* to, unsigned long id, PGresult* result)
: SQLresult(self, to, id), res(result), currentrow(0), fieldlist(NULL), fieldmap(NULL)
{
rows = PQntuples(res);
cols = PQnfields(res);
}
~PgSQLresult()
{
/* If we allocated these, free them... */
if(fieldlist)
DELETE(fieldlist);
if(fieldmap)
DELETE(fieldmap);
PQclear(res);
}
virtual int Rows()
{
if(!cols && !rows)
{
return atoi(PQcmdTuples(res));
}
else
{
return rows;
}
}
virtual int Cols()
{
return PQnfields(res);
}
virtual std::string ColName(int column)
{
char* name = PQfname(res, column);
return (name) ? name : "";
}
virtual int ColNum(const std::string &column)
{
int n = PQfnumber(res, column.c_str());
if(n == -1)
{
throw SQLbadColName();
}
else
{
return n;
}
}
virtual SQLfield GetValue(int row, int column)
{
char* v = PQgetvalue(res, row, column);
if(v)
{
return SQLfield(std::string(v, PQgetlength(res, row, column)), PQgetisnull(res, row, column));
}
else
{
throw SQLbadColName();
}
}
virtual SQLfieldList& GetRow()
{
/* In an effort to reduce overhead we don't actually allocate the list
* until the first time it's needed...so...
*/
if(fieldlist)
{
fieldlist->clear();
}
else
{
fieldlist = new SQLfieldList;
}
if(currentrow < PQntuples(res))
{
int cols = PQnfields(res);
for(int i = 0; i < cols; i++)
{
fieldlist->push_back(GetValue(currentrow, i));
}
currentrow++;
}
return *fieldlist;
}
virtual SQLfieldMap& GetRowMap()
{
/* In an effort to reduce overhead we don't actually allocate the map
* until the first time it's needed...so...
*/
if(fieldmap)
{
fieldmap->clear();
}
else
{
fieldmap = new SQLfieldMap;
}
if(currentrow < PQntuples(res))
{
int cols = PQnfields(res);
for(int i = 0; i < cols; i++)
{
fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));
}
currentrow++;
}
return *fieldmap;
}
virtual SQLfieldList* GetRowPtr()
{
SQLfieldList* fl = new SQLfieldList;
if(currentrow < PQntuples(res))
{
int cols = PQnfields(res);
for(int i = 0; i < cols; i++)
{
fl->push_back(GetValue(currentrow, i));
}
currentrow++;
}
return fl;
}
virtual SQLfieldMap* GetRowMapPtr()
{
SQLfieldMap* fm = new SQLfieldMap;
if(currentrow < PQntuples(res))
{
int cols = PQnfields(res);
for(int i = 0; i < cols; i++)
{
fm->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));
}
currentrow++;
}
return fm;
}
virtual void Free(SQLfieldMap* fm)
{
DELETE(fm);
}
virtual void Free(SQLfieldList* fl)
{
DELETE(fl);
}
};
/** SQLConn represents one SQL session.
*/
class SQLConn : public EventHandler
{
private:
InspIRCd* Instance;
SQLhost confhost; /* The <database> entry */
Module* us; /* Pointer to the SQL provider itself */
PGconn* sql; /* PgSQL database connection handle */
SQLstatus status; /* PgSQL database connection status */
bool qinprog; /* If there is currently a query in progress */
QueryQueue queue; /* Queue of queries waiting to be executed on this connection */
time_t idle; /* Time we last heard from the database */
public:
SQLConn(InspIRCd* SI, Module* self, const SQLhost& hi)
: EventHandler(), Instance(SI), confhost(hi), us(self), sql(NULL), status(CWRITE), qinprog(false)
{
idle = this->Instance->Time();
if(!DoConnect())
{
Instance->Log(DEFAULT, "WARNING: Could not connect to database with id: " + ConvToStr(hi.id));
DelayReconnect();
}
}
~SQLConn()
{
Close();
}
virtual void HandleEvent(EventType et, int errornum)
{
switch (et)
{
case EVENT_READ:
OnDataReady();
break;
case EVENT_WRITE:
OnWriteReady();
break;
case EVENT_ERROR:
DelayReconnect();
break;
default:
break;
}
}
bool DoConnect()
{
if(!(sql = PQconnectStart(confhost.GetDSN().c_str())))
return false;
if(PQstatus(sql) == CONNECTION_BAD)
return false;
if(PQsetnonblocking(sql, 1) == -1)
return false;
/* OK, we've initalised the connection, now to get it hooked into the socket engine
* and then start polling it.
*/
this->fd = PQsocket(sql);
if(this->fd <= -1)
return false;
if (!this->Instance->SE->AddFd(this))
{
Instance->Log(DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
return false;
}
/* Socket all hooked into the engine, now to tell PgSQL to start connecting */
return DoPoll();
}
bool DoPoll()
{
switch(PQconnectPoll(sql))
{
case PGRES_POLLING_WRITING:
Instance->SE->WantWrite(this);
status = CWRITE;
return true;
case PGRES_POLLING_READING:
status = CREAD;
return true;
case PGRES_POLLING_FAILED:
return false;
case PGRES_POLLING_OK:
status = WWRITE;
return DoConnectedPoll();
default:
return true;
}
}
bool DoConnectedPoll()
{
if(!qinprog && queue.totalsize())
{
/* There's no query currently in progress, and there's queries in the queue. */
SQLrequest& query = queue.front();
DoQuery(query);
}
if(PQconsumeInput(sql))
{
/* We just read stuff from the server, that counts as it being alive
* so update the idle-since time :p
*/
idle = this->Instance->Time();
if (PQisBusy(sql))
{
/* Nothing happens here */
}
else if (qinprog)
{
/* Grab the request we're processing */
SQLrequest& query = queue.front();
/* Get a pointer to the module we're about to return the result to */
Module* to = query.GetSource();
/* Fetch the result.. */
PGresult* result = PQgetResult(sql);
/* PgSQL would allow a query string to be sent which has multiple
* queries in it, this isn't portable across database backends and
* we don't want modules doing it. But just in case we make sure we
* drain any results there are and just use the last one.
* If the module devs are behaving there will only be one result.
*/
while (PGresult* temp = PQgetResult(sql))
{
PQclear(result);
result = temp;
}
if(to)
{
/* ..and the result */
PgSQLresult reply(us, to, query.id, result);
/* Fix by brain, make sure the original query gets sent back in the reply */
reply.query = query.query.q;
switch(PQresultStatus(result))
{
case PGRES_EMPTY_QUERY:
case PGRES_BAD_RESPONSE:
case PGRES_FATAL_ERROR:
reply.error.Id(QREPLY_FAIL);
reply.error.Str(PQresultErrorMessage(result));
default:;
/* No action, other values are not errors */
}
reply.Send();
/* PgSQLresult's destructor will free the PGresult */
}
else
{
/* If the client module is unloaded partway through a query then the provider will set
* the pointer to NULL. We cannot just cancel the query as the result will still come
* through at some point...and it could get messy if we play with invalid pointers...
*/
PQclear(result);
}
qinprog = false;
queue.pop();
DoConnectedPoll();
}
return true;
}
else
{
/* I think we'll assume this means the server died...it might not,
* but I think that any error serious enough we actually get here
* deserves to reconnect [/excuse]
* Returning true so the core doesn't try and close the connection.
*/
DelayReconnect();
return true;
}
}
bool DoResetPoll()
{
switch(PQresetPoll(sql))
{
case PGRES_POLLING_WRITING:
Instance->SE->WantWrite(this);
status = CWRITE;
return DoPoll();
case PGRES_POLLING_READING:
status = CREAD;
return true;
case PGRES_POLLING_FAILED:
return false;
case PGRES_POLLING_OK:
status = WWRITE;
return DoConnectedPoll();
default:
return true;
}
}
bool OnDataReady()
{
/* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */
return DoEvent();
}
bool OnWriteReady()
{
/* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */
return DoEvent();
}
bool OnConnected()
{
return DoEvent();
}
void DelayReconnect();
bool DoEvent()
{
bool ret;
if((status == CREAD) || (status == CWRITE))
{
ret = DoPoll();
}
else if((status == RREAD) || (status == RWRITE))
{
ret = DoResetPoll();
}
else
{
ret = DoConnectedPoll();
}
return ret;
}
SQLerror DoQuery(SQLrequest &req)
{
if((status == WREAD) || (status == WWRITE))
{
if(!qinprog)
{
/* Parse the command string and dispatch it */
/* Pointer to the buffer we screw around with substitution in */
char* query;
/* Pointer to the current end of query, where we append new stuff */
char* queryend;
/* Total length of the unescaped parameters */
unsigned int paramlen;
paramlen = 0;
for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)
{
paramlen += i->size();
}
/* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.
* sizeofquery + (totalparamlength*2) + 1
*
* The +1 is for null-terminating the string for PQsendQuery()
*/
query = new char[req.query.q.length() + (paramlen*2) + 1];
queryend = query;
/* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting
* the parameters into it...
*/
for(unsigned int i = 0; i < req.query.q.length(); i++)
{
if(req.query.q[i] == '?')
{
/* We found a place to substitute..what fun.
* Use the PgSQL calls to escape and write the
* escaped string onto the end of our query buffer,
* then we "just" need to make sure queryend is
* pointing at the right place.
*/
if(req.query.p.size())
{
int error = 0;
size_t len = 0;
#ifdef PGSQL_HAS_ESCAPECONN
len = PQescapeStringConn(sql, queryend, req.query.p.front().c_str(), req.query.p.front().length(), &error);
#else
len = PQescapeString (queryend, req.query.p.front().c_str(), req.query.p.front().length());
#endif
if(error)
{
Instance->Log(DEBUG, "BUG: Apparently PQescapeStringConn() failed somehow...don't know how or what to do...");
}
/* Incremenet queryend to the end of the newly escaped parameter */
queryend += len;
/* Remove the parameter we just substituted in */
req.query.p.pop_front();
}
else
{
Instance->Log(DEBUG, "BUG: Found a substitution location but no parameter to substitute :|");
break;
}
}
else
{
*queryend = req.query.q[i];
queryend++;
}
}
/* Null-terminate the query */
*queryend = 0;
req.query.q = query;
if(PQsendQuery(sql, query))
{
qinprog = true;
delete[] query;
return SQLerror();
}
else
{
delete[] query;
return SQLerror(QSEND_FAIL, PQerrorMessage(sql));
}
}
}
return SQLerror(BAD_CONN, "Can't query until connection is complete");
}
SQLerror Query(const SQLrequest &req)
{
queue.push(req);
if(!qinprog && queue.totalsize())
{
/* There's no query currently in progress, and there's queries in the queue. */
SQLrequest& query = queue.front();
return DoQuery(query);
}
else
{
return SQLerror();
}
}
void OnUnloadModule(Module* mod)
{
queue.PurgeModule(mod);
}
const SQLhost GetConfHost()
{
return confhost;
}
void Close() {
if (!this->Instance->SE->DelFd(this))
{
if (sql && PQstatus(sql) == CONNECTION_BAD)
{
this->Instance->SE->DelFd(this, true);
}
else
{
Instance->Log(DEBUG, "BUG: PQsocket cant be removed from socket engine!");
}
}
if(sql)
{
PQfinish(sql);
sql = NULL;
}
}
};
class ModulePgSQL : public Module
{
private:
ConnMap connections;
unsigned long currid;
char* sqlsuccess;
ReconnectTimer* retimer;
public:
ModulePgSQL(InspIRCd* Me)
: Module::Module(Me), currid(0)
{
ServerInstance->UseInterface("SQLutils");
sqlsuccess = new char[strlen(SQLSUCCESS)+1];
strlcpy(sqlsuccess, SQLSUCCESS, strlen(SQLSUCCESS));
if (!ServerInstance->PublishFeature("SQL", this))
{
throw ModuleException("BUG: PgSQL Unable to publish feature 'SQL'");
}
ReadConf();
ServerInstance->PublishInterface("SQL", this);
}
virtual ~ModulePgSQL()
{
if (retimer)
ServerInstance->Timers->DelTimer(retimer);
ClearAllConnections();
delete[] sqlsuccess;
ServerInstance->UnpublishInterface("SQL", this);
ServerInstance->UnpublishFeature("SQL");
ServerInstance->DoneWithInterface("SQLutils");
}
void Implements(char* List)
{
List[I_OnUnloadModule] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadConf();
}
bool HasHost(const SQLhost &host)
{
for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
{
if (host == iter->second->GetConfHost())
return true;
}
return false;
}
bool HostInConf(const SQLhost &h)
{
ConfigReader conf(ServerInstance);
for(int i = 0; i < conf.Enumerate("database"); i++)
{
SQLhost host;
host.id = conf.ReadValue("database", "id", i);
host.host = conf.ReadValue("database", "hostname", i);
host.port = conf.ReadInteger("database", "port", i, true);
host.name = conf.ReadValue("database", "name", i);
host.user = conf.ReadValue("database", "username", i);
host.pass = conf.ReadValue("database", "password", i);
host.ssl = conf.ReadFlag("database", "ssl", "0", i);
if (h == host)
return true;
}
return false;
}
void ReadConf()
{
ClearOldConnections();
ConfigReader conf(ServerInstance);
for(int i = 0; i < conf.Enumerate("database"); i++)
{
SQLhost host;
int ipvalid;
host.id = conf.ReadValue("database", "id", i);
host.host = conf.ReadValue("database", "hostname", i);
host.port = conf.ReadInteger("database", "port", i, true);
host.name = conf.ReadValue("database", "name", i);
host.user = conf.ReadValue("database", "username", i);
host.pass = conf.ReadValue("database", "password", i);
host.ssl = conf.ReadFlag("database", "ssl", "0", i);
if (HasHost(host))
continue;
#ifdef IPV6
if (strchr(host.host.c_str(),':'))
{
in6_addr blargle;
ipvalid = inet_pton(AF_INET6, host.host.c_str(), &blargle);
}
else
#endif
{
in_addr blargle;
ipvalid = inet_aton(host.host.c_str(), &blargle);
}
if(ipvalid > 0)
{
/* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */
host.ip = host.host;
this->AddConn(host);
}
else if(ipvalid == 0)
{
/* Conversion failed, assume it's a host */
SQLresolver* resolver;
try
{
bool cached;
resolver = new SQLresolver(this, ServerInstance, host, cached);
ServerInstance->AddResolver(resolver, cached);
}
catch(...)
{
/* THE WORLD IS COMING TO AN END! */
}
}
else
{
/* Invalid address family, die horribly. */
ServerInstance->Log(DEBUG, "BUG: insp_aton failed returning -1, oh noes.");
}
}
}
void ClearOldConnections()
{
ConnMap::iterator iter,safei;
for (iter = connections.begin(); iter != connections.end(); iter++)
{
if (!HostInConf(iter->second->GetConfHost()))
{
DELETE(iter->second);
safei = iter;
--iter;
connections.erase(safei);
}
}
}
void ClearAllConnections()
{
ConnMap::iterator i;
while ((i = connections.begin()) != connections.end())
{
connections.erase(i);
DELETE(i->second);
}
}
void AddConn(const SQLhost& hi)
{
if (HasHost(hi))
{
ServerInstance->Log(DEFAULT, "WARNING: A pgsql connection with id: %s already exists, possibly due to DNS delay. Aborting connection attempt.", hi.id.c_str());
return;
}
SQLConn* newconn;
/* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */
newconn = new SQLConn(ServerInstance, this, hi);
connections.insert(std::make_pair(hi.id, newconn));
}
void ReconnectConn(SQLConn* conn)
{
for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
{
if (conn == iter->second)
{
DELETE(iter->second);
connections.erase(iter);
break;
}
}
retimer = new ReconnectTimer(ServerInstance, this);
ServerInstance->Timers->AddTimer(retimer);
}
virtual char* OnRequest(Request* request)
{
if(strcmp(SQLREQID, request->GetId()) == 0)
{
SQLrequest* req = (SQLrequest*)request;
ConnMap::iterator iter;
if((iter = connections.find(req->dbid)) != connections.end())
{
/* Execute query */
req->id = NewID();
req->error = iter->second->Query(*req);
return (req->error.Id() == NO_ERROR) ? sqlsuccess : NULL;
}
else
{
req->error.Id(BAD_DBID);
return NULL;
}
}
return NULL;
}
virtual void OnUnloadModule(Module* mod, const std::string& name)
{
/* When a module unloads we have to check all the pending queries for all our connections
* and set the Module* specifying where the query came from to NULL. If the query has already
* been dispatched then when it is processed it will be dropped if the pointer is NULL.
*
* If the queries we find are not already being executed then we can simply remove them immediately.
*/
for(ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
{
iter->second->OnUnloadModule(mod);
}
}
unsigned long NewID()
{
if (currid+1 == 0)
currid++;
return ++currid;
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
}
};
/* move this here to use AddConn, rather that than having the whole
* module above SQLConn, since this is buggin me right now :/
*/
void SQLresolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
{
host.ip = result;
((ModulePgSQL*)mod)->AddConn(host);
((ModulePgSQL*)mod)->ClearOldConnections();
}
void ReconnectTimer::Tick(time_t time)
{
((ModulePgSQL*)mod)->ReadConf();
}
void SQLConn::DelayReconnect()
{
((ModulePgSQL*)us)->ReconnectConn(this);
}
MODULE_INIT(ModulePgSQL);
\ No newline at end of file diff --git a/src/modules/extra/m_sqlauth.cpp b/src/modules/extra/m_sqlauth.cpp index 6b05ee521..862929919 100644 --- a/src/modules/extra/m_sqlauth.cpp +++ b/src/modules/extra/m_sqlauth.cpp @@ -1,194 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_sqlv2.h" -#include "m_sqlutils.h" - -/* $ModDesc: Allow/Deny connections based upon an arbitary SQL table */ -/* $ModDep: m_sqlv2.h m_sqlutils.h */ - -class ModuleSQLAuth : public Module -{ - Module* SQLutils; - Module* SQLprovider; - - std::string usertable; - std::string userfield; - std::string passfield; - std::string encryption; - std::string killreason; - std::string allowpattern; - std::string databaseid; - - bool verbose; - -public: - ModuleSQLAuth(InspIRCd* Me) - : Module::Module(Me) - { - ServerInstance->UseInterface("SQLutils"); - ServerInstance->UseInterface("SQL"); - - SQLutils = ServerInstance->FindModule("m_sqlutils.so"); - if (!SQLutils) - throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so."); - - SQLprovider = ServerInstance->FindFeature("SQL"); - if (!SQLprovider) - throw ModuleException("Can't find an SQL provider module. Please load one before attempting to load m_sqlauth."); - - OnRehash(NULL,""); - } - - virtual ~ModuleSQLAuth() - { - ServerInstance->DoneWithInterface("SQL"); - ServerInstance->DoneWithInterface("SQLutils"); - } - - void Implements(char* List) - { - List[I_OnUserDisconnect] = List[I_OnCheckReady] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - - usertable = Conf.ReadValue("sqlauth", "usertable", 0); /* User table name */ - databaseid = Conf.ReadValue("sqlauth", "dbid", 0); /* Database ID, given to the SQL service provider */ - userfield = Conf.ReadValue("sqlauth", "userfield", 0); /* Field name where username can be found */ - passfield = Conf.ReadValue("sqlauth", "passfield", 0); /* Field name where password can be found */ - killreason = Conf.ReadValue("sqlauth", "killreason", 0); /* Reason to give when access is denied to a user (put your reg details here) */ - allowpattern= Conf.ReadValue("sqlauth", "allowpattern",0 ); /* Allow nicks matching this pattern without requiring auth */ - encryption = Conf.ReadValue("sqlauth", "encryption", 0); /* Name of sql function used to encrypt password, e.g. "md5" or "passwd". - * define, but leave blank if no encryption is to be used. - */ - verbose = Conf.ReadFlag("sqlauth", "verbose", 0); /* Set to true if failed connects should be reported to operators */ - - if (encryption.find("(") == std::string::npos) - { - encryption.append("("); - } - } - - virtual int OnUserRegister(userrec* user) - { - if ((!allowpattern.empty()) && (ServerInstance->MatchText(user->nick,allowpattern))) - { - user->Extend("sqlauthed"); - return 0; - } - - if (!CheckCredentials(user)) - { - userrec::QuitUser(ServerInstance,user,killreason); - return 1; - } - return 0; - } - - bool CheckCredentials(userrec* user) - { - SQLrequest req = SQLreq(this, SQLprovider, databaseid, "SELECT ? FROM ? WHERE ? = '?' AND ? = ?'?')", userfield, usertable, userfield, user->nick, passfield, encryption, user->password); - - if(req.Send()) - { - /* When we get the query response from the service provider we will be given an ID to play with, - * just an ID number which is unique to this query. We need a way of associating that ID with a userrec - * so we insert it into a map mapping the IDs to users. - * Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the - * association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling - * us to discard the query. - */ - AssociateUser(this, SQLutils, req.id, user).Send(); - - return true; - } - else - { - if (verbose) - ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, req.error.Str()); - return false; - } - } - - virtual char* OnRequest(Request* request) - { - if(strcmp(SQLRESID, request->GetId()) == 0) - { - SQLresult* res = static_cast<SQLresult*>(request); - - userrec* user = GetAssocUser(this, SQLutils, res->id).S().user; - UnAssociate(this, SQLutils, res->id).S(); - - if(user) - { - if(res->error.Id() == NO_ERROR) - { - if(res->Rows()) - { - /* We got a row in the result, this is enough really */ - user->Extend("sqlauthed"); - } - else if (verbose) - { - /* No rows in result, this means there was no record matching the user */ - ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query returned no matches)", user->nick, user->ident, user->host); - user->Extend("sqlauth_failed"); - } - } - else if (verbose) - { - ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, res->error.Str()); - user->Extend("sqlauth_failed"); - } - } - else - { - return NULL; - } - - if (!user->GetExt("sqlauthed")) - { - userrec::QuitUser(ServerInstance,user,killreason); - } - return SQLSUCCESS; - } - return NULL; - } - - virtual void OnUserDisconnect(userrec* user) - { - user->Shrink("sqlauthed"); - user->Shrink("sqlauth_failed"); - } - - virtual bool OnCheckReady(userrec* user) - { - return user->GetExt("sqlauthed"); - } - - virtual Version GetVersion() - { - return Version(1,1,1,0,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSQLAuth); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_sqlv2.h"
#include "m_sqlutils.h"
/* $ModDesc: Allow/Deny connections based upon an arbitary SQL table */
/* $ModDep: m_sqlv2.h m_sqlutils.h */
class ModuleSQLAuth : public Module
{
Module* SQLutils;
Module* SQLprovider;
std::string usertable;
std::string userfield;
std::string passfield;
std::string encryption;
std::string killreason;
std::string allowpattern;
std::string databaseid;
bool verbose;
public:
ModuleSQLAuth(InspIRCd* Me)
: Module::Module(Me)
{
ServerInstance->UseInterface("SQLutils");
ServerInstance->UseInterface("SQL");
SQLutils = ServerInstance->FindModule("m_sqlutils.so");
if (!SQLutils)
throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");
SQLprovider = ServerInstance->FindFeature("SQL");
if (!SQLprovider)
throw ModuleException("Can't find an SQL provider module. Please load one before attempting to load m_sqlauth.");
OnRehash(NULL,"");
}
virtual ~ModuleSQLAuth()
{
ServerInstance->DoneWithInterface("SQL");
ServerInstance->DoneWithInterface("SQLutils");
}
void Implements(char* List)
{
List[I_OnUserDisconnect] = List[I_OnCheckReady] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
usertable = Conf.ReadValue("sqlauth", "usertable", 0); /* User table name */
databaseid = Conf.ReadValue("sqlauth", "dbid", 0); /* Database ID, given to the SQL service provider */
userfield = Conf.ReadValue("sqlauth", "userfield", 0); /* Field name where username can be found */
passfield = Conf.ReadValue("sqlauth", "passfield", 0); /* Field name where password can be found */
killreason = Conf.ReadValue("sqlauth", "killreason", 0); /* Reason to give when access is denied to a user (put your reg details here) */
allowpattern= Conf.ReadValue("sqlauth", "allowpattern",0 ); /* Allow nicks matching this pattern without requiring auth */
encryption = Conf.ReadValue("sqlauth", "encryption", 0); /* Name of sql function used to encrypt password, e.g. "md5" or "passwd".
* define, but leave blank if no encryption is to be used.
*/
verbose = Conf.ReadFlag("sqlauth", "verbose", 0); /* Set to true if failed connects should be reported to operators */
if (encryption.find("(") == std::string::npos)
{
encryption.append("(");
}
}
virtual int OnUserRegister(userrec* user)
{
if ((!allowpattern.empty()) && (ServerInstance->MatchText(user->nick,allowpattern)))
{
user->Extend("sqlauthed");
return 0;
}
if (!CheckCredentials(user))
{
userrec::QuitUser(ServerInstance,user,killreason);
return 1;
}
return 0;
}
bool CheckCredentials(userrec* user)
{
SQLrequest req = SQLreq(this, SQLprovider, databaseid, "SELECT ? FROM ? WHERE ? = '?' AND ? = ?'?')", userfield, usertable, userfield, user->nick, passfield, encryption, user->password);
if(req.Send())
{
/* When we get the query response from the service provider we will be given an ID to play with,
* just an ID number which is unique to this query. We need a way of associating that ID with a userrec
* so we insert it into a map mapping the IDs to users.
* Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the
* association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling
* us to discard the query.
*/
AssociateUser(this, SQLutils, req.id, user).Send();
return true;
}
else
{
if (verbose)
ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, req.error.Str());
return false;
}
}
virtual char* OnRequest(Request* request)
{
if(strcmp(SQLRESID, request->GetId()) == 0)
{
SQLresult* res = static_cast<SQLresult*>(request);
userrec* user = GetAssocUser(this, SQLutils, res->id).S().user;
UnAssociate(this, SQLutils, res->id).S();
if(user)
{
if(res->error.Id() == NO_ERROR)
{
if(res->Rows())
{
/* We got a row in the result, this is enough really */
user->Extend("sqlauthed");
}
else if (verbose)
{
/* No rows in result, this means there was no record matching the user */
ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query returned no matches)", user->nick, user->ident, user->host);
user->Extend("sqlauth_failed");
}
}
else if (verbose)
{
ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, res->error.Str());
user->Extend("sqlauth_failed");
}
}
else
{
return NULL;
}
if (!user->GetExt("sqlauthed"))
{
userrec::QuitUser(ServerInstance,user,killreason);
}
return SQLSUCCESS;
}
return NULL;
}
virtual void OnUserDisconnect(userrec* user)
{
user->Shrink("sqlauthed");
user->Shrink("sqlauth_failed");
}
virtual bool OnCheckReady(userrec* user)
{
return user->GetExt("sqlauthed");
}
virtual Version GetVersion()
{
return Version(1,1,1,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSQLAuth);
\ No newline at end of file diff --git a/src/modules/extra/m_sqlite3.cpp b/src/modules/extra/m_sqlite3.cpp index 735591496..6741d7745 100644 --- a/src/modules/extra/m_sqlite3.cpp +++ b/src/modules/extra/m_sqlite3.cpp @@ -1,660 +1 @@ -/* +------------------------------------+
- * | Inspire Internet Relay Chat Daemon |
- * +------------------------------------+
- *
- * InspIRCd: (C) 2002-2007 InspIRCd Development Team
- * See: http://www.inspircd.org/wiki/index.php/Credits
- *
- * This program is free but copyrighted software; see
- * the file COPYING for details.
- *
- * ---------------------------------------------------
- */
-
-#include "inspircd.h"
-#include <sqlite3.h>
-#include "users.h"
-#include "channels.h"
-#include "modules.h"
-
-#include "m_sqlv2.h"
-
-/* $ModDesc: sqlite3 provider */
-/* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") */
-/* $LinkerFlags: pkgconflibs("sqlite3","/libsqlite3.so","-lsqlite3") */
-/* $ModDep: m_sqlv2.h */
-
-
-class SQLConn;
-class SQLite3Result;
-class ResultNotifier;
-
-typedef std::map<std::string, SQLConn*> ConnMap;
-typedef std::deque<classbase*> paramlist;
-typedef std::deque<SQLite3Result*> ResultQueue;
-
-ResultNotifier* resultnotify = NULL;
-
-
-class ResultNotifier : public InspSocket
-{
- Module* mod;
- insp_sockaddr sock_us;
- socklen_t uslen;
-
- public:
- /* Create a socket on a random port. Let the tcp stack allocate us an available port */
-#ifdef IPV6
- ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "::1", 0, true, 3000), mod(m)
-#else
- ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "127.0.0.1", 0, true, 3000), mod(m)
-#endif
- {
- uslen = sizeof(sock_us);
- if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen))
- {
- throw ModuleException("Could not create random listening port on localhost");
- }
- }
-
- ResultNotifier(InspIRCd* SI, Module* m, int newfd, char* ip) : InspSocket(SI, newfd, ip), mod(m)
- {
- }
-
- /* Using getsockname and ntohs, we can determine which port number we were allocated */
- int GetPort()
- {
-#ifdef IPV6
- return ntohs(sock_us.sin6_port);
-#else
- return ntohs(sock_us.sin_port);
-#endif
- }
-
- virtual int OnIncomingConnection(int newsock, char* ip)
- {
- Dispatch();
- return false;
- }
-
- void Dispatch();
-};
-
-
-class SQLite3Result : public SQLresult
-{
- private:
- int currentrow;
- int rows;
- int cols;
-
- std::vector<std::string> colnames;
- std::vector<SQLfieldList> fieldlists;
- SQLfieldList emptyfieldlist;
-
- SQLfieldList* fieldlist;
- SQLfieldMap* fieldmap;
-
- public:
- SQLite3Result(Module* self, Module* to, unsigned int id)
- : SQLresult(self, to, id), currentrow(0), rows(0), cols(0), fieldlist(NULL), fieldmap(NULL)
- {
- }
-
- ~SQLite3Result()
- {
- }
-
- void AddRow(int colsnum, char **data, char **colname)
- {
- colnames.clear();
- cols = colsnum;
- for (int i = 0; i < colsnum; i++)
- {
- fieldlists.resize(fieldlists.size()+1);
- colnames.push_back(colname[i]);
- SQLfield sf(data[i] ? data[i] : "", data[i] ? false : true);
- fieldlists[rows].push_back(sf);
- }
- rows++;
- }
-
- void UpdateAffectedCount()
- {
- rows++;
- }
-
- virtual int Rows()
- {
- return rows;
- }
-
- virtual int Cols()
- {
- return cols;
- }
-
- virtual std::string ColName(int column)
- {
- if (column < (int)colnames.size())
- {
- return colnames[column];
- }
- else
- {
- throw SQLbadColName();
- }
- return "";
- }
-
- virtual int ColNum(const std::string &column)
- {
- for (unsigned int i = 0; i < colnames.size(); i++)
- {
- if (column == colnames[i])
- return i;
- }
- throw SQLbadColName();
- return 0;
- }
-
- virtual SQLfield GetValue(int row, int column)
- {
- if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))
- {
- return fieldlists[row][column];
- }
-
- throw SQLbadColName();
-
- /* XXX: We never actually get here because of the throw */
- return SQLfield("",true);
- }
-
- virtual SQLfieldList& GetRow()
- {
- if (currentrow < rows)
- return fieldlists[currentrow];
- else
- return emptyfieldlist;
- }
-
- virtual SQLfieldMap& GetRowMap()
- {
- /* In an effort to reduce overhead we don't actually allocate the map
- * until the first time it's needed...so...
- */
- if(fieldmap)
- {
- fieldmap->clear();
- }
- else
- {
- fieldmap = new SQLfieldMap;
- }
-
- if (currentrow < rows)
- {
- for (int i = 0; i < Cols(); i++)
- {
- fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));
- }
- currentrow++;
- }
-
- return *fieldmap;
- }
-
- virtual SQLfieldList* GetRowPtr()
- {
- fieldlist = new SQLfieldList();
-
- if (currentrow < rows)
- {
- for (int i = 0; i < Rows(); i++)
- {
- fieldlist->push_back(fieldlists[currentrow][i]);
- }
- currentrow++;
- }
- return fieldlist;
- }
-
- virtual SQLfieldMap* GetRowMapPtr()
- {
- fieldmap = new SQLfieldMap();
-
- if (currentrow < rows)
- {
- for (int i = 0; i < Cols(); i++)
- {
- fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i)));
- }
- currentrow++;
- }
-
- return fieldmap;
- }
-
- virtual void Free(SQLfieldMap* fm)
- {
- delete fm;
- }
-
- virtual void Free(SQLfieldList* fl)
- {
- delete fl;
- }
-
-
-};
-
-class SQLConn : public classbase
-{
- private:
- ResultQueue results;
- InspIRCd* Instance;
- Module* mod;
- SQLhost host;
- sqlite3* conn;
-
- public:
- SQLConn(InspIRCd* SI, Module* m, const SQLhost& hi)
- : Instance(SI), mod(m), host(hi)
- {
- if (OpenDB() != SQLITE_OK)
- {
- Instance->Log(DEFAULT, "WARNING: Could not open DB with id: " + host.id);
- CloseDB();
- }
- }
-
- ~SQLConn()
- {
- CloseDB();
- }
-
- SQLerror Query(SQLrequest &req)
- {
- /* Pointer to the buffer we screw around with substitution in */
- char* query;
-
- /* Pointer to the current end of query, where we append new stuff */
- char* queryend;
-
- /* Total length of the unescaped parameters */
- unsigned long paramlen;
-
- /* Total length of query, used for binary-safety in mysql_real_query */
- unsigned long querylength = 0;
-
- paramlen = 0;
- for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)
- {
- paramlen += i->size();
- }
-
- /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.
- * sizeofquery + (totalparamlength*2) + 1
- *
- * The +1 is for null-terminating the string for mysql_real_escape_string
- */
- query = new char[req.query.q.length() + (paramlen*2) + 1];
- queryend = query;
-
- for(unsigned long i = 0; i < req.query.q.length(); i++)
- {
- if(req.query.q[i] == '?')
- {
- if(req.query.p.size())
- {
- char* escaped;
- escaped = sqlite3_mprintf("%q", req.query.p.front().c_str());
- for (char* n = escaped; *n; n++)
- {
- *queryend = *n;
- queryend++;
- }
- sqlite3_free(escaped);
- req.query.p.pop_front();
- }
- else
- break;
- }
- else
- {
- *queryend = req.query.q[i];
- queryend++;
- }
- querylength++;
- }
- *queryend = 0;
- req.query.q = query;
-
- SQLite3Result* res = new SQLite3Result(mod, req.GetSource(), req.id);
- res->dbid = host.id;
- res->query = req.query.q;
- paramlist params;
- params.push_back(this);
- params.push_back(res);
-
- char *errmsg = 0;
- sqlite3_update_hook(conn, QueryUpdateHook, ¶ms);
- if (sqlite3_exec(conn, req.query.q.data(), QueryResult, ¶ms, &errmsg) != SQLITE_OK)
- {
- std::string error(errmsg);
- sqlite3_free(errmsg);
- delete[] query;
- delete res;
- return SQLerror(QSEND_FAIL, error);
- }
- delete[] query;
-
- results.push_back(res);
- SendNotify();
- return SQLerror();
- }
-
- static int QueryResult(void *params, int argc, char **argv, char **azColName)
- {
- paramlist* p = (paramlist*)params;
- ((SQLConn*)(*p)[0])->ResultReady(((SQLite3Result*)(*p)[1]), argc, argv, azColName);
- return 0;
- }
-
- static void QueryUpdateHook(void *params, int eventid, char const * azSQLite, char const * azColName, sqlite_int64 rowid)
- {
- paramlist* p = (paramlist*)params;
- ((SQLConn*)(*p)[0])->AffectedReady(((SQLite3Result*)(*p)[1]));
- }
-
- void ResultReady(SQLite3Result *res, int cols, char **data, char **colnames)
- {
- res->AddRow(cols, data, colnames);
- }
-
- void AffectedReady(SQLite3Result *res)
- {
- res->UpdateAffectedCount();
- }
-
- int OpenDB()
- {
- return sqlite3_open(host.host.c_str(), &conn);
- }
-
- void CloseDB()
- {
- sqlite3_interrupt(conn);
- sqlite3_close(conn);
- }
-
- SQLhost GetConfHost()
- {
- return host;
- }
-
- void SendResults()
- {
- while (results.size())
- {
- SQLite3Result* res = results[0];
- if (res->GetDest())
- {
- res->Send();
- }
- else
- {
- /* If the client module is unloaded partway through a query then the provider will set
- * the pointer to NULL. We cannot just cancel the query as the result will still come
- * through at some point...and it could get messy if we play with invalid pointers...
- */
- delete res;
- }
- results.pop_front();
- }
- }
-
- void ClearResults()
- {
- while (results.size())
- {
- SQLite3Result* res = results[0];
- delete res;
- results.pop_front();
- }
- }
-
- void SendNotify()
- {
- int QueueFD;
- if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1)
- {
- /* crap, we're out of sockets... */
- return;
- }
-
- insp_sockaddr addr;
-
-#ifdef IPV6
- insp_aton("::1", &addr.sin6_addr);
- addr.sin6_family = AF_FAMILY;
- addr.sin6_port = htons(resultnotify->GetPort());
-#else
- insp_inaddr ia;
- insp_aton("127.0.0.1", &ia);
- addr.sin_family = AF_FAMILY;
- addr.sin_addr = ia;
- addr.sin_port = htons(resultnotify->GetPort());
-#endif
-
- if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1)
- {
- /* wtf, we cant connect to it, but we just created it! */
- return;
- }
- }
-
-};
-
-
-class ModuleSQLite3 : public Module
-{
- private:
- ConnMap connections;
- unsigned long currid;
-
- public:
- ModuleSQLite3(InspIRCd* Me)
- : Module::Module(Me), currid(0)
- {
- ServerInstance->UseInterface("SQLutils");
-
- if (!ServerInstance->PublishFeature("SQL", this))
- {
- throw ModuleException("m_sqlite3: Unable to publish feature 'SQL'");
- }
-
- resultnotify = new ResultNotifier(ServerInstance, this);
-
- ReadConf();
-
- ServerInstance->PublishInterface("SQL", this);
- }
-
- virtual ~ModuleSQLite3()
- {
- ClearQueue();
- ClearAllConnections();
- resultnotify->SetFd(-1);
- resultnotify->state = I_ERROR;
- resultnotify->OnError(I_ERR_SOCKET);
- resultnotify->ClosePending = true;
- delete resultnotify;
- ServerInstance->UnpublishInterface("SQL", this);
- ServerInstance->UnpublishFeature("SQL");
- ServerInstance->DoneWithInterface("SQLutils");
- }
-
- void Implements(char* List)
- {
- List[I_OnRequest] = List[I_OnRehash] = 1;
- }
-
- void SendQueue()
- {
- for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
- {
- iter->second->SendResults();
- }
- }
-
- void ClearQueue()
- {
- for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
- {
- iter->second->ClearResults();
- }
- }
-
- bool HasHost(const SQLhost &host)
- {
- for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
- {
- if (host == iter->second->GetConfHost())
- return true;
- }
- return false;
- }
-
- bool HostInConf(const SQLhost &h)
- {
- ConfigReader conf(ServerInstance);
- for(int i = 0; i < conf.Enumerate("database"); i++)
- {
- SQLhost host;
- host.id = conf.ReadValue("database", "id", i);
- host.host = conf.ReadValue("database", "hostname", i);
- host.port = conf.ReadInteger("database", "port", i, true);
- host.name = conf.ReadValue("database", "name", i);
- host.user = conf.ReadValue("database", "username", i);
- host.pass = conf.ReadValue("database", "password", i);
- host.ssl = conf.ReadFlag("database", "ssl", "0", i);
- if (h == host)
- return true;
- }
- return false;
- }
-
- void ReadConf()
- {
- ClearOldConnections();
-
- ConfigReader conf(ServerInstance);
- for(int i = 0; i < conf.Enumerate("database"); i++)
- {
- SQLhost host;
-
- host.id = conf.ReadValue("database", "id", i);
- host.host = conf.ReadValue("database", "hostname", i);
- host.port = conf.ReadInteger("database", "port", i, true);
- host.name = conf.ReadValue("database", "name", i);
- host.user = conf.ReadValue("database", "username", i);
- host.pass = conf.ReadValue("database", "password", i);
- host.ssl = conf.ReadFlag("database", "ssl", "0", i);
-
- if (HasHost(host))
- continue;
-
- this->AddConn(host);
- }
- }
-
- void AddConn(const SQLhost& hi)
- {
- if (HasHost(hi))
- {
- ServerInstance->Log(DEFAULT, "WARNING: A sqlite connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str());
- return;
- }
-
- SQLConn* newconn;
-
- newconn = new SQLConn(ServerInstance, this, hi);
-
- connections.insert(std::make_pair(hi.id, newconn));
- }
-
- void ClearOldConnections()
- {
- ConnMap::iterator iter,safei;
- for (iter = connections.begin(); iter != connections.end(); iter++)
- {
- if (!HostInConf(iter->second->GetConfHost()))
- {
- DELETE(iter->second);
- safei = iter;
- --iter;
- connections.erase(safei);
- }
- }
- }
-
- void ClearAllConnections()
- {
- ConnMap::iterator i;
- while ((i = connections.begin()) != connections.end())
- {
- connections.erase(i);
- DELETE(i->second);
- }
- }
-
- virtual void OnRehash(userrec* user, const std::string ¶meter)
- {
- ReadConf();
- }
-
- virtual char* OnRequest(Request* request)
- {
- if(strcmp(SQLREQID, request->GetId()) == 0)
- {
- SQLrequest* req = (SQLrequest*)request;
- ConnMap::iterator iter;
- if((iter = connections.find(req->dbid)) != connections.end())
- {
- req->id = NewID();
- req->error = iter->second->Query(*req);
- return SQLSUCCESS;
- }
- else
- {
- req->error.Id(BAD_DBID);
- return NULL;
- }
- }
- return NULL;
- }
-
- unsigned long NewID()
- {
- if (currid+1 == 0)
- currid++;
-
- return ++currid;
- }
-
- virtual Version GetVersion()
- {
- return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
- }
-
-};
-
-void ResultNotifier::Dispatch()
-{
- ((ModuleSQLite3*)mod)->SendQueue();
-}
-
-MODULE_INIT(ModuleSQLite3);
-
+/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <sqlite3.h>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_sqlv2.h"
/* $ModDesc: sqlite3 provider */
/* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") */
/* $LinkerFlags: pkgconflibs("sqlite3","/libsqlite3.so","-lsqlite3") */
/* $ModDep: m_sqlv2.h */
class SQLConn;
class SQLite3Result;
class ResultNotifier;
typedef std::map<std::string, SQLConn*> ConnMap;
typedef std::deque<classbase*> paramlist;
typedef std::deque<SQLite3Result*> ResultQueue;
ResultNotifier* resultnotify = NULL;
class ResultNotifier : public InspSocket
{
Module* mod;
insp_sockaddr sock_us;
socklen_t uslen;
public:
/* Create a socket on a random port. Let the tcp stack allocate us an available port */
#ifdef IPV6
ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "::1", 0, true, 3000), mod(m)
#else
ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "127.0.0.1", 0, true, 3000), mod(m)
#endif
{
uslen = sizeof(sock_us);
if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen))
{
throw ModuleException("Could not create random listening port on localhost");
}
}
ResultNotifier(InspIRCd* SI, Module* m, int newfd, char* ip) : InspSocket(SI, newfd, ip), mod(m)
{
}
/* Using getsockname and ntohs, we can determine which port number we were allocated */
int GetPort()
{
#ifdef IPV6
return ntohs(sock_us.sin6_port);
#else
return ntohs(sock_us.sin_port);
#endif
}
virtual int OnIncomingConnection(int newsock, char* ip)
{
Dispatch();
return false;
}
void Dispatch();
};
class SQLite3Result : public SQLresult
{
private:
int currentrow;
int rows;
int cols;
std::vector<std::string> colnames;
std::vector<SQLfieldList> fieldlists;
SQLfieldList emptyfieldlist;
SQLfieldList* fieldlist;
SQLfieldMap* fieldmap;
public:
SQLite3Result(Module* self, Module* to, unsigned int id)
: SQLresult(self, to, id), currentrow(0), rows(0), cols(0), fieldlist(NULL), fieldmap(NULL)
{
}
~SQLite3Result()
{
}
void AddRow(int colsnum, char **data, char **colname)
{
colnames.clear();
cols = colsnum;
for (int i = 0; i < colsnum; i++)
{
fieldlists.resize(fieldlists.size()+1);
colnames.push_back(colname[i]);
SQLfield sf(data[i] ? data[i] : "", data[i] ? false : true);
fieldlists[rows].push_back(sf);
}
rows++;
}
void UpdateAffectedCount()
{
rows++;
}
virtual int Rows()
{
return rows;
}
virtual int Cols()
{
return cols;
}
virtual std::string ColName(int column)
{
if (column < (int)colnames.size())
{
return colnames[column];
}
else
{
throw SQLbadColName();
}
return "";
}
virtual int ColNum(const std::string &column)
{
for (unsigned int i = 0; i < colnames.size(); i++)
{
if (column == colnames[i])
return i;
}
throw SQLbadColName();
return 0;
}
virtual SQLfield GetValue(int row, int column)
{
if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))
{
return fieldlists[row][column];
}
throw SQLbadColName();
/* XXX: We never actually get here because of the throw */
return SQLfield("",true);
}
virtual SQLfieldList& GetRow()
{
if (currentrow < rows)
return fieldlists[currentrow];
else
return emptyfieldlist;
}
virtual SQLfieldMap& GetRowMap()
{
/* In an effort to reduce overhead we don't actually allocate the map
* until the first time it's needed...so...
*/
if(fieldmap)
{
fieldmap->clear();
}
else
{
fieldmap = new SQLfieldMap;
}
if (currentrow < rows)
{
for (int i = 0; i < Cols(); i++)
{
fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));
}
currentrow++;
}
return *fieldmap;
}
virtual SQLfieldList* GetRowPtr()
{
fieldlist = new SQLfieldList();
if (currentrow < rows)
{
for (int i = 0; i < Rows(); i++)
{
fieldlist->push_back(fieldlists[currentrow][i]);
}
currentrow++;
}
return fieldlist;
}
virtual SQLfieldMap* GetRowMapPtr()
{
fieldmap = new SQLfieldMap();
if (currentrow < rows)
{
for (int i = 0; i < Cols(); i++)
{
fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i)));
}
currentrow++;
}
return fieldmap;
}
virtual void Free(SQLfieldMap* fm)
{
delete fm;
}
virtual void Free(SQLfieldList* fl)
{
delete fl;
}
};
class SQLConn : public classbase
{
private:
ResultQueue results;
InspIRCd* Instance;
Module* mod;
SQLhost host;
sqlite3* conn;
public:
SQLConn(InspIRCd* SI, Module* m, const SQLhost& hi)
: Instance(SI), mod(m), host(hi)
{
if (OpenDB() != SQLITE_OK)
{
Instance->Log(DEFAULT, "WARNING: Could not open DB with id: " + host.id);
CloseDB();
}
}
~SQLConn()
{
CloseDB();
}
SQLerror Query(SQLrequest &req)
{
/* Pointer to the buffer we screw around with substitution in */
char* query;
/* Pointer to the current end of query, where we append new stuff */
char* queryend;
/* Total length of the unescaped parameters */
unsigned long paramlen;
/* Total length of query, used for binary-safety in mysql_real_query */
unsigned long querylength = 0;
paramlen = 0;
for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)
{
paramlen += i->size();
}
/* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.
* sizeofquery + (totalparamlength*2) + 1
*
* The +1 is for null-terminating the string for mysql_real_escape_string
*/
query = new char[req.query.q.length() + (paramlen*2) + 1];
queryend = query;
for(unsigned long i = 0; i < req.query.q.length(); i++)
{
if(req.query.q[i] == '?')
{
if(req.query.p.size())
{
char* escaped;
escaped = sqlite3_mprintf("%q", req.query.p.front().c_str());
for (char* n = escaped; *n; n++)
{
*queryend = *n;
queryend++;
}
sqlite3_free(escaped);
req.query.p.pop_front();
}
else
break;
}
else
{
*queryend = req.query.q[i];
queryend++;
}
querylength++;
}
*queryend = 0;
req.query.q = query;
SQLite3Result* res = new SQLite3Result(mod, req.GetSource(), req.id);
res->dbid = host.id;
res->query = req.query.q;
paramlist params;
params.push_back(this);
params.push_back(res);
char *errmsg = 0;
sqlite3_update_hook(conn, QueryUpdateHook, ¶ms);
if (sqlite3_exec(conn, req.query.q.data(), QueryResult, ¶ms, &errmsg) != SQLITE_OK)
{
std::string error(errmsg);
sqlite3_free(errmsg);
delete[] query;
delete res;
return SQLerror(QSEND_FAIL, error);
}
delete[] query;
results.push_back(res);
SendNotify();
return SQLerror();
}
static int QueryResult(void *params, int argc, char **argv, char **azColName)
{
paramlist* p = (paramlist*)params;
((SQLConn*)(*p)[0])->ResultReady(((SQLite3Result*)(*p)[1]), argc, argv, azColName);
return 0;
}
static void QueryUpdateHook(void *params, int eventid, char const * azSQLite, char const * azColName, sqlite_int64 rowid)
{
paramlist* p = (paramlist*)params;
((SQLConn*)(*p)[0])->AffectedReady(((SQLite3Result*)(*p)[1]));
}
void ResultReady(SQLite3Result *res, int cols, char **data, char **colnames)
{
res->AddRow(cols, data, colnames);
}
void AffectedReady(SQLite3Result *res)
{
res->UpdateAffectedCount();
}
int OpenDB()
{
return sqlite3_open(host.host.c_str(), &conn);
}
void CloseDB()
{
sqlite3_interrupt(conn);
sqlite3_close(conn);
}
SQLhost GetConfHost()
{
return host;
}
void SendResults()
{
while (results.size())
{
SQLite3Result* res = results[0];
if (res->GetDest())
{
res->Send();
}
else
{
/* If the client module is unloaded partway through a query then the provider will set
* the pointer to NULL. We cannot just cancel the query as the result will still come
* through at some point...and it could get messy if we play with invalid pointers...
*/
delete res;
}
results.pop_front();
}
}
void ClearResults()
{
while (results.size())
{
SQLite3Result* res = results[0];
delete res;
results.pop_front();
}
}
void SendNotify()
{
int QueueFD;
if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1)
{
/* crap, we're out of sockets... */
return;
}
insp_sockaddr addr;
#ifdef IPV6
insp_aton("::1", &addr.sin6_addr);
addr.sin6_family = AF_FAMILY;
addr.sin6_port = htons(resultnotify->GetPort());
#else
insp_inaddr ia;
insp_aton("127.0.0.1", &ia);
addr.sin_family = AF_FAMILY;
addr.sin_addr = ia;
addr.sin_port = htons(resultnotify->GetPort());
#endif
if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1)
{
/* wtf, we cant connect to it, but we just created it! */
return;
}
}
};
class ModuleSQLite3 : public Module
{
private:
ConnMap connections;
unsigned long currid;
public:
ModuleSQLite3(InspIRCd* Me)
: Module::Module(Me), currid(0)
{
ServerInstance->UseInterface("SQLutils");
if (!ServerInstance->PublishFeature("SQL", this))
{
throw ModuleException("m_sqlite3: Unable to publish feature 'SQL'");
}
resultnotify = new ResultNotifier(ServerInstance, this);
ReadConf();
ServerInstance->PublishInterface("SQL", this);
}
virtual ~ModuleSQLite3()
{
ClearQueue();
ClearAllConnections();
resultnotify->SetFd(-1);
resultnotify->state = I_ERROR;
resultnotify->OnError(I_ERR_SOCKET);
resultnotify->ClosePending = true;
delete resultnotify;
ServerInstance->UnpublishInterface("SQL", this);
ServerInstance->UnpublishFeature("SQL");
ServerInstance->DoneWithInterface("SQLutils");
}
void Implements(char* List)
{
List[I_OnRequest] = List[I_OnRehash] = 1;
}
void SendQueue()
{
for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
{
iter->second->SendResults();
}
}
void ClearQueue()
{
for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
{
iter->second->ClearResults();
}
}
bool HasHost(const SQLhost &host)
{
for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
{
if (host == iter->second->GetConfHost())
return true;
}
return false;
}
bool HostInConf(const SQLhost &h)
{
ConfigReader conf(ServerInstance);
for(int i = 0; i < conf.Enumerate("database"); i++)
{
SQLhost host;
host.id = conf.ReadValue("database", "id", i);
host.host = conf.ReadValue("database", "hostname", i);
host.port = conf.ReadInteger("database", "port", i, true);
host.name = conf.ReadValue("database", "name", i);
host.user = conf.ReadValue("database", "username", i);
host.pass = conf.ReadValue("database", "password", i);
host.ssl = conf.ReadFlag("database", "ssl", "0", i);
if (h == host)
return true;
}
return false;
}
void ReadConf()
{
ClearOldConnections();
ConfigReader conf(ServerInstance);
for(int i = 0; i < conf.Enumerate("database"); i++)
{
SQLhost host;
host.id = conf.ReadValue("database", "id", i);
host.host = conf.ReadValue("database", "hostname", i);
host.port = conf.ReadInteger("database", "port", i, true);
host.name = conf.ReadValue("database", "name", i);
host.user = conf.ReadValue("database", "username", i);
host.pass = conf.ReadValue("database", "password", i);
host.ssl = conf.ReadFlag("database", "ssl", "0", i);
if (HasHost(host))
continue;
this->AddConn(host);
}
}
void AddConn(const SQLhost& hi)
{
if (HasHost(hi))
{
ServerInstance->Log(DEFAULT, "WARNING: A sqlite connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str());
return;
}
SQLConn* newconn;
newconn = new SQLConn(ServerInstance, this, hi);
connections.insert(std::make_pair(hi.id, newconn));
}
void ClearOldConnections()
{
ConnMap::iterator iter,safei;
for (iter = connections.begin(); iter != connections.end(); iter++)
{
if (!HostInConf(iter->second->GetConfHost()))
{
DELETE(iter->second);
safei = iter;
--iter;
connections.erase(safei);
}
}
}
void ClearAllConnections()
{
ConnMap::iterator i;
while ((i = connections.begin()) != connections.end())
{
connections.erase(i);
DELETE(i->second);
}
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadConf();
}
virtual char* OnRequest(Request* request)
{
if(strcmp(SQLREQID, request->GetId()) == 0)
{
SQLrequest* req = (SQLrequest*)request;
ConnMap::iterator iter;
if((iter = connections.find(req->dbid)) != connections.end())
{
req->id = NewID();
req->error = iter->second->Query(*req);
return SQLSUCCESS;
}
else
{
req->error.Id(BAD_DBID);
return NULL;
}
}
return NULL;
}
unsigned long NewID()
{
if (currid+1 == 0)
currid++;
return ++currid;
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
}
};
void ResultNotifier::Dispatch()
{
((ModuleSQLite3*)mod)->SendQueue();
}
MODULE_INIT(ModuleSQLite3);
\ No newline at end of file diff --git a/src/modules/extra/m_sqllog.cpp b/src/modules/extra/m_sqllog.cpp index 391e4bbba..04eb1fef1 100644 --- a/src/modules/extra/m_sqllog.cpp +++ b/src/modules/extra/m_sqllog.cpp @@ -1,310 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" -#include "m_sqlv2.h" - -static Module* SQLModule; -static Module* MyMod; -static std::string dbid; - -enum LogTypes { LT_OPER = 1, LT_KILL, LT_SERVLINK, LT_XLINE, LT_CONNECT, LT_DISCONNECT, LT_FLOOD, LT_LOADMODULE }; - -enum QueryState { FIND_SOURCE, FIND_NICK, FIND_HOST, DONE}; - -class QueryInfo; - -std::map<unsigned long,QueryInfo*> active_queries; - -class QueryInfo -{ -public: - QueryState qs; - unsigned long id; - std::string nick; - std::string source; - std::string hostname; - int sourceid; - int nickid; - int hostid; - int category; - time_t date; - bool insert; - - QueryInfo(const std::string &n, const std::string &s, const std::string &h, unsigned long i, int cat) - { - qs = FIND_SOURCE; - nick = n; - source = s; - hostname = h; - id = i; - category = cat; - sourceid = nickid = hostid = -1; - date = time(NULL); - insert = false; - } - - void Go(SQLresult* res) - { - SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "", ""); - switch (qs) - { - case FIND_SOURCE: - if (res->Rows() && sourceid == -1 && !insert) - { - sourceid = atoi(res->GetValue(0,0).d.c_str()); - req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick); - if(req.Send()) - { - insert = false; - qs = FIND_NICK; - active_queries[req.id] = this; - } - } - else if (res->Rows() && sourceid == -1 && insert) - { - req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source); - if(req.Send()) - { - insert = false; - qs = FIND_SOURCE; - active_queries[req.id] = this; - } - } - else - { - req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')", source); - if(req.Send()) - { - insert = true; - qs = FIND_SOURCE; - active_queries[req.id] = this; - } - } - break; - - case FIND_NICK: - if (res->Rows() && nickid == -1 && !insert) - { - nickid = atoi(res->GetValue(0,0).d.c_str()); - req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname); - if(req.Send()) - { - insert = false; - qs = FIND_HOST; - active_queries[req.id] = this; - } - } - else if (res->Rows() && nickid == -1 && insert) - { - req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick); - if(req.Send()) - { - insert = false; - qs = FIND_NICK; - active_queries[req.id] = this; - } - } - else - { - req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')",nick); - if(req.Send()) - { - insert = true; - qs = FIND_NICK; - active_queries[req.id] = this; - } - } - break; - - case FIND_HOST: - if (res->Rows() && hostid == -1 && !insert) - { - hostid = atoi(res->GetValue(0,0).d.c_str()); - req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log (category_id,nick,host,source,dtime) VALUES("+ConvToStr(category)+","+ConvToStr(nickid)+","+ConvToStr(hostid)+","+ConvToStr(sourceid)+","+ConvToStr(date)+")"); - if(req.Send()) - { - insert = true; - qs = DONE; - active_queries[req.id] = this; - } - } - else if (res->Rows() && hostid == -1 && insert) - { - req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname); - if(req.Send()) - { - insert = false; - qs = FIND_HOST; - active_queries[req.id] = this; - } - } - else - { - req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_hosts (hostname) VALUES('?')", hostname); - if(req.Send()) - { - insert = true; - qs = FIND_HOST; - active_queries[req.id] = this; - } - } - break; - - case DONE: - delete active_queries[req.id]; - active_queries[req.id] = NULL; - break; - } - } -}; - -/* $ModDesc: Logs network-wide data to an SQL database */ - -class ModuleSQLLog : public Module -{ - ConfigReader* Conf; - - public: - ModuleSQLLog(InspIRCd* Me) - : Module::Module(Me) - { - ServerInstance->UseInterface("SQLutils"); - ServerInstance->UseInterface("SQL"); - - Module* SQLutils = ServerInstance->FindModule("m_sqlutils.so"); - if (!SQLutils) - throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so."); - - SQLModule = ServerInstance->FindFeature("SQL"); - - OnRehash(NULL,""); - MyMod = this; - active_queries.clear(); - } - - virtual ~ModuleSQLLog() - { - ServerInstance->DoneWithInterface("SQL"); - ServerInstance->DoneWithInterface("SQLutils"); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnOper] = List[I_OnGlobalOper] = List[I_OnKill] = 1; - List[I_OnPreCommand] = List[I_OnUserConnect] = 1; - List[I_OnUserQuit] = List[I_OnLoadModule] = List[I_OnRequest] = 1; - } - - void ReadConfig() - { - ConfigReader Conf(ServerInstance); - dbid = Conf.ReadValue("sqllog","dbid",0); // database id of a database configured in sql module - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ReadConfig(); - } - - virtual char* OnRequest(Request* request) - { - if(strcmp(SQLRESID, request->GetId()) == 0) - { - SQLresult* res; - std::map<unsigned long, QueryInfo*>::iterator n; - - res = static_cast<SQLresult*>(request); - n = active_queries.find(res->id); - - if (n != active_queries.end()) - { - n->second->Go(res); - std::map<unsigned long, QueryInfo*>::iterator n = active_queries.find(res->id); - active_queries.erase(n); - } - - return SQLSUCCESS; - } - - return NULL; - } - - void AddLogEntry(int category, const std::string &nick, const std::string &host, const std::string &source) - { - // is the sql module loaded? If not, we don't attempt to do anything. - if (!SQLModule) - return; - - SQLrequest req = SQLreq(this, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source); - if(req.Send()) - { - QueryInfo* i = new QueryInfo(nick, source, host, req.id, category); - i->qs = FIND_SOURCE; - active_queries[req.id] = i; - } - } - - virtual void OnOper(userrec* user, const std::string &opertype) - { - AddLogEntry(LT_OPER,user->nick,user->host,user->server); - } - - virtual void OnGlobalOper(userrec* user) - { - AddLogEntry(LT_OPER,user->nick,user->host,user->server); - } - - virtual int OnKill(userrec* source, userrec* dest, const std::string &reason) - { - AddLogEntry(LT_KILL,dest->nick,dest->host,source->nick); - return 0; - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - if ((command == "GLINE" || command == "KLINE" || command == "ELINE" || command == "ZLINE") && validated) - { - AddLogEntry(LT_XLINE,user->nick,command[0]+std::string(":")+std::string(parameters[0]),user->server); - } - return 0; - } - - virtual void OnUserConnect(userrec* user) - { - AddLogEntry(LT_CONNECT,user->nick,user->host,user->server); - } - - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - AddLogEntry(LT_DISCONNECT,user->nick,user->host,user->server); - } - - virtual void OnLoadModule(Module* mod, const std::string &name) - { - AddLogEntry(LT_LOADMODULE,name,ServerInstance->Config->ServerName, ServerInstance->Config->ServerName); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSQLLog); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
#include "m_sqlv2.h"
static Module* SQLModule;
static Module* MyMod;
static std::string dbid;
enum LogTypes { LT_OPER = 1, LT_KILL, LT_SERVLINK, LT_XLINE, LT_CONNECT, LT_DISCONNECT, LT_FLOOD, LT_LOADMODULE };
enum QueryState { FIND_SOURCE, FIND_NICK, FIND_HOST, DONE};
class QueryInfo;
std::map<unsigned long,QueryInfo*> active_queries;
class QueryInfo
{
public:
QueryState qs;
unsigned long id;
std::string nick;
std::string source;
std::string hostname;
int sourceid;
int nickid;
int hostid;
int category;
time_t date;
bool insert;
QueryInfo(const std::string &n, const std::string &s, const std::string &h, unsigned long i, int cat)
{
qs = FIND_SOURCE;
nick = n;
source = s;
hostname = h;
id = i;
category = cat;
sourceid = nickid = hostid = -1;
date = time(NULL);
insert = false;
}
void Go(SQLresult* res)
{
SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "", "");
switch (qs)
{
case FIND_SOURCE:
if (res->Rows() && sourceid == -1 && !insert)
{
sourceid = atoi(res->GetValue(0,0).d.c_str());
req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
if(req.Send())
{
insert = false;
qs = FIND_NICK;
active_queries[req.id] = this;
}
}
else if (res->Rows() && sourceid == -1 && insert)
{
req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source);
if(req.Send())
{
insert = false;
qs = FIND_SOURCE;
active_queries[req.id] = this;
}
}
else
{
req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')", source);
if(req.Send())
{
insert = true;
qs = FIND_SOURCE;
active_queries[req.id] = this;
}
}
break;
case FIND_NICK:
if (res->Rows() && nickid == -1 && !insert)
{
nickid = atoi(res->GetValue(0,0).d.c_str());
req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname);
if(req.Send())
{
insert = false;
qs = FIND_HOST;
active_queries[req.id] = this;
}
}
else if (res->Rows() && nickid == -1 && insert)
{
req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
if(req.Send())
{
insert = false;
qs = FIND_NICK;
active_queries[req.id] = this;
}
}
else
{
req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')",nick);
if(req.Send())
{
insert = true;
qs = FIND_NICK;
active_queries[req.id] = this;
}
}
break;
case FIND_HOST:
if (res->Rows() && hostid == -1 && !insert)
{
hostid = atoi(res->GetValue(0,0).d.c_str());
req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log (category_id,nick,host,source,dtime) VALUES("+ConvToStr(category)+","+ConvToStr(nickid)+","+ConvToStr(hostid)+","+ConvToStr(sourceid)+","+ConvToStr(date)+")");
if(req.Send())
{
insert = true;
qs = DONE;
active_queries[req.id] = this;
}
}
else if (res->Rows() && hostid == -1 && insert)
{
req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname);
if(req.Send())
{
insert = false;
qs = FIND_HOST;
active_queries[req.id] = this;
}
}
else
{
req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_hosts (hostname) VALUES('?')", hostname);
if(req.Send())
{
insert = true;
qs = FIND_HOST;
active_queries[req.id] = this;
}
}
break;
case DONE:
delete active_queries[req.id];
active_queries[req.id] = NULL;
break;
}
}
};
/* $ModDesc: Logs network-wide data to an SQL database */
class ModuleSQLLog : public Module
{
ConfigReader* Conf;
public:
ModuleSQLLog(InspIRCd* Me)
: Module::Module(Me)
{
ServerInstance->UseInterface("SQLutils");
ServerInstance->UseInterface("SQL");
Module* SQLutils = ServerInstance->FindModule("m_sqlutils.so");
if (!SQLutils)
throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");
SQLModule = ServerInstance->FindFeature("SQL");
OnRehash(NULL,"");
MyMod = this;
active_queries.clear();
}
virtual ~ModuleSQLLog()
{
ServerInstance->DoneWithInterface("SQL");
ServerInstance->DoneWithInterface("SQLutils");
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnOper] = List[I_OnGlobalOper] = List[I_OnKill] = 1;
List[I_OnPreCommand] = List[I_OnUserConnect] = 1;
List[I_OnUserQuit] = List[I_OnLoadModule] = List[I_OnRequest] = 1;
}
void ReadConfig()
{
ConfigReader Conf(ServerInstance);
dbid = Conf.ReadValue("sqllog","dbid",0); // database id of a database configured in sql module
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadConfig();
}
virtual char* OnRequest(Request* request)
{
if(strcmp(SQLRESID, request->GetId()) == 0)
{
SQLresult* res;
std::map<unsigned long, QueryInfo*>::iterator n;
res = static_cast<SQLresult*>(request);
n = active_queries.find(res->id);
if (n != active_queries.end())
{
n->second->Go(res);
std::map<unsigned long, QueryInfo*>::iterator n = active_queries.find(res->id);
active_queries.erase(n);
}
return SQLSUCCESS;
}
return NULL;
}
void AddLogEntry(int category, const std::string &nick, const std::string &host, const std::string &source)
{
// is the sql module loaded? If not, we don't attempt to do anything.
if (!SQLModule)
return;
SQLrequest req = SQLreq(this, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source);
if(req.Send())
{
QueryInfo* i = new QueryInfo(nick, source, host, req.id, category);
i->qs = FIND_SOURCE;
active_queries[req.id] = i;
}
}
virtual void OnOper(userrec* user, const std::string &opertype)
{
AddLogEntry(LT_OPER,user->nick,user->host,user->server);
}
virtual void OnGlobalOper(userrec* user)
{
AddLogEntry(LT_OPER,user->nick,user->host,user->server);
}
virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)
{
AddLogEntry(LT_KILL,dest->nick,dest->host,source->nick);
return 0;
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
if ((command == "GLINE" || command == "KLINE" || command == "ELINE" || command == "ZLINE") && validated)
{
AddLogEntry(LT_XLINE,user->nick,command[0]+std::string(":")+std::string(parameters[0]),user->server);
}
return 0;
}
virtual void OnUserConnect(userrec* user)
{
AddLogEntry(LT_CONNECT,user->nick,user->host,user->server);
}
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
AddLogEntry(LT_DISCONNECT,user->nick,user->host,user->server);
}
virtual void OnLoadModule(Module* mod, const std::string &name)
{
AddLogEntry(LT_LOADMODULE,name,ServerInstance->Config->ServerName, ServerInstance->Config->ServerName);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSQLLog);
\ No newline at end of file diff --git a/src/modules/extra/m_sqloper.cpp b/src/modules/extra/m_sqloper.cpp index 520869e21..4b09ac26e 100644 --- a/src/modules/extra/m_sqloper.cpp +++ b/src/modules/extra/m_sqloper.cpp @@ -1,283 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" - -#include "m_sqlv2.h" -#include "m_sqlutils.h" -#include "m_hash.h" -#include "commands/cmd_oper.h" - -/* $ModDesc: Allows storage of oper credentials in an SQL table */ -/* $ModDep: m_sqlv2.h m_sqlutils.h */ - -class ModuleSQLOper : public Module -{ - Module* SQLutils; - Module* HashModule; - std::string databaseid; - -public: - ModuleSQLOper(InspIRCd* Me) - : Module::Module(Me) - { - ServerInstance->UseInterface("SQLutils"); - ServerInstance->UseInterface("SQL"); - ServerInstance->UseInterface("HashRequest"); - - /* Attempt to locate the md5 service provider, bail if we can't find it */ - HashModule = ServerInstance->FindModule("m_md5.so"); - if (!HashModule) - throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_sqloper.so."); - - SQLutils = ServerInstance->FindModule("m_sqlutils.so"); - if (!SQLutils) - throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqloper.so."); - - OnRehash(NULL,""); - } - - virtual ~ModuleSQLOper() - { - ServerInstance->DoneWithInterface("SQL"); - ServerInstance->DoneWithInterface("SQLutils"); - ServerInstance->DoneWithInterface("HashRequest"); - } - - void Implements(char* List) - { - List[I_OnRequest] = List[I_OnRehash] = List[I_OnPreCommand] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - - databaseid = Conf.ReadValue("sqloper", "dbid", 0); /* Database ID of a database configured for the service provider module */ - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - if ((validated) && (command == "OPER")) - { - if (LookupOper(user, parameters[0], parameters[1])) - { - /* Returning true here just means the query is in progress, or on it's way to being - * in progress. Nothing about the /oper actually being successful.. - * If the oper lookup fails later, we pass the command to the original handler - * for /oper by calling its Handle method directly. - */ - return 1; - } - } - return 0; - } - - bool LookupOper(userrec* user, const std::string &username, const std::string &password) - { - Module* target; - - target = ServerInstance->FindFeature("SQL"); - - if (target) - { - /* Reset hash module first back to MD5 standard state */ - HashResetRequest(this, HashModule).Send(); - /* Make an MD5 hash of the password for using in the query */ - std::string md5_pass_hash = HashSumRequest(this, HashModule, password.c_str()).Send(); - - /* We generate our own MD5 sum here because some database providers (e.g. SQLite) dont have a builtin md5 function, - * also hashing it in the module and only passing a remote query containing a hash is more secure. - */ - - SQLrequest req = SQLreq(this, target, databaseid, "SELECT username, password, hostname, type FROM ircd_opers WHERE username = '?' AND password='?'", username, md5_pass_hash); - - if (req.Send()) - { - /* When we get the query response from the service provider we will be given an ID to play with, - * just an ID number which is unique to this query. We need a way of associating that ID with a userrec - * so we insert it into a map mapping the IDs to users. - * Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the - * association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling - * us to discard the query. - */ - AssociateUser(this, SQLutils, req.id, user).Send(); - - user->Extend("oper_user", strdup(username.c_str())); - user->Extend("oper_pass", strdup(password.c_str())); - - return true; - } - else - { - return false; - } - } - else - { - ServerInstance->Log(SPARSE, "WARNING: Couldn't find SQL provider module. NOBODY will be able to oper up unless their o:line is statically configured"); - return false; - } - } - - virtual char* OnRequest(Request* request) - { - if (strcmp(SQLRESID, request->GetId()) == 0) - { - SQLresult* res = static_cast<SQLresult*>(request); - - userrec* user = GetAssocUser(this, SQLutils, res->id).S().user; - UnAssociate(this, SQLutils, res->id).S(); - - char* tried_user = NULL; - char* tried_pass = NULL; - - user->GetExt("oper_user", tried_user); - user->GetExt("oper_pass", tried_pass); - - if (user) - { - if (res->error.Id() == NO_ERROR) - { - if (res->Rows()) - { - /* We got a row in the result, this means there was a record for the oper.. - * now we just need to check if their host matches, and if it does then - * oper them up. - * - * We now (previous versions of the module didn't) support multiple SQL - * rows per-oper in the same way the config file does, all rows will be tried - * until one is found which matches. This is useful to define several different - * hosts for a single oper. - * - * The for() loop works as SQLresult::GetRowMap() returns an empty map when there - * are no more rows to return. - */ - - for (SQLfieldMap& row = res->GetRowMap(); row.size(); row = res->GetRowMap()) - { - if (OperUser(user, row["username"].d, row["password"].d, row["hostname"].d, row["type"].d)) - { - /* If/when one of the rows matches, stop checking and return */ - return SQLSUCCESS; - } - if (tried_user && tried_pass) - { - LoginFail(user, tried_user, tried_pass); - free(tried_user); - free(tried_pass); - user->Shrink("oper_user"); - user->Shrink("oper_pass"); - } - } - } - else - { - /* No rows in result, this means there was no oper line for the user, - * we should have already checked the o:lines so now we need an - * "insufficient awesomeness" (invalid credentials) error - */ - if (tried_user && tried_pass) - { - LoginFail(user, tried_user, tried_pass); - free(tried_user); - free(tried_pass); - user->Shrink("oper_user"); - user->Shrink("oper_pass"); - } - } - } - else - { - /* This one shouldn't happen, the query failed for some reason. - * We have to fail the /oper request and give them the same error - * as above. - */ - if (tried_user && tried_pass) - { - LoginFail(user, tried_user, tried_pass); - free(tried_user); - free(tried_pass); - user->Shrink("oper_user"); - user->Shrink("oper_pass"); - } - - } - } - - return SQLSUCCESS; - } - - return NULL; - } - - void LoginFail(userrec* user, const std::string &username, const std::string &pass) - { - command_t* oper_command = ServerInstance->Parser->GetHandler("OPER"); - - if (oper_command) - { - const char* params[] = { username.c_str(), pass.c_str() }; - oper_command->Handle(params, 2, user); - } - else - { - ServerInstance->Log(DEBUG, "BUG: WHAT?! Why do we have no OPER command?!"); - } - } - - bool OperUser(userrec* user, const std::string &username, const std::string &password, const std::string &pattern, const std::string &type) - { - ConfigReader Conf(ServerInstance); - - for (int j = 0; j < Conf.Enumerate("type"); j++) - { - std::string tname = Conf.ReadValue("type","name",j); - std::string hostname(user->ident); - - hostname.append("@").append(user->host); - - if ((tname == type) && OneOfMatches(hostname.c_str(), user->GetIPString(), pattern.c_str())) - { - /* Opertype and host match, looks like this is it. */ - std::string operhost = Conf.ReadValue("type", "host", j); - - if (operhost.size()) - user->ChangeDisplayedHost(operhost.c_str()); - - ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s", user->nick, user->ident, user->host, type.c_str()); - user->WriteServ("381 %s :You are now an IRC operator of type %s", user->nick, type.c_str()); - - if (!user->modes[UM_OPERATOR]) - user->Oper(type); - - return true; - } - } - - return false; - } - - virtual Version GetVersion() - { - return Version(1,1,1,0,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSQLOper); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
#include "m_sqlv2.h"
#include "m_sqlutils.h"
#include "m_hash.h"
#include "commands/cmd_oper.h"
/* $ModDesc: Allows storage of oper credentials in an SQL table */
/* $ModDep: m_sqlv2.h m_sqlutils.h */
class ModuleSQLOper : public Module
{
Module* SQLutils;
Module* HashModule;
std::string databaseid;
public:
ModuleSQLOper(InspIRCd* Me)
: Module::Module(Me)
{
ServerInstance->UseInterface("SQLutils");
ServerInstance->UseInterface("SQL");
ServerInstance->UseInterface("HashRequest");
/* Attempt to locate the md5 service provider, bail if we can't find it */
HashModule = ServerInstance->FindModule("m_md5.so");
if (!HashModule)
throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_sqloper.so.");
SQLutils = ServerInstance->FindModule("m_sqlutils.so");
if (!SQLutils)
throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqloper.so.");
OnRehash(NULL,"");
}
virtual ~ModuleSQLOper()
{
ServerInstance->DoneWithInterface("SQL");
ServerInstance->DoneWithInterface("SQLutils");
ServerInstance->DoneWithInterface("HashRequest");
}
void Implements(char* List)
{
List[I_OnRequest] = List[I_OnRehash] = List[I_OnPreCommand] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
databaseid = Conf.ReadValue("sqloper", "dbid", 0); /* Database ID of a database configured for the service provider module */
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
if ((validated) && (command == "OPER"))
{
if (LookupOper(user, parameters[0], parameters[1]))
{
/* Returning true here just means the query is in progress, or on it's way to being
* in progress. Nothing about the /oper actually being successful..
* If the oper lookup fails later, we pass the command to the original handler
* for /oper by calling its Handle method directly.
*/
return 1;
}
}
return 0;
}
bool LookupOper(userrec* user, const std::string &username, const std::string &password)
{
Module* target;
target = ServerInstance->FindFeature("SQL");
if (target)
{
/* Reset hash module first back to MD5 standard state */
HashResetRequest(this, HashModule).Send();
/* Make an MD5 hash of the password for using in the query */
std::string md5_pass_hash = HashSumRequest(this, HashModule, password.c_str()).Send();
/* We generate our own MD5 sum here because some database providers (e.g. SQLite) dont have a builtin md5 function,
* also hashing it in the module and only passing a remote query containing a hash is more secure.
*/
SQLrequest req = SQLreq(this, target, databaseid, "SELECT username, password, hostname, type FROM ircd_opers WHERE username = '?' AND password='?'", username, md5_pass_hash);
if (req.Send())
{
/* When we get the query response from the service provider we will be given an ID to play with,
* just an ID number which is unique to this query. We need a way of associating that ID with a userrec
* so we insert it into a map mapping the IDs to users.
* Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the
* association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling
* us to discard the query.
*/
AssociateUser(this, SQLutils, req.id, user).Send();
user->Extend("oper_user", strdup(username.c_str()));
user->Extend("oper_pass", strdup(password.c_str()));
return true;
}
else
{
return false;
}
}
else
{
ServerInstance->Log(SPARSE, "WARNING: Couldn't find SQL provider module. NOBODY will be able to oper up unless their o:line is statically configured");
return false;
}
}
virtual char* OnRequest(Request* request)
{
if (strcmp(SQLRESID, request->GetId()) == 0)
{
SQLresult* res = static_cast<SQLresult*>(request);
userrec* user = GetAssocUser(this, SQLutils, res->id).S().user;
UnAssociate(this, SQLutils, res->id).S();
char* tried_user = NULL;
char* tried_pass = NULL;
user->GetExt("oper_user", tried_user);
user->GetExt("oper_pass", tried_pass);
if (user)
{
if (res->error.Id() == NO_ERROR)
{
if (res->Rows())
{
/* We got a row in the result, this means there was a record for the oper..
* now we just need to check if their host matches, and if it does then
* oper them up.
*
* We now (previous versions of the module didn't) support multiple SQL
* rows per-oper in the same way the config file does, all rows will be tried
* until one is found which matches. This is useful to define several different
* hosts for a single oper.
*
* The for() loop works as SQLresult::GetRowMap() returns an empty map when there
* are no more rows to return.
*/
for (SQLfieldMap& row = res->GetRowMap(); row.size(); row = res->GetRowMap())
{
if (OperUser(user, row["username"].d, row["password"].d, row["hostname"].d, row["type"].d))
{
/* If/when one of the rows matches, stop checking and return */
return SQLSUCCESS;
}
if (tried_user && tried_pass)
{
LoginFail(user, tried_user, tried_pass);
free(tried_user);
free(tried_pass);
user->Shrink("oper_user");
user->Shrink("oper_pass");
}
}
}
else
{
/* No rows in result, this means there was no oper line for the user,
* we should have already checked the o:lines so now we need an
* "insufficient awesomeness" (invalid credentials) error
*/
if (tried_user && tried_pass)
{
LoginFail(user, tried_user, tried_pass);
free(tried_user);
free(tried_pass);
user->Shrink("oper_user");
user->Shrink("oper_pass");
}
}
}
else
{
/* This one shouldn't happen, the query failed for some reason.
* We have to fail the /oper request and give them the same error
* as above.
*/
if (tried_user && tried_pass)
{
LoginFail(user, tried_user, tried_pass);
free(tried_user);
free(tried_pass);
user->Shrink("oper_user");
user->Shrink("oper_pass");
}
}
}
return SQLSUCCESS;
}
return NULL;
}
void LoginFail(userrec* user, const std::string &username, const std::string &pass)
{
command_t* oper_command = ServerInstance->Parser->GetHandler("OPER");
if (oper_command)
{
const char* params[] = { username.c_str(), pass.c_str() };
oper_command->Handle(params, 2, user);
}
else
{
ServerInstance->Log(DEBUG, "BUG: WHAT?! Why do we have no OPER command?!");
}
}
bool OperUser(userrec* user, const std::string &username, const std::string &password, const std::string &pattern, const std::string &type)
{
ConfigReader Conf(ServerInstance);
for (int j = 0; j < Conf.Enumerate("type"); j++)
{
std::string tname = Conf.ReadValue("type","name",j);
std::string hostname(user->ident);
hostname.append("@").append(user->host);
if ((tname == type) && OneOfMatches(hostname.c_str(), user->GetIPString(), pattern.c_str()))
{
/* Opertype and host match, looks like this is it. */
std::string operhost = Conf.ReadValue("type", "host", j);
if (operhost.size())
user->ChangeDisplayedHost(operhost.c_str());
ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s", user->nick, user->ident, user->host, type.c_str());
user->WriteServ("381 %s :You are now an IRC operator of type %s", user->nick, type.c_str());
if (!user->modes[UM_OPERATOR])
user->Oper(type);
return true;
}
}
return false;
}
virtual Version GetVersion()
{
return Version(1,1,1,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSQLOper);
\ No newline at end of file diff --git a/src/modules/extra/m_sqlutils.cpp b/src/modules/extra/m_sqlutils.cpp index b470f99af..6cd09252b 100644 --- a/src/modules/extra/m_sqlutils.cpp +++ b/src/modules/extra/m_sqlutils.cpp @@ -1,238 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <sstream> -#include <list> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" -#include "m_sqlutils.h" - -/* $ModDesc: Provides some utilities to SQL client modules, such as mapping queries to users and channels */ -/* $ModDep: m_sqlutils.h */ - -typedef std::map<unsigned long, userrec*> IdUserMap; -typedef std::map<unsigned long, chanrec*> IdChanMap; -typedef std::list<unsigned long> AssocIdList; - -class ModuleSQLutils : public Module -{ -private: - IdUserMap iduser; - IdChanMap idchan; - -public: - ModuleSQLutils(InspIRCd* Me) - : Module::Module(Me) - { - ServerInstance->PublishInterface("SQLutils", this); - } - - virtual ~ModuleSQLutils() - { - ServerInstance->UnpublishInterface("SQLutils", this); - } - - void Implements(char* List) - { - List[I_OnChannelDelete] = List[I_OnUnloadModule] = List[I_OnRequest] = List[I_OnUserDisconnect] = 1; - } - - virtual char* OnRequest(Request* request) - { - if(strcmp(SQLUTILAU, request->GetId()) == 0) - { - AssociateUser* req = (AssociateUser*)request; - - iduser.insert(std::make_pair(req->id, req->user)); - - AttachList(req->user, req->id); - } - else if(strcmp(SQLUTILAC, request->GetId()) == 0) - { - AssociateChan* req = (AssociateChan*)request; - - idchan.insert(std::make_pair(req->id, req->chan)); - - AttachList(req->chan, req->id); - } - else if(strcmp(SQLUTILUA, request->GetId()) == 0) - { - UnAssociate* req = (UnAssociate*)request; - - /* Unassociate a given query ID with all users and channels - * it is associated with. - */ - - DoUnAssociate(iduser, req->id); - DoUnAssociate(idchan, req->id); - } - else if(strcmp(SQLUTILGU, request->GetId()) == 0) - { - GetAssocUser* req = (GetAssocUser*)request; - - IdUserMap::iterator iter = iduser.find(req->id); - - if(iter != iduser.end()) - { - req->user = iter->second; - } - } - else if(strcmp(SQLUTILGC, request->GetId()) == 0) - { - GetAssocChan* req = (GetAssocChan*)request; - - IdChanMap::iterator iter = idchan.find(req->id); - - if(iter != idchan.end()) - { - req->chan = iter->second; - } - } - - return SQLUTILSUCCESS; - } - - virtual void OnUserDisconnect(userrec* user) - { - /* A user is disconnecting, first we need to check if they have a list of queries associated with them. - * Then, if they do, we need to erase each of them from our IdUserMap (iduser) so when the module that - * associated them asks to look them up then it gets a NULL result and knows to discard the query. - */ - AssocIdList* il; - - if(user->GetExt("sqlutils_queryids", il)) - { - for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++) - { - IdUserMap::iterator iter; - - iter = iduser.find(*listiter); - - if(iter != iduser.end()) - { - if(iter->second != user) - { - ServerInstance->Log(DEBUG, "BUG: ID associated with user %s doesn't have the same userrec* associated with it in the map (erasing anyway)", user->nick); - } - - iduser.erase(iter); - } - else - { - ServerInstance->Log(DEBUG, "BUG: user %s was extended with sqlutils_queryids but there was nothing matching in the map", user->nick); - } - } - - user->Shrink("sqlutils_queryids"); - delete il; - } - } - - void AttachList(Extensible* obj, unsigned long id) - { - AssocIdList* il; - - if(!obj->GetExt("sqlutils_queryids", il)) - { - /* Doesn't already exist, create a new list and attach it. */ - il = new AssocIdList; - obj->Extend("sqlutils_queryids", il); - } - - /* Now either way we have a valid list in il, attached. */ - il->push_back(id); - } - - void RemoveFromList(Extensible* obj, unsigned long id) - { - AssocIdList* il; - - if(obj->GetExt("sqlutils_queryids", il)) - { - /* Only do anything if the list exists... (which it ought to) */ - il->remove(id); - - if(il->empty()) - { - /* If we just emptied it.. */ - delete il; - obj->Shrink("sqlutils_queryids"); - } - } - } - - template <class T> void DoUnAssociate(T &map, unsigned long id) - { - /* For each occurence of 'id' (well, only one..it's not a multimap) in 'map' - * remove it from the map, take an Extensible* value from the map and remove - * 'id' from the list of query IDs attached to it. - */ - typename T::iterator iter = map.find(id); - - if(iter != map.end()) - { - /* Found a value indexed by 'id', call RemoveFromList() - * on it with 'id' to remove 'id' from the list attached - * to the value. - */ - RemoveFromList(iter->second, id); - } - } - - virtual void OnChannelDelete(chanrec* chan) - { - /* A channel is being destroyed, first we need to check if it has a list of queries associated with it. - * Then, if it does, we need to erase each of them from our IdChanMap (idchan) so when the module that - * associated them asks to look them up then it gets a NULL result and knows to discard the query. - */ - AssocIdList* il; - - if(chan->GetExt("sqlutils_queryids", il)) - { - for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++) - { - IdChanMap::iterator iter; - - iter = idchan.find(*listiter); - - if(iter != idchan.end()) - { - if(iter->second != chan) - { - ServerInstance->Log(DEBUG, "BUG: ID associated with channel %s doesn't have the same chanrec* associated with it in the map (erasing anyway)", chan->name); - } - idchan.erase(iter); - } - else - { - ServerInstance->Log(DEBUG, "BUG: channel %s was extended with sqlutils_queryids but there was nothing matching in the map", chan->name); - } - } - - chan->Shrink("sqlutils_queryids"); - delete il; - } - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION); - } - -}; - -MODULE_INIT(ModuleSQLutils); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <sstream>
#include <list>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
#include "m_sqlutils.h"
/* $ModDesc: Provides some utilities to SQL client modules, such as mapping queries to users and channels */
/* $ModDep: m_sqlutils.h */
typedef std::map<unsigned long, userrec*> IdUserMap;
typedef std::map<unsigned long, chanrec*> IdChanMap;
typedef std::list<unsigned long> AssocIdList;
class ModuleSQLutils : public Module
{
private:
IdUserMap iduser;
IdChanMap idchan;
public:
ModuleSQLutils(InspIRCd* Me)
: Module::Module(Me)
{
ServerInstance->PublishInterface("SQLutils", this);
}
virtual ~ModuleSQLutils()
{
ServerInstance->UnpublishInterface("SQLutils", this);
}
void Implements(char* List)
{
List[I_OnChannelDelete] = List[I_OnUnloadModule] = List[I_OnRequest] = List[I_OnUserDisconnect] = 1;
}
virtual char* OnRequest(Request* request)
{
if(strcmp(SQLUTILAU, request->GetId()) == 0)
{
AssociateUser* req = (AssociateUser*)request;
iduser.insert(std::make_pair(req->id, req->user));
AttachList(req->user, req->id);
}
else if(strcmp(SQLUTILAC, request->GetId()) == 0)
{
AssociateChan* req = (AssociateChan*)request;
idchan.insert(std::make_pair(req->id, req->chan));
AttachList(req->chan, req->id);
}
else if(strcmp(SQLUTILUA, request->GetId()) == 0)
{
UnAssociate* req = (UnAssociate*)request;
/* Unassociate a given query ID with all users and channels
* it is associated with.
*/
DoUnAssociate(iduser, req->id);
DoUnAssociate(idchan, req->id);
}
else if(strcmp(SQLUTILGU, request->GetId()) == 0)
{
GetAssocUser* req = (GetAssocUser*)request;
IdUserMap::iterator iter = iduser.find(req->id);
if(iter != iduser.end())
{
req->user = iter->second;
}
}
else if(strcmp(SQLUTILGC, request->GetId()) == 0)
{
GetAssocChan* req = (GetAssocChan*)request;
IdChanMap::iterator iter = idchan.find(req->id);
if(iter != idchan.end())
{
req->chan = iter->second;
}
}
return SQLUTILSUCCESS;
}
virtual void OnUserDisconnect(userrec* user)
{
/* A user is disconnecting, first we need to check if they have a list of queries associated with them.
* Then, if they do, we need to erase each of them from our IdUserMap (iduser) so when the module that
* associated them asks to look them up then it gets a NULL result and knows to discard the query.
*/
AssocIdList* il;
if(user->GetExt("sqlutils_queryids", il))
{
for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)
{
IdUserMap::iterator iter;
iter = iduser.find(*listiter);
if(iter != iduser.end())
{
if(iter->second != user)
{
ServerInstance->Log(DEBUG, "BUG: ID associated with user %s doesn't have the same userrec* associated with it in the map (erasing anyway)", user->nick);
}
iduser.erase(iter);
}
else
{
ServerInstance->Log(DEBUG, "BUG: user %s was extended with sqlutils_queryids but there was nothing matching in the map", user->nick);
}
}
user->Shrink("sqlutils_queryids");
delete il;
}
}
void AttachList(Extensible* obj, unsigned long id)
{
AssocIdList* il;
if(!obj->GetExt("sqlutils_queryids", il))
{
/* Doesn't already exist, create a new list and attach it. */
il = new AssocIdList;
obj->Extend("sqlutils_queryids", il);
}
/* Now either way we have a valid list in il, attached. */
il->push_back(id);
}
void RemoveFromList(Extensible* obj, unsigned long id)
{
AssocIdList* il;
if(obj->GetExt("sqlutils_queryids", il))
{
/* Only do anything if the list exists... (which it ought to) */
il->remove(id);
if(il->empty())
{
/* If we just emptied it.. */
delete il;
obj->Shrink("sqlutils_queryids");
}
}
}
template <class T> void DoUnAssociate(T &map, unsigned long id)
{
/* For each occurence of 'id' (well, only one..it's not a multimap) in 'map'
* remove it from the map, take an Extensible* value from the map and remove
* 'id' from the list of query IDs attached to it.
*/
typename T::iterator iter = map.find(id);
if(iter != map.end())
{
/* Found a value indexed by 'id', call RemoveFromList()
* on it with 'id' to remove 'id' from the list attached
* to the value.
*/
RemoveFromList(iter->second, id);
}
}
virtual void OnChannelDelete(chanrec* chan)
{
/* A channel is being destroyed, first we need to check if it has a list of queries associated with it.
* Then, if it does, we need to erase each of them from our IdChanMap (idchan) so when the module that
* associated them asks to look them up then it gets a NULL result and knows to discard the query.
*/
AssocIdList* il;
if(chan->GetExt("sqlutils_queryids", il))
{
for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)
{
IdChanMap::iterator iter;
iter = idchan.find(*listiter);
if(iter != idchan.end())
{
if(iter->second != chan)
{
ServerInstance->Log(DEBUG, "BUG: ID associated with channel %s doesn't have the same chanrec* associated with it in the map (erasing anyway)", chan->name);
}
idchan.erase(iter);
}
else
{
ServerInstance->Log(DEBUG, "BUG: channel %s was extended with sqlutils_queryids but there was nothing matching in the map", chan->name);
}
}
chan->Shrink("sqlutils_queryids");
delete il;
}
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
}
};
MODULE_INIT(ModuleSQLutils);
\ No newline at end of file diff --git a/src/modules/extra/m_sqlutils.h b/src/modules/extra/m_sqlutils.h index 92fbdf5c7..cdde51f67 100644 --- a/src/modules/extra/m_sqlutils.h +++ b/src/modules/extra/m_sqlutils.h @@ -1,143 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef INSPIRCD_SQLUTILS -#define INSPIRCD_SQLUTILS - -#include "modules.h" - -#define SQLUTILAU "SQLutil AssociateUser" -#define SQLUTILAC "SQLutil AssociateChan" -#define SQLUTILUA "SQLutil UnAssociate" -#define SQLUTILGU "SQLutil GetAssocUser" -#define SQLUTILGC "SQLutil GetAssocChan" -#define SQLUTILSUCCESS "You shouldn't be reading this (success)" - -/** Used to associate an SQL query with a user - */ -class AssociateUser : public Request -{ -public: - /** Query ID - */ - unsigned long id; - /** User - */ - userrec* user; - - AssociateUser(Module* s, Module* d, unsigned long i, userrec* u) - : Request(s, d, SQLUTILAU), id(i), user(u) - { - } - - AssociateUser& S() - { - Send(); - return *this; - } -}; - -/** Used to associate an SQL query with a channel - */ -class AssociateChan : public Request -{ -public: - /** Query ID - */ - unsigned long id; - /** Channel - */ - chanrec* chan; - - AssociateChan(Module* s, Module* d, unsigned long i, chanrec* u) - : Request(s, d, SQLUTILAC), id(i), chan(u) - { - } - - AssociateChan& S() - { - Send(); - return *this; - } -}; - -/** Unassociate a user or class from an SQL query - */ -class UnAssociate : public Request -{ -public: - /** The query ID - */ - unsigned long id; - - UnAssociate(Module* s, Module* d, unsigned long i) - : Request(s, d, SQLUTILUA), id(i) - { - } - - UnAssociate& S() - { - Send(); - return *this; - } -}; - -/** Get the user associated with an SQL query ID - */ -class GetAssocUser : public Request -{ -public: - /** The query id - */ - unsigned long id; - /** The user - */ - userrec* user; - - GetAssocUser(Module* s, Module* d, unsigned long i) - : Request(s, d, SQLUTILGU), id(i), user(NULL) - { - } - - GetAssocUser& S() - { - Send(); - return *this; - } -}; - -/** Get the channel associated with an SQL query ID - */ -class GetAssocChan : public Request -{ -public: - /** The query id - */ - unsigned long id; - /** The channel - */ - chanrec* chan; - - GetAssocChan(Module* s, Module* d, unsigned long i) - : Request(s, d, SQLUTILGC), id(i), chan(NULL) - { - } - - GetAssocChan& S() - { - Send(); - return *this; - } -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef INSPIRCD_SQLUTILS
#define INSPIRCD_SQLUTILS
#include "modules.h"
#define SQLUTILAU "SQLutil AssociateUser"
#define SQLUTILAC "SQLutil AssociateChan"
#define SQLUTILUA "SQLutil UnAssociate"
#define SQLUTILGU "SQLutil GetAssocUser"
#define SQLUTILGC "SQLutil GetAssocChan"
#define SQLUTILSUCCESS "You shouldn't be reading this (success)"
/** Used to associate an SQL query with a user
*/
class AssociateUser : public Request
{
public:
/** Query ID
*/
unsigned long id;
/** User
*/
userrec* user;
AssociateUser(Module* s, Module* d, unsigned long i, userrec* u)
: Request(s, d, SQLUTILAU), id(i), user(u)
{
}
AssociateUser& S()
{
Send();
return *this;
}
};
/** Used to associate an SQL query with a channel
*/
class AssociateChan : public Request
{
public:
/** Query ID
*/
unsigned long id;
/** Channel
*/
chanrec* chan;
AssociateChan(Module* s, Module* d, unsigned long i, chanrec* u)
: Request(s, d, SQLUTILAC), id(i), chan(u)
{
}
AssociateChan& S()
{
Send();
return *this;
}
};
/** Unassociate a user or class from an SQL query
*/
class UnAssociate : public Request
{
public:
/** The query ID
*/
unsigned long id;
UnAssociate(Module* s, Module* d, unsigned long i)
: Request(s, d, SQLUTILUA), id(i)
{
}
UnAssociate& S()
{
Send();
return *this;
}
};
/** Get the user associated with an SQL query ID
*/
class GetAssocUser : public Request
{
public:
/** The query id
*/
unsigned long id;
/** The user
*/
userrec* user;
GetAssocUser(Module* s, Module* d, unsigned long i)
: Request(s, d, SQLUTILGU), id(i), user(NULL)
{
}
GetAssocUser& S()
{
Send();
return *this;
}
};
/** Get the channel associated with an SQL query ID
*/
class GetAssocChan : public Request
{
public:
/** The query id
*/
unsigned long id;
/** The channel
*/
chanrec* chan;
GetAssocChan(Module* s, Module* d, unsigned long i)
: Request(s, d, SQLUTILGC), id(i), chan(NULL)
{
}
GetAssocChan& S()
{
Send();
return *this;
}
};
#endif
\ No newline at end of file diff --git a/src/modules/extra/m_sqlv2.h b/src/modules/extra/m_sqlv2.h index c7f6edbb9..decac4b57 100644 --- a/src/modules/extra/m_sqlv2.h +++ b/src/modules/extra/m_sqlv2.h @@ -1,605 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef INSPIRCD_SQLAPI_2 -#define INSPIRCD_SQLAPI_2 - -#include <string> -#include <deque> -#include <map> -#include "modules.h" - -/** SQLreq define. - * This is the voodoo magic which lets us pass multiple - * parameters to the SQLrequest constructor... voodoo... - */ -#define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e)) - -/** Identifiers used to identify Request types - */ -#define SQLREQID "SQLv2 Request" -#define SQLRESID "SQLv2 Result" -#define SQLSUCCESS "You shouldn't be reading this (success)" - -/** Defines the error types which SQLerror may be set to - */ -enum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL }; - -/** A list of format parameters for an SQLquery object. - */ -typedef std::deque<std::string> ParamL; - -/** The base class of SQL exceptions - */ -class SQLexception : public ModuleException -{ - public: - SQLexception(const std::string &reason) : ModuleException(reason) - { - } - - SQLexception() : ModuleException("SQLv2: Undefined exception") - { - } -}; - -/** An exception thrown when a bad column or row name or id is requested - */ -class SQLbadColName : public SQLexception -{ -public: - SQLbadColName() : SQLexception("SQLv2: Bad column name") - { - } -}; - -/** SQLerror holds the error state of any SQLrequest or SQLresult. - * The error string varies from database software to database software - * and should be used to display informational error messages to users. - */ -class SQLerror : public classbase -{ - /** The error id - */ - SQLerrorNum id; - /** The error string - */ - std::string str; -public: - /** Initialize an SQLerror - * @param i The error ID to set - * @param s The (optional) error string to set - */ - SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "") - : id(i), str(s) - { - } - - /** Return the ID of the error - */ - SQLerrorNum Id() - { - return id; - } - - /** Set the ID of an error - * @param i The new error ID to set - * @return the ID which was set - */ - SQLerrorNum Id(SQLerrorNum i) - { - id = i; - return id; - } - - /** Set the error string for an error - * @param s The new error string to set - */ - void Str(const std::string &s) - { - str = s; - } - - /** Return the error string for an error - */ - const char* Str() - { - if(str.length()) - return str.c_str(); - - switch(id) - { - case NO_ERROR: - return "No error"; - case BAD_DBID: - return "Invalid database ID"; - case BAD_CONN: - return "Invalid connection"; - case QSEND_FAIL: - return "Sending query failed"; - case QREPLY_FAIL: - return "Getting query result failed"; - default: - return "Unknown error"; - } - } -}; - -/** SQLquery provides a way to represent a query string, and its parameters in a type-safe way. - * C++ has no native type-safe way of having a variable number of arguments to a function, - * the workaround for this isn't easy to describe simply, but in a nutshell what's really - * happening when - from the above example - you do this: - * - * SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42"); - * - * what's actually happening is functionally this: - * - * SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42")); - * - * with 'query()' returning a reference to an object with a 'addparam()' member function which - * in turn returns a reference to that object. There are actually four ways you can create a - * SQLrequest..all have their disadvantages and advantages. In the real implementations the - * 'query()' function is replaced by the constructor of another class 'SQLquery' which holds - * the query string and a ParamL (std::deque<std::string>) of query parameters. - * This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is: - * - * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter)); - */ -class SQLquery : public classbase -{ -public: - /** The query 'format string' - */ - std::string q; - /** The query parameter list - * There should be one parameter for every ? character - * within the format string shown above. - */ - ParamL p; - - /** Initialize an SQLquery with a given format string only - */ - SQLquery(const std::string &query) - : q(query) - { - } - - /** Initialize an SQLquery with a format string and parameters. - * If you provide parameters, you must initialize the list yourself - * if you choose to do it via this method, using std::deque::push_back(). - */ - SQLquery(const std::string &query, const ParamL ¶ms) - : q(query), p(params) - { - } - - /** An overloaded operator for pushing parameters onto the parameter list - */ - template<typename T> SQLquery& operator,(const T &foo) - { - p.push_back(ConvToStr(foo)); - return *this; - } - - /** An overloaded operator for pushing parameters onto the parameter list. - * This has higher precedence than 'operator,' and can save on parenthesis. - */ - template<typename T> SQLquery& operator%(const T &foo) - { - p.push_back(ConvToStr(foo)); - return *this; - } -}; - -/** SQLrequest is sent to the SQL API to command it to run a query and return the result. - * You must instantiate this object with a valid SQLquery object and its parameters, then - * send it using its Send() method to the module providing the 'SQL' feature. To find this - * module, use Server::FindFeature(). - */ -class SQLrequest : public Request -{ -public: - /** The fully parsed and expanded query string - * This is initialized from the SQLquery parameter given in the constructor. - */ - SQLquery query; - /** The database ID to apply the request to - */ - std::string dbid; - /** True if this is a priority query. - * Priority queries may 'queue jump' in the request queue. - */ - bool pri; - /** The query ID, assigned by the SQL api. - * After your request is processed, this will - * be initialized for you by the API to a valid request ID, - * except in the case of an error. - */ - unsigned long id; - /** If an error occured, error.id will be any other value than NO_ERROR. - */ - SQLerror error; - - /** Initialize an SQLrequest. - * For example: - * - * SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick); - * - * @param s A pointer to the sending module, where the result should be routed - * @param d A pointer to the receiving module, identified as implementing the 'SQL' feature - * @param databaseid The database ID to perform the query on. This must match a valid - * database ID from the configuration of the SQL module. - * @param q A properly initialized SQLquery object. - */ - SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q) - : Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0) - { - } - - /** Set the priority of a request. - */ - void Priority(bool p = true) - { - pri = p; - } - - /** Set the source of a request. You should not need to use this method. - */ - void SetSource(Module* mod) - { - source = mod; - } -}; - -/** - * This class contains a field's data plus a way to determine if the field - * is NULL or not without having to mess around with NULL pointers. - */ -class SQLfield -{ -public: - /** - * The data itself - */ - std::string d; - - /** - * If the field was null - */ - bool null; - - /** Initialize an SQLfield - */ - SQLfield(const std::string &data = "", bool n = false) - : d(data), null(n) - { - - } -}; - -/** A list of items which make up a row of a result or table (tuple) - * This does not include field names. - */ -typedef std::vector<SQLfield> SQLfieldList; -/** A list of items which make up a row of a result or table (tuple) - * This also includes the field names. - */ -typedef std::map<std::string, SQLfield> SQLfieldMap; - -/** SQLresult is a reply to a previous query. - * If you send a query to the SQL api, the response will arrive at your - * OnRequest method of your module at some later time, depending on the - * congestion of the SQL server and complexity of the query. The ID of - * this result will match the ID assigned to your original request. - * SQLresult contains its own internal cursor (row counter) which is - * incremented with each method call which retrieves a single row. - */ -class SQLresult : public Request -{ -public: - /** The original query string passed initially to the SQL API - */ - std::string query; - /** The database ID the query was executed on - */ - std::string dbid; - /** - * The error (if any) which occured. - * If an error occured the value of error.id will be any - * other value than NO_ERROR. - */ - SQLerror error; - /** - * This will match query ID you were given when sending - * the request at an earlier time. - */ - unsigned long id; - - /** Used by the SQL API to instantiate an SQLrequest - */ - SQLresult(Module* s, Module* d, unsigned long i) - : Request(s, d, SQLRESID), id(i) - { - } - - /** - * Return the number of rows in the result - * Note that if you have perfomed an INSERT - * or UPDATE query or other query which will - * not return rows, this will return the - * number of affected rows, and SQLresult::Cols() - * will contain 0. In this case you SHOULD NEVER - * access any of the result set rows, as there arent any! - * @returns Number of rows in the result set. - */ - virtual int Rows() = 0; - - /** - * Return the number of columns in the result. - * If you performed an UPDATE or INSERT which - * does not return a dataset, this value will - * be 0. - * @returns Number of columns in the result set. - */ - virtual int Cols() = 0; - - /** - * Get a string name of the column by an index number - * @param column The id number of a column - * @returns The column name associated with the given ID - */ - virtual std::string ColName(int column) = 0; - - /** - * Get an index number for a column from a string name. - * An exception of type SQLbadColName will be thrown if - * the name given is invalid. - * @param column The column name to get the ID of - * @returns The ID number of the column provided - */ - virtual int ColNum(const std::string &column) = 0; - - /** - * Get a string value in a given row and column - * This does not effect the internal cursor. - * @returns The value stored at [row,column] in the table - */ - virtual SQLfield GetValue(int row, int column) = 0; - - /** - * Return a list of values in a row, this should - * increment an internal counter so you can repeatedly - * call it until it returns an empty vector. - * This returns a reference to an internal object, - * the same object is used for all calls to this function - * and therefore the return value is only valid until - * you call this function again. It is also invalid if - * the SQLresult object is destroyed. - * The internal cursor (row counter) is incremented by one. - * @returns A reference to the current row's SQLfieldList - */ - virtual SQLfieldList& GetRow() = 0; - - /** - * As above, but return a map indexed by key name. - * The internal cursor (row counter) is incremented by one. - * @returns A reference to the current row's SQLfieldMap - */ - virtual SQLfieldMap& GetRowMap() = 0; - - /** - * Like GetRow(), but returns a pointer to a dynamically - * allocated object which must be explicitly freed. For - * portability reasons this must be freed with SQLresult::Free() - * The internal cursor (row counter) is incremented by one. - * @returns A newly-allocated SQLfieldList - */ - virtual SQLfieldList* GetRowPtr() = 0; - - /** - * As above, but return a map indexed by key name - * The internal cursor (row counter) is incremented by one. - * @returns A newly-allocated SQLfieldMap - */ - virtual SQLfieldMap* GetRowMapPtr() = 0; - - /** - * Overloaded function for freeing the lists and maps - * returned by GetRowPtr or GetRowMapPtr. - * @param fm The SQLfieldMap to free - */ - virtual void Free(SQLfieldMap* fm) = 0; - - /** - * Overloaded function for freeing the lists and maps - * returned by GetRowPtr or GetRowMapPtr. - * @param fl The SQLfieldList to free - */ - virtual void Free(SQLfieldList* fl) = 0; -}; - - -/** SQLHost represents a <database> config line and is useful - * for storing in a map and iterating on rehash to see which - * <database> tags was added/removed/unchanged. - */ -class SQLhost -{ - public: - std::string id; /* Database handle id */ - std::string host; /* Database server hostname */ - std::string ip; /* resolved IP, needed for at least pgsql.so */ - unsigned int port; /* Database server port */ - std::string name; /* Database name */ - std::string user; /* Database username */ - std::string pass; /* Database password */ - bool ssl; /* If we should require SSL */ - - SQLhost() - { - } - - SQLhost(const std::string& i, const std::string& h, unsigned int p, const std::string& n, const std::string& u, const std::string& pa, bool s) - : id(i), host(h), port(p), name(n), user(u), pass(pa), ssl(s) - { - } - - /** Overload this to return a correct Data source Name (DSN) for - * the current SQL module. - */ - std::string GetDSN(); -}; - -/** Overload operator== for two SQLhost objects for easy comparison. - */ -bool operator== (const SQLhost& l, const SQLhost& r) -{ - return (l.id == r.id && l.host == r.host && l.port == r.port && l.name == r.name && l.user == l.user && l.pass == r.pass && l.ssl == r.ssl); -} - - -/** QueryQueue, a queue of queries waiting to be executed. - * This maintains two queues internally, one for 'priority' - * queries and one for less important ones. Each queue has - * new queries appended to it and ones to execute are popped - * off the front. This keeps them flowing round nicely and no - * query should ever get 'stuck' for too long. If there are - * queries in the priority queue they will be executed first, - * 'unimportant' queries will only be executed when the - * priority queue is empty. - * - * We store lists of SQLrequest's here, by value as we want to avoid storing - * any data allocated inside the client module (in case that module is unloaded - * while the query is in progress). - * - * Because we want to work on the current SQLrequest in-situ, we need a way - * of accessing the request we are currently processing, QueryQueue::front(), - * but that call needs to always return the same request until that request - * is removed from the queue, this is what the 'which' variable is. New queries are - * always added to the back of one of the two queues, but if when front() - * is first called then the priority queue is empty then front() will return - * a query from the normal queue, but if a query is then added to the priority - * queue then front() must continue to return the front of the *normal* queue - * until pop() is called. - */ - -class QueryQueue : public classbase -{ -private: - typedef std::deque<SQLrequest> ReqDeque; - - ReqDeque priority; /* The priority queue */ - ReqDeque normal; /* The 'normal' queue */ - enum { PRI, NOR, NON } which; /* Which queue the currently active element is at the front of */ - -public: - QueryQueue() - : which(NON) - { - } - - void push(const SQLrequest &q) - { - if(q.pri) - priority.push_back(q); - else - normal.push_back(q); - } - - void pop() - { - if((which == PRI) && priority.size()) - { - priority.pop_front(); - } - else if((which == NOR) && normal.size()) - { - normal.pop_front(); - } - - /* Reset this */ - which = NON; - - /* Silently do nothing if there was no element to pop() */ - } - - SQLrequest& front() - { - switch(which) - { - case PRI: - return priority.front(); - case NOR: - return normal.front(); - default: - if(priority.size()) - { - which = PRI; - return priority.front(); - } - - if(normal.size()) - { - which = NOR; - return normal.front(); - } - - /* This will probably result in a segfault, - * but the caller should have checked totalsize() - * first so..meh - moron :p - */ - - return priority.front(); - } - } - - std::pair<int, int> size() - { - return std::make_pair(priority.size(), normal.size()); - } - - int totalsize() - { - return priority.size() + normal.size(); - } - - void PurgeModule(Module* mod) - { - DoPurgeModule(mod, priority); - DoPurgeModule(mod, normal); - } - -private: - void DoPurgeModule(Module* mod, ReqDeque& q) - { - for(ReqDeque::iterator iter = q.begin(); iter != q.end(); iter++) - { - if(iter->GetSource() == mod) - { - if(iter->id == front().id) - { - /* It's the currently active query.. :x */ - iter->SetSource(NULL); - } - else - { - /* It hasn't been executed yet..just remove it */ - iter = q.erase(iter); - } - } - } - } -}; - - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef INSPIRCD_SQLAPI_2
#define INSPIRCD_SQLAPI_2
#include <string>
#include <deque>
#include <map>
#include "modules.h"
/** SQLreq define.
* This is the voodoo magic which lets us pass multiple
* parameters to the SQLrequest constructor... voodoo...
*/
#define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e))
/** Identifiers used to identify Request types
*/
#define SQLREQID "SQLv2 Request"
#define SQLRESID "SQLv2 Result"
#define SQLSUCCESS "You shouldn't be reading this (success)"
/** Defines the error types which SQLerror may be set to
*/
enum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL };
/** A list of format parameters for an SQLquery object.
*/
typedef std::deque<std::string> ParamL;
/** The base class of SQL exceptions
*/
class SQLexception : public ModuleException
{
public:
SQLexception(const std::string &reason) : ModuleException(reason)
{
}
SQLexception() : ModuleException("SQLv2: Undefined exception")
{
}
};
/** An exception thrown when a bad column or row name or id is requested
*/
class SQLbadColName : public SQLexception
{
public:
SQLbadColName() : SQLexception("SQLv2: Bad column name")
{
}
};
/** SQLerror holds the error state of any SQLrequest or SQLresult.
* The error string varies from database software to database software
* and should be used to display informational error messages to users.
*/
class SQLerror : public classbase
{
/** The error id
*/
SQLerrorNum id;
/** The error string
*/
std::string str;
public:
/** Initialize an SQLerror
* @param i The error ID to set
* @param s The (optional) error string to set
*/
SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "")
: id(i), str(s)
{
}
/** Return the ID of the error
*/
SQLerrorNum Id()
{
return id;
}
/** Set the ID of an error
* @param i The new error ID to set
* @return the ID which was set
*/
SQLerrorNum Id(SQLerrorNum i)
{
id = i;
return id;
}
/** Set the error string for an error
* @param s The new error string to set
*/
void Str(const std::string &s)
{
str = s;
}
/** Return the error string for an error
*/
const char* Str()
{
if(str.length())
return str.c_str();
switch(id)
{
case NO_ERROR:
return "No error";
case BAD_DBID:
return "Invalid database ID";
case BAD_CONN:
return "Invalid connection";
case QSEND_FAIL:
return "Sending query failed";
case QREPLY_FAIL:
return "Getting query result failed";
default:
return "Unknown error";
}
}
};
/** SQLquery provides a way to represent a query string, and its parameters in a type-safe way.
* C++ has no native type-safe way of having a variable number of arguments to a function,
* the workaround for this isn't easy to describe simply, but in a nutshell what's really
* happening when - from the above example - you do this:
*
* SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42");
*
* what's actually happening is functionally this:
*
* SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42"));
*
* with 'query()' returning a reference to an object with a 'addparam()' member function which
* in turn returns a reference to that object. There are actually four ways you can create a
* SQLrequest..all have their disadvantages and advantages. In the real implementations the
* 'query()' function is replaced by the constructor of another class 'SQLquery' which holds
* the query string and a ParamL (std::deque<std::string>) of query parameters.
* This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is:
*
* SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter));
*/
class SQLquery : public classbase
{
public:
/** The query 'format string'
*/
std::string q;
/** The query parameter list
* There should be one parameter for every ? character
* within the format string shown above.
*/
ParamL p;
/** Initialize an SQLquery with a given format string only
*/
SQLquery(const std::string &query)
: q(query)
{
}
/** Initialize an SQLquery with a format string and parameters.
* If you provide parameters, you must initialize the list yourself
* if you choose to do it via this method, using std::deque::push_back().
*/
SQLquery(const std::string &query, const ParamL ¶ms)
: q(query), p(params)
{
}
/** An overloaded operator for pushing parameters onto the parameter list
*/
template<typename T> SQLquery& operator,(const T &foo)
{
p.push_back(ConvToStr(foo));
return *this;
}
/** An overloaded operator for pushing parameters onto the parameter list.
* This has higher precedence than 'operator,' and can save on parenthesis.
*/
template<typename T> SQLquery& operator%(const T &foo)
{
p.push_back(ConvToStr(foo));
return *this;
}
};
/** SQLrequest is sent to the SQL API to command it to run a query and return the result.
* You must instantiate this object with a valid SQLquery object and its parameters, then
* send it using its Send() method to the module providing the 'SQL' feature. To find this
* module, use Server::FindFeature().
*/
class SQLrequest : public Request
{
public:
/** The fully parsed and expanded query string
* This is initialized from the SQLquery parameter given in the constructor.
*/
SQLquery query;
/** The database ID to apply the request to
*/
std::string dbid;
/** True if this is a priority query.
* Priority queries may 'queue jump' in the request queue.
*/
bool pri;
/** The query ID, assigned by the SQL api.
* After your request is processed, this will
* be initialized for you by the API to a valid request ID,
* except in the case of an error.
*/
unsigned long id;
/** If an error occured, error.id will be any other value than NO_ERROR.
*/
SQLerror error;
/** Initialize an SQLrequest.
* For example:
*
* SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick);
*
* @param s A pointer to the sending module, where the result should be routed
* @param d A pointer to the receiving module, identified as implementing the 'SQL' feature
* @param databaseid The database ID to perform the query on. This must match a valid
* database ID from the configuration of the SQL module.
* @param q A properly initialized SQLquery object.
*/
SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q)
: Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0)
{
}
/** Set the priority of a request.
*/
void Priority(bool p = true)
{
pri = p;
}
/** Set the source of a request. You should not need to use this method.
*/
void SetSource(Module* mod)
{
source = mod;
}
};
/**
* This class contains a field's data plus a way to determine if the field
* is NULL or not without having to mess around with NULL pointers.
*/
class SQLfield
{
public:
/**
* The data itself
*/
std::string d;
/**
* If the field was null
*/
bool null;
/** Initialize an SQLfield
*/
SQLfield(const std::string &data = "", bool n = false)
: d(data), null(n)
{
}
};
/** A list of items which make up a row of a result or table (tuple)
* This does not include field names.
*/
typedef std::vector<SQLfield> SQLfieldList;
/** A list of items which make up a row of a result or table (tuple)
* This also includes the field names.
*/
typedef std::map<std::string, SQLfield> SQLfieldMap;
/** SQLresult is a reply to a previous query.
* If you send a query to the SQL api, the response will arrive at your
* OnRequest method of your module at some later time, depending on the
* congestion of the SQL server and complexity of the query. The ID of
* this result will match the ID assigned to your original request.
* SQLresult contains its own internal cursor (row counter) which is
* incremented with each method call which retrieves a single row.
*/
class SQLresult : public Request
{
public:
/** The original query string passed initially to the SQL API
*/
std::string query;
/** The database ID the query was executed on
*/
std::string dbid;
/**
* The error (if any) which occured.
* If an error occured the value of error.id will be any
* other value than NO_ERROR.
*/
SQLerror error;
/**
* This will match query ID you were given when sending
* the request at an earlier time.
*/
unsigned long id;
/** Used by the SQL API to instantiate an SQLrequest
*/
SQLresult(Module* s, Module* d, unsigned long i)
: Request(s, d, SQLRESID), id(i)
{
}
/**
* Return the number of rows in the result
* Note that if you have perfomed an INSERT
* or UPDATE query or other query which will
* not return rows, this will return the
* number of affected rows, and SQLresult::Cols()
* will contain 0. In this case you SHOULD NEVER
* access any of the result set rows, as there arent any!
* @returns Number of rows in the result set.
*/
virtual int Rows() = 0;
/**
* Return the number of columns in the result.
* If you performed an UPDATE or INSERT which
* does not return a dataset, this value will
* be 0.
* @returns Number of columns in the result set.
*/
virtual int Cols() = 0;
/**
* Get a string name of the column by an index number
* @param column The id number of a column
* @returns The column name associated with the given ID
*/
virtual std::string ColName(int column) = 0;
/**
* Get an index number for a column from a string name.
* An exception of type SQLbadColName will be thrown if
* the name given is invalid.
* @param column The column name to get the ID of
* @returns The ID number of the column provided
*/
virtual int ColNum(const std::string &column) = 0;
/**
* Get a string value in a given row and column
* This does not effect the internal cursor.
* @returns The value stored at [row,column] in the table
*/
virtual SQLfield GetValue(int row, int column) = 0;
/**
* Return a list of values in a row, this should
* increment an internal counter so you can repeatedly
* call it until it returns an empty vector.
* This returns a reference to an internal object,
* the same object is used for all calls to this function
* and therefore the return value is only valid until
* you call this function again. It is also invalid if
* the SQLresult object is destroyed.
* The internal cursor (row counter) is incremented by one.
* @returns A reference to the current row's SQLfieldList
*/
virtual SQLfieldList& GetRow() = 0;
/**
* As above, but return a map indexed by key name.
* The internal cursor (row counter) is incremented by one.
* @returns A reference to the current row's SQLfieldMap
*/
virtual SQLfieldMap& GetRowMap() = 0;
/**
* Like GetRow(), but returns a pointer to a dynamically
* allocated object which must be explicitly freed. For
* portability reasons this must be freed with SQLresult::Free()
* The internal cursor (row counter) is incremented by one.
* @returns A newly-allocated SQLfieldList
*/
virtual SQLfieldList* GetRowPtr() = 0;
/**
* As above, but return a map indexed by key name
* The internal cursor (row counter) is incremented by one.
* @returns A newly-allocated SQLfieldMap
*/
virtual SQLfieldMap* GetRowMapPtr() = 0;
/**
* Overloaded function for freeing the lists and maps
* returned by GetRowPtr or GetRowMapPtr.
* @param fm The SQLfieldMap to free
*/
virtual void Free(SQLfieldMap* fm) = 0;
/**
* Overloaded function for freeing the lists and maps
* returned by GetRowPtr or GetRowMapPtr.
* @param fl The SQLfieldList to free
*/
virtual void Free(SQLfieldList* fl) = 0;
};
/** SQLHost represents a <database> config line and is useful
* for storing in a map and iterating on rehash to see which
* <database> tags was added/removed/unchanged.
*/
class SQLhost
{
public:
std::string id; /* Database handle id */
std::string host; /* Database server hostname */
std::string ip; /* resolved IP, needed for at least pgsql.so */
unsigned int port; /* Database server port */
std::string name; /* Database name */
std::string user; /* Database username */
std::string pass; /* Database password */
bool ssl; /* If we should require SSL */
SQLhost()
{
}
SQLhost(const std::string& i, const std::string& h, unsigned int p, const std::string& n, const std::string& u, const std::string& pa, bool s)
: id(i), host(h), port(p), name(n), user(u), pass(pa), ssl(s)
{
}
/** Overload this to return a correct Data source Name (DSN) for
* the current SQL module.
*/
std::string GetDSN();
};
/** Overload operator== for two SQLhost objects for easy comparison.
*/
bool operator== (const SQLhost& l, const SQLhost& r)
{
return (l.id == r.id && l.host == r.host && l.port == r.port && l.name == r.name && l.user == l.user && l.pass == r.pass && l.ssl == r.ssl);
}
/** QueryQueue, a queue of queries waiting to be executed.
* This maintains two queues internally, one for 'priority'
* queries and one for less important ones. Each queue has
* new queries appended to it and ones to execute are popped
* off the front. This keeps them flowing round nicely and no
* query should ever get 'stuck' for too long. If there are
* queries in the priority queue they will be executed first,
* 'unimportant' queries will only be executed when the
* priority queue is empty.
*
* We store lists of SQLrequest's here, by value as we want to avoid storing
* any data allocated inside the client module (in case that module is unloaded
* while the query is in progress).
*
* Because we want to work on the current SQLrequest in-situ, we need a way
* of accessing the request we are currently processing, QueryQueue::front(),
* but that call needs to always return the same request until that request
* is removed from the queue, this is what the 'which' variable is. New queries are
* always added to the back of one of the two queues, but if when front()
* is first called then the priority queue is empty then front() will return
* a query from the normal queue, but if a query is then added to the priority
* queue then front() must continue to return the front of the *normal* queue
* until pop() is called.
*/
class QueryQueue : public classbase
{
private:
typedef std::deque<SQLrequest> ReqDeque;
ReqDeque priority; /* The priority queue */
ReqDeque normal; /* The 'normal' queue */
enum { PRI, NOR, NON } which; /* Which queue the currently active element is at the front of */
public:
QueryQueue()
: which(NON)
{
}
void push(const SQLrequest &q)
{
if(q.pri)
priority.push_back(q);
else
normal.push_back(q);
}
void pop()
{
if((which == PRI) && priority.size())
{
priority.pop_front();
}
else if((which == NOR) && normal.size())
{
normal.pop_front();
}
/* Reset this */
which = NON;
/* Silently do nothing if there was no element to pop() */
}
SQLrequest& front()
{
switch(which)
{
case PRI:
return priority.front();
case NOR:
return normal.front();
default:
if(priority.size())
{
which = PRI;
return priority.front();
}
if(normal.size())
{
which = NOR;
return normal.front();
}
/* This will probably result in a segfault,
* but the caller should have checked totalsize()
* first so..meh - moron :p
*/
return priority.front();
}
}
std::pair<int, int> size()
{
return std::make_pair(priority.size(), normal.size());
}
int totalsize()
{
return priority.size() + normal.size();
}
void PurgeModule(Module* mod)
{
DoPurgeModule(mod, priority);
DoPurgeModule(mod, normal);
}
private:
void DoPurgeModule(Module* mod, ReqDeque& q)
{
for(ReqDeque::iterator iter = q.begin(); iter != q.end(); iter++)
{
if(iter->GetSource() == mod)
{
if(iter->id == front().id)
{
/* It's the currently active query.. :x */
iter->SetSource(NULL);
}
else
{
/* It hasn't been executed yet..just remove it */
iter = q.erase(iter);
}
}
}
}
};
#endif
\ No newline at end of file diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index fd8b12d32..037d2cf72 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -1,843 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" - -#include <gnutls/gnutls.h> -#include <gnutls/x509.h> - -#include "inspircd_config.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "socket.h" -#include "hashcomp.h" -#include "transport.h" - -#ifdef WINDOWS -#pragma comment(lib, "libgnutls-13.lib") -#undef MAX_DESCRIPTORS -#define MAX_DESCRIPTORS 10000 -#endif - -/* $ModDesc: Provides SSL support for clients */ -/* $CompileFlags: exec("libgnutls-config --cflags") */ -/* $LinkerFlags: rpath("libgnutls-config --libs") exec("libgnutls-config --libs") */ -/* $ModDep: transport.h */ - - -enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED }; - -bool isin(int port, const std::vector<int> &portlist) -{ - for(unsigned int i = 0; i < portlist.size(); i++) - if(portlist[i] == port) - return true; - - return false; -} - -/** Represents an SSL user's extra data - */ -class issl_session : public classbase -{ -public: - gnutls_session_t sess; - issl_status status; - std::string outbuf; - int inbufoffset; - char* inbuf; - int fd; -}; - -class ModuleSSLGnuTLS : public Module -{ - - ConfigReader* Conf; - - char* dummy; - - std::vector<int> listenports; - - int inbufsize; - issl_session sessions[MAX_DESCRIPTORS]; - - gnutls_certificate_credentials x509_cred; - gnutls_dh_params dh_params; - - std::string keyfile; - std::string certfile; - std::string cafile; - std::string crlfile; - std::string sslports; - int dh_bits; - - int clientactive; - - public: - - ModuleSSLGnuTLS(InspIRCd* Me) - : Module(Me) - { - ServerInstance->PublishInterface("InspSocketHook", this); - - // Not rehashable...because I cba to reduce all the sizes of existing buffers. - inbufsize = ServerInstance->Config->NetBufferSize; - - gnutls_global_init(); // This must be called once in the program - - if(gnutls_certificate_allocate_credentials(&x509_cred) != 0) - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to allocate certificate credentials"); - - // Guessing return meaning - if(gnutls_dh_params_init(&dh_params) < 0) - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters"); - - // Needs the flag as it ignores a plain /rehash - OnRehash(NULL,"ssl"); - - // Void return, guess we assume success - gnutls_certificate_set_dh_params(x509_cred, dh_params); - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - if(param != "ssl") - return; - - Conf = new ConfigReader(ServerInstance); - - for(unsigned int i = 0; i < listenports.size(); i++) - { - ServerInstance->Config->DelIOHook(listenports[i]); - } - - listenports.clear(); - clientactive = 0; - sslports.clear(); - - for(int i = 0; i < Conf->Enumerate("bind"); i++) - { - // For each <bind> tag - std::string x = Conf->ReadValue("bind", "type", i); - if(((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "gnutls")) - { - // Get the port we're meant to be listening on with SSL - std::string port = Conf->ReadValue("bind", "port", i); - irc::portparser portrange(port, false); - long portno = -1; - while ((portno = portrange.GetToken())) - { - clientactive++; - try - { - if (ServerInstance->Config->AddIOHook(portno, this)) - { - listenports.push_back(portno); - for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++) - if (ServerInstance->Config->ports[i]->GetPort() == portno) - ServerInstance->Config->ports[i]->SetDescription("ssl"); - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", portno); - sslports.append("*:").append(ConvToStr(portno)).append(";"); - } - else - { - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno); - } - } - catch (ModuleException &e) - { - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have an other SSL or similar module loaded?", portno, e.GetReason()); - } - } - } - } - - std::string confdir(ServerInstance->ConfigFileName); - // +1 so we the path ends with a / - confdir = confdir.substr(0, confdir.find_last_of('/') + 1); - - cafile = Conf->ReadValue("gnutls", "cafile", 0); - crlfile = Conf->ReadValue("gnutls", "crlfile", 0); - certfile = Conf->ReadValue("gnutls", "certfile", 0); - keyfile = Conf->ReadValue("gnutls", "keyfile", 0); - dh_bits = Conf->ReadInteger("gnutls", "dhbits", 0, false); - - // Set all the default values needed. - if (cafile.empty()) - cafile = "ca.pem"; - - if (crlfile.empty()) - crlfile = "crl.pem"; - - if (certfile.empty()) - certfile = "cert.pem"; - - if (keyfile.empty()) - keyfile = "key.pem"; - - if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096)) - dh_bits = 1024; - - // Prepend relative paths with the path to the config directory. - if(cafile[0] != '/') - cafile = confdir + cafile; - - if(crlfile[0] != '/') - crlfile = confdir + crlfile; - - if(certfile[0] != '/') - certfile = confdir + certfile; - - if(keyfile[0] != '/') - keyfile = confdir + keyfile; - - int ret; - - if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret)); - - if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret)); - - if((ret = gnutls_certificate_set_x509_key_file (x509_cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) - { - // If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException - throw ModuleException("Unable to load GnuTLS server certificate: " + std::string(gnutls_strerror(ret))); - } - - // This may be on a large (once a day or week) timer eventually. - GenerateDHParams(); - - DELETE(Conf); - } - - void GenerateDHParams() - { - // Generate Diffie Hellman parameters - for use with DHE - // kx algorithms. These should be discarded and regenerated - // once a day, once a week or once a month. Depending on the - // security requirements. - - int ret; - - if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0) - ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret)); - } - - virtual ~ModuleSSLGnuTLS() - { - gnutls_dh_params_deinit(dh_params); - gnutls_certificate_free_credentials(x509_cred); - gnutls_global_deinit(); - } - - virtual void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - - if(user->GetExt("ssl", dummy) && isin(user->GetPort(), listenports)) - { - // User is using SSL, they're a local user, and they're using one of *our* SSL ports. - // Potentially there could be multiple SSL modules loaded at once on different ports. - ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading"); - } - if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports)) - { - ssl_cert* tofree; - user->GetExt("ssl_cert", tofree); - delete tofree; - user->Shrink("ssl_cert"); - } - } - } - - virtual void OnUnloadModule(Module* mod, const std::string &name) - { - if(mod == this) - { - for(unsigned int i = 0; i < listenports.size(); i++) - { - ServerInstance->Config->DelIOHook(listenports[i]); - for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++) - if (ServerInstance->Config->ports[j]->GetPort() == listenports[i]) - ServerInstance->Config->ports[j]->SetDescription("plaintext"); - } - } - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_On005Numeric] = List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1; - List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1; - } - - virtual void On005Numeric(std::string &output) - { - output.append(" SSL=" + sslports); - } - - virtual char* OnRequest(Request* request) - { - ISHRequest* ISR = (ISHRequest*)request; - if (strcmp("IS_NAME", request->GetId()) == 0) - { - return "gnutls"; - } - else if (strcmp("IS_HOOK", request->GetId()) == 0) - { - char* ret = "OK"; - try - { - ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL; - } - catch (ModuleException &e) - { - return NULL; - } - return ret; - } - else if (strcmp("IS_UNHOOK", request->GetId()) == 0) - { - return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL; - } - else if (strcmp("IS_HSDONE", request->GetId()) == 0) - { - if (ISR->Sock->GetFd() < 0) - return (char*)"OK"; - - issl_session* session = &sessions[ISR->Sock->GetFd()]; - return (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) ? NULL : (char*)"OK"; - } - else if (strcmp("IS_ATTACH", request->GetId()) == 0) - { - if (ISR->Sock->GetFd() > -1) - { - issl_session* session = &sessions[ISR->Sock->GetFd()]; - if (session->sess) - { - if ((Extensible*)ServerInstance->FindDescriptor(ISR->Sock->GetFd()) == (Extensible*)(ISR->Sock)) - { - VerifyCertificate(session, (InspSocket*)ISR->Sock); - return "OK"; - } - } - } - } - return NULL; - } - - - virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport) - { - issl_session* session = &sessions[fd]; - - session->fd = fd; - session->inbuf = new char[inbufsize]; - session->inbufoffset = 0; - - gnutls_init(&session->sess, GNUTLS_SERVER); - - gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. - gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); - gnutls_dh_set_prime_bits(session->sess, dh_bits); - - /* This is an experimental change to avoid a warning on 64bit systems about casting between integer and pointer of different sizes - * This needs testing, but it's easy enough to rollback if need be - * Old: gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket. - * New: gnutls_transport_set_ptr(session->sess, &fd); // Give gnutls the fd for the socket. - * - * With testing this seems to...not work :/ - */ - - gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket. - - gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. - - Handshake(session); - } - - virtual void OnRawSocketConnect(int fd) - { - issl_session* session = &sessions[fd]; - - session->fd = fd; - session->inbuf = new char[inbufsize]; - session->inbufoffset = 0; - - gnutls_init(&session->sess, GNUTLS_CLIENT); - - gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. - gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); - gnutls_dh_set_prime_bits(session->sess, dh_bits); - gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket. - - Handshake(session); - } - - virtual void OnRawSocketClose(int fd) - { - CloseSession(&sessions[fd]); - - EventHandler* user = ServerInstance->SE->GetRef(fd); - - if ((user) && (user->GetExt("ssl_cert", dummy))) - { - ssl_cert* tofree; - user->GetExt("ssl_cert", tofree); - delete tofree; - user->Shrink("ssl_cert"); - } - } - - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) - { - issl_session* session = &sessions[fd]; - - if (!session->sess) - { - readresult = 0; - CloseSession(session); - return 1; - } - - if (session->status == ISSL_HANDSHAKING_READ) - { - // The handshake isn't finished, try to finish it. - - if(!Handshake(session)) - { - // Couldn't resume handshake. - return -1; - } - } - else if (session->status == ISSL_HANDSHAKING_WRITE) - { - errno = EAGAIN; - return -1; - } - - // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN. - - if (session->status == ISSL_HANDSHAKEN) - { - // Is this right? Not sure if the unencrypted data is garaunteed to be the same length. - // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet. - int ret = gnutls_record_recv(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset); - - if (ret == 0) - { - // Client closed connection. - readresult = 0; - CloseSession(session); - return 1; - } - else if (ret < 0) - { - if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) - { - errno = EAGAIN; - return -1; - } - else - { - readresult = 0; - CloseSession(session); - } - } - else - { - // Read successfully 'ret' bytes into inbuf + inbufoffset - // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf' - // 'buffer' is 'count' long - - unsigned int length = ret + session->inbufoffset; - - if(count <= length) - { - memcpy(buffer, session->inbuf, count); - // Move the stuff left in inbuf to the beginning of it - memcpy(session->inbuf, session->inbuf + count, (length - count)); - // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp. - session->inbufoffset = length - count; - // Insp uses readresult as the count of how much data there is in buffer, so: - readresult = count; - } - else - { - // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing. - memcpy(buffer, session->inbuf, length); - // Zero the offset, as there's nothing there.. - session->inbufoffset = 0; - // As above - readresult = length; - } - } - } - else if(session->status == ISSL_CLOSING) - readresult = 0; - - return 1; - } - - virtual int OnRawSocketWrite(int fd, const char* buffer, int count) - { - if (!count) - return 0; - - issl_session* session = &sessions[fd]; - const char* sendbuffer = buffer; - - if (!session->sess) - { - ServerInstance->Log(DEBUG,"No session"); - CloseSession(session); - return 1; - } - - session->outbuf.append(sendbuffer, count); - sendbuffer = session->outbuf.c_str(); - count = session->outbuf.size(); - - if (session->status == ISSL_HANDSHAKING_WRITE) - { - // The handshake isn't finished, try to finish it. - ServerInstance->Log(DEBUG,"Finishing handshake"); - Handshake(session); - errno = EAGAIN; - return -1; - } - - int ret = 0; - - if (session->status == ISSL_HANDSHAKEN) - { - ServerInstance->Log(DEBUG,"Send record"); - ret = gnutls_record_send(session->sess, sendbuffer, count); - ServerInstance->Log(DEBUG,"Return: %d", ret); - - if (ret == 0) - { - CloseSession(session); - } - else if (ret < 0) - { - if(ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED) - { - ServerInstance->Log(DEBUG,"Not egain or interrupt, close session"); - CloseSession(session); - } - else - { - ServerInstance->Log(DEBUG,"Again please"); - errno = EAGAIN; - return -1; - } - } - else - { - ServerInstance->Log(DEBUG,"Trim buffer"); - session->outbuf = session->outbuf.substr(ret); - } - } - - /* Who's smart idea was it to return 1 when we havent written anything? - * This fucks the buffer up in InspSocket :p - */ - return ret < 1 ? 0 : ret; - } - - // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection - virtual void OnWhois(userrec* source, userrec* dest) - { - if (!clientactive) - return; - - // Bugfix, only send this numeric for *our* SSL users - if(dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) && isin(dest->GetPort(), listenports))) - { - ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick); - } - } - - virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable) - { - // check if the linking module wants to know about OUR metadata - if(extname == "ssl") - { - // check if this user has an swhois field to send - if(user->GetExt(extname, dummy)) - { - // call this function in the linking module, let it format the data how it - // sees fit, and send it on its way. We dont need or want to know how. - proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON"); - } - } - } - - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - // check if its our metadata key, and its associated with a user - if ((target_type == TYPE_USER) && (extname == "ssl")) - { - userrec* dest = (userrec*)target; - // if they dont already have an ssl flag, accept the remote server's - if (!dest->GetExt(extname, dummy)) - { - dest->Extend(extname, "ON"); - } - } - } - - bool Handshake(issl_session* session) - { - int ret = gnutls_handshake(session->sess); - - if (ret < 0) - { - if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) - { - // Handshake needs resuming later, read() or write() would have blocked. - - if(gnutls_record_get_direction(session->sess) == 0) - { - // gnutls_handshake() wants to read() again. - session->status = ISSL_HANDSHAKING_READ; - } - else - { - // gnutls_handshake() wants to write() again. - session->status = ISSL_HANDSHAKING_WRITE; - MakePollWrite(session); - } - } - else - { - // Handshake failed. - CloseSession(session); - session->status = ISSL_CLOSING; - } - - return false; - } - else - { - // Handshake complete. - // This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater. - userrec* extendme = ServerInstance->FindDescriptor(session->fd); - if (extendme) - { - if (!extendme->GetExt("ssl", dummy)) - extendme->Extend("ssl", "ON"); - } - - // Change the seesion state - session->status = ISSL_HANDSHAKEN; - - // Finish writing, if any left - MakePollWrite(session); - - return true; - } - } - - virtual void OnPostConnect(userrec* user) - { - // This occurs AFTER OnUserConnect so we can be sure the - // protocol module has propogated the NICK message. - if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user))) - { - // Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW. - std::deque<std::string>* metadata = new std::deque<std::string>; - metadata->push_back(user->nick); - metadata->push_back("ssl"); // The metadata id - metadata->push_back("ON"); // The value to send - Event* event = new Event((char*)metadata,(Module*)this,"send_metadata"); - event->Send(ServerInstance); // Trigger the event. We don't care what module picks it up. - DELETE(event); - DELETE(metadata); - - VerifyCertificate(&sessions[user->GetFd()],user); - if (sessions[user->GetFd()].sess) - { - std::string cipher = gnutls_kx_get_name(gnutls_kx_get(sessions[user->GetFd()].sess)); - cipher.append("-").append(gnutls_cipher_get_name(gnutls_cipher_get(sessions[user->GetFd()].sess))).append("-"); - cipher.append(gnutls_mac_get_name(gnutls_mac_get(sessions[user->GetFd()].sess))); - user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, cipher.c_str()); - } - } - } - - void MakePollWrite(issl_session* session) - { - OnRawSocketWrite(session->fd, NULL, 0); - } - - void CloseSession(issl_session* session) - { - if(session->sess) - { - gnutls_bye(session->sess, GNUTLS_SHUT_WR); - gnutls_deinit(session->sess); - } - - if(session->inbuf) - { - delete[] session->inbuf; - } - - session->outbuf.clear(); - session->inbuf = NULL; - session->sess = NULL; - session->status = ISSL_NONE; - } - - void VerifyCertificate(issl_session* session, Extensible* user) - { - if (!session->sess || !user) - return; - - unsigned int status; - const gnutls_datum_t* cert_list; - int ret; - unsigned int cert_list_size; - gnutls_x509_crt_t cert; - char name[MAXBUF]; - unsigned char digest[MAXBUF]; - size_t digest_size = sizeof(digest); - size_t name_size = sizeof(name); - ssl_cert* certinfo = new ssl_cert; - - user->Extend("ssl_cert",certinfo); - - /* This verification function uses the trusted CAs in the credentials - * structure. So you must have installed one or more CA certificates. - */ - ret = gnutls_certificate_verify_peers2(session->sess, &status); - - if (ret < 0) - { - certinfo->data.insert(std::make_pair("error",std::string(gnutls_strerror(ret)))); - return; - } - - if (status & GNUTLS_CERT_INVALID) - { - certinfo->data.insert(std::make_pair("invalid",ConvToStr(1))); - } - else - { - certinfo->data.insert(std::make_pair("invalid",ConvToStr(0))); - } - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) - { - certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1))); - } - else - { - certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0))); - } - if (status & GNUTLS_CERT_REVOKED) - { - certinfo->data.insert(std::make_pair("revoked",ConvToStr(1))); - } - else - { - certinfo->data.insert(std::make_pair("revoked",ConvToStr(0))); - } - if (status & GNUTLS_CERT_SIGNER_NOT_CA) - { - certinfo->data.insert(std::make_pair("trusted",ConvToStr(0))); - } - else - { - certinfo->data.insert(std::make_pair("trusted",ConvToStr(1))); - } - - /* Up to here the process is the same for X.509 certificates and - * OpenPGP keys. From now on X.509 certificates are assumed. This can - * be easily extended to work with openpgp keys as well. - */ - if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509) - { - certinfo->data.insert(std::make_pair("error","No X509 keys sent")); - return; - } - - ret = gnutls_x509_crt_init(&cert); - if (ret < 0) - { - certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret))); - return; - } - - cert_list_size = 0; - cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size); - if (cert_list == NULL) - { - certinfo->data.insert(std::make_pair("error","No certificate was found")); - return; - } - - /* This is not a real world example, since we only check the first - * certificate in the given chain. - */ - - ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); - if (ret < 0) - { - certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret))); - return; - } - - gnutls_x509_crt_get_dn(cert, name, &name_size); - - certinfo->data.insert(std::make_pair("dn",name)); - - gnutls_x509_crt_get_issuer_dn(cert, name, &name_size); - - certinfo->data.insert(std::make_pair("issuer",name)); - - if ((ret = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, digest, &digest_size)) < 0) - { - certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret))); - } - else - { - certinfo->data.insert(std::make_pair("fingerprint",irc::hex(digest, digest_size))); - } - - /* Beware here we do not check for errors. - */ - if ((gnutls_x509_crt_get_expiration_time(cert) < time(0)) || (gnutls_x509_crt_get_activation_time(cert) > time(0))) - { - certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate")); - } - - gnutls_x509_crt_deinit(cert); - - return; - } - -}; - -MODULE_INIT(ModuleSSLGnuTLS); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "inspircd_config.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "socket.h"
#include "hashcomp.h"
#include "transport.h"
#ifdef WINDOWS
#pragma comment(lib, "libgnutls-13.lib")
#undef MAX_DESCRIPTORS
#define MAX_DESCRIPTORS 10000
#endif
/* $ModDesc: Provides SSL support for clients */
/* $CompileFlags: exec("libgnutls-config --cflags") */
/* $LinkerFlags: rpath("libgnutls-config --libs") exec("libgnutls-config --libs") */
/* $ModDep: transport.h */
enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED };
bool isin(int port, const std::vector<int> &portlist)
{
for(unsigned int i = 0; i < portlist.size(); i++)
if(portlist[i] == port)
return true;
return false;
}
/** Represents an SSL user's extra data
*/
class issl_session : public classbase
{
public:
gnutls_session_t sess;
issl_status status;
std::string outbuf;
int inbufoffset;
char* inbuf;
int fd;
};
class ModuleSSLGnuTLS : public Module
{
ConfigReader* Conf;
char* dummy;
std::vector<int> listenports;
int inbufsize;
issl_session sessions[MAX_DESCRIPTORS];
gnutls_certificate_credentials x509_cred;
gnutls_dh_params dh_params;
std::string keyfile;
std::string certfile;
std::string cafile;
std::string crlfile;
std::string sslports;
int dh_bits;
int clientactive;
public:
ModuleSSLGnuTLS(InspIRCd* Me)
: Module(Me)
{
ServerInstance->PublishInterface("InspSocketHook", this);
// Not rehashable...because I cba to reduce all the sizes of existing buffers.
inbufsize = ServerInstance->Config->NetBufferSize;
gnutls_global_init(); // This must be called once in the program
if(gnutls_certificate_allocate_credentials(&x509_cred) != 0)
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to allocate certificate credentials");
// Guessing return meaning
if(gnutls_dh_params_init(&dh_params) < 0)
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters");
// Needs the flag as it ignores a plain /rehash
OnRehash(NULL,"ssl");
// Void return, guess we assume success
gnutls_certificate_set_dh_params(x509_cred, dh_params);
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
if(param != "ssl")
return;
Conf = new ConfigReader(ServerInstance);
for(unsigned int i = 0; i < listenports.size(); i++)
{
ServerInstance->Config->DelIOHook(listenports[i]);
}
listenports.clear();
clientactive = 0;
sslports.clear();
for(int i = 0; i < Conf->Enumerate("bind"); i++)
{
// For each <bind> tag
std::string x = Conf->ReadValue("bind", "type", i);
if(((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "gnutls"))
{
// Get the port we're meant to be listening on with SSL
std::string port = Conf->ReadValue("bind", "port", i);
irc::portparser portrange(port, false);
long portno = -1;
while ((portno = portrange.GetToken()))
{
clientactive++;
try
{
if (ServerInstance->Config->AddIOHook(portno, this))
{
listenports.push_back(portno);
for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
if (ServerInstance->Config->ports[i]->GetPort() == portno)
ServerInstance->Config->ports[i]->SetDescription("ssl");
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", portno);
sslports.append("*:").append(ConvToStr(portno)).append(";");
}
else
{
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);
}
}
catch (ModuleException &e)
{
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have an other SSL or similar module loaded?", portno, e.GetReason());
}
}
}
}
std::string confdir(ServerInstance->ConfigFileName);
// +1 so we the path ends with a /
confdir = confdir.substr(0, confdir.find_last_of('/') + 1);
cafile = Conf->ReadValue("gnutls", "cafile", 0);
crlfile = Conf->ReadValue("gnutls", "crlfile", 0);
certfile = Conf->ReadValue("gnutls", "certfile", 0);
keyfile = Conf->ReadValue("gnutls", "keyfile", 0);
dh_bits = Conf->ReadInteger("gnutls", "dhbits", 0, false);
// Set all the default values needed.
if (cafile.empty())
cafile = "ca.pem";
if (crlfile.empty())
crlfile = "crl.pem";
if (certfile.empty())
certfile = "cert.pem";
if (keyfile.empty())
keyfile = "key.pem";
if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096))
dh_bits = 1024;
// Prepend relative paths with the path to the config directory.
if(cafile[0] != '/')
cafile = confdir + cafile;
if(crlfile[0] != '/')
crlfile = confdir + crlfile;
if(certfile[0] != '/')
certfile = confdir + certfile;
if(keyfile[0] != '/')
keyfile = confdir + keyfile;
int ret;
if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret));
if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret));
if((ret = gnutls_certificate_set_x509_key_file (x509_cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
{
// If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException
throw ModuleException("Unable to load GnuTLS server certificate: " + std::string(gnutls_strerror(ret)));
}
// This may be on a large (once a day or week) timer eventually.
GenerateDHParams();
DELETE(Conf);
}
void GenerateDHParams()
{
// Generate Diffie Hellman parameters - for use with DHE
// kx algorithms. These should be discarded and regenerated
// once a day, once a week or once a month. Depending on the
// security requirements.
int ret;
if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0)
ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret));
}
virtual ~ModuleSSLGnuTLS()
{
gnutls_dh_params_deinit(dh_params);
gnutls_certificate_free_credentials(x509_cred);
gnutls_global_deinit();
}
virtual void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
if(user->GetExt("ssl", dummy) && isin(user->GetPort(), listenports))
{
// User is using SSL, they're a local user, and they're using one of *our* SSL ports.
// Potentially there could be multiple SSL modules loaded at once on different ports.
ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading");
}
if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports))
{
ssl_cert* tofree;
user->GetExt("ssl_cert", tofree);
delete tofree;
user->Shrink("ssl_cert");
}
}
}
virtual void OnUnloadModule(Module* mod, const std::string &name)
{
if(mod == this)
{
for(unsigned int i = 0; i < listenports.size(); i++)
{
ServerInstance->Config->DelIOHook(listenports[i]);
for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])
ServerInstance->Config->ports[j]->SetDescription("plaintext");
}
}
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_On005Numeric] = List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;
List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
}
virtual void On005Numeric(std::string &output)
{
output.append(" SSL=" + sslports);
}
virtual char* OnRequest(Request* request)
{
ISHRequest* ISR = (ISHRequest*)request;
if (strcmp("IS_NAME", request->GetId()) == 0)
{
return "gnutls";
}
else if (strcmp("IS_HOOK", request->GetId()) == 0)
{
char* ret = "OK";
try
{
ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
}
catch (ModuleException &e)
{
return NULL;
}
return ret;
}
else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
{
return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
}
else if (strcmp("IS_HSDONE", request->GetId()) == 0)
{
if (ISR->Sock->GetFd() < 0)
return (char*)"OK";
issl_session* session = &sessions[ISR->Sock->GetFd()];
return (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) ? NULL : (char*)"OK";
}
else if (strcmp("IS_ATTACH", request->GetId()) == 0)
{
if (ISR->Sock->GetFd() > -1)
{
issl_session* session = &sessions[ISR->Sock->GetFd()];
if (session->sess)
{
if ((Extensible*)ServerInstance->FindDescriptor(ISR->Sock->GetFd()) == (Extensible*)(ISR->Sock))
{
VerifyCertificate(session, (InspSocket*)ISR->Sock);
return "OK";
}
}
}
}
return NULL;
}
virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
{
issl_session* session = &sessions[fd];
session->fd = fd;
session->inbuf = new char[inbufsize];
session->inbufoffset = 0;
gnutls_init(&session->sess, GNUTLS_SERVER);
gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.
gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
gnutls_dh_set_prime_bits(session->sess, dh_bits);
/* This is an experimental change to avoid a warning on 64bit systems about casting between integer and pointer of different sizes
* This needs testing, but it's easy enough to rollback if need be
* Old: gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
* New: gnutls_transport_set_ptr(session->sess, &fd); // Give gnutls the fd for the socket.
*
* With testing this seems to...not work :/
*/
gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any.
Handshake(session);
}
virtual void OnRawSocketConnect(int fd)
{
issl_session* session = &sessions[fd];
session->fd = fd;
session->inbuf = new char[inbufsize];
session->inbufoffset = 0;
gnutls_init(&session->sess, GNUTLS_CLIENT);
gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.
gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
gnutls_dh_set_prime_bits(session->sess, dh_bits);
gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
Handshake(session);
}
virtual void OnRawSocketClose(int fd)
{
CloseSession(&sessions[fd]);
EventHandler* user = ServerInstance->SE->GetRef(fd);
if ((user) && (user->GetExt("ssl_cert", dummy)))
{
ssl_cert* tofree;
user->GetExt("ssl_cert", tofree);
delete tofree;
user->Shrink("ssl_cert");
}
}
virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
{
issl_session* session = &sessions[fd];
if (!session->sess)
{
readresult = 0;
CloseSession(session);
return 1;
}
if (session->status == ISSL_HANDSHAKING_READ)
{
// The handshake isn't finished, try to finish it.
if(!Handshake(session))
{
// Couldn't resume handshake.
return -1;
}
}
else if (session->status == ISSL_HANDSHAKING_WRITE)
{
errno = EAGAIN;
return -1;
}
// If we resumed the handshake then session->status will be ISSL_HANDSHAKEN.
if (session->status == ISSL_HANDSHAKEN)
{
// Is this right? Not sure if the unencrypted data is garaunteed to be the same length.
// Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet.
int ret = gnutls_record_recv(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);
if (ret == 0)
{
// Client closed connection.
readresult = 0;
CloseSession(session);
return 1;
}
else if (ret < 0)
{
if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
{
errno = EAGAIN;
return -1;
}
else
{
readresult = 0;
CloseSession(session);
}
}
else
{
// Read successfully 'ret' bytes into inbuf + inbufoffset
// There are 'ret' + 'inbufoffset' bytes of data in 'inbuf'
// 'buffer' is 'count' long
unsigned int length = ret + session->inbufoffset;
if(count <= length)
{
memcpy(buffer, session->inbuf, count);
// Move the stuff left in inbuf to the beginning of it
memcpy(session->inbuf, session->inbuf + count, (length - count));
// Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp.
session->inbufoffset = length - count;
// Insp uses readresult as the count of how much data there is in buffer, so:
readresult = count;
}
else
{
// There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing.
memcpy(buffer, session->inbuf, length);
// Zero the offset, as there's nothing there..
session->inbufoffset = 0;
// As above
readresult = length;
}
}
}
else if(session->status == ISSL_CLOSING)
readresult = 0;
return 1;
}
virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
{
if (!count)
return 0;
issl_session* session = &sessions[fd];
const char* sendbuffer = buffer;
if (!session->sess)
{
ServerInstance->Log(DEBUG,"No session");
CloseSession(session);
return 1;
}
session->outbuf.append(sendbuffer, count);
sendbuffer = session->outbuf.c_str();
count = session->outbuf.size();
if (session->status == ISSL_HANDSHAKING_WRITE)
{
// The handshake isn't finished, try to finish it.
ServerInstance->Log(DEBUG,"Finishing handshake");
Handshake(session);
errno = EAGAIN;
return -1;
}
int ret = 0;
if (session->status == ISSL_HANDSHAKEN)
{
ServerInstance->Log(DEBUG,"Send record");
ret = gnutls_record_send(session->sess, sendbuffer, count);
ServerInstance->Log(DEBUG,"Return: %d", ret);
if (ret == 0)
{
CloseSession(session);
}
else if (ret < 0)
{
if(ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED)
{
ServerInstance->Log(DEBUG,"Not egain or interrupt, close session");
CloseSession(session);
}
else
{
ServerInstance->Log(DEBUG,"Again please");
errno = EAGAIN;
return -1;
}
}
else
{
ServerInstance->Log(DEBUG,"Trim buffer");
session->outbuf = session->outbuf.substr(ret);
}
}
/* Who's smart idea was it to return 1 when we havent written anything?
* This fucks the buffer up in InspSocket :p
*/
return ret < 1 ? 0 : ret;
}
// :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection
virtual void OnWhois(userrec* source, userrec* dest)
{
if (!clientactive)
return;
// Bugfix, only send this numeric for *our* SSL users
if(dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) && isin(dest->GetPort(), listenports)))
{
ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
}
}
virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
{
// check if the linking module wants to know about OUR metadata
if(extname == "ssl")
{
// check if this user has an swhois field to send
if(user->GetExt(extname, dummy))
{
// call this function in the linking module, let it format the data how it
// sees fit, and send it on its way. We dont need or want to know how.
proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");
}
}
}
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
// check if its our metadata key, and its associated with a user
if ((target_type == TYPE_USER) && (extname == "ssl"))
{
userrec* dest = (userrec*)target;
// if they dont already have an ssl flag, accept the remote server's
if (!dest->GetExt(extname, dummy))
{
dest->Extend(extname, "ON");
}
}
}
bool Handshake(issl_session* session)
{
int ret = gnutls_handshake(session->sess);
if (ret < 0)
{
if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
{
// Handshake needs resuming later, read() or write() would have blocked.
if(gnutls_record_get_direction(session->sess) == 0)
{
// gnutls_handshake() wants to read() again.
session->status = ISSL_HANDSHAKING_READ;
}
else
{
// gnutls_handshake() wants to write() again.
session->status = ISSL_HANDSHAKING_WRITE;
MakePollWrite(session);
}
}
else
{
// Handshake failed.
CloseSession(session);
session->status = ISSL_CLOSING;
}
return false;
}
else
{
// Handshake complete.
// This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater.
userrec* extendme = ServerInstance->FindDescriptor(session->fd);
if (extendme)
{
if (!extendme->GetExt("ssl", dummy))
extendme->Extend("ssl", "ON");
}
// Change the seesion state
session->status = ISSL_HANDSHAKEN;
// Finish writing, if any left
MakePollWrite(session);
return true;
}
}
virtual void OnPostConnect(userrec* user)
{
// This occurs AFTER OnUserConnect so we can be sure the
// protocol module has propogated the NICK message.
if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))
{
// Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW.
std::deque<std::string>* metadata = new std::deque<std::string>;
metadata->push_back(user->nick);
metadata->push_back("ssl"); // The metadata id
metadata->push_back("ON"); // The value to send
Event* event = new Event((char*)metadata,(Module*)this,"send_metadata");
event->Send(ServerInstance); // Trigger the event. We don't care what module picks it up.
DELETE(event);
DELETE(metadata);
VerifyCertificate(&sessions[user->GetFd()],user);
if (sessions[user->GetFd()].sess)
{
std::string cipher = gnutls_kx_get_name(gnutls_kx_get(sessions[user->GetFd()].sess));
cipher.append("-").append(gnutls_cipher_get_name(gnutls_cipher_get(sessions[user->GetFd()].sess))).append("-");
cipher.append(gnutls_mac_get_name(gnutls_mac_get(sessions[user->GetFd()].sess)));
user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, cipher.c_str());
}
}
}
void MakePollWrite(issl_session* session)
{
OnRawSocketWrite(session->fd, NULL, 0);
}
void CloseSession(issl_session* session)
{
if(session->sess)
{
gnutls_bye(session->sess, GNUTLS_SHUT_WR);
gnutls_deinit(session->sess);
}
if(session->inbuf)
{
delete[] session->inbuf;
}
session->outbuf.clear();
session->inbuf = NULL;
session->sess = NULL;
session->status = ISSL_NONE;
}
void VerifyCertificate(issl_session* session, Extensible* user)
{
if (!session->sess || !user)
return;
unsigned int status;
const gnutls_datum_t* cert_list;
int ret;
unsigned int cert_list_size;
gnutls_x509_crt_t cert;
char name[MAXBUF];
unsigned char digest[MAXBUF];
size_t digest_size = sizeof(digest);
size_t name_size = sizeof(name);
ssl_cert* certinfo = new ssl_cert;
user->Extend("ssl_cert",certinfo);
/* This verification function uses the trusted CAs in the credentials
* structure. So you must have installed one or more CA certificates.
*/
ret = gnutls_certificate_verify_peers2(session->sess, &status);
if (ret < 0)
{
certinfo->data.insert(std::make_pair("error",std::string(gnutls_strerror(ret))));
return;
}
if (status & GNUTLS_CERT_INVALID)
{
certinfo->data.insert(std::make_pair("invalid",ConvToStr(1)));
}
else
{
certinfo->data.insert(std::make_pair("invalid",ConvToStr(0)));
}
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
{
certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1)));
}
else
{
certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0)));
}
if (status & GNUTLS_CERT_REVOKED)
{
certinfo->data.insert(std::make_pair("revoked",ConvToStr(1)));
}
else
{
certinfo->data.insert(std::make_pair("revoked",ConvToStr(0)));
}
if (status & GNUTLS_CERT_SIGNER_NOT_CA)
{
certinfo->data.insert(std::make_pair("trusted",ConvToStr(0)));
}
else
{
certinfo->data.insert(std::make_pair("trusted",ConvToStr(1)));
}
/* Up to here the process is the same for X.509 certificates and
* OpenPGP keys. From now on X.509 certificates are assumed. This can
* be easily extended to work with openpgp keys as well.
*/
if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509)
{
certinfo->data.insert(std::make_pair("error","No X509 keys sent"));
return;
}
ret = gnutls_x509_crt_init(&cert);
if (ret < 0)
{
certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
return;
}
cert_list_size = 0;
cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size);
if (cert_list == NULL)
{
certinfo->data.insert(std::make_pair("error","No certificate was found"));
return;
}
/* This is not a real world example, since we only check the first
* certificate in the given chain.
*/
ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
if (ret < 0)
{
certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
return;
}
gnutls_x509_crt_get_dn(cert, name, &name_size);
certinfo->data.insert(std::make_pair("dn",name));
gnutls_x509_crt_get_issuer_dn(cert, name, &name_size);
certinfo->data.insert(std::make_pair("issuer",name));
if ((ret = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, digest, &digest_size)) < 0)
{
certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
}
else
{
certinfo->data.insert(std::make_pair("fingerprint",irc::hex(digest, digest_size)));
}
/* Beware here we do not check for errors.
*/
if ((gnutls_x509_crt_get_expiration_time(cert) < time(0)) || (gnutls_x509_crt_get_activation_time(cert) > time(0)))
{
certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate"));
}
gnutls_x509_crt_deinit(cert);
return;
}
};
MODULE_INIT(ModuleSSLGnuTLS);
\ No newline at end of file diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index ffd9d4032..43dc43aea 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -1,901 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" - -#include <openssl/ssl.h> -#include <openssl/err.h> - -#ifdef WINDOWS -#include <openssl/applink.c> -#endif - -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -#include "socket.h" -#include "hashcomp.h" - -#include "transport.h" - -#ifdef WINDOWS -#pragma comment(lib, "libeay32MTd") -#pragma comment(lib, "ssleay32MTd") -#undef MAX_DESCRIPTORS -#define MAX_DESCRIPTORS 10000 -#endif - -/* $ModDesc: Provides SSL support for clients */ -/* $CompileFlags: pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */ -/* $LinkerFlags: rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto -ldl") */ -/* $ModDep: transport.h */ - -enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN }; -enum issl_io_status { ISSL_WRITE, ISSL_READ }; - -static bool SelfSigned = false; - -bool isin(int port, const std::vector<int> &portlist) -{ - for(unsigned int i = 0; i < portlist.size(); i++) - if(portlist[i] == port) - return true; - - return false; -} - -char* get_error() -{ - return ERR_error_string(ERR_get_error(), NULL); -} - -static int error_callback(const char *str, size_t len, void *u); - -/** Represents an SSL user's extra data - */ -class issl_session : public classbase -{ -public: - SSL* sess; - issl_status status; - issl_io_status rstat; - issl_io_status wstat; - - unsigned int inbufoffset; - char* inbuf; // Buffer OpenSSL reads into. - std::string outbuf; // Buffer for outgoing data that OpenSSL will not take. - int fd; - bool outbound; - - issl_session() - { - outbound = false; - rstat = ISSL_READ; - wstat = ISSL_WRITE; - } -}; - -static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx) -{ - /* XXX: This will allow self signed certificates. - * In the future if we want an option to not allow this, - * we can just return preverify_ok here, and openssl - * will boot off self-signed and invalid peer certs. - */ - int ve = X509_STORE_CTX_get_error(ctx); - - SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); - - return 1; -} - -class ModuleSSLOpenSSL : public Module -{ - - ConfigReader* Conf; - - std::vector<int> listenports; - - int inbufsize; - issl_session sessions[MAX_DESCRIPTORS]; - - SSL_CTX* ctx; - SSL_CTX* clictx; - - char* dummy; - char cipher[MAXBUF]; - - std::string keyfile; - std::string certfile; - std::string cafile; - // std::string crlfile; - std::string dhfile; - std::string sslports; - - int clientactive; - - public: - - InspIRCd* PublicInstance; - - ModuleSSLOpenSSL(InspIRCd* Me) - : Module(Me), PublicInstance(Me) - { - ServerInstance->PublishInterface("InspSocketHook", this); - - // Not rehashable...because I cba to reduce all the sizes of existing buffers. - inbufsize = ServerInstance->Config->NetBufferSize; - - /* Global SSL library initialization*/ - SSL_library_init(); - SSL_load_error_strings(); - - /* Build our SSL contexts: - * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK. - */ - ctx = SSL_CTX_new( SSLv23_server_method() ); - clictx = SSL_CTX_new( SSLv23_client_method() ); - - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify); - SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify); - - // Needs the flag as it ignores a plain /rehash - OnRehash(NULL,"ssl"); - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - if (param != "ssl") - return; - - Conf = new ConfigReader(ServerInstance); - - for (unsigned int i = 0; i < listenports.size(); i++) - { - ServerInstance->Config->DelIOHook(listenports[i]); - } - - listenports.clear(); - clientactive = 0; - sslports.clear(); - - for (int i = 0; i < Conf->Enumerate("bind"); i++) - { - // For each <bind> tag - std::string x = Conf->ReadValue("bind", "type", i); - if (((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "openssl")) - { - // Get the port we're meant to be listening on with SSL - std::string port = Conf->ReadValue("bind", "port", i); - irc::portparser portrange(port, false); - long portno = -1; - while ((portno = portrange.GetToken())) - { - clientactive++; - try - { - if (ServerInstance->Config->AddIOHook(portno, this)) - { - listenports.push_back(portno); - for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++) - if (ServerInstance->Config->ports[i]->GetPort() == portno) - ServerInstance->Config->ports[i]->SetDescription("ssl"); - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %d", portno); - sslports.append("*:").append(ConvToStr(portno)).append(";"); - } - else - { - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno); - } - } - catch (ModuleException &e) - { - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another SSL or similar module loaded?", portno, e.GetReason()); - } - } - } - } - - if (!sslports.empty()) - sslports.erase(sslports.end() - 1); - - std::string confdir(ServerInstance->ConfigFileName); - // +1 so we the path ends with a / - confdir = confdir.substr(0, confdir.find_last_of('/') + 1); - - cafile = Conf->ReadValue("openssl", "cafile", 0); - certfile = Conf->ReadValue("openssl", "certfile", 0); - keyfile = Conf->ReadValue("openssl", "keyfile", 0); - dhfile = Conf->ReadValue("openssl", "dhfile", 0); - - // Set all the default values needed. - if (cafile.empty()) - cafile = "ca.pem"; - - if (certfile.empty()) - certfile = "cert.pem"; - - if (keyfile.empty()) - keyfile = "key.pem"; - - if (dhfile.empty()) - dhfile = "dhparams.pem"; - - // Prepend relative paths with the path to the config directory. - if (cafile[0] != '/') - cafile = confdir + cafile; - - if (certfile[0] != '/') - certfile = confdir + certfile; - - if (keyfile[0] != '/') - keyfile = confdir + keyfile; - - if (dhfile[0] != '/') - dhfile = confdir + dhfile; - - /* Load our keys and certificates - * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck. - */ - if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str()))) - { - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno)); - ERR_print_errors_cb(error_callback, this); - } - - if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM))) - { - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno)); - ERR_print_errors_cb(error_callback, this); - } - - /* Load the CAs we trust*/ - if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0))) - { - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read CA list from %s. %s", cafile.c_str(), strerror(errno)); - ERR_print_errors_cb(error_callback, this); - } - - FILE* dhpfile = fopen(dhfile.c_str(), "r"); - DH* ret; - - if (dhpfile == NULL) - { - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno)); - throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno)); - } - else - { - ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL); - if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0)) - { - ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str()); - ERR_print_errors_cb(error_callback, this); - } - } - - fclose(dhpfile); - - DELETE(Conf); - } - - virtual void On005Numeric(std::string &output) - { - output.append(" SSL=" + sslports); - } - - virtual ~ModuleSSLOpenSSL() - { - SSL_CTX_free(ctx); - SSL_CTX_free(clictx); - } - - virtual void OnCleanup(int target_type, void* item) - { - if (target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - - if (user->GetExt("ssl", dummy) && IS_LOCAL(user) && isin(user->GetPort(), listenports)) - { - // User is using SSL, they're a local user, and they're using one of *our* SSL ports. - // Potentially there could be multiple SSL modules loaded at once on different ports. - ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading"); - } - if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports)) - { - ssl_cert* tofree; - user->GetExt("ssl_cert", tofree); - delete tofree; - user->Shrink("ssl_cert"); - } - } - } - - virtual void OnUnloadModule(Module* mod, const std::string &name) - { - if (mod == this) - { - for(unsigned int i = 0; i < listenports.size(); i++) - { - ServerInstance->Config->DelIOHook(listenports[i]); - for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++) - if (ServerInstance->Config->ports[j]->GetPort() == listenports[i]) - ServerInstance->Config->ports[j]->SetDescription("plaintext"); - } - } - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = List[I_On005Numeric] = 1; - List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1; - } - - virtual char* OnRequest(Request* request) - { - ISHRequest* ISR = (ISHRequest*)request; - if (strcmp("IS_NAME", request->GetId()) == 0) - { - return "openssl"; - } - else if (strcmp("IS_HOOK", request->GetId()) == 0) - { - char* ret = "OK"; - try - { - ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL; - } - catch (ModuleException &e) - { - return NULL; - } - - return ret; - } - else if (strcmp("IS_UNHOOK", request->GetId()) == 0) - { - return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL; - } - else if (strcmp("IS_HSDONE", request->GetId()) == 0) - { - ServerInstance->Log(DEBUG,"Module checking if handshake is done"); - if (ISR->Sock->GetFd() < 0) - return (char*)"OK"; - - issl_session* session = &sessions[ISR->Sock->GetFd()]; - return (session->status == ISSL_HANDSHAKING) ? NULL : (char*)"OK"; - } - else if (strcmp("IS_ATTACH", request->GetId()) == 0) - { - issl_session* session = &sessions[ISR->Sock->GetFd()]; - if (session->sess) - { - VerifyCertificate(session, (InspSocket*)ISR->Sock); - return "OK"; - } - } - return NULL; - } - - - virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport) - { - issl_session* session = &sessions[fd]; - - session->fd = fd; - session->inbuf = new char[inbufsize]; - session->inbufoffset = 0; - session->sess = SSL_new(ctx); - session->status = ISSL_NONE; - session->outbound = false; - - if (session->sess == NULL) - return; - - if (SSL_set_fd(session->sess, fd) == 0) - { - ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd); - return; - } - - Handshake(session); - } - - virtual void OnRawSocketConnect(int fd) - { - ServerInstance->Log(DEBUG,"OnRawSocketConnect connecting"); - issl_session* session = &sessions[fd]; - - session->fd = fd; - session->inbuf = new char[inbufsize]; - session->inbufoffset = 0; - session->sess = SSL_new(clictx); - session->status = ISSL_NONE; - session->outbound = true; - - if (session->sess == NULL) - return; - - if (SSL_set_fd(session->sess, fd) == 0) - { - ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd); - return; - } - - Handshake(session); - ServerInstance->Log(DEBUG,"Exiting OnRawSocketConnect"); - } - - virtual void OnRawSocketClose(int fd) - { - CloseSession(&sessions[fd]); - - EventHandler* user = ServerInstance->SE->GetRef(fd); - - if ((user) && (user->GetExt("ssl_cert", dummy))) - { - ssl_cert* tofree; - user->GetExt("ssl_cert", tofree); - delete tofree; - user->Shrink("ssl_cert"); - } - } - - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) - { - issl_session* session = &sessions[fd]; - - ServerInstance->Log(DEBUG,"OnRawSocketRead"); - - if (!session->sess) - { - ServerInstance->Log(DEBUG,"OnRawSocketRead has no session"); - readresult = 0; - CloseSession(session); - return 1; - } - - if (session->status == ISSL_HANDSHAKING) - { - if (session->rstat == ISSL_READ || session->wstat == ISSL_READ) - { - ServerInstance->Log(DEBUG,"Resume handshake in read"); - // The handshake isn't finished and it wants to read, try to finish it. - if (!Handshake(session)) - { - ServerInstance->Log(DEBUG,"Cant resume handshake in read"); - // Couldn't resume handshake. - return -1; - } - } - else - { - errno = EAGAIN; - return -1; - } - } - - // If we resumed the handshake then session->status will be ISSL_OPEN - - if (session->status == ISSL_OPEN) - { - if (session->wstat == ISSL_READ) - { - if(DoWrite(session) == 0) - return 0; - } - - if (session->rstat == ISSL_READ) - { - int ret = DoRead(session); - - if (ret > 0) - { - if (count <= session->inbufoffset) - { - memcpy(buffer, session->inbuf, count); - // Move the stuff left in inbuf to the beginning of it - memcpy(session->inbuf, session->inbuf + count, (session->inbufoffset - count)); - // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp. - session->inbufoffset -= count; - // Insp uses readresult as the count of how much data there is in buffer, so: - readresult = count; - } - else - { - // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing. - memcpy(buffer, session->inbuf, session->inbufoffset); - - readresult = session->inbufoffset; - // Zero the offset, as there's nothing there.. - session->inbufoffset = 0; - } - - return 1; - } - else - { - return ret; - } - } - } - - return -1; - } - - virtual int OnRawSocketWrite(int fd, const char* buffer, int count) - { - issl_session* session = &sessions[fd]; - - if (!session->sess) - { - ServerInstance->Log(DEBUG,"Close session missing sess"); - CloseSession(session); - return -1; - } - - session->outbuf.append(buffer, count); - - if (session->status == ISSL_HANDSHAKING) - { - // The handshake isn't finished, try to finish it. - if (session->rstat == ISSL_WRITE || session->wstat == ISSL_WRITE) - { - ServerInstance->Log(DEBUG,"Handshake resume"); - Handshake(session); - } - } - - if (session->status == ISSL_OPEN) - { - if (session->rstat == ISSL_WRITE) - { - ServerInstance->Log(DEBUG,"DoRead"); - DoRead(session); - } - - if (session->wstat == ISSL_WRITE) - { - ServerInstance->Log(DEBUG,"DoWrite"); - return DoWrite(session); - } - } - - return 1; - } - - int DoWrite(issl_session* session) - { - if (!session->outbuf.size()) - return -1; - - int ret = SSL_write(session->sess, session->outbuf.data(), session->outbuf.size()); - - if (ret == 0) - { - ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_write"); - CloseSession(session); - return 0; - } - else if (ret < 0) - { - int err = SSL_get_error(session->sess, ret); - - if (err == SSL_ERROR_WANT_WRITE) - { - session->wstat = ISSL_WRITE; - return -1; - } - else if (err == SSL_ERROR_WANT_READ) - { - session->wstat = ISSL_READ; - return -1; - } - else - { - ServerInstance->Log(DEBUG,"Close due to returned -1 in SSL_Write"); - CloseSession(session); - return 0; - } - } - else - { - session->outbuf = session->outbuf.substr(ret); - return ret; - } - } - - int DoRead(issl_session* session) - { - // Is this right? Not sure if the unencrypted data is garaunteed to be the same length. - // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet. - - ServerInstance->Log(DEBUG,"DoRead"); - - int ret = SSL_read(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset); - - if (ret == 0) - { - // Client closed connection. - ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_read"); - CloseSession(session); - return 0; - } - else if (ret < 0) - { - int err = SSL_get_error(session->sess, ret); - - if (err == SSL_ERROR_WANT_READ) - { - session->rstat = ISSL_READ; - ServerInstance->Log(DEBUG,"Setting want_read"); - return -1; - } - else if (err == SSL_ERROR_WANT_WRITE) - { - session->rstat = ISSL_WRITE; - ServerInstance->Log(DEBUG,"Setting want_write"); - return -1; - } - else - { - ServerInstance->Log(DEBUG,"Closed due to returned -1 in SSL_Read"); - CloseSession(session); - return 0; - } - } - else - { - // Read successfully 'ret' bytes into inbuf + inbufoffset - // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf' - // 'buffer' is 'count' long - - session->inbufoffset += ret; - - return ret; - } - } - - // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection - virtual void OnWhois(userrec* source, userrec* dest) - { - if (!clientactive) - return; - - // Bugfix, only send this numeric for *our* SSL users - if (dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) && isin(dest->GetPort(), listenports))) - { - ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick); - } - } - - virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable) - { - // check if the linking module wants to know about OUR metadata - if (extname == "ssl") - { - // check if this user has an swhois field to send - if(user->GetExt(extname, dummy)) - { - // call this function in the linking module, let it format the data how it - // sees fit, and send it on its way. We dont need or want to know how. - proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON"); - } - } - } - - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - // check if its our metadata key, and its associated with a user - if ((target_type == TYPE_USER) && (extname == "ssl")) - { - userrec* dest = (userrec*)target; - // if they dont already have an ssl flag, accept the remote server's - if (!dest->GetExt(extname, dummy)) - { - dest->Extend(extname, "ON"); - } - } - } - - bool Handshake(issl_session* session) - { - ServerInstance->Log(DEBUG,"Handshake"); - int ret; - - if (session->outbound) - { - ServerInstance->Log(DEBUG,"SSL_connect"); - ret = SSL_connect(session->sess); - } - else - ret = SSL_accept(session->sess); - - if (ret < 0) - { - int err = SSL_get_error(session->sess, ret); - - if (err == SSL_ERROR_WANT_READ) - { - ServerInstance->Log(DEBUG,"Want read, handshaking"); - session->rstat = ISSL_READ; - session->status = ISSL_HANDSHAKING; - return true; - } - else if (err == SSL_ERROR_WANT_WRITE) - { - ServerInstance->Log(DEBUG,"Want write, handshaking"); - session->wstat = ISSL_WRITE; - session->status = ISSL_HANDSHAKING; - MakePollWrite(session); - return true; - } - else - { - ServerInstance->Log(DEBUG,"Handshake failed"); - CloseSession(session); - } - - return false; - } - else if (ret > 0) - { - // Handshake complete. - // This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater. - userrec* u = ServerInstance->FindDescriptor(session->fd); - if (u) - { - if (!u->GetExt("ssl", dummy)) - u->Extend("ssl", "ON"); - } - - session->status = ISSL_OPEN; - - MakePollWrite(session); - - return true; - } - else if (ret == 0) - { - int ssl_err = SSL_get_error(session->sess, ret); - char buf[1024]; - ERR_print_errors_fp(stderr); - ServerInstance->Log(DEBUG,"Handshake fail 2: %d: %s", ssl_err, ERR_error_string(ssl_err,buf)); - CloseSession(session); - return true; - } - - return true; - } - - virtual void OnPostConnect(userrec* user) - { - // This occurs AFTER OnUserConnect so we can be sure the - // protocol module has propogated the NICK message. - if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user))) - { - // Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW. - std::deque<std::string>* metadata = new std::deque<std::string>; - metadata->push_back(user->nick); - metadata->push_back("ssl"); // The metadata id - metadata->push_back("ON"); // The value to send - Event* event = new Event((char*)metadata,(Module*)this,"send_metadata"); - event->Send(ServerInstance); // Trigger the event. We don't care what module picks it up. - DELETE(event); - DELETE(metadata); - - VerifyCertificate(&sessions[user->GetFd()], user); - if (sessions[user->GetFd()].sess) - user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, SSL_get_cipher(sessions[user->GetFd()].sess)); - } - } - - void MakePollWrite(issl_session* session) - { - OnRawSocketWrite(session->fd, NULL, 0); - //EventHandler* eh = ServerInstance->FindDescriptor(session->fd); - //if (eh) - // ServerInstance->SE->WantWrite(eh); - } - - void CloseSession(issl_session* session) - { - if (session->sess) - { - SSL_shutdown(session->sess); - SSL_free(session->sess); - } - - if (session->inbuf) - { - delete[] session->inbuf; - } - - session->outbuf.clear(); - session->inbuf = NULL; - session->sess = NULL; - session->status = ISSL_NONE; - } - - void VerifyCertificate(issl_session* session, Extensible* user) - { - if (!session->sess || !user) - return; - - X509* cert; - ssl_cert* certinfo = new ssl_cert; - unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; - const EVP_MD *digest = EVP_md5(); - - user->Extend("ssl_cert",certinfo); - - cert = SSL_get_peer_certificate((SSL*)session->sess); - - if (!cert) - { - certinfo->data.insert(std::make_pair("error","Could not get peer certificate: "+std::string(get_error()))); - return; - } - - certinfo->data.insert(std::make_pair("invalid", SSL_get_verify_result(session->sess) != X509_V_OK ? ConvToStr(1) : ConvToStr(0))); - - if (SelfSigned) - { - certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0))); - certinfo->data.insert(std::make_pair("trusted",ConvToStr(1))); - } - else - { - certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1))); - certinfo->data.insert(std::make_pair("trusted",ConvToStr(0))); - } - - certinfo->data.insert(std::make_pair("dn",std::string(X509_NAME_oneline(X509_get_subject_name(cert),0,0)))); - certinfo->data.insert(std::make_pair("issuer",std::string(X509_NAME_oneline(X509_get_issuer_name(cert),0,0)))); - - if (!X509_digest(cert, digest, md, &n)) - { - certinfo->data.insert(std::make_pair("error","Out of memory generating fingerprint")); - } - else - { - certinfo->data.insert(std::make_pair("fingerprint",irc::hex(md, n))); - } - - if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), time(NULL)) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), time(NULL)) == 0)) - { - certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate")); - } - - X509_free(cert); - } -}; - -static int error_callback(const char *str, size_t len, void *u) -{ - ModuleSSLOpenSSL* mssl = (ModuleSSLOpenSSL*)u; - mssl->PublicInstance->Log(DEFAULT, "SSL error: " + std::string(str, len - 1)); - return 0; -} - -MODULE_INIT(ModuleSSLOpenSSL); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
#ifdef WINDOWS
#include <openssl/applink.c>
#endif
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "socket.h"
#include "hashcomp.h"
#include "transport.h"
#ifdef WINDOWS
#pragma comment(lib, "libeay32MTd")
#pragma comment(lib, "ssleay32MTd")
#undef MAX_DESCRIPTORS
#define MAX_DESCRIPTORS 10000
#endif
/* $ModDesc: Provides SSL support for clients */
/* $CompileFlags: pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */
/* $LinkerFlags: rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto -ldl") */
/* $ModDep: transport.h */
enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
enum issl_io_status { ISSL_WRITE, ISSL_READ };
static bool SelfSigned = false;
bool isin(int port, const std::vector<int> &portlist)
{
for(unsigned int i = 0; i < portlist.size(); i++)
if(portlist[i] == port)
return true;
return false;
}
char* get_error()
{
return ERR_error_string(ERR_get_error(), NULL);
}
static int error_callback(const char *str, size_t len, void *u);
/** Represents an SSL user's extra data
*/
class issl_session : public classbase
{
public:
SSL* sess;
issl_status status;
issl_io_status rstat;
issl_io_status wstat;
unsigned int inbufoffset;
char* inbuf; // Buffer OpenSSL reads into.
std::string outbuf; // Buffer for outgoing data that OpenSSL will not take.
int fd;
bool outbound;
issl_session()
{
outbound = false;
rstat = ISSL_READ;
wstat = ISSL_WRITE;
}
};
static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
{
/* XXX: This will allow self signed certificates.
* In the future if we want an option to not allow this,
* we can just return preverify_ok here, and openssl
* will boot off self-signed and invalid peer certs.
*/
int ve = X509_STORE_CTX_get_error(ctx);
SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
return 1;
}
class ModuleSSLOpenSSL : public Module
{
ConfigReader* Conf;
std::vector<int> listenports;
int inbufsize;
issl_session sessions[MAX_DESCRIPTORS];
SSL_CTX* ctx;
SSL_CTX* clictx;
char* dummy;
char cipher[MAXBUF];
std::string keyfile;
std::string certfile;
std::string cafile;
// std::string crlfile;
std::string dhfile;
std::string sslports;
int clientactive;
public:
InspIRCd* PublicInstance;
ModuleSSLOpenSSL(InspIRCd* Me)
: Module(Me), PublicInstance(Me)
{
ServerInstance->PublishInterface("InspSocketHook", this);
// Not rehashable...because I cba to reduce all the sizes of existing buffers.
inbufsize = ServerInstance->Config->NetBufferSize;
/* Global SSL library initialization*/
SSL_library_init();
SSL_load_error_strings();
/* Build our SSL contexts:
* NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK.
*/
ctx = SSL_CTX_new( SSLv23_server_method() );
clictx = SSL_CTX_new( SSLv23_client_method() );
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
// Needs the flag as it ignores a plain /rehash
OnRehash(NULL,"ssl");
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
if (param != "ssl")
return;
Conf = new ConfigReader(ServerInstance);
for (unsigned int i = 0; i < listenports.size(); i++)
{
ServerInstance->Config->DelIOHook(listenports[i]);
}
listenports.clear();
clientactive = 0;
sslports.clear();
for (int i = 0; i < Conf->Enumerate("bind"); i++)
{
// For each <bind> tag
std::string x = Conf->ReadValue("bind", "type", i);
if (((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "openssl"))
{
// Get the port we're meant to be listening on with SSL
std::string port = Conf->ReadValue("bind", "port", i);
irc::portparser portrange(port, false);
long portno = -1;
while ((portno = portrange.GetToken()))
{
clientactive++;
try
{
if (ServerInstance->Config->AddIOHook(portno, this))
{
listenports.push_back(portno);
for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
if (ServerInstance->Config->ports[i]->GetPort() == portno)
ServerInstance->Config->ports[i]->SetDescription("ssl");
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %d", portno);
sslports.append("*:").append(ConvToStr(portno)).append(";");
}
else
{
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);
}
}
catch (ModuleException &e)
{
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another SSL or similar module loaded?", portno, e.GetReason());
}
}
}
}
if (!sslports.empty())
sslports.erase(sslports.end() - 1);
std::string confdir(ServerInstance->ConfigFileName);
// +1 so we the path ends with a /
confdir = confdir.substr(0, confdir.find_last_of('/') + 1);
cafile = Conf->ReadValue("openssl", "cafile", 0);
certfile = Conf->ReadValue("openssl", "certfile", 0);
keyfile = Conf->ReadValue("openssl", "keyfile", 0);
dhfile = Conf->ReadValue("openssl", "dhfile", 0);
// Set all the default values needed.
if (cafile.empty())
cafile = "ca.pem";
if (certfile.empty())
certfile = "cert.pem";
if (keyfile.empty())
keyfile = "key.pem";
if (dhfile.empty())
dhfile = "dhparams.pem";
// Prepend relative paths with the path to the config directory.
if (cafile[0] != '/')
cafile = confdir + cafile;
if (certfile[0] != '/')
certfile = confdir + certfile;
if (keyfile[0] != '/')
keyfile = confdir + keyfile;
if (dhfile[0] != '/')
dhfile = confdir + dhfile;
/* Load our keys and certificates
* NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.
*/
if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str())))
{
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno));
ERR_print_errors_cb(error_callback, this);
}
if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM)))
{
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno));
ERR_print_errors_cb(error_callback, this);
}
/* Load the CAs we trust*/
if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0)))
{
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read CA list from %s. %s", cafile.c_str(), strerror(errno));
ERR_print_errors_cb(error_callback, this);
}
FILE* dhpfile = fopen(dhfile.c_str(), "r");
DH* ret;
if (dhpfile == NULL)
{
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno));
throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno));
}
else
{
ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0))
{
ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str());
ERR_print_errors_cb(error_callback, this);
}
}
fclose(dhpfile);
DELETE(Conf);
}
virtual void On005Numeric(std::string &output)
{
output.append(" SSL=" + sslports);
}
virtual ~ModuleSSLOpenSSL()
{
SSL_CTX_free(ctx);
SSL_CTX_free(clictx);
}
virtual void OnCleanup(int target_type, void* item)
{
if (target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
if (user->GetExt("ssl", dummy) && IS_LOCAL(user) && isin(user->GetPort(), listenports))
{
// User is using SSL, they're a local user, and they're using one of *our* SSL ports.
// Potentially there could be multiple SSL modules loaded at once on different ports.
ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading");
}
if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports))
{
ssl_cert* tofree;
user->GetExt("ssl_cert", tofree);
delete tofree;
user->Shrink("ssl_cert");
}
}
}
virtual void OnUnloadModule(Module* mod, const std::string &name)
{
if (mod == this)
{
for(unsigned int i = 0; i < listenports.size(); i++)
{
ServerInstance->Config->DelIOHook(listenports[i]);
for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])
ServerInstance->Config->ports[j]->SetDescription("plaintext");
}
}
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = List[I_On005Numeric] = 1;
List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
}
virtual char* OnRequest(Request* request)
{
ISHRequest* ISR = (ISHRequest*)request;
if (strcmp("IS_NAME", request->GetId()) == 0)
{
return "openssl";
}
else if (strcmp("IS_HOOK", request->GetId()) == 0)
{
char* ret = "OK";
try
{
ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
}
catch (ModuleException &e)
{
return NULL;
}
return ret;
}
else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
{
return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
}
else if (strcmp("IS_HSDONE", request->GetId()) == 0)
{
ServerInstance->Log(DEBUG,"Module checking if handshake is done");
if (ISR->Sock->GetFd() < 0)
return (char*)"OK";
issl_session* session = &sessions[ISR->Sock->GetFd()];
return (session->status == ISSL_HANDSHAKING) ? NULL : (char*)"OK";
}
else if (strcmp("IS_ATTACH", request->GetId()) == 0)
{
issl_session* session = &sessions[ISR->Sock->GetFd()];
if (session->sess)
{
VerifyCertificate(session, (InspSocket*)ISR->Sock);
return "OK";
}
}
return NULL;
}
virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
{
issl_session* session = &sessions[fd];
session->fd = fd;
session->inbuf = new char[inbufsize];
session->inbufoffset = 0;
session->sess = SSL_new(ctx);
session->status = ISSL_NONE;
session->outbound = false;
if (session->sess == NULL)
return;
if (SSL_set_fd(session->sess, fd) == 0)
{
ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
return;
}
Handshake(session);
}
virtual void OnRawSocketConnect(int fd)
{
ServerInstance->Log(DEBUG,"OnRawSocketConnect connecting");
issl_session* session = &sessions[fd];
session->fd = fd;
session->inbuf = new char[inbufsize];
session->inbufoffset = 0;
session->sess = SSL_new(clictx);
session->status = ISSL_NONE;
session->outbound = true;
if (session->sess == NULL)
return;
if (SSL_set_fd(session->sess, fd) == 0)
{
ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
return;
}
Handshake(session);
ServerInstance->Log(DEBUG,"Exiting OnRawSocketConnect");
}
virtual void OnRawSocketClose(int fd)
{
CloseSession(&sessions[fd]);
EventHandler* user = ServerInstance->SE->GetRef(fd);
if ((user) && (user->GetExt("ssl_cert", dummy)))
{
ssl_cert* tofree;
user->GetExt("ssl_cert", tofree);
delete tofree;
user->Shrink("ssl_cert");
}
}
virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
{
issl_session* session = &sessions[fd];
ServerInstance->Log(DEBUG,"OnRawSocketRead");
if (!session->sess)
{
ServerInstance->Log(DEBUG,"OnRawSocketRead has no session");
readresult = 0;
CloseSession(session);
return 1;
}
if (session->status == ISSL_HANDSHAKING)
{
if (session->rstat == ISSL_READ || session->wstat == ISSL_READ)
{
ServerInstance->Log(DEBUG,"Resume handshake in read");
// The handshake isn't finished and it wants to read, try to finish it.
if (!Handshake(session))
{
ServerInstance->Log(DEBUG,"Cant resume handshake in read");
// Couldn't resume handshake.
return -1;
}
}
else
{
errno = EAGAIN;
return -1;
}
}
// If we resumed the handshake then session->status will be ISSL_OPEN
if (session->status == ISSL_OPEN)
{
if (session->wstat == ISSL_READ)
{
if(DoWrite(session) == 0)
return 0;
}
if (session->rstat == ISSL_READ)
{
int ret = DoRead(session);
if (ret > 0)
{
if (count <= session->inbufoffset)
{
memcpy(buffer, session->inbuf, count);
// Move the stuff left in inbuf to the beginning of it
memcpy(session->inbuf, session->inbuf + count, (session->inbufoffset - count));
// Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp.
session->inbufoffset -= count;
// Insp uses readresult as the count of how much data there is in buffer, so:
readresult = count;
}
else
{
// There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing.
memcpy(buffer, session->inbuf, session->inbufoffset);
readresult = session->inbufoffset;
// Zero the offset, as there's nothing there..
session->inbufoffset = 0;
}
return 1;
}
else
{
return ret;
}
}
}
return -1;
}
virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
{
issl_session* session = &sessions[fd];
if (!session->sess)
{
ServerInstance->Log(DEBUG,"Close session missing sess");
CloseSession(session);
return -1;
}
session->outbuf.append(buffer, count);
if (session->status == ISSL_HANDSHAKING)
{
// The handshake isn't finished, try to finish it.
if (session->rstat == ISSL_WRITE || session->wstat == ISSL_WRITE)
{
ServerInstance->Log(DEBUG,"Handshake resume");
Handshake(session);
}
}
if (session->status == ISSL_OPEN)
{
if (session->rstat == ISSL_WRITE)
{
ServerInstance->Log(DEBUG,"DoRead");
DoRead(session);
}
if (session->wstat == ISSL_WRITE)
{
ServerInstance->Log(DEBUG,"DoWrite");
return DoWrite(session);
}
}
return 1;
}
int DoWrite(issl_session* session)
{
if (!session->outbuf.size())
return -1;
int ret = SSL_write(session->sess, session->outbuf.data(), session->outbuf.size());
if (ret == 0)
{
ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_write");
CloseSession(session);
return 0;
}
else if (ret < 0)
{
int err = SSL_get_error(session->sess, ret);
if (err == SSL_ERROR_WANT_WRITE)
{
session->wstat = ISSL_WRITE;
return -1;
}
else if (err == SSL_ERROR_WANT_READ)
{
session->wstat = ISSL_READ;
return -1;
}
else
{
ServerInstance->Log(DEBUG,"Close due to returned -1 in SSL_Write");
CloseSession(session);
return 0;
}
}
else
{
session->outbuf = session->outbuf.substr(ret);
return ret;
}
}
int DoRead(issl_session* session)
{
// Is this right? Not sure if the unencrypted data is garaunteed to be the same length.
// Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet.
ServerInstance->Log(DEBUG,"DoRead");
int ret = SSL_read(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);
if (ret == 0)
{
// Client closed connection.
ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_read");
CloseSession(session);
return 0;
}
else if (ret < 0)
{
int err = SSL_get_error(session->sess, ret);
if (err == SSL_ERROR_WANT_READ)
{
session->rstat = ISSL_READ;
ServerInstance->Log(DEBUG,"Setting want_read");
return -1;
}
else if (err == SSL_ERROR_WANT_WRITE)
{
session->rstat = ISSL_WRITE;
ServerInstance->Log(DEBUG,"Setting want_write");
return -1;
}
else
{
ServerInstance->Log(DEBUG,"Closed due to returned -1 in SSL_Read");
CloseSession(session);
return 0;
}
}
else
{
// Read successfully 'ret' bytes into inbuf + inbufoffset
// There are 'ret' + 'inbufoffset' bytes of data in 'inbuf'
// 'buffer' is 'count' long
session->inbufoffset += ret;
return ret;
}
}
// :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection
virtual void OnWhois(userrec* source, userrec* dest)
{
if (!clientactive)
return;
// Bugfix, only send this numeric for *our* SSL users
if (dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) && isin(dest->GetPort(), listenports)))
{
ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
}
}
virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
{
// check if the linking module wants to know about OUR metadata
if (extname == "ssl")
{
// check if this user has an swhois field to send
if(user->GetExt(extname, dummy))
{
// call this function in the linking module, let it format the data how it
// sees fit, and send it on its way. We dont need or want to know how.
proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");
}
}
}
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
// check if its our metadata key, and its associated with a user
if ((target_type == TYPE_USER) && (extname == "ssl"))
{
userrec* dest = (userrec*)target;
// if they dont already have an ssl flag, accept the remote server's
if (!dest->GetExt(extname, dummy))
{
dest->Extend(extname, "ON");
}
}
}
bool Handshake(issl_session* session)
{
ServerInstance->Log(DEBUG,"Handshake");
int ret;
if (session->outbound)
{
ServerInstance->Log(DEBUG,"SSL_connect");
ret = SSL_connect(session->sess);
}
else
ret = SSL_accept(session->sess);
if (ret < 0)
{
int err = SSL_get_error(session->sess, ret);
if (err == SSL_ERROR_WANT_READ)
{
ServerInstance->Log(DEBUG,"Want read, handshaking");
session->rstat = ISSL_READ;
session->status = ISSL_HANDSHAKING;
return true;
}
else if (err == SSL_ERROR_WANT_WRITE)
{
ServerInstance->Log(DEBUG,"Want write, handshaking");
session->wstat = ISSL_WRITE;
session->status = ISSL_HANDSHAKING;
MakePollWrite(session);
return true;
}
else
{
ServerInstance->Log(DEBUG,"Handshake failed");
CloseSession(session);
}
return false;
}
else if (ret > 0)
{
// Handshake complete.
// This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater.
userrec* u = ServerInstance->FindDescriptor(session->fd);
if (u)
{
if (!u->GetExt("ssl", dummy))
u->Extend("ssl", "ON");
}
session->status = ISSL_OPEN;
MakePollWrite(session);
return true;
}
else if (ret == 0)
{
int ssl_err = SSL_get_error(session->sess, ret);
char buf[1024];
ERR_print_errors_fp(stderr);
ServerInstance->Log(DEBUG,"Handshake fail 2: %d: %s", ssl_err, ERR_error_string(ssl_err,buf));
CloseSession(session);
return true;
}
return true;
}
virtual void OnPostConnect(userrec* user)
{
// This occurs AFTER OnUserConnect so we can be sure the
// protocol module has propogated the NICK message.
if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))
{
// Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW.
std::deque<std::string>* metadata = new std::deque<std::string>;
metadata->push_back(user->nick);
metadata->push_back("ssl"); // The metadata id
metadata->push_back("ON"); // The value to send
Event* event = new Event((char*)metadata,(Module*)this,"send_metadata");
event->Send(ServerInstance); // Trigger the event. We don't care what module picks it up.
DELETE(event);
DELETE(metadata);
VerifyCertificate(&sessions[user->GetFd()], user);
if (sessions[user->GetFd()].sess)
user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, SSL_get_cipher(sessions[user->GetFd()].sess));
}
}
void MakePollWrite(issl_session* session)
{
OnRawSocketWrite(session->fd, NULL, 0);
//EventHandler* eh = ServerInstance->FindDescriptor(session->fd);
//if (eh)
// ServerInstance->SE->WantWrite(eh);
}
void CloseSession(issl_session* session)
{
if (session->sess)
{
SSL_shutdown(session->sess);
SSL_free(session->sess);
}
if (session->inbuf)
{
delete[] session->inbuf;
}
session->outbuf.clear();
session->inbuf = NULL;
session->sess = NULL;
session->status = ISSL_NONE;
}
void VerifyCertificate(issl_session* session, Extensible* user)
{
if (!session->sess || !user)
return;
X509* cert;
ssl_cert* certinfo = new ssl_cert;
unsigned int n;
unsigned char md[EVP_MAX_MD_SIZE];
const EVP_MD *digest = EVP_md5();
user->Extend("ssl_cert",certinfo);
cert = SSL_get_peer_certificate((SSL*)session->sess);
if (!cert)
{
certinfo->data.insert(std::make_pair("error","Could not get peer certificate: "+std::string(get_error())));
return;
}
certinfo->data.insert(std::make_pair("invalid", SSL_get_verify_result(session->sess) != X509_V_OK ? ConvToStr(1) : ConvToStr(0)));
if (SelfSigned)
{
certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0)));
certinfo->data.insert(std::make_pair("trusted",ConvToStr(1)));
}
else
{
certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1)));
certinfo->data.insert(std::make_pair("trusted",ConvToStr(0)));
}
certinfo->data.insert(std::make_pair("dn",std::string(X509_NAME_oneline(X509_get_subject_name(cert),0,0))));
certinfo->data.insert(std::make_pair("issuer",std::string(X509_NAME_oneline(X509_get_issuer_name(cert),0,0))));
if (!X509_digest(cert, digest, md, &n))
{
certinfo->data.insert(std::make_pair("error","Out of memory generating fingerprint"));
}
else
{
certinfo->data.insert(std::make_pair("fingerprint",irc::hex(md, n)));
}
if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), time(NULL)) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), time(NULL)) == 0))
{
certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate"));
}
X509_free(cert);
}
};
static int error_callback(const char *str, size_t len, void *u)
{
ModuleSSLOpenSSL* mssl = (ModuleSSLOpenSSL*)u;
mssl->PublicInstance->Log(DEFAULT, "SSL error: " + std::string(str, len - 1));
return 0;
}
MODULE_INIT(ModuleSSLOpenSSL);
\ No newline at end of file diff --git a/src/modules/extra/m_ssl_oper_cert.cpp b/src/modules/extra/m_ssl_oper_cert.cpp index c67b50c8c..7b1c90868 100644 --- a/src/modules/extra/m_ssl_oper_cert.cpp +++ b/src/modules/extra/m_ssl_oper_cert.cpp @@ -1,180 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Allows for MD5 encrypted oper passwords */ -/* $ModDep: transport.h */ - -#include "inspircd.h" -#include "inspircd_config.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "transport.h" -#include "wildcard.h" - -/** Handle /FINGERPRINT - */ -class cmd_fingerprint : public command_t -{ - public: - cmd_fingerprint (InspIRCd* Instance) : command_t(Instance,"FINGERPRINT", 0, 1) - { - this->source = "m_ssl_oper_cert.so"; - syntax = "<nickname>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* target = ServerInstance->FindNick(parameters[0]); - if (target) - { - ssl_cert* cert; - if (target->GetExt("ssl_cert",cert)) - { - if (cert->GetFingerprint().length()) - { - user->WriteServ("NOTICE %s :Certificate fingerprint for %s is %s",user->nick,target->nick,cert->GetFingerprint().c_str()); - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick,target->nick); - return CMD_FAILURE; - } - } - else - { - user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick, target->nick); - return CMD_FAILURE; - } - } - else - { - user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]); - return CMD_FAILURE; - } - } -}; - - - -class ModuleOperSSLCert : public Module -{ - ssl_cert* cert; - bool HasCert; - cmd_fingerprint* mycommand; - ConfigReader* cf; - public: - - ModuleOperSSLCert(InspIRCd* Me) - : Module(Me) - { - mycommand = new cmd_fingerprint(ServerInstance); - ServerInstance->AddCommand(mycommand); - cf = new ConfigReader(ServerInstance); - } - - virtual ~ModuleOperSSLCert() - { - delete cf; - } - - void Implements(char* List) - { - List[I_OnPreCommand] = List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - delete cf; - cf = new ConfigReader(ServerInstance); - } - - bool OneOfMatches(const char* host, const char* ip, const char* hostlist) - { - std::stringstream hl(hostlist); - std::string xhost; - while (hl >> xhost) - { - if (match(host,xhost.c_str()) || match(ip,xhost.c_str(),true)) - { - return true; - } - } - return false; - } - - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - irc::string cmd = command.c_str(); - - if ((cmd == "OPER") && (validated)) - { - char TheHost[MAXBUF]; - char TheIP[MAXBUF]; - std::string LoginName; - std::string Password; - std::string OperType; - std::string HostName; - std::string FingerPrint; - bool SSLOnly; - char* dummy; - - snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host); - snprintf(TheIP, MAXBUF,"%s@%s",user->ident,user->GetIPString()); - - HasCert = user->GetExt("ssl_cert",cert); - - for (int i = 0; i < cf->Enumerate("oper"); i++) - { - LoginName = cf->ReadValue("oper", "name", i); - Password = cf->ReadValue("oper", "password", i); - OperType = cf->ReadValue("oper", "type", i); - HostName = cf->ReadValue("oper", "host", i); - FingerPrint = cf->ReadValue("oper", "fingerprint", i); - SSLOnly = cf->ReadFlag("oper", "sslonly", i); - - if (SSLOnly || !FingerPrint.empty()) - { - if ((!strcmp(LoginName.c_str(),parameters[0])) && (!ServerInstance->OperPassCompare(Password.c_str(),parameters[1],i)) && (OneOfMatches(TheHost,TheIP,HostName.c_str()))) - { - if (SSLOnly && !user->GetExt("ssl", dummy)) - { - user->WriteServ("491 %s :This oper login name requires an SSL connection.", user->nick); - return 1; - } - - /* This oper would match */ - if ((!cert) || (cert->GetFingerprint() != FingerPrint)) - { - user->WriteServ("491 %s :This oper login name requires a matching key fingerprint.",user->nick); - ServerInstance->SNO->WriteToSnoMask('o',"'%s' cannot oper, does not match fingerprint", user->nick); - ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but wrong fingerprint.",user->nick,user->ident,user->host); - return 1; - } - } - } - } - } - return 0; - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleOperSSLCert); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Allows for MD5 encrypted oper passwords */
/* $ModDep: transport.h */
#include "inspircd.h"
#include "inspircd_config.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "transport.h"
#include "wildcard.h"
/** Handle /FINGERPRINT
*/
class cmd_fingerprint : public command_t
{
public:
cmd_fingerprint (InspIRCd* Instance) : command_t(Instance,"FINGERPRINT", 0, 1)
{
this->source = "m_ssl_oper_cert.so";
syntax = "<nickname>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* target = ServerInstance->FindNick(parameters[0]);
if (target)
{
ssl_cert* cert;
if (target->GetExt("ssl_cert",cert))
{
if (cert->GetFingerprint().length())
{
user->WriteServ("NOTICE %s :Certificate fingerprint for %s is %s",user->nick,target->nick,cert->GetFingerprint().c_str());
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick,target->nick);
return CMD_FAILURE;
}
}
else
{
user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick, target->nick);
return CMD_FAILURE;
}
}
else
{
user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]);
return CMD_FAILURE;
}
}
};
class ModuleOperSSLCert : public Module
{
ssl_cert* cert;
bool HasCert;
cmd_fingerprint* mycommand;
ConfigReader* cf;
public:
ModuleOperSSLCert(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_fingerprint(ServerInstance);
ServerInstance->AddCommand(mycommand);
cf = new ConfigReader(ServerInstance);
}
virtual ~ModuleOperSSLCert()
{
delete cf;
}
void Implements(char* List)
{
List[I_OnPreCommand] = List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
delete cf;
cf = new ConfigReader(ServerInstance);
}
bool OneOfMatches(const char* host, const char* ip, const char* hostlist)
{
std::stringstream hl(hostlist);
std::string xhost;
while (hl >> xhost)
{
if (match(host,xhost.c_str()) || match(ip,xhost.c_str(),true))
{
return true;
}
}
return false;
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
irc::string cmd = command.c_str();
if ((cmd == "OPER") && (validated))
{
char TheHost[MAXBUF];
char TheIP[MAXBUF];
std::string LoginName;
std::string Password;
std::string OperType;
std::string HostName;
std::string FingerPrint;
bool SSLOnly;
char* dummy;
snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host);
snprintf(TheIP, MAXBUF,"%s@%s",user->ident,user->GetIPString());
HasCert = user->GetExt("ssl_cert",cert);
for (int i = 0; i < cf->Enumerate("oper"); i++)
{
LoginName = cf->ReadValue("oper", "name", i);
Password = cf->ReadValue("oper", "password", i);
OperType = cf->ReadValue("oper", "type", i);
HostName = cf->ReadValue("oper", "host", i);
FingerPrint = cf->ReadValue("oper", "fingerprint", i);
SSLOnly = cf->ReadFlag("oper", "sslonly", i);
if (SSLOnly || !FingerPrint.empty())
{
if ((!strcmp(LoginName.c_str(),parameters[0])) && (!ServerInstance->OperPassCompare(Password.c_str(),parameters[1],i)) && (OneOfMatches(TheHost,TheIP,HostName.c_str())))
{
if (SSLOnly && !user->GetExt("ssl", dummy))
{
user->WriteServ("491 %s :This oper login name requires an SSL connection.", user->nick);
return 1;
}
/* This oper would match */
if ((!cert) || (cert->GetFingerprint() != FingerPrint))
{
user->WriteServ("491 %s :This oper login name requires a matching key fingerprint.",user->nick);
ServerInstance->SNO->WriteToSnoMask('o',"'%s' cannot oper, does not match fingerprint", user->nick);
ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but wrong fingerprint.",user->nick,user->ident,user->host);
return 1;
}
}
}
}
}
return 0;
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleOperSSLCert);
\ No newline at end of file diff --git a/src/modules/extra/m_sslinfo.cpp b/src/modules/extra/m_sslinfo.cpp index dc9274f1e..83de798c8 100644 --- a/src/modules/extra/m_sslinfo.cpp +++ b/src/modules/extra/m_sslinfo.cpp @@ -1,94 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "transport.h" -#include "wildcard.h" -#include "dns.h" - -/* $ModDesc: Provides /sslinfo command used to test who a mask matches */ -/* $ModDep: transport.h */ - -/** Handle /SSLINFO - */ -class cmd_sslinfo : public command_t -{ - public: - cmd_sslinfo (InspIRCd* Instance) : command_t(Instance,"SSLINFO", 0, 1) - { - this->source = "m_sslinfo.so"; - this->syntax = "<nick>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* target = ServerInstance->FindNick(parameters[0]); - ssl_cert* cert; - - if (target) - { - if (target->GetExt("ssl_cert", cert)) - { - if (cert->GetError().length()) - { - user->WriteServ("NOTICE %s :*** Error: %s", user->nick, cert->GetError().c_str()); - } - user->WriteServ("NOTICE %s :*** Distinguised Name: %s", user->nick, cert->GetDN().c_str()); - user->WriteServ("NOTICE %s :*** Issuer: %s", user->nick, cert->GetIssuer().c_str()); - user->WriteServ("NOTICE %s :*** Key Fingerprint: %s", user->nick, cert->GetFingerprint().c_str()); - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE %s :*** No SSL certificate information for this user.", user->nick); - return CMD_FAILURE; - } - } - else - user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]); - - return CMD_FAILURE; - } -}; - -class ModuleSSLInfo : public Module -{ - cmd_sslinfo* newcommand; - public: - ModuleSSLInfo(InspIRCd* Me) - : Module(Me) - { - - newcommand = new cmd_sslinfo(ServerInstance); - ServerInstance->AddCommand(newcommand); - } - - void Implements(char* List) - { - } - - virtual ~ModuleSSLInfo() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleSSLInfo); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "transport.h"
#include "wildcard.h"
#include "dns.h"
/* $ModDesc: Provides /sslinfo command used to test who a mask matches */
/* $ModDep: transport.h */
/** Handle /SSLINFO
*/
class cmd_sslinfo : public command_t
{
public:
cmd_sslinfo (InspIRCd* Instance) : command_t(Instance,"SSLINFO", 0, 1)
{
this->source = "m_sslinfo.so";
this->syntax = "<nick>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* target = ServerInstance->FindNick(parameters[0]);
ssl_cert* cert;
if (target)
{
if (target->GetExt("ssl_cert", cert))
{
if (cert->GetError().length())
{
user->WriteServ("NOTICE %s :*** Error: %s", user->nick, cert->GetError().c_str());
}
user->WriteServ("NOTICE %s :*** Distinguised Name: %s", user->nick, cert->GetDN().c_str());
user->WriteServ("NOTICE %s :*** Issuer: %s", user->nick, cert->GetIssuer().c_str());
user->WriteServ("NOTICE %s :*** Key Fingerprint: %s", user->nick, cert->GetFingerprint().c_str());
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE %s :*** No SSL certificate information for this user.", user->nick);
return CMD_FAILURE;
}
}
else
user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]);
return CMD_FAILURE;
}
};
class ModuleSSLInfo : public Module
{
cmd_sslinfo* newcommand;
public:
ModuleSSLInfo(InspIRCd* Me)
: Module(Me)
{
newcommand = new cmd_sslinfo(ServerInstance);
ServerInstance->AddCommand(newcommand);
}
void Implements(char* List)
{
}
virtual ~ModuleSSLInfo()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleSSLInfo);
\ No newline at end of file diff --git a/src/modules/extra/m_testclient.cpp b/src/modules/extra/m_testclient.cpp index f4e58b7b5..a867dad20 100644 --- a/src/modules/extra/m_testclient.cpp +++ b/src/modules/extra/m_testclient.cpp @@ -1,110 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" -#include "m_sqlv2.h" - -class ModuleTestClient : public Module -{ -private: - - -public: - ModuleTestClient(InspIRCd* Me) - : Module::Module(Me) - { - } - - void Implements(char* List) - { - List[I_OnRequest] = List[I_OnBackgroundTimer] = 1; - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - - virtual void OnBackgroundTimer(time_t foo) - { - Module* target = ServerInstance->FindFeature("SQL"); - - if(target) - { - SQLrequest foo = SQLreq(this, target, "foo", "UPDATE rawr SET foo = '?' WHERE bar = 42", ConvToStr(time(NULL))); - - if(foo.Send()) - { - ServerInstance->Log(DEBUG, "Sent query, got given ID %lu", foo.id); - } - else - { - ServerInstance->Log(DEBUG, "SQLrequest failed: %s", foo.error.Str()); - } - } - } - - virtual char* OnRequest(Request* request) - { - if(strcmp(SQLRESID, request->GetId()) == 0) - { - ServerInstance->Log(DEBUG, "Got SQL result (%s)", request->GetId()); - - SQLresult* res = (SQLresult*)request; - - if (res->error.Id() == NO_ERROR) - { - if(res->Cols()) - { - ServerInstance->Log(DEBUG, "Got result with %d rows and %d columns", res->Rows(), res->Cols()); - - for (int r = 0; r < res->Rows(); r++) - { - ServerInstance->Log(DEBUG, "Row %d:", r); - - for(int i = 0; i < res->Cols(); i++) - { - ServerInstance->Log(DEBUG, "\t[%s]: %s", res->ColName(i).c_str(), res->GetValue(r, i).d.c_str()); - } - } - } - else - { - ServerInstance->Log(DEBUG, "%d rows affected in query", res->Rows()); - } - } - else - { - ServerInstance->Log(DEBUG, "SQLrequest failed: %s", res->error.Str()); - - } - - return SQLSUCCESS; - } - - ServerInstance->Log(DEBUG, "Got unsupported API version string: %s", request->GetId()); - - return NULL; - } - - virtual ~ModuleTestClient() - { - } -}; - -MODULE_INIT(ModuleTestClient); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
#include "m_sqlv2.h"
class ModuleTestClient : public Module
{
private:
public:
ModuleTestClient(InspIRCd* Me)
: Module::Module(Me)
{
}
void Implements(char* List)
{
List[I_OnRequest] = List[I_OnBackgroundTimer] = 1;
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
virtual void OnBackgroundTimer(time_t foo)
{
Module* target = ServerInstance->FindFeature("SQL");
if(target)
{
SQLrequest foo = SQLreq(this, target, "foo", "UPDATE rawr SET foo = '?' WHERE bar = 42", ConvToStr(time(NULL)));
if(foo.Send())
{
ServerInstance->Log(DEBUG, "Sent query, got given ID %lu", foo.id);
}
else
{
ServerInstance->Log(DEBUG, "SQLrequest failed: %s", foo.error.Str());
}
}
}
virtual char* OnRequest(Request* request)
{
if(strcmp(SQLRESID, request->GetId()) == 0)
{
ServerInstance->Log(DEBUG, "Got SQL result (%s)", request->GetId());
SQLresult* res = (SQLresult*)request;
if (res->error.Id() == NO_ERROR)
{
if(res->Cols())
{
ServerInstance->Log(DEBUG, "Got result with %d rows and %d columns", res->Rows(), res->Cols());
for (int r = 0; r < res->Rows(); r++)
{
ServerInstance->Log(DEBUG, "Row %d:", r);
for(int i = 0; i < res->Cols(); i++)
{
ServerInstance->Log(DEBUG, "\t[%s]: %s", res->ColName(i).c_str(), res->GetValue(r, i).d.c_str());
}
}
}
else
{
ServerInstance->Log(DEBUG, "%d rows affected in query", res->Rows());
}
}
else
{
ServerInstance->Log(DEBUG, "SQLrequest failed: %s", res->error.Str());
}
return SQLSUCCESS;
}
ServerInstance->Log(DEBUG, "Got unsupported API version string: %s", request->GetId());
return NULL;
}
virtual ~ModuleTestClient()
{
}
};
MODULE_INIT(ModuleTestClient);
\ No newline at end of file diff --git a/src/modules/extra/m_ziplink.cpp b/src/modules/extra/m_ziplink.cpp index e815d1042..2a127258d 100644 --- a/src/modules/extra/m_ziplink.cpp +++ b/src/modules/extra/m_ziplink.cpp @@ -1,452 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <zlib.h> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "socket.h" -#include "hashcomp.h" -#include "transport.h" - -/* $ModDesc: Provides zlib link support for servers */ -/* $LinkerFlags: -lz */ -/* $ModDep: transport.h */ - -/* - * Compressed data is transmitted across the link in the following format: - * - * 0 1 2 3 4 ... n - * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - * | n | Z0 -> Zn | - * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - * - * Where: n is the size of a frame, in network byte order, 4 bytes. - * Z0 through Zn are Zlib compressed data, n bytes in length. - * - * If the module fails to read the entire frame, then it will buffer - * the portion of the last frame it received, then attempt to read - * the next part of the frame next time a write notification arrives. - * - * ZLIB_BEST_COMPRESSION (9) is used for all sending of data with - * a flush after each frame. A frame may contain multiple lines - * and should be treated as raw binary data. - * - */ - -/* Status of a connection */ -enum izip_status { IZIP_OPEN, IZIP_CLOSED }; - -/* Maximum transfer size per read operation */ -const unsigned int CHUNK = 128 * 1024; - -/* This class manages a compressed chunk of data preceeded by - * a length count. - * - * It can handle having multiple chunks of data in the buffer - * at any time. - */ -class CountedBuffer : public classbase -{ - std::string buffer; /* Current buffer contents */ - unsigned int amount_expected; /* Amount of data expected */ - public: - CountedBuffer() - { - amount_expected = 0; - } - - /** Adds arbitrary compressed data to the buffer. - * - Binsry safe, of course. - */ - void AddData(unsigned char* data, int data_length) - { - buffer.append((const char*)data, data_length); - this->NextFrameSize(); - } - - /** Works out the size of the next compressed frame - */ - void NextFrameSize() - { - if ((!amount_expected) && (buffer.length() >= 4)) - { - /* We have enough to read an int - - * Yes, this is safe, but its ugly. Give me - * a nicer way to read 4 bytes from a binary - * stream, and push them into a 32 bit int, - * and i'll consider replacing this. - */ - amount_expected = ntohl((buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]); - buffer = buffer.substr(4); - } - } - - /** Gets the next frame and returns its size, or returns - * zero if there isnt one available yet. - * A frame can contain multiple plaintext lines. - * - Binary safe. - */ - int GetFrame(unsigned char* frame, int maxsize) - { - if (amount_expected) - { - /* We know how much we're expecting... - * Do we have enough yet? - */ - if (buffer.length() >= amount_expected) - { - int j = 0; - for (unsigned int i = 0; i < amount_expected; i++, j++) - frame[i] = buffer[i]; - - buffer = buffer.substr(j); - amount_expected = 0; - NextFrameSize(); - return j; - } - } - /* Not enough for a frame yet, COME AGAIN! */ - return 0; - } -}; - -/** Represents an zipped connections extra data - */ -class izip_session : public classbase -{ - public: - z_stream c_stream; /* compression stream */ - z_stream d_stream; /* decompress stream */ - izip_status status; /* Connection status */ - int fd; /* File descriptor */ - CountedBuffer* inbuf; /* Holds input buffer */ - std::string outbuf; /* Holds output buffer */ -}; - -class ModuleZLib : public Module -{ - izip_session sessions[MAX_DESCRIPTORS]; - - /* Used for stats z extensions */ - float total_out_compressed; - float total_in_compressed; - float total_out_uncompressed; - float total_in_uncompressed; - - public: - - ModuleZLib(InspIRCd* Me) - : Module::Module(Me) - { - ServerInstance->PublishInterface("InspSocketHook", this); - - total_out_compressed = total_in_compressed = 0; - total_out_uncompressed = total_out_uncompressed = 0; - } - - virtual ~ModuleZLib() - { - ServerInstance->UnpublishInterface("InspSocketHook", this); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = 1; - List[I_OnStats] = List[I_OnRequest] = 1; - } - - /* Handle InspSocketHook API requests */ - virtual char* OnRequest(Request* request) - { - ISHRequest* ISR = (ISHRequest*)request; - if (strcmp("IS_NAME", request->GetId()) == 0) - { - /* Return name */ - return "zip"; - } - else if (strcmp("IS_HOOK", request->GetId()) == 0) - { - /* Attach to an inspsocket */ - char* ret = "OK"; - try - { - ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL; - } - catch (ModuleException& e) - { - return NULL; - } - return ret; - } - else if (strcmp("IS_UNHOOK", request->GetId()) == 0) - { - /* Detatch from an inspsocket */ - return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL; - } - else if (strcmp("IS_HSDONE", request->GetId()) == 0) - { - /* Check for completion of handshake - * (actually, this module doesnt handshake) - */ - return "OK"; - } - else if (strcmp("IS_ATTACH", request->GetId()) == 0) - { - /* Attach certificate data to the inspsocket - * (this module doesnt do that, either) - */ - return NULL; - } - return NULL; - } - - /* Handle stats z (misc stats) */ - virtual int OnStats(char symbol, userrec* user, string_list &results) - { - if (symbol == 'z') - { - std::string sn = ServerInstance->Config->ServerName; - - /* Yeah yeah, i know, floats are ew. - * We used them here because we'd be casting to float anyway to do this maths, - * and also only floating point numbers can deal with the pretty large numbers - * involved in the total throughput of a server over a large period of time. - * (we dont count 64 bit ints because not all systems have 64 bit ints, and floats - * can still hold more. - */ - float outbound_r = 100 - ((total_out_compressed / (total_out_uncompressed + 0.001)) * 100); - float inbound_r = 100 - ((total_in_compressed / (total_in_uncompressed + 0.001)) * 100); - - float total_compressed = total_in_compressed + total_out_compressed; - float total_uncompressed = total_in_uncompressed + total_out_uncompressed; - - float total_r = 100 - ((total_compressed / (total_uncompressed + 0.001)) * 100); - - char outbound_ratio[MAXBUF], inbound_ratio[MAXBUF], combined_ratio[MAXBUF]; - - sprintf(outbound_ratio, "%3.2f%%", outbound_r); - sprintf(inbound_ratio, "%3.2f%%", inbound_r); - sprintf(combined_ratio, "%3.2f%%", total_r); - - results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_compressed = "+ConvToStr(total_out_compressed)); - results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_compressed = "+ConvToStr(total_in_compressed)); - results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_uncompressed = "+ConvToStr(total_out_uncompressed)); - results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_uncompressed = "+ConvToStr(total_in_uncompressed)); - results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_ratio = "+outbound_ratio); - results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_ratio = "+inbound_ratio); - results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS combined_ratio = "+combined_ratio); - return 0; - } - - return 0; - } - - virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport) - { - izip_session* session = &sessions[fd]; - - /* allocate state and buffers */ - session->fd = fd; - session->status = IZIP_OPEN; - session->inbuf = new CountedBuffer(); - - session->c_stream.zalloc = (alloc_func)0; - session->c_stream.zfree = (free_func)0; - session->c_stream.opaque = (voidpf)0; - - session->d_stream.zalloc = (alloc_func)0; - session->d_stream.zfree = (free_func)0; - session->d_stream.opaque = (voidpf)0; - } - - virtual void OnRawSocketConnect(int fd) - { - /* Nothing special needs doing here compared to accept() */ - OnRawSocketAccept(fd, "", 0); - } - - virtual void OnRawSocketClose(int fd) - { - CloseSession(&sessions[fd]); - } - - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) - { - /* Find the sockets session */ - izip_session* session = &sessions[fd]; - - if (session->status == IZIP_CLOSED) - return 0; - - unsigned char compr[CHUNK + 4]; - unsigned int offset = 0; - unsigned int total_size = 0; - - /* Read CHUNK bytes at a time to the buffer (usually 128k) */ - readresult = read(fd, compr, CHUNK); - - /* Did we get anything? */ - if (readresult > 0) - { - /* Add it to the frame queue */ - session->inbuf->AddData(compr, readresult); - total_in_compressed += readresult; - - /* Parse all completed frames */ - int size = 0; - while ((size = session->inbuf->GetFrame(compr, CHUNK)) != 0) - { - session->d_stream.next_in = (Bytef*)compr; - session->d_stream.avail_in = 0; - session->d_stream.next_out = (Bytef*)(buffer + offset); - - /* If we cant call this, well, we're boned. */ - if (inflateInit(&session->d_stream) != Z_OK) - return 0; - - while ((session->d_stream.total_out < count) && (session->d_stream.total_in < (unsigned int)size)) - { - session->d_stream.avail_in = session->d_stream.avail_out = 1; - if (inflate(&session->d_stream, Z_NO_FLUSH) == Z_STREAM_END) - break; - } - - /* Stick a fork in me, i'm done */ - inflateEnd(&session->d_stream); - - /* Update counters and offsets */ - total_size += session->d_stream.total_out; - total_in_uncompressed += session->d_stream.total_out; - offset += session->d_stream.total_out; - } - - /* Null-terminate the buffer -- this doesnt harm binary data */ - buffer[total_size] = 0; - - /* Set the read size to the correct total size */ - readresult = total_size; - - } - return (readresult > 0); - } - - virtual int OnRawSocketWrite(int fd, const char* buffer, int count) - { - izip_session* session = &sessions[fd]; - int ocount = count; - - if (!count) /* Nothing to do! */ - return 0; - - if(session->status != IZIP_OPEN) - { - /* Seriously, wtf? */ - CloseSession(session); - return 0; - } - - unsigned char compr[CHUNK + 4]; - - /* Gentlemen, start your engines! */ - if (deflateInit(&session->c_stream, Z_BEST_COMPRESSION) != Z_OK) - { - CloseSession(session); - return 0; - } - - /* Set buffer sizes (we reserve 4 bytes at the start of the - * buffer for the length counters) - */ - session->c_stream.next_in = (Bytef*)buffer; - session->c_stream.next_out = compr + 4; - - /* Compress the text */ - while ((session->c_stream.total_in < (unsigned int)count) && (session->c_stream.total_out < CHUNK)) - { - session->c_stream.avail_in = session->c_stream.avail_out = 1; - if (deflate(&session->c_stream, Z_NO_FLUSH) != Z_OK) - { - CloseSession(session); - return 0; - } - } - /* Finish the stream */ - for (session->c_stream.avail_out = 1; deflate(&session->c_stream, Z_FINISH) != Z_STREAM_END; session->c_stream.avail_out = 1); - deflateEnd(&session->c_stream); - - total_out_uncompressed += ocount; - total_out_compressed += session->c_stream.total_out; - - /** Assemble the frame length onto the frame, in network byte order */ - compr[0] = (session->c_stream.total_out >> 24); - compr[1] = (session->c_stream.total_out >> 16); - compr[2] = (session->c_stream.total_out >> 8); - compr[3] = (session->c_stream.total_out & 0xFF); - - /* Add compressed data plus leading length to the output buffer - - * Note, we may have incomplete half-sent frames in here. - */ - session->outbuf.append((const char*)compr, session->c_stream.total_out + 4); - - /* Lets see how much we can send out */ - int ret = write(fd, session->outbuf.data(), session->outbuf.length()); - - /* Check for errors, and advance the buffer if any was sent */ - if (ret > 0) - session->outbuf = session->outbuf.substr(ret); - else if (ret < 1) - { - if (ret == -1) - { - if (errno == EAGAIN) - return 0; - else - { - session->outbuf.clear(); - return 0; - } - } - else - { - session->outbuf.clear(); - return 0; - } - } - - /* ALL LIES the lot of it, we havent really written - * this amount, but the layer above doesnt need to know. - */ - return ocount; - } - - void CloseSession(izip_session* session) - { - if (session->status == IZIP_OPEN) - { - session->status = IZIP_CLOSED; - session->outbuf.clear(); - delete session->inbuf; - } - } - -}; - -MODULE_INIT(ModuleZLib); - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <zlib.h>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "socket.h"
#include "hashcomp.h"
#include "transport.h"
/* $ModDesc: Provides zlib link support for servers */
/* $LinkerFlags: -lz */
/* $ModDep: transport.h */
/*
* Compressed data is transmitted across the link in the following format:
*
* 0 1 2 3 4 ... n
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | n | Z0 -> Zn |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* Where: n is the size of a frame, in network byte order, 4 bytes.
* Z0 through Zn are Zlib compressed data, n bytes in length.
*
* If the module fails to read the entire frame, then it will buffer
* the portion of the last frame it received, then attempt to read
* the next part of the frame next time a write notification arrives.
*
* ZLIB_BEST_COMPRESSION (9) is used for all sending of data with
* a flush after each frame. A frame may contain multiple lines
* and should be treated as raw binary data.
*
*/
/* Status of a connection */
enum izip_status { IZIP_OPEN, IZIP_CLOSED };
/* Maximum transfer size per read operation */
const unsigned int CHUNK = 128 * 1024;
/* This class manages a compressed chunk of data preceeded by
* a length count.
*
* It can handle having multiple chunks of data in the buffer
* at any time.
*/
class CountedBuffer : public classbase
{
std::string buffer; /* Current buffer contents */
unsigned int amount_expected; /* Amount of data expected */
public:
CountedBuffer()
{
amount_expected = 0;
}
/** Adds arbitrary compressed data to the buffer.
* - Binsry safe, of course.
*/
void AddData(unsigned char* data, int data_length)
{
buffer.append((const char*)data, data_length);
this->NextFrameSize();
}
/** Works out the size of the next compressed frame
*/
void NextFrameSize()
{
if ((!amount_expected) && (buffer.length() >= 4))
{
/* We have enough to read an int -
* Yes, this is safe, but its ugly. Give me
* a nicer way to read 4 bytes from a binary
* stream, and push them into a 32 bit int,
* and i'll consider replacing this.
*/
amount_expected = ntohl((buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]);
buffer = buffer.substr(4);
}
}
/** Gets the next frame and returns its size, or returns
* zero if there isnt one available yet.
* A frame can contain multiple plaintext lines.
* - Binary safe.
*/
int GetFrame(unsigned char* frame, int maxsize)
{
if (amount_expected)
{
/* We know how much we're expecting...
* Do we have enough yet?
*/
if (buffer.length() >= amount_expected)
{
int j = 0;
for (unsigned int i = 0; i < amount_expected; i++, j++)
frame[i] = buffer[i];
buffer = buffer.substr(j);
amount_expected = 0;
NextFrameSize();
return j;
}
}
/* Not enough for a frame yet, COME AGAIN! */
return 0;
}
};
/** Represents an zipped connections extra data
*/
class izip_session : public classbase
{
public:
z_stream c_stream; /* compression stream */
z_stream d_stream; /* decompress stream */
izip_status status; /* Connection status */
int fd; /* File descriptor */
CountedBuffer* inbuf; /* Holds input buffer */
std::string outbuf; /* Holds output buffer */
};
class ModuleZLib : public Module
{
izip_session sessions[MAX_DESCRIPTORS];
/* Used for stats z extensions */
float total_out_compressed;
float total_in_compressed;
float total_out_uncompressed;
float total_in_uncompressed;
public:
ModuleZLib(InspIRCd* Me)
: Module::Module(Me)
{
ServerInstance->PublishInterface("InspSocketHook", this);
total_out_compressed = total_in_compressed = 0;
total_out_uncompressed = total_out_uncompressed = 0;
}
virtual ~ModuleZLib()
{
ServerInstance->UnpublishInterface("InspSocketHook", this);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = 1;
List[I_OnStats] = List[I_OnRequest] = 1;
}
/* Handle InspSocketHook API requests */
virtual char* OnRequest(Request* request)
{
ISHRequest* ISR = (ISHRequest*)request;
if (strcmp("IS_NAME", request->GetId()) == 0)
{
/* Return name */
return "zip";
}
else if (strcmp("IS_HOOK", request->GetId()) == 0)
{
/* Attach to an inspsocket */
char* ret = "OK";
try
{
ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
}
catch (ModuleException& e)
{
return NULL;
}
return ret;
}
else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
{
/* Detatch from an inspsocket */
return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
}
else if (strcmp("IS_HSDONE", request->GetId()) == 0)
{
/* Check for completion of handshake
* (actually, this module doesnt handshake)
*/
return "OK";
}
else if (strcmp("IS_ATTACH", request->GetId()) == 0)
{
/* Attach certificate data to the inspsocket
* (this module doesnt do that, either)
*/
return NULL;
}
return NULL;
}
/* Handle stats z (misc stats) */
virtual int OnStats(char symbol, userrec* user, string_list &results)
{
if (symbol == 'z')
{
std::string sn = ServerInstance->Config->ServerName;
/* Yeah yeah, i know, floats are ew.
* We used them here because we'd be casting to float anyway to do this maths,
* and also only floating point numbers can deal with the pretty large numbers
* involved in the total throughput of a server over a large period of time.
* (we dont count 64 bit ints because not all systems have 64 bit ints, and floats
* can still hold more.
*/
float outbound_r = 100 - ((total_out_compressed / (total_out_uncompressed + 0.001)) * 100);
float inbound_r = 100 - ((total_in_compressed / (total_in_uncompressed + 0.001)) * 100);
float total_compressed = total_in_compressed + total_out_compressed;
float total_uncompressed = total_in_uncompressed + total_out_uncompressed;
float total_r = 100 - ((total_compressed / (total_uncompressed + 0.001)) * 100);
char outbound_ratio[MAXBUF], inbound_ratio[MAXBUF], combined_ratio[MAXBUF];
sprintf(outbound_ratio, "%3.2f%%", outbound_r);
sprintf(inbound_ratio, "%3.2f%%", inbound_r);
sprintf(combined_ratio, "%3.2f%%", total_r);
results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_compressed = "+ConvToStr(total_out_compressed));
results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_compressed = "+ConvToStr(total_in_compressed));
results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_uncompressed = "+ConvToStr(total_out_uncompressed));
results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_uncompressed = "+ConvToStr(total_in_uncompressed));
results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_ratio = "+outbound_ratio);
results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_ratio = "+inbound_ratio);
results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS combined_ratio = "+combined_ratio);
return 0;
}
return 0;
}
virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
{
izip_session* session = &sessions[fd];
/* allocate state and buffers */
session->fd = fd;
session->status = IZIP_OPEN;
session->inbuf = new CountedBuffer();
session->c_stream.zalloc = (alloc_func)0;
session->c_stream.zfree = (free_func)0;
session->c_stream.opaque = (voidpf)0;
session->d_stream.zalloc = (alloc_func)0;
session->d_stream.zfree = (free_func)0;
session->d_stream.opaque = (voidpf)0;
}
virtual void OnRawSocketConnect(int fd)
{
/* Nothing special needs doing here compared to accept() */
OnRawSocketAccept(fd, "", 0);
}
virtual void OnRawSocketClose(int fd)
{
CloseSession(&sessions[fd]);
}
virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
{
/* Find the sockets session */
izip_session* session = &sessions[fd];
if (session->status == IZIP_CLOSED)
return 0;
unsigned char compr[CHUNK + 4];
unsigned int offset = 0;
unsigned int total_size = 0;
/* Read CHUNK bytes at a time to the buffer (usually 128k) */
readresult = read(fd, compr, CHUNK);
/* Did we get anything? */
if (readresult > 0)
{
/* Add it to the frame queue */
session->inbuf->AddData(compr, readresult);
total_in_compressed += readresult;
/* Parse all completed frames */
int size = 0;
while ((size = session->inbuf->GetFrame(compr, CHUNK)) != 0)
{
session->d_stream.next_in = (Bytef*)compr;
session->d_stream.avail_in = 0;
session->d_stream.next_out = (Bytef*)(buffer + offset);
/* If we cant call this, well, we're boned. */
if (inflateInit(&session->d_stream) != Z_OK)
return 0;
while ((session->d_stream.total_out < count) && (session->d_stream.total_in < (unsigned int)size))
{
session->d_stream.avail_in = session->d_stream.avail_out = 1;
if (inflate(&session->d_stream, Z_NO_FLUSH) == Z_STREAM_END)
break;
}
/* Stick a fork in me, i'm done */
inflateEnd(&session->d_stream);
/* Update counters and offsets */
total_size += session->d_stream.total_out;
total_in_uncompressed += session->d_stream.total_out;
offset += session->d_stream.total_out;
}
/* Null-terminate the buffer -- this doesnt harm binary data */
buffer[total_size] = 0;
/* Set the read size to the correct total size */
readresult = total_size;
}
return (readresult > 0);
}
virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
{
izip_session* session = &sessions[fd];
int ocount = count;
if (!count) /* Nothing to do! */
return 0;
if(session->status != IZIP_OPEN)
{
/* Seriously, wtf? */
CloseSession(session);
return 0;
}
unsigned char compr[CHUNK + 4];
/* Gentlemen, start your engines! */
if (deflateInit(&session->c_stream, Z_BEST_COMPRESSION) != Z_OK)
{
CloseSession(session);
return 0;
}
/* Set buffer sizes (we reserve 4 bytes at the start of the
* buffer for the length counters)
*/
session->c_stream.next_in = (Bytef*)buffer;
session->c_stream.next_out = compr + 4;
/* Compress the text */
while ((session->c_stream.total_in < (unsigned int)count) && (session->c_stream.total_out < CHUNK))
{
session->c_stream.avail_in = session->c_stream.avail_out = 1;
if (deflate(&session->c_stream, Z_NO_FLUSH) != Z_OK)
{
CloseSession(session);
return 0;
}
}
/* Finish the stream */
for (session->c_stream.avail_out = 1; deflate(&session->c_stream, Z_FINISH) != Z_STREAM_END; session->c_stream.avail_out = 1);
deflateEnd(&session->c_stream);
total_out_uncompressed += ocount;
total_out_compressed += session->c_stream.total_out;
/** Assemble the frame length onto the frame, in network byte order */
compr[0] = (session->c_stream.total_out >> 24);
compr[1] = (session->c_stream.total_out >> 16);
compr[2] = (session->c_stream.total_out >> 8);
compr[3] = (session->c_stream.total_out & 0xFF);
/* Add compressed data plus leading length to the output buffer -
* Note, we may have incomplete half-sent frames in here.
*/
session->outbuf.append((const char*)compr, session->c_stream.total_out + 4);
/* Lets see how much we can send out */
int ret = write(fd, session->outbuf.data(), session->outbuf.length());
/* Check for errors, and advance the buffer if any was sent */
if (ret > 0)
session->outbuf = session->outbuf.substr(ret);
else if (ret < 1)
{
if (ret == -1)
{
if (errno == EAGAIN)
return 0;
else
{
session->outbuf.clear();
return 0;
}
}
else
{
session->outbuf.clear();
return 0;
}
}
/* ALL LIES the lot of it, we havent really written
* this amount, but the layer above doesnt need to know.
*/
return ocount;
}
void CloseSession(izip_session* session)
{
if (session->status == IZIP_OPEN)
{
session->status = IZIP_CLOSED;
session->outbuf.clear();
delete session->inbuf;
}
}
};
MODULE_INIT(ModuleZLib);
\ No newline at end of file diff --git a/src/modules/httpclient.h b/src/modules/httpclient.h index c5e84261f..109bfa666 100644 --- a/src/modules/httpclient.h +++ b/src/modules/httpclient.h @@ -1,127 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "base.h" - -#ifndef HTTPCLIENT_H__ -#define HTTPCLIENT_H__ - -#include <string> -#include <map> - -typedef std::map<std::string,std::string> HeaderMap; - -const char* HTTP_CLIENT_RESPONSE = "HTTPCLIENT_RESPONSE"; -const char* HTTP_CLIENT_REQUEST = "HTTPCLIENT_REQUEST"; - -/** This class represents an outgoing HTTP request - */ -class HTTPClientRequest : public Request -{ - protected: - std::string url; - InspIRCd *Instance; - Module *src; - HeaderMap Headers; - public: - HTTPClientRequest(InspIRCd *Instance, Module *src, Module* target, const std::string &url) - : Request(src, target, HTTP_CLIENT_REQUEST), url(url), Instance(Instance), src(src) - { - Headers["User-Agent"] = "InspIRCd (m_http_client.so)"; - Headers["Connection"] = "Close"; - Headers["Accept"] = "*/*"; - } - - HTTPClientRequest() : Request(NULL, NULL, HTTP_CLIENT_REQUEST) - { - } - - const std::string &GetURL() - { - return url; - } - - void AddHeader(std::string &header, std::string &data) - { - Headers[header] = data; - } - - void DeleteHeader(std::string &header) - { - Headers.erase(header); - } - - HeaderMap GetHeaders() - { - return Headers; - } -}; - -class HTTPClientResponse : public Request -{ - protected: - friend class HTTPSocket; - - std::string url; - std::string data; - int response; - std::string responsestr; - HeaderMap Headers; - public: - HTTPClientResponse(Module* src, Module* target, std::string &url, int response, std::string responsestr) - : Request(src, target, HTTP_CLIENT_RESPONSE), url(url), response(response), responsestr(responsestr) - { - } - - HTTPClientResponse() : Request(NULL, NULL, HTTP_CLIENT_RESPONSE) - { - } - - void SetData(const std::string &ndata) - { - data = ndata; - } - - void AddHeader(const std::string &header, const std::string &data) - { - Headers[header] = data; - } - - const std::string &GetURL() - { - return url; - } - - const std::string &GetData() - { - return data; - } - - int GetResponse(std::string &str) - { - str = responsestr; - return response; - } - - std::string GetHeader(const std::string &header) - { - HeaderMap::iterator i = Headers.find(header); - - if (i != Headers.end()) - return i->second; - else - return ""; - } -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "base.h"
#ifndef HTTPCLIENT_H__
#define HTTPCLIENT_H__
#include <string>
#include <map>
typedef std::map<std::string,std::string> HeaderMap;
const char* HTTP_CLIENT_RESPONSE = "HTTPCLIENT_RESPONSE";
const char* HTTP_CLIENT_REQUEST = "HTTPCLIENT_REQUEST";
/** This class represents an outgoing HTTP request
*/
class HTTPClientRequest : public Request
{
protected:
std::string url;
InspIRCd *Instance;
Module *src;
HeaderMap Headers;
public:
HTTPClientRequest(InspIRCd *Instance, Module *src, Module* target, const std::string &url)
: Request(src, target, HTTP_CLIENT_REQUEST), url(url), Instance(Instance), src(src)
{
Headers["User-Agent"] = "InspIRCd (m_http_client.so)";
Headers["Connection"] = "Close";
Headers["Accept"] = "*/*";
}
HTTPClientRequest() : Request(NULL, NULL, HTTP_CLIENT_REQUEST)
{
}
const std::string &GetURL()
{
return url;
}
void AddHeader(std::string &header, std::string &data)
{
Headers[header] = data;
}
void DeleteHeader(std::string &header)
{
Headers.erase(header);
}
HeaderMap GetHeaders()
{
return Headers;
}
};
class HTTPClientResponse : public Request
{
protected:
friend class HTTPSocket;
std::string url;
std::string data;
int response;
std::string responsestr;
HeaderMap Headers;
public:
HTTPClientResponse(Module* src, Module* target, std::string &url, int response, std::string responsestr)
: Request(src, target, HTTP_CLIENT_RESPONSE), url(url), response(response), responsestr(responsestr)
{
}
HTTPClientResponse() : Request(NULL, NULL, HTTP_CLIENT_RESPONSE)
{
}
void SetData(const std::string &ndata)
{
data = ndata;
}
void AddHeader(const std::string &header, const std::string &data)
{
Headers[header] = data;
}
const std::string &GetURL()
{
return url;
}
const std::string &GetData()
{
return data;
}
int GetResponse(std::string &str)
{
str = responsestr;
return response;
}
std::string GetHeader(const std::string &header)
{
HeaderMap::iterator i = Headers.find(header);
if (i != Headers.end())
return i->second;
else
return "";
}
};
#endif
\ No newline at end of file diff --git a/src/modules/httpd.h b/src/modules/httpd.h index a8b0bafcd..32bac757f 100644 --- a/src/modules/httpd.h +++ b/src/modules/httpd.h @@ -1,166 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "base.h" - -#ifndef __HTTPD_H__ -#define __HTTPD_H__ - -#include <string> -#include <sstream> - -/** This class represents a HTTP request. - * It will be sent to all modules as the data section of - * an Event. - */ -class HTTPRequest : public classbase -{ - protected: - - std::string type; - std::string document; - std::string ipaddr; - std::string postdata; - std::stringstream* headers; - - public: - - /** A socket pointer, which you must return in your HTTPDocument class - * if you reply to this request. - */ - void* sock; - - /** Initialize HTTPRequest. - * This constructor is called by m_httpd.so to initialize the class. - * @param request_type The request type, e.g. GET, POST, HEAD - * @param uri The URI, e.g. /page - * @param hdr The headers sent with the request - * @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply. - * @param ip The IP address making the web request. - * @param pdata The post data (content after headers) received with the request, up to Content-Length in size - */ - HTTPRequest(const std::string &request_type, const std::string &uri, std::stringstream* hdr, void* opaque, const std::string &ip, const std::string &pdata) - : type(request_type), document(uri), ipaddr(ip), postdata(pdata), headers(hdr), sock(opaque) - { - } - - /** Get headers. - * All the headers for the web request are returned, as a pointer to a stringstream. - * @return The header information - */ - std::stringstream* GetHeaders() - { - return headers; - } - - /** Get the post data (request content). - * All post data will be returned, including carriage returns and linefeeds. - * @return The postdata - */ - std::string& GetPostData() - { - return postdata; - } - - /** Get the request type. - * Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec. - * @return The request type, e.g. GET, POST, HEAD - */ - std::string& GetType() - { - return type; - } - - /** Get URI. - * The URI string (URL minus hostname and scheme) will be provided by this function. - * @return The URI being requested - */ - std::string& GetURI() - { - return document; - } - - /** Get IP address of requester. - * The requesting system's ip address will be returned. - * @return The IP address as a string - */ - std::string& GetIP() - { - return ipaddr; - } -}; - -/** You must return a HTTPDocument to the httpd module by using the Request class. - * When you initialize this class you may initialize it with all components required to - * form a valid HTTP response, including document data, headers, and a response code. - */ -class HTTPDocument : public classbase -{ - protected: - - std::stringstream* document; - int responsecode; - std::string extraheaders; - - public: - - /** The socket pointer from an earlier HTTPRequest - */ - void* sock; - - /** Initialize a HTTPRequest ready for sending to m_httpd.so. - * @param opaque The socket pointer you obtained from the HTTPRequest at an earlier time - * @param doc A stringstream containing the document body - * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you - * based upon the response code. - * @param extra Any extra headers to include with the defaults, seperated by carriage return and linefeed. - */ - HTTPDocument(void* opaque, std::stringstream* doc, int response, const std::string &extra) : document(doc), responsecode(response), extraheaders(extra), sock(opaque) - { - } - - /** Get the document text. - * @return The document text - */ - std::stringstream* GetDocument() - { - return this->document; - } - - /** Get the document size. - * @return the size of the document text in bytes - */ - unsigned long GetDocumentSize() - { - return this->document->str().length(); - } - - /** Get the response code. - * @return The response code - */ - int GetResponseCode() - { - return this->responsecode; - } - - /** Get the headers. - * @return The header text, headers seperated by carriage return and linefeed. - */ - std::string& GetExtraHeaders() - { - return this->extraheaders; - } -}; - -#endif - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "base.h"
#ifndef __HTTPD_H__
#define __HTTPD_H__
#include <string>
#include <sstream>
/** This class represents a HTTP request.
* It will be sent to all modules as the data section of
* an Event.
*/
class HTTPRequest : public classbase
{
protected:
std::string type;
std::string document;
std::string ipaddr;
std::string postdata;
std::stringstream* headers;
public:
/** A socket pointer, which you must return in your HTTPDocument class
* if you reply to this request.
*/
void* sock;
/** Initialize HTTPRequest.
* This constructor is called by m_httpd.so to initialize the class.
* @param request_type The request type, e.g. GET, POST, HEAD
* @param uri The URI, e.g. /page
* @param hdr The headers sent with the request
* @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply.
* @param ip The IP address making the web request.
* @param pdata The post data (content after headers) received with the request, up to Content-Length in size
*/
HTTPRequest(const std::string &request_type, const std::string &uri, std::stringstream* hdr, void* opaque, const std::string &ip, const std::string &pdata)
: type(request_type), document(uri), ipaddr(ip), postdata(pdata), headers(hdr), sock(opaque)
{
}
/** Get headers.
* All the headers for the web request are returned, as a pointer to a stringstream.
* @return The header information
*/
std::stringstream* GetHeaders()
{
return headers;
}
/** Get the post data (request content).
* All post data will be returned, including carriage returns and linefeeds.
* @return The postdata
*/
std::string& GetPostData()
{
return postdata;
}
/** Get the request type.
* Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec.
* @return The request type, e.g. GET, POST, HEAD
*/
std::string& GetType()
{
return type;
}
/** Get URI.
* The URI string (URL minus hostname and scheme) will be provided by this function.
* @return The URI being requested
*/
std::string& GetURI()
{
return document;
}
/** Get IP address of requester.
* The requesting system's ip address will be returned.
* @return The IP address as a string
*/
std::string& GetIP()
{
return ipaddr;
}
};
/** You must return a HTTPDocument to the httpd module by using the Request class.
* When you initialize this class you may initialize it with all components required to
* form a valid HTTP response, including document data, headers, and a response code.
*/
class HTTPDocument : public classbase
{
protected:
std::stringstream* document;
int responsecode;
std::string extraheaders;
public:
/** The socket pointer from an earlier HTTPRequest
*/
void* sock;
/** Initialize a HTTPRequest ready for sending to m_httpd.so.
* @param opaque The socket pointer you obtained from the HTTPRequest at an earlier time
* @param doc A stringstream containing the document body
* @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you
* based upon the response code.
* @param extra Any extra headers to include with the defaults, seperated by carriage return and linefeed.
*/
HTTPDocument(void* opaque, std::stringstream* doc, int response, const std::string &extra) : document(doc), responsecode(response), extraheaders(extra), sock(opaque)
{
}
/** Get the document text.
* @return The document text
*/
std::stringstream* GetDocument()
{
return this->document;
}
/** Get the document size.
* @return the size of the document text in bytes
*/
unsigned long GetDocumentSize()
{
return this->document->str().length();
}
/** Get the response code.
* @return The response code
*/
int GetResponseCode()
{
return this->responsecode;
}
/** Get the headers.
* @return The header text, headers seperated by carriage return and linefeed.
*/
std::string& GetExtraHeaders()
{
return this->extraheaders;
}
};
#endif
\ No newline at end of file diff --git a/src/modules/m_alias.cpp b/src/modules/m_alias.cpp index 94c64b405..039aeed92 100644 --- a/src/modules/m_alias.cpp +++ b/src/modules/m_alias.cpp @@ -1,272 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "wildcard.h" - -/* $ModDesc: Provides aliases of commands. */ - -/** An alias definition - */ -class Alias : public classbase -{ - public: - /** The text of the alias command */ - irc::string text; - /** Text to replace with */ - std::string replace_with; - /** Nickname required to perform alias */ - std::string requires; - /** Alias requires ulined server */ - bool uline; - /** Requires oper? */ - bool operonly; - /* is case sensitive params */ - bool case_sensitive; - /** Format that must be matched for use */ - std::string format; -}; - -class ModuleAlias : public Module -{ - private: - /** We cant use a map, there may be multiple aliases with the same name */ - std::vector<Alias> Aliases; - std::map<std::string, int> AliasMap; - std::vector<std::string> pars; - - virtual void ReadAliases() - { - ConfigReader MyConf(ServerInstance); - - Aliases.clear(); - AliasMap.clear(); - for (int i = 0; i < MyConf.Enumerate("alias"); i++) - { - Alias a; - std::string txt; - txt = MyConf.ReadValue("alias", "text", i); - a.text = txt.c_str(); - a.replace_with = MyConf.ReadValue("alias", "replace", i, true); - a.requires = MyConf.ReadValue("alias", "requires", i); - a.uline = MyConf.ReadFlag("alias", "uline", i); - a.operonly = MyConf.ReadFlag("alias", "operonly", i); - a.format = MyConf.ReadValue("alias", "format", i); - a.case_sensitive = MyConf.ReadFlag("alias", "matchcase", i); - Aliases.push_back(a); - AliasMap[txt] = 1; - } - } - - public: - - ModuleAlias(InspIRCd* Me) - : Module(Me) - { - ReadAliases(); - pars.resize(127); - } - - void Implements(char* List) - { - List[I_OnPreCommand] = List[I_OnRehash] = 1; - } - - virtual ~ModuleAlias() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - std::string GetVar(std::string varname, const std::string &original_line) - { - irc::spacesepstream ss(original_line); - varname.erase(varname.begin()); - int index = *(varname.begin()) - 48; - varname.erase(varname.begin()); - bool everything_after = (varname == "-"); - std::string word; - - for (int j = 0; j < index; j++) - word = ss.GetToken(); - - if (everything_after) - { - std::string more = "*"; - while ((more = ss.GetToken()) != "") - { - word.append(" "); - word.append(more); - } - } - - return word; - } - - void SearchAndReplace(std::string& newline, const std::string &find, const std::string &replace) - { - std::string::size_type x = newline.find(find); - while (x != std::string::npos) - { - newline.erase(x, find.length()); - newline.insert(x, replace); - x = newline.find(find); - } - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - userrec *u = NULL; - - /* If theyre not registered yet, we dont want - * to know. - */ - if (user->registered != REG_ALL) - return 0; - - /* We dont have any commands looking like this, dont bother with the loop */ - if (AliasMap.find(command) == AliasMap.end()) - return 0; - - irc::string c = command.c_str(); - /* The parameters for the command in their original form, with the command stripped off */ - std::string compare = original_line.substr(command.length()); - while (*(compare.c_str()) == ' ') - compare.erase(compare.begin()); - - std::string safe(original_line); - - /* Escape out any $ symbols in the user provided text */ - - SearchAndReplace(safe, "$", "\r"); - - for (unsigned int i = 0; i < Aliases.size(); i++) - { - if (Aliases[i].text == c) - { - /* Does it match the pattern? */ - if (!Aliases[i].format.empty()) - { - if (!match(Aliases[i].case_sensitive, compare.c_str(), Aliases[i].format.c_str())) - continue; - } - - if ((Aliases[i].operonly) && (!IS_OPER(user))) - return 0; - - if (!Aliases[i].requires.empty()) - { - u = ServerInstance->FindNick(Aliases[i].requires); - if (!u) - { - user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is currently unavailable. Please try again later."); - return 1; - } - } - if ((u != NULL) && (!Aliases[i].requires.empty()) && (Aliases[i].uline)) - { - if (!ServerInstance->ULine(u->server)) - { - ServerInstance->WriteOpers("*** NOTICE -- Service "+Aliases[i].requires+" required by alias "+std::string(Aliases[i].text.c_str())+" is not on a u-lined server, possibly underhanded antics detected!"); - user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is an imposter! Please inform an IRC operator as soon as possible."); - return 1; - } - } - - /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */ - - std::string::size_type crlf = Aliases[i].replace_with.find('\n'); - - if (crlf == std::string::npos) - { - DoCommand(Aliases[i].replace_with, user, safe); - return 1; - } - else - { - irc::sepstream commands(Aliases[i].replace_with, '\n'); - std::string command = "*"; - while ((command = commands.GetToken()) != "") - { - DoCommand(command, user, safe); - } - return 1; - } - } - } - return 0; - } - - void DoCommand(std::string newline, userrec* user, const std::string &original_line) - { - for (int v = 1; v < 10; v++) - { - std::string var = "$"; - var.append(ConvToStr(v)); - var.append("-"); - std::string::size_type x = newline.find(var); - - while (x != std::string::npos) - { - newline.erase(x, var.length()); - newline.insert(x, GetVar(var, original_line)); - x = newline.find(var); - } - - var = "$"; - var.append(ConvToStr(v)); - x = newline.find(var); - - while (x != std::string::npos) - { - newline.erase(x, var.length()); - newline.insert(x, GetVar(var, original_line)); - x = newline.find(var); - } - } - - /* Special variables */ - SearchAndReplace(newline, "$nick", user->nick); - SearchAndReplace(newline, "$ident", user->ident); - SearchAndReplace(newline, "$host", user->host); - SearchAndReplace(newline, "$vhost", user->dhost); - - /* Unescape any variable names in the user text before sending */ - SearchAndReplace(newline, "\r", "$"); - - irc::tokenstream ss(newline); - const char* parv[127]; - int x = 0; - - while (ss.GetToken(pars[x])) - { - parv[x] = pars[x].c_str(); - x++; - } - - ServerInstance->Parser->CallHandler(parv[0], &parv[1], x-1, user); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ReadAliases(); - } -}; - -MODULE_INIT(ModuleAlias) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "wildcard.h"
/* $ModDesc: Provides aliases of commands. */
/** An alias definition
*/
class Alias : public classbase
{
public:
/** The text of the alias command */
irc::string text;
/** Text to replace with */
std::string replace_with;
/** Nickname required to perform alias */
std::string requires;
/** Alias requires ulined server */
bool uline;
/** Requires oper? */
bool operonly;
/* is case sensitive params */
bool case_sensitive;
/** Format that must be matched for use */
std::string format;
};
class ModuleAlias : public Module
{
private:
/** We cant use a map, there may be multiple aliases with the same name */
std::vector<Alias> Aliases;
std::map<std::string, int> AliasMap;
std::vector<std::string> pars;
virtual void ReadAliases()
{
ConfigReader MyConf(ServerInstance);
Aliases.clear();
AliasMap.clear();
for (int i = 0; i < MyConf.Enumerate("alias"); i++)
{
Alias a;
std::string txt;
txt = MyConf.ReadValue("alias", "text", i);
a.text = txt.c_str();
a.replace_with = MyConf.ReadValue("alias", "replace", i, true);
a.requires = MyConf.ReadValue("alias", "requires", i);
a.uline = MyConf.ReadFlag("alias", "uline", i);
a.operonly = MyConf.ReadFlag("alias", "operonly", i);
a.format = MyConf.ReadValue("alias", "format", i);
a.case_sensitive = MyConf.ReadFlag("alias", "matchcase", i);
Aliases.push_back(a);
AliasMap[txt] = 1;
}
}
public:
ModuleAlias(InspIRCd* Me)
: Module(Me)
{
ReadAliases();
pars.resize(127);
}
void Implements(char* List)
{
List[I_OnPreCommand] = List[I_OnRehash] = 1;
}
virtual ~ModuleAlias()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
std::string GetVar(std::string varname, const std::string &original_line)
{
irc::spacesepstream ss(original_line);
varname.erase(varname.begin());
int index = *(varname.begin()) - 48;
varname.erase(varname.begin());
bool everything_after = (varname == "-");
std::string word;
for (int j = 0; j < index; j++)
word = ss.GetToken();
if (everything_after)
{
std::string more = "*";
while ((more = ss.GetToken()) != "")
{
word.append(" ");
word.append(more);
}
}
return word;
}
void SearchAndReplace(std::string& newline, const std::string &find, const std::string &replace)
{
std::string::size_type x = newline.find(find);
while (x != std::string::npos)
{
newline.erase(x, find.length());
newline.insert(x, replace);
x = newline.find(find);
}
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
userrec *u = NULL;
/* If theyre not registered yet, we dont want
* to know.
*/
if (user->registered != REG_ALL)
return 0;
/* We dont have any commands looking like this, dont bother with the loop */
if (AliasMap.find(command) == AliasMap.end())
return 0;
irc::string c = command.c_str();
/* The parameters for the command in their original form, with the command stripped off */
std::string compare = original_line.substr(command.length());
while (*(compare.c_str()) == ' ')
compare.erase(compare.begin());
std::string safe(original_line);
/* Escape out any $ symbols in the user provided text */
SearchAndReplace(safe, "$", "\r");
for (unsigned int i = 0; i < Aliases.size(); i++)
{
if (Aliases[i].text == c)
{
/* Does it match the pattern? */
if (!Aliases[i].format.empty())
{
if (!match(Aliases[i].case_sensitive, compare.c_str(), Aliases[i].format.c_str()))
continue;
}
if ((Aliases[i].operonly) && (!IS_OPER(user)))
return 0;
if (!Aliases[i].requires.empty())
{
u = ServerInstance->FindNick(Aliases[i].requires);
if (!u)
{
user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is currently unavailable. Please try again later.");
return 1;
}
}
if ((u != NULL) && (!Aliases[i].requires.empty()) && (Aliases[i].uline))
{
if (!ServerInstance->ULine(u->server))
{
ServerInstance->WriteOpers("*** NOTICE -- Service "+Aliases[i].requires+" required by alias "+std::string(Aliases[i].text.c_str())+" is not on a u-lined server, possibly underhanded antics detected!");
user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is an imposter! Please inform an IRC operator as soon as possible.");
return 1;
}
}
/* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */
std::string::size_type crlf = Aliases[i].replace_with.find('\n');
if (crlf == std::string::npos)
{
DoCommand(Aliases[i].replace_with, user, safe);
return 1;
}
else
{
irc::sepstream commands(Aliases[i].replace_with, '\n');
std::string command = "*";
while ((command = commands.GetToken()) != "")
{
DoCommand(command, user, safe);
}
return 1;
}
}
}
return 0;
}
void DoCommand(std::string newline, userrec* user, const std::string &original_line)
{
for (int v = 1; v < 10; v++)
{
std::string var = "$";
var.append(ConvToStr(v));
var.append("-");
std::string::size_type x = newline.find(var);
while (x != std::string::npos)
{
newline.erase(x, var.length());
newline.insert(x, GetVar(var, original_line));
x = newline.find(var);
}
var = "$";
var.append(ConvToStr(v));
x = newline.find(var);
while (x != std::string::npos)
{
newline.erase(x, var.length());
newline.insert(x, GetVar(var, original_line));
x = newline.find(var);
}
}
/* Special variables */
SearchAndReplace(newline, "$nick", user->nick);
SearchAndReplace(newline, "$ident", user->ident);
SearchAndReplace(newline, "$host", user->host);
SearchAndReplace(newline, "$vhost", user->dhost);
/* Unescape any variable names in the user text before sending */
SearchAndReplace(newline, "\r", "$");
irc::tokenstream ss(newline);
const char* parv[127];
int x = 0;
while (ss.GetToken(pars[x]))
{
parv[x] = pars[x].c_str();
x++;
}
ServerInstance->Parser->CallHandler(parv[0], &parv[1], x-1, user);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadAliases();
}
};
MODULE_INIT(ModuleAlias)
\ No newline at end of file diff --git a/src/modules/m_alltime.cpp b/src/modules/m_alltime.cpp index 97ab6a3fe..6a3f27ba8 100644 --- a/src/modules/m_alltime.cpp +++ b/src/modules/m_alltime.cpp @@ -1,83 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "modules.h" - -/* $ModDesc: Display timestamps from all servers connected to the network */ - -class cmd_alltime : public command_t -{ - public: - cmd_alltime(InspIRCd *Instance) : command_t(Instance, "ALLTIME", 'o', 0) - { - this->source = "m_alltime.so"; - syntax.clear(); - } - - CmdResult Handle(const char **parameters, int pcnt, userrec *user) - { - char fmtdate[64]; - char fmtdate2[64]; - time_t now = ServerInstance->Time(false); - strftime(fmtdate, sizeof(fmtdate), "%F %T", gmtime(&now)); - now = ServerInstance->Time(true); - strftime(fmtdate2, sizeof(fmtdate2), "%F %T", gmtime(&now)); - - int delta = ServerInstance->GetTimeDelta(); - - string msg = ":" + string(ServerInstance->Config->ServerName) + " NOTICE " + user->nick + " :System time for " + - ServerInstance->Config->ServerName + " is: " + fmtdate + " (delta " + ConvToStr(delta) + " seconds): Time with delta: "+ fmtdate2; - - if (IS_LOCAL(user)) - { - user->Write(msg); - } - else - { - deque<string> params; - params.push_back(user->nick); - params.push_back(msg); - Event ev((char *) ¶ms, NULL, "send_push"); - ev.Send(ServerInstance); - } - - /* we want this routed out! */ - return CMD_SUCCESS; - } -}; - - -class Modulealltime : public Module -{ - cmd_alltime *mycommand; - public: - Modulealltime(InspIRCd *Me) - : Module(Me) - { - mycommand = new cmd_alltime(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~Modulealltime() - { - } - - virtual Version GetVersion() - { - return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } - -}; - -MODULE_INIT(Modulealltime) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "modules.h"
/* $ModDesc: Display timestamps from all servers connected to the network */
class cmd_alltime : public command_t
{
public:
cmd_alltime(InspIRCd *Instance) : command_t(Instance, "ALLTIME", 'o', 0)
{
this->source = "m_alltime.so";
syntax.clear();
}
CmdResult Handle(const char **parameters, int pcnt, userrec *user)
{
char fmtdate[64];
char fmtdate2[64];
time_t now = ServerInstance->Time(false);
strftime(fmtdate, sizeof(fmtdate), "%F %T", gmtime(&now));
now = ServerInstance->Time(true);
strftime(fmtdate2, sizeof(fmtdate2), "%F %T", gmtime(&now));
int delta = ServerInstance->GetTimeDelta();
string msg = ":" + string(ServerInstance->Config->ServerName) + " NOTICE " + user->nick + " :System time for " +
ServerInstance->Config->ServerName + " is: " + fmtdate + " (delta " + ConvToStr(delta) + " seconds): Time with delta: "+ fmtdate2;
if (IS_LOCAL(user))
{
user->Write(msg);
}
else
{
deque<string> params;
params.push_back(user->nick);
params.push_back(msg);
Event ev((char *) ¶ms, NULL, "send_push");
ev.Send(ServerInstance);
}
/* we want this routed out! */
return CMD_SUCCESS;
}
};
class Modulealltime : public Module
{
cmd_alltime *mycommand;
public:
Modulealltime(InspIRCd *Me)
: Module(Me)
{
mycommand = new cmd_alltime(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~Modulealltime()
{
}
virtual Version GetVersion()
{
return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(Modulealltime)
\ No newline at end of file diff --git a/src/modules/m_antibear.cpp b/src/modules/m_antibear.cpp index 2718cbb4c..d95c70282 100644 --- a/src/modules/m_antibear.cpp +++ b/src/modules/m_antibear.cpp @@ -1,78 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "xline.h" - -/* $ModDesc: Sends a numeric on connect which cripples a common type of trojan/spambot */ - -class ModuleAntiBear : public Module -{ - private: - - public: - ModuleAntiBear(InspIRCd* Me) : Module(Me) - { - - } - - virtual ~ModuleAntiBear() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserRegister] = List[I_OnPreCommand] = 1; - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - if (command == "NOTICE" && !validated && pcnt > 1 && user->GetExt("antibear_timewait")) - { - if (!strncmp(parameters[1], "\1TIME Mon May 01 18:54:20 2006", 30)) - { - if (ServerInstance->XLines->add_zline(86400, ServerInstance->Config->ServerName, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP())) - { - ServerInstance->XLines->apply_lines(APPLY_ZLINES); - FOREACH_MOD(I_OnAddGLine,OnAddZLine(86400, NULL, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP())); - return 1; - } - } - - user->Shrink("antibear_timewait"); - // Block the command, so the user doesn't receive a no such nick notice - return 1; - } - - return 0; - } - - virtual int OnUserRegister(userrec* user) - { - user->WriteServ("439 %s :This server has anti-spambot mechanisms enabled.", user->nick); - user->WriteServ("931 %s :Malicious bots, spammers, and other automated systems of dubious origin are NOT welcome here.", user->nick); - user->WriteServ("PRIVMSG %s :\1TIME\1", user->nick); - user->Extend("antibear_timewait"); - return 0; - } -}; - -MODULE_INIT(ModuleAntiBear) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "xline.h"
/* $ModDesc: Sends a numeric on connect which cripples a common type of trojan/spambot */
class ModuleAntiBear : public Module
{
private:
public:
ModuleAntiBear(InspIRCd* Me) : Module(Me)
{
}
virtual ~ModuleAntiBear()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserRegister] = List[I_OnPreCommand] = 1;
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
if (command == "NOTICE" && !validated && pcnt > 1 && user->GetExt("antibear_timewait"))
{
if (!strncmp(parameters[1], "\1TIME Mon May 01 18:54:20 2006", 30))
{
if (ServerInstance->XLines->add_zline(86400, ServerInstance->Config->ServerName, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP()))
{
ServerInstance->XLines->apply_lines(APPLY_ZLINES);
FOREACH_MOD(I_OnAddGLine,OnAddZLine(86400, NULL, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP()));
return 1;
}
}
user->Shrink("antibear_timewait");
// Block the command, so the user doesn't receive a no such nick notice
return 1;
}
return 0;
}
virtual int OnUserRegister(userrec* user)
{
user->WriteServ("439 %s :This server has anti-spambot mechanisms enabled.", user->nick);
user->WriteServ("931 %s :Malicious bots, spammers, and other automated systems of dubious origin are NOT welcome here.", user->nick);
user->WriteServ("PRIVMSG %s :\1TIME\1", user->nick);
user->Extend("antibear_timewait");
return 0;
}
};
MODULE_INIT(ModuleAntiBear)
\ No newline at end of file diff --git a/src/modules/m_antibottler.cpp b/src/modules/m_antibottler.cpp index 3aa5592cc..907cfb39d 100644 --- a/src/modules/m_antibottler.cpp +++ b/src/modules/m_antibottler.cpp @@ -1,99 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Changes the ident of connecting bottler clients to 'bottler' */ - -class ModuleAntiBottler : public Module -{ - public: - ModuleAntiBottler(InspIRCd* Me) - : Module(Me) - { - - } - - void Implements(char* List) - { - List[I_OnPreCommand] = 1; - } - - - virtual ~ModuleAntiBottler() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - char data[MAXBUF]; - strlcpy(data,original_line.c_str(),MAXBUF); - bool not_bottler = false; - if (!strncmp(data,"user ",5)) - { - for (char* j = data; *j; j++) - { - if (*j == ':') - break; - - if (*j == '"') - { - not_bottler = true; - } - } - // Bug Fix (#14) -- FCS - if (!(data) || !(*data)) - return 0; - - strtok(data," "); - char *ident = strtok(NULL," "); - char *local = strtok(NULL," "); - char *remote = strtok(NULL," :"); - char *gecos = strtok(NULL,"\r\n"); - - if (!ident || !local || !remote || !gecos) - return 0; - - for (char* j = remote; *j; j++) - { - if (((*j < '0') || (*j > '9')) && (*j != '.')) - { - not_bottler = true; - } - } - - if (!not_bottler) - { - std::string strgecos = std::string(gecos) + "[Possible bottler, ident: " + std::string(ident) + "]"; - const char* modified[4]; - modified[0] = "bottler"; - modified[1] = local; - modified[2] = remote; - modified[3] = strgecos.c_str(); - ServerInstance->Parser->CallHandler("USER", modified, 4, user); - return 1; - } - } - return 0; - } -}; - -MODULE_INIT(ModuleAntiBottler) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Changes the ident of connecting bottler clients to 'bottler' */
class ModuleAntiBottler : public Module
{
public:
ModuleAntiBottler(InspIRCd* Me)
: Module(Me)
{
}
void Implements(char* List)
{
List[I_OnPreCommand] = 1;
}
virtual ~ModuleAntiBottler()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
char data[MAXBUF];
strlcpy(data,original_line.c_str(),MAXBUF);
bool not_bottler = false;
if (!strncmp(data,"user ",5))
{
for (char* j = data; *j; j++)
{
if (*j == ':')
break;
if (*j == '"')
{
not_bottler = true;
}
}
// Bug Fix (#14) -- FCS
if (!(data) || !(*data))
return 0;
strtok(data," ");
char *ident = strtok(NULL," ");
char *local = strtok(NULL," ");
char *remote = strtok(NULL," :");
char *gecos = strtok(NULL,"\r\n");
if (!ident || !local || !remote || !gecos)
return 0;
for (char* j = remote; *j; j++)
{
if (((*j < '0') || (*j > '9')) && (*j != '.'))
{
not_bottler = true;
}
}
if (!not_bottler)
{
std::string strgecos = std::string(gecos) + "[Possible bottler, ident: " + std::string(ident) + "]";
const char* modified[4];
modified[0] = "bottler";
modified[1] = local;
modified[2] = remote;
modified[3] = strgecos.c_str();
ServerInstance->Parser->CallHandler("USER", modified, 4, user);
return 1;
}
}
return 0;
}
};
MODULE_INIT(ModuleAntiBottler)
\ No newline at end of file diff --git a/src/modules/m_auditorium.cpp b/src/modules/m_auditorium.cpp index 6d709e431..419738ea7 100644 --- a/src/modules/m_auditorium.cpp +++ b/src/modules/m_auditorium.cpp @@ -1,191 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list */ - -class AuditoriumMode : public ModeHandler -{ - public: - AuditoriumMode(InspIRCd* Instance) : ModeHandler(Instance, 'u', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (channel->IsModeSet('u') != adding) - { - if (IS_LOCAL(source) && (channel->GetStatus(source) < STATUS_OP)) - { - source->WriteServ("482 %s %s :Only channel operators may %sset channel mode +u", source->nick, channel->name, adding ? "" : "un"); - return MODEACTION_DENY; - } - else - { - channel->SetMode('u', adding); - return MODEACTION_ALLOW; - } - } - else - { - return MODEACTION_DENY; - } - } -}; - -class ModuleAuditorium : public Module -{ - private: - AuditoriumMode* aum; - bool ShowOps; - CUList nl; - CUList except_list; - public: - ModuleAuditorium(InspIRCd* Me) - : Module(Me) - { - aum = new AuditoriumMode(ServerInstance); - if (!ServerInstance->AddMode(aum, 'u')) - throw ModuleException("Could not add new modes!"); - OnRehash(NULL, ""); - } - - virtual ~ModuleAuditorium() - { - ServerInstance->Modes->DelMode(aum); - DELETE(aum); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader conf(ServerInstance); - ShowOps = conf.ReadFlag("auditorium", "showops", 0); - } - - Priority Prioritize() - { - /* To ensure that we get priority over namesx for names list generation on +u channels */ - return (Priority)ServerInstance->PriorityBefore("m_namesx.so"); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserKick] = List[I_OnUserQuit] = List[I_OnUserList] = List[I_OnRehash] = 1; - } - - virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &nameslist) - { - if (Ptr->IsModeSet('u')) - { - if (ShowOps) - { - /* Leave the names list alone, theyre an op - * doing /names on the channel after joining it - */ - if (Ptr->GetStatus(user) >= STATUS_OP) - { - nameslist = Ptr->GetUsers(); - return 0; - } - - /* Show all the opped users */ - nl = *(Ptr->GetOppedUsers()); - nl[user] = user->nick; - nameslist = &nl; - return 0; - } - else - { - /* HELLOOO, IS ANYBODY THERE? -- nope, just us. */ - user->WriteServ("353 %s = %s :%s", user->nick, Ptr->name, user->nick); - user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name); - return 1; - } - } - return 0; - } - - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - if (channel->IsModeSet('u')) - { - silent = true; - /* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */ - user->WriteFrom(user, "JOIN %s", channel->name); - if (ShowOps) - channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "JOIN %s", channel->name); - } - } - - void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent) - { - if (channel->IsModeSet('u')) - { - silent = true; - /* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */ - user->WriteFrom(user, "PART %s%s%s", channel->name, - partmessage.empty() ? "" : " :", - partmessage.empty() ? "" : partmessage.c_str()); - if (ShowOps) - { - channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "PART %s%s%s", channel->name, partmessage.empty() ? "" : " :", - partmessage.empty() ? "" : partmessage.c_str()); - } - } - } - - void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent) - { - if (chan->IsModeSet('u')) - { - silent = true; - /* Send silenced event only to the user being kicked and the user doing the kick */ - source->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str()); - if (ShowOps) - chan->WriteAllExcept(source, false, chan->GetStatus(source) >= STATUS_OP ? 0 : '@', except_list, "KICK %s %s %s", chan->name, user->nick, reason.c_str()); - else - user->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str()); - } - } - - void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - command_t* parthandler = ServerInstance->Parser->GetHandler("PART"); - std::vector<std::string> to_leave; - const char* parameters[2]; - if (parthandler) - { - for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++) - { - if (f->first->IsModeSet('u')) - to_leave.push_back(f->first->name); - } - /* We cant do this neatly in one loop, as we are modifying the map we are iterating */ - for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++) - { - parameters[0] = n->c_str(); - /* This triggers our OnUserPart, above, making the PART silent */ - parthandler->Handle(parameters, 1, user); - } - } - } -}; - -MODULE_INIT(ModuleAuditorium) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list */
class AuditoriumMode : public ModeHandler
{
public:
AuditoriumMode(InspIRCd* Instance) : ModeHandler(Instance, 'u', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (channel->IsModeSet('u') != adding)
{
if (IS_LOCAL(source) && (channel->GetStatus(source) < STATUS_OP))
{
source->WriteServ("482 %s %s :Only channel operators may %sset channel mode +u", source->nick, channel->name, adding ? "" : "un");
return MODEACTION_DENY;
}
else
{
channel->SetMode('u', adding);
return MODEACTION_ALLOW;
}
}
else
{
return MODEACTION_DENY;
}
}
};
class ModuleAuditorium : public Module
{
private:
AuditoriumMode* aum;
bool ShowOps;
CUList nl;
CUList except_list;
public:
ModuleAuditorium(InspIRCd* Me)
: Module(Me)
{
aum = new AuditoriumMode(ServerInstance);
if (!ServerInstance->AddMode(aum, 'u'))
throw ModuleException("Could not add new modes!");
OnRehash(NULL, "");
}
virtual ~ModuleAuditorium()
{
ServerInstance->Modes->DelMode(aum);
DELETE(aum);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader conf(ServerInstance);
ShowOps = conf.ReadFlag("auditorium", "showops", 0);
}
Priority Prioritize()
{
/* To ensure that we get priority over namesx for names list generation on +u channels */
return (Priority)ServerInstance->PriorityBefore("m_namesx.so");
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserKick] = List[I_OnUserQuit] = List[I_OnUserList] = List[I_OnRehash] = 1;
}
virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &nameslist)
{
if (Ptr->IsModeSet('u'))
{
if (ShowOps)
{
/* Leave the names list alone, theyre an op
* doing /names on the channel after joining it
*/
if (Ptr->GetStatus(user) >= STATUS_OP)
{
nameslist = Ptr->GetUsers();
return 0;
}
/* Show all the opped users */
nl = *(Ptr->GetOppedUsers());
nl[user] = user->nick;
nameslist = &nl;
return 0;
}
else
{
/* HELLOOO, IS ANYBODY THERE? -- nope, just us. */
user->WriteServ("353 %s = %s :%s", user->nick, Ptr->name, user->nick);
user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
return 1;
}
}
return 0;
}
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
if (channel->IsModeSet('u'))
{
silent = true;
/* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */
user->WriteFrom(user, "JOIN %s", channel->name);
if (ShowOps)
channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "JOIN %s", channel->name);
}
}
void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
{
if (channel->IsModeSet('u'))
{
silent = true;
/* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */
user->WriteFrom(user, "PART %s%s%s", channel->name,
partmessage.empty() ? "" : " :",
partmessage.empty() ? "" : partmessage.c_str());
if (ShowOps)
{
channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "PART %s%s%s", channel->name, partmessage.empty() ? "" : " :",
partmessage.empty() ? "" : partmessage.c_str());
}
}
}
void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
{
if (chan->IsModeSet('u'))
{
silent = true;
/* Send silenced event only to the user being kicked and the user doing the kick */
source->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str());
if (ShowOps)
chan->WriteAllExcept(source, false, chan->GetStatus(source) >= STATUS_OP ? 0 : '@', except_list, "KICK %s %s %s", chan->name, user->nick, reason.c_str());
else
user->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str());
}
}
void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
command_t* parthandler = ServerInstance->Parser->GetHandler("PART");
std::vector<std::string> to_leave;
const char* parameters[2];
if (parthandler)
{
for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)
{
if (f->first->IsModeSet('u'))
to_leave.push_back(f->first->name);
}
/* We cant do this neatly in one loop, as we are modifying the map we are iterating */
for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++)
{
parameters[0] = n->c_str();
/* This triggers our OnUserPart, above, making the PART silent */
parthandler->Handle(parameters, 1, user);
}
}
}
};
MODULE_INIT(ModuleAuditorium)
\ No newline at end of file diff --git a/src/modules/m_banexception.cpp b/src/modules/m_banexception.cpp index 0cd03a08b..8a73e6070 100644 --- a/src/modules/m_banexception.cpp +++ b/src/modules/m_banexception.cpp @@ -1,153 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "mode.h" -#include "u_listmode.h" -#include "wildcard.h" - -/* $ModDesc: Provides support for the +e channel mode */ -/* $ModDep: ../../include/u_listmode.h */ - -/* Written by Om<om@inspircd.org>, April 2005. */ -/* Rewritten to use the listmode utility by Om, December 2005 */ -/* Adapted from m_exception, which was originally based on m_chanprotect and m_silence */ - -// The +e channel mode takes a nick!ident@host, glob patterns allowed, -// and if a user matches an entry on the +e list then they can join the channel, overriding any (+b) bans set on them -// Now supports CIDR and IP addresses -- Brain - - -/** Handles +e channel mode - */ -class BanException : public ListModeBase -{ - public: - BanException(InspIRCd* Instance) : ListModeBase(Instance, 'e', "End of Channel Exception List", "348", "349", true) { } -}; - - -class ModuleBanException : public Module -{ - BanException* be; - - -public: - ModuleBanException(InspIRCd* Me) - : Module(Me) - { - be = new BanException(ServerInstance); - if (!ServerInstance->AddMode(be, 'e')) - throw ModuleException("Could not add new modes!"); - ServerInstance->PublishInterface("ChannelBanList", this); - } - - virtual void Implements(char* List) - { - be->DoImplements(List); - List[I_OnRehash] = List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckBan] = 1; - } - - virtual void On005Numeric(std::string &output) - { - output.append(" EXCEPTS=e"); - } - - virtual int OnCheckBan(userrec* user, chanrec* chan) - { - if (chan != NULL) - { - modelist* list; - chan->GetExt(be->GetInfoKey(), list); - - if (list) - { - char mask[MAXBUF]; - snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString()); - for (modelist::iterator it = list->begin(); it != list->end(); it++) - { - if (match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true))) - { - // They match an entry on the list, so let them in. - return 1; - } - } - return 0; - } - // or if there wasn't a list, there can't be anyone on it, so we don't need to do anything. - } - return 0; - } - - virtual void OnCleanup(int target_type, void* item) - { - be->DoCleanup(target_type, item); - } - - virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque) - { - be->DoSyncChannel(chan, proto, opaque); - } - - virtual void OnChannelDelete(chanrec* chan) - { - be->DoChannelDelete(chan); - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - be->DoRehash(); - } - - virtual char* OnRequest(Request* request) - { - ListModeRequest* LM = (ListModeRequest*)request; - if (strcmp("LM_CHECKLIST", request->GetId()) == 0) - { - modelist* list; - LM->chan->GetExt(be->GetInfoKey(), list); - if (list) - { - char mask[MAXBUF]; - snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString()); - for (modelist::iterator it = list->begin(); it != list->end(); it++) - { - if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true))) - { - // They match an entry - return (char*)it->mask.c_str(); - } - } - return NULL; - } - } - return NULL; - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 3, VF_COMMON | VF_VENDOR, API_VERSION); - } - - virtual ~ModuleBanException() - { - ServerInstance->Modes->DelMode(be); - DELETE(be); - ServerInstance->UnpublishInterface("ChannelBanList", this); - } -}; - -MODULE_INIT(ModuleBanException) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "mode.h"
#include "u_listmode.h"
#include "wildcard.h"
/* $ModDesc: Provides support for the +e channel mode */
/* $ModDep: ../../include/u_listmode.h */
/* Written by Om<om@inspircd.org>, April 2005. */
/* Rewritten to use the listmode utility by Om, December 2005 */
/* Adapted from m_exception, which was originally based on m_chanprotect and m_silence */
// The +e channel mode takes a nick!ident@host, glob patterns allowed,
// and if a user matches an entry on the +e list then they can join the channel, overriding any (+b) bans set on them
// Now supports CIDR and IP addresses -- Brain
/** Handles +e channel mode
*/
class BanException : public ListModeBase
{
public:
BanException(InspIRCd* Instance) : ListModeBase(Instance, 'e', "End of Channel Exception List", "348", "349", true) { }
};
class ModuleBanException : public Module
{
BanException* be;
public:
ModuleBanException(InspIRCd* Me)
: Module(Me)
{
be = new BanException(ServerInstance);
if (!ServerInstance->AddMode(be, 'e'))
throw ModuleException("Could not add new modes!");
ServerInstance->PublishInterface("ChannelBanList", this);
}
virtual void Implements(char* List)
{
be->DoImplements(List);
List[I_OnRehash] = List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckBan] = 1;
}
virtual void On005Numeric(std::string &output)
{
output.append(" EXCEPTS=e");
}
virtual int OnCheckBan(userrec* user, chanrec* chan)
{
if (chan != NULL)
{
modelist* list;
chan->GetExt(be->GetInfoKey(), list);
if (list)
{
char mask[MAXBUF];
snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());
for (modelist::iterator it = list->begin(); it != list->end(); it++)
{
if (match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
{
// They match an entry on the list, so let them in.
return 1;
}
}
return 0;
}
// or if there wasn't a list, there can't be anyone on it, so we don't need to do anything.
}
return 0;
}
virtual void OnCleanup(int target_type, void* item)
{
be->DoCleanup(target_type, item);
}
virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
{
be->DoSyncChannel(chan, proto, opaque);
}
virtual void OnChannelDelete(chanrec* chan)
{
be->DoChannelDelete(chan);
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
be->DoRehash();
}
virtual char* OnRequest(Request* request)
{
ListModeRequest* LM = (ListModeRequest*)request;
if (strcmp("LM_CHECKLIST", request->GetId()) == 0)
{
modelist* list;
LM->chan->GetExt(be->GetInfoKey(), list);
if (list)
{
char mask[MAXBUF];
snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString());
for (modelist::iterator it = list->begin(); it != list->end(); it++)
{
if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
{
// They match an entry
return (char*)it->mask.c_str();
}
}
return NULL;
}
}
return NULL;
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 3, VF_COMMON | VF_VENDOR, API_VERSION);
}
virtual ~ModuleBanException()
{
ServerInstance->Modes->DelMode(be);
DELETE(be);
ServerInstance->UnpublishInterface("ChannelBanList", this);
}
};
MODULE_INIT(ModuleBanException)
\ No newline at end of file diff --git a/src/modules/m_banredirect.cpp b/src/modules/m_banredirect.cpp index 1764e6f56..2a0ed2ded 100644 --- a/src/modules/m_banredirect.cpp +++ b/src/modules/m_banredirect.cpp @@ -1,343 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "mode.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "u_listmode.h" - -/* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */ - -/* Originally written by Om, January 2007 - */ - -class BanRedirectEntry -{ - public: - std::string targetchan; - std::string banmask; - - BanRedirectEntry(const std::string &target = "", const std::string &mask = "") - : targetchan(target), banmask(mask) - { - } -}; - -typedef std::vector<BanRedirectEntry> BanRedirectList; -typedef std::deque<std::string> StringDeque; - -class BanRedirect : public ModeWatcher -{ - private: - InspIRCd* Srv; - public: - BanRedirect(InspIRCd* Instance) - : ModeWatcher(Instance, 'b', MODETYPE_CHANNEL), Srv(Instance) - { - } - - bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string ¶m, bool adding, ModeType type) - { - /* nick!ident@host -> nick!ident@host - * nick!ident@host#chan -> nick!ident@host#chan - * nick@host#chan -> nick!*@host#chan - * nick!ident#chan -> nick!ident@*#chan - * nick#chan -> nick!*@*#chan - */ - - if(channel && (type == MODETYPE_CHANNEL) && param.length()) - { - BanRedirectList* redirects; - - std::string mask[4]; - enum { NICK, IDENT, HOST, CHAN } current = NICK; - std::string::iterator start_pos = param.begin(); - long maxbans = channel->GetMaxBans(); - - if(channel->bans.size() > static_cast<unsigned>(maxbans)) - { - source->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %d)", source->nick, channel->name, channel->name, maxbans); - return false; - } - - for(std::string::iterator curr = start_pos; curr != param.end(); curr++) - { - switch(*curr) - { - case '!': - mask[current].assign(start_pos, curr); - current = IDENT; - start_pos = curr+1; - break; - case '@': - mask[current].assign(start_pos, curr); - current = HOST; - start_pos = curr+1; - break; - case '#': - mask[current].assign(start_pos, curr); - current = CHAN; - start_pos = curr; - break; - } - } - - if(mask[current].empty()) - { - mask[current].assign(start_pos, param.end()); - } - - /* nick@host wants to be changed to *!nick@host rather than nick!*@host... */ - if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty()) - { - /* std::string::swap() is fast - it runs in constant time */ - mask[NICK].swap(mask[IDENT]); - } - - for(int i = 0; i < 3; i++) - { - if(mask[i].empty()) - { - mask[i].assign("*"); - } - } - - param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]); - - if(mask[CHAN].length()) - { - if(Srv->IsChannel(mask[CHAN].c_str())) - { - if(irc::string(channel->name) == irc::string(mask[CHAN].c_str())) - { - source->WriteServ("690 %s %s :You cannot set a ban redirection to the channel the ban is on", source->nick, channel->name); - return false; - } - else - { - if(adding) - { - /* It's a properly valid redirecting ban, and we're adding it */ - if(!channel->GetExt("banredirects", redirects)) - { - redirects = new BanRedirectList; - channel->Extend("banredirects", redirects); - } - - /* Here 'param' doesn't have the channel on it yet */ - redirects->push_back(BanRedirectEntry(mask[CHAN].c_str(), param.c_str())); - - /* Now it does */ - param.append(mask[CHAN]); - } - else - { - /* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */ - if(channel->GetExt("banredirects", redirects)) - { - /* But there were, so we need to remove the matching one if there is one */ - - for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++) - { - /* Ugly as fuck */ - if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str()))) - { - redirects->erase(redir); - - if(redirects->empty()) - { - DELETE(redirects); - channel->Shrink("banredirects"); - } - - break; - } - } - } - - /* Append the channel so the default +b handler can remove the entry too */ - param.append(mask[CHAN]); - } - } - } - else - { - source->WriteServ("403 %s %s :Invalid channel name in redirection (%s)", source->nick, channel->name, mask[CHAN].c_str()); - return false; - } - } - } - - return true; - } -}; - -class ModuleBanRedirect : public Module -{ - BanRedirect* re; - bool nofollow; - Module* ExceptionModule; - - public: - ModuleBanRedirect(InspIRCd* Me) - : Module(Me) - { - re = new BanRedirect(Me); - nofollow = false; - - if(!ServerInstance->AddModeWatcher(re)) - throw ModuleException("Could not add mode watcher"); - - OnRehash(NULL, ""); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnUserPreJoin] = List[I_OnChannelDelete] = List[I_OnCleanup] = 1; - } - - virtual void OnChannelDelete(chanrec* chan) - { - OnCleanup(TYPE_CHANNEL, chan); - } - - virtual void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_CHANNEL) - { - chanrec* chan = static_cast<chanrec*>(item); - BanRedirectList* redirects; - - if(chan->GetExt("banredirects", redirects)) - { - irc::modestacker modestack(false); - StringDeque stackresult; - const char* mode_junk[MAXMODES+2]; - userrec* myhorriblefakeuser = new userrec(ServerInstance); - myhorriblefakeuser->SetFd(FD_MAGIC_NUMBER); - - mode_junk[0] = chan->name; - - for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++) - { - modestack.Push('b', i->targetchan.insert(0, i->banmask)); - } - - for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++) - { - modestack.PushPlus(); - modestack.Push('b', i->banmask); - } - - while(modestack.GetStackedLine(stackresult)) - { - for(StringDeque::size_type i = 0; i < stackresult.size(); i++) - { - mode_junk[i+1] = stackresult[i].c_str(); - } - - ServerInstance->SendMode(mode_junk, stackresult.size() + 1, myhorriblefakeuser); - } - - DELETE(myhorriblefakeuser); - DELETE(redirects); - chan->Shrink("banredirects"); - } - } - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - ExceptionModule = ServerInstance->FindModule("m_banexception.so"); - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - /* This prevents recursion when a user sets multiple ban redirects in a chain - * (thanks Potter) - */ - if (nofollow) - return 0; - - /* Return 1 to prevent the join, 0 to allow it */ - if (chan) - { - BanRedirectList* redirects; - - if(chan->GetExt("banredirects", redirects)) - { - /* We actually had some ban redirects to check */ - - /* This was replaced with user->MakeHostIP() when I had a snprintf(), but MakeHostIP() doesn't seem to add the nick. - * Maybe we should have a GetFullIPHost() or something to match GetFullHost() and GetFullRealHost? - */ - - if (ExceptionModule) - { - ListModeRequest n(this, ExceptionModule, user, chan); - /* Users with ban exceptions are allowed to join without being redirected */ - if (n.Send()) - return 0; - } - - std::string ipmask(user->nick); - ipmask.append(1, '!').append(user->MakeHostIP()); - - for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++) - { - if(ServerInstance->MatchText(user->GetFullRealHost(), redir->banmask) || ServerInstance->MatchText(user->GetFullHost(), redir->banmask) || ServerInstance->MatchText(ipmask, redir->banmask)) - { - /* tell them they're banned and are being transferred */ - chanrec* destchan = ServerInstance->FindChan(redir->targetchan); - - if(destchan && ServerInstance->FindModule("m_redirect.so") && destchan->IsModeSet('L') && destchan->limit && (destchan->GetUserCounter() >= destchan->limit)) - { - user->WriteServ("474 %s %s :Cannot join channel (You are banned)", user->nick, chan->name); - return 1; - } - else - { - user->WriteServ("470 %s :You are banned from %s. You are being automatically redirected to %s", user->nick, chan->name, redir->targetchan.c_str()); - nofollow = true; - chanrec::JoinUser(ServerInstance, user, redir->targetchan.c_str(), false, "", ServerInstance->Time(true)); - nofollow = false; - return 1; - } - } - } - } - } - return 0; - } - - virtual ~ModuleBanRedirect() - { - ServerInstance->Modes->DelModeWatcher(re); - DELETE(re); - } - - virtual Version GetVersion() - { - return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } - - Priority Prioritize() - { - return (Priority)ServerInstance->PriorityBefore("m_banexception.so"); - } -}; - - -MODULE_INIT(ModuleBanRedirect) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "mode.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "u_listmode.h"
/* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */
/* Originally written by Om, January 2007
*/
class BanRedirectEntry
{
public:
std::string targetchan;
std::string banmask;
BanRedirectEntry(const std::string &target = "", const std::string &mask = "")
: targetchan(target), banmask(mask)
{
}
};
typedef std::vector<BanRedirectEntry> BanRedirectList;
typedef std::deque<std::string> StringDeque;
class BanRedirect : public ModeWatcher
{
private:
InspIRCd* Srv;
public:
BanRedirect(InspIRCd* Instance)
: ModeWatcher(Instance, 'b', MODETYPE_CHANNEL), Srv(Instance)
{
}
bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string ¶m, bool adding, ModeType type)
{
/* nick!ident@host -> nick!ident@host
* nick!ident@host#chan -> nick!ident@host#chan
* nick@host#chan -> nick!*@host#chan
* nick!ident#chan -> nick!ident@*#chan
* nick#chan -> nick!*@*#chan
*/
if(channel && (type == MODETYPE_CHANNEL) && param.length())
{
BanRedirectList* redirects;
std::string mask[4];
enum { NICK, IDENT, HOST, CHAN } current = NICK;
std::string::iterator start_pos = param.begin();
long maxbans = channel->GetMaxBans();
if(channel->bans.size() > static_cast<unsigned>(maxbans))
{
source->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %d)", source->nick, channel->name, channel->name, maxbans);
return false;
}
for(std::string::iterator curr = start_pos; curr != param.end(); curr++)
{
switch(*curr)
{
case '!':
mask[current].assign(start_pos, curr);
current = IDENT;
start_pos = curr+1;
break;
case '@':
mask[current].assign(start_pos, curr);
current = HOST;
start_pos = curr+1;
break;
case '#':
mask[current].assign(start_pos, curr);
current = CHAN;
start_pos = curr;
break;
}
}
if(mask[current].empty())
{
mask[current].assign(start_pos, param.end());
}
/* nick@host wants to be changed to *!nick@host rather than nick!*@host... */
if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty())
{
/* std::string::swap() is fast - it runs in constant time */
mask[NICK].swap(mask[IDENT]);
}
for(int i = 0; i < 3; i++)
{
if(mask[i].empty())
{
mask[i].assign("*");
}
}
param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]);
if(mask[CHAN].length())
{
if(Srv->IsChannel(mask[CHAN].c_str()))
{
if(irc::string(channel->name) == irc::string(mask[CHAN].c_str()))
{
source->WriteServ("690 %s %s :You cannot set a ban redirection to the channel the ban is on", source->nick, channel->name);
return false;
}
else
{
if(adding)
{
/* It's a properly valid redirecting ban, and we're adding it */
if(!channel->GetExt("banredirects", redirects))
{
redirects = new BanRedirectList;
channel->Extend("banredirects", redirects);
}
/* Here 'param' doesn't have the channel on it yet */
redirects->push_back(BanRedirectEntry(mask[CHAN].c_str(), param.c_str()));
/* Now it does */
param.append(mask[CHAN]);
}
else
{
/* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */
if(channel->GetExt("banredirects", redirects))
{
/* But there were, so we need to remove the matching one if there is one */
for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
{
/* Ugly as fuck */
if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str())))
{
redirects->erase(redir);
if(redirects->empty())
{
DELETE(redirects);
channel->Shrink("banredirects");
}
break;
}
}
}
/* Append the channel so the default +b handler can remove the entry too */
param.append(mask[CHAN]);
}
}
}
else
{
source->WriteServ("403 %s %s :Invalid channel name in redirection (%s)", source->nick, channel->name, mask[CHAN].c_str());
return false;
}
}
}
return true;
}
};
class ModuleBanRedirect : public Module
{
BanRedirect* re;
bool nofollow;
Module* ExceptionModule;
public:
ModuleBanRedirect(InspIRCd* Me)
: Module(Me)
{
re = new BanRedirect(Me);
nofollow = false;
if(!ServerInstance->AddModeWatcher(re))
throw ModuleException("Could not add mode watcher");
OnRehash(NULL, "");
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnUserPreJoin] = List[I_OnChannelDelete] = List[I_OnCleanup] = 1;
}
virtual void OnChannelDelete(chanrec* chan)
{
OnCleanup(TYPE_CHANNEL, chan);
}
virtual void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_CHANNEL)
{
chanrec* chan = static_cast<chanrec*>(item);
BanRedirectList* redirects;
if(chan->GetExt("banredirects", redirects))
{
irc::modestacker modestack(false);
StringDeque stackresult;
const char* mode_junk[MAXMODES+2];
userrec* myhorriblefakeuser = new userrec(ServerInstance);
myhorriblefakeuser->SetFd(FD_MAGIC_NUMBER);
mode_junk[0] = chan->name;
for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
{
modestack.Push('b', i->targetchan.insert(0, i->banmask));
}
for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
{
modestack.PushPlus();
modestack.Push('b', i->banmask);
}
while(modestack.GetStackedLine(stackresult))
{
for(StringDeque::size_type i = 0; i < stackresult.size(); i++)
{
mode_junk[i+1] = stackresult[i].c_str();
}
ServerInstance->SendMode(mode_junk, stackresult.size() + 1, myhorriblefakeuser);
}
DELETE(myhorriblefakeuser);
DELETE(redirects);
chan->Shrink("banredirects");
}
}
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
ExceptionModule = ServerInstance->FindModule("m_banexception.so");
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
/* This prevents recursion when a user sets multiple ban redirects in a chain
* (thanks Potter)
*/
if (nofollow)
return 0;
/* Return 1 to prevent the join, 0 to allow it */
if (chan)
{
BanRedirectList* redirects;
if(chan->GetExt("banredirects", redirects))
{
/* We actually had some ban redirects to check */
/* This was replaced with user->MakeHostIP() when I had a snprintf(), but MakeHostIP() doesn't seem to add the nick.
* Maybe we should have a GetFullIPHost() or something to match GetFullHost() and GetFullRealHost?
*/
if (ExceptionModule)
{
ListModeRequest n(this, ExceptionModule, user, chan);
/* Users with ban exceptions are allowed to join without being redirected */
if (n.Send())
return 0;
}
std::string ipmask(user->nick);
ipmask.append(1, '!').append(user->MakeHostIP());
for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
{
if(ServerInstance->MatchText(user->GetFullRealHost(), redir->banmask) || ServerInstance->MatchText(user->GetFullHost(), redir->banmask) || ServerInstance->MatchText(ipmask, redir->banmask))
{
/* tell them they're banned and are being transferred */
chanrec* destchan = ServerInstance->FindChan(redir->targetchan);
if(destchan && ServerInstance->FindModule("m_redirect.so") && destchan->IsModeSet('L') && destchan->limit && (destchan->GetUserCounter() >= destchan->limit))
{
user->WriteServ("474 %s %s :Cannot join channel (You are banned)", user->nick, chan->name);
return 1;
}
else
{
user->WriteServ("470 %s :You are banned from %s. You are being automatically redirected to %s", user->nick, chan->name, redir->targetchan.c_str());
nofollow = true;
chanrec::JoinUser(ServerInstance, user, redir->targetchan.c_str(), false, "", ServerInstance->Time(true));
nofollow = false;
return 1;
}
}
}
}
}
return 0;
}
virtual ~ModuleBanRedirect()
{
ServerInstance->Modes->DelModeWatcher(re);
DELETE(re);
}
virtual Version GetVersion()
{
return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
Priority Prioritize()
{
return (Priority)ServerInstance->PriorityBefore("m_banexception.so");
}
};
MODULE_INIT(ModuleBanRedirect)
\ No newline at end of file diff --git a/src/modules/m_blockamsg.cpp b/src/modules/m_blockamsg.cpp index 69e99d0bb..5ff0c1100 100644 --- a/src/modules/m_blockamsg.cpp +++ b/src/modules/m_blockamsg.cpp @@ -1,191 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" - -/* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */ - -enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT }; -/* IBLOCK_NOTICE - Send a notice to the user informing them of what happened. - * IBLOCK_NOTICEOPERS - Send a notice to the user informing them and send an oper notice. - * IBLOCK_SILENT - Generate no output, silently drop messages. - * IBLOCK_KILL - Kill the user with the reason "Global message (/amsg or /ame) detected". - * IBLOCK_KILLOPERS - As above, but send an oper notice as well. This is the default. - */ - -/** Holds a blocked message's details - */ -class BlockedMessage : public classbase -{ -public: - std::string message; - irc::string target; - time_t sent; - - BlockedMessage(const std::string &msg, const irc::string &tgt, time_t when) - : message(msg), target(tgt), sent(when) - { - } -}; - -class ModuleBlockAmsg : public Module -{ - int ForgetDelay; - BlockAction action; - - public: - ModuleBlockAmsg(InspIRCd* Me) - : Module(Me) - { - - this->OnRehash(NULL,""); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnPreCommand] = List[I_OnCleanup] = 1; - } - - virtual ~ModuleBlockAmsg() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - - ForgetDelay = Conf.ReadInteger("blockamsg", "delay", 0, false); - - if(Conf.GetError() == CONF_VALUE_NOT_FOUND) - ForgetDelay = -1; - - std::string act = Conf.ReadValue("blockamsg", "action", 0); - - if(act == "notice") - action = IBLOCK_NOTICE; - else if(act == "noticeopers") - action = IBLOCK_NOTICEOPERS; - else if(act == "silent") - action = IBLOCK_SILENT; - else if(act == "kill") - action = IBLOCK_KILL; - else - action = IBLOCK_KILLOPERS; - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - // Don't do anything with unregistered users, or remote ones. - if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user)) - return 0; - - // We want case insensitive command comparison. - // Add std::string contructor for irc::string :x - irc::string cmd = command.c_str(); - - if(validated && (cmd == "PRIVMSG" || cmd == "NOTICE") && (pcnt >= 2)) - { - // parameters[0] should have the target(s) in it. - // I think it will be faster to first check if there are any commas, and if there are then try and parse it out. - // Most messages have a single target so... - - int targets = 1; - int userchans = 0; - - if(*parameters[0] != '#') - { - // Decrement if the first target wasn't a channel. - targets--; - } - - for(const char* c = parameters[0]; *c; c++) - if((*c == ',') && *(c+1) && (*(c+1) == '#')) - targets++; - - /* targets should now contain the number of channel targets the msg/notice was pointed at. - * If the msg/notice was a PM there should be no channel targets and 'targets' should = 0. - * We don't want to block PMs so... - */ - if(targets == 0) - { - return 0; - } - - userchans = user->chans.size(); - - // Check that this message wasn't already sent within a few seconds. - BlockedMessage* m; - user->GetExt("amsgblock", m); - - // If the message is identical and within the time. - // We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing... - // OR - // The number of target channels is equal to the number of channels the sender is on..a little suspicious. - // Check it's more than 1 too, or else users on one channel would have fun. - if((m && (m->message == parameters[1]) && (m->target != parameters[0]) && (ForgetDelay != -1) && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == userchans))) - { - // Block it... - if(action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS) - ServerInstance->WriteOpers("*** %s had an /amsg or /ame denied", user->nick); - - if(action == IBLOCK_KILL || action == IBLOCK_KILLOPERS) - userrec::QuitUser(ServerInstance, user, "Global message (/amsg or /ame) detected"); - else if(action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS) - user->WriteServ( "NOTICE %s :Global message (/amsg or /ame) detected", user->nick); - - return 1; - } - - if(m) - { - // If there's already a BlockedMessage allocated, use it. - m->message = parameters[1]; - m->target = parameters[0]; - m->sent = ServerInstance->Time(); - } - else - { - m = new BlockedMessage(parameters[1], parameters[0], ServerInstance->Time()); - user->Extend("amsgblock", (char*)m); - } - } - return 0; - } - - void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - BlockedMessage* m; - user->GetExt("amsgblock", m); - if(m) - { - DELETE(m); - user->Shrink("amsgblock"); - } - } - } -}; - - -MODULE_INIT(ModuleBlockAmsg) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
/* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */
enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT };
/* IBLOCK_NOTICE - Send a notice to the user informing them of what happened.
* IBLOCK_NOTICEOPERS - Send a notice to the user informing them and send an oper notice.
* IBLOCK_SILENT - Generate no output, silently drop messages.
* IBLOCK_KILL - Kill the user with the reason "Global message (/amsg or /ame) detected".
* IBLOCK_KILLOPERS - As above, but send an oper notice as well. This is the default.
*/
/** Holds a blocked message's details
*/
class BlockedMessage : public classbase
{
public:
std::string message;
irc::string target;
time_t sent;
BlockedMessage(const std::string &msg, const irc::string &tgt, time_t when)
: message(msg), target(tgt), sent(when)
{
}
};
class ModuleBlockAmsg : public Module
{
int ForgetDelay;
BlockAction action;
public:
ModuleBlockAmsg(InspIRCd* Me)
: Module(Me)
{
this->OnRehash(NULL,"");
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnPreCommand] = List[I_OnCleanup] = 1;
}
virtual ~ModuleBlockAmsg()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
ForgetDelay = Conf.ReadInteger("blockamsg", "delay", 0, false);
if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
ForgetDelay = -1;
std::string act = Conf.ReadValue("blockamsg", "action", 0);
if(act == "notice")
action = IBLOCK_NOTICE;
else if(act == "noticeopers")
action = IBLOCK_NOTICEOPERS;
else if(act == "silent")
action = IBLOCK_SILENT;
else if(act == "kill")
action = IBLOCK_KILL;
else
action = IBLOCK_KILLOPERS;
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
// Don't do anything with unregistered users, or remote ones.
if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user))
return 0;
// We want case insensitive command comparison.
// Add std::string contructor for irc::string :x
irc::string cmd = command.c_str();
if(validated && (cmd == "PRIVMSG" || cmd == "NOTICE") && (pcnt >= 2))
{
// parameters[0] should have the target(s) in it.
// I think it will be faster to first check if there are any commas, and if there are then try and parse it out.
// Most messages have a single target so...
int targets = 1;
int userchans = 0;
if(*parameters[0] != '#')
{
// Decrement if the first target wasn't a channel.
targets--;
}
for(const char* c = parameters[0]; *c; c++)
if((*c == ',') && *(c+1) && (*(c+1) == '#'))
targets++;
/* targets should now contain the number of channel targets the msg/notice was pointed at.
* If the msg/notice was a PM there should be no channel targets and 'targets' should = 0.
* We don't want to block PMs so...
*/
if(targets == 0)
{
return 0;
}
userchans = user->chans.size();
// Check that this message wasn't already sent within a few seconds.
BlockedMessage* m;
user->GetExt("amsgblock", m);
// If the message is identical and within the time.
// We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing...
// OR
// The number of target channels is equal to the number of channels the sender is on..a little suspicious.
// Check it's more than 1 too, or else users on one channel would have fun.
if((m && (m->message == parameters[1]) && (m->target != parameters[0]) && (ForgetDelay != -1) && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == userchans)))
{
// Block it...
if(action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS)
ServerInstance->WriteOpers("*** %s had an /amsg or /ame denied", user->nick);
if(action == IBLOCK_KILL || action == IBLOCK_KILLOPERS)
userrec::QuitUser(ServerInstance, user, "Global message (/amsg or /ame) detected");
else if(action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS)
user->WriteServ( "NOTICE %s :Global message (/amsg or /ame) detected", user->nick);
return 1;
}
if(m)
{
// If there's already a BlockedMessage allocated, use it.
m->message = parameters[1];
m->target = parameters[0];
m->sent = ServerInstance->Time();
}
else
{
m = new BlockedMessage(parameters[1], parameters[0], ServerInstance->Time());
user->Extend("amsgblock", (char*)m);
}
}
return 0;
}
void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
BlockedMessage* m;
user->GetExt("amsgblock", m);
if(m)
{
DELETE(m);
user->Shrink("amsgblock");
}
}
}
};
MODULE_INIT(ModuleBlockAmsg)
\ No newline at end of file diff --git a/src/modules/m_blockcaps.cpp b/src/modules/m_blockcaps.cpp index 9197a8f11..8713f8c0d 100644 --- a/src/modules/m_blockcaps.cpp +++ b/src/modules/m_blockcaps.cpp @@ -1,143 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "mode.h" - -/* $ModDesc: Provides support for channel mode +P to block all-CAPS channel messages and notices */ - - -/** Handles the +P channel mode - */ -class BlockCaps : public ModeHandler -{ - public: - BlockCaps(InspIRCd* Instance) : ModeHandler(Instance, 'P', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('P')) - { - channel->SetMode('P',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('P')) - { - channel->SetMode('P',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleBlockCAPS : public Module -{ - BlockCaps* bc; - int percent; - unsigned int minlen; - char capsmap[256]; -public: - - ModuleBlockCAPS(InspIRCd* Me) : Module(Me) - { - OnRehash(NULL,""); - bc = new BlockCaps(ServerInstance); - if (!ServerInstance->AddMode(bc, 'P')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - ReadConf(); - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if (target_type == TYPE_CHANNEL) - { - if ((!IS_LOCAL(user)) || (text.length() < minlen)) - return 0; - - chanrec* c = (chanrec*)dest; - - if (c->IsModeSet('P')) - { - int caps = 0; - for (std::string::iterator i = text.begin(); i != text.end(); i++) - caps += capsmap[(unsigned char)*i]; - if ( ((caps*100)/(int)text.length()) >= percent ) - { - user->WriteServ( "404 %s %s :Your line cannot be more than %d%% capital letters if it is %d or more letters long", user->nick, c->name, percent, minlen); - return 1; - } - } - } - return 0; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - void ReadConf() - { - ConfigReader Conf(ServerInstance); - percent = Conf.ReadInteger("blockcaps", "percent", "100", 0, true); - minlen = Conf.ReadInteger("blockcaps", "minlen", "0", 0, true); - std::string hmap = Conf.ReadValue("blockcaps", "capsmap", 0); - if (hmap.empty()) - hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - memset(&capsmap, 0, 255); - for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++) - capsmap[(unsigned char)*n] = 1; - if (percent < 0 || percent > 100) - { - ServerInstance->Log(DEFAULT, "<blockcaps:percent> out of range, setting to default of 100."); - percent = 100; - } - if (minlen < 0 || minlen > MAXBUF-1) - { - ServerInstance->Log(DEFAULT, "<blockcaps:minlen> out of range, setting to default of 0."); - minlen = 0; - } - } - - virtual ~ModuleBlockCAPS() - { - ServerInstance->Modes->DelMode(bc); - DELETE(bc); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleBlockCAPS) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "mode.h"
/* $ModDesc: Provides support for channel mode +P to block all-CAPS channel messages and notices */
/** Handles the +P channel mode
*/
class BlockCaps : public ModeHandler
{
public:
BlockCaps(InspIRCd* Instance) : ModeHandler(Instance, 'P', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('P'))
{
channel->SetMode('P',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('P'))
{
channel->SetMode('P',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleBlockCAPS : public Module
{
BlockCaps* bc;
int percent;
unsigned int minlen;
char capsmap[256];
public:
ModuleBlockCAPS(InspIRCd* Me) : Module(Me)
{
OnRehash(NULL,"");
bc = new BlockCaps(ServerInstance);
if (!ServerInstance->AddMode(bc, 'P'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
ReadConf();
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (target_type == TYPE_CHANNEL)
{
if ((!IS_LOCAL(user)) || (text.length() < minlen))
return 0;
chanrec* c = (chanrec*)dest;
if (c->IsModeSet('P'))
{
int caps = 0;
for (std::string::iterator i = text.begin(); i != text.end(); i++)
caps += capsmap[(unsigned char)*i];
if ( ((caps*100)/(int)text.length()) >= percent )
{
user->WriteServ( "404 %s %s :Your line cannot be more than %d%% capital letters if it is %d or more letters long", user->nick, c->name, percent, minlen);
return 1;
}
}
}
return 0;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
}
void ReadConf()
{
ConfigReader Conf(ServerInstance);
percent = Conf.ReadInteger("blockcaps", "percent", "100", 0, true);
minlen = Conf.ReadInteger("blockcaps", "minlen", "0", 0, true);
std::string hmap = Conf.ReadValue("blockcaps", "capsmap", 0);
if (hmap.empty())
hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
memset(&capsmap, 0, 255);
for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
capsmap[(unsigned char)*n] = 1;
if (percent < 0 || percent > 100)
{
ServerInstance->Log(DEFAULT, "<blockcaps:percent> out of range, setting to default of 100.");
percent = 100;
}
if (minlen < 0 || minlen > MAXBUF-1)
{
ServerInstance->Log(DEFAULT, "<blockcaps:minlen> out of range, setting to default of 0.");
minlen = 0;
}
}
virtual ~ModuleBlockCAPS()
{
ServerInstance->Modes->DelMode(bc);
DELETE(bc);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleBlockCAPS)
\ No newline at end of file diff --git a/src/modules/m_blockcolor.cpp b/src/modules/m_blockcolor.cpp index 69b0e4686..0646caa0b 100644 --- a/src/modules/m_blockcolor.cpp +++ b/src/modules/m_blockcolor.cpp @@ -1,118 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style channel mode +c */ - -/** Handles the +c channel mode - */ -class BlockColor : public ModeHandler -{ - public: - BlockColor(InspIRCd* Instance) : ModeHandler(Instance, 'c', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('c')) - { - channel->SetMode('c',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('c')) - { - channel->SetMode('c',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleBlockColour : public Module -{ - bool AllowChanOps; - BlockColor *bc; - public: - - ModuleBlockColour(InspIRCd* Me) : Module(Me) - { - bc = new BlockColor(ServerInstance); - if (!ServerInstance->AddMode(bc, 'c')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1; - } - - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) - { - chanrec* c = (chanrec*)dest; - - if(c->IsModeSet('c')) - { - if (!CHANOPS_EXEMPT(ServerInstance, 'c') || CHANOPS_EXEMPT(ServerInstance, 'c') && c->GetStatus(user) != STATUS_OP) - { - for (std::string::iterator i = text.begin(); i != text.end(); i++) - { - switch (*i) - { - case 2: - case 3: - case 15: - case 21: - case 22: - case 31: - user->WriteServ("404 %s %s :Can't send colours to channel (+c set)",user->nick, c->name); - return 1; - break; - } - } - } - } - } - return 0; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual ~ModuleBlockColour() - { - ServerInstance->Modes->DelMode(bc); - DELETE(bc); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleBlockColour) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style channel mode +c */
/** Handles the +c channel mode
*/
class BlockColor : public ModeHandler
{
public:
BlockColor(InspIRCd* Instance) : ModeHandler(Instance, 'c', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('c'))
{
channel->SetMode('c',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('c'))
{
channel->SetMode('c',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleBlockColour : public Module
{
bool AllowChanOps;
BlockColor *bc;
public:
ModuleBlockColour(InspIRCd* Me) : Module(Me)
{
bc = new BlockColor(ServerInstance);
if (!ServerInstance->AddMode(bc, 'c'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
{
chanrec* c = (chanrec*)dest;
if(c->IsModeSet('c'))
{
if (!CHANOPS_EXEMPT(ServerInstance, 'c') || CHANOPS_EXEMPT(ServerInstance, 'c') && c->GetStatus(user) != STATUS_OP)
{
for (std::string::iterator i = text.begin(); i != text.end(); i++)
{
switch (*i)
{
case 2:
case 3:
case 15:
case 21:
case 22:
case 31:
user->WriteServ("404 %s %s :Can't send colours to channel (+c set)",user->nick, c->name);
return 1;
break;
}
}
}
}
}
return 0;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
}
virtual ~ModuleBlockColour()
{
ServerInstance->Modes->DelMode(bc);
DELETE(bc);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleBlockColour)
\ No newline at end of file diff --git a/src/modules/m_botmode.cpp b/src/modules/m_botmode.cpp index a6cad9577..8cc999f12 100644 --- a/src/modules/m_botmode.cpp +++ b/src/modules/m_botmode.cpp @@ -1,95 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <stdio.h> -#include <string> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" - -/* $ModDesc: Provides support for unreal-style umode +B */ - -/** Handles user mode +B - */ -class BotMode : public ModeHandler -{ - public: - BotMode(InspIRCd* Instance) : ModeHandler(Instance, 'B', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('B')) - { - dest->SetMode('B',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('B')) - { - dest->SetMode('B',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleBotMode : public Module -{ - - BotMode* bm; - public: - ModuleBotMode(InspIRCd* Me) - : Module(Me) - { - - bm = new BotMode(ServerInstance); - if (!ServerInstance->AddMode(bm, 'B')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnWhois] = 1; - } - - virtual ~ModuleBotMode() - { - ServerInstance->Modes->DelMode(bm); - DELETE(bm); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } - - virtual void OnWhois(userrec* src, userrec* dst) - { - if (dst->IsModeSet('B')) - { - ServerInstance->SendWhoisLine(src, dst, 335, std::string(src->nick)+" "+std::string(dst->nick)+" :is a bot on "+ServerInstance->Config->Network); - } - } - -}; - - -MODULE_INIT(ModuleBotMode) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <stdio.h>
#include <string>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
/* $ModDesc: Provides support for unreal-style umode +B */
/** Handles user mode +B
*/
class BotMode : public ModeHandler
{
public:
BotMode(InspIRCd* Instance) : ModeHandler(Instance, 'B', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!dest->IsModeSet('B'))
{
dest->SetMode('B',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('B'))
{
dest->SetMode('B',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleBotMode : public Module
{
BotMode* bm;
public:
ModuleBotMode(InspIRCd* Me)
: Module(Me)
{
bm = new BotMode(ServerInstance);
if (!ServerInstance->AddMode(bm, 'B'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnWhois] = 1;
}
virtual ~ModuleBotMode()
{
ServerInstance->Modes->DelMode(bm);
DELETE(bm);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
virtual void OnWhois(userrec* src, userrec* dst)
{
if (dst->IsModeSet('B'))
{
ServerInstance->SendWhoisLine(src, dst, 335, std::string(src->nick)+" "+std::string(dst->nick)+" :is a bot on "+ServerInstance->Config->Network);
}
}
};
MODULE_INIT(ModuleBotMode)
\ No newline at end of file diff --git a/src/modules/m_cban.cpp b/src/modules/m_cban.cpp index c8e6a86b9..65be0d9bb 100644 --- a/src/modules/m_cban.cpp +++ b/src/modules/m_cban.cpp @@ -1,251 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <algorithm> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" - -/* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */ - -/** Holds a CBAN item - */ -class CBan : public classbase -{ -public: - irc::string chname; - std::string set_by; - time_t set_on; - long length; - std::string reason; - - CBan() - { - } - - CBan(irc::string cn, std::string sb, time_t so, long ln, std::string rs) : chname(cn), set_by(sb), set_on(so), length(ln), reason(rs) - { - } -}; - -bool CBanComp(const CBan &ban1, const CBan &ban2); - -typedef std::vector<CBan> cbanlist; - -/* cbans is declared here, as our type is right above. Don't try move it. */ -cbanlist cbans; - -/** Handle /CBAN - */ -class cmd_cban : public command_t -{ - public: - cmd_cban(InspIRCd* Me) : command_t(Me, "CBAN", 'o', 1) - { - this->source = "m_cban.so"; - this->syntax = "<channel> [<duration> :<reason>]"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - /* syntax: CBAN #channel time :reason goes here */ - /* 'time' is a human-readable timestring, like 2d3h2s. */ - - if(pcnt == 1) - { - /* form: CBAN #channel removes a CBAN */ - for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++) - { - if (parameters[0] == iter->chname) - { - long remaining = iter->length + ServerInstance->Time(); - user->WriteServ("386 %s %s :Removed CBAN due to expire at %s (%s)", user->nick, iter->chname.c_str(), ServerInstance->TimeString(remaining).c_str(), iter->reason.c_str()); - cbans.erase(iter); - break; - } - } - } - else if (pcnt >= 2) - { - /* full form to add a CBAN */ - if (ServerInstance->IsChannel(parameters[0])) - { - // parameters[0] = #channel - // parameters[1] = 1h3m2s - // parameters[2] = Tortoise abuser - long length = ServerInstance->Duration(parameters[1]); - std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied"; - - cbans.push_back(CBan(parameters[0], user->nick, ServerInstance->Time(), length, reason)); - - std::sort(cbans.begin(), cbans.end(), CBanComp); - - if(length > 0) - { - user->WriteServ("385 %s %s :Added %lu second channel ban (%s)", user->nick, parameters[0], length, reason.c_str()); - ServerInstance->WriteOpers("*** %s added %lu second channel ban on %s (%s)", user->nick, length, parameters[0], reason.c_str()); - } - else - { - user->WriteServ("385 %s %s :Added permanent channel ban (%s)", user->nick, parameters[0], reason.c_str()); - ServerInstance->WriteOpers("*** %s added permanent channel ban on %s (%s)", user->nick, parameters[0], reason.c_str()); - } - } - else - { - user->WriteServ("403 %s %s :Invalid channel name", user->nick, parameters[0]); - return CMD_FAILURE; - } - } - - /* we want this routed! */ - return CMD_SUCCESS; - } -}; - -bool CBanComp(const CBan &ban1, const CBan &ban2) -{ - return ((ban1.set_on + ban1.length) < (ban2.set_on + ban2.length)); -} - -class ModuleCBan : public Module -{ - cmd_cban* mycommand; - - - public: - ModuleCBan(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_cban(Me); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - List[I_OnUserPreJoin] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1; - } - - virtual int OnStats(char symbol, userrec* user, string_list &results) - { - ExpireBans(); - - if(symbol == 'C') - { - for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++) - { - unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time(); - results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+iter->chname.c_str()+" "+iter->set_by+" "+ConvToStr(iter->set_on)+" "+ConvToStr(iter->length)+" "+ConvToStr(remaining)+" :"+iter->reason); - } - } - - return 0; - } - - virtual int OnUserPreJoin(userrec *user, chanrec *chan, const char *cname, std::string &privs) - { - ExpireBans(); - - /* check cbans in here, and apply as necessary. */ - for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++) - { - if(iter->chname == cname && !user->modes[UM_OPERATOR]) - { - // Channel is banned. - user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick, cname, iter->reason.c_str()); - ServerInstance->WriteOpers("*** %s tried to join %s which is CBANed (%s)", user->nick, cname, iter->reason.c_str()); - return 1; - } - } - return 0; - } - - virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable) - { - for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++) - { - proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "cban", EncodeCBan(*iter)); - } - } - - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - if((target_type == TYPE_OTHER) && (extname == "cban")) - { - cbans.push_back(DecodeCBan(extdata)); - std::sort(cbans.begin(), cbans.end(), CBanComp); - } - } - - virtual ~ModuleCBan() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - std::string EncodeCBan(const CBan &ban) - { - std::ostringstream stream; - stream << ban.chname << " " << ban.set_by << " " << ban.set_on << " " << ban.length << " :" << ban.reason; - return stream.str(); - } - - CBan DecodeCBan(const std::string &data) - { - CBan res; - int set_on; - irc::tokenstream tokens(data); - tokens.GetToken(res.chname); - tokens.GetToken(res.set_by); - tokens.GetToken(set_on); - res.set_on = set_on; - tokens.GetToken(res.length); - tokens.GetToken(res.reason); - return res; - } - - void ExpireBans() - { - bool go_again = true; - - while (go_again) - { - go_again = false; - - for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++) - { - /* 0 == permanent, don't mess with them! -- w00t */ - if (iter->length != 0) - { - if (iter->set_on + iter->length <= ServerInstance->Time()) - { - ServerInstance->WriteOpers("*** %li second CBAN on %s (%s) set on %s expired", iter->length, iter->chname.c_str(), iter->reason.c_str(), ServerInstance->TimeString(iter->set_on).c_str()); - cbans.erase(iter); - go_again = true; - } - } - - if (go_again == true) - break; - } - } - } -}; - -MODULE_INIT(ModuleCBan) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <algorithm>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
/* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */
/** Holds a CBAN item
*/
class CBan : public classbase
{
public:
irc::string chname;
std::string set_by;
time_t set_on;
long length;
std::string reason;
CBan()
{
}
CBan(irc::string cn, std::string sb, time_t so, long ln, std::string rs) : chname(cn), set_by(sb), set_on(so), length(ln), reason(rs)
{
}
};
bool CBanComp(const CBan &ban1, const CBan &ban2);
typedef std::vector<CBan> cbanlist;
/* cbans is declared here, as our type is right above. Don't try move it. */
cbanlist cbans;
/** Handle /CBAN
*/
class cmd_cban : public command_t
{
public:
cmd_cban(InspIRCd* Me) : command_t(Me, "CBAN", 'o', 1)
{
this->source = "m_cban.so";
this->syntax = "<channel> [<duration> :<reason>]";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
/* syntax: CBAN #channel time :reason goes here */
/* 'time' is a human-readable timestring, like 2d3h2s. */
if(pcnt == 1)
{
/* form: CBAN #channel removes a CBAN */
for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
if (parameters[0] == iter->chname)
{
long remaining = iter->length + ServerInstance->Time();
user->WriteServ("386 %s %s :Removed CBAN due to expire at %s (%s)", user->nick, iter->chname.c_str(), ServerInstance->TimeString(remaining).c_str(), iter->reason.c_str());
cbans.erase(iter);
break;
}
}
}
else if (pcnt >= 2)
{
/* full form to add a CBAN */
if (ServerInstance->IsChannel(parameters[0]))
{
// parameters[0] = #channel
// parameters[1] = 1h3m2s
// parameters[2] = Tortoise abuser
long length = ServerInstance->Duration(parameters[1]);
std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";
cbans.push_back(CBan(parameters[0], user->nick, ServerInstance->Time(), length, reason));
std::sort(cbans.begin(), cbans.end(), CBanComp);
if(length > 0)
{
user->WriteServ("385 %s %s :Added %lu second channel ban (%s)", user->nick, parameters[0], length, reason.c_str());
ServerInstance->WriteOpers("*** %s added %lu second channel ban on %s (%s)", user->nick, length, parameters[0], reason.c_str());
}
else
{
user->WriteServ("385 %s %s :Added permanent channel ban (%s)", user->nick, parameters[0], reason.c_str());
ServerInstance->WriteOpers("*** %s added permanent channel ban on %s (%s)", user->nick, parameters[0], reason.c_str());
}
}
else
{
user->WriteServ("403 %s %s :Invalid channel name", user->nick, parameters[0]);
return CMD_FAILURE;
}
}
/* we want this routed! */
return CMD_SUCCESS;
}
};
bool CBanComp(const CBan &ban1, const CBan &ban2)
{
return ((ban1.set_on + ban1.length) < (ban2.set_on + ban2.length));
}
class ModuleCBan : public Module
{
cmd_cban* mycommand;
public:
ModuleCBan(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_cban(Me);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
List[I_OnUserPreJoin] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;
}
virtual int OnStats(char symbol, userrec* user, string_list &results)
{
ExpireBans();
if(symbol == 'C')
{
for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();
results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+iter->chname.c_str()+" "+iter->set_by+" "+ConvToStr(iter->set_on)+" "+ConvToStr(iter->length)+" "+ConvToStr(remaining)+" :"+iter->reason);
}
}
return 0;
}
virtual int OnUserPreJoin(userrec *user, chanrec *chan, const char *cname, std::string &privs)
{
ExpireBans();
/* check cbans in here, and apply as necessary. */
for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
if(iter->chname == cname && !user->modes[UM_OPERATOR])
{
// Channel is banned.
user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick, cname, iter->reason.c_str());
ServerInstance->WriteOpers("*** %s tried to join %s which is CBANed (%s)", user->nick, cname, iter->reason.c_str());
return 1;
}
}
return 0;
}
virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
{
for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "cban", EncodeCBan(*iter));
}
}
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
if((target_type == TYPE_OTHER) && (extname == "cban"))
{
cbans.push_back(DecodeCBan(extdata));
std::sort(cbans.begin(), cbans.end(), CBanComp);
}
}
virtual ~ModuleCBan()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
std::string EncodeCBan(const CBan &ban)
{
std::ostringstream stream;
stream << ban.chname << " " << ban.set_by << " " << ban.set_on << " " << ban.length << " :" << ban.reason;
return stream.str();
}
CBan DecodeCBan(const std::string &data)
{
CBan res;
int set_on;
irc::tokenstream tokens(data);
tokens.GetToken(res.chname);
tokens.GetToken(res.set_by);
tokens.GetToken(set_on);
res.set_on = set_on;
tokens.GetToken(res.length);
tokens.GetToken(res.reason);
return res;
}
void ExpireBans()
{
bool go_again = true;
while (go_again)
{
go_again = false;
for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
/* 0 == permanent, don't mess with them! -- w00t */
if (iter->length != 0)
{
if (iter->set_on + iter->length <= ServerInstance->Time())
{
ServerInstance->WriteOpers("*** %li second CBAN on %s (%s) set on %s expired", iter->length, iter->chname.c_str(), iter->reason.c_str(), ServerInstance->TimeString(iter->set_on).c_str());
cbans.erase(iter);
go_again = true;
}
}
if (go_again == true)
break;
}
}
}
};
MODULE_INIT(ModuleCBan)
\ No newline at end of file diff --git a/src/modules/m_censor.cpp b/src/modules/m_censor.cpp index f4a5bd620..a7aa2f8b1 100644 --- a/src/modules/m_censor.cpp +++ b/src/modules/m_censor.cpp @@ -1,196 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#define _CRT_SECURE_NO_DEPRECATE -#define _SCL_SECURE_NO_DEPRECATE - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -typedef std::map<irc::string,irc::string> censor_t; - -/* $ModDesc: Provides user and channel +G mode */ - -/** Handles usermode +G - */ -class CensorUser : public ModeHandler -{ - public: - CensorUser(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('G')) - { - dest->SetMode('G',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('G')) - { - dest->SetMode('G',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** Handles channel mode +G - */ -class CensorChannel : public ModeHandler -{ - public: - CensorChannel(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('G')) - { - channel->SetMode('G',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('G')) - { - channel->SetMode('G',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_ALLOW; - } -}; - -class ModuleCensor : public Module -{ - - - censor_t censors; - CensorUser *cu; - CensorChannel *cc; - - public: - ModuleCensor(InspIRCd* Me) - : Module(Me) - { - /* Read the configuration file on startup. - */ - OnRehash(NULL,""); - cu = new CensorUser(ServerInstance); - cc = new CensorChannel(ServerInstance); - if (!ServerInstance->AddMode(cu, 'G') || !ServerInstance->AddMode(cc, 'G')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1; - } - - virtual ~ModuleCensor() - { - ServerInstance->Modes->DelMode(cu); - ServerInstance->Modes->DelMode(cc); - DELETE(cu); - DELETE(cc); - } - - virtual void ReplaceLine(irc::string &text, irc::string pattern, irc::string replace) - { - if ((!pattern.empty()) && (!text.empty())) - { - std::string::size_type pos; - while ((pos = text.find(pattern)) != irc::string::npos) - { - text.erase(pos,pattern.length()); - text.insert(pos,replace); - } - } - } - - // format of a config entry is <badword text="shit" replace="poo"> - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if (!IS_LOCAL(user)) - return 0; - - bool active = false; - - if (target_type == TYPE_USER) - active = ((userrec*)dest)->IsModeSet('G'); - else if (target_type == TYPE_CHANNEL) - active = ((chanrec*)dest)->IsModeSet('G'); - - if (!active) - return 0; - - irc::string text2 = text.c_str(); - for (censor_t::iterator index = censors.begin(); index != censors.end(); index++) - { - if (text2.find(index->first) != irc::string::npos) - { - if (index->second.empty()) - { - user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked", user->nick, ((chanrec*)dest)->name, index->first.c_str()); - return 1; - } - - this->ReplaceLine(text2,index->first,index->second); - } - } - text = text2.c_str(); - return 0; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - /* - * reload our config file on rehash - we must destroy and re-allocate the classes - * to call the constructor again and re-read our data. - */ - ConfigReader* MyConf = new ConfigReader(ServerInstance); - censors.clear(); - for (int index = 0; index < MyConf->Enumerate("badword"); index++) - { - irc::string pattern = (MyConf->ReadValue("badword","text",index)).c_str(); - irc::string replace = (MyConf->ReadValue("badword","replace",index)).c_str(); - censors[pattern] = replace; - } - DELETE(MyConf); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleCensor) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_DEPRECATE
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
typedef std::map<irc::string,irc::string> censor_t;
/* $ModDesc: Provides user and channel +G mode */
/** Handles usermode +G
*/
class CensorUser : public ModeHandler
{
public:
CensorUser(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!dest->IsModeSet('G'))
{
dest->SetMode('G',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('G'))
{
dest->SetMode('G',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** Handles channel mode +G
*/
class CensorChannel : public ModeHandler
{
public:
CensorChannel(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('G'))
{
channel->SetMode('G',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('G'))
{
channel->SetMode('G',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_ALLOW;
}
};
class ModuleCensor : public Module
{
censor_t censors;
CensorUser *cu;
CensorChannel *cc;
public:
ModuleCensor(InspIRCd* Me)
: Module(Me)
{
/* Read the configuration file on startup.
*/
OnRehash(NULL,"");
cu = new CensorUser(ServerInstance);
cc = new CensorChannel(ServerInstance);
if (!ServerInstance->AddMode(cu, 'G') || !ServerInstance->AddMode(cc, 'G'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
}
virtual ~ModuleCensor()
{
ServerInstance->Modes->DelMode(cu);
ServerInstance->Modes->DelMode(cc);
DELETE(cu);
DELETE(cc);
}
virtual void ReplaceLine(irc::string &text, irc::string pattern, irc::string replace)
{
if ((!pattern.empty()) && (!text.empty()))
{
std::string::size_type pos;
while ((pos = text.find(pattern)) != irc::string::npos)
{
text.erase(pos,pattern.length());
text.insert(pos,replace);
}
}
}
// format of a config entry is <badword text="shit" replace="poo">
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (!IS_LOCAL(user))
return 0;
bool active = false;
if (target_type == TYPE_USER)
active = ((userrec*)dest)->IsModeSet('G');
else if (target_type == TYPE_CHANNEL)
active = ((chanrec*)dest)->IsModeSet('G');
if (!active)
return 0;
irc::string text2 = text.c_str();
for (censor_t::iterator index = censors.begin(); index != censors.end(); index++)
{
if (text2.find(index->first) != irc::string::npos)
{
if (index->second.empty())
{
user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked", user->nick, ((chanrec*)dest)->name, index->first.c_str());
return 1;
}
this->ReplaceLine(text2,index->first,index->second);
}
}
text = text2.c_str();
return 0;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
/*
* reload our config file on rehash - we must destroy and re-allocate the classes
* to call the constructor again and re-read our data.
*/
ConfigReader* MyConf = new ConfigReader(ServerInstance);
censors.clear();
for (int index = 0; index < MyConf->Enumerate("badword"); index++)
{
irc::string pattern = (MyConf->ReadValue("badword","text",index)).c_str();
irc::string replace = (MyConf->ReadValue("badword","replace",index)).c_str();
censors[pattern] = replace;
}
DELETE(MyConf);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleCensor)
\ No newline at end of file diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 290f55d22..64fd6c69f 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -1,511 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "modules.h" -#include "dns.h" -#ifndef WINDOWS -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif - -/* $ModDesc: Change user's hosts connecting from known CGI:IRC hosts */ - -enum CGItype { PASS, IDENT, PASSFIRST, IDENTFIRST, WEBIRC }; - - -/** Holds a CGI site's details - */ -class CGIhost : public classbase -{ -public: - std::string hostmask; - CGItype type; - std::string password; - - CGIhost(const std::string &mask = "", CGItype t = IDENTFIRST, const std::string &password ="") - : hostmask(mask), type(t), password(password) - { - } -}; -typedef std::vector<CGIhost> CGIHostlist; - -class cmd_webirc : public command_t -{ - InspIRCd* Me; - CGIHostlist Hosts; - bool notify; - public: - cmd_webirc(InspIRCd* Me, CGIHostlist &Hosts, bool notify) : command_t(Me, "WEBIRC", 0, 4, true), Hosts(Hosts), notify(notify) - { - this->source = "m_cgiirc.so"; - this->syntax = "password client hostname ip"; - } - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - if(user->registered == REG_ALL) - return CMD_FAILURE; - - for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++) - { - if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask)) - { - if(iter->type == WEBIRC && parameters[0] == iter->password) - { - user->Extend("cgiirc_realhost", new std::string(user->host)); - user->Extend("cgiirc_realip", new std::string(user->GetIPString())); - if (notify) - ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick, user->host, parameters[2], user->host); - user->Extend("cgiirc_webirc_hostname", new std::string(parameters[2])); - user->Extend("cgiirc_webirc_ip", new std::string(parameters[3])); - return CMD_LOCALONLY; - } - } - } - return CMD_FAILURE; - } -}; - - -/** Resolver for CGI:IRC hostnames encoded in ident/GECOS - */ -class CGIResolver : public Resolver -{ - std::string typ; - int theirfd; - userrec* them; - bool notify; - public: - CGIResolver(Module* me, InspIRCd* ServerInstance, bool NotifyOpers, const std::string &source, bool forward, userrec* u, int userfd, const std::string &type, bool &cached) - : Resolver(ServerInstance, source, forward ? DNS_QUERY_A : DNS_QUERY_PTR4, cached, me), typ(type), theirfd(userfd), them(u), notify(NotifyOpers) { } - - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) - { - /* Check the user still exists */ - if ((them) && (them == ServerInstance->SE->GetRef(theirfd))) - { - if (notify) - ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick, them->host, result.c_str(), typ.c_str()); - - strlcpy(them->host, result.c_str(), 63); - strlcpy(them->dhost, result.c_str(), 63); - strlcpy(them->ident, "~cgiirc", 8); - them->InvalidateCache(); - } - } - - virtual void OnError(ResolverError e, const std::string &errormessage) - { - if ((them) && (them == ServerInstance->SE->GetRef(theirfd))) - { - if (notify) - ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick, them->host,typ.c_str()); - } - } - - virtual ~CGIResolver() - { - } -}; - -class ModuleCgiIRC : public Module -{ - cmd_webirc* mycommand; - bool NotifyOpers; - CGIHostlist Hosts; -public: - ModuleCgiIRC(InspIRCd* Me) : Module(Me) - { - - OnRehash(NULL,""); - mycommand=new cmd_webirc(Me, Hosts, NotifyOpers); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCleanup] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserQuit] = List[I_OnUserConnect] = 1; - } - - virtual Priority Prioritize() - { - // We want to get here before m_cloaking and m_hostchange etc - return PRIORITY_FIRST; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - - NotifyOpers = Conf.ReadFlag("cgiirc", "opernotice", 0); // If we send an oper notice when a CGI:IRC has their host changed. - - if(Conf.GetError() == CONF_VALUE_NOT_FOUND) - NotifyOpers = true; - - for(int i = 0; i < Conf.Enumerate("cgihost"); i++) - { - std::string hostmask = Conf.ReadValue("cgihost", "mask", i); // An allowed CGI:IRC host - std::string type = Conf.ReadValue("cgihost", "type", i); // What type of user-munging we do on this host. - std::string password = Conf.ReadValue("cgihost", "password", i); - - if(hostmask.length()) - { - if(type == "webirc" && !password.length()) { - ServerInstance->Log(DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str()); - } else { - CGItype cgitype; - if(type == "pass") - cgitype = PASS; - else if(type == "ident") - cgitype = IDENT; - else if(type == "passfirst") - cgitype = PASSFIRST; - else if(type == "webirc") { - cgitype = WEBIRC; - } - Hosts.push_back(CGIhost(hostmask,cgitype, password.length() ? password : "" )); - } - } - else - { - ServerInstance->Log(DEFAULT, "m_cgiirc.so: Invalid <cgihost:mask> value in config: %s", hostmask.c_str()); - continue; - } - } - } - - virtual void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - std::string* realhost; - std::string* realip; - - if(user->GetExt("cgiirc_realhost", realhost)) - { - delete realhost; - user->Shrink("cgiirc_realhost"); - } - - if(user->GetExt("cgiirc_realip", realip)) - { - delete realip; - user->Shrink("cgiirc_realip"); - } - } - } - - virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable) - { - if((extname == "cgiirc_realhost") || (extname == "cgiirc_realip")) - { - std::string* data; - - if(user->GetExt(extname, data)) - { - proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *data); - } - } - } - - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - if(target_type == TYPE_USER) - { - userrec* dest = (userrec*)target; - std::string* bleh; - if(((extname == "cgiirc_realhost") || (extname == "cgiirc_realip")) && (!dest->GetExt(extname, bleh))) - { - dest->Extend(extname, new std::string(extdata)); - } - } - } - - virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message) - { - OnCleanup(TYPE_USER, user); - } - - - virtual int OnUserRegister(userrec* user) - { - for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++) - { - if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask)) - { - // Deal with it... - if(iter->type == PASS) - { - CheckPass(user); // We do nothing if it fails so... - } - else if(iter->type == PASSFIRST && !CheckPass(user)) - { - // If the password lookup failed, try the ident - CheckIdent(user); // If this fails too, do nothing - } - else if(iter->type == IDENT) - { - CheckIdent(user); // Nothing on failure. - } - else if(iter->type == IDENTFIRST && !CheckIdent(user)) - { - // If the ident lookup fails, try the password. - CheckPass(user); - } - else if(iter->type == WEBIRC) - { - // We don't need to do anything here - } - return 0; - } - } - return 0; - } - - virtual void OnUserConnect(userrec* user) - { - std::string *webirc_hostname, *webirc_ip; - if(user->GetExt("cgiirc_webirc_hostname", webirc_hostname)) - { - strlcpy(user->host,webirc_hostname->c_str(),63); - strlcpy(user->dhost,webirc_hostname->c_str(),63); - delete webirc_hostname; - user->InvalidateCache(); - user->Shrink("cgiirc_webirc_hostname"); - } - if(user->GetExt("cgiirc_webirc_ip", webirc_ip)) - { - bool valid=false; - user->RemoveCloneCounts(); -#ifdef IPV6 - valid = (inet_pton(AF_INET6, webirc_ip->c_str(), &((sockaddr_in6*)user->ip)->sin6_addr) > 0); - - if(!valid) - valid = (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr)); -#else - if (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr)) - valid = true; -#endif - - delete webirc_ip; - user->InvalidateCache(); - user->Shrink("cgiirc_webirc_ip"); - ServerInstance->AddLocalClone(user); - ServerInstance->AddGlobalClone(user); - user->CheckClass(); - } - } - - bool CheckPass(userrec* user) - { - if(IsValidHost(user->password)) - { - user->Extend("cgiirc_realhost", new std::string(user->host)); - user->Extend("cgiirc_realip", new std::string(user->GetIPString())); - strlcpy(user->host, user->password, 64); - strlcpy(user->dhost, user->password, 64); - user->InvalidateCache(); - - bool valid = false; - user->RemoveCloneCounts(); -#ifdef IPV6 - if (user->GetProtocolFamily() == AF_INET6) - valid = (inet_pton(AF_INET6, user->password, &((sockaddr_in6*)user->ip)->sin6_addr) > 0); - else - valid = (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr)); -#else - if (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr)) - valid = true; -#endif - ServerInstance->AddLocalClone(user); - ServerInstance->AddGlobalClone(user); - user->CheckClass(); - - if (valid) - { - /* We were given a IP in the password, we don't do DNS so they get this is as their host as well. */ - if(NotifyOpers) - ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password); - } - else - { - /* We got as resolved hostname in the password. */ - try - { - - bool cached; - CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, user->password, false, user, user->GetFd(), "PASS", cached); - ServerInstance->AddResolver(r, cached); - } - catch (...) - { - if (NotifyOpers) - ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host); - } - } - - *user->password = 0; - - /*if(NotifyOpers) - ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password);*/ - - return true; - } - - return false; - } - - bool CheckIdent(userrec* user) - { - int ip[4]; - char* ident; - char newip[16]; - int len = strlen(user->ident); - - if(len == 8) - ident = user->ident; - else if(len == 9 && *user->ident == '~') - ident = user->ident+1; - else - return false; - - for(int i = 0; i < 4; i++) - if(!HexToInt(ip[i], ident + i*2)) - return false; - - snprintf(newip, 16, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); - - user->Extend("cgiirc_realhost", new std::string(user->host)); - user->Extend("cgiirc_realip", new std::string(user->GetIPString())); - user->RemoveCloneCounts(); -#ifdef IPV6 - if (user->GetProtocolFamily() == AF_INET6) - inet_pton(AF_INET6, newip, &((sockaddr_in6*)user->ip)->sin6_addr); - else -#endif - inet_aton(newip, &((sockaddr_in*)user->ip)->sin_addr); - ServerInstance->AddLocalClone(user); - ServerInstance->AddGlobalClone(user); - user->CheckClass(); - try - { - strlcpy(user->host, newip, 16); - strlcpy(user->dhost, newip, 16); - strlcpy(user->ident, "~cgiirc", 8); - - bool cached; - CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, newip, false, user, user->GetFd(), "IDENT", cached); - ServerInstance->AddResolver(r, cached); - } - catch (...) - { - strlcpy(user->host, newip, 16); - strlcpy(user->dhost, newip, 16); - strlcpy(user->ident, "~cgiirc", 8); - user->InvalidateCache(); - - if(NotifyOpers) - ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host); - } - /*strlcpy(user->host, newip, 16); - strlcpy(user->dhost, newip, 16); - strlcpy(user->ident, "~cgiirc", 8);*/ - - return true; - } - - bool IsValidHost(const std::string &host) - { - if(!host.size()) - return false; - - for(unsigned int i = 0; i < host.size(); i++) - { - if( ((host[i] >= '0') && (host[i] <= '9')) || - ((host[i] >= 'A') && (host[i] <= 'Z')) || - ((host[i] >= 'a') && (host[i] <= 'z')) || - ((host[i] == '-') && (i > 0) && (i+1 < host.size()) && (host[i-1] != '.') && (host[i+1] != '.')) || - ((host[i] == '.') && (i > 0) && (i+1 < host.size())) ) - - continue; - else - return false; - } - - return true; - } - - bool IsValidIP(const std::string &ip) - { - if(ip.size() < 7 || ip.size() > 15) - return false; - - short sincedot = 0; - short dots = 0; - - for(unsigned int i = 0; i < ip.size(); i++) - { - if((dots <= 3) && (sincedot <= 3)) - { - if((ip[i] >= '0') && (ip[i] <= '9')) - { - sincedot++; - } - else if(ip[i] == '.') - { - sincedot = 0; - dots++; - } - } - else - { - return false; - - } - } - - if(dots != 3) - return false; - - return true; - } - - bool HexToInt(int &out, const char* in) - { - char ip[3]; - ip[0] = in[0]; - ip[1] = in[1]; - ip[2] = 0; - out = strtol(ip, NULL, 16); - - if(out > 255 || out < 0) - return false; - - return true; - } - - virtual ~ModuleCgiIRC() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleCgiIRC) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "modules.h"
#include "dns.h"
#ifndef WINDOWS
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
/* $ModDesc: Change user's hosts connecting from known CGI:IRC hosts */
enum CGItype { PASS, IDENT, PASSFIRST, IDENTFIRST, WEBIRC };
/** Holds a CGI site's details
*/
class CGIhost : public classbase
{
public:
std::string hostmask;
CGItype type;
std::string password;
CGIhost(const std::string &mask = "", CGItype t = IDENTFIRST, const std::string &password ="")
: hostmask(mask), type(t), password(password)
{
}
};
typedef std::vector<CGIhost> CGIHostlist;
class cmd_webirc : public command_t
{
InspIRCd* Me;
CGIHostlist Hosts;
bool notify;
public:
cmd_webirc(InspIRCd* Me, CGIHostlist &Hosts, bool notify) : command_t(Me, "WEBIRC", 0, 4, true), Hosts(Hosts), notify(notify)
{
this->source = "m_cgiirc.so";
this->syntax = "password client hostname ip";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
if(user->registered == REG_ALL)
return CMD_FAILURE;
for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++)
{
if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask))
{
if(iter->type == WEBIRC && parameters[0] == iter->password)
{
user->Extend("cgiirc_realhost", new std::string(user->host));
user->Extend("cgiirc_realip", new std::string(user->GetIPString()));
if (notify)
ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick, user->host, parameters[2], user->host);
user->Extend("cgiirc_webirc_hostname", new std::string(parameters[2]));
user->Extend("cgiirc_webirc_ip", new std::string(parameters[3]));
return CMD_LOCALONLY;
}
}
}
return CMD_FAILURE;
}
};
/** Resolver for CGI:IRC hostnames encoded in ident/GECOS
*/
class CGIResolver : public Resolver
{
std::string typ;
int theirfd;
userrec* them;
bool notify;
public:
CGIResolver(Module* me, InspIRCd* ServerInstance, bool NotifyOpers, const std::string &source, bool forward, userrec* u, int userfd, const std::string &type, bool &cached)
: Resolver(ServerInstance, source, forward ? DNS_QUERY_A : DNS_QUERY_PTR4, cached, me), typ(type), theirfd(userfd), them(u), notify(NotifyOpers) { }
virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
{
/* Check the user still exists */
if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
{
if (notify)
ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick, them->host, result.c_str(), typ.c_str());
strlcpy(them->host, result.c_str(), 63);
strlcpy(them->dhost, result.c_str(), 63);
strlcpy(them->ident, "~cgiirc", 8);
them->InvalidateCache();
}
}
virtual void OnError(ResolverError e, const std::string &errormessage)
{
if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
{
if (notify)
ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick, them->host,typ.c_str());
}
}
virtual ~CGIResolver()
{
}
};
class ModuleCgiIRC : public Module
{
cmd_webirc* mycommand;
bool NotifyOpers;
CGIHostlist Hosts;
public:
ModuleCgiIRC(InspIRCd* Me) : Module(Me)
{
OnRehash(NULL,"");
mycommand=new cmd_webirc(Me, Hosts, NotifyOpers);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCleanup] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserQuit] = List[I_OnUserConnect] = 1;
}
virtual Priority Prioritize()
{
// We want to get here before m_cloaking and m_hostchange etc
return PRIORITY_FIRST;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
NotifyOpers = Conf.ReadFlag("cgiirc", "opernotice", 0); // If we send an oper notice when a CGI:IRC has their host changed.
if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
NotifyOpers = true;
for(int i = 0; i < Conf.Enumerate("cgihost"); i++)
{
std::string hostmask = Conf.ReadValue("cgihost", "mask", i); // An allowed CGI:IRC host
std::string type = Conf.ReadValue("cgihost", "type", i); // What type of user-munging we do on this host.
std::string password = Conf.ReadValue("cgihost", "password", i);
if(hostmask.length())
{
if(type == "webirc" && !password.length()) {
ServerInstance->Log(DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str());
} else {
CGItype cgitype;
if(type == "pass")
cgitype = PASS;
else if(type == "ident")
cgitype = IDENT;
else if(type == "passfirst")
cgitype = PASSFIRST;
else if(type == "webirc") {
cgitype = WEBIRC;
}
Hosts.push_back(CGIhost(hostmask,cgitype, password.length() ? password : "" ));
}
}
else
{
ServerInstance->Log(DEFAULT, "m_cgiirc.so: Invalid <cgihost:mask> value in config: %s", hostmask.c_str());
continue;
}
}
}
virtual void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
std::string* realhost;
std::string* realip;
if(user->GetExt("cgiirc_realhost", realhost))
{
delete realhost;
user->Shrink("cgiirc_realhost");
}
if(user->GetExt("cgiirc_realip", realip))
{
delete realip;
user->Shrink("cgiirc_realip");
}
}
}
virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
{
if((extname == "cgiirc_realhost") || (extname == "cgiirc_realip"))
{
std::string* data;
if(user->GetExt(extname, data))
{
proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *data);
}
}
}
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
if(target_type == TYPE_USER)
{
userrec* dest = (userrec*)target;
std::string* bleh;
if(((extname == "cgiirc_realhost") || (extname == "cgiirc_realip")) && (!dest->GetExt(extname, bleh)))
{
dest->Extend(extname, new std::string(extdata));
}
}
}
virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
{
OnCleanup(TYPE_USER, user);
}
virtual int OnUserRegister(userrec* user)
{
for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++)
{
if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask))
{
// Deal with it...
if(iter->type == PASS)
{
CheckPass(user); // We do nothing if it fails so...
}
else if(iter->type == PASSFIRST && !CheckPass(user))
{
// If the password lookup failed, try the ident
CheckIdent(user); // If this fails too, do nothing
}
else if(iter->type == IDENT)
{
CheckIdent(user); // Nothing on failure.
}
else if(iter->type == IDENTFIRST && !CheckIdent(user))
{
// If the ident lookup fails, try the password.
CheckPass(user);
}
else if(iter->type == WEBIRC)
{
// We don't need to do anything here
}
return 0;
}
}
return 0;
}
virtual void OnUserConnect(userrec* user)
{
std::string *webirc_hostname, *webirc_ip;
if(user->GetExt("cgiirc_webirc_hostname", webirc_hostname))
{
strlcpy(user->host,webirc_hostname->c_str(),63);
strlcpy(user->dhost,webirc_hostname->c_str(),63);
delete webirc_hostname;
user->InvalidateCache();
user->Shrink("cgiirc_webirc_hostname");
}
if(user->GetExt("cgiirc_webirc_ip", webirc_ip))
{
bool valid=false;
user->RemoveCloneCounts();
#ifdef IPV6
valid = (inet_pton(AF_INET6, webirc_ip->c_str(), &((sockaddr_in6*)user->ip)->sin6_addr) > 0);
if(!valid)
valid = (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr));
#else
if (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr))
valid = true;
#endif
delete webirc_ip;
user->InvalidateCache();
user->Shrink("cgiirc_webirc_ip");
ServerInstance->AddLocalClone(user);
ServerInstance->AddGlobalClone(user);
user->CheckClass();
}
}
bool CheckPass(userrec* user)
{
if(IsValidHost(user->password))
{
user->Extend("cgiirc_realhost", new std::string(user->host));
user->Extend("cgiirc_realip", new std::string(user->GetIPString()));
strlcpy(user->host, user->password, 64);
strlcpy(user->dhost, user->password, 64);
user->InvalidateCache();
bool valid = false;
user->RemoveCloneCounts();
#ifdef IPV6
if (user->GetProtocolFamily() == AF_INET6)
valid = (inet_pton(AF_INET6, user->password, &((sockaddr_in6*)user->ip)->sin6_addr) > 0);
else
valid = (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr));
#else
if (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr))
valid = true;
#endif
ServerInstance->AddLocalClone(user);
ServerInstance->AddGlobalClone(user);
user->CheckClass();
if (valid)
{
/* We were given a IP in the password, we don't do DNS so they get this is as their host as well. */
if(NotifyOpers)
ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password);
}
else
{
/* We got as resolved hostname in the password. */
try
{
bool cached;
CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, user->password, false, user, user->GetFd(), "PASS", cached);
ServerInstance->AddResolver(r, cached);
}
catch (...)
{
if (NotifyOpers)
ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host);
}
}
*user->password = 0;
/*if(NotifyOpers)
ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password);*/
return true;
}
return false;
}
bool CheckIdent(userrec* user)
{
int ip[4];
char* ident;
char newip[16];
int len = strlen(user->ident);
if(len == 8)
ident = user->ident;
else if(len == 9 && *user->ident == '~')
ident = user->ident+1;
else
return false;
for(int i = 0; i < 4; i++)
if(!HexToInt(ip[i], ident + i*2))
return false;
snprintf(newip, 16, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
user->Extend("cgiirc_realhost", new std::string(user->host));
user->Extend("cgiirc_realip", new std::string(user->GetIPString()));
user->RemoveCloneCounts();
#ifdef IPV6
if (user->GetProtocolFamily() == AF_INET6)
inet_pton(AF_INET6, newip, &((sockaddr_in6*)user->ip)->sin6_addr);
else
#endif
inet_aton(newip, &((sockaddr_in*)user->ip)->sin_addr);
ServerInstance->AddLocalClone(user);
ServerInstance->AddGlobalClone(user);
user->CheckClass();
try
{
strlcpy(user->host, newip, 16);
strlcpy(user->dhost, newip, 16);
strlcpy(user->ident, "~cgiirc", 8);
bool cached;
CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, newip, false, user, user->GetFd(), "IDENT", cached);
ServerInstance->AddResolver(r, cached);
}
catch (...)
{
strlcpy(user->host, newip, 16);
strlcpy(user->dhost, newip, 16);
strlcpy(user->ident, "~cgiirc", 8);
user->InvalidateCache();
if(NotifyOpers)
ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host);
}
/*strlcpy(user->host, newip, 16);
strlcpy(user->dhost, newip, 16);
strlcpy(user->ident, "~cgiirc", 8);*/
return true;
}
bool IsValidHost(const std::string &host)
{
if(!host.size())
return false;
for(unsigned int i = 0; i < host.size(); i++)
{
if( ((host[i] >= '0') && (host[i] <= '9')) ||
((host[i] >= 'A') && (host[i] <= 'Z')) ||
((host[i] >= 'a') && (host[i] <= 'z')) ||
((host[i] == '-') && (i > 0) && (i+1 < host.size()) && (host[i-1] != '.') && (host[i+1] != '.')) ||
((host[i] == '.') && (i > 0) && (i+1 < host.size())) )
continue;
else
return false;
}
return true;
}
bool IsValidIP(const std::string &ip)
{
if(ip.size() < 7 || ip.size() > 15)
return false;
short sincedot = 0;
short dots = 0;
for(unsigned int i = 0; i < ip.size(); i++)
{
if((dots <= 3) && (sincedot <= 3))
{
if((ip[i] >= '0') && (ip[i] <= '9'))
{
sincedot++;
}
else if(ip[i] == '.')
{
sincedot = 0;
dots++;
}
}
else
{
return false;
}
}
if(dots != 3)
return false;
return true;
}
bool HexToInt(int &out, const char* in)
{
char ip[3];
ip[0] = in[0];
ip[1] = in[1];
ip[2] = 0;
out = strtol(ip, NULL, 16);
if(out > 255 || out < 0)
return false;
return true;
}
virtual ~ModuleCgiIRC()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleCgiIRC)
\ No newline at end of file diff --git a/src/modules/m_chancreate.cpp b/src/modules/m_chancreate.cpp index 915e7c8cb..8837db9c5 100644 --- a/src/modules/m_chancreate.cpp +++ b/src/modules/m_chancreate.cpp @@ -1,55 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Creates a snomask with notices whenever a new channel is created */ - -class ModuleChanCreate : public Module -{ - private: - public: - ModuleChanCreate(InspIRCd* Me) - : Module(Me) - { - ServerInstance->SNO->EnableSnomask('j', "CHANCREATE"); - } - - virtual ~ModuleChanCreate() - { - ServerInstance->SNO->DisableSnomask('j'); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserJoin] = 1; - } - - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - if (channel->GetUserCounter() == 1) - { - ServerInstance->SNO->WriteToSnoMask('j', "Channel %s created by %s!%s@%s", channel->name, user->nick, user->ident, user->host); - } - } -}; - -MODULE_INIT(ModuleChanCreate) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Creates a snomask with notices whenever a new channel is created */
class ModuleChanCreate : public Module
{
private:
public:
ModuleChanCreate(InspIRCd* Me)
: Module(Me)
{
ServerInstance->SNO->EnableSnomask('j', "CHANCREATE");
}
virtual ~ModuleChanCreate()
{
ServerInstance->SNO->DisableSnomask('j');
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserJoin] = 1;
}
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
if (channel->GetUserCounter() == 1)
{
ServerInstance->SNO->WriteToSnoMask('j', "Channel %s created by %s!%s@%s", channel->name, user->nick, user->ident, user->host);
}
}
};
MODULE_INIT(ModuleChanCreate)
\ No newline at end of file diff --git a/src/modules/m_chanfilter.cpp b/src/modules/m_chanfilter.cpp index 375fbce9c..44aac9dae 100644 --- a/src/modules/m_chanfilter.cpp +++ b/src/modules/m_chanfilter.cpp @@ -1,155 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#define _CRT_SECURE_NO_DEPRECATE -#define _SCL_SECURE_NO_DEPRECATE - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" -#include "u_listmode.h" - -/* $ModDesc: Provides channel-specific censor lists (like mode +G but varies from channel to channel) */ -/* $ModDep: ../../include/u_listmode.h */ - -/** Handles channel mode +g - */ -class ChanFilter : public ListModeBase -{ - public: - ChanFilter(InspIRCd* Instance) : ListModeBase(Instance, 'g', "End of channel spamfilter list", "941", "940", false, "chanfilter") { } - - virtual bool ValidateParam(userrec* user, chanrec* chan, std::string &word) - { - if ((word.length() > 35) || (word.empty())) - { - user->WriteServ("935 %s %s %s :word is too %s for censor list",user->nick, chan->name,word.c_str(), (word.empty() ? "short" : "long")); - return false; - } - - return true; - } - - virtual bool TellListTooLong(userrec* user, chanrec* chan, std::string &word) - { - user->WriteServ("939 %s %s %s :Channel spamfilter list is full",user->nick, chan->name, word.c_str()); - return true; - } - - virtual void TellAlreadyOnList(userrec* user, chanrec* chan, std::string &word) - { - user->WriteServ("937 %s %s :The word %s is already on the spamfilter list",user->nick, chan->name,word.c_str()); - } - - virtual void TellNotSet(userrec* user, chanrec* chan, std::string &word) - { - user->WriteServ("938 %s %s :No such spamfilter word is set",user->nick, chan->name); - } -}; - -class ModuleChanFilter : public Module -{ - - ChanFilter* cf; - - public: - - ModuleChanFilter(InspIRCd* Me) - : Module(Me) - { - cf = new ChanFilter(ServerInstance); - if (!ServerInstance->AddMode(cf, 'g')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - cf->DoImplements(List); - List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnSyncChannel] = 1; - } - - virtual void OnChannelDelete(chanrec* chan) - { - cf->DoChannelDelete(chan); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - cf->DoRehash(); - } - - virtual int ProcessMessages(userrec* user,chanrec* chan,std::string &text) - { - if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'g') && chan->GetStatus(user) == STATUS_OP) - return 0; - - // Create a copy of the string in irc::string - irc::string line = text.c_str(); - - modelist* list; - chan->GetExt(cf->GetInfoKey(), list); - - if (list) - { - for (modelist::iterator i = list->begin(); i != list->end(); i++) - { - if (line.find(i->mask.c_str()) != std::string::npos) - { - user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked",user->nick, chan->name, i->mask.c_str()); - return 1; - } - } - } - - return 0; - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if (target_type == TYPE_CHANNEL) - { - return ProcessMessages(user,(chanrec*)dest,text); - } - else return 0; - } - - virtual void OnCleanup(int target_type, void* item) - { - cf->DoCleanup(target_type, item); - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque) - { - cf->DoSyncChannel(chan, proto, opaque); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } - - virtual ~ModuleChanFilter() - { - ServerInstance->Modes->DelMode(cf); - DELETE(cf); - } -}; - -MODULE_INIT(ModuleChanFilter) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_DEPRECATE
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
#include "u_listmode.h"
/* $ModDesc: Provides channel-specific censor lists (like mode +G but varies from channel to channel) */
/* $ModDep: ../../include/u_listmode.h */
/** Handles channel mode +g
*/
class ChanFilter : public ListModeBase
{
public:
ChanFilter(InspIRCd* Instance) : ListModeBase(Instance, 'g', "End of channel spamfilter list", "941", "940", false, "chanfilter") { }
virtual bool ValidateParam(userrec* user, chanrec* chan, std::string &word)
{
if ((word.length() > 35) || (word.empty()))
{
user->WriteServ("935 %s %s %s :word is too %s for censor list",user->nick, chan->name,word.c_str(), (word.empty() ? "short" : "long"));
return false;
}
return true;
}
virtual bool TellListTooLong(userrec* user, chanrec* chan, std::string &word)
{
user->WriteServ("939 %s %s %s :Channel spamfilter list is full",user->nick, chan->name, word.c_str());
return true;
}
virtual void TellAlreadyOnList(userrec* user, chanrec* chan, std::string &word)
{
user->WriteServ("937 %s %s :The word %s is already on the spamfilter list",user->nick, chan->name,word.c_str());
}
virtual void TellNotSet(userrec* user, chanrec* chan, std::string &word)
{
user->WriteServ("938 %s %s :No such spamfilter word is set",user->nick, chan->name);
}
};
class ModuleChanFilter : public Module
{
ChanFilter* cf;
public:
ModuleChanFilter(InspIRCd* Me)
: Module(Me)
{
cf = new ChanFilter(ServerInstance);
if (!ServerInstance->AddMode(cf, 'g'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
cf->DoImplements(List);
List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnSyncChannel] = 1;
}
virtual void OnChannelDelete(chanrec* chan)
{
cf->DoChannelDelete(chan);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
cf->DoRehash();
}
virtual int ProcessMessages(userrec* user,chanrec* chan,std::string &text)
{
if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'g') && chan->GetStatus(user) == STATUS_OP)
return 0;
// Create a copy of the string in irc::string
irc::string line = text.c_str();
modelist* list;
chan->GetExt(cf->GetInfoKey(), list);
if (list)
{
for (modelist::iterator i = list->begin(); i != list->end(); i++)
{
if (line.find(i->mask.c_str()) != std::string::npos)
{
user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked",user->nick, chan->name, i->mask.c_str());
return 1;
}
}
}
return 0;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (target_type == TYPE_CHANNEL)
{
return ProcessMessages(user,(chanrec*)dest,text);
}
else return 0;
}
virtual void OnCleanup(int target_type, void* item)
{
cf->DoCleanup(target_type, item);
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
}
virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
{
cf->DoSyncChannel(chan, proto, opaque);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
virtual ~ModuleChanFilter()
{
ServerInstance->Modes->DelMode(cf);
DELETE(cf);
}
};
MODULE_INIT(ModuleChanFilter)
\ No newline at end of file diff --git a/src/modules/m_chanprotect.cpp b/src/modules/m_chanprotect.cpp index 87bc1ca4c..74640fe52 100644 --- a/src/modules/m_chanprotect.cpp +++ b/src/modules/m_chanprotect.cpp @@ -1,531 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides channel modes +a and +q */ -/* $ModDep: ../../include/u_listmode.h */ - -#define PROTECT_VALUE 40000 -#define FOUNDER_VALUE 50000 - -const char* fakevalue = "on"; - -/* When this is set to true, no restrictions apply to setting or - * removal of +qa. This is used while unloading so that the server - * can freely clear all of its users of the modes. - */ -bool unload_kludge = false; - -/** Handles basic operation of +qa channel modes - */ -class FounderProtectBase -{ - private: - InspIRCd* MyInstance; - std::string extend; - std::string type; - int list; - int end; - char* dummyptr; - protected: - bool& remove_own_privs; - bool& remove_other_privs; - public: - FounderProtectBase(InspIRCd* Instance, const std::string &ext, const std::string &mtype, int l, int e, bool &remove_own, bool &remove_others) : - MyInstance(Instance), extend(ext), type(mtype), list(l), end(e), remove_own_privs(remove_own), remove_other_privs(remove_others) - { - } - - ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) - { - userrec* x = MyInstance->FindNick(parameter); - if (x) - { - if (!channel->HasUser(x)) - { - return std::make_pair(false, parameter); - } - else - { - std::string item = extend+std::string(channel->name); - if (x->GetExt(item,dummyptr)) - { - return std::make_pair(true, x->nick); - } - else - { - return std::make_pair(false, parameter); - } - } - } - return std::make_pair(false, parameter); - } - - void RemoveMode(chanrec* channel, char mc) - { - unload_kludge = true; - CUList* cl = channel->GetUsers(); - std::string item = extend + std::string(channel->name); - const char* mode_junk[MAXMODES+2]; - userrec* n = new userrec(MyInstance); - n->SetFd(FD_MAGIC_NUMBER); - mode_junk[0] = channel->name; - irc::modestacker modestack(false); - std::deque<std::string> stackresult; - for (CUList::iterator i = cl->begin(); i != cl->end(); i++) - { - if (i->first->GetExt(item, dummyptr)) - { - modestack.Push(mc, i->first->nick); - } - } - - while (modestack.GetStackedLine(stackresult)) - { - for (size_t j = 0; j < stackresult.size(); j++) - { - mode_junk[j+1] = stackresult[j].c_str(); - } - MyInstance->SendMode(mode_junk, stackresult.size() + 1, n); - } - - delete n; - unload_kludge = false; - } - - void DisplayList(userrec* user, chanrec* channel) - { - CUList* cl = channel->GetUsers(); - std::string item = extend+std::string(channel->name); - for (CUList::reverse_iterator i = cl->rbegin(); i != cl->rend(); ++i) - { - if (i->first->GetExt(item, dummyptr)) - { - user->WriteServ("%d %s %s %s", list, user->nick, channel->name,i->first->nick); - } - } - user->WriteServ("%d %s %s :End of channel %s list", end, user->nick, channel->name, type.c_str()); - } - - userrec* FindAndVerify(std::string ¶meter, chanrec* channel) - { - userrec* theuser = MyInstance->FindNick(parameter); - if ((!theuser) || (!channel->HasUser(theuser))) - { - parameter.clear(); - return NULL; - } - return theuser; - } - - bool CanRemoveOthers(userrec* u1, userrec* u2, chanrec* c) - { - std::string item = extend+std::string(c->name); - return (u1->GetExt(item, dummyptr) && u2->GetExt(item, dummyptr)); - } - - ModeAction HandleChange(userrec* source, userrec* theuser, bool adding, chanrec* channel, std::string ¶meter) - { - std::string item = extend+std::string(channel->name); - - if (adding) - { - if (!theuser->GetExt(item, dummyptr)) - { - theuser->Extend(item, fakevalue); - parameter = theuser->nick; - return MODEACTION_ALLOW; - } - } - else - { - if (theuser->GetExt(item, dummyptr)) - { - theuser->Shrink(item); - parameter = theuser->nick; - return MODEACTION_ALLOW; - } - } - return MODEACTION_DENY; - } -}; - -/** Abstraction of FounderProtectBase for channel mode +q - */ -class ChanFounder : public ModeHandler, public FounderProtectBase -{ - char* dummyptr; - public: - ChanFounder(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others) - : ModeHandler(Instance, 'q', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '~' : 0), - FounderProtectBase(Instance, "cm_founder_", "founder", 386, 387, depriv_self, depriv_others) { } - - unsigned int GetPrefixRank() - { - return FOUNDER_VALUE; - } - - ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) - { - return FounderProtectBase::ModeSet(source, dest, channel, parameter); - } - - void RemoveMode(chanrec* channel) - { - FounderProtectBase::RemoveMode(channel, this->GetModeChar()); - } - - void RemoveMode(userrec* user) - { - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel); - - if (!theuser) - { - return MODEACTION_DENY; - } - - if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel)) - { - return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter); - } - // source is a server, or ulined, we'll let them +-q the user. - if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (!IS_LOCAL(source))) - { - return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter); - } - else - { - // whoops, someones being naughty! - source->WriteServ("468 %s %s :Only servers may set channel mode +q",source->nick, channel->name); - parameter.clear(); - return MODEACTION_DENY; - } - } - - void DisplayList(userrec* user, chanrec* channel) - { - FounderProtectBase::DisplayList(user,channel); - } -}; - -/** Abstraction of FounderProtectBase for channel mode +a - */ -class ChanProtect : public ModeHandler, public FounderProtectBase -{ - char* dummyptr; - public: - ChanProtect(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others) - : ModeHandler(Instance, 'a', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '&' : 0), - FounderProtectBase(Instance,"cm_protect_","protected user", 388, 389, depriv_self, depriv_others) { } - - unsigned int GetPrefixRank() - { - return PROTECT_VALUE; - } - - ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) - { - return FounderProtectBase::ModeSet(source, dest, channel, parameter); - } - - void RemoveMode(chanrec* channel) - { - FounderProtectBase::RemoveMode(channel, this->GetModeChar()); - } - - void RemoveMode(userrec* user) - { - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel); - - if (!theuser) - return MODEACTION_DENY; - - std::string founder = "cm_founder_"+std::string(channel->name); - - if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel)) - { - return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter); - } - // source has +q, is a server, or ulined, we'll let them +-a the user. - if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (source->GetExt(founder,dummyptr)) || (!IS_LOCAL(source))) - { - return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter); - } - else - { - // bzzzt, wrong answer! - source->WriteServ("482 %s %s :You are not a channel founder",source->nick, channel->name); - return MODEACTION_DENY; - } - } - - virtual void DisplayList(userrec* user, chanrec* channel) - { - FounderProtectBase::DisplayList(user, channel); - } - -}; - -class ModuleChanProtect : public Module -{ - - bool FirstInGetsFounder; - bool QAPrefixes; - bool DeprivSelf; - bool DeprivOthers; - bool booting; - ChanProtect* cp; - ChanFounder* cf; - char* dummyptr; - - public: - - ModuleChanProtect(InspIRCd* Me) - : Module(Me), FirstInGetsFounder(false), QAPrefixes(false), DeprivSelf(false), DeprivOthers(false), booting(true) - { - /* Load config stuff */ - OnRehash(NULL,""); - booting = false; - - /* Initialise module variables */ - - cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers); - cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers); - - if (!ServerInstance->AddMode(cp, 'a') || !ServerInstance->AddMode(cf, 'q')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserKick] = List[I_OnUserPart] = List[I_OnRehash] = List[I_OnUserJoin] = List[I_OnAccessCheck] = List[I_OnSyncChannel] = 1; - } - - virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent) - { - // FIX: when someone gets kicked from a channel we must remove their Extensibles! - user->Shrink("cm_founder_"+std::string(chan->name)); - user->Shrink("cm_protect_"+std::string(chan->name)); - } - - virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent) - { - // FIX: when someone parts a channel we must remove their Extensibles! - user->Shrink("cm_founder_"+std::string(channel->name)); - user->Shrink("cm_protect_"+std::string(channel->name)); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - /* Create a configreader class and read our flag, - * in old versions this was heap-allocated and the - * object was kept between rehashes...now we just - * stack-allocate it locally. - */ - ConfigReader Conf(ServerInstance); - - bool old_qa = QAPrefixes; - - FirstInGetsFounder = Conf.ReadFlag("options","noservices",0); - QAPrefixes = Conf.ReadFlag("options","qaprefixes",0); - DeprivSelf = Conf.ReadFlag("options","deprotectself",0); - DeprivOthers = Conf.ReadFlag("options","deprotectothers",0); - - /* Did the user change the QA prefixes on the fly? - * If so, remove all instances of the mode, and reinit - * the module with prefixes enabled. - */ - if ((old_qa != QAPrefixes) && (!booting)) - { - ServerInstance->Modes->DelMode(cp); - ServerInstance->Modes->DelMode(cf); - DELETE(cp); - DELETE(cf); - cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers); - cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers); - /* These wont fail, we already owned the mode characters before */ - ServerInstance->AddMode(cp, 'a'); - ServerInstance->AddMode(cf, 'q'); - ServerInstance->WriteOpers("*** WARNING: +qa prefixes were enabled or disabled via a REHASH. Clients will probably need to reconnect to pick up this change."); - } - } - - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - // if the user is the first user into the channel, mark them as the founder, but only if - // the config option for it is set - if (FirstInGetsFounder) - { - if (channel->GetUserCounter() == 1) - { - // we're using Extensible::Extend to add data into user objects. - // this way is best as it adds data thats accessible to other modules - // (so long as you document your code properly) without breaking anything - // because its encapsulated neatly in a map. - - // Change requested by katsklaw... when the first in is set to get founder, - // to make it clearer that +q has been given, send that one user the +q notice - // so that their client's syncronization and their sanity are left intact. - user->WriteServ("MODE %s +q %s",channel->name,user->nick); - user->Extend("cm_founder_"+std::string(channel->name),fakevalue); - } - } - } - - virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type) - { - // here we perform access checks, this is the important bit that actually stops kicking/deopping - // etc of protected users. There are many types of access check, we're going to handle - // a relatively small number of them relevent to our module using a switch statement. - // don't allow action if: - // (A) Theyre founder (no matter what) - // (B) Theyre protected, and you're not - // always allow the action if: - // (A) The source is ulined - - - // firstly, if a ulined nick, or a server, is setting the mode, then allow them to set the mode - // without any access checks, we're not worthy :p - if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server)) - return ACR_ALLOW; - - std::string founder = "cm_founder_"+std::string(channel->name); - std::string protect = "cm_protect_"+std::string(channel->name); - - switch (access_type) - { - // a user has been deopped. Do we let them? hmmm... - case AC_DEOP: - if (dest->GetExt(founder,dummyptr)) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're a channel founder"); - return ACR_DENY; - } - if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr))) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're protected (+a)"); - return ACR_DENY; - } - break; - - // a user is being kicked. do we chop off the end of the army boot? - case AC_KICK: - if (dest->GetExt(founder,dummyptr)) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're a channel founder"); - return ACR_DENY; - } - if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr))) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're protected (+a)"); - return ACR_DENY; - } - break; - - // a user is being dehalfopped. Yes, we do disallow -h of a +ha user - case AC_DEHALFOP: - if (dest->GetExt(founder,dummyptr)) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're a channel founder"); - return ACR_DENY; - } - if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr))) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're protected (+a)"); - return ACR_DENY; - } - break; - - // same with devoice. - case AC_DEVOICE: - if (dest->GetExt(founder,dummyptr)) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're a channel founder"); - return ACR_DENY; - } - if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr))) - { - source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're protected (+a)"); - return ACR_DENY; - } - break; - } - - // we dont know what this access check is, or dont care. just carry on, nothing to see here. - return ACR_DEFAULT; - } - - virtual ~ModuleChanProtect() - { - ServerInstance->Modes->DelMode(cp); - ServerInstance->Modes->DelMode(cf); - DELETE(cp); - DELETE(cf); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } - - virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque) - { - /* NOTE: If +qa prefix is on, this is propogated by the channel join, - * so we dont need to propogate it manually - */ - if (!QAPrefixes) - { - // this is called when the server is linking into a net and wants to sync channel data. - // we should send our mode changes for the channel here to ensure that other servers - // know whos +q/+a on the channel. - CUList* cl = chan->GetUsers(); - string_list commands; - std::string founder = "cm_founder_"+std::string(chan->name); - std::string protect = "cm_protect_"+std::string(chan->name); - irc::modestacker modestack(true); - std::deque<std::string> stackresult; - for (CUList::iterator i = cl->begin(); i != cl->end(); i++) - { - if (i->first->GetExt(founder,dummyptr)) - { - modestack.Push('q',i->first->nick); - } - if (i->first->GetExt(protect,dummyptr)) - { - modestack.Push('a',i->first->nick); - } - } - while (modestack.GetStackedLine(stackresult)) - { - irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1); - std::string line = mode_join.GetJoined(); - proto->ProtoSendMode(opaque,TYPE_CHANNEL,chan, line); - } - } - } - -}; - -MODULE_INIT(ModuleChanProtect) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides channel modes +a and +q */
/* $ModDep: ../../include/u_listmode.h */
#define PROTECT_VALUE 40000
#define FOUNDER_VALUE 50000
const char* fakevalue = "on";
/* When this is set to true, no restrictions apply to setting or
* removal of +qa. This is used while unloading so that the server
* can freely clear all of its users of the modes.
*/
bool unload_kludge = false;
/** Handles basic operation of +qa channel modes
*/
class FounderProtectBase
{
private:
InspIRCd* MyInstance;
std::string extend;
std::string type;
int list;
int end;
char* dummyptr;
protected:
bool& remove_own_privs;
bool& remove_other_privs;
public:
FounderProtectBase(InspIRCd* Instance, const std::string &ext, const std::string &mtype, int l, int e, bool &remove_own, bool &remove_others) :
MyInstance(Instance), extend(ext), type(mtype), list(l), end(e), remove_own_privs(remove_own), remove_other_privs(remove_others)
{
}
ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
{
userrec* x = MyInstance->FindNick(parameter);
if (x)
{
if (!channel->HasUser(x))
{
return std::make_pair(false, parameter);
}
else
{
std::string item = extend+std::string(channel->name);
if (x->GetExt(item,dummyptr))
{
return std::make_pair(true, x->nick);
}
else
{
return std::make_pair(false, parameter);
}
}
}
return std::make_pair(false, parameter);
}
void RemoveMode(chanrec* channel, char mc)
{
unload_kludge = true;
CUList* cl = channel->GetUsers();
std::string item = extend + std::string(channel->name);
const char* mode_junk[MAXMODES+2];
userrec* n = new userrec(MyInstance);
n->SetFd(FD_MAGIC_NUMBER);
mode_junk[0] = channel->name;
irc::modestacker modestack(false);
std::deque<std::string> stackresult;
for (CUList::iterator i = cl->begin(); i != cl->end(); i++)
{
if (i->first->GetExt(item, dummyptr))
{
modestack.Push(mc, i->first->nick);
}
}
while (modestack.GetStackedLine(stackresult))
{
for (size_t j = 0; j < stackresult.size(); j++)
{
mode_junk[j+1] = stackresult[j].c_str();
}
MyInstance->SendMode(mode_junk, stackresult.size() + 1, n);
}
delete n;
unload_kludge = false;
}
void DisplayList(userrec* user, chanrec* channel)
{
CUList* cl = channel->GetUsers();
std::string item = extend+std::string(channel->name);
for (CUList::reverse_iterator i = cl->rbegin(); i != cl->rend(); ++i)
{
if (i->first->GetExt(item, dummyptr))
{
user->WriteServ("%d %s %s %s", list, user->nick, channel->name,i->first->nick);
}
}
user->WriteServ("%d %s %s :End of channel %s list", end, user->nick, channel->name, type.c_str());
}
userrec* FindAndVerify(std::string ¶meter, chanrec* channel)
{
userrec* theuser = MyInstance->FindNick(parameter);
if ((!theuser) || (!channel->HasUser(theuser)))
{
parameter.clear();
return NULL;
}
return theuser;
}
bool CanRemoveOthers(userrec* u1, userrec* u2, chanrec* c)
{
std::string item = extend+std::string(c->name);
return (u1->GetExt(item, dummyptr) && u2->GetExt(item, dummyptr));
}
ModeAction HandleChange(userrec* source, userrec* theuser, bool adding, chanrec* channel, std::string ¶meter)
{
std::string item = extend+std::string(channel->name);
if (adding)
{
if (!theuser->GetExt(item, dummyptr))
{
theuser->Extend(item, fakevalue);
parameter = theuser->nick;
return MODEACTION_ALLOW;
}
}
else
{
if (theuser->GetExt(item, dummyptr))
{
theuser->Shrink(item);
parameter = theuser->nick;
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** Abstraction of FounderProtectBase for channel mode +q
*/
class ChanFounder : public ModeHandler, public FounderProtectBase
{
char* dummyptr;
public:
ChanFounder(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others)
: ModeHandler(Instance, 'q', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '~' : 0),
FounderProtectBase(Instance, "cm_founder_", "founder", 386, 387, depriv_self, depriv_others) { }
unsigned int GetPrefixRank()
{
return FOUNDER_VALUE;
}
ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
{
return FounderProtectBase::ModeSet(source, dest, channel, parameter);
}
void RemoveMode(chanrec* channel)
{
FounderProtectBase::RemoveMode(channel, this->GetModeChar());
}
void RemoveMode(userrec* user)
{
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);
if (!theuser)
{
return MODEACTION_DENY;
}
if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel))
{
return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
}
// source is a server, or ulined, we'll let them +-q the user.
if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (!IS_LOCAL(source)))
{
return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
}
else
{
// whoops, someones being naughty!
source->WriteServ("468 %s %s :Only servers may set channel mode +q",source->nick, channel->name);
parameter.clear();
return MODEACTION_DENY;
}
}
void DisplayList(userrec* user, chanrec* channel)
{
FounderProtectBase::DisplayList(user,channel);
}
};
/** Abstraction of FounderProtectBase for channel mode +a
*/
class ChanProtect : public ModeHandler, public FounderProtectBase
{
char* dummyptr;
public:
ChanProtect(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others)
: ModeHandler(Instance, 'a', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '&' : 0),
FounderProtectBase(Instance,"cm_protect_","protected user", 388, 389, depriv_self, depriv_others) { }
unsigned int GetPrefixRank()
{
return PROTECT_VALUE;
}
ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
{
return FounderProtectBase::ModeSet(source, dest, channel, parameter);
}
void RemoveMode(chanrec* channel)
{
FounderProtectBase::RemoveMode(channel, this->GetModeChar());
}
void RemoveMode(userrec* user)
{
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);
if (!theuser)
return MODEACTION_DENY;
std::string founder = "cm_founder_"+std::string(channel->name);
if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel))
{
return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
}
// source has +q, is a server, or ulined, we'll let them +-a the user.
if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (source->GetExt(founder,dummyptr)) || (!IS_LOCAL(source)))
{
return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
}
else
{
// bzzzt, wrong answer!
source->WriteServ("482 %s %s :You are not a channel founder",source->nick, channel->name);
return MODEACTION_DENY;
}
}
virtual void DisplayList(userrec* user, chanrec* channel)
{
FounderProtectBase::DisplayList(user, channel);
}
};
class ModuleChanProtect : public Module
{
bool FirstInGetsFounder;
bool QAPrefixes;
bool DeprivSelf;
bool DeprivOthers;
bool booting;
ChanProtect* cp;
ChanFounder* cf;
char* dummyptr;
public:
ModuleChanProtect(InspIRCd* Me)
: Module(Me), FirstInGetsFounder(false), QAPrefixes(false), DeprivSelf(false), DeprivOthers(false), booting(true)
{
/* Load config stuff */
OnRehash(NULL,"");
booting = false;
/* Initialise module variables */
cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
if (!ServerInstance->AddMode(cp, 'a') || !ServerInstance->AddMode(cf, 'q'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserKick] = List[I_OnUserPart] = List[I_OnRehash] = List[I_OnUserJoin] = List[I_OnAccessCheck] = List[I_OnSyncChannel] = 1;
}
virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
{
// FIX: when someone gets kicked from a channel we must remove their Extensibles!
user->Shrink("cm_founder_"+std::string(chan->name));
user->Shrink("cm_protect_"+std::string(chan->name));
}
virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent)
{
// FIX: when someone parts a channel we must remove their Extensibles!
user->Shrink("cm_founder_"+std::string(channel->name));
user->Shrink("cm_protect_"+std::string(channel->name));
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
/* Create a configreader class and read our flag,
* in old versions this was heap-allocated and the
* object was kept between rehashes...now we just
* stack-allocate it locally.
*/
ConfigReader Conf(ServerInstance);
bool old_qa = QAPrefixes;
FirstInGetsFounder = Conf.ReadFlag("options","noservices",0);
QAPrefixes = Conf.ReadFlag("options","qaprefixes",0);
DeprivSelf = Conf.ReadFlag("options","deprotectself",0);
DeprivOthers = Conf.ReadFlag("options","deprotectothers",0);
/* Did the user change the QA prefixes on the fly?
* If so, remove all instances of the mode, and reinit
* the module with prefixes enabled.
*/
if ((old_qa != QAPrefixes) && (!booting))
{
ServerInstance->Modes->DelMode(cp);
ServerInstance->Modes->DelMode(cf);
DELETE(cp);
DELETE(cf);
cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
/* These wont fail, we already owned the mode characters before */
ServerInstance->AddMode(cp, 'a');
ServerInstance->AddMode(cf, 'q');
ServerInstance->WriteOpers("*** WARNING: +qa prefixes were enabled or disabled via a REHASH. Clients will probably need to reconnect to pick up this change.");
}
}
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
// if the user is the first user into the channel, mark them as the founder, but only if
// the config option for it is set
if (FirstInGetsFounder)
{
if (channel->GetUserCounter() == 1)
{
// we're using Extensible::Extend to add data into user objects.
// this way is best as it adds data thats accessible to other modules
// (so long as you document your code properly) without breaking anything
// because its encapsulated neatly in a map.
// Change requested by katsklaw... when the first in is set to get founder,
// to make it clearer that +q has been given, send that one user the +q notice
// so that their client's syncronization and their sanity are left intact.
user->WriteServ("MODE %s +q %s",channel->name,user->nick);
user->Extend("cm_founder_"+std::string(channel->name),fakevalue);
}
}
}
virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)
{
// here we perform access checks, this is the important bit that actually stops kicking/deopping
// etc of protected users. There are many types of access check, we're going to handle
// a relatively small number of them relevent to our module using a switch statement.
// don't allow action if:
// (A) Theyre founder (no matter what)
// (B) Theyre protected, and you're not
// always allow the action if:
// (A) The source is ulined
// firstly, if a ulined nick, or a server, is setting the mode, then allow them to set the mode
// without any access checks, we're not worthy :p
if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server))
return ACR_ALLOW;
std::string founder = "cm_founder_"+std::string(channel->name);
std::string protect = "cm_protect_"+std::string(channel->name);
switch (access_type)
{
// a user has been deopped. Do we let them? hmmm...
case AC_DEOP:
if (dest->GetExt(founder,dummyptr))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're a channel founder");
return ACR_DENY;
}
if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're protected (+a)");
return ACR_DENY;
}
break;
// a user is being kicked. do we chop off the end of the army boot?
case AC_KICK:
if (dest->GetExt(founder,dummyptr))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're a channel founder");
return ACR_DENY;
}
if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're protected (+a)");
return ACR_DENY;
}
break;
// a user is being dehalfopped. Yes, we do disallow -h of a +ha user
case AC_DEHALFOP:
if (dest->GetExt(founder,dummyptr))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're a channel founder");
return ACR_DENY;
}
if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're protected (+a)");
return ACR_DENY;
}
break;
// same with devoice.
case AC_DEVOICE:
if (dest->GetExt(founder,dummyptr))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're a channel founder");
return ACR_DENY;
}
if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
{
source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're protected (+a)");
return ACR_DENY;
}
break;
}
// we dont know what this access check is, or dont care. just carry on, nothing to see here.
return ACR_DEFAULT;
}
virtual ~ModuleChanProtect()
{
ServerInstance->Modes->DelMode(cp);
ServerInstance->Modes->DelMode(cf);
DELETE(cp);
DELETE(cf);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
{
/* NOTE: If +qa prefix is on, this is propogated by the channel join,
* so we dont need to propogate it manually
*/
if (!QAPrefixes)
{
// this is called when the server is linking into a net and wants to sync channel data.
// we should send our mode changes for the channel here to ensure that other servers
// know whos +q/+a on the channel.
CUList* cl = chan->GetUsers();
string_list commands;
std::string founder = "cm_founder_"+std::string(chan->name);
std::string protect = "cm_protect_"+std::string(chan->name);
irc::modestacker modestack(true);
std::deque<std::string> stackresult;
for (CUList::iterator i = cl->begin(); i != cl->end(); i++)
{
if (i->first->GetExt(founder,dummyptr))
{
modestack.Push('q',i->first->nick);
}
if (i->first->GetExt(protect,dummyptr))
{
modestack.Push('a',i->first->nick);
}
}
while (modestack.GetStackedLine(stackresult))
{
irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
std::string line = mode_join.GetJoined();
proto->ProtoSendMode(opaque,TYPE_CHANNEL,chan, line);
}
}
}
};
MODULE_INIT(ModuleChanProtect)
\ No newline at end of file diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index 643af8e15..c99e985cc 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -1,188 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "wildcard.h" - -/* $ModDesc: Provides the /check command to retrieve information on a user, channel, or IP address */ - -/** Handle /CHECK - */ -class cmd_check : public command_t -{ - public: - cmd_check (InspIRCd* Instance) : command_t(Instance,"CHECK", 'o', 1) - { - this->source = "m_check.so"; - syntax = "<nickname>|<ip>|<hostmask>|<channel>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec *targuser; - chanrec *targchan; - std::string checkstr; - std::string chliststr; - - char timebuf[60]; - struct tm *mytime; - - - checkstr = "304 " + std::string(user->nick) + " :CHECK"; - - targuser = ServerInstance->FindNick(parameters[0]); - targchan = ServerInstance->FindChan(parameters[0]); - - /* - * Syntax of a /check reply: - * :server.name 304 target :CHECK START <target> - * :server.name 304 target :CHECK <field> <value> - * :server.name 304 target :CHECK END - */ - - user->WriteServ(checkstr + " START " + parameters[0]); - - if (targuser) - { - /* /check on a user */ - user->WriteServ(checkstr + " nuh " + targuser->GetFullHost()); - user->WriteServ(checkstr + " realnuh " + targuser->GetFullRealHost()); - user->WriteServ(checkstr + " realname " + targuser->fullname); - user->WriteServ(checkstr + " modes +" + targuser->FormatModes()); - user->WriteServ(checkstr + " snomasks +" + targuser->FormatNoticeMasks()); - user->WriteServ(checkstr + " server " + targuser->server); - - if (IS_AWAY(targuser)) - { - /* user is away */ - user->WriteServ(checkstr + " awaymsg " + targuser->awaymsg); - } - - if (IS_OPER(targuser)) - { - /* user is an oper of type ____ */ - user->WriteServ(checkstr + " opertype " + irc::Spacify(targuser->oper)); - } - - if (IS_LOCAL(targuser)) - { - /* port information is only held for a local user! */ - user->WriteServ(checkstr + " onport " + ConvToStr(targuser->GetPort())); - } - - chliststr = targuser->ChannelList(targuser); - std::stringstream dump(chliststr); - - ServerInstance->DumpText(user,checkstr + " onchans ", dump); - } - else if (targchan) - { - /* /check on a channel */ - time_t creation_time = targchan->created; - time_t topic_time = targchan->topicset; - - mytime = gmtime(&creation_time); - strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime); - user->WriteServ(checkstr + " created " + timebuf); - - if (targchan->topic[0] != 0) - { - /* there is a topic, assume topic related information exists */ - user->WriteServ(checkstr + " topic " + targchan->topic); - user->WriteServ(checkstr + " topic_setby " + targchan->setby); - mytime = gmtime(&topic_time); - strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime); - user->WriteServ(checkstr + " topic_setat " + timebuf); - } - - user->WriteServ(checkstr + " modes " + targchan->ChanModes(true)); - user->WriteServ(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter())); - - /* now the ugly bit, spool current members of a channel. :| */ - - CUList *ulist= targchan->GetUsers(); - - /* note that unlike /names, we do NOT check +i vs in the channel */ - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - char tmpbuf[MAXBUF]; - /* - * Unlike Asuka, I define a clone as coming from the same host. --w00t - */ - snprintf(tmpbuf, MAXBUF, "%lu %s%s (%s@%s) %s ", i->first->GlobalCloneCount(), targchan->GetAllPrefixChars(i->first), i->first->nick, i->first->ident, i->first->dhost, i->first->fullname); - user->WriteServ(checkstr + " member " + tmpbuf); - } - } - else - { - /* /check on an IP address, or something that doesn't exist */ - long x = 0; - - /* hostname or other */ - for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++) - { - if (match(a->second->host, parameters[0]) || match(a->second->dhost, parameters[0])) - { - /* host or vhost matches mask */ - user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost()); - } - /* IP address */ - else if (match(a->second->GetIPString(), parameters[0], true)) - { - /* same IP. */ - user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost()); - } - } - - user->WriteServ(checkstr + " matches " + ConvToStr(x)); - } - - user->WriteServ(checkstr + " END " + std::string(parameters[0])); - - return CMD_LOCALONLY; - } -}; - - -class ModuleCheck : public Module -{ - private: - cmd_check *mycommand; - public: - ModuleCheck(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_check(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleCheck() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - /* we don't hook anything, nothing required */ - } - -}; - -MODULE_INIT(ModuleCheck) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "wildcard.h"
/* $ModDesc: Provides the /check command to retrieve information on a user, channel, or IP address */
/** Handle /CHECK
*/
class cmd_check : public command_t
{
public:
cmd_check (InspIRCd* Instance) : command_t(Instance,"CHECK", 'o', 1)
{
this->source = "m_check.so";
syntax = "<nickname>|<ip>|<hostmask>|<channel>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec *targuser;
chanrec *targchan;
std::string checkstr;
std::string chliststr;
char timebuf[60];
struct tm *mytime;
checkstr = "304 " + std::string(user->nick) + " :CHECK";
targuser = ServerInstance->FindNick(parameters[0]);
targchan = ServerInstance->FindChan(parameters[0]);
/*
* Syntax of a /check reply:
* :server.name 304 target :CHECK START <target>
* :server.name 304 target :CHECK <field> <value>
* :server.name 304 target :CHECK END
*/
user->WriteServ(checkstr + " START " + parameters[0]);
if (targuser)
{
/* /check on a user */
user->WriteServ(checkstr + " nuh " + targuser->GetFullHost());
user->WriteServ(checkstr + " realnuh " + targuser->GetFullRealHost());
user->WriteServ(checkstr + " realname " + targuser->fullname);
user->WriteServ(checkstr + " modes +" + targuser->FormatModes());
user->WriteServ(checkstr + " snomasks +" + targuser->FormatNoticeMasks());
user->WriteServ(checkstr + " server " + targuser->server);
if (IS_AWAY(targuser))
{
/* user is away */
user->WriteServ(checkstr + " awaymsg " + targuser->awaymsg);
}
if (IS_OPER(targuser))
{
/* user is an oper of type ____ */
user->WriteServ(checkstr + " opertype " + irc::Spacify(targuser->oper));
}
if (IS_LOCAL(targuser))
{
/* port information is only held for a local user! */
user->WriteServ(checkstr + " onport " + ConvToStr(targuser->GetPort()));
}
chliststr = targuser->ChannelList(targuser);
std::stringstream dump(chliststr);
ServerInstance->DumpText(user,checkstr + " onchans ", dump);
}
else if (targchan)
{
/* /check on a channel */
time_t creation_time = targchan->created;
time_t topic_time = targchan->topicset;
mytime = gmtime(&creation_time);
strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime);
user->WriteServ(checkstr + " created " + timebuf);
if (targchan->topic[0] != 0)
{
/* there is a topic, assume topic related information exists */
user->WriteServ(checkstr + " topic " + targchan->topic);
user->WriteServ(checkstr + " topic_setby " + targchan->setby);
mytime = gmtime(&topic_time);
strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime);
user->WriteServ(checkstr + " topic_setat " + timebuf);
}
user->WriteServ(checkstr + " modes " + targchan->ChanModes(true));
user->WriteServ(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter()));
/* now the ugly bit, spool current members of a channel. :| */
CUList *ulist= targchan->GetUsers();
/* note that unlike /names, we do NOT check +i vs in the channel */
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
char tmpbuf[MAXBUF];
/*
* Unlike Asuka, I define a clone as coming from the same host. --w00t
*/
snprintf(tmpbuf, MAXBUF, "%lu %s%s (%s@%s) %s ", i->first->GlobalCloneCount(), targchan->GetAllPrefixChars(i->first), i->first->nick, i->first->ident, i->first->dhost, i->first->fullname);
user->WriteServ(checkstr + " member " + tmpbuf);
}
}
else
{
/* /check on an IP address, or something that doesn't exist */
long x = 0;
/* hostname or other */
for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++)
{
if (match(a->second->host, parameters[0]) || match(a->second->dhost, parameters[0]))
{
/* host or vhost matches mask */
user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost());
}
/* IP address */
else if (match(a->second->GetIPString(), parameters[0], true))
{
/* same IP. */
user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost());
}
}
user->WriteServ(checkstr + " matches " + ConvToStr(x));
}
user->WriteServ(checkstr + " END " + std::string(parameters[0]));
return CMD_LOCALONLY;
}
};
class ModuleCheck : public Module
{
private:
cmd_check *mycommand;
public:
ModuleCheck(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_check(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleCheck()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
/* we don't hook anything, nothing required */
}
};
MODULE_INIT(ModuleCheck)
\ No newline at end of file diff --git a/src/modules/m_chghost.cpp b/src/modules/m_chghost.cpp index 0ec88d7e1..9fb751b8e 100644 --- a/src/modules/m_chghost.cpp +++ b/src/modules/m_chghost.cpp @@ -1,120 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for the CHGHOST command */ - -/** Handle /CHGHOST - */ -class cmd_chghost : public command_t -{ - private: - char* hostmap; - public: - cmd_chghost (InspIRCd* Instance, char* hmap) : command_t(Instance,"CHGHOST",'o',2), hostmap(hmap) - { - this->source = "m_chghost.so"; - syntax = "<nick> <newhost>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - const char * x = parameters[1]; - - for (; *x; x++) - { - if (!hostmap[(unsigned char)*x]) - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** CHGHOST: Invalid characters in hostname"); - return CMD_FAILURE; - } - } - if (!*parameters[0]) - { - user->WriteServ("NOTICE %s :*** CHGHOST: Host must be specified", user->nick); - return CMD_FAILURE; - } - - if ((parameters[1] - x) > 63) - { - user->WriteServ("NOTICE %s :*** CHGHOST: Host too long", user->nick); - return CMD_FAILURE; - } - userrec* dest = ServerInstance->FindNick(parameters[0]); - - if (!dest) - { - user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]); - return CMD_FAILURE; - } - - if ((dest->ChangeDisplayedHost(parameters[1])) && (!ServerInstance->ULine(user->server))) - { - // fix by brain - ulines set hosts silently - ServerInstance->WriteOpers(std::string(user->nick)+" used CHGHOST to make the displayed host of "+dest->nick+" become "+dest->dhost); - } - - /* route it! */ - return CMD_SUCCESS; - - } -}; - - -class ModuleChgHost : public Module -{ - cmd_chghost* mycommand; - char hostmap[256]; - public: - ModuleChgHost(InspIRCd* Me) - : Module(Me) - { - OnRehash(NULL,""); - mycommand = new cmd_chghost(ServerInstance, hostmap); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - List[I_OnRehash] = 1; - } - - void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - std::string hmap = Conf.ReadValue("hostname", "charmap", 0); - - if (hmap.empty()) - hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789"; - - memset(&hostmap, 0, 255); - for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++) - hostmap[(unsigned char)*n] = 1; - } - - ~ModuleChgHost() - { - } - - Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - -}; - -MODULE_INIT(ModuleChgHost) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for the CHGHOST command */
/** Handle /CHGHOST
*/
class cmd_chghost : public command_t
{
private:
char* hostmap;
public:
cmd_chghost (InspIRCd* Instance, char* hmap) : command_t(Instance,"CHGHOST",'o',2), hostmap(hmap)
{
this->source = "m_chghost.so";
syntax = "<nick> <newhost>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
const char * x = parameters[1];
for (; *x; x++)
{
if (!hostmap[(unsigned char)*x])
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** CHGHOST: Invalid characters in hostname");
return CMD_FAILURE;
}
}
if (!*parameters[0])
{
user->WriteServ("NOTICE %s :*** CHGHOST: Host must be specified", user->nick);
return CMD_FAILURE;
}
if ((parameters[1] - x) > 63)
{
user->WriteServ("NOTICE %s :*** CHGHOST: Host too long", user->nick);
return CMD_FAILURE;
}
userrec* dest = ServerInstance->FindNick(parameters[0]);
if (!dest)
{
user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
return CMD_FAILURE;
}
if ((dest->ChangeDisplayedHost(parameters[1])) && (!ServerInstance->ULine(user->server)))
{
// fix by brain - ulines set hosts silently
ServerInstance->WriteOpers(std::string(user->nick)+" used CHGHOST to make the displayed host of "+dest->nick+" become "+dest->dhost);
}
/* route it! */
return CMD_SUCCESS;
}
};
class ModuleChgHost : public Module
{
cmd_chghost* mycommand;
char hostmap[256];
public:
ModuleChgHost(InspIRCd* Me)
: Module(Me)
{
OnRehash(NULL,"");
mycommand = new cmd_chghost(ServerInstance, hostmap);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
List[I_OnRehash] = 1;
}
void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
std::string hmap = Conf.ReadValue("hostname", "charmap", 0);
if (hmap.empty())
hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789";
memset(&hostmap, 0, 255);
for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
hostmap[(unsigned char)*n] = 1;
}
~ModuleChgHost()
{
}
Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleChgHost)
\ No newline at end of file diff --git a/src/modules/m_chgident.cpp b/src/modules/m_chgident.cpp index 168adcc93..fb909b7ff 100644 --- a/src/modules/m_chgident.cpp +++ b/src/modules/m_chgident.cpp @@ -1,92 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "modules.h" - -/* $ModDesc: Provides support for the CHGIDENT command */ - -/** Handle /CHGIDENT - */ -class cmd_chgident : public command_t -{ - public: - cmd_chgident (InspIRCd* Instance) : command_t(Instance,"CHGIDENT", 'o', 2) - { - this->source = "m_chgident.so"; - syntax = "<nick> <newident>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - userrec* dest = ServerInstance->FindNick(parameters[0]); - - if (!dest) - { - user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]); - return CMD_FAILURE; - } - - if (!*parameters[1]) - { - user->WriteServ("NOTICE %s :*** CHGIDENT: Ident must be specified", user->nick); - return CMD_FAILURE; - } - - if (strlen(parameters[1]) > IDENTMAX) - { - user->WriteServ("NOTICE %s :*** CHGIDENT: Ident is too long", user->nick); - return CMD_FAILURE; - } - - if (!ServerInstance->IsIdent(parameters[1])) - { - user->WriteServ("NOTICE %s :*** CHGIDENT: Invalid characters in ident", user->nick); - return CMD_FAILURE; - } - - dest->ChangeIdent(parameters[1]); - ServerInstance->WriteOpers("%s used CHGIDENT to change %s's ident to '%s'", user->nick, dest->nick, dest->ident); - - /* route it! */ - return CMD_SUCCESS; - } -}; - - -class ModuleChgIdent : public Module -{ - cmd_chgident* mycommand; - - -public: - ModuleChgIdent(InspIRCd* Me) : Module(Me) - { - mycommand = new cmd_chgident(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleChgIdent() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleChgIdent) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "modules.h"
/* $ModDesc: Provides support for the CHGIDENT command */
/** Handle /CHGIDENT
*/
class cmd_chgident : public command_t
{
public:
cmd_chgident (InspIRCd* Instance) : command_t(Instance,"CHGIDENT", 'o', 2)
{
this->source = "m_chgident.so";
syntax = "<nick> <newident>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
userrec* dest = ServerInstance->FindNick(parameters[0]);
if (!dest)
{
user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
return CMD_FAILURE;
}
if (!*parameters[1])
{
user->WriteServ("NOTICE %s :*** CHGIDENT: Ident must be specified", user->nick);
return CMD_FAILURE;
}
if (strlen(parameters[1]) > IDENTMAX)
{
user->WriteServ("NOTICE %s :*** CHGIDENT: Ident is too long", user->nick);
return CMD_FAILURE;
}
if (!ServerInstance->IsIdent(parameters[1]))
{
user->WriteServ("NOTICE %s :*** CHGIDENT: Invalid characters in ident", user->nick);
return CMD_FAILURE;
}
dest->ChangeIdent(parameters[1]);
ServerInstance->WriteOpers("%s used CHGIDENT to change %s's ident to '%s'", user->nick, dest->nick, dest->ident);
/* route it! */
return CMD_SUCCESS;
}
};
class ModuleChgIdent : public Module
{
cmd_chgident* mycommand;
public:
ModuleChgIdent(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_chgident(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleChgIdent()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleChgIdent)
\ No newline at end of file diff --git a/src/modules/m_chgname.cpp b/src/modules/m_chgname.cpp index a4a31714b..0bf9004dd 100644 --- a/src/modules/m_chgname.cpp +++ b/src/modules/m_chgname.cpp @@ -1,89 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "modules.h" - -/* $ModDesc: Provides support for the CHGNAME command */ - -/** Handle /CHGNAME - */ -class cmd_chgname : public command_t -{ - public: - cmd_chgname (InspIRCd* Instance) : command_t(Instance,"CHGNAME", 'o', 2) - { - this->source = "m_chgname.so"; - syntax = "<nick> <newname>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - userrec* dest = ServerInstance->FindNick(parameters[0]); - - if (!dest) - { - user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]); - return CMD_FAILURE; - } - - if (!*parameters[1]) - { - user->WriteServ("NOTICE %s :*** GECOS must be specified", user->nick); - return CMD_FAILURE; - } - - if (strlen(parameters[1]) > MAXGECOS) - { - user->WriteServ("NOTICE %s :*** GECOS too long", user->nick); - return CMD_FAILURE; - } - - if (IS_LOCAL(dest)) - { - dest->ChangeName(parameters[1]); - ServerInstance->WriteOpers("%s used CHGNAME to change %s's real name to '%s'", user->nick, dest->nick, dest->fullname); - return CMD_LOCALONLY; /* name change routed by FNAME in spanningtree now */ - } - - /* route it! */ - return CMD_SUCCESS; - } -}; - - -class ModuleChgName : public Module -{ - cmd_chgname* mycommand; - - -public: - ModuleChgName(InspIRCd* Me) : Module(Me) - { - mycommand = new cmd_chgname(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleChgName() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleChgName) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "modules.h"
/* $ModDesc: Provides support for the CHGNAME command */
/** Handle /CHGNAME
*/
class cmd_chgname : public command_t
{
public:
cmd_chgname (InspIRCd* Instance) : command_t(Instance,"CHGNAME", 'o', 2)
{
this->source = "m_chgname.so";
syntax = "<nick> <newname>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
userrec* dest = ServerInstance->FindNick(parameters[0]);
if (!dest)
{
user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
return CMD_FAILURE;
}
if (!*parameters[1])
{
user->WriteServ("NOTICE %s :*** GECOS must be specified", user->nick);
return CMD_FAILURE;
}
if (strlen(parameters[1]) > MAXGECOS)
{
user->WriteServ("NOTICE %s :*** GECOS too long", user->nick);
return CMD_FAILURE;
}
if (IS_LOCAL(dest))
{
dest->ChangeName(parameters[1]);
ServerInstance->WriteOpers("%s used CHGNAME to change %s's real name to '%s'", user->nick, dest->nick, dest->fullname);
return CMD_LOCALONLY; /* name change routed by FNAME in spanningtree now */
}
/* route it! */
return CMD_SUCCESS;
}
};
class ModuleChgName : public Module
{
cmd_chgname* mycommand;
public:
ModuleChgName(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_chgname(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleChgName()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleChgName)
\ No newline at end of file diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp index dfa5ee4e8..d7992301c 100644 --- a/src/modules/m_cloaking.cpp +++ b/src/modules/m_cloaking.cpp @@ -1,315 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_hash.h" - -/* $ModDesc: Provides masking of user hostnames */ -/* $ModDep: m_hash.h */ - -/* Used to vary the output a little more depending on the cloak keys */ -static const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"}; - -/** Handles user mode +x - */ -class CloakUser : public ModeHandler -{ - - std::string prefix; - unsigned int key1; - unsigned int key2; - unsigned int key3; - unsigned int key4; - Module* Sender; - Module* HashProvider; - - /** This function takes a domain name string and returns just the last two domain parts, - * or the last domain part if only two are available. Failing that it just returns what it was given. - * - * For example, if it is passed "svn.inspircd.org" it will return ".inspircd.org". - * If it is passed "brainbox.winbot.co.uk" it will return ".co.uk", - * and if it is passed "localhost.localdomain" it will return ".localdomain". - * - * This is used to ensure a significant part of the host is always cloaked (see Bug #216) - */ - std::string LastTwoDomainParts(const std::string &host) - { - int dots = 0; - std::string::size_type splitdot = host.length(); - - for (std::string::size_type x = host.length() - 1; x; --x) - { - if (host[x] == '.') - { - splitdot = x; - dots++; - } - if (dots >= 3) - break; - } - - if (splitdot == host.length()) - return host; - else - return host.substr(splitdot); - } - - public: - CloakUser(InspIRCd* Instance, Module* Source, Module* Hash) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), HashProvider(Hash) - { - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (source != dest) - return MODEACTION_DENY; - - /* For remote clients, we dont take any action, we just allow it. - * The local server where they are will set their cloak instead. - */ - if (!IS_LOCAL(dest)) - return MODEACTION_ALLOW; - - if (adding) - { - if(!dest->IsModeSet('x')) - { - /* The mode is being turned on - so attempt to - * allocate the user a cloaked host using a non-reversible - * algorithm (its simple, but its non-reversible so the - * simplicity doesnt really matter). This algorithm - * will not work if the user has only one level of domain - * naming in their hostname (e.g. if they are on a lan or - * are connecting via localhost) -- this doesnt matter much. - */ - - char* n1 = strchr(dest->host,'.'); - char* n2 = strchr(dest->host,':'); - - if (n1 || n2) - { - /* InspIRCd users have two hostnames; A displayed - * hostname which can be modified by modules (e.g. - * to create vhosts, implement chghost, etc) and a - * 'real' hostname which you shouldnt write to. - */ - - unsigned int iv[] = { key1, key2, key3, key4 }; - std::string a = LastTwoDomainParts(dest->host); - std::string b; - - /** Reset the Hash module, and send it our IV and hex table */ - HashResetRequest(Sender, HashProvider).Send(); - HashKeyRequest(Sender, HashProvider, iv).Send(); - HashHexRequest(Sender, HashProvider, xtab[(*dest->host) % 4]); - - /* Generate a cloak using specialized Hash */ - std::string hostcloak = prefix + "-" + std::string(HashSumRequest(Sender, HashProvider, dest->host).Send()).substr(0,8) + a; - - /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes - * according to the DNS RFC) then tough titty, they get cloaked as an IP. - * Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie - * vhost. - */ -#ifdef IPV6 - in6_addr testaddr; - in_addr testaddr2; - if ((dest->GetProtocolFamily() == AF_INET6) && (inet_pton(AF_INET6,dest->host,&testaddr) < 1) && (hostcloak.length() <= 64)) - /* Invalid ipv6 address, and ipv6 user (resolved host) */ - b = hostcloak; - else if ((dest->GetProtocolFamily() == AF_INET) && (inet_aton(dest->host,&testaddr2) < 1) && (hostcloak.length() <= 64)) - /* Invalid ipv4 address, and ipv4 user (resolved host) */ - b = hostcloak; - else - /* Valid ipv6 or ipv4 address (not resolved) ipv4 or ipv6 user */ - b = ((!strchr(dest->host,':')) ? Cloak4(dest->host) : Cloak6(dest->host)); -#else - in_addr testaddr; - if ((inet_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64)) - /* Invalid ipv4 address, and ipv4 user (resolved host) */ - b = hostcloak; - else - /* Valid ipv4 address (not resolved) ipv4 user */ - b = Cloak4(dest->host); -#endif - - dest->ChangeDisplayedHost(b.c_str()); - } - - dest->SetMode('x',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('x')) - { - /* User is removing the mode, so just restore their real host - * and make it match the displayed one. - */ - dest->ChangeDisplayedHost(dest->host); - dest->SetMode('x',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } - - std::string Cloak4(const char* ip) - { - unsigned int iv[] = { key1, key2, key3, key4 }; - irc::sepstream seps(ip, '.'); - std::string ra[4];; - std::string octet[4]; - int i[4]; - - for (int j = 0; j < 4; j++) - { - octet[j] = seps.GetToken(); - i[j] = atoi(octet[j].c_str()); - } - - octet[3] = octet[0] + "." + octet[1] + "." + octet[2] + "." + octet[3]; - octet[2] = octet[0] + "." + octet[1] + "." + octet[2]; - octet[1] = octet[0] + "." + octet[1]; - - /* Reset the Hash module and send it our IV */ - HashResetRequest(Sender, HashProvider).Send(); - HashKeyRequest(Sender, HashProvider, iv).Send(); - - /* Send the Hash module a different hex table for each octet group's Hash sum */ - for (int k = 0; k < 4; k++) - { - HashHexRequest(Sender, HashProvider, xtab[(iv[k]+i[k]) % 4]).Send(); - ra[k] = std::string(HashSumRequest(Sender, HashProvider, octet[k]).Send()).substr(0,6); - } - /* Stick them all together */ - return std::string().append(ra[0]).append(".").append(ra[1]).append(".").append(ra[2]).append(".").append(ra[3]); - } - - std::string Cloak6(const char* ip) - { - /* Theyre using 4in6 (YUCK). Translate as ipv4 cloak */ - if (!strncmp(ip, "0::ffff:", 8)) - return Cloak4(ip + 8); - - /* If we get here, yes it really is an ipv6 ip */ - unsigned int iv[] = { key1, key2, key3, key4 }; - std::vector<std::string> hashies; - std::string item; - int rounds = 0; - - /* Reset the Hash module and send it our IV */ - HashResetRequest(Sender, HashProvider).Send(); - HashKeyRequest(Sender, HashProvider, iv).Send(); - - for (const char* input = ip; *input; input++) - { - item += *input; - if (item.length() > 7) - { - /* Send the Hash module a different hex table for each octet group's Hash sum */ - HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send(); - hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8)); - item.clear(); - } - rounds++; - } - if (!item.empty()) - { - /* Send the Hash module a different hex table for each octet group's Hash sum */ - HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send(); - hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8)); - item.clear(); - } - /* Stick them all together */ - return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined(); - } - - void DoRehash() - { - ConfigReader Conf(ServerInstance); - key1 = key2 = key3 = key4 = 0; - key1 = Conf.ReadInteger("cloak","key1",0,true); - key2 = Conf.ReadInteger("cloak","key2",0,true); - key3 = Conf.ReadInteger("cloak","key3",0,true); - key4 = Conf.ReadInteger("cloak","key4",0,true); - prefix = Conf.ReadValue("cloak","prefix",0); - - if (prefix.empty()) - prefix = ServerInstance->Config->Network; - - if (!key1 && !key2 && !key3 && !key4) - throw ModuleException("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!"); - } -}; - - -class ModuleCloaking : public Module -{ - private: - - CloakUser* cu; - Module* HashModule; - - public: - ModuleCloaking(InspIRCd* Me) - : Module(Me) - { - ServerInstance->UseInterface("HashRequest"); - - /* Attempt to locate the md5 service provider, bail if we can't find it */ - HashModule = ServerInstance->FindModule("m_md5.so"); - if (!HashModule) - throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so."); - - /* Create new mode handler object */ - cu = new CloakUser(ServerInstance, this, HashModule); - - /* Register it with the core */ - if (!ServerInstance->AddMode(cu, 'x')) - throw ModuleException("Could not add new modes!"); - - OnRehash(NULL,""); - } - - virtual ~ModuleCloaking() - { - ServerInstance->Modes->DelMode(cu); - DELETE(cu); - ServerInstance->DoneWithInterface("HashRequest"); - } - - virtual Version GetVersion() - { - // returns the version number of the module to be - // listed in /MODULES - return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - cu->DoRehash(); - } - - void Implements(char* List) - { - List[I_OnRehash] = 1; - } -}; - -MODULE_INIT(ModuleCloaking) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_hash.h"
/* $ModDesc: Provides masking of user hostnames */
/* $ModDep: m_hash.h */
/* Used to vary the output a little more depending on the cloak keys */
static const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"};
/** Handles user mode +x
*/
class CloakUser : public ModeHandler
{
std::string prefix;
unsigned int key1;
unsigned int key2;
unsigned int key3;
unsigned int key4;
Module* Sender;
Module* HashProvider;
/** This function takes a domain name string and returns just the last two domain parts,
* or the last domain part if only two are available. Failing that it just returns what it was given.
*
* For example, if it is passed "svn.inspircd.org" it will return ".inspircd.org".
* If it is passed "brainbox.winbot.co.uk" it will return ".co.uk",
* and if it is passed "localhost.localdomain" it will return ".localdomain".
*
* This is used to ensure a significant part of the host is always cloaked (see Bug #216)
*/
std::string LastTwoDomainParts(const std::string &host)
{
int dots = 0;
std::string::size_type splitdot = host.length();
for (std::string::size_type x = host.length() - 1; x; --x)
{
if (host[x] == '.')
{
splitdot = x;
dots++;
}
if (dots >= 3)
break;
}
if (splitdot == host.length())
return host;
else
return host.substr(splitdot);
}
public:
CloakUser(InspIRCd* Instance, Module* Source, Module* Hash) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), HashProvider(Hash)
{
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (source != dest)
return MODEACTION_DENY;
/* For remote clients, we dont take any action, we just allow it.
* The local server where they are will set their cloak instead.
*/
if (!IS_LOCAL(dest))
return MODEACTION_ALLOW;
if (adding)
{
if(!dest->IsModeSet('x'))
{
/* The mode is being turned on - so attempt to
* allocate the user a cloaked host using a non-reversible
* algorithm (its simple, but its non-reversible so the
* simplicity doesnt really matter). This algorithm
* will not work if the user has only one level of domain
* naming in their hostname (e.g. if they are on a lan or
* are connecting via localhost) -- this doesnt matter much.
*/
char* n1 = strchr(dest->host,'.');
char* n2 = strchr(dest->host,':');
if (n1 || n2)
{
/* InspIRCd users have two hostnames; A displayed
* hostname which can be modified by modules (e.g.
* to create vhosts, implement chghost, etc) and a
* 'real' hostname which you shouldnt write to.
*/
unsigned int iv[] = { key1, key2, key3, key4 };
std::string a = LastTwoDomainParts(dest->host);
std::string b;
/** Reset the Hash module, and send it our IV and hex table */
HashResetRequest(Sender, HashProvider).Send();
HashKeyRequest(Sender, HashProvider, iv).Send();
HashHexRequest(Sender, HashProvider, xtab[(*dest->host) % 4]);
/* Generate a cloak using specialized Hash */
std::string hostcloak = prefix + "-" + std::string(HashSumRequest(Sender, HashProvider, dest->host).Send()).substr(0,8) + a;
/* Fix by brain - if the cloaked host is > the max length of a host (64 bytes
* according to the DNS RFC) then tough titty, they get cloaked as an IP.
* Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie
* vhost.
*/
#ifdef IPV6
in6_addr testaddr;
in_addr testaddr2;
if ((dest->GetProtocolFamily() == AF_INET6) && (inet_pton(AF_INET6,dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
/* Invalid ipv6 address, and ipv6 user (resolved host) */
b = hostcloak;
else if ((dest->GetProtocolFamily() == AF_INET) && (inet_aton(dest->host,&testaddr2) < 1) && (hostcloak.length() <= 64))
/* Invalid ipv4 address, and ipv4 user (resolved host) */
b = hostcloak;
else
/* Valid ipv6 or ipv4 address (not resolved) ipv4 or ipv6 user */
b = ((!strchr(dest->host,':')) ? Cloak4(dest->host) : Cloak6(dest->host));
#else
in_addr testaddr;
if ((inet_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
/* Invalid ipv4 address, and ipv4 user (resolved host) */
b = hostcloak;
else
/* Valid ipv4 address (not resolved) ipv4 user */
b = Cloak4(dest->host);
#endif
dest->ChangeDisplayedHost(b.c_str());
}
dest->SetMode('x',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('x'))
{
/* User is removing the mode, so just restore their real host
* and make it match the displayed one.
*/
dest->ChangeDisplayedHost(dest->host);
dest->SetMode('x',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
std::string Cloak4(const char* ip)
{
unsigned int iv[] = { key1, key2, key3, key4 };
irc::sepstream seps(ip, '.');
std::string ra[4];;
std::string octet[4];
int i[4];
for (int j = 0; j < 4; j++)
{
octet[j] = seps.GetToken();
i[j] = atoi(octet[j].c_str());
}
octet[3] = octet[0] + "." + octet[1] + "." + octet[2] + "." + octet[3];
octet[2] = octet[0] + "." + octet[1] + "." + octet[2];
octet[1] = octet[0] + "." + octet[1];
/* Reset the Hash module and send it our IV */
HashResetRequest(Sender, HashProvider).Send();
HashKeyRequest(Sender, HashProvider, iv).Send();
/* Send the Hash module a different hex table for each octet group's Hash sum */
for (int k = 0; k < 4; k++)
{
HashHexRequest(Sender, HashProvider, xtab[(iv[k]+i[k]) % 4]).Send();
ra[k] = std::string(HashSumRequest(Sender, HashProvider, octet[k]).Send()).substr(0,6);
}
/* Stick them all together */
return std::string().append(ra[0]).append(".").append(ra[1]).append(".").append(ra[2]).append(".").append(ra[3]);
}
std::string Cloak6(const char* ip)
{
/* Theyre using 4in6 (YUCK). Translate as ipv4 cloak */
if (!strncmp(ip, "0::ffff:", 8))
return Cloak4(ip + 8);
/* If we get here, yes it really is an ipv6 ip */
unsigned int iv[] = { key1, key2, key3, key4 };
std::vector<std::string> hashies;
std::string item;
int rounds = 0;
/* Reset the Hash module and send it our IV */
HashResetRequest(Sender, HashProvider).Send();
HashKeyRequest(Sender, HashProvider, iv).Send();
for (const char* input = ip; *input; input++)
{
item += *input;
if (item.length() > 7)
{
/* Send the Hash module a different hex table for each octet group's Hash sum */
HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();
hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));
item.clear();
}
rounds++;
}
if (!item.empty())
{
/* Send the Hash module a different hex table for each octet group's Hash sum */
HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();
hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));
item.clear();
}
/* Stick them all together */
return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
}
void DoRehash()
{
ConfigReader Conf(ServerInstance);
key1 = key2 = key3 = key4 = 0;
key1 = Conf.ReadInteger("cloak","key1",0,true);
key2 = Conf.ReadInteger("cloak","key2",0,true);
key3 = Conf.ReadInteger("cloak","key3",0,true);
key4 = Conf.ReadInteger("cloak","key4",0,true);
prefix = Conf.ReadValue("cloak","prefix",0);
if (prefix.empty())
prefix = ServerInstance->Config->Network;
if (!key1 && !key2 && !key3 && !key4)
throw ModuleException("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");
}
};
class ModuleCloaking : public Module
{
private:
CloakUser* cu;
Module* HashModule;
public:
ModuleCloaking(InspIRCd* Me)
: Module(Me)
{
ServerInstance->UseInterface("HashRequest");
/* Attempt to locate the md5 service provider, bail if we can't find it */
HashModule = ServerInstance->FindModule("m_md5.so");
if (!HashModule)
throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
/* Create new mode handler object */
cu = new CloakUser(ServerInstance, this, HashModule);
/* Register it with the core */
if (!ServerInstance->AddMode(cu, 'x'))
throw ModuleException("Could not add new modes!");
OnRehash(NULL,"");
}
virtual ~ModuleCloaking()
{
ServerInstance->Modes->DelMode(cu);
DELETE(cu);
ServerInstance->DoneWithInterface("HashRequest");
}
virtual Version GetVersion()
{
// returns the version number of the module to be
// listed in /MODULES
return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
cu->DoRehash();
}
void Implements(char* List)
{
List[I_OnRehash] = 1;
}
};
MODULE_INIT(ModuleCloaking)
\ No newline at end of file diff --git a/src/modules/m_clones.cpp b/src/modules/m_clones.cpp index 72a7ca7e8..429b9c2b9 100644 --- a/src/modules/m_clones.cpp +++ b/src/modules/m_clones.cpp @@ -1,100 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "wildcard.h" - -/* $ModDesc: Provides the /clones command to retrieve information on a user, channel, or IP address */ - -/** Handle /CHECK - */ -class cmd_clones : public command_t -{ - public: - cmd_clones (InspIRCd* Instance) : command_t(Instance,"CLONES", 'o', 1) - { - this->source = "m_clones.so"; - syntax = "<limit>"; - } - - std::string FindMatchingIP(const irc::string &ipaddr) - { - std::string n = assign(ipaddr); - for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++) - if (a->second->GetIPString() == n) - return a->second->GetFullRealHost(); - return "<?>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - - std::string clonesstr = "304 " + std::string(user->nick) + " :CLONES"; - - unsigned long limit = atoi(parameters[0]); - - /* - * Syntax of a /clones reply: - * :server.name 304 target :CLONES START - * :server.name 304 target :CLONES <count> <ip> <fullhost> - * :server.name 304 target :CHECK END - */ - - user->WriteServ(clonesstr + " START"); - - /* hostname or other */ - for (clonemap::iterator x = ServerInstance->global_clones.begin(); x != ServerInstance->global_clones.end(); x++) - { - if (x->second >= limit) - user->WriteServ(clonesstr + " "+ ConvToStr(x->second) + " " + assign(x->first) + " " + FindMatchingIP(x->first)); - } - - user->WriteServ(clonesstr + " END"); - - return CMD_LOCALONLY; - } -}; - - -class ModuleClones : public Module -{ - private: - cmd_clones *mycommand; - public: - ModuleClones(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_clones(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleClones() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - /* we don't hook anything, nothing required */ - } - -}; - -MODULE_INIT(ModuleClones) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "wildcard.h"
/* $ModDesc: Provides the /clones command to retrieve information on a user, channel, or IP address */
/** Handle /CHECK
*/
class cmd_clones : public command_t
{
public:
cmd_clones (InspIRCd* Instance) : command_t(Instance,"CLONES", 'o', 1)
{
this->source = "m_clones.so";
syntax = "<limit>";
}
std::string FindMatchingIP(const irc::string &ipaddr)
{
std::string n = assign(ipaddr);
for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++)
if (a->second->GetIPString() == n)
return a->second->GetFullRealHost();
return "<?>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
std::string clonesstr = "304 " + std::string(user->nick) + " :CLONES";
unsigned long limit = atoi(parameters[0]);
/*
* Syntax of a /clones reply:
* :server.name 304 target :CLONES START
* :server.name 304 target :CLONES <count> <ip> <fullhost>
* :server.name 304 target :CHECK END
*/
user->WriteServ(clonesstr + " START");
/* hostname or other */
for (clonemap::iterator x = ServerInstance->global_clones.begin(); x != ServerInstance->global_clones.end(); x++)
{
if (x->second >= limit)
user->WriteServ(clonesstr + " "+ ConvToStr(x->second) + " " + assign(x->first) + " " + FindMatchingIP(x->first));
}
user->WriteServ(clonesstr + " END");
return CMD_LOCALONLY;
}
};
class ModuleClones : public Module
{
private:
cmd_clones *mycommand;
public:
ModuleClones(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_clones(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleClones()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
/* we don't hook anything, nothing required */
}
};
MODULE_INIT(ModuleClones)
\ No newline at end of file diff --git a/src/modules/m_conn_join.cpp b/src/modules/m_conn_join.cpp index 2d639f310..a8e81fcd8 100644 --- a/src/modules/m_conn_join.cpp +++ b/src/modules/m_conn_join.cpp @@ -1,96 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Forces users to join the specified channel(s) on connect */ - -class ModuleConnJoin : public Module -{ - private: - std::string JoinChan; - std::vector<std::string> Joinchans; - - - int tokenize(const string &str, std::vector<std::string> &tokens) - { - // skip delimiters at beginning. - string::size_type lastPos = str.find_first_not_of(",", 0); - // find first "non-delimiter". - string::size_type pos = str.find_first_of(",", lastPos); - - while (string::npos != pos || string::npos != lastPos) - { - // found a token, add it to the vector. - tokens.push_back(str.substr(lastPos, pos - lastPos)); - // skip delimiters. Note the "not_of" - lastPos = str.find_first_not_of(",", pos); - // find next "non-delimiter" - pos = str.find_first_of(",", lastPos); - } - return tokens.size(); - } - - public: - ModuleConnJoin(InspIRCd* Me) - : Module(Me) - { - OnRehash(NULL, ""); - } - - Priority Prioritize() - { - return PRIORITY_LAST; - } - - void Implements(char* List) - { - List[I_OnPostConnect] = List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader* conf = new ConfigReader(ServerInstance); - JoinChan = conf->ReadValue("autojoin", "channel", 0); - Joinchans.clear(); - if (!JoinChan.empty()) - tokenize(JoinChan,Joinchans); - DELETE(conf); - } - - virtual ~ModuleConnJoin() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void OnPostConnect(userrec* user) - { - if (!IS_LOCAL(user)) - return; - - for(std::vector<std::string>::iterator it = Joinchans.begin(); it != Joinchans.end(); it++) - if (ServerInstance->IsChannel(it->c_str())) - chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true)); - } - -}; - - -MODULE_INIT(ModuleConnJoin) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Forces users to join the specified channel(s) on connect */
class ModuleConnJoin : public Module
{
private:
std::string JoinChan;
std::vector<std::string> Joinchans;
int tokenize(const string &str, std::vector<std::string> &tokens)
{
// skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(",", 0);
// find first "non-delimiter".
string::size_type pos = str.find_first_of(",", lastPos);
while (string::npos != pos || string::npos != lastPos)
{
// found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(",", pos);
// find next "non-delimiter"
pos = str.find_first_of(",", lastPos);
}
return tokens.size();
}
public:
ModuleConnJoin(InspIRCd* Me)
: Module(Me)
{
OnRehash(NULL, "");
}
Priority Prioritize()
{
return PRIORITY_LAST;
}
void Implements(char* List)
{
List[I_OnPostConnect] = List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader* conf = new ConfigReader(ServerInstance);
JoinChan = conf->ReadValue("autojoin", "channel", 0);
Joinchans.clear();
if (!JoinChan.empty())
tokenize(JoinChan,Joinchans);
DELETE(conf);
}
virtual ~ModuleConnJoin()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void OnPostConnect(userrec* user)
{
if (!IS_LOCAL(user))
return;
for(std::vector<std::string>::iterator it = Joinchans.begin(); it != Joinchans.end(); it++)
if (ServerInstance->IsChannel(it->c_str()))
chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true));
}
};
MODULE_INIT(ModuleConnJoin)
\ No newline at end of file diff --git a/src/modules/m_conn_umodes.cpp b/src/modules/m_conn_umodes.cpp index 3f27eeff5..f9118a384 100644 --- a/src/modules/m_conn_umodes.cpp +++ b/src/modules/m_conn_umodes.cpp @@ -1,104 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "wildcard.h" - -/* $ModDesc: Sets (and unsets) modes on users when they connect */ - -class ModuleModesOnConnect : public Module -{ - private: - - ConfigReader *Conf; - - public: - ModuleModesOnConnect(InspIRCd* Me) - : Module(Me) - { - - Conf = new ConfigReader(ServerInstance); - } - - void Implements(char* List) - { - List[I_OnPostConnect] = List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - DELETE(Conf); - Conf = new ConfigReader(ServerInstance); - } - - virtual ~ModuleModesOnConnect() - { - DELETE(Conf); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void OnPostConnect(userrec* user) - { - if (!IS_LOCAL(user)) - return; - - for (int j = 0; j < Conf->Enumerate("connect"); j++) - { - std::string hostn = Conf->ReadValue("connect","allow",j); - if ((match(user->GetIPString(),hostn.c_str(),true)) || (match(user->host,hostn.c_str()))) - { - std::string ThisModes = Conf->ReadValue("connect","modes",j); - if (!ThisModes.empty()) - { - std::string buf; - stringstream ss(ThisModes); - - vector<string> tokens; - - // split ThisUserModes into modes and mode params - while (ss >> buf) - tokens.push_back(buf); - - int size = tokens.size() + 1; - const char** modes = new const char*[size]; - modes[0] = user->nick; - modes[1] = tokens[0].c_str(); - - if (tokens.size() > 1) - { - // process mode params - int i = 2; - for (unsigned int k = 1; k < tokens.size(); k++) - { - modes[i] = tokens[k].c_str(); - i++; - } - } - - ServerInstance->Parser->CallHandler("MODE", modes, size, user); - delete [] modes; - } - break; - } - } - } -}; - -MODULE_INIT(ModuleModesOnConnect) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "wildcard.h"
/* $ModDesc: Sets (and unsets) modes on users when they connect */
class ModuleModesOnConnect : public Module
{
private:
ConfigReader *Conf;
public:
ModuleModesOnConnect(InspIRCd* Me)
: Module(Me)
{
Conf = new ConfigReader(ServerInstance);
}
void Implements(char* List)
{
List[I_OnPostConnect] = List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
DELETE(Conf);
Conf = new ConfigReader(ServerInstance);
}
virtual ~ModuleModesOnConnect()
{
DELETE(Conf);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void OnPostConnect(userrec* user)
{
if (!IS_LOCAL(user))
return;
for (int j = 0; j < Conf->Enumerate("connect"); j++)
{
std::string hostn = Conf->ReadValue("connect","allow",j);
if ((match(user->GetIPString(),hostn.c_str(),true)) || (match(user->host,hostn.c_str())))
{
std::string ThisModes = Conf->ReadValue("connect","modes",j);
if (!ThisModes.empty())
{
std::string buf;
stringstream ss(ThisModes);
vector<string> tokens;
// split ThisUserModes into modes and mode params
while (ss >> buf)
tokens.push_back(buf);
int size = tokens.size() + 1;
const char** modes = new const char*[size];
modes[0] = user->nick;
modes[1] = tokens[0].c_str();
if (tokens.size() > 1)
{
// process mode params
int i = 2;
for (unsigned int k = 1; k < tokens.size(); k++)
{
modes[i] = tokens[k].c_str();
i++;
}
}
ServerInstance->Parser->CallHandler("MODE", modes, size, user);
delete [] modes;
}
break;
}
}
}
};
MODULE_INIT(ModuleModesOnConnect)
\ No newline at end of file diff --git a/src/modules/m_conn_waitpong.cpp b/src/modules/m_conn_waitpong.cpp index 0dd27ddbd..b84533f88 100644 --- a/src/modules/m_conn_waitpong.cpp +++ b/src/modules/m_conn_waitpong.cpp @@ -1,148 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Forces connecting clients to send a PONG message back to the server before they can complete their connection */ - -class ModuleWaitPong : public Module -{ - bool sendsnotice; - bool killonbadreply; - const char* extenstr; - - public: - ModuleWaitPong(InspIRCd* Me) - : Module(Me), extenstr("waitpong_pingstr") - { - OnRehash(NULL,""); - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - ConfigReader Conf(ServerInstance); - - sendsnotice = Conf.ReadFlag("waitpong", "sendsnotice", 0); - - if(Conf.GetError() == CONF_VALUE_NOT_FOUND) - sendsnotice = true; - - killonbadreply = Conf.ReadFlag("waitpong", "killonbadreply", 0); - - if(Conf.GetError() == CONF_VALUE_NOT_FOUND) - killonbadreply = true; - } - - void Implements(char* List) - { - List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnPreCommand] = List[I_OnRehash] = List[I_OnUserDisconnect] = List[I_OnCleanup] = 1; - } - - char* RandString(unsigned int length) - { - unsigned char* out = new unsigned char[length+1]; - for(unsigned int i = 0; i < length; i++) - out[i] = ((rand() % 26) + 65); - out[length] = '\0'; - - return (char*)out; - } - - virtual int OnUserRegister(userrec* user) - { - char* pingrpl = RandString(10); - - user->Write("PING :%s", pingrpl); - - if(sendsnotice) - user->WriteServ("NOTICE %s :*** If you are having problems connecting due to ping timeouts, please type /quote PONG %s or /raw PONG %s now.", user->nick, pingrpl, pingrpl); - - user->Extend(extenstr, pingrpl); - return 0; - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec* user, bool validated, const std::string &original_line) - { - if(command == "PONG") - { - char* pingrpl; - user->GetExt(extenstr, pingrpl); - - if(pingrpl) - { - if(strcmp(pingrpl, parameters[0]) == 0) - { - DELETE(pingrpl); - user->Shrink(extenstr); - return 1; - } - else - { - if(killonbadreply) - userrec::QuitUser(ServerInstance, user, "Incorrect ping reply for registration"); - return 1; - } - } - } - return 0; - } - - virtual bool OnCheckReady(userrec* user) - { - char* pingrpl; - return (!user->GetExt(extenstr, pingrpl)); - } - - virtual void OnUserDisconnect(userrec* user) - { - char* pingrpl; - user->GetExt(extenstr, pingrpl); - - if(pingrpl) - { - DELETE(pingrpl); - user->Shrink(extenstr); - } - } - - virtual void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - char* pingrpl; - user->GetExt(extenstr, pingrpl); - - if(pingrpl) - { - DELETE(pingrpl); - user->Shrink(extenstr); - } - } - } - - virtual ~ModuleWaitPong() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 1, VF_VENDOR, API_VERSION); - } - -}; - -MODULE_INIT(ModuleWaitPong) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Forces connecting clients to send a PONG message back to the server before they can complete their connection */
class ModuleWaitPong : public Module
{
bool sendsnotice;
bool killonbadreply;
const char* extenstr;
public:
ModuleWaitPong(InspIRCd* Me)
: Module(Me), extenstr("waitpong_pingstr")
{
OnRehash(NULL,"");
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
ConfigReader Conf(ServerInstance);
sendsnotice = Conf.ReadFlag("waitpong", "sendsnotice", 0);
if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
sendsnotice = true;
killonbadreply = Conf.ReadFlag("waitpong", "killonbadreply", 0);
if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
killonbadreply = true;
}
void Implements(char* List)
{
List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnPreCommand] = List[I_OnRehash] = List[I_OnUserDisconnect] = List[I_OnCleanup] = 1;
}
char* RandString(unsigned int length)
{
unsigned char* out = new unsigned char[length+1];
for(unsigned int i = 0; i < length; i++)
out[i] = ((rand() % 26) + 65);
out[length] = '\0';
return (char*)out;
}
virtual int OnUserRegister(userrec* user)
{
char* pingrpl = RandString(10);
user->Write("PING :%s", pingrpl);
if(sendsnotice)
user->WriteServ("NOTICE %s :*** If you are having problems connecting due to ping timeouts, please type /quote PONG %s or /raw PONG %s now.", user->nick, pingrpl, pingrpl);
user->Extend(extenstr, pingrpl);
return 0;
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec* user, bool validated, const std::string &original_line)
{
if(command == "PONG")
{
char* pingrpl;
user->GetExt(extenstr, pingrpl);
if(pingrpl)
{
if(strcmp(pingrpl, parameters[0]) == 0)
{
DELETE(pingrpl);
user->Shrink(extenstr);
return 1;
}
else
{
if(killonbadreply)
userrec::QuitUser(ServerInstance, user, "Incorrect ping reply for registration");
return 1;
}
}
}
return 0;
}
virtual bool OnCheckReady(userrec* user)
{
char* pingrpl;
return (!user->GetExt(extenstr, pingrpl));
}
virtual void OnUserDisconnect(userrec* user)
{
char* pingrpl;
user->GetExt(extenstr, pingrpl);
if(pingrpl)
{
DELETE(pingrpl);
user->Shrink(extenstr);
}
}
virtual void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
char* pingrpl;
user->GetExt(extenstr, pingrpl);
if(pingrpl)
{
DELETE(pingrpl);
user->Shrink(extenstr);
}
}
}
virtual ~ModuleWaitPong()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 1, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleWaitPong)
\ No newline at end of file diff --git a/src/modules/m_connflood.cpp b/src/modules/m_connflood.cpp index 47b19fdf4..71e52fd01 100644 --- a/src/modules/m_connflood.cpp +++ b/src/modules/m_connflood.cpp @@ -1,120 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "modules.h" - -/* $ModDesc: Connection throttle */ - -int conns = 0, throttled = 0; - -class ModuleConnFlood : public Module -{ -private: - int seconds, maxconns, timeout, boot_wait; - time_t first; - std::string quitmsg; - - ConfigReader* conf; - - -public: - ModuleConnFlood(InspIRCd* Me) : Module(Me) - { - - InitConf(); - } - - virtual ~ModuleConnFlood() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnUserRegister] = 1; - } - - void InitConf() - { - /* read configuration variables */ - conf = new ConfigReader(ServerInstance); - /* throttle configuration */ - seconds = conf->ReadInteger("connflood", "seconds", 0, true); - maxconns = conf->ReadInteger("connflood", "maxconns", 0, true); - timeout = conf->ReadInteger("connflood", "timeout", 0, true); - quitmsg = conf->ReadValue("connflood", "quitmsg", 0); - - /* seconds to wait when the server just booted */ - boot_wait = conf->ReadInteger("connflood", "bootwait", 0, true); - - first = ServerInstance->Time(); - } - - virtual int OnUserRegister(userrec* user) - { - time_t next = ServerInstance->Time(); - - if ((ServerInstance->startup_time + boot_wait) > next) - return 0; - - /* time difference between first and latest connection */ - time_t tdiff = next - first; - - /* increase connection count */ - conns++; - - if (throttled == 1) - { - if (tdiff > seconds + timeout) - { - /* expire throttle */ - throttled = 0; - ServerInstance->WriteOpers("*** Connection throttle deactivated"); - return 0; - } - userrec::QuitUser(ServerInstance, user, quitmsg); - return 1; - } - - if (tdiff <= seconds) - { - if (conns >= maxconns) - { - throttled = 1; - ServerInstance->WriteOpers("*** Connection throttle activated"); - userrec::QuitUser(ServerInstance, user, quitmsg); - return 1; - } - } - else - { - conns = 1; - first = next; - } - return 0; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - InitConf(); - } - -}; - -MODULE_INIT(ModuleConnFlood) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "modules.h"
/* $ModDesc: Connection throttle */
int conns = 0, throttled = 0;
class ModuleConnFlood : public Module
{
private:
int seconds, maxconns, timeout, boot_wait;
time_t first;
std::string quitmsg;
ConfigReader* conf;
public:
ModuleConnFlood(InspIRCd* Me) : Module(Me)
{
InitConf();
}
virtual ~ModuleConnFlood()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnUserRegister] = 1;
}
void InitConf()
{
/* read configuration variables */
conf = new ConfigReader(ServerInstance);
/* throttle configuration */
seconds = conf->ReadInteger("connflood", "seconds", 0, true);
maxconns = conf->ReadInteger("connflood", "maxconns", 0, true);
timeout = conf->ReadInteger("connflood", "timeout", 0, true);
quitmsg = conf->ReadValue("connflood", "quitmsg", 0);
/* seconds to wait when the server just booted */
boot_wait = conf->ReadInteger("connflood", "bootwait", 0, true);
first = ServerInstance->Time();
}
virtual int OnUserRegister(userrec* user)
{
time_t next = ServerInstance->Time();
if ((ServerInstance->startup_time + boot_wait) > next)
return 0;
/* time difference between first and latest connection */
time_t tdiff = next - first;
/* increase connection count */
conns++;
if (throttled == 1)
{
if (tdiff > seconds + timeout)
{
/* expire throttle */
throttled = 0;
ServerInstance->WriteOpers("*** Connection throttle deactivated");
return 0;
}
userrec::QuitUser(ServerInstance, user, quitmsg);
return 1;
}
if (tdiff <= seconds)
{
if (conns >= maxconns)
{
throttled = 1;
ServerInstance->WriteOpers("*** Connection throttle activated");
userrec::QuitUser(ServerInstance, user, quitmsg);
return 1;
}
}
else
{
conns = 1;
first = next;
}
return 0;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
InitConf();
}
};
MODULE_INIT(ModuleConnFlood)
\ No newline at end of file diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp index eb20f4f99..b1a22941d 100644 --- a/src/modules/m_cycle.cpp +++ b/src/modules/m_cycle.cpp @@ -1,99 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style CYCLE command. */ - -/** Handle /CYCLE - */ -class cmd_cycle : public command_t -{ - public: - cmd_cycle (InspIRCd* Instance) : command_t(Instance,"CYCLE", 0, 1) - { - this->source = "m_cycle.so"; - syntax = "<channel> :[reason]"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - chanrec* channel = ServerInstance->FindChan(parameters[0]); - std::string reason = ConvToStr("Cycling"); - - if (pcnt > 1) - { - /* reason provided, use it */ - reason = reason + ": " + parameters[1]; - } - - if (channel) - { - /* - * technically, this is only ever sent locally, but pays to be safe ;p - */ - if (IS_LOCAL(user)) - { - if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user)) - { - /* banned, boned. drop the message. */ - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not cycle, as you are banned on channel " + channel->name); - return CMD_FAILURE; - } - - /* XXX in the future, this may move to a static chanrec method (the delete.) -- w00t */ - if (!channel->PartUser(user, reason.c_str())) - delete channel; - - chanrec::JoinUser(ServerInstance, user, parameters[0], true, "", ServerInstance->Time(true)); - } - - return CMD_LOCALONLY; - } - else - { - user->WriteServ("NOTICE %s :*** You are not on this channel", user->nick); - } - - return CMD_FAILURE; - } -}; - - -class ModuleCycle : public Module -{ - cmd_cycle* mycommand; - public: - ModuleCycle(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_cycle(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleCycle() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleCycle) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style CYCLE command. */
/** Handle /CYCLE
*/
class cmd_cycle : public command_t
{
public:
cmd_cycle (InspIRCd* Instance) : command_t(Instance,"CYCLE", 0, 1)
{
this->source = "m_cycle.so";
syntax = "<channel> :[reason]";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
chanrec* channel = ServerInstance->FindChan(parameters[0]);
std::string reason = ConvToStr("Cycling");
if (pcnt > 1)
{
/* reason provided, use it */
reason = reason + ": " + parameters[1];
}
if (channel)
{
/*
* technically, this is only ever sent locally, but pays to be safe ;p
*/
if (IS_LOCAL(user))
{
if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user))
{
/* banned, boned. drop the message. */
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not cycle, as you are banned on channel " + channel->name);
return CMD_FAILURE;
}
/* XXX in the future, this may move to a static chanrec method (the delete.) -- w00t */
if (!channel->PartUser(user, reason.c_str()))
delete channel;
chanrec::JoinUser(ServerInstance, user, parameters[0], true, "", ServerInstance->Time(true));
}
return CMD_LOCALONLY;
}
else
{
user->WriteServ("NOTICE %s :*** You are not on this channel", user->nick);
}
return CMD_FAILURE;
}
};
class ModuleCycle : public Module
{
cmd_cycle* mycommand;
public:
ModuleCycle(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_cycle(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleCycle()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleCycle)
\ No newline at end of file diff --git a/src/modules/m_dccallow.cpp b/src/modules/m_dccallow.cpp index bfec3c5e1..61ef90d89 100644 --- a/src/modules/m_dccallow.cpp +++ b/src/modules/m_dccallow.cpp @@ -1,489 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Povides support for the /DCCALLOW command */ - -static ConfigReader *Conf; - -class BannedFileList -{ - public: - std::string filemask; - std::string action; -}; - -class DCCAllow -{ - public: - std::string nickname; - std::string hostmask; - time_t set_on; - long length; - - DCCAllow() { } - - DCCAllow(const std::string &nick, const std::string &hm, const time_t so, const long ln) : nickname(nick), hostmask(hm), set_on(so), length(ln) { } -}; - -typedef std::vector<userrec *> userlist; -userlist ul; -typedef std::vector<DCCAllow> dccallowlist; -dccallowlist* dl; -typedef std::vector<BannedFileList> bannedfilelist; -bannedfilelist bfl; - -class cmd_dccallow : public command_t -{ - public: - cmd_dccallow(InspIRCd* Me) : command_t(Me, "DCCALLOW", 0, 0) - { - this->source = "m_dccallow.so"; - syntax = "{[+|-]<nick> <time>|HELP|LIST}"; - } - - CmdResult Handle(const char **parameters, int pcnt, userrec *user) - { - /* syntax: DCCALLOW [+|-]<nick> (<time>) */ - if (!pcnt) - { - // display current DCCALLOW list - DisplayDCCAllowList(user); - return CMD_FAILURE; - } - else if (pcnt > 0) - { - char action = *parameters[0]; - - // if they didn't specify an action, this is probably a command - if (action != '+' && action != '-') - { - if (!strcasecmp(parameters[0], "LIST")) - { - // list current DCCALLOW list - DisplayDCCAllowList(user); - return CMD_FAILURE; - } - else if (!strcasecmp(parameters[0], "HELP")) - { - // display help - DisplayHelp(user); - return CMD_FAILURE; - } - } - - std::string nick = parameters[0] + 1; - userrec *target = ServerInstance->FindNick(nick); - - if (target) - { - - if (action == '-') - { - user->GetExt("dccallow_list", dl); - // check if it contains any entries - if (dl) - { - if (dl->size()) - { - for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i) - { - // search through list - if (i->nickname == target->nick) - { - dl->erase(i); - user->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", user->nick, user->nick, target->nick); - break; - } - } - } - } - else - { - DELETE(dl); - user->Shrink("dccallow_list"); - - // remove from userlist - for (userlist::iterator j = ul.begin(); j != ul.end(); ++j) - { - userrec* u = (userrec*)(*j); - if (u == user) - { - ul.erase(j); - break; - } - } - } - } - else if (action == '+') - { - // fetch current DCCALLOW list - user->GetExt("dccallow_list", dl); - // they don't have one, create it - if (!dl) - { - dl = new dccallowlist; - user->Extend("dccallow_list", dl); - // add this user to the userlist - ul.push_back(user); - } - for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k) - { - if (k->nickname == target->nick) - { - user->WriteServ("996 %s %s :%s is already on your DCCALLOW list", user->nick, user->nick, target->nick); - return CMD_FAILURE; - } - else if (ServerInstance->MatchText(user->GetFullHost(), k->hostmask)) - { - user->WriteServ("996 %s %s :You cannot add yourself to your own DCCALLOW list!", user->nick, user->nick); - return CMD_FAILURE; - } - } - - std::string mask = std::string(target->nick)+"!"+std::string(target->ident)+"@"+std::string(target->dhost); - std::string default_length = Conf->ReadValue("dccallow", "length", 0); - - long length; - if (pcnt < 2) - { - length = ServerInstance->Duration(default_length); - } - else if (!atoi(parameters[1])) - { - length = 0; - } - else - { - length = ServerInstance->Duration(parameters[1]); - } - - if (!ServerInstance->IsValidMask(mask.c_str())) - { - return CMD_FAILURE; - } - - dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length)); - - if (length > 0) - { - user->WriteServ("993 %s %s :Added %s to DCCALLOW list for %d seconds", user->nick, user->nick, target->nick, length); - } - else - { - user->WriteServ("994 %s %s :Added %s to DCCALLOW list for this session", user->nick, user->nick, target->nick); - } - - /* route it. */ - return CMD_SUCCESS; - } - } - else - { - // nick doesn't exist - user->WriteServ("401 %s %s :No such nick/channel", user->nick, nick.c_str()); - return CMD_FAILURE; - } - } - return CMD_FAILURE; - } - - void DisplayHelp(userrec* user) - { - user->WriteServ("998 %s :DCCALLOW [<+|->nick [time]] [list] [help]", user->nick); - user->WriteServ("998 %s :You may allow DCCs from specific users by specifying a", user->nick); - user->WriteServ("998 %s :DCC allow for the user you want to receive DCCs from.", user->nick); - user->WriteServ("998 %s :For example, to allow the user Brain to send you inspircd.exe", user->nick); - user->WriteServ("998 %s :you would type:", user->nick); - user->WriteServ("998 %s :/DCCALLOW +Brain", user->nick); - user->WriteServ("998 %s :Brain would then be able to send you files. They would have to", user->nick); - user->WriteServ("998 %s :resend the file again if the server gave them an error message", user->nick); - user->WriteServ("998 %s :before you added them to your DCCALLOW list.", user->nick); - user->WriteServ("998 %s :DCCALLOW entries will be temporary by default, if you want to add", user->nick); - user->WriteServ("998 %s :them to your DCCALLOW list until you leave IRC, type:", user->nick); - user->WriteServ("998 %s :/DCCALLOW +Brain 0", user->nick); - user->WriteServ("998 %s :To remove the user from your DCCALLOW list, type:", user->nick); - user->WriteServ("998 %s :/DCCALLOW -Brain", user->nick); - user->WriteServ("998 %s :To see the users in your DCCALLOW list, type:", user->nick); - user->WriteServ("998 %s :/DCCALLOW LIST", user->nick); - user->WriteServ("998 %s :NOTE: If the user leaves IRC or changes their nickname", user->nick); - user->WriteServ("998 %s : they will be removed from your DCCALLOW list.", user->nick); - user->WriteServ("998 %s : your DCCALLOW list will be deleted when you leave IRC.", user->nick); - user->WriteServ("999 %s :End of DCCALLOW HELP", user->nick); - } - - void DisplayDCCAllowList(userrec* user) - { - // display current DCCALLOW list - user->WriteServ("990 %s :Users on your DCCALLOW list:", user->nick); - user->GetExt("dccallow_list", dl); - - if (dl) - { - for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c) - { - user->WriteServ("991 %s %s :%s (%s)", user->nick, user->nick, c->nickname.c_str(), c->hostmask.c_str()); - } - } - - user->WriteServ("992 %s :End of DCCALLOW list", user->nick); - } - -}; - -class ModuleDCCAllow : public Module -{ - cmd_dccallow* mycommand; - public: - - ModuleDCCAllow(InspIRCd* Me) - : Module(Me) - { - Conf = new ConfigReader(ServerInstance); - mycommand = new cmd_dccallow(ServerInstance); - ServerInstance->AddCommand(mycommand); - ReadFileConf(); - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserQuit] = List[I_OnUserPreNick] = List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - delete Conf; - Conf = new ConfigReader(ServerInstance); - } - - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - dccallowlist* dl; - - // remove their DCCALLOW list if they have one - user->GetExt("dccallow_list", dl); - if (dl) - { - DELETE(dl); - user->Shrink("dccallow_list"); - RemoveFromUserlist(user); - } - - // remove them from any DCCALLOW lists - // they are currently on - RemoveNick(user); - } - - - virtual int OnUserPreNick(userrec* user, const std::string &newnick) - { - RemoveNick(user); - return 0; - } - - virtual int OnUserPreMessage(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreNotice(user, dest, target_type, text, status, exempt_list); - } - - virtual int OnUserPreNotice(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list) - { - if (!IS_LOCAL(user)) - return 0; - - if (target_type == TYPE_USER) - { - userrec* u = (userrec*)dest; - - /* Always allow a user to dcc themselves (although... why?) */ - if (user == u) - return 0; - - if ((text.length()) && (text[0] == '\1')) - { - Expire(); - - // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676 - // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION - - if (strncmp(text.c_str(), "\1DCC ", 5) == 0) - { - u->GetExt("dccallow_list", dl); - - if (dl && dl->size()) - { - for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter) - if (ServerInstance->MatchText(user->GetFullHost(), iter->hostmask)) - return 0; - } - - // tokenize - std::stringstream ss(text); - std::string buf; - std::vector<std::string> tokens; - - while (ss >> buf) - tokens.push_back(buf); - - irc::string type = tokens[1].c_str(); - - bool blockchat = Conf->ReadFlag("dccallow", "blockchat", 0); - - if (type == "SEND") - { - std::string defaultaction = Conf->ReadValue("dccallow", "action", 0); - std::string filename = tokens[2]; - - if (defaultaction == "allow") - return 0; - - for (unsigned int i = 0; i < bfl.size(); i++) - { - if (ServerInstance->MatchText(filename, bfl[i].filemask)) - { - if (bfl[i].action == "allow") - return 0; - } - else - { - if (defaultaction == "allow") - return 0; - } - user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick, u->nick, filename.c_str()); - u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick, user->nick, user->ident, user->dhost, filename.c_str()); - u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick); - return 1; - } - } - else if ((type == "CHAT") && (blockchat)) - { - user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick, u->nick); - u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick, user->nick, user->ident, user->dhost); - u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick); - return 1; - } - } - } - } - return 0; - } - - void Expire() - { - for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter) - { - userrec* u = (userrec*)(*iter); - u->GetExt("dccallow_list", dl); - - if (dl) - { - if (dl->size()) - { - dccallowlist::iterator iter = dl->begin(); - while (iter != dl->end()) - { - if ((iter->set_on + iter->length) <= ServerInstance->Time()) - { - u->WriteServ("997 %s %s :DCCALLOW entry for %s has expired", u->nick, u->nick, iter->nickname.c_str()); - iter = dl->erase(iter); - } - else - { - ++iter; - } - } - } - } - else - { - RemoveFromUserlist(u); - } - } - } - - void RemoveNick(userrec* user) - { - /* Iterate through all DCCALLOW lists and remove user */ - for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter) - { - userrec *u = (userrec*)(*iter); - u->GetExt("dccallow_list", dl); - - if (dl) - { - if (dl->size()) - { - for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i) - { - if (i->nickname == user->nick) - { - - u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick, i->nickname.c_str()); - u->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", u->nick, u->nick, i->nickname.c_str()); - dl->erase(i); - break; - } - } - } - } - else - { - RemoveFromUserlist(u); - } - } - } - - void RemoveFromUserlist(userrec *user) - { - // remove user from userlist - for (userlist::iterator j = ul.begin(); j != ul.end(); ++j) - { - userrec* u = (userrec*)(*j); - if (u == user) - { - ul.erase(j); - break; - } - } - } - - void ReadFileConf() - { - bfl.clear(); - for (int i = 0; i < Conf->Enumerate("banfile"); i++) - { - BannedFileList bf; - std::string fileglob = Conf->ReadValue("banfile", "pattern", i); - std::string action = Conf->ReadValue("banfile", "action", i); - bf.filemask = fileglob; - bf.action = action; - bfl.push_back(bf); - } - - } - - virtual ~ModuleDCCAllow() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleDCCAllow) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Povides support for the /DCCALLOW command */
static ConfigReader *Conf;
class BannedFileList
{
public:
std::string filemask;
std::string action;
};
class DCCAllow
{
public:
std::string nickname;
std::string hostmask;
time_t set_on;
long length;
DCCAllow() { }
DCCAllow(const std::string &nick, const std::string &hm, const time_t so, const long ln) : nickname(nick), hostmask(hm), set_on(so), length(ln) { }
};
typedef std::vector<userrec *> userlist;
userlist ul;
typedef std::vector<DCCAllow> dccallowlist;
dccallowlist* dl;
typedef std::vector<BannedFileList> bannedfilelist;
bannedfilelist bfl;
class cmd_dccallow : public command_t
{
public:
cmd_dccallow(InspIRCd* Me) : command_t(Me, "DCCALLOW", 0, 0)
{
this->source = "m_dccallow.so";
syntax = "{[+|-]<nick> <time>|HELP|LIST}";
}
CmdResult Handle(const char **parameters, int pcnt, userrec *user)
{
/* syntax: DCCALLOW [+|-]<nick> (<time>) */
if (!pcnt)
{
// display current DCCALLOW list
DisplayDCCAllowList(user);
return CMD_FAILURE;
}
else if (pcnt > 0)
{
char action = *parameters[0];
// if they didn't specify an action, this is probably a command
if (action != '+' && action != '-')
{
if (!strcasecmp(parameters[0], "LIST"))
{
// list current DCCALLOW list
DisplayDCCAllowList(user);
return CMD_FAILURE;
}
else if (!strcasecmp(parameters[0], "HELP"))
{
// display help
DisplayHelp(user);
return CMD_FAILURE;
}
}
std::string nick = parameters[0] + 1;
userrec *target = ServerInstance->FindNick(nick);
if (target)
{
if (action == '-')
{
user->GetExt("dccallow_list", dl);
// check if it contains any entries
if (dl)
{
if (dl->size())
{
for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
{
// search through list
if (i->nickname == target->nick)
{
dl->erase(i);
user->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", user->nick, user->nick, target->nick);
break;
}
}
}
}
else
{
DELETE(dl);
user->Shrink("dccallow_list");
// remove from userlist
for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
{
userrec* u = (userrec*)(*j);
if (u == user)
{
ul.erase(j);
break;
}
}
}
}
else if (action == '+')
{
// fetch current DCCALLOW list
user->GetExt("dccallow_list", dl);
// they don't have one, create it
if (!dl)
{
dl = new dccallowlist;
user->Extend("dccallow_list", dl);
// add this user to the userlist
ul.push_back(user);
}
for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)
{
if (k->nickname == target->nick)
{
user->WriteServ("996 %s %s :%s is already on your DCCALLOW list", user->nick, user->nick, target->nick);
return CMD_FAILURE;
}
else if (ServerInstance->MatchText(user->GetFullHost(), k->hostmask))
{
user->WriteServ("996 %s %s :You cannot add yourself to your own DCCALLOW list!", user->nick, user->nick);
return CMD_FAILURE;
}
}
std::string mask = std::string(target->nick)+"!"+std::string(target->ident)+"@"+std::string(target->dhost);
std::string default_length = Conf->ReadValue("dccallow", "length", 0);
long length;
if (pcnt < 2)
{
length = ServerInstance->Duration(default_length);
}
else if (!atoi(parameters[1]))
{
length = 0;
}
else
{
length = ServerInstance->Duration(parameters[1]);
}
if (!ServerInstance->IsValidMask(mask.c_str()))
{
return CMD_FAILURE;
}
dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));
if (length > 0)
{
user->WriteServ("993 %s %s :Added %s to DCCALLOW list for %d seconds", user->nick, user->nick, target->nick, length);
}
else
{
user->WriteServ("994 %s %s :Added %s to DCCALLOW list for this session", user->nick, user->nick, target->nick);
}
/* route it. */
return CMD_SUCCESS;
}
}
else
{
// nick doesn't exist
user->WriteServ("401 %s %s :No such nick/channel", user->nick, nick.c_str());
return CMD_FAILURE;
}
}
return CMD_FAILURE;
}
void DisplayHelp(userrec* user)
{
user->WriteServ("998 %s :DCCALLOW [<+|->nick [time]] [list] [help]", user->nick);
user->WriteServ("998 %s :You may allow DCCs from specific users by specifying a", user->nick);
user->WriteServ("998 %s :DCC allow for the user you want to receive DCCs from.", user->nick);
user->WriteServ("998 %s :For example, to allow the user Brain to send you inspircd.exe", user->nick);
user->WriteServ("998 %s :you would type:", user->nick);
user->WriteServ("998 %s :/DCCALLOW +Brain", user->nick);
user->WriteServ("998 %s :Brain would then be able to send you files. They would have to", user->nick);
user->WriteServ("998 %s :resend the file again if the server gave them an error message", user->nick);
user->WriteServ("998 %s :before you added them to your DCCALLOW list.", user->nick);
user->WriteServ("998 %s :DCCALLOW entries will be temporary by default, if you want to add", user->nick);
user->WriteServ("998 %s :them to your DCCALLOW list until you leave IRC, type:", user->nick);
user->WriteServ("998 %s :/DCCALLOW +Brain 0", user->nick);
user->WriteServ("998 %s :To remove the user from your DCCALLOW list, type:", user->nick);
user->WriteServ("998 %s :/DCCALLOW -Brain", user->nick);
user->WriteServ("998 %s :To see the users in your DCCALLOW list, type:", user->nick);
user->WriteServ("998 %s :/DCCALLOW LIST", user->nick);
user->WriteServ("998 %s :NOTE: If the user leaves IRC or changes their nickname", user->nick);
user->WriteServ("998 %s : they will be removed from your DCCALLOW list.", user->nick);
user->WriteServ("998 %s : your DCCALLOW list will be deleted when you leave IRC.", user->nick);
user->WriteServ("999 %s :End of DCCALLOW HELP", user->nick);
}
void DisplayDCCAllowList(userrec* user)
{
// display current DCCALLOW list
user->WriteServ("990 %s :Users on your DCCALLOW list:", user->nick);
user->GetExt("dccallow_list", dl);
if (dl)
{
for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
{
user->WriteServ("991 %s %s :%s (%s)", user->nick, user->nick, c->nickname.c_str(), c->hostmask.c_str());
}
}
user->WriteServ("992 %s :End of DCCALLOW list", user->nick);
}
};
class ModuleDCCAllow : public Module
{
cmd_dccallow* mycommand;
public:
ModuleDCCAllow(InspIRCd* Me)
: Module(Me)
{
Conf = new ConfigReader(ServerInstance);
mycommand = new cmd_dccallow(ServerInstance);
ServerInstance->AddCommand(mycommand);
ReadFileConf();
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserQuit] = List[I_OnUserPreNick] = List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
delete Conf;
Conf = new ConfigReader(ServerInstance);
}
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
dccallowlist* dl;
// remove their DCCALLOW list if they have one
user->GetExt("dccallow_list", dl);
if (dl)
{
DELETE(dl);
user->Shrink("dccallow_list");
RemoveFromUserlist(user);
}
// remove them from any DCCALLOW lists
// they are currently on
RemoveNick(user);
}
virtual int OnUserPreNick(userrec* user, const std::string &newnick)
{
RemoveNick(user);
return 0;
}
virtual int OnUserPreMessage(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
}
virtual int OnUserPreNotice(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
{
if (!IS_LOCAL(user))
return 0;
if (target_type == TYPE_USER)
{
userrec* u = (userrec*)dest;
/* Always allow a user to dcc themselves (although... why?) */
if (user == u)
return 0;
if ((text.length()) && (text[0] == '\1'))
{
Expire();
// :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676
// :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION
if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
{
u->GetExt("dccallow_list", dl);
if (dl && dl->size())
{
for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
if (ServerInstance->MatchText(user->GetFullHost(), iter->hostmask))
return 0;
}
// tokenize
std::stringstream ss(text);
std::string buf;
std::vector<std::string> tokens;
while (ss >> buf)
tokens.push_back(buf);
irc::string type = tokens[1].c_str();
bool blockchat = Conf->ReadFlag("dccallow", "blockchat", 0);
if (type == "SEND")
{
std::string defaultaction = Conf->ReadValue("dccallow", "action", 0);
std::string filename = tokens[2];
if (defaultaction == "allow")
return 0;
for (unsigned int i = 0; i < bfl.size(); i++)
{
if (ServerInstance->MatchText(filename, bfl[i].filemask))
{
if (bfl[i].action == "allow")
return 0;
}
else
{
if (defaultaction == "allow")
return 0;
}
user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick, u->nick, filename.c_str());
u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick, user->nick, user->ident, user->dhost, filename.c_str());
u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);
return 1;
}
}
else if ((type == "CHAT") && (blockchat))
{
user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick, u->nick);
u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick, user->nick, user->ident, user->dhost);
u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);
return 1;
}
}
}
}
return 0;
}
void Expire()
{
for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
{
userrec* u = (userrec*)(*iter);
u->GetExt("dccallow_list", dl);
if (dl)
{
if (dl->size())
{
dccallowlist::iterator iter = dl->begin();
while (iter != dl->end())
{
if ((iter->set_on + iter->length) <= ServerInstance->Time())
{
u->WriteServ("997 %s %s :DCCALLOW entry for %s has expired", u->nick, u->nick, iter->nickname.c_str());
iter = dl->erase(iter);
}
else
{
++iter;
}
}
}
}
else
{
RemoveFromUserlist(u);
}
}
}
void RemoveNick(userrec* user)
{
/* Iterate through all DCCALLOW lists and remove user */
for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
{
userrec *u = (userrec*)(*iter);
u->GetExt("dccallow_list", dl);
if (dl)
{
if (dl->size())
{
for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
{
if (i->nickname == user->nick)
{
u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick, i->nickname.c_str());
u->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", u->nick, u->nick, i->nickname.c_str());
dl->erase(i);
break;
}
}
}
}
else
{
RemoveFromUserlist(u);
}
}
}
void RemoveFromUserlist(userrec *user)
{
// remove user from userlist
for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
{
userrec* u = (userrec*)(*j);
if (u == user)
{
ul.erase(j);
break;
}
}
}
void ReadFileConf()
{
bfl.clear();
for (int i = 0; i < Conf->Enumerate("banfile"); i++)
{
BannedFileList bf;
std::string fileglob = Conf->ReadValue("banfile", "pattern", i);
std::string action = Conf->ReadValue("banfile", "action", i);
bf.filemask = fileglob;
bf.action = action;
bfl.push_back(bf);
}
}
virtual ~ModuleDCCAllow()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleDCCAllow)
\ No newline at end of file diff --git a/src/modules/m_deaf.cpp b/src/modules/m_deaf.cpp index ad8b31714..d9681010d 100644 --- a/src/modules/m_deaf.cpp +++ b/src/modules/m_deaf.cpp @@ -1,135 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for ircu style usermode +d (deaf to channel messages and channel notices) */ - -/** User mode +d - filter out channel messages and channel notices - */ -class User_d : public ModeHandler -{ - public: - User_d(InspIRCd* Instance) : ModeHandler(Instance, 'd', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('d')) - { - dest->WriteServ("NOTICE %s :*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode %s -d.", dest->nick, dest->nick); - dest->SetMode('d',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('d')) - { - dest->SetMode('d',false); - return MODEACTION_ALLOW; - } - } - return MODEACTION_DENY; - } -}; - -class ModuleDeaf : public Module -{ - User_d* m1; - public: - ModuleDeaf(InspIRCd* Me) - : Module(Me) - { - m1 = new User_d(ServerInstance); - if (!ServerInstance->AddMode(m1, 'd')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnBuildExemptList] = 1; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return PreText(user, dest, target_type, text, status, exempt_list); - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return PreText(user, dest, target_type, text, status, exempt_list); - } - - virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list) - { - CUList *ulist; - switch (status) - { - case '@': - ulist = chan->GetOppedUsers(); - break; - case '%': - ulist = chan->GetHalfoppedUsers(); - break; - case '+': - ulist = chan->GetVoicedUsers(); - break; - default: - ulist = chan->GetUsers(); - break; - } - - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - if (IS_LOCAL(i->first)) - { - if (i->first->IsModeSet('d')) - { - exempt_list[i->first] = i->first->nick; - } - } - } - } - - virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if ((target_type == TYPE_CHANNEL) & (IS_LOCAL(user))) - { - chanrec* chan = (chanrec*)dest; - if (chan) - { - this->OnBuildExemptList(MSG_PRIVMSG, chan, user, status, exempt_list); - } - } - return 0; - } - - virtual ~ModuleDeaf() - { - ServerInstance->Modes->DelMode(m1); - DELETE(m1); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleDeaf) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for ircu style usermode +d (deaf to channel messages and channel notices) */
/** User mode +d - filter out channel messages and channel notices
*/
class User_d : public ModeHandler
{
public:
User_d(InspIRCd* Instance) : ModeHandler(Instance, 'd', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!dest->IsModeSet('d'))
{
dest->WriteServ("NOTICE %s :*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode %s -d.", dest->nick, dest->nick);
dest->SetMode('d',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('d'))
{
dest->SetMode('d',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleDeaf : public Module
{
User_d* m1;
public:
ModuleDeaf(InspIRCd* Me)
: Module(Me)
{
m1 = new User_d(ServerInstance);
if (!ServerInstance->AddMode(m1, 'd'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnBuildExemptList] = 1;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return PreText(user, dest, target_type, text, status, exempt_list);
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return PreText(user, dest, target_type, text, status, exempt_list);
}
virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list)
{
CUList *ulist;
switch (status)
{
case '@':
ulist = chan->GetOppedUsers();
break;
case '%':
ulist = chan->GetHalfoppedUsers();
break;
case '+':
ulist = chan->GetVoicedUsers();
break;
default:
ulist = chan->GetUsers();
break;
}
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
if (IS_LOCAL(i->first))
{
if (i->first->IsModeSet('d'))
{
exempt_list[i->first] = i->first->nick;
}
}
}
}
virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if ((target_type == TYPE_CHANNEL) & (IS_LOCAL(user)))
{
chanrec* chan = (chanrec*)dest;
if (chan)
{
this->OnBuildExemptList(MSG_PRIVMSG, chan, user, status, exempt_list);
}
}
return 0;
}
virtual ~ModuleDeaf()
{
ServerInstance->Modes->DelMode(m1);
DELETE(m1);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleDeaf)
\ No newline at end of file diff --git a/src/modules/m_denychans.cpp b/src/modules/m_denychans.cpp index 4a01faa7c..d09e04766 100644 --- a/src/modules/m_denychans.cpp +++ b/src/modules/m_denychans.cpp @@ -1,80 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" -#include "wildcard.h" - -/* $ModDesc: Implements config tags which allow blocking of joins to channels */ - -class ModuleDenyChannels : public Module -{ - private: - - - ConfigReader *Conf; - - public: - ModuleDenyChannels(InspIRCd* Me) : Module(Me) - { - - Conf = new ConfigReader(ServerInstance); - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - DELETE(Conf); - Conf = new ConfigReader(ServerInstance); - } - - virtual ~ModuleDenyChannels() - { - DELETE(Conf); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserPreJoin] = List[I_OnRehash] = 1; - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - for (int j =0; j < Conf->Enumerate("badchan"); j++) - { - if (match(cname, Conf->ReadValue("badchan","name",j).c_str())) - { - if (IS_OPER(user) && Conf->ReadFlag("badchan","allowopers",j)) - { - return 0; - } - else - { - std::string reason = Conf->ReadValue("badchan","reason",j); - user->WriteServ("926 %s %s :Channel %s is forbidden: %s",user->nick,cname,cname,reason.c_str()); - return 1; - } - } - } - return 0; - } -}; - -MODULE_INIT(ModuleDenyChannels) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
#include "wildcard.h"
/* $ModDesc: Implements config tags which allow blocking of joins to channels */
class ModuleDenyChannels : public Module
{
private:
ConfigReader *Conf;
public:
ModuleDenyChannels(InspIRCd* Me) : Module(Me)
{
Conf = new ConfigReader(ServerInstance);
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
DELETE(Conf);
Conf = new ConfigReader(ServerInstance);
}
virtual ~ModuleDenyChannels()
{
DELETE(Conf);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserPreJoin] = List[I_OnRehash] = 1;
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
for (int j =0; j < Conf->Enumerate("badchan"); j++)
{
if (match(cname, Conf->ReadValue("badchan","name",j).c_str()))
{
if (IS_OPER(user) && Conf->ReadFlag("badchan","allowopers",j))
{
return 0;
}
else
{
std::string reason = Conf->ReadValue("badchan","reason",j);
user->WriteServ("926 %s %s :Channel %s is forbidden: %s",user->nick,cname,cname,reason.c_str());
return 1;
}
}
}
return 0;
}
};
MODULE_INIT(ModuleDenyChannels)
\ No newline at end of file diff --git a/src/modules/m_devoice.cpp b/src/modules/m_devoice.cpp index e2ada413b..e760db859 100644 --- a/src/modules/m_devoice.cpp +++ b/src/modules/m_devoice.cpp @@ -1,81 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* - * DEVOICE module for InspIRCd - * Syntax: /DEVOICE <#chan> - */ - -/* $ModDesc: Provides voiced users with the ability to devoice themselves. */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/** Handle /DEVOICE - */ -class cmd_devoice : public command_t -{ - public: - cmd_devoice (InspIRCd* Instance) : command_t(Instance,"DEVOICE", 0, 1) - { - this->source = "m_devoice.so"; - syntax = "<channel>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - chanrec* c = ServerInstance->FindChan(parameters[0]); - if (c && c->HasUser(user)) - { - const char* modes[3]; - modes[0] = parameters[0]; - modes[1] = "-v"; - modes[2] = user->nick; - - userrec* n = new userrec(ServerInstance); - n->SetFd(FD_MAGIC_NUMBER); - ServerInstance->SendMode(modes,3,n); - delete n; - - /* route it */ - return CMD_SUCCESS; - } - - return CMD_FAILURE; - } -}; - -class ModuleDeVoice : public Module -{ - cmd_devoice *mycommand; - public: - ModuleDeVoice(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_devoice(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleDeVoice() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleDeVoice) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/*
* DEVOICE module for InspIRCd
* Syntax: /DEVOICE <#chan>
*/
/* $ModDesc: Provides voiced users with the ability to devoice themselves. */
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/** Handle /DEVOICE
*/
class cmd_devoice : public command_t
{
public:
cmd_devoice (InspIRCd* Instance) : command_t(Instance,"DEVOICE", 0, 1)
{
this->source = "m_devoice.so";
syntax = "<channel>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
chanrec* c = ServerInstance->FindChan(parameters[0]);
if (c && c->HasUser(user))
{
const char* modes[3];
modes[0] = parameters[0];
modes[1] = "-v";
modes[2] = user->nick;
userrec* n = new userrec(ServerInstance);
n->SetFd(FD_MAGIC_NUMBER);
ServerInstance->SendMode(modes,3,n);
delete n;
/* route it */
return CMD_SUCCESS;
}
return CMD_FAILURE;
}
};
class ModuleDeVoice : public Module
{
cmd_devoice *mycommand;
public:
ModuleDeVoice(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_devoice(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleDeVoice()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleDeVoice)
\ No newline at end of file diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index d07b268f7..87e9a2cba 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -1,353 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "xline.h" -#include "dns.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -#ifndef WINDOWS -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif - -/* $ModDesc: Provides handling of DNS blacklists */ - -/* Class holding data for a single entry */ -class DNSBLConfEntry -{ - public: - enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE }; - std::string name, domain, reason; - EnumBanaction banaction; - long duration; - int bitmask; - unsigned long stats_hits, stats_misses; - DNSBLConfEntry(): duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {} - ~DNSBLConfEntry() { } -}; - - -/** Resolver for CGI:IRC hostnames encoded in ident/GECOS - */ -class DNSBLResolver : public Resolver -{ - int theirfd; - userrec* them; - DNSBLConfEntry *ConfEntry; - - public: - - DNSBLResolver(Module *me, InspIRCd *ServerInstance, const std::string &hostname, userrec* u, int userfd, DNSBLConfEntry *conf, bool &cached) - : Resolver(ServerInstance, hostname, DNS_QUERY_A, cached, me) - { - theirfd = userfd; - them = u; - ConfEntry = conf; - } - - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) - { - /* Check the user still exists */ - if ((them) && (them == ServerInstance->SE->GetRef(theirfd))) - { - // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d - if(result.length()) - { - unsigned int bitmask = 0; - bool show = false; - in_addr resultip; - - /* Convert the result to an in_addr (we can gaurantee we got ipv4) - * Whoever did the loop that was here before, I AM CONFISCATING - * YOUR CRACKPIPE. you know who you are. -- Brain - */ - inet_aton(result.c_str(), &resultip); - bitmask = resultip.s_addr >> 24; /* Last octet (network byte order */ - - bitmask &= ConfEntry->bitmask; - - if (bitmask != 0) - { - std::string reason = ConfEntry->reason; - std::string::size_type x = reason.find("%ip%"); - while (x != std::string::npos) - { - reason.erase(x, 4); - reason.insert(x, them->GetIPString()); - x = reason.find("%ip%"); - } - - ConfEntry->stats_hits++; - - switch (ConfEntry->banaction) - { - case DNSBLConfEntry::I_KILL: - { - userrec::QuitUser(ServerInstance, them, std::string("Killed (") + reason + ")"); - break; - } - case DNSBLConfEntry::I_KLINE: - { - std::string ban = std::string("*@") + them->GetIPString(); - if (show) - ServerInstance->XLines->apply_lines(APPLY_KLINES); - show = ServerInstance->XLines->add_kline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str()); - FOREACH_MOD(I_OnAddKLine,OnAddKLine(ConfEntry->duration, NULL, reason, ban)); - break; - } - case DNSBLConfEntry::I_GLINE: - { - std::string ban = std::string("*@") + them->GetIPString(); - show = ServerInstance->XLines->add_gline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str()); - if (show) - ServerInstance->XLines->apply_lines(APPLY_GLINES); - FOREACH_MOD(I_OnAddGLine,OnAddGLine(ConfEntry->duration, NULL, reason, ban)); - break; - } - case DNSBLConfEntry::I_ZLINE: - { - show = ServerInstance->XLines->add_zline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), them->GetIPString()); - if (show) - ServerInstance->XLines->apply_lines(APPLY_ZLINES); - FOREACH_MOD(I_OnAddZLine,OnAddZLine(ConfEntry->duration, NULL, reason, them->GetIPString())); - break; - } - case DNSBLConfEntry::I_UNKNOWN: - { - break; - } - break; - } - - if (show) - { - ServerInstance->WriteOpers("*** Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost(), ConfEntry->name.c_str(), bitmask); - } - } - else - ConfEntry->stats_misses++; - } - else - ConfEntry->stats_misses++; - } - } - - virtual void OnError(ResolverError e, const std::string &errormessage) - { - } - - virtual ~DNSBLResolver() - { - } -}; - -class ModuleDNSBL : public Module -{ - private: - std::vector<DNSBLConfEntry *> DNSBLConfEntries; - - /* - * Convert a string to EnumBanaction - */ - DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action) - { - if(action.compare("KILL")==0) - return DNSBLConfEntry::I_KILL; - if(action.compare("KLINE")==0) - return DNSBLConfEntry::I_KLINE; - if(action.compare("ZLINE")==0) - return DNSBLConfEntry::I_ZLINE; - if(action.compare("GLINE")==0) - return DNSBLConfEntry::I_GLINE; - - return DNSBLConfEntry::I_UNKNOWN; - } - public: - ModuleDNSBL(InspIRCd *Me) : Module(Me) - { - ReadConf(); - } - - virtual ~ModuleDNSBL() - { - ClearEntries(); - } - - virtual Version GetVersion() - { - return Version(2, 0, 0, 1, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnStats] = 1; - } - - /** Clear entries and free the mem it was using - */ - void ClearEntries() - { - std::vector<DNSBLConfEntry *>::iterator i; - for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++) - delete *i; - DNSBLConfEntries.clear(); - } - - /** Fill our conf vector with data - */ - virtual void ReadConf() - { - ConfigReader *MyConf = new ConfigReader(ServerInstance); - ClearEntries(); - - for (int i=0; i< MyConf->Enumerate("dnsbl"); i++) - { - DNSBLConfEntry *e = new DNSBLConfEntry(); - - e->name = MyConf->ReadValue("dnsbl", "name", i); - e->reason = MyConf->ReadValue("dnsbl", "reason", i); - e->domain = MyConf->ReadValue("dnsbl", "domain", i); - e->banaction = str2banaction(MyConf->ReadValue("dnsbl", "action", i)); - e->duration = ServerInstance->Duration(MyConf->ReadValue("dnsbl", "duration", i)); - e->bitmask = MyConf->ReadInteger("dnsbl", "bitmask", i, false); - - /* yeah, logic here is a little messy */ - if (e->bitmask <= 0) - { - ServerInstance->WriteOpers("*** DNSBL(#%d): invalid bitmask",i); - } - else if (e->name.empty()) - { - ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid name",i); - } - else if (e->domain.empty()) - { - ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid domain",i); - } - else if (e->banaction == DNSBLConfEntry::I_UNKNOWN) - { - ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid banaction", i); - } - else - { - if (e->reason.empty()) - { - ServerInstance->WriteOpers("*** DNSBL(#%d): empty reason, using defaults",i); - e->reason = "Your IP has been blacklisted."; - } - - /* add it, all is ok */ - DNSBLConfEntries.push_back(e); - continue; - } - - /* delete and drop it, error somewhere */ - delete e; - } - - delete MyConf; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ReadConf(); - } - - virtual int OnUserRegister(userrec* user) - { - /* only do lookups on local users */ - if (IS_LOCAL(user)) - { - /* following code taken from bopm, reverses an IP address. */ - struct in_addr in; - unsigned char a, b, c, d; - char reversedipbuf[128]; - std::string reversedip; - bool success = false; - - if (!inet_aton(user->GetIPString(), &in)) - { -#ifdef IPV6 - /* We could have an ipv6 address here */ - std::string x = user->GetIPString(); - /* Is it a 4in6 address? (Compensate for this kernel kludge that people love) */ - if (x.find("0::ffff:") == 0) - { - x.erase(x.begin(), x.begin() + 8); - if (inet_aton(x.c_str(), &in)) - success = true; - } -#endif - } - else - { - success = true; - } - - if (!success) - return 0; - - d = (unsigned char) (in.s_addr >> 24) & 0xFF; - c = (unsigned char) (in.s_addr >> 16) & 0xFF; - b = (unsigned char) (in.s_addr >> 8) & 0xFF; - a = (unsigned char) in.s_addr & 0xFF; - - snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a); - reversedip = std::string(reversedipbuf); - - // For each DNSBL, we will run through this lookup - for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++) - { - // Fill hostname with a dnsbl style host (d.c.b.a.domain.tld) - std::string hostname = reversedip + "." + (*i)->domain; - - /* now we'd need to fire off lookups for `hostname'. */ - bool cached; - DNSBLResolver *r = new DNSBLResolver(this, ServerInstance, hostname, user, user->GetFd(), *i, cached); - ServerInstance->AddResolver(r, cached); - } - } - - /* don't do anything with this hot potato */ - return 0; - } - - virtual int OnStats(char symbol, userrec* user, string_list &results) - { - if (symbol != 'd') - return 0; - - unsigned long total_hits = 0, total_misses = 0; - - for (std::vector<DNSBLConfEntry*>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++) - { - total_hits += (*i)->stats_hits; - total_misses += (*i)->stats_misses; - - results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " + - ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses"); - } - - results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits)); - results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses)); - - return 0; - } -}; - -MODULE_INIT(ModuleDNSBL) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "xline.h"
#include "dns.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#ifndef WINDOWS
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
/* $ModDesc: Provides handling of DNS blacklists */
/* Class holding data for a single entry */
class DNSBLConfEntry
{
public:
enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE };
std::string name, domain, reason;
EnumBanaction banaction;
long duration;
int bitmask;
unsigned long stats_hits, stats_misses;
DNSBLConfEntry(): duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {}
~DNSBLConfEntry() { }
};
/** Resolver for CGI:IRC hostnames encoded in ident/GECOS
*/
class DNSBLResolver : public Resolver
{
int theirfd;
userrec* them;
DNSBLConfEntry *ConfEntry;
public:
DNSBLResolver(Module *me, InspIRCd *ServerInstance, const std::string &hostname, userrec* u, int userfd, DNSBLConfEntry *conf, bool &cached)
: Resolver(ServerInstance, hostname, DNS_QUERY_A, cached, me)
{
theirfd = userfd;
them = u;
ConfEntry = conf;
}
virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
{
/* Check the user still exists */
if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
{
// Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
if(result.length())
{
unsigned int bitmask = 0;
bool show = false;
in_addr resultip;
/* Convert the result to an in_addr (we can gaurantee we got ipv4)
* Whoever did the loop that was here before, I AM CONFISCATING
* YOUR CRACKPIPE. you know who you are. -- Brain
*/
inet_aton(result.c_str(), &resultip);
bitmask = resultip.s_addr >> 24; /* Last octet (network byte order */
bitmask &= ConfEntry->bitmask;
if (bitmask != 0)
{
std::string reason = ConfEntry->reason;
std::string::size_type x = reason.find("%ip%");
while (x != std::string::npos)
{
reason.erase(x, 4);
reason.insert(x, them->GetIPString());
x = reason.find("%ip%");
}
ConfEntry->stats_hits++;
switch (ConfEntry->banaction)
{
case DNSBLConfEntry::I_KILL:
{
userrec::QuitUser(ServerInstance, them, std::string("Killed (") + reason + ")");
break;
}
case DNSBLConfEntry::I_KLINE:
{
std::string ban = std::string("*@") + them->GetIPString();
if (show)
ServerInstance->XLines->apply_lines(APPLY_KLINES);
show = ServerInstance->XLines->add_kline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());
FOREACH_MOD(I_OnAddKLine,OnAddKLine(ConfEntry->duration, NULL, reason, ban));
break;
}
case DNSBLConfEntry::I_GLINE:
{
std::string ban = std::string("*@") + them->GetIPString();
show = ServerInstance->XLines->add_gline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());
if (show)
ServerInstance->XLines->apply_lines(APPLY_GLINES);
FOREACH_MOD(I_OnAddGLine,OnAddGLine(ConfEntry->duration, NULL, reason, ban));
break;
}
case DNSBLConfEntry::I_ZLINE:
{
show = ServerInstance->XLines->add_zline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), them->GetIPString());
if (show)
ServerInstance->XLines->apply_lines(APPLY_ZLINES);
FOREACH_MOD(I_OnAddZLine,OnAddZLine(ConfEntry->duration, NULL, reason, them->GetIPString()));
break;
}
case DNSBLConfEntry::I_UNKNOWN:
{
break;
}
break;
}
if (show)
{
ServerInstance->WriteOpers("*** Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost(), ConfEntry->name.c_str(), bitmask);
}
}
else
ConfEntry->stats_misses++;
}
else
ConfEntry->stats_misses++;
}
}
virtual void OnError(ResolverError e, const std::string &errormessage)
{
}
virtual ~DNSBLResolver()
{
}
};
class ModuleDNSBL : public Module
{
private:
std::vector<DNSBLConfEntry *> DNSBLConfEntries;
/*
* Convert a string to EnumBanaction
*/
DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action)
{
if(action.compare("KILL")==0)
return DNSBLConfEntry::I_KILL;
if(action.compare("KLINE")==0)
return DNSBLConfEntry::I_KLINE;
if(action.compare("ZLINE")==0)
return DNSBLConfEntry::I_ZLINE;
if(action.compare("GLINE")==0)
return DNSBLConfEntry::I_GLINE;
return DNSBLConfEntry::I_UNKNOWN;
}
public:
ModuleDNSBL(InspIRCd *Me) : Module(Me)
{
ReadConf();
}
virtual ~ModuleDNSBL()
{
ClearEntries();
}
virtual Version GetVersion()
{
return Version(2, 0, 0, 1, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnStats] = 1;
}
/** Clear entries and free the mem it was using
*/
void ClearEntries()
{
std::vector<DNSBLConfEntry *>::iterator i;
for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
delete *i;
DNSBLConfEntries.clear();
}
/** Fill our conf vector with data
*/
virtual void ReadConf()
{
ConfigReader *MyConf = new ConfigReader(ServerInstance);
ClearEntries();
for (int i=0; i< MyConf->Enumerate("dnsbl"); i++)
{
DNSBLConfEntry *e = new DNSBLConfEntry();
e->name = MyConf->ReadValue("dnsbl", "name", i);
e->reason = MyConf->ReadValue("dnsbl", "reason", i);
e->domain = MyConf->ReadValue("dnsbl", "domain", i);
e->banaction = str2banaction(MyConf->ReadValue("dnsbl", "action", i));
e->duration = ServerInstance->Duration(MyConf->ReadValue("dnsbl", "duration", i));
e->bitmask = MyConf->ReadInteger("dnsbl", "bitmask", i, false);
/* yeah, logic here is a little messy */
if (e->bitmask <= 0)
{
ServerInstance->WriteOpers("*** DNSBL(#%d): invalid bitmask",i);
}
else if (e->name.empty())
{
ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid name",i);
}
else if (e->domain.empty())
{
ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid domain",i);
}
else if (e->banaction == DNSBLConfEntry::I_UNKNOWN)
{
ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid banaction", i);
}
else
{
if (e->reason.empty())
{
ServerInstance->WriteOpers("*** DNSBL(#%d): empty reason, using defaults",i);
e->reason = "Your IP has been blacklisted.";
}
/* add it, all is ok */
DNSBLConfEntries.push_back(e);
continue;
}
/* delete and drop it, error somewhere */
delete e;
}
delete MyConf;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadConf();
}
virtual int OnUserRegister(userrec* user)
{
/* only do lookups on local users */
if (IS_LOCAL(user))
{
/* following code taken from bopm, reverses an IP address. */
struct in_addr in;
unsigned char a, b, c, d;
char reversedipbuf[128];
std::string reversedip;
bool success = false;
if (!inet_aton(user->GetIPString(), &in))
{
#ifdef IPV6
/* We could have an ipv6 address here */
std::string x = user->GetIPString();
/* Is it a 4in6 address? (Compensate for this kernel kludge that people love) */
if (x.find("0::ffff:") == 0)
{
x.erase(x.begin(), x.begin() + 8);
if (inet_aton(x.c_str(), &in))
success = true;
}
#endif
}
else
{
success = true;
}
if (!success)
return 0;
d = (unsigned char) (in.s_addr >> 24) & 0xFF;
c = (unsigned char) (in.s_addr >> 16) & 0xFF;
b = (unsigned char) (in.s_addr >> 8) & 0xFF;
a = (unsigned char) in.s_addr & 0xFF;
snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a);
reversedip = std::string(reversedipbuf);
// For each DNSBL, we will run through this lookup
for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
{
// Fill hostname with a dnsbl style host (d.c.b.a.domain.tld)
std::string hostname = reversedip + "." + (*i)->domain;
/* now we'd need to fire off lookups for `hostname'. */
bool cached;
DNSBLResolver *r = new DNSBLResolver(this, ServerInstance, hostname, user, user->GetFd(), *i, cached);
ServerInstance->AddResolver(r, cached);
}
}
/* don't do anything with this hot potato */
return 0;
}
virtual int OnStats(char symbol, userrec* user, string_list &results)
{
if (symbol != 'd')
return 0;
unsigned long total_hits = 0, total_misses = 0;
for (std::vector<DNSBLConfEntry*>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
{
total_hits += (*i)->stats_hits;
total_misses += (*i)->stats_misses;
results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " +
ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses");
}
results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits));
results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses));
return 0;
}
};
MODULE_INIT(ModuleDNSBL)
\ No newline at end of file diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp index 70de88e2c..9c16c8bf3 100644 --- a/src/modules/m_filter.cpp +++ b/src/modules/m_filter.cpp @@ -1,135 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_filter.h" - -/* $ModDesc: An advanced spam filtering module */ -/* $ModDep: m_filter.h */ - -typedef std::map<std::string,FilterResult*> filter_t; - -class ModuleFilter : public FilterBase -{ - - filter_t filters; - - public: - ModuleFilter(InspIRCd* Me) - : FilterBase(Me, "m_filter.so") - { - OnRehash(NULL,""); - } - - virtual ~ModuleFilter() - { - } - - virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags) - { - for (filter_t::iterator index = filters.begin(); index != filters.end(); index++) - { - - /* Skip ones that dont apply to us */ - if (!FilterBase::AppliesToMe(user, index->second, flags)) - continue; - - if (ServerInstance->MatchText(text,index->first)) - { - FilterResult* fr = index->second; - if (index != filters.begin()) - { - std::string pat = index->first; - filters.erase(index); - filters.insert(filters.begin(), std::make_pair(pat,fr)); - } - return fr; - } - } - return NULL; - } - - virtual bool DeleteFilter(const std::string &freeform) - { - if (filters.find(freeform) != filters.end()) - { - delete (filters.find(freeform))->second; - filters.erase(filters.find(freeform)); - return true; - } - return false; - } - - virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags) - { - if (filters.find(freeform) != filters.end()) - { - return std::make_pair(false, "Filter already exists"); - } - - FilterResult* x = new FilterResult(freeform, reason, type, duration, flags); - filters[freeform] = x; - - return std::make_pair(true, ""); - } - - virtual void SyncFilters(Module* proto, void* opaque) - { - for (filter_t::iterator n = filters.begin(); n != filters.end(); n++) - { - this->SendFilter(proto, opaque, n->second); - } - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader* MyConf = new ConfigReader(ServerInstance); - - for (int index = 0; index < MyConf->Enumerate("keyword"); index++) - { - this->DeleteFilter(MyConf->ReadValue("keyword","pattern",index)); - - std::string pattern = MyConf->ReadValue("keyword","pattern",index); - std::string reason = MyConf->ReadValue("keyword","reason",index); - std::string do_action = MyConf->ReadValue("keyword","action",index); - std::string flags = MyConf->ReadValue("keyword","flags",index); - long gline_time = ServerInstance->Duration(MyConf->ReadValue("keyword","duration",index)); - if (do_action.empty()) - do_action = "none"; - if (flags.empty()) - flags = "*"; - FilterResult* x = new FilterResult(pattern, reason, do_action, gline_time, flags); - filters[pattern] = x; - } - DELETE(MyConf); - } - - virtual int OnStats(char symbol, userrec* user, string_list &results) - { - if (symbol == 's') - { - std::string sn = ServerInstance->Config->ServerName; - for (filter_t::iterator n = filters.begin(); n != filters.end(); n++) - { - results.push_back(sn+" 223 "+user->nick+" :GLOB:"+n->second->freeform+" "+n->second->flags+" "+n->second->action+" "+ConvToStr(n->second->gline_time)+" :"+n->second->reason); - } - } - return 0; - } -}; - - -MODULE_INIT(ModuleFilter) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_filter.h"
/* $ModDesc: An advanced spam filtering module */
/* $ModDep: m_filter.h */
typedef std::map<std::string,FilterResult*> filter_t;
class ModuleFilter : public FilterBase
{
filter_t filters;
public:
ModuleFilter(InspIRCd* Me)
: FilterBase(Me, "m_filter.so")
{
OnRehash(NULL,"");
}
virtual ~ModuleFilter()
{
}
virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags)
{
for (filter_t::iterator index = filters.begin(); index != filters.end(); index++)
{
/* Skip ones that dont apply to us */
if (!FilterBase::AppliesToMe(user, index->second, flags))
continue;
if (ServerInstance->MatchText(text,index->first))
{
FilterResult* fr = index->second;
if (index != filters.begin())
{
std::string pat = index->first;
filters.erase(index);
filters.insert(filters.begin(), std::make_pair(pat,fr));
}
return fr;
}
}
return NULL;
}
virtual bool DeleteFilter(const std::string &freeform)
{
if (filters.find(freeform) != filters.end())
{
delete (filters.find(freeform))->second;
filters.erase(filters.find(freeform));
return true;
}
return false;
}
virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags)
{
if (filters.find(freeform) != filters.end())
{
return std::make_pair(false, "Filter already exists");
}
FilterResult* x = new FilterResult(freeform, reason, type, duration, flags);
filters[freeform] = x;
return std::make_pair(true, "");
}
virtual void SyncFilters(Module* proto, void* opaque)
{
for (filter_t::iterator n = filters.begin(); n != filters.end(); n++)
{
this->SendFilter(proto, opaque, n->second);
}
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader* MyConf = new ConfigReader(ServerInstance);
for (int index = 0; index < MyConf->Enumerate("keyword"); index++)
{
this->DeleteFilter(MyConf->ReadValue("keyword","pattern",index));
std::string pattern = MyConf->ReadValue("keyword","pattern",index);
std::string reason = MyConf->ReadValue("keyword","reason",index);
std::string do_action = MyConf->ReadValue("keyword","action",index);
std::string flags = MyConf->ReadValue("keyword","flags",index);
long gline_time = ServerInstance->Duration(MyConf->ReadValue("keyword","duration",index));
if (do_action.empty())
do_action = "none";
if (flags.empty())
flags = "*";
FilterResult* x = new FilterResult(pattern, reason, do_action, gline_time, flags);
filters[pattern] = x;
}
DELETE(MyConf);
}
virtual int OnStats(char symbol, userrec* user, string_list &results)
{
if (symbol == 's')
{
std::string sn = ServerInstance->Config->ServerName;
for (filter_t::iterator n = filters.begin(); n != filters.end(); n++)
{
results.push_back(sn+" 223 "+user->nick+" :GLOB:"+n->second->freeform+" "+n->second->flags+" "+n->second->action+" "+ConvToStr(n->second->gline_time)+" :"+n->second->reason);
}
}
return 0;
}
};
MODULE_INIT(ModuleFilter)
\ No newline at end of file diff --git a/src/modules/m_filter.h b/src/modules/m_filter.h index f2986804c..ddf448e2e 100644 --- a/src/modules/m_filter.h +++ b/src/modules/m_filter.h @@ -1,453 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "xline.h" - -enum FilterFlags -{ - FLAG_NOOPERS = 1, - FLAG_PART = 2, - FLAG_QUIT = 4, - FLAG_PRIVMSG = 8, - FLAG_NOTICE = 16 -}; - -class FilterResult : public classbase -{ - public: - std::string freeform; - std::string reason; - std::string action; - long gline_time; - std::string flags; - - bool flag_no_opers; - bool flag_part_message; - bool flag_quit_message; - bool flag_privmsg; - bool flag_notice; - - FilterResult(const std::string free, const std::string &rea, const std::string &act, long gt, const std::string &fla) : freeform(free), reason(rea), - action(act), gline_time(gt), flags(fla) - { - this->FillFlags(flags); - } - - int FillFlags(const std::string &fl) - { - flags = fl; - flag_no_opers = flag_part_message = flag_quit_message = flag_privmsg = flag_notice = false; - size_t x = 0; - - for (std::string::const_iterator n = flags.begin(); n != flags.end(); ++n, ++x) - { - switch (*n) - { - case 'o': - flag_no_opers = true; - break; - case 'P': - flag_part_message = true; - break; - case 'q': - flag_quit_message = true; - break; - case 'p': - flag_privmsg = true; - break; - case 'n': - flag_notice = true; - break; - case '*': - flag_no_opers = flag_part_message = flag_quit_message = - flag_privmsg = flag_notice = true; - break; - default: - return x; - break; - } - } - return 0; - } - - FilterResult() - { - } - - virtual ~FilterResult() - { - } -}; - -class cmd_filter; - -class FilterBase : public Module -{ - cmd_filter* filtcommand; - int flags; - public: - FilterBase(InspIRCd* Me, const std::string &source); - virtual ~FilterBase(); - virtual void Implements(char* List); - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list); - virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags) = 0; - virtual bool DeleteFilter(const std::string &freeform) = 0; - virtual void SyncFilters(Module* proto, void* opaque) = 0; - virtual void SendFilter(Module* proto, void* opaque, FilterResult* iter); - virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags) = 0; - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list); - virtual void OnRehash(userrec* user, const std::string ¶meter); - virtual Version GetVersion(); - std::string EncodeFilter(FilterResult* filter); - FilterResult DecodeFilter(const std::string &data); - virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false); - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata); - virtual int OnStats(char symbol, userrec* user, string_list &results) = 0; - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line); - bool AppliesToMe(userrec* user, FilterResult* filter, int flags); -}; - -class cmd_filter : public command_t -{ - FilterBase* Base; - public: - cmd_filter(FilterBase* f, InspIRCd* Me, const std::string &source) : command_t(Me, "FILTER", 'o', 1), Base(f) - { - this->source = source; - this->syntax = "<filter-definition> <type> <flags> [<gline-duration>] :<reason>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - if (pcnt == 1) - { - /* Deleting a filter */ - if (Base->DeleteFilter(parameters[0])) - { - user->WriteServ("NOTICE %s :*** Deleted filter '%s'", user->nick, parameters[0]); - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE %s :*** Filter '%s' not found on list.", user->nick, parameters[0]); - return CMD_FAILURE; - } - } - else - { - /* Adding a filter */ - if (pcnt >= 4) - { - std::string freeform = parameters[0]; - std::string type = parameters[1]; - std::string flags = parameters[2]; - std::string reason; - long duration = 0; - - - if ((type != "gline") && (type != "none") && (type != "block") && (type != "kill") && (type != "silent")) - { - user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.", user->nick, freeform.c_str()); - return CMD_FAILURE; - } - - if (type == "gline") - { - if (pcnt >= 5) - { - duration = ServerInstance->Duration(parameters[3]); - reason = parameters[4]; - } - else - { - this->TooFewParams(user, " When setting a gline type filter, a gline duration must be specified as the third parameter."); - return CMD_FAILURE; - } - } - else - { - reason = parameters[3]; - } - std::pair<bool, std::string> result = Base->AddFilter(freeform, type, reason, duration, flags); - if (result.first) - { - user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick, freeform.c_str(), - type.c_str(), (duration ? " duration: " : ""), (duration ? parameters[3] : ""), - flags.c_str(), reason.c_str()); - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick, freeform.c_str(), result.second.c_str()); - return CMD_FAILURE; - } - } - else - { - this->TooFewParams(user, "."); - return CMD_FAILURE; - } - - } - } - - void TooFewParams(userrec* user, const std::string &extra_text) - { - user->WriteServ("NOTICE %s :*** Not enough parameters%s", user->nick, extra_text.c_str()); - } -}; - -bool FilterBase::AppliesToMe(userrec* user, FilterResult* filter, int flags) -{ - if ((flags & FLAG_NOOPERS) && (filter->flag_no_opers) && IS_OPER(user)) - return false; - if ((flags & FLAG_PRIVMSG) && (!filter->flag_privmsg)) - return false; - if ((flags & FLAG_NOTICE) && (!filter->flag_notice)) - return false; - if ((flags & FLAG_QUIT) && (!filter->flag_quit_message)) - return false; - if ((flags & FLAG_PART) && (!filter->flag_part_message)) - return false; - return true; -} - -FilterBase::FilterBase(InspIRCd* Me, const std::string &source) : Module(Me) -{ - filtcommand = new cmd_filter(this, Me, source); - ServerInstance->AddCommand(filtcommand); -} - -FilterBase::~FilterBase() -{ -} - -void FilterBase::Implements(char* List) -{ - List[I_OnPreCommand] = List[I_OnStats] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1; -} - -int FilterBase::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) -{ - flags = FLAG_PRIVMSG; - return OnUserPreNotice(user,dest,target_type,text,status,exempt_list); -} - -int FilterBase::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) -{ - if (!flags) - flags = FLAG_NOTICE; - - /* Leave ulines alone */ - if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user))) - return 0; - - FilterResult* f = this->FilterMatch(user, text, flags); - if (f) - { - std::string target = ""; - if (target_type == TYPE_USER) - { - userrec* t = (userrec*)dest; - target = std::string(t->nick); - } - else if (target_type == TYPE_CHANNEL) - { - chanrec* t = (chanrec*)dest; - target = std::string(t->name); - } - if (f->action == "block") - { - ServerInstance->WriteOpers(std::string("FILTER: ")+user->nick+" had their message filtered, target was "+target+": "+f->reason); - user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered and opers notified: "+f->reason); - } - if (f->action == "silent") - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered: "+f->reason); - } - if (f->action == "kill") - { - userrec::QuitUser(ServerInstance,user,"Filtered: "+f->reason); - } - if (f->action == "gline") - { - if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), user->MakeHostIP())) - { - ServerInstance->XLines->apply_lines(APPLY_GLINES); - FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP())); - } - } - - ServerInstance->Log(DEFAULT,"FILTER: "+std::string(user->nick)+std::string(" had their message filtered, target was ")+target+": "+f->reason+" Action: "+f->action); - return 1; - } - return 0; -} - -int FilterBase::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) -{ - flags = 0; - if ((validated == 1) && (IS_LOCAL(user))) - { - std::string checkline; - int replacepoint = 0; - bool parting = false; - - if (command == "QUIT") - { - /* QUIT with no reason: nothing to do */ - if (pcnt < 1) - return 0; - - checkline = parameters[0]; - replacepoint = 0; - parting = false; - flags = FLAG_QUIT; - } - else if (command == "PART") - { - /* PART with no reason: nothing to do */ - if (pcnt < 2) - return 0; - - checkline = parameters[1]; - replacepoint = 1; - parting = true; - flags = FLAG_PART; - } - else - /* We're only messing with PART and QUIT */ - return 0; - - FilterResult* f = NULL; - - if (flags) - f = this->FilterMatch(user, checkline, flags); - - if (!f) - /* PART or QUIT reason doesnt match a filter */ - return 0; - - /* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */ - command_t* c = ServerInstance->Parser->GetHandler(command); - if (c) - { - const char* params[127]; - for (int item = 0; item < pcnt; item++) - params[item] = parameters[item]; - params[replacepoint] = "Reason filtered"; - - /* We're blocking, OR theyre quitting and its a KILL action - * (we cant kill someone whos already quitting, so filter them anyway) - */ - if ((f->action == "block") || (((!parting) && (f->action == "kill"))) || (f->action == "silent")) - { - c->Handle(params, pcnt, user); - return 1; - } - else - { - /* Are they parting, if so, kill is applicable */ - if ((parting) && (f->action == "kill")) - { - user->SetWriteError("Filtered: "+f->reason); - /* This WriteServ causes the write error to be applied. - * Its not safe to kill here with QuitUser in a PreCommand handler, - * so we do it this way, which is safe just about anywhere. - */ - user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick, f->reason.c_str()); - } - if (f->action == "gline") - { - /* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */ - std::string wild = "*@"; - wild.append(user->GetIPString()); - - if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), wild.c_str())) - { - ServerInstance->XLines->apply_lines(APPLY_GLINES); - FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP())); - } - } - return 1; - } - } - return 0; - } - return 0; -} - -void FilterBase::OnRehash(userrec* user, const std::string ¶meter) -{ -} - -Version FilterBase::GetVersion() -{ - return Version(1,1,0,2,VF_VENDOR|VF_COMMON,API_VERSION); -} - - -std::string FilterBase::EncodeFilter(FilterResult* filter) -{ - std::ostringstream stream; - std::string x = filter->freeform; - - /* Hax to allow spaces in the freeform without changing the design of the irc protocol */ - for (std::string::iterator n = x.begin(); n != x.end(); n++) - if (*n == ' ') - *n = '\7'; - - stream << x << " " << filter->action << " " << (filter->flags.empty() ? "-" : filter->flags) << " " << filter->gline_time << " :" << filter->reason; - return stream.str(); -} - -FilterResult FilterBase::DecodeFilter(const std::string &data) -{ - FilterResult res; - irc::tokenstream tokens(data); - tokens.GetToken(res.freeform); - tokens.GetToken(res.action); - tokens.GetToken(res.flags); - if (res.flags == "-") - res.flags = ""; - res.FillFlags(res.flags); - tokens.GetToken(res.gline_time); - tokens.GetToken(res.reason); - - /* Hax to allow spaces in the freeform without changing the design of the irc protocol */ - for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++) - if (*n == '\7') - *n = ' '; - - return res; -} - -void FilterBase::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable) -{ - this->SyncFilters(proto, opaque); -} - -void FilterBase::SendFilter(Module* proto, void* opaque, FilterResult* iter) -{ - proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "filter", EncodeFilter(iter)); -} - -void FilterBase::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) -{ - if ((target_type == TYPE_OTHER) && (extname == "filter")) - { - FilterResult data = DecodeFilter(extdata); - this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.flags); - } -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "xline.h"
enum FilterFlags
{
FLAG_NOOPERS = 1,
FLAG_PART = 2,
FLAG_QUIT = 4,
FLAG_PRIVMSG = 8,
FLAG_NOTICE = 16
};
class FilterResult : public classbase
{
public:
std::string freeform;
std::string reason;
std::string action;
long gline_time;
std::string flags;
bool flag_no_opers;
bool flag_part_message;
bool flag_quit_message;
bool flag_privmsg;
bool flag_notice;
FilterResult(const std::string free, const std::string &rea, const std::string &act, long gt, const std::string &fla) : freeform(free), reason(rea),
action(act), gline_time(gt), flags(fla)
{
this->FillFlags(flags);
}
int FillFlags(const std::string &fl)
{
flags = fl;
flag_no_opers = flag_part_message = flag_quit_message = flag_privmsg = flag_notice = false;
size_t x = 0;
for (std::string::const_iterator n = flags.begin(); n != flags.end(); ++n, ++x)
{
switch (*n)
{
case 'o':
flag_no_opers = true;
break;
case 'P':
flag_part_message = true;
break;
case 'q':
flag_quit_message = true;
break;
case 'p':
flag_privmsg = true;
break;
case 'n':
flag_notice = true;
break;
case '*':
flag_no_opers = flag_part_message = flag_quit_message =
flag_privmsg = flag_notice = true;
break;
default:
return x;
break;
}
}
return 0;
}
FilterResult()
{
}
virtual ~FilterResult()
{
}
};
class cmd_filter;
class FilterBase : public Module
{
cmd_filter* filtcommand;
int flags;
public:
FilterBase(InspIRCd* Me, const std::string &source);
virtual ~FilterBase();
virtual void Implements(char* List);
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags) = 0;
virtual bool DeleteFilter(const std::string &freeform) = 0;
virtual void SyncFilters(Module* proto, void* opaque) = 0;
virtual void SendFilter(Module* proto, void* opaque, FilterResult* iter);
virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags) = 0;
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
virtual void OnRehash(userrec* user, const std::string ¶meter);
virtual Version GetVersion();
std::string EncodeFilter(FilterResult* filter);
FilterResult DecodeFilter(const std::string &data);
virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false);
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata);
virtual int OnStats(char symbol, userrec* user, string_list &results) = 0;
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);
bool AppliesToMe(userrec* user, FilterResult* filter, int flags);
};
class cmd_filter : public command_t
{
FilterBase* Base;
public:
cmd_filter(FilterBase* f, InspIRCd* Me, const std::string &source) : command_t(Me, "FILTER", 'o', 1), Base(f)
{
this->source = source;
this->syntax = "<filter-definition> <type> <flags> [<gline-duration>] :<reason>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
if (pcnt == 1)
{
/* Deleting a filter */
if (Base->DeleteFilter(parameters[0]))
{
user->WriteServ("NOTICE %s :*** Deleted filter '%s'", user->nick, parameters[0]);
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE %s :*** Filter '%s' not found on list.", user->nick, parameters[0]);
return CMD_FAILURE;
}
}
else
{
/* Adding a filter */
if (pcnt >= 4)
{
std::string freeform = parameters[0];
std::string type = parameters[1];
std::string flags = parameters[2];
std::string reason;
long duration = 0;
if ((type != "gline") && (type != "none") && (type != "block") && (type != "kill") && (type != "silent"))
{
user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.", user->nick, freeform.c_str());
return CMD_FAILURE;
}
if (type == "gline")
{
if (pcnt >= 5)
{
duration = ServerInstance->Duration(parameters[3]);
reason = parameters[4];
}
else
{
this->TooFewParams(user, " When setting a gline type filter, a gline duration must be specified as the third parameter.");
return CMD_FAILURE;
}
}
else
{
reason = parameters[3];
}
std::pair<bool, std::string> result = Base->AddFilter(freeform, type, reason, duration, flags);
if (result.first)
{
user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick, freeform.c_str(),
type.c_str(), (duration ? " duration: " : ""), (duration ? parameters[3] : ""),
flags.c_str(), reason.c_str());
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick, freeform.c_str(), result.second.c_str());
return CMD_FAILURE;
}
}
else
{
this->TooFewParams(user, ".");
return CMD_FAILURE;
}
}
}
void TooFewParams(userrec* user, const std::string &extra_text)
{
user->WriteServ("NOTICE %s :*** Not enough parameters%s", user->nick, extra_text.c_str());
}
};
bool FilterBase::AppliesToMe(userrec* user, FilterResult* filter, int flags)
{
if ((flags & FLAG_NOOPERS) && (filter->flag_no_opers) && IS_OPER(user))
return false;
if ((flags & FLAG_PRIVMSG) && (!filter->flag_privmsg))
return false;
if ((flags & FLAG_NOTICE) && (!filter->flag_notice))
return false;
if ((flags & FLAG_QUIT) && (!filter->flag_quit_message))
return false;
if ((flags & FLAG_PART) && (!filter->flag_part_message))
return false;
return true;
}
FilterBase::FilterBase(InspIRCd* Me, const std::string &source) : Module(Me)
{
filtcommand = new cmd_filter(this, Me, source);
ServerInstance->AddCommand(filtcommand);
}
FilterBase::~FilterBase()
{
}
void FilterBase::Implements(char* List)
{
List[I_OnPreCommand] = List[I_OnStats] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1;
}
int FilterBase::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
flags = FLAG_PRIVMSG;
return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
}
int FilterBase::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (!flags)
flags = FLAG_NOTICE;
/* Leave ulines alone */
if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user)))
return 0;
FilterResult* f = this->FilterMatch(user, text, flags);
if (f)
{
std::string target = "";
if (target_type == TYPE_USER)
{
userrec* t = (userrec*)dest;
target = std::string(t->nick);
}
else if (target_type == TYPE_CHANNEL)
{
chanrec* t = (chanrec*)dest;
target = std::string(t->name);
}
if (f->action == "block")
{
ServerInstance->WriteOpers(std::string("FILTER: ")+user->nick+" had their message filtered, target was "+target+": "+f->reason);
user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered and opers notified: "+f->reason);
}
if (f->action == "silent")
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered: "+f->reason);
}
if (f->action == "kill")
{
userrec::QuitUser(ServerInstance,user,"Filtered: "+f->reason);
}
if (f->action == "gline")
{
if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), user->MakeHostIP()))
{
ServerInstance->XLines->apply_lines(APPLY_GLINES);
FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));
}
}
ServerInstance->Log(DEFAULT,"FILTER: "+std::string(user->nick)+std::string(" had their message filtered, target was ")+target+": "+f->reason+" Action: "+f->action);
return 1;
}
return 0;
}
int FilterBase::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
flags = 0;
if ((validated == 1) && (IS_LOCAL(user)))
{
std::string checkline;
int replacepoint = 0;
bool parting = false;
if (command == "QUIT")
{
/* QUIT with no reason: nothing to do */
if (pcnt < 1)
return 0;
checkline = parameters[0];
replacepoint = 0;
parting = false;
flags = FLAG_QUIT;
}
else if (command == "PART")
{
/* PART with no reason: nothing to do */
if (pcnt < 2)
return 0;
checkline = parameters[1];
replacepoint = 1;
parting = true;
flags = FLAG_PART;
}
else
/* We're only messing with PART and QUIT */
return 0;
FilterResult* f = NULL;
if (flags)
f = this->FilterMatch(user, checkline, flags);
if (!f)
/* PART or QUIT reason doesnt match a filter */
return 0;
/* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */
command_t* c = ServerInstance->Parser->GetHandler(command);
if (c)
{
const char* params[127];
for (int item = 0; item < pcnt; item++)
params[item] = parameters[item];
params[replacepoint] = "Reason filtered";
/* We're blocking, OR theyre quitting and its a KILL action
* (we cant kill someone whos already quitting, so filter them anyway)
*/
if ((f->action == "block") || (((!parting) && (f->action == "kill"))) || (f->action == "silent"))
{
c->Handle(params, pcnt, user);
return 1;
}
else
{
/* Are they parting, if so, kill is applicable */
if ((parting) && (f->action == "kill"))
{
user->SetWriteError("Filtered: "+f->reason);
/* This WriteServ causes the write error to be applied.
* Its not safe to kill here with QuitUser in a PreCommand handler,
* so we do it this way, which is safe just about anywhere.
*/
user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick, f->reason.c_str());
}
if (f->action == "gline")
{
/* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */
std::string wild = "*@";
wild.append(user->GetIPString());
if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), wild.c_str()))
{
ServerInstance->XLines->apply_lines(APPLY_GLINES);
FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));
}
}
return 1;
}
}
return 0;
}
return 0;
}
void FilterBase::OnRehash(userrec* user, const std::string ¶meter)
{
}
Version FilterBase::GetVersion()
{
return Version(1,1,0,2,VF_VENDOR|VF_COMMON,API_VERSION);
}
std::string FilterBase::EncodeFilter(FilterResult* filter)
{
std::ostringstream stream;
std::string x = filter->freeform;
/* Hax to allow spaces in the freeform without changing the design of the irc protocol */
for (std::string::iterator n = x.begin(); n != x.end(); n++)
if (*n == ' ')
*n = '\7';
stream << x << " " << filter->action << " " << (filter->flags.empty() ? "-" : filter->flags) << " " << filter->gline_time << " :" << filter->reason;
return stream.str();
}
FilterResult FilterBase::DecodeFilter(const std::string &data)
{
FilterResult res;
irc::tokenstream tokens(data);
tokens.GetToken(res.freeform);
tokens.GetToken(res.action);
tokens.GetToken(res.flags);
if (res.flags == "-")
res.flags = "";
res.FillFlags(res.flags);
tokens.GetToken(res.gline_time);
tokens.GetToken(res.reason);
/* Hax to allow spaces in the freeform without changing the design of the irc protocol */
for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++)
if (*n == '\7')
*n = ' ';
return res;
}
void FilterBase::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
{
this->SyncFilters(proto, opaque);
}
void FilterBase::SendFilter(Module* proto, void* opaque, FilterResult* iter)
{
proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "filter", EncodeFilter(iter));
}
void FilterBase::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
if ((target_type == TYPE_OTHER) && (extname == "filter"))
{
FilterResult data = DecodeFilter(extdata);
this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.flags);
}
}
\ No newline at end of file diff --git a/src/modules/m_foobar.cpp b/src/modules/m_foobar.cpp index 7de305923..857f4d16d 100644 --- a/src/modules/m_foobar.cpp +++ b/src/modules/m_foobar.cpp @@ -1,98 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: A dummy module for testing */ - -// Class ModuleFoobar inherits from Module -// It just outputs simple debug strings to show its methods are working. - -class ModuleFoobar : public Module -{ - private: - - // It is recommended that your class makes use of one or more Server - // objects. A server object is a class which contains methods which - // encapsulate the exports from the core of the ircd. - // such methods include Debug, SendChannel, etc. - - - public: - ModuleFoobar(InspIRCd* Me) - : Module(Me) - { - // The constructor just makes a copy of the server class - - - } - - virtual ~ModuleFoobar() - { - } - - virtual Version GetVersion() - { - // this method instantiates a class of type Version, and returns - // the modules version information using it. - - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserConnect] = List[I_OnUserQuit] = List[I_OnUserJoin] = List[I_OnUserPart] = 1; - } - - virtual void OnUserConnect(userrec* user) - { - // method called when a user connects - - std::string b = user->nick; - ServerInstance->Log(DEBUG,"Foobar: User connecting: "+b); - } - - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - // method called when a user disconnects - - std::string b = user->nick; - ServerInstance->Log(DEBUG,"Foobar: User quitting: "+b); - } - - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - // method called when a user joins a channel - - std::string c = channel->name; - std::string b = user->nick; - ServerInstance->Log(DEBUG,"Foobar: User "+b+" joined "+c); - } - - virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent) - { - // method called when a user parts a channel - - std::string c = channel->name; - std::string b = user->nick; - ServerInstance->Log(DEBUG,"Foobar: User "+b+" parted "+c); - } - -}; - - -MODULE_INIT(ModuleFoobar) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: A dummy module for testing */
// Class ModuleFoobar inherits from Module
// It just outputs simple debug strings to show its methods are working.
class ModuleFoobar : public Module
{
private:
// It is recommended that your class makes use of one or more Server
// objects. A server object is a class which contains methods which
// encapsulate the exports from the core of the ircd.
// such methods include Debug, SendChannel, etc.
public:
ModuleFoobar(InspIRCd* Me)
: Module(Me)
{
// The constructor just makes a copy of the server class
}
virtual ~ModuleFoobar()
{
}
virtual Version GetVersion()
{
// this method instantiates a class of type Version, and returns
// the modules version information using it.
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserConnect] = List[I_OnUserQuit] = List[I_OnUserJoin] = List[I_OnUserPart] = 1;
}
virtual void OnUserConnect(userrec* user)
{
// method called when a user connects
std::string b = user->nick;
ServerInstance->Log(DEBUG,"Foobar: User connecting: "+b);
}
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
// method called when a user disconnects
std::string b = user->nick;
ServerInstance->Log(DEBUG,"Foobar: User quitting: "+b);
}
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
// method called when a user joins a channel
std::string c = channel->name;
std::string b = user->nick;
ServerInstance->Log(DEBUG,"Foobar: User "+b+" joined "+c);
}
virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent)
{
// method called when a user parts a channel
std::string c = channel->name;
std::string b = user->nick;
ServerInstance->Log(DEBUG,"Foobar: User "+b+" parted "+c);
}
};
MODULE_INIT(ModuleFoobar)
\ No newline at end of file diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp index ae87451ba..4f3438e05 100644 --- a/src/modules/m_globalload.cpp +++ b/src/modules/m_globalload.cpp @@ -1,141 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Allows global loading of a module. */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/** Handle /GLOADMODULE - */ -class cmd_gloadmodule : public command_t -{ - public: - cmd_gloadmodule (InspIRCd* Instance) : command_t(Instance,"GLOADMODULE", 'o', 1) - { - this->source = "m_globalload.so"; - syntax = "<modulename>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - if (ServerInstance->LoadModule(parameters[0])) - { - ServerInstance->WriteOpers("*** NEW MODULE '%s' GLOBALLY LOADED BY '%s'",parameters[0],user->nick); - user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]); - - /* route it! */ - return CMD_SUCCESS; - } - else - { - user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError()); - /* XXX - returning CMD_FAILURE here could potentially mean half the net loads it, half doesn't. pass it on anyway? -- w00t - * - * Returning CMD_SUCCESS would have the same effect, just with less servers. Someone should update this module to properly - * pass the success/failure for each server to the caller (or to all opers) -Special */ - return CMD_FAILURE; - } - } -}; - -/** Handle /GUNLOADMODULE - */ -class cmd_gunloadmodule : public command_t -{ - public: - cmd_gunloadmodule (InspIRCd* Instance) : command_t(Instance,"GUNLOADMODULE", 'o', 1) - { - this->source = "m_globalload.so"; - syntax = "<modulename>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - if (ServerInstance->UnloadModule(parameters[0])) - { - ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY UNLOADED BY '%s'",parameters[0],user->nick); - user->WriteServ("973 %s %s :Module successfully unloaded.",user->nick, parameters[0]); - } - else - { - /* Return CMD_SUCCESS so the module will be unloaded on any servers it is loaded on - this is a seperate case entirely from loading -Special */ - user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError()); - } - return CMD_SUCCESS; - } -}; - -/** Handle /GRELOADMODULE - */ -class cmd_greloadmodule : public command_t -{ - public: - cmd_greloadmodule (InspIRCd* Instance) : command_t(Instance, "GRELOADMODULE", 'o', 1) - { - this->source = "m_globalload.so"; - syntax = "<modulename>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - if (!ServerInstance->UnloadModule(parameters[0])) - { - user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError()); - return CMD_FAILURE; - } - - if (!ServerInstance->LoadModule(parameters[0])) - { - user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError()); - return CMD_FAILURE; - } - - ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY RELOADED BY '%s'",parameters[0],user->nick); - user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]); - - return CMD_SUCCESS; - } -}; - -class ModuleGlobalLoad : public Module -{ - cmd_gloadmodule *mycommand; - cmd_gunloadmodule *mycommand2; - cmd_greloadmodule *mycommand3; - - public: - ModuleGlobalLoad(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_gloadmodule(ServerInstance); - mycommand2 = new cmd_gunloadmodule(ServerInstance); - mycommand3 = new cmd_greloadmodule(ServerInstance); - ServerInstance->AddCommand(mycommand); - ServerInstance->AddCommand(mycommand2); - ServerInstance->AddCommand(mycommand3); - } - - virtual ~ModuleGlobalLoad() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleGlobalLoad) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Allows global loading of a module. */
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/** Handle /GLOADMODULE
*/
class cmd_gloadmodule : public command_t
{
public:
cmd_gloadmodule (InspIRCd* Instance) : command_t(Instance,"GLOADMODULE", 'o', 1)
{
this->source = "m_globalload.so";
syntax = "<modulename>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
if (ServerInstance->LoadModule(parameters[0]))
{
ServerInstance->WriteOpers("*** NEW MODULE '%s' GLOBALLY LOADED BY '%s'",parameters[0],user->nick);
user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);
/* route it! */
return CMD_SUCCESS;
}
else
{
user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
/* XXX - returning CMD_FAILURE here could potentially mean half the net loads it, half doesn't. pass it on anyway? -- w00t
*
* Returning CMD_SUCCESS would have the same effect, just with less servers. Someone should update this module to properly
* pass the success/failure for each server to the caller (or to all opers) -Special */
return CMD_FAILURE;
}
}
};
/** Handle /GUNLOADMODULE
*/
class cmd_gunloadmodule : public command_t
{
public:
cmd_gunloadmodule (InspIRCd* Instance) : command_t(Instance,"GUNLOADMODULE", 'o', 1)
{
this->source = "m_globalload.so";
syntax = "<modulename>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
if (ServerInstance->UnloadModule(parameters[0]))
{
ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY UNLOADED BY '%s'",parameters[0],user->nick);
user->WriteServ("973 %s %s :Module successfully unloaded.",user->nick, parameters[0]);
}
else
{
/* Return CMD_SUCCESS so the module will be unloaded on any servers it is loaded on - this is a seperate case entirely from loading -Special */
user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
}
return CMD_SUCCESS;
}
};
/** Handle /GRELOADMODULE
*/
class cmd_greloadmodule : public command_t
{
public:
cmd_greloadmodule (InspIRCd* Instance) : command_t(Instance, "GRELOADMODULE", 'o', 1)
{
this->source = "m_globalload.so";
syntax = "<modulename>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
if (!ServerInstance->UnloadModule(parameters[0]))
{
user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
return CMD_FAILURE;
}
if (!ServerInstance->LoadModule(parameters[0]))
{
user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
return CMD_FAILURE;
}
ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY RELOADED BY '%s'",parameters[0],user->nick);
user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);
return CMD_SUCCESS;
}
};
class ModuleGlobalLoad : public Module
{
cmd_gloadmodule *mycommand;
cmd_gunloadmodule *mycommand2;
cmd_greloadmodule *mycommand3;
public:
ModuleGlobalLoad(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_gloadmodule(ServerInstance);
mycommand2 = new cmd_gunloadmodule(ServerInstance);
mycommand3 = new cmd_greloadmodule(ServerInstance);
ServerInstance->AddCommand(mycommand);
ServerInstance->AddCommand(mycommand2);
ServerInstance->AddCommand(mycommand3);
}
virtual ~ModuleGlobalLoad()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleGlobalLoad)
\ No newline at end of file diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp index 1a49858e2..5745cc9c6 100644 --- a/src/modules/m_globops.cpp +++ b/src/modules/m_globops.cpp @@ -1,76 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -// Globops and +g support module by C.J.Edwards - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for GLOBOPS and user mode +g */ - -/** Handle /GLOBOPS - */ -class cmd_globops : public command_t -{ - public: - cmd_globops (InspIRCd* Instance) : command_t(Instance,"GLOBOPS",'o',1) - { - this->source = "m_globops.so"; - syntax = "<any-text>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - std::string line = "From " + std::string(user->nick) + ": "; - for (int i = 0; i < pcnt; i++) - { - line = line + std::string(parameters[i]) + " "; - } - ServerInstance->SNO->WriteToSnoMask('g',line); - - /* route it (ofc :p) */ - return CMD_SUCCESS; - } -}; - -class ModuleGlobops : public Module -{ - cmd_globops* mycommand; - public: - ModuleGlobops(InspIRCd* Me) - : Module(Me) - { - mycommand = new cmd_globops(ServerInstance); - ServerInstance->AddCommand(mycommand); - ServerInstance->SNO->EnableSnomask('g',"GLOBOPS"); - } - - virtual ~ModuleGlobops() - { - ServerInstance->SNO->DisableSnomask('g'); - DELETE(mycommand); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 1, VF_COMMON | VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - } -}; - -MODULE_INIT(ModuleGlobops) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
// Globops and +g support module by C.J.Edwards
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for GLOBOPS and user mode +g */
/** Handle /GLOBOPS
*/
class cmd_globops : public command_t
{
public:
cmd_globops (InspIRCd* Instance) : command_t(Instance,"GLOBOPS",'o',1)
{
this->source = "m_globops.so";
syntax = "<any-text>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
std::string line = "From " + std::string(user->nick) + ": ";
for (int i = 0; i < pcnt; i++)
{
line = line + std::string(parameters[i]) + " ";
}
ServerInstance->SNO->WriteToSnoMask('g',line);
/* route it (ofc :p) */
return CMD_SUCCESS;
}
};
class ModuleGlobops : public Module
{
cmd_globops* mycommand;
public:
ModuleGlobops(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_globops(ServerInstance);
ServerInstance->AddCommand(mycommand);
ServerInstance->SNO->EnableSnomask('g',"GLOBOPS");
}
virtual ~ModuleGlobops()
{
ServerInstance->SNO->DisableSnomask('g');
DELETE(mycommand);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 1, VF_COMMON | VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
}
};
MODULE_INIT(ModuleGlobops)
\ No newline at end of file diff --git a/src/modules/m_hash.h b/src/modules/m_hash.h index ee9ead21c..d82104cdb 100644 --- a/src/modules/m_hash.h +++ b/src/modules/m_hash.h @@ -1,196 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __HASH_H__ -#define __HASH_H__ - -#include "modules.h" - -#define SHA256_DIGEST_SIZE (256 / 8) -#define SHA256_BLOCK_SIZE (512 / 8) - -/** HashRequest is the base class used to send Hash requests to hashing.so. - * You should not instantiate classes of type HashRequest directly, instead - * you should instantiate classes of type HashResetRequest, HashSumRequest, - * HashKeyRequest and HashHexRequest, shown below. - */ -class HashRequest : public Request -{ - /** The keys (IV) to use */ - unsigned int* keys; - /** The output characters (hex sequence) to use */ - const char* outputs; - /** The string to hash */ - std::string tohash; - public: - /** Initialize HashRequest as an Hash_RESET message */ - HashRequest(const char* req, Module* Me, Module* Target) : Request(Me, Target, req) - { - } - - /** Initialize HashRequest as an Hash_SUM message */ - HashRequest(Module* Me, Module* Target, const std::string &hashable) : Request(Me, Target, "SUM"), keys(NULL), outputs(NULL), tohash(hashable) - { - } - - /** Initialize HashRequest as an Hash_KEY message */ - HashRequest(Module* Me, Module* Target, unsigned int* k) : Request(Me, Target, "KEY"), keys(k), outputs(NULL), tohash("") - { - } - - /** Initialize HashRequest as an Hash_HEX message */ - HashRequest(Module* Me, Module* Target, const char* out) : Request(Me, Target, "HEX"), keys(NULL), outputs(out), tohash("") - { - } - - /** Get data to be hashed */ - const char* GetHashData() - { - return tohash.c_str(); - } - - /** Get keys (IVs) to be used */ - unsigned int* GetKeyData() - { - return keys; - } - - /** Get output characters (hex sequence) to be used */ - const char* GetOutputs() - { - return outputs; - } -}; - -/** Send this class to the hashing module to query for its name. - * - * Example: - * \code - * cout << "Using hash algorithm: " << HashNameRequest(this, HashModule).Send(); - * \endcode - */ -class HashNameRequest : public HashRequest -{ - public: - /** Initialize HashNameRequest for sending. - * @param Me A pointer to the sending module - * @param Target A pointer to the hashing module - */ - HashNameRequest(Module* Me, Module* Target) : HashRequest("NAME", Me, Target) - { - } -}; - -/** Send this class to the hashing module to reset the Hash module to a known state. - * This will reset the IV to the defaults specified by the Hash spec, - * and reset the hex sequence to "0123456789abcdef". It should be sent before - * ANY other Request types. - * - * Example: - * \code - * // Reset the Hash module. - * HashResetRequest(this, HashModule).Send(); - * \endcode - */ -class HashResetRequest : public HashRequest -{ - public: - /** Initialize HashResetRequest for sending. - * @param Me A pointer to the sending module - * @param Target A pointer to the hashing module - */ - HashResetRequest(Module* Me, Module* Target) : HashRequest("RESET", Me, Target) - { - } -}; - -/** Send this class to the hashing module to HashSUM a std::string. - * You should make sure you know the state of the module before you send this - * class, e.g. by first sending an HashResetRequest class. The hash will be - * returned when you call Send(). - * - * Example: - * \code - * // ALWAYS ALWAYS reset first, or set your own IV and hex chars. - * HashResetRequest(this, HashModule).Send(); - * // Get the Hash sum of the string 'doodads'. - * std::string result = HashSumRequest(this, HashModule, "doodads").Send(); - * \endcode - */ -class HashSumRequest : public HashRequest -{ - public: - /** Initialize HashSumRequest for sending. - * @param Me A pointer to the sending module - * @param Target A pointer to the hashing module - * @param data The data to be hashed - */ - HashSumRequest(Module* Me, Module* Target, const std::string &data) : HashRequest(Me, Target, data) - { - } -}; - -/** Send this class to hashing module to change the IVs (keys) to use for hashing. - * You should make sure you know the state of the module before you send this - * class, e.g. by first sending an HashResetRequest class. The default values for - * the IV's are those specified in the Hash specification. Only in very special - * circumstances should you need to change the IV's (see for example m_cloaking.cpp) - * - * Example: - * \code - * unsigned int iv[] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0xCCCCCCCC }; - * HashKeyRequest(this, HashModule, iv); - * \endcode - */ -class HashKeyRequest : public HashRequest -{ - public: - /** Initialize HashKeyRequest for sending. - * @param Me A pointer to the sending module - * @param Target A pointer to the hashing module - * @param data The new IV's. This should be an array of exactly four 32 bit values. - * On 64-bit architectures, the upper 32 bits of the values will be discarded. - */ - HashKeyRequest(Module* Me, Module* Target, unsigned int* data) : HashRequest(Me, Target, data) - { - } -}; - -/** Send this class to the hashing module to change the hex sequence to use for generating the returned value. - * You should make sure you know the state of the module before you send this - * class, e.g. by first sending an HashResetRequest class. The default value for - * the hex sequence is "0123456789abcdef". Only in very special circumstances should - * you need to change the hex sequence (see for example m_cloaking.cpp). - * - * Example: - * \code - * static const char tab[] = "fedcba9876543210"; - * HashHexRequest(this, HashModule, tab); - * \endcode - */ -class HashHexRequest : public HashRequest -{ - public: - /** Initialize HashHexRequest for sending. - * @param Me A pointer to the sending module - * @param Target A pointer to the hashing module - * @param data The hex sequence to use. This should contain exactly 16 ASCII characters, - * terminated by a NULL char. - */ - HashHexRequest(Module* Me, Module* Target, const char* data) : HashRequest(Me, Target, data) - { - } -}; - -#endif - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __HASH_H__
#define __HASH_H__
#include "modules.h"
#define SHA256_DIGEST_SIZE (256 / 8)
#define SHA256_BLOCK_SIZE (512 / 8)
/** HashRequest is the base class used to send Hash requests to hashing.so.
* You should not instantiate classes of type HashRequest directly, instead
* you should instantiate classes of type HashResetRequest, HashSumRequest,
* HashKeyRequest and HashHexRequest, shown below.
*/
class HashRequest : public Request
{
/** The keys (IV) to use */
unsigned int* keys;
/** The output characters (hex sequence) to use */
const char* outputs;
/** The string to hash */
std::string tohash;
public:
/** Initialize HashRequest as an Hash_RESET message */
HashRequest(const char* req, Module* Me, Module* Target) : Request(Me, Target, req)
{
}
/** Initialize HashRequest as an Hash_SUM message */
HashRequest(Module* Me, Module* Target, const std::string &hashable) : Request(Me, Target, "SUM"), keys(NULL), outputs(NULL), tohash(hashable)
{
}
/** Initialize HashRequest as an Hash_KEY message */
HashRequest(Module* Me, Module* Target, unsigned int* k) : Request(Me, Target, "KEY"), keys(k), outputs(NULL), tohash("")
{
}
/** Initialize HashRequest as an Hash_HEX message */
HashRequest(Module* Me, Module* Target, const char* out) : Request(Me, Target, "HEX"), keys(NULL), outputs(out), tohash("")
{
}
/** Get data to be hashed */
const char* GetHashData()
{
return tohash.c_str();
}
/** Get keys (IVs) to be used */
unsigned int* GetKeyData()
{
return keys;
}
/** Get output characters (hex sequence) to be used */
const char* GetOutputs()
{
return outputs;
}
};
/** Send this class to the hashing module to query for its name.
*
* Example:
* \code
* cout << "Using hash algorithm: " << HashNameRequest(this, HashModule).Send();
* \endcode
*/
class HashNameRequest : public HashRequest
{
public:
/** Initialize HashNameRequest for sending.
* @param Me A pointer to the sending module
* @param Target A pointer to the hashing module
*/
HashNameRequest(Module* Me, Module* Target) : HashRequest("NAME", Me, Target)
{
}
};
/** Send this class to the hashing module to reset the Hash module to a known state.
* This will reset the IV to the defaults specified by the Hash spec,
* and reset the hex sequence to "0123456789abcdef". It should be sent before
* ANY other Request types.
*
* Example:
* \code
* // Reset the Hash module.
* HashResetRequest(this, HashModule).Send();
* \endcode
*/
class HashResetRequest : public HashRequest
{
public:
/** Initialize HashResetRequest for sending.
* @param Me A pointer to the sending module
* @param Target A pointer to the hashing module
*/
HashResetRequest(Module* Me, Module* Target) : HashRequest("RESET", Me, Target)
{
}
};
/** Send this class to the hashing module to HashSUM a std::string.
* You should make sure you know the state of the module before you send this
* class, e.g. by first sending an HashResetRequest class. The hash will be
* returned when you call Send().
*
* Example:
* \code
* // ALWAYS ALWAYS reset first, or set your own IV and hex chars.
* HashResetRequest(this, HashModule).Send();
* // Get the Hash sum of the string 'doodads'.
* std::string result = HashSumRequest(this, HashModule, "doodads").Send();
* \endcode
*/
class HashSumRequest : public HashRequest
{
public:
/** Initialize HashSumRequest for sending.
* @param Me A pointer to the sending module
* @param Target A pointer to the hashing module
* @param data The data to be hashed
*/
HashSumRequest(Module* Me, Module* Target, const std::string &data) : HashRequest(Me, Target, data)
{
}
};
/** Send this class to hashing module to change the IVs (keys) to use for hashing.
* You should make sure you know the state of the module before you send this
* class, e.g. by first sending an HashResetRequest class. The default values for
* the IV's are those specified in the Hash specification. Only in very special
* circumstances should you need to change the IV's (see for example m_cloaking.cpp)
*
* Example:
* \code
* unsigned int iv[] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0xCCCCCCCC };
* HashKeyRequest(this, HashModule, iv);
* \endcode
*/
class HashKeyRequest : public HashRequest
{
public:
/** Initialize HashKeyRequest for sending.
* @param Me A pointer to the sending module
* @param Target A pointer to the hashing module
* @param data The new IV's. This should be an array of exactly four 32 bit values.
* On 64-bit architectures, the upper 32 bits of the values will be discarded.
*/
HashKeyRequest(Module* Me, Module* Target, unsigned int* data) : HashRequest(Me, Target, data)
{
}
};
/** Send this class to the hashing module to change the hex sequence to use for generating the returned value.
* You should make sure you know the state of the module before you send this
* class, e.g. by first sending an HashResetRequest class. The default value for
* the hex sequence is "0123456789abcdef". Only in very special circumstances should
* you need to change the hex sequence (see for example m_cloaking.cpp).
*
* Example:
* \code
* static const char tab[] = "fedcba9876543210";
* HashHexRequest(this, HashModule, tab);
* \endcode
*/
class HashHexRequest : public HashRequest
{
public:
/** Initialize HashHexRequest for sending.
* @param Me A pointer to the sending module
* @param Target A pointer to the hashing module
* @param data The hex sequence to use. This should contain exactly 16 ASCII characters,
* terminated by a NULL char.
*/
HashHexRequest(Module* Me, Module* Target, const char* data) : HashRequest(Me, Target, data)
{
}
};
#endif
\ No newline at end of file diff --git a/src/modules/m_helpop.cpp b/src/modules/m_helpop.cpp index 341f2b861..965194a08 100644 --- a/src/modules/m_helpop.cpp +++ b/src/modules/m_helpop.cpp @@ -1,191 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: /helpop Command, Works like Unreal helpop */ -static std::map<irc::string, std::string> helpop_map; - - -/** Handles user mode +h - */ -class Helpop : public ModeHandler -{ - public: - Helpop(InspIRCd* Instance) : ModeHandler(Instance, 'h', 0, 0, false, MODETYPE_USER, true) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('h')) - { - dest->SetMode('h',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('h')) - { - dest->SetMode('h',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** Handles /HELPOP - */ -class cmd_helpop : public command_t -{ - public: - cmd_helpop (InspIRCd* Instance) : command_t(Instance, "HELPOP", 0, 0) - { - this->source = "m_helpop.so"; - syntax = "<any-text>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - irc::string parameter; - if (pcnt > 0) - parameter = parameters[0]; - - if (pcnt == 0 || parameter == "index") - { - /* iterate over all helpop items */ - user->WriteServ("NOTICE %s :HELPOP topic index", user->nick); - for (std::map<irc::string, std::string>::iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++) - { - user->WriteServ("NOTICE %s : %s", user->nick, iter->first.c_str()); - } - user->WriteServ("NOTICE %s :*** End of HELPOP topic index", user->nick); - } - else - { - user->WriteServ("NOTICE %s :*** HELPOP for %s", user->nick, parameters[0]); - - std::map<irc::string, std::string>::iterator iter = helpop_map.find(parameter); - - if (iter == helpop_map.end()) - { - iter = helpop_map.find("nohelp"); - } - - std::string value = iter->second; - irc::sepstream stream(value, '\n'); - std::string token = "*"; - - while ((token = stream.GetToken()) != "") - { - user->WriteServ("NOTICE %s :%s", user->nick, token.c_str()); - } - - user->WriteServ("NOTICE %s :*** End of HELPOP", user->nick); - } - - /* We dont want these going out over the network, return CMD_FAILURE - * to make sure the protocol module thinks theyre not worth sending. - */ - return CMD_FAILURE; - } -}; - -class ModuleHelpop : public Module -{ - private: - std::string h_file; - cmd_helpop* mycommand; - Helpop* ho; - - public: - ModuleHelpop(InspIRCd* Me) - : Module(Me) - { - ReadConfig(); - ho = new Helpop(ServerInstance); - if (!ServerInstance->AddMode(ho, 'h')) - throw ModuleException("Could not add new modes!"); - mycommand = new cmd_helpop(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual void ReadConfig() - { - ConfigReader *MyConf = new ConfigReader(ServerInstance); - - helpop_map.clear(); - - for (int i = 0; i < MyConf->Enumerate("helpop"); i++) - { - irc::string key = assign(MyConf->ReadValue("helpop", "key", i)); - std::string value = MyConf->ReadValue("helpop", "value", i, true); /* Linefeeds allowed! */ - - if (key == "index") - { - throw ModuleException("m_helpop: The key 'index' is reserved for internal purposes. Please remove it."); - } - - helpop_map[key] = value; - } - - if (helpop_map.find("start") == helpop_map.end()) - { - // error! - throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf."); - } - else if (helpop_map.find("nohelp") == helpop_map.end()) - { - // error! - throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf."); - } - - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnWhois] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ReadConfig(); - } - - virtual void OnWhois(userrec* src, userrec* dst) - { - if (dst->IsModeSet('h')) - { - ServerInstance->SendWhoisLine(src, dst, 310, std::string(src->nick)+" "+std::string(dst->nick)+" :is available for help."); - } - } - - virtual ~ModuleHelpop() - { - ServerInstance->Modes->DelMode(ho); - DELETE(ho); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleHelpop) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: /helpop Command, Works like Unreal helpop */
static std::map<irc::string, std::string> helpop_map;
/** Handles user mode +h
*/
class Helpop : public ModeHandler
{
public:
Helpop(InspIRCd* Instance) : ModeHandler(Instance, 'h', 0, 0, false, MODETYPE_USER, true) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!dest->IsModeSet('h'))
{
dest->SetMode('h',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('h'))
{
dest->SetMode('h',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** Handles /HELPOP
*/
class cmd_helpop : public command_t
{
public:
cmd_helpop (InspIRCd* Instance) : command_t(Instance, "HELPOP", 0, 0)
{
this->source = "m_helpop.so";
syntax = "<any-text>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
irc::string parameter;
if (pcnt > 0)
parameter = parameters[0];
if (pcnt == 0 || parameter == "index")
{
/* iterate over all helpop items */
user->WriteServ("NOTICE %s :HELPOP topic index", user->nick);
for (std::map<irc::string, std::string>::iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++)
{
user->WriteServ("NOTICE %s : %s", user->nick, iter->first.c_str());
}
user->WriteServ("NOTICE %s :*** End of HELPOP topic index", user->nick);
}
else
{
user->WriteServ("NOTICE %s :*** HELPOP for %s", user->nick, parameters[0]);
std::map<irc::string, std::string>::iterator iter = helpop_map.find(parameter);
if (iter == helpop_map.end())
{
iter = helpop_map.find("nohelp");
}
std::string value = iter->second;
irc::sepstream stream(value, '\n');
std::string token = "*";
while ((token = stream.GetToken()) != "")
{
user->WriteServ("NOTICE %s :%s", user->nick, token.c_str());
}
user->WriteServ("NOTICE %s :*** End of HELPOP", user->nick);
}
/* We dont want these going out over the network, return CMD_FAILURE
* to make sure the protocol module thinks theyre not worth sending.
*/
return CMD_FAILURE;
}
};
class ModuleHelpop : public Module
{
private:
std::string h_file;
cmd_helpop* mycommand;
Helpop* ho;
public:
ModuleHelpop(InspIRCd* Me)
: Module(Me)
{
ReadConfig();
ho = new Helpop(ServerInstance);
if (!ServerInstance->AddMode(ho, 'h'))
throw ModuleException("Could not add new modes!");
mycommand = new cmd_helpop(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual void ReadConfig()
{
ConfigReader *MyConf = new ConfigReader(ServerInstance);
helpop_map.clear();
for (int i = 0; i < MyConf->Enumerate("helpop"); i++)
{
irc::string key = assign(MyConf->ReadValue("helpop", "key", i));
std::string value = MyConf->ReadValue("helpop", "value", i, true); /* Linefeeds allowed! */
if (key == "index")
{
throw ModuleException("m_helpop: The key 'index' is reserved for internal purposes. Please remove it.");
}
helpop_map[key] = value;
}
if (helpop_map.find("start") == helpop_map.end())
{
// error!
throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf.");
}
else if (helpop_map.find("nohelp") == helpop_map.end())
{
// error!
throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf.");
}
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnWhois] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadConfig();
}
virtual void OnWhois(userrec* src, userrec* dst)
{
if (dst->IsModeSet('h'))
{
ServerInstance->SendWhoisLine(src, dst, 310, std::string(src->nick)+" "+std::string(dst->nick)+" :is available for help.");
}
}
virtual ~ModuleHelpop()
{
ServerInstance->Modes->DelMode(ho);
DELETE(ho);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleHelpop)
\ No newline at end of file diff --git a/src/modules/m_hidechans.cpp b/src/modules/m_hidechans.cpp index 2c3769f7a..3924b84b9 100644 --- a/src/modules/m_hidechans.cpp +++ b/src/modules/m_hidechans.cpp @@ -1,95 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for hiding channels with user mode +I */ - -/** Handles user mode +I - */ -class HideChans : public ModeHandler -{ - public: - HideChans(InspIRCd* Instance) : ModeHandler(Instance, 'I', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - /* Only opers can change other users modes */ - if (source != dest) - return MODEACTION_DENY; - - if (adding) - { - if (!dest->IsModeSet('I')) - { - dest->SetMode('I',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('I')) - { - dest->SetMode('I',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleHideChans : public Module -{ - - HideChans* hm; - public: - ModuleHideChans(InspIRCd* Me) - : Module(Me) - { - - hm = new HideChans(ServerInstance); - if (!ServerInstance->AddMode(hm, 'I')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnWhoisLine] = 1; - } - - virtual ~ModuleHideChans() - { - ServerInstance->Modes->DelMode(hm); - DELETE(hm); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } - - int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text) - { - /* Dont display channels if they have +I set and the - * person doing the WHOIS is not an oper - */ - return ((user != dest) && (!IS_OPER(user)) && (numeric == 319) && dest->IsModeSet('I')); - } -}; - - -MODULE_INIT(ModuleHideChans) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for hiding channels with user mode +I */
/** Handles user mode +I
*/
class HideChans : public ModeHandler
{
public:
HideChans(InspIRCd* Instance) : ModeHandler(Instance, 'I', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
/* Only opers can change other users modes */
if (source != dest)
return MODEACTION_DENY;
if (adding)
{
if (!dest->IsModeSet('I'))
{
dest->SetMode('I',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('I'))
{
dest->SetMode('I',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleHideChans : public Module
{
HideChans* hm;
public:
ModuleHideChans(InspIRCd* Me)
: Module(Me)
{
hm = new HideChans(ServerInstance);
if (!ServerInstance->AddMode(hm, 'I'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnWhoisLine] = 1;
}
virtual ~ModuleHideChans()
{
ServerInstance->Modes->DelMode(hm);
DELETE(hm);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)
{
/* Dont display channels if they have +I set and the
* person doing the WHOIS is not an oper
*/
return ((user != dest) && (!IS_OPER(user)) && (numeric == 319) && dest->IsModeSet('I'));
}
};
MODULE_INIT(ModuleHideChans)
\ No newline at end of file diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index 9f547d77d..c2b472bad 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -1,94 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for hiding oper status with user mode +H */ - -/** Handles user mode +B - */ -class HideOper : public ModeHandler -{ - public: - HideOper(InspIRCd* Instance) : ModeHandler(Instance, 'H', 0, 0, false, MODETYPE_USER, true) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (source != dest) - return MODEACTION_DENY; - - if (adding) - { - if (!dest->IsModeSet('H')) - { - dest->SetMode('H',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('H')) - { - dest->SetMode('H',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleHideOper : public Module -{ - - HideOper* hm; - public: - ModuleHideOper(InspIRCd* Me) - : Module(Me) - { - - hm = new HideOper(ServerInstance); - if (!ServerInstance->AddMode(hm, 'H')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnWhoisLine] = 1; - } - - virtual ~ModuleHideOper() - { - ServerInstance->Modes->DelMode(hm); - DELETE(hm); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } - - int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text) - { - /* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the - * person doing the WHOIS is not an oper - */ - return ((!IS_OPER(user)) && (numeric == 313) && dest->IsModeSet('H')); - } -}; - - -MODULE_INIT(ModuleHideOper) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for hiding oper status with user mode +H */
/** Handles user mode +B
*/
class HideOper : public ModeHandler
{
public:
HideOper(InspIRCd* Instance) : ModeHandler(Instance, 'H', 0, 0, false, MODETYPE_USER, true) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (source != dest)
return MODEACTION_DENY;
if (adding)
{
if (!dest->IsModeSet('H'))
{
dest->SetMode('H',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('H'))
{
dest->SetMode('H',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleHideOper : public Module
{
HideOper* hm;
public:
ModuleHideOper(InspIRCd* Me)
: Module(Me)
{
hm = new HideOper(ServerInstance);
if (!ServerInstance->AddMode(hm, 'H'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnWhoisLine] = 1;
}
virtual ~ModuleHideOper()
{
ServerInstance->Modes->DelMode(hm);
DELETE(hm);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)
{
/* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the
* person doing the WHOIS is not an oper
*/
return ((!IS_OPER(user)) && (numeric == 313) && dest->IsModeSet('H'));
}
};
MODULE_INIT(ModuleHideOper)
\ No newline at end of file diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp index dc45a43d4..f7ff58fa1 100644 --- a/src/modules/m_hostchange.cpp +++ b/src/modules/m_hostchange.cpp @@ -1,148 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides masking of user hostnames in a different way to m_cloaking */ - -/** Holds information on a host set by m_hostchange - */ -class Host : public classbase -{ - public: - std::string action; - std::string newhost; -}; - -typedef std::map<std::string,Host*> hostchanges_t; - -class ModuleHostChange : public Module -{ - private: - hostchanges_t hostchanges; - std::string MySuffix; - std::string MyPrefix; - std::string MySeparator; - - public: - ModuleHostChange(InspIRCd* Me) - : Module(Me) - { - OnRehash(NULL,""); - } - - virtual ~ModuleHostChange() - { - for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) - { - DELETE(i->second); - } - hostchanges.clear(); - } - - Priority Prioritize() - { - return (Priority)ServerInstance->PriorityAfter("m_cloaking.so"); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnUserConnect] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - MySuffix = Conf.ReadValue("host","suffix",0); - MyPrefix = Conf.ReadValue("host","prefix","",0); - MySeparator = Conf.ReadValue("host","separator",".",0); - for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) - { - DELETE(i->second); - } - hostchanges.clear(); - for (int index = 0; index < Conf.Enumerate("hostchange"); index++) - { - std::string mask = Conf.ReadValue("hostchange","mask",index); - std::string action = Conf.ReadValue("hostchange","action",index); - std::string newhost = Conf.ReadValue("hostchange","value",index); - Host* x = new Host; - x->action = action; - x->newhost = newhost; - hostchanges[mask] = x; - } - } - - virtual Version GetVersion() - { - // returns the version number of the module to be - // listed in /MODULES - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void OnUserConnect(userrec* user) - { - for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) - { - if (ServerInstance->MatchText(std::string(user->ident)+"@"+std::string(user->host),i->first)) - { - Host* h = (Host*)i->second; - // host of new user matches a hostchange tag's mask - std::string newhost; - if (h->action == "set") - { - newhost = h->newhost; - } - else if (h->action == "suffix") - { - newhost = MySuffix; - } - else if (h->action == "addnick") - { - // first take their nick and strip out non-dns, leaving just [A-Z0-9\-] - std::string complete; - std::string old = user->nick; - for (unsigned int j = 0; j < old.length(); j++) - { - if (((old[j] >= 'A') && (old[j] <= 'Z')) || - ((old[j] >= 'a') && (old[j] <= 'z')) || - ((old[j] >= '0') && (old[j] <= '9')) || - (old[j] == '-')) - { - complete = complete + old[j]; - } - } - if (complete.empty()) - complete = "i-have-a-lame-nick"; - - if (!MyPrefix.empty()) - newhost = MyPrefix + MySeparator + complete; - else - newhost = complete + MySeparator + MySuffix; - } - if (!newhost.empty()) - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your virtual host: " + newhost); - if (!user->ChangeDisplayedHost(newhost.c_str())) - user->WriteServ("NOTICE "+std::string(user->nick)+" :Could not set your virtual host: " + newhost); - return; - } - } - } - } -}; - -MODULE_INIT(ModuleHostChange) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides masking of user hostnames in a different way to m_cloaking */
/** Holds information on a host set by m_hostchange
*/
class Host : public classbase
{
public:
std::string action;
std::string newhost;
};
typedef std::map<std::string,Host*> hostchanges_t;
class ModuleHostChange : public Module
{
private:
hostchanges_t hostchanges;
std::string MySuffix;
std::string MyPrefix;
std::string MySeparator;
public:
ModuleHostChange(InspIRCd* Me)
: Module(Me)
{
OnRehash(NULL,"");
}
virtual ~ModuleHostChange()
{
for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
{
DELETE(i->second);
}
hostchanges.clear();
}
Priority Prioritize()
{
return (Priority)ServerInstance->PriorityAfter("m_cloaking.so");
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnUserConnect] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
MySuffix = Conf.ReadValue("host","suffix",0);
MyPrefix = Conf.ReadValue("host","prefix","",0);
MySeparator = Conf.ReadValue("host","separator",".",0);
for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
{
DELETE(i->second);
}
hostchanges.clear();
for (int index = 0; index < Conf.Enumerate("hostchange"); index++)
{
std::string mask = Conf.ReadValue("hostchange","mask",index);
std::string action = Conf.ReadValue("hostchange","action",index);
std::string newhost = Conf.ReadValue("hostchange","value",index);
Host* x = new Host;
x->action = action;
x->newhost = newhost;
hostchanges[mask] = x;
}
}
virtual Version GetVersion()
{
// returns the version number of the module to be
// listed in /MODULES
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void OnUserConnect(userrec* user)
{
for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
{
if (ServerInstance->MatchText(std::string(user->ident)+"@"+std::string(user->host),i->first))
{
Host* h = (Host*)i->second;
// host of new user matches a hostchange tag's mask
std::string newhost;
if (h->action == "set")
{
newhost = h->newhost;
}
else if (h->action == "suffix")
{
newhost = MySuffix;
}
else if (h->action == "addnick")
{
// first take their nick and strip out non-dns, leaving just [A-Z0-9\-]
std::string complete;
std::string old = user->nick;
for (unsigned int j = 0; j < old.length(); j++)
{
if (((old[j] >= 'A') && (old[j] <= 'Z')) ||
((old[j] >= 'a') && (old[j] <= 'z')) ||
((old[j] >= '0') && (old[j] <= '9')) ||
(old[j] == '-'))
{
complete = complete + old[j];
}
}
if (complete.empty())
complete = "i-have-a-lame-nick";
if (!MyPrefix.empty())
newhost = MyPrefix + MySeparator + complete;
else
newhost = complete + MySeparator + MySuffix;
}
if (!newhost.empty())
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your virtual host: " + newhost);
if (!user->ChangeDisplayedHost(newhost.c_str()))
user->WriteServ("NOTICE "+std::string(user->nick)+" :Could not set your virtual host: " + newhost);
return;
}
}
}
}
};
MODULE_INIT(ModuleHostChange)
\ No newline at end of file diff --git a/src/modules/m_http_client.cpp b/src/modules/m_http_client.cpp index 35b93b581..3f9875caf 100644 --- a/src/modules/m_http_client.cpp +++ b/src/modules/m_http_client.cpp @@ -1,346 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "httpclient.h" - -/* $ModDesc: HTTP client service provider */ - -class URL -{ - public: - std::string url; - std::string protocol, username, password, domain, request; - int port; -}; - -class HTTPSocket : public InspSocket -{ - private: - InspIRCd *Server; - class ModuleHTTPClient *Mod; - HTTPClientRequest req; - HTTPClientResponse *response; - URL url; - enum { HTTP_CLOSED, HTTP_REQSENT, HTTP_HEADERS, HTTP_DATA } status; - std::string data; - std::string buffer; - - public: - HTTPSocket(InspIRCd *Instance, class ModuleHTTPClient *Mod); - virtual ~HTTPSocket(); - virtual bool DoRequest(HTTPClientRequest *req); - virtual bool ParseURL(const std::string &url); - virtual void Connect(const std::string &ip); - virtual bool OnConnected(); - virtual bool OnDataReady(); - virtual void OnClose(); -}; - -class HTTPResolver : public Resolver -{ - private: - HTTPSocket *socket; - public: - HTTPResolver(HTTPSocket *socket, InspIRCd *Instance, const string &hostname, bool &cached, Module* me) : Resolver(Instance, hostname, DNS_QUERY_FORWARD, cached, me), socket(socket) - { - } - - void OnLookupComplete(const string &result, unsigned int ttl, bool cached) - { - socket->Connect(result); - } - - void OnError(ResolverError e, const string &errmsg) - { - delete socket; - } -}; - -typedef vector<HTTPSocket*> HTTPList; - -class ModuleHTTPClient : public Module -{ - public: - HTTPList sockets; - - ModuleHTTPClient(InspIRCd *Me) - : Module(Me) - { - } - - virtual ~ModuleHTTPClient() - { - for (HTTPList::iterator i = sockets.begin(); i != sockets.end(); i++) - delete *i; - } - - virtual Version GetVersion() - { - return Version(1, 0, 0, 0, VF_SERVICEPROVIDER | VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnRequest] = 1; - } - - char* OnRequest(Request *req) - { - HTTPClientRequest *httpreq = (HTTPClientRequest *)req; - if (!strcmp(httpreq->GetId(), HTTP_CLIENT_REQUEST)) - { - HTTPSocket *sock = new HTTPSocket(ServerInstance, this); - sock->DoRequest(httpreq); - // No return value - } - return NULL; - } -}; - -HTTPSocket::HTTPSocket(InspIRCd *Instance, ModuleHTTPClient *Mod) - : InspSocket(Instance), Server(Instance), Mod(Mod), status(HTTP_CLOSED) -{ - this->ClosePending = false; - this->port = 80; -} - -HTTPSocket::~HTTPSocket() -{ - Close(); - for (HTTPList::iterator i = Mod->sockets.begin(); i != Mod->sockets.end(); i++) - { - if (*i == this) - { - Mod->sockets.erase(i); - break; - } - } -} - -bool HTTPSocket::DoRequest(HTTPClientRequest *req) -{ - /* Tweak by brain - we take a copy of this, - * so that the caller doesnt need to leave - * pointers knocking around, less chance of - * a memory leak. - */ - this->req = *req; - - if (!ParseURL(this->req.GetURL())) - return false; - - this->port = url.port; - strlcpy(this->host, url.domain.c_str(), MAXBUF); - - in_addr addy1; -#ifdef IPV6 - in6_addr addy2; - if ((inet_aton(this->host, &addy1) > 0) || (inet_pton(AF_INET6, this->host, &addy2) > 0)) -#else - if (inet_aton(this->host, &addy1) > 0) -#endif - { - bool cached; - HTTPResolver* r = new HTTPResolver(this, Server, url.domain, cached, (Module*)Mod); - Instance->AddResolver(r, cached); - return true; - } - else - { - this->Connect(url.domain); - } - - return true; -} - -bool HTTPSocket::ParseURL(const std::string &iurl) -{ - url.url = iurl; - url.port = 80; - url.protocol = "http"; - - irc::sepstream tokenizer(iurl, '/'); - - for (int p = 0;; p++) - { - std::string part = tokenizer.GetToken(); - if (part.empty() && tokenizer.StreamEnd()) - break; - - if ((p == 0) && (part[part.length() - 1] == ':')) - { - // Protocol ('http:') - url.protocol = part.substr(0, part.length() - 1); - } - else if ((p == 1) && (part.empty())) - { - continue; - } - else if (url.domain.empty()) - { - // Domain part: [user[:pass]@]domain[:port] - std::string::size_type usrpos = part.find('@'); - if (usrpos != std::string::npos) - { - // Have a user (and possibly password) part - std::string::size_type ppos = part.find(':'); - if ((ppos != std::string::npos) && (ppos < usrpos)) - { - // Have password too - url.password = part.substr(ppos + 1, usrpos - ppos - 1); - url.username = part.substr(0, ppos); - } - else - { - url.username = part.substr(0, usrpos); - } - - part = part.substr(usrpos + 1); - } - - std::string::size_type popos = part.rfind(':'); - if (popos != std::string::npos) - { - url.port = atoi(part.substr(popos + 1).c_str()); - url.domain = part.substr(0, popos); - } - else - { - url.domain = part; - } - } - else - { - // Request (part of it).. - url.request.append("/"); - url.request.append(part); - } - } - - if (url.request.empty()) - url.request = "/"; - - if ((url.domain.empty()) || (!url.port) || (url.protocol.empty())) - { - Instance->Log(DEFAULT, "Invalid URL (%s): Missing required value", iurl.c_str()); - return false; - } - - if (url.protocol != "http") - { - Instance->Log(DEFAULT, "Invalid URL (%s): Unsupported protocol '%s'", iurl.c_str(), url.protocol.c_str()); - return false; - } - - return true; -} - -void HTTPSocket::Connect(const string &ip) -{ - strlcpy(this->IP, ip.c_str(), MAXBUF); - - if (!this->DoConnect()) - { - delete this; - } -} - -bool HTTPSocket::OnConnected() -{ - std::string request = "GET " + url.request + " HTTP/1.1\r\n"; - - // Dump headers into the request - HeaderMap headers = req.GetHeaders(); - - for (HeaderMap::iterator i = headers.begin(); i != headers.end(); i++) - request += i->first + ": " + i->second + "\r\n"; - - // The Host header is required for HTTP 1.1 and isn't known when the request is created; if they didn't overload it - // manually, add it here - if (headers.find("Host") == headers.end()) - request += "Host: " + url.domain + "\r\n"; - - request += "\r\n"; - - this->status = HTTP_REQSENT; - - return this->Write(request); -} - -bool HTTPSocket::OnDataReady() -{ - char *data = this->Read(); - - if (!data) - { - this->Close(); - return false; - } - - if (this->status < HTTP_DATA) - { - std::string line; - std::string::size_type pos; - - this->buffer += data; - while ((pos = buffer.find("\r\n")) != std::string::npos) - { - line = buffer.substr(0, pos); - buffer = buffer.substr(pos + 2); - if (line.empty()) - { - this->status = HTTP_DATA; - this->data += this->buffer; - this->buffer.clear(); - break; - } - - if (this->status == HTTP_REQSENT) - { - // HTTP reply (HTTP/1.1 200 msg) - char const* data = line.c_str(); - data += 9; - response = new HTTPClientResponse((Module*)Mod, req.GetSource() , url.url, atoi(data), data + 4); - this->status = HTTP_HEADERS; - continue; - } - - if ((pos = line.find(':')) != std::string::npos) - { - response->AddHeader(line.substr(0, pos), line.substr(pos + 1)); - } - else - { - continue; - } - } - } - else - { - this->data += data; - } - return true; -} - -void HTTPSocket::OnClose() -{ - if (data.empty()) - return; // notification that request failed? - - response->data = data; - response->Send(); - delete response; -} - -MODULE_INIT(ModuleHTTPClient) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "httpclient.h"
/* $ModDesc: HTTP client service provider */
class URL
{
public:
std::string url;
std::string protocol, username, password, domain, request;
int port;
};
class HTTPSocket : public InspSocket
{
private:
InspIRCd *Server;
class ModuleHTTPClient *Mod;
HTTPClientRequest req;
HTTPClientResponse *response;
URL url;
enum { HTTP_CLOSED, HTTP_REQSENT, HTTP_HEADERS, HTTP_DATA } status;
std::string data;
std::string buffer;
public:
HTTPSocket(InspIRCd *Instance, class ModuleHTTPClient *Mod);
virtual ~HTTPSocket();
virtual bool DoRequest(HTTPClientRequest *req);
virtual bool ParseURL(const std::string &url);
virtual void Connect(const std::string &ip);
virtual bool OnConnected();
virtual bool OnDataReady();
virtual void OnClose();
};
class HTTPResolver : public Resolver
{
private:
HTTPSocket *socket;
public:
HTTPResolver(HTTPSocket *socket, InspIRCd *Instance, const string &hostname, bool &cached, Module* me) : Resolver(Instance, hostname, DNS_QUERY_FORWARD, cached, me), socket(socket)
{
}
void OnLookupComplete(const string &result, unsigned int ttl, bool cached)
{
socket->Connect(result);
}
void OnError(ResolverError e, const string &errmsg)
{
delete socket;
}
};
typedef vector<HTTPSocket*> HTTPList;
class ModuleHTTPClient : public Module
{
public:
HTTPList sockets;
ModuleHTTPClient(InspIRCd *Me)
: Module(Me)
{
}
virtual ~ModuleHTTPClient()
{
for (HTTPList::iterator i = sockets.begin(); i != sockets.end(); i++)
delete *i;
}
virtual Version GetVersion()
{
return Version(1, 0, 0, 0, VF_SERVICEPROVIDER | VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnRequest] = 1;
}
char* OnRequest(Request *req)
{
HTTPClientRequest *httpreq = (HTTPClientRequest *)req;
if (!strcmp(httpreq->GetId(), HTTP_CLIENT_REQUEST))
{
HTTPSocket *sock = new HTTPSocket(ServerInstance, this);
sock->DoRequest(httpreq);
// No return value
}
return NULL;
}
};
HTTPSocket::HTTPSocket(InspIRCd *Instance, ModuleHTTPClient *Mod)
: InspSocket(Instance), Server(Instance), Mod(Mod), status(HTTP_CLOSED)
{
this->ClosePending = false;
this->port = 80;
}
HTTPSocket::~HTTPSocket()
{
Close();
for (HTTPList::iterator i = Mod->sockets.begin(); i != Mod->sockets.end(); i++)
{
if (*i == this)
{
Mod->sockets.erase(i);
break;
}
}
}
bool HTTPSocket::DoRequest(HTTPClientRequest *req)
{
/* Tweak by brain - we take a copy of this,
* so that the caller doesnt need to leave
* pointers knocking around, less chance of
* a memory leak.
*/
this->req = *req;
if (!ParseURL(this->req.GetURL()))
return false;
this->port = url.port;
strlcpy(this->host, url.domain.c_str(), MAXBUF);
in_addr addy1;
#ifdef IPV6
in6_addr addy2;
if ((inet_aton(this->host, &addy1) > 0) || (inet_pton(AF_INET6, this->host, &addy2) > 0))
#else
if (inet_aton(this->host, &addy1) > 0)
#endif
{
bool cached;
HTTPResolver* r = new HTTPResolver(this, Server, url.domain, cached, (Module*)Mod);
Instance->AddResolver(r, cached);
return true;
}
else
{
this->Connect(url.domain);
}
return true;
}
bool HTTPSocket::ParseURL(const std::string &iurl)
{
url.url = iurl;
url.port = 80;
url.protocol = "http";
irc::sepstream tokenizer(iurl, '/');
for (int p = 0;; p++)
{
std::string part = tokenizer.GetToken();
if (part.empty() && tokenizer.StreamEnd())
break;
if ((p == 0) && (part[part.length() - 1] == ':'))
{
// Protocol ('http:')
url.protocol = part.substr(0, part.length() - 1);
}
else if ((p == 1) && (part.empty()))
{
continue;
}
else if (url.domain.empty())
{
// Domain part: [user[:pass]@]domain[:port]
std::string::size_type usrpos = part.find('@');
if (usrpos != std::string::npos)
{
// Have a user (and possibly password) part
std::string::size_type ppos = part.find(':');
if ((ppos != std::string::npos) && (ppos < usrpos))
{
// Have password too
url.password = part.substr(ppos + 1, usrpos - ppos - 1);
url.username = part.substr(0, ppos);
}
else
{
url.username = part.substr(0, usrpos);
}
part = part.substr(usrpos + 1);
}
std::string::size_type popos = part.rfind(':');
if (popos != std::string::npos)
{
url.port = atoi(part.substr(popos + 1).c_str());
url.domain = part.substr(0, popos);
}
else
{
url.domain = part;
}
}
else
{
// Request (part of it)..
url.request.append("/");
url.request.append(part);
}
}
if (url.request.empty())
url.request = "/";
if ((url.domain.empty()) || (!url.port) || (url.protocol.empty()))
{
Instance->Log(DEFAULT, "Invalid URL (%s): Missing required value", iurl.c_str());
return false;
}
if (url.protocol != "http")
{
Instance->Log(DEFAULT, "Invalid URL (%s): Unsupported protocol '%s'", iurl.c_str(), url.protocol.c_str());
return false;
}
return true;
}
void HTTPSocket::Connect(const string &ip)
{
strlcpy(this->IP, ip.c_str(), MAXBUF);
if (!this->DoConnect())
{
delete this;
}
}
bool HTTPSocket::OnConnected()
{
std::string request = "GET " + url.request + " HTTP/1.1\r\n";
// Dump headers into the request
HeaderMap headers = req.GetHeaders();
for (HeaderMap::iterator i = headers.begin(); i != headers.end(); i++)
request += i->first + ": " + i->second + "\r\n";
// The Host header is required for HTTP 1.1 and isn't known when the request is created; if they didn't overload it
// manually, add it here
if (headers.find("Host") == headers.end())
request += "Host: " + url.domain + "\r\n";
request += "\r\n";
this->status = HTTP_REQSENT;
return this->Write(request);
}
bool HTTPSocket::OnDataReady()
{
char *data = this->Read();
if (!data)
{
this->Close();
return false;
}
if (this->status < HTTP_DATA)
{
std::string line;
std::string::size_type pos;
this->buffer += data;
while ((pos = buffer.find("\r\n")) != std::string::npos)
{
line = buffer.substr(0, pos);
buffer = buffer.substr(pos + 2);
if (line.empty())
{
this->status = HTTP_DATA;
this->data += this->buffer;
this->buffer.clear();
break;
}
if (this->status == HTTP_REQSENT)
{
// HTTP reply (HTTP/1.1 200 msg)
char const* data = line.c_str();
data += 9;
response = new HTTPClientResponse((Module*)Mod, req.GetSource() , url.url, atoi(data), data + 4);
this->status = HTTP_HEADERS;
continue;
}
if ((pos = line.find(':')) != std::string::npos)
{
response->AddHeader(line.substr(0, pos), line.substr(pos + 1));
}
else
{
continue;
}
}
}
else
{
this->data += data;
}
return true;
}
void HTTPSocket::OnClose()
{
if (data.empty())
return; // notification that request failed?
response->data = data;
response->Send();
delete response;
}
MODULE_INIT(ModuleHTTPClient)
\ No newline at end of file diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index 8494863a3..6ff80ad80 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -1,419 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <algorithm> -#include "modules.h" -#include "httpd.h" - -/* $ModDesc: Provides HTTP serving facilities to modules */ - -class ModuleHttpServer; - -static ModuleHttpServer* HttpModule; -static bool claimed; - -/** HTTP socket states - */ -enum HttpState -{ - HTTP_LISTEN = 0, - HTTP_SERVE_WAIT_REQUEST = 1, - HTTP_SERVE_RECV_POSTDATA = 2, - HTTP_SERVE_SEND_DATA = 3 -}; - -class HttpServerSocket; - -/** This class is used to handle HTTP socket timeouts - */ -class HttpServerTimeout : public InspTimer -{ - private: - /** HttpServerSocket we are attached to - */ - HttpServerSocket* s; - /** Socketengine the file descriptor is in - */ - SocketEngine* SE; - public: - /** Attach timeout to HttpServerSocket - */ - HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine); - /** Handle timer tick - */ - void Tick(time_t TIME); -}; - -/** A socket used for HTTP transport - */ -class HttpServerSocket : public InspSocket -{ - FileReader* index; - HttpState InternalState; - std::stringstream headers; - std::string postdata; - std::string request_type; - std::string uri; - std::string http_version; - unsigned int postsize; - HttpServerTimeout* Timeout; - - public: - - HttpServerSocket(InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, FileReader* index_page) : InspSocket(SI, host, port, listening, maxtime), index(index_page), postsize(0) - { - InternalState = HTTP_LISTEN; - Timeout = NULL; - } - - HttpServerSocket(InspIRCd* SI, int newfd, char* ip, FileReader* ind) : InspSocket(SI, newfd, ip), index(ind), postsize(0) - { - InternalState = HTTP_SERVE_WAIT_REQUEST; - Timeout = new HttpServerTimeout(this, Instance->SE); - Instance->Timers->AddTimer(Timeout); - } - - FileReader* GetIndex() - { - return index; - } - - ~HttpServerSocket() - { - if (Timeout) - { - if (Instance->Time() < Timeout->GetTimer()) - Instance->Timers->DelTimer(Timeout); - Timeout = NULL; - } - } - - virtual int OnIncomingConnection(int newsock, char* ip) - { - if (InternalState == HTTP_LISTEN) - { - HttpServerSocket* s = new HttpServerSocket(this->Instance, newsock, ip, index); - s = s; /* Stop GCC whining */ - } - return true; - } - - virtual void OnClose() - { - } - - std::string Response(int response) - { - switch (response) - { - case 100: - return "CONTINUE"; - case 101: - return "SWITCHING PROTOCOLS"; - case 200: - return "OK"; - case 201: - return "CREATED"; - case 202: - return "ACCEPTED"; - case 203: - return "NON-AUTHORITATIVE INFORMATION"; - case 204: - return "NO CONTENT"; - case 205: - return "RESET CONTENT"; - case 206: - return "PARTIAL CONTENT"; - case 300: - return "MULTIPLE CHOICES"; - case 301: - return "MOVED PERMENANTLY"; - case 302: - return "FOUND"; - case 303: - return "SEE OTHER"; - case 304: - return "NOT MODIFIED"; - case 305: - return "USE PROXY"; - case 307: - return "TEMPORARY REDIRECT"; - case 400: - return "BAD REQUEST"; - case 401: - return "UNAUTHORIZED"; - case 402: - return "PAYMENT REQUIRED"; - case 403: - return "FORBIDDEN"; - case 404: - return "NOT FOUND"; - case 405: - return "METHOD NOT ALLOWED"; - case 406: - return "NOT ACCEPTABLE"; - case 407: - return "PROXY AUTHENTICATION REQUIRED"; - case 408: - return "REQUEST TIMEOUT"; - case 409: - return "CONFLICT"; - case 410: - return "GONE"; - case 411: - return "LENGTH REQUIRED"; - case 412: - return "PRECONDITION FAILED"; - case 413: - return "REQUEST ENTITY TOO LARGE"; - case 414: - return "REQUEST-URI TOO LONG"; - case 415: - return "UNSUPPORTED MEDIA TYPE"; - case 416: - return "REQUESTED RANGE NOT SATISFIABLE"; - case 417: - return "EXPECTATION FAILED"; - case 500: - return "INTERNAL SERVER ERROR"; - case 501: - return "NOT IMPLEMENTED"; - case 502: - return "BAD GATEWAY"; - case 503: - return "SERVICE UNAVAILABLE"; - case 504: - return "GATEWAY TIMEOUT"; - case 505: - return "HTTP VERSION NOT SUPPORTED"; - default: - return "WTF"; - break; - - } - } - - void SendHeaders(unsigned long size, int response, const std::string &extraheaders) - { - time_t local = this->Instance->Time(); - struct tm *timeinfo = gmtime(&local); - this->Write("HTTP/1.1 "+ConvToStr(response)+" "+Response(response)+"\r\nDate: "); - this->Write(asctime(timeinfo)); - if (extraheaders.empty()) - { - this->Write("Content-Type: text/html\r\n"); - } - else - { - this->Write(extraheaders); - } - this->Write("Server: InspIRCd/m_httpd.so/1.1\r\nContent-Length: "+ConvToStr(size)+ - "\r\nConnection: close\r\n\r\n"); - } - - virtual bool OnDataReady() - { - char* data = this->Read(); - - /* Check that the data read is a valid pointer and it has some content */ - if (data && *data) - { - headers << data; - - if (headers.str().find("\r\n\r\n") != std::string::npos) - { - if (request_type.empty()) - { - headers >> request_type; - headers >> uri; - headers >> http_version; - - std::transform(request_type.begin(), request_type.end(), request_type.begin(), ::toupper); - std::transform(http_version.begin(), http_version.end(), http_version.begin(), ::toupper); - } - - if ((InternalState == HTTP_SERVE_WAIT_REQUEST) && (request_type == "POST")) - { - /* Do we need to fetch postdata? */ - postdata.clear(); - InternalState = HTTP_SERVE_RECV_POSTDATA; - std::string header_item; - while (headers >> header_item) - { - if (header_item == "Content-Length:") - { - headers >> header_item; - postsize = atoi(header_item.c_str()); - } - } - if (!postsize) - { - InternalState = HTTP_SERVE_SEND_DATA; - SendHeaders(0, 400, ""); - Timeout = new HttpServerTimeout(this, Instance->SE); - Instance->Timers->AddTimer(Timeout); - } - else - { - std::string::size_type x = headers.str().find("\r\n\r\n"); - postdata = headers.str().substr(x+4, headers.str().length()); - /* Get content length and store */ - if (postdata.length() >= postsize) - ServeData(); - } - } - else if (InternalState == HTTP_SERVE_RECV_POSTDATA) - { - /* Add postdata, once we have it all, send the event */ - postdata.append(data); - if (postdata.length() >= postsize) - ServeData(); - } - else - { - ServeData(); - } - return true; - } - return true; - } - else - { - return false; - } - } - - void ServeData() - { - /* Headers are complete */ - InternalState = HTTP_SERVE_SEND_DATA; - - Instance->Timers->DelTimer(Timeout); - Timeout = NULL; - - if ((http_version != "HTTP/1.1") && (http_version != "HTTP/1.0")) - { - SendHeaders(0, 505, ""); - } - else - { - if ((request_type == "GET") && (uri == "/")) - { - SendHeaders(index->ContentSize(), 200, ""); - this->Write(index->Contents()); - } - else - { - claimed = false; - HTTPRequest httpr(request_type,uri,&headers,this,this->GetIP(),postdata); - Event e((char*)&httpr, (Module*)HttpModule, "httpd_url"); - e.Send(this->Instance); - if (!claimed) - { - SendHeaders(0, 404, ""); - } - } - } - Timeout = new HttpServerTimeout(this, Instance->SE); - Instance->Timers->AddTimer(Timeout); - } - - void Page(std::stringstream* n, int response, std::string& extraheaders) - { - SendHeaders(n->str().length(), response, extraheaders); - this->Write(n->str()); - } -}; - -HttpServerTimeout::HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine) : InspTimer(60, time(NULL)), s(sock), SE(engine) -{ -} - -void HttpServerTimeout::Tick(time_t TIME) -{ - SE->DelFd(s); - s->Close(); -} - -class ModuleHttpServer : public Module -{ - std::vector<HttpServerSocket*> httpsocks; - public: - - void ReadConfig() - { - int port; - std::string host; - std::string bindip; - std::string indexfile; - FileReader* index; - HttpServerSocket* http; - ConfigReader c(ServerInstance); - - httpsocks.clear(); - - for (int i = 0; i < c.Enumerate("http"); i++) - { - host = c.ReadValue("http", "host", i); - bindip = c.ReadValue("http", "ip", i); - port = c.ReadInteger("http", "port", i, true); - indexfile = c.ReadValue("http", "index", i); - index = new FileReader(ServerInstance, indexfile); - if (!index->Exists()) - throw ModuleException("Can't read index file: "+indexfile); - http = new HttpServerSocket(ServerInstance, bindip, port, true, 0, index); - httpsocks.push_back(http); - } - } - - ModuleHttpServer(InspIRCd* Me) : Module(Me) - { - ReadConfig(); - } - - void OnEvent(Event* event) - { - } - - char* OnRequest(Request* request) - { - claimed = true; - HTTPDocument* doc = (HTTPDocument*)request->GetData(); - HttpServerSocket* sock = (HttpServerSocket*)doc->sock; - sock->Page(doc->GetDocument(), doc->GetResponseCode(), doc->GetExtraHeaders()); - return NULL; - } - - void Implements(char* List) - { - List[I_OnEvent] = List[I_OnRequest] = 1; - } - - virtual ~ModuleHttpServer() - { - for (size_t i = 0; i < httpsocks.size(); i++) - { - ServerInstance->SE->DelFd(httpsocks[i]); - delete httpsocks[i]->GetIndex(); - delete httpsocks[i]; - } - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION); - } -}; - -MODULE_INIT(ModuleHttpServer) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <algorithm>
#include "modules.h"
#include "httpd.h"
/* $ModDesc: Provides HTTP serving facilities to modules */
class ModuleHttpServer;
static ModuleHttpServer* HttpModule;
static bool claimed;
/** HTTP socket states
*/
enum HttpState
{
HTTP_LISTEN = 0,
HTTP_SERVE_WAIT_REQUEST = 1,
HTTP_SERVE_RECV_POSTDATA = 2,
HTTP_SERVE_SEND_DATA = 3
};
class HttpServerSocket;
/** This class is used to handle HTTP socket timeouts
*/
class HttpServerTimeout : public InspTimer
{
private:
/** HttpServerSocket we are attached to
*/
HttpServerSocket* s;
/** Socketengine the file descriptor is in
*/
SocketEngine* SE;
public:
/** Attach timeout to HttpServerSocket
*/
HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine);
/** Handle timer tick
*/
void Tick(time_t TIME);
};
/** A socket used for HTTP transport
*/
class HttpServerSocket : public InspSocket
{
FileReader* index;
HttpState InternalState;
std::stringstream headers;
std::string postdata;
std::string request_type;
std::string uri;
std::string http_version;
unsigned int postsize;
HttpServerTimeout* Timeout;
public:
HttpServerSocket(InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, FileReader* index_page) : InspSocket(SI, host, port, listening, maxtime), index(index_page), postsize(0)
{
InternalState = HTTP_LISTEN;
Timeout = NULL;
}
HttpServerSocket(InspIRCd* SI, int newfd, char* ip, FileReader* ind) : InspSocket(SI, newfd, ip), index(ind), postsize(0)
{
InternalState = HTTP_SERVE_WAIT_REQUEST;
Timeout = new HttpServerTimeout(this, Instance->SE);
Instance->Timers->AddTimer(Timeout);
}
FileReader* GetIndex()
{
return index;
}
~HttpServerSocket()
{
if (Timeout)
{
if (Instance->Time() < Timeout->GetTimer())
Instance->Timers->DelTimer(Timeout);
Timeout = NULL;
}
}
virtual int OnIncomingConnection(int newsock, char* ip)
{
if (InternalState == HTTP_LISTEN)
{
HttpServerSocket* s = new HttpServerSocket(this->Instance, newsock, ip, index);
s = s; /* Stop GCC whining */
}
return true;
}
virtual void OnClose()
{
}
std::string Response(int response)
{
switch (response)
{
case 100:
return "CONTINUE";
case 101:
return "SWITCHING PROTOCOLS";
case 200:
return "OK";
case 201:
return "CREATED";
case 202:
return "ACCEPTED";
case 203:
return "NON-AUTHORITATIVE INFORMATION";
case 204:
return "NO CONTENT";
case 205:
return "RESET CONTENT";
case 206:
return "PARTIAL CONTENT";
case 300:
return "MULTIPLE CHOICES";
case 301:
return "MOVED PERMENANTLY";
case 302:
return "FOUND";
case 303:
return "SEE OTHER";
case 304:
return "NOT MODIFIED";
case 305:
return "USE PROXY";
case 307:
return "TEMPORARY REDIRECT";
case 400:
return "BAD REQUEST";
case 401:
return "UNAUTHORIZED";
case 402:
return "PAYMENT REQUIRED";
case 403:
return "FORBIDDEN";
case 404:
return "NOT FOUND";
case 405:
return "METHOD NOT ALLOWED";
case 406:
return "NOT ACCEPTABLE";
case 407:
return "PROXY AUTHENTICATION REQUIRED";
case 408:
return "REQUEST TIMEOUT";
case 409:
return "CONFLICT";
case 410:
return "GONE";
case 411:
return "LENGTH REQUIRED";
case 412:
return "PRECONDITION FAILED";
case 413:
return "REQUEST ENTITY TOO LARGE";
case 414:
return "REQUEST-URI TOO LONG";
case 415:
return "UNSUPPORTED MEDIA TYPE";
case 416:
return "REQUESTED RANGE NOT SATISFIABLE";
case 417:
return "EXPECTATION FAILED";
case 500:
return "INTERNAL SERVER ERROR";
case 501:
return "NOT IMPLEMENTED";
case 502:
return "BAD GATEWAY";
case 503:
return "SERVICE UNAVAILABLE";
case 504:
return "GATEWAY TIMEOUT";
case 505:
return "HTTP VERSION NOT SUPPORTED";
default:
return "WTF";
break;
}
}
void SendHeaders(unsigned long size, int response, const std::string &extraheaders)
{
time_t local = this->Instance->Time();
struct tm *timeinfo = gmtime(&local);
this->Write("HTTP/1.1 "+ConvToStr(response)+" "+Response(response)+"\r\nDate: ");
this->Write(asctime(timeinfo));
if (extraheaders.empty())
{
this->Write("Content-Type: text/html\r\n");
}
else
{
this->Write(extraheaders);
}
this->Write("Server: InspIRCd/m_httpd.so/1.1\r\nContent-Length: "+ConvToStr(size)+
"\r\nConnection: close\r\n\r\n");
}
virtual bool OnDataReady()
{
char* data = this->Read();
/* Check that the data read is a valid pointer and it has some content */
if (data && *data)
{
headers << data;
if (headers.str().find("\r\n\r\n") != std::string::npos)
{
if (request_type.empty())
{
headers >> request_type;
headers >> uri;
headers >> http_version;
std::transform(request_type.begin(), request_type.end(), request_type.begin(), ::toupper);
std::transform(http_version.begin(), http_version.end(), http_version.begin(), ::toupper);
}
if ((InternalState == HTTP_SERVE_WAIT_REQUEST) && (request_type == "POST"))
{
/* Do we need to fetch postdata? */
postdata.clear();
InternalState = HTTP_SERVE_RECV_POSTDATA;
std::string header_item;
while (headers >> header_item)
{
if (header_item == "Content-Length:")
{
headers >> header_item;
postsize = atoi(header_item.c_str());
}
}
if (!postsize)
{
InternalState = HTTP_SERVE_SEND_DATA;
SendHeaders(0, 400, "");
Timeout = new HttpServerTimeout(this, Instance->SE);
Instance->Timers->AddTimer(Timeout);
}
else
{
std::string::size_type x = headers.str().find("\r\n\r\n");
postdata = headers.str().substr(x+4, headers.str().length());
/* Get content length and store */
if (postdata.length() >= postsize)
ServeData();
}
}
else if (InternalState == HTTP_SERVE_RECV_POSTDATA)
{
/* Add postdata, once we have it all, send the event */
postdata.append(data);
if (postdata.length() >= postsize)
ServeData();
}
else
{
ServeData();
}
return true;
}
return true;
}
else
{
return false;
}
}
void ServeData()
{
/* Headers are complete */
InternalState = HTTP_SERVE_SEND_DATA;
Instance->Timers->DelTimer(Timeout);
Timeout = NULL;
if ((http_version != "HTTP/1.1") && (http_version != "HTTP/1.0"))
{
SendHeaders(0, 505, "");
}
else
{
if ((request_type == "GET") && (uri == "/"))
{
SendHeaders(index->ContentSize(), 200, "");
this->Write(index->Contents());
}
else
{
claimed = false;
HTTPRequest httpr(request_type,uri,&headers,this,this->GetIP(),postdata);
Event e((char*)&httpr, (Module*)HttpModule, "httpd_url");
e.Send(this->Instance);
if (!claimed)
{
SendHeaders(0, 404, "");
}
}
}
Timeout = new HttpServerTimeout(this, Instance->SE);
Instance->Timers->AddTimer(Timeout);
}
void Page(std::stringstream* n, int response, std::string& extraheaders)
{
SendHeaders(n->str().length(), response, extraheaders);
this->Write(n->str());
}
};
HttpServerTimeout::HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine) : InspTimer(60, time(NULL)), s(sock), SE(engine)
{
}
void HttpServerTimeout::Tick(time_t TIME)
{
SE->DelFd(s);
s->Close();
}
class ModuleHttpServer : public Module
{
std::vector<HttpServerSocket*> httpsocks;
public:
void ReadConfig()
{
int port;
std::string host;
std::string bindip;
std::string indexfile;
FileReader* index;
HttpServerSocket* http;
ConfigReader c(ServerInstance);
httpsocks.clear();
for (int i = 0; i < c.Enumerate("http"); i++)
{
host = c.ReadValue("http", "host", i);
bindip = c.ReadValue("http", "ip", i);
port = c.ReadInteger("http", "port", i, true);
indexfile = c.ReadValue("http", "index", i);
index = new FileReader(ServerInstance, indexfile);
if (!index->Exists())
throw ModuleException("Can't read index file: "+indexfile);
http = new HttpServerSocket(ServerInstance, bindip, port, true, 0, index);
httpsocks.push_back(http);
}
}
ModuleHttpServer(InspIRCd* Me) : Module(Me)
{
ReadConfig();
}
void OnEvent(Event* event)
{
}
char* OnRequest(Request* request)
{
claimed = true;
HTTPDocument* doc = (HTTPDocument*)request->GetData();
HttpServerSocket* sock = (HttpServerSocket*)doc->sock;
sock->Page(doc->GetDocument(), doc->GetResponseCode(), doc->GetExtraHeaders());
return NULL;
}
void Implements(char* List)
{
List[I_OnEvent] = List[I_OnRequest] = 1;
}
virtual ~ModuleHttpServer()
{
for (size_t i = 0; i < httpsocks.size(); i++)
{
ServerInstance->SE->DelFd(httpsocks[i]);
delete httpsocks[i]->GetIndex();
delete httpsocks[i];
}
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
}
};
MODULE_INIT(ModuleHttpServer)
\ No newline at end of file diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 5c29123f8..49b5bbab5 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -1,241 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "configreader.h" -#include "modules.h" -#include "inspsocket.h" -#include "httpd.h" - -/* $ModDesc: Provides statistics over HTTP via m_httpd.so */ - -typedef std::map<irc::string,int> StatsHash; -typedef StatsHash::iterator StatsIter; - -typedef std::vector<std::pair<int,irc::string> > SortedList; -typedef SortedList::iterator SortedIter; - -static StatsHash* sh = new StatsHash(); -static SortedList* so = new SortedList(); - -class ModuleHttpStats : public Module -{ - - std::string stylesheet; - bool changed; - - public: - - void ReadConfig() - { - ConfigReader c(ServerInstance); - this->stylesheet = c.ReadValue("httpstats", "stylesheet", 0); - } - - ModuleHttpStats(InspIRCd* Me) : Module(Me) - { - - ReadConfig(); - this->changed = false; - } - - void InsertOrder(irc::string channel, int count) - { - /* This function figures out where in the sorted list to put an item from the hash */ - SortedIter a; - for (a = so->begin(); a != so->end(); a++) - { - /* Found an item equal to or less than, we insert our item before it */ - if (a->first <= count) - { - so->insert(a,std::pair<int,irc::string>(count,channel)); - return; - } - } - /* There are no items in the list yet, insert something at the beginning */ - so->insert(so->begin(), std::pair<int,irc::string>(count,channel)); - } - - void SortList() - { - /* Sorts the hash into the sorted list using an insertion sort */ - so->clear(); - for (StatsIter a = sh->begin(); a != sh->end(); a++) - InsertOrder(a->first, a->second); - this->changed = false; - } - - void OnEvent(Event* event) - { - std::stringstream data(""); - - if (event->GetEventID() == "httpd_url") - { - HTTPRequest* http = (HTTPRequest*)event->GetData(); - - if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/")) - { - data << "<!DOCTYPE html PUBLIC \ - \"-//W3C//DTD XHTML 1.1//EN\" \ - \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n\ - <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">"; - - data << "<head>"; - data << "<link rel='stylesheet' href='" << this->stylesheet << "' type='text/css' />"; - data << "<title>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</title>"; - data << "</head><body>"; - data << "<h1>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</h1>"; - - data << "<div class='totals'>"; - data << "<h2>Totals</h2>"; - data << "<table>"; - data << "<tr><td>Users</td><td>" << ServerInstance->clientlist->size() << "</td></tr>"; - data << "<tr><td>Channels</td><td>" << ServerInstance->chanlist->size() << "</td></tr>"; - data << "<tr><td>Opers</td><td>" << ServerInstance->all_opers.size() << "</td></tr>"; - data << "<tr><td>Sockets</td><td>" << (ServerInstance->SE->GetMaxFds() - ServerInstance->SE->GetRemainingFds()) << " (Max: " << ServerInstance->SE->GetMaxFds() << " via socket engine '" << ServerInstance->SE->GetName() << "')</td></tr>"; - data << "</table>"; - data << "</div>"; - - data << "<div class='modules'>"; - data << "<h2>Modules</h2>"; - data << "<table>"; - for (int i = 0; i <= ServerInstance->GetModuleCount(); i++) - { - if (!ServerInstance->Config->module_names[i].empty()) - data << "<tr><td>" << ServerInstance->Config->module_names[i] << "</td></tr>"; - } - data << "</table>"; - data << "</div>"; - - data << "<div class='channels'>"; - data << "<h2>Channels</h2>"; - data << "<table>"; - data << "<tr><th>Users</th><th>Name</th><th>@</th><th>%</th><th>+</th><th>Topic</th></tr>"; - - /* If the list has changed since last time it was displayed, re-sort it - * this time only (not every time, as this would be moronic) - */ - if (this->changed) - this->SortList(); - - int n = 0; - for (SortedIter a = so->begin(); ((a != so->end()) && (n < 25)); a++, n++) - { - chanrec* c = ServerInstance->FindChan(a->second.c_str()); - if (c) - { - data << "<tr><td>" << a->first << "</td><td>" << a->second << "</td>"; - data << "<td>" << c->GetOppedUsers()->size() << "</td>"; - data << "<td>" << c->GetHalfoppedUsers()->size() << "</td>"; - data << "<td>" << c->GetVoicedUsers()->size() << "</td>"; - data << "<td>" << c->topic << "</td>"; - data << "</tr>"; - } - } - - data << "</table>"; - data << "</div>"; - - - - - - data << "<div class='validion'>"; - data << "<p><a href='http://validator.w3.org/check?uri=referer'><img src='http://www.w3.org/Icons/valid-xhtml11' alt='Valid XHTML 1.1' height='31' width='88' /></a></p>"; - data << "</div>"; - - data << "</body>"; - data << "</html>"; - - /* Send the document back to m_httpd */ - HTTPDocument response(http->sock, &data, 200, "X-Powered-By: m_http_stats.so\r\nContent-Type: text/html; charset=iso-8859-1\r\n"); - Request req((char*)&response, (Module*)this, event->GetSource()); - req.Send(); - } - } - } - - void OnChannelDelete(chanrec* chan) - { - StatsIter a = sh->find(chan->name); - if (a != sh->end()) - { - sh->erase(a); - } - this->changed = true; - } - - void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - StatsIter a = sh->find(channel->name); - if (a != sh->end()) - { - a->second++; - } - else - { - irc::string name = channel->name; - sh->insert(std::pair<irc::string,int>(name,1)); - } - this->changed = true; - } - - void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent) - { - StatsIter a = sh->find(channel->name); - if (a != sh->end()) - { - a->second--; - } - this->changed = true; - } - - void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message) - { - for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++) - { - chanrec* c = v->first; - StatsIter a = sh->find(c->name); - if (a != sh->end()) - { - a->second--; - } - } - this->changed = true; - } - - char* OnRequest(Request* request) - { - return NULL; - } - - void Implements(char* List) - { - List[I_OnEvent] = List[I_OnRequest] = List[I_OnChannelDelete] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = 1; - } - - virtual ~ModuleHttpStats() - { - delete sh; - delete so; - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleHttpStats) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "configreader.h"
#include "modules.h"
#include "inspsocket.h"
#include "httpd.h"
/* $ModDesc: Provides statistics over HTTP via m_httpd.so */
typedef std::map<irc::string,int> StatsHash;
typedef StatsHash::iterator StatsIter;
typedef std::vector<std::pair<int,irc::string> > SortedList;
typedef SortedList::iterator SortedIter;
static StatsHash* sh = new StatsHash();
static SortedList* so = new SortedList();
class ModuleHttpStats : public Module
{
std::string stylesheet;
bool changed;
public:
void ReadConfig()
{
ConfigReader c(ServerInstance);
this->stylesheet = c.ReadValue("httpstats", "stylesheet", 0);
}
ModuleHttpStats(InspIRCd* Me) : Module(Me)
{
ReadConfig();
this->changed = false;
}
void InsertOrder(irc::string channel, int count)
{
/* This function figures out where in the sorted list to put an item from the hash */
SortedIter a;
for (a = so->begin(); a != so->end(); a++)
{
/* Found an item equal to or less than, we insert our item before it */
if (a->first <= count)
{
so->insert(a,std::pair<int,irc::string>(count,channel));
return;
}
}
/* There are no items in the list yet, insert something at the beginning */
so->insert(so->begin(), std::pair<int,irc::string>(count,channel));
}
void SortList()
{
/* Sorts the hash into the sorted list using an insertion sort */
so->clear();
for (StatsIter a = sh->begin(); a != sh->end(); a++)
InsertOrder(a->first, a->second);
this->changed = false;
}
void OnEvent(Event* event)
{
std::stringstream data("");
if (event->GetEventID() == "httpd_url")
{
HTTPRequest* http = (HTTPRequest*)event->GetData();
if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/"))
{
data << "<!DOCTYPE html PUBLIC \
\"-//W3C//DTD XHTML 1.1//EN\" \
\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">";
data << "<head>";
data << "<link rel='stylesheet' href='" << this->stylesheet << "' type='text/css' />";
data << "<title>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</title>";
data << "</head><body>";
data << "<h1>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</h1>";
data << "<div class='totals'>";
data << "<h2>Totals</h2>";
data << "<table>";
data << "<tr><td>Users</td><td>" << ServerInstance->clientlist->size() << "</td></tr>";
data << "<tr><td>Channels</td><td>" << ServerInstance->chanlist->size() << "</td></tr>";
data << "<tr><td>Opers</td><td>" << ServerInstance->all_opers.size() << "</td></tr>";
data << "<tr><td>Sockets</td><td>" << (ServerInstance->SE->GetMaxFds() - ServerInstance->SE->GetRemainingFds()) << " (Max: " << ServerInstance->SE->GetMaxFds() << " via socket engine '" << ServerInstance->SE->GetName() << "')</td></tr>";
data << "</table>";
data << "</div>";
data << "<div class='modules'>";
data << "<h2>Modules</h2>";
data << "<table>";
for (int i = 0; i <= ServerInstance->GetModuleCount(); i++)
{
if (!ServerInstance->Config->module_names[i].empty())
data << "<tr><td>" << ServerInstance->Config->module_names[i] << "</td></tr>";
}
data << "</table>";
data << "</div>";
data << "<div class='channels'>";
data << "<h2>Channels</h2>";
data << "<table>";
data << "<tr><th>Users</th><th>Name</th><th>@</th><th>%</th><th>+</th><th>Topic</th></tr>";
/* If the list has changed since last time it was displayed, re-sort it
* this time only (not every time, as this would be moronic)
*/
if (this->changed)
this->SortList();
int n = 0;
for (SortedIter a = so->begin(); ((a != so->end()) && (n < 25)); a++, n++)
{
chanrec* c = ServerInstance->FindChan(a->second.c_str());
if (c)
{
data << "<tr><td>" << a->first << "</td><td>" << a->second << "</td>";
data << "<td>" << c->GetOppedUsers()->size() << "</td>";
data << "<td>" << c->GetHalfoppedUsers()->size() << "</td>";
data << "<td>" << c->GetVoicedUsers()->size() << "</td>";
data << "<td>" << c->topic << "</td>";
data << "</tr>";
}
}
data << "</table>";
data << "</div>";
data << "<div class='validion'>";
data << "<p><a href='http://validator.w3.org/check?uri=referer'><img src='http://www.w3.org/Icons/valid-xhtml11' alt='Valid XHTML 1.1' height='31' width='88' /></a></p>";
data << "</div>";
data << "</body>";
data << "</html>";
/* Send the document back to m_httpd */
HTTPDocument response(http->sock, &data, 200, "X-Powered-By: m_http_stats.so\r\nContent-Type: text/html; charset=iso-8859-1\r\n");
Request req((char*)&response, (Module*)this, event->GetSource());
req.Send();
}
}
}
void OnChannelDelete(chanrec* chan)
{
StatsIter a = sh->find(chan->name);
if (a != sh->end())
{
sh->erase(a);
}
this->changed = true;
}
void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
StatsIter a = sh->find(channel->name);
if (a != sh->end())
{
a->second++;
}
else
{
irc::string name = channel->name;
sh->insert(std::pair<irc::string,int>(name,1));
}
this->changed = true;
}
void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
{
StatsIter a = sh->find(channel->name);
if (a != sh->end())
{
a->second--;
}
this->changed = true;
}
void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
{
for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)
{
chanrec* c = v->first;
StatsIter a = sh->find(c->name);
if (a != sh->end())
{
a->second--;
}
}
this->changed = true;
}
char* OnRequest(Request* request)
{
return NULL;
}
void Implements(char* List)
{
List[I_OnEvent] = List[I_OnRequest] = List[I_OnChannelDelete] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = 1;
}
virtual ~ModuleHttpStats()
{
delete sh;
delete so;
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleHttpStats)
\ No newline at end of file diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index 732c2eaee..bf71f8189 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -1,326 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for RFC 1413 ident lookups */ - -// Version 1.5.0.0 - Updated to use InspSocket, faster and neater. - -/** Handles RFC1413 ident connections to users - */ -class RFC1413 : public InspSocket -{ - protected: - socklen_t uslen; // length of our port number - socklen_t themlen; // length of their port number - char ident_request[128]; // buffer used to make up the request string - public: - - userrec* u; // user record that the lookup is associated with - int ufd; - - RFC1413(InspIRCd* SI, userrec* user, int maxtime, const std::string &bindto) : InspSocket(SI, user->GetIPString(), 113, false, maxtime, bindto), u(user) - { - ufd = user->GetFd(); - } - - virtual void OnTimeout() - { - // When we timeout, the connection failed within the allowed timeframe, - // so we just display a notice, and tidy off the ident_data. - if (u && (Instance->SE->GetRef(ufd) == u)) - { - u->Shrink("ident_data"); - Instance->next_call = Instance->Time(); - } - } - - virtual bool OnDataReady() - { - char* ibuf = this->Read(); - if (ibuf) - { - char* savept; - char* section = strtok_r(ibuf,":",&savept); - while (section) - { - if (strstr(section,"USERID")) - { - section = strtok_r(NULL,":",&savept); - if (section) - { - // ID type, usually UNIX or OTHER... we dont want it, so read the next token - section = strtok_r(NULL,":",&savept); - if (section) - { - while (*section == ' ') section++; // strip leading spaces - for (char* j = section; *j; j++) - if ((*j < 33) || (*j > 126)) - *j = '\0'; // truncate at invalid chars - if (*section) - { - if (u && (Instance->SE->GetRef(ufd) == u)) - { - if (this->Instance->IsIdent(section)) - { - u->Extend("IDENT", new std::string(std::string(section) + "," + std::string(u->ident))); - strlcpy(u->ident,section,IDENTMAX); - u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Found your ident: "+std::string(u->ident)); - } - } - } - return false; - } - } - } - section = strtok_r(NULL,":",&savept); - } - } - return false; - } - - virtual void OnClose() - { - // tidy up after ourselves when the connection is done. - // We receive this event straight after a timeout, too. - // - // - // OK, now listen up. The weird looking check here is - // REQUIRED. Don't try and optimize it away. - // - // When a socket is closed, it is not immediately removed - // from the socket list, there can be a short delay - // before it is culled from the list. This means that - // without this check, there is a chance that a user - // may not exist when we come to ::Shrink them, which - // results in a segfault. The value of "u" may not - // always be NULL at this point, so, what we do is - // check against the fd_ref_table, to see if (1) the user - // exists, and (2) its the SAME user, on the same file - // descriptor that they were when the lookup began. - // - // Fixes issue reported by webs, 7 Jun 2006 - if (u && (Instance->SE->GetRef(ufd) == u)) - { - Instance->next_call = Instance->Time(); - u->Shrink("ident_data"); - } - } - - virtual void OnError(InspSocketError e) - { - if (u && (Instance->SE->GetRef(ufd) == u)) - { - if (*u->ident == '~') - u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Could not find your ident, using "+std::string(u->ident)+" instead."); - - Instance->next_call = Instance->Time(); - u->Shrink("ident_data"); - } - } - - virtual bool OnConnected() - { - if (u && (Instance->SE->GetRef(ufd) == u)) - { - sockaddr* sock_us = new sockaddr[2]; - sockaddr* sock_them = new sockaddr[2]; - bool success = false; - uslen = sizeof(sockaddr_in); - themlen = sizeof(sockaddr_in); -#ifdef IPV6 - if (this->u->GetProtocolFamily() == AF_INET6) - { - themlen = sizeof(sockaddr_in6); - uslen = sizeof(sockaddr_in6); - } -#endif - success = ((getsockname(this->u->GetFd(),sock_us,&uslen) || getpeername(this->u->GetFd(), sock_them, &themlen))); - if (success) - { - delete[] sock_us; - delete[] sock_them; - return false; - } - else - { - // send the request in the following format: theirsocket,oursocket -#ifdef IPV6 - if (this->u->GetProtocolFamily() == AF_INET6) - snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in6*)sock_them)->sin6_port),ntohs(((sockaddr_in6*)sock_us)->sin6_port)); - else -#endif - snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in*)sock_them)->sin_port),ntohs(((sockaddr_in*)sock_us)->sin_port)); - this->Write(ident_request); - delete[] sock_us; - delete[] sock_them; - return true; - } - } - else - { - Instance->next_call = Instance->Time(); - return true; - } - } -}; - -class ModuleIdent : public Module -{ - - ConfigReader* Conf; - int IdentTimeout; - std::string PortBind; - - public: - void ReadSettings() - { - Conf = new ConfigReader(ServerInstance); - IdentTimeout = Conf->ReadInteger("ident", "timeout", 0, true); - PortBind = Conf->ReadValue("ident", "bind", 0); - if (!IdentTimeout) - IdentTimeout = 1; - DELETE(Conf); - } - - ModuleIdent(InspIRCd* Me) - : Module(Me) - { - - ReadSettings(); - } - - void Implements(char* List) - { - List[I_OnCleanup] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1; - } - - void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable) - { - if ((displayable) && (extname == "IDENT")) - { - std::string* ident; - if (GetExt("IDENT", ident)) - proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *ident); - } - } - - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ReadSettings(); - } - - virtual int OnUserRegister(userrec* user) - { - /* - * when the new user connects, before they authenticate with USER/NICK/PASS, we do - * their ident lookup. We do this by instantiating an object of type RFC1413, which - * is derived from InspSocket, and inserting it into the socket engine using the - * Server::AddSocket() call. - */ - char newident[MAXBUF]; - strcpy(newident,"~"); - strlcat(newident,user->ident,IDENTMAX); - strlcpy(user->ident,newident,IDENTMAX); - - - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Looking up your ident..."); - RFC1413* ident = new RFC1413(ServerInstance, user, IdentTimeout, PortBind); - if ((ident->GetState() == I_CONNECTING) || (ident->GetState() == I_CONNECTED)) - { - user->Extend("ident_data", (char*)ident); - } - else - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not find your ident, using "+std::string(user->ident)+" instead."); - ServerInstance->next_call = ServerInstance->Time(); - } - return 0; - } - - virtual bool OnCheckReady(userrec* user) - { - /* - * The socket engine will clean up their ident request for us when it completes, - * either due to timeout or due to closing, so, we just hold them until they dont - * have an ident field any more. - */ - RFC1413* ident; - return (!user->GetExt("ident_data", ident)); - } - - virtual void OnCleanup(int target_type, void* item) - { - if (target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - RFC1413* ident; - std::string* identstr; - if (user->GetExt("ident_data", ident)) - { - // FIX: If the user record is deleted, the socket wont be removed - // immediately so there is chance of the socket trying to write to - // a user which has now vanished! To prevent this, set ident::u - // to NULL and check it so that we dont write users who have gone away. - ident->u = NULL; - ServerInstance->SE->DelFd(ident); - //delete ident; - } - if (user->GetExt("IDENT", identstr)) - { - delete identstr; - } - } - } - - virtual void OnUserDisconnect(userrec* user) - { - /* - * when the user quits tidy up any ident lookup they have pending to keep things tidy. - * When we call RemoveSocket, the abstractions tied into the system evnetually work their - * way to RFC1459::OnClose(), which shrinks off the ident_data for us, so we dont need - * to do it here. If we don't tidy this up, there may still be lingering idents for users - * who have quit, as class RFC1459 is only loosely bound to userrec* via a pair of pointers - * and this would leave at least one of the invalid ;) - */ - RFC1413* ident; - std::string* identstr; - if (user->GetExt("ident_data", ident)) - { - ident->u = NULL; - ServerInstance->SE->DelFd(ident); - } - if (user->GetExt("IDENT", identstr)) - { - delete identstr; - } - } - - virtual ~ModuleIdent() - { - ServerInstance->next_call = ServerInstance->Time(); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleIdent) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for RFC 1413 ident lookups */
// Version 1.5.0.0 - Updated to use InspSocket, faster and neater.
/** Handles RFC1413 ident connections to users
*/
class RFC1413 : public InspSocket
{
protected:
socklen_t uslen; // length of our port number
socklen_t themlen; // length of their port number
char ident_request[128]; // buffer used to make up the request string
public:
userrec* u; // user record that the lookup is associated with
int ufd;
RFC1413(InspIRCd* SI, userrec* user, int maxtime, const std::string &bindto) : InspSocket(SI, user->GetIPString(), 113, false, maxtime, bindto), u(user)
{
ufd = user->GetFd();
}
virtual void OnTimeout()
{
// When we timeout, the connection failed within the allowed timeframe,
// so we just display a notice, and tidy off the ident_data.
if (u && (Instance->SE->GetRef(ufd) == u))
{
u->Shrink("ident_data");
Instance->next_call = Instance->Time();
}
}
virtual bool OnDataReady()
{
char* ibuf = this->Read();
if (ibuf)
{
char* savept;
char* section = strtok_r(ibuf,":",&savept);
while (section)
{
if (strstr(section,"USERID"))
{
section = strtok_r(NULL,":",&savept);
if (section)
{
// ID type, usually UNIX or OTHER... we dont want it, so read the next token
section = strtok_r(NULL,":",&savept);
if (section)
{
while (*section == ' ') section++; // strip leading spaces
for (char* j = section; *j; j++)
if ((*j < 33) || (*j > 126))
*j = '\0'; // truncate at invalid chars
if (*section)
{
if (u && (Instance->SE->GetRef(ufd) == u))
{
if (this->Instance->IsIdent(section))
{
u->Extend("IDENT", new std::string(std::string(section) + "," + std::string(u->ident)));
strlcpy(u->ident,section,IDENTMAX);
u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Found your ident: "+std::string(u->ident));
}
}
}
return false;
}
}
}
section = strtok_r(NULL,":",&savept);
}
}
return false;
}
virtual void OnClose()
{
// tidy up after ourselves when the connection is done.
// We receive this event straight after a timeout, too.
//
//
// OK, now listen up. The weird looking check here is
// REQUIRED. Don't try and optimize it away.
//
// When a socket is closed, it is not immediately removed
// from the socket list, there can be a short delay
// before it is culled from the list. This means that
// without this check, there is a chance that a user
// may not exist when we come to ::Shrink them, which
// results in a segfault. The value of "u" may not
// always be NULL at this point, so, what we do is
// check against the fd_ref_table, to see if (1) the user
// exists, and (2) its the SAME user, on the same file
// descriptor that they were when the lookup began.
//
// Fixes issue reported by webs, 7 Jun 2006
if (u && (Instance->SE->GetRef(ufd) == u))
{
Instance->next_call = Instance->Time();
u->Shrink("ident_data");
}
}
virtual void OnError(InspSocketError e)
{
if (u && (Instance->SE->GetRef(ufd) == u))
{
if (*u->ident == '~')
u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Could not find your ident, using "+std::string(u->ident)+" instead.");
Instance->next_call = Instance->Time();
u->Shrink("ident_data");
}
}
virtual bool OnConnected()
{
if (u && (Instance->SE->GetRef(ufd) == u))
{
sockaddr* sock_us = new sockaddr[2];
sockaddr* sock_them = new sockaddr[2];
bool success = false;
uslen = sizeof(sockaddr_in);
themlen = sizeof(sockaddr_in);
#ifdef IPV6
if (this->u->GetProtocolFamily() == AF_INET6)
{
themlen = sizeof(sockaddr_in6);
uslen = sizeof(sockaddr_in6);
}
#endif
success = ((getsockname(this->u->GetFd(),sock_us,&uslen) || getpeername(this->u->GetFd(), sock_them, &themlen)));
if (success)
{
delete[] sock_us;
delete[] sock_them;
return false;
}
else
{
// send the request in the following format: theirsocket,oursocket
#ifdef IPV6
if (this->u->GetProtocolFamily() == AF_INET6)
snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in6*)sock_them)->sin6_port),ntohs(((sockaddr_in6*)sock_us)->sin6_port));
else
#endif
snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in*)sock_them)->sin_port),ntohs(((sockaddr_in*)sock_us)->sin_port));
this->Write(ident_request);
delete[] sock_us;
delete[] sock_them;
return true;
}
}
else
{
Instance->next_call = Instance->Time();
return true;
}
}
};
class ModuleIdent : public Module
{
ConfigReader* Conf;
int IdentTimeout;
std::string PortBind;
public:
void ReadSettings()
{
Conf = new ConfigReader(ServerInstance);
IdentTimeout = Conf->ReadInteger("ident", "timeout", 0, true);
PortBind = Conf->ReadValue("ident", "bind", 0);
if (!IdentTimeout)
IdentTimeout = 1;
DELETE(Conf);
}
ModuleIdent(InspIRCd* Me)
: Module(Me)
{
ReadSettings();
}
void Implements(char* List)
{
List[I_OnCleanup] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1;
}
void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)
{
if ((displayable) && (extname == "IDENT"))
{
std::string* ident;
if (GetExt("IDENT", ident))
proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *ident);
}
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadSettings();
}
virtual int OnUserRegister(userrec* user)
{
/*
* when the new user connects, before they authenticate with USER/NICK/PASS, we do
* their ident lookup. We do this by instantiating an object of type RFC1413, which
* is derived from InspSocket, and inserting it into the socket engine using the
* Server::AddSocket() call.
*/
char newident[MAXBUF];
strcpy(newident,"~");
strlcat(newident,user->ident,IDENTMAX);
strlcpy(user->ident,newident,IDENTMAX);
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Looking up your ident...");
RFC1413* ident = new RFC1413(ServerInstance, user, IdentTimeout, PortBind);
if ((ident->GetState() == I_CONNECTING) || (ident->GetState() == I_CONNECTED))
{
user->Extend("ident_data", (char*)ident);
}
else
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not find your ident, using "+std::string(user->ident)+" instead.");
ServerInstance->next_call = ServerInstance->Time();
}
return 0;
}
virtual bool OnCheckReady(userrec* user)
{
/*
* The socket engine will clean up their ident request for us when it completes,
* either due to timeout or due to closing, so, we just hold them until they dont
* have an ident field any more.
*/
RFC1413* ident;
return (!user->GetExt("ident_data", ident));
}
virtual void OnCleanup(int target_type, void* item)
{
if (target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
RFC1413* ident;
std::string* identstr;
if (user->GetExt("ident_data", ident))
{
// FIX: If the user record is deleted, the socket wont be removed
// immediately so there is chance of the socket trying to write to
// a user which has now vanished! To prevent this, set ident::u
// to NULL and check it so that we dont write users who have gone away.
ident->u = NULL;
ServerInstance->SE->DelFd(ident);
//delete ident;
}
if (user->GetExt("IDENT", identstr))
{
delete identstr;
}
}
}
virtual void OnUserDisconnect(userrec* user)
{
/*
* when the user quits tidy up any ident lookup they have pending to keep things tidy.
* When we call RemoveSocket, the abstractions tied into the system evnetually work their
* way to RFC1459::OnClose(), which shrinks off the ident_data for us, so we dont need
* to do it here. If we don't tidy this up, there may still be lingering idents for users
* who have quit, as class RFC1459 is only loosely bound to userrec* via a pair of pointers
* and this would leave at least one of the invalid ;)
*/
RFC1413* ident;
std::string* identstr;
if (user->GetExt("ident_data", ident))
{
ident->u = NULL;
ServerInstance->SE->DelFd(ident);
}
if (user->GetExt("IDENT", identstr))
{
delete identstr;
}
}
virtual ~ModuleIdent()
{
ServerInstance->next_call = ServerInstance->Time();
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleIdent)
\ No newline at end of file diff --git a/src/modules/m_invisible.cpp b/src/modules/m_invisible.cpp index e1fb88ca0..ce2f2062b 100644 --- a/src/modules/m_invisible.cpp +++ b/src/modules/m_invisible.cpp @@ -1,277 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include <stdarg.h> - -/* $ModDesc: Allows for opered clients to join channels without being seen, similar to unreal 3.1 +I mode */ - -static ConfigReader* conf; - -class QuietOper : public VisData -{ - public: - QuietOper() - { - } - - virtual ~QuietOper() - { - } - - virtual bool VisibleTo(userrec* user) - { - return IS_OPER(user); - } -}; - - -class InvisibleMode : public ModeHandler -{ - QuietOper* qo; - public: - InvisibleMode(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_USER, true) - { - qo = new QuietOper(); - } - - ~InvisibleMode() - { - for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++) - if (i->second->Visibility == qo) - i->second->Visibility = NULL; - delete qo; - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (source != dest) - return MODEACTION_DENY; - - if (dest->IsModeSet('Q') != adding) - { - bool ok = false; - - for (int j = 0; j < conf->Enumerate("type"); j++) - { - std::string opertype = conf->ReadValue("type","name",j); - if (opertype == source->oper) - { - ok = conf->ReadFlag("type", "canquiet", j); - break; - } - } - - if (!ok) - { - source->WriteServ("481 %s :Permission Denied - You do not have access to become invisible via user mode +Q", source->nick); - return MODEACTION_DENY; - } - - dest->SetMode('Q', adding); - - /* Set visibility handler object */ - dest->Visibility = adding ? qo : NULL; - - /* User appears to vanish or appear from nowhere */ - for (UCListIter f = dest->chans.begin(); f != dest->chans.end(); f++) - { - CUList *ulist = f->first->GetUsers(); - char tb[MAXBUF]; - - snprintf(tb,MAXBUF,":%s %s %s", dest->GetFullHost(), adding ? "PART" : "JOIN", f->first->name); - std::string out = tb; - std::string n = this->ServerInstance->Modes->ModeString(dest, f->first); - - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - /* User only appears to vanish for non-opers */ - if (IS_LOCAL(i->first) && !IS_OPER(i->first)) - { - i->first->Write(out); - if (!n.empty() && !adding) - i->first->WriteServ("MODE %s +%s", f->first->name, n.c_str()); - } - } - - ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has become %svisible (%sQ)", dest->GetFullHost(), adding ? "in" : "", adding ? "+" : "-"); - } - return MODEACTION_ALLOW; - } - else - { - return MODEACTION_DENY; - } - } -}; - -class InvisibleDeOper : public ModeWatcher -{ - private: - InspIRCd* Srv; - public: - InvisibleDeOper(InspIRCd* Instance) : ModeWatcher(Instance, 'o', MODETYPE_USER), Srv(Instance) - { - } - - bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string ¶m, bool adding, ModeType type) - { - /* Users who are opers and have +Q get their +Q removed when they deoper */ - if ((!adding) && (dest->IsModeSet('Q'))) - { - const char* newmodes[] = { dest->nick, "-Q" }; - ServerInstance->Modes->Process(newmodes, 2, source, true); - } - return true; - } -}; - - -class ModuleInvisible : public Module -{ - private: - InvisibleMode* qm; - InvisibleDeOper* ido; - public: - ModuleInvisible(InspIRCd* Me) - : Module(Me) - { - conf = new ConfigReader(ServerInstance); - qm = new InvisibleMode(ServerInstance); - if (!ServerInstance->AddMode(qm, 'Q')) - throw ModuleException("Could not add new modes!"); - ido = new InvisibleDeOper(ServerInstance); - if (!ServerInstance->AddModeWatcher(ido)) - throw ModuleException("Could not add new mode watcher on usermode +o!"); - } - - virtual ~ModuleInvisible() - { - ServerInstance->Modes->DelMode(qm); - ServerInstance->Modes->DelModeWatcher(ido); - DELETE(qm); - DELETE(ido); - DELETE(conf); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = List[I_OnRehash] = 1; - } - - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - if (user->IsModeSet('Q')) - { - silent = true; - /* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */ - this->WriteCommonFrom(user, channel, "JOIN %s", channel->name); - ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has joined %s invisibly (+Q)", user->GetFullHost(), channel->name); - } - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - DELETE(conf); - conf = new ConfigReader(ServerInstance); - } - - void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent) - { - if (user->IsModeSet('Q')) - { - silent = true; - /* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */ - this->WriteCommonFrom(user, channel, "PART %s%s%s", channel->name, - partmessage.empty() ? "" : " :", - partmessage.empty() ? "" : partmessage.c_str()); - } - } - - void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - if (user->IsModeSet('Q')) - { - command_t* parthandler = ServerInstance->Parser->GetHandler("PART"); - std::vector<std::string> to_leave; - const char* parameters[2]; - if (parthandler) - { - for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++) - to_leave.push_back(f->first->name); - /* We cant do this neatly in one loop, as we are modifying the map we are iterating */ - for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++) - { - parameters[0] = n->c_str(); - /* This triggers our OnUserPart, above, making the PART silent */ - parthandler->Handle(parameters, 1, user); - } - } - } - } - - /* No privmsg response when hiding - submitted by Eric at neowin */ - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if ((target_type == TYPE_USER) && (IS_LOCAL(user))) - { - userrec* target = (userrec*)dest; - if(target->IsModeSet('Q') && !*user->oper) - { - user->WriteServ("401 %s %s :No such nick/channel",user->nick, target->nick); - return 1; - } - } - return 0; - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreNotice(user, dest, target_type, text, status, exempt_list); - } - - /* Fix by Eric @ neowin.net, thanks :) -- Brain */ - void WriteCommonFrom(userrec *user, chanrec* channel, const char* text, ...) - { - va_list argsPtr; - char textbuffer[MAXBUF]; - char tb[MAXBUF]; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),textbuffer); - - CUList *ulist = channel->GetUsers(); - - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - /* User only appears to vanish for non-opers */ - if (IS_LOCAL(i->first) && IS_OPER(i->first)) - { - i->first->Write(std::string(tb)); - } - } - } - -}; - -MODULE_INIT(ModuleInvisible) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include <stdarg.h>
/* $ModDesc: Allows for opered clients to join channels without being seen, similar to unreal 3.1 +I mode */
static ConfigReader* conf;
class QuietOper : public VisData
{
public:
QuietOper()
{
}
virtual ~QuietOper()
{
}
virtual bool VisibleTo(userrec* user)
{
return IS_OPER(user);
}
};
class InvisibleMode : public ModeHandler
{
QuietOper* qo;
public:
InvisibleMode(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_USER, true)
{
qo = new QuietOper();
}
~InvisibleMode()
{
for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
if (i->second->Visibility == qo)
i->second->Visibility = NULL;
delete qo;
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (source != dest)
return MODEACTION_DENY;
if (dest->IsModeSet('Q') != adding)
{
bool ok = false;
for (int j = 0; j < conf->Enumerate("type"); j++)
{
std::string opertype = conf->ReadValue("type","name",j);
if (opertype == source->oper)
{
ok = conf->ReadFlag("type", "canquiet", j);
break;
}
}
if (!ok)
{
source->WriteServ("481 %s :Permission Denied - You do not have access to become invisible via user mode +Q", source->nick);
return MODEACTION_DENY;
}
dest->SetMode('Q', adding);
/* Set visibility handler object */
dest->Visibility = adding ? qo : NULL;
/* User appears to vanish or appear from nowhere */
for (UCListIter f = dest->chans.begin(); f != dest->chans.end(); f++)
{
CUList *ulist = f->first->GetUsers();
char tb[MAXBUF];
snprintf(tb,MAXBUF,":%s %s %s", dest->GetFullHost(), adding ? "PART" : "JOIN", f->first->name);
std::string out = tb;
std::string n = this->ServerInstance->Modes->ModeString(dest, f->first);
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
/* User only appears to vanish for non-opers */
if (IS_LOCAL(i->first) && !IS_OPER(i->first))
{
i->first->Write(out);
if (!n.empty() && !adding)
i->first->WriteServ("MODE %s +%s", f->first->name, n.c_str());
}
}
ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has become %svisible (%sQ)", dest->GetFullHost(), adding ? "in" : "", adding ? "+" : "-");
}
return MODEACTION_ALLOW;
}
else
{
return MODEACTION_DENY;
}
}
};
class InvisibleDeOper : public ModeWatcher
{
private:
InspIRCd* Srv;
public:
InvisibleDeOper(InspIRCd* Instance) : ModeWatcher(Instance, 'o', MODETYPE_USER), Srv(Instance)
{
}
bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string ¶m, bool adding, ModeType type)
{
/* Users who are opers and have +Q get their +Q removed when they deoper */
if ((!adding) && (dest->IsModeSet('Q')))
{
const char* newmodes[] = { dest->nick, "-Q" };
ServerInstance->Modes->Process(newmodes, 2, source, true);
}
return true;
}
};
class ModuleInvisible : public Module
{
private:
InvisibleMode* qm;
InvisibleDeOper* ido;
public:
ModuleInvisible(InspIRCd* Me)
: Module(Me)
{
conf = new ConfigReader(ServerInstance);
qm = new InvisibleMode(ServerInstance);
if (!ServerInstance->AddMode(qm, 'Q'))
throw ModuleException("Could not add new modes!");
ido = new InvisibleDeOper(ServerInstance);
if (!ServerInstance->AddModeWatcher(ido))
throw ModuleException("Could not add new mode watcher on usermode +o!");
}
virtual ~ModuleInvisible()
{
ServerInstance->Modes->DelMode(qm);
ServerInstance->Modes->DelModeWatcher(ido);
DELETE(qm);
DELETE(ido);
DELETE(conf);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = List[I_OnRehash] = 1;
}
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
if (user->IsModeSet('Q'))
{
silent = true;
/* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */
this->WriteCommonFrom(user, channel, "JOIN %s", channel->name);
ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has joined %s invisibly (+Q)", user->GetFullHost(), channel->name);
}
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
DELETE(conf);
conf = new ConfigReader(ServerInstance);
}
void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
{
if (user->IsModeSet('Q'))
{
silent = true;
/* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */
this->WriteCommonFrom(user, channel, "PART %s%s%s", channel->name,
partmessage.empty() ? "" : " :",
partmessage.empty() ? "" : partmessage.c_str());
}
}
void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
if (user->IsModeSet('Q'))
{
command_t* parthandler = ServerInstance->Parser->GetHandler("PART");
std::vector<std::string> to_leave;
const char* parameters[2];
if (parthandler)
{
for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)
to_leave.push_back(f->first->name);
/* We cant do this neatly in one loop, as we are modifying the map we are iterating */
for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++)
{
parameters[0] = n->c_str();
/* This triggers our OnUserPart, above, making the PART silent */
parthandler->Handle(parameters, 1, user);
}
}
}
}
/* No privmsg response when hiding - submitted by Eric at neowin */
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
{
userrec* target = (userrec*)dest;
if(target->IsModeSet('Q') && !*user->oper)
{
user->WriteServ("401 %s %s :No such nick/channel",user->nick, target->nick);
return 1;
}
}
return 0;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
}
/* Fix by Eric @ neowin.net, thanks :) -- Brain */
void WriteCommonFrom(userrec *user, chanrec* channel, const char* text, ...)
{
va_list argsPtr;
char textbuffer[MAXBUF];
char tb[MAXBUF];
va_start(argsPtr, text);
vsnprintf(textbuffer, MAXBUF, text, argsPtr);
va_end(argsPtr);
snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),textbuffer);
CUList *ulist = channel->GetUsers();
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
/* User only appears to vanish for non-opers */
if (IS_LOCAL(i->first) && IS_OPER(i->first))
{
i->first->Write(std::string(tb));
}
}
}
};
MODULE_INIT(ModuleInvisible)
\ No newline at end of file diff --git a/src/modules/m_inviteexception.cpp b/src/modules/m_inviteexception.cpp index b7b9920c5..e51503b26 100644 --- a/src/modules/m_inviteexception.cpp +++ b/src/modules/m_inviteexception.cpp @@ -1,150 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "mode.h" -#include "u_listmode.h" - -/* $ModDesc: Provides support for the +I channel mode */ -/* $ModDep: ../../include/u_listmode.h */ - -/* - * Written by Om <om@inspircd.org>, April 2005. - * Based on m_exception, which was originally based on m_chanprotect and m_silence - * - * The +I channel mode takes a nick!ident@host, glob patterns allowed, - * and if a user matches an entry on the +I list then they can join the channel, - * ignoring if +i is set on the channel - * Now supports CIDR and IP addresses -- Brain - */ - -class InspIRCd* ServerInstance; - -/** Handles channel mode +I - */ -class InviteException : public ListModeBase -{ - public: - InviteException(InspIRCd* Instance) : ListModeBase(Instance, 'I', "End of Channel Invite Exception List", "346", "347", true) { } -}; - -class ModuleInviteException : public Module -{ - InviteException* ie; -public: - ModuleInviteException(InspIRCd* Me) : Module(Me) - { - ie = new InviteException(ServerInstance); - if (!ServerInstance->AddMode(ie, 'I')) - throw ModuleException("Could not add new modes!"); - ServerInstance->PublishInterface("ChannelBanList", this); - } - - virtual void Implements(char* List) - { - ie->DoImplements(List); - List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckInvite] = 1; - } - - virtual void On005Numeric(std::string &output) - { - output.append(" INVEX=I"); - } - - virtual int OnCheckInvite(userrec* user, chanrec* chan) - { - if(chan != NULL) - { - modelist* list; - chan->GetExt(ie->GetInfoKey(), list); - if (list) - { - char mask[MAXBUF]; - snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString()); - for (modelist::iterator it = list->begin(); it != list->end(); it++) - { - if(match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true))) - { - // They match an entry on the list, so let them in. - return 1; - } - } - } - // or if there wasn't a list, there can't be anyone on it, so we don't need to do anything. - } - - return 0; - } - - virtual char* OnRequest(Request* request) - { - ListModeRequest* LM = (ListModeRequest*)request; - if (strcmp("LM_CHECKLIST", request->GetId()) == 0) - { - modelist* list; - LM->chan->GetExt(ie->GetInfoKey(), list); - if (list) - { - char mask[MAXBUF]; - snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString()); - for (modelist::iterator it = list->begin(); it != list->end(); it++) - { - if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true))) - { - // They match an entry - return (char*)it->mask.c_str(); - } - } - return NULL; - } - } - return NULL; - } - - virtual void OnCleanup(int target_type, void* item) - { - ie->DoCleanup(target_type, item); - } - - virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque) - { - ie->DoSyncChannel(chan, proto, opaque); - } - - virtual void OnChannelDelete(chanrec* chan) - { - ie->DoChannelDelete(chan); - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - ie->DoRehash(); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 3, VF_VENDOR | VF_COMMON, API_VERSION); - } - - ~ModuleInviteException() - { - ServerInstance->Modes->DelMode(ie); - DELETE(ie); - ServerInstance->UnpublishInterface("ChannelBanList", this); - } -}; - -MODULE_INIT(ModuleInviteException) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "mode.h"
#include "u_listmode.h"
/* $ModDesc: Provides support for the +I channel mode */
/* $ModDep: ../../include/u_listmode.h */
/*
* Written by Om <om@inspircd.org>, April 2005.
* Based on m_exception, which was originally based on m_chanprotect and m_silence
*
* The +I channel mode takes a nick!ident@host, glob patterns allowed,
* and if a user matches an entry on the +I list then they can join the channel,
* ignoring if +i is set on the channel
* Now supports CIDR and IP addresses -- Brain
*/
class InspIRCd* ServerInstance;
/** Handles channel mode +I
*/
class InviteException : public ListModeBase
{
public:
InviteException(InspIRCd* Instance) : ListModeBase(Instance, 'I', "End of Channel Invite Exception List", "346", "347", true) { }
};
class ModuleInviteException : public Module
{
InviteException* ie;
public:
ModuleInviteException(InspIRCd* Me) : Module(Me)
{
ie = new InviteException(ServerInstance);
if (!ServerInstance->AddMode(ie, 'I'))
throw ModuleException("Could not add new modes!");
ServerInstance->PublishInterface("ChannelBanList", this);
}
virtual void Implements(char* List)
{
ie->DoImplements(List);
List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckInvite] = 1;
}
virtual void On005Numeric(std::string &output)
{
output.append(" INVEX=I");
}
virtual int OnCheckInvite(userrec* user, chanrec* chan)
{
if(chan != NULL)
{
modelist* list;
chan->GetExt(ie->GetInfoKey(), list);
if (list)
{
char mask[MAXBUF];
snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());
for (modelist::iterator it = list->begin(); it != list->end(); it++)
{
if(match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
{
// They match an entry on the list, so let them in.
return 1;
}
}
}
// or if there wasn't a list, there can't be anyone on it, so we don't need to do anything.
}
return 0;
}
virtual char* OnRequest(Request* request)
{
ListModeRequest* LM = (ListModeRequest*)request;
if (strcmp("LM_CHECKLIST", request->GetId()) == 0)
{
modelist* list;
LM->chan->GetExt(ie->GetInfoKey(), list);
if (list)
{
char mask[MAXBUF];
snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString());
for (modelist::iterator it = list->begin(); it != list->end(); it++)
{
if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
{
// They match an entry
return (char*)it->mask.c_str();
}
}
return NULL;
}
}
return NULL;
}
virtual void OnCleanup(int target_type, void* item)
{
ie->DoCleanup(target_type, item);
}
virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
{
ie->DoSyncChannel(chan, proto, opaque);
}
virtual void OnChannelDelete(chanrec* chan)
{
ie->DoChannelDelete(chan);
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
ie->DoRehash();
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 3, VF_VENDOR | VF_COMMON, API_VERSION);
}
~ModuleInviteException()
{
ServerInstance->Modes->DelMode(ie);
DELETE(ie);
ServerInstance->UnpublishInterface("ChannelBanList", this);
}
};
MODULE_INIT(ModuleInviteException)
\ No newline at end of file diff --git a/src/modules/m_joinflood.cpp b/src/modules/m_joinflood.cpp index 3d342b636..26339e207 100644 --- a/src/modules/m_joinflood.cpp +++ b/src/modules/m_joinflood.cpp @@ -1,285 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides channel mode +j (join flood protection) */ - -/** Holds settings and state associated with channel mode +j - */ -class joinfloodsettings : public classbase -{ - public: - - int secs; - int joins; - time_t reset; - time_t unlocktime; - int counter; - bool locked; - InspIRCd* ServerInstance; - - joinfloodsettings() : secs(0), joins(0) {}; - - joinfloodsettings(int b, int c) : secs(b), joins(c) - { - reset = time(NULL) + secs; - counter = 0; - locked = false; - }; - - void addjoin() - { - counter++; - if (time(NULL) > reset) - { - counter = 0; - reset = time(NULL) + secs; - } - } - - bool shouldlock() - { - return (counter >= this->joins); - } - - void clear() - { - counter = 0; - } - - bool islocked() - { - if (locked) - { - if (time(NULL) > unlocktime) - { - locked = false; - return false; - } - else - { - return true; - } - } - return false; - } - - void lock() - { - locked = true; - unlocktime = time(NULL) + 60; - } - -}; - -/** Handles channel mode +j - */ -class JoinFlood : public ModeHandler -{ - public: - JoinFlood(InspIRCd* Instance) : ModeHandler(Instance, 'j', 1, 0, false, MODETYPE_CHANNEL, false) { } - - ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) - { - joinfloodsettings* x; - if (channel->GetExt("joinflood",x)) - return std::make_pair(true, ConvToStr(x->joins)+":"+ConvToStr(x->secs)); - else - return std::make_pair(false, parameter); - } - - bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel) - { - /* When TS is equal, the alphabetically later one wins */ - return (their_param < our_param); - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - joinfloodsettings* dummy; - - if (adding) - { - char ndata[MAXBUF]; - char* data = ndata; - strlcpy(ndata,parameter.c_str(),MAXBUF); - char* joins = data; - char* secs = NULL; - while (*data) - { - if (*data == ':') - { - *data = 0; - data++; - secs = data; - break; - } - else data++; - } - if (secs) - - { - /* Set up the flood parameters for this channel */ - int njoins = atoi(joins); - int nsecs = atoi(secs); - if ((njoins<1) || (nsecs<1)) - { - source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - if (!channel->GetExt("joinflood", dummy)) - { - parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs); - joinfloodsettings *f = new joinfloodsettings(nsecs,njoins); - channel->Extend("joinflood", f); - channel->SetMode('j', true); - channel->SetModeParam('j', parameter.c_str(), true); - return MODEACTION_ALLOW; - } - else - { - std::string cur_param = channel->GetModeParameter('j'); - parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs); - if (cur_param == parameter) - { - // mode params match - return MODEACTION_DENY; - } - else - { - // new mode param, replace old with new - if ((nsecs > 0) && (njoins > 0)) - { - joinfloodsettings* f; - channel->GetExt("joinflood", f); - delete f; - f = new joinfloodsettings(nsecs,njoins); - channel->Shrink("joinflood"); - channel->Extend("joinflood", f); - channel->SetModeParam('j', cur_param.c_str(), false); - channel->SetModeParam('j', parameter.c_str(), true); - return MODEACTION_ALLOW; - } - else - { - return MODEACTION_DENY; - } - } - } - } - } - else - { - source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name); - return MODEACTION_DENY; - } - } - else - { - if (channel->GetExt("joinflood", dummy)) - { - joinfloodsettings *f; - channel->GetExt("joinflood", f); - DELETE(f); - channel->Shrink("joinflood"); - channel->SetMode('j', false); - return MODEACTION_ALLOW; - } - } - return MODEACTION_DENY; - } -}; - -class ModuleJoinFlood : public Module -{ - - JoinFlood* jf; - - public: - - ModuleJoinFlood(InspIRCd* Me) - : Module(Me) - { - - jf = new JoinFlood(ServerInstance); - if (!ServerInstance->AddMode(jf, 'j')) - throw ModuleException("Could not add new modes!"); - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if (chan) - { - joinfloodsettings *f; - if (chan->GetExt("joinflood", f)) - { - if (f->islocked()) - { - user->WriteServ("609 %s %s :This channel is temporarily unavailable (+j). Please try again later.",user->nick,chan->name); - return 1; - } - } - } - return 0; - } - - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent) - { - joinfloodsettings *f; - if (channel->GetExt("joinflood",f)) - { - f->addjoin(); - if (f->shouldlock()) - { - f->clear(); - f->lock(); - channel->WriteChannelWithServ((char*)ServerInstance->Config->ServerName, "NOTICE %s :This channel has been closed to new users for 60 seconds because there have been more than %d joins in %d seconds.", channel->name, f->joins, f->secs); - } - } - } - - void OnChannelDelete(chanrec* chan) - { - joinfloodsettings *f; - if (chan->GetExt("joinflood",f)) - { - DELETE(f); - chan->Shrink("joinflood"); - } - } - - void Implements(char* List) - { - List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserJoin] = 1; - } - - virtual ~ModuleJoinFlood() - { - ServerInstance->Modes->DelMode(jf); - DELETE(jf); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleJoinFlood) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides channel mode +j (join flood protection) */
/** Holds settings and state associated with channel mode +j
*/
class joinfloodsettings : public classbase
{
public:
int secs;
int joins;
time_t reset;
time_t unlocktime;
int counter;
bool locked;
InspIRCd* ServerInstance;
joinfloodsettings() : secs(0), joins(0) {};
joinfloodsettings(int b, int c) : secs(b), joins(c)
{
reset = time(NULL) + secs;
counter = 0;
locked = false;
};
void addjoin()
{
counter++;
if (time(NULL) > reset)
{
counter = 0;
reset = time(NULL) + secs;
}
}
bool shouldlock()
{
return (counter >= this->joins);
}
void clear()
{
counter = 0;
}
bool islocked()
{
if (locked)
{
if (time(NULL) > unlocktime)
{
locked = false;
return false;
}
else
{
return true;
}
}
return false;
}
void lock()
{
locked = true;
unlocktime = time(NULL) + 60;
}
};
/** Handles channel mode +j
*/
class JoinFlood : public ModeHandler
{
public:
JoinFlood(InspIRCd* Instance) : ModeHandler(Instance, 'j', 1, 0, false, MODETYPE_CHANNEL, false) { }
ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
{
joinfloodsettings* x;
if (channel->GetExt("joinflood",x))
return std::make_pair(true, ConvToStr(x->joins)+":"+ConvToStr(x->secs));
else
return std::make_pair(false, parameter);
}
bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
{
/* When TS is equal, the alphabetically later one wins */
return (their_param < our_param);
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
joinfloodsettings* dummy;
if (adding)
{
char ndata[MAXBUF];
char* data = ndata;
strlcpy(ndata,parameter.c_str(),MAXBUF);
char* joins = data;
char* secs = NULL;
while (*data)
{
if (*data == ':')
{
*data = 0;
data++;
secs = data;
break;
}
else data++;
}
if (secs)
{
/* Set up the flood parameters for this channel */
int njoins = atoi(joins);
int nsecs = atoi(secs);
if ((njoins<1) || (nsecs<1))
{
source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
parameter.clear();
return MODEACTION_DENY;
}
else
{
if (!channel->GetExt("joinflood", dummy))
{
parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);
joinfloodsettings *f = new joinfloodsettings(nsecs,njoins);
channel->Extend("joinflood", f);
channel->SetMode('j', true);
channel->SetModeParam('j', parameter.c_str(), true);
return MODEACTION_ALLOW;
}
else
{
std::string cur_param = channel->GetModeParameter('j');
parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);
if (cur_param == parameter)
{
// mode params match
return MODEACTION_DENY;
}
else
{
// new mode param, replace old with new
if ((nsecs > 0) && (njoins > 0))
{
joinfloodsettings* f;
channel->GetExt("joinflood", f);
delete f;
f = new joinfloodsettings(nsecs,njoins);
channel->Shrink("joinflood");
channel->Extend("joinflood", f);
channel->SetModeParam('j', cur_param.c_str(), false);
channel->SetModeParam('j', parameter.c_str(), true);
return MODEACTION_ALLOW;
}
else
{
return MODEACTION_DENY;
}
}
}
}
}
else
{
source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
return MODEACTION_DENY;
}
}
else
{
if (channel->GetExt("joinflood", dummy))
{
joinfloodsettings *f;
channel->GetExt("joinflood", f);
DELETE(f);
channel->Shrink("joinflood");
channel->SetMode('j', false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleJoinFlood : public Module
{
JoinFlood* jf;
public:
ModuleJoinFlood(InspIRCd* Me)
: Module(Me)
{
jf = new JoinFlood(ServerInstance);
if (!ServerInstance->AddMode(jf, 'j'))
throw ModuleException("Could not add new modes!");
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if (chan)
{
joinfloodsettings *f;
if (chan->GetExt("joinflood", f))
{
if (f->islocked())
{
user->WriteServ("609 %s %s :This channel is temporarily unavailable (+j). Please try again later.",user->nick,chan->name);
return 1;
}
}
}
return 0;
}
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
joinfloodsettings *f;
if (channel->GetExt("joinflood",f))
{
f->addjoin();
if (f->shouldlock())
{
f->clear();
f->lock();
channel->WriteChannelWithServ((char*)ServerInstance->Config->ServerName, "NOTICE %s :This channel has been closed to new users for 60 seconds because there have been more than %d joins in %d seconds.", channel->name, f->joins, f->secs);
}
}
}
void OnChannelDelete(chanrec* chan)
{
joinfloodsettings *f;
if (chan->GetExt("joinflood",f))
{
DELETE(f);
chan->Shrink("joinflood");
}
}
void Implements(char* List)
{
List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserJoin] = 1;
}
virtual ~ModuleJoinFlood()
{
ServerInstance->Modes->DelMode(jf);
DELETE(jf);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleJoinFlood)
\ No newline at end of file diff --git a/src/modules/m_jumpserver.cpp b/src/modules/m_jumpserver.cpp index 28bbd056e..5a823b44c 100644 --- a/src/modules/m_jumpserver.cpp +++ b/src/modules/m_jumpserver.cpp @@ -1,164 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style SAPART command */ - -/** Handle /SAPART - */ -class cmd_jumpserver : public command_t -{ - public: - bool redirect_all_immediately; - bool redirect_new_users; - bool direction; - std::string redirect_to; - std::string reason; - int port; - - cmd_jumpserver (InspIRCd* Instance) : command_t(Instance, "JUMPSERVER", 'o', 0) - { - this->source = "m_jumpserver.so"; - syntax = "[<server> <port> <+/-a> :<reason>]"; - redirect_to.clear(); - reason.clear(); - port = 0; - redirect_all_immediately = redirect_new_users = false; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - int n_done = 0; - reason = (pcnt < 4) ? "Please use this server/port instead" : parameters[3]; - redirect_all_immediately = false; - redirect_new_users = true; - direction = true; - std::string n_done_s; - - /* No parameters: jumpserver disabled */ - if (!pcnt) - { - if (port) - user->WriteServ("NOTICE %s :*** Disabled jumpserver (previously set to '%s:%d')", user->nick, redirect_to.c_str(), port); - else - user->WriteServ("NOTICE %s :*** jumpserver was not enabled.", user->nick); - - port = 0; - redirect_to.clear(); - return CMD_LOCALONLY; - } - - port = 0; - redirect_to.clear(); - - for (const char* n = parameters[2]; *n; n++) - { - switch (*n) - { - case '+': - direction = true; - break; - case '-': - direction = false; - break; - case 'a': - redirect_all_immediately = direction; - break; - case 'n': - redirect_new_users = direction; - break; - } - } - - if (redirect_all_immediately) - { - /* Redirect everyone but the oper sending the command */ - for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++) - { - userrec* t = *i; - if (!IS_OPER(t)) - { - t->WriteServ("010 %s %s %s :Please use this Server/Port instead", user->nick, parameters[0], parameters[1]); - userrec::QuitUser(ServerInstance, t, reason); - n_done++; - } - } - if (n_done) - { - n_done_s = ConvToStr(n_done); - } - } - - if (redirect_new_users) - { - redirect_to = parameters[0]; - port = atoi(parameters[1]); - } - - user->WriteServ("NOTICE %s :*** Set jumpserver to server '%s' port '%s', flags '+%s%s'%s%s%s: %s", user->nick, parameters[0], parameters[1], - redirect_all_immediately ? "a" : "", - redirect_new_users ? "n" : "", - n_done ? " (" : "", - n_done ? n_done_s.c_str() : "", - n_done ? " user(s) redirected)" : "", - reason.c_str()); - - return CMD_LOCALONLY; - } -}; - - -class ModuleJumpServer : public Module -{ - cmd_jumpserver* js; - public: - ModuleJumpServer(InspIRCd* Me) - : Module(Me) - { - - js = new cmd_jumpserver(ServerInstance); - ServerInstance->AddCommand(js); - } - - virtual ~ModuleJumpServer() - { - } - - virtual int OnUserRegister(userrec* user) - { - if (js->port && js->redirect_new_users) - { - user->WriteServ("010 %s %s %d :Please use this Server/Port instead", user->nick, js->redirect_to.c_str(), js->port); - userrec::QuitUser(ServerInstance, user, js->reason); - return 0; - } - return 0; - } - - virtual void Implements(char* List) - { - List[I_OnUserRegister] = 1; - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleJumpServer) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style SAPART command */
/** Handle /SAPART
*/
class cmd_jumpserver : public command_t
{
public:
bool redirect_all_immediately;
bool redirect_new_users;
bool direction;
std::string redirect_to;
std::string reason;
int port;
cmd_jumpserver (InspIRCd* Instance) : command_t(Instance, "JUMPSERVER", 'o', 0)
{
this->source = "m_jumpserver.so";
syntax = "[<server> <port> <+/-a> :<reason>]";
redirect_to.clear();
reason.clear();
port = 0;
redirect_all_immediately = redirect_new_users = false;
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
int n_done = 0;
reason = (pcnt < 4) ? "Please use this server/port instead" : parameters[3];
redirect_all_immediately = false;
redirect_new_users = true;
direction = true;
std::string n_done_s;
/* No parameters: jumpserver disabled */
if (!pcnt)
{
if (port)
user->WriteServ("NOTICE %s :*** Disabled jumpserver (previously set to '%s:%d')", user->nick, redirect_to.c_str(), port);
else
user->WriteServ("NOTICE %s :*** jumpserver was not enabled.", user->nick);
port = 0;
redirect_to.clear();
return CMD_LOCALONLY;
}
port = 0;
redirect_to.clear();
for (const char* n = parameters[2]; *n; n++)
{
switch (*n)
{
case '+':
direction = true;
break;
case '-':
direction = false;
break;
case 'a':
redirect_all_immediately = direction;
break;
case 'n':
redirect_new_users = direction;
break;
}
}
if (redirect_all_immediately)
{
/* Redirect everyone but the oper sending the command */
for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
{
userrec* t = *i;
if (!IS_OPER(t))
{
t->WriteServ("010 %s %s %s :Please use this Server/Port instead", user->nick, parameters[0], parameters[1]);
userrec::QuitUser(ServerInstance, t, reason);
n_done++;
}
}
if (n_done)
{
n_done_s = ConvToStr(n_done);
}
}
if (redirect_new_users)
{
redirect_to = parameters[0];
port = atoi(parameters[1]);
}
user->WriteServ("NOTICE %s :*** Set jumpserver to server '%s' port '%s', flags '+%s%s'%s%s%s: %s", user->nick, parameters[0], parameters[1],
redirect_all_immediately ? "a" : "",
redirect_new_users ? "n" : "",
n_done ? " (" : "",
n_done ? n_done_s.c_str() : "",
n_done ? " user(s) redirected)" : "",
reason.c_str());
return CMD_LOCALONLY;
}
};
class ModuleJumpServer : public Module
{
cmd_jumpserver* js;
public:
ModuleJumpServer(InspIRCd* Me)
: Module(Me)
{
js = new cmd_jumpserver(ServerInstance);
ServerInstance->AddCommand(js);
}
virtual ~ModuleJumpServer()
{
}
virtual int OnUserRegister(userrec* user)
{
if (js->port && js->redirect_new_users)
{
user->WriteServ("010 %s %s %d :Please use this Server/Port instead", user->nick, js->redirect_to.c_str(), js->port);
userrec::QuitUser(ServerInstance, user, js->reason);
return 0;
}
return 0;
}
virtual void Implements(char* List)
{
List[I_OnUserRegister] = 1;
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleJumpServer)
\ No newline at end of file diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index bdb988ad2..97d88786f 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -1,224 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <sstream> -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides channel mode +J (delay rejoin after kick) */ - -inline int strtoint(const std::string &str) -{ - std::istringstream ss(str); - int result; - ss >> result; - return result; -} - -typedef std::map<userrec*, time_t> delaylist; - -/** Handles channel mode +J - */ -class KickRejoin : public ModeHandler -{ - public: - KickRejoin(InspIRCd* Instance) : ModeHandler(Instance, 'J', 1, 0, false, MODETYPE_CHANNEL, false) { } - - ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) - { - if (channel->IsModeSet('J')) - return std::make_pair(true, channel->GetModeParameter('J')); - else - return std::make_pair(false, parameter); - } - - bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel) - { - /* When TS is equal, the alphabetically later one wins */ - return (their_param < our_param); - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (!adding) - { - // Taking the mode off, we need to clean up. - delaylist* dl; - - if (channel->GetExt("norejoinusers", dl)) - { - DELETE(dl); - channel->Shrink("norejoinusers"); - } - - if (!channel->IsModeSet('J')) - { - return MODEACTION_DENY; - } - else - { - channel->SetMode('J', false); - return MODEACTION_ALLOW; - } - } - else if (atoi(parameter.c_str()) > 0) - { - if (!channel->IsModeSet('J')) - { - parameter = ConvToStr(atoi(parameter.c_str())); - channel->SetModeParam('J', parameter.c_str(), adding); - channel->SetMode('J', adding); - return MODEACTION_ALLOW; - } - else - { - std::string cur_param = channel->GetModeParameter('J'); - if (cur_param == parameter) - { - // mode params match, don't change mode - return MODEACTION_DENY; - } - else - { - // new mode param, replace old with new - parameter = ConvToStr(atoi(parameter.c_str())); - cur_param = ConvToStr(atoi(cur_param.c_str())); - if (parameter != "0") - { - channel->SetModeParam('J', cur_param.c_str(), false); - channel->SetModeParam('J', parameter.c_str(), adding); - return MODEACTION_ALLOW; - } - else - { - /* Fix to jamie's fix, dont allow +J 0 on the new value! */ - return MODEACTION_DENY; - } - } - } - } - else - { - return MODEACTION_DENY; - } - } -}; - -class ModuleKickNoRejoin : public Module -{ - - KickRejoin* kr; - -public: - - ModuleKickNoRejoin(InspIRCd* Me) - : Module(Me) - { - - kr = new KickRejoin(ServerInstance); - if (!ServerInstance->AddMode(kr, 'J')) - throw ModuleException("Could not add new modes!"); - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if (chan) - { - delaylist* dl; - if (chan->GetExt("norejoinusers", dl)) - { - std::vector<userrec*> itemstoremove; - - for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++) - { - if (iter->second > time(NULL)) - { - if (iter->first == user) - { - user->WriteServ( "495 %s %s :You cannot rejoin this channel yet after being kicked (+J)", user->nick, chan->name); - return 1; - } - } - else - { - // Expired record, remove. - itemstoremove.push_back(iter->first); - } - } - - for (unsigned int i = 0; i < itemstoremove.size(); i++) - dl->erase(itemstoremove[i]); - - if (!dl->size()) - { - // Now it's empty.. - DELETE(dl); - chan->Shrink("norejoinusers"); - } - } - } - return 0; - } - - virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent) - { - if (chan->IsModeSet('J') && (source != user)) - { - delaylist* dl; - if (!chan->GetExt("norejoinusers", dl)) - { - dl = new delaylist; - chan->Extend("norejoinusers", dl); - } - (*dl)[user] = time(NULL) + strtoint(chan->GetModeParameter('J')); - } - } - - virtual void OnChannelDelete(chanrec* chan) - { - delaylist* dl; - - if (chan->GetExt("norejoinusers", dl)) - { - DELETE(dl); - chan->Shrink("norejoinusers"); - } - } - - virtual void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_CHANNEL) - OnChannelDelete((chanrec*)item); - } - - virtual void Implements(char* List) - { - List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserKick] = 1; - } - - virtual ~ModuleKickNoRejoin() - { - ServerInstance->Modes->DelMode(kr); - DELETE(kr); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } -}; - - -MODULE_INIT(ModuleKickNoRejoin) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <sstream>
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides channel mode +J (delay rejoin after kick) */
inline int strtoint(const std::string &str)
{
std::istringstream ss(str);
int result;
ss >> result;
return result;
}
typedef std::map<userrec*, time_t> delaylist;
/** Handles channel mode +J
*/
class KickRejoin : public ModeHandler
{
public:
KickRejoin(InspIRCd* Instance) : ModeHandler(Instance, 'J', 1, 0, false, MODETYPE_CHANNEL, false) { }
ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
{
if (channel->IsModeSet('J'))
return std::make_pair(true, channel->GetModeParameter('J'));
else
return std::make_pair(false, parameter);
}
bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
{
/* When TS is equal, the alphabetically later one wins */
return (their_param < our_param);
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (!adding)
{
// Taking the mode off, we need to clean up.
delaylist* dl;
if (channel->GetExt("norejoinusers", dl))
{
DELETE(dl);
channel->Shrink("norejoinusers");
}
if (!channel->IsModeSet('J'))
{
return MODEACTION_DENY;
}
else
{
channel->SetMode('J', false);
return MODEACTION_ALLOW;
}
}
else if (atoi(parameter.c_str()) > 0)
{
if (!channel->IsModeSet('J'))
{
parameter = ConvToStr(atoi(parameter.c_str()));
channel->SetModeParam('J', parameter.c_str(), adding);
channel->SetMode('J', adding);
return MODEACTION_ALLOW;
}
else
{
std::string cur_param = channel->GetModeParameter('J');
if (cur_param == parameter)
{
// mode params match, don't change mode
return MODEACTION_DENY;
}
else
{
// new mode param, replace old with new
parameter = ConvToStr(atoi(parameter.c_str()));
cur_param = ConvToStr(atoi(cur_param.c_str()));
if (parameter != "0")
{
channel->SetModeParam('J', cur_param.c_str(), false);
channel->SetModeParam('J', parameter.c_str(), adding);
return MODEACTION_ALLOW;
}
else
{
/* Fix to jamie's fix, dont allow +J 0 on the new value! */
return MODEACTION_DENY;
}
}
}
}
else
{
return MODEACTION_DENY;
}
}
};
class ModuleKickNoRejoin : public Module
{
KickRejoin* kr;
public:
ModuleKickNoRejoin(InspIRCd* Me)
: Module(Me)
{
kr = new KickRejoin(ServerInstance);
if (!ServerInstance->AddMode(kr, 'J'))
throw ModuleException("Could not add new modes!");
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if (chan)
{
delaylist* dl;
if (chan->GetExt("norejoinusers", dl))
{
std::vector<userrec*> itemstoremove;
for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++)
{
if (iter->second > time(NULL))
{
if (iter->first == user)
{
user->WriteServ( "495 %s %s :You cannot rejoin this channel yet after being kicked (+J)", user->nick, chan->name);
return 1;
}
}
else
{
// Expired record, remove.
itemstoremove.push_back(iter->first);
}
}
for (unsigned int i = 0; i < itemstoremove.size(); i++)
dl->erase(itemstoremove[i]);
if (!dl->size())
{
// Now it's empty..
DELETE(dl);
chan->Shrink("norejoinusers");
}
}
}
return 0;
}
virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
{
if (chan->IsModeSet('J') && (source != user))
{
delaylist* dl;
if (!chan->GetExt("norejoinusers", dl))
{
dl = new delaylist;
chan->Extend("norejoinusers", dl);
}
(*dl)[user] = time(NULL) + strtoint(chan->GetModeParameter('J'));
}
}
virtual void OnChannelDelete(chanrec* chan)
{
delaylist* dl;
if (chan->GetExt("norejoinusers", dl))
{
DELETE(dl);
chan->Shrink("norejoinusers");
}
}
virtual void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_CHANNEL)
OnChannelDelete((chanrec*)item);
}
virtual void Implements(char* List)
{
List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserKick] = 1;
}
virtual ~ModuleKickNoRejoin()
{
ServerInstance->Modes->DelMode(kr);
DELETE(kr);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleKickNoRejoin)
\ No newline at end of file diff --git a/src/modules/m_knock.cpp b/src/modules/m_knock.cpp index 3bc45cceb..9beaa699e 100644 --- a/src/modules/m_knock.cpp +++ b/src/modules/m_knock.cpp @@ -1,129 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for /KNOCK and mode +K */ - -/** Handles the /KNOCK command - */ -class cmd_knock : public command_t -{ - public: - cmd_knock (InspIRCd* Instance) : command_t(Instance,"KNOCK", 0, 2) - { - this->source = "m_knock.so"; - syntax = "<channel> <reason>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - chanrec* c = ServerInstance->FindChan(parameters[0]); - - if (!c) - { - user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]); - return CMD_FAILURE; - } - - std::string line; - - if (c->IsModeSet('K')) - { - user->WriteServ("480 %s :Can't KNOCK on %s, +K is set.",user->nick, c->name); - return CMD_FAILURE; - } - - for (int i = 1; i < pcnt - 1; i++) - { - line = line + std::string(parameters[i]) + " "; - } - line = line + std::string(parameters[pcnt-1]); - - if (!c->modes[CM_INVITEONLY]) - { - user->WriteServ("480 %s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick, c->name); - return CMD_FAILURE; - } - - c->WriteChannelWithServ((char*)ServerInstance->Config->ServerName, "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name, user->nick, c->name, line.c_str()); - user->WriteServ("NOTICE %s :KNOCKing on %s",user->nick,c->name); - return CMD_SUCCESS; - } -}; - -/** Handles channel mode +K - */ -class Knock : public ModeHandler -{ - public: - Knock(InspIRCd* Instance) : ModeHandler(Instance, 'K', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('K')) - { - channel->SetMode('K',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('K')) - { - channel->SetMode('K',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleKnock : public Module -{ - cmd_knock* mycommand; - Knock* kn; - public: - ModuleKnock(InspIRCd* Me) : Module(Me) - { - - kn = new Knock(ServerInstance); - if (!ServerInstance->AddMode(kn, 'K')) - throw ModuleException("Could not add new modes!"); - mycommand = new cmd_knock(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - } - - virtual ~ModuleKnock() - { - ServerInstance->Modes->DelMode(kn); - DELETE(kn); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleKnock) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for /KNOCK and mode +K */
/** Handles the /KNOCK command
*/
class cmd_knock : public command_t
{
public:
cmd_knock (InspIRCd* Instance) : command_t(Instance,"KNOCK", 0, 2)
{
this->source = "m_knock.so";
syntax = "<channel> <reason>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
chanrec* c = ServerInstance->FindChan(parameters[0]);
if (!c)
{
user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]);
return CMD_FAILURE;
}
std::string line;
if (c->IsModeSet('K'))
{
user->WriteServ("480 %s :Can't KNOCK on %s, +K is set.",user->nick, c->name);
return CMD_FAILURE;
}
for (int i = 1; i < pcnt - 1; i++)
{
line = line + std::string(parameters[i]) + " ";
}
line = line + std::string(parameters[pcnt-1]);
if (!c->modes[CM_INVITEONLY])
{
user->WriteServ("480 %s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick, c->name);
return CMD_FAILURE;
}
c->WriteChannelWithServ((char*)ServerInstance->Config->ServerName, "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name, user->nick, c->name, line.c_str());
user->WriteServ("NOTICE %s :KNOCKing on %s",user->nick,c->name);
return CMD_SUCCESS;
}
};
/** Handles channel mode +K
*/
class Knock : public ModeHandler
{
public:
Knock(InspIRCd* Instance) : ModeHandler(Instance, 'K', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('K'))
{
channel->SetMode('K',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('K'))
{
channel->SetMode('K',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleKnock : public Module
{
cmd_knock* mycommand;
Knock* kn;
public:
ModuleKnock(InspIRCd* Me) : Module(Me)
{
kn = new Knock(ServerInstance);
if (!ServerInstance->AddMode(kn, 'K'))
throw ModuleException("Could not add new modes!");
mycommand = new cmd_knock(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
}
virtual ~ModuleKnock()
{
ServerInstance->Modes->DelMode(kn);
DELETE(kn);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleKnock)
\ No newline at end of file diff --git a/src/modules/m_lockserv.cpp b/src/modules/m_lockserv.cpp index 2ca2e3f44..d83961233 100644 --- a/src/modules/m_lockserv.cpp +++ b/src/modules/m_lockserv.cpp @@ -1,131 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Allows locking of the server to stop all incoming connections till unlocked again */ - -/** Adds numerics - * 988 <nick> <servername> :Closed for new connections - * 989 <nick> <servername> :Open for new connections -*/ - - -class cmd_lockserv : public command_t -{ -private: - bool& locked; - -public: - cmd_lockserv (InspIRCd* Instance, bool &lock) - : command_t(Instance, "LOCKSERV", 'o', 0), locked(lock) - { - this->source = "m_lockserv.so"; - syntax.clear(); - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - locked = true; - user->WriteServ("988 %s %s :Closed for new connections", user->nick, user->server); - ServerInstance->WriteOpers("*** Oper %s used LOCKSERV to temporarily close for new connections", user->nick); - /* Dont send to the network */ - return CMD_LOCALONLY; - } -}; - -class cmd_unlockserv : public command_t -{ -private: - bool& locked; - -public: - cmd_unlockserv (InspIRCd* Instance, bool &lock) - : command_t(Instance, "UNLOCKSERV", 'o', 0), locked(lock) - { - this->source = "m_lockserv.so"; - syntax.clear(); - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - locked = false; - user->WriteServ("989 %s %s :Open for new connections", user->nick, user->server); - ServerInstance->WriteOpers("*** Oper %s used UNLOCKSERV to allow for new connections", user->nick); - /* Dont send to the network */ - return CMD_LOCALONLY; - } -}; - -class ModuleLockserv : public Module -{ -private: - bool locked; - cmd_lockserv* lockcommand; - cmd_unlockserv* unlockcommand; - - virtual void ResetLocked() - { - locked = false; - } - -public: - ModuleLockserv(InspIRCd* Me) : Module(Me) - { - ResetLocked(); - lockcommand = new cmd_lockserv(ServerInstance, locked); - ServerInstance->AddCommand(lockcommand); - - unlockcommand = new cmd_unlockserv(ServerInstance, locked); - ServerInstance->AddCommand(unlockcommand); - } - - virtual ~ModuleLockserv() - { - } - - void Implements(char* List) - { - List[I_OnUserRegister] = List[I_OnRehash] = List[I_OnCheckReady] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ResetLocked(); - } - - virtual int OnUserRegister(userrec* user) - { - if (locked) - { - userrec::QuitUser(ServerInstance, user, "Server is temporarily closed. Please try again later."); - return 1; - } - return 0; - } - - virtual bool OnCheckReady(userrec* user) - { - return !locked; - } - - virtual Version GetVersion() - { - return Version(1, 0, 0, 1, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleLockserv) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Allows locking of the server to stop all incoming connections till unlocked again */
/** Adds numerics
* 988 <nick> <servername> :Closed for new connections
* 989 <nick> <servername> :Open for new connections
*/
class cmd_lockserv : public command_t
{
private:
bool& locked;
public:
cmd_lockserv (InspIRCd* Instance, bool &lock)
: command_t(Instance, "LOCKSERV", 'o', 0), locked(lock)
{
this->source = "m_lockserv.so";
syntax.clear();
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
locked = true;
user->WriteServ("988 %s %s :Closed for new connections", user->nick, user->server);
ServerInstance->WriteOpers("*** Oper %s used LOCKSERV to temporarily close for new connections", user->nick);
/* Dont send to the network */
return CMD_LOCALONLY;
}
};
class cmd_unlockserv : public command_t
{
private:
bool& locked;
public:
cmd_unlockserv (InspIRCd* Instance, bool &lock)
: command_t(Instance, "UNLOCKSERV", 'o', 0), locked(lock)
{
this->source = "m_lockserv.so";
syntax.clear();
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
locked = false;
user->WriteServ("989 %s %s :Open for new connections", user->nick, user->server);
ServerInstance->WriteOpers("*** Oper %s used UNLOCKSERV to allow for new connections", user->nick);
/* Dont send to the network */
return CMD_LOCALONLY;
}
};
class ModuleLockserv : public Module
{
private:
bool locked;
cmd_lockserv* lockcommand;
cmd_unlockserv* unlockcommand;
virtual void ResetLocked()
{
locked = false;
}
public:
ModuleLockserv(InspIRCd* Me) : Module(Me)
{
ResetLocked();
lockcommand = new cmd_lockserv(ServerInstance, locked);
ServerInstance->AddCommand(lockcommand);
unlockcommand = new cmd_unlockserv(ServerInstance, locked);
ServerInstance->AddCommand(unlockcommand);
}
virtual ~ModuleLockserv()
{
}
void Implements(char* List)
{
List[I_OnUserRegister] = List[I_OnRehash] = List[I_OnCheckReady] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ResetLocked();
}
virtual int OnUserRegister(userrec* user)
{
if (locked)
{
userrec::QuitUser(ServerInstance, user, "Server is temporarily closed. Please try again later.");
return 1;
}
return 0;
}
virtual bool OnCheckReady(userrec* user)
{
return !locked;
}
virtual Version GetVersion()
{
return Version(1, 0, 0, 1, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleLockserv)
\ No newline at end of file diff --git a/src/modules/m_md5.cpp b/src/modules/m_md5.cpp index 3b7df8369..c9b062e43 100644 --- a/src/modules/m_md5.cpp +++ b/src/modules/m_md5.cpp @@ -1,322 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Allows for MD5 encrypted oper passwords */ -/* $ModDep: m_hash.h */ - -#include "inspircd.h" -#ifdef HAS_STDINT -#include <stdint.h> -#endif -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_hash.h" - -/* The four core functions - F1 is optimized somewhat */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f,w,x,y,z,in,s) \ - (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) - -#ifndef HAS_STDINT -typedef unsigned int uint32_t; -#endif - -typedef uint32_t word32; /* NOT unsigned long. We don't support 16 bit platforms, anyway. */ -typedef unsigned char byte; - -/** An MD5 context, used by m_opermd5 - */ -class MD5Context : public classbase -{ - public: - word32 buf[4]; - word32 bytes[2]; - word32 in[16]; -}; - -class ModuleMD5 : public Module -{ - void byteSwap(word32 *buf, unsigned words) - { - byte *p = (byte *)buf; - - do - { - *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16 | - ((unsigned)p[1] << 8 | p[0]); - p += 4; - } while (--words); - } - - void MD5Init(MD5Context *ctx, unsigned int* key = NULL) - { - /* These are the defaults for md5 */ - if (!key) - { - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - } - else - { - ctx->buf[0] = key[0]; - ctx->buf[1] = key[1]; - ctx->buf[2] = key[2]; - ctx->buf[3] = key[3]; - } - - ctx->bytes[0] = 0; - ctx->bytes[1] = 0; - } - - void MD5Update(MD5Context *ctx, byte const *buf, int len) - { - word32 t; - - /* Update byte count */ - - t = ctx->bytes[0]; - if ((ctx->bytes[0] = t + len) < t) - ctx->bytes[1]++; /* Carry from low to high */ - - t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ - if ((unsigned)t > (unsigned)len) - { - memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, len); - return; - } - /* First chunk is an odd size */ - memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, (unsigned)t); - byteSwap(ctx->in, 16); - MD5Transform(ctx->buf, ctx->in); - buf += (unsigned)t; - len -= (unsigned)t; - - /* Process data in 64-byte chunks */ - while (len >= 64) - { - memcpy(ctx->in, buf, 64); - byteSwap(ctx->in, 16); - MD5Transform(ctx->buf, ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); - } - - void MD5Final(byte digest[16], MD5Context *ctx) - { - int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */ - byte *p = (byte *)ctx->in + count; /* First unused byte */ - - /* Set the first char of padding to 0x80. There is always room. */ - *p++ = 0x80; - - /* Bytes of padding needed to make 56 bytes (-8..55) */ - count = 56 - 1 - count; - - if (count < 0) - { /* Padding forces an extra block */ - memset(p, 0, count+8); - byteSwap(ctx->in, 16); - MD5Transform(ctx->buf, ctx->in); - p = (byte *)ctx->in; - count = 56; - } - memset(p, 0, count+8); - byteSwap(ctx->in, 14); - - /* Append length in bits and transform */ - ctx->in[14] = ctx->bytes[0] << 3; - ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; - MD5Transform(ctx->buf, ctx->in); - - byteSwap(ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); - } - - void MD5Transform(word32 buf[4], word32 const in[16]) - { - register word32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; - } - - - void MyMD5(void *dest, void *orig, int len, unsigned int* key) - { - MD5Context context; - MD5Init(&context, key); - MD5Update(&context, (const unsigned char*)orig, len); - MD5Final((unsigned char*)dest, &context); - } - - - void GenHash(const char* src, char* dest, const char* xtab, unsigned int* key) - { - unsigned char bytes[16]; - - MyMD5((char*)bytes, (void*)src, strlen(src), key); - - for (int i = 0; i < 16; i++) - { - *dest++ = xtab[bytes[i] / 16]; - *dest++ = xtab[bytes[i] % 16]; - } - *dest++ = 0; - } - - unsigned int *key; - char* chars; - - public: - - ModuleMD5(InspIRCd* Me) - : Module(Me), key(NULL), chars(NULL) - { - ServerInstance->PublishInterface("HashRequest", this); - } - - virtual ~ModuleMD5() - { - ServerInstance->UnpublishInterface("HashRequest", this); - } - - void Implements(char* List) - { - List[I_OnRequest] = 1; - } - - virtual char* OnRequest(Request* request) - { - HashRequest* MD5 = (HashRequest*)request; - - if (strcmp("KEY", request->GetId()) == 0) - { - this->key = (unsigned int*)MD5->GetKeyData(); - } - else if (strcmp("HEX", request->GetId()) == 0) - { - this->chars = (char*)MD5->GetOutputs(); - } - else if (strcmp("SUM", request->GetId()) == 0) - { - static char data[MAXBUF]; - GenHash((const char*)MD5->GetHashData(), data, chars ? chars : "0123456789abcdef", key); - return data; - } - else if (strcmp("NAME", request->GetId()) == 0) - { - return "md5"; - } - else if (strcmp("RESET", request->GetId()) == 0) - { - this->chars = NULL; - this->key = NULL; - } - return NULL; - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION); - } -}; - -MODULE_INIT(ModuleMD5) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Allows for MD5 encrypted oper passwords */
/* $ModDep: m_hash.h */
#include "inspircd.h"
#ifdef HAS_STDINT
#include <stdint.h>
#endif
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_hash.h"
/* The four core functions - F1 is optimized somewhat */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f,w,x,y,z,in,s) \
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
#ifndef HAS_STDINT
typedef unsigned int uint32_t;
#endif
typedef uint32_t word32; /* NOT unsigned long. We don't support 16 bit platforms, anyway. */
typedef unsigned char byte;
/** An MD5 context, used by m_opermd5
*/
class MD5Context : public classbase
{
public:
word32 buf[4];
word32 bytes[2];
word32 in[16];
};
class ModuleMD5 : public Module
{
void byteSwap(word32 *buf, unsigned words)
{
byte *p = (byte *)buf;
do
{
*buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16 |
((unsigned)p[1] << 8 | p[0]);
p += 4;
} while (--words);
}
void MD5Init(MD5Context *ctx, unsigned int* key = NULL)
{
/* These are the defaults for md5 */
if (!key)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
}
else
{
ctx->buf[0] = key[0];
ctx->buf[1] = key[1];
ctx->buf[2] = key[2];
ctx->buf[3] = key[3];
}
ctx->bytes[0] = 0;
ctx->bytes[1] = 0;
}
void MD5Update(MD5Context *ctx, byte const *buf, int len)
{
word32 t;
/* Update byte count */
t = ctx->bytes[0];
if ((ctx->bytes[0] = t + len) < t)
ctx->bytes[1]++; /* Carry from low to high */
t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
if ((unsigned)t > (unsigned)len)
{
memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, len);
return;
}
/* First chunk is an odd size */
memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, (unsigned)t);
byteSwap(ctx->in, 16);
MD5Transform(ctx->buf, ctx->in);
buf += (unsigned)t;
len -= (unsigned)t;
/* Process data in 64-byte chunks */
while (len >= 64)
{
memcpy(ctx->in, buf, 64);
byteSwap(ctx->in, 16);
MD5Transform(ctx->buf, ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
void MD5Final(byte digest[16], MD5Context *ctx)
{
int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */
byte *p = (byte *)ctx->in + count; /* First unused byte */
/* Set the first char of padding to 0x80. There is always room. */
*p++ = 0x80;
/* Bytes of padding needed to make 56 bytes (-8..55) */
count = 56 - 1 - count;
if (count < 0)
{ /* Padding forces an extra block */
memset(p, 0, count+8);
byteSwap(ctx->in, 16);
MD5Transform(ctx->buf, ctx->in);
p = (byte *)ctx->in;
count = 56;
}
memset(p, 0, count+8);
byteSwap(ctx->in, 14);
/* Append length in bits and transform */
ctx->in[14] = ctx->bytes[0] << 3;
ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
MD5Transform(ctx->buf, ctx->in);
byteSwap(ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx));
}
void MD5Transform(word32 buf[4], word32 const in[16])
{
register word32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
void MyMD5(void *dest, void *orig, int len, unsigned int* key)
{
MD5Context context;
MD5Init(&context, key);
MD5Update(&context, (const unsigned char*)orig, len);
MD5Final((unsigned char*)dest, &context);
}
void GenHash(const char* src, char* dest, const char* xtab, unsigned int* key)
{
unsigned char bytes[16];
MyMD5((char*)bytes, (void*)src, strlen(src), key);
for (int i = 0; i < 16; i++)
{
*dest++ = xtab[bytes[i] / 16];
*dest++ = xtab[bytes[i] % 16];
}
*dest++ = 0;
}
unsigned int *key;
char* chars;
public:
ModuleMD5(InspIRCd* Me)
: Module(Me), key(NULL), chars(NULL)
{
ServerInstance->PublishInterface("HashRequest", this);
}
virtual ~ModuleMD5()
{
ServerInstance->UnpublishInterface("HashRequest", this);
}
void Implements(char* List)
{
List[I_OnRequest] = 1;
}
virtual char* OnRequest(Request* request)
{
HashRequest* MD5 = (HashRequest*)request;
if (strcmp("KEY", request->GetId()) == 0)
{
this->key = (unsigned int*)MD5->GetKeyData();
}
else if (strcmp("HEX", request->GetId()) == 0)
{
this->chars = (char*)MD5->GetOutputs();
}
else if (strcmp("SUM", request->GetId()) == 0)
{
static char data[MAXBUF];
GenHash((const char*)MD5->GetHashData(), data, chars ? chars : "0123456789abcdef", key);
return data;
}
else if (strcmp("NAME", request->GetId()) == 0)
{
return "md5";
}
else if (strcmp("RESET", request->GetId()) == 0)
{
this->chars = NULL;
this->key = NULL;
}
return NULL;
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
}
};
MODULE_INIT(ModuleMD5)
\ No newline at end of file diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp index a942262ed..e5263719b 100644 --- a/src/modules/m_messageflood.cpp +++ b/src/modules/m_messageflood.cpp @@ -1,304 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides channel mode +f (message flood protection) */ - -/** Holds flood settings and state for mode +f - */ -class floodsettings : public classbase -{ - public: - bool ban; - int secs; - int lines; - time_t reset; - std::map<userrec*,int> counters; - - floodsettings() : ban(0), secs(0), lines(0) {}; - floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c) - { - reset = time(NULL) + secs; - }; - - void addmessage(userrec* who) - { - std::map<userrec*,int>::iterator iter = counters.find(who); - if (iter != counters.end()) - { - iter->second++; - } - else - { - counters[who] = 1; - } - if (time(NULL) > reset) - { - counters.clear(); - reset = time(NULL) + secs; - } - } - - bool shouldkick(userrec* who) - { - std::map<userrec*,int>::iterator iter = counters.find(who); - if (iter != counters.end()) - { - return (iter->second >= this->lines); - } - else return false; - } - - void clear(userrec* who) - { - std::map<userrec*,int>::iterator iter = counters.find(who); - if (iter != counters.end()) - { - counters.erase(iter); - } - } -}; - -/** Handles channel mode +f - */ -class MsgFlood : public ModeHandler -{ - public: - MsgFlood(InspIRCd* Instance) : ModeHandler(Instance, 'f', 1, 0, false, MODETYPE_CHANNEL, false) { } - - ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) - { - floodsettings* x; - if (channel->GetExt("flood",x)) - return std::make_pair(true, (x->ban ? "*" : "")+ConvToStr(x->lines)+":"+ConvToStr(x->secs)); - else - return std::make_pair(false, parameter); - } - - bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel) - { - /* When TS is equal, the alphabetically later one wins */ - return (their_param < our_param); - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - floodsettings *f; - - if (adding) - { - char ndata[MAXBUF]; - char* data = ndata; - strlcpy(ndata,parameter.c_str(),MAXBUF); - char* lines = data; - char* secs = NULL; - bool ban = false; - if (*data == '*') - { - ban = true; - lines++; - } - else - { - ban = false; - } - while (*data) - { - if (*data == ':') - { - *data = 0; - data++; - secs = data; - break; - } - else data++; - } - if (secs) - { - /* Set up the flood parameters for this channel */ - int nlines = atoi(lines); - int nsecs = atoi(secs); - if ((nlines<1) || (nsecs<1)) - { - source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - if (!channel->GetExt("flood", f)) - { - parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs); - floodsettings *f = new floodsettings(ban,nsecs,nlines); - channel->Extend("flood",f); - channel->SetMode('f', true); - channel->SetModeParam('f', parameter.c_str(), true); - return MODEACTION_ALLOW; - } - else - { - std::string cur_param = channel->GetModeParameter('f'); - parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs); - if (cur_param == parameter) - { - // mode params match - return MODEACTION_DENY; - } - else - { - if (((nlines != f->lines) || (nsecs != f->secs)) && ((nsecs > 0) && (nlines > 0)) || (ban != f->ban)) - { - delete f; - floodsettings *f = new floodsettings(ban,nsecs,nlines); - channel->Shrink("flood"); - channel->Extend("flood",f); - channel->SetModeParam('f', cur_param.c_str(), false); - channel->SetModeParam('f', parameter.c_str(), true); - return MODEACTION_ALLOW; - } - else - { - return MODEACTION_DENY; - } - } - } - } - } - else - { - source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name); - parameter.clear(); - return MODEACTION_DENY; - } - } - else - { - if (channel->GetExt("flood", f)) - { - DELETE(f); - channel->Shrink("flood"); - channel->SetMode('f', false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleMsgFlood : public Module -{ - - MsgFlood* mf; - - public: - - ModuleMsgFlood(InspIRCd* Me) - : Module(Me) - { - - mf = new MsgFlood(ServerInstance); - if (!ServerInstance->AddMode(mf, 'f')) - throw ModuleException("Could not add new modes!"); - } - - void ProcessMessages(userrec* user,chanrec* dest, const std::string &text) - { - if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'f') && dest->GetStatus(user) == STATUS_OP) - { - return; - } - - floodsettings *f; - if (dest->GetExt("flood", f)) - { - f->addmessage(user); - if (f->shouldkick(user)) - { - /* Youre outttta here! */ - f->clear(user); - if (f->ban) - { - const char* parameters[3]; - parameters[0] = dest->name; - parameters[1] = "+b"; - parameters[2] = user->MakeWildHost(); - ServerInstance->SendMode(parameters,3,user); - std::deque<std::string> n; - /* Propogate the ban to other servers. - * We dont know what protocol we may be using, - * so this event is picked up by our protocol - * module and formed into a ban command that - * suits the protocol in use. - */ - n.push_back(dest->name); - n.push_back("+b"); - n.push_back(user->MakeWildHost()); - Event rmode((char *)&n, NULL, "send_mode"); - rmode.Send(ServerInstance); - } - char kickmessage[MAXBUF]; - snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %d lines in %d secs)", f->lines, f->secs); - dest->ServerKickUser(user, kickmessage, true); - } - } - } - - virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) - { - if (target_type == TYPE_CHANNEL) - { - ProcessMessages(user,(chanrec*)dest,text); - } - } - - virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) - { - if (target_type == TYPE_CHANNEL) - { - ProcessMessages(user,(chanrec*)dest,text); - } - } - - void OnChannelDelete(chanrec* chan) - { - floodsettings* f; - if (chan->GetExt("flood", f)) - { - DELETE(f); - chan->Shrink("flood"); - } - } - - void Implements(char* List) - { - List[I_OnChannelDelete] = List[I_OnUserNotice] = List[I_OnUserMessage] = 1; - } - - virtual ~ModuleMsgFlood() - { - ServerInstance->Modes->DelMode(mf); - DELETE(mf); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleMsgFlood) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides channel mode +f (message flood protection) */
/** Holds flood settings and state for mode +f
*/
class floodsettings : public classbase
{
public:
bool ban;
int secs;
int lines;
time_t reset;
std::map<userrec*,int> counters;
floodsettings() : ban(0), secs(0), lines(0) {};
floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c)
{
reset = time(NULL) + secs;
};
void addmessage(userrec* who)
{
std::map<userrec*,int>::iterator iter = counters.find(who);
if (iter != counters.end())
{
iter->second++;
}
else
{
counters[who] = 1;
}
if (time(NULL) > reset)
{
counters.clear();
reset = time(NULL) + secs;
}
}
bool shouldkick(userrec* who)
{
std::map<userrec*,int>::iterator iter = counters.find(who);
if (iter != counters.end())
{
return (iter->second >= this->lines);
}
else return false;
}
void clear(userrec* who)
{
std::map<userrec*,int>::iterator iter = counters.find(who);
if (iter != counters.end())
{
counters.erase(iter);
}
}
};
/** Handles channel mode +f
*/
class MsgFlood : public ModeHandler
{
public:
MsgFlood(InspIRCd* Instance) : ModeHandler(Instance, 'f', 1, 0, false, MODETYPE_CHANNEL, false) { }
ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
{
floodsettings* x;
if (channel->GetExt("flood",x))
return std::make_pair(true, (x->ban ? "*" : "")+ConvToStr(x->lines)+":"+ConvToStr(x->secs));
else
return std::make_pair(false, parameter);
}
bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
{
/* When TS is equal, the alphabetically later one wins */
return (their_param < our_param);
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
floodsettings *f;
if (adding)
{
char ndata[MAXBUF];
char* data = ndata;
strlcpy(ndata,parameter.c_str(),MAXBUF);
char* lines = data;
char* secs = NULL;
bool ban = false;
if (*data == '*')
{
ban = true;
lines++;
}
else
{
ban = false;
}
while (*data)
{
if (*data == ':')
{
*data = 0;
data++;
secs = data;
break;
}
else data++;
}
if (secs)
{
/* Set up the flood parameters for this channel */
int nlines = atoi(lines);
int nsecs = atoi(secs);
if ((nlines<1) || (nsecs<1))
{
source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
parameter.clear();
return MODEACTION_DENY;
}
else
{
if (!channel->GetExt("flood", f))
{
parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs);
floodsettings *f = new floodsettings(ban,nsecs,nlines);
channel->Extend("flood",f);
channel->SetMode('f', true);
channel->SetModeParam('f', parameter.c_str(), true);
return MODEACTION_ALLOW;
}
else
{
std::string cur_param = channel->GetModeParameter('f');
parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs);
if (cur_param == parameter)
{
// mode params match
return MODEACTION_DENY;
}
else
{
if (((nlines != f->lines) || (nsecs != f->secs)) && ((nsecs > 0) && (nlines > 0)) || (ban != f->ban))
{
delete f;
floodsettings *f = new floodsettings(ban,nsecs,nlines);
channel->Shrink("flood");
channel->Extend("flood",f);
channel->SetModeParam('f', cur_param.c_str(), false);
channel->SetModeParam('f', parameter.c_str(), true);
return MODEACTION_ALLOW;
}
else
{
return MODEACTION_DENY;
}
}
}
}
}
else
{
source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
parameter.clear();
return MODEACTION_DENY;
}
}
else
{
if (channel->GetExt("flood", f))
{
DELETE(f);
channel->Shrink("flood");
channel->SetMode('f', false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleMsgFlood : public Module
{
MsgFlood* mf;
public:
ModuleMsgFlood(InspIRCd* Me)
: Module(Me)
{
mf = new MsgFlood(ServerInstance);
if (!ServerInstance->AddMode(mf, 'f'))
throw ModuleException("Could not add new modes!");
}
void ProcessMessages(userrec* user,chanrec* dest, const std::string &text)
{
if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'f') && dest->GetStatus(user) == STATUS_OP)
{
return;
}
floodsettings *f;
if (dest->GetExt("flood", f))
{
f->addmessage(user);
if (f->shouldkick(user))
{
/* Youre outttta here! */
f->clear(user);
if (f->ban)
{
const char* parameters[3];
parameters[0] = dest->name;
parameters[1] = "+b";
parameters[2] = user->MakeWildHost();
ServerInstance->SendMode(parameters,3,user);
std::deque<std::string> n;
/* Propogate the ban to other servers.
* We dont know what protocol we may be using,
* so this event is picked up by our protocol
* module and formed into a ban command that
* suits the protocol in use.
*/
n.push_back(dest->name);
n.push_back("+b");
n.push_back(user->MakeWildHost());
Event rmode((char *)&n, NULL, "send_mode");
rmode.Send(ServerInstance);
}
char kickmessage[MAXBUF];
snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %d lines in %d secs)", f->lines, f->secs);
dest->ServerKickUser(user, kickmessage, true);
}
}
}
virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
if (target_type == TYPE_CHANNEL)
{
ProcessMessages(user,(chanrec*)dest,text);
}
}
virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
if (target_type == TYPE_CHANNEL)
{
ProcessMessages(user,(chanrec*)dest,text);
}
}
void OnChannelDelete(chanrec* chan)
{
floodsettings* f;
if (chan->GetExt("flood", f))
{
DELETE(f);
chan->Shrink("flood");
}
}
void Implements(char* List)
{
List[I_OnChannelDelete] = List[I_OnUserNotice] = List[I_OnUserMessage] = 1;
}
virtual ~ModuleMsgFlood()
{
ServerInstance->Modes->DelMode(mf);
DELETE(mf);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleMsgFlood)
\ No newline at end of file diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp index c45d777f8..37f584331 100644 --- a/src/modules/m_namesx.cpp +++ b/src/modules/m_namesx.cpp @@ -1,127 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -static const char* dummy = "ON"; - -/* $ModDesc: Provides aliases of commands. */ - -class ModuleNamesX : public Module -{ - public: - - ModuleNamesX(InspIRCd* Me) - : Module(Me) - { - } - - void Implements(char* List) - { - List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1; - } - - virtual ~ModuleNamesX() - { - } - - void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable) - { - if ((displayable) && (extname == "NAMESX")) - proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled"); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void On005Numeric(std::string &output) - { - output.append(" NAMESX"); - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - irc::string c = command.c_str(); - /* We don't actually create a proper command handler class for PROTOCTL, - * because other modules might want to have PROTOCTL hooks too. - * Therefore, we just hook its as an unvalidated command therefore we - * can capture it even if it doesnt exist! :-) - */ - if (c == "PROTOCTL") - { - if ((pcnt) && (!strcasecmp(parameters[0],"NAMESX"))) - { - user->Extend("NAMESX",dummy); - return 1; - } - } - return 0; - } - - virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist) - { - if (user->GetExt("NAMESX")) - { - char list[MAXBUF]; - size_t dlen, curlen; - dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name); - int numusers = 0; - char* ptr = list + dlen; - - if (!ulist) - ulist = Ptr->GetUsers(); - - bool has_user = Ptr->HasUser(user); - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - if ((!has_user) && (i->first->IsModeSet('i'))) - continue; - - if (i->first->Visibility && !i->first->Visibility->VisibleTo(user)) - continue; - - size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", Ptr->GetAllPrefixChars(i->first), i->second.c_str()); - /* OnUserList can change this - reset it back to normal */ - i->second = i->first->nick; - curlen += ptrlen; - ptr += ptrlen; - numusers++; - if (curlen > (480-NICKMAX)) - { - /* list overflowed into multiple numerics */ - user->WriteServ(std::string(list)); - /* reset our lengths */ - dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name); - ptr = list + dlen; - ptrlen = 0; - numusers = 0; - } - } - /* if whats left in the list isnt empty, send it */ - if (numusers) - { - user->WriteServ(std::string(list)); - } - user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name); - return 1; - } - return 0; - } -}; - -MODULE_INIT(ModuleNamesX) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
static const char* dummy = "ON";
/* $ModDesc: Provides aliases of commands. */
class ModuleNamesX : public Module
{
public:
ModuleNamesX(InspIRCd* Me)
: Module(Me)
{
}
void Implements(char* List)
{
List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1;
}
virtual ~ModuleNamesX()
{
}
void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)
{
if ((displayable) && (extname == "NAMESX"))
proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled");
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void On005Numeric(std::string &output)
{
output.append(" NAMESX");
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
irc::string c = command.c_str();
/* We don't actually create a proper command handler class for PROTOCTL,
* because other modules might want to have PROTOCTL hooks too.
* Therefore, we just hook its as an unvalidated command therefore we
* can capture it even if it doesnt exist! :-)
*/
if (c == "PROTOCTL")
{
if ((pcnt) && (!strcasecmp(parameters[0],"NAMESX")))
{
user->Extend("NAMESX",dummy);
return 1;
}
}
return 0;
}
virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist)
{
if (user->GetExt("NAMESX"))
{
char list[MAXBUF];
size_t dlen, curlen;
dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name);
int numusers = 0;
char* ptr = list + dlen;
if (!ulist)
ulist = Ptr->GetUsers();
bool has_user = Ptr->HasUser(user);
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
if ((!has_user) && (i->first->IsModeSet('i')))
continue;
if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))
continue;
size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", Ptr->GetAllPrefixChars(i->first), i->second.c_str());
/* OnUserList can change this - reset it back to normal */
i->second = i->first->nick;
curlen += ptrlen;
ptr += ptrlen;
numusers++;
if (curlen > (480-NICKMAX))
{
/* list overflowed into multiple numerics */
user->WriteServ(std::string(list));
/* reset our lengths */
dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name);
ptr = list + dlen;
ptrlen = 0;
numusers = 0;
}
}
/* if whats left in the list isnt empty, send it */
if (numusers)
{
user->WriteServ(std::string(list));
}
user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
return 1;
}
return 0;
}
};
MODULE_INIT(ModuleNamesX)
\ No newline at end of file diff --git a/src/modules/m_nicklock.cpp b/src/modules/m_nicklock.cpp index 26d5bfbd7..94c934e6f 100644 --- a/src/modules/m_nicklock.cpp +++ b/src/modules/m_nicklock.cpp @@ -1,159 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" - -/* $ModDesc: Provides the NICKLOCK command, allows an oper to chage a users nick and lock them to it until they quit */ - -/** Handle /NICKLOCK - */ -class cmd_nicklock : public command_t -{ - char* dummy; - public: - cmd_nicklock (InspIRCd* Instance) : command_t(Instance,"NICKLOCK", 'o', 2) - { - this->source = "m_nicklock.so"; - syntax = "<oldnick> <newnick>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - userrec* source = ServerInstance->FindNick(parameters[0]); - irc::string server; - irc::string me; - - // check user exists - if (!source) - { - return CMD_FAILURE; - } - - // check if user is locked - if (source->GetExt("nick_locked", dummy)) - { - user->WriteServ("946 %s %s :This user's nickname is already locked.",user->nick,source->nick); - return CMD_FAILURE; - } - - // check nick is valid - if (!ServerInstance->IsNick(parameters[1])) - { - return CMD_FAILURE; - } - - // let others know - ServerInstance->WriteOpers(std::string(user->nick)+" used NICKLOCK to change and hold "+parameters[0]+" to "+parameters[1]); - - if (!source->ForceNickChange(parameters[1])) - { - // ugh, nickchange failed for some reason -- possibly existing nick? - userrec::QuitUser(ServerInstance, source, "Nickname collision"); - return CMD_FAILURE; - } - - // give them a lock flag - source->Extend("nick_locked", "ON"); - - /* route */ - return CMD_SUCCESS; - } -}; - -/** Handle /NICKUNLOCK - */ -class cmd_nickunlock : public command_t -{ - public: - cmd_nickunlock (InspIRCd* Instance) : command_t(Instance,"NICKUNLOCK", 'o', 1) - { - this->source = "m_nickunlock.so"; - syntax = "<locked-nick>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* source = ServerInstance->FindNick(parameters[0]); - if (source) - { - source->Shrink("nick_locked"); - user->WriteServ("945 %s %s :Nickname now unlocked.",user->nick,source->nick); - ServerInstance->WriteOpers(std::string(user->nick)+" used NICKUNLOCK on "+parameters[0]); - return CMD_SUCCESS; - } - - return CMD_FAILURE; - } -}; - - -class ModuleNickLock : public Module -{ - cmd_nicklock* cmd1; - cmd_nickunlock* cmd2; - char* n; - public: - ModuleNickLock(InspIRCd* Me) - : Module(Me) - { - - cmd1 = new cmd_nicklock(ServerInstance); - cmd2 = new cmd_nickunlock(ServerInstance); - ServerInstance->AddCommand(cmd1); - ServerInstance->AddCommand(cmd2); - } - - virtual ~ModuleNickLock() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserPreNick] = List[I_OnUserQuit] = List[I_OnCleanup] = 1; - } - - virtual int OnUserPreNick(userrec* user, const std::string &newnick) - { - if (user->GetExt("nick_locked", n)) - { - user->WriteServ("447 %s :You cannot change your nickname (your nick is locked)",user->nick); - return 1; - } - return 0; - } - - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - user->Shrink("nick_locked"); - } - - virtual void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - user->Shrink("nick_locked"); - } - } -}; - -MODULE_INIT(ModuleNickLock) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
/* $ModDesc: Provides the NICKLOCK command, allows an oper to chage a users nick and lock them to it until they quit */
/** Handle /NICKLOCK
*/
class cmd_nicklock : public command_t
{
char* dummy;
public:
cmd_nicklock (InspIRCd* Instance) : command_t(Instance,"NICKLOCK", 'o', 2)
{
this->source = "m_nicklock.so";
syntax = "<oldnick> <newnick>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
userrec* source = ServerInstance->FindNick(parameters[0]);
irc::string server;
irc::string me;
// check user exists
if (!source)
{
return CMD_FAILURE;
}
// check if user is locked
if (source->GetExt("nick_locked", dummy))
{
user->WriteServ("946 %s %s :This user's nickname is already locked.",user->nick,source->nick);
return CMD_FAILURE;
}
// check nick is valid
if (!ServerInstance->IsNick(parameters[1]))
{
return CMD_FAILURE;
}
// let others know
ServerInstance->WriteOpers(std::string(user->nick)+" used NICKLOCK to change and hold "+parameters[0]+" to "+parameters[1]);
if (!source->ForceNickChange(parameters[1]))
{
// ugh, nickchange failed for some reason -- possibly existing nick?
userrec::QuitUser(ServerInstance, source, "Nickname collision");
return CMD_FAILURE;
}
// give them a lock flag
source->Extend("nick_locked", "ON");
/* route */
return CMD_SUCCESS;
}
};
/** Handle /NICKUNLOCK
*/
class cmd_nickunlock : public command_t
{
public:
cmd_nickunlock (InspIRCd* Instance) : command_t(Instance,"NICKUNLOCK", 'o', 1)
{
this->source = "m_nickunlock.so";
syntax = "<locked-nick>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* source = ServerInstance->FindNick(parameters[0]);
if (source)
{
source->Shrink("nick_locked");
user->WriteServ("945 %s %s :Nickname now unlocked.",user->nick,source->nick);
ServerInstance->WriteOpers(std::string(user->nick)+" used NICKUNLOCK on "+parameters[0]);
return CMD_SUCCESS;
}
return CMD_FAILURE;
}
};
class ModuleNickLock : public Module
{
cmd_nicklock* cmd1;
cmd_nickunlock* cmd2;
char* n;
public:
ModuleNickLock(InspIRCd* Me)
: Module(Me)
{
cmd1 = new cmd_nicklock(ServerInstance);
cmd2 = new cmd_nickunlock(ServerInstance);
ServerInstance->AddCommand(cmd1);
ServerInstance->AddCommand(cmd2);
}
virtual ~ModuleNickLock()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserPreNick] = List[I_OnUserQuit] = List[I_OnCleanup] = 1;
}
virtual int OnUserPreNick(userrec* user, const std::string &newnick)
{
if (user->GetExt("nick_locked", n))
{
user->WriteServ("447 %s :You cannot change your nickname (your nick is locked)",user->nick);
return 1;
}
return 0;
}
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
user->Shrink("nick_locked");
}
virtual void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
user->Shrink("nick_locked");
}
}
};
MODULE_INIT(ModuleNickLock)
\ No newline at end of file diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp index 05dbd69ca..b3445155a 100644 --- a/src/modules/m_noctcp.cpp +++ b/src/modules/m_noctcp.cpp @@ -1,107 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style channel mode +c */ - -class NoCTCP : public ModeHandler -{ - public: - NoCTCP(InspIRCd* Instance) : ModeHandler(Instance, 'C', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('C')) - { - channel->SetMode('C',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('C')) - { - channel->SetMode('C',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleNoCTCP : public Module -{ - - NoCTCP* nc; - - public: - - ModuleNoCTCP(InspIRCd* Me) - : Module(Me) - { - - nc = new NoCTCP(ServerInstance); - if (!ServerInstance->AddMode(nc, 'C')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1; - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreNotice(user,dest,target_type,text,status,exempt_list); - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) - { - chanrec* c = (chanrec*)dest; - if (c->IsModeSet('C')) - { - if ((text.length()) && (text[0] == '\1')) - { - if (strncmp(text.c_str(),"\1ACTION ",8)) - { - user->WriteServ("492 %s %s :Can't send CTCP to channel (+C set)",user->nick, c->name); - return 1; - } - } - } - } - return 0; - } - - virtual ~ModuleNoCTCP() - { - ServerInstance->Modes->DelMode(nc); - DELETE(nc); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleNoCTCP) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style channel mode +c */
class NoCTCP : public ModeHandler
{
public:
NoCTCP(InspIRCd* Instance) : ModeHandler(Instance, 'C', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('C'))
{
channel->SetMode('C',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('C'))
{
channel->SetMode('C',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleNoCTCP : public Module
{
NoCTCP* nc;
public:
ModuleNoCTCP(InspIRCd* Me)
: Module(Me)
{
nc = new NoCTCP(ServerInstance);
if (!ServerInstance->AddMode(nc, 'C'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
{
chanrec* c = (chanrec*)dest;
if (c->IsModeSet('C'))
{
if ((text.length()) && (text[0] == '\1'))
{
if (strncmp(text.c_str(),"\1ACTION ",8))
{
user->WriteServ("492 %s %s :Can't send CTCP to channel (+C set)",user->nick, c->name);
return 1;
}
}
}
}
return 0;
}
virtual ~ModuleNoCTCP()
{
ServerInstance->Modes->DelMode(nc);
DELETE(nc);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleNoCTCP)
\ No newline at end of file diff --git a/src/modules/m_noinvite.cpp b/src/modules/m_noinvite.cpp index 26965d319..76e2616e3 100644 --- a/src/modules/m_noinvite.cpp +++ b/src/modules/m_noinvite.cpp @@ -1,88 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style channel mode +V */ - -class NoInvite : public ModeHandler -{ - public: - NoInvite(InspIRCd* Instance) : ModeHandler(Instance, 'V', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('V')) - { - channel->SetMode('V',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('V')) - { - channel->SetMode('V',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleNoInvite : public Module -{ - NoInvite *ni; - public: - - ModuleNoInvite(InspIRCd* Me) : Module(Me) - { - ni = new NoInvite(ServerInstance); - if (!ServerInstance->AddMode(ni, 'V')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreInvite] = 1; - } - - virtual int OnUserPreInvite(userrec* user,userrec* dest,chanrec* channel) - { - if (channel->IsModeSet('V')) - { - user->WriteServ("492 %s %s :Can't invite %s to channel (+V set)",user->nick, channel->name, dest->nick); - return 1; - } - return 0; - } - - virtual ~ModuleNoInvite() - { - ServerInstance->Modes->DelMode(ni); - DELETE(ni); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleNoInvite) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style channel mode +V */
class NoInvite : public ModeHandler
{
public:
NoInvite(InspIRCd* Instance) : ModeHandler(Instance, 'V', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('V'))
{
channel->SetMode('V',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('V'))
{
channel->SetMode('V',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleNoInvite : public Module
{
NoInvite *ni;
public:
ModuleNoInvite(InspIRCd* Me) : Module(Me)
{
ni = new NoInvite(ServerInstance);
if (!ServerInstance->AddMode(ni, 'V'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreInvite] = 1;
}
virtual int OnUserPreInvite(userrec* user,userrec* dest,chanrec* channel)
{
if (channel->IsModeSet('V'))
{
user->WriteServ("492 %s %s :Can't invite %s to channel (+V set)",user->nick, channel->name, dest->nick);
return 1;
}
return 0;
}
virtual ~ModuleNoInvite()
{
ServerInstance->Modes->DelMode(ni);
DELETE(ni);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleNoInvite)
\ No newline at end of file diff --git a/src/modules/m_nokicks.cpp b/src/modules/m_nokicks.cpp index 315eb7399..ac78b4d7a 100644 --- a/src/modules/m_nokicks.cpp +++ b/src/modules/m_nokicks.cpp @@ -1,105 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style channel mode +Q */ - -class NoKicks : public ModeHandler -{ - public: - NoKicks(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('Q')) - { - channel->SetMode('Q',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('Q')) - { - channel->SetMode('Q',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleNoKicks : public Module -{ - - NoKicks* nk; - - public: - - ModuleNoKicks(InspIRCd* Me) - : Module(Me) - { - - nk = new NoKicks(ServerInstance); - if (!ServerInstance->AddMode(nk, 'Q')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnAccessCheck] = 1; - } - - virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type) - { - if (access_type == AC_KICK) - { - if (channel->IsModeSet('Q')) - { - if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server)) - { - // ulines can still kick with +Q in place - return ACR_ALLOW; - } - else - { - // nobody else can (not even opers with override, and founders) - source->WriteServ("484 %s %s :Can't kick user %s from channel (+Q set)",source->nick, channel->name,dest->nick); - return ACR_DENY; - } - } - } - return ACR_DEFAULT; - } - - virtual ~ModuleNoKicks() - { - ServerInstance->Modes->DelMode(nk); - DELETE(nk); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - - -MODULE_INIT(ModuleNoKicks) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style channel mode +Q */
class NoKicks : public ModeHandler
{
public:
NoKicks(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('Q'))
{
channel->SetMode('Q',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('Q'))
{
channel->SetMode('Q',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleNoKicks : public Module
{
NoKicks* nk;
public:
ModuleNoKicks(InspIRCd* Me)
: Module(Me)
{
nk = new NoKicks(ServerInstance);
if (!ServerInstance->AddMode(nk, 'Q'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnAccessCheck] = 1;
}
virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)
{
if (access_type == AC_KICK)
{
if (channel->IsModeSet('Q'))
{
if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server))
{
// ulines can still kick with +Q in place
return ACR_ALLOW;
}
else
{
// nobody else can (not even opers with override, and founders)
source->WriteServ("484 %s %s :Can't kick user %s from channel (+Q set)",source->nick, channel->name,dest->nick);
return ACR_DENY;
}
}
}
return ACR_DEFAULT;
}
virtual ~ModuleNoKicks()
{
ServerInstance->Modes->DelMode(nk);
DELETE(nk);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleNoKicks)
\ No newline at end of file diff --git a/src/modules/m_nonicks.cpp b/src/modules/m_nonicks.cpp index bb1843a95..d6e6553e9 100644 --- a/src/modules/m_nonicks.cpp +++ b/src/modules/m_nonicks.cpp @@ -1,102 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" -#include "configreader.h" - -/* $ModDesc: Provides support for channel mode +N which prevents nick changes on channel */ - -class NoNicks : public ModeHandler -{ - public: - NoNicks(InspIRCd* Instance) : ModeHandler(Instance, 'N', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('N')) - { - channel->SetMode('N',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('N')) - { - channel->SetMode('N',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleNoNickChange : public Module -{ - NoNicks* nn; - public: - ModuleNoNickChange(InspIRCd* Me) - : Module(Me) - { - - nn = new NoNicks(ServerInstance); - ServerInstance->AddMode(nn, 'N'); - } - - virtual ~ModuleNoNickChange() - { - ServerInstance->Modes->DelMode(nn); - DELETE(nn); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserPreNick] = 1; - } - - virtual int OnUserPreNick(userrec* user, const std::string &newnick) - { - if (IS_LOCAL(user)) - { - for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) - { - chanrec* curr = i->first; - - if (curr->IsModeSet('N')) - { - if (CHANOPS_EXEMPT(ServerInstance, 'N') && curr->GetStatus(user) == STATUS_OP) - continue; - - user->WriteServ("447 %s :Can't change nickname while on %s (+N is set)", user->nick, curr->name); - return 1; - } - } - } - - return 0; - } -}; - -MODULE_INIT(ModuleNoNickChange) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
#include "configreader.h"
/* $ModDesc: Provides support for channel mode +N which prevents nick changes on channel */
class NoNicks : public ModeHandler
{
public:
NoNicks(InspIRCd* Instance) : ModeHandler(Instance, 'N', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('N'))
{
channel->SetMode('N',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('N'))
{
channel->SetMode('N',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleNoNickChange : public Module
{
NoNicks* nn;
public:
ModuleNoNickChange(InspIRCd* Me)
: Module(Me)
{
nn = new NoNicks(ServerInstance);
ServerInstance->AddMode(nn, 'N');
}
virtual ~ModuleNoNickChange()
{
ServerInstance->Modes->DelMode(nn);
DELETE(nn);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserPreNick] = 1;
}
virtual int OnUserPreNick(userrec* user, const std::string &newnick)
{
if (IS_LOCAL(user))
{
for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
{
chanrec* curr = i->first;
if (curr->IsModeSet('N'))
{
if (CHANOPS_EXEMPT(ServerInstance, 'N') && curr->GetStatus(user) == STATUS_OP)
continue;
user->WriteServ("447 %s :Can't change nickname while on %s (+N is set)", user->nick, curr->name);
return 1;
}
}
}
return 0;
}
};
MODULE_INIT(ModuleNoNickChange)
\ No newline at end of file diff --git a/src/modules/m_nonotice.cpp b/src/modules/m_nonotice.cpp index ae926b4bb..fd4c474cb 100644 --- a/src/modules/m_nonotice.cpp +++ b/src/modules/m_nonotice.cpp @@ -1,103 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style channel mode +T */ - -class NoNotice : public ModeHandler -{ - public: - NoNotice(InspIRCd* Instance) : ModeHandler(Instance, 'T', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('T')) - { - channel->SetMode('T',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('T')) - { - channel->SetMode('T',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleNoNotice : public Module -{ - - NoNotice* nt; - public: - - ModuleNoNotice(InspIRCd* Me) - : Module(Me) - { - - nt = new NoNotice(ServerInstance); - if (!ServerInstance->AddMode(nt, 'T')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreNotice] = 1; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) - { - chanrec* c = (chanrec*)dest; - if (c->IsModeSet('T')) - { - if ((ServerInstance->ULine(user->server)) || (c->GetStatus(user) == STATUS_OP) || (c->GetStatus(user) == STATUS_HOP)) - { - // ops and halfops can still /NOTICE the channel - return 0; - } - else - { - user->WriteServ("404 %s %s :Can't send NOTICE to channel (+T set)",user->nick, c->name); - return 1; - } - } - } - return 0; - } - - virtual ~ModuleNoNotice() - { - ServerInstance->Modes->DelMode(nt); - DELETE(nt); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleNoNotice) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style channel mode +T */
class NoNotice : public ModeHandler
{
public:
NoNotice(InspIRCd* Instance) : ModeHandler(Instance, 'T', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('T'))
{
channel->SetMode('T',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('T'))
{
channel->SetMode('T',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleNoNotice : public Module
{
NoNotice* nt;
public:
ModuleNoNotice(InspIRCd* Me)
: Module(Me)
{
nt = new NoNotice(ServerInstance);
if (!ServerInstance->AddMode(nt, 'T'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreNotice] = 1;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
{
chanrec* c = (chanrec*)dest;
if (c->IsModeSet('T'))
{
if ((ServerInstance->ULine(user->server)) || (c->GetStatus(user) == STATUS_OP) || (c->GetStatus(user) == STATUS_HOP))
{
// ops and halfops can still /NOTICE the channel
return 0;
}
else
{
user->WriteServ("404 %s %s :Can't send NOTICE to channel (+T set)",user->nick, c->name);
return 1;
}
}
}
return 0;
}
virtual ~ModuleNoNotice()
{
ServerInstance->Modes->DelMode(nt);
DELETE(nt);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleNoNotice)
\ No newline at end of file diff --git a/src/modules/m_oper_hash.cpp b/src/modules/m_oper_hash.cpp index b4661741b..a3989ad91 100644 --- a/src/modules/m_oper_hash.cpp +++ b/src/modules/m_oper_hash.cpp @@ -1,163 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Allows for hashed oper passwords */ -/* $ModDep: m_hash.h */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_hash.h" - -typedef std::map<irc::string, Module*> hashymodules; - -/* Handle /MKPASSWD - */ -class cmd_mkpasswd : public command_t -{ - Module* Sender; - hashymodules &hashers; - std::deque<std::string> &names; - public: - cmd_mkpasswd (InspIRCd* Instance, Module* S, hashymodules &h, std::deque<std::string> &n) - : command_t(Instance,"MKPASSWD", 'o', 2), Sender(S), hashers(h), names(n) - { - this->source = "m_oper_hash.so"; - syntax = "<hashtype> <any-text>"; - } - - void MakeHash(userrec* user, const char* algo, const char* stuff) - { - /* Lets see if they gave us an algorithm which has been implemented */ - hashymodules::iterator x = hashers.find(algo); - if (x != hashers.end()) - { - /* Yup, reset it first (Always ALWAYS do this) */ - HashResetRequest(Sender, x->second).Send(); - /* Now attempt to generate a hash */ - user->WriteServ("NOTICE %s :%s hashed password for %s is %s",user->nick, algo, stuff, HashSumRequest(Sender, x->second, stuff).Send() ); - } - else - { - /* I dont do flying, bob. */ - user->WriteServ("NOTICE %s :Unknown hash type, valid hash types are: %s", user->nick, irc::stringjoiner(", ", names, 0, names.size() - 1).GetJoined().c_str() ); - } - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - MakeHash(user, parameters[0], parameters[1]); - /* NOTE: Don't propogate this across the network! - * We dont want plaintext passes going all over the place... - * To make sure it goes nowhere, return CMD_FAILURE! - */ - return CMD_FAILURE; - } -}; - -class ModuleOperHash : public Module -{ - - cmd_mkpasswd* mycommand; - ConfigReader* Conf; - hashymodules hashers; /* List of modules which implement HashRequest */ - std::deque<std::string> names; /* Module names which implement HashRequest */ - - public: - - ModuleOperHash(InspIRCd* Me) - : Module(Me) - { - - /* Read the config file first */ - Conf = NULL; - OnRehash(NULL,""); - - ServerInstance->UseInterface("HashRequest"); - - /* Find all modules which implement the interface 'HashRequest' */ - modulelist* ml = ServerInstance->FindInterface("HashRequest"); - - /* Did we find any modules? */ - if (ml) - { - /* Yes, enumerate them all to find out the hashing algorithm name */ - for (modulelist::iterator m = ml->begin(); m != ml->end(); m++) - { - /* Make a request to it for its name, its implementing - * HashRequest so we know its safe to do this - */ - std::string name = HashNameRequest(this, *m).Send(); - /* Build a map of them */ - hashers[name.c_str()] = *m; - names.push_back(name); - } - } - else - { - throw ModuleException("I can't find any modules loaded which implement the HashRequest interface! You probably forgot to load a hashing module such as m_md5.so or m_sha256.so."); - } - - mycommand = new cmd_mkpasswd(ServerInstance, this, hashers, names); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleOperHash() - { - ServerInstance->DoneWithInterface("HashRequest"); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnOperCompare] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - /* Re-read configuration file */ - if (Conf) - delete Conf; - - Conf = new ConfigReader(ServerInstance); - } - - virtual int OnOperCompare(const std::string &data, const std::string &input, int tagnumber) - { - /* First, lets see what hash theyre using on this oper */ - std::string hashtype = Conf->ReadValue("oper", "hash", tagnumber); - hashymodules::iterator x = hashers.find(hashtype.c_str()); - - /* Is this a valid hash name? (case insensitive) */ - if (x != hashers.end()) - { - /* Reset the hashing module */ - HashResetRequest(this, x->second).Send(); - /* Compare the hash in the config to the generated hash */ - if (!strcasecmp(data.c_str(), HashSumRequest(this, x->second, input.c_str()).Send())) - return 1; - /* No match, and must be hashed, forbid */ - else return -1; - } - - /* Not a hash, fall through to strcmp in core */ - return 0; - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleOperHash) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Allows for hashed oper passwords */
/* $ModDep: m_hash.h */
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_hash.h"
typedef std::map<irc::string, Module*> hashymodules;
/* Handle /MKPASSWD
*/
class cmd_mkpasswd : public command_t
{
Module* Sender;
hashymodules &hashers;
std::deque<std::string> &names;
public:
cmd_mkpasswd (InspIRCd* Instance, Module* S, hashymodules &h, std::deque<std::string> &n)
: command_t(Instance,"MKPASSWD", 'o', 2), Sender(S), hashers(h), names(n)
{
this->source = "m_oper_hash.so";
syntax = "<hashtype> <any-text>";
}
void MakeHash(userrec* user, const char* algo, const char* stuff)
{
/* Lets see if they gave us an algorithm which has been implemented */
hashymodules::iterator x = hashers.find(algo);
if (x != hashers.end())
{
/* Yup, reset it first (Always ALWAYS do this) */
HashResetRequest(Sender, x->second).Send();
/* Now attempt to generate a hash */
user->WriteServ("NOTICE %s :%s hashed password for %s is %s",user->nick, algo, stuff, HashSumRequest(Sender, x->second, stuff).Send() );
}
else
{
/* I dont do flying, bob. */
user->WriteServ("NOTICE %s :Unknown hash type, valid hash types are: %s", user->nick, irc::stringjoiner(", ", names, 0, names.size() - 1).GetJoined().c_str() );
}
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
MakeHash(user, parameters[0], parameters[1]);
/* NOTE: Don't propogate this across the network!
* We dont want plaintext passes going all over the place...
* To make sure it goes nowhere, return CMD_FAILURE!
*/
return CMD_FAILURE;
}
};
class ModuleOperHash : public Module
{
cmd_mkpasswd* mycommand;
ConfigReader* Conf;
hashymodules hashers; /* List of modules which implement HashRequest */
std::deque<std::string> names; /* Module names which implement HashRequest */
public:
ModuleOperHash(InspIRCd* Me)
: Module(Me)
{
/* Read the config file first */
Conf = NULL;
OnRehash(NULL,"");
ServerInstance->UseInterface("HashRequest");
/* Find all modules which implement the interface 'HashRequest' */
modulelist* ml = ServerInstance->FindInterface("HashRequest");
/* Did we find any modules? */
if (ml)
{
/* Yes, enumerate them all to find out the hashing algorithm name */
for (modulelist::iterator m = ml->begin(); m != ml->end(); m++)
{
/* Make a request to it for its name, its implementing
* HashRequest so we know its safe to do this
*/
std::string name = HashNameRequest(this, *m).Send();
/* Build a map of them */
hashers[name.c_str()] = *m;
names.push_back(name);
}
}
else
{
throw ModuleException("I can't find any modules loaded which implement the HashRequest interface! You probably forgot to load a hashing module such as m_md5.so or m_sha256.so.");
}
mycommand = new cmd_mkpasswd(ServerInstance, this, hashers, names);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleOperHash()
{
ServerInstance->DoneWithInterface("HashRequest");
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnOperCompare] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
/* Re-read configuration file */
if (Conf)
delete Conf;
Conf = new ConfigReader(ServerInstance);
}
virtual int OnOperCompare(const std::string &data, const std::string &input, int tagnumber)
{
/* First, lets see what hash theyre using on this oper */
std::string hashtype = Conf->ReadValue("oper", "hash", tagnumber);
hashymodules::iterator x = hashers.find(hashtype.c_str());
/* Is this a valid hash name? (case insensitive) */
if (x != hashers.end())
{
/* Reset the hashing module */
HashResetRequest(this, x->second).Send();
/* Compare the hash in the config to the generated hash */
if (!strcasecmp(data.c_str(), HashSumRequest(this, x->second, input.c_str()).Send()))
return 1;
/* No match, and must be hashed, forbid */
else return -1;
}
/* Not a hash, fall through to strcmp in core */
return 0;
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleOperHash)
\ No newline at end of file diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp index 6fd6c9e98..493904e35 100644 --- a/src/modules/m_operchans.cpp +++ b/src/modules/m_operchans.cpp @@ -1,97 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for oper-only chans via the +O channel mode */ - -class OperChans : public ModeHandler -{ - public: - /* This is an oper-only mode */ - OperChans(InspIRCd* Instance) : ModeHandler(Instance, 'O', 0, 0, false, MODETYPE_CHANNEL, true) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('O')) - { - channel->SetMode('O',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('O')) - { - channel->SetMode('O',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleOperChans : public Module -{ - - OperChans* oc; - public: - ModuleOperChans(InspIRCd* Me) - : Module(Me) - { - - oc = new OperChans(ServerInstance); - if (!ServerInstance->AddMode(oc, 'O')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreJoin] = 1; - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if (!IS_OPER(user)) - { - if (chan) - { - if (chan->IsModeSet('O')) - { - user->WriteServ("520 %s %s :Only IRC operators may join the channel %s (+O is set)",user->nick, chan->name,chan->name); - return 1; - } - } - } - return 0; - } - - virtual ~ModuleOperChans() - { - ServerInstance->Modes->DelMode(oc); - DELETE(oc); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR|VF_COMMON,API_VERSION); - } -}; - -MODULE_INIT(ModuleOperChans) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for oper-only chans via the +O channel mode */
class OperChans : public ModeHandler
{
public:
/* This is an oper-only mode */
OperChans(InspIRCd* Instance) : ModeHandler(Instance, 'O', 0, 0, false, MODETYPE_CHANNEL, true) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('O'))
{
channel->SetMode('O',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('O'))
{
channel->SetMode('O',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleOperChans : public Module
{
OperChans* oc;
public:
ModuleOperChans(InspIRCd* Me)
: Module(Me)
{
oc = new OperChans(ServerInstance);
if (!ServerInstance->AddMode(oc, 'O'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreJoin] = 1;
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if (!IS_OPER(user))
{
if (chan)
{
if (chan->IsModeSet('O'))
{
user->WriteServ("520 %s %s :Only IRC operators may join the channel %s (+O is set)",user->nick, chan->name,chan->name);
return 1;
}
}
}
return 0;
}
virtual ~ModuleOperChans()
{
ServerInstance->Modes->DelMode(oc);
DELETE(oc);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR|VF_COMMON,API_VERSION);
}
};
MODULE_INIT(ModuleOperChans)
\ No newline at end of file diff --git a/src/modules/m_operjoin.cpp b/src/modules/m_operjoin.cpp index d12bc1932..d69112eba 100644 --- a/src/modules/m_operjoin.cpp +++ b/src/modules/m_operjoin.cpp @@ -1,90 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Forces opers to join the specified channel(s) on oper-up */ - -class ModuleOperjoin : public Module -{ - private: - std::string operChan; - std::vector<std::string> operChans; - - int tokenize(const string &str, std::vector<std::string> &tokens) - { - // skip delimiters at beginning. - string::size_type lastPos = str.find_first_not_of(",", 0); - // find first "non-delimiter". - string::size_type pos = str.find_first_of(",", lastPos); - - while (string::npos != pos || string::npos != lastPos) - { - // found a token, add it to the vector. - tokens.push_back(str.substr(lastPos, pos - lastPos)); - // skip delimiters. Note the "not_of" - lastPos = str.find_first_not_of(",", pos); - // find next "non-delimiter" - pos = str.find_first_of(",", lastPos); - } - return tokens.size(); - } - - public: - ModuleOperjoin(InspIRCd* Me) : Module(Me) - { - OnRehash(NULL, ""); - } - - void Implements(char* List) - { - List[I_OnPostOper] = List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader* conf = new ConfigReader(ServerInstance); - - operChan = conf->ReadValue("operjoin", "channel", 0); - operChans.clear(); - if (!operChan.empty()) - tokenize(operChan,operChans); - - DELETE(conf); - } - - virtual ~ModuleOperjoin() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void OnPostOper(userrec* user, const std::string &opertype) - { - if (!IS_LOCAL(user)) - return; - - for(std::vector<std::string>::iterator it = operChans.begin(); it != operChans.end(); it++) - if (ServerInstance->IsChannel(it->c_str())) - chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true)); - } - -}; - -MODULE_INIT(ModuleOperjoin) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Forces opers to join the specified channel(s) on oper-up */
class ModuleOperjoin : public Module
{
private:
std::string operChan;
std::vector<std::string> operChans;
int tokenize(const string &str, std::vector<std::string> &tokens)
{
// skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(",", 0);
// find first "non-delimiter".
string::size_type pos = str.find_first_of(",", lastPos);
while (string::npos != pos || string::npos != lastPos)
{
// found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(",", pos);
// find next "non-delimiter"
pos = str.find_first_of(",", lastPos);
}
return tokens.size();
}
public:
ModuleOperjoin(InspIRCd* Me) : Module(Me)
{
OnRehash(NULL, "");
}
void Implements(char* List)
{
List[I_OnPostOper] = List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader* conf = new ConfigReader(ServerInstance);
operChan = conf->ReadValue("operjoin", "channel", 0);
operChans.clear();
if (!operChan.empty())
tokenize(operChan,operChans);
DELETE(conf);
}
virtual ~ModuleOperjoin()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void OnPostOper(userrec* user, const std::string &opertype)
{
if (!IS_LOCAL(user))
return;
for(std::vector<std::string>::iterator it = operChans.begin(); it != operChans.end(); it++)
if (ServerInstance->IsChannel(it->c_str()))
chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true));
}
};
MODULE_INIT(ModuleOperjoin)
\ No newline at end of file diff --git a/src/modules/m_operlevels.cpp b/src/modules/m_operlevels.cpp index 918d444ac..6d3aa7b14 100644 --- a/src/modules/m_operlevels.cpp +++ b/src/modules/m_operlevels.cpp @@ -1,122 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Gives each oper type a 'level', cannot kill opers 'above' your level. */ - - - -class ModuleOperLevels : public Module -{ - - private: - - - ConfigReader* conf; - - public: - - ModuleOperLevels(InspIRCd* Me) - : Module(Me) - { - - - conf = new ConfigReader(ServerInstance); - } - - virtual ~ModuleOperLevels() - { - DELETE(conf); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnKill] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - DELETE(conf); - conf = new ConfigReader(ServerInstance); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual int OnKill(userrec* source, userrec* dest, const std::string &reason) - { - long dest_level = 0,source_level = 0; - - // oper killing an oper? - if (IS_OPER(dest) && IS_OPER(source)) - { - for (int j =0; j < conf->Enumerate("type"); j++) - { - std::string typen = conf->ReadValue("type","name",j); - if (!strcmp(typen.c_str(),dest->oper)) - { - dest_level = conf->ReadInteger("type","level",j,true); - break; - } - } - for (int k =0; k < conf->Enumerate("type"); k++) - { - std::string typen = conf->ReadValue("type","name",k); - if (!strcmp(typen.c_str(),source->oper)) - { - source_level = conf->ReadInteger("type","level",k,true); - break; - } - } - if (dest_level > source_level) - { - ServerInstance->WriteOpers("Oper %s (level %d) attempted to /kill a higher oper: %s (level %d): Reason: %s",source->nick,source_level,dest->nick,dest_level,reason.c_str()); - dest->WriteServ("NOTICE %s :Oper %s attempted to /kill you!",dest->nick,source->nick); - source->WriteServ("481 %s :Permission Denied - Oper %s is a higher level than you",source->nick,dest->nick); - return 1; - } - } - return 0; - } - -}; - -class ModuleOperLevelsFactory : public ModuleFactory -{ - public: - ModuleOperLevelsFactory() - { - } - - ~ModuleOperLevelsFactory() - { - } - - virtual Module * CreateModule(InspIRCd* Me) - { - return new ModuleOperLevels(Me); - } - -}; - -extern "C" DllExport void * init_module( void ) -{ - return new ModuleOperLevelsFactory; -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Gives each oper type a 'level', cannot kill opers 'above' your level. */
class ModuleOperLevels : public Module
{
private:
ConfigReader* conf;
public:
ModuleOperLevels(InspIRCd* Me)
: Module(Me)
{
conf = new ConfigReader(ServerInstance);
}
virtual ~ModuleOperLevels()
{
DELETE(conf);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnKill] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
DELETE(conf);
conf = new ConfigReader(ServerInstance);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)
{
long dest_level = 0,source_level = 0;
// oper killing an oper?
if (IS_OPER(dest) && IS_OPER(source))
{
for (int j =0; j < conf->Enumerate("type"); j++)
{
std::string typen = conf->ReadValue("type","name",j);
if (!strcmp(typen.c_str(),dest->oper))
{
dest_level = conf->ReadInteger("type","level",j,true);
break;
}
}
for (int k =0; k < conf->Enumerate("type"); k++)
{
std::string typen = conf->ReadValue("type","name",k);
if (!strcmp(typen.c_str(),source->oper))
{
source_level = conf->ReadInteger("type","level",k,true);
break;
}
}
if (dest_level > source_level)
{
ServerInstance->WriteOpers("Oper %s (level %d) attempted to /kill a higher oper: %s (level %d): Reason: %s",source->nick,source_level,dest->nick,dest_level,reason.c_str());
dest->WriteServ("NOTICE %s :Oper %s attempted to /kill you!",dest->nick,source->nick);
source->WriteServ("481 %s :Permission Denied - Oper %s is a higher level than you",source->nick,dest->nick);
return 1;
}
}
return 0;
}
};
class ModuleOperLevelsFactory : public ModuleFactory
{
public:
ModuleOperLevelsFactory()
{
}
~ModuleOperLevelsFactory()
{
}
virtual Module * CreateModule(InspIRCd* Me)
{
return new ModuleOperLevels(Me);
}
};
extern "C" DllExport void * init_module( void )
{
return new ModuleOperLevelsFactory;
}
\ No newline at end of file diff --git a/src/modules/m_operlog.cpp b/src/modules/m_operlog.cpp index 9bbdbef25..1a7d5bd8a 100644 --- a/src/modules/m_operlog.cpp +++ b/src/modules/m_operlog.cpp @@ -1,75 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: A module which logs all oper commands to the ircd log at default loglevel. */ - -class ModuleOperLog : public Module -{ - private: - - public: - ModuleOperLog(InspIRCd* Me) : Module(Me) - { - - } - - virtual ~ModuleOperLog() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnPreCommand] = List[I_On005Numeric] = 1; - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - /* If the command doesnt appear to be valid, we dont want to mess with it. */ - if (!validated) - return 0; - - if ((IS_OPER(user)) && (IS_LOCAL(user)) && (user->HasPermission(command))) - { - command_t* thiscommand = ServerInstance->Parser->GetHandler(command); - if ((thiscommand) && (thiscommand->flags_needed = 'o')) - { - std::string plist; - for (int j = 0; j < pcnt; j++) - plist.append(std::string(" ")+std::string(parameters[j])); - - ServerInstance->Log(DEFAULT,"OPERLOG: [%s!%s@%s] %s%s",user->nick,user->ident,user->host,command.c_str(),plist.c_str()); - } - } - - return 0; - } - - virtual void On005Numeric(std::string &output) - { - output.append(" OPERLOG"); - } - -}; - - -MODULE_INIT(ModuleOperLog) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: A module which logs all oper commands to the ircd log at default loglevel. */
class ModuleOperLog : public Module
{
private:
public:
ModuleOperLog(InspIRCd* Me) : Module(Me)
{
}
virtual ~ModuleOperLog()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnPreCommand] = List[I_On005Numeric] = 1;
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
/* If the command doesnt appear to be valid, we dont want to mess with it. */
if (!validated)
return 0;
if ((IS_OPER(user)) && (IS_LOCAL(user)) && (user->HasPermission(command)))
{
command_t* thiscommand = ServerInstance->Parser->GetHandler(command);
if ((thiscommand) && (thiscommand->flags_needed = 'o'))
{
std::string plist;
for (int j = 0; j < pcnt; j++)
plist.append(std::string(" ")+std::string(parameters[j]));
ServerInstance->Log(DEFAULT,"OPERLOG: [%s!%s@%s] %s%s",user->nick,user->ident,user->host,command.c_str(),plist.c_str());
}
}
return 0;
}
virtual void On005Numeric(std::string &output)
{
output.append(" OPERLOG");
}
};
MODULE_INIT(ModuleOperLog)
\ No newline at end of file diff --git a/src/modules/m_opermodes.cpp b/src/modules/m_opermodes.cpp index 598f84e43..05d7a2b42 100644 --- a/src/modules/m_opermodes.cpp +++ b/src/modules/m_opermodes.cpp @@ -1,109 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Sets (and unsets) modes on opers when they oper up */ - -class ModuleModesOnOper : public Module -{ - private: - - - ConfigReader *Conf; - - public: - ModuleModesOnOper(InspIRCd* Me) - : Module(Me) - { - - Conf = new ConfigReader(ServerInstance); - } - - void Implements(char* List) - { - List[I_OnPostOper] = List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - DELETE(Conf); - Conf = new ConfigReader(ServerInstance); - } - - virtual ~ModuleModesOnOper() - { - DELETE(Conf); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void OnPostOper(userrec* user, const std::string &opertype) - { - // whenever a user opers, go through the oper types, find their <type:modes>, - // and if they have one apply their modes. The mode string can contain +modes - // to add modes to the user or -modes to take modes from the user. - for (int j =0; j < Conf->Enumerate("type"); j++) - { - std::string typen = Conf->ReadValue("type","name",j); - if (!strcmp(typen.c_str(),user->oper)) - { - std::string ThisOpersModes = Conf->ReadValue("type","modes",j); - if (!ThisOpersModes.empty()) - { - char first = *(ThisOpersModes.c_str()); - if ((first != '+') && (first != '-')) - ThisOpersModes = "+" + ThisOpersModes; - - std::string buf; - stringstream ss(ThisOpersModes); - vector<string> tokens; - - // split ThisOperModes into modes and mode params - while (ss >> buf) - tokens.push_back(buf); - - int size = tokens.size() + 1; - const char** modes = new const char*[size]; - modes[0] = user->nick; - - // process mode params - int i = 1; - for (unsigned int k = 0; k < tokens.size(); k++) - { - modes[i] = tokens[k].c_str(); - i++; - } - - std::deque<std::string> n; - Event rmode((char *)&n, NULL, "send_mode_explicit"); - for (unsigned int j = 0; j < tokens.size(); j++) - n.push_back(modes[j]); - - rmode.Send(ServerInstance); - ServerInstance->SendMode(modes, size, user); - delete [] modes; - } - break; - } - } - } -}; - -MODULE_INIT(ModuleModesOnOper) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Sets (and unsets) modes on opers when they oper up */
class ModuleModesOnOper : public Module
{
private:
ConfigReader *Conf;
public:
ModuleModesOnOper(InspIRCd* Me)
: Module(Me)
{
Conf = new ConfigReader(ServerInstance);
}
void Implements(char* List)
{
List[I_OnPostOper] = List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
DELETE(Conf);
Conf = new ConfigReader(ServerInstance);
}
virtual ~ModuleModesOnOper()
{
DELETE(Conf);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void OnPostOper(userrec* user, const std::string &opertype)
{
// whenever a user opers, go through the oper types, find their <type:modes>,
// and if they have one apply their modes. The mode string can contain +modes
// to add modes to the user or -modes to take modes from the user.
for (int j =0; j < Conf->Enumerate("type"); j++)
{
std::string typen = Conf->ReadValue("type","name",j);
if (!strcmp(typen.c_str(),user->oper))
{
std::string ThisOpersModes = Conf->ReadValue("type","modes",j);
if (!ThisOpersModes.empty())
{
char first = *(ThisOpersModes.c_str());
if ((first != '+') && (first != '-'))
ThisOpersModes = "+" + ThisOpersModes;
std::string buf;
stringstream ss(ThisOpersModes);
vector<string> tokens;
// split ThisOperModes into modes and mode params
while (ss >> buf)
tokens.push_back(buf);
int size = tokens.size() + 1;
const char** modes = new const char*[size];
modes[0] = user->nick;
// process mode params
int i = 1;
for (unsigned int k = 0; k < tokens.size(); k++)
{
modes[i] = tokens[k].c_str();
i++;
}
std::deque<std::string> n;
Event rmode((char *)&n, NULL, "send_mode_explicit");
for (unsigned int j = 0; j < tokens.size(); j++)
n.push_back(modes[j]);
rmode.Send(ServerInstance);
ServerInstance->SendMode(modes, size, user);
delete [] modes;
}
break;
}
}
}
};
MODULE_INIT(ModuleModesOnOper)
\ No newline at end of file diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index 55608dcb8..7e48eefdb 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -1,116 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */ - -static FileReader* opermotd; - -CmdResult ShowOperMOTD(userrec* user) -{ - if(!opermotd->FileSize()) - { - user->WriteServ(std::string("425 ") + user->nick + std::string(" :OPERMOTD file is missing")); - return CMD_FAILURE; - } - - user->WriteServ(std::string("375 ") + user->nick + std::string(" :- IRC Operators Message of the Day")); - - for(int i=0; i != opermotd->FileSize(); i++) - { - user->WriteServ(std::string("372 ") + user->nick + std::string(" :- ") + opermotd->GetLine(i)); - } - - user->WriteServ(std::string("376 ") + user->nick + std::string(" :- End of OPERMOTD")); - - /* don't route me */ - return CMD_LOCALONLY; -} - -/** Handle /OPERMOTD - */ -class cmd_opermotd : public command_t -{ - public: - cmd_opermotd (InspIRCd* Instance) : command_t(Instance,"OPERMOTD", 'o', 0) - { - this->source = "m_opermotd.so"; - syntax = "[<servername>]"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec* user) - { - return ShowOperMOTD(user); - } -}; - - -class ModuleOpermotd : public Module -{ - cmd_opermotd* mycommand; - public: - - void LoadOperMOTD() - { - ConfigReader* conf = new ConfigReader(ServerInstance); - std::string filename; - filename = conf->ReadValue("opermotd","file",0); - if (opermotd) - { - delete opermotd; - opermotd = NULL; - } - opermotd = new FileReader(ServerInstance, filename); - DELETE(conf); - } - - ModuleOpermotd(InspIRCd* Me) - : Module(Me) - { - opermotd = NULL; - mycommand = new cmd_opermotd(ServerInstance); - ServerInstance->AddCommand(mycommand); - opermotd = new FileReader(ServerInstance); - LoadOperMOTD(); - } - - virtual ~ModuleOpermotd() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnOper] = 1; - } - - virtual void OnOper(userrec* user, const std::string &opertype) - { - ShowOperMOTD(user); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - LoadOperMOTD(); - } -}; - -MODULE_INIT(ModuleOpermotd) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */
static FileReader* opermotd;
CmdResult ShowOperMOTD(userrec* user)
{
if(!opermotd->FileSize())
{
user->WriteServ(std::string("425 ") + user->nick + std::string(" :OPERMOTD file is missing"));
return CMD_FAILURE;
}
user->WriteServ(std::string("375 ") + user->nick + std::string(" :- IRC Operators Message of the Day"));
for(int i=0; i != opermotd->FileSize(); i++)
{
user->WriteServ(std::string("372 ") + user->nick + std::string(" :- ") + opermotd->GetLine(i));
}
user->WriteServ(std::string("376 ") + user->nick + std::string(" :- End of OPERMOTD"));
/* don't route me */
return CMD_LOCALONLY;
}
/** Handle /OPERMOTD
*/
class cmd_opermotd : public command_t
{
public:
cmd_opermotd (InspIRCd* Instance) : command_t(Instance,"OPERMOTD", 'o', 0)
{
this->source = "m_opermotd.so";
syntax = "[<servername>]";
}
CmdResult Handle (const char** parameters, int pcnt, userrec* user)
{
return ShowOperMOTD(user);
}
};
class ModuleOpermotd : public Module
{
cmd_opermotd* mycommand;
public:
void LoadOperMOTD()
{
ConfigReader* conf = new ConfigReader(ServerInstance);
std::string filename;
filename = conf->ReadValue("opermotd","file",0);
if (opermotd)
{
delete opermotd;
opermotd = NULL;
}
opermotd = new FileReader(ServerInstance, filename);
DELETE(conf);
}
ModuleOpermotd(InspIRCd* Me)
: Module(Me)
{
opermotd = NULL;
mycommand = new cmd_opermotd(ServerInstance);
ServerInstance->AddCommand(mycommand);
opermotd = new FileReader(ServerInstance);
LoadOperMOTD();
}
virtual ~ModuleOpermotd()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnOper] = 1;
}
virtual void OnOper(userrec* user, const std::string &opertype)
{
ShowOperMOTD(user);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
LoadOperMOTD();
}
};
MODULE_INIT(ModuleOpermotd)
\ No newline at end of file diff --git a/src/modules/m_override.cpp b/src/modules/m_override.cpp index be123d4fd..c5b343552 100644 --- a/src/modules/m_override.cpp +++ b/src/modules/m_override.cpp @@ -1,294 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" -#include "wildcard.h" - -/* $ModDesc: Provides support for unreal-style oper-override */ - -typedef std::map<std::string,std::string> override_t; - -class ModuleOverride : public Module -{ - - override_t overrides; - bool NoisyOverride; - bool OverriddenMode; - int OverOps, OverDeops, OverVoices, OverDevoices, OverHalfops, OverDehalfops; - - public: - - ModuleOverride(InspIRCd* Me) - : Module(Me) - { - // read our config options (main config file) - OnRehash(NULL,""); - ServerInstance->SNO->EnableSnomask('O',"OVERRIDE"); - OverriddenMode = false; - OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - // on a rehash we delete our classes for good measure and create them again. - ConfigReader* Conf = new ConfigReader(ServerInstance); - - // re-read our config options on a rehash - NoisyOverride = Conf->ReadFlag("override","noisy",0); - overrides.clear(); - for (int j =0; j < Conf->Enumerate("type"); j++) - { - std::string typen = Conf->ReadValue("type","name",j); - std::string tokenlist = Conf->ReadValue("type","override",j); - overrides[typen] = tokenlist; - } - - DELETE(Conf); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnAccessCheck] = List[I_On005Numeric] = List[I_OnUserPreJoin] = List[I_OnUserPreKick] = List[I_OnPostCommand] = 1; - } - - virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line) - { - if ((NoisyOverride) && (OverriddenMode) && (irc::string(command.c_str()) == "MODE") && (result == CMD_SUCCESS)) - { - int Total = OverOps + OverDeops + OverVoices + OverDevoices + OverHalfops + OverDehalfops; - - ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" Overriding modes: "+ServerInstance->Modes->GetLastParse()+" "+(Total ? "[Detail: " : "")+ - (OverOps ? ConvToStr(OverOps)+" op"+(OverOps != 1 ? "s" : "")+" " : "")+ - (OverDeops ? ConvToStr(OverDeops)+" deop"+(OverDeops != 1 ? "s" : "")+" " : "")+ - (OverVoices ? ConvToStr(OverVoices)+" voice"+(OverVoices != 1 ? "s" : "")+" " : "")+ - (OverDevoices ? ConvToStr(OverDevoices)+" devoice"+(OverDevoices != 1 ? "s" : "")+" " : "")+ - (OverHalfops ? ConvToStr(OverHalfops)+" halfop"+(OverHalfops != 1 ? "s" : "")+" " : "")+ - (OverDehalfops ? ConvToStr(OverDehalfops)+" dehalfop"+(OverDehalfops != 1 ? "s" : "") : "") - +(Total ? "]" : "")); - - OverriddenMode = false; - OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0; - } - } - - virtual void On005Numeric(std::string &output) - { - output.append(" OVERRIDE"); - } - - virtual bool CanOverride(userrec* source, char* token) - { - // checks to see if the oper's type has <type:override> - override_t::iterator j = overrides.find(source->oper); - - if (j != overrides.end()) - { - // its defined or * is set, return its value as a boolean for if the token is set - return ((j->second.find(token, 0) != std::string::npos) || (j->second.find("*", 0) != std::string::npos)); - } - - // its not defined at all, count as false - return false; - } - - virtual int OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason) - { - if (IS_OPER(source) && CanOverride(source,"KICK")) - { - if (((chan->GetStatus(source) == STATUS_HOP) && (chan->GetStatus(user) == STATUS_OP)) || (chan->GetStatus(source) < STATUS_VOICE)) - { - ServerInstance->SNO->WriteToSnoMask('O',std::string(source->nick)+" Override-Kicked "+std::string(user->nick)+" on "+std::string(chan->name)+" ("+reason+")"); - } - /* Returning -1 explicitly allows the kick */ - return -1; - } - return 0; - } - - virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type) - { - if (IS_OPER(source)) - { - if (source && channel) - { - // Fix by brain - allow the change if they arent on channel - rely on boolean short-circuit - // to not check the other items in the statement if they arent on the channel - int mode = channel->GetStatus(source); - switch (access_type) - { - case AC_DEOP: - if (CanOverride(source,"MODEDEOP")) - { - if (NoisyOverride) - if ((!channel->HasUser(source)) || (mode < STATUS_OP)) - OverDeops++; - return ACR_ALLOW; - } - else - { - return ACR_DEFAULT; - } - break; - case AC_OP: - if (CanOverride(source,"MODEOP")) - { - if (NoisyOverride) - if ((!channel->HasUser(source)) || (mode < STATUS_OP)) - OverOps++; - return ACR_ALLOW; - } - else - { - return ACR_DEFAULT; - } - break; - case AC_VOICE: - if (CanOverride(source,"MODEVOICE")) - { - if (NoisyOverride) - if ((!channel->HasUser(source)) || (mode < STATUS_HOP)) - OverVoices++; - return ACR_ALLOW; - } - else - { - return ACR_DEFAULT; - } - break; - case AC_DEVOICE: - if (CanOverride(source,"MODEDEVOICE")) - { - if (NoisyOverride) - if ((!channel->HasUser(source)) || (mode < STATUS_HOP)) - OverDevoices++; - return ACR_ALLOW; - } - else - { - return ACR_DEFAULT; - } - break; - case AC_HALFOP: - if (CanOverride(source,"MODEHALFOP")) - { - if (NoisyOverride) - if ((!channel->HasUser(source)) || (mode < STATUS_OP)) - OverHalfops++; - return ACR_ALLOW; - } - else - { - return ACR_DEFAULT; - } - break; - case AC_DEHALFOP: - if (CanOverride(source,"MODEDEHALFOP")) - { - if (NoisyOverride) - if ((!channel->HasUser(source)) || (mode < STATUS_OP)) - OverDehalfops++; - return ACR_ALLOW; - } - else - { - return ACR_DEFAULT; - } - break; - } - - if (CanOverride(source,"OTHERMODE")) - { - if (NoisyOverride) - if ((!channel->HasUser(source)) || (mode < STATUS_OP)) - { - OverriddenMode = true; - OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0; - } - return ACR_ALLOW; - } - else - { - return ACR_DEFAULT; - } - } - } - - return ACR_DEFAULT; - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if (IS_OPER(user)) - { - if (chan) - { - if ((chan->modes[CM_INVITEONLY]) && (CanOverride(user,"INVITE"))) - { - irc::string x = chan->name; - if (!user->IsInvited(x)) - { - /* XXX - Ugly cast for a parameter that isn't used? :< - Om */ - if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass invite-only", cname, user->nick); - ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +i on "+std::string(cname)); - } - return -1; - } - - if ((*chan->key) && (CanOverride(user,"KEY"))) - { - if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel key", cname, user->nick); - ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +k on "+std::string(cname)); - return -1; - } - - if ((chan->limit > 0) && (chan->GetUserCounter() >= chan->limit) && (CanOverride(user,"LIMIT"))) - { - if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel limit", cname, user->nick); - ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +l on "+std::string(cname)); - return -1; - } - - if (CanOverride(user,"BANWALK")) - { - if (chan->IsBanned(user)) - { - if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass channel ban", cname, user->nick); - ServerInstance->SNO->WriteToSnoMask('O',"%s used oper-override to bypass channel ban on %s", user->nick, cname); - } - return -1; - } - } - } - return 0; - } - - virtual ~ModuleOverride() - { - ServerInstance->SNO->DisableSnomask('O'); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleOverride) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
#include "wildcard.h"
/* $ModDesc: Provides support for unreal-style oper-override */
typedef std::map<std::string,std::string> override_t;
class ModuleOverride : public Module
{
override_t overrides;
bool NoisyOverride;
bool OverriddenMode;
int OverOps, OverDeops, OverVoices, OverDevoices, OverHalfops, OverDehalfops;
public:
ModuleOverride(InspIRCd* Me)
: Module(Me)
{
// read our config options (main config file)
OnRehash(NULL,"");
ServerInstance->SNO->EnableSnomask('O',"OVERRIDE");
OverriddenMode = false;
OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
// on a rehash we delete our classes for good measure and create them again.
ConfigReader* Conf = new ConfigReader(ServerInstance);
// re-read our config options on a rehash
NoisyOverride = Conf->ReadFlag("override","noisy",0);
overrides.clear();
for (int j =0; j < Conf->Enumerate("type"); j++)
{
std::string typen = Conf->ReadValue("type","name",j);
std::string tokenlist = Conf->ReadValue("type","override",j);
overrides[typen] = tokenlist;
}
DELETE(Conf);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnAccessCheck] = List[I_On005Numeric] = List[I_OnUserPreJoin] = List[I_OnUserPreKick] = List[I_OnPostCommand] = 1;
}
virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line)
{
if ((NoisyOverride) && (OverriddenMode) && (irc::string(command.c_str()) == "MODE") && (result == CMD_SUCCESS))
{
int Total = OverOps + OverDeops + OverVoices + OverDevoices + OverHalfops + OverDehalfops;
ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" Overriding modes: "+ServerInstance->Modes->GetLastParse()+" "+(Total ? "[Detail: " : "")+
(OverOps ? ConvToStr(OverOps)+" op"+(OverOps != 1 ? "s" : "")+" " : "")+
(OverDeops ? ConvToStr(OverDeops)+" deop"+(OverDeops != 1 ? "s" : "")+" " : "")+
(OverVoices ? ConvToStr(OverVoices)+" voice"+(OverVoices != 1 ? "s" : "")+" " : "")+
(OverDevoices ? ConvToStr(OverDevoices)+" devoice"+(OverDevoices != 1 ? "s" : "")+" " : "")+
(OverHalfops ? ConvToStr(OverHalfops)+" halfop"+(OverHalfops != 1 ? "s" : "")+" " : "")+
(OverDehalfops ? ConvToStr(OverDehalfops)+" dehalfop"+(OverDehalfops != 1 ? "s" : "") : "")
+(Total ? "]" : ""));
OverriddenMode = false;
OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;
}
}
virtual void On005Numeric(std::string &output)
{
output.append(" OVERRIDE");
}
virtual bool CanOverride(userrec* source, char* token)
{
// checks to see if the oper's type has <type:override>
override_t::iterator j = overrides.find(source->oper);
if (j != overrides.end())
{
// its defined or * is set, return its value as a boolean for if the token is set
return ((j->second.find(token, 0) != std::string::npos) || (j->second.find("*", 0) != std::string::npos));
}
// its not defined at all, count as false
return false;
}
virtual int OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason)
{
if (IS_OPER(source) && CanOverride(source,"KICK"))
{
if (((chan->GetStatus(source) == STATUS_HOP) && (chan->GetStatus(user) == STATUS_OP)) || (chan->GetStatus(source) < STATUS_VOICE))
{
ServerInstance->SNO->WriteToSnoMask('O',std::string(source->nick)+" Override-Kicked "+std::string(user->nick)+" on "+std::string(chan->name)+" ("+reason+")");
}
/* Returning -1 explicitly allows the kick */
return -1;
}
return 0;
}
virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)
{
if (IS_OPER(source))
{
if (source && channel)
{
// Fix by brain - allow the change if they arent on channel - rely on boolean short-circuit
// to not check the other items in the statement if they arent on the channel
int mode = channel->GetStatus(source);
switch (access_type)
{
case AC_DEOP:
if (CanOverride(source,"MODEDEOP"))
{
if (NoisyOverride)
if ((!channel->HasUser(source)) || (mode < STATUS_OP))
OverDeops++;
return ACR_ALLOW;
}
else
{
return ACR_DEFAULT;
}
break;
case AC_OP:
if (CanOverride(source,"MODEOP"))
{
if (NoisyOverride)
if ((!channel->HasUser(source)) || (mode < STATUS_OP))
OverOps++;
return ACR_ALLOW;
}
else
{
return ACR_DEFAULT;
}
break;
case AC_VOICE:
if (CanOverride(source,"MODEVOICE"))
{
if (NoisyOverride)
if ((!channel->HasUser(source)) || (mode < STATUS_HOP))
OverVoices++;
return ACR_ALLOW;
}
else
{
return ACR_DEFAULT;
}
break;
case AC_DEVOICE:
if (CanOverride(source,"MODEDEVOICE"))
{
if (NoisyOverride)
if ((!channel->HasUser(source)) || (mode < STATUS_HOP))
OverDevoices++;
return ACR_ALLOW;
}
else
{
return ACR_DEFAULT;
}
break;
case AC_HALFOP:
if (CanOverride(source,"MODEHALFOP"))
{
if (NoisyOverride)
if ((!channel->HasUser(source)) || (mode < STATUS_OP))
OverHalfops++;
return ACR_ALLOW;
}
else
{
return ACR_DEFAULT;
}
break;
case AC_DEHALFOP:
if (CanOverride(source,"MODEDEHALFOP"))
{
if (NoisyOverride)
if ((!channel->HasUser(source)) || (mode < STATUS_OP))
OverDehalfops++;
return ACR_ALLOW;
}
else
{
return ACR_DEFAULT;
}
break;
}
if (CanOverride(source,"OTHERMODE"))
{
if (NoisyOverride)
if ((!channel->HasUser(source)) || (mode < STATUS_OP))
{
OverriddenMode = true;
OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;
}
return ACR_ALLOW;
}
else
{
return ACR_DEFAULT;
}
}
}
return ACR_DEFAULT;
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if (IS_OPER(user))
{
if (chan)
{
if ((chan->modes[CM_INVITEONLY]) && (CanOverride(user,"INVITE")))
{
irc::string x = chan->name;
if (!user->IsInvited(x))
{
/* XXX - Ugly cast for a parameter that isn't used? :< - Om */
if (NoisyOverride)
chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass invite-only", cname, user->nick);
ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +i on "+std::string(cname));
}
return -1;
}
if ((*chan->key) && (CanOverride(user,"KEY")))
{
if (NoisyOverride)
chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel key", cname, user->nick);
ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +k on "+std::string(cname));
return -1;
}
if ((chan->limit > 0) && (chan->GetUserCounter() >= chan->limit) && (CanOverride(user,"LIMIT")))
{
if (NoisyOverride)
chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel limit", cname, user->nick);
ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +l on "+std::string(cname));
return -1;
}
if (CanOverride(user,"BANWALK"))
{
if (chan->IsBanned(user))
{
if (NoisyOverride)
chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass channel ban", cname, user->nick);
ServerInstance->SNO->WriteToSnoMask('O',"%s used oper-override to bypass channel ban on %s", user->nick, cname);
}
return -1;
}
}
}
return 0;
}
virtual ~ModuleOverride()
{
ServerInstance->SNO->DisableSnomask('O');
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleOverride)
\ No newline at end of file diff --git a/src/modules/m_randquote.cpp b/src/modules/m_randquote.cpp index 2ad7831ce..8ab9aab4e 100644 --- a/src/modules/m_randquote.cpp +++ b/src/modules/m_randquote.cpp @@ -1,138 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -static FileReader *quotes = NULL; - -std::string q_file; -std::string prefix; -std::string suffix; - -/* $ModDesc: Provides random Quotes on Connect. */ - -/** Handle /RANDQUOTE - */ -class cmd_randquote : public command_t -{ - public: - cmd_randquote (InspIRCd* Instance) : command_t(Instance,"RANDQUOTE", 0, 0) - { - this->source = "m_randquote.so"; - } - - CmdResult Handle (const char** parameters, int pcntl, userrec *user) - { - std::string str; - int fsize; - - if (q_file.empty() || quotes->Exists()) - { - fsize = quotes->FileSize(); - str = quotes->GetLine(rand() % fsize); - user->WriteServ("NOTICE %s :%s%s%s",user->nick,prefix.c_str(),str.c_str(),suffix.c_str()); - } - else - { - user->WriteServ("NOTICE %s :Your administrator specified an invalid quotes file, please bug them about this.", user->nick); - return CMD_FAILURE; - } - - return CMD_LOCALONLY; - } -}; - -/** Thrown by m_randquote - */ -class RandquoteException : public ModuleException -{ - private: - const std::string err; - public: - RandquoteException(const std::string &message) : err(message) { } - - ~RandquoteException() throw () { } - - virtual const char* GetReason() - { - return err.c_str(); - } -}; - -class ModuleRandQuote : public Module -{ - private: - cmd_randquote* mycommand; - ConfigReader *conf; - public: - ModuleRandQuote(InspIRCd* Me) - : Module(Me) - { - - conf = new ConfigReader(ServerInstance); - // Sort the Randomizer thingie.. - srand(time(NULL)); - - q_file = conf->ReadValue("randquote","file",0); - prefix = conf->ReadValue("randquote","prefix",0); - suffix = conf->ReadValue("randquote","suffix",0); - - mycommand = NULL; - - if (q_file.empty()) - { - RandquoteException e("m_randquote: Quotefile not specified - Please check your config."); - throw(e); - } - - quotes = new FileReader(ServerInstance, q_file); - if(!quotes->Exists()) - { - RandquoteException e("m_randquote: QuoteFile not Found!! Please check your config - module will not function."); - throw(e); - } - else - { - /* Hidden Command -- Mode clients assume /quote sends raw data to an IRCd >:D */ - mycommand = new cmd_randquote(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - } - - void Implements(char* List) - { - List[I_OnUserConnect] = 1; - } - - virtual ~ModuleRandQuote() - { - DELETE(conf); - DELETE(quotes); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void OnUserConnect(userrec* user) - { - if (mycommand) - mycommand->Handle(NULL, 0, user); - } -}; - -MODULE_INIT(ModuleRandQuote) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
static FileReader *quotes = NULL;
std::string q_file;
std::string prefix;
std::string suffix;
/* $ModDesc: Provides random Quotes on Connect. */
/** Handle /RANDQUOTE
*/
class cmd_randquote : public command_t
{
public:
cmd_randquote (InspIRCd* Instance) : command_t(Instance,"RANDQUOTE", 0, 0)
{
this->source = "m_randquote.so";
}
CmdResult Handle (const char** parameters, int pcntl, userrec *user)
{
std::string str;
int fsize;
if (q_file.empty() || quotes->Exists())
{
fsize = quotes->FileSize();
str = quotes->GetLine(rand() % fsize);
user->WriteServ("NOTICE %s :%s%s%s",user->nick,prefix.c_str(),str.c_str(),suffix.c_str());
}
else
{
user->WriteServ("NOTICE %s :Your administrator specified an invalid quotes file, please bug them about this.", user->nick);
return CMD_FAILURE;
}
return CMD_LOCALONLY;
}
};
/** Thrown by m_randquote
*/
class RandquoteException : public ModuleException
{
private:
const std::string err;
public:
RandquoteException(const std::string &message) : err(message) { }
~RandquoteException() throw () { }
virtual const char* GetReason()
{
return err.c_str();
}
};
class ModuleRandQuote : public Module
{
private:
cmd_randquote* mycommand;
ConfigReader *conf;
public:
ModuleRandQuote(InspIRCd* Me)
: Module(Me)
{
conf = new ConfigReader(ServerInstance);
// Sort the Randomizer thingie..
srand(time(NULL));
q_file = conf->ReadValue("randquote","file",0);
prefix = conf->ReadValue("randquote","prefix",0);
suffix = conf->ReadValue("randquote","suffix",0);
mycommand = NULL;
if (q_file.empty())
{
RandquoteException e("m_randquote: Quotefile not specified - Please check your config.");
throw(e);
}
quotes = new FileReader(ServerInstance, q_file);
if(!quotes->Exists())
{
RandquoteException e("m_randquote: QuoteFile not Found!! Please check your config - module will not function.");
throw(e);
}
else
{
/* Hidden Command -- Mode clients assume /quote sends raw data to an IRCd >:D */
mycommand = new cmd_randquote(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
}
void Implements(char* List)
{
List[I_OnUserConnect] = 1;
}
virtual ~ModuleRandQuote()
{
DELETE(conf);
DELETE(quotes);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void OnUserConnect(userrec* user)
{
if (mycommand)
mycommand->Handle(NULL, 0, user);
}
};
MODULE_INIT(ModuleRandQuote)
\ No newline at end of file diff --git a/src/modules/m_redirect.cpp b/src/modules/m_redirect.cpp index a746644c2..ee2d3f004 100644 --- a/src/modules/m_redirect.cpp +++ b/src/modules/m_redirect.cpp @@ -1,160 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides channel mode +L (limit redirection) */ - -/** Handle channel mode +L - */ -class Redirect : public ModeHandler -{ - public: - Redirect(InspIRCd* Instance) : ModeHandler(Instance, 'L', 1, 0, false, MODETYPE_CHANNEL, false) { } - - ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) - { - if (channel->IsModeSet('L')) - return std::make_pair(true, channel->GetModeParameter('L')); - else - return std::make_pair(false, parameter); - } - - bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel) - { - /* When TS is equal, the alphabetically later one wins */ - return (their_param < our_param); - } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - chanrec* c = NULL; - - if (!ServerInstance->IsChannel(parameter.c_str())) - { - source->WriteServ("403 %s %s :Invalid channel name",source->nick, parameter.c_str()); - parameter.clear(); - return MODEACTION_DENY; - } - - c = ServerInstance->FindChan(parameter); - if (c) - { - /* Fix by brain: Dont let a channel be linked to *itself* either */ - if (IS_LOCAL(source)) - { - if ((c == channel) || (c->IsModeSet('L'))) - { - source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Channel already has +L). Pack of wild dogs has been unleashed.",source->nick,parameter.c_str()); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) - { - if ((i->second != channel) && (i->second->IsModeSet('L')) && (irc::string(i->second->GetModeParameter('L').c_str()) == irc::string(channel->name))) - { - source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Already forwarded here from %s). Angry monkeys dispatched.",source->nick,parameter.c_str(),i->second->name); - return MODEACTION_DENY; - } - } - } - } - } - - channel->SetMode('L', true); - channel->SetModeParam('L', parameter.c_str(), true); - return MODEACTION_ALLOW; - } - else - { - if (channel->IsModeSet('L')) - { - channel->SetMode('L', false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - - } -}; - -class ModuleRedirect : public Module -{ - - Redirect* re; - - public: - - ModuleRedirect(InspIRCd* Me) - : Module(Me) - { - - re = new Redirect(ServerInstance); - if (!ServerInstance->AddMode(re, 'L')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreJoin] = 1; - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if (chan) - { - if (chan->IsModeSet('L') && chan->limit) - { - if (chan->GetUserCounter() >= chan->limit) - { - std::string channel = chan->GetModeParameter('L'); - - /* sometimes broken ulines can make circular or chained +L, avoid this */ - chanrec* destchan = NULL; - destchan = ServerInstance->FindChan(channel); - if (destchan && destchan->IsModeSet('L')) - { - user->WriteServ("470 %s :%s is full, but has a circular redirect (+L), not following redirection to %s", user->nick, cname, channel.c_str()); - return 1; - } - - user->WriteServ("470 %s :%s has become full, so you are automatically being transferred to the linked channel %s", user->nick, cname, channel.c_str()); - chanrec::JoinUser(ServerInstance, user, channel.c_str(), false, "", ServerInstance->Time(true)); - return 1; - } - } - } - return 0; - } - - virtual ~ModuleRedirect() - { - ServerInstance->Modes->DelMode(re); - DELETE(re); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleRedirect) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides channel mode +L (limit redirection) */
/** Handle channel mode +L
*/
class Redirect : public ModeHandler
{
public:
Redirect(InspIRCd* Instance) : ModeHandler(Instance, 'L', 1, 0, false, MODETYPE_CHANNEL, false) { }
ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
{
if (channel->IsModeSet('L'))
return std::make_pair(true, channel->GetModeParameter('L'));
else
return std::make_pair(false, parameter);
}
bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
{
/* When TS is equal, the alphabetically later one wins */
return (their_param < our_param);
}
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
chanrec* c = NULL;
if (!ServerInstance->IsChannel(parameter.c_str()))
{
source->WriteServ("403 %s %s :Invalid channel name",source->nick, parameter.c_str());
parameter.clear();
return MODEACTION_DENY;
}
c = ServerInstance->FindChan(parameter);
if (c)
{
/* Fix by brain: Dont let a channel be linked to *itself* either */
if (IS_LOCAL(source))
{
if ((c == channel) || (c->IsModeSet('L')))
{
source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Channel already has +L). Pack of wild dogs has been unleashed.",source->nick,parameter.c_str());
parameter.clear();
return MODEACTION_DENY;
}
else
{
for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
{
if ((i->second != channel) && (i->second->IsModeSet('L')) && (irc::string(i->second->GetModeParameter('L').c_str()) == irc::string(channel->name)))
{
source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Already forwarded here from %s). Angry monkeys dispatched.",source->nick,parameter.c_str(),i->second->name);
return MODEACTION_DENY;
}
}
}
}
}
channel->SetMode('L', true);
channel->SetModeParam('L', parameter.c_str(), true);
return MODEACTION_ALLOW;
}
else
{
if (channel->IsModeSet('L'))
{
channel->SetMode('L', false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleRedirect : public Module
{
Redirect* re;
public:
ModuleRedirect(InspIRCd* Me)
: Module(Me)
{
re = new Redirect(ServerInstance);
if (!ServerInstance->AddMode(re, 'L'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreJoin] = 1;
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if (chan)
{
if (chan->IsModeSet('L') && chan->limit)
{
if (chan->GetUserCounter() >= chan->limit)
{
std::string channel = chan->GetModeParameter('L');
/* sometimes broken ulines can make circular or chained +L, avoid this */
chanrec* destchan = NULL;
destchan = ServerInstance->FindChan(channel);
if (destchan && destchan->IsModeSet('L'))
{
user->WriteServ("470 %s :%s is full, but has a circular redirect (+L), not following redirection to %s", user->nick, cname, channel.c_str());
return 1;
}
user->WriteServ("470 %s :%s has become full, so you are automatically being transferred to the linked channel %s", user->nick, cname, channel.c_str());
chanrec::JoinUser(ServerInstance, user, channel.c_str(), false, "", ServerInstance->Time(true));
return 1;
}
}
}
return 0;
}
virtual ~ModuleRedirect()
{
ServerInstance->Modes->DelMode(re);
DELETE(re);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleRedirect)
\ No newline at end of file diff --git a/src/modules/m_regonlycreate.cpp b/src/modules/m_regonlycreate.cpp index 2174c860c..0d911a0bf 100644 --- a/src/modules/m_regonlycreate.cpp +++ b/src/modules/m_regonlycreate.cpp @@ -1,61 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Prevents users who's nicks are not registered from creating new channels */ - -class ModuleRegOnlyCreate : public Module -{ - public: - ModuleRegOnlyCreate(InspIRCd* Me) - : Module(Me) - { - } - - void Implements(char* List) - { - List[I_OnUserPreJoin] = 1; - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if (chan) - return 0; - - if (IS_OPER(user)) - return 0; - - if ((!user->IsModeSet('r')) && (!user->GetExt("accountname"))) - { - user->WriteServ("482 %s %s :You must have a registered nickname to create a new channel", user->nick, cname); - return 1; - } - - return 0; - } - - virtual ~ModuleRegOnlyCreate() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleRegOnlyCreate) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Prevents users who's nicks are not registered from creating new channels */
class ModuleRegOnlyCreate : public Module
{
public:
ModuleRegOnlyCreate(InspIRCd* Me)
: Module(Me)
{
}
void Implements(char* List)
{
List[I_OnUserPreJoin] = 1;
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if (chan)
return 0;
if (IS_OPER(user))
return 0;
if ((!user->IsModeSet('r')) && (!user->GetExt("accountname")))
{
user->WriteServ("482 %s %s :You must have a registered nickname to create a new channel", user->nick, cname);
return 1;
}
return 0;
}
virtual ~ModuleRegOnlyCreate()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleRegOnlyCreate)
\ No newline at end of file diff --git a/src/modules/m_remove.cpp b/src/modules/m_remove.cpp index d28087ba8..6d9be00ad 100644 --- a/src/modules/m_remove.cpp +++ b/src/modules/m_remove.cpp @@ -1,288 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <sstream> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" - -/* $ModDesc: Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel */ - -/* - * This module supports the use of the +q and +a usermodes, but should work without them too. - * Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself. - * eg: +h can remove +hv and users with no modes. +a can remove +aohv and users with no modes. -*/ - -/** Base class for /FPART and /REMOVE - */ -class RemoveBase -{ - private: - bool& supportnokicks; - InspIRCd* ServerInstance; - - protected: - RemoveBase(InspIRCd* Instance, bool& snk) : supportnokicks(snk), ServerInstance(Instance) - { - } - - enum ModeLevel { PEON = 0, HALFOP = 1, OP = 2, ADMIN = 3, OWNER = 4, ULINE = 5 }; - - /* This little function just converts a chanmode character (U ~ & @ & +) into an integer (5 4 3 2 1 0) */ - /* XXX - We should probably use the new mode prefix rank stuff - * for this instead now -- Brain */ - ModeLevel chartolevel(const std::string &privs) - { - if(privs.empty()) - { - return PEON; - } - - switch (privs[0]) - { - case 'U': - /* Ulined */ - return ULINE; - case '~': - /* Owner */ - return OWNER; - case '&': - /* Admin */ - return ADMIN; - case '@': - /* Operator */ - return OP; - case '%': - /* Halfop */ - return HALFOP; - default: - /* Peon */ - return PEON; - } - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user, bool neworder) - { - const char* channame; - const char* username; - userrec* target; - chanrec* channel; - ModeLevel tlevel; - ModeLevel ulevel; - std::string reason; - std::string protectkey; - std::string founderkey; - bool hasnokicks; - - /* Set these to the parameters needed, the new version of this module switches it's parameters around - * supplying a new command with the new order while keeping the old /remove with the older order. - * /remove <nick> <channel> [reason ...] - * /fpart <channel> <nick> [reason ...] - */ - channame = parameters[ neworder ? 0 : 1]; - username = parameters[ neworder ? 1 : 0]; - - /* Look up the user we're meant to be removing from the channel */ - target = ServerInstance->FindNick(username); - - /* And the channel we're meant to be removing them from */ - channel = ServerInstance->FindChan(channame); - - /* Fix by brain - someone needs to learn to validate their input! */ - if (!target || !channel) - { - user->WriteServ("401 %s %s :No such nick/channel", user->nick, !target ? username : channame); - return CMD_FAILURE; - } - - if (!channel->HasUser(target)) - { - user->WriteServ( "NOTICE %s :*** The user %s is not on channel %s", user->nick, target->nick, channel->name); - return CMD_FAILURE; - } - - /* This is adding support for the +q and +a channel modes, basically if they are enabled, and the remover has them set. - * Then we change the @|%|+ to & if they are +a, or ~ if they are +q */ - protectkey = "cm_protect_" + std::string(channel->name); - founderkey = "cm_founder_" + std::string(channel->name); - - if (ServerInstance->ULine(user->server) || ServerInstance->ULine(user->nick)) - { - ulevel = chartolevel("U"); - } - if (user->GetExt(founderkey)) - { - ulevel = chartolevel("~"); - } - else if (user->GetExt(protectkey)) - { - ulevel = chartolevel("&"); - } - else - { - ulevel = chartolevel(channel->GetPrefixChar(user)); - } - - /* Now it's the same idea, except for the target. If they're ulined make sure they get a higher level than the sender can */ - if (ServerInstance->ULine(target->server) || ServerInstance->ULine(target->nick)) - { - tlevel = chartolevel("U"); - } - else if (target->GetExt(founderkey)) - { - tlevel = chartolevel("~"); - } - else if (target->GetExt(protectkey)) - { - tlevel = chartolevel("&"); - } - else - { - tlevel = chartolevel(channel->GetPrefixChar(target)); - } - - hasnokicks = (ServerInstance->FindModule("m_nokicks.so") && channel->IsModeSet('Q')); - - /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */ - if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks || (ulevel == ULINE))) - { - /* We'll let everyone remove their level and below, eg: - * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1) - * a ulined target will get a higher level than it's possible for a /remover to get..so they're safe. - * Nobody may remove a founder. - */ - if ((!IS_LOCAL(user)) || ((ulevel > PEON) && (ulevel >= tlevel) && (tlevel != OWNER))) - { - // no you can't just go from a std::ostringstream to a std::string, Om. -nenolod - // but you can do this, nenolod -brain - - std::string reasonparam("No reason given"); - - /* If a reason is given, use it */ - if(pcnt > 2) - { - /* Join params 2 ... pcnt - 1 (inclusive) into one */ - irc::stringjoiner reason_join(" ", parameters, 2, pcnt - 1); - reasonparam = reason_join.GetJoined(); - } - - /* Build up the part reason string. */ - reason = std::string("Removed by ") + user->nick + ": " + reasonparam; - - channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name, user->nick, target->nick); - target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick, user->nick, channel->name, reasonparam.c_str()); - - if (!channel->PartUser(target, reason.c_str())) - delete channel; - } - else - { - user->WriteServ( "NOTICE %s :*** You do not have access to /remove %s from %s", user->nick, target->nick, channel->name); - return CMD_FAILURE; - } - } - else - { - /* m_nokicks.so was loaded and +Q was set, block! */ - user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick, channel->name, target->nick); - return CMD_FAILURE; - } - - /* route me */ - return CMD_SUCCESS; - } -}; - -/** Handle /REMOVE - */ -class cmd_remove : public command_t, public RemoveBase -{ - public: - cmd_remove(InspIRCd* Instance, bool& snk) : command_t(Instance, "REMOVE", 0, 2), RemoveBase(Instance, snk) - { - this->source = "m_remove.so"; - syntax = "<nick> <channel> [<reason>]"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - return RemoveBase::Handle(parameters, pcnt, user, false); - } -}; - -/** Handle /FPART - */ -class cmd_fpart : public command_t, public RemoveBase -{ - public: - cmd_fpart(InspIRCd* Instance, bool& snk) : command_t(Instance, "FPART", 0, 2), RemoveBase(Instance, snk) - { - this->source = "m_remove.so"; - syntax = "<channel> <nick> [<reason>]"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - return RemoveBase::Handle(parameters, pcnt, user, true); - } -}; - -class ModuleRemove : public Module -{ - cmd_remove* mycommand; - cmd_fpart* mycommand2; - bool supportnokicks; - - - public: - ModuleRemove(InspIRCd* Me) - : Module(Me) - { - mycommand = new cmd_remove(ServerInstance, supportnokicks); - mycommand2 = new cmd_fpart(ServerInstance, supportnokicks); - ServerInstance->AddCommand(mycommand); - ServerInstance->AddCommand(mycommand2); - OnRehash(NULL,""); - } - - void Implements(char* List) - { - List[I_On005Numeric] = List[I_OnRehash] = 1; - } - - virtual void On005Numeric(std::string &output) - { - output.append(" REMOVE"); - } - - virtual void OnRehash(userrec* user, const std::string&) - { - ConfigReader conf(ServerInstance); - supportnokicks = conf.ReadFlag("remove", "supportnokicks", 0); - } - - virtual ~ModuleRemove() - { - } - - virtual Version GetVersion() - { - return Version(1,1,1,0,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleRemove) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <sstream>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
/* $ModDesc: Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel */
/*
* This module supports the use of the +q and +a usermodes, but should work without them too.
* Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself.
* eg: +h can remove +hv and users with no modes. +a can remove +aohv and users with no modes.
*/
/** Base class for /FPART and /REMOVE
*/
class RemoveBase
{
private:
bool& supportnokicks;
InspIRCd* ServerInstance;
protected:
RemoveBase(InspIRCd* Instance, bool& snk) : supportnokicks(snk), ServerInstance(Instance)
{
}
enum ModeLevel { PEON = 0, HALFOP = 1, OP = 2, ADMIN = 3, OWNER = 4, ULINE = 5 };
/* This little function just converts a chanmode character (U ~ & @ & +) into an integer (5 4 3 2 1 0) */
/* XXX - We should probably use the new mode prefix rank stuff
* for this instead now -- Brain */
ModeLevel chartolevel(const std::string &privs)
{
if(privs.empty())
{
return PEON;
}
switch (privs[0])
{
case 'U':
/* Ulined */
return ULINE;
case '~':
/* Owner */
return OWNER;
case '&':
/* Admin */
return ADMIN;
case '@':
/* Operator */
return OP;
case '%':
/* Halfop */
return HALFOP;
default:
/* Peon */
return PEON;
}
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user, bool neworder)
{
const char* channame;
const char* username;
userrec* target;
chanrec* channel;
ModeLevel tlevel;
ModeLevel ulevel;
std::string reason;
std::string protectkey;
std::string founderkey;
bool hasnokicks;
/* Set these to the parameters needed, the new version of this module switches it's parameters around
* supplying a new command with the new order while keeping the old /remove with the older order.
* /remove <nick> <channel> [reason ...]
* /fpart <channel> <nick> [reason ...]
*/
channame = parameters[ neworder ? 0 : 1];
username = parameters[ neworder ? 1 : 0];
/* Look up the user we're meant to be removing from the channel */
target = ServerInstance->FindNick(username);
/* And the channel we're meant to be removing them from */
channel = ServerInstance->FindChan(channame);
/* Fix by brain - someone needs to learn to validate their input! */
if (!target || !channel)
{
user->WriteServ("401 %s %s :No such nick/channel", user->nick, !target ? username : channame);
return CMD_FAILURE;
}
if (!channel->HasUser(target))
{
user->WriteServ( "NOTICE %s :*** The user %s is not on channel %s", user->nick, target->nick, channel->name);
return CMD_FAILURE;
}
/* This is adding support for the +q and +a channel modes, basically if they are enabled, and the remover has them set.
* Then we change the @|%|+ to & if they are +a, or ~ if they are +q */
protectkey = "cm_protect_" + std::string(channel->name);
founderkey = "cm_founder_" + std::string(channel->name);
if (ServerInstance->ULine(user->server) || ServerInstance->ULine(user->nick))
{
ulevel = chartolevel("U");
}
if (user->GetExt(founderkey))
{
ulevel = chartolevel("~");
}
else if (user->GetExt(protectkey))
{
ulevel = chartolevel("&");
}
else
{
ulevel = chartolevel(channel->GetPrefixChar(user));
}
/* Now it's the same idea, except for the target. If they're ulined make sure they get a higher level than the sender can */
if (ServerInstance->ULine(target->server) || ServerInstance->ULine(target->nick))
{
tlevel = chartolevel("U");
}
else if (target->GetExt(founderkey))
{
tlevel = chartolevel("~");
}
else if (target->GetExt(protectkey))
{
tlevel = chartolevel("&");
}
else
{
tlevel = chartolevel(channel->GetPrefixChar(target));
}
hasnokicks = (ServerInstance->FindModule("m_nokicks.so") && channel->IsModeSet('Q'));
/* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */
if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks || (ulevel == ULINE)))
{
/* We'll let everyone remove their level and below, eg:
* ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1)
* a ulined target will get a higher level than it's possible for a /remover to get..so they're safe.
* Nobody may remove a founder.
*/
if ((!IS_LOCAL(user)) || ((ulevel > PEON) && (ulevel >= tlevel) && (tlevel != OWNER)))
{
// no you can't just go from a std::ostringstream to a std::string, Om. -nenolod
// but you can do this, nenolod -brain
std::string reasonparam("No reason given");
/* If a reason is given, use it */
if(pcnt > 2)
{
/* Join params 2 ... pcnt - 1 (inclusive) into one */
irc::stringjoiner reason_join(" ", parameters, 2, pcnt - 1);
reasonparam = reason_join.GetJoined();
}
/* Build up the part reason string. */
reason = std::string("Removed by ") + user->nick + ": " + reasonparam;
channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name, user->nick, target->nick);
target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick, user->nick, channel->name, reasonparam.c_str());
if (!channel->PartUser(target, reason.c_str()))
delete channel;
}
else
{
user->WriteServ( "NOTICE %s :*** You do not have access to /remove %s from %s", user->nick, target->nick, channel->name);
return CMD_FAILURE;
}
}
else
{
/* m_nokicks.so was loaded and +Q was set, block! */
user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick, channel->name, target->nick);
return CMD_FAILURE;
}
/* route me */
return CMD_SUCCESS;
}
};
/** Handle /REMOVE
*/
class cmd_remove : public command_t, public RemoveBase
{
public:
cmd_remove(InspIRCd* Instance, bool& snk) : command_t(Instance, "REMOVE", 0, 2), RemoveBase(Instance, snk)
{
this->source = "m_remove.so";
syntax = "<nick> <channel> [<reason>]";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
return RemoveBase::Handle(parameters, pcnt, user, false);
}
};
/** Handle /FPART
*/
class cmd_fpart : public command_t, public RemoveBase
{
public:
cmd_fpart(InspIRCd* Instance, bool& snk) : command_t(Instance, "FPART", 0, 2), RemoveBase(Instance, snk)
{
this->source = "m_remove.so";
syntax = "<channel> <nick> [<reason>]";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
return RemoveBase::Handle(parameters, pcnt, user, true);
}
};
class ModuleRemove : public Module
{
cmd_remove* mycommand;
cmd_fpart* mycommand2;
bool supportnokicks;
public:
ModuleRemove(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_remove(ServerInstance, supportnokicks);
mycommand2 = new cmd_fpart(ServerInstance, supportnokicks);
ServerInstance->AddCommand(mycommand);
ServerInstance->AddCommand(mycommand2);
OnRehash(NULL,"");
}
void Implements(char* List)
{
List[I_On005Numeric] = List[I_OnRehash] = 1;
}
virtual void On005Numeric(std::string &output)
{
output.append(" REMOVE");
}
virtual void OnRehash(userrec* user, const std::string&)
{
ConfigReader conf(ServerInstance);
supportnokicks = conf.ReadFlag("remove", "supportnokicks", 0);
}
virtual ~ModuleRemove()
{
}
virtual Version GetVersion()
{
return Version(1,1,1,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleRemove)
\ No newline at end of file diff --git a/src/modules/m_restrictbanned.cpp b/src/modules/m_restrictbanned.cpp index 9315385a1..5535ca464 100644 --- a/src/modules/m_restrictbanned.cpp +++ b/src/modules/m_restrictbanned.cpp @@ -1,98 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Restricts banned users in a channel. May not speak, etc. */ - -class ModuleRestrictBanned : public Module -{ - private: - public: - ModuleRestrictBanned(InspIRCd* Me) : Module(Me) - { - } - - virtual ~ModuleRestrictBanned() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnLocalTopicChange] = List[I_OnUserPreNick] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1; - } - - int CheckRestricted(userrec *user, chanrec *channel, const std::string &action) - { - /* aren't local? we don't care. */ - if (!IS_LOCAL(user)) - return 0; - - if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user)) - { - /* banned, boned. drop the message. */ - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not " + action + ", as you are banned on channel " + channel->name); - return 1; - } - - return 0; - } - - virtual int OnUserPreNick(userrec *user, const std::string &newnick) - { - /* if they aren't local, we don't care */ - if (!IS_LOCAL(user)) - return 0; - - /* bit of a special case. */ - for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) - { - if (CheckRestricted(user, i->first, "change your nickname") == 1) - return 1; - } - - return 0; - } - - virtual int OnLocalTopicChange(userrec *user, chanrec *channel, const std::string &topic) - { - return CheckRestricted(user, channel, "change the topic"); - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreNotice(user,dest,target_type,text,status,exempt_list); - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if (target_type == TYPE_CHANNEL) - { - chanrec *channel = (chanrec *)dest; - - return CheckRestricted(user, channel, "message the channel"); - } - - return 0; - } -}; - -MODULE_INIT(ModuleRestrictBanned) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Restricts banned users in a channel. May not speak, etc. */
class ModuleRestrictBanned : public Module
{
private:
public:
ModuleRestrictBanned(InspIRCd* Me) : Module(Me)
{
}
virtual ~ModuleRestrictBanned()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnLocalTopicChange] = List[I_OnUserPreNick] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1;
}
int CheckRestricted(userrec *user, chanrec *channel, const std::string &action)
{
/* aren't local? we don't care. */
if (!IS_LOCAL(user))
return 0;
if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user))
{
/* banned, boned. drop the message. */
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not " + action + ", as you are banned on channel " + channel->name);
return 1;
}
return 0;
}
virtual int OnUserPreNick(userrec *user, const std::string &newnick)
{
/* if they aren't local, we don't care */
if (!IS_LOCAL(user))
return 0;
/* bit of a special case. */
for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
{
if (CheckRestricted(user, i->first, "change your nickname") == 1)
return 1;
}
return 0;
}
virtual int OnLocalTopicChange(userrec *user, chanrec *channel, const std::string &topic)
{
return CheckRestricted(user, channel, "change the topic");
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (target_type == TYPE_CHANNEL)
{
chanrec *channel = (chanrec *)dest;
return CheckRestricted(user, channel, "message the channel");
}
return 0;
}
};
MODULE_INIT(ModuleRestrictBanned)
\ No newline at end of file diff --git a/src/modules/m_restrictchans.cpp b/src/modules/m_restrictchans.cpp index 1f2416d44..1fc44f22b 100644 --- a/src/modules/m_restrictchans.cpp +++ b/src/modules/m_restrictchans.cpp @@ -1,85 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Only opers may create new channels if this module is loaded */ - -class ModuleRestrictChans : public Module -{ - - - std::map<irc::string,int> allowchans; - - void ReadConfig() - { - ConfigReader* MyConf = new ConfigReader(ServerInstance); - allowchans.clear(); - for (int i = 0; i < MyConf->Enumerate("allowchannel"); i++) - { - std::string txt; - txt = MyConf->ReadValue("allowchannel", "name", i); - irc::string channel = txt.c_str(); - allowchans[channel] = 1; - } - DELETE(MyConf); - } - - public: - ModuleRestrictChans(InspIRCd* Me) - : Module(Me) - { - - ReadConfig(); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ReadConfig(); - } - - void Implements(char* List) - { - List[I_OnUserPreJoin] = List[I_OnRehash] = 1; - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - irc::string x = cname; - // user is not an oper and its not in the allow list - if ((!IS_OPER(user)) && (allowchans.find(x) == allowchans.end())) - { - // channel does not yet exist (record is null, about to be created IF we were to allow it) - if (!chan) - { - user->WriteServ("530 %s %s :Only IRC operators may create new channels",user->nick,cname,cname); - return 1; - } - } - return 0; - } - - virtual ~ModuleRestrictChans() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleRestrictChans) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Only opers may create new channels if this module is loaded */
class ModuleRestrictChans : public Module
{
std::map<irc::string,int> allowchans;
void ReadConfig()
{
ConfigReader* MyConf = new ConfigReader(ServerInstance);
allowchans.clear();
for (int i = 0; i < MyConf->Enumerate("allowchannel"); i++)
{
std::string txt;
txt = MyConf->ReadValue("allowchannel", "name", i);
irc::string channel = txt.c_str();
allowchans[channel] = 1;
}
DELETE(MyConf);
}
public:
ModuleRestrictChans(InspIRCd* Me)
: Module(Me)
{
ReadConfig();
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ReadConfig();
}
void Implements(char* List)
{
List[I_OnUserPreJoin] = List[I_OnRehash] = 1;
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
irc::string x = cname;
// user is not an oper and its not in the allow list
if ((!IS_OPER(user)) && (allowchans.find(x) == allowchans.end()))
{
// channel does not yet exist (record is null, about to be created IF we were to allow it)
if (!chan)
{
user->WriteServ("530 %s %s :Only IRC operators may create new channels",user->nick,cname,cname);
return 1;
}
}
return 0;
}
virtual ~ModuleRestrictChans()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleRestrictChans)
\ No newline at end of file diff --git a/src/modules/m_restrictmsg.cpp b/src/modules/m_restrictmsg.cpp index 0e95660b2..c05e320fe 100644 --- a/src/modules/m_restrictmsg.cpp +++ b/src/modules/m_restrictmsg.cpp @@ -1,75 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Forbids users from messaging each other. Users may still message opers and opers may message other opers. */ - - -class ModuleRestrictMsg : public Module -{ - - public: - - ModuleRestrictMsg(InspIRCd* Me) - : Module(Me) - { - - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1; - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if ((target_type == TYPE_USER) && (IS_LOCAL(user))) - { - userrec* u = (userrec*)dest; - - // message allowed if: - // (1) the sender is opered - // (2) the recipient is opered - // anything else, blocked. - if (IS_OPER(u) || IS_OPER(user)) - { - return 0; - } - user->WriteServ("531 %s %s :You are not permitted to send private messages to this user",user->nick,u->nick); - return 1; - } - - // however, we must allow channel messages... - return 0; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return this->OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual ~ModuleRestrictMsg() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleRestrictMsg) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Forbids users from messaging each other. Users may still message opers and opers may message other opers. */
class ModuleRestrictMsg : public Module
{
public:
ModuleRestrictMsg(InspIRCd* Me)
: Module(Me)
{
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
{
userrec* u = (userrec*)dest;
// message allowed if:
// (1) the sender is opered
// (2) the recipient is opered
// anything else, blocked.
if (IS_OPER(u) || IS_OPER(user))
{
return 0;
}
user->WriteServ("531 %s %s :You are not permitted to send private messages to this user",user->nick,u->nick);
return 1;
}
// however, we must allow channel messages...
return 0;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return this->OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
}
virtual ~ModuleRestrictMsg()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleRestrictMsg)
\ No newline at end of file diff --git a/src/modules/m_safelist.cpp b/src/modules/m_safelist.cpp index 4adfc0011..abd782c86 100644 --- a/src/modules/m_safelist.cpp +++ b/src/modules/m_safelist.cpp @@ -1,268 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "wildcard.h" - -/** Holds a users m_safelist state - */ -class ListData : public classbase -{ - public: - long list_start; - long list_position; - bool list_ended; - const std::string glob; - int minusers; - int maxusers; - - ListData() : list_start(0), list_position(0), list_ended(false) {}; - ListData(long pos, time_t t, const std::string &pattern, int mi, int ma) : list_start(t), list_position(pos), list_ended(false), glob(pattern), minusers(mi), maxusers(ma) {}; -}; - -/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */ - -class ModuleSafeList : public Module -{ - time_t ThrottleSecs; - size_t ServerNameSize; - int global_listing; - int LimitList; - public: - ModuleSafeList(InspIRCd* Me) : Module(Me) - { - OnRehash(NULL, ""); - } - - virtual ~ModuleSafeList() - { - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader MyConf(ServerInstance); - ThrottleSecs = MyConf.ReadInteger("safelist", "throttle", "60", 0, true); - LimitList = MyConf.ReadInteger("safelist", "maxlisters", "50", 0, true); - ServerNameSize = strlen(ServerInstance->Config->ServerName) + 4; - global_listing = 0; - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - - void Implements(char* List) - { - List[I_OnBufferFlushed] = List[I_OnPreCommand] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnRehash] = 1; - } - - /* - * OnPreCommand() - * Intercept the LIST command. - */ - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - /* If the command doesnt appear to be valid, we dont want to mess with it. */ - if (!validated) - return 0; - - if (command == "LIST") - { - return this->HandleList(parameters, pcnt, user); - } - return 0; - } - - /* - * HandleList() - * Handle (override) the LIST command. - */ - int HandleList(const char** parameters, int pcnt, userrec* user) - { - int minusers = 0, maxusers = 0; - - if (global_listing >= LimitList) - { - user->WriteServ("NOTICE %s :*** Server load is currently too heavy. Please try again later.", user->nick); - user->WriteServ("321 %s Channel :Users Name",user->nick); - user->WriteServ("323 %s :End of channel list.",user->nick); - return 1; - } - - /* First, let's check if the user is currently /list'ing */ - ListData *ld; - user->GetExt("safelist_cache", ld); - - if (ld) - { - /* user is already /list'ing, we don't want to do shit. */ - return 1; - } - - /* Work around mIRC suckyness. YOU SUCK, KHALED! */ - if (pcnt == 1) - { - if (*parameters[0] == '<') - { - maxusers = atoi(parameters[0]+1); - ServerInstance->Log(DEBUG,"Max users: %d", maxusers); - pcnt = 0; - } - else if (*parameters[0] == '>') - { - minusers = atoi(parameters[0]+1); - ServerInstance->Log(DEBUG,"Min users: %d", minusers); - pcnt = 0; - } - } - - time_t* last_list_time; - user->GetExt("safelist_last", last_list_time); - if (last_list_time) - { - if (ServerInstance->Time() < (*last_list_time)+ThrottleSecs) - { - user->WriteServ("NOTICE %s :*** Woah there, slow down a little, you can't /LIST so often!",user->nick); - user->WriteServ("321 %s Channel :Users Name",user->nick); - user->WriteServ("323 %s :End of channel list.",user->nick); - return 1; - } - - DELETE(last_list_time); - user->Shrink("safelist_last"); - } - - - /* - * start at channel 0! ;) - */ - ld = new ListData(0,ServerInstance->Time(), pcnt ? parameters[0] : "*", minusers, maxusers); - user->Extend("safelist_cache", ld); - - time_t* llt = new time_t; - *llt = ServerInstance->Time(); - user->Extend("safelist_last", llt); - - user->WriteServ("321 %s Channel :Users Name",user->nick); - - global_listing++; - - return 1; - } - - virtual void OnBufferFlushed(userrec* user) - { - char buffer[MAXBUF]; - ListData* ld; - if (user->GetExt("safelist_cache", ld)) - { - chanrec* chan = NULL; - long amount_sent = 0; - do - { - chan = ServerInstance->GetChannelIndex(ld->list_position); - bool has_user = (chan && chan->HasUser(user)); - long users = chan ? chan->GetUserCounter() : 0; - - bool too_few = (ld->minusers && (users <= ld->minusers)); - bool too_many = (ld->maxusers && (users >= ld->maxusers)); - - if (chan && (too_many || too_few)) - { - ld->list_position++; - continue; - } - - if ((chan) && (chan->modes[CM_PRIVATE])) - { - bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str()))); - if ((users) && (display)) - { - int counter = snprintf(buffer, MAXBUF, "322 %s *", user->nick); - amount_sent += counter + ServerNameSize; - user->WriteServ(std::string(buffer)); - } - } - else if ((chan) && (((!(chan->modes[CM_PRIVATE])) && (!(chan->modes[CM_SECRET]))) || (has_user))) - { - bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str()))); - if ((users) && (display)) - { - int counter = snprintf(buffer, MAXBUF, "322 %s %s %ld :[+%s] %s",user->nick, chan->name, users, chan->ChanModes(has_user), chan->topic); - amount_sent += counter + ServerNameSize; - user->WriteServ(std::string(buffer)); - } - } - else - { - if (!chan) - { - if (!ld->list_ended) - { - ld->list_ended = true; - user->WriteServ("323 %s :End of channel list.",user->nick); - } - } - } - ld->list_position++; - } - while ((chan != NULL) && (amount_sent < (user->sendqmax / 4))); - if (ld->list_ended) - { - user->Shrink("safelist_cache"); - DELETE(ld); - global_listing--; - } - } - } - - virtual void OnCleanup(int target_type, void* item) - { - if(target_type == TYPE_USER) - { - userrec* u = (userrec*)item; - ListData* ld; - u->GetExt("safelist_cache", ld); - if (ld) - { - u->Shrink("safelist_cache"); - DELETE(ld); - global_listing--; - } - time_t* last_list_time; - u->GetExt("safelist_last", last_list_time); - if (last_list_time) - { - DELETE(last_list_time); - u->Shrink("safelist_last"); - } - } - } - - virtual void On005Numeric(std::string &output) - { - output.append(" SAFELIST"); - } - - virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message) - { - this->OnCleanup(TYPE_USER,user); - } - -}; - -MODULE_INIT(ModuleSafeList) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "wildcard.h"
/** Holds a users m_safelist state
*/
class ListData : public classbase
{
public:
long list_start;
long list_position;
bool list_ended;
const std::string glob;
int minusers;
int maxusers;
ListData() : list_start(0), list_position(0), list_ended(false) {};
ListData(long pos, time_t t, const std::string &pattern, int mi, int ma) : list_start(t), list_position(pos), list_ended(false), glob(pattern), minusers(mi), maxusers(ma) {};
};
/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */
class ModuleSafeList : public Module
{
time_t ThrottleSecs;
size_t ServerNameSize;
int global_listing;
int LimitList;
public:
ModuleSafeList(InspIRCd* Me) : Module(Me)
{
OnRehash(NULL, "");
}
virtual ~ModuleSafeList()
{
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader MyConf(ServerInstance);
ThrottleSecs = MyConf.ReadInteger("safelist", "throttle", "60", 0, true);
LimitList = MyConf.ReadInteger("safelist", "maxlisters", "50", 0, true);
ServerNameSize = strlen(ServerInstance->Config->ServerName) + 4;
global_listing = 0;
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
void Implements(char* List)
{
List[I_OnBufferFlushed] = List[I_OnPreCommand] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnRehash] = 1;
}
/*
* OnPreCommand()
* Intercept the LIST command.
*/
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
/* If the command doesnt appear to be valid, we dont want to mess with it. */
if (!validated)
return 0;
if (command == "LIST")
{
return this->HandleList(parameters, pcnt, user);
}
return 0;
}
/*
* HandleList()
* Handle (override) the LIST command.
*/
int HandleList(const char** parameters, int pcnt, userrec* user)
{
int minusers = 0, maxusers = 0;
if (global_listing >= LimitList)
{
user->WriteServ("NOTICE %s :*** Server load is currently too heavy. Please try again later.", user->nick);
user->WriteServ("321 %s Channel :Users Name",user->nick);
user->WriteServ("323 %s :End of channel list.",user->nick);
return 1;
}
/* First, let's check if the user is currently /list'ing */
ListData *ld;
user->GetExt("safelist_cache", ld);
if (ld)
{
/* user is already /list'ing, we don't want to do shit. */
return 1;
}
/* Work around mIRC suckyness. YOU SUCK, KHALED! */
if (pcnt == 1)
{
if (*parameters[0] == '<')
{
maxusers = atoi(parameters[0]+1);
ServerInstance->Log(DEBUG,"Max users: %d", maxusers);
pcnt = 0;
}
else if (*parameters[0] == '>')
{
minusers = atoi(parameters[0]+1);
ServerInstance->Log(DEBUG,"Min users: %d", minusers);
pcnt = 0;
}
}
time_t* last_list_time;
user->GetExt("safelist_last", last_list_time);
if (last_list_time)
{
if (ServerInstance->Time() < (*last_list_time)+ThrottleSecs)
{
user->WriteServ("NOTICE %s :*** Woah there, slow down a little, you can't /LIST so often!",user->nick);
user->WriteServ("321 %s Channel :Users Name",user->nick);
user->WriteServ("323 %s :End of channel list.",user->nick);
return 1;
}
DELETE(last_list_time);
user->Shrink("safelist_last");
}
/*
* start at channel 0! ;)
*/
ld = new ListData(0,ServerInstance->Time(), pcnt ? parameters[0] : "*", minusers, maxusers);
user->Extend("safelist_cache", ld);
time_t* llt = new time_t;
*llt = ServerInstance->Time();
user->Extend("safelist_last", llt);
user->WriteServ("321 %s Channel :Users Name",user->nick);
global_listing++;
return 1;
}
virtual void OnBufferFlushed(userrec* user)
{
char buffer[MAXBUF];
ListData* ld;
if (user->GetExt("safelist_cache", ld))
{
chanrec* chan = NULL;
long amount_sent = 0;
do
{
chan = ServerInstance->GetChannelIndex(ld->list_position);
bool has_user = (chan && chan->HasUser(user));
long users = chan ? chan->GetUserCounter() : 0;
bool too_few = (ld->minusers && (users <= ld->minusers));
bool too_many = (ld->maxusers && (users >= ld->maxusers));
if (chan && (too_many || too_few))
{
ld->list_position++;
continue;
}
if ((chan) && (chan->modes[CM_PRIVATE]))
{
bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str())));
if ((users) && (display))
{
int counter = snprintf(buffer, MAXBUF, "322 %s *", user->nick);
amount_sent += counter + ServerNameSize;
user->WriteServ(std::string(buffer));
}
}
else if ((chan) && (((!(chan->modes[CM_PRIVATE])) && (!(chan->modes[CM_SECRET]))) || (has_user)))
{
bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str())));
if ((users) && (display))
{
int counter = snprintf(buffer, MAXBUF, "322 %s %s %ld :[+%s] %s",user->nick, chan->name, users, chan->ChanModes(has_user), chan->topic);
amount_sent += counter + ServerNameSize;
user->WriteServ(std::string(buffer));
}
}
else
{
if (!chan)
{
if (!ld->list_ended)
{
ld->list_ended = true;
user->WriteServ("323 %s :End of channel list.",user->nick);
}
}
}
ld->list_position++;
}
while ((chan != NULL) && (amount_sent < (user->sendqmax / 4)));
if (ld->list_ended)
{
user->Shrink("safelist_cache");
DELETE(ld);
global_listing--;
}
}
}
virtual void OnCleanup(int target_type, void* item)
{
if(target_type == TYPE_USER)
{
userrec* u = (userrec*)item;
ListData* ld;
u->GetExt("safelist_cache", ld);
if (ld)
{
u->Shrink("safelist_cache");
DELETE(ld);
global_listing--;
}
time_t* last_list_time;
u->GetExt("safelist_last", last_list_time);
if (last_list_time)
{
DELETE(last_list_time);
u->Shrink("safelist_last");
}
}
}
virtual void On005Numeric(std::string &output)
{
output.append(" SAFELIST");
}
virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
{
this->OnCleanup(TYPE_USER,user);
}
};
MODULE_INIT(ModuleSafeList)
\ No newline at end of file diff --git a/src/modules/m_sajoin.cpp b/src/modules/m_sajoin.cpp index 0c9822fb9..2b143606f 100644 --- a/src/modules/m_sajoin.cpp +++ b/src/modules/m_sajoin.cpp @@ -1,114 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style SAJOIN command */ - -/** Handle /SAJOIN - */ -class cmd_sajoin : public command_t -{ - public: - cmd_sajoin (InspIRCd* Instance) : command_t(Instance,"SAJOIN", 'o', 2) - { - this->source = "m_sajoin.so"; - syntax = "<nick> <channel>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* dest = ServerInstance->FindNick(parameters[0]); - if (dest) - { - if (ServerInstance->ULine(dest->server)) - { - user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick); - return CMD_FAILURE; - } - if (!ServerInstance->IsChannel(parameters[1])) - { - /* we didn't need to check this for each character ;) */ - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Invalid characters in channel name"); - return CMD_FAILURE; - } - - /* For local users, we send the JoinUser which may create a channel and set its TS. - * For non-local users, we just return CMD_SUCCESS, knowing this will propogate it where it needs to be - * and then that server will generate the users JOIN or FJOIN instead. - */ - if (IS_LOCAL(dest)) - { - chanrec::JoinUser(ServerInstance, dest, parameters[1], true, "", ServerInstance->Time(true)); - /* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propogate */ - chanrec* n = ServerInstance->FindChan(parameters[1]); - if (n) - { - if (n->HasUser(dest)) - { - ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]); - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]+" (User is probably banned, or blocking modes)"); - return CMD_FAILURE; - } - } - else - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]); - return CMD_FAILURE; - } - } - else - { - ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]); - return CMD_SUCCESS; - } - } - else - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** No such nickname "+parameters[0]); - return CMD_FAILURE; - } - } -}; - -class ModuleSajoin : public Module -{ - cmd_sajoin* mycommand; - public: - ModuleSajoin(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_sajoin(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSajoin() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSajoin) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style SAJOIN command */
/** Handle /SAJOIN
*/
class cmd_sajoin : public command_t
{
public:
cmd_sajoin (InspIRCd* Instance) : command_t(Instance,"SAJOIN", 'o', 2)
{
this->source = "m_sajoin.so";
syntax = "<nick> <channel>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* dest = ServerInstance->FindNick(parameters[0]);
if (dest)
{
if (ServerInstance->ULine(dest->server))
{
user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
return CMD_FAILURE;
}
if (!ServerInstance->IsChannel(parameters[1]))
{
/* we didn't need to check this for each character ;) */
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Invalid characters in channel name");
return CMD_FAILURE;
}
/* For local users, we send the JoinUser which may create a channel and set its TS.
* For non-local users, we just return CMD_SUCCESS, knowing this will propogate it where it needs to be
* and then that server will generate the users JOIN or FJOIN instead.
*/
if (IS_LOCAL(dest))
{
chanrec::JoinUser(ServerInstance, dest, parameters[1], true, "", ServerInstance->Time(true));
/* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propogate */
chanrec* n = ServerInstance->FindChan(parameters[1]);
if (n)
{
if (n->HasUser(dest))
{
ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]);
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]+" (User is probably banned, or blocking modes)");
return CMD_FAILURE;
}
}
else
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]);
return CMD_FAILURE;
}
}
else
{
ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]);
return CMD_SUCCESS;
}
}
else
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** No such nickname "+parameters[0]);
return CMD_FAILURE;
}
}
};
class ModuleSajoin : public Module
{
cmd_sajoin* mycommand;
public:
ModuleSajoin(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_sajoin(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSajoin()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSajoin)
\ No newline at end of file diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp index 88d0d666e..f48e078b1 100644 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@ -1,98 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Provides more advanced UnrealIRCd SAMODE command */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/** Handle /SAMODE - */ -class cmd_samode : public command_t -{ - public: - cmd_samode (InspIRCd* Instance) : command_t(Instance,"SAMODE", 'o', 2) - { - this->source = "m_samode.so"; - syntax = "<target> <modes> {<mode-parameters>}"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - /* - * Handles an SAMODE request. Notifies all +s users. - */ - - userrec* n = new userrec(ServerInstance); - n->SetFd(FD_MAGIC_NUMBER); - ServerInstance->SendMode(parameters,pcnt,n); - delete n; - - if (ServerInstance->Modes->GetLastParse().length()) - { - ServerInstance->WriteOpers("*** " + std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse()); - - std::deque<std::string> n; - irc::spacesepstream spaced(ServerInstance->Modes->GetLastParse()); - std::string one = "*"; - while ((one = spaced.GetToken()) != "") - n.push_back(one); - - Event rmode((char *)&n, NULL, "send_mode"); - rmode.Send(ServerInstance); - - n.clear(); - n.push_back(std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse()); - Event rmode2((char *)&n, NULL, "send_opers"); - rmode2.Send(ServerInstance); - - /* XXX: Yes, this is right. We dont want to propogate the - * actual SAMODE command, just the MODE command generated - * by the send_mode - */ - return CMD_LOCALONLY; - } - else - { - user->WriteServ("NOTICE %s :*** Invalid SAMODE sequence.", user->nick); - } - - return CMD_FAILURE; - } -}; - -class ModuleSaMode : public Module -{ - cmd_samode* mycommand; - public: - ModuleSaMode(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_samode(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSaMode() - { - } - - virtual Version GetVersion() - { - return Version(1,1,2,2,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleSaMode) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Provides more advanced UnrealIRCd SAMODE command */
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/** Handle /SAMODE
*/
class cmd_samode : public command_t
{
public:
cmd_samode (InspIRCd* Instance) : command_t(Instance,"SAMODE", 'o', 2)
{
this->source = "m_samode.so";
syntax = "<target> <modes> {<mode-parameters>}";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
/*
* Handles an SAMODE request. Notifies all +s users.
*/
userrec* n = new userrec(ServerInstance);
n->SetFd(FD_MAGIC_NUMBER);
ServerInstance->SendMode(parameters,pcnt,n);
delete n;
if (ServerInstance->Modes->GetLastParse().length())
{
ServerInstance->WriteOpers("*** " + std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse());
std::deque<std::string> n;
irc::spacesepstream spaced(ServerInstance->Modes->GetLastParse());
std::string one = "*";
while ((one = spaced.GetToken()) != "")
n.push_back(one);
Event rmode((char *)&n, NULL, "send_mode");
rmode.Send(ServerInstance);
n.clear();
n.push_back(std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse());
Event rmode2((char *)&n, NULL, "send_opers");
rmode2.Send(ServerInstance);
/* XXX: Yes, this is right. We dont want to propogate the
* actual SAMODE command, just the MODE command generated
* by the send_mode
*/
return CMD_LOCALONLY;
}
else
{
user->WriteServ("NOTICE %s :*** Invalid SAMODE sequence.", user->nick);
}
return CMD_FAILURE;
}
};
class ModuleSaMode : public Module
{
cmd_samode* mycommand;
public:
ModuleSaMode(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_samode(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSaMode()
{
}
virtual Version GetVersion()
{
return Version(1,1,2,2,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSaMode)
\ No newline at end of file diff --git a/src/modules/m_sanick.cpp b/src/modules/m_sanick.cpp index 715d978c3..8810550ae 100644 --- a/src/modules/m_sanick.cpp +++ b/src/modules/m_sanick.cpp @@ -1,97 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for SANICK command */ - -/** Handle /SANICK - */ -class cmd_sanick : public command_t -{ - public: - cmd_sanick (InspIRCd* Instance) : command_t(Instance,"SANICK", 'o', 2) - { - this->source = "m_sanick.so"; - syntax = "<nick> <new-nick>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* source = ServerInstance->FindNick(parameters[0]); - if (source) - { - if (ServerInstance->ULine(source->server)) - { - user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick); - return CMD_FAILURE; - } - std::string oldnick = user->nick; - if (ServerInstance->IsNick(parameters[1])) - { - if (source->ForceNickChange(parameters[1])) - { - ServerInstance->WriteOpers("*** " + oldnick+" used SANICK to change "+std::string(parameters[0])+" to "+parameters[1]); - return CMD_SUCCESS; - } - else - { - /* We couldnt change the nick */ - ServerInstance->WriteOpers("*** " + oldnick+" failed SANICK (from "+std::string(parameters[0])+" to "+parameters[1]+")"); - return CMD_FAILURE; - } - } - else - { - user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[1]); - } - - return CMD_FAILURE; - } - else - { - user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick, parameters[0]); - } - - return CMD_FAILURE; - } -}; - - -class ModuleSanick : public Module -{ - cmd_sanick* mycommand; - public: - ModuleSanick(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_sanick(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSanick() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSanick) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for SANICK command */
/** Handle /SANICK
*/
class cmd_sanick : public command_t
{
public:
cmd_sanick (InspIRCd* Instance) : command_t(Instance,"SANICK", 'o', 2)
{
this->source = "m_sanick.so";
syntax = "<nick> <new-nick>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* source = ServerInstance->FindNick(parameters[0]);
if (source)
{
if (ServerInstance->ULine(source->server))
{
user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
return CMD_FAILURE;
}
std::string oldnick = user->nick;
if (ServerInstance->IsNick(parameters[1]))
{
if (source->ForceNickChange(parameters[1]))
{
ServerInstance->WriteOpers("*** " + oldnick+" used SANICK to change "+std::string(parameters[0])+" to "+parameters[1]);
return CMD_SUCCESS;
}
else
{
/* We couldnt change the nick */
ServerInstance->WriteOpers("*** " + oldnick+" failed SANICK (from "+std::string(parameters[0])+" to "+parameters[1]+")");
return CMD_FAILURE;
}
}
else
{
user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[1]);
}
return CMD_FAILURE;
}
else
{
user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick, parameters[0]);
}
return CMD_FAILURE;
}
};
class ModuleSanick : public Module
{
cmd_sanick* mycommand;
public:
ModuleSanick(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_sanick(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSanick()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSanick)
\ No newline at end of file diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp index 829607e58..4d663e822 100644 --- a/src/modules/m_sapart.cpp +++ b/src/modules/m_sapart.cpp @@ -1,113 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style SAPART command */ - -/** Handle /SAPART - */ -class cmd_sapart : public command_t -{ - public: - cmd_sapart (InspIRCd* Instance) : command_t(Instance,"SAPART", 'o', 2) - { - this->source = "m_sapart.so"; - syntax = "<nick> <channel>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* dest = ServerInstance->FindNick(parameters[0]); - chanrec* channel = ServerInstance->FindChan(parameters[1]); - if (dest && channel) - { - if (ServerInstance->ULine(dest->server)) - { - user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick); - return CMD_FAILURE; - } - - /* For local clients, directly part them generating a PART message. For remote clients, - * just return CMD_SUCCESS knowing the protocol module will route the SAPART to the users - * local server and that will generate the PART instead - */ - if (IS_LOCAL(dest)) - { - if (!channel->PartUser(dest, dest->nick)) - delete channel; - chanrec* n = ServerInstance->FindChan(parameters[1]); - if (!n) - { - ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]); - return CMD_SUCCESS; - } - else - { - if (!n->HasUser(dest)) - { - ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]); - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE %s :*** Unable to make %s part %s",user->nick, dest->nick, parameters[1]); - return CMD_FAILURE; - } - } - } - else - { - ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAPART to make "+dest->nick+" part "+parameters[1]); - } - - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick); - } - - return CMD_FAILURE; - } -}; - - -class ModuleSapart : public Module -{ - cmd_sapart* mycommand; - public: - ModuleSapart(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_sapart(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSapart() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSapart) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style SAPART command */
/** Handle /SAPART
*/
class cmd_sapart : public command_t
{
public:
cmd_sapart (InspIRCd* Instance) : command_t(Instance,"SAPART", 'o', 2)
{
this->source = "m_sapart.so";
syntax = "<nick> <channel>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* dest = ServerInstance->FindNick(parameters[0]);
chanrec* channel = ServerInstance->FindChan(parameters[1]);
if (dest && channel)
{
if (ServerInstance->ULine(dest->server))
{
user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
return CMD_FAILURE;
}
/* For local clients, directly part them generating a PART message. For remote clients,
* just return CMD_SUCCESS knowing the protocol module will route the SAPART to the users
* local server and that will generate the PART instead
*/
if (IS_LOCAL(dest))
{
if (!channel->PartUser(dest, dest->nick))
delete channel;
chanrec* n = ServerInstance->FindChan(parameters[1]);
if (!n)
{
ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]);
return CMD_SUCCESS;
}
else
{
if (!n->HasUser(dest))
{
ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]);
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE %s :*** Unable to make %s part %s",user->nick, dest->nick, parameters[1]);
return CMD_FAILURE;
}
}
}
else
{
ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAPART to make "+dest->nick+" part "+parameters[1]);
}
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick);
}
return CMD_FAILURE;
}
};
class ModuleSapart : public Module
{
cmd_sapart* mycommand;
public:
ModuleSapart(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_sapart(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSapart()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSapart)
\ No newline at end of file diff --git a/src/modules/m_saquit.cpp b/src/modules/m_saquit.cpp index d2fa8e89b..36d511af9 100644 --- a/src/modules/m_saquit.cpp +++ b/src/modules/m_saquit.cpp @@ -1,82 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for an SAQUIT command, exits user with a reason */ - -/** Handle /SAQUIT - */ -class cmd_saquit : public command_t -{ - public: - cmd_saquit (InspIRCd* Instance) : command_t(Instance,"SAQUIT",'o',2) - { - this->source = "m_saquit.so"; - syntax = "<nick> <reason>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* dest = ServerInstance->FindNick(parameters[0]); - if (dest) - { - if (ServerInstance->ULine(dest->server)) - { - user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick); - return CMD_FAILURE; - } - irc::stringjoiner reason_join(" ", parameters, 1, pcnt - 1); - std::string line = reason_join.GetJoined(); - - ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAQUIT to make "+std::string(dest->nick)+" quit with a reason of "+line); - userrec::QuitUser(ServerInstance, dest, line); - - return CMD_SUCCESS; - } - else - { - user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[0]); - } - - return CMD_FAILURE; - } -}; - -class ModuleSaquit : public Module -{ - cmd_saquit* mycommand; - public: - ModuleSaquit(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_saquit(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSaquit() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSaquit) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for an SAQUIT command, exits user with a reason */
/** Handle /SAQUIT
*/
class cmd_saquit : public command_t
{
public:
cmd_saquit (InspIRCd* Instance) : command_t(Instance,"SAQUIT",'o',2)
{
this->source = "m_saquit.so";
syntax = "<nick> <reason>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* dest = ServerInstance->FindNick(parameters[0]);
if (dest)
{
if (ServerInstance->ULine(dest->server))
{
user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
return CMD_FAILURE;
}
irc::stringjoiner reason_join(" ", parameters, 1, pcnt - 1);
std::string line = reason_join.GetJoined();
ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAQUIT to make "+std::string(dest->nick)+" quit with a reason of "+line);
userrec::QuitUser(ServerInstance, dest, line);
return CMD_SUCCESS;
}
else
{
user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[0]);
}
return CMD_FAILURE;
}
};
class ModuleSaquit : public Module
{
cmd_saquit* mycommand;
public:
ModuleSaquit(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_saquit(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSaquit()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSaquit)
\ No newline at end of file diff --git a/src/modules/m_securelist.cpp b/src/modules/m_securelist.cpp index 8761716c0..264090311 100644 --- a/src/modules/m_securelist.cpp +++ b/src/modules/m_securelist.cpp @@ -1,97 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */ - -class ModuleSecureList : public Module -{ - private: - std::vector<std::string> allowlist; - time_t WaitTime; - public: - ModuleSecureList(InspIRCd* Me) : Module(Me) - { - OnRehash(NULL,""); - } - - virtual ~ModuleSecureList() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - - void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader* MyConf = new ConfigReader(ServerInstance); - allowlist.clear(); - for (int i = 0; i < MyConf->Enumerate("securehost"); i++) - allowlist.push_back(MyConf->ReadValue("securehost", "exception", i)); - WaitTime = MyConf->ReadInteger("securelist", "waittime", "60", 0, true); - DELETE(MyConf); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnPreCommand] = List[I_On005Numeric] = 1; - } - - /* - * OnPreCommand() - * Intercept the LIST command. - */ - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - /* If the command doesnt appear to be valid, we dont want to mess with it. */ - if (!validated) - return 0; - - if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!IS_OPER(user))) - { - /* Normally wouldnt be allowed here, are they exempt? */ - for (std::vector<std::string>::iterator x = allowlist.begin(); x != allowlist.end(); x++) - if (ServerInstance->MatchText(user->MakeHost(), *x)) - return 0; - - /* Not exempt, BOOK EM DANNO! */ - user->WriteServ("NOTICE %s :*** You cannot list within the first %d seconds of connecting. Please try again later.",user->nick, WaitTime); - /* Some crap clients (read: mIRC, various java chat applets) muck up if they don't - * receive these numerics whenever they send LIST, so give them an empty LIST to mull over. - */ - user->WriteServ("321 %s Channel :Users Name",user->nick); - user->WriteServ("323 %s :End of channel list.",user->nick); - return 1; - } - return 0; - } - - virtual void On005Numeric(std::string &output) - { - output.append(" SECURELIST"); - } - - virtual Priority Prioritize() - { - return (Priority)ServerInstance->PriorityBefore("m_safelist.so"); - } - -}; - -MODULE_INIT(ModuleSecureList) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */
class ModuleSecureList : public Module
{
private:
std::vector<std::string> allowlist;
time_t WaitTime;
public:
ModuleSecureList(InspIRCd* Me) : Module(Me)
{
OnRehash(NULL,"");
}
virtual ~ModuleSecureList()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader* MyConf = new ConfigReader(ServerInstance);
allowlist.clear();
for (int i = 0; i < MyConf->Enumerate("securehost"); i++)
allowlist.push_back(MyConf->ReadValue("securehost", "exception", i));
WaitTime = MyConf->ReadInteger("securelist", "waittime", "60", 0, true);
DELETE(MyConf);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnPreCommand] = List[I_On005Numeric] = 1;
}
/*
* OnPreCommand()
* Intercept the LIST command.
*/
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
/* If the command doesnt appear to be valid, we dont want to mess with it. */
if (!validated)
return 0;
if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!IS_OPER(user)))
{
/* Normally wouldnt be allowed here, are they exempt? */
for (std::vector<std::string>::iterator x = allowlist.begin(); x != allowlist.end(); x++)
if (ServerInstance->MatchText(user->MakeHost(), *x))
return 0;
/* Not exempt, BOOK EM DANNO! */
user->WriteServ("NOTICE %s :*** You cannot list within the first %d seconds of connecting. Please try again later.",user->nick, WaitTime);
/* Some crap clients (read: mIRC, various java chat applets) muck up if they don't
* receive these numerics whenever they send LIST, so give them an empty LIST to mull over.
*/
user->WriteServ("321 %s Channel :Users Name",user->nick);
user->WriteServ("323 %s :End of channel list.",user->nick);
return 1;
}
return 0;
}
virtual void On005Numeric(std::string &output)
{
output.append(" SECURELIST");
}
virtual Priority Prioritize()
{
return (Priority)ServerInstance->PriorityBefore("m_safelist.so");
}
};
MODULE_INIT(ModuleSecureList)
\ No newline at end of file diff --git a/src/modules/m_seenicks.cpp b/src/modules/m_seenicks.cpp index 215cd34b0..2e7755810 100644 --- a/src/modules/m_seenicks.cpp +++ b/src/modules/m_seenicks.cpp @@ -1,55 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" -#include "configreader.h" - -/* $ModDesc: Provides support for seeing local and remote nickchanges via snomasks */ - -class ModuleSeeNicks : public Module -{ - public: - ModuleSeeNicks(InspIRCd* Me) - : Module(Me) - { - ServerInstance->SNO->EnableSnomask('n',"NICK"); - ServerInstance->SNO->EnableSnomask('N',"REMOTENICK"); - } - - virtual ~ModuleSeeNicks() - { - ServerInstance->SNO->DisableSnomask('n'); - ServerInstance->SNO->DisableSnomask('N'); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUserPostNick] = 1; - } - - virtual void OnUserPostNick(userrec* user, const std::string &oldnick) - { - ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'n' : 'N',"User %s changed their nickname to %s", oldnick.c_str(), user->nick); - } -}; - -MODULE_INIT(ModuleSeeNicks) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
#include "configreader.h"
/* $ModDesc: Provides support for seeing local and remote nickchanges via snomasks */
class ModuleSeeNicks : public Module
{
public:
ModuleSeeNicks(InspIRCd* Me)
: Module(Me)
{
ServerInstance->SNO->EnableSnomask('n',"NICK");
ServerInstance->SNO->EnableSnomask('N',"REMOTENICK");
}
virtual ~ModuleSeeNicks()
{
ServerInstance->SNO->DisableSnomask('n');
ServerInstance->SNO->DisableSnomask('N');
}
virtual Version GetVersion()
{
return Version(1,1,0,1, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnUserPostNick] = 1;
}
virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
{
ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'n' : 'N',"User %s changed their nickname to %s", oldnick.c_str(), user->nick);
}
};
MODULE_INIT(ModuleSeeNicks)
\ No newline at end of file diff --git a/src/modules/m_services.cpp b/src/modules/m_services.cpp index 22b5dfcb5..d429b2860 100644 --- a/src/modules/m_services.cpp +++ b/src/modules/m_services.cpp @@ -1,310 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -static bool kludgeme = false; - -/* $ModDesc: Povides support for services +r user/chan modes and more */ - -/** Channel mode +r - mark a channel as identified - */ -class Channel_r : public ModeHandler -{ - - public: - Channel_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - // only a u-lined server may add or remove the +r mode. - if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.')))) - { - channel->SetMode('r',adding); - return MODEACTION_ALLOW; - } - else - { - source->WriteServ("500 %s :Only a server may modify the +r channel mode", source->nick); - return MODEACTION_DENY; - } - } -}; - -/** User mode +r - mark a user as identified - */ -class User_r : public ModeHandler -{ - - public: - User_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if ((kludgeme) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.')))) - { - if ((adding && !dest->IsModeSet('r')) || (!adding && dest->IsModeSet('r'))) - { - dest->SetMode('r',adding); - return MODEACTION_ALLOW; - } - return MODEACTION_DENY; - } - else - { - source->WriteServ("500 %s :Only a server may modify the +r user mode", source->nick); - return MODEACTION_DENY; - } - } -}; - -/** Channel mode +R - registered users only - */ -class Channel_R : public ModeHandler -{ - public: - Channel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('R')) - { - channel->SetMode('R',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('R')) - { - channel->SetMode('R',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** User mode +R - only allow PRIVMSG and NOTICE from registered users - */ -class User_R : public ModeHandler -{ - public: - User_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('R')) - { - dest->SetMode('R',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('R')) - { - dest->SetMode('R',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** Channel mode +M - only allow privmsg and notice to channel from registered users - */ -class Channel_M : public ModeHandler -{ - public: - Channel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('M')) - { - channel->SetMode('M',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('M')) - { - channel->SetMode('M',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** Dreamnforge-like services support - */ -class ModuleServices : public Module -{ - - Channel_r* m1; - Channel_R* m2; - Channel_M* m3; - User_r* m4; - User_R* m5; - public: - ModuleServices(InspIRCd* Me) - : Module(Me) - { - - m1 = new Channel_r(ServerInstance); - m2 = new Channel_R(ServerInstance); - m3 = new Channel_M(ServerInstance); - m4 = new User_r(ServerInstance); - m5 = new User_R(ServerInstance); - - if (!ServerInstance->AddMode(m1, 'r') || !ServerInstance->AddMode(m2, 'R') || !ServerInstance->AddMode(m3, 'M') - || !ServerInstance->AddMode(m4, 'r') || !ServerInstance->AddMode(m5, 'R')) - { - throw ModuleException("Could not add user and channel modes!"); - } - - kludgeme = false; - } - - /* <- :stitch.chatspike.net 307 w00t w00t :is a registered nick */ - virtual void OnWhois(userrec* source, userrec* dest) - { - if (dest->IsModeSet('r')) - { - /* user is registered */ - ServerInstance->SendWhoisLine(source, dest, 307, "%s %s :is a registered nick", source->nick, dest->nick); - } - } - - void Implements(char* List) - { - List[I_OnWhois] = List[I_OnUserPostNick] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1; - } - - virtual void OnUserPostNick(userrec* user, const std::string &oldnick) - { - /* On nickchange, if they have +r, remove it */ - if (user->IsModeSet('r')) - { - const char* modechange[2]; - modechange[0] = user->nick; - modechange[1] = "-r"; - kludgeme = true; - ServerInstance->SendMode(modechange,2,user); - kludgeme = false; - } - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if (!IS_LOCAL(user)) - return 0; - - if (target_type == TYPE_CHANNEL) - { - chanrec* c = (chanrec*)dest; - if ((c->IsModeSet('M')) && (!user->IsModeSet('r'))) - { - if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server))) - { - // user is ulined, can speak regardless - return 0; - } - // user messaging a +M channel and is not registered - user->WriteServ("477 %s %s :You need a registered nickname to speak on this channel", user->nick, c->name); - return 1; - } - } - if (target_type == TYPE_USER) - { - userrec* u = (userrec*)dest; - if ((u->IsModeSet('R')) && (!user->IsModeSet('r'))) - { - if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server))) - { - // user is ulined, can speak regardless - return 0; - } - // user messaging a +R user and is not registered - user->WriteServ("477 %s %s :You need a registered nickname to message this user", user->nick, u->nick); - return 1; - } - } - return 0; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status, exempt_list); - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if (chan) - { - if (chan->IsModeSet('R')) - { - if (!user->IsModeSet('r')) - { - if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server))) - { - // user is ulined, won't be stopped from joining - return 0; - } - // joining a +R channel and not identified - user->WriteServ("477 %s %s :You need a registered nickname to join this channel", user->nick, chan->name); - return 1; - } - } - } - return 0; - } - - virtual ~ModuleServices() - { - kludgeme = true; - ServerInstance->Modes->DelMode(m1); - ServerInstance->Modes->DelMode(m2); - ServerInstance->Modes->DelMode(m3); - ServerInstance->Modes->DelMode(m4); - ServerInstance->Modes->DelMode(m5); - DELETE(m1); - DELETE(m2); - DELETE(m3); - DELETE(m4); - DELETE(m5); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - - -MODULE_INIT(ModuleServices) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
static bool kludgeme = false;
/* $ModDesc: Povides support for services +r user/chan modes and more */
/** Channel mode +r - mark a channel as identified
*/
class Channel_r : public ModeHandler
{
public:
Channel_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
// only a u-lined server may add or remove the +r mode.
if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.'))))
{
channel->SetMode('r',adding);
return MODEACTION_ALLOW;
}
else
{
source->WriteServ("500 %s :Only a server may modify the +r channel mode", source->nick);
return MODEACTION_DENY;
}
}
};
/** User mode +r - mark a user as identified
*/
class User_r : public ModeHandler
{
public:
User_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if ((kludgeme) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.'))))
{
if ((adding && !dest->IsModeSet('r')) || (!adding && dest->IsModeSet('r')))
{
dest->SetMode('r',adding);
return MODEACTION_ALLOW;
}
return MODEACTION_DENY;
}
else
{
source->WriteServ("500 %s :Only a server may modify the +r user mode", source->nick);
return MODEACTION_DENY;
}
}
};
/** Channel mode +R - registered users only
*/
class Channel_R : public ModeHandler
{
public:
Channel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('R'))
{
channel->SetMode('R',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('R'))
{
channel->SetMode('R',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** User mode +R - only allow PRIVMSG and NOTICE from registered users
*/
class User_R : public ModeHandler
{
public:
User_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!dest->IsModeSet('R'))
{
dest->SetMode('R',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('R'))
{
dest->SetMode('R',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** Channel mode +M - only allow privmsg and notice to channel from registered users
*/
class Channel_M : public ModeHandler
{
public:
Channel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('M'))
{
channel->SetMode('M',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('M'))
{
channel->SetMode('M',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** Dreamnforge-like services support
*/
class ModuleServices : public Module
{
Channel_r* m1;
Channel_R* m2;
Channel_M* m3;
User_r* m4;
User_R* m5;
public:
ModuleServices(InspIRCd* Me)
: Module(Me)
{
m1 = new Channel_r(ServerInstance);
m2 = new Channel_R(ServerInstance);
m3 = new Channel_M(ServerInstance);
m4 = new User_r(ServerInstance);
m5 = new User_R(ServerInstance);
if (!ServerInstance->AddMode(m1, 'r') || !ServerInstance->AddMode(m2, 'R') || !ServerInstance->AddMode(m3, 'M')
|| !ServerInstance->AddMode(m4, 'r') || !ServerInstance->AddMode(m5, 'R'))
{
throw ModuleException("Could not add user and channel modes!");
}
kludgeme = false;
}
/* <- :stitch.chatspike.net 307 w00t w00t :is a registered nick */
virtual void OnWhois(userrec* source, userrec* dest)
{
if (dest->IsModeSet('r'))
{
/* user is registered */
ServerInstance->SendWhoisLine(source, dest, 307, "%s %s :is a registered nick", source->nick, dest->nick);
}
}
void Implements(char* List)
{
List[I_OnWhois] = List[I_OnUserPostNick] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1;
}
virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
{
/* On nickchange, if they have +r, remove it */
if (user->IsModeSet('r'))
{
const char* modechange[2];
modechange[0] = user->nick;
modechange[1] = "-r";
kludgeme = true;
ServerInstance->SendMode(modechange,2,user);
kludgeme = false;
}
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (!IS_LOCAL(user))
return 0;
if (target_type == TYPE_CHANNEL)
{
chanrec* c = (chanrec*)dest;
if ((c->IsModeSet('M')) && (!user->IsModeSet('r')))
{
if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
{
// user is ulined, can speak regardless
return 0;
}
// user messaging a +M channel and is not registered
user->WriteServ("477 %s %s :You need a registered nickname to speak on this channel", user->nick, c->name);
return 1;
}
}
if (target_type == TYPE_USER)
{
userrec* u = (userrec*)dest;
if ((u->IsModeSet('R')) && (!user->IsModeSet('r')))
{
if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
{
// user is ulined, can speak regardless
return 0;
}
// user messaging a +R user and is not registered
user->WriteServ("477 %s %s :You need a registered nickname to message this user", user->nick, u->nick);
return 1;
}
}
return 0;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreMessage(user,dest,target_type,text,status, exempt_list);
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if (chan)
{
if (chan->IsModeSet('R'))
{
if (!user->IsModeSet('r'))
{
if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
{
// user is ulined, won't be stopped from joining
return 0;
}
// joining a +R channel and not identified
user->WriteServ("477 %s %s :You need a registered nickname to join this channel", user->nick, chan->name);
return 1;
}
}
}
return 0;
}
virtual ~ModuleServices()
{
kludgeme = true;
ServerInstance->Modes->DelMode(m1);
ServerInstance->Modes->DelMode(m2);
ServerInstance->Modes->DelMode(m3);
ServerInstance->Modes->DelMode(m4);
ServerInstance->Modes->DelMode(m5);
DELETE(m1);
DELETE(m2);
DELETE(m3);
DELETE(m4);
DELETE(m5);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleServices)
\ No newline at end of file diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp index cff0d7698..3d32e3156 100644 --- a/src/modules/m_services_account.cpp +++ b/src/modules/m_services_account.cpp @@ -1,332 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" - -/* $ModDesc: Povides support for ircu-style services accounts, including chmode +R, etc. */ - -/** Channel mode +R - unidentified users cannot join - */ -class AChannel_R : public ModeHandler -{ - public: - AChannel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('R')) - { - channel->SetMode('R',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('R')) - { - channel->SetMode('R',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** User mode +R - unidentified users cannot message - */ -class AUser_R : public ModeHandler -{ - public: - AUser_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('R')) - { - dest->SetMode('R',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('R')) - { - dest->SetMode('R',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** Channel mode +M - unidentified users cannot message channel - */ -class AChannel_M : public ModeHandler -{ - public: - AChannel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('M')) - { - channel->SetMode('M',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('M')) - { - channel->SetMode('M',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleServicesAccount : public Module -{ - - AChannel_R* m1; - AChannel_M* m2; - AUser_R* m3; - public: - ModuleServicesAccount(InspIRCd* Me) : Module(Me) - { - - m1 = new AChannel_R(ServerInstance); - m2 = new AChannel_M(ServerInstance); - m3 = new AUser_R(ServerInstance); - if (!ServerInstance->AddMode(m1, 'R') || !ServerInstance->AddMode(m2, 'M') || !ServerInstance->AddMode(m3, 'R')) - throw ModuleException("Could not add new modes!"); - } - - /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */ - virtual void OnWhois(userrec* source, userrec* dest) - { - std::string *account; - dest->GetExt("accountname", account); - - if (account) - { - ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick, dest->nick, account->c_str()); - } - } - - void Implements(char* List) - { - List[I_OnWhois] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1; - List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnDecodeMetaData] = 1; - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - std::string *account; - - if (!IS_LOCAL(user)) - return 0; - - user->GetExt("accountname", account); - - if (target_type == TYPE_CHANNEL) - { - chanrec* c = (chanrec*)dest; - - if ((c->IsModeSet('M')) && (!account)) - { - if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server))) - { - // user is ulined, can speak regardless - return 0; - } - - // user messaging a +M channel and is not registered - user->WriteServ("477 "+std::string(user->nick)+" "+std::string(c->name)+" :You need to be identified to a registered account to message this channel"); - return 1; - } - } - if (target_type == TYPE_USER) - { - userrec* u = (userrec*)dest; - - if ((u->modes['R'-65]) && (!account)) - { - if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server))) - { - // user is ulined, can speak regardless - return 0; - } - - // user messaging a +R user and is not registered - user->WriteServ("477 "+std::string(user->nick)+" "+std::string(u->nick)+" :You need to be identified to a registered account to message this user"); - return 1; - } - } - return 0; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user, dest, target_type, text, status, exempt_list); - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - std::string *account; - user->GetExt("accountname", account); - - if (chan) - { - if (chan->IsModeSet('R')) - { - if (!account) - { - if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server))) - { - // user is ulined, won't be stopped from joining - return 0; - } - // joining a +R channel and not identified - user->WriteServ("477 "+std::string(user->nick)+" "+std::string(chan->name)+" :You need to be identified to a registered account to join this channel"); - return 1; - } - } - } - return 0; - } - - // Whenever the linking module wants to send out data, but doesnt know what the data - // represents (e.g. it is metadata, added to a userrec or chanrec by a module) then - // this method is called. We should use the ProtoSendMetaData function after we've - // corrected decided how the data should look, to send the metadata on its way if - // it is ours. - virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable) - { - // check if the linking module wants to know about OUR metadata - if (extname == "accountname") - { - // check if this user has an swhois field to send - std::string* account; - user->GetExt("accountname", account); - if (account) - { - // remove any accidental leading/trailing spaces - trim(*account); - - // call this function in the linking module, let it format the data how it - // sees fit, and send it on its way. We dont need or want to know how. - proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*account); - } - } - } - - // when a user quits, tidy up their metadata - virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message) - { - std::string* account; - user->GetExt("accountname", account); - if (account) - { - user->Shrink("accountname"); - delete account; - } - } - - // if the module is unloaded, tidy up all our dangling metadata - virtual void OnCleanup(int target_type, void* item) - { - if (target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - std::string* account; - user->GetExt("accountname", account); - if (account) - { - user->Shrink("accountname"); - delete account; - } - } - } - - // Whenever the linking module receives metadata from another server and doesnt know what - // to do with it (of course, hence the 'meta') it calls this method, and it is up to each - // module in turn to figure out if this metadata key belongs to them, and what they want - // to do with it. - // In our case we're only sending a single string around, so we just construct a std::string. - // Some modules will probably get much more complex and format more detailed structs and classes - // in a textual way for sending over the link. - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - // check if its our metadata key, and its associated with a user - if ((target_type == TYPE_USER) && (extname == "accountname")) - { - userrec* dest = (userrec*)target; - - /* logging them out? */ - if (extdata.empty()) - { - std::string* account; - dest->GetExt("accountname", account); - if (account) - { - dest->Shrink("accountname"); - delete account; - } - } - else - { - // if they dont already have an accountname field, accept the remote server's - std::string* text; - if (!dest->GetExt("accountname", text)) - { - text = new std::string(extdata); - // remove any accidental leading/trailing spaces - trim(*text); - dest->Extend("accountname", text); - } - } - } - } - - virtual ~ModuleServicesAccount() - { - ServerInstance->Modes->DelMode(m1); - ServerInstance->Modes->DelMode(m2); - ServerInstance->Modes->DelMode(m3); - DELETE(m1); - DELETE(m2); - DELETE(m3); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleServicesAccount) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
/* $ModDesc: Povides support for ircu-style services accounts, including chmode +R, etc. */
/** Channel mode +R - unidentified users cannot join
*/
class AChannel_R : public ModeHandler
{
public:
AChannel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('R'))
{
channel->SetMode('R',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('R'))
{
channel->SetMode('R',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** User mode +R - unidentified users cannot message
*/
class AUser_R : public ModeHandler
{
public:
AUser_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!dest->IsModeSet('R'))
{
dest->SetMode('R',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('R'))
{
dest->SetMode('R',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** Channel mode +M - unidentified users cannot message channel
*/
class AChannel_M : public ModeHandler
{
public:
AChannel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('M'))
{
channel->SetMode('M',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('M'))
{
channel->SetMode('M',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleServicesAccount : public Module
{
AChannel_R* m1;
AChannel_M* m2;
AUser_R* m3;
public:
ModuleServicesAccount(InspIRCd* Me) : Module(Me)
{
m1 = new AChannel_R(ServerInstance);
m2 = new AChannel_M(ServerInstance);
m3 = new AUser_R(ServerInstance);
if (!ServerInstance->AddMode(m1, 'R') || !ServerInstance->AddMode(m2, 'M') || !ServerInstance->AddMode(m3, 'R'))
throw ModuleException("Could not add new modes!");
}
/* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */
virtual void OnWhois(userrec* source, userrec* dest)
{
std::string *account;
dest->GetExt("accountname", account);
if (account)
{
ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick, dest->nick, account->c_str());
}
}
void Implements(char* List)
{
List[I_OnWhois] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1;
List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnDecodeMetaData] = 1;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
std::string *account;
if (!IS_LOCAL(user))
return 0;
user->GetExt("accountname", account);
if (target_type == TYPE_CHANNEL)
{
chanrec* c = (chanrec*)dest;
if ((c->IsModeSet('M')) && (!account))
{
if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
{
// user is ulined, can speak regardless
return 0;
}
// user messaging a +M channel and is not registered
user->WriteServ("477 "+std::string(user->nick)+" "+std::string(c->name)+" :You need to be identified to a registered account to message this channel");
return 1;
}
}
if (target_type == TYPE_USER)
{
userrec* u = (userrec*)dest;
if ((u->modes['R'-65]) && (!account))
{
if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
{
// user is ulined, can speak regardless
return 0;
}
// user messaging a +R user and is not registered
user->WriteServ("477 "+std::string(user->nick)+" "+std::string(u->nick)+" :You need to be identified to a registered account to message this user");
return 1;
}
}
return 0;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
std::string *account;
user->GetExt("accountname", account);
if (chan)
{
if (chan->IsModeSet('R'))
{
if (!account)
{
if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
{
// user is ulined, won't be stopped from joining
return 0;
}
// joining a +R channel and not identified
user->WriteServ("477 "+std::string(user->nick)+" "+std::string(chan->name)+" :You need to be identified to a registered account to join this channel");
return 1;
}
}
}
return 0;
}
// Whenever the linking module wants to send out data, but doesnt know what the data
// represents (e.g. it is metadata, added to a userrec or chanrec by a module) then
// this method is called. We should use the ProtoSendMetaData function after we've
// corrected decided how the data should look, to send the metadata on its way if
// it is ours.
virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
{
// check if the linking module wants to know about OUR metadata
if (extname == "accountname")
{
// check if this user has an swhois field to send
std::string* account;
user->GetExt("accountname", account);
if (account)
{
// remove any accidental leading/trailing spaces
trim(*account);
// call this function in the linking module, let it format the data how it
// sees fit, and send it on its way. We dont need or want to know how.
proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*account);
}
}
}
// when a user quits, tidy up their metadata
virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
{
std::string* account;
user->GetExt("accountname", account);
if (account)
{
user->Shrink("accountname");
delete account;
}
}
// if the module is unloaded, tidy up all our dangling metadata
virtual void OnCleanup(int target_type, void* item)
{
if (target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
std::string* account;
user->GetExt("accountname", account);
if (account)
{
user->Shrink("accountname");
delete account;
}
}
}
// Whenever the linking module receives metadata from another server and doesnt know what
// to do with it (of course, hence the 'meta') it calls this method, and it is up to each
// module in turn to figure out if this metadata key belongs to them, and what they want
// to do with it.
// In our case we're only sending a single string around, so we just construct a std::string.
// Some modules will probably get much more complex and format more detailed structs and classes
// in a textual way for sending over the link.
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
// check if its our metadata key, and its associated with a user
if ((target_type == TYPE_USER) && (extname == "accountname"))
{
userrec* dest = (userrec*)target;
/* logging them out? */
if (extdata.empty())
{
std::string* account;
dest->GetExt("accountname", account);
if (account)
{
dest->Shrink("accountname");
delete account;
}
}
else
{
// if they dont already have an accountname field, accept the remote server's
std::string* text;
if (!dest->GetExt("accountname", text))
{
text = new std::string(extdata);
// remove any accidental leading/trailing spaces
trim(*text);
dest->Extend("accountname", text);
}
}
}
}
virtual ~ModuleServicesAccount()
{
ServerInstance->Modes->DelMode(m1);
ServerInstance->Modes->DelMode(m2);
ServerInstance->Modes->DelMode(m3);
DELETE(m1);
DELETE(m2);
DELETE(m3);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleServicesAccount)
\ No newline at end of file diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp index e69a944e7..833f8e684 100644 --- a/src/modules/m_sethost.cpp +++ b/src/modules/m_sethost.cpp @@ -1,108 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for the SETHOST command */ - -/** Handle /SETHOST - */ -class cmd_sethost : public command_t -{ - private: - char* hostmap; - public: - cmd_sethost (InspIRCd* Instance, char* hmap) : command_t(Instance,"SETHOST",'o',1), hostmap(hmap) - { - this->source = "m_sethost.so"; - syntax = "<new-hostname>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - size_t len = 0; - for (const char* x = parameters[0]; *x; x++, len++) - { - if (!hostmap[(unsigned char)*x]) - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :*** SETHOST: Invalid characters in hostname"); - return CMD_FAILURE; - } - } - if (len == 0) - { - user->WriteServ("NOTICE %s :*** SETHOST: Host must be specified", user->nick); - return CMD_FAILURE; - } - if (len > 64) - { - user->WriteServ("NOTICE %s :*** SETHOST: Host too long",user->nick); - return CMD_FAILURE; - } - if (user->ChangeDisplayedHost(parameters[0])) - { - ServerInstance->WriteOpers(std::string(user->nick)+" used SETHOST to change their displayed host to "+user->dhost); - return CMD_SUCCESS; - } - - return CMD_FAILURE; - } -}; - - -class ModuleSetHost : public Module -{ - cmd_sethost* mycommand; - char hostmap[256]; - public: - ModuleSetHost(InspIRCd* Me) - : Module(Me) - { - OnRehash(NULL,""); - mycommand = new cmd_sethost(ServerInstance, hostmap); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - List[I_OnRehash] = 1; - } - - void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - std::string hmap = Conf.ReadValue("hostname", "charmap", 0); - - if (hmap.empty()) - hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789"; - - memset(&hostmap, 0, 255); - for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++) - hostmap[(unsigned char)*n] = 1; - } - - virtual ~ModuleSetHost() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSetHost) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for the SETHOST command */
/** Handle /SETHOST
*/
class cmd_sethost : public command_t
{
private:
char* hostmap;
public:
cmd_sethost (InspIRCd* Instance, char* hmap) : command_t(Instance,"SETHOST",'o',1), hostmap(hmap)
{
this->source = "m_sethost.so";
syntax = "<new-hostname>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
size_t len = 0;
for (const char* x = parameters[0]; *x; x++, len++)
{
if (!hostmap[(unsigned char)*x])
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :*** SETHOST: Invalid characters in hostname");
return CMD_FAILURE;
}
}
if (len == 0)
{
user->WriteServ("NOTICE %s :*** SETHOST: Host must be specified", user->nick);
return CMD_FAILURE;
}
if (len > 64)
{
user->WriteServ("NOTICE %s :*** SETHOST: Host too long",user->nick);
return CMD_FAILURE;
}
if (user->ChangeDisplayedHost(parameters[0]))
{
ServerInstance->WriteOpers(std::string(user->nick)+" used SETHOST to change their displayed host to "+user->dhost);
return CMD_SUCCESS;
}
return CMD_FAILURE;
}
};
class ModuleSetHost : public Module
{
cmd_sethost* mycommand;
char hostmap[256];
public:
ModuleSetHost(InspIRCd* Me)
: Module(Me)
{
OnRehash(NULL,"");
mycommand = new cmd_sethost(ServerInstance, hostmap);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
List[I_OnRehash] = 1;
}
void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
std::string hmap = Conf.ReadValue("hostname", "charmap", 0);
if (hmap.empty())
hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789";
memset(&hostmap, 0, 255);
for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
hostmap[(unsigned char)*n] = 1;
}
virtual ~ModuleSetHost()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSetHost)
\ No newline at end of file diff --git a/src/modules/m_setident.cpp b/src/modules/m_setident.cpp index 3f33061cd..f512a1f59 100644 --- a/src/modules/m_setident.cpp +++ b/src/modules/m_setident.cpp @@ -1,83 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "modules.h" - -/* $ModDesc: Provides support for the SETIDENT command */ - -/** Handle /SETIDENT - */ -class cmd_setident : public command_t -{ - public: - cmd_setident (InspIRCd* Instance) : command_t(Instance,"SETIDENT", 'o', 1) - { - this->source = "m_setident.so"; - syntax = "<new-ident>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - if (!*parameters[0]) - { - user->WriteServ("NOTICE %s :*** SETIDENT: Ident must be specified", user->nick); - return CMD_FAILURE; - } - - if (strlen(parameters[0]) > IDENTMAX) - { - user->WriteServ("NOTICE %s :*** SETIDENT: Ident is too long", user->nick); - return CMD_FAILURE; - } - - if (!ServerInstance->IsIdent(parameters[0])) - { - user->WriteServ("NOTICE %s :*** SETIDENT: Invalid characters in ident", user->nick); - return CMD_FAILURE; - } - - user->ChangeIdent(parameters[0]); - ServerInstance->WriteOpers("%s used SETIDENT to change their ident to '%s'", user->nick, user->ident); - - return CMD_SUCCESS; - } -}; - - -class ModuleSetIdent : public Module -{ - cmd_setident* mycommand; - - public: - ModuleSetIdent(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_setident(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSetIdent() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } - -}; - - -MODULE_INIT(ModuleSetIdent) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "modules.h"
/* $ModDesc: Provides support for the SETIDENT command */
/** Handle /SETIDENT
*/
class cmd_setident : public command_t
{
public:
cmd_setident (InspIRCd* Instance) : command_t(Instance,"SETIDENT", 'o', 1)
{
this->source = "m_setident.so";
syntax = "<new-ident>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
if (!*parameters[0])
{
user->WriteServ("NOTICE %s :*** SETIDENT: Ident must be specified", user->nick);
return CMD_FAILURE;
}
if (strlen(parameters[0]) > IDENTMAX)
{
user->WriteServ("NOTICE %s :*** SETIDENT: Ident is too long", user->nick);
return CMD_FAILURE;
}
if (!ServerInstance->IsIdent(parameters[0]))
{
user->WriteServ("NOTICE %s :*** SETIDENT: Invalid characters in ident", user->nick);
return CMD_FAILURE;
}
user->ChangeIdent(parameters[0]);
ServerInstance->WriteOpers("%s used SETIDENT to change their ident to '%s'", user->nick, user->ident);
return CMD_SUCCESS;
}
};
class ModuleSetIdent : public Module
{
cmd_setident* mycommand;
public:
ModuleSetIdent(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_setident(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSetIdent()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSetIdent)
\ No newline at end of file diff --git a/src/modules/m_setidle.cpp b/src/modules/m_setidle.cpp index e16369aa4..917368d7b 100644 --- a/src/modules/m_setidle.cpp +++ b/src/modules/m_setidle.cpp @@ -1,74 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Allows opers to set their idle time */ - -/** Handle /SETIDLE - */ -class cmd_setidle : public command_t -{ - public: - cmd_setidle (InspIRCd* Instance) : command_t(Instance,"SETIDLE", 'o', 1) - { - this->source = "m_setidle.so"; - syntax = "<duration>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - time_t idle = ServerInstance->Duration(parameters[0]); - if (idle < 1) - { - user->WriteServ("948 %s :Invalid idle time.",user->nick); - return CMD_FAILURE; - } - user->idle_lastmsg = (ServerInstance->Time() - idle); - // minor tweak - we cant have signon time shorter than our idle time! - if (user->signon > user->idle_lastmsg) - user->signon = user->idle_lastmsg; - ServerInstance->WriteOpers(std::string(user->nick)+" used SETIDLE to set their idle time to "+ConvToStr(idle)+" seconds"); - user->WriteServ("944 %s :Idle time set.",user->nick); - - return CMD_LOCALONLY; - } -}; - - -class ModuleSetIdle : public Module -{ - cmd_setidle* mycommand; - public: - ModuleSetIdle(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_setidle(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSetIdle() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleSetIdle) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Allows opers to set their idle time */
/** Handle /SETIDLE
*/
class cmd_setidle : public command_t
{
public:
cmd_setidle (InspIRCd* Instance) : command_t(Instance,"SETIDLE", 'o', 1)
{
this->source = "m_setidle.so";
syntax = "<duration>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
time_t idle = ServerInstance->Duration(parameters[0]);
if (idle < 1)
{
user->WriteServ("948 %s :Invalid idle time.",user->nick);
return CMD_FAILURE;
}
user->idle_lastmsg = (ServerInstance->Time() - idle);
// minor tweak - we cant have signon time shorter than our idle time!
if (user->signon > user->idle_lastmsg)
user->signon = user->idle_lastmsg;
ServerInstance->WriteOpers(std::string(user->nick)+" used SETIDLE to set their idle time to "+ConvToStr(idle)+" seconds");
user->WriteServ("944 %s :Idle time set.",user->nick);
return CMD_LOCALONLY;
}
};
class ModuleSetIdle : public Module
{
cmd_setidle* mycommand;
public:
ModuleSetIdle(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_setidle(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSetIdle()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSetIdle)
\ No newline at end of file diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp index 586c6f84e..3f525622f 100644 --- a/src/modules/m_setname.cpp +++ b/src/modules/m_setname.cpp @@ -1,80 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for the SETNAME command */ - - - -class cmd_setname : public command_t -{ - public: - cmd_setname (InspIRCd* Instance) : command_t(Instance,"SETNAME", 0, 1) - { - this->source = "m_setname.so"; - syntax = "<new-gecos>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - if (!*parameters[0]) - { - user->WriteServ("NOTICE %s :*** SETNAME: GECOS must be specified", user->nick); - return CMD_FAILURE; - } - - if (strlen(parameters[0]) > MAXGECOS) - { - user->WriteServ("NOTICE %s :*** SETNAME: GECOS too long", user->nick); - return CMD_FAILURE; - } - - if (user->ChangeName(parameters[0])) - { - ServerInstance->WriteOpers("%s used SETNAME to change their GECOS to %s", user->nick, parameters[0]); - return CMD_SUCCESS; - } - - return CMD_SUCCESS; - } -}; - - -class ModuleSetName : public Module -{ - cmd_setname* mycommand; - public: - ModuleSetName(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_setname(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleSetName() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleSetName) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for the SETNAME command */
class cmd_setname : public command_t
{
public:
cmd_setname (InspIRCd* Instance) : command_t(Instance,"SETNAME", 0, 1)
{
this->source = "m_setname.so";
syntax = "<new-gecos>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
if (!*parameters[0])
{
user->WriteServ("NOTICE %s :*** SETNAME: GECOS must be specified", user->nick);
return CMD_FAILURE;
}
if (strlen(parameters[0]) > MAXGECOS)
{
user->WriteServ("NOTICE %s :*** SETNAME: GECOS too long", user->nick);
return CMD_FAILURE;
}
if (user->ChangeName(parameters[0]))
{
ServerInstance->WriteOpers("%s used SETNAME to change their GECOS to %s", user->nick, parameters[0]);
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
};
class ModuleSetName : public Module
{
cmd_setname* mycommand;
public:
ModuleSetName(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_setname(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleSetName()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSetName)
\ No newline at end of file diff --git a/src/modules/m_sha256.cpp b/src/modules/m_sha256.cpp index 547e7655c..0dfef40b9 100644 --- a/src/modules/m_sha256.cpp +++ b/src/modules/m_sha256.cpp @@ -1,296 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* m_sha256 - Based on m_opersha256 written by Special <john@yarbbles.com> - * Modified and improved by Craig Edwards, December 2006. - * - * - * FIPS 180-2 SHA-224/256/384/512 implementation - * Last update: 05/23/2005 - * Issue date: 04/30/2005 - * - * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $ModDesc: Allows for SHA-256 encrypted oper passwords */ -/* $ModDep: m_hash.h */ - -#include "inspircd.h" -#ifdef HAS_STDINT -#include <stdint.h> -#endif -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "m_hash.h" - -#ifndef HAS_STDINT -typedef unsigned int uint32_t; -#endif - -/** An sha 256 context, used by m_opersha256 - */ -class SHA256Context : public classbase -{ - public: - unsigned int tot_len; - unsigned int len; - unsigned char block[2 * SHA256_BLOCK_SIZE]; - uint32_t h[8]; -}; - -#define SHFR(x, n) (x >> n) -#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) -#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) -#define CH(x, y, z) ((x & y) ^ (~x & z)) -#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) - -#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) -#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) -#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) -#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) - -#define UNPACK32(x, str) \ -{ \ - *((str) + 3) = (uint8_t) ((x) ); \ - *((str) + 2) = (uint8_t) ((x) >> 8); \ - *((str) + 1) = (uint8_t) ((x) >> 16); \ - *((str) + 0) = (uint8_t) ((x) >> 24); \ -} - -#define PACK32(str, x) \ -{ \ - *(x) = ((uint32_t) *((str) + 3) ) \ - | ((uint32_t) *((str) + 2) << 8) \ - | ((uint32_t) *((str) + 1) << 16) \ - | ((uint32_t) *((str) + 0) << 24); \ -} - -/* Macros used for loops unrolling */ - -#define SHA256_SCR(i) \ -{ \ - w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ - + SHA256_F3(w[i - 15]) + w[i - 16]; \ -} - -const unsigned int sha256_h0[8] = -{ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 -}; - -uint32_t sha256_k[64] = -{ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -class ModuleSHA256 : public Module -{ - void SHA256Init(SHA256Context *ctx, const unsigned int* key) - { - if (key) - { - for (int i = 0; i < 8; i++) - ctx->h[i] = key[i]; - } - else - { - for (int i = 0; i < 8; i++) - ctx->h[i] = sha256_h0[i]; - } - ctx->len = 0; - ctx->tot_len = 0; - } - - void SHA256Transform(SHA256Context *ctx, unsigned char *message, unsigned int block_nb) - { - uint32_t w[64]; - uint32_t wv[8]; - unsigned char *sub_block; - for (unsigned int i = 1; i <= block_nb; i++) - { - int j; - sub_block = message + ((i - 1) << 6); - - for (j = 0; j < 16; j++) - PACK32(&sub_block[j << 2], &w[j]); - for (j = 16; j < 64; j++) - SHA256_SCR(j); - for (j = 0; j < 8; j++) - wv[j] = ctx->h[j]; - for (j = 0; j < 64; j++) - { - uint32_t t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; - uint32_t t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); - wv[7] = wv[6]; - wv[6] = wv[5]; - wv[5] = wv[4]; - wv[4] = wv[3] + t1; - wv[3] = wv[2]; - wv[2] = wv[1]; - wv[1] = wv[0]; - wv[0] = t1 + t2; - } - for (j = 0; j < 8; j++) - ctx->h[j] += wv[j]; - } - } - - void SHA256Update(SHA256Context *ctx, unsigned char *message, unsigned int len) - { - unsigned int rem_len = SHA256_BLOCK_SIZE - ctx->len; - memcpy(&ctx->block[ctx->len], message, rem_len); - if (ctx->len + len < SHA256_BLOCK_SIZE) - { - ctx->len += len; - return; - } - unsigned int new_len = len - rem_len; - unsigned int block_nb = new_len / SHA256_BLOCK_SIZE; - unsigned char *shifted_message = message + rem_len; - SHA256Transform(ctx, ctx->block, 1); - SHA256Transform(ctx, shifted_message, block_nb); - rem_len = new_len % SHA256_BLOCK_SIZE; - memcpy(ctx->block, &shifted_message[block_nb << 6],rem_len); - ctx->len = rem_len; - ctx->tot_len += (block_nb + 1) << 6; - } - - void SHA256Final(SHA256Context *ctx, unsigned char *digest) - { - unsigned int block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); - unsigned int len_b = (ctx->tot_len + ctx->len) << 3; - unsigned int pm_len = block_nb << 6; - memset(ctx->block + ctx->len, 0, pm_len - ctx->len); - ctx->block[ctx->len] = 0x80; - UNPACK32(len_b, ctx->block + pm_len - 4); - SHA256Transform(ctx, ctx->block, block_nb); - for (int i = 0 ; i < 8; i++) - UNPACK32(ctx->h[i], &digest[i << 2]); - } - - void SHA256(const char *src, char *dest, int len, const char* hxc, const unsigned int* key = NULL) - { - // Generate the hash - unsigned char bytehash[SHA256_DIGEST_SIZE]; - SHA256Context ctx; - SHA256Init(&ctx, key); - SHA256Update(&ctx, (unsigned char *)src, (unsigned int)len); - SHA256Final(&ctx, bytehash); - // Convert it to hex - for (int i = 0, j = 0; i < SHA256_DIGEST_SIZE; i++) - { - dest[j++] = hxc[bytehash[i] / 16]; - dest[j++] = hxc[bytehash[i] % 16]; - dest[j] = '\0'; - } - } - - unsigned int* key; - char* chars; - - public: - - ModuleSHA256(InspIRCd* Me) : Module(Me), key(NULL), chars(NULL) - { - ServerInstance->PublishInterface("HashRequest", this); - } - - virtual ~ModuleSHA256() - { - ServerInstance->UnpublishInterface("HashRequest", this); - } - - void Implements(char *List) - { - List[I_OnRequest] = 1; - } - - virtual char* OnRequest(Request* request) - { - HashRequest* SHA = (HashRequest*)request; - if (strcmp("KEY", request->GetId()) == 0) - { - this->key = (unsigned int*)SHA->GetKeyData(); - } - else if (strcmp("HEX", request->GetId()) == 0) - { - this->chars = (char*)SHA->GetOutputs(); - } - else if (strcmp("SUM", request->GetId()) == 0) - { - static char data[MAXBUF]; - SHA256((const char*)SHA->GetHashData(), data, strlen(SHA->GetHashData()), chars ? chars : "0123456789abcdef", key); - return data; - } - else if (strcmp("NAME", request->GetId()) == 0) - { - return "sha256"; - } - else if (strcmp("RESET", request->GetId()) == 0) - { - this->chars = NULL; - this->key = NULL; - } - return NULL; - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 1, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION); - } -}; - -MODULE_INIT(ModuleSHA256) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* m_sha256 - Based on m_opersha256 written by Special <john@yarbbles.com>
* Modified and improved by Craig Edwards, December 2006.
*
*
* FIPS 180-2 SHA-224/256/384/512 implementation
* Last update: 05/23/2005
* Issue date: 04/30/2005
*
* Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* $ModDesc: Allows for SHA-256 encrypted oper passwords */
/* $ModDep: m_hash.h */
#include "inspircd.h"
#ifdef HAS_STDINT
#include <stdint.h>
#endif
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "m_hash.h"
#ifndef HAS_STDINT
typedef unsigned int uint32_t;
#endif
/** An sha 256 context, used by m_opersha256
*/
class SHA256Context : public classbase
{
public:
unsigned int tot_len;
unsigned int len;
unsigned char block[2 * SHA256_BLOCK_SIZE];
uint32_t h[8];
};
#define SHFR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define CH(x, y, z) ((x & y) ^ (~x & z))
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
#define UNPACK32(x, str) \
{ \
*((str) + 3) = (uint8_t) ((x) ); \
*((str) + 2) = (uint8_t) ((x) >> 8); \
*((str) + 1) = (uint8_t) ((x) >> 16); \
*((str) + 0) = (uint8_t) ((x) >> 24); \
}
#define PACK32(str, x) \
{ \
*(x) = ((uint32_t) *((str) + 3) ) \
| ((uint32_t) *((str) + 2) << 8) \
| ((uint32_t) *((str) + 1) << 16) \
| ((uint32_t) *((str) + 0) << 24); \
}
/* Macros used for loops unrolling */
#define SHA256_SCR(i) \
{ \
w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \
+ SHA256_F3(w[i - 15]) + w[i - 16]; \
}
const unsigned int sha256_h0[8] =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
uint32_t sha256_k[64] =
{
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
class ModuleSHA256 : public Module
{
void SHA256Init(SHA256Context *ctx, const unsigned int* key)
{
if (key)
{
for (int i = 0; i < 8; i++)
ctx->h[i] = key[i];
}
else
{
for (int i = 0; i < 8; i++)
ctx->h[i] = sha256_h0[i];
}
ctx->len = 0;
ctx->tot_len = 0;
}
void SHA256Transform(SHA256Context *ctx, unsigned char *message, unsigned int block_nb)
{
uint32_t w[64];
uint32_t wv[8];
unsigned char *sub_block;
for (unsigned int i = 1; i <= block_nb; i++)
{
int j;
sub_block = message + ((i - 1) << 6);
for (j = 0; j < 16; j++)
PACK32(&sub_block[j << 2], &w[j]);
for (j = 16; j < 64; j++)
SHA256_SCR(j);
for (j = 0; j < 8; j++)
wv[j] = ctx->h[j];
for (j = 0; j < 64; j++)
{
uint32_t t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j];
uint32_t t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++)
ctx->h[j] += wv[j];
}
}
void SHA256Update(SHA256Context *ctx, unsigned char *message, unsigned int len)
{
unsigned int rem_len = SHA256_BLOCK_SIZE - ctx->len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA256_BLOCK_SIZE)
{
ctx->len += len;
return;
}
unsigned int new_len = len - rem_len;
unsigned int block_nb = new_len / SHA256_BLOCK_SIZE;
unsigned char *shifted_message = message + rem_len;
SHA256Transform(ctx, ctx->block, 1);
SHA256Transform(ctx, shifted_message, block_nb);
rem_len = new_len % SHA256_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 6],rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 6;
}
void SHA256Final(SHA256Context *ctx, unsigned char *digest)
{
unsigned int block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE)));
unsigned int len_b = (ctx->tot_len + ctx->len) << 3;
unsigned int pm_len = block_nb << 6;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
SHA256Transform(ctx, ctx->block, block_nb);
for (int i = 0 ; i < 8; i++)
UNPACK32(ctx->h[i], &digest[i << 2]);
}
void SHA256(const char *src, char *dest, int len, const char* hxc, const unsigned int* key = NULL)
{
// Generate the hash
unsigned char bytehash[SHA256_DIGEST_SIZE];
SHA256Context ctx;
SHA256Init(&ctx, key);
SHA256Update(&ctx, (unsigned char *)src, (unsigned int)len);
SHA256Final(&ctx, bytehash);
// Convert it to hex
for (int i = 0, j = 0; i < SHA256_DIGEST_SIZE; i++)
{
dest[j++] = hxc[bytehash[i] / 16];
dest[j++] = hxc[bytehash[i] % 16];
dest[j] = '\0';
}
}
unsigned int* key;
char* chars;
public:
ModuleSHA256(InspIRCd* Me) : Module(Me), key(NULL), chars(NULL)
{
ServerInstance->PublishInterface("HashRequest", this);
}
virtual ~ModuleSHA256()
{
ServerInstance->UnpublishInterface("HashRequest", this);
}
void Implements(char *List)
{
List[I_OnRequest] = 1;
}
virtual char* OnRequest(Request* request)
{
HashRequest* SHA = (HashRequest*)request;
if (strcmp("KEY", request->GetId()) == 0)
{
this->key = (unsigned int*)SHA->GetKeyData();
}
else if (strcmp("HEX", request->GetId()) == 0)
{
this->chars = (char*)SHA->GetOutputs();
}
else if (strcmp("SUM", request->GetId()) == 0)
{
static char data[MAXBUF];
SHA256((const char*)SHA->GetHashData(), data, strlen(SHA->GetHashData()), chars ? chars : "0123456789abcdef", key);
return data;
}
else if (strcmp("NAME", request->GetId()) == 0)
{
return "sha256";
}
else if (strcmp("RESET", request->GetId()) == 0)
{
this->chars = NULL;
this->key = NULL;
}
return NULL;
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 1, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
}
};
MODULE_INIT(ModuleSHA256)
\ No newline at end of file diff --git a/src/modules/m_showwhois.cpp b/src/modules/m_showwhois.cpp index cb6a0ffb0..676962818 100644 --- a/src/modules/m_showwhois.cpp +++ b/src/modules/m_showwhois.cpp @@ -1,109 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Allows opers to set +W to see when a user uses WHOIS on them */ - -/** Handle user mode +W - */ -class SeeWhois : public ModeHandler -{ - public: - SeeWhois(InspIRCd* Instance) : ModeHandler(Instance, 'W', 0, 0, false, MODETYPE_USER, true) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - /* Only opers can change other users modes */ - if (source != dest) - return MODEACTION_DENY; - - if (adding) - { - if (!dest->IsModeSet('W')) - { - dest->SetMode('W',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('W')) - { - dest->SetMode('W',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -class ModuleShowwhois : public Module -{ - - SeeWhois* sw; - - public: - - ModuleShowwhois(InspIRCd* Me) : Module(Me) - { - - sw = new SeeWhois(ServerInstance); - if (!ServerInstance->AddMode(sw, 'W')) - throw ModuleException("Could not add new modes!"); - } - - ~ModuleShowwhois() - { - ServerInstance->Modes->DelMode(sw); - DELETE(sw); - } - - void Implements(char* List) - { - List[I_OnWhois] = 1; - } - - virtual Version GetVersion() - { - return Version(1,1,0,3,VF_COMMON|VF_VENDOR,API_VERSION); - } - - virtual void OnWhois(userrec* source, userrec* dest) - { - if ((dest->IsModeSet('W')) && (source != dest)) - { - if (IS_LOCAL(dest)) - { - dest->WriteServ("NOTICE %s :*** %s (%s@%s) did a /whois on you.",dest->nick,source->nick,source->ident,source->host); - } - else - { - std::deque<std::string> params; - params.push_back(dest->nick); - std::string msg = ":"; - msg = msg + dest->server + " NOTICE " + dest->nick + " :*** " + source->nick + " (" + source->ident + "@" + source->host + ") did a /whois on you."; - params.push_back(msg); - Event ev((char *) ¶ms, NULL, "send_push"); - ev.Send(ServerInstance); - } - } - } - -}; - -MODULE_INIT(ModuleShowwhois) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Allows opers to set +W to see when a user uses WHOIS on them */
/** Handle user mode +W
*/
class SeeWhois : public ModeHandler
{
public:
SeeWhois(InspIRCd* Instance) : ModeHandler(Instance, 'W', 0, 0, false, MODETYPE_USER, true) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
/* Only opers can change other users modes */
if (source != dest)
return MODEACTION_DENY;
if (adding)
{
if (!dest->IsModeSet('W'))
{
dest->SetMode('W',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('W'))
{
dest->SetMode('W',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleShowwhois : public Module
{
SeeWhois* sw;
public:
ModuleShowwhois(InspIRCd* Me) : Module(Me)
{
sw = new SeeWhois(ServerInstance);
if (!ServerInstance->AddMode(sw, 'W'))
throw ModuleException("Could not add new modes!");
}
~ModuleShowwhois()
{
ServerInstance->Modes->DelMode(sw);
DELETE(sw);
}
void Implements(char* List)
{
List[I_OnWhois] = 1;
}
virtual Version GetVersion()
{
return Version(1,1,0,3,VF_COMMON|VF_VENDOR,API_VERSION);
}
virtual void OnWhois(userrec* source, userrec* dest)
{
if ((dest->IsModeSet('W')) && (source != dest))
{
if (IS_LOCAL(dest))
{
dest->WriteServ("NOTICE %s :*** %s (%s@%s) did a /whois on you.",dest->nick,source->nick,source->ident,source->host);
}
else
{
std::deque<std::string> params;
params.push_back(dest->nick);
std::string msg = ":";
msg = msg + dest->server + " NOTICE " + dest->nick + " :*** " + source->nick + " (" + source->ident + "@" + source->host + ") did a /whois on you.";
params.push_back(msg);
Event ev((char *) ¶ms, NULL, "send_push");
ev.Send(ServerInstance);
}
}
}
};
MODULE_INIT(ModuleShowwhois)
\ No newline at end of file diff --git a/src/modules/m_silence.cpp b/src/modules/m_silence.cpp index b05689056..3becb06f2 100644 --- a/src/modules/m_silence.cpp +++ b/src/modules/m_silence.cpp @@ -1,215 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" -#include "wildcard.h" - -/* $ModDesc: Provides support for the /SILENCE command */ - -// This typedef holds a silence list. Each user may or may not have a -// silencelist, if a silence list is empty for a user, he/she does not -// have one of these structures associated with their user record. -typedef std::map<irc::string, time_t> silencelist; - -class cmd_silence : public command_t -{ - unsigned int& maxsilence; - public: - cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max) - { - this->source = "m_silence.so"; - syntax = "{[+|-]<mask>}"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - if (!pcnt) - { - // no parameters, show the current silence list. - // Use Extensible::GetExt to fetch the silence list - silencelist* sl; - user->GetExt("silence_list", sl); - // if the user has a silence list associated with their user record, show it - if (sl) - { - for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++) - { - user->WriteServ("271 %s %s %s :%lu",user->nick, user->nick, c->first.c_str(), (unsigned long)c->second); - } - } - user->WriteServ("272 %s :End of Silence List",user->nick); - - return CMD_SUCCESS; - } - else if (pcnt > 0) - { - // one or more parameters, add or delete entry from the list (only the first parameter is used) - std::string mask = parameters[0] + 1; - char action = *parameters[0]; - - if (!mask.length()) - { - // 'SILENCE +' or 'SILENCE -', assume *!*@* - mask = "*!*@*"; - } - - ModeParser::CleanMask(mask); - - if (action == '-') - { - // fetch their silence list - silencelist* sl; - user->GetExt("silence_list", sl); - // does it contain any entries and does it exist? - if (sl) - { - silencelist::iterator i = sl->find(mask.c_str()); - if (i != sl->end()) - { - sl->erase(i); - user->WriteServ("950 %s %s :Removed %s from silence list",user->nick, user->nick, mask.c_str()); - if (!sl->size()) - { - // tidy up -- if a user's list is empty, theres no use having it - // hanging around in the user record. - DELETE(sl); - user->Shrink("silence_list"); - } - } - else - user->WriteServ("952 %s %s :%s does not exist on your silence list",user->nick, user->nick, mask.c_str()); - } - } - else if (action == '+') - { - // fetch the user's current silence list - silencelist* sl; - user->GetExt("silence_list", sl); - // what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one. - if (!sl) - { - sl = new silencelist; - user->Extend("silence_list", sl); - } - silencelist::iterator n = sl->find(mask.c_str()); - if (n != sl->end()) - { - user->WriteServ("952 %s %s :%s is already on your silence list",user->nick, user->nick, mask.c_str()); - return CMD_FAILURE; - } - if (sl->size() >= maxsilence) - { - user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick, mask.c_str()); - return CMD_FAILURE; - } - sl->insert(std::make_pair<irc::string, time_t>(mask.c_str(), ServerInstance->Time())); - user->WriteServ("951 %s %s :Added %s to silence list",user->nick, user->nick, mask.c_str()); - return CMD_SUCCESS; - } - } - return CMD_SUCCESS; - } -}; - -class ModuleSilence : public Module -{ - - cmd_silence* mycommand; - unsigned int maxsilence; - public: - - ModuleSilence(InspIRCd* Me) - : Module(Me), maxsilence(32) - { - OnRehash(NULL, ""); - mycommand = new cmd_silence(ServerInstance, maxsilence); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true); - if (!maxsilence) - maxsilence = 32; - } - - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - // when the user quits tidy up any silence list they might have just to keep things tidy - // and to prevent a HONKING BIG MEMORY LEAK! - silencelist* sl; - user->GetExt("silence_list", sl); - if (sl) - { - DELETE(sl); - user->Shrink("silence_list"); - } - } - - virtual void On005Numeric(std::string &output) - { - // we don't really have a limit... - output = output + " SILENCE=" + ConvToStr(maxsilence); - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - // im not sure how unreal's silence operates but ours is sensible. It blocks notices and - // privmsgs from people on the silence list, directed privately at the user. - // channel messages are unaffected (ever tried to follow the flow of conversation in - // a channel when you've set an ignore on the two most talkative people?) - if ((target_type == TYPE_USER) && (IS_LOCAL(user))) - { - userrec* u = (userrec*)dest; - silencelist* sl; - u->GetExt("silence_list", sl); - if (sl) - { - for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++) - { - if (match(user->GetFullHost(), c->first.c_str())) - { - return 1; - } - } - } - } - return 0; - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreNotice(user,dest,target_type,text,status,exempt_list); - } - - virtual ~ModuleSilence() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleSilence) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
#include "wildcard.h"
/* $ModDesc: Provides support for the /SILENCE command */
// This typedef holds a silence list. Each user may or may not have a
// silencelist, if a silence list is empty for a user, he/she does not
// have one of these structures associated with their user record.
typedef std::map<irc::string, time_t> silencelist;
class cmd_silence : public command_t
{
unsigned int& maxsilence;
public:
cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max)
{
this->source = "m_silence.so";
syntax = "{[+|-]<mask>}";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
if (!pcnt)
{
// no parameters, show the current silence list.
// Use Extensible::GetExt to fetch the silence list
silencelist* sl;
user->GetExt("silence_list", sl);
// if the user has a silence list associated with their user record, show it
if (sl)
{
for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
{
user->WriteServ("271 %s %s %s :%lu",user->nick, user->nick, c->first.c_str(), (unsigned long)c->second);
}
}
user->WriteServ("272 %s :End of Silence List",user->nick);
return CMD_SUCCESS;
}
else if (pcnt > 0)
{
// one or more parameters, add or delete entry from the list (only the first parameter is used)
std::string mask = parameters[0] + 1;
char action = *parameters[0];
if (!mask.length())
{
// 'SILENCE +' or 'SILENCE -', assume *!*@*
mask = "*!*@*";
}
ModeParser::CleanMask(mask);
if (action == '-')
{
// fetch their silence list
silencelist* sl;
user->GetExt("silence_list", sl);
// does it contain any entries and does it exist?
if (sl)
{
silencelist::iterator i = sl->find(mask.c_str());
if (i != sl->end())
{
sl->erase(i);
user->WriteServ("950 %s %s :Removed %s from silence list",user->nick, user->nick, mask.c_str());
if (!sl->size())
{
// tidy up -- if a user's list is empty, theres no use having it
// hanging around in the user record.
DELETE(sl);
user->Shrink("silence_list");
}
}
else
user->WriteServ("952 %s %s :%s does not exist on your silence list",user->nick, user->nick, mask.c_str());
}
}
else if (action == '+')
{
// fetch the user's current silence list
silencelist* sl;
user->GetExt("silence_list", sl);
// what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one.
if (!sl)
{
sl = new silencelist;
user->Extend("silence_list", sl);
}
silencelist::iterator n = sl->find(mask.c_str());
if (n != sl->end())
{
user->WriteServ("952 %s %s :%s is already on your silence list",user->nick, user->nick, mask.c_str());
return CMD_FAILURE;
}
if (sl->size() >= maxsilence)
{
user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick, mask.c_str());
return CMD_FAILURE;
}
sl->insert(std::make_pair<irc::string, time_t>(mask.c_str(), ServerInstance->Time()));
user->WriteServ("951 %s %s :Added %s to silence list",user->nick, user->nick, mask.c_str());
return CMD_SUCCESS;
}
}
return CMD_SUCCESS;
}
};
class ModuleSilence : public Module
{
cmd_silence* mycommand;
unsigned int maxsilence;
public:
ModuleSilence(InspIRCd* Me)
: Module(Me), maxsilence(32)
{
OnRehash(NULL, "");
mycommand = new cmd_silence(ServerInstance, maxsilence);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);
if (!maxsilence)
maxsilence = 32;
}
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
// when the user quits tidy up any silence list they might have just to keep things tidy
// and to prevent a HONKING BIG MEMORY LEAK!
silencelist* sl;
user->GetExt("silence_list", sl);
if (sl)
{
DELETE(sl);
user->Shrink("silence_list");
}
}
virtual void On005Numeric(std::string &output)
{
// we don't really have a limit...
output = output + " SILENCE=" + ConvToStr(maxsilence);
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
// im not sure how unreal's silence operates but ours is sensible. It blocks notices and
// privmsgs from people on the silence list, directed privately at the user.
// channel messages are unaffected (ever tried to follow the flow of conversation in
// a channel when you've set an ignore on the two most talkative people?)
if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
{
userrec* u = (userrec*)dest;
silencelist* sl;
u->GetExt("silence_list", sl);
if (sl)
{
for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
{
if (match(user->GetFullHost(), c->first.c_str()))
{
return 1;
}
}
}
}
return 0;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
}
virtual ~ModuleSilence()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSilence)
\ No newline at end of file diff --git a/src/modules/m_silence_ext.cpp b/src/modules/m_silence_ext.cpp index 06eee9dd4..7b1588043 100644 --- a/src/modules/m_silence_ext.cpp +++ b/src/modules/m_silence_ext.cpp @@ -1,372 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" -#include "wildcard.h" - -/* $ModDesc: Provides support for the /SILENCE command */ - -/* Improved drop-in replacement for the /SILENCE command - * syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude> - * - * example that blocks all except private messages - * /SILENCE +*!*@* a - * /SILENCE +*!*@* px - * - * example that blocks all invites except from channel services - * /SILENCE +*!*@* i - * /SILENCE +chanserv!services@chatters.net ix - * - * example that blocks some bad dude from private, notice and inviting you - * /SILENCE +*!kiddie@lamerz.net pin - * - * TODO: possibly have add and remove check for existing host and only modify flags according to - * what's been changed instead of having to remove first, then add if you want to change - * an entry. - */ - -// pair of hostmask and flags -typedef std::pair<std::string, int> silenceset; - -// deque list of pairs -typedef std::deque<silenceset> silencelist; - -// intmasks for flags -static int SILENCE_PRIVATE = 0x0001; /* p private messages */ -static int SILENCE_CHANNEL = 0x0002; /* c channel messages */ -static int SILENCE_INVITE = 0x0004; /* i invites */ -static int SILENCE_NOTICE = 0x0008; /* n notices */ -static int SILENCE_CNOTICE = 0x0010; /* t channel notices */ -static int SILENCE_ALL = 0x0020; /* a all, (pcint) */ -static int SILENCE_EXCLUDE = 0x0040; /* x exclude this pattern */ - - -class cmd_silence : public command_t -{ - unsigned int& maxsilence; - public: - cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max) - { - this->source = "m_silence_ext.so"; - syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - if (!pcnt) - { - // no parameters, show the current silence list. - // Use Extensible::GetExt to fetch the silence list - silencelist* sl; - user->GetExt("silence_list", sl); - // if the user has a silence list associated with their user record, show it - if (sl) - { - for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++) - { - user->WriteServ("271 %s %s %s %s",user->nick, user->nick,c->first.c_str(), DecompPattern(c->second).c_str()); - } - } - user->WriteServ("272 %s :End of Silence List",user->nick); - - return CMD_LOCALONLY; - } - else if (pcnt > 0) - { - // one or more parameters, add or delete entry from the list (only the first parameter is used) - std::string mask = parameters[0] + 1; - char action = *parameters[0]; - // Default is private and notice so clients do not break - int pattern = CompilePattern("pn"); - - // if pattern supplied, use it - if (pcnt > 1) { - pattern = CompilePattern(parameters[1]); - } - - if (!mask.length()) - { - // 'SILENCE +' or 'SILENCE -', assume *!*@* - mask = "*!*@*"; - } - - ModeParser::CleanMask(mask); - - if (action == '-') - { - // fetch their silence list - silencelist* sl; - user->GetExt("silence_list", sl); - // does it contain any entries and does it exist? - if (sl) - { - for (silencelist::iterator i = sl->begin(); i != sl->end(); i++) - { - // search through for the item - irc::string listitem = i->first.c_str(); - if (listitem == mask && i->second == pattern) - { - sl->erase(i); - user->WriteServ("950 %s %s :Removed %s %s from silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str()); - if (!sl->size()) - { - DELETE(sl); - user->Shrink("silence_list"); - } - break; - } - } - } - user->WriteServ("952 %s %s :%s %s does not exist on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str()); - } - else if (action == '+') - { - // fetch the user's current silence list - silencelist* sl; - user->GetExt("silence_list", sl); - // what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one. - if (!sl) - { - sl = new silencelist; - user->Extend("silence_list", sl); - } - if (sl->size() > maxsilence) - { - user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick); - return CMD_FAILURE; - } - for (silencelist::iterator n = sl->begin(); n != sl->end(); n++) - { - irc::string listitem = n->first.c_str(); - if (listitem == mask && n->second == pattern) - { - user->WriteServ("952 %s %s :%s %s is already on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str()); - return CMD_FAILURE; - } - } - if (((pattern & SILENCE_EXCLUDE) > 0)) - { - sl->push_front(silenceset(mask,pattern)); - } - else - { - sl->push_back(silenceset(mask,pattern)); - } - user->WriteServ("951 %s %s :Added %s %s to silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str()); - return CMD_LOCALONLY; - } - } - return CMD_LOCALONLY; - } - - /* turn the nice human readable pattern into a mask */ - int CompilePattern(const char* pattern) - { - int p = 0; - for (const char* n = pattern; *n; n++) - { - switch (*n) - { - case 'p': - p |= SILENCE_PRIVATE; - break; - case 'c': - p |= SILENCE_CHANNEL; - break; - case 'i': - p |= SILENCE_INVITE; - break; - case 'n': - p |= SILENCE_NOTICE; - break; - case 't': - p |= SILENCE_CNOTICE; - break; - case 'a': - p |= SILENCE_ALL; - break; - case 'x': - p |= SILENCE_EXCLUDE; - break; - default: - break; - } - } - return p; - } - - /* turn the mask into a nice human readable format */ - std::string DecompPattern (const int pattern) - { - std::string out; - if ((pattern & SILENCE_PRIVATE) > 0) - out += ",privatemessages"; - if ((pattern & SILENCE_CHANNEL) > 0) - out += ",channelmessages"; - if ((pattern & SILENCE_INVITE) > 0) - out += ",invites"; - if ((pattern & SILENCE_NOTICE) > 0) - out += ",privatenotices"; - if ((pattern & SILENCE_CNOTICE) > 0) - out += ",channelnotices"; - if ((pattern & SILENCE_ALL) > 0) - out = ",all"; - if ((pattern & SILENCE_EXCLUDE) > 0) - out += ",exclude"; - return "<" + out.substr(1) + ">"; - } - -}; - -class ModuleSilence : public Module -{ - cmd_silence* mycommand; - unsigned int maxsilence; - public: - - ModuleSilence(InspIRCd* Me) - : Module(Me), maxsilence(32) - { - OnRehash(NULL, ""); - mycommand = new cmd_silence(ServerInstance,maxsilence); - ServerInstance->AddCommand(mycommand); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true); - if (!maxsilence) - maxsilence = 32; - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnBuildExemptList] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = List[I_OnUserPreInvite] = 1; - } - - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - // when the user quits tidy up any silence list they might have just to keep things tidy - silencelist* sl; - user->GetExt("silence_list", sl); - if (sl) - { - DELETE(sl); - user->Shrink("silence_list"); - } - } - - virtual void On005Numeric(std::string &output) - { - // we don't really have a limit... - output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence); - } - - virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list) - { - int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE); - CUList *ulist; - switch (status) - { - case '@': - ulist = chan->GetOppedUsers(); - break; - case '%': - ulist = chan->GetHalfoppedUsers(); - break; - case '+': - ulist = chan->GetVoicedUsers(); - break; - default: - ulist = chan->GetUsers(); - break; - } - - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - if (IS_LOCAL(i->first)) - { - if (MatchPattern(i->first, sender, public_silence) == 1) - { - exempt_list[i->first] = i->first->nick; - } - } - } - } - - virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type) - { - if (!IS_LOCAL(user)) - return 0; - - if (target_type == TYPE_USER) - { - return MatchPattern((userrec*)dest, user, silence_type); - } - else if (target_type == TYPE_CHANNEL) - { - chanrec* chan = (chanrec*)dest; - if (chan) - { - this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list); - } - } - return 0; - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE); - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE); - } - - virtual int OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel) - { - return MatchPattern(dest, source, SILENCE_INVITE); - } - - int MatchPattern(userrec* dest, userrec* source, int pattern) - { - silencelist* sl; - dest->GetExt("silence_list", sl); - if (sl) - { - for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++) - { - if (((((c->second & pattern) > 0)) || ((c->second & SILENCE_ALL) > 0)) && (ServerInstance->MatchText(source->GetFullHost(), c->first))) - return !(((c->second & SILENCE_EXCLUDE) > 0)); - } - } - return 0; - } - - virtual ~ModuleSilence() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleSilence) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
#include "wildcard.h"
/* $ModDesc: Provides support for the /SILENCE command */
/* Improved drop-in replacement for the /SILENCE command
* syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude>
*
* example that blocks all except private messages
* /SILENCE +*!*@* a
* /SILENCE +*!*@* px
*
* example that blocks all invites except from channel services
* /SILENCE +*!*@* i
* /SILENCE +chanserv!services@chatters.net ix
*
* example that blocks some bad dude from private, notice and inviting you
* /SILENCE +*!kiddie@lamerz.net pin
*
* TODO: possibly have add and remove check for existing host and only modify flags according to
* what's been changed instead of having to remove first, then add if you want to change
* an entry.
*/
// pair of hostmask and flags
typedef std::pair<std::string, int> silenceset;
// deque list of pairs
typedef std::deque<silenceset> silencelist;
// intmasks for flags
static int SILENCE_PRIVATE = 0x0001; /* p private messages */
static int SILENCE_CHANNEL = 0x0002; /* c channel messages */
static int SILENCE_INVITE = 0x0004; /* i invites */
static int SILENCE_NOTICE = 0x0008; /* n notices */
static int SILENCE_CNOTICE = 0x0010; /* t channel notices */
static int SILENCE_ALL = 0x0020; /* a all, (pcint) */
static int SILENCE_EXCLUDE = 0x0040; /* x exclude this pattern */
class cmd_silence : public command_t
{
unsigned int& maxsilence;
public:
cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max)
{
this->source = "m_silence_ext.so";
syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
if (!pcnt)
{
// no parameters, show the current silence list.
// Use Extensible::GetExt to fetch the silence list
silencelist* sl;
user->GetExt("silence_list", sl);
// if the user has a silence list associated with their user record, show it
if (sl)
{
for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
{
user->WriteServ("271 %s %s %s %s",user->nick, user->nick,c->first.c_str(), DecompPattern(c->second).c_str());
}
}
user->WriteServ("272 %s :End of Silence List",user->nick);
return CMD_LOCALONLY;
}
else if (pcnt > 0)
{
// one or more parameters, add or delete entry from the list (only the first parameter is used)
std::string mask = parameters[0] + 1;
char action = *parameters[0];
// Default is private and notice so clients do not break
int pattern = CompilePattern("pn");
// if pattern supplied, use it
if (pcnt > 1) {
pattern = CompilePattern(parameters[1]);
}
if (!mask.length())
{
// 'SILENCE +' or 'SILENCE -', assume *!*@*
mask = "*!*@*";
}
ModeParser::CleanMask(mask);
if (action == '-')
{
// fetch their silence list
silencelist* sl;
user->GetExt("silence_list", sl);
// does it contain any entries and does it exist?
if (sl)
{
for (silencelist::iterator i = sl->begin(); i != sl->end(); i++)
{
// search through for the item
irc::string listitem = i->first.c_str();
if (listitem == mask && i->second == pattern)
{
sl->erase(i);
user->WriteServ("950 %s %s :Removed %s %s from silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
if (!sl->size())
{
DELETE(sl);
user->Shrink("silence_list");
}
break;
}
}
}
user->WriteServ("952 %s %s :%s %s does not exist on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
}
else if (action == '+')
{
// fetch the user's current silence list
silencelist* sl;
user->GetExt("silence_list", sl);
// what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one.
if (!sl)
{
sl = new silencelist;
user->Extend("silence_list", sl);
}
if (sl->size() > maxsilence)
{
user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick);
return CMD_FAILURE;
}
for (silencelist::iterator n = sl->begin(); n != sl->end(); n++)
{
irc::string listitem = n->first.c_str();
if (listitem == mask && n->second == pattern)
{
user->WriteServ("952 %s %s :%s %s is already on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
return CMD_FAILURE;
}
}
if (((pattern & SILENCE_EXCLUDE) > 0))
{
sl->push_front(silenceset(mask,pattern));
}
else
{
sl->push_back(silenceset(mask,pattern));
}
user->WriteServ("951 %s %s :Added %s %s to silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
return CMD_LOCALONLY;
}
}
return CMD_LOCALONLY;
}
/* turn the nice human readable pattern into a mask */
int CompilePattern(const char* pattern)
{
int p = 0;
for (const char* n = pattern; *n; n++)
{
switch (*n)
{
case 'p':
p |= SILENCE_PRIVATE;
break;
case 'c':
p |= SILENCE_CHANNEL;
break;
case 'i':
p |= SILENCE_INVITE;
break;
case 'n':
p |= SILENCE_NOTICE;
break;
case 't':
p |= SILENCE_CNOTICE;
break;
case 'a':
p |= SILENCE_ALL;
break;
case 'x':
p |= SILENCE_EXCLUDE;
break;
default:
break;
}
}
return p;
}
/* turn the mask into a nice human readable format */
std::string DecompPattern (const int pattern)
{
std::string out;
if ((pattern & SILENCE_PRIVATE) > 0)
out += ",privatemessages";
if ((pattern & SILENCE_CHANNEL) > 0)
out += ",channelmessages";
if ((pattern & SILENCE_INVITE) > 0)
out += ",invites";
if ((pattern & SILENCE_NOTICE) > 0)
out += ",privatenotices";
if ((pattern & SILENCE_CNOTICE) > 0)
out += ",channelnotices";
if ((pattern & SILENCE_ALL) > 0)
out = ",all";
if ((pattern & SILENCE_EXCLUDE) > 0)
out += ",exclude";
return "<" + out.substr(1) + ">";
}
};
class ModuleSilence : public Module
{
cmd_silence* mycommand;
unsigned int maxsilence;
public:
ModuleSilence(InspIRCd* Me)
: Module(Me), maxsilence(32)
{
OnRehash(NULL, "");
mycommand = new cmd_silence(ServerInstance,maxsilence);
ServerInstance->AddCommand(mycommand);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);
if (!maxsilence)
maxsilence = 32;
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnBuildExemptList] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = List[I_OnUserPreInvite] = 1;
}
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
// when the user quits tidy up any silence list they might have just to keep things tidy
silencelist* sl;
user->GetExt("silence_list", sl);
if (sl)
{
DELETE(sl);
user->Shrink("silence_list");
}
}
virtual void On005Numeric(std::string &output)
{
// we don't really have a limit...
output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence);
}
virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list)
{
int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE);
CUList *ulist;
switch (status)
{
case '@':
ulist = chan->GetOppedUsers();
break;
case '%':
ulist = chan->GetHalfoppedUsers();
break;
case '+':
ulist = chan->GetVoicedUsers();
break;
default:
ulist = chan->GetUsers();
break;
}
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
if (IS_LOCAL(i->first))
{
if (MatchPattern(i->first, sender, public_silence) == 1)
{
exempt_list[i->first] = i->first->nick;
}
}
}
}
virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type)
{
if (!IS_LOCAL(user))
return 0;
if (target_type == TYPE_USER)
{
return MatchPattern((userrec*)dest, user, silence_type);
}
else if (target_type == TYPE_CHANNEL)
{
chanrec* chan = (chanrec*)dest;
if (chan)
{
this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list);
}
}
return 0;
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE);
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE);
}
virtual int OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel)
{
return MatchPattern(dest, source, SILENCE_INVITE);
}
int MatchPattern(userrec* dest, userrec* source, int pattern)
{
silencelist* sl;
dest->GetExt("silence_list", sl);
if (sl)
{
for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
{
if (((((c->second & pattern) > 0)) || ((c->second & SILENCE_ALL) > 0)) && (ServerInstance->MatchText(source->GetFullHost(), c->first)))
return !(((c->second & SILENCE_EXCLUDE) > 0));
}
}
return 0;
}
virtual ~ModuleSilence()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSilence)
\ No newline at end of file diff --git a/src/modules/m_spanningtree/README b/src/modules/m_spanningtree/README index ff23e0381..76c678c1f 100644 --- a/src/modules/m_spanningtree/README +++ b/src/modules/m_spanningtree/README @@ -1,24 +1 @@ -m_spanningtree --------------- - -This directory contains all files required to build the m_spanningtree.so module. -Directories like this one starting with m_ and containing .cpp files are aggregated -together by the makefile to form a single .so, with the same name as the directory. - -This directory contains the following files: - -* handshaketimer.cpp Code for detecting end of ziplink/ssl handshake -* handshaketimer.h Header for above code -* link.h Contains the definition of the Link block class -* main.cpp The main group of classes and code for the module class -* main.h The header for the main file -* resolvers.h The header file that defines certain DNS utility classes -* treesocket.cpp Contains code that inherits InspSocket into a server socket -* treesocket.h Header definitions for above code -* treeserver.cpp Contains code that defines the behaviour of a single server -* treeserver.h Header definitions for above code -* utils.cpp Contains general and message routing utility classes -* utils.h Header code for general and message routing utilities - -Have fun - -- Brain :-) +m_spanningtree
--------------
This directory contains all files required to build the m_spanningtree.so module.
Directories like this one starting with m_ and containing .cpp files are aggregated
together by the makefile to form a single .so, with the same name as the directory.
This directory contains the following files:
* handshaketimer.cpp Code for detecting end of ziplink/ssl handshake
* handshaketimer.h Header for above code
* link.h Contains the definition of the Link block class
* main.cpp The main group of classes and code for the module class
* main.h The header for the main file
* resolvers.h The header file that defines certain DNS utility classes
* treesocket.cpp Contains code that inherits InspSocket into a server socket
* treesocket.h Header definitions for above code
* treeserver.cpp Contains code that defines the behaviour of a single server
* treeserver.h Header definitions for above code
* utils.cpp Contains general and message routing utility classes
* utils.h Header code for general and message routing utilities
Have fun
-- Brain :-)
\ No newline at end of file diff --git a/src/modules/m_spanningtree/handshaketimer.cpp b/src/modules/m_spanningtree/handshaketimer.cpp index 4aeb1da88..93856f467 100644 --- a/src/modules/m_spanningtree/handshaketimer.cpp +++ b/src/modules/m_spanningtree/handshaketimer.cpp @@ -1,62 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" -#include "m_spanningtree/handshaketimer.h" - -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */ - -HandshakeTimer::HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay) : InspTimer(delay, time(NULL)), Instance(Inst), sock(s), lnk(l), Utils(u) -{ - thefd = sock->GetFd(); -} - -void HandshakeTimer::Tick(time_t TIME) -{ - if (Instance->SE->GetRef(thefd) == sock) - { - if (!sock->GetHook()) - { - sock->SendCapabilities(); - } - else - { - if (sock->GetHook() && InspSocketHSCompleteRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send()) - { - InspSocketAttachCertRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send(); - sock->SendCapabilities(); - } - else - { - Instance->Timers->AddTimer(new HandshakeTimer(Instance, sock, lnk, Utils, 1)); - } - } - } -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/handshaketimer.h"
/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
HandshakeTimer::HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay) : InspTimer(delay, time(NULL)), Instance(Inst), sock(s), lnk(l), Utils(u)
{
thefd = sock->GetFd();
}
void HandshakeTimer::Tick(time_t TIME)
{
if (Instance->SE->GetRef(thefd) == sock)
{
if (!sock->GetHook())
{
sock->SendCapabilities();
}
else
{
if (sock->GetHook() && InspSocketHSCompleteRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send())
{
InspSocketAttachCertRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send();
sock->SendCapabilities();
}
else
{
Instance->Timers->AddTimer(new HandshakeTimer(Instance, sock, lnk, Utils, 1));
}
}
}
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/handshaketimer.h b/src/modules/m_spanningtree/handshaketimer.h index 496102dda..e94fe67d7 100644 --- a/src/modules/m_spanningtree/handshaketimer.h +++ b/src/modules/m_spanningtree/handshaketimer.h @@ -1,37 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __HANDSHAKE_TIMER_H__ -#define __HANDSHAKE_TIMER_H__ - -#include "inspircd.h" -#include "timer.h" - -class SpanningTreeUtilities; -class TreeSocket; -class Link; - -class HandshakeTimer : public InspTimer -{ - private: - InspIRCd* Instance; - TreeSocket* sock; - Link* lnk; - SpanningTreeUtilities* Utils; - int thefd; - public: - HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay); - virtual void Tick(time_t TIME); -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __HANDSHAKE_TIMER_H__
#define __HANDSHAKE_TIMER_H__
#include "inspircd.h"
#include "timer.h"
class SpanningTreeUtilities;
class TreeSocket;
class Link;
class HandshakeTimer : public InspTimer
{
private:
InspIRCd* Instance;
TreeSocket* sock;
Link* lnk;
SpanningTreeUtilities* Utils;
int thefd;
public:
HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay);
virtual void Tick(time_t TIME);
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/link.h b/src/modules/m_spanningtree/link.h index 3de326153..9636d565f 100644 --- a/src/modules/m_spanningtree/link.h +++ b/src/modules/m_spanningtree/link.h @@ -1,42 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __LINK_H__ -#define __LINK_H__ - -/** The Link class might as well be a struct, - * but this is C++ and we don't believe in structs (!). - * It holds the entire information of one <link> - * tag from the main config file. We maintain a list - * of them, and populate the list on rehash/load. - */ -class Link : public classbase -{ - public: - irc::string Name; - std::string IPAddr; - int Port; - std::string SendPass; - std::string RecvPass; - std::string AllowMask; - unsigned long AutoConnect; - time_t NextConnectTime; - bool HiddenFromStats; - std::string FailOver; - std::string Hook; - int Timeout; - std::string Bind; - bool Hidden; -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __LINK_H__
#define __LINK_H__
/** The Link class might as well be a struct,
* but this is C++ and we don't believe in structs (!).
* It holds the entire information of one <link>
* tag from the main config file. We maintain a list
* of them, and populate the list on rehash/load.
*/
class Link : public classbase
{
public:
irc::string Name;
std::string IPAddr;
int Port;
std::string SendPass;
std::string RecvPass;
std::string AllowMask;
unsigned long AutoConnect;
time_t NextConnectTime;
bool HiddenFromStats;
std::string FailOver;
std::string Hook;
int Timeout;
std::string Bind;
bool Hidden;
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 1cc18dae6..352cae870 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -1,1392 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Provides a spanning tree server link protocol */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/timesynctimer.h" -#include "m_spanningtree/resolvers.h" -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" -#include "m_spanningtree/rconnect.h" -#include "m_spanningtree/rsquit.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */ - -ModuleSpanningTree::ModuleSpanningTree(InspIRCd* Me) - : Module(Me), max_local(0), max_global(0) -{ - ServerInstance->UseInterface("InspSocketHook"); - Utils = new SpanningTreeUtilities(Me, this); - command_rconnect = new cmd_rconnect(ServerInstance, this, Utils); - ServerInstance->AddCommand(command_rconnect); - command_rsquit = new cmd_rsquit(ServerInstance, this, Utils); - ServerInstance->AddCommand(command_rsquit); - if (Utils->EnableTimeSync) - { - SyncTimer = new TimeSyncTimer(ServerInstance, this); - ServerInstance->Timers->AddTimer(SyncTimer); - } - else - SyncTimer = NULL; - - RefreshTimer = new CacheRefreshTimer(ServerInstance, Utils); - ServerInstance->Timers->AddTimer(RefreshTimer); -} - -void ModuleSpanningTree::ShowLinks(TreeServer* Current, userrec* user, int hops) -{ - std::string Parent = Utils->TreeRoot->GetName(); - if (Current->GetParent()) - { - Parent = Current->GetParent()->GetName(); - } - for (unsigned int q = 0; q < Current->ChildCount(); q++) - { - if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str())))) - { - if (*user->oper) - { - ShowLinks(Current->GetChild(q),user,hops+1); - } - } - else - { - ShowLinks(Current->GetChild(q),user,hops+1); - } - } - /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */ - if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName().c_str())) && (!IS_OPER(user))) - return; - /* Or if the server is hidden and they're not an oper */ - else if ((Current->Hidden) && (!IS_OPER(user))) - return; - - user->WriteServ("364 %s %s %s :%d %s", user->nick,Current->GetName().c_str(), - (Utils->FlatLinks && (!IS_OPER(user))) ? ServerInstance->Config->ServerName : Parent.c_str(), - (Utils->FlatLinks && (!IS_OPER(user))) ? 0 : hops, - Current->GetDesc().c_str()); -} - -int ModuleSpanningTree::CountLocalServs() -{ - return Utils->TreeRoot->ChildCount(); -} - -int ModuleSpanningTree::CountServs() -{ - return Utils->serverlist.size(); -} - -void ModuleSpanningTree::HandleLinks(const char** parameters, int pcnt, userrec* user) -{ - ShowLinks(Utils->TreeRoot,user,0); - user->WriteServ("365 %s * :End of /LINKS list.",user->nick); - return; -} - -void ModuleSpanningTree::HandleLusers(const char** parameters, int pcnt, userrec* user) -{ - unsigned int n_users = ServerInstance->UserCount(); - - /* Only update these when someone wants to see them, more efficient */ - if ((unsigned int)ServerInstance->LocalUserCount() > max_local) - max_local = ServerInstance->LocalUserCount(); - if (n_users > max_global) - max_global = n_users; - - unsigned int ulined_count = 0; - unsigned int ulined_local_count = 0; - - /* If ulined are hidden and we're not an oper, count the number of ulined servers hidden, - * locally and globally (locally means directly connected to us) - */ - if ((Utils->HideULines) && (!*user->oper)) - { - for (server_hash::iterator q = Utils->serverlist.begin(); q != Utils->serverlist.end(); q++) - { - if (ServerInstance->ULine(q->second->GetName().c_str())) - { - ulined_count++; - if (q->second->GetParent() == Utils->TreeRoot) - ulined_local_count++; - } - } - } - user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount(),ulined_count ? this->CountServs() - ulined_count : this->CountServs()); - if (ServerInstance->OperCount()) - user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount()); - if (ServerInstance->UnregisteredUserCount()) - user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount()); - if (ServerInstance->ChannelCount()) - user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount()); - user->WriteServ("255 %s :I have %d clients and %d servers",user->nick,ServerInstance->LocalUserCount(),ulined_local_count ? this->CountLocalServs() - ulined_local_count : this->CountLocalServs()); - user->WriteServ("265 %s :Current Local Users: %d Max: %d",user->nick,ServerInstance->LocalUserCount(),max_local); - user->WriteServ("266 %s :Current Global Users: %d Max: %d",user->nick,n_users,max_global); - return; -} - -std::string ModuleSpanningTree::TimeToStr(time_t secs) -{ - time_t mins_up = secs / 60; - time_t hours_up = mins_up / 60; - time_t days_up = hours_up / 24; - secs = secs % 60; - mins_up = mins_up % 60; - hours_up = hours_up % 24; - return ((days_up ? (ConvToStr(days_up) + "d") : std::string("")) - + (hours_up ? (ConvToStr(hours_up) + "h") : std::string("")) - + (mins_up ? (ConvToStr(mins_up) + "m") : std::string("")) - + ConvToStr(secs) + "s"); -} - -const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current) -{ - time_t secs_up = ServerInstance->Time() - Current->age; - return (" [Up: " + TimeToStr(secs_up) + " Lag: "+ConvToStr(Current->rtt)+"s]"); -} - -// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS. -void ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers) -{ - if (line < 128) - { - for (int t = 0; t < depth; t++) - { - matrix[line][t] = ' '; - } - // For Aligning, we need to work out exactly how deep this thing is, and produce - // a 'Spacer' String to compensate. - char spacer[40]; - memset(spacer,' ',40); - if ((40 - Current->GetName().length() - depth) > 1) { - spacer[40 - Current->GetName().length() - depth] = '\0'; - } - else - { - spacer[5] = '\0'; - } - float percent; - char text[128]; - /* Neat and tidy default values, as we're dealing with a matrix not a simple string */ - memset(text, 0, 128); - - if (ServerInstance->clientlist->size() == 0) { - // If there are no users, WHO THE HELL DID THE /MAP?!?!?! - percent = 0; - } - else - { - percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100; - } - const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : ""; - snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str()); - totusers += Current->GetUserCount(); - totservers++; - strlcpy(&matrix[line][depth],text,126); - line++; - for (unsigned int q = 0; q < Current->ChildCount(); q++) - { - if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str())))) - { - if (*user->oper) - { - ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); - } - } - else - { - ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); - } - } - } -} - -int ModuleSpanningTree::HandleMotd(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - /* Remote MOTD, the server is within the 1st parameter */ - std::deque<std::string> params; - params.push_back(parameters[0]); - /* Send it out remotely, generate no reply yet */ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->nick, "MOTD", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleAdmin(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - /* Remote ADMIN, the server is within the 1st parameter */ - std::deque<std::string> params; - params.push_back(parameters[0]); - /* Send it out remotely, generate no reply yet */ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->nick, "ADMIN", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleModules(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - std::deque<std::string> params; - params.push_back(parameters[0]); - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->nick, "MODULES", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 1) - { - if (match(ServerInstance->Config->ServerName, parameters[1])) - return 0; - - /* Remote STATS, the server is within the 2nd parameter */ - std::deque<std::string> params; - params.push_back(parameters[0]); - params.push_back(parameters[1]); - /* Send it out remotely, generate no reply yet */ - - TreeServer* s = Utils->FindServerMask(parameters[1]); - if (s) - { - params[1] = s->GetName(); - Utils->DoOneToOne(user->nick, "STATS", params, s->GetName()); - } - else - { - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]); - } - return 1; - } - return 0; -} - -// Ok, prepare to be confused. -// After much mulling over how to approach this, it struck me that -// the 'usual' way of doing a /MAP isnt the best way. Instead of -// keeping track of a ton of ascii characters, and line by line -// under recursion working out where to place them using multiplications -// and divisons, we instead render the map onto a backplane of characters -// (a character matrix), then draw the branches as a series of "L" shapes -// from the nodes. This is not only friendlier on CPU it uses less stack. -void ModuleSpanningTree::HandleMap(const char** parameters, int pcnt, userrec* user) -{ - // This array represents a virtual screen which we will - // "scratch" draw to, as the console device of an irc - // client does not provide for a proper terminal. - float totusers = 0; - float totservers = 0; - char matrix[128][128]; - for (unsigned int t = 0; t < 128; t++) - { - matrix[t][0] = '\0'; - } - line = 0; - // The only recursive bit is called here. - ShowMap(Utils->TreeRoot,user,0,matrix,totusers,totservers); - // Process each line one by one. The algorithm has a limit of - // 128 servers (which is far more than a spanning tree should have - // anyway, so we're ok). This limit can be raised simply by making - // the character matrix deeper, 128 rows taking 10k of memory. - for (int l = 1; l < line; l++) - { - // scan across the line looking for the start of the - // servername (the recursive part of the algorithm has placed - // the servers at indented positions depending on what they - // are related to) - int first_nonspace = 0; - while (matrix[l][first_nonspace] == ' ') - { - first_nonspace++; - } - first_nonspace--; - // Draw the `- (corner) section: this may be overwritten by - // another L shape passing along the same vertical pane, becoming - // a |- (branch) section instead. - matrix[l][first_nonspace] = '-'; - matrix[l][first_nonspace-1] = '`'; - int l2 = l - 1; - // Draw upwards until we hit the parent server, causing possibly - // other corners (`-) to become branches (|-) - while ((matrix[l2][first_nonspace-1] == ' ') || (matrix[l2][first_nonspace-1] == '`')) - { - matrix[l2][first_nonspace-1] = '|'; - l2--; - } - } - // dump the whole lot to the user. This is the easy bit, honest. - for (int t = 0; t < line; t++) - { - user->WriteServ("006 %s :%s",user->nick,&matrix[t][0]); - } - float avg_users = totusers / totservers; - user->WriteServ("270 %s :%.0f server%s and %.0f user%s, average %.2f users per server",user->nick,totservers,(totservers > 1 ? "s" : ""),totusers,(totusers > 1 ? "s" : ""),avg_users); - user->WriteServ("007 %s :End of /MAP",user->nick); - return; -} - -int ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user) -{ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - if (s == Utils->TreeRoot) - { - user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]); - return 1; - } - TreeSocket* sock = s->GetSocket(); - if (sock) - { - ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); - sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost()); - ServerInstance->SE->DelFd(sock); - sock->Close(); - } - else - { - if (IS_LOCAL(user)) - user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick); - } - } - else - { - user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]); - } - return 1; -} - -int ModuleSpanningTree::HandleTime(const char** parameters, int pcnt, userrec* user) -{ - if ((IS_LOCAL(user)) && (pcnt)) - { - TreeServer* found = Utils->FindServerMask(parameters[0]); - if (found) - { - // we dont' override for local server - if (found == Utils->TreeRoot) - return 0; - - std::deque<std::string> params; - params.push_back(found->GetName()); - params.push_back(user->nick); - Utils->DoOneToOne(ServerInstance->Config->ServerName,"TIME",params,found->GetName()); - } - else - { - user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]); - } - } - return 1; -} - -int ModuleSpanningTree::HandleRemoteWhois(const char** parameters, int pcnt, userrec* user) -{ - if ((IS_LOCAL(user)) && (pcnt > 1)) - { - userrec* remote = ServerInstance->FindNick(parameters[1]); - if ((remote) && (remote->GetFd() < 0)) - { - std::deque<std::string> params; - params.push_back(parameters[1]); - Utils->DoOneToOne(user->nick,"IDLE",params,remote->server); - return 1; - } - else if (!remote) - { - user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]); - user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, parameters[1]); - return 1; - } - } - return 0; -} - -void ModuleSpanningTree::DoPingChecks(time_t curtime) -{ - for (unsigned int j = 0; j < Utils->TreeRoot->ChildCount(); j++) - { - TreeServer* serv = Utils->TreeRoot->GetChild(j); - TreeSocket* sock = serv->GetSocket(); - if (sock) - { - if (curtime >= serv->NextPingTime()) - { - if (serv->AnsweredLastPing()) - { - sock->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" PING "+serv->GetName()); - serv->SetNextPingTime(curtime + 60); - serv->LastPing = curtime; - serv->Warned = false; - } - else - { - /* they didnt answer, boot them */ - sock->SendError("Ping timeout"); - sock->Squit(serv,"Ping timeout"); - /*** XXX SOCKET CULL ***/ - return; - } - } - else if ((Utils->PingWarnTime) && (!serv->Warned) && (curtime >= serv->NextPingTime() - (60 - Utils->PingWarnTime)) && (!serv->AnsweredLastPing())) - { - /* The server hasnt responded, send a warning to opers */ - ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", serv->GetName().c_str(), Utils->PingWarnTime); - serv->Warned = true; - } - } - } - - /* Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data. - * This prevents lost REMOTECONNECT notices - */ - for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++) - Utils->SetRemoteBursting(i->second, false); -} - -void ModuleSpanningTree::ConnectServer(Link* x) -{ - bool ipvalid = true; - QueryType start_type = DNS_QUERY_A; -#ifdef IPV6 - start_type = DNS_QUERY_AAAA; - if (strchr(x->IPAddr.c_str(),':')) - { - in6_addr n; - if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1) - ipvalid = false; - } - else -#endif - { - in_addr n; - if (inet_aton(x->IPAddr.c_str(),&n) < 1) - ipvalid = false; - } - - /* Do we already have an IP? If so, no need to resolve it. */ - if (ipvalid) - { - /* Gave a hook, but it wasnt one we know */ - if ((!x->Hook.empty()) && (Utils->hooks.find(x->Hook.c_str()) == Utils->hooks.end())) - return; - TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port,false,x->Timeout ? x->Timeout : 10,x->Name.c_str(), x->Bind, x->Hook.empty() ? NULL : Utils->hooks[x->Hook.c_str()]); - if (newsocket->GetFd() > -1) - { - /* Handled automatically on success */ - } - else - { - ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno)); - delete newsocket; - Utils->DoFailOver(x); - } - } - else - { - try - { - bool cached; - ServernameResolver* snr = new ServernameResolver((Module*)this, Utils, ServerInstance,x->IPAddr, *x, cached, start_type); - ServerInstance->AddResolver(snr, cached); - } - catch (ModuleException& e) - { - ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason()); - Utils->DoFailOver(x); - } - } -} - -void ModuleSpanningTree::AutoConnectServers(time_t curtime) -{ - for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++) - { - if ((x->AutoConnect) && (curtime >= x->NextConnectTime)) - { - x->NextConnectTime = curtime + x->AutoConnect; - TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str()); - if (x->FailOver.length()) - { - TreeServer* CheckFailOver = Utils->FindServer(x->FailOver.c_str()); - if (CheckFailOver) - { - /* The failover for this server is currently a member of the network. - * The failover probably succeeded, where the main link did not. - * Don't try the main link until the failover is gone again. - */ - continue; - } - } - if (!CheckDupe) - { - // an autoconnected server is not connected. Check if its time to connect it - ServerInstance->SNO->WriteToSnoMask('l',"AUTOCONNECT: Auto-connecting server \002%s\002 (%lu seconds until next attempt)",x->Name.c_str(),x->AutoConnect); - this->ConnectServer(&(*x)); - } - } - } -} - -int ModuleSpanningTree::HandleVersion(const char** parameters, int pcnt, userrec* user) -{ - // we've already checked if pcnt > 0, so this is safe - TreeServer* found = Utils->FindServerMask(parameters[0]); - if (found) - { - std::string Version = found->GetVersion(); - user->WriteServ("351 %s :%s",user->nick,Version.c_str()); - if (found == Utils->TreeRoot) - { - ServerInstance->Config->Send005(user); - } - } - else - { - user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]); - } - return 1; -} - -int ModuleSpanningTree::HandleConnect(const char** parameters, int pcnt, userrec* user) -{ - for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++) - { - if (ServerInstance->MatchText(x->Name.c_str(),parameters[0])) - { - TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str()); - if (!CheckDupe) - { - user->WriteServ("NOTICE %s :*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",user->nick,x->Name.c_str(),(x->HiddenFromStats ? "<hidden>" : x->IPAddr.c_str()),x->Port); - ConnectServer(&(*x)); - return 1; - } - else - { - user->WriteServ("NOTICE %s :*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002",user->nick,x->Name.c_str(),CheckDupe->GetParent()->GetName().c_str()); - return 1; - } - } - } - user->WriteServ("NOTICE %s :*** CONNECT: No server matching \002%s\002 could be found in the config file.",user->nick,parameters[0]); - return 1; -} - -void ModuleSpanningTree::BroadcastTimeSync() -{ - if (Utils->MasterTime) - { - std::deque<std::string> params; - params.push_back(ConvToStr(ServerInstance->Time(false))); - params.push_back("FORCE"); - Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params); - } -} - -int ModuleSpanningTree::OnStats(char statschar, userrec* user, string_list &results) -{ - if ((statschar == 'c') || (statschar == 'n')) - { - for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++) - { - results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].Hook.empty() ? "plaintext" : Utils->LinkBlocks[i].Hook)+" "+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s'); - if (statschar == 'c') - results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str()); - } - results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); - ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host); - return 1; - } - - if (statschar == 'p') - { - /* show all server ports, after showing client ports. -- w00t */ - - for (unsigned int i = 0; i < Utils->Bindings.size(); i++) - { - std::string ip = Utils->Bindings[i]->IP; - if (ip.empty()) - ip = "*"; - - std::string transport("plaintext"); - if (Utils->Bindings[i]->GetHook()) - transport = InspSocketNameRequest(this, Utils->Bindings[i]->GetHook()).Send(); - - results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->port)+ - " (server, " + transport + ")"); - } - } - return 0; -} - -int ModuleSpanningTree::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) -{ - /* If the command doesnt appear to be valid, we dont want to mess with it. */ - if (!validated) - return 0; - - if (command == "CONNECT") - { - return this->HandleConnect(parameters,pcnt,user); - } - else if (command == "STATS") - { - return this->HandleStats(parameters,pcnt,user); - } - else if (command == "MOTD") - { - return this->HandleMotd(parameters,pcnt,user); - } - else if (command == "ADMIN") - { - return this->HandleAdmin(parameters,pcnt,user); - } - else if (command == "SQUIT") - { - return this->HandleSquit(parameters,pcnt,user); - } - else if (command == "MAP") - { - this->HandleMap(parameters,pcnt,user); - return 1; - } - else if ((command == "TIME") && (pcnt > 0)) - { - return this->HandleTime(parameters,pcnt,user); - } - else if (command == "LUSERS") - { - this->HandleLusers(parameters,pcnt,user); - return 1; - } - else if (command == "LINKS") - { - this->HandleLinks(parameters,pcnt,user); - return 1; - } - else if (command == "WHOIS") - { - if (pcnt > 1) - { - // remote whois - return this->HandleRemoteWhois(parameters,pcnt,user); - } - } - else if ((command == "VERSION") && (pcnt > 0)) - { - this->HandleVersion(parameters,pcnt,user); - return 1; - } - else if ((command == "MODULES") && (pcnt > 0)) - { - return this->HandleModules(parameters,pcnt,user); - } - return 0; -} - -void ModuleSpanningTree::OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line) -{ - if ((result == CMD_SUCCESS) && (ServerInstance->IsValidModuleCommand(command, pcnt, user))) - { - // this bit of code cleverly routes all module commands - // to all remote severs *automatically* so that modules - // can just handle commands locally, without having - // to have any special provision in place for remote - // commands and linking protocols. - std::deque<std::string> params; - params.clear(); - for (int j = 0; j < pcnt; j++) - { - if (strchr(parameters[j],' ')) - { - params.push_back(":" + std::string(parameters[j])); - } - else - { - params.push_back(std::string(parameters[j])); - } - } - Utils->DoOneToMany(user->nick,command,params); - } -} - -void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description) -{ - TreeServer* s = Utils->FindServer(servername); - if (s) - { - description = s->GetDesc(); - } -} - -void ModuleSpanningTree::OnUserInvite(userrec* source,userrec* dest,chanrec* channel) -{ - if (IS_LOCAL(source)) - { - std::deque<std::string> params; - params.push_back(dest->nick); - params.push_back(channel->name); - Utils->DoOneToMany(source->nick,"INVITE",params); - } -} - -void ModuleSpanningTree::OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic) -{ - std::deque<std::string> params; - params.push_back(chan->name); - params.push_back(":"+topic); - Utils->DoOneToMany(user->nick,"TOPIC",params); -} - -void ModuleSpanningTree::OnWallops(userrec* user, const std::string &text) -{ - if (IS_LOCAL(user)) - { - std::deque<std::string> params; - params.push_back(":"+text); - Utils->DoOneToMany(user->nick,"WALLOPS",params); - } -} - -void ModuleSpanningTree::OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) -{ - if (target_type == TYPE_USER) - { - userrec* d = (userrec*)dest; - if ((d->GetFd() < 0) && (IS_LOCAL(user))) - { - std::deque<std::string> params; - params.clear(); - params.push_back(d->nick); - params.push_back(":"+text); - Utils->DoOneToOne(user->nick,"NOTICE",params,d->server); - } - } - else if (target_type == TYPE_CHANNEL) - { - if (IS_LOCAL(user)) - { - chanrec *c = (chanrec*)dest; - if (c) - { - std::string cname = c->name; - if (status) - cname = status + cname; - TreeServerList list; - Utils->GetListOfServersForChannel(c,list,status,exempt_list); - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if (Sock) - Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text); - } - } - } - } - else if (target_type == TYPE_SERVER) - { - if (IS_LOCAL(user)) - { - char* target = (char*)dest; - std::deque<std::string> par; - par.push_back(target); - par.push_back(":"+text); - Utils->DoOneToMany(user->nick,"NOTICE",par); - } - } -} - -void ModuleSpanningTree::OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) -{ - if (target_type == TYPE_USER) - { - // route private messages which are targetted at clients only to the server - // which needs to receive them - userrec* d = (userrec*)dest; - if ((d->GetFd() < 0) && (IS_LOCAL(user))) - { - std::deque<std::string> params; - params.clear(); - params.push_back(d->nick); - params.push_back(":"+text); - Utils->DoOneToOne(user->nick,"PRIVMSG",params,d->server); - } - } - else if (target_type == TYPE_CHANNEL) - { - if (IS_LOCAL(user)) - { - chanrec *c = (chanrec*)dest; - if (c) - { - std::string cname = c->name; - if (status) - cname = status + cname; - TreeServerList list; - Utils->GetListOfServersForChannel(c,list,status,exempt_list); - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if (Sock) - Sock->WriteLine(":"+std::string(user->nick)+" PRIVMSG "+cname+" :"+text); - } - } - } - } - else if (target_type == TYPE_SERVER) - { - if (IS_LOCAL(user)) - { - char* target = (char*)dest; - std::deque<std::string> par; - par.push_back(target); - par.push_back(":"+text); - Utils->DoOneToMany(user->nick,"PRIVMSG",par); - } - } -} - -void ModuleSpanningTree::OnBackgroundTimer(time_t curtime) -{ - AutoConnectServers(curtime); - DoPingChecks(curtime); -} - -void ModuleSpanningTree::OnUserJoin(userrec* user, chanrec* channel, bool &silent) -{ - // Only do this for local users - if (IS_LOCAL(user)) - { - if (channel->GetUserCounter() == 1) - { - std::deque<std::string> params; - // set up their permissions and the channel TS with FJOIN. - // All users are FJOINed now, because a module may specify - // new joining permissions for the user. - params.push_back(channel->name); - params.push_back(ConvToStr(channel->age)); - params.push_back(std::string(channel->GetAllPrefixChars(user))+","+std::string(user->nick)); - Utils->DoOneToMany(ServerInstance->Config->ServerName,"FJOIN",params); - /* First user in, sync the modes for the channel */ - params.pop_back(); - params.push_back(channel->ChanModes(true)); - Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",params); - } - else - { - std::deque<std::string> params; - params.push_back(channel->name); - params.push_back(ConvToStr(channel->age)); - Utils->DoOneToMany(user->nick,"JOIN",params); - } - } -} - -void ModuleSpanningTree::OnChangeHost(userrec* user, const std::string &newhost) -{ - // only occurs for local clients - if (user->registered != REG_ALL) - return; - std::deque<std::string> params; - params.push_back(newhost); - Utils->DoOneToMany(user->nick,"FHOST",params); -} - -void ModuleSpanningTree::OnChangeName(userrec* user, const std::string &gecos) -{ - // only occurs for local clients - if (user->registered != REG_ALL) - return; - std::deque<std::string> params; - params.push_back(gecos); - Utils->DoOneToMany(user->nick,"FNAME",params); -} - -void ModuleSpanningTree::OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent) -{ - if (IS_LOCAL(user)) - { - std::deque<std::string> params; - params.push_back(channel->name); - if (!partmessage.empty()) - params.push_back(":"+partmessage); - Utils->DoOneToMany(user->nick,"PART",params); - } -} - -void ModuleSpanningTree::OnUserConnect(userrec* user) -{ - char agestr[MAXBUF]; - if (IS_LOCAL(user)) - { - std::deque<std::string> params; - snprintf(agestr,MAXBUF,"%lu",(unsigned long)user->age); - params.push_back(agestr); - params.push_back(user->nick); - params.push_back(user->host); - params.push_back(user->dhost); - params.push_back(user->ident); - params.push_back("+"+std::string(user->FormatModes())); - params.push_back(user->GetIPString()); - params.push_back(":"+std::string(user->fullname)); - Utils->DoOneToMany(ServerInstance->Config->ServerName,"NICK",params); - // User is Local, change needs to be reflected! - TreeServer* SourceServer = Utils->FindServer(user->server); - if (SourceServer) - { - SourceServer->AddUserCount(); - } - } -} - -void ModuleSpanningTree::OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) -{ - if ((IS_LOCAL(user)) && (user->registered == REG_ALL)) - { - std::deque<std::string> params; - - if (oper_message != reason) - { - params.push_back(":"+oper_message); - Utils->DoOneToMany(user->nick,"OPERQUIT",params); - } - params.clear(); - params.push_back(":"+reason); - Utils->DoOneToMany(user->nick,"QUIT",params); - } - // Regardless, We need to modify the user Counts.. - TreeServer* SourceServer = Utils->FindServer(user->server); - if (SourceServer) - { - SourceServer->DelUserCount(); - } -} - -void ModuleSpanningTree::OnUserPostNick(userrec* user, const std::string &oldnick) -{ - if (IS_LOCAL(user)) - { - std::deque<std::string> params; - params.push_back(user->nick); - Utils->DoOneToMany(oldnick,"NICK",params); - } -} - -void ModuleSpanningTree::OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent) -{ - if ((source) && (IS_LOCAL(source))) - { - std::deque<std::string> params; - params.push_back(chan->name); - params.push_back(user->nick); - params.push_back(":"+reason); - Utils->DoOneToMany(source->nick,"KICK",params); - } - else if (!source) - { - std::deque<std::string> params; - params.push_back(chan->name); - params.push_back(user->nick); - params.push_back(":"+reason); - Utils->DoOneToMany(ServerInstance->Config->ServerName,"KICK",params); - } -} - -void ModuleSpanningTree::OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason) -{ - std::deque<std::string> params; - params.push_back(":"+reason); - Utils->DoOneToMany(dest->nick,"OPERQUIT",params); - params.clear(); - params.push_back(dest->nick); - params.push_back(":"+reason); - dest->SetOperQuit(operreason); - Utils->DoOneToMany(source->nick,"KILL",params); -} - -void ModuleSpanningTree::OnRehash(userrec* user, const std::string ¶meter) -{ - if (!parameter.empty()) - { - std::deque<std::string> params; - params.push_back(parameter); - Utils->DoOneToMany(user ? user->nick : ServerInstance->Config->ServerName, "REHASH", params); - // check for self - if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameter)) - { - ServerInstance->WriteOpers("*** Remote rehash initiated locally by \002%s\002", user ? user->nick : ServerInstance->Config->ServerName); - ServerInstance->RehashServer(); - } - } - Utils->ReadConfiguration(false); - InitializeDisabledCommands(ServerInstance->Config->DisabledCommands, ServerInstance); -} - -// note: the protocol does not allow direct umode +o except -// via NICK with 8 params. sending OPERTYPE infers +o modechange -// locally. -void ModuleSpanningTree::OnOper(userrec* user, const std::string &opertype) -{ - if (IS_LOCAL(user)) - { - std::deque<std::string> params; - params.push_back(opertype); - Utils->DoOneToMany(user->nick,"OPERTYPE",params); - } -} - -void ModuleSpanningTree::OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason) -{ - if (!source) - { - /* Server-set lines */ - char data[MAXBUF]; - snprintf(data,MAXBUF,"%c %s %s %lu %lu :%s", linetype, host.c_str(), ServerInstance->Config->ServerName, (unsigned long)ServerInstance->Time(false), - (unsigned long)duration, reason.c_str()); - std::deque<std::string> params; - params.push_back(data); - Utils->DoOneToMany(ServerInstance->Config->ServerName, "ADDLINE", params); - } - else - { - if (IS_LOCAL(source)) - { - char type[8]; - snprintf(type,8,"%cLINE",linetype); - std::string stype = type; - if (adding) - { - char sduration[MAXBUF]; - snprintf(sduration,MAXBUF,"%ld",duration); - std::deque<std::string> params; - params.push_back(host); - params.push_back(sduration); - params.push_back(":"+reason); - Utils->DoOneToMany(source->nick,stype,params); - } - else - { - std::deque<std::string> params; - params.push_back(host); - Utils->DoOneToMany(source->nick,stype,params); - } - } - } -} - -void ModuleSpanningTree::OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) -{ - OnLine(source,hostmask,true,'G',duration,reason); -} - -void ModuleSpanningTree::OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask) -{ - OnLine(source,ipmask,true,'Z',duration,reason); -} - -void ModuleSpanningTree::OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask) -{ - OnLine(source,nickmask,true,'Q',duration,reason); -} - -void ModuleSpanningTree::OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) -{ - OnLine(source,hostmask,true,'E',duration,reason); -} - -void ModuleSpanningTree::OnDelGLine(userrec* source, const std::string &hostmask) -{ - OnLine(source,hostmask,false,'G',0,""); -} - -void ModuleSpanningTree::OnDelZLine(userrec* source, const std::string &ipmask) -{ - OnLine(source,ipmask,false,'Z',0,""); -} - -void ModuleSpanningTree::OnDelQLine(userrec* source, const std::string &nickmask) -{ - OnLine(source,nickmask,false,'Q',0,""); -} - -void ModuleSpanningTree::OnDelELine(userrec* source, const std::string &hostmask) -{ - OnLine(source,hostmask,false,'E',0,""); -} - -void ModuleSpanningTree::OnMode(userrec* user, void* dest, int target_type, const std::string &text) -{ - if ((IS_LOCAL(user)) && (user->registered == REG_ALL)) - { - std::deque<std::string> params; - std::string command; - - if (target_type == TYPE_USER) - { - userrec* u = (userrec*)dest; - params.push_back(u->nick); - params.push_back(text); - command = "MODE"; - } - else - { - chanrec* c = (chanrec*)dest; - params.push_back(c->name); - params.push_back(ConvToStr(c->age)); - params.push_back(text); - command = "FMODE"; - } - Utils->DoOneToMany(user->nick, command, params); - } -} - -void ModuleSpanningTree::OnSetAway(userrec* user) -{ - if (IS_LOCAL(user)) - { - std::deque<std::string> params; - params.push_back(":"+std::string(user->awaymsg)); - Utils->DoOneToMany(user->nick,"AWAY",params); - } -} - -void ModuleSpanningTree::OnCancelAway(userrec* user) -{ - if (IS_LOCAL(user)) - { - std::deque<std::string> params; - params.clear(); - Utils->DoOneToMany(user->nick,"AWAY",params); - } -} - -void ModuleSpanningTree::ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline) -{ - TreeSocket* s = (TreeSocket*)opaque; - if (target) - { - if (target_type == TYPE_USER) - { - userrec* u = (userrec*)target; - s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline); - } - else - { - chanrec* c = (chanrec*)target; - s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline); - } - } -} - -void ModuleSpanningTree::ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata) -{ - TreeSocket* s = (TreeSocket*)opaque; - if (target) - { - if (target_type == TYPE_USER) - { - userrec* u = (userrec*)target; - s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+u->nick+" "+extname+" :"+extdata); - } - else if (target_type == TYPE_CHANNEL) - { - chanrec* c = (chanrec*)target; - s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+c->name+" "+extname+" :"+extdata); - } - } - if (target_type == TYPE_OTHER) - { - s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA * "+extname+" :"+extdata); - } -} - -void ModuleSpanningTree::OnEvent(Event* event) -{ - std::deque<std::string>* params = (std::deque<std::string>*)event->GetData(); - if (event->GetEventID() == "send_metadata") - { - if (params->size() < 3) - return; - (*params)[2] = ":" + (*params)[2]; - Utils->DoOneToMany(ServerInstance->Config->ServerName,"METADATA",*params); - } - else if (event->GetEventID() == "send_topic") - { - if (params->size() < 2) - return; - (*params)[1] = ":" + (*params)[1]; - params->insert(params->begin() + 1,ServerInstance->Config->ServerName); - params->insert(params->begin() + 1,ConvToStr(ServerInstance->Time(true))); - Utils->DoOneToMany(ServerInstance->Config->ServerName,"FTOPIC",*params); - } - else if (event->GetEventID() == "send_mode") - { - if (params->size() < 2) - return; - // Insert the TS value of the object, either userrec or chanrec - time_t ourTS = 0; - userrec* a = ServerInstance->FindNick((*params)[0]); - if (a) - { - ourTS = a->age; - Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params); - return; - } - else - { - chanrec* a = ServerInstance->FindChan((*params)[0]); - if (a) - { - ourTS = a->age; - params->insert(params->begin() + 1,ConvToStr(ourTS)); - Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",*params); - } - } - } - else if (event->GetEventID() == "send_mode_explicit") - { - if (params->size() < 2) - return; - Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params); - } - else if (event->GetEventID() == "send_opers") - { - if (params->size() < 1) - return; - (*params)[0] = ":" + (*params)[0]; - Utils->DoOneToMany(ServerInstance->Config->ServerName,"OPERNOTICE",*params); - } - else if (event->GetEventID() == "send_modeset") - { - if (params->size() < 2) - return; - (*params)[1] = ":" + (*params)[1]; - Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODENOTICE",*params); - } - else if (event->GetEventID() == "send_snoset") - { - if (params->size() < 2) - return; - (*params)[1] = ":" + (*params)[1]; - Utils->DoOneToMany(ServerInstance->Config->ServerName,"SNONOTICE",*params); - } - else if (event->GetEventID() == "send_push") - { - if (params->size() < 2) - return; - - userrec *a = ServerInstance->FindNick((*params)[0]); - - if (!a) - return; - - (*params)[1] = ":" + (*params)[1]; - Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", *params, a->server); - } -} - -ModuleSpanningTree::~ModuleSpanningTree() -{ - /* This will also free the listeners */ - delete Utils; - if (SyncTimer) - ServerInstance->Timers->DelTimer(SyncTimer); - - ServerInstance->Timers->DelTimer(RefreshTimer); - - ServerInstance->DoneWithInterface("InspSocketHook"); -} - -Version ModuleSpanningTree::GetVersion() -{ - return Version(1,1,0,2,VF_VENDOR,API_VERSION); -} - -void ModuleSpanningTree::Implements(char* List) -{ - List[I_OnPreCommand] = List[I_OnGetServerDescription] = List[I_OnUserInvite] = List[I_OnPostLocalTopicChange] = 1; - List[I_OnWallops] = List[I_OnUserNotice] = List[I_OnUserMessage] = List[I_OnBackgroundTimer] = 1; - List[I_OnUserJoin] = List[I_OnChangeHost] = List[I_OnChangeName] = List[I_OnUserPart] = List[I_OnUserConnect] = 1; - List[I_OnUserQuit] = List[I_OnUserPostNick] = List[I_OnUserKick] = List[I_OnRemoteKill] = List[I_OnRehash] = 1; - List[I_OnOper] = List[I_OnAddGLine] = List[I_OnAddZLine] = List[I_OnAddQLine] = List[I_OnAddELine] = 1; - List[I_OnDelGLine] = List[I_OnDelZLine] = List[I_OnDelQLine] = List[I_OnDelELine] = List[I_ProtoSendMode] = List[I_OnMode] = 1; - List[I_OnStats] = List[I_ProtoSendMetaData] = List[I_OnEvent] = List[I_OnSetAway] = List[I_OnCancelAway] = List[I_OnPostCommand] = 1; -} - -/* It is IMPORTANT that m_spanningtree is the last module in the chain - * so that any activity it sees is FINAL, e.g. we arent going to send out - * a NICK message before m_cloaking has finished putting the +x on the user, - * etc etc. - * Therefore, we return PRIORITY_LAST to make sure we end up at the END of - * the module call queue. - */ -Priority ModuleSpanningTree::Prioritize() -{ - return PRIORITY_LAST; -} - -MODULE_INIT(ModuleSpanningTree) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Provides a spanning tree server link protocol */
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/timesynctimer.h"
#include "m_spanningtree/resolvers.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/rconnect.h"
#include "m_spanningtree/rsquit.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */
ModuleSpanningTree::ModuleSpanningTree(InspIRCd* Me)
: Module(Me), max_local(0), max_global(0)
{
ServerInstance->UseInterface("InspSocketHook");
Utils = new SpanningTreeUtilities(Me, this);
command_rconnect = new cmd_rconnect(ServerInstance, this, Utils);
ServerInstance->AddCommand(command_rconnect);
command_rsquit = new cmd_rsquit(ServerInstance, this, Utils);
ServerInstance->AddCommand(command_rsquit);
if (Utils->EnableTimeSync)
{
SyncTimer = new TimeSyncTimer(ServerInstance, this);
ServerInstance->Timers->AddTimer(SyncTimer);
}
else
SyncTimer = NULL;
RefreshTimer = new CacheRefreshTimer(ServerInstance, Utils);
ServerInstance->Timers->AddTimer(RefreshTimer);
}
void ModuleSpanningTree::ShowLinks(TreeServer* Current, userrec* user, int hops)
{
std::string Parent = Utils->TreeRoot->GetName();
if (Current->GetParent())
{
Parent = Current->GetParent()->GetName();
}
for (unsigned int q = 0; q < Current->ChildCount(); q++)
{
if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))))
{
if (*user->oper)
{
ShowLinks(Current->GetChild(q),user,hops+1);
}
}
else
{
ShowLinks(Current->GetChild(q),user,hops+1);
}
}
/* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */
if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName().c_str())) && (!IS_OPER(user)))
return;
/* Or if the server is hidden and they're not an oper */
else if ((Current->Hidden) && (!IS_OPER(user)))
return;
user->WriteServ("364 %s %s %s :%d %s", user->nick,Current->GetName().c_str(),
(Utils->FlatLinks && (!IS_OPER(user))) ? ServerInstance->Config->ServerName : Parent.c_str(),
(Utils->FlatLinks && (!IS_OPER(user))) ? 0 : hops,
Current->GetDesc().c_str());
}
int ModuleSpanningTree::CountLocalServs()
{
return Utils->TreeRoot->ChildCount();
}
int ModuleSpanningTree::CountServs()
{
return Utils->serverlist.size();
}
void ModuleSpanningTree::HandleLinks(const char** parameters, int pcnt, userrec* user)
{
ShowLinks(Utils->TreeRoot,user,0);
user->WriteServ("365 %s * :End of /LINKS list.",user->nick);
return;
}
void ModuleSpanningTree::HandleLusers(const char** parameters, int pcnt, userrec* user)
{
unsigned int n_users = ServerInstance->UserCount();
/* Only update these when someone wants to see them, more efficient */
if ((unsigned int)ServerInstance->LocalUserCount() > max_local)
max_local = ServerInstance->LocalUserCount();
if (n_users > max_global)
max_global = n_users;
unsigned int ulined_count = 0;
unsigned int ulined_local_count = 0;
/* If ulined are hidden and we're not an oper, count the number of ulined servers hidden,
* locally and globally (locally means directly connected to us)
*/
if ((Utils->HideULines) && (!*user->oper))
{
for (server_hash::iterator q = Utils->serverlist.begin(); q != Utils->serverlist.end(); q++)
{
if (ServerInstance->ULine(q->second->GetName().c_str()))
{
ulined_count++;
if (q->second->GetParent() == Utils->TreeRoot)
ulined_local_count++;
}
}
}
user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount(),ulined_count ? this->CountServs() - ulined_count : this->CountServs());
if (ServerInstance->OperCount())
user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount());
if (ServerInstance->UnregisteredUserCount())
user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount());
if (ServerInstance->ChannelCount())
user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount());
user->WriteServ("255 %s :I have %d clients and %d servers",user->nick,ServerInstance->LocalUserCount(),ulined_local_count ? this->CountLocalServs() - ulined_local_count : this->CountLocalServs());
user->WriteServ("265 %s :Current Local Users: %d Max: %d",user->nick,ServerInstance->LocalUserCount(),max_local);
user->WriteServ("266 %s :Current Global Users: %d Max: %d",user->nick,n_users,max_global);
return;
}
std::string ModuleSpanningTree::TimeToStr(time_t secs)
{
time_t mins_up = secs / 60;
time_t hours_up = mins_up / 60;
time_t days_up = hours_up / 24;
secs = secs % 60;
mins_up = mins_up % 60;
hours_up = hours_up % 24;
return ((days_up ? (ConvToStr(days_up) + "d") : std::string(""))
+ (hours_up ? (ConvToStr(hours_up) + "h") : std::string(""))
+ (mins_up ? (ConvToStr(mins_up) + "m") : std::string(""))
+ ConvToStr(secs) + "s");
}
const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current)
{
time_t secs_up = ServerInstance->Time() - Current->age;
return (" [Up: " + TimeToStr(secs_up) + " Lag: "+ConvToStr(Current->rtt)+"s]");
}
// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS.
void ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers)
{
if (line < 128)
{
for (int t = 0; t < depth; t++)
{
matrix[line][t] = ' ';
}
// For Aligning, we need to work out exactly how deep this thing is, and produce
// a 'Spacer' String to compensate.
char spacer[40];
memset(spacer,' ',40);
if ((40 - Current->GetName().length() - depth) > 1) {
spacer[40 - Current->GetName().length() - depth] = '\0';
}
else
{
spacer[5] = '\0';
}
float percent;
char text[128];
/* Neat and tidy default values, as we're dealing with a matrix not a simple string */
memset(text, 0, 128);
if (ServerInstance->clientlist->size() == 0) {
// If there are no users, WHO THE HELL DID THE /MAP?!?!?!
percent = 0;
}
else
{
percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100;
}
const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : "";
snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str());
totusers += Current->GetUserCount();
totservers++;
strlcpy(&matrix[line][depth],text,126);
line++;
for (unsigned int q = 0; q < Current->ChildCount(); q++)
{
if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))))
{
if (*user->oper)
{
ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers);
}
}
else
{
ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers);
}
}
}
}
int ModuleSpanningTree::HandleMotd(const char** parameters, int pcnt, userrec* user)
{
if (pcnt > 0)
{
if (match(ServerInstance->Config->ServerName, parameters[0]))
return 0;
/* Remote MOTD, the server is within the 1st parameter */
std::deque<std::string> params;
params.push_back(parameters[0]);
/* Send it out remotely, generate no reply yet */
TreeServer* s = Utils->FindServerMask(parameters[0]);
if (s)
{
params[0] = s->GetName();
Utils->DoOneToOne(user->nick, "MOTD", params, s->GetName());
}
else
user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);
return 1;
}
return 0;
}
int ModuleSpanningTree::HandleAdmin(const char** parameters, int pcnt, userrec* user)
{
if (pcnt > 0)
{
if (match(ServerInstance->Config->ServerName, parameters[0]))
return 0;
/* Remote ADMIN, the server is within the 1st parameter */
std::deque<std::string> params;
params.push_back(parameters[0]);
/* Send it out remotely, generate no reply yet */
TreeServer* s = Utils->FindServerMask(parameters[0]);
if (s)
{
params[0] = s->GetName();
Utils->DoOneToOne(user->nick, "ADMIN", params, s->GetName());
}
else
user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);
return 1;
}
return 0;
}
int ModuleSpanningTree::HandleModules(const char** parameters, int pcnt, userrec* user)
{
if (pcnt > 0)
{
if (match(ServerInstance->Config->ServerName, parameters[0]))
return 0;
std::deque<std::string> params;
params.push_back(parameters[0]);
TreeServer* s = Utils->FindServerMask(parameters[0]);
if (s)
{
params[0] = s->GetName();
Utils->DoOneToOne(user->nick, "MODULES", params, s->GetName());
}
else
user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);
return 1;
}
return 0;
}
int ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user)
{
if (pcnt > 1)
{
if (match(ServerInstance->Config->ServerName, parameters[1]))
return 0;
/* Remote STATS, the server is within the 2nd parameter */
std::deque<std::string> params;
params.push_back(parameters[0]);
params.push_back(parameters[1]);
/* Send it out remotely, generate no reply yet */
TreeServer* s = Utils->FindServerMask(parameters[1]);
if (s)
{
params[1] = s->GetName();
Utils->DoOneToOne(user->nick, "STATS", params, s->GetName());
}
else
{
user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]);
}
return 1;
}
return 0;
}
// Ok, prepare to be confused.
// After much mulling over how to approach this, it struck me that
// the 'usual' way of doing a /MAP isnt the best way. Instead of
// keeping track of a ton of ascii characters, and line by line
// under recursion working out where to place them using multiplications
// and divisons, we instead render the map onto a backplane of characters
// (a character matrix), then draw the branches as a series of "L" shapes
// from the nodes. This is not only friendlier on CPU it uses less stack.
void ModuleSpanningTree::HandleMap(const char** parameters, int pcnt, userrec* user)
{
// This array represents a virtual screen which we will
// "scratch" draw to, as the console device of an irc
// client does not provide for a proper terminal.
float totusers = 0;
float totservers = 0;
char matrix[128][128];
for (unsigned int t = 0; t < 128; t++)
{
matrix[t][0] = '\0';
}
line = 0;
// The only recursive bit is called here.
ShowMap(Utils->TreeRoot,user,0,matrix,totusers,totservers);
// Process each line one by one. The algorithm has a limit of
// 128 servers (which is far more than a spanning tree should have
// anyway, so we're ok). This limit can be raised simply by making
// the character matrix deeper, 128 rows taking 10k of memory.
for (int l = 1; l < line; l++)
{
// scan across the line looking for the start of the
// servername (the recursive part of the algorithm has placed
// the servers at indented positions depending on what they
// are related to)
int first_nonspace = 0;
while (matrix[l][first_nonspace] == ' ')
{
first_nonspace++;
}
first_nonspace--;
// Draw the `- (corner) section: this may be overwritten by
// another L shape passing along the same vertical pane, becoming
// a |- (branch) section instead.
matrix[l][first_nonspace] = '-';
matrix[l][first_nonspace-1] = '`';
int l2 = l - 1;
// Draw upwards until we hit the parent server, causing possibly
// other corners (`-) to become branches (|-)
while ((matrix[l2][first_nonspace-1] == ' ') || (matrix[l2][first_nonspace-1] == '`'))
{
matrix[l2][first_nonspace-1] = '|';
l2--;
}
}
// dump the whole lot to the user. This is the easy bit, honest.
for (int t = 0; t < line; t++)
{
user->WriteServ("006 %s :%s",user->nick,&matrix[t][0]);
}
float avg_users = totusers / totservers;
user->WriteServ("270 %s :%.0f server%s and %.0f user%s, average %.2f users per server",user->nick,totservers,(totservers > 1 ? "s" : ""),totusers,(totusers > 1 ? "s" : ""),avg_users);
user->WriteServ("007 %s :End of /MAP",user->nick);
return;
}
int ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user)
{
TreeServer* s = Utils->FindServerMask(parameters[0]);
if (s)
{
if (s == Utils->TreeRoot)
{
user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]);
return 1;
}
TreeSocket* sock = s->GetSocket();
if (sock)
{
ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick);
sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost());
ServerInstance->SE->DelFd(sock);
sock->Close();
}
else
{
if (IS_LOCAL(user))
user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick);
}
}
else
{
user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]);
}
return 1;
}
int ModuleSpanningTree::HandleTime(const char** parameters, int pcnt, userrec* user)
{
if ((IS_LOCAL(user)) && (pcnt))
{
TreeServer* found = Utils->FindServerMask(parameters[0]);
if (found)
{
// we dont' override for local server
if (found == Utils->TreeRoot)
return 0;
std::deque<std::string> params;
params.push_back(found->GetName());
params.push_back(user->nick);
Utils->DoOneToOne(ServerInstance->Config->ServerName,"TIME",params,found->GetName());
}
else
{
user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]);
}
}
return 1;
}
int ModuleSpanningTree::HandleRemoteWhois(const char** parameters, int pcnt, userrec* user)
{
if ((IS_LOCAL(user)) && (pcnt > 1))
{
userrec* remote = ServerInstance->FindNick(parameters[1]);
if ((remote) && (remote->GetFd() < 0))
{
std::deque<std::string> params;
params.push_back(parameters[1]);
Utils->DoOneToOne(user->nick,"IDLE",params,remote->server);
return 1;
}
else if (!remote)
{
user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);
user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, parameters[1]);
return 1;
}
}
return 0;
}
void ModuleSpanningTree::DoPingChecks(time_t curtime)
{
for (unsigned int j = 0; j < Utils->TreeRoot->ChildCount(); j++)
{
TreeServer* serv = Utils->TreeRoot->GetChild(j);
TreeSocket* sock = serv->GetSocket();
if (sock)
{
if (curtime >= serv->NextPingTime())
{
if (serv->AnsweredLastPing())
{
sock->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" PING "+serv->GetName());
serv->SetNextPingTime(curtime + 60);
serv->LastPing = curtime;
serv->Warned = false;
}
else
{
/* they didnt answer, boot them */
sock->SendError("Ping timeout");
sock->Squit(serv,"Ping timeout");
/*** XXX SOCKET CULL ***/
return;
}
}
else if ((Utils->PingWarnTime) && (!serv->Warned) && (curtime >= serv->NextPingTime() - (60 - Utils->PingWarnTime)) && (!serv->AnsweredLastPing()))
{
/* The server hasnt responded, send a warning to opers */
ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", serv->GetName().c_str(), Utils->PingWarnTime);
serv->Warned = true;
}
}
}
/* Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data.
* This prevents lost REMOTECONNECT notices
*/
for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)
Utils->SetRemoteBursting(i->second, false);
}
void ModuleSpanningTree::ConnectServer(Link* x)
{
bool ipvalid = true;
QueryType start_type = DNS_QUERY_A;
#ifdef IPV6
start_type = DNS_QUERY_AAAA;
if (strchr(x->IPAddr.c_str(),':'))
{
in6_addr n;
if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1)
ipvalid = false;
}
else
#endif
{
in_addr n;
if (inet_aton(x->IPAddr.c_str(),&n) < 1)
ipvalid = false;
}
/* Do we already have an IP? If so, no need to resolve it. */
if (ipvalid)
{
/* Gave a hook, but it wasnt one we know */
if ((!x->Hook.empty()) && (Utils->hooks.find(x->Hook.c_str()) == Utils->hooks.end()))
return;
TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port,false,x->Timeout ? x->Timeout : 10,x->Name.c_str(), x->Bind, x->Hook.empty() ? NULL : Utils->hooks[x->Hook.c_str()]);
if (newsocket->GetFd() > -1)
{
/* Handled automatically on success */
}
else
{
ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno));
delete newsocket;
Utils->DoFailOver(x);
}
}
else
{
try
{
bool cached;
ServernameResolver* snr = new ServernameResolver((Module*)this, Utils, ServerInstance,x->IPAddr, *x, cached, start_type);
ServerInstance->AddResolver(snr, cached);
}
catch (ModuleException& e)
{
ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason());
Utils->DoFailOver(x);
}
}
}
void ModuleSpanningTree::AutoConnectServers(time_t curtime)
{
for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
{
if ((x->AutoConnect) && (curtime >= x->NextConnectTime))
{
x->NextConnectTime = curtime + x->AutoConnect;
TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str());
if (x->FailOver.length())
{
TreeServer* CheckFailOver = Utils->FindServer(x->FailOver.c_str());
if (CheckFailOver)
{
/* The failover for this server is currently a member of the network.
* The failover probably succeeded, where the main link did not.
* Don't try the main link until the failover is gone again.
*/
continue;
}
}
if (!CheckDupe)
{
// an autoconnected server is not connected. Check if its time to connect it
ServerInstance->SNO->WriteToSnoMask('l',"AUTOCONNECT: Auto-connecting server \002%s\002 (%lu seconds until next attempt)",x->Name.c_str(),x->AutoConnect);
this->ConnectServer(&(*x));
}
}
}
}
int ModuleSpanningTree::HandleVersion(const char** parameters, int pcnt, userrec* user)
{
// we've already checked if pcnt > 0, so this is safe
TreeServer* found = Utils->FindServerMask(parameters[0]);
if (found)
{
std::string Version = found->GetVersion();
user->WriteServ("351 %s :%s",user->nick,Version.c_str());
if (found == Utils->TreeRoot)
{
ServerInstance->Config->Send005(user);
}
}
else
{
user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]);
}
return 1;
}
int ModuleSpanningTree::HandleConnect(const char** parameters, int pcnt, userrec* user)
{
for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
{
if (ServerInstance->MatchText(x->Name.c_str(),parameters[0]))
{
TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str());
if (!CheckDupe)
{
user->WriteServ("NOTICE %s :*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",user->nick,x->Name.c_str(),(x->HiddenFromStats ? "<hidden>" : x->IPAddr.c_str()),x->Port);
ConnectServer(&(*x));
return 1;
}
else
{
user->WriteServ("NOTICE %s :*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002",user->nick,x->Name.c_str(),CheckDupe->GetParent()->GetName().c_str());
return 1;
}
}
}
user->WriteServ("NOTICE %s :*** CONNECT: No server matching \002%s\002 could be found in the config file.",user->nick,parameters[0]);
return 1;
}
void ModuleSpanningTree::BroadcastTimeSync()
{
if (Utils->MasterTime)
{
std::deque<std::string> params;
params.push_back(ConvToStr(ServerInstance->Time(false)));
params.push_back("FORCE");
Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);
}
}
int ModuleSpanningTree::OnStats(char statschar, userrec* user, string_list &results)
{
if ((statschar == 'c') || (statschar == 'n'))
{
for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++)
{
results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].Hook.empty() ? "plaintext" : Utils->LinkBlocks[i].Hook)+" "+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s');
if (statschar == 'c')
results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str());
}
results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report");
ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host);
return 1;
}
if (statschar == 'p')
{
/* show all server ports, after showing client ports. -- w00t */
for (unsigned int i = 0; i < Utils->Bindings.size(); i++)
{
std::string ip = Utils->Bindings[i]->IP;
if (ip.empty())
ip = "*";
std::string transport("plaintext");
if (Utils->Bindings[i]->GetHook())
transport = InspSocketNameRequest(this, Utils->Bindings[i]->GetHook()).Send();
results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->port)+
" (server, " + transport + ")");
}
}
return 0;
}
int ModuleSpanningTree::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
/* If the command doesnt appear to be valid, we dont want to mess with it. */
if (!validated)
return 0;
if (command == "CONNECT")
{
return this->HandleConnect(parameters,pcnt,user);
}
else if (command == "STATS")
{
return this->HandleStats(parameters,pcnt,user);
}
else if (command == "MOTD")
{
return this->HandleMotd(parameters,pcnt,user);
}
else if (command == "ADMIN")
{
return this->HandleAdmin(parameters,pcnt,user);
}
else if (command == "SQUIT")
{
return this->HandleSquit(parameters,pcnt,user);
}
else if (command == "MAP")
{
this->HandleMap(parameters,pcnt,user);
return 1;
}
else if ((command == "TIME") && (pcnt > 0))
{
return this->HandleTime(parameters,pcnt,user);
}
else if (command == "LUSERS")
{
this->HandleLusers(parameters,pcnt,user);
return 1;
}
else if (command == "LINKS")
{
this->HandleLinks(parameters,pcnt,user);
return 1;
}
else if (command == "WHOIS")
{
if (pcnt > 1)
{
// remote whois
return this->HandleRemoteWhois(parameters,pcnt,user);
}
}
else if ((command == "VERSION") && (pcnt > 0))
{
this->HandleVersion(parameters,pcnt,user);
return 1;
}
else if ((command == "MODULES") && (pcnt > 0))
{
return this->HandleModules(parameters,pcnt,user);
}
return 0;
}
void ModuleSpanningTree::OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line)
{
if ((result == CMD_SUCCESS) && (ServerInstance->IsValidModuleCommand(command, pcnt, user)))
{
// this bit of code cleverly routes all module commands
// to all remote severs *automatically* so that modules
// can just handle commands locally, without having
// to have any special provision in place for remote
// commands and linking protocols.
std::deque<std::string> params;
params.clear();
for (int j = 0; j < pcnt; j++)
{
if (strchr(parameters[j],' '))
{
params.push_back(":" + std::string(parameters[j]));
}
else
{
params.push_back(std::string(parameters[j]));
}
}
Utils->DoOneToMany(user->nick,command,params);
}
}
void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description)
{
TreeServer* s = Utils->FindServer(servername);
if (s)
{
description = s->GetDesc();
}
}
void ModuleSpanningTree::OnUserInvite(userrec* source,userrec* dest,chanrec* channel)
{
if (IS_LOCAL(source))
{
std::deque<std::string> params;
params.push_back(dest->nick);
params.push_back(channel->name);
Utils->DoOneToMany(source->nick,"INVITE",params);
}
}
void ModuleSpanningTree::OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic)
{
std::deque<std::string> params;
params.push_back(chan->name);
params.push_back(":"+topic);
Utils->DoOneToMany(user->nick,"TOPIC",params);
}
void ModuleSpanningTree::OnWallops(userrec* user, const std::string &text)
{
if (IS_LOCAL(user))
{
std::deque<std::string> params;
params.push_back(":"+text);
Utils->DoOneToMany(user->nick,"WALLOPS",params);
}
}
void ModuleSpanningTree::OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
if (target_type == TYPE_USER)
{
userrec* d = (userrec*)dest;
if ((d->GetFd() < 0) && (IS_LOCAL(user)))
{
std::deque<std::string> params;
params.clear();
params.push_back(d->nick);
params.push_back(":"+text);
Utils->DoOneToOne(user->nick,"NOTICE",params,d->server);
}
}
else if (target_type == TYPE_CHANNEL)
{
if (IS_LOCAL(user))
{
chanrec *c = (chanrec*)dest;
if (c)
{
std::string cname = c->name;
if (status)
cname = status + cname;
TreeServerList list;
Utils->GetListOfServersForChannel(c,list,status,exempt_list);
for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
{
TreeSocket* Sock = i->second->GetSocket();
if (Sock)
Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text);
}
}
}
}
else if (target_type == TYPE_SERVER)
{
if (IS_LOCAL(user))
{
char* target = (char*)dest;
std::deque<std::string> par;
par.push_back(target);
par.push_back(":"+text);
Utils->DoOneToMany(user->nick,"NOTICE",par);
}
}
}
void ModuleSpanningTree::OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
if (target_type == TYPE_USER)
{
// route private messages which are targetted at clients only to the server
// which needs to receive them
userrec* d = (userrec*)dest;
if ((d->GetFd() < 0) && (IS_LOCAL(user)))
{
std::deque<std::string> params;
params.clear();
params.push_back(d->nick);
params.push_back(":"+text);
Utils->DoOneToOne(user->nick,"PRIVMSG",params,d->server);
}
}
else if (target_type == TYPE_CHANNEL)
{
if (IS_LOCAL(user))
{
chanrec *c = (chanrec*)dest;
if (c)
{
std::string cname = c->name;
if (status)
cname = status + cname;
TreeServerList list;
Utils->GetListOfServersForChannel(c,list,status,exempt_list);
for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
{
TreeSocket* Sock = i->second->GetSocket();
if (Sock)
Sock->WriteLine(":"+std::string(user->nick)+" PRIVMSG "+cname+" :"+text);
}
}
}
}
else if (target_type == TYPE_SERVER)
{
if (IS_LOCAL(user))
{
char* target = (char*)dest;
std::deque<std::string> par;
par.push_back(target);
par.push_back(":"+text);
Utils->DoOneToMany(user->nick,"PRIVMSG",par);
}
}
}
void ModuleSpanningTree::OnBackgroundTimer(time_t curtime)
{
AutoConnectServers(curtime);
DoPingChecks(curtime);
}
void ModuleSpanningTree::OnUserJoin(userrec* user, chanrec* channel, bool &silent)
{
// Only do this for local users
if (IS_LOCAL(user))
{
if (channel->GetUserCounter() == 1)
{
std::deque<std::string> params;
// set up their permissions and the channel TS with FJOIN.
// All users are FJOINed now, because a module may specify
// new joining permissions for the user.
params.push_back(channel->name);
params.push_back(ConvToStr(channel->age));
params.push_back(std::string(channel->GetAllPrefixChars(user))+","+std::string(user->nick));
Utils->DoOneToMany(ServerInstance->Config->ServerName,"FJOIN",params);
/* First user in, sync the modes for the channel */
params.pop_back();
params.push_back(channel->ChanModes(true));
Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",params);
}
else
{
std::deque<std::string> params;
params.push_back(channel->name);
params.push_back(ConvToStr(channel->age));
Utils->DoOneToMany(user->nick,"JOIN",params);
}
}
}
void ModuleSpanningTree::OnChangeHost(userrec* user, const std::string &newhost)
{
// only occurs for local clients
if (user->registered != REG_ALL)
return;
std::deque<std::string> params;
params.push_back(newhost);
Utils->DoOneToMany(user->nick,"FHOST",params);
}
void ModuleSpanningTree::OnChangeName(userrec* user, const std::string &gecos)
{
// only occurs for local clients
if (user->registered != REG_ALL)
return;
std::deque<std::string> params;
params.push_back(gecos);
Utils->DoOneToMany(user->nick,"FNAME",params);
}
void ModuleSpanningTree::OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
{
if (IS_LOCAL(user))
{
std::deque<std::string> params;
params.push_back(channel->name);
if (!partmessage.empty())
params.push_back(":"+partmessage);
Utils->DoOneToMany(user->nick,"PART",params);
}
}
void ModuleSpanningTree::OnUserConnect(userrec* user)
{
char agestr[MAXBUF];
if (IS_LOCAL(user))
{
std::deque<std::string> params;
snprintf(agestr,MAXBUF,"%lu",(unsigned long)user->age);
params.push_back(agestr);
params.push_back(user->nick);
params.push_back(user->host);
params.push_back(user->dhost);
params.push_back(user->ident);
params.push_back("+"+std::string(user->FormatModes()));
params.push_back(user->GetIPString());
params.push_back(":"+std::string(user->fullname));
Utils->DoOneToMany(ServerInstance->Config->ServerName,"NICK",params);
// User is Local, change needs to be reflected!
TreeServer* SourceServer = Utils->FindServer(user->server);
if (SourceServer)
{
SourceServer->AddUserCount();
}
}
}
void ModuleSpanningTree::OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
if ((IS_LOCAL(user)) && (user->registered == REG_ALL))
{
std::deque<std::string> params;
if (oper_message != reason)
{
params.push_back(":"+oper_message);
Utils->DoOneToMany(user->nick,"OPERQUIT",params);
}
params.clear();
params.push_back(":"+reason);
Utils->DoOneToMany(user->nick,"QUIT",params);
}
// Regardless, We need to modify the user Counts..
TreeServer* SourceServer = Utils->FindServer(user->server);
if (SourceServer)
{
SourceServer->DelUserCount();
}
}
void ModuleSpanningTree::OnUserPostNick(userrec* user, const std::string &oldnick)
{
if (IS_LOCAL(user))
{
std::deque<std::string> params;
params.push_back(user->nick);
Utils->DoOneToMany(oldnick,"NICK",params);
}
}
void ModuleSpanningTree::OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
{
if ((source) && (IS_LOCAL(source)))
{
std::deque<std::string> params;
params.push_back(chan->name);
params.push_back(user->nick);
params.push_back(":"+reason);
Utils->DoOneToMany(source->nick,"KICK",params);
}
else if (!source)
{
std::deque<std::string> params;
params.push_back(chan->name);
params.push_back(user->nick);
params.push_back(":"+reason);
Utils->DoOneToMany(ServerInstance->Config->ServerName,"KICK",params);
}
}
void ModuleSpanningTree::OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason)
{
std::deque<std::string> params;
params.push_back(":"+reason);
Utils->DoOneToMany(dest->nick,"OPERQUIT",params);
params.clear();
params.push_back(dest->nick);
params.push_back(":"+reason);
dest->SetOperQuit(operreason);
Utils->DoOneToMany(source->nick,"KILL",params);
}
void ModuleSpanningTree::OnRehash(userrec* user, const std::string ¶meter)
{
if (!parameter.empty())
{
std::deque<std::string> params;
params.push_back(parameter);
Utils->DoOneToMany(user ? user->nick : ServerInstance->Config->ServerName, "REHASH", params);
// check for self
if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameter))
{
ServerInstance->WriteOpers("*** Remote rehash initiated locally by \002%s\002", user ? user->nick : ServerInstance->Config->ServerName);
ServerInstance->RehashServer();
}
}
Utils->ReadConfiguration(false);
InitializeDisabledCommands(ServerInstance->Config->DisabledCommands, ServerInstance);
}
// note: the protocol does not allow direct umode +o except
// via NICK with 8 params. sending OPERTYPE infers +o modechange
// locally.
void ModuleSpanningTree::OnOper(userrec* user, const std::string &opertype)
{
if (IS_LOCAL(user))
{
std::deque<std::string> params;
params.push_back(opertype);
Utils->DoOneToMany(user->nick,"OPERTYPE",params);
}
}
void ModuleSpanningTree::OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason)
{
if (!source)
{
/* Server-set lines */
char data[MAXBUF];
snprintf(data,MAXBUF,"%c %s %s %lu %lu :%s", linetype, host.c_str(), ServerInstance->Config->ServerName, (unsigned long)ServerInstance->Time(false),
(unsigned long)duration, reason.c_str());
std::deque<std::string> params;
params.push_back(data);
Utils->DoOneToMany(ServerInstance->Config->ServerName, "ADDLINE", params);
}
else
{
if (IS_LOCAL(source))
{
char type[8];
snprintf(type,8,"%cLINE",linetype);
std::string stype = type;
if (adding)
{
char sduration[MAXBUF];
snprintf(sduration,MAXBUF,"%ld",duration);
std::deque<std::string> params;
params.push_back(host);
params.push_back(sduration);
params.push_back(":"+reason);
Utils->DoOneToMany(source->nick,stype,params);
}
else
{
std::deque<std::string> params;
params.push_back(host);
Utils->DoOneToMany(source->nick,stype,params);
}
}
}
}
void ModuleSpanningTree::OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)
{
OnLine(source,hostmask,true,'G',duration,reason);
}
void ModuleSpanningTree::OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask)
{
OnLine(source,ipmask,true,'Z',duration,reason);
}
void ModuleSpanningTree::OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask)
{
OnLine(source,nickmask,true,'Q',duration,reason);
}
void ModuleSpanningTree::OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)
{
OnLine(source,hostmask,true,'E',duration,reason);
}
void ModuleSpanningTree::OnDelGLine(userrec* source, const std::string &hostmask)
{
OnLine(source,hostmask,false,'G',0,"");
}
void ModuleSpanningTree::OnDelZLine(userrec* source, const std::string &ipmask)
{
OnLine(source,ipmask,false,'Z',0,"");
}
void ModuleSpanningTree::OnDelQLine(userrec* source, const std::string &nickmask)
{
OnLine(source,nickmask,false,'Q',0,"");
}
void ModuleSpanningTree::OnDelELine(userrec* source, const std::string &hostmask)
{
OnLine(source,hostmask,false,'E',0,"");
}
void ModuleSpanningTree::OnMode(userrec* user, void* dest, int target_type, const std::string &text)
{
if ((IS_LOCAL(user)) && (user->registered == REG_ALL))
{
std::deque<std::string> params;
std::string command;
if (target_type == TYPE_USER)
{
userrec* u = (userrec*)dest;
params.push_back(u->nick);
params.push_back(text);
command = "MODE";
}
else
{
chanrec* c = (chanrec*)dest;
params.push_back(c->name);
params.push_back(ConvToStr(c->age));
params.push_back(text);
command = "FMODE";
}
Utils->DoOneToMany(user->nick, command, params);
}
}
void ModuleSpanningTree::OnSetAway(userrec* user)
{
if (IS_LOCAL(user))
{
std::deque<std::string> params;
params.push_back(":"+std::string(user->awaymsg));
Utils->DoOneToMany(user->nick,"AWAY",params);
}
}
void ModuleSpanningTree::OnCancelAway(userrec* user)
{
if (IS_LOCAL(user))
{
std::deque<std::string> params;
params.clear();
Utils->DoOneToMany(user->nick,"AWAY",params);
}
}
void ModuleSpanningTree::ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline)
{
TreeSocket* s = (TreeSocket*)opaque;
if (target)
{
if (target_type == TYPE_USER)
{
userrec* u = (userrec*)target;
s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline);
}
else
{
chanrec* c = (chanrec*)target;
s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline);
}
}
}
void ModuleSpanningTree::ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)
{
TreeSocket* s = (TreeSocket*)opaque;
if (target)
{
if (target_type == TYPE_USER)
{
userrec* u = (userrec*)target;
s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+u->nick+" "+extname+" :"+extdata);
}
else if (target_type == TYPE_CHANNEL)
{
chanrec* c = (chanrec*)target;
s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+c->name+" "+extname+" :"+extdata);
}
}
if (target_type == TYPE_OTHER)
{
s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA * "+extname+" :"+extdata);
}
}
void ModuleSpanningTree::OnEvent(Event* event)
{
std::deque<std::string>* params = (std::deque<std::string>*)event->GetData();
if (event->GetEventID() == "send_metadata")
{
if (params->size() < 3)
return;
(*params)[2] = ":" + (*params)[2];
Utils->DoOneToMany(ServerInstance->Config->ServerName,"METADATA",*params);
}
else if (event->GetEventID() == "send_topic")
{
if (params->size() < 2)
return;
(*params)[1] = ":" + (*params)[1];
params->insert(params->begin() + 1,ServerInstance->Config->ServerName);
params->insert(params->begin() + 1,ConvToStr(ServerInstance->Time(true)));
Utils->DoOneToMany(ServerInstance->Config->ServerName,"FTOPIC",*params);
}
else if (event->GetEventID() == "send_mode")
{
if (params->size() < 2)
return;
// Insert the TS value of the object, either userrec or chanrec
time_t ourTS = 0;
userrec* a = ServerInstance->FindNick((*params)[0]);
if (a)
{
ourTS = a->age;
Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params);
return;
}
else
{
chanrec* a = ServerInstance->FindChan((*params)[0]);
if (a)
{
ourTS = a->age;
params->insert(params->begin() + 1,ConvToStr(ourTS));
Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",*params);
}
}
}
else if (event->GetEventID() == "send_mode_explicit")
{
if (params->size() < 2)
return;
Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params);
}
else if (event->GetEventID() == "send_opers")
{
if (params->size() < 1)
return;
(*params)[0] = ":" + (*params)[0];
Utils->DoOneToMany(ServerInstance->Config->ServerName,"OPERNOTICE",*params);
}
else if (event->GetEventID() == "send_modeset")
{
if (params->size() < 2)
return;
(*params)[1] = ":" + (*params)[1];
Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODENOTICE",*params);
}
else if (event->GetEventID() == "send_snoset")
{
if (params->size() < 2)
return;
(*params)[1] = ":" + (*params)[1];
Utils->DoOneToMany(ServerInstance->Config->ServerName,"SNONOTICE",*params);
}
else if (event->GetEventID() == "send_push")
{
if (params->size() < 2)
return;
userrec *a = ServerInstance->FindNick((*params)[0]);
if (!a)
return;
(*params)[1] = ":" + (*params)[1];
Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", *params, a->server);
}
}
ModuleSpanningTree::~ModuleSpanningTree()
{
/* This will also free the listeners */
delete Utils;
if (SyncTimer)
ServerInstance->Timers->DelTimer(SyncTimer);
ServerInstance->Timers->DelTimer(RefreshTimer);
ServerInstance->DoneWithInterface("InspSocketHook");
}
Version ModuleSpanningTree::GetVersion()
{
return Version(1,1,0,2,VF_VENDOR,API_VERSION);
}
void ModuleSpanningTree::Implements(char* List)
{
List[I_OnPreCommand] = List[I_OnGetServerDescription] = List[I_OnUserInvite] = List[I_OnPostLocalTopicChange] = 1;
List[I_OnWallops] = List[I_OnUserNotice] = List[I_OnUserMessage] = List[I_OnBackgroundTimer] = 1;
List[I_OnUserJoin] = List[I_OnChangeHost] = List[I_OnChangeName] = List[I_OnUserPart] = List[I_OnUserConnect] = 1;
List[I_OnUserQuit] = List[I_OnUserPostNick] = List[I_OnUserKick] = List[I_OnRemoteKill] = List[I_OnRehash] = 1;
List[I_OnOper] = List[I_OnAddGLine] = List[I_OnAddZLine] = List[I_OnAddQLine] = List[I_OnAddELine] = 1;
List[I_OnDelGLine] = List[I_OnDelZLine] = List[I_OnDelQLine] = List[I_OnDelELine] = List[I_ProtoSendMode] = List[I_OnMode] = 1;
List[I_OnStats] = List[I_ProtoSendMetaData] = List[I_OnEvent] = List[I_OnSetAway] = List[I_OnCancelAway] = List[I_OnPostCommand] = 1;
}
/* It is IMPORTANT that m_spanningtree is the last module in the chain
* so that any activity it sees is FINAL, e.g. we arent going to send out
* a NICK message before m_cloaking has finished putting the +x on the user,
* etc etc.
* Therefore, we return PRIORITY_LAST to make sure we end up at the END of
* the module call queue.
*/
Priority ModuleSpanningTree::Prioritize()
{
return PRIORITY_LAST;
}
MODULE_INIT(ModuleSpanningTree)
\ No newline at end of file diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h index c184ef076..5bfb73e6a 100644 --- a/src/modules/m_spanningtree/main.h +++ b/src/modules/m_spanningtree/main.h @@ -1,198 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __ST_MAIN__ -#define __ST_MAIN__ - -#include "inspircd.h" -#include "modules.h" - -/** If you make a change which breaks the protocol, increment this. - * If you completely change the protocol, completely change the number. - * - * IMPORTANT: If you make changes, document your changes here, without fail: - * http://www.inspircd.org/wiki/List_of_protocol_changes_between_versions - * - * Failure to document your protocol changes will result in a painfully - * painful death by pain. You have been warned. - */ -const long ProtocolVersion = 1105; - -/** Forward declarations - */ -class cmd_rconnect; -class cmd_rsquit; -class SpanningTreeUtilities; -class TimeSyncTimer; -class CacheRefreshTimer; -class TreeServer; -class Link; - -/** This is the main class for the spanningtree module - */ -class ModuleSpanningTree : public Module -{ - int line; - int NumServers; - unsigned int max_local; - unsigned int max_global; - cmd_rconnect* command_rconnect; - cmd_rsquit* command_rsquit; - SpanningTreeUtilities* Utils; - - public: - /** Timer for clock syncs - */ - TimeSyncTimer *SyncTimer; - - CacheRefreshTimer *RefreshTimer; - - /** Constructor - */ - ModuleSpanningTree(InspIRCd* Me); - - /** Shows /LINKS - */ - void ShowLinks(TreeServer* Current, userrec* user, int hops); - - /** Counts local servers - */ - int CountLocalServs(); - - /** Counts local and remote servers - */ - int CountServs(); - - /** Handle LINKS command - */ - void HandleLinks(const char** parameters, int pcnt, userrec* user); - - /** Handle LUSERS command - */ - void HandleLusers(const char** parameters, int pcnt, userrec* user); - - /** Show MAP output to a user (recursive) - */ - void ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers); - - /** Handle remote MOTD - */ - int HandleMotd(const char** parameters, int pcnt, userrec* user); - - /** Handle remote ADMIN - */ - int HandleAdmin(const char** parameters, int pcnt, userrec* user); - - /** Handle remote STATS - */ - int HandleStats(const char** parameters, int pcnt, userrec* user); - - /** Handle MAP command - */ - void HandleMap(const char** parameters, int pcnt, userrec* user); - - /** Handle SQUIT - */ - int HandleSquit(const char** parameters, int pcnt, userrec* user); - - /** Handle TIME - */ - int HandleTime(const char** parameters, int pcnt, userrec* user); - - /** Handle remote WHOIS - */ - int HandleRemoteWhois(const char** parameters, int pcnt, userrec* user); - - /** Handle remote MODULES - */ - int HandleModules(const char** parameters, int pcnt, userrec* user); - - /** Ping all local servers - */ - void DoPingChecks(time_t curtime); - - /** Connect a server locally - */ - void ConnectServer(Link* x); - - /** Check if any servers are due to be autoconnected - */ - void AutoConnectServers(time_t curtime); - - /** Handle remote VERSON - */ - int HandleVersion(const char** parameters, int pcnt, userrec* user); - - /** Handle CONNECT - */ - int HandleConnect(const char** parameters, int pcnt, userrec* user); - - /** Send out time sync to all servers - */ - void BroadcastTimeSync(); - - /** Returns oper-specific MAP information - */ - const std::string MapOperInfo(TreeServer* Current); - - /** Display a time as a human readable string - */ - std::string TimeToStr(time_t secs); - - /** - ** *** MODULE EVENTS *** - **/ - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line); - virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line); - virtual void OnGetServerDescription(const std::string &servername,std::string &description); - virtual void OnUserInvite(userrec* source,userrec* dest,chanrec* channel); - virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic); - virtual void OnWallops(userrec* user, const std::string &text); - virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list); - virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list); - virtual void OnBackgroundTimer(time_t curtime); - virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent); - virtual void OnChangeHost(userrec* user, const std::string &newhost); - virtual void OnChangeName(userrec* user, const std::string &gecos); - virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent); - virtual void OnUserConnect(userrec* user); - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message); - virtual void OnUserPostNick(userrec* user, const std::string &oldnick); - virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent); - virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason); - virtual void OnRehash(userrec* user, const std::string ¶meter); - virtual void OnOper(userrec* user, const std::string &opertype); - void OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason); - virtual void OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask); - virtual void OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask); - virtual void OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask); - virtual void OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask); - virtual void OnDelGLine(userrec* source, const std::string &hostmask); - virtual void OnDelZLine(userrec* source, const std::string &ipmask); - virtual void OnDelQLine(userrec* source, const std::string &nickmask); - virtual void OnDelELine(userrec* source, const std::string &hostmask); - virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text); - virtual int OnStats(char statschar, userrec* user, string_list &results); - virtual void OnSetAway(userrec* user); - virtual void OnCancelAway(userrec* user); - virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline); - virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata); - virtual void OnEvent(Event* event); - virtual ~ModuleSpanningTree(); - virtual Version GetVersion(); - void Implements(char* List); - Priority Prioritize(); -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __ST_MAIN__
#define __ST_MAIN__
#include "inspircd.h"
#include "modules.h"
/** If you make a change which breaks the protocol, increment this.
* If you completely change the protocol, completely change the number.
*
* IMPORTANT: If you make changes, document your changes here, without fail:
* http://www.inspircd.org/wiki/List_of_protocol_changes_between_versions
*
* Failure to document your protocol changes will result in a painfully
* painful death by pain. You have been warned.
*/
const long ProtocolVersion = 1105;
/** Forward declarations
*/
class cmd_rconnect;
class cmd_rsquit;
class SpanningTreeUtilities;
class TimeSyncTimer;
class CacheRefreshTimer;
class TreeServer;
class Link;
/** This is the main class for the spanningtree module
*/
class ModuleSpanningTree : public Module
{
int line;
int NumServers;
unsigned int max_local;
unsigned int max_global;
cmd_rconnect* command_rconnect;
cmd_rsquit* command_rsquit;
SpanningTreeUtilities* Utils;
public:
/** Timer for clock syncs
*/
TimeSyncTimer *SyncTimer;
CacheRefreshTimer *RefreshTimer;
/** Constructor
*/
ModuleSpanningTree(InspIRCd* Me);
/** Shows /LINKS
*/
void ShowLinks(TreeServer* Current, userrec* user, int hops);
/** Counts local servers
*/
int CountLocalServs();
/** Counts local and remote servers
*/
int CountServs();
/** Handle LINKS command
*/
void HandleLinks(const char** parameters, int pcnt, userrec* user);
/** Handle LUSERS command
*/
void HandleLusers(const char** parameters, int pcnt, userrec* user);
/** Show MAP output to a user (recursive)
*/
void ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers);
/** Handle remote MOTD
*/
int HandleMotd(const char** parameters, int pcnt, userrec* user);
/** Handle remote ADMIN
*/
int HandleAdmin(const char** parameters, int pcnt, userrec* user);
/** Handle remote STATS
*/
int HandleStats(const char** parameters, int pcnt, userrec* user);
/** Handle MAP command
*/
void HandleMap(const char** parameters, int pcnt, userrec* user);
/** Handle SQUIT
*/
int HandleSquit(const char** parameters, int pcnt, userrec* user);
/** Handle TIME
*/
int HandleTime(const char** parameters, int pcnt, userrec* user);
/** Handle remote WHOIS
*/
int HandleRemoteWhois(const char** parameters, int pcnt, userrec* user);
/** Handle remote MODULES
*/
int HandleModules(const char** parameters, int pcnt, userrec* user);
/** Ping all local servers
*/
void DoPingChecks(time_t curtime);
/** Connect a server locally
*/
void ConnectServer(Link* x);
/** Check if any servers are due to be autoconnected
*/
void AutoConnectServers(time_t curtime);
/** Handle remote VERSON
*/
int HandleVersion(const char** parameters, int pcnt, userrec* user);
/** Handle CONNECT
*/
int HandleConnect(const char** parameters, int pcnt, userrec* user);
/** Send out time sync to all servers
*/
void BroadcastTimeSync();
/** Returns oper-specific MAP information
*/
const std::string MapOperInfo(TreeServer* Current);
/** Display a time as a human readable string
*/
std::string TimeToStr(time_t secs);
/**
** *** MODULE EVENTS ***
**/
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);
virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line);
virtual void OnGetServerDescription(const std::string &servername,std::string &description);
virtual void OnUserInvite(userrec* source,userrec* dest,chanrec* channel);
virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic);
virtual void OnWallops(userrec* user, const std::string &text);
virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
virtual void OnBackgroundTimer(time_t curtime);
virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent);
virtual void OnChangeHost(userrec* user, const std::string &newhost);
virtual void OnChangeName(userrec* user, const std::string &gecos);
virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent);
virtual void OnUserConnect(userrec* user);
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message);
virtual void OnUserPostNick(userrec* user, const std::string &oldnick);
virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent);
virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason);
virtual void OnRehash(userrec* user, const std::string ¶meter);
virtual void OnOper(userrec* user, const std::string &opertype);
void OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason);
virtual void OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);
virtual void OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask);
virtual void OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask);
virtual void OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);
virtual void OnDelGLine(userrec* source, const std::string &hostmask);
virtual void OnDelZLine(userrec* source, const std::string &ipmask);
virtual void OnDelQLine(userrec* source, const std::string &nickmask);
virtual void OnDelELine(userrec* source, const std::string &hostmask);
virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text);
virtual int OnStats(char statschar, userrec* user, string_list &results);
virtual void OnSetAway(userrec* user);
virtual void OnCancelAway(userrec* user);
virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline);
virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata);
virtual void OnEvent(Event* event);
virtual ~ModuleSpanningTree();
virtual Version GetVersion();
void Implements(char* List);
Priority Prioritize();
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/rconnect.cpp b/src/modules/m_spanningtree/rconnect.cpp index 5500ccdc0..88b1fde8b 100644 --- a/src/modules/m_spanningtree/rconnect.cpp +++ b/src/modules/m_spanningtree/rconnect.cpp @@ -1,67 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/timesynctimer.h" -#include "m_spanningtree/resolvers.h" -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" -#include "m_spanningtree/rconnect.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h */ - -cmd_rconnect::cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RCONNECT", 'o', 2), Creator(Callback), Utils(Util) -{ - this->source = "m_spanningtree.so"; - syntax = "<remote-server-mask> <target-server-mask>"; -} - -CmdResult cmd_rconnect::Handle (const char** parameters, int pcnt, userrec *user) -{ - if (IS_LOCAL(user)) - { - if (!Utils->FindServerMask(parameters[0])) - { - user->WriteServ("NOTICE %s :*** RCONNECT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]); - return CMD_FAILURE; - } - user->WriteServ("NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick,parameters[0],parameters[1]); - } - - /* Is this aimed at our server? */ - if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0])) - { - /* Yes, initiate the given connect */ - ServerInstance->SNO->WriteToSnoMask('l',"Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick,parameters[0],parameters[1]); - const char* para[1]; - para[0] = parameters[1]; - std::string original_command = std::string("CONNECT ") + parameters[1]; - Creator->OnPreCommand("CONNECT", para, 1, user, true, original_command); - } - return CMD_SUCCESS; -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/timesynctimer.h"
#include "m_spanningtree/resolvers.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/rconnect.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h */
cmd_rconnect::cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RCONNECT", 'o', 2), Creator(Callback), Utils(Util)
{
this->source = "m_spanningtree.so";
syntax = "<remote-server-mask> <target-server-mask>";
}
CmdResult cmd_rconnect::Handle (const char** parameters, int pcnt, userrec *user)
{
if (IS_LOCAL(user))
{
if (!Utils->FindServerMask(parameters[0]))
{
user->WriteServ("NOTICE %s :*** RCONNECT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]);
return CMD_FAILURE;
}
user->WriteServ("NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick,parameters[0],parameters[1]);
}
/* Is this aimed at our server? */
if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0]))
{
/* Yes, initiate the given connect */
ServerInstance->SNO->WriteToSnoMask('l',"Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick,parameters[0],parameters[1]);
const char* para[1];
para[0] = parameters[1];
std::string original_command = std::string("CONNECT ") + parameters[1];
Creator->OnPreCommand("CONNECT", para, 1, user, true, original_command);
}
return CMD_SUCCESS;
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/rconnect.h b/src/modules/m_spanningtree/rconnect.h index 77e271949..fca96f4a8 100644 --- a/src/modules/m_spanningtree/rconnect.h +++ b/src/modules/m_spanningtree/rconnect.h @@ -1,28 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __RCONNECT_H__ -#define __RCONNECT_H__ - -/** Handle /RCONNECT - */ -class cmd_rconnect : public command_t -{ - Module* Creator; /* Creator */ - SpanningTreeUtilities* Utils; /* Utility class */ - public: - cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util); - CmdResult Handle (const char** parameters, int pcnt, userrec *user); -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __RCONNECT_H__
#define __RCONNECT_H__
/** Handle /RCONNECT
*/
class cmd_rconnect : public command_t
{
Module* Creator; /* Creator */
SpanningTreeUtilities* Utils; /* Utility class */
public:
cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util);
CmdResult Handle (const char** parameters, int pcnt, userrec *user);
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/resolvers.cpp b/src/modules/m_spanningtree/resolvers.cpp index 0d94da99f..80971c699 100644 --- a/src/modules/m_spanningtree/resolvers.cpp +++ b/src/modules/m_spanningtree/resolvers.cpp @@ -1,88 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/resolvers.h" -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */ - -/** This class is used to resolve server hostnames during /connect and autoconnect. - * As of 1.1, the resolver system is seperated out from InspSocket, so we must do this - * resolver step first ourselves if we need it. This is totally nonblocking, and will - * callback to OnLookupComplete or OnError when completed. Once it has completed we - * will have an IP address which we can then use to continue our connection. - */ -ServernameResolver::ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt) : Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(Util), query(qt), host(hostname), mine(me) -{ - /* Nothing in here, folks */ -} - -void ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) -{ - /* Initiate the connection, now that we have an IP to use. - * Passing a hostname directly to InspSocket causes it to - * just bail and set its FD to -1. - */ - TreeServer* CheckDupe = Utils->FindServer(MyLink.Name.c_str()); - if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */ - { - - if ((!MyLink.Hook.empty()) && (Utils->hooks.find(MyLink.Hook.c_str()) == Utils->hooks.end())) - return; - - TreeSocket* newsocket = new TreeSocket(this->Utils, ServerInstance, result,MyLink.Port,false,MyLink.Timeout ? MyLink.Timeout : 10,MyLink.Name.c_str(), - MyLink.Bind, MyLink.Hook.empty() ? NULL : Utils->hooks[MyLink.Hook.c_str()]); - if (newsocket->GetFd() > -1) - { - /* We're all OK */ - } - else - { - /* Something barfed, show the opers */ - ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno)); - delete newsocket; - Utils->DoFailOver(&MyLink); - } - } -} - -void ServernameResolver::OnError(ResolverError e, const std::string &errormessage) -{ - /* Ooops! */ - if (query == DNS_QUERY_AAAA) - { - bool cached; - ServernameResolver* snr = new ServernameResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A); - ServerInstance->AddResolver(snr, cached); - return; - } - ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s",MyLink.Name.c_str(),errormessage.c_str()); - Utils->DoFailOver(&MyLink); -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/resolvers.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
/** This class is used to resolve server hostnames during /connect and autoconnect.
* As of 1.1, the resolver system is seperated out from InspSocket, so we must do this
* resolver step first ourselves if we need it. This is totally nonblocking, and will
* callback to OnLookupComplete or OnError when completed. Once it has completed we
* will have an IP address which we can then use to continue our connection.
*/
ServernameResolver::ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt) : Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(Util), query(qt), host(hostname), mine(me)
{
/* Nothing in here, folks */
}
void ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
{
/* Initiate the connection, now that we have an IP to use.
* Passing a hostname directly to InspSocket causes it to
* just bail and set its FD to -1.
*/
TreeServer* CheckDupe = Utils->FindServer(MyLink.Name.c_str());
if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */
{
if ((!MyLink.Hook.empty()) && (Utils->hooks.find(MyLink.Hook.c_str()) == Utils->hooks.end()))
return;
TreeSocket* newsocket = new TreeSocket(this->Utils, ServerInstance, result,MyLink.Port,false,MyLink.Timeout ? MyLink.Timeout : 10,MyLink.Name.c_str(),
MyLink.Bind, MyLink.Hook.empty() ? NULL : Utils->hooks[MyLink.Hook.c_str()]);
if (newsocket->GetFd() > -1)
{
/* We're all OK */
}
else
{
/* Something barfed, show the opers */
ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno));
delete newsocket;
Utils->DoFailOver(&MyLink);
}
}
}
void ServernameResolver::OnError(ResolverError e, const std::string &errormessage)
{
/* Ooops! */
if (query == DNS_QUERY_AAAA)
{
bool cached;
ServernameResolver* snr = new ServernameResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A);
ServerInstance->AddResolver(snr, cached);
return;
}
ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s",MyLink.Name.c_str(),errormessage.c_str());
Utils->DoFailOver(&MyLink);
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/resolvers.h b/src/modules/m_spanningtree/resolvers.h index 06fd05bad..0ba9d6bd6 100644 --- a/src/modules/m_spanningtree/resolvers.h +++ b/src/modules/m_spanningtree/resolvers.h @@ -1,90 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __RESOLVERS__H__ -#define __RESOLVERS__H__ - -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "inspircd.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/utils.h" -#include "m_spanningtree/link.h" - -/** Handle resolving of server IPs for the cache - */ -class SecurityIPResolver : public Resolver -{ - private: - Link MyLink; - SpanningTreeUtilities* Utils; - Module* mine; - std::string host; - QueryType query; - public: - SecurityIPResolver(Module* me, SpanningTreeUtilities* U, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt) - : Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(U), mine(me), host(hostname), query(qt) - { - } - - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) - { - Utils->ValidIPs.push_back(result); - } - - void OnError(ResolverError e, const std::string &errormessage) - { - if (query == DNS_QUERY_AAAA) - { - bool cached; - SecurityIPResolver* res = new SecurityIPResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A); - ServerInstance->AddResolver(res, cached); - return; - } - ServerInstance->Log(DEFAULT,"Could not resolve IP associated with Link '%s': %s",MyLink.Name.c_str(),errormessage.c_str()); - } -}; - -/** This class is used to resolve server hostnames during /connect and autoconnect. - * As of 1.1, the resolver system is seperated out from InspSocket, so we must do this - * resolver step first ourselves if we need it. This is totally nonblocking, and will - * callback to OnLookupComplete or OnError when completed. Once it has completed we - * will have an IP address which we can then use to continue our connection. - */ -class ServernameResolver : public Resolver -{ - private: - /** A copy of the Link tag info for what we're connecting to. - * We take a copy, rather than using a pointer, just in case the - * admin takes the tag away and rehashes while the domain is resolving. - */ - Link MyLink; - SpanningTreeUtilities* Utils; - QueryType query; - std::string host; - Module* mine; - public: - ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt); - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); - void OnError(ResolverError e, const std::string &errormessage); -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __RESOLVERS__H__
#define __RESOLVERS__H__
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "inspircd.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/link.h"
/** Handle resolving of server IPs for the cache
*/
class SecurityIPResolver : public Resolver
{
private:
Link MyLink;
SpanningTreeUtilities* Utils;
Module* mine;
std::string host;
QueryType query;
public:
SecurityIPResolver(Module* me, SpanningTreeUtilities* U, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt)
: Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(U), mine(me), host(hostname), query(qt)
{
}
void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
{
Utils->ValidIPs.push_back(result);
}
void OnError(ResolverError e, const std::string &errormessage)
{
if (query == DNS_QUERY_AAAA)
{
bool cached;
SecurityIPResolver* res = new SecurityIPResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A);
ServerInstance->AddResolver(res, cached);
return;
}
ServerInstance->Log(DEFAULT,"Could not resolve IP associated with Link '%s': %s",MyLink.Name.c_str(),errormessage.c_str());
}
};
/** This class is used to resolve server hostnames during /connect and autoconnect.
* As of 1.1, the resolver system is seperated out from InspSocket, so we must do this
* resolver step first ourselves if we need it. This is totally nonblocking, and will
* callback to OnLookupComplete or OnError when completed. Once it has completed we
* will have an IP address which we can then use to continue our connection.
*/
class ServernameResolver : public Resolver
{
private:
/** A copy of the Link tag info for what we're connecting to.
* We take a copy, rather than using a pointer, just in case the
* admin takes the tag away and rehashes while the domain is resolving.
*/
Link MyLink;
SpanningTreeUtilities* Utils;
QueryType query;
std::string host;
Module* mine;
public:
ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt);
void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);
void OnError(ResolverError e, const std::string &errormessage);
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/rsquit.cpp b/src/modules/m_spanningtree/rsquit.cpp index 5f3d33fc0..7bb6abfc1 100644 --- a/src/modules/m_spanningtree/rsquit.cpp +++ b/src/modules/m_spanningtree/rsquit.cpp @@ -1,123 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/timesynctimer.h" -#include "m_spanningtree/resolvers.h" -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" -#include "m_spanningtree/rsquit.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rsquit.h */ - -cmd_rsquit::cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RSQUIT", 'o', 1), Creator(Callback), Utils(Util) -{ - this->source = "m_spanningtree.so"; - syntax = "<remote-server-mask> [target-server-mask]"; -} - -CmdResult cmd_rsquit::Handle (const char** parameters, int pcnt, userrec *user) -{ - if (IS_LOCAL(user)) - { - if (!Utils->FindServerMask(parameters[0])) - { - user->WriteServ("NOTICE %s :*** RSQUIT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]); - return CMD_FAILURE; - } - if (pcnt > 1) - user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit to \002%s\002 to squit server \002%s\002.",user->nick,parameters[0],parameters[1]); - else - user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit for server \002%s\002.",user->nick,parameters[0]); - } - - TreeServer* s = (pcnt > 1) ? Utils->FindServerMask(parameters[1]) : Utils->FindServerMask(parameters[0]); - - if (pcnt > 1) - { - if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0])) - { - if (s) - { - if (s == Utils->TreeRoot) - { - NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[1])+" matches local server name)"); - return CMD_FAILURE; - } - TreeSocket* sock = s->GetSocket(); - if (!sock) - { - NoticeUser(user, "*** RSQUIT: Server \002"+ConvToStr(parameters[1])+"\002 isn't connected to \002"+ConvToStr(parameters[0])+"\002."); - return CMD_FAILURE; - } - ServerInstance->SNO->WriteToSnoMask('l',"Remote SQUIT from %s matching \002%s\002, squitting server \002%s\002",user->nick,parameters[0],parameters[1]); - const char* para[1]; - para[0] = parameters[1]; - std::string original_command = std::string("SQUIT ") + parameters[1]; - Creator->OnPreCommand("SQUIT", para, 1, user, true, original_command); - return CMD_LOCALONLY; - } - } - } - else - { - if (s) - { - if (s == Utils->TreeRoot) - { - NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[0])+" matches local server name)"); - return CMD_FAILURE; - } - TreeSocket* sock = s->GetSocket(); - if (sock) - { - ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); - sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost()); - ServerInstance->SE->DelFd(sock); - sock->Close(); - return CMD_LOCALONLY; - } - } - } - - return CMD_SUCCESS; -} - -void cmd_rsquit::NoticeUser(userrec* user, const std::string &msg) -{ - if (IS_LOCAL(user)) - { - user->WriteServ("NOTICE %s :%s",user->nick,msg.c_str()); - } - else - { - std::deque<std::string> params; - params.push_back(user->nick); - params.push_back("NOTICE "+ConvToStr(user->nick)+" :"+msg); - Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", params, user->server); - } -} +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/timesynctimer.h"
#include "m_spanningtree/resolvers.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/rsquit.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rsquit.h */
cmd_rsquit::cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RSQUIT", 'o', 1), Creator(Callback), Utils(Util)
{
this->source = "m_spanningtree.so";
syntax = "<remote-server-mask> [target-server-mask]";
}
CmdResult cmd_rsquit::Handle (const char** parameters, int pcnt, userrec *user)
{
if (IS_LOCAL(user))
{
if (!Utils->FindServerMask(parameters[0]))
{
user->WriteServ("NOTICE %s :*** RSQUIT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]);
return CMD_FAILURE;
}
if (pcnt > 1)
user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit to \002%s\002 to squit server \002%s\002.",user->nick,parameters[0],parameters[1]);
else
user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit for server \002%s\002.",user->nick,parameters[0]);
}
TreeServer* s = (pcnt > 1) ? Utils->FindServerMask(parameters[1]) : Utils->FindServerMask(parameters[0]);
if (pcnt > 1)
{
if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0]))
{
if (s)
{
if (s == Utils->TreeRoot)
{
NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[1])+" matches local server name)");
return CMD_FAILURE;
}
TreeSocket* sock = s->GetSocket();
if (!sock)
{
NoticeUser(user, "*** RSQUIT: Server \002"+ConvToStr(parameters[1])+"\002 isn't connected to \002"+ConvToStr(parameters[0])+"\002.");
return CMD_FAILURE;
}
ServerInstance->SNO->WriteToSnoMask('l',"Remote SQUIT from %s matching \002%s\002, squitting server \002%s\002",user->nick,parameters[0],parameters[1]);
const char* para[1];
para[0] = parameters[1];
std::string original_command = std::string("SQUIT ") + parameters[1];
Creator->OnPreCommand("SQUIT", para, 1, user, true, original_command);
return CMD_LOCALONLY;
}
}
}
else
{
if (s)
{
if (s == Utils->TreeRoot)
{
NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[0])+" matches local server name)");
return CMD_FAILURE;
}
TreeSocket* sock = s->GetSocket();
if (sock)
{
ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick);
sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost());
ServerInstance->SE->DelFd(sock);
sock->Close();
return CMD_LOCALONLY;
}
}
}
return CMD_SUCCESS;
}
void cmd_rsquit::NoticeUser(userrec* user, const std::string &msg)
{
if (IS_LOCAL(user))
{
user->WriteServ("NOTICE %s :%s",user->nick,msg.c_str());
}
else
{
std::deque<std::string> params;
params.push_back(user->nick);
params.push_back("NOTICE "+ConvToStr(user->nick)+" :"+msg);
Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", params, user->server);
}
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/rsquit.h b/src/modules/m_spanningtree/rsquit.h index 81e9bc2b7..ed9eb83d4 100644 --- a/src/modules/m_spanningtree/rsquit.h +++ b/src/modules/m_spanningtree/rsquit.h @@ -1,29 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __RSQUIT_H__ -#define __RSQUIT_H__ - -/** Handle /RCONNECT - */ -class cmd_rsquit : public command_t -{ - Module* Creator; /* Creator */ - SpanningTreeUtilities* Utils; /* Utility class */ - public: - cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util); - CmdResult Handle (const char** parameters, int pcnt, userrec *user); - void NoticeUser(userrec* user, const std::string &msg); -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __RSQUIT_H__
#define __RSQUIT_H__
/** Handle /RCONNECT
*/
class cmd_rsquit : public command_t
{
Module* Creator; /* Creator */
SpanningTreeUtilities* Utils; /* Utility class */
public:
cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util);
CmdResult Handle (const char** parameters, int pcnt, userrec *user);
void NoticeUser(userrec* user, const std::string &msg);
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/timesynctimer.cpp b/src/modules/m_spanningtree/timesynctimer.cpp index af615e91e..8ecb84a4b 100644 --- a/src/modules/m_spanningtree/timesynctimer.cpp +++ b/src/modules/m_spanningtree/timesynctimer.cpp @@ -1,52 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/timesynctimer.h" -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */ - -TimeSyncTimer::TimeSyncTimer(InspIRCd *Inst, ModuleSpanningTree *Mod) : InspTimer(600, Inst->Time(), true), Instance(Inst), Module(Mod) -{ -} - -void TimeSyncTimer::Tick(time_t TIME) -{ - Module->BroadcastTimeSync(); -} - -CacheRefreshTimer::CacheRefreshTimer(InspIRCd *Inst, SpanningTreeUtilities *Util) : InspTimer(3600, Inst->Time(), true), Instance(Inst), Utils(Util) -{ -} - -void CacheRefreshTimer::Tick(time_t TIME) -{ - Utils->RefreshIPCache(); -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/timesynctimer.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
TimeSyncTimer::TimeSyncTimer(InspIRCd *Inst, ModuleSpanningTree *Mod) : InspTimer(600, Inst->Time(), true), Instance(Inst), Module(Mod)
{
}
void TimeSyncTimer::Tick(time_t TIME)
{
Module->BroadcastTimeSync();
}
CacheRefreshTimer::CacheRefreshTimer(InspIRCd *Inst, SpanningTreeUtilities *Util) : InspTimer(3600, Inst->Time(), true), Instance(Inst), Utils(Util)
{
}
void CacheRefreshTimer::Tick(time_t TIME)
{
Utils->RefreshIPCache();
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/timesynctimer.h b/src/modules/m_spanningtree/timesynctimer.h index 434ee253c..dd23ee171 100644 --- a/src/modules/m_spanningtree/timesynctimer.h +++ b/src/modules/m_spanningtree/timesynctimer.h @@ -1,47 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __TIMESYNC_H__ -#define __TIMESYNC_H__ - -#include "timer.h" - -class ModuleSpanningTree; -class SpanningTreeUtilities; -class InspIRCd; - -/** Create a timer which recurs every second, we inherit from InspTimer. - * InspTimer is only one-shot however, so at the end of each Tick() we simply - * insert another of ourselves into the pending queue :) - */ -class TimeSyncTimer : public InspTimer -{ - private: - InspIRCd *Instance; - ModuleSpanningTree *Module; - public: - TimeSyncTimer(InspIRCd *Instance, ModuleSpanningTree *Mod); - virtual void Tick(time_t TIME); -}; - -class CacheRefreshTimer : public InspTimer -{ - private: - InspIRCd *Instance; - SpanningTreeUtilities *Utils; - public: - CacheRefreshTimer(InspIRCd *Instance, SpanningTreeUtilities* Util); - virtual void Tick(time_t TIME); -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __TIMESYNC_H__
#define __TIMESYNC_H__
#include "timer.h"
class ModuleSpanningTree;
class SpanningTreeUtilities;
class InspIRCd;
/** Create a timer which recurs every second, we inherit from InspTimer.
* InspTimer is only one-shot however, so at the end of each Tick() we simply
* insert another of ourselves into the pending queue :)
*/
class TimeSyncTimer : public InspTimer
{
private:
InspIRCd *Instance;
ModuleSpanningTree *Module;
public:
TimeSyncTimer(InspIRCd *Instance, ModuleSpanningTree *Mod);
virtual void Tick(time_t TIME);
};
class CacheRefreshTimer : public InspTimer
{
private:
InspIRCd *Instance;
SpanningTreeUtilities *Utils;
public:
CacheRefreshTimer(InspIRCd *Instance, SpanningTreeUtilities* Util);
virtual void Tick(time_t TIME);
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/treeserver.cpp b/src/modules/m_spanningtree/treeserver.cpp index b5cac1802..670f7e420 100644 --- a/src/modules/m_spanningtree/treeserver.cpp +++ b/src/modules/m_spanningtree/treeserver.cpp @@ -1,325 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" - -/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h */ - -TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance) : ServerInstance(Instance), Utils(Util) -{ - Parent = NULL; - ServerName.clear(); - ServerDesc.clear(); - VersionString.clear(); - UserCount = OperCount = 0; - rtt = LastPing = 0; - Hidden = false; - VersionString = ServerInstance->GetVersionString(); -} - -/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which - * represents our own server. Therefore, it has no route, no parent, and - * no socket associated with it. Its version string is our own local version. - */ -TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc) : ServerInstance(Instance), ServerName(Name.c_str()), ServerDesc(Desc), Utils(Util) -{ - Parent = NULL; - VersionString.clear(); - UserCount = ServerInstance->UserCount(); - OperCount = ServerInstance->OperCount(); - VersionString = ServerInstance->GetVersionString(); - Route = NULL; - Socket = NULL; /* Fix by brain */ - rtt = LastPing = 0; - Hidden = false; - AddHashEntry(); -} - -/** When we create a new server, we call this constructor to initialize it. - * This constructor initializes the server's Route and Parent, and sets up - * its ping counters so that it will be pinged one minute from now. - */ -TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide) - : ServerInstance(Instance), Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock), Utils(Util), Hidden(Hide) -{ - VersionString.clear(); - UserCount = OperCount = 0; - this->SetNextPingTime(time(NULL) + 60); - this->SetPingFlag(); - rtt = LastPing = 0; - /* find the 'route' for this server (e.g. the one directly connected - * to the local server, which we can use to reach it) - * - * In the following example, consider we have just added a TreeServer - * class for server G on our network, of which we are server A. - * To route traffic to G (marked with a *) we must send the data to - * B (marked with a +) so this algorithm initializes the 'Route' - * value to point at whichever server traffic must be routed through - * to get here. If we were to try this algorithm with server B, - * the Route pointer would point at its own object ('this'). - * - * A - * / \ - * + B C - * / \ \ - * D E F - * / \ - * * G H - * - * We only run this algorithm when a server is created, as - * the routes remain constant while ever the server exists, and - * do not need to be re-calculated. - */ - - Route = Above; - if (Route == Utils->TreeRoot) - { - Route = this; - } - else - { - while (this->Route->GetParent() != Utils->TreeRoot) - { - this->Route = Route->GetParent(); - } - } - - /* Because recursive code is slow and takes a lot of resources, - * we store two representations of the server tree. The first - * is a recursive structure where each server references its - * children and its parent, which is used for netbursts and - * netsplits to dump the whole dataset to the other server, - * and the second is used for very fast lookups when routing - * messages and is instead a hash_map, where each item can - * be referenced by its server name. The AddHashEntry() - * call below automatically inserts each TreeServer class - * into the hash_map as it is created. There is a similar - * maintainance call in the destructor to tidy up deleted - * servers. - */ - - this->AddHashEntry(); -} - -int TreeServer::QuitUsers(const std::string &reason) -{ - const char* reason_s = reason.c_str(); - std::vector<userrec*> time_to_die; - for (user_hash::iterator n = ServerInstance->clientlist->begin(); n != ServerInstance->clientlist->end(); n++) - { - if (!strcmp(n->second->server, this->ServerName.c_str())) - { - time_to_die.push_back(n->second); - } - } - for (std::vector<userrec*>::iterator n = time_to_die.begin(); n != time_to_die.end(); n++) - { - userrec* a = (userrec*)*n; - if (!IS_LOCAL(a)) - { - if (ServerInstance->Config->HideSplits) - userrec::QuitUser(ServerInstance, a, "*.net *.split", reason_s); - else - userrec::QuitUser(ServerInstance, a, reason_s); - - if (this->Utils->quiet_bursts) - ServerInstance->GlobalCulls.MakeSilent(a); - } - } - return time_to_die.size(); -} - -/** This method is used to add the structure to the - * hash_map for linear searches. It is only called - * by the constructors. - */ -void TreeServer::AddHashEntry() -{ - server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str()); - if (iter == Utils->serverlist.end()) - Utils->serverlist[this->ServerName.c_str()] = this; -} - -/** This method removes the reference to this object - * from the hash_map which is used for linear searches. - * It is only called by the default destructor. - */ -void TreeServer::DelHashEntry() -{ - server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str()); - if (iter != Utils->serverlist.end()) - Utils->serverlist.erase(iter); -} - -/** These accessors etc should be pretty self- - * explanitory. - */ -TreeServer* TreeServer::GetRoute() -{ - return Route; -} - -std::string TreeServer::GetName() -{ - return ServerName.c_str(); -} - -std::string TreeServer::GetDesc() -{ - return ServerDesc; -} - -std::string TreeServer::GetVersion() -{ - return VersionString; -} - -void TreeServer::SetNextPingTime(time_t t) -{ - this->NextPing = t; - LastPingWasGood = false; -} - -time_t TreeServer::NextPingTime() -{ - return NextPing; -} - -bool TreeServer::AnsweredLastPing() -{ - return LastPingWasGood; -} - -void TreeServer::SetPingFlag() -{ - LastPingWasGood = true; -} - -int TreeServer::GetUserCount() -{ - return UserCount; -} - -void TreeServer::AddUserCount() -{ - UserCount++; -} - -void TreeServer::DelUserCount() -{ - UserCount--; -} - -int TreeServer::GetOperCount() -{ - return OperCount; -} - -TreeSocket* TreeServer::GetSocket() -{ - return Socket; -} - -TreeServer* TreeServer::GetParent() -{ - return Parent; -} - -void TreeServer::SetVersion(const std::string &Version) -{ - VersionString = Version; -} - -unsigned int TreeServer::ChildCount() -{ - return Children.size(); -} - -TreeServer* TreeServer::GetChild(unsigned int n) -{ - if (n < Children.size()) - { - /* Make sure they cant request - * an out-of-range object. After - * all we know what these programmer - * types are like *grin*. - */ - return Children[n]; - } - else - { - return NULL; - } -} - -void TreeServer::AddChild(TreeServer* Child) -{ - Children.push_back(Child); -} - -bool TreeServer::DelChild(TreeServer* Child) -{ - for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++) - { - if (*a == Child) - { - Children.erase(a); - return true; - } - } - return false; -} - -/** Removes child nodes of this node, and of that node, etc etc. - * This is used during netsplits to automatically tidy up the - * server tree. It is slow, we don't use it for much else. - */ -bool TreeServer::Tidy() -{ - bool stillchildren = true; - while (stillchildren) - { - stillchildren = false; - for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++) - { - TreeServer* s = (TreeServer*)*a; - s->Tidy(); - Children.erase(a); - DELETE(s); - stillchildren = true; - break; - } - } - return true; -} - -TreeServer::~TreeServer() -{ - /* We'd better tidy up after ourselves, eh? */ - this->DelHashEntry(); -} - - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h */
TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance) : ServerInstance(Instance), Utils(Util)
{
Parent = NULL;
ServerName.clear();
ServerDesc.clear();
VersionString.clear();
UserCount = OperCount = 0;
rtt = LastPing = 0;
Hidden = false;
VersionString = ServerInstance->GetVersionString();
}
/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
* represents our own server. Therefore, it has no route, no parent, and
* no socket associated with it. Its version string is our own local version.
*/
TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc) : ServerInstance(Instance), ServerName(Name.c_str()), ServerDesc(Desc), Utils(Util)
{
Parent = NULL;
VersionString.clear();
UserCount = ServerInstance->UserCount();
OperCount = ServerInstance->OperCount();
VersionString = ServerInstance->GetVersionString();
Route = NULL;
Socket = NULL; /* Fix by brain */
rtt = LastPing = 0;
Hidden = false;
AddHashEntry();
}
/** When we create a new server, we call this constructor to initialize it.
* This constructor initializes the server's Route and Parent, and sets up
* its ping counters so that it will be pinged one minute from now.
*/
TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide)
: ServerInstance(Instance), Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock), Utils(Util), Hidden(Hide)
{
VersionString.clear();
UserCount = OperCount = 0;
this->SetNextPingTime(time(NULL) + 60);
this->SetPingFlag();
rtt = LastPing = 0;
/* find the 'route' for this server (e.g. the one directly connected
* to the local server, which we can use to reach it)
*
* In the following example, consider we have just added a TreeServer
* class for server G on our network, of which we are server A.
* To route traffic to G (marked with a *) we must send the data to
* B (marked with a +) so this algorithm initializes the 'Route'
* value to point at whichever server traffic must be routed through
* to get here. If we were to try this algorithm with server B,
* the Route pointer would point at its own object ('this').
*
* A
* / \
* + B C
* / \ \
* D E F
* / \
* * G H
*
* We only run this algorithm when a server is created, as
* the routes remain constant while ever the server exists, and
* do not need to be re-calculated.
*/
Route = Above;
if (Route == Utils->TreeRoot)
{
Route = this;
}
else
{
while (this->Route->GetParent() != Utils->TreeRoot)
{
this->Route = Route->GetParent();
}
}
/* Because recursive code is slow and takes a lot of resources,
* we store two representations of the server tree. The first
* is a recursive structure where each server references its
* children and its parent, which is used for netbursts and
* netsplits to dump the whole dataset to the other server,
* and the second is used for very fast lookups when routing
* messages and is instead a hash_map, where each item can
* be referenced by its server name. The AddHashEntry()
* call below automatically inserts each TreeServer class
* into the hash_map as it is created. There is a similar
* maintainance call in the destructor to tidy up deleted
* servers.
*/
this->AddHashEntry();
}
int TreeServer::QuitUsers(const std::string &reason)
{
const char* reason_s = reason.c_str();
std::vector<userrec*> time_to_die;
for (user_hash::iterator n = ServerInstance->clientlist->begin(); n != ServerInstance->clientlist->end(); n++)
{
if (!strcmp(n->second->server, this->ServerName.c_str()))
{
time_to_die.push_back(n->second);
}
}
for (std::vector<userrec*>::iterator n = time_to_die.begin(); n != time_to_die.end(); n++)
{
userrec* a = (userrec*)*n;
if (!IS_LOCAL(a))
{
if (ServerInstance->Config->HideSplits)
userrec::QuitUser(ServerInstance, a, "*.net *.split", reason_s);
else
userrec::QuitUser(ServerInstance, a, reason_s);
if (this->Utils->quiet_bursts)
ServerInstance->GlobalCulls.MakeSilent(a);
}
}
return time_to_die.size();
}
/** This method is used to add the structure to the
* hash_map for linear searches. It is only called
* by the constructors.
*/
void TreeServer::AddHashEntry()
{
server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
if (iter == Utils->serverlist.end())
Utils->serverlist[this->ServerName.c_str()] = this;
}
/** This method removes the reference to this object
* from the hash_map which is used for linear searches.
* It is only called by the default destructor.
*/
void TreeServer::DelHashEntry()
{
server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
if (iter != Utils->serverlist.end())
Utils->serverlist.erase(iter);
}
/** These accessors etc should be pretty self-
* explanitory.
*/
TreeServer* TreeServer::GetRoute()
{
return Route;
}
std::string TreeServer::GetName()
{
return ServerName.c_str();
}
std::string TreeServer::GetDesc()
{
return ServerDesc;
}
std::string TreeServer::GetVersion()
{
return VersionString;
}
void TreeServer::SetNextPingTime(time_t t)
{
this->NextPing = t;
LastPingWasGood = false;
}
time_t TreeServer::NextPingTime()
{
return NextPing;
}
bool TreeServer::AnsweredLastPing()
{
return LastPingWasGood;
}
void TreeServer::SetPingFlag()
{
LastPingWasGood = true;
}
int TreeServer::GetUserCount()
{
return UserCount;
}
void TreeServer::AddUserCount()
{
UserCount++;
}
void TreeServer::DelUserCount()
{
UserCount--;
}
int TreeServer::GetOperCount()
{
return OperCount;
}
TreeSocket* TreeServer::GetSocket()
{
return Socket;
}
TreeServer* TreeServer::GetParent()
{
return Parent;
}
void TreeServer::SetVersion(const std::string &Version)
{
VersionString = Version;
}
unsigned int TreeServer::ChildCount()
{
return Children.size();
}
TreeServer* TreeServer::GetChild(unsigned int n)
{
if (n < Children.size())
{
/* Make sure they cant request
* an out-of-range object. After
* all we know what these programmer
* types are like *grin*.
*/
return Children[n];
}
else
{
return NULL;
}
}
void TreeServer::AddChild(TreeServer* Child)
{
Children.push_back(Child);
}
bool TreeServer::DelChild(TreeServer* Child)
{
for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++)
{
if (*a == Child)
{
Children.erase(a);
return true;
}
}
return false;
}
/** Removes child nodes of this node, and of that node, etc etc.
* This is used during netsplits to automatically tidy up the
* server tree. It is slow, we don't use it for much else.
*/
bool TreeServer::Tidy()
{
bool stillchildren = true;
while (stillchildren)
{
stillchildren = false;
for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++)
{
TreeServer* s = (TreeServer*)*a;
s->Tidy();
Children.erase(a);
DELETE(s);
stillchildren = true;
break;
}
}
return true;
}
TreeServer::~TreeServer()
{
/* We'd better tidy up after ourselves, eh? */
this->DelHashEntry();
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/treeserver.h b/src/modules/m_spanningtree/treeserver.h index 514d6bc07..e942c1acc 100644 --- a/src/modules/m_spanningtree/treeserver.h +++ b/src/modules/m_spanningtree/treeserver.h @@ -1,186 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __TREESERVER_H__ -#define __TREESERVER_H__ - -/** Each server in the tree is represented by one class of - * type TreeServer. A locally connected TreeServer can - * have a class of type TreeSocket associated with it, for - * remote servers, the TreeSocket entry will be NULL. - * Each server also maintains a pointer to its parent - * (NULL if this server is ours, at the top of the tree) - * and a pointer to its "Route" (see the comments in the - * constructors below), and also a dynamic list of pointers - * to its children which can be iterated recursively - * if required. Creating or deleting objects of type - i* TreeServer automatically maintains the hash_map of - * TreeServer items, deleting and inserting them as they - * are created and destroyed. - */ -class TreeServer : public classbase -{ - InspIRCd* ServerInstance; /* Creator */ - TreeServer* Parent; /* Parent entry */ - TreeServer* Route; /* Route entry */ - std::vector<TreeServer*> Children; /* List of child objects */ - irc::string ServerName; /* Server's name */ - std::string ServerDesc; /* Server's description */ - std::string VersionString; /* Version string or empty string */ - int UserCount; /* Not used in this version */ - int OperCount; /* Not used in this version */ - TreeSocket* Socket; /* For directly connected servers this points at the socket object */ - time_t NextPing; /* After this time, the server should be PINGed*/ - bool LastPingWasGood; /* True if the server responded to the last PING with a PONG */ - SpanningTreeUtilities* Utils; /* Utility class */ - - public: - - bool Warned; /* True if we've warned opers about high latency on this server */ - - /** We don't use this constructor. Its a dummy, and won't cause any insertion - * of the TreeServer into the hash_map. See below for the two we DO use. - */ - TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance); - - /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which - * represents our own server. Therefore, it has no route, no parent, and - * no socket associated with it. Its version string is our own local version. - */ - TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc); - - /** When we create a new server, we call this constructor to initialize it. - * This constructor initializes the server's Route and Parent, and sets up - * its ping counters so that it will be pinged one minute from now. - */ - TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide); - - int QuitUsers(const std::string &reason); - - /** This method is used to add the structure to the - * hash_map for linear searches. It is only called - * by the constructors. - */ - void AddHashEntry(); - - /** This method removes the reference to this object - * from the hash_map which is used for linear searches. - * It is only called by the default destructor. - */ - void DelHashEntry(); - - /** Get route. - * The 'route' is defined as the locally- - * connected server which can be used to reach this server. - */ - TreeServer* GetRoute(); - - /** Get server name - */ - std::string GetName(); - - /** Get server description (GECOS) - */ - std::string GetDesc(); - - /** Get server version string - */ - std::string GetVersion(); - - /** Set time we are next due to ping this server - */ - void SetNextPingTime(time_t t); - - /** Get the time we are next due to ping this server - */ - time_t NextPingTime(); - - /** Time of last ping used to calculate this->rtt below - */ - time_t LastPing; - - /** Round trip time of last ping - */ - time_t rtt; - - /** True if this server is hidden - */ - bool Hidden; - - /** True if the server answered their last ping - */ - bool AnsweredLastPing(); - - /** Set the server as responding to its last ping - */ - void SetPingFlag(); - - /** Get the number of users on this server for MAP - */ - int GetUserCount(); - - /** Increment the user counter - */ - void AddUserCount(); - - /** Decrement the user counter - */ - void DelUserCount(); - - /** Get the oper count for this server - */ - int GetOperCount(); - - /** Get the TreeSocket pointer for local servers. - * For remote servers, this returns NULL. - */ - TreeSocket* GetSocket(); - - /** Get the parent server. - * For the root node, this returns NULL. - */ - TreeServer* GetParent(); - - /** Set the server version string - */ - void SetVersion(const std::string &Version); - - /** Return number of child servers - */ - unsigned int ChildCount(); - - /** Return a child server indexed 0..n - */ - TreeServer* GetChild(unsigned int n); - - /** Add a child server - */ - void AddChild(TreeServer* Child); - - /** Delete a child server, return false if it didn't exist. - */ - bool DelChild(TreeServer* Child); - - /** Removes child nodes of this node, and of that node, etc etc. - * This is used during netsplits to automatically tidy up the - * server tree. It is slow, we don't use it for much else. - */ - bool Tidy(); - - /** Destructor - */ - ~TreeServer(); - -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __TREESERVER_H__
#define __TREESERVER_H__
/** Each server in the tree is represented by one class of
* type TreeServer. A locally connected TreeServer can
* have a class of type TreeSocket associated with it, for
* remote servers, the TreeSocket entry will be NULL.
* Each server also maintains a pointer to its parent
* (NULL if this server is ours, at the top of the tree)
* and a pointer to its "Route" (see the comments in the
* constructors below), and also a dynamic list of pointers
* to its children which can be iterated recursively
* if required. Creating or deleting objects of type
i* TreeServer automatically maintains the hash_map of
* TreeServer items, deleting and inserting them as they
* are created and destroyed.
*/
class TreeServer : public classbase
{
InspIRCd* ServerInstance; /* Creator */
TreeServer* Parent; /* Parent entry */
TreeServer* Route; /* Route entry */
std::vector<TreeServer*> Children; /* List of child objects */
irc::string ServerName; /* Server's name */
std::string ServerDesc; /* Server's description */
std::string VersionString; /* Version string or empty string */
int UserCount; /* Not used in this version */
int OperCount; /* Not used in this version */
TreeSocket* Socket; /* For directly connected servers this points at the socket object */
time_t NextPing; /* After this time, the server should be PINGed*/
bool LastPingWasGood; /* True if the server responded to the last PING with a PONG */
SpanningTreeUtilities* Utils; /* Utility class */
public:
bool Warned; /* True if we've warned opers about high latency on this server */
/** We don't use this constructor. Its a dummy, and won't cause any insertion
* of the TreeServer into the hash_map. See below for the two we DO use.
*/
TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance);
/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
* represents our own server. Therefore, it has no route, no parent, and
* no socket associated with it. Its version string is our own local version.
*/
TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc);
/** When we create a new server, we call this constructor to initialize it.
* This constructor initializes the server's Route and Parent, and sets up
* its ping counters so that it will be pinged one minute from now.
*/
TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide);
int QuitUsers(const std::string &reason);
/** This method is used to add the structure to the
* hash_map for linear searches. It is only called
* by the constructors.
*/
void AddHashEntry();
/** This method removes the reference to this object
* from the hash_map which is used for linear searches.
* It is only called by the default destructor.
*/
void DelHashEntry();
/** Get route.
* The 'route' is defined as the locally-
* connected server which can be used to reach this server.
*/
TreeServer* GetRoute();
/** Get server name
*/
std::string GetName();
/** Get server description (GECOS)
*/
std::string GetDesc();
/** Get server version string
*/
std::string GetVersion();
/** Set time we are next due to ping this server
*/
void SetNextPingTime(time_t t);
/** Get the time we are next due to ping this server
*/
time_t NextPingTime();
/** Time of last ping used to calculate this->rtt below
*/
time_t LastPing;
/** Round trip time of last ping
*/
time_t rtt;
/** True if this server is hidden
*/
bool Hidden;
/** True if the server answered their last ping
*/
bool AnsweredLastPing();
/** Set the server as responding to its last ping
*/
void SetPingFlag();
/** Get the number of users on this server for MAP
*/
int GetUserCount();
/** Increment the user counter
*/
void AddUserCount();
/** Decrement the user counter
*/
void DelUserCount();
/** Get the oper count for this server
*/
int GetOperCount();
/** Get the TreeSocket pointer for local servers.
* For remote servers, this returns NULL.
*/
TreeSocket* GetSocket();
/** Get the parent server.
* For the root node, this returns NULL.
*/
TreeServer* GetParent();
/** Set the server version string
*/
void SetVersion(const std::string &Version);
/** Return number of child servers
*/
unsigned int ChildCount();
/** Return a child server indexed 0..n
*/
TreeServer* GetChild(unsigned int n);
/** Add a child server
*/
void AddChild(TreeServer* Child);
/** Delete a child server, return false if it didn't exist.
*/
bool DelChild(TreeServer* Child);
/** Removes child nodes of this node, and of that node, etc etc.
* This is used during netsplits to automatically tidy up the
* server tree. It is slow, we don't use it for much else.
*/
bool Tidy();
/** Destructor
*/
~TreeServer();
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index fae22638d..bd99c1480 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -1,413 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __TREESOCKET_H__ -#define __TREESOCKET_H__ - -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "inspircd.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" - -#include "m_spanningtree/utils.h" - -/* - * The server list in InspIRCd is maintained as two structures - * which hold the data in different ways. Most of the time, we - * want to very quicky obtain three pieces of information: - * - * (1) The information on a server - * (2) The information on the server we must send data through - * to actually REACH the server we're after - * (3) Potentially, the child/parent objects of this server - * - * The InspIRCd spanning protocol provides easy access to these - * by storing the data firstly in a recursive structure, where - * each item references its parent item, and a dynamic list - * of child items, and another structure which stores the items - * hashed, linearly. This means that if we want to find a server - * by name quickly, we can look it up in the hash, avoiding - * any O(n) lookups. If however, during a split or sync, we want - * to apply an operation to a server, and any of its child objects - * we can resort to recursion to walk the tree structure. - * Any socket can have one of five states at any one time. - * The LISTENER state indicates a socket which is listening - * for connections. It cannot receive data itself, only incoming - * sockets. - * The CONNECTING state indicates an outbound socket which is - * waiting to be writeable. - * The WAIT_AUTH_1 state indicates the socket is outbound and - * has successfully connected, but has not yet sent and received - * SERVER strings. - * The WAIT_AUTH_2 state indicates that the socket is inbound - * (allocated by a LISTENER) but has not yet sent and received - * SERVER strings. - * The CONNECTED state represents a fully authorized, fully - * connected server. - */ -enum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED }; - -/** Every SERVER connection inbound or outbound is represented by - * an object of type TreeSocket. - * TreeSockets, being inherited from InspSocket, can be tied into - * the core socket engine, and we cn therefore receive activity events - * for them, just like activex objects on speed. (yes really, that - * is a technical term!) Each of these which relates to a locally - * connected server is assocated with it, by hooking it onto a - * TreeSocket class using its constructor. In this way, we can - * maintain a list of servers, some of which are directly connected, - * some of which are not. - */ -class TreeSocket : public InspSocket -{ - SpanningTreeUtilities* Utils; /* Utility class */ - std::string myhost; /* Canonical hostname */ - std::string in_buffer; /* Input buffer */ - ServerState LinkState; /* Link state */ - std::string InboundServerName; /* Server name sent to us by other side */ - std::string InboundDescription; /* Server description (GECOS) sent to us by the other side */ - int num_lost_users; /* Users lost in split */ - int num_lost_servers; /* Servers lost in split */ - time_t NextPing; /* Time when we are due to ping this server */ - bool LastPingWasGood; /* Responded to last ping we sent? */ - bool bursting; /* True if not finished bursting yet */ - unsigned int keylength; /* Is this still used? */ - std::string ModuleList; /* Module list of other server from CAPAB */ - std::map<std::string,std::string> CapKeys; /* CAPAB keys from other server */ - Module* Hook; /* I/O hooking module that we're attached to for this socket */ - std::string ourchallenge; /* Challenge sent for challenge/response */ - std::string theirchallenge; /* Challenge recv for challenge/response */ - std::string OutboundPass; /* Outbound password */ - bool sentcapab; /* Have sent CAPAB already */ - public: - - /** Because most of the I/O gubbins are encapsulated within - * InspSocket, we just call the superclass constructor for - * most of the action, and append a few of our own values - * to it. - */ - TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod = NULL); - - /** Because most of the I/O gubbins are encapsulated within - * InspSocket, we just call the superclass constructor for - * most of the action, and append a few of our own values - * to it. - */ - TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod = NULL); - - /** When a listening socket gives us a new file descriptor, - * we must associate it with a socket without creating a new - * connection. This constructor is used for this purpose. - */ - TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod = NULL); - - /** Get link state - */ - ServerState GetLinkState(); - - /** Get challenge set in our CAPAB for challenge/response - */ - const std::string& GetOurChallenge(); - - /** Get challenge set in our CAPAB for challenge/response - */ - void SetOurChallenge(const std::string &c); - - /** Get challenge set in their CAPAB for challenge/response - */ - const std::string& GetTheirChallenge(); - - /** Get challenge set in their CAPAB for challenge/response - */ - void SetTheirChallenge(const std::string &c); - - /** Compare two passwords based on authentication scheme - */ - bool ComparePass(const std::string &ours, const std::string &theirs); - - /** Return the module which we are hooking to for I/O encapsulation - */ - Module* GetHook(); - - /** Destructor - */ - ~TreeSocket(); - - /** Generate random string used for challenge-response auth - */ - std::string RandString(unsigned int length); - - /** Construct a password, optionally hashed with the other side's - * challenge string - */ - std::string MakePass(const std::string &password, const std::string &challenge); - - /** When an outbound connection finishes connecting, we receive - * this event, and must send our SERVER string to the other - * side. If the other side is happy, as outlined in the server - * to server docs on the inspircd.org site, the other side - * will then send back its own server string. - */ - virtual bool OnConnected(); - - /** Handle socket error event - */ - virtual void OnError(InspSocketError e); - - /** Sends an error to the remote server, and displays it locally to show - * that it was sent. - */ - void SendError(const std::string &errormessage); - - /** Handle socket disconnect event - */ - virtual int OnDisconnect(); - - /** Recursively send the server tree with distances as hops. - * This is used during network burst to inform the other server - * (and any of ITS servers too) of what servers we know about. - * If at any point any of these servers already exist on the other - * end, our connection may be terminated. The hopcounts given - * by this function are relative, this doesn't matter so long as - * they are all >1, as all the remote servers re-calculate them - * to be relative too, with themselves as hop 0. - */ - void SendServers(TreeServer* Current, TreeServer* s, int hops); - - /** Returns my capabilities as a string - */ - std::string MyCapabilities(); - - /** Send my capabilities to the remote side - */ - void SendCapabilities(); - - /* Check a comma seperated list for an item */ - bool HasItem(const std::string &list, const std::string &item); - - /* Isolate and return the elements that are different between two comma seperated lists */ - std::string ListDifference(const std::string &one, const std::string &two); - - bool Capab(const std::deque<std::string> ¶ms); - - /** This function forces this server to quit, removing this server - * and any users on it (and servers and users below that, etc etc). - * It's very slow and pretty clunky, but luckily unless your network - * is having a REAL bad hair day, this function shouldnt be called - * too many times a month ;-) - */ - void SquitServer(std::string &from, TreeServer* Current); - - /** This is a wrapper function for SquitServer above, which - * does some validation first and passes on the SQUIT to all - * other remaining servers. - */ - void Squit(TreeServer* Current, const std::string &reason); - - /** FMODE command - server mode with timestamp checks */ - bool ForceMode(const std::string &source, std::deque<std::string> ¶ms); - - /** FTOPIC command */ - bool ForceTopic(const std::string &source, std::deque<std::string> ¶ms); - - /** FJOIN, similar to TS6 SJOIN, but not quite. */ - bool ForceJoin(const std::string &source, std::deque<std::string> ¶ms); - - /** NICK command */ - bool IntroduceClient(const std::string &source, std::deque<std::string> ¶ms); - - /** Send one or more FJOINs for a channel of users. - * If the length of a single line is more than 480-NICKMAX - * in length, it is split over multiple lines. - */ - void SendFJoins(TreeServer* Current, chanrec* c); - - /** Send G, Q, Z and E lines */ - void SendXLines(TreeServer* Current); - - /** Send channel modes and topics */ - void SendChannelModes(TreeServer* Current); - - /** send all users and their oper state/modes */ - void SendUsers(TreeServer* Current); - - /** This function is called when we want to send a netburst to a local - * server. There is a set order we must do this, because for example - * users require their servers to exist, and channels require their - * users to exist. You get the idea. - */ - void DoBurst(TreeServer* s); - - /** This function is called when we receive data from a remote - * server. We buffer the data in a std::string (it doesnt stay - * there for long), reading using InspSocket::Read() which can - * read up to 16 kilobytes in one operation. - * - * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES - * THE SOCKET OBJECT FOR US. - */ - virtual bool OnDataReady(); - - /** Send one or more complete lines down the socket - */ - int WriteLine(std::string line); - - /** Handle ERROR command */ - bool Error(std::deque<std::string> ¶ms); - - /** remote MOTD. leet, huh? */ - bool Motd(const std::string &prefix, std::deque<std::string> ¶ms); - - /** remote ADMIN. leet, huh? */ - bool Admin(const std::string &prefix, std::deque<std::string> ¶ms); - - /** Remote MODULES */ - bool Modules(const std::string &prefix, std::deque<std::string> ¶ms); - - bool Stats(const std::string &prefix, std::deque<std::string> ¶ms); - - /** Because the core won't let users or even SERVERS set +o, - * we use the OPERTYPE command to do this. - */ - bool OperType(const std::string &prefix, std::deque<std::string> ¶ms); - - /** Because Andy insists that services-compatible servers must - * implement SVSNICK and SVSJOIN, that's exactly what we do :p - */ - bool ForceNick(const std::string &prefix, std::deque<std::string> ¶ms); - - bool OperQuit(const std::string &prefix, std::deque<std::string> ¶ms); - - /** SVSJOIN - */ - bool ServiceJoin(const std::string &prefix, std::deque<std::string> ¶ms); - - /** REHASH - */ - bool RemoteRehash(const std::string &prefix, std::deque<std::string> ¶ms); - - /** KILL - */ - bool RemoteKill(const std::string &prefix, std::deque<std::string> ¶ms); - - /** PONG - */ - bool LocalPong(const std::string &prefix, std::deque<std::string> ¶ms); - - /** METADATA - */ - bool MetaData(const std::string &prefix, std::deque<std::string> ¶ms); - - /** VERSION - */ - bool ServerVersion(const std::string &prefix, std::deque<std::string> ¶ms); - - /** CHGHOST - */ - bool ChangeHost(const std::string &prefix, std::deque<std::string> ¶ms); - - /** ADDLINE - */ - bool AddLine(const std::string &prefix, std::deque<std::string> ¶ms); - - /** CHGNAME - */ - bool ChangeName(const std::string &prefix, std::deque<std::string> ¶ms); - - /** WHOIS - */ - bool Whois(const std::string &prefix, std::deque<std::string> ¶ms); - - /** PUSH - */ - bool Push(const std::string &prefix, std::deque<std::string> ¶ms); - - /** SETTIME - */ - bool HandleSetTime(const std::string &prefix, std::deque<std::string> ¶ms); - - /** TIME - */ - bool Time(const std::string &prefix, std::deque<std::string> ¶ms); - - /** PING - */ - bool LocalPing(const std::string &prefix, std::deque<std::string> ¶ms); - - /** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes. - * This does not update the timestamp of the target channel, this must be done seperately. - */ - bool RemoveStatus(const std::string &prefix, std::deque<std::string> ¶ms); - - /** <- (remote) <- SERVER - */ - bool RemoteServer(const std::string &prefix, std::deque<std::string> ¶ms); - - /** (local) -> SERVER - */ - bool Outbound_Reply_Server(std::deque<std::string> ¶ms); - - /** (local) <- SERVER - */ - bool Inbound_Server(std::deque<std::string> ¶ms); - - /** Handle netsplit - */ - void Split(const std::string &line, std::deque<std::string> &n); - - /** Process complete line from buffer - */ - bool ProcessLine(std::string &line); - - /** Get this server's name - */ - virtual std::string GetName(); - - /** Handle socket timeout from connect() - */ - virtual void OnTimeout(); - - /** Handle socket close event - */ - virtual void OnClose(); - - /** Handle incoming connection event - */ - virtual int OnIncomingConnection(int newsock, char* ip); -}; - -/* Used to validate the value lengths of multiple parameters for a command */ -struct cmd_validation -{ - const char* item; - size_t param; - size_t length; -}; - -/* Used to validate the length values in CAPAB CAPABILITIES */ -struct cap_validation -{ - const char* reason; - const char* key; - size_t size; -}; - -#endif - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __TREESOCKET_H__
#define __TREESOCKET_H__
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "inspircd.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_spanningtree/utils.h"
/*
* The server list in InspIRCd is maintained as two structures
* which hold the data in different ways. Most of the time, we
* want to very quicky obtain three pieces of information:
*
* (1) The information on a server
* (2) The information on the server we must send data through
* to actually REACH the server we're after
* (3) Potentially, the child/parent objects of this server
*
* The InspIRCd spanning protocol provides easy access to these
* by storing the data firstly in a recursive structure, where
* each item references its parent item, and a dynamic list
* of child items, and another structure which stores the items
* hashed, linearly. This means that if we want to find a server
* by name quickly, we can look it up in the hash, avoiding
* any O(n) lookups. If however, during a split or sync, we want
* to apply an operation to a server, and any of its child objects
* we can resort to recursion to walk the tree structure.
* Any socket can have one of five states at any one time.
* The LISTENER state indicates a socket which is listening
* for connections. It cannot receive data itself, only incoming
* sockets.
* The CONNECTING state indicates an outbound socket which is
* waiting to be writeable.
* The WAIT_AUTH_1 state indicates the socket is outbound and
* has successfully connected, but has not yet sent and received
* SERVER strings.
* The WAIT_AUTH_2 state indicates that the socket is inbound
* (allocated by a LISTENER) but has not yet sent and received
* SERVER strings.
* The CONNECTED state represents a fully authorized, fully
* connected server.
*/
enum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED };
/** Every SERVER connection inbound or outbound is represented by
* an object of type TreeSocket.
* TreeSockets, being inherited from InspSocket, can be tied into
* the core socket engine, and we cn therefore receive activity events
* for them, just like activex objects on speed. (yes really, that
* is a technical term!) Each of these which relates to a locally
* connected server is assocated with it, by hooking it onto a
* TreeSocket class using its constructor. In this way, we can
* maintain a list of servers, some of which are directly connected,
* some of which are not.
*/
class TreeSocket : public InspSocket
{
SpanningTreeUtilities* Utils; /* Utility class */
std::string myhost; /* Canonical hostname */
std::string in_buffer; /* Input buffer */
ServerState LinkState; /* Link state */
std::string InboundServerName; /* Server name sent to us by other side */
std::string InboundDescription; /* Server description (GECOS) sent to us by the other side */
int num_lost_users; /* Users lost in split */
int num_lost_servers; /* Servers lost in split */
time_t NextPing; /* Time when we are due to ping this server */
bool LastPingWasGood; /* Responded to last ping we sent? */
bool bursting; /* True if not finished bursting yet */
unsigned int keylength; /* Is this still used? */
std::string ModuleList; /* Module list of other server from CAPAB */
std::map<std::string,std::string> CapKeys; /* CAPAB keys from other server */
Module* Hook; /* I/O hooking module that we're attached to for this socket */
std::string ourchallenge; /* Challenge sent for challenge/response */
std::string theirchallenge; /* Challenge recv for challenge/response */
std::string OutboundPass; /* Outbound password */
bool sentcapab; /* Have sent CAPAB already */
public:
/** Because most of the I/O gubbins are encapsulated within
* InspSocket, we just call the superclass constructor for
* most of the action, and append a few of our own values
* to it.
*/
TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod = NULL);
/** Because most of the I/O gubbins are encapsulated within
* InspSocket, we just call the superclass constructor for
* most of the action, and append a few of our own values
* to it.
*/
TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod = NULL);
/** When a listening socket gives us a new file descriptor,
* we must associate it with a socket without creating a new
* connection. This constructor is used for this purpose.
*/
TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod = NULL);
/** Get link state
*/
ServerState GetLinkState();
/** Get challenge set in our CAPAB for challenge/response
*/
const std::string& GetOurChallenge();
/** Get challenge set in our CAPAB for challenge/response
*/
void SetOurChallenge(const std::string &c);
/** Get challenge set in their CAPAB for challenge/response
*/
const std::string& GetTheirChallenge();
/** Get challenge set in their CAPAB for challenge/response
*/
void SetTheirChallenge(const std::string &c);
/** Compare two passwords based on authentication scheme
*/
bool ComparePass(const std::string &ours, const std::string &theirs);
/** Return the module which we are hooking to for I/O encapsulation
*/
Module* GetHook();
/** Destructor
*/
~TreeSocket();
/** Generate random string used for challenge-response auth
*/
std::string RandString(unsigned int length);
/** Construct a password, optionally hashed with the other side's
* challenge string
*/
std::string MakePass(const std::string &password, const std::string &challenge);
/** When an outbound connection finishes connecting, we receive
* this event, and must send our SERVER string to the other
* side. If the other side is happy, as outlined in the server
* to server docs on the inspircd.org site, the other side
* will then send back its own server string.
*/
virtual bool OnConnected();
/** Handle socket error event
*/
virtual void OnError(InspSocketError e);
/** Sends an error to the remote server, and displays it locally to show
* that it was sent.
*/
void SendError(const std::string &errormessage);
/** Handle socket disconnect event
*/
virtual int OnDisconnect();
/** Recursively send the server tree with distances as hops.
* This is used during network burst to inform the other server
* (and any of ITS servers too) of what servers we know about.
* If at any point any of these servers already exist on the other
* end, our connection may be terminated. The hopcounts given
* by this function are relative, this doesn't matter so long as
* they are all >1, as all the remote servers re-calculate them
* to be relative too, with themselves as hop 0.
*/
void SendServers(TreeServer* Current, TreeServer* s, int hops);
/** Returns my capabilities as a string
*/
std::string MyCapabilities();
/** Send my capabilities to the remote side
*/
void SendCapabilities();
/* Check a comma seperated list for an item */
bool HasItem(const std::string &list, const std::string &item);
/* Isolate and return the elements that are different between two comma seperated lists */
std::string ListDifference(const std::string &one, const std::string &two);
bool Capab(const std::deque<std::string> ¶ms);
/** This function forces this server to quit, removing this server
* and any users on it (and servers and users below that, etc etc).
* It's very slow and pretty clunky, but luckily unless your network
* is having a REAL bad hair day, this function shouldnt be called
* too many times a month ;-)
*/
void SquitServer(std::string &from, TreeServer* Current);
/** This is a wrapper function for SquitServer above, which
* does some validation first and passes on the SQUIT to all
* other remaining servers.
*/
void Squit(TreeServer* Current, const std::string &reason);
/** FMODE command - server mode with timestamp checks */
bool ForceMode(const std::string &source, std::deque<std::string> ¶ms);
/** FTOPIC command */
bool ForceTopic(const std::string &source, std::deque<std::string> ¶ms);
/** FJOIN, similar to TS6 SJOIN, but not quite. */
bool ForceJoin(const std::string &source, std::deque<std::string> ¶ms);
/** NICK command */
bool IntroduceClient(const std::string &source, std::deque<std::string> ¶ms);
/** Send one or more FJOINs for a channel of users.
* If the length of a single line is more than 480-NICKMAX
* in length, it is split over multiple lines.
*/
void SendFJoins(TreeServer* Current, chanrec* c);
/** Send G, Q, Z and E lines */
void SendXLines(TreeServer* Current);
/** Send channel modes and topics */
void SendChannelModes(TreeServer* Current);
/** send all users and their oper state/modes */
void SendUsers(TreeServer* Current);
/** This function is called when we want to send a netburst to a local
* server. There is a set order we must do this, because for example
* users require their servers to exist, and channels require their
* users to exist. You get the idea.
*/
void DoBurst(TreeServer* s);
/** This function is called when we receive data from a remote
* server. We buffer the data in a std::string (it doesnt stay
* there for long), reading using InspSocket::Read() which can
* read up to 16 kilobytes in one operation.
*
* IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES
* THE SOCKET OBJECT FOR US.
*/
virtual bool OnDataReady();
/** Send one or more complete lines down the socket
*/
int WriteLine(std::string line);
/** Handle ERROR command */
bool Error(std::deque<std::string> ¶ms);
/** remote MOTD. leet, huh? */
bool Motd(const std::string &prefix, std::deque<std::string> ¶ms);
/** remote ADMIN. leet, huh? */
bool Admin(const std::string &prefix, std::deque<std::string> ¶ms);
/** Remote MODULES */
bool Modules(const std::string &prefix, std::deque<std::string> ¶ms);
bool Stats(const std::string &prefix, std::deque<std::string> ¶ms);
/** Because the core won't let users or even SERVERS set +o,
* we use the OPERTYPE command to do this.
*/
bool OperType(const std::string &prefix, std::deque<std::string> ¶ms);
/** Because Andy insists that services-compatible servers must
* implement SVSNICK and SVSJOIN, that's exactly what we do :p
*/
bool ForceNick(const std::string &prefix, std::deque<std::string> ¶ms);
bool OperQuit(const std::string &prefix, std::deque<std::string> ¶ms);
/** SVSJOIN
*/
bool ServiceJoin(const std::string &prefix, std::deque<std::string> ¶ms);
/** REHASH
*/
bool RemoteRehash(const std::string &prefix, std::deque<std::string> ¶ms);
/** KILL
*/
bool RemoteKill(const std::string &prefix, std::deque<std::string> ¶ms);
/** PONG
*/
bool LocalPong(const std::string &prefix, std::deque<std::string> ¶ms);
/** METADATA
*/
bool MetaData(const std::string &prefix, std::deque<std::string> ¶ms);
/** VERSION
*/
bool ServerVersion(const std::string &prefix, std::deque<std::string> ¶ms);
/** CHGHOST
*/
bool ChangeHost(const std::string &prefix, std::deque<std::string> ¶ms);
/** ADDLINE
*/
bool AddLine(const std::string &prefix, std::deque<std::string> ¶ms);
/** CHGNAME
*/
bool ChangeName(const std::string &prefix, std::deque<std::string> ¶ms);
/** WHOIS
*/
bool Whois(const std::string &prefix, std::deque<std::string> ¶ms);
/** PUSH
*/
bool Push(const std::string &prefix, std::deque<std::string> ¶ms);
/** SETTIME
*/
bool HandleSetTime(const std::string &prefix, std::deque<std::string> ¶ms);
/** TIME
*/
bool Time(const std::string &prefix, std::deque<std::string> ¶ms);
/** PING
*/
bool LocalPing(const std::string &prefix, std::deque<std::string> ¶ms);
/** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes.
* This does not update the timestamp of the target channel, this must be done seperately.
*/
bool RemoveStatus(const std::string &prefix, std::deque<std::string> ¶ms);
/** <- (remote) <- SERVER
*/
bool RemoteServer(const std::string &prefix, std::deque<std::string> ¶ms);
/** (local) -> SERVER
*/
bool Outbound_Reply_Server(std::deque<std::string> ¶ms);
/** (local) <- SERVER
*/
bool Inbound_Server(std::deque<std::string> ¶ms);
/** Handle netsplit
*/
void Split(const std::string &line, std::deque<std::string> &n);
/** Process complete line from buffer
*/
bool ProcessLine(std::string &line);
/** Get this server's name
*/
virtual std::string GetName();
/** Handle socket timeout from connect()
*/
virtual void OnTimeout();
/** Handle socket close event
*/
virtual void OnClose();
/** Handle incoming connection event
*/
virtual int OnIncomingConnection(int newsock, char* ip);
};
/* Used to validate the value lengths of multiple parameters for a command */
struct cmd_validation
{
const char* item;
size_t param;
size_t length;
};
/* Used to validate the length values in CAPAB CAPABILITIES */
struct cap_validation
{
const char* reason;
const char* key;
size_t size;
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index a907bb440..ad2588cab 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -1,1273 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" -#include "m_hash.h" -#include "socketengine.h" - -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" -#include "m_spanningtree/resolvers.h" -#include "m_spanningtree/handshaketimer.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */ - - -/** Because most of the I/O gubbins are encapsulated within - * InspSocket, we just call the superclass constructor for - * most of the action, and append a few of our own values - * to it. - */ -TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod) - : InspSocket(SI, host, port, listening, maxtime), Utils(Util), Hook(HookMod) -{ - myhost = host; - this->LinkState = LISTENER; - theirchallenge.clear(); - ourchallenge.clear(); - if (listening && Hook) - InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send(); -} - -TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod) - : InspSocket(SI, host, port, listening, maxtime, bindto), Utils(Util), Hook(HookMod) -{ - myhost = ServerName; - theirchallenge.clear(); - ourchallenge.clear(); - this->LinkState = CONNECTING; - if (Hook) - InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send(); -} - -/** When a listening socket gives us a new file descriptor, - * we must associate it with a socket without creating a new - * connection. This constructor is used for this purpose. - */ -TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod) - : InspSocket(SI, newfd, ip), Utils(Util), Hook(HookMod) -{ - this->LinkState = WAIT_AUTH_1; - theirchallenge.clear(); - ourchallenge.clear(); - sentcapab = false; - /* If we have a transport module hooked to the parent, hook the same module to this - * socket, and set a timer waiting for handshake before we send CAPAB etc. - */ - if (Hook) - InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send(); - - Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils, 1)); -} - -ServerState TreeSocket::GetLinkState() -{ - return this->LinkState; -} - -Module* TreeSocket::GetHook() -{ - return this->Hook; -} - -TreeSocket::~TreeSocket() -{ - if (Hook) - InspSocketUnhookRequest(this, (Module*)Utils->Creator, Hook).Send(); - - Utils->DelBurstingServer(this); -} - -const std::string& TreeSocket::GetOurChallenge() -{ - return this->ourchallenge; -} - -void TreeSocket::SetOurChallenge(const std::string &c) -{ - this->ourchallenge = c; -} - -const std::string& TreeSocket::GetTheirChallenge() -{ - return this->theirchallenge; -} - -void TreeSocket::SetTheirChallenge(const std::string &c) -{ - this->theirchallenge = c; -} - -std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge) -{ - /* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for - * suggesting the use of HMAC to secure the password against various attacks. - * - * Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no - * HMAC challenge/response. - */ - Module* sha256 = Instance->FindModule("m_sha256.so"); - if (Utils->ChallengeResponse && sha256 && !challenge.empty()) - { - /* XXX: This is how HMAC is supposed to be done: - * - * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) ) - * - * Note that we are encoding the hex hash, not the binary - * output of the hash which is slightly different to standard. - * - * Don't ask me why its always 0x5c and 0x36... it just is. - */ - std::string hmac1, hmac2; - - for (size_t n = 0; n < password.length(); n++) - { - hmac1 += static_cast<char>(password[n] ^ 0x5C); - hmac2 += static_cast<char>(password[n] ^ 0x36); - } - - hmac2 += challenge; - HashResetRequest(Utils->Creator, sha256).Send(); - hmac2 = HashSumRequest(Utils->Creator, sha256, hmac2).Send(); - - HashResetRequest(Utils->Creator, sha256).Send(); - std::string hmac = hmac1 + hmac2; - hmac = HashSumRequest(Utils->Creator, sha256, hmac).Send(); - - return "HMAC-SHA256:"+ hmac; - } - else if (!challenge.empty() && !sha256) - Instance->Log(DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!"); - - return password; -} - -/** When an outbound connection finishes connecting, we receive - * this event, and must send our SERVER string to the other - * side. If the other side is happy, as outlined in the server - * to server docs on the inspircd.org site, the other side - * will then send back its own server string. - */ -bool TreeSocket::OnConnected() -{ - if (this->LinkState == CONNECTING) - { - /* we do not need to change state here. */ - for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++) - { - if (x->Name == this->myhost) - { - this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] started."); - if (Hook) - { - InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send(); - this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+x->Hook+"\2"); - } - this->OutboundPass = x->SendPass; - sentcapab = false; - - /* found who we're supposed to be connecting to, send the neccessary gubbins. */ - if (this->GetHook()) - Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils, 1)); - else - this->SendCapabilities(); - - return true; - } - } - } - /* There is a (remote) chance that between the /CONNECT and the connection - * being accepted, some muppet has removed the <link> block and rehashed. - * If that happens the connection hangs here until it's closed. Unlikely - * and rather harmless. - */ - this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2 lost link tag(!)"); - return true; -} - -void TreeSocket::OnError(InspSocketError e) -{ - Link* MyLink; - - switch (e) - { - case I_ERR_CONNECT: - this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Connection to \002"+myhost+"\002 refused"); - MyLink = Utils->FindLink(myhost); - if (MyLink) - Utils->DoFailOver(MyLink); - break; - case I_ERR_SOCKET: - this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Could not create socket"); - break; - case I_ERR_BIND: - this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Error binding socket to address or port"); - break; - case I_ERR_WRITE: - this->Instance->SNO->WriteToSnoMask('l',"Connection failed: I/O error on connection"); - break; - case I_ERR_NOMOREFDS: - this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Operating system is out of file descriptors!"); - break; - default: - if ((errno) && (errno != EINPROGRESS) && (errno != EAGAIN)) - { - std::string errstr = strerror(errno); - this->Instance->SNO->WriteToSnoMask('l',"Connection to \002"+myhost+"\002 failed with OS error: " + errstr); - } - break; - } -} - -int TreeSocket::OnDisconnect() -{ - /* For the same reason as above, we don't - * handle OnDisconnect() - */ - return true; -} - -/** Recursively send the server tree with distances as hops. - * This is used during network burst to inform the other server - * (and any of ITS servers too) of what servers we know about. - * If at any point any of these servers already exist on the other - * end, our connection may be terminated. The hopcounts given - * by this function are relative, this doesn't matter so long as - * they are all >1, as all the remote servers re-calculate them - * to be relative too, with themselves as hop 0. - */ -void TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops) -{ - char command[1024]; - for (unsigned int q = 0; q < Current->ChildCount(); q++) - { - TreeServer* recursive_server = Current->GetChild(q); - if (recursive_server != s) - { - snprintf(command,1024,":%s SERVER %s * %d :%s",Current->GetName().c_str(),recursive_server->GetName().c_str(),hops,recursive_server->GetDesc().c_str()); - this->WriteLine(command); - this->WriteLine(":"+recursive_server->GetName()+" VERSION :"+recursive_server->GetVersion()); - /* down to next level */ - this->SendServers(recursive_server, s, hops+1); - } - } -} - -std::string TreeSocket::MyCapabilities() -{ - std::vector<std::string> modlist; - std::string capabilities; - for (int i = 0; i <= this->Instance->GetModuleCount(); i++) - { - if (this->Instance->modules[i]->GetVersion().Flags & VF_COMMON) - modlist.push_back(this->Instance->Config->module_names[i]); - } - sort(modlist.begin(),modlist.end()); - for (unsigned int i = 0; i < modlist.size(); i++) - { - if (i) - capabilities = capabilities + ","; - capabilities = capabilities + modlist[i]; - } - return capabilities; -} - -std::string TreeSocket::RandString(unsigned int length) -{ - char* randombuf = new char[length+1]; - std::string out; -#ifdef WINDOWS - int fd = -1; -#else - int fd = open("/dev/urandom", O_RDONLY, 0); -#endif - - if (fd >= 0) - { -#ifndef WINDOWS - read(fd, randombuf, length); - close(fd); -#endif - } - else - { - for (unsigned int i = 0; i < length; i++) - randombuf[i] = rand(); - } - - for (unsigned int i = 0; i < length; i++) - { - char randchar = static_cast<char>((randombuf[i] & 0x7F) | 0x21); - out += (randchar == '=' ? '_' : randchar); - } - - delete[] randombuf; - return out; -} - -void TreeSocket::SendCapabilities() -{ - if (sentcapab) - return; - - sentcapab = true; - irc::commasepstream modulelist(MyCapabilities()); - this->WriteLine("CAPAB START"); - - /* Send module names, split at 509 length */ - std::string item = "*"; - std::string line = "CAPAB MODULES "; - while ((item = modulelist.GetToken()) != "") - { - if (line.length() + item.length() + 1 > 509) - { - this->WriteLine(line); - line = "CAPAB MODULES "; - } - - if (line != "CAPAB MODULES ") - line.append(","); - - line.append(item); - } - if (line != "CAPAB MODULES ") - this->WriteLine(line); - - int ip6 = 0; - int ip6support = 0; -#ifdef IPV6 - ip6 = 1; -#endif -#ifdef SUPPORT_IP6LINKS - ip6support = 1; -#endif - std::string extra; - /* Do we have sha256 available? If so, we send a challenge */ - if (Utils->ChallengeResponse && (Instance->FindModule("m_sha256.so"))) - { - this->SetOurChallenge(RandString(20)); - extra = " CHALLENGE=" + this->GetOurChallenge(); - } - - this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+extra+" PREFIX="+Instance->Modes->BuildPrefixes()+" CHANMODES="+Instance->Modes->ChanModes()); - - this->WriteLine("CAPAB END"); -} - -/* Check a comma seperated list for an item */ -bool TreeSocket::HasItem(const std::string &list, const std::string &item) -{ - irc::commasepstream seplist(list); - std::string item2 = "*"; - while ((item2 = seplist.GetToken()) != "") - { - if (item2 == item) - return true; - } - return false; -} - -/* Isolate and return the elements that are different between two comma seperated lists */ -std::string TreeSocket::ListDifference(const std::string &one, const std::string &two) -{ - irc::commasepstream list_one(one); - std::string item = "*"; - std::string result; - while ((item = list_one.GetToken()) != "") - { - if (!HasItem(two, item)) - { - result.append(" "); - result.append(item); - } - } - return result; -} - -void TreeSocket::SendError(const std::string &errormessage) -{ - /* Display the error locally as well as sending it remotely */ - this->WriteLine("ERROR :"+errormessage); - this->Instance->SNO->WriteToSnoMask('l',"Sent \2ERROR\2 to "+this->InboundServerName+": "+errormessage); - /* One last attempt to make sure the error reaches its target */ - this->FlushWriteBuffer(); -} - -bool TreeSocket::Capab(const std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - { - this->SendError("Invalid number of parameters for CAPAB - Mismatched version"); - return false; - } - if (params[0] == "START") - { - this->ModuleList.clear(); - this->CapKeys.clear(); - } - else if (params[0] == "END") - { - std::string reason; - int ip6support = 0; -#ifdef SUPPORT_IP6LINKS - ip6support = 1; -#endif - /* Compare ModuleList and check CapKeys... - * Maybe this could be tidier? -- Brain - */ - if ((this->ModuleList != this->MyCapabilities()) && (this->ModuleList.length())) - { - std::string diff = ListDifference(this->ModuleList, this->MyCapabilities()); - if (!diff.length()) - { - diff = "your server:" + ListDifference(this->MyCapabilities(), this->ModuleList); - } - else - { - diff = "this server:" + diff; - } - if (diff.length() == 12) - reason = "Module list in CAPAB is not alphabetically ordered, cannot compare lists."; - else - reason = "Modules loaded on these servers are not correctly matched, these modules are not loaded on " + diff; - } - - cap_validation valid_capab[] = { - {"Maximum nickname lengths differ or remote nickname length not specified", "NICKMAX", NICKMAX}, - {"Maximum ident lengths differ or remote ident length not specified", "IDENTMAX", IDENTMAX}, - {"Maximum channel lengths differ or remote channel length not specified", "CHANMAX", CHANMAX}, - {"Maximum modes per line differ or remote modes per line not specified", "MAXMODES", MAXMODES}, - {"Maximum quit lengths differ or remote quit length not specified", "MAXQUIT", MAXQUIT}, - {"Maximum topic lengths differ or remote topic length not specified", "MAXTOPIC", MAXTOPIC}, - {"Maximum kick lengths differ or remote kick length not specified", "MAXKICK", MAXKICK}, - {"Maximum GECOS (fullname) lengths differ or remote GECOS length not specified", "MAXGECOS", MAXGECOS}, - {"Maximum awaymessage lengths differ or remote awaymessage length not specified", "MAXAWAY", MAXAWAY}, - {"", "", 0} - }; - - if (((this->CapKeys.find("IP6SUPPORT") == this->CapKeys.end()) && (ip6support)) || ((this->CapKeys.find("IP6SUPPORT") != this->CapKeys.end()) && (this->CapKeys.find("IP6SUPPORT")->second != ConvToStr(ip6support)))) - reason = "We don't both support linking to IPV6 servers"; - if (((this->CapKeys.find("IP6NATIVE") != this->CapKeys.end()) && (this->CapKeys.find("IP6NATIVE")->second == "1")) && (!ip6support)) - reason = "The remote server is IPV6 native, and we don't support linking to IPV6 servers"; - if (((this->CapKeys.find("PROTOCOL") == this->CapKeys.end()) || ((this->CapKeys.find("PROTOCOL") != this->CapKeys.end()) && (this->CapKeys.find("PROTOCOL")->second != ConvToStr(ProtocolVersion))))) - { - if (this->CapKeys.find("PROTOCOL") != this->CapKeys.end()) - reason = "Mismatched protocol versions "+this->CapKeys.find("PROTOCOL")->second+" and "+ConvToStr(ProtocolVersion); - else - reason = "Protocol version not specified"; - } - - if(this->CapKeys.find("PREFIX") != this->CapKeys.end() && this->CapKeys.find("PREFIX")->second != this->Instance->Modes->BuildPrefixes()) - reason = "One or more of the prefixes on the remote server are invalid on this server."; - - if (((this->CapKeys.find("HALFOP") == this->CapKeys.end()) && (Instance->Config->AllowHalfop)) || ((this->CapKeys.find("HALFOP") != this->CapKeys.end()) && (this->CapKeys.find("HALFOP")->second != ConvToStr(Instance->Config->AllowHalfop)))) - reason = "We don't both have halfop support enabled/disabled identically"; - - for (int x = 0; valid_capab[x].size; ++x) - { - if (((this->CapKeys.find(valid_capab[x].key) == this->CapKeys.end()) || ((this->CapKeys.find(valid_capab[x].key) != this->CapKeys.end()) && - (this->CapKeys.find(valid_capab[x].key)->second != ConvToStr(valid_capab[x].size))))) - reason = valid_capab[x].reason; - } - - /* Challenge response, store their challenge for our password */ - std::map<std::string,std::string>::iterator n = this->CapKeys.find("CHALLENGE"); - if (Utils->ChallengeResponse && (n != this->CapKeys.end()) && (Instance->FindModule("m_sha256.so"))) - { - /* Challenge-response is on now */ - this->SetTheirChallenge(n->second); - if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING)) - { - this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc); - } - } - else - { - /* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */ - if (this->LinkState == CONNECTING) - this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+OutboundPass+" 0 :"+this->Instance->Config->ServerDesc); - } - - if (reason.length()) - { - this->SendError("CAPAB negotiation failed: "+reason); - return false; - } - } - else if ((params[0] == "MODULES") && (params.size() == 2)) - { - if (!this->ModuleList.length()) - { - this->ModuleList.append(params[1]); - } - else - { - this->ModuleList.append(","); - this->ModuleList.append(params[1]); - } - } - - else if ((params[0] == "CAPABILITIES") && (params.size() == 2)) - { - irc::tokenstream capabs(params[1]); - std::string item; - bool more = true; - while ((more = capabs.GetToken(item))) - { - /* Process each key/value pair */ - std::string::size_type equals = item.rfind('='); - if (equals != std::string::npos) - { - std::string var = item.substr(0, equals); - std::string value = item.substr(equals+1, item.length()); - CapKeys[var] = value; - } - } - } - return true; -} - -/** This function forces this server to quit, removing this server - * and any users on it (and servers and users below that, etc etc). - * It's very slow and pretty clunky, but luckily unless your network - * is having a REAL bad hair day, this function shouldnt be called - * too many times a month ;-) - */ -void TreeSocket::SquitServer(std::string &from, TreeServer* Current) -{ - /* recursively squit the servers attached to 'Current'. - * We're going backwards so we don't remove users - * while we still need them ;) - */ - for (unsigned int q = 0; q < Current->ChildCount(); q++) - { - TreeServer* recursive_server = Current->GetChild(q); - this->SquitServer(from,recursive_server); - } - /* Now we've whacked the kids, whack self */ - num_lost_servers++; - num_lost_users += Current->QuitUsers(from); -} - -/** This is a wrapper function for SquitServer above, which - * does some validation first and passes on the SQUIT to all - * other remaining servers. - */ -void TreeSocket::Squit(TreeServer* Current, const std::string &reason) -{ - if ((Current) && (Current != Utils->TreeRoot)) - { - Event rmode((char*)Current->GetName().c_str(), (Module*)Utils->Creator, "lost_server"); - rmode.Send(Instance); - - std::deque<std::string> params; - params.push_back(Current->GetName()); - params.push_back(":"+reason); - Utils->DoOneToAllButSender(Current->GetParent()->GetName(),"SQUIT",params,Current->GetName()); - if (Current->GetParent() == Utils->TreeRoot) - { - this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split: "+reason); - } - else - { - this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason); - } - num_lost_servers = 0; - num_lost_users = 0; - std::string from = Current->GetParent()->GetName()+" "+Current->GetName(); - SquitServer(from, Current); - Current->Tidy(); - Current->GetParent()->DelChild(Current); - DELETE(Current); - this->Instance->SNO->WriteToSnoMask('l',"Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers); - } - else - Instance->Log(DEFAULT,"Squit from unknown server"); -} - -/** FMODE command - server mode with timestamp checks */ -bool TreeSocket::ForceMode(const std::string &source, std::deque<std::string> ¶ms) -{ - /* Chances are this is a 1.0 FMODE without TS */ - if (params.size() < 3) - { - /* No modes were in the command, probably a channel with no modes set on it */ - return true; - } - - bool smode = false; - std::string sourceserv; - /* Are we dealing with an FMODE from a user, or from a server? */ - userrec* who = this->Instance->FindNick(source); - if (who) - { - /* FMODE from a user, set sourceserv to the users server name */ - sourceserv = who->server; - } - else - { - /* FMODE from a server, create a fake user to receive mode feedback */ - who = new userrec(this->Instance); - who->SetFd(FD_MAGIC_NUMBER); - smode = true; /* Setting this flag tells us we should free the userrec later */ - sourceserv = source; /* Set sourceserv to the actual source string */ - } - const char* modelist[64]; - time_t TS = 0; - int n = 0; - memset(&modelist,0,sizeof(modelist)); - for (unsigned int q = 0; (q < params.size()) && (q < 64); q++) - { - if (q == 1) - { - /* The timestamp is in this position. - * We don't want to pass that up to the - * server->client protocol! - */ - TS = atoi(params[q].c_str()); - } - else - { - /* Everything else is fine to append to the modelist */ - modelist[n++] = params[q].c_str(); - } - - } - /* Extract the TS value of the object, either userrec or chanrec */ - userrec* dst = this->Instance->FindNick(params[0]); - chanrec* chan = NULL; - time_t ourTS = 0; - if (dst) - { - ourTS = dst->age; - } - else - { - chan = this->Instance->FindChan(params[0]); - if (chan) - { - ourTS = chan->age; - } - else - /* Oops, channel doesnt exist! */ - return true; - } - - if (!TS) - { - Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropped."); - Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq. Mode was dropped.", sourceserv.c_str()); - return true; - } - - /* TS is equal or less: Merge the mode changes into ours and pass on. - */ - if (TS <= ourTS) - { - if ((TS < ourTS) && (!dst)) - Instance->Log(DEFAULT,"*** BUG *** Channel TS sent in FMODE to %s is %lu which is not equal to %lu!", params[0].c_str(), TS, ourTS); - - if (smode) - { - this->Instance->SendMode(modelist, n, who); - } - else - { - this->Instance->CallCommandHandler("MODE", modelist, n, who); - } - /* HOT POTATO! PASS IT ON! */ - Utils->DoOneToAllButSender(source,"FMODE",params,sourceserv); - } - /* If the TS is greater than ours, we drop the mode and dont pass it anywhere. - */ - - if (smode) - DELETE(who); - - return true; -} - -/** FTOPIC command */ -bool TreeSocket::ForceTopic(const std::string &source, std::deque<std::string> ¶ms) -{ - if (params.size() != 4) - return true; - time_t ts = atoi(params[1].c_str()); - std::string nsource = source; - chanrec* c = this->Instance->FindChan(params[0]); - if (c) - { - if ((ts >= c->topicset) || (!*c->topic)) - { - std::string oldtopic = c->topic; - strlcpy(c->topic,params[3].c_str(),MAXTOPIC); - strlcpy(c->setby,params[2].c_str(),127); - c->topicset = ts; - /* if the topic text is the same as the current topic, - * dont bother to send the TOPIC command out, just silently - * update the set time and set nick. - */ - if (oldtopic != params[3]) - { - userrec* user = this->Instance->FindNick(source); - if (!user) - { - c->WriteChannelWithServ(Instance->Config->ServerName, "TOPIC %s :%s", c->name, c->topic); - } - else - { - c->WriteChannel(user, "TOPIC %s :%s", c->name, c->topic); - nsource = user->server; - } - /* all done, send it on its way */ - params[3] = ":" + params[3]; - Utils->DoOneToAllButSender(source,"FTOPIC",params,nsource); - } - } - - } - return true; -} - -/** FJOIN, similar to TS6 SJOIN, but not quite. */ -bool TreeSocket::ForceJoin(const std::string &source, std::deque<std::string> ¶ms) -{ - /* 1.1 FJOIN works as follows: - * - * Each FJOIN is sent along with a timestamp, and the side with the lowest - * timestamp 'wins'. From this point on we will refer to this side as the - * winner. The side with the higher timestamp loses, from this point on we - * will call this side the loser or losing side. This should be familiar to - * anyone who's dealt with dreamforge or TS6 before. - * - * When two sides of a split heal and this occurs, the following things - * will happen: - * - * If the timestamps are exactly equal, both sides merge their privilages - * and users, as in InspIRCd 1.0 and ircd2.8. The channels have not been - * re-created during a split, this is safe to do. - * - * If the timestamps are NOT equal, the losing side removes all of its - * modes from the channel, before introducing new users into the channel - * which are listed in the FJOIN command's parameters. The losing side then - * LOWERS its timestamp value of the channel to match that of the winning - * side, and the modes of the users of the winning side are merged in with - * the losing side. - * - * The winning side on the other hand will ignore all user modes from the - * losing side, so only its own modes get applied. Life is simple for those - * who succeed at internets. :-) - * - * NOTE: Unlike TS6 and dreamforge and other protocols which have SJOIN, - * FJOIN does not contain the simple-modes such as +iklmnsp. Why not, - * you ask? Well, quite simply because we don't need to. They'll be sent - * after the FJOIN by FMODE, and FMODE is timestamped, so in the event - * the losing side sends any modes for the channel which shouldnt win, - * they wont as their timestamp will be too high :-) - */ - - if (params.size() < 3) - return true; - - irc::modestacker modestack(true); /* Modes to apply from the users in the user list */ - userrec* who = NULL; /* User we are currently checking */ - std::string channel = params[0]; /* Channel name, as a string */ - time_t TS = atoi(params[1].c_str()); /* Timestamp given to us for remote side */ - irc::tokenstream users(params[2]); /* Users from the user list */ - bool apply_other_sides_modes = true; /* True if we are accepting the other side's modes */ - chanrec* chan = this->Instance->FindChan(channel); /* The channel we're sending joins to */ - time_t ourTS = chan ? chan->age : Instance->Time(true)+600; /* The TS of our side of the link */ - bool created = !chan; /* True if the channel doesnt exist here yet */ - std::string item; /* One item in the list of nicks */ - - params[2] = ":" + params[2]; - Utils->DoOneToAllButSender(source,"FJOIN",params,source); - - if (!TS) - { - Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped."); - Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", source.c_str()); - return true; - } - - /* If our TS is less than theirs, we dont accept their modes */ - if (ourTS < TS) - apply_other_sides_modes = false; - - /* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */ - if (ourTS > TS) - { - std::deque<std::string> param_list; - if (Utils->AnnounceTSChange && chan) - chan->WriteChannelWithServ(Instance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name, chan->name, ourTS, TS); - ourTS = TS; - if (!created) - { - chan->age = TS; - param_list.push_back(channel); - this->RemoveStatus(Instance->Config->ServerName, param_list); - } - } - - /* Now, process every 'prefixes,nick' pair */ - while (users.GetToken(item)) - { - const char* usr = item.c_str(); - if (usr && *usr) - { - const char* permissions = usr; - /* Iterate through all the prefix values, convert them from prefixes to mode letters */ - std::string modes; - while ((*permissions) && (*permissions != ',')) - { - ModeHandler* mh = Instance->Modes->FindPrefix(*permissions); - if (mh) - modes = modes + mh->GetModeChar(); - else - { - this->SendError(std::string("Invalid prefix '")+(*permissions)+"' in FJOIN"); - return false; - } - usr++; - permissions++; - } - /* Advance past the comma, to the nick */ - usr++; - - /* Check the user actually exists */ - who = this->Instance->FindNick(usr); - if (who) - { - /* Check that the user's 'direction' is correct */ - TreeServer* route_back_again = Utils->BestRouteTo(who->server); - if ((!route_back_again) || (route_back_again->GetSocket() != this)) - continue; - - /* Add any permissions this user had to the mode stack */ - for (std::string::iterator x = modes.begin(); x != modes.end(); ++x) - modestack.Push(*x, who->nick); - - chanrec::JoinUser(this->Instance, who, channel.c_str(), true, "", TS); - } - else - { - Instance->Log(SPARSE,"Warning! Invalid user %s in FJOIN to channel %s IGNORED", usr, channel.c_str()); - continue; - } - } - } - - /* Flush mode stacker if we lost the FJOIN or had equal TS */ - if (apply_other_sides_modes) - { - std::deque<std::string> stackresult; - const char* mode_junk[MAXMODES+2]; - userrec* n = new userrec(Instance); - n->SetFd(FD_MAGIC_NUMBER); - mode_junk[0] = channel.c_str(); - - while (modestack.GetStackedLine(stackresult)) - { - for (size_t j = 0; j < stackresult.size(); j++) - { - mode_junk[j+1] = stackresult[j].c_str(); - } - Instance->SendMode(mode_junk, stackresult.size() + 1, n); - } - - delete n; - } - - return true; -} - -/** NICK command */ -bool TreeSocket::IntroduceClient(const std::string &source, std::deque<std::string> ¶ms) -{ - /** Do we have enough parameters: - * NICK age nick host dhost ident +modes ip :gecos - */ - if (params.size() != 8) - { - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction ("+params[1]+"?)"); - return true; - } - - time_t age = ConvToInt(params[0]); - const char* tempnick = params[1].c_str(); - - cmd_validation valid[] = { {"Nickname", 1, NICKMAX}, {"Hostname", 2, 64}, {"Displayed hostname", 3, 64}, {"Ident", 4, IDENTMAX}, {"GECOS", 7, MAXGECOS}, {"", 0, 0} }; - - TreeServer* remoteserver = Utils->FindServer(source); - if (!remoteserver) - { - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Unknown server "+source+")"); - return true; - } - - /* Check parameters for validity before introducing the client, discovered by dmb */ - if (!age) - { - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Invalid TS?)"); - return true; - } - for (size_t x = 0; valid[x].length; ++x) - { - if (params[valid[x].param].length() > valid[x].length) - { - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (" + valid[x].item + " > " + ConvToStr(valid[x].length) + ")"); - return true; - } - } - - /** Our client looks ok, lets introduce it now - */ - Instance->Log(DEBUG,"New remote client %s",tempnick); - user_hash::iterator iter = this->Instance->clientlist->find(tempnick); - - if (iter != this->Instance->clientlist->end()) - { - /* nick collision */ - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+tempnick+" :Nickname collision"); - userrec::QuitUser(this->Instance, iter->second, "Nickname collision"); - return true; - } - - userrec* _new = new userrec(this->Instance); - (*(this->Instance->clientlist))[tempnick] = _new; - _new->SetFd(FD_MAGIC_NUMBER); - strlcpy(_new->nick, tempnick,NICKMAX-1); - strlcpy(_new->host, params[2].c_str(),64); - strlcpy(_new->dhost, params[3].c_str(),64); - _new->server = this->Instance->FindServerNamePtr(source.c_str()); - strlcpy(_new->ident, params[4].c_str(),IDENTMAX); - strlcpy(_new->fullname, params[7].c_str(),MAXGECOS); - _new->registered = REG_ALL; - _new->signon = age; - - /* we need to remove the + from the modestring, so we can do our stuff */ - std::string::size_type pos_after_plus = params[5].find_first_not_of('+'); - if (pos_after_plus != std::string::npos) - params[5] = params[5].substr(pos_after_plus); - - for (std::string::iterator v = params[5].begin(); v != params[5].end(); v++) - { - _new->modes[(*v)-65] = 1; - /* For each mode thats set, increase counter */ - ModeHandler* mh = Instance->Modes->FindMode(*v, MODETYPE_USER); - if (mh) - mh->ChangeCount(1); - } - - /* now we've done with modes processing, put the + back for remote servers */ - params[5] = "+" + params[5]; - -#ifdef SUPPORT_IP6LINKS - if (params[6].find_first_of(":") != std::string::npos) - _new->SetSockAddr(AF_INET6, params[6].c_str(), 0); - else -#endif - _new->SetSockAddr(AF_INET, params[6].c_str(), 0); - - Instance->AddGlobalClone(_new); - - bool dosend = !(((this->Utils->quiet_bursts) && (this->bursting || Utils->FindRemoteBurstServer(remoteserver))) || (this->Instance->SilentULine(_new->server))); - - if (dosend) - this->Instance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s!%s@%s [%s] [%s]",_new->server,_new->nick,_new->ident,_new->host, _new->GetIPString(), _new->fullname); - - params[7] = ":" + params[7]; - Utils->DoOneToAllButSender(source,"NICK", params, source); - - // Increment the Source Servers User Count.. - TreeServer* SourceServer = Utils->FindServer(source); - if (SourceServer) - { - SourceServer->AddUserCount(); - } - - FOREACH_MOD_I(Instance,I_OnPostConnect,OnPostConnect(_new)); - - return true; -} - -/** Send one or more FJOINs for a channel of users. - * If the length of a single line is more than 480-NICKMAX - * in length, it is split over multiple lines. - */ -void TreeSocket::SendFJoins(TreeServer* Current, chanrec* c) -{ - std::string buffer; - char list[MAXBUF]; - std::string individual_halfops = std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age); - - size_t dlen, curlen; - dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age); - int numusers = 0; - char* ptr = list + dlen; - - CUList *ulist = c->GetUsers(); - std::string modes; - std::string params; - - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - // The first parameter gets a : before it - size_t ptrlen = snprintf(ptr, MAXBUF, " %s%s,%s", !numusers ? ":" : "", c->GetAllPrefixChars(i->first), i->first->nick); - - curlen += ptrlen; - ptr += ptrlen; - - numusers++; - - if (curlen > (480-NICKMAX)) - { - buffer.append(list).append("\r\n"); - dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age); - ptr = list + dlen; - ptrlen = 0; - numusers = 0; - } - } - - if (numusers) - buffer.append(list).append("\r\n"); - - buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(c->ChanModes(true)).append("\r\n"); - - int linesize = 1; - for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) - { - int size = strlen(b->data) + 2; - int currsize = linesize + size; - if (currsize <= 350) - { - modes.append("b"); - params.append(" ").append(b->data); - linesize += size; - } - if ((params.length() >= MAXMODES) || (currsize > 350)) - { - /* Wrap at MAXMODES */ - buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); - modes.clear(); - params.clear(); - linesize = 1; - } - } - - /* Only send these if there are any */ - if (!modes.empty()) - buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params); - - this->WriteLine(buffer); -} - -/** Send G, Q, Z and E lines */ -void TreeSocket::SendXLines(TreeServer* Current) -{ - char data[MAXBUF]; - std::string buffer; - std::string n = this->Instance->Config->ServerName; - const char* sn = n.c_str(); - /* Yes, these arent too nice looking, but they get the job done */ - for (std::vector<ZLine*>::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - for (std::vector<QLine*>::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - for (std::vector<GLine*>::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - for (std::vector<ELine*>::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - for (std::vector<ZLine*>::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - for (std::vector<QLine*>::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - for (std::vector<GLine*>::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - for (std::vector<ELine*>::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++) - { - snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - buffer.append(data); - } - - if (!buffer.empty()) - this->WriteLine(buffer); -} - -/** Send channel modes and topics */ -void TreeSocket::SendChannelModes(TreeServer* Current) -{ - char data[MAXBUF]; - std::deque<std::string> list; - std::string n = this->Instance->Config->ServerName; - const char* sn = n.c_str(); - Instance->Log(DEBUG,"Sending channels and modes, %d to send", this->Instance->chanlist->size()); - for (chan_hash::iterator c = this->Instance->chanlist->begin(); c != this->Instance->chanlist->end(); c++) - { - SendFJoins(Current, c->second); - if (*c->second->topic) - { - snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s",sn,c->second->name,(unsigned long)c->second->topicset,c->second->setby,c->second->topic); - this->WriteLine(data); - } - FOREACH_MOD_I(this->Instance,I_OnSyncChannel,OnSyncChannel(c->second,(Module*)Utils->Creator,(void*)this)); - list.clear(); - c->second->GetExtList(list); - for (unsigned int j = 0; j < list.size(); j++) - { - FOREACH_MOD_I(this->Instance,I_OnSyncChannelMetaData,OnSyncChannelMetaData(c->second,(Module*)Utils->Creator,(void*)this,list[j])); - } - } -} - -/** send all users and their oper state/modes */ -void TreeSocket::SendUsers(TreeServer* Current) -{ - char data[MAXBUF]; - std::deque<std::string> list; - std::string dataline; - for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++) - { - if (u->second->registered == REG_ALL) - { - snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->FormatModes(),u->second->GetIPString(),u->second->fullname); - this->WriteLine(data); - if (*u->second->oper) - { - snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->nick, u->second->oper); - this->WriteLine(data); - } - if (*u->second->awaymsg) - { - snprintf(data,MAXBUF,":%s AWAY :%s", u->second->nick, u->second->awaymsg); - this->WriteLine(data); - } - } - } - for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++) - { - FOREACH_MOD_I(this->Instance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this)); - list.clear(); - u->second->GetExtList(list); - for (unsigned int j = 0; j < list.size(); j++) - { - FOREACH_MOD_I(this->Instance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)Utils->Creator,(void*)this,list[j])); - } - } -} - -/** This function is called when we want to send a netburst to a local - * server. There is a set order we must do this, because for example - * users require their servers to exist, and channels require their - * users to exist. You get the idea. - */ -void TreeSocket::DoBurst(TreeServer* s) -{ - std::string name = s->GetName(); - std::string burst = "BURST "+ConvToStr(Instance->Time(true)); - std::string endburst = "ENDBURST"; - this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s).", name.c_str(), this->GetTheirChallenge().empty() ? "plaintext password" : "SHA256-HMAC challenge-response"); - this->WriteLine(burst); - /* send our version string */ - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" VERSION :"+this->Instance->GetVersionString()); - /* Send server tree */ - this->SendServers(Utils->TreeRoot,s,1); - /* Send users and their oper status */ - this->SendUsers(s); - /* Send everything else (channel modes, xlines etc) */ - this->SendChannelModes(s); - this->SendXLines(s); - FOREACH_MOD_I(this->Instance,I_OnSyncOtherMetaData,OnSyncOtherMetaData((Module*)Utils->Creator,(void*)this)); - this->WriteLine(endburst); - this->Instance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+name+"\2."); -} - -/** This function is called when we receive data from a remote - * server. We buffer the data in a std::string (it doesnt stay - * there for long), reading using InspSocket::Read() which can - * read up to 16 kilobytes in one operation. - * - * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES - * THE SOCKET OBJECT FOR US. - */ -bool TreeSocket::OnDataReady() -{ - char* data = this->Read(); - /* Check that the data read is a valid pointer and it has some content */ - if (data && *data) - { - this->in_buffer.append(data); - /* While there is at least one new line in the buffer, - * do something useful (we hope!) with it. - */ - while (in_buffer.find("\n") != std::string::npos) - { - std::string ret = in_buffer.substr(0,in_buffer.find("\n")-1); - in_buffer = in_buffer.substr(in_buffer.find("\n")+1,in_buffer.length()-in_buffer.find("\n")); - /* Use rfind here not find, as theres more - * chance of the \r being near the end of the - * string, not the start. - */ - if (ret.find("\r") != std::string::npos) - ret = in_buffer.substr(0,in_buffer.find("\r")-1); - /* Process this one, abort if it - * didnt return true. - */ - if (!this->ProcessLine(ret)) - { - return false; - } - } - return true; - } - /* EAGAIN returns an empty but non-NULL string, so this - * evaluates to TRUE for EAGAIN but to FALSE for EOF. - */ - return (data && !*data); -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_hash.h"
#include "socketengine.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/resolvers.h"
#include "m_spanningtree/handshaketimer.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */
/** Because most of the I/O gubbins are encapsulated within
* InspSocket, we just call the superclass constructor for
* most of the action, and append a few of our own values
* to it.
*/
TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod)
: InspSocket(SI, host, port, listening, maxtime), Utils(Util), Hook(HookMod)
{
myhost = host;
this->LinkState = LISTENER;
theirchallenge.clear();
ourchallenge.clear();
if (listening && Hook)
InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
}
TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod)
: InspSocket(SI, host, port, listening, maxtime, bindto), Utils(Util), Hook(HookMod)
{
myhost = ServerName;
theirchallenge.clear();
ourchallenge.clear();
this->LinkState = CONNECTING;
if (Hook)
InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
}
/** When a listening socket gives us a new file descriptor,
* we must associate it with a socket without creating a new
* connection. This constructor is used for this purpose.
*/
TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod)
: InspSocket(SI, newfd, ip), Utils(Util), Hook(HookMod)
{
this->LinkState = WAIT_AUTH_1;
theirchallenge.clear();
ourchallenge.clear();
sentcapab = false;
/* If we have a transport module hooked to the parent, hook the same module to this
* socket, and set a timer waiting for handshake before we send CAPAB etc.
*/
if (Hook)
InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils, 1));
}
ServerState TreeSocket::GetLinkState()
{
return this->LinkState;
}
Module* TreeSocket::GetHook()
{
return this->Hook;
}
TreeSocket::~TreeSocket()
{
if (Hook)
InspSocketUnhookRequest(this, (Module*)Utils->Creator, Hook).Send();
Utils->DelBurstingServer(this);
}
const std::string& TreeSocket::GetOurChallenge()
{
return this->ourchallenge;
}
void TreeSocket::SetOurChallenge(const std::string &c)
{
this->ourchallenge = c;
}
const std::string& TreeSocket::GetTheirChallenge()
{
return this->theirchallenge;
}
void TreeSocket::SetTheirChallenge(const std::string &c)
{
this->theirchallenge = c;
}
std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge)
{
/* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for
* suggesting the use of HMAC to secure the password against various attacks.
*
* Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no
* HMAC challenge/response.
*/
Module* sha256 = Instance->FindModule("m_sha256.so");
if (Utils->ChallengeResponse && sha256 && !challenge.empty())
{
/* XXX: This is how HMAC is supposed to be done:
*
* sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) )
*
* Note that we are encoding the hex hash, not the binary
* output of the hash which is slightly different to standard.
*
* Don't ask me why its always 0x5c and 0x36... it just is.
*/
std::string hmac1, hmac2;
for (size_t n = 0; n < password.length(); n++)
{
hmac1 += static_cast<char>(password[n] ^ 0x5C);
hmac2 += static_cast<char>(password[n] ^ 0x36);
}
hmac2 += challenge;
HashResetRequest(Utils->Creator, sha256).Send();
hmac2 = HashSumRequest(Utils->Creator, sha256, hmac2).Send();
HashResetRequest(Utils->Creator, sha256).Send();
std::string hmac = hmac1 + hmac2;
hmac = HashSumRequest(Utils->Creator, sha256, hmac).Send();
return "HMAC-SHA256:"+ hmac;
}
else if (!challenge.empty() && !sha256)
Instance->Log(DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!");
return password;
}
/** When an outbound connection finishes connecting, we receive
* this event, and must send our SERVER string to the other
* side. If the other side is happy, as outlined in the server
* to server docs on the inspircd.org site, the other side
* will then send back its own server string.
*/
bool TreeSocket::OnConnected()
{
if (this->LinkState == CONNECTING)
{
/* we do not need to change state here. */
for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
{
if (x->Name == this->myhost)
{
this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] started.");
if (Hook)
{
InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+x->Hook+"\2");
}
this->OutboundPass = x->SendPass;
sentcapab = false;
/* found who we're supposed to be connecting to, send the neccessary gubbins. */
if (this->GetHook())
Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils, 1));
else
this->SendCapabilities();
return true;
}
}
}
/* There is a (remote) chance that between the /CONNECT and the connection
* being accepted, some muppet has removed the <link> block and rehashed.
* If that happens the connection hangs here until it's closed. Unlikely
* and rather harmless.
*/
this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2 lost link tag(!)");
return true;
}
void TreeSocket::OnError(InspSocketError e)
{
Link* MyLink;
switch (e)
{
case I_ERR_CONNECT:
this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Connection to \002"+myhost+"\002 refused");
MyLink = Utils->FindLink(myhost);
if (MyLink)
Utils->DoFailOver(MyLink);
break;
case I_ERR_SOCKET:
this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Could not create socket");
break;
case I_ERR_BIND:
this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Error binding socket to address or port");
break;
case I_ERR_WRITE:
this->Instance->SNO->WriteToSnoMask('l',"Connection failed: I/O error on connection");
break;
case I_ERR_NOMOREFDS:
this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Operating system is out of file descriptors!");
break;
default:
if ((errno) && (errno != EINPROGRESS) && (errno != EAGAIN))
{
std::string errstr = strerror(errno);
this->Instance->SNO->WriteToSnoMask('l',"Connection to \002"+myhost+"\002 failed with OS error: " + errstr);
}
break;
}
}
int TreeSocket::OnDisconnect()
{
/* For the same reason as above, we don't
* handle OnDisconnect()
*/
return true;
}
/** Recursively send the server tree with distances as hops.
* This is used during network burst to inform the other server
* (and any of ITS servers too) of what servers we know about.
* If at any point any of these servers already exist on the other
* end, our connection may be terminated. The hopcounts given
* by this function are relative, this doesn't matter so long as
* they are all >1, as all the remote servers re-calculate them
* to be relative too, with themselves as hop 0.
*/
void TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops)
{
char command[1024];
for (unsigned int q = 0; q < Current->ChildCount(); q++)
{
TreeServer* recursive_server = Current->GetChild(q);
if (recursive_server != s)
{
snprintf(command,1024,":%s SERVER %s * %d :%s",Current->GetName().c_str(),recursive_server->GetName().c_str(),hops,recursive_server->GetDesc().c_str());
this->WriteLine(command);
this->WriteLine(":"+recursive_server->GetName()+" VERSION :"+recursive_server->GetVersion());
/* down to next level */
this->SendServers(recursive_server, s, hops+1);
}
}
}
std::string TreeSocket::MyCapabilities()
{
std::vector<std::string> modlist;
std::string capabilities;
for (int i = 0; i <= this->Instance->GetModuleCount(); i++)
{
if (this->Instance->modules[i]->GetVersion().Flags & VF_COMMON)
modlist.push_back(this->Instance->Config->module_names[i]);
}
sort(modlist.begin(),modlist.end());
for (unsigned int i = 0; i < modlist.size(); i++)
{
if (i)
capabilities = capabilities + ",";
capabilities = capabilities + modlist[i];
}
return capabilities;
}
std::string TreeSocket::RandString(unsigned int length)
{
char* randombuf = new char[length+1];
std::string out;
#ifdef WINDOWS
int fd = -1;
#else
int fd = open("/dev/urandom", O_RDONLY, 0);
#endif
if (fd >= 0)
{
#ifndef WINDOWS
read(fd, randombuf, length);
close(fd);
#endif
}
else
{
for (unsigned int i = 0; i < length; i++)
randombuf[i] = rand();
}
for (unsigned int i = 0; i < length; i++)
{
char randchar = static_cast<char>((randombuf[i] & 0x7F) | 0x21);
out += (randchar == '=' ? '_' : randchar);
}
delete[] randombuf;
return out;
}
void TreeSocket::SendCapabilities()
{
if (sentcapab)
return;
sentcapab = true;
irc::commasepstream modulelist(MyCapabilities());
this->WriteLine("CAPAB START");
/* Send module names, split at 509 length */
std::string item = "*";
std::string line = "CAPAB MODULES ";
while ((item = modulelist.GetToken()) != "")
{
if (line.length() + item.length() + 1 > 509)
{
this->WriteLine(line);
line = "CAPAB MODULES ";
}
if (line != "CAPAB MODULES ")
line.append(",");
line.append(item);
}
if (line != "CAPAB MODULES ")
this->WriteLine(line);
int ip6 = 0;
int ip6support = 0;
#ifdef IPV6
ip6 = 1;
#endif
#ifdef SUPPORT_IP6LINKS
ip6support = 1;
#endif
std::string extra;
/* Do we have sha256 available? If so, we send a challenge */
if (Utils->ChallengeResponse && (Instance->FindModule("m_sha256.so")))
{
this->SetOurChallenge(RandString(20));
extra = " CHALLENGE=" + this->GetOurChallenge();
}
this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+extra+" PREFIX="+Instance->Modes->BuildPrefixes()+" CHANMODES="+Instance->Modes->ChanModes());
this->WriteLine("CAPAB END");
}
/* Check a comma seperated list for an item */
bool TreeSocket::HasItem(const std::string &list, const std::string &item)
{
irc::commasepstream seplist(list);
std::string item2 = "*";
while ((item2 = seplist.GetToken()) != "")
{
if (item2 == item)
return true;
}
return false;
}
/* Isolate and return the elements that are different between two comma seperated lists */
std::string TreeSocket::ListDifference(const std::string &one, const std::string &two)
{
irc::commasepstream list_one(one);
std::string item = "*";
std::string result;
while ((item = list_one.GetToken()) != "")
{
if (!HasItem(two, item))
{
result.append(" ");
result.append(item);
}
}
return result;
}
void TreeSocket::SendError(const std::string &errormessage)
{
/* Display the error locally as well as sending it remotely */
this->WriteLine("ERROR :"+errormessage);
this->Instance->SNO->WriteToSnoMask('l',"Sent \2ERROR\2 to "+this->InboundServerName+": "+errormessage);
/* One last attempt to make sure the error reaches its target */
this->FlushWriteBuffer();
}
bool TreeSocket::Capab(const std::deque<std::string> ¶ms)
{
if (params.size() < 1)
{
this->SendError("Invalid number of parameters for CAPAB - Mismatched version");
return false;
}
if (params[0] == "START")
{
this->ModuleList.clear();
this->CapKeys.clear();
}
else if (params[0] == "END")
{
std::string reason;
int ip6support = 0;
#ifdef SUPPORT_IP6LINKS
ip6support = 1;
#endif
/* Compare ModuleList and check CapKeys...
* Maybe this could be tidier? -- Brain
*/
if ((this->ModuleList != this->MyCapabilities()) && (this->ModuleList.length()))
{
std::string diff = ListDifference(this->ModuleList, this->MyCapabilities());
if (!diff.length())
{
diff = "your server:" + ListDifference(this->MyCapabilities(), this->ModuleList);
}
else
{
diff = "this server:" + diff;
}
if (diff.length() == 12)
reason = "Module list in CAPAB is not alphabetically ordered, cannot compare lists.";
else
reason = "Modules loaded on these servers are not correctly matched, these modules are not loaded on " + diff;
}
cap_validation valid_capab[] = {
{"Maximum nickname lengths differ or remote nickname length not specified", "NICKMAX", NICKMAX},
{"Maximum ident lengths differ or remote ident length not specified", "IDENTMAX", IDENTMAX},
{"Maximum channel lengths differ or remote channel length not specified", "CHANMAX", CHANMAX},
{"Maximum modes per line differ or remote modes per line not specified", "MAXMODES", MAXMODES},
{"Maximum quit lengths differ or remote quit length not specified", "MAXQUIT", MAXQUIT},
{"Maximum topic lengths differ or remote topic length not specified", "MAXTOPIC", MAXTOPIC},
{"Maximum kick lengths differ or remote kick length not specified", "MAXKICK", MAXKICK},
{"Maximum GECOS (fullname) lengths differ or remote GECOS length not specified", "MAXGECOS", MAXGECOS},
{"Maximum awaymessage lengths differ or remote awaymessage length not specified", "MAXAWAY", MAXAWAY},
{"", "", 0}
};
if (((this->CapKeys.find("IP6SUPPORT") == this->CapKeys.end()) && (ip6support)) || ((this->CapKeys.find("IP6SUPPORT") != this->CapKeys.end()) && (this->CapKeys.find("IP6SUPPORT")->second != ConvToStr(ip6support))))
reason = "We don't both support linking to IPV6 servers";
if (((this->CapKeys.find("IP6NATIVE") != this->CapKeys.end()) && (this->CapKeys.find("IP6NATIVE")->second == "1")) && (!ip6support))
reason = "The remote server is IPV6 native, and we don't support linking to IPV6 servers";
if (((this->CapKeys.find("PROTOCOL") == this->CapKeys.end()) || ((this->CapKeys.find("PROTOCOL") != this->CapKeys.end()) && (this->CapKeys.find("PROTOCOL")->second != ConvToStr(ProtocolVersion)))))
{
if (this->CapKeys.find("PROTOCOL") != this->CapKeys.end())
reason = "Mismatched protocol versions "+this->CapKeys.find("PROTOCOL")->second+" and "+ConvToStr(ProtocolVersion);
else
reason = "Protocol version not specified";
}
if(this->CapKeys.find("PREFIX") != this->CapKeys.end() && this->CapKeys.find("PREFIX")->second != this->Instance->Modes->BuildPrefixes())
reason = "One or more of the prefixes on the remote server are invalid on this server.";
if (((this->CapKeys.find("HALFOP") == this->CapKeys.end()) && (Instance->Config->AllowHalfop)) || ((this->CapKeys.find("HALFOP") != this->CapKeys.end()) && (this->CapKeys.find("HALFOP")->second != ConvToStr(Instance->Config->AllowHalfop))))
reason = "We don't both have halfop support enabled/disabled identically";
for (int x = 0; valid_capab[x].size; ++x)
{
if (((this->CapKeys.find(valid_capab[x].key) == this->CapKeys.end()) || ((this->CapKeys.find(valid_capab[x].key) != this->CapKeys.end()) &&
(this->CapKeys.find(valid_capab[x].key)->second != ConvToStr(valid_capab[x].size)))))
reason = valid_capab[x].reason;
}
/* Challenge response, store their challenge for our password */
std::map<std::string,std::string>::iterator n = this->CapKeys.find("CHALLENGE");
if (Utils->ChallengeResponse && (n != this->CapKeys.end()) && (Instance->FindModule("m_sha256.so")))
{
/* Challenge-response is on now */
this->SetTheirChallenge(n->second);
if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING))
{
this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
}
}
else
{
/* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */
if (this->LinkState == CONNECTING)
this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+OutboundPass+" 0 :"+this->Instance->Config->ServerDesc);
}
if (reason.length())
{
this->SendError("CAPAB negotiation failed: "+reason);
return false;
}
}
else if ((params[0] == "MODULES") && (params.size() == 2))
{
if (!this->ModuleList.length())
{
this->ModuleList.append(params[1]);
}
else
{
this->ModuleList.append(",");
this->ModuleList.append(params[1]);
}
}
else if ((params[0] == "CAPABILITIES") && (params.size() == 2))
{
irc::tokenstream capabs(params[1]);
std::string item;
bool more = true;
while ((more = capabs.GetToken(item)))
{
/* Process each key/value pair */
std::string::size_type equals = item.rfind('=');
if (equals != std::string::npos)
{
std::string var = item.substr(0, equals);
std::string value = item.substr(equals+1, item.length());
CapKeys[var] = value;
}
}
}
return true;
}
/** This function forces this server to quit, removing this server
* and any users on it (and servers and users below that, etc etc).
* It's very slow and pretty clunky, but luckily unless your network
* is having a REAL bad hair day, this function shouldnt be called
* too many times a month ;-)
*/
void TreeSocket::SquitServer(std::string &from, TreeServer* Current)
{
/* recursively squit the servers attached to 'Current'.
* We're going backwards so we don't remove users
* while we still need them ;)
*/
for (unsigned int q = 0; q < Current->ChildCount(); q++)
{
TreeServer* recursive_server = Current->GetChild(q);
this->SquitServer(from,recursive_server);
}
/* Now we've whacked the kids, whack self */
num_lost_servers++;
num_lost_users += Current->QuitUsers(from);
}
/** This is a wrapper function for SquitServer above, which
* does some validation first and passes on the SQUIT to all
* other remaining servers.
*/
void TreeSocket::Squit(TreeServer* Current, const std::string &reason)
{
if ((Current) && (Current != Utils->TreeRoot))
{
Event rmode((char*)Current->GetName().c_str(), (Module*)Utils->Creator, "lost_server");
rmode.Send(Instance);
std::deque<std::string> params;
params.push_back(Current->GetName());
params.push_back(":"+reason);
Utils->DoOneToAllButSender(Current->GetParent()->GetName(),"SQUIT",params,Current->GetName());
if (Current->GetParent() == Utils->TreeRoot)
{
this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split: "+reason);
}
else
{
this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason);
}
num_lost_servers = 0;
num_lost_users = 0;
std::string from = Current->GetParent()->GetName()+" "+Current->GetName();
SquitServer(from, Current);
Current->Tidy();
Current->GetParent()->DelChild(Current);
DELETE(Current);
this->Instance->SNO->WriteToSnoMask('l',"Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers);
}
else
Instance->Log(DEFAULT,"Squit from unknown server");
}
/** FMODE command - server mode with timestamp checks */
bool TreeSocket::ForceMode(const std::string &source, std::deque<std::string> ¶ms)
{
/* Chances are this is a 1.0 FMODE without TS */
if (params.size() < 3)
{
/* No modes were in the command, probably a channel with no modes set on it */
return true;
}
bool smode = false;
std::string sourceserv;
/* Are we dealing with an FMODE from a user, or from a server? */
userrec* who = this->Instance->FindNick(source);
if (who)
{
/* FMODE from a user, set sourceserv to the users server name */
sourceserv = who->server;
}
else
{
/* FMODE from a server, create a fake user to receive mode feedback */
who = new userrec(this->Instance);
who->SetFd(FD_MAGIC_NUMBER);
smode = true; /* Setting this flag tells us we should free the userrec later */
sourceserv = source; /* Set sourceserv to the actual source string */
}
const char* modelist[64];
time_t TS = 0;
int n = 0;
memset(&modelist,0,sizeof(modelist));
for (unsigned int q = 0; (q < params.size()) && (q < 64); q++)
{
if (q == 1)
{
/* The timestamp is in this position.
* We don't want to pass that up to the
* server->client protocol!
*/
TS = atoi(params[q].c_str());
}
else
{
/* Everything else is fine to append to the modelist */
modelist[n++] = params[q].c_str();
}
}
/* Extract the TS value of the object, either userrec or chanrec */
userrec* dst = this->Instance->FindNick(params[0]);
chanrec* chan = NULL;
time_t ourTS = 0;
if (dst)
{
ourTS = dst->age;
}
else
{
chan = this->Instance->FindChan(params[0]);
if (chan)
{
ourTS = chan->age;
}
else
/* Oops, channel doesnt exist! */
return true;
}
if (!TS)
{
Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq. Mode was dropped.", sourceserv.c_str());
return true;
}
/* TS is equal or less: Merge the mode changes into ours and pass on.
*/
if (TS <= ourTS)
{
if ((TS < ourTS) && (!dst))
Instance->Log(DEFAULT,"*** BUG *** Channel TS sent in FMODE to %s is %lu which is not equal to %lu!", params[0].c_str(), TS, ourTS);
if (smode)
{
this->Instance->SendMode(modelist, n, who);
}
else
{
this->Instance->CallCommandHandler("MODE", modelist, n, who);
}
/* HOT POTATO! PASS IT ON! */
Utils->DoOneToAllButSender(source,"FMODE",params,sourceserv);
}
/* If the TS is greater than ours, we drop the mode and dont pass it anywhere.
*/
if (smode)
DELETE(who);
return true;
}
/** FTOPIC command */
bool TreeSocket::ForceTopic(const std::string &source, std::deque<std::string> ¶ms)
{
if (params.size() != 4)
return true;
time_t ts = atoi(params[1].c_str());
std::string nsource = source;
chanrec* c = this->Instance->FindChan(params[0]);
if (c)
{
if ((ts >= c->topicset) || (!*c->topic))
{
std::string oldtopic = c->topic;
strlcpy(c->topic,params[3].c_str(),MAXTOPIC);
strlcpy(c->setby,params[2].c_str(),127);
c->topicset = ts;
/* if the topic text is the same as the current topic,
* dont bother to send the TOPIC command out, just silently
* update the set time and set nick.
*/
if (oldtopic != params[3])
{
userrec* user = this->Instance->FindNick(source);
if (!user)
{
c->WriteChannelWithServ(Instance->Config->ServerName, "TOPIC %s :%s", c->name, c->topic);
}
else
{
c->WriteChannel(user, "TOPIC %s :%s", c->name, c->topic);
nsource = user->server;
}
/* all done, send it on its way */
params[3] = ":" + params[3];
Utils->DoOneToAllButSender(source,"FTOPIC",params,nsource);
}
}
}
return true;
}
/** FJOIN, similar to TS6 SJOIN, but not quite. */
bool TreeSocket::ForceJoin(const std::string &source, std::deque<std::string> ¶ms)
{
/* 1.1 FJOIN works as follows:
*
* Each FJOIN is sent along with a timestamp, and the side with the lowest
* timestamp 'wins'. From this point on we will refer to this side as the
* winner. The side with the higher timestamp loses, from this point on we
* will call this side the loser or losing side. This should be familiar to
* anyone who's dealt with dreamforge or TS6 before.
*
* When two sides of a split heal and this occurs, the following things
* will happen:
*
* If the timestamps are exactly equal, both sides merge their privilages
* and users, as in InspIRCd 1.0 and ircd2.8. The channels have not been
* re-created during a split, this is safe to do.
*
* If the timestamps are NOT equal, the losing side removes all of its
* modes from the channel, before introducing new users into the channel
* which are listed in the FJOIN command's parameters. The losing side then
* LOWERS its timestamp value of the channel to match that of the winning
* side, and the modes of the users of the winning side are merged in with
* the losing side.
*
* The winning side on the other hand will ignore all user modes from the
* losing side, so only its own modes get applied. Life is simple for those
* who succeed at internets. :-)
*
* NOTE: Unlike TS6 and dreamforge and other protocols which have SJOIN,
* FJOIN does not contain the simple-modes such as +iklmnsp. Why not,
* you ask? Well, quite simply because we don't need to. They'll be sent
* after the FJOIN by FMODE, and FMODE is timestamped, so in the event
* the losing side sends any modes for the channel which shouldnt win,
* they wont as their timestamp will be too high :-)
*/
if (params.size() < 3)
return true;
irc::modestacker modestack(true); /* Modes to apply from the users in the user list */
userrec* who = NULL; /* User we are currently checking */
std::string channel = params[0]; /* Channel name, as a string */
time_t TS = atoi(params[1].c_str()); /* Timestamp given to us for remote side */
irc::tokenstream users(params[2]); /* Users from the user list */
bool apply_other_sides_modes = true; /* True if we are accepting the other side's modes */
chanrec* chan = this->Instance->FindChan(channel); /* The channel we're sending joins to */
time_t ourTS = chan ? chan->age : Instance->Time(true)+600; /* The TS of our side of the link */
bool created = !chan; /* True if the channel doesnt exist here yet */
std::string item; /* One item in the list of nicks */
params[2] = ":" + params[2];
Utils->DoOneToAllButSender(source,"FJOIN",params,source);
if (!TS)
{
Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", source.c_str());
return true;
}
/* If our TS is less than theirs, we dont accept their modes */
if (ourTS < TS)
apply_other_sides_modes = false;
/* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */
if (ourTS > TS)
{
std::deque<std::string> param_list;
if (Utils->AnnounceTSChange && chan)
chan->WriteChannelWithServ(Instance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name, chan->name, ourTS, TS);
ourTS = TS;
if (!created)
{
chan->age = TS;
param_list.push_back(channel);
this->RemoveStatus(Instance->Config->ServerName, param_list);
}
}
/* Now, process every 'prefixes,nick' pair */
while (users.GetToken(item))
{
const char* usr = item.c_str();
if (usr && *usr)
{
const char* permissions = usr;
/* Iterate through all the prefix values, convert them from prefixes to mode letters */
std::string modes;
while ((*permissions) && (*permissions != ','))
{
ModeHandler* mh = Instance->Modes->FindPrefix(*permissions);
if (mh)
modes = modes + mh->GetModeChar();
else
{
this->SendError(std::string("Invalid prefix '")+(*permissions)+"' in FJOIN");
return false;
}
usr++;
permissions++;
}
/* Advance past the comma, to the nick */
usr++;
/* Check the user actually exists */
who = this->Instance->FindNick(usr);
if (who)
{
/* Check that the user's 'direction' is correct */
TreeServer* route_back_again = Utils->BestRouteTo(who->server);
if ((!route_back_again) || (route_back_again->GetSocket() != this))
continue;
/* Add any permissions this user had to the mode stack */
for (std::string::iterator x = modes.begin(); x != modes.end(); ++x)
modestack.Push(*x, who->nick);
chanrec::JoinUser(this->Instance, who, channel.c_str(), true, "", TS);
}
else
{
Instance->Log(SPARSE,"Warning! Invalid user %s in FJOIN to channel %s IGNORED", usr, channel.c_str());
continue;
}
}
}
/* Flush mode stacker if we lost the FJOIN or had equal TS */
if (apply_other_sides_modes)
{
std::deque<std::string> stackresult;
const char* mode_junk[MAXMODES+2];
userrec* n = new userrec(Instance);
n->SetFd(FD_MAGIC_NUMBER);
mode_junk[0] = channel.c_str();
while (modestack.GetStackedLine(stackresult))
{
for (size_t j = 0; j < stackresult.size(); j++)
{
mode_junk[j+1] = stackresult[j].c_str();
}
Instance->SendMode(mode_junk, stackresult.size() + 1, n);
}
delete n;
}
return true;
}
/** NICK command */
bool TreeSocket::IntroduceClient(const std::string &source, std::deque<std::string> ¶ms)
{
/** Do we have enough parameters:
* NICK age nick host dhost ident +modes ip :gecos
*/
if (params.size() != 8)
{
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction ("+params[1]+"?)");
return true;
}
time_t age = ConvToInt(params[0]);
const char* tempnick = params[1].c_str();
cmd_validation valid[] = { {"Nickname", 1, NICKMAX}, {"Hostname", 2, 64}, {"Displayed hostname", 3, 64}, {"Ident", 4, IDENTMAX}, {"GECOS", 7, MAXGECOS}, {"", 0, 0} };
TreeServer* remoteserver = Utils->FindServer(source);
if (!remoteserver)
{
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Unknown server "+source+")");
return true;
}
/* Check parameters for validity before introducing the client, discovered by dmb */
if (!age)
{
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Invalid TS?)");
return true;
}
for (size_t x = 0; valid[x].length; ++x)
{
if (params[valid[x].param].length() > valid[x].length)
{
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (" + valid[x].item + " > " + ConvToStr(valid[x].length) + ")");
return true;
}
}
/** Our client looks ok, lets introduce it now
*/
Instance->Log(DEBUG,"New remote client %s",tempnick);
user_hash::iterator iter = this->Instance->clientlist->find(tempnick);
if (iter != this->Instance->clientlist->end())
{
/* nick collision */
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+tempnick+" :Nickname collision");
userrec::QuitUser(this->Instance, iter->second, "Nickname collision");
return true;
}
userrec* _new = new userrec(this->Instance);
(*(this->Instance->clientlist))[tempnick] = _new;
_new->SetFd(FD_MAGIC_NUMBER);
strlcpy(_new->nick, tempnick,NICKMAX-1);
strlcpy(_new->host, params[2].c_str(),64);
strlcpy(_new->dhost, params[3].c_str(),64);
_new->server = this->Instance->FindServerNamePtr(source.c_str());
strlcpy(_new->ident, params[4].c_str(),IDENTMAX);
strlcpy(_new->fullname, params[7].c_str(),MAXGECOS);
_new->registered = REG_ALL;
_new->signon = age;
/* we need to remove the + from the modestring, so we can do our stuff */
std::string::size_type pos_after_plus = params[5].find_first_not_of('+');
if (pos_after_plus != std::string::npos)
params[5] = params[5].substr(pos_after_plus);
for (std::string::iterator v = params[5].begin(); v != params[5].end(); v++)
{
_new->modes[(*v)-65] = 1;
/* For each mode thats set, increase counter */
ModeHandler* mh = Instance->Modes->FindMode(*v, MODETYPE_USER);
if (mh)
mh->ChangeCount(1);
}
/* now we've done with modes processing, put the + back for remote servers */
params[5] = "+" + params[5];
#ifdef SUPPORT_IP6LINKS
if (params[6].find_first_of(":") != std::string::npos)
_new->SetSockAddr(AF_INET6, params[6].c_str(), 0);
else
#endif
_new->SetSockAddr(AF_INET, params[6].c_str(), 0);
Instance->AddGlobalClone(_new);
bool dosend = !(((this->Utils->quiet_bursts) && (this->bursting || Utils->FindRemoteBurstServer(remoteserver))) || (this->Instance->SilentULine(_new->server)));
if (dosend)
this->Instance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s!%s@%s [%s] [%s]",_new->server,_new->nick,_new->ident,_new->host, _new->GetIPString(), _new->fullname);
params[7] = ":" + params[7];
Utils->DoOneToAllButSender(source,"NICK", params, source);
// Increment the Source Servers User Count..
TreeServer* SourceServer = Utils->FindServer(source);
if (SourceServer)
{
SourceServer->AddUserCount();
}
FOREACH_MOD_I(Instance,I_OnPostConnect,OnPostConnect(_new));
return true;
}
/** Send one or more FJOINs for a channel of users.
* If the length of a single line is more than 480-NICKMAX
* in length, it is split over multiple lines.
*/
void TreeSocket::SendFJoins(TreeServer* Current, chanrec* c)
{
std::string buffer;
char list[MAXBUF];
std::string individual_halfops = std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age);
size_t dlen, curlen;
dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age);
int numusers = 0;
char* ptr = list + dlen;
CUList *ulist = c->GetUsers();
std::string modes;
std::string params;
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
// The first parameter gets a : before it
size_t ptrlen = snprintf(ptr, MAXBUF, " %s%s,%s", !numusers ? ":" : "", c->GetAllPrefixChars(i->first), i->first->nick);
curlen += ptrlen;
ptr += ptrlen;
numusers++;
if (curlen > (480-NICKMAX))
{
buffer.append(list).append("\r\n");
dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age);
ptr = list + dlen;
ptrlen = 0;
numusers = 0;
}
}
if (numusers)
buffer.append(list).append("\r\n");
buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(c->ChanModes(true)).append("\r\n");
int linesize = 1;
for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++)
{
int size = strlen(b->data) + 2;
int currsize = linesize + size;
if (currsize <= 350)
{
modes.append("b");
params.append(" ").append(b->data);
linesize += size;
}
if ((params.length() >= MAXMODES) || (currsize > 350))
{
/* Wrap at MAXMODES */
buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n");
modes.clear();
params.clear();
linesize = 1;
}
}
/* Only send these if there are any */
if (!modes.empty())
buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params);
this->WriteLine(buffer);
}
/** Send G, Q, Z and E lines */
void TreeSocket::SendXLines(TreeServer* Current)
{
char data[MAXBUF];
std::string buffer;
std::string n = this->Instance->Config->ServerName;
const char* sn = n.c_str();
/* Yes, these arent too nice looking, but they get the job done */
for (std::vector<ZLine*>::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
for (std::vector<QLine*>::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
for (std::vector<GLine*>::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
for (std::vector<ELine*>::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
for (std::vector<ZLine*>::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
for (std::vector<QLine*>::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
for (std::vector<GLine*>::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
for (std::vector<ELine*>::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++)
{
snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
buffer.append(data);
}
if (!buffer.empty())
this->WriteLine(buffer);
}
/** Send channel modes and topics */
void TreeSocket::SendChannelModes(TreeServer* Current)
{
char data[MAXBUF];
std::deque<std::string> list;
std::string n = this->Instance->Config->ServerName;
const char* sn = n.c_str();
Instance->Log(DEBUG,"Sending channels and modes, %d to send", this->Instance->chanlist->size());
for (chan_hash::iterator c = this->Instance->chanlist->begin(); c != this->Instance->chanlist->end(); c++)
{
SendFJoins(Current, c->second);
if (*c->second->topic)
{
snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s",sn,c->second->name,(unsigned long)c->second->topicset,c->second->setby,c->second->topic);
this->WriteLine(data);
}
FOREACH_MOD_I(this->Instance,I_OnSyncChannel,OnSyncChannel(c->second,(Module*)Utils->Creator,(void*)this));
list.clear();
c->second->GetExtList(list);
for (unsigned int j = 0; j < list.size(); j++)
{
FOREACH_MOD_I(this->Instance,I_OnSyncChannelMetaData,OnSyncChannelMetaData(c->second,(Module*)Utils->Creator,(void*)this,list[j]));
}
}
}
/** send all users and their oper state/modes */
void TreeSocket::SendUsers(TreeServer* Current)
{
char data[MAXBUF];
std::deque<std::string> list;
std::string dataline;
for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++)
{
if (u->second->registered == REG_ALL)
{
snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->FormatModes(),u->second->GetIPString(),u->second->fullname);
this->WriteLine(data);
if (*u->second->oper)
{
snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->nick, u->second->oper);
this->WriteLine(data);
}
if (*u->second->awaymsg)
{
snprintf(data,MAXBUF,":%s AWAY :%s", u->second->nick, u->second->awaymsg);
this->WriteLine(data);
}
}
}
for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++)
{
FOREACH_MOD_I(this->Instance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this));
list.clear();
u->second->GetExtList(list);
for (unsigned int j = 0; j < list.size(); j++)
{
FOREACH_MOD_I(this->Instance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)Utils->Creator,(void*)this,list[j]));
}
}
}
/** This function is called when we want to send a netburst to a local
* server. There is a set order we must do this, because for example
* users require their servers to exist, and channels require their
* users to exist. You get the idea.
*/
void TreeSocket::DoBurst(TreeServer* s)
{
std::string name = s->GetName();
std::string burst = "BURST "+ConvToStr(Instance->Time(true));
std::string endburst = "ENDBURST";
this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s).", name.c_str(), this->GetTheirChallenge().empty() ? "plaintext password" : "SHA256-HMAC challenge-response");
this->WriteLine(burst);
/* send our version string */
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" VERSION :"+this->Instance->GetVersionString());
/* Send server tree */
this->SendServers(Utils->TreeRoot,s,1);
/* Send users and their oper status */
this->SendUsers(s);
/* Send everything else (channel modes, xlines etc) */
this->SendChannelModes(s);
this->SendXLines(s);
FOREACH_MOD_I(this->Instance,I_OnSyncOtherMetaData,OnSyncOtherMetaData((Module*)Utils->Creator,(void*)this));
this->WriteLine(endburst);
this->Instance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+name+"\2.");
}
/** This function is called when we receive data from a remote
* server. We buffer the data in a std::string (it doesnt stay
* there for long), reading using InspSocket::Read() which can
* read up to 16 kilobytes in one operation.
*
* IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES
* THE SOCKET OBJECT FOR US.
*/
bool TreeSocket::OnDataReady()
{
char* data = this->Read();
/* Check that the data read is a valid pointer and it has some content */
if (data && *data)
{
this->in_buffer.append(data);
/* While there is at least one new line in the buffer,
* do something useful (we hope!) with it.
*/
while (in_buffer.find("\n") != std::string::npos)
{
std::string ret = in_buffer.substr(0,in_buffer.find("\n")-1);
in_buffer = in_buffer.substr(in_buffer.find("\n")+1,in_buffer.length()-in_buffer.find("\n"));
/* Use rfind here not find, as theres more
* chance of the \r being near the end of the
* string, not the start.
*/
if (ret.find("\r") != std::string::npos)
ret = in_buffer.substr(0,in_buffer.find("\r")-1);
/* Process this one, abort if it
* didnt return true.
*/
if (!this->ProcessLine(ret))
{
return false;
}
}
return true;
}
/* EAGAIN returns an empty but non-NULL string, so this
* evaluates to TRUE for EAGAIN but to FALSE for EOF.
*/
return (data && !*data);
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index f518151e9..d383e2394 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -1,1554 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" -#include "socketengine.h" - -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" -#include "m_spanningtree/resolvers.h" -#include "m_spanningtree/handshaketimer.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */ - -static std::map<std::string, std::string> warned; /* Server names that have had protocol violation warnings displayed for them */ - -int TreeSocket::WriteLine(std::string line) -{ - Instance->Log(DEBUG, "S[%d] -> %s", this->GetFd(), line.c_str()); - line.append("\r\n"); - return this->Write(line); -} - - -/* Handle ERROR command */ -bool TreeSocket::Error(std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return false; - this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str()); - /* we will return false to cause the socket to close. */ - return false; -} - -bool TreeSocket::Modules(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.empty()) - return true; - - if (!this->Instance->MatchText(this->Instance->Config->ServerName, params[0])) - { - /* Pass it on, not for us */ - Utils->DoOneToOne(prefix, "MODULES", params, params[0]); - return true; - } - - char strbuf[MAXBUF]; - std::deque<std::string> par; - par.push_back(prefix); - par.push_back(""); - - userrec* source = this->Instance->FindNick(prefix); - if (!source) - return true; - - for (unsigned int i = 0; i < Instance->Config->module_names.size(); i++) - { - Version V = Instance->modules[i]->GetVersion(); - char modulename[MAXBUF]; - char flagstate[MAXBUF]; - *flagstate = 0; - if (V.Flags & VF_STATIC) - strlcat(flagstate,", static",MAXBUF); - if (V.Flags & VF_VENDOR) - strlcat(flagstate,", vendor",MAXBUF); - if (V.Flags & VF_COMMON) - strlcat(flagstate,", common",MAXBUF); - if (V.Flags & VF_SERVICEPROVIDER) - strlcat(flagstate,", service provider",MAXBUF); - if (!flagstate[0]) - strcpy(flagstate," <no flags>"); - strlcpy(modulename,Instance->Config->module_names[i].c_str(),256); - if (*source->oper) - { - snprintf(strbuf, MAXBUF, "::%s 900 %s :0x%08lx %d.%d.%d.%d %s (%s)",Instance->Config->ServerName,source->nick,(long unsigned int)Instance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2); - } - else - { - snprintf(strbuf, MAXBUF, "::%s 900 %s :%s",Instance->Config->ServerName,source->nick,ServerConfig::CleanFilename(modulename)); - } - par[1] = strbuf; - Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server); - } - snprintf(strbuf, MAXBUF, "::%s 901 %s :End of MODULES list", Instance->Config->ServerName, source->nick); - par[1] = strbuf; - Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server); - return true; -} - -/** remote MOTD. leet, huh? */ -bool TreeSocket::Motd(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() > 0) - { - if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0])) - { - /* It's for our server */ - string_list results; - userrec* source = this->Instance->FindNick(prefix); - - if (source) - { - std::deque<std::string> par; - par.push_back(prefix); - par.push_back(""); - - if (!Instance->Config->MOTD.size()) - { - par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing."; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - return true; - } - - par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day"; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - - for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++) - { - par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i]; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - } - - par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" End of message of the day."; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - } - } - else - { - /* Pass it on */ - userrec* source = this->Instance->FindNick(prefix); - if (source) - Utils->DoOneToOne(prefix, "MOTD", params, params[0]); - } - } - return true; -} - -/** remote ADMIN. leet, huh? */ -bool TreeSocket::Admin(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() > 0) - { - if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0])) - { - /* It's for our server */ - string_list results; - userrec* source = this->Instance->FindNick(prefix); - if (source) - { - std::deque<std::string> par; - par.push_back(prefix); - par.push_back(""); - par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name - "+Instance->Config->AdminName; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail - "+Instance->Config->AdminEmail; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - } - } - else - { - /* Pass it on */ - userrec* source = this->Instance->FindNick(prefix); - if (source) - Utils->DoOneToOne(prefix, "ADMIN", params, params[0]); - } - } - return true; -} - -bool TreeSocket::Stats(const std::string &prefix, std::deque<std::string> ¶ms) -{ - /* Get the reply to a STATS query if it matches this servername, - * and send it back as a load of PUSH queries - */ - if (params.size() > 1) - { - if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1])) - { - /* It's for our server */ - string_list results; - userrec* source = this->Instance->FindNick(prefix); - if (source) - { - std::deque<std::string> par; - par.push_back(prefix); - par.push_back(""); - DoStats(this->Instance, *(params[0].c_str()), source, results); - for (size_t i = 0; i < results.size(); i++) - { - par[1] = "::" + results[i]; - Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server); - } - } - } - else - { - /* Pass it on */ - userrec* source = this->Instance->FindNick(prefix); - if (source) - Utils->DoOneToOne(prefix, "STATS", params, params[1]); - } - } - return true; -} - - -/** Because the core won't let users or even SERVERS set +o, - * we use the OPERTYPE command to do this. - */ -bool TreeSocket::OperType(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() != 1) - return true; - std::string opertype = params[0]; - userrec* u = this->Instance->FindNick(prefix); - if (u) - { - u->modes[UM_OPERATOR] = 1; - this->Instance->all_opers.push_back(u); - strlcpy(u->oper,opertype.c_str(),NICKMAX-1); - Utils->DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server); - this->Instance->SNO->WriteToSnoMask('o',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick,u->ident,u->host,irc::Spacify(opertype.c_str())); - } - return true; -} - -/** Because Andy insists that services-compatible servers must - * implement SVSNICK and SVSJOIN, that's exactly what we do :p - */ -bool TreeSocket::ForceNick(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 3) - return true; - - userrec* u = this->Instance->FindNick(params[0]); - - if (u) - { - Utils->DoOneToAllButSender(prefix,"SVSNICK",params,prefix); - if (IS_LOCAL(u)) - { - std::deque<std::string> par; - par.push_back(params[1]); - if (!u->ForceNickChange(params[1].c_str())) - { - userrec::QuitUser(this->Instance, u, "Nickname collision"); - return true; - } - u->age = atoi(params[2].c_str()); - } - } - return true; -} - -bool TreeSocket::OperQuit(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - - userrec* u = this->Instance->FindNick(prefix); - - if (u) - { - u->SetOperQuit(params[0]); - params[0] = ":" + params[0]; - Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix); - } - return true; -} - -bool TreeSocket::ServiceJoin(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 2) - return true; - - userrec* u = this->Instance->FindNick(params[0]); - - if (u) - { - /* only join if it's local, otherwise just pass it on! */ - if (IS_LOCAL(u)) - chanrec::JoinUser(this->Instance, u, params[1].c_str(), false, "", Instance->Time()); - Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix); - } - return true; -} - -bool TreeSocket::RemoteRehash(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return false; - - std::string servermask = params[0]; - - if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask)) - { - this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated by \002"+prefix+"\002."); - this->Instance->RehashServer(); - Utils->ReadConfiguration(false); - InitializeDisabledCommands(Instance->Config->DisabledCommands, Instance); - } - Utils->DoOneToAllButSender(prefix,"REHASH",params,prefix); - return true; -} - -bool TreeSocket::RemoteKill(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() != 2) - return true; - - userrec* who = this->Instance->FindNick(params[0]); - - if (who) - { - /* Prepend kill source, if we don't have one */ - if (*(params[1].c_str()) != '[') - { - params[1] = "[" + prefix + "] Killed (" + params[1] +")"; - } - std::string reason = params[1]; - params[1] = ":" + params[1]; - Utils->DoOneToAllButSender(prefix,"KILL",params,prefix); - // NOTE: This is safe with kill hiding on, as RemoteKill is only reached if we have a server prefix. - // in short this is not executed for USERS. - who->Write(":%s KILL %s :%s (%s)", prefix.c_str(), who->nick, prefix.c_str(), reason.c_str()); - userrec::QuitUser(this->Instance,who,reason); - } - return true; -} - -bool TreeSocket::LocalPong(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - - if (params.size() == 1) - { - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - { - ServerSource->SetPingFlag(); - ServerSource->rtt = Instance->Time() - ServerSource->LastPing; - } - } - else - { - std::string forwardto = params[1]; - if (forwardto == this->Instance->Config->ServerName) - { - /* - * this is a PONG for us - * if the prefix is a user, check theyre local, and if they are, - * dump the PONG reply back to their fd. If its a server, do nowt. - * Services might want to send these s->s, but we dont need to yet. - */ - userrec* u = this->Instance->FindNick(prefix); - if (u) - { - u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str()); - } - } - else - { - // not for us, pass it on :) - Utils->DoOneToOne(prefix,"PONG",params,forwardto); - } - } - - return true; -} - -bool TreeSocket::MetaData(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 2) - return true; - else if (params.size() < 3) - params.push_back(""); - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - { - Utils->SetRemoteBursting(ServerSource, false); - - if (params[0] == "*") - { - FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2])); - } - else if (*(params[0].c_str()) == '#') - { - chanrec* c = this->Instance->FindChan(params[0]); - if (c) - { - FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2])); - } - } - else if (*(params[0].c_str()) != '#') - { - userrec* u = this->Instance->FindNick(params[0]); - if (u) - { - FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2])); - } - } - } - - params[2] = ":" + params[2]; - Utils->DoOneToAllButSender(prefix,"METADATA",params,prefix); - return true; -} - -bool TreeSocket::ServerVersion(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - - TreeServer* ServerSource = Utils->FindServer(prefix); - - if (ServerSource) - { - ServerSource->SetVersion(params[0]); - } - params[0] = ":" + params[0]; - Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix); - return true; -} - -bool TreeSocket::ChangeHost(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - userrec* u = this->Instance->FindNick(prefix); - - if (u) - { - u->ChangeDisplayedHost(params[0].c_str()); - Utils->DoOneToAllButSender(prefix,"FHOST",params,u->server); - } - return true; -} - -bool TreeSocket::AddLine(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 6) - return true; - bool propogate = false; - if (!this->bursting) - Utils->lines_to_apply = 0; - switch (*(params[0].c_str())) - { - case 'Z': - propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); - if (propogate) - Utils->lines_to_apply |= APPLY_ZLINES; - break; - case 'Q': - propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); - if (propogate) - Utils->lines_to_apply |= APPLY_QLINES; - break; - case 'E': - propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); - break; - case 'G': - propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); - if (propogate) - Utils->lines_to_apply |= APPLY_GLINES; - break; - case 'K': - propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - if (propogate) - Utils->lines_to_apply |= APPLY_KLINES; - break; - default: - /* Just in case... */ - this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!"); - propogate = false; - break; - } - /* Send it on its way */ - if (propogate) - { - if (atoi(params[4].c_str())) - { - time_t c_requires_crap = ConvToInt(params[4]) + Instance->Time(); - this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),Instance->TimeString(c_requires_crap).c_str(),params[5].c_str()); - } - else - { - this->Instance->SNO->WriteToSnoMask('x',"%s Added permenant %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str()); - } - params[5] = ":" + params[5]; - Utils->DoOneToAllButSender(prefix,"ADDLINE",params,prefix); - } - if (!this->bursting) - { - Instance->XLines->apply_lines(Utils->lines_to_apply); - Utils->lines_to_apply = 0; - } - return true; -} - -bool TreeSocket::ChangeName(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - userrec* u = this->Instance->FindNick(prefix); - if (u) - { - u->ChangeName(params[0].c_str()); - params[0] = ":" + params[0]; - Utils->DoOneToAllButSender(prefix,"FNAME",params,u->server); - } - return true; -} - -bool TreeSocket::Whois(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - userrec* u = this->Instance->FindNick(prefix); - if (u) - { - // an incoming request - if (params.size() == 1) - { - userrec* x = this->Instance->FindNick(params[0]); - if ((x) && (IS_LOCAL(x))) - { - userrec* x = this->Instance->FindNick(params[0]); - char signon[MAXBUF]; - char idle[MAXBUF]; - snprintf(signon, MAXBUF, "%lu", (unsigned long)x->signon); - snprintf(idle, MAXBUF, "%lu", (unsigned long)abs((x->idle_lastmsg) - Instance->Time(true))); - std::deque<std::string> par; - par.push_back(prefix); - par.push_back(signon); - par.push_back(idle); - // ours, we're done, pass it BACK - Utils->DoOneToOne(params[0], "IDLE", par, u->server); - } - else - { - // not ours pass it on - if (x) - Utils->DoOneToOne(prefix, "IDLE", params, x->server); - } - } - else if (params.size() == 3) - { - std::string who_did_the_whois = params[0]; - userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois); - if ((who_to_send_to) && (IS_LOCAL(who_to_send_to))) - { - // an incoming reply to a whois we sent out - std::string nick_whoised = prefix; - unsigned long signon = atoi(params[1].c_str()); - unsigned long idle = atoi(params[2].c_str()); - if ((who_to_send_to) && (IS_LOCAL(who_to_send_to))) - { - do_whois(this->Instance, who_to_send_to, u, signon, idle, nick_whoised.c_str()); - } - } - else - { - // not ours, pass it on - if (who_to_send_to) - Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server); - } - } - } - return true; -} - -bool TreeSocket::Push(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 2) - return true; - userrec* u = this->Instance->FindNick(params[0]); - if (!u) - return true; - if (IS_LOCAL(u)) - { - u->Write(params[1]); - } - else - { - // continue the raw onwards - params[1] = ":" + params[1]; - Utils->DoOneToOne(prefix,"PUSH",params,u->server); - } - return true; -} - -bool TreeSocket::HandleSetTime(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (!params.size() || !Utils->EnableTimeSync) - return true; - - bool force = false; - - if ((params.size() == 2) && (params[1] == "FORCE")) - force = true; - - time_t them = atoi(params[0].c_str()); - time_t us = Instance->Time(false); - - time_t diff = them - us; - - Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix); - - if (force || (them != us)) - { - time_t old = Instance->SetTimeDelta(diff); - Instance->Log(DEBUG, "TS (diff %d) from %s applied (old delta was %d)", diff, prefix.c_str(), old); - } - - return true; -} - -bool TreeSocket::Time(const std::string &prefix, std::deque<std::string> ¶ms) -{ - // :source.server TIME remote.server sendernick - // :remote.server TIME source.server sendernick TS - if (params.size() == 2) - { - // someone querying our time? - if (this->Instance->Config->ServerName == params[0]) - { - userrec* u = this->Instance->FindNick(params[1]); - if (u) - { - params.push_back(ConvToStr(Instance->Time(false))); - params[0] = prefix; - Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]); - } - } - else - { - // not us, pass it on - userrec* u = this->Instance->FindNick(params[1]); - if (u) - Utils->DoOneToOne(prefix,"TIME",params,params[0]); - } - } - else if (params.size() == 3) - { - // a response to a previous TIME - userrec* u = this->Instance->FindNick(params[1]); - if ((u) && (IS_LOCAL(u))) - { - time_t rawtime = atol(params[2].c_str()); - struct tm * timeinfo; - timeinfo = localtime(&rawtime); - char tms[26]; - snprintf(tms,26,"%s",asctime(timeinfo)); - tms[24] = 0; - u->WriteServ("391 %s %s :%s",u->nick,prefix.c_str(),tms); - } - else - { - if (u) - Utils->DoOneToOne(prefix,"TIME",params,u->server); - } - } - return true; -} - -bool TreeSocket::LocalPing(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - if (params.size() == 1) - { - std::string stufftobounce = params[0]; - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce); - return true; - } - else - { - std::string forwardto = params[1]; - if (forwardto == this->Instance->Config->ServerName) - { - // this is a ping for us, send back PONG to the requesting server - params[1] = params[0]; - params[0] = forwardto; - Utils->DoOneToOne(forwardto,"PONG",params,params[1]); - } - else - { - // not for us, pass it on :) - Utils->DoOneToOne(prefix,"PING",params,forwardto); - } - return true; - } -} - -/** TODO: This creates a total mess of output and needs to really use irc::modestacker. - */ -bool TreeSocket::RemoveStatus(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 1) - return true; - chanrec* c = Instance->FindChan(params[0]); - if (c) - { - for (char modeletter = 'A'; modeletter <= 'z'; modeletter++) - { - ModeHandler* mh = Instance->Modes->FindMode(modeletter, MODETYPE_CHANNEL); - if (mh) - mh->RemoveMode(c); - } - } - return true; -} - -bool TreeSocket::RemoteServer(const std::string &prefix, std::deque<std::string> ¶ms) -{ - if (params.size() < 4) - return false; - std::string servername = params[0]; - std::string password = params[1]; - // hopcount is not used for a remote server, we calculate this ourselves - std::string description = params[3]; - TreeServer* ParentOfThis = Utils->FindServer(prefix); - if (!ParentOfThis) - { - this->SendError("Protocol error - Introduced remote server from unknown server "+prefix); - return false; - } - TreeServer* CheckDupe = Utils->FindServer(servername); - if (CheckDupe) - { - this->SendError("Server "+servername+" already exists!"); - this->Instance->SNO->WriteToSnoMask('l',"Server \2"+servername+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix); - return false; - } - Link* lnk = Utils->FindLink(servername); - TreeServer* Node = new TreeServer(this->Utils,this->Instance,servername,description,ParentOfThis,NULL, lnk ? lnk->Hidden : false); - ParentOfThis->AddChild(Node); - params[3] = ":" + params[3]; - Utils->SetRemoteBursting(Node, true); - Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix); - this->Instance->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")"); - return true; -} - -bool TreeSocket::ComparePass(const std::string &ours, const std::string &theirs) -{ - if ((!strncmp(ours.c_str(), "HMAC-SHA256:", 12)) || (!strncmp(theirs.c_str(), "HMAC-SHA256:", 12))) - { - /* One or both of us specified hmac sha256, but we don't have sha256 module loaded! - * We can't allow this password as valid. - */ - if (!Instance->FindModule("m_sha256.so") || !Utils->ChallengeResponse) - return false; - else - /* Straight string compare of hashes */ - return ours == theirs; - } - else - /* Straight string compare of plaintext */ - return ours == theirs; -} - -bool TreeSocket::Outbound_Reply_Server(std::deque<std::string> ¶ms) -{ - if (params.size() < 4) - return false; - - irc::string servername = params[0].c_str(); - std::string sname = params[0]; - std::string password = params[1]; - std::string description = params[3]; - int hops = atoi(params[2].c_str()); - - this->InboundServerName = sname; - this->InboundDescription = description; - - if (!sentcapab) - this->SendCapabilities(); - - if (hops) - { - this->SendError("Server too far away for authentication"); - this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); - return false; - } - - for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++) - { - if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password)) || (x->RecvPass == password && (this->GetTheirChallenge().empty())))) - { - TreeServer* CheckDupe = Utils->FindServer(sname); - if (CheckDupe) - { - this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); - return false; - } - // Begin the sync here. this kickstarts the - // other side, waiting in WAIT_AUTH_2 state, - // into starting their burst, as it shows - // that we're happy. - this->LinkState = CONNECTED; - // we should add the details of this server now - // to the servers tree, as a child of the root - // node. - TreeServer* Node = new TreeServer(this->Utils,this->Instance,sname,description,Utils->TreeRoot,this,x->Hidden); - Utils->TreeRoot->AddChild(Node); - params[3] = ":" + params[3]; - Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,sname); - this->bursting = true; - this->DoBurst(Node); - return true; - } - } - this->SendError("Invalid credentials"); - this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); - return false; -} - -bool TreeSocket::Inbound_Server(std::deque<std::string> ¶ms) -{ - if (params.size() < 4) - return false; - irc::string servername = params[0].c_str(); - std::string sname = params[0]; - std::string password = params[1]; - std::string description = params[3]; - int hops = atoi(params[2].c_str()); - - this->InboundServerName = sname; - this->InboundDescription = description; - - if (!sentcapab) - this->SendCapabilities(); - - if (hops) - { - this->SendError("Server too far away for authentication"); - this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); - return false; - } - - for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++) - { - if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password) || x->RecvPass == password && (this->GetTheirChallenge().empty())))) - { - /* First check for instances of the server that are waiting between the inbound and outbound SERVER command */ - TreeSocket* CheckDupeSocket = Utils->FindBurstingServer(sname); - if (CheckDupeSocket) - { - /* If we find one, we abort the link to prevent a race condition */ - this->SendError("Negotiation collision"); - this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists in a negotiating state."); - CheckDupeSocket->SendError("Negotiation collision"); - Instance->SE->DelFd(CheckDupeSocket); - CheckDupeSocket->Close(); - delete CheckDupeSocket; - return false; - } - /* Now check for fully initialized instances of the server */ - TreeServer* CheckDupe = Utils->FindServer(sname); - if (CheckDupe) - { - this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); - return false; - } - this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] ("+description+")"); - if (this->Hook) - { - std::string name = InspSocketNameRequest((Module*)Utils->Creator, this->Hook).Send(); - this->Instance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+name+"\2"); - } - - Utils->AddBurstingServer(sname,this); - - // this is good. Send our details: Our server name and description and hopcount of 0, - // along with the sendpass from this block. - this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc); - // move to the next state, we are now waiting for THEM. - this->LinkState = WAIT_AUTH_2; - return true; - } - } - this->SendError("Invalid credentials"); - this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); - return false; -} - -void TreeSocket::Split(const std::string &line, std::deque<std::string> &n) -{ - n.clear(); - irc::tokenstream tokens(line); - std::string param; - while (tokens.GetToken(param)) - { - if (!param.empty()) - n.push_back(param); - } - return; -} - -bool TreeSocket::ProcessLine(std::string &line) -{ - std::deque<std::string> params; - irc::string command; - std::string prefix; - - line = line.substr(0, line.find_first_of("\r\n")); - - if (line.empty()) - return true; - - Instance->Log(DEBUG, "S[%d] <- %s", this->GetFd(), line.c_str()); - - this->Split(line.c_str(),params); - - if (params.empty()) - return true; - - if ((params[0][0] == ':') && (params.size() > 1)) - { - prefix = params[0].substr(1); - params.pop_front(); - } - command = params[0].c_str(); - params.pop_front(); - switch (this->LinkState) - { - TreeServer* Node; - - case WAIT_AUTH_1: - // Waiting for SERVER command from remote server. Server initiating - // the connection sends the first SERVER command, listening server - // replies with theirs if its happy, then if the initiator is happy, - // it starts to send its net sync, which starts the merge, otherwise - // it sends an ERROR. - if (command == "PASS") - { - /* Silently ignored */ - } - else if (command == "SERVER") - { - return this->Inbound_Server(params); - } - else if (command == "ERROR") - { - return this->Error(params); - } - else if (command == "USER") - { - this->SendError("Client connections to this port are prohibited."); - return false; - } - else if (command == "CAPAB") - { - return this->Capab(params); - } - else if ((command == "U") || (command == "S")) - { - this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!"); - return false; - } - else - { - irc::string error = "Invalid command in negotiation phase: " + command; - this->SendError(assign(error)); - return false; - } - break; - case WAIT_AUTH_2: - // Waiting for start of other side's netmerge to say they liked our - // password. - if (command == "SERVER") - { - // cant do this, they sent it to us in the WAIT_AUTH_1 state! - // silently ignore. - return true; - } - else if ((command == "U") || (command == "S")) - { - this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!"); - return false; - } - else if (command == "BURST") - { - if (params.size() && Utils->EnableTimeSync) - { - bool we_have_delta = (Instance->Time(false) != Instance->Time(true)); - time_t them = atoi(params[0].c_str()); - time_t delta = them - Instance->Time(false); - if ((delta < -300) || (delta > 300)) - { - Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta)); - SendError("Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!"); - return false; - } - else if ((delta < -30) || (delta > 30)) - { - Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs(delta)); - } - - if (!Utils->MasterTime && !we_have_delta) - { - this->Instance->SetTimeDelta(delta); - // Send this new timestamp to any other servers - Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params); - } - } - this->LinkState = CONNECTED; - Link* lnk = Utils->FindLink(InboundServerName); - Node = new TreeServer(this->Utils,this->Instance, InboundServerName, InboundDescription, Utils->TreeRoot, this, lnk ? lnk->Hidden : false); - Utils->DelBurstingServer(this); - Utils->TreeRoot->AddChild(Node); - params.clear(); - params.push_back(InboundServerName); - params.push_back("*"); - params.push_back("1"); - params.push_back(":"+InboundDescription); - Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,InboundServerName); - this->bursting = true; - this->DoBurst(Node); - } - else if (command == "ERROR") - { - return this->Error(params); - } - else if (command == "CAPAB") - { - return this->Capab(params); - } - - break; - case LISTENER: - this->SendError("Internal error -- listening socket accepted its own descriptor!!!"); - return false; - break; - case CONNECTING: - if (command == "SERVER") - { - // another server we connected to, which was in WAIT_AUTH_1 state, - // has just sent us their credentials. If we get this far, theyre - // happy with OUR credentials, and they are now in WAIT_AUTH_2 state. - // if we're happy with this, we should send our netburst which - // kickstarts the merge. - return this->Outbound_Reply_Server(params); - } - else if (command == "ERROR") - { - return this->Error(params); - } - else if (command == "CAPAB") - { - return this->Capab(params); - } - break; - case CONNECTED: - // This is the 'authenticated' state, when all passwords - // have been exchanged and anything past this point is taken - // as gospel. - - if (!prefix.empty()) - { - std::string direction = prefix; - userrec* t = this->Instance->FindNick(prefix); - if (t) - { - direction = t->server; - } - TreeServer* route_back_again = Utils->BestRouteTo(direction); - if ((!route_back_again) || (route_back_again->GetSocket() != this)) - { - if (route_back_again) - Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str()); - return true; - } - /* Fix by brain: - * When there is activity on the socket, reset the ping counter so - * that we're not wasting bandwidth pinging an active server. - */ - route_back_again->SetNextPingTime(time(NULL) + 60); - route_back_again->SetPingFlag(); - } - else - { - prefix = this->GetName(); - } - - if ((command == "MODE") && (params.size() >= 2)) - { - chanrec* channel = Instance->FindChan(params[0]); - if (channel) - { - userrec* x = Instance->FindNick(prefix); - if (x) - { - if (warned.find(x->server) == warned.end()) - { - Instance->Log(DEFAULT,"WARNING: I revceived modes '%s' from another server '%s'. This is not compliant with InspIRCd. Please check that server for bugs.", params[1].c_str(), x->server); - Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending nonstandard modes: '%s MODE %s' where FMODE should be used, and may cause desyncs.", x->server, x->nick, params[1].c_str()); - warned[x->server] = x->nick; - } - } - } - } - - if (command == "SVSMODE") - { - /* Services expects us to implement - * SVSMODE. In inspircd its the same as - * MODE anyway. - */ - command = "MODE"; - } - std::string target; - /* Yes, know, this is a mess. Its reasonably fast though as we're - * working with std::string here. - */ - if ((command == "NICK") && (params.size() >= 8)) - { - return this->IntroduceClient(prefix,params); - } - else if (command == "FJOIN") - { - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - Utils->SetRemoteBursting(ServerSource, false); - return this->ForceJoin(prefix,params); - } - else if (command == "STATS") - { - return this->Stats(prefix, params); - } - else if (command == "MOTD") - { - return this->Motd(prefix, params); - } - else if (command == "KILL" && Utils->IsServer(prefix)) - { - return this->RemoteKill(prefix,params); - } - else if (command == "MODULES") - { - return this->Modules(prefix, params); - } - else if (command == "ADMIN") - { - return this->Admin(prefix, params); - } - else if (command == "SERVER") - { - return this->RemoteServer(prefix,params); - } - else if (command == "ERROR") - { - return this->Error(params); - } - else if (command == "OPERTYPE") - { - return this->OperType(prefix,params); - } - else if (command == "FMODE") - { - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - Utils->SetRemoteBursting(ServerSource, false); - return this->ForceMode(prefix,params); - } - else if (command == "FTOPIC") - { - return this->ForceTopic(prefix,params); - } - else if (command == "REHASH") - { - return this->RemoteRehash(prefix,params); - } - else if (command == "METADATA") - { - return this->MetaData(prefix,params); - } - else if (command == "REMSTATUS") - { - return this->RemoveStatus(prefix,params); - } - else if (command == "PING") - { - if (prefix.empty()) - prefix = this->GetName(); - /* - * We just got a ping from a server that's bursting. - * This can't be right, so set them to not bursting, and - * apply their lines. - */ - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - Utils->SetRemoteBursting(ServerSource, false); - - if (this->bursting) - { - this->bursting = false; - Instance->XLines->apply_lines(Utils->lines_to_apply); - Utils->lines_to_apply = 0; - } - - return this->LocalPing(prefix,params); - } - else if (command == "PONG") - { - if (prefix.empty()) - prefix = this->GetName(); - /* - * We just got a pong from a server that's bursting. - * This can't be right, so set them to not bursting, and - * apply their lines. - */ - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - Utils->SetRemoteBursting(ServerSource, false); - - if (this->bursting) - { - this->bursting = false; - Instance->XLines->apply_lines(Utils->lines_to_apply); - Utils->lines_to_apply = 0; - } - - return this->LocalPong(prefix,params); - } - else if (command == "VERSION") - { - return this->ServerVersion(prefix,params); - } - else if (command == "FHOST") - { - return this->ChangeHost(prefix,params); - } - else if (command == "FNAME") - { - return this->ChangeName(prefix,params); - } - else if (command == "ADDLINE") - { - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - Utils->SetRemoteBursting(ServerSource, false); - return this->AddLine(prefix,params); - } - else if (command == "SVSNICK") - { - if (prefix.empty()) - { - prefix = this->GetName(); - } - return this->ForceNick(prefix,params); - } - else if (command == "OPERQUIT") - { - return this->OperQuit(prefix,params); - } - else if (command == "IDLE") - { - return this->Whois(prefix,params); - } - else if (command == "PUSH") - { - return this->Push(prefix,params); - } - else if (command == "TIMESET") - { - return this->HandleSetTime(prefix, params); - } - else if (command == "TIME") - { - return this->Time(prefix,params); - } - else if ((command == "KICK") && (Utils->IsServer(prefix))) - { - std::string sourceserv = this->myhost; - if (params.size() == 3) - { - userrec* user = this->Instance->FindNick(params[1]); - chanrec* chan = this->Instance->FindChan(params[0]); - if (user && chan) - { - if (!chan->ServerKickUser(user, params[2].c_str(), false)) - /* Yikes, the channels gone! */ - delete chan; - } - } - if (!this->InboundServerName.empty()) - { - sourceserv = this->InboundServerName; - } - return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params); - } - else if (command == "SVSJOIN") - { - if (prefix.empty()) - { - prefix = this->GetName(); - } - return this->ServiceJoin(prefix,params); - } - else if (command == "SQUIT") - { - if (params.size() == 2) - { - this->Squit(Utils->FindServer(params[0]),params[1]); - } - return true; - } - else if (command == "OPERNOTICE") - { - std::string sourceserv = this->myhost; - if (!this->InboundServerName.empty()) - sourceserv = this->InboundServerName; - if (params.size() >= 1) - Instance->WriteOpers("*** From " + sourceserv + ": " + params[0]); - return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params); - } - else if (command == "MODENOTICE") - { - std::string sourceserv = this->myhost; - if (!this->InboundServerName.empty()) - sourceserv = this->InboundServerName; - if (params.size() >= 2) - { - Instance->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", sourceserv.c_str(), params[1].c_str()); - } - return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params); - } - else if (command == "SNONOTICE") - { - std::string sourceserv = this->myhost; - if (!this->InboundServerName.empty()) - sourceserv = this->InboundServerName; - if (params.size() >= 2) - { - Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + sourceserv + ": "+ params[1]); - } - return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params); - } - else if (command == "ENDBURST") - { - this->bursting = false; - Instance->XLines->apply_lines(Utils->lines_to_apply); - Utils->lines_to_apply = 0; - std::string sourceserv = this->myhost; - if (!this->InboundServerName.empty()) - sourceserv = this->InboundServerName; - this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str()); - - Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server"); - rmode.Send(Instance); - - return true; - } - else - { - // not a special inter-server command. - // Emulate the actual user doing the command, - // this saves us having a huge ugly parser. - userrec* who = this->Instance->FindNick(prefix); - std::string sourceserv = this->myhost; - if (!this->InboundServerName.empty()) - { - sourceserv = this->InboundServerName; - } - if ((!who) && (command == "MODE")) - { - if (Utils->IsServer(prefix)) - { - const char* modelist[127]; - for (size_t i = 0; i < params.size(); i++) - modelist[i] = params[i].c_str(); - userrec* fake = new userrec(Instance); - fake->SetFd(FD_MAGIC_NUMBER); - this->Instance->SendMode(modelist, params.size(), fake); - - delete fake; - /* Hot potato! pass it on! */ - return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params); - } - } - if (who) - { - if ((command == "NICK") && (params.size() > 0)) - { - /* On nick messages, check that the nick doesnt - * already exist here. If it does, kill their copy, - * and our copy. - */ - userrec* x = this->Instance->FindNick(params[0]); - if ((x) && (x != who)) - { - std::deque<std::string> p; - p.push_back(params[0]); - p.push_back("Nickname collision ("+prefix+" -> "+params[0]+")"); - Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p); - p.clear(); - p.push_back(prefix); - p.push_back("Nickname collision"); - Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p); - userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")"); - userrec* y = this->Instance->FindNick(prefix); - if (y) - { - userrec::QuitUser(this->Instance,y,"Nickname collision"); - } - return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params); - } - } - // its a user - target = who->server; - const char* strparams[127]; - for (unsigned int q = 0; q < params.size(); q++) - { - strparams[q] = params[q].c_str(); - } - switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who)) - { - case CMD_INVALID: - this->SendError("Unrecognised command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules"); - return false; - break; - case CMD_FAILURE: - return true; - break; - default: - /* CMD_SUCCESS and CMD_USER_DELETED fall through here */ - break; - } - } - else - { - // its not a user. Its either a server, or somethings screwed up. - if (Utils->IsServer(prefix)) - target = this->Instance->Config->ServerName; - else - return true; - } - return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params); - - } - return true; - break; - } - return true; -} - -std::string TreeSocket::GetName() -{ - std::string sourceserv = this->myhost; - if (!this->InboundServerName.empty()) - { - sourceserv = this->InboundServerName; - } - return sourceserv; -} - -void TreeSocket::OnTimeout() -{ - if (this->LinkState == CONNECTING) - { - this->Instance->SNO->WriteToSnoMask('l',"CONNECT: Connection to \002"+myhost+"\002 timed out."); - Link* MyLink = Utils->FindLink(myhost); - if (MyLink) - Utils->DoFailOver(MyLink); - } -} - -void TreeSocket::OnClose() -{ - // Connection closed. - // If the connection is fully up (state CONNECTED) - // then propogate a netsplit to all peers. - std::string quitserver = this->myhost; - if (!this->InboundServerName.empty()) - { - quitserver = this->InboundServerName; - } - TreeServer* s = Utils->FindServer(quitserver); - if (s) - { - Squit(s,"Remote host closed the connection"); - } - - if (!quitserver.empty()) - { - this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str()); - time_t server_uptime = Instance->Time() - this->age; - if (server_uptime) - Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str()); - } -} - -int TreeSocket::OnIncomingConnection(int newsock, char* ip) -{ - /* To prevent anyone from attempting to flood opers/DDoS by connecting to the server port, - * or discovering if this port is the server port, we don't allow connections from any - * IPs for which we don't have a link block. - */ - bool found = false; - - found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end()); - if (!found) - { - for (vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++) - if (irc::sockets::MatchCIDR(ip, (*i).c_str())) - found = true; - - if (!found) - { - this->Instance->SNO->WriteToSnoMask('l',"Server connection from %s denied (no link blocks with that IP address)", ip); - close(newsock); - return false; - } - } - - TreeSocket* s = new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook); - s = s; /* Whinge whinge whinge, thats all GCC ever does. */ - return true; -} +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "socketengine.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/resolvers.h"
#include "m_spanningtree/handshaketimer.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
static std::map<std::string, std::string> warned; /* Server names that have had protocol violation warnings displayed for them */
int TreeSocket::WriteLine(std::string line)
{
Instance->Log(DEBUG, "S[%d] -> %s", this->GetFd(), line.c_str());
line.append("\r\n");
return this->Write(line);
}
/* Handle ERROR command */
bool TreeSocket::Error(std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return false;
this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str());
/* we will return false to cause the socket to close. */
return false;
}
bool TreeSocket::Modules(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.empty())
return true;
if (!this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
{
/* Pass it on, not for us */
Utils->DoOneToOne(prefix, "MODULES", params, params[0]);
return true;
}
char strbuf[MAXBUF];
std::deque<std::string> par;
par.push_back(prefix);
par.push_back("");
userrec* source = this->Instance->FindNick(prefix);
if (!source)
return true;
for (unsigned int i = 0; i < Instance->Config->module_names.size(); i++)
{
Version V = Instance->modules[i]->GetVersion();
char modulename[MAXBUF];
char flagstate[MAXBUF];
*flagstate = 0;
if (V.Flags & VF_STATIC)
strlcat(flagstate,", static",MAXBUF);
if (V.Flags & VF_VENDOR)
strlcat(flagstate,", vendor",MAXBUF);
if (V.Flags & VF_COMMON)
strlcat(flagstate,", common",MAXBUF);
if (V.Flags & VF_SERVICEPROVIDER)
strlcat(flagstate,", service provider",MAXBUF);
if (!flagstate[0])
strcpy(flagstate," <no flags>");
strlcpy(modulename,Instance->Config->module_names[i].c_str(),256);
if (*source->oper)
{
snprintf(strbuf, MAXBUF, "::%s 900 %s :0x%08lx %d.%d.%d.%d %s (%s)",Instance->Config->ServerName,source->nick,(long unsigned int)Instance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2);
}
else
{
snprintf(strbuf, MAXBUF, "::%s 900 %s :%s",Instance->Config->ServerName,source->nick,ServerConfig::CleanFilename(modulename));
}
par[1] = strbuf;
Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
}
snprintf(strbuf, MAXBUF, "::%s 901 %s :End of MODULES list", Instance->Config->ServerName, source->nick);
par[1] = strbuf;
Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
return true;
}
/** remote MOTD. leet, huh? */
bool TreeSocket::Motd(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() > 0)
{
if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
{
/* It's for our server */
string_list results;
userrec* source = this->Instance->FindNick(prefix);
if (source)
{
std::deque<std::string> par;
par.push_back(prefix);
par.push_back("");
if (!Instance->Config->MOTD.size())
{
par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing.";
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
return true;
}
par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day";
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++)
{
par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i];
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
}
par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" End of message of the day.";
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
}
}
else
{
/* Pass it on */
userrec* source = this->Instance->FindNick(prefix);
if (source)
Utils->DoOneToOne(prefix, "MOTD", params, params[0]);
}
}
return true;
}
/** remote ADMIN. leet, huh? */
bool TreeSocket::Admin(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() > 0)
{
if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
{
/* It's for our server */
string_list results;
userrec* source = this->Instance->FindNick(prefix);
if (source)
{
std::deque<std::string> par;
par.push_back(prefix);
par.push_back("");
par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName;
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name - "+Instance->Config->AdminName;
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick;
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail - "+Instance->Config->AdminEmail;
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
}
}
else
{
/* Pass it on */
userrec* source = this->Instance->FindNick(prefix);
if (source)
Utils->DoOneToOne(prefix, "ADMIN", params, params[0]);
}
}
return true;
}
bool TreeSocket::Stats(const std::string &prefix, std::deque<std::string> ¶ms)
{
/* Get the reply to a STATS query if it matches this servername,
* and send it back as a load of PUSH queries
*/
if (params.size() > 1)
{
if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1]))
{
/* It's for our server */
string_list results;
userrec* source = this->Instance->FindNick(prefix);
if (source)
{
std::deque<std::string> par;
par.push_back(prefix);
par.push_back("");
DoStats(this->Instance, *(params[0].c_str()), source, results);
for (size_t i = 0; i < results.size(); i++)
{
par[1] = "::" + results[i];
Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
}
}
}
else
{
/* Pass it on */
userrec* source = this->Instance->FindNick(prefix);
if (source)
Utils->DoOneToOne(prefix, "STATS", params, params[1]);
}
}
return true;
}
/** Because the core won't let users or even SERVERS set +o,
* we use the OPERTYPE command to do this.
*/
bool TreeSocket::OperType(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() != 1)
return true;
std::string opertype = params[0];
userrec* u = this->Instance->FindNick(prefix);
if (u)
{
u->modes[UM_OPERATOR] = 1;
this->Instance->all_opers.push_back(u);
strlcpy(u->oper,opertype.c_str(),NICKMAX-1);
Utils->DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server);
this->Instance->SNO->WriteToSnoMask('o',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick,u->ident,u->host,irc::Spacify(opertype.c_str()));
}
return true;
}
/** Because Andy insists that services-compatible servers must
* implement SVSNICK and SVSJOIN, that's exactly what we do :p
*/
bool TreeSocket::ForceNick(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 3)
return true;
userrec* u = this->Instance->FindNick(params[0]);
if (u)
{
Utils->DoOneToAllButSender(prefix,"SVSNICK",params,prefix);
if (IS_LOCAL(u))
{
std::deque<std::string> par;
par.push_back(params[1]);
if (!u->ForceNickChange(params[1].c_str()))
{
userrec::QuitUser(this->Instance, u, "Nickname collision");
return true;
}
u->age = atoi(params[2].c_str());
}
}
return true;
}
bool TreeSocket::OperQuit(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
userrec* u = this->Instance->FindNick(prefix);
if (u)
{
u->SetOperQuit(params[0]);
params[0] = ":" + params[0];
Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix);
}
return true;
}
bool TreeSocket::ServiceJoin(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 2)
return true;
userrec* u = this->Instance->FindNick(params[0]);
if (u)
{
/* only join if it's local, otherwise just pass it on! */
if (IS_LOCAL(u))
chanrec::JoinUser(this->Instance, u, params[1].c_str(), false, "", Instance->Time());
Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix);
}
return true;
}
bool TreeSocket::RemoteRehash(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return false;
std::string servermask = params[0];
if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask))
{
this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated by \002"+prefix+"\002.");
this->Instance->RehashServer();
Utils->ReadConfiguration(false);
InitializeDisabledCommands(Instance->Config->DisabledCommands, Instance);
}
Utils->DoOneToAllButSender(prefix,"REHASH",params,prefix);
return true;
}
bool TreeSocket::RemoteKill(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() != 2)
return true;
userrec* who = this->Instance->FindNick(params[0]);
if (who)
{
/* Prepend kill source, if we don't have one */
if (*(params[1].c_str()) != '[')
{
params[1] = "[" + prefix + "] Killed (" + params[1] +")";
}
std::string reason = params[1];
params[1] = ":" + params[1];
Utils->DoOneToAllButSender(prefix,"KILL",params,prefix);
// NOTE: This is safe with kill hiding on, as RemoteKill is only reached if we have a server prefix.
// in short this is not executed for USERS.
who->Write(":%s KILL %s :%s (%s)", prefix.c_str(), who->nick, prefix.c_str(), reason.c_str());
userrec::QuitUser(this->Instance,who,reason);
}
return true;
}
bool TreeSocket::LocalPong(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
if (params.size() == 1)
{
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
{
ServerSource->SetPingFlag();
ServerSource->rtt = Instance->Time() - ServerSource->LastPing;
}
}
else
{
std::string forwardto = params[1];
if (forwardto == this->Instance->Config->ServerName)
{
/*
* this is a PONG for us
* if the prefix is a user, check theyre local, and if they are,
* dump the PONG reply back to their fd. If its a server, do nowt.
* Services might want to send these s->s, but we dont need to yet.
*/
userrec* u = this->Instance->FindNick(prefix);
if (u)
{
u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str());
}
}
else
{
// not for us, pass it on :)
Utils->DoOneToOne(prefix,"PONG",params,forwardto);
}
}
return true;
}
bool TreeSocket::MetaData(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 2)
return true;
else if (params.size() < 3)
params.push_back("");
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
{
Utils->SetRemoteBursting(ServerSource, false);
if (params[0] == "*")
{
FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2]));
}
else if (*(params[0].c_str()) == '#')
{
chanrec* c = this->Instance->FindChan(params[0]);
if (c)
{
FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2]));
}
}
else if (*(params[0].c_str()) != '#')
{
userrec* u = this->Instance->FindNick(params[0]);
if (u)
{
FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2]));
}
}
}
params[2] = ":" + params[2];
Utils->DoOneToAllButSender(prefix,"METADATA",params,prefix);
return true;
}
bool TreeSocket::ServerVersion(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
{
ServerSource->SetVersion(params[0]);
}
params[0] = ":" + params[0];
Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix);
return true;
}
bool TreeSocket::ChangeHost(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
userrec* u = this->Instance->FindNick(prefix);
if (u)
{
u->ChangeDisplayedHost(params[0].c_str());
Utils->DoOneToAllButSender(prefix,"FHOST",params,u->server);
}
return true;
}
bool TreeSocket::AddLine(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 6)
return true;
bool propogate = false;
if (!this->bursting)
Utils->lines_to_apply = 0;
switch (*(params[0].c_str()))
{
case 'Z':
propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
if (propogate)
Utils->lines_to_apply |= APPLY_ZLINES;
break;
case 'Q':
propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
if (propogate)
Utils->lines_to_apply |= APPLY_QLINES;
break;
case 'E':
propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
break;
case 'G':
propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
if (propogate)
Utils->lines_to_apply |= APPLY_GLINES;
break;
case 'K':
propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
if (propogate)
Utils->lines_to_apply |= APPLY_KLINES;
break;
default:
/* Just in case... */
this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!");
propogate = false;
break;
}
/* Send it on its way */
if (propogate)
{
if (atoi(params[4].c_str()))
{
time_t c_requires_crap = ConvToInt(params[4]) + Instance->Time();
this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),Instance->TimeString(c_requires_crap).c_str(),params[5].c_str());
}
else
{
this->Instance->SNO->WriteToSnoMask('x',"%s Added permenant %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str());
}
params[5] = ":" + params[5];
Utils->DoOneToAllButSender(prefix,"ADDLINE",params,prefix);
}
if (!this->bursting)
{
Instance->XLines->apply_lines(Utils->lines_to_apply);
Utils->lines_to_apply = 0;
}
return true;
}
bool TreeSocket::ChangeName(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
userrec* u = this->Instance->FindNick(prefix);
if (u)
{
u->ChangeName(params[0].c_str());
params[0] = ":" + params[0];
Utils->DoOneToAllButSender(prefix,"FNAME",params,u->server);
}
return true;
}
bool TreeSocket::Whois(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
userrec* u = this->Instance->FindNick(prefix);
if (u)
{
// an incoming request
if (params.size() == 1)
{
userrec* x = this->Instance->FindNick(params[0]);
if ((x) && (IS_LOCAL(x)))
{
userrec* x = this->Instance->FindNick(params[0]);
char signon[MAXBUF];
char idle[MAXBUF];
snprintf(signon, MAXBUF, "%lu", (unsigned long)x->signon);
snprintf(idle, MAXBUF, "%lu", (unsigned long)abs((x->idle_lastmsg) - Instance->Time(true)));
std::deque<std::string> par;
par.push_back(prefix);
par.push_back(signon);
par.push_back(idle);
// ours, we're done, pass it BACK
Utils->DoOneToOne(params[0], "IDLE", par, u->server);
}
else
{
// not ours pass it on
if (x)
Utils->DoOneToOne(prefix, "IDLE", params, x->server);
}
}
else if (params.size() == 3)
{
std::string who_did_the_whois = params[0];
userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois);
if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
{
// an incoming reply to a whois we sent out
std::string nick_whoised = prefix;
unsigned long signon = atoi(params[1].c_str());
unsigned long idle = atoi(params[2].c_str());
if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
{
do_whois(this->Instance, who_to_send_to, u, signon, idle, nick_whoised.c_str());
}
}
else
{
// not ours, pass it on
if (who_to_send_to)
Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server);
}
}
}
return true;
}
bool TreeSocket::Push(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 2)
return true;
userrec* u = this->Instance->FindNick(params[0]);
if (!u)
return true;
if (IS_LOCAL(u))
{
u->Write(params[1]);
}
else
{
// continue the raw onwards
params[1] = ":" + params[1];
Utils->DoOneToOne(prefix,"PUSH",params,u->server);
}
return true;
}
bool TreeSocket::HandleSetTime(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (!params.size() || !Utils->EnableTimeSync)
return true;
bool force = false;
if ((params.size() == 2) && (params[1] == "FORCE"))
force = true;
time_t them = atoi(params[0].c_str());
time_t us = Instance->Time(false);
time_t diff = them - us;
Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix);
if (force || (them != us))
{
time_t old = Instance->SetTimeDelta(diff);
Instance->Log(DEBUG, "TS (diff %d) from %s applied (old delta was %d)", diff, prefix.c_str(), old);
}
return true;
}
bool TreeSocket::Time(const std::string &prefix, std::deque<std::string> ¶ms)
{
// :source.server TIME remote.server sendernick
// :remote.server TIME source.server sendernick TS
if (params.size() == 2)
{
// someone querying our time?
if (this->Instance->Config->ServerName == params[0])
{
userrec* u = this->Instance->FindNick(params[1]);
if (u)
{
params.push_back(ConvToStr(Instance->Time(false)));
params[0] = prefix;
Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]);
}
}
else
{
// not us, pass it on
userrec* u = this->Instance->FindNick(params[1]);
if (u)
Utils->DoOneToOne(prefix,"TIME",params,params[0]);
}
}
else if (params.size() == 3)
{
// a response to a previous TIME
userrec* u = this->Instance->FindNick(params[1]);
if ((u) && (IS_LOCAL(u)))
{
time_t rawtime = atol(params[2].c_str());
struct tm * timeinfo;
timeinfo = localtime(&rawtime);
char tms[26];
snprintf(tms,26,"%s",asctime(timeinfo));
tms[24] = 0;
u->WriteServ("391 %s %s :%s",u->nick,prefix.c_str(),tms);
}
else
{
if (u)
Utils->DoOneToOne(prefix,"TIME",params,u->server);
}
}
return true;
}
bool TreeSocket::LocalPing(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
if (params.size() == 1)
{
std::string stufftobounce = params[0];
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce);
return true;
}
else
{
std::string forwardto = params[1];
if (forwardto == this->Instance->Config->ServerName)
{
// this is a ping for us, send back PONG to the requesting server
params[1] = params[0];
params[0] = forwardto;
Utils->DoOneToOne(forwardto,"PONG",params,params[1]);
}
else
{
// not for us, pass it on :)
Utils->DoOneToOne(prefix,"PING",params,forwardto);
}
return true;
}
}
/** TODO: This creates a total mess of output and needs to really use irc::modestacker.
*/
bool TreeSocket::RemoveStatus(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 1)
return true;
chanrec* c = Instance->FindChan(params[0]);
if (c)
{
for (char modeletter = 'A'; modeletter <= 'z'; modeletter++)
{
ModeHandler* mh = Instance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);
if (mh)
mh->RemoveMode(c);
}
}
return true;
}
bool TreeSocket::RemoteServer(const std::string &prefix, std::deque<std::string> ¶ms)
{
if (params.size() < 4)
return false;
std::string servername = params[0];
std::string password = params[1];
// hopcount is not used for a remote server, we calculate this ourselves
std::string description = params[3];
TreeServer* ParentOfThis = Utils->FindServer(prefix);
if (!ParentOfThis)
{
this->SendError("Protocol error - Introduced remote server from unknown server "+prefix);
return false;
}
TreeServer* CheckDupe = Utils->FindServer(servername);
if (CheckDupe)
{
this->SendError("Server "+servername+" already exists!");
this->Instance->SNO->WriteToSnoMask('l',"Server \2"+servername+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix);
return false;
}
Link* lnk = Utils->FindLink(servername);
TreeServer* Node = new TreeServer(this->Utils,this->Instance,servername,description,ParentOfThis,NULL, lnk ? lnk->Hidden : false);
ParentOfThis->AddChild(Node);
params[3] = ":" + params[3];
Utils->SetRemoteBursting(Node, true);
Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix);
this->Instance->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")");
return true;
}
bool TreeSocket::ComparePass(const std::string &ours, const std::string &theirs)
{
if ((!strncmp(ours.c_str(), "HMAC-SHA256:", 12)) || (!strncmp(theirs.c_str(), "HMAC-SHA256:", 12)))
{
/* One or both of us specified hmac sha256, but we don't have sha256 module loaded!
* We can't allow this password as valid.
*/
if (!Instance->FindModule("m_sha256.so") || !Utils->ChallengeResponse)
return false;
else
/* Straight string compare of hashes */
return ours == theirs;
}
else
/* Straight string compare of plaintext */
return ours == theirs;
}
bool TreeSocket::Outbound_Reply_Server(std::deque<std::string> ¶ms)
{
if (params.size() < 4)
return false;
irc::string servername = params[0].c_str();
std::string sname = params[0];
std::string password = params[1];
std::string description = params[3];
int hops = atoi(params[2].c_str());
this->InboundServerName = sname;
this->InboundDescription = description;
if (!sentcapab)
this->SendCapabilities();
if (hops)
{
this->SendError("Server too far away for authentication");
this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
return false;
}
for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
{
if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password)) || (x->RecvPass == password && (this->GetTheirChallenge().empty()))))
{
TreeServer* CheckDupe = Utils->FindServer(sname);
if (CheckDupe)
{
this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
return false;
}
// Begin the sync here. this kickstarts the
// other side, waiting in WAIT_AUTH_2 state,
// into starting their burst, as it shows
// that we're happy.
this->LinkState = CONNECTED;
// we should add the details of this server now
// to the servers tree, as a child of the root
// node.
TreeServer* Node = new TreeServer(this->Utils,this->Instance,sname,description,Utils->TreeRoot,this,x->Hidden);
Utils->TreeRoot->AddChild(Node);
params[3] = ":" + params[3];
Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,sname);
this->bursting = true;
this->DoBurst(Node);
return true;
}
}
this->SendError("Invalid credentials");
this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
return false;
}
bool TreeSocket::Inbound_Server(std::deque<std::string> ¶ms)
{
if (params.size() < 4)
return false;
irc::string servername = params[0].c_str();
std::string sname = params[0];
std::string password = params[1];
std::string description = params[3];
int hops = atoi(params[2].c_str());
this->InboundServerName = sname;
this->InboundDescription = description;
if (!sentcapab)
this->SendCapabilities();
if (hops)
{
this->SendError("Server too far away for authentication");
this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
return false;
}
for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
{
if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password) || x->RecvPass == password && (this->GetTheirChallenge().empty()))))
{
/* First check for instances of the server that are waiting between the inbound and outbound SERVER command */
TreeSocket* CheckDupeSocket = Utils->FindBurstingServer(sname);
if (CheckDupeSocket)
{
/* If we find one, we abort the link to prevent a race condition */
this->SendError("Negotiation collision");
this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists in a negotiating state.");
CheckDupeSocket->SendError("Negotiation collision");
Instance->SE->DelFd(CheckDupeSocket);
CheckDupeSocket->Close();
delete CheckDupeSocket;
return false;
}
/* Now check for fully initialized instances of the server */
TreeServer* CheckDupe = Utils->FindServer(sname);
if (CheckDupe)
{
this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
return false;
}
this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] ("+description+")");
if (this->Hook)
{
std::string name = InspSocketNameRequest((Module*)Utils->Creator, this->Hook).Send();
this->Instance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+name+"\2");
}
Utils->AddBurstingServer(sname,this);
// this is good. Send our details: Our server name and description and hopcount of 0,
// along with the sendpass from this block.
this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
// move to the next state, we are now waiting for THEM.
this->LinkState = WAIT_AUTH_2;
return true;
}
}
this->SendError("Invalid credentials");
this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
return false;
}
void TreeSocket::Split(const std::string &line, std::deque<std::string> &n)
{
n.clear();
irc::tokenstream tokens(line);
std::string param;
while (tokens.GetToken(param))
{
if (!param.empty())
n.push_back(param);
}
return;
}
bool TreeSocket::ProcessLine(std::string &line)
{
std::deque<std::string> params;
irc::string command;
std::string prefix;
line = line.substr(0, line.find_first_of("\r\n"));
if (line.empty())
return true;
Instance->Log(DEBUG, "S[%d] <- %s", this->GetFd(), line.c_str());
this->Split(line.c_str(),params);
if (params.empty())
return true;
if ((params[0][0] == ':') && (params.size() > 1))
{
prefix = params[0].substr(1);
params.pop_front();
}
command = params[0].c_str();
params.pop_front();
switch (this->LinkState)
{
TreeServer* Node;
case WAIT_AUTH_1:
// Waiting for SERVER command from remote server. Server initiating
// the connection sends the first SERVER command, listening server
// replies with theirs if its happy, then if the initiator is happy,
// it starts to send its net sync, which starts the merge, otherwise
// it sends an ERROR.
if (command == "PASS")
{
/* Silently ignored */
}
else if (command == "SERVER")
{
return this->Inbound_Server(params);
}
else if (command == "ERROR")
{
return this->Error(params);
}
else if (command == "USER")
{
this->SendError("Client connections to this port are prohibited.");
return false;
}
else if (command == "CAPAB")
{
return this->Capab(params);
}
else if ((command == "U") || (command == "S"))
{
this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
return false;
}
else
{
irc::string error = "Invalid command in negotiation phase: " + command;
this->SendError(assign(error));
return false;
}
break;
case WAIT_AUTH_2:
// Waiting for start of other side's netmerge to say they liked our
// password.
if (command == "SERVER")
{
// cant do this, they sent it to us in the WAIT_AUTH_1 state!
// silently ignore.
return true;
}
else if ((command == "U") || (command == "S"))
{
this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
return false;
}
else if (command == "BURST")
{
if (params.size() && Utils->EnableTimeSync)
{
bool we_have_delta = (Instance->Time(false) != Instance->Time(true));
time_t them = atoi(params[0].c_str());
time_t delta = them - Instance->Time(false);
if ((delta < -300) || (delta > 300))
{
Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta));
SendError("Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
return false;
}
else if ((delta < -30) || (delta > 30))
{
Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs(delta));
}
if (!Utils->MasterTime && !we_have_delta)
{
this->Instance->SetTimeDelta(delta);
// Send this new timestamp to any other servers
Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);
}
}
this->LinkState = CONNECTED;
Link* lnk = Utils->FindLink(InboundServerName);
Node = new TreeServer(this->Utils,this->Instance, InboundServerName, InboundDescription, Utils->TreeRoot, this, lnk ? lnk->Hidden : false);
Utils->DelBurstingServer(this);
Utils->TreeRoot->AddChild(Node);
params.clear();
params.push_back(InboundServerName);
params.push_back("*");
params.push_back("1");
params.push_back(":"+InboundDescription);
Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,InboundServerName);
this->bursting = true;
this->DoBurst(Node);
}
else if (command == "ERROR")
{
return this->Error(params);
}
else if (command == "CAPAB")
{
return this->Capab(params);
}
break;
case LISTENER:
this->SendError("Internal error -- listening socket accepted its own descriptor!!!");
return false;
break;
case CONNECTING:
if (command == "SERVER")
{
// another server we connected to, which was in WAIT_AUTH_1 state,
// has just sent us their credentials. If we get this far, theyre
// happy with OUR credentials, and they are now in WAIT_AUTH_2 state.
// if we're happy with this, we should send our netburst which
// kickstarts the merge.
return this->Outbound_Reply_Server(params);
}
else if (command == "ERROR")
{
return this->Error(params);
}
else if (command == "CAPAB")
{
return this->Capab(params);
}
break;
case CONNECTED:
// This is the 'authenticated' state, when all passwords
// have been exchanged and anything past this point is taken
// as gospel.
if (!prefix.empty())
{
std::string direction = prefix;
userrec* t = this->Instance->FindNick(prefix);
if (t)
{
direction = t->server;
}
TreeServer* route_back_again = Utils->BestRouteTo(direction);
if ((!route_back_again) || (route_back_again->GetSocket() != this))
{
if (route_back_again)
Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str());
return true;
}
/* Fix by brain:
* When there is activity on the socket, reset the ping counter so
* that we're not wasting bandwidth pinging an active server.
*/
route_back_again->SetNextPingTime(time(NULL) + 60);
route_back_again->SetPingFlag();
}
else
{
prefix = this->GetName();
}
if ((command == "MODE") && (params.size() >= 2))
{
chanrec* channel = Instance->FindChan(params[0]);
if (channel)
{
userrec* x = Instance->FindNick(prefix);
if (x)
{
if (warned.find(x->server) == warned.end())
{
Instance->Log(DEFAULT,"WARNING: I revceived modes '%s' from another server '%s'. This is not compliant with InspIRCd. Please check that server for bugs.", params[1].c_str(), x->server);
Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending nonstandard modes: '%s MODE %s' where FMODE should be used, and may cause desyncs.", x->server, x->nick, params[1].c_str());
warned[x->server] = x->nick;
}
}
}
}
if (command == "SVSMODE")
{
/* Services expects us to implement
* SVSMODE. In inspircd its the same as
* MODE anyway.
*/
command = "MODE";
}
std::string target;
/* Yes, know, this is a mess. Its reasonably fast though as we're
* working with std::string here.
*/
if ((command == "NICK") && (params.size() >= 8))
{
return this->IntroduceClient(prefix,params);
}
else if (command == "FJOIN")
{
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
Utils->SetRemoteBursting(ServerSource, false);
return this->ForceJoin(prefix,params);
}
else if (command == "STATS")
{
return this->Stats(prefix, params);
}
else if (command == "MOTD")
{
return this->Motd(prefix, params);
}
else if (command == "KILL" && Utils->IsServer(prefix))
{
return this->RemoteKill(prefix,params);
}
else if (command == "MODULES")
{
return this->Modules(prefix, params);
}
else if (command == "ADMIN")
{
return this->Admin(prefix, params);
}
else if (command == "SERVER")
{
return this->RemoteServer(prefix,params);
}
else if (command == "ERROR")
{
return this->Error(params);
}
else if (command == "OPERTYPE")
{
return this->OperType(prefix,params);
}
else if (command == "FMODE")
{
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
Utils->SetRemoteBursting(ServerSource, false);
return this->ForceMode(prefix,params);
}
else if (command == "FTOPIC")
{
return this->ForceTopic(prefix,params);
}
else if (command == "REHASH")
{
return this->RemoteRehash(prefix,params);
}
else if (command == "METADATA")
{
return this->MetaData(prefix,params);
}
else if (command == "REMSTATUS")
{
return this->RemoveStatus(prefix,params);
}
else if (command == "PING")
{
if (prefix.empty())
prefix = this->GetName();
/*
* We just got a ping from a server that's bursting.
* This can't be right, so set them to not bursting, and
* apply their lines.
*/
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
Utils->SetRemoteBursting(ServerSource, false);
if (this->bursting)
{
this->bursting = false;
Instance->XLines->apply_lines(Utils->lines_to_apply);
Utils->lines_to_apply = 0;
}
return this->LocalPing(prefix,params);
}
else if (command == "PONG")
{
if (prefix.empty())
prefix = this->GetName();
/*
* We just got a pong from a server that's bursting.
* This can't be right, so set them to not bursting, and
* apply their lines.
*/
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
Utils->SetRemoteBursting(ServerSource, false);
if (this->bursting)
{
this->bursting = false;
Instance->XLines->apply_lines(Utils->lines_to_apply);
Utils->lines_to_apply = 0;
}
return this->LocalPong(prefix,params);
}
else if (command == "VERSION")
{
return this->ServerVersion(prefix,params);
}
else if (command == "FHOST")
{
return this->ChangeHost(prefix,params);
}
else if (command == "FNAME")
{
return this->ChangeName(prefix,params);
}
else if (command == "ADDLINE")
{
TreeServer* ServerSource = Utils->FindServer(prefix);
if (ServerSource)
Utils->SetRemoteBursting(ServerSource, false);
return this->AddLine(prefix,params);
}
else if (command == "SVSNICK")
{
if (prefix.empty())
{
prefix = this->GetName();
}
return this->ForceNick(prefix,params);
}
else if (command == "OPERQUIT")
{
return this->OperQuit(prefix,params);
}
else if (command == "IDLE")
{
return this->Whois(prefix,params);
}
else if (command == "PUSH")
{
return this->Push(prefix,params);
}
else if (command == "TIMESET")
{
return this->HandleSetTime(prefix, params);
}
else if (command == "TIME")
{
return this->Time(prefix,params);
}
else if ((command == "KICK") && (Utils->IsServer(prefix)))
{
std::string sourceserv = this->myhost;
if (params.size() == 3)
{
userrec* user = this->Instance->FindNick(params[1]);
chanrec* chan = this->Instance->FindChan(params[0]);
if (user && chan)
{
if (!chan->ServerKickUser(user, params[2].c_str(), false))
/* Yikes, the channels gone! */
delete chan;
}
}
if (!this->InboundServerName.empty())
{
sourceserv = this->InboundServerName;
}
return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
}
else if (command == "SVSJOIN")
{
if (prefix.empty())
{
prefix = this->GetName();
}
return this->ServiceJoin(prefix,params);
}
else if (command == "SQUIT")
{
if (params.size() == 2)
{
this->Squit(Utils->FindServer(params[0]),params[1]);
}
return true;
}
else if (command == "OPERNOTICE")
{
std::string sourceserv = this->myhost;
if (!this->InboundServerName.empty())
sourceserv = this->InboundServerName;
if (params.size() >= 1)
Instance->WriteOpers("*** From " + sourceserv + ": " + params[0]);
return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
}
else if (command == "MODENOTICE")
{
std::string sourceserv = this->myhost;
if (!this->InboundServerName.empty())
sourceserv = this->InboundServerName;
if (params.size() >= 2)
{
Instance->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", sourceserv.c_str(), params[1].c_str());
}
return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
}
else if (command == "SNONOTICE")
{
std::string sourceserv = this->myhost;
if (!this->InboundServerName.empty())
sourceserv = this->InboundServerName;
if (params.size() >= 2)
{
Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + sourceserv + ": "+ params[1]);
}
return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
}
else if (command == "ENDBURST")
{
this->bursting = false;
Instance->XLines->apply_lines(Utils->lines_to_apply);
Utils->lines_to_apply = 0;
std::string sourceserv = this->myhost;
if (!this->InboundServerName.empty())
sourceserv = this->InboundServerName;
this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str());
Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server");
rmode.Send(Instance);
return true;
}
else
{
// not a special inter-server command.
// Emulate the actual user doing the command,
// this saves us having a huge ugly parser.
userrec* who = this->Instance->FindNick(prefix);
std::string sourceserv = this->myhost;
if (!this->InboundServerName.empty())
{
sourceserv = this->InboundServerName;
}
if ((!who) && (command == "MODE"))
{
if (Utils->IsServer(prefix))
{
const char* modelist[127];
for (size_t i = 0; i < params.size(); i++)
modelist[i] = params[i].c_str();
userrec* fake = new userrec(Instance);
fake->SetFd(FD_MAGIC_NUMBER);
this->Instance->SendMode(modelist, params.size(), fake);
delete fake;
/* Hot potato! pass it on! */
return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
}
}
if (who)
{
if ((command == "NICK") && (params.size() > 0))
{
/* On nick messages, check that the nick doesnt
* already exist here. If it does, kill their copy,
* and our copy.
*/
userrec* x = this->Instance->FindNick(params[0]);
if ((x) && (x != who))
{
std::deque<std::string> p;
p.push_back(params[0]);
p.push_back("Nickname collision ("+prefix+" -> "+params[0]+")");
Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
p.clear();
p.push_back(prefix);
p.push_back("Nickname collision");
Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")");
userrec* y = this->Instance->FindNick(prefix);
if (y)
{
userrec::QuitUser(this->Instance,y,"Nickname collision");
}
return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
}
}
// its a user
target = who->server;
const char* strparams[127];
for (unsigned int q = 0; q < params.size(); q++)
{
strparams[q] = params[q].c_str();
}
switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who))
{
case CMD_INVALID:
this->SendError("Unrecognised command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules");
return false;
break;
case CMD_FAILURE:
return true;
break;
default:
/* CMD_SUCCESS and CMD_USER_DELETED fall through here */
break;
}
}
else
{
// its not a user. Its either a server, or somethings screwed up.
if (Utils->IsServer(prefix))
target = this->Instance->Config->ServerName;
else
return true;
}
return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
}
return true;
break;
}
return true;
}
std::string TreeSocket::GetName()
{
std::string sourceserv = this->myhost;
if (!this->InboundServerName.empty())
{
sourceserv = this->InboundServerName;
}
return sourceserv;
}
void TreeSocket::OnTimeout()
{
if (this->LinkState == CONNECTING)
{
this->Instance->SNO->WriteToSnoMask('l',"CONNECT: Connection to \002"+myhost+"\002 timed out.");
Link* MyLink = Utils->FindLink(myhost);
if (MyLink)
Utils->DoFailOver(MyLink);
}
}
void TreeSocket::OnClose()
{
// Connection closed.
// If the connection is fully up (state CONNECTED)
// then propogate a netsplit to all peers.
std::string quitserver = this->myhost;
if (!this->InboundServerName.empty())
{
quitserver = this->InboundServerName;
}
TreeServer* s = Utils->FindServer(quitserver);
if (s)
{
Squit(s,"Remote host closed the connection");
}
if (!quitserver.empty())
{
this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str());
time_t server_uptime = Instance->Time() - this->age;
if (server_uptime)
Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str());
}
}
int TreeSocket::OnIncomingConnection(int newsock, char* ip)
{
/* To prevent anyone from attempting to flood opers/DDoS by connecting to the server port,
* or discovering if this port is the server port, we don't allow connections from any
* IPs for which we don't have a link block.
*/
bool found = false;
found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end());
if (!found)
{
for (vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++)
if (irc::sockets::MatchCIDR(ip, (*i).c_str()))
found = true;
if (!found)
{
this->Instance->SNO->WriteToSnoMask('l',"Server connection from %s denied (no link blocks with that IP address)", ip);
close(newsock);
return false;
}
}
TreeSocket* s = new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook);
s = s; /* Whinge whinge whinge, thats all GCC ever does. */
return true;
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index 9675a6ac8..4d0256fa2 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -1,649 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "commands/cmd_whois.h" -#include "commands/cmd_stats.h" -#include "socket.h" -#include "wildcard.h" -#include "xline.h" -#include "transport.h" -#include "socketengine.h" - -#include "m_spanningtree/main.h" -#include "m_spanningtree/utils.h" -#include "m_spanningtree/treeserver.h" -#include "m_spanningtree/link.h" -#include "m_spanningtree/treesocket.h" -#include "m_spanningtree/resolvers.h" - -/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */ - -/** Yay for fast searches! - * This is hundreds of times faster than recursion - * or even scanning a linked list, especially when - * there are more than a few servers to deal with. - * (read as: lots). - */ -TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName) -{ - server_hash::iterator iter = serverlist.find(ServerName.c_str()); - if (iter != serverlist.end()) - { - return iter->second; - } - else - { - return NULL; - } -} - -TreeServer* SpanningTreeUtilities::FindRemoteBurstServer(TreeServer* Server) -{ - server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str()); - if (iter != RemoteServersBursting.end()) - return iter->second; - else - return NULL; -} - -TreeSocket* SpanningTreeUtilities::FindBurstingServer(const std::string &ServerName) -{ - std::map<irc::string,TreeSocket*>::iterator iter; - iter = burstingserverlist.find(ServerName.c_str()); - if (iter != burstingserverlist.end()) - { - return iter->second; - } - else - { - return NULL; - } -} - -void SpanningTreeUtilities::SetRemoteBursting(TreeServer* Server, bool bursting) -{ - server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str()); - if (bursting) - { - if (iter == RemoteServersBursting.end()) - RemoteServersBursting.insert(make_pair(Server->GetName(), Server)); - else return; - } - else - { - if (iter != RemoteServersBursting.end()) - RemoteServersBursting.erase(iter); - else return; - } - ServerInstance->Log(DEBUG,"Server %s is %sbursting nicknames", Server->GetName().c_str(), bursting ? "" : "no longer "); -} - -void SpanningTreeUtilities::AddBurstingServer(const std::string &ServerName, TreeSocket* s) -{ - std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.find(ServerName.c_str()); - if (iter == burstingserverlist.end()) - burstingserverlist[ServerName.c_str()] = s; -} - -void SpanningTreeUtilities::DelBurstingServer(TreeSocket* s) -{ - for (std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.begin(); iter != burstingserverlist.end(); iter++) - { - if (iter->second == s) - { - burstingserverlist.erase(iter); - return; - } - } -} - -/** Returns the locally connected server we must route a - * message through to reach server 'ServerName'. This - * only applies to one-to-one and not one-to-many routing. - * See the comments for the constructor of TreeServer - * for more details. - */ -TreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName) -{ - if (ServerName.c_str() == TreeRoot->GetName()) - return NULL; - TreeServer* Found = FindServer(ServerName); - if (Found) - { - return Found->GetRoute(); - } - else - { - return NULL; - } -} - -/** Find the first server matching a given glob mask. - * Theres no find-using-glob method of hash_map [awwww :-(] - * so instead, we iterate over the list using an iterator - * and match each one until we get a hit. Yes its slow, - * deal with it. - */ -TreeServer* SpanningTreeUtilities::FindServerMask(const std::string &ServerName) -{ - for (server_hash::iterator i = serverlist.begin(); i != serverlist.end(); i++) - { - if (match(i->first.c_str(),ServerName.c_str())) - return i->second; - } - return NULL; -} - -/* A convenient wrapper that returns true if a server exists */ -bool SpanningTreeUtilities::IsServer(const std::string &ServerName) -{ - return (FindServer(ServerName) != NULL); -} - -SpanningTreeUtilities::SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* C) : ServerInstance(Instance), Creator(C) -{ - Bindings.clear(); - - lines_to_apply = 0; - - this->TreeRoot = new TreeServer(this, ServerInstance, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc); - - modulelist* ml = ServerInstance->FindInterface("InspSocketHook"); - - /* Did we find any modules? */ - if (ml) - { - /* Yes, enumerate them all to find out the hook name */ - for (modulelist::iterator m = ml->begin(); m != ml->end(); m++) - { - /* Make a request to it for its name, its implementing - * InspSocketHook so we know its safe to do this - */ - std::string name = InspSocketNameRequest((Module*)Creator, *m).Send(); - /* Build a map of them */ - hooks[name.c_str()] = *m; - hooknames.push_back(name); - } - } - - this->ReadConfiguration(true); -} - -SpanningTreeUtilities::~SpanningTreeUtilities() -{ - for (unsigned int i = 0; i < Bindings.size(); i++) - { - ServerInstance->SE->DelFd(Bindings[i]); - Bindings[i]->Close(); - DELETE(Bindings[i]); - } - while (TreeRoot->ChildCount()) - { - TreeServer* child_server = TreeRoot->GetChild(0); - if (child_server) - { - TreeSocket* sock = child_server->GetSocket(); - ServerInstance->SE->DelFd(sock); - sock->Close(); - DELETE(sock); - } - } - delete TreeRoot; -} - -void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list) -{ - if (list.find(server) == list.end()) - list[server] = server; -} - -/* returns a list of DIRECT servernames for a specific channel */ -void SpanningTreeUtilities::GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list) -{ - CUList *ulist; - switch (status) - { - case '@': - ulist = c->GetOppedUsers(); - break; - case '%': - ulist = c->GetHalfoppedUsers(); - break; - case '+': - ulist = c->GetVoicedUsers(); - break; - default: - ulist = c->GetUsers(); - break; - } - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - if ((i->first->GetFd() < 0) && (exempt_list.find(i->first) == exempt_list.end())) - { - TreeServer* best = this->BestRouteTo(i->first->server); - if (best) - AddThisServer(best,list); - } - } - return; -} - -bool SpanningTreeUtilities::DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> ¶ms) -{ - char pfx = 0; - TreeServer* omitroute = this->BestRouteTo(omit); - if ((command == "NOTICE") || (command == "PRIVMSG")) - { - if (params.size() >= 2) - { - /* Prefixes */ - if ((*(params[0].c_str()) == '@') || (*(params[0].c_str()) == '%') || (*(params[0].c_str()) == '+')) - { - pfx = params[0][0]; - params[0] = params[0].substr(1, params[0].length()-1); - } - if ((*(params[0].c_str()) != '#') && (*(params[0].c_str()) != '$')) - { - // special routing for private messages/notices - userrec* d = ServerInstance->FindNick(params[0]); - if (d) - { - std::deque<std::string> par; - par.push_back(params[0]); - par.push_back(":"+params[1]); - this->DoOneToOne(prefix,command.c_str(),par,d->server); - return true; - } - } - else if (*(params[0].c_str()) == '$') - { - std::deque<std::string> par; - par.push_back(params[0]); - par.push_back(":"+params[1]); - this->DoOneToAllButSender(prefix,command.c_str(),par,omitroute->GetName()); - return true; - } - else - { - chanrec* c = ServerInstance->FindChan(params[0]); - userrec* u = ServerInstance->FindNick(prefix); - if (c && u) - { - CUList elist; - TreeServerList list; - FOREACH_MOD(I_OnBuildExemptList, OnBuildExemptList((command == "PRIVMSG" ? MSG_PRIVMSG : MSG_NOTICE), c, u, pfx, elist)); - GetListOfServersForChannel(c,list,pfx,elist); - - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if ((Sock) && (i->second->GetName() != omit) && (omitroute != i->second)) - { - Sock->WriteLine(data); - } - } - return true; - } - } - } - } - unsigned int items =this->TreeRoot->ChildCount(); - for (unsigned int x = 0; x < items; x++) - { - TreeServer* Route = this->TreeRoot->GetChild(x); - if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route)) - { - TreeSocket* Sock = Route->GetSocket(); - if (Sock) - Sock->WriteLine(data); - } - } - return true; -} - -bool SpanningTreeUtilities::DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string omit) -{ - TreeServer* omitroute = this->BestRouteTo(omit); - std::string FullLine = ":" + prefix + " " + command; - unsigned int words = params.size(); - for (unsigned int x = 0; x < words; x++) - { - FullLine = FullLine + " " + params[x]; - } - unsigned int items = this->TreeRoot->ChildCount(); - for (unsigned int x = 0; x < items; x++) - { - TreeServer* Route = this->TreeRoot->GetChild(x); - // Send the line IF: - // The route has a socket (its a direct connection) - // The route isnt the one to be omitted - // The route isnt the path to the one to be omitted - if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route)) - { - TreeSocket* Sock = Route->GetSocket(); - if (Sock) - Sock->WriteLine(FullLine); - } - } - return true; -} - -bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms) -{ - std::string FullLine = ":" + prefix + " " + command; - unsigned int words = params.size(); - for (unsigned int x = 0; x < words; x++) - { - FullLine = FullLine + " " + params[x]; - } - unsigned int items = this->TreeRoot->ChildCount(); - for (unsigned int x = 0; x < items; x++) - { - TreeServer* Route = this->TreeRoot->GetChild(x); - if (Route && Route->GetSocket()) - { - TreeSocket* Sock = Route->GetSocket(); - if (Sock) - Sock->WriteLine(FullLine); - } - } - return true; -} - -bool SpanningTreeUtilities::DoOneToMany(const char* prefix, const char* command, std::deque<std::string> ¶ms) -{ - std::string spfx = prefix; - std::string scmd = command; - return this->DoOneToMany(spfx, scmd, params); -} - -bool SpanningTreeUtilities::DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> ¶ms, std::string omit) -{ - std::string spfx = prefix; - std::string scmd = command; - return this->DoOneToAllButSender(spfx, scmd, params, omit); -} - -bool SpanningTreeUtilities::DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string target) -{ - TreeServer* Route = this->BestRouteTo(target); - if (Route) - { - std::string FullLine = ":" + prefix + " " + command; - unsigned int words = params.size(); - for (unsigned int x = 0; x < words; x++) - { - FullLine = FullLine + " " + params[x]; - } - if (Route && Route->GetSocket()) - { - TreeSocket* Sock = Route->GetSocket(); - if (Sock) - Sock->WriteLine(FullLine); - } - return true; - } - else - { - return false; - } -} - -void SpanningTreeUtilities::RefreshIPCache() -{ - ValidIPs.clear(); - for (std::vector<Link>::iterator L = LinkBlocks.begin(); L != LinkBlocks.end(); L++) - { - if ((!L->IPAddr.empty()) && (!L->RecvPass.empty()) && (!L->SendPass.empty()) && (!L->Name.empty()) && (L->Port)) - { - ValidIPs.push_back(L->IPAddr); - - if (L->AllowMask.length()) - ValidIPs.push_back(L->AllowMask); - - /* Needs resolving */ - bool ipvalid = true; - QueryType start_type = DNS_QUERY_A; -#ifdef IPV6 - start_type = DNS_QUERY_AAAA; - if (strchr(L->IPAddr.c_str(),':')) - { - in6_addr n; - if (inet_pton(AF_INET6, L->IPAddr.c_str(), &n) < 1) - ipvalid = false; - } - else -#endif - { - in_addr n; - if (inet_aton(L->IPAddr.c_str(),&n) < 1) - ipvalid = false; - } - if (!ipvalid) - { - try - { - bool cached; - SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L->IPAddr, *L, cached, start_type); - ServerInstance->AddResolver(sr, cached); - } - catch (...) - { - } - } - } - } -} - -void SpanningTreeUtilities::ReadConfiguration(bool rebind) -{ - ConfigReader* Conf = new ConfigReader(ServerInstance); - if (rebind) - { - for (int j = 0; j < Conf->Enumerate("bind"); j++) - { - std::string Type = Conf->ReadValue("bind","type",j); - std::string IP = Conf->ReadValue("bind","address",j); - std::string Port = Conf->ReadValue("bind","port",j); - std::string transport = Conf->ReadValue("bind","transport",j); - if (Type == "servers") - { - irc::portparser portrange(Port, false); - int portno = -1; - while ((portno = portrange.GetToken())) - { - if (IP == "*") - IP.clear(); - - if ((!transport.empty()) && (hooks.find(transport.c_str()) == hooks.end())) - { - ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for port %s:%s - maybe you forgot to load it BEFORE m_spanningtree in your config file? - Skipping this port binding", transport.c_str(), IP.c_str(), Port.c_str()); - break; - } - - TreeSocket* listener = new TreeSocket(this, ServerInstance, IP.c_str(), portno, true, 10, transport.empty() ? NULL : hooks[transport.c_str()]); - if (listener->GetState() == I_LISTENING) - { - ServerInstance->Log(DEFAULT,"m_spanningtree: Binding server port %s:%d successful!", IP.c_str(), portno); - Bindings.push_back(listener); - } - else - { - ServerInstance->Log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port: %s:%d: %s",IP.c_str(), portno, strerror(errno)); - listener->Close(); - DELETE(listener); - } - } - } - } - } - FlatLinks = Conf->ReadFlag("options","flatlinks",0); - HideULines = Conf->ReadFlag("options","hideulines",0); - AnnounceTSChange = Conf->ReadFlag("options","announcets",0); - EnableTimeSync = Conf->ReadFlag("timesync","enable",0); - MasterTime = Conf->ReadFlag("timesync", "master", 0); - ChallengeResponse = !Conf->ReadFlag("options", "disablehmac", 0); - quiet_bursts = Conf->ReadFlag("options", "quietbursts", 0); - PingWarnTime = Conf->ReadInteger("options", "pingwarning", 0, true); - - if (PingWarnTime < 0 || PingWarnTime > 59) - PingWarnTime = 0; - - LinkBlocks.clear(); - ValidIPs.clear(); - for (int j = 0; j < Conf->Enumerate("link"); j++) - { - Link L; - std::string Allow = Conf->ReadValue("link", "allowmask", j); - L.Name = (Conf->ReadValue("link", "name", j)).c_str(); - L.AllowMask = Allow; - L.IPAddr = Conf->ReadValue("link", "ipaddr", j); - L.FailOver = Conf->ReadValue("link", "failover", j).c_str(); - L.Port = Conf->ReadInteger("link", "port", j, true); - L.SendPass = Conf->ReadValue("link", "sendpass", j); - L.RecvPass = Conf->ReadValue("link", "recvpass", j); - L.AutoConnect = Conf->ReadInteger("link", "autoconnect", j, true); - L.HiddenFromStats = Conf->ReadFlag("link", "statshidden", j); - L.Timeout = Conf->ReadInteger("link", "timeout", j, true); - L.Hook = Conf->ReadValue("link", "transport", j); - L.Bind = Conf->ReadValue("link", "bind", j); - L.Hidden = Conf->ReadFlag("link", "hidden", j); - - if ((!L.Hook.empty()) && (hooks.find(L.Hook.c_str()) == hooks.end())) - { - ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for link '%s' - maybe you forgot to load it BEFORE m_spanningtree in your config file? Skipping <link> tag completely.", - L.Hook.c_str(), L.Name.c_str()); - continue; - - } - - L.NextConnectTime = time(NULL) + L.AutoConnect; - /* Bugfix by brain, do not allow people to enter bad configurations */ - if (L.Name != ServerInstance->Config->ServerName) - { - if ((!L.IPAddr.empty()) && (!L.RecvPass.empty()) && (!L.SendPass.empty()) && (!L.Name.empty()) && (L.Port)) - { - ValidIPs.push_back(L.IPAddr); - - if (Allow.length()) - ValidIPs.push_back(Allow); - - /* Needs resolving */ - bool ipvalid = true; - QueryType start_type = DNS_QUERY_A; -#ifdef IPV6 - start_type = DNS_QUERY_AAAA; - if (strchr(L.IPAddr.c_str(),':')) - { - in6_addr n; - if (inet_pton(AF_INET6, L.IPAddr.c_str(), &n) < 1) - ipvalid = false; - } - else - { - in_addr n; - if (inet_aton(L.IPAddr.c_str(),&n) < 1) - ipvalid = false; - } -#else - in_addr n; - if (inet_aton(L.IPAddr.c_str(),&n) < 1) - ipvalid = false; -#endif - - if (!ipvalid) - { - try - { - bool cached; - SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L.IPAddr, L, cached, start_type); - ServerInstance->AddResolver(sr, cached); - } - catch (...) - { - } - } - - LinkBlocks.push_back(L); - } - else - { - if (L.IPAddr.empty()) - { - ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', IP address not defined!",L.Name.c_str()); - } - else if (L.RecvPass.empty()) - { - ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', recvpass not defined!",L.Name.c_str()); - } - else if (L.SendPass.empty()) - { - ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', sendpass not defined!",L.Name.c_str()); - } - else if (L.Name.empty()) - { - ServerInstance->Log(DEFAULT,"Invalid configuration, link tag without a name!"); - } - else if (!L.Port) - { - ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', no port specified!",L.Name.c_str()); - } - } - } - else - { - ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', link tag has the same server name as the local server!",L.Name.c_str()); - } - } - DELETE(Conf); -} - -void SpanningTreeUtilities::DoFailOver(Link* x) -{ - if (x->FailOver.length()) - { - if (x->FailOver == x->Name) - { - ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Some muppet configured the failover for server \002%s\002 to point at itself. Not following it!", x->Name.c_str()); - return; - } - Link* TryThisOne = this->FindLink(x->FailOver.c_str()); - if (TryThisOne) - { - ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Name.c_str(), TryThisOne->Name.c_str()); - Creator->ConnectServer(TryThisOne); - } - else - { - ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Name.c_str()); - } - } -} - -Link* SpanningTreeUtilities::FindLink(const std::string& name) -{ - for (std::vector<Link>::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++) - { - if (ServerInstance->MatchText(x->Name.c_str(), name.c_str())) - { - return &(*x); - } - } - return NULL; -} - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "socketengine.h"
#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/resolvers.h"
/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
/** Yay for fast searches!
* This is hundreds of times faster than recursion
* or even scanning a linked list, especially when
* there are more than a few servers to deal with.
* (read as: lots).
*/
TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName)
{
server_hash::iterator iter = serverlist.find(ServerName.c_str());
if (iter != serverlist.end())
{
return iter->second;
}
else
{
return NULL;
}
}
TreeServer* SpanningTreeUtilities::FindRemoteBurstServer(TreeServer* Server)
{
server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str());
if (iter != RemoteServersBursting.end())
return iter->second;
else
return NULL;
}
TreeSocket* SpanningTreeUtilities::FindBurstingServer(const std::string &ServerName)
{
std::map<irc::string,TreeSocket*>::iterator iter;
iter = burstingserverlist.find(ServerName.c_str());
if (iter != burstingserverlist.end())
{
return iter->second;
}
else
{
return NULL;
}
}
void SpanningTreeUtilities::SetRemoteBursting(TreeServer* Server, bool bursting)
{
server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str());
if (bursting)
{
if (iter == RemoteServersBursting.end())
RemoteServersBursting.insert(make_pair(Server->GetName(), Server));
else return;
}
else
{
if (iter != RemoteServersBursting.end())
RemoteServersBursting.erase(iter);
else return;
}
ServerInstance->Log(DEBUG,"Server %s is %sbursting nicknames", Server->GetName().c_str(), bursting ? "" : "no longer ");
}
void SpanningTreeUtilities::AddBurstingServer(const std::string &ServerName, TreeSocket* s)
{
std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.find(ServerName.c_str());
if (iter == burstingserverlist.end())
burstingserverlist[ServerName.c_str()] = s;
}
void SpanningTreeUtilities::DelBurstingServer(TreeSocket* s)
{
for (std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.begin(); iter != burstingserverlist.end(); iter++)
{
if (iter->second == s)
{
burstingserverlist.erase(iter);
return;
}
}
}
/** Returns the locally connected server we must route a
* message through to reach server 'ServerName'. This
* only applies to one-to-one and not one-to-many routing.
* See the comments for the constructor of TreeServer
* for more details.
*/
TreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName)
{
if (ServerName.c_str() == TreeRoot->GetName())
return NULL;
TreeServer* Found = FindServer(ServerName);
if (Found)
{
return Found->GetRoute();
}
else
{
return NULL;
}
}
/** Find the first server matching a given glob mask.
* Theres no find-using-glob method of hash_map [awwww :-(]
* so instead, we iterate over the list using an iterator
* and match each one until we get a hit. Yes its slow,
* deal with it.
*/
TreeServer* SpanningTreeUtilities::FindServerMask(const std::string &ServerName)
{
for (server_hash::iterator i = serverlist.begin(); i != serverlist.end(); i++)
{
if (match(i->first.c_str(),ServerName.c_str()))
return i->second;
}
return NULL;
}
/* A convenient wrapper that returns true if a server exists */
bool SpanningTreeUtilities::IsServer(const std::string &ServerName)
{
return (FindServer(ServerName) != NULL);
}
SpanningTreeUtilities::SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* C) : ServerInstance(Instance), Creator(C)
{
Bindings.clear();
lines_to_apply = 0;
this->TreeRoot = new TreeServer(this, ServerInstance, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc);
modulelist* ml = ServerInstance->FindInterface("InspSocketHook");
/* Did we find any modules? */
if (ml)
{
/* Yes, enumerate them all to find out the hook name */
for (modulelist::iterator m = ml->begin(); m != ml->end(); m++)
{
/* Make a request to it for its name, its implementing
* InspSocketHook so we know its safe to do this
*/
std::string name = InspSocketNameRequest((Module*)Creator, *m).Send();
/* Build a map of them */
hooks[name.c_str()] = *m;
hooknames.push_back(name);
}
}
this->ReadConfiguration(true);
}
SpanningTreeUtilities::~SpanningTreeUtilities()
{
for (unsigned int i = 0; i < Bindings.size(); i++)
{
ServerInstance->SE->DelFd(Bindings[i]);
Bindings[i]->Close();
DELETE(Bindings[i]);
}
while (TreeRoot->ChildCount())
{
TreeServer* child_server = TreeRoot->GetChild(0);
if (child_server)
{
TreeSocket* sock = child_server->GetSocket();
ServerInstance->SE->DelFd(sock);
sock->Close();
DELETE(sock);
}
}
delete TreeRoot;
}
void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list)
{
if (list.find(server) == list.end())
list[server] = server;
}
/* returns a list of DIRECT servernames for a specific channel */
void SpanningTreeUtilities::GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list)
{
CUList *ulist;
switch (status)
{
case '@':
ulist = c->GetOppedUsers();
break;
case '%':
ulist = c->GetHalfoppedUsers();
break;
case '+':
ulist = c->GetVoicedUsers();
break;
default:
ulist = c->GetUsers();
break;
}
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
if ((i->first->GetFd() < 0) && (exempt_list.find(i->first) == exempt_list.end()))
{
TreeServer* best = this->BestRouteTo(i->first->server);
if (best)
AddThisServer(best,list);
}
}
return;
}
bool SpanningTreeUtilities::DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> ¶ms)
{
char pfx = 0;
TreeServer* omitroute = this->BestRouteTo(omit);
if ((command == "NOTICE") || (command == "PRIVMSG"))
{
if (params.size() >= 2)
{
/* Prefixes */
if ((*(params[0].c_str()) == '@') || (*(params[0].c_str()) == '%') || (*(params[0].c_str()) == '+'))
{
pfx = params[0][0];
params[0] = params[0].substr(1, params[0].length()-1);
}
if ((*(params[0].c_str()) != '#') && (*(params[0].c_str()) != '$'))
{
// special routing for private messages/notices
userrec* d = ServerInstance->FindNick(params[0]);
if (d)
{
std::deque<std::string> par;
par.push_back(params[0]);
par.push_back(":"+params[1]);
this->DoOneToOne(prefix,command.c_str(),par,d->server);
return true;
}
}
else if (*(params[0].c_str()) == '$')
{
std::deque<std::string> par;
par.push_back(params[0]);
par.push_back(":"+params[1]);
this->DoOneToAllButSender(prefix,command.c_str(),par,omitroute->GetName());
return true;
}
else
{
chanrec* c = ServerInstance->FindChan(params[0]);
userrec* u = ServerInstance->FindNick(prefix);
if (c && u)
{
CUList elist;
TreeServerList list;
FOREACH_MOD(I_OnBuildExemptList, OnBuildExemptList((command == "PRIVMSG" ? MSG_PRIVMSG : MSG_NOTICE), c, u, pfx, elist));
GetListOfServersForChannel(c,list,pfx,elist);
for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
{
TreeSocket* Sock = i->second->GetSocket();
if ((Sock) && (i->second->GetName() != omit) && (omitroute != i->second))
{
Sock->WriteLine(data);
}
}
return true;
}
}
}
}
unsigned int items =this->TreeRoot->ChildCount();
for (unsigned int x = 0; x < items; x++)
{
TreeServer* Route = this->TreeRoot->GetChild(x);
if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))
{
TreeSocket* Sock = Route->GetSocket();
if (Sock)
Sock->WriteLine(data);
}
}
return true;
}
bool SpanningTreeUtilities::DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string omit)
{
TreeServer* omitroute = this->BestRouteTo(omit);
std::string FullLine = ":" + prefix + " " + command;
unsigned int words = params.size();
for (unsigned int x = 0; x < words; x++)
{
FullLine = FullLine + " " + params[x];
}
unsigned int items = this->TreeRoot->ChildCount();
for (unsigned int x = 0; x < items; x++)
{
TreeServer* Route = this->TreeRoot->GetChild(x);
// Send the line IF:
// The route has a socket (its a direct connection)
// The route isnt the one to be omitted
// The route isnt the path to the one to be omitted
if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))
{
TreeSocket* Sock = Route->GetSocket();
if (Sock)
Sock->WriteLine(FullLine);
}
}
return true;
}
bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms)
{
std::string FullLine = ":" + prefix + " " + command;
unsigned int words = params.size();
for (unsigned int x = 0; x < words; x++)
{
FullLine = FullLine + " " + params[x];
}
unsigned int items = this->TreeRoot->ChildCount();
for (unsigned int x = 0; x < items; x++)
{
TreeServer* Route = this->TreeRoot->GetChild(x);
if (Route && Route->GetSocket())
{
TreeSocket* Sock = Route->GetSocket();
if (Sock)
Sock->WriteLine(FullLine);
}
}
return true;
}
bool SpanningTreeUtilities::DoOneToMany(const char* prefix, const char* command, std::deque<std::string> ¶ms)
{
std::string spfx = prefix;
std::string scmd = command;
return this->DoOneToMany(spfx, scmd, params);
}
bool SpanningTreeUtilities::DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> ¶ms, std::string omit)
{
std::string spfx = prefix;
std::string scmd = command;
return this->DoOneToAllButSender(spfx, scmd, params, omit);
}
bool SpanningTreeUtilities::DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string target)
{
TreeServer* Route = this->BestRouteTo(target);
if (Route)
{
std::string FullLine = ":" + prefix + " " + command;
unsigned int words = params.size();
for (unsigned int x = 0; x < words; x++)
{
FullLine = FullLine + " " + params[x];
}
if (Route && Route->GetSocket())
{
TreeSocket* Sock = Route->GetSocket();
if (Sock)
Sock->WriteLine(FullLine);
}
return true;
}
else
{
return false;
}
}
void SpanningTreeUtilities::RefreshIPCache()
{
ValidIPs.clear();
for (std::vector<Link>::iterator L = LinkBlocks.begin(); L != LinkBlocks.end(); L++)
{
if ((!L->IPAddr.empty()) && (!L->RecvPass.empty()) && (!L->SendPass.empty()) && (!L->Name.empty()) && (L->Port))
{
ValidIPs.push_back(L->IPAddr);
if (L->AllowMask.length())
ValidIPs.push_back(L->AllowMask);
/* Needs resolving */
bool ipvalid = true;
QueryType start_type = DNS_QUERY_A;
#ifdef IPV6
start_type = DNS_QUERY_AAAA;
if (strchr(L->IPAddr.c_str(),':'))
{
in6_addr n;
if (inet_pton(AF_INET6, L->IPAddr.c_str(), &n) < 1)
ipvalid = false;
}
else
#endif
{
in_addr n;
if (inet_aton(L->IPAddr.c_str(),&n) < 1)
ipvalid = false;
}
if (!ipvalid)
{
try
{
bool cached;
SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L->IPAddr, *L, cached, start_type);
ServerInstance->AddResolver(sr, cached);
}
catch (...)
{
}
}
}
}
}
void SpanningTreeUtilities::ReadConfiguration(bool rebind)
{
ConfigReader* Conf = new ConfigReader(ServerInstance);
if (rebind)
{
for (int j = 0; j < Conf->Enumerate("bind"); j++)
{
std::string Type = Conf->ReadValue("bind","type",j);
std::string IP = Conf->ReadValue("bind","address",j);
std::string Port = Conf->ReadValue("bind","port",j);
std::string transport = Conf->ReadValue("bind","transport",j);
if (Type == "servers")
{
irc::portparser portrange(Port, false);
int portno = -1;
while ((portno = portrange.GetToken()))
{
if (IP == "*")
IP.clear();
if ((!transport.empty()) && (hooks.find(transport.c_str()) == hooks.end()))
{
ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for port %s:%s - maybe you forgot to load it BEFORE m_spanningtree in your config file? - Skipping this port binding", transport.c_str(), IP.c_str(), Port.c_str());
break;
}
TreeSocket* listener = new TreeSocket(this, ServerInstance, IP.c_str(), portno, true, 10, transport.empty() ? NULL : hooks[transport.c_str()]);
if (listener->GetState() == I_LISTENING)
{
ServerInstance->Log(DEFAULT,"m_spanningtree: Binding server port %s:%d successful!", IP.c_str(), portno);
Bindings.push_back(listener);
}
else
{
ServerInstance->Log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port: %s:%d: %s",IP.c_str(), portno, strerror(errno));
listener->Close();
DELETE(listener);
}
}
}
}
}
FlatLinks = Conf->ReadFlag("options","flatlinks",0);
HideULines = Conf->ReadFlag("options","hideulines",0);
AnnounceTSChange = Conf->ReadFlag("options","announcets",0);
EnableTimeSync = Conf->ReadFlag("timesync","enable",0);
MasterTime = Conf->ReadFlag("timesync", "master", 0);
ChallengeResponse = !Conf->ReadFlag("options", "disablehmac", 0);
quiet_bursts = Conf->ReadFlag("options", "quietbursts", 0);
PingWarnTime = Conf->ReadInteger("options", "pingwarning", 0, true);
if (PingWarnTime < 0 || PingWarnTime > 59)
PingWarnTime = 0;
LinkBlocks.clear();
ValidIPs.clear();
for (int j = 0; j < Conf->Enumerate("link"); j++)
{
Link L;
std::string Allow = Conf->ReadValue("link", "allowmask", j);
L.Name = (Conf->ReadValue("link", "name", j)).c_str();
L.AllowMask = Allow;
L.IPAddr = Conf->ReadValue("link", "ipaddr", j);
L.FailOver = Conf->ReadValue("link", "failover", j).c_str();
L.Port = Conf->ReadInteger("link", "port", j, true);
L.SendPass = Conf->ReadValue("link", "sendpass", j);
L.RecvPass = Conf->ReadValue("link", "recvpass", j);
L.AutoConnect = Conf->ReadInteger("link", "autoconnect", j, true);
L.HiddenFromStats = Conf->ReadFlag("link", "statshidden", j);
L.Timeout = Conf->ReadInteger("link", "timeout", j, true);
L.Hook = Conf->ReadValue("link", "transport", j);
L.Bind = Conf->ReadValue("link", "bind", j);
L.Hidden = Conf->ReadFlag("link", "hidden", j);
if ((!L.Hook.empty()) && (hooks.find(L.Hook.c_str()) == hooks.end()))
{
ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for link '%s' - maybe you forgot to load it BEFORE m_spanningtree in your config file? Skipping <link> tag completely.",
L.Hook.c_str(), L.Name.c_str());
continue;
}
L.NextConnectTime = time(NULL) + L.AutoConnect;
/* Bugfix by brain, do not allow people to enter bad configurations */
if (L.Name != ServerInstance->Config->ServerName)
{
if ((!L.IPAddr.empty()) && (!L.RecvPass.empty()) && (!L.SendPass.empty()) && (!L.Name.empty()) && (L.Port))
{
ValidIPs.push_back(L.IPAddr);
if (Allow.length())
ValidIPs.push_back(Allow);
/* Needs resolving */
bool ipvalid = true;
QueryType start_type = DNS_QUERY_A;
#ifdef IPV6
start_type = DNS_QUERY_AAAA;
if (strchr(L.IPAddr.c_str(),':'))
{
in6_addr n;
if (inet_pton(AF_INET6, L.IPAddr.c_str(), &n) < 1)
ipvalid = false;
}
else
{
in_addr n;
if (inet_aton(L.IPAddr.c_str(),&n) < 1)
ipvalid = false;
}
#else
in_addr n;
if (inet_aton(L.IPAddr.c_str(),&n) < 1)
ipvalid = false;
#endif
if (!ipvalid)
{
try
{
bool cached;
SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L.IPAddr, L, cached, start_type);
ServerInstance->AddResolver(sr, cached);
}
catch (...)
{
}
}
LinkBlocks.push_back(L);
}
else
{
if (L.IPAddr.empty())
{
ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', IP address not defined!",L.Name.c_str());
}
else if (L.RecvPass.empty())
{
ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', recvpass not defined!",L.Name.c_str());
}
else if (L.SendPass.empty())
{
ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', sendpass not defined!",L.Name.c_str());
}
else if (L.Name.empty())
{
ServerInstance->Log(DEFAULT,"Invalid configuration, link tag without a name!");
}
else if (!L.Port)
{
ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', no port specified!",L.Name.c_str());
}
}
}
else
{
ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', link tag has the same server name as the local server!",L.Name.c_str());
}
}
DELETE(Conf);
}
void SpanningTreeUtilities::DoFailOver(Link* x)
{
if (x->FailOver.length())
{
if (x->FailOver == x->Name)
{
ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Some muppet configured the failover for server \002%s\002 to point at itself. Not following it!", x->Name.c_str());
return;
}
Link* TryThisOne = this->FindLink(x->FailOver.c_str());
if (TryThisOne)
{
ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Name.c_str(), TryThisOne->Name.c_str());
Creator->ConnectServer(TryThisOne);
}
else
{
ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Name.c_str());
}
}
}
Link* SpanningTreeUtilities::FindLink(const std::string& name)
{
for (std::vector<Link>::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++)
{
if (ServerInstance->MatchText(x->Name.c_str(), name.c_str()))
{
return &(*x);
}
}
return NULL;
}
\ No newline at end of file diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h index cb783a81a..48146e89e 100644 --- a/src/modules/m_spanningtree/utils.h +++ b/src/modules/m_spanningtree/utils.h @@ -1,194 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __ST__UTIL__ -#define __ST__UTIL__ - -#include "configreader.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "inspircd.h" - -/* Foward declarations */ -class TreeServer; -class TreeSocket; -class Link; -class ModuleSpanningTree; - -/* This hash_map holds the hash equivalent of the server - * tree, used for rapid linear lookups. - */ -#ifdef WINDOWS -typedef nspace::hash_map<std::string, TreeServer*, nspace::hash_compare<string, less<string> > > server_hash; -#else -typedef nspace::hash_map<std::string, TreeServer*, nspace::hash<string>, irc::StrHashComp> server_hash; -#endif - -typedef std::map<TreeServer*,TreeServer*> TreeServerList; - -/** A group of modules that implement InspSocketHook - * that we can use to hook our server to server connections. - */ -typedef std::map<irc::string, Module*> hookmodules; - -/** Contains helper functions and variables for this module, - * and keeps them out of the global namespace - */ -class SpanningTreeUtilities -{ - private: - /** Creator server - */ - InspIRCd* ServerInstance; - public: - /** Creator module - */ - ModuleSpanningTree* Creator; - /** Remote servers that are currently bursting - */ - server_hash RemoteServersBursting; - /** Flatten links and /MAP for non-opers - */ - bool FlatLinks; - /** Hide U-Lined servers in /MAP and /LINKS - */ - bool HideULines; - /** Announce TS changes to channels on merge - */ - bool AnnounceTSChange; - /** Synchronize timestamps between servers - */ - bool EnableTimeSync; - /** Make snomasks +CQ quiet during bursts and splits - */ - bool quiet_bursts; - /** Socket bindings for listening sockets - */ - std::vector<TreeSocket*> Bindings; - /* Number of seconds that a server can go without ping - * before opers are warned of high latency. - */ - int PingWarnTime; - /** This variable represents the root of the server tree - */ - TreeServer *TreeRoot; - /** IPs allowed to link to us - */ - std::vector<std::string> ValidIPs; - /** Hash of currently connected servers by name - */ - server_hash serverlist; - /** Hash of servers currently bursting but not initialized as connected - */ - std::map<irc::string,TreeSocket*> burstingserverlist; - /** Holds the data from the <link> tags in the conf - */ - std::vector<Link> LinkBlocks; - /** Holds a bitmask of queued xline types waiting to be applied. - * Will be a mask containing values APPLY_GLINES, APPLY_KLINES, - * APPLY_QLINES and APPLY_ZLINES. - */ - int lines_to_apply; - - /** If this is true, this server is the master sync server for time - * synching - e.g. it is the server with its clock correct. It will - * send out the correct time at intervals. - */ - bool MasterTime; - - /** List of module pointers which can provide I/O abstraction - */ - hookmodules hooks; - - /** List of module names which can provide I/O abstraction - */ - std::vector<std::string> hooknames; - - /** True (default) if we are to use challenge-response HMAC - * to authenticate passwords. - * - * NOTE: This defaults to on, but should be turned off if - * you are linking to an older version of inspircd. - */ - bool ChallengeResponse; - - /** Initialise utility class - */ - SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* Creator); - /** Destroy class and free listeners etc - */ - ~SpanningTreeUtilities(); - /** Send a message from this server to one other local or remote - */ - bool DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string target); - /** Send a message from this server to all but one other, local or remote - */ - bool DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string omit); - /** Send a message from this server to all but one other, local or remote - */ - bool DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> ¶ms, std::string omit); - /** Send a message from this server to all others - */ - bool DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms); - /** Send a message from this server to all others - */ - bool DoOneToMany(const char* prefix, const char* command, std::deque<std::string> ¶ms); - /** Send a message from this server to all others, without doing any processing on the command (e.g. send it as-is with colons and all) - */ - bool DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> ¶ms); - /** Read the spanningtree module's tags from the config file - */ - void ReadConfiguration(bool rebind); - /** Add a server to the server list for GetListOfServersForChannel - */ - void AddThisServer(TreeServer* server, TreeServerList &list); - /** Compile a list of servers which contain members of channel c - */ - void GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list); - /** Find a server by name - */ - TreeServer* FindServer(const std::string &ServerName); - /** Find a remote bursting server by name - */ - TreeServer* FindRemoteBurstServer(TreeServer* Server); - /** Set a remote server to bursting or not bursting - */ - void SetRemoteBursting(TreeServer* Server, bool bursting); - /** Find a route to a server by name - */ - TreeServer* BestRouteTo(const std::string &ServerName); - /** Find a server by glob mask - */ - TreeServer* FindServerMask(const std::string &ServerName); - /** Returns true if this is a server name we recognise - */ - bool IsServer(const std::string &ServerName); - /** Attempt to connect to the failover link of link x - */ - void DoFailOver(Link* x); - /** Find a link tag from a server name - */ - Link* FindLink(const std::string& name); - /** Refresh the IP cache used for allowing inbound connections - */ - void RefreshIPCache(); - - TreeSocket* FindBurstingServer(const std::string &ServerName); - - void AddBurstingServer(const std::string &ServerName, TreeSocket* s); - - void DelBurstingServer(TreeSocket* s); -}; - -#endif +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __ST__UTIL__
#define __ST__UTIL__
#include "configreader.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "inspircd.h"
/* Foward declarations */
class TreeServer;
class TreeSocket;
class Link;
class ModuleSpanningTree;
/* This hash_map holds the hash equivalent of the server
* tree, used for rapid linear lookups.
*/
#ifdef WINDOWS
typedef nspace::hash_map<std::string, TreeServer*, nspace::hash_compare<string, less<string> > > server_hash;
#else
typedef nspace::hash_map<std::string, TreeServer*, nspace::hash<string>, irc::StrHashComp> server_hash;
#endif
typedef std::map<TreeServer*,TreeServer*> TreeServerList;
/** A group of modules that implement InspSocketHook
* that we can use to hook our server to server connections.
*/
typedef std::map<irc::string, Module*> hookmodules;
/** Contains helper functions and variables for this module,
* and keeps them out of the global namespace
*/
class SpanningTreeUtilities
{
private:
/** Creator server
*/
InspIRCd* ServerInstance;
public:
/** Creator module
*/
ModuleSpanningTree* Creator;
/** Remote servers that are currently bursting
*/
server_hash RemoteServersBursting;
/** Flatten links and /MAP for non-opers
*/
bool FlatLinks;
/** Hide U-Lined servers in /MAP and /LINKS
*/
bool HideULines;
/** Announce TS changes to channels on merge
*/
bool AnnounceTSChange;
/** Synchronize timestamps between servers
*/
bool EnableTimeSync;
/** Make snomasks +CQ quiet during bursts and splits
*/
bool quiet_bursts;
/** Socket bindings for listening sockets
*/
std::vector<TreeSocket*> Bindings;
/* Number of seconds that a server can go without ping
* before opers are warned of high latency.
*/
int PingWarnTime;
/** This variable represents the root of the server tree
*/
TreeServer *TreeRoot;
/** IPs allowed to link to us
*/
std::vector<std::string> ValidIPs;
/** Hash of currently connected servers by name
*/
server_hash serverlist;
/** Hash of servers currently bursting but not initialized as connected
*/
std::map<irc::string,TreeSocket*> burstingserverlist;
/** Holds the data from the <link> tags in the conf
*/
std::vector<Link> LinkBlocks;
/** Holds a bitmask of queued xline types waiting to be applied.
* Will be a mask containing values APPLY_GLINES, APPLY_KLINES,
* APPLY_QLINES and APPLY_ZLINES.
*/
int lines_to_apply;
/** If this is true, this server is the master sync server for time
* synching - e.g. it is the server with its clock correct. It will
* send out the correct time at intervals.
*/
bool MasterTime;
/** List of module pointers which can provide I/O abstraction
*/
hookmodules hooks;
/** List of module names which can provide I/O abstraction
*/
std::vector<std::string> hooknames;
/** True (default) if we are to use challenge-response HMAC
* to authenticate passwords.
*
* NOTE: This defaults to on, but should be turned off if
* you are linking to an older version of inspircd.
*/
bool ChallengeResponse;
/** Initialise utility class
*/
SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* Creator);
/** Destroy class and free listeners etc
*/
~SpanningTreeUtilities();
/** Send a message from this server to one other local or remote
*/
bool DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string target);
/** Send a message from this server to all but one other, local or remote
*/
bool DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms, std::string omit);
/** Send a message from this server to all but one other, local or remote
*/
bool DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> ¶ms, std::string omit);
/** Send a message from this server to all others
*/
bool DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> ¶ms);
/** Send a message from this server to all others
*/
bool DoOneToMany(const char* prefix, const char* command, std::deque<std::string> ¶ms);
/** Send a message from this server to all others, without doing any processing on the command (e.g. send it as-is with colons and all)
*/
bool DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> ¶ms);
/** Read the spanningtree module's tags from the config file
*/
void ReadConfiguration(bool rebind);
/** Add a server to the server list for GetListOfServersForChannel
*/
void AddThisServer(TreeServer* server, TreeServerList &list);
/** Compile a list of servers which contain members of channel c
*/
void GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list);
/** Find a server by name
*/
TreeServer* FindServer(const std::string &ServerName);
/** Find a remote bursting server by name
*/
TreeServer* FindRemoteBurstServer(TreeServer* Server);
/** Set a remote server to bursting or not bursting
*/
void SetRemoteBursting(TreeServer* Server, bool bursting);
/** Find a route to a server by name
*/
TreeServer* BestRouteTo(const std::string &ServerName);
/** Find a server by glob mask
*/
TreeServer* FindServerMask(const std::string &ServerName);
/** Returns true if this is a server name we recognise
*/
bool IsServer(const std::string &ServerName);
/** Attempt to connect to the failover link of link x
*/
void DoFailOver(Link* x);
/** Find a link tag from a server name
*/
Link* FindLink(const std::string& name);
/** Refresh the IP cache used for allowing inbound connections
*/
void RefreshIPCache();
TreeSocket* FindBurstingServer(const std::string &ServerName);
void AddBurstingServer(const std::string &ServerName, TreeSocket* s);
void DelBurstingServer(TreeSocket* s);
};
#endif
\ No newline at end of file diff --git a/src/modules/m_spy.cpp b/src/modules/m_spy.cpp index 20b59977c..11257c437 100644 --- a/src/modules/m_spy.cpp +++ b/src/modules/m_spy.cpp @@ -1,163 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* NO, THIS MODULE DOES NOT SPY ON CHANNELS OR USERS. - * IT JUST ALLOWS OPERS TO SEE +s CHANNELS IN LIST AND - * WHOIS, WHICH IS SUPPORTED BY MOST IRCDS IN CORE. - */ - -/* $ModDesc: Provides SPYLIST and SPYNAMES capability, allowing opers to see who's in +s channels */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "wildcard.h" - -void spy_userlist(userrec *user, chanrec *c) -{ - char list[MAXBUF]; - size_t dlen, curlen; - - dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name); - - int numusers = 0; - char* ptr = list + dlen; - - CUList *ulist= c->GetUsers(); - - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - { - size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", c->GetPrefixChar(i->first), i->first->nick); - - curlen += ptrlen; - ptr += ptrlen; - - numusers++; - - if (curlen > (480-NICKMAX)) - { - /* list overflowed into multiple numerics */ - user->WriteServ(std::string(list)); - - /* reset our lengths */ - dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name); - ptr = list + dlen; - - ptrlen = 0; - numusers = 0; - } - } - - /* if whats left in the list isnt empty, send it */ - if (numusers) - { - user->WriteServ(std::string(list)); - } - - user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, c->name); - -} - -/** Handle /SPYLIST - */ -class cmd_spylist : public command_t -{ - public: - cmd_spylist (InspIRCd* Instance) : command_t(Instance,"SPYLIST", 'o', 0) - { - this->source = "m_spy.so"; - syntax.clear(); - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - ServerInstance->WriteOpers("*** Oper %s used SPYLIST to list +s/+p channels and keys.",user->nick); - user->WriteServ("321 %s Channel :Users Name",user->nick); - for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) - { - if (pcnt && !match(i->second->name, parameters[0])) - continue; - user->WriteServ("322 %s %s %d :[+%s] %s",user->nick,i->second->name,i->second->GetUserCounter(),i->second->ChanModes(true),i->second->topic); - } - user->WriteServ("323 %s :End of channel list.",user->nick); - - /* Dont send out across the network */ - return CMD_FAILURE; - } -}; - -/** Handle /SPYNAMES - */ -class cmd_spynames : public command_t -{ - public: - cmd_spynames (InspIRCd* Instance) : command_t(Instance,"SPYNAMES", 'o', 0) - { - this->source = "m_spy.so"; - syntax = "{<channel>{,<channel>}}"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - chanrec* c = NULL; - - if (!pcnt) - { - user->WriteServ("366 %s * :End of /NAMES list.",user->nick); - return CMD_FAILURE; - } - - if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0)) - return CMD_FAILURE; - - c = ServerInstance->FindChan(parameters[0]); - if (c) - { - ServerInstance->WriteOpers("*** Oper %s used SPYNAMES to view the users on %s", user->nick, parameters[0]); - spy_userlist(user,c); - } - else - { - user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]); - } - - return CMD_FAILURE; - } -}; - -class ModuleSpy : public Module -{ - cmd_spylist *mycommand; - cmd_spynames *mycommand2; - public: - ModuleSpy(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_spylist(ServerInstance); - mycommand2 = new cmd_spynames(ServerInstance); - ServerInstance->AddCommand(mycommand); - ServerInstance->AddCommand(mycommand2); - } - - virtual ~ModuleSpy() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleSpy) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* NO, THIS MODULE DOES NOT SPY ON CHANNELS OR USERS.
* IT JUST ALLOWS OPERS TO SEE +s CHANNELS IN LIST AND
* WHOIS, WHICH IS SUPPORTED BY MOST IRCDS IN CORE.
*/
/* $ModDesc: Provides SPYLIST and SPYNAMES capability, allowing opers to see who's in +s channels */
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "wildcard.h"
void spy_userlist(userrec *user, chanrec *c)
{
char list[MAXBUF];
size_t dlen, curlen;
dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
int numusers = 0;
char* ptr = list + dlen;
CUList *ulist= c->GetUsers();
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", c->GetPrefixChar(i->first), i->first->nick);
curlen += ptrlen;
ptr += ptrlen;
numusers++;
if (curlen > (480-NICKMAX))
{
/* list overflowed into multiple numerics */
user->WriteServ(std::string(list));
/* reset our lengths */
dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
ptr = list + dlen;
ptrlen = 0;
numusers = 0;
}
}
/* if whats left in the list isnt empty, send it */
if (numusers)
{
user->WriteServ(std::string(list));
}
user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, c->name);
}
/** Handle /SPYLIST
*/
class cmd_spylist : public command_t
{
public:
cmd_spylist (InspIRCd* Instance) : command_t(Instance,"SPYLIST", 'o', 0)
{
this->source = "m_spy.so";
syntax.clear();
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
ServerInstance->WriteOpers("*** Oper %s used SPYLIST to list +s/+p channels and keys.",user->nick);
user->WriteServ("321 %s Channel :Users Name",user->nick);
for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
{
if (pcnt && !match(i->second->name, parameters[0]))
continue;
user->WriteServ("322 %s %s %d :[+%s] %s",user->nick,i->second->name,i->second->GetUserCounter(),i->second->ChanModes(true),i->second->topic);
}
user->WriteServ("323 %s :End of channel list.",user->nick);
/* Dont send out across the network */
return CMD_FAILURE;
}
};
/** Handle /SPYNAMES
*/
class cmd_spynames : public command_t
{
public:
cmd_spynames (InspIRCd* Instance) : command_t(Instance,"SPYNAMES", 'o', 0)
{
this->source = "m_spy.so";
syntax = "{<channel>{,<channel>}}";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
chanrec* c = NULL;
if (!pcnt)
{
user->WriteServ("366 %s * :End of /NAMES list.",user->nick);
return CMD_FAILURE;
}
if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
return CMD_FAILURE;
c = ServerInstance->FindChan(parameters[0]);
if (c)
{
ServerInstance->WriteOpers("*** Oper %s used SPYNAMES to view the users on %s", user->nick, parameters[0]);
spy_userlist(user,c);
}
else
{
user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
}
return CMD_FAILURE;
}
};
class ModuleSpy : public Module
{
cmd_spylist *mycommand;
cmd_spynames *mycommand2;
public:
ModuleSpy(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_spylist(ServerInstance);
mycommand2 = new cmd_spynames(ServerInstance);
ServerInstance->AddCommand(mycommand);
ServerInstance->AddCommand(mycommand2);
}
virtual ~ModuleSpy()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleSpy)
\ No newline at end of file diff --git a/src/modules/m_ssl_dummy.cpp b/src/modules/m_ssl_dummy.cpp index fb3032da2..3b872b81c 100644 --- a/src/modules/m_ssl_dummy.cpp +++ b/src/modules/m_ssl_dummy.cpp @@ -1,84 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "modules.h" - -/* $ModDesc: Makes remote /whoises to SSL servers work on a non-ssl server */ - -class ModuleSSLDummy : public Module -{ - - char* dummy; - public: - - ModuleSSLDummy(InspIRCd* Me) : Module(Me) - { - - } - - virtual ~ModuleSSLDummy() - { - } - - virtual Version GetVersion() - { - return Version(1, 0, 0, 0, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnWhois] = 1; - } - - // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection - virtual void OnWhois(userrec* source, userrec* dest) - { - if(dest->GetExt("ssl", dummy)) - { - ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick); - } - } - - virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable) - { - // check if the linking module wants to know about OUR metadata - if(extname == "ssl") - { - // check if this user has an ssl field to send - if(user->GetExt(extname, dummy)) - { - // call this function in the linking module, let it format the data how it - // sees fit, and send it on its way. We dont need or want to know how. - proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON"); - } - } - } - - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - // check if its our metadata key, and its associated with a user - if ((target_type == TYPE_USER) && (extname == "ssl")) - { - userrec* dest = (userrec*)target; - // if they dont already have an ssl flag, accept the remote server's - if (!dest->GetExt(extname, dummy)) - { - dest->Extend(extname, "ON"); - } - } - } -}; - -MODULE_INIT(ModuleSSLDummy) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "modules.h"
/* $ModDesc: Makes remote /whoises to SSL servers work on a non-ssl server */
class ModuleSSLDummy : public Module
{
char* dummy;
public:
ModuleSSLDummy(InspIRCd* Me) : Module(Me)
{
}
virtual ~ModuleSSLDummy()
{
}
virtual Version GetVersion()
{
return Version(1, 0, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnWhois] = 1;
}
// :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection
virtual void OnWhois(userrec* source, userrec* dest)
{
if(dest->GetExt("ssl", dummy))
{
ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
}
}
virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
{
// check if the linking module wants to know about OUR metadata
if(extname == "ssl")
{
// check if this user has an ssl field to send
if(user->GetExt(extname, dummy))
{
// call this function in the linking module, let it format the data how it
// sees fit, and send it on its way. We dont need or want to know how.
proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");
}
}
}
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
// check if its our metadata key, and its associated with a user
if ((target_type == TYPE_USER) && (extname == "ssl"))
{
userrec* dest = (userrec*)target;
// if they dont already have an ssl flag, accept the remote server's
if (!dest->GetExt(extname, dummy))
{
dest->Extend(extname, "ON");
}
}
}
};
MODULE_INIT(ModuleSSLDummy)
\ No newline at end of file diff --git a/src/modules/m_sslmodes.cpp b/src/modules/m_sslmodes.cpp index c8eee5a03..0e06aa314 100644 --- a/src/modules/m_sslmodes.cpp +++ b/src/modules/m_sslmodes.cpp @@ -1,145 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for unreal-style channel mode +z */ - -static char* dummy; - -/** Handle channel mode +z - */ -class SSLMode : public ModeHandler -{ - public: - SSLMode(InspIRCd* Instance) : ModeHandler(Instance, 'z', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('z')) - { - if (IS_LOCAL(source)) - { - CUList* userlist = channel->GetUsers(); - for(CUList::iterator i = userlist->begin(); i != userlist->end(); i++) - { - if(!i->first->GetExt("ssl", dummy)) - { - source->WriteServ("490 %s %s :all members of the channel must be connected via SSL", source->nick, channel->name); - return MODEACTION_DENY; - } - } - } - channel->SetMode('z',true); - return MODEACTION_ALLOW; - } - else - { - return MODEACTION_DENY; - } - } - else - { - if (channel->IsModeSet('z')) - { - channel->SetMode('z',false); - return MODEACTION_ALLOW; - } - - return MODEACTION_DENY; - } - } -}; - -class ModuleSSLModes : public Module -{ - - SSLMode* sslm; - - public: - ModuleSSLModes(InspIRCd* Me) - : Module(Me) - { - - - sslm = new SSLMode(ServerInstance); - if (!ServerInstance->AddMode(sslm, 'z')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreJoin] = 1; - } - - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - if(chan && chan->IsModeSet('z')) - { - if(user->GetExt("ssl", dummy)) - { - // Let them in - return 0; - } - else - { - // Deny - user->WriteServ( "489 %s %s :Cannot join channel; SSL users only (+z)", user->nick, cname); - return 1; - } - } - - return 0; - } - - virtual ~ModuleSSLModes() - { - ServerInstance->Modes->DelMode(sslm); - DELETE(sslm); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } -}; - - -class ModuleSSLModesFactory : public ModuleFactory -{ - public: - ModuleSSLModesFactory() - { - } - - ~ModuleSSLModesFactory() - { - } - - virtual Module* CreateModule(InspIRCd* Me) - { - return new ModuleSSLModes(Me); - } - -}; - - -extern "C" DllExport void * init_module( void ) -{ - return new ModuleSSLModesFactory; -} +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for unreal-style channel mode +z */
static char* dummy;
/** Handle channel mode +z
*/
class SSLMode : public ModeHandler
{
public:
SSLMode(InspIRCd* Instance) : ModeHandler(Instance, 'z', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('z'))
{
if (IS_LOCAL(source))
{
CUList* userlist = channel->GetUsers();
for(CUList::iterator i = userlist->begin(); i != userlist->end(); i++)
{
if(!i->first->GetExt("ssl", dummy))
{
source->WriteServ("490 %s %s :all members of the channel must be connected via SSL", source->nick, channel->name);
return MODEACTION_DENY;
}
}
}
channel->SetMode('z',true);
return MODEACTION_ALLOW;
}
else
{
return MODEACTION_DENY;
}
}
else
{
if (channel->IsModeSet('z'))
{
channel->SetMode('z',false);
return MODEACTION_ALLOW;
}
return MODEACTION_DENY;
}
}
};
class ModuleSSLModes : public Module
{
SSLMode* sslm;
public:
ModuleSSLModes(InspIRCd* Me)
: Module(Me)
{
sslm = new SSLMode(ServerInstance);
if (!ServerInstance->AddMode(sslm, 'z'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreJoin] = 1;
}
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
{
if(chan && chan->IsModeSet('z'))
{
if(user->GetExt("ssl", dummy))
{
// Let them in
return 0;
}
else
{
// Deny
user->WriteServ( "489 %s %s :Cannot join channel; SSL users only (+z)", user->nick, cname);
return 1;
}
}
return 0;
}
virtual ~ModuleSSLModes()
{
ServerInstance->Modes->DelMode(sslm);
DELETE(sslm);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
};
class ModuleSSLModesFactory : public ModuleFactory
{
public:
ModuleSSLModesFactory()
{
}
~ModuleSSLModesFactory()
{
}
virtual Module* CreateModule(InspIRCd* Me)
{
return new ModuleSSLModes(Me);
}
};
extern "C" DllExport void * init_module( void )
{
return new ModuleSSLModesFactory;
}
\ No newline at end of file diff --git a/src/modules/m_stripcolor.cpp b/src/modules/m_stripcolor.cpp index aad253bc7..6f1d7b130 100644 --- a/src/modules/m_stripcolor.cpp +++ b/src/modules/m_stripcolor.cpp @@ -1,185 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides channel +S mode (strip ansi colour) */ - -/** Handles channel mode +S - */ -class ChannelStripColor : public ModeHandler -{ - public: - ChannelStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_CHANNEL, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('S')) - { - channel->SetMode('S',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('S')) - { - channel->SetMode('S',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - -/** Handles user mode +S - */ -class UserStripColor : public ModeHandler -{ - public: - UserStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_USER, false) { } - - ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) - { - /* Only opers can change other users modes */ - if (source != dest) - return MODEACTION_DENY; - - if (adding) - { - if (!dest->IsModeSet('S')) - { - dest->SetMode('S',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('S')) - { - dest->SetMode('S',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - - -class ModuleStripColor : public Module -{ - bool AllowChanOps; - ChannelStripColor *csc; - UserStripColor *usc; - - public: - ModuleStripColor(InspIRCd* Me) : Module(Me) - { - usc = new UserStripColor(ServerInstance); - csc = new ChannelStripColor(ServerInstance); - - if (!ServerInstance->AddMode(usc, 'S') || !ServerInstance->AddMode(csc, 'S')) - throw ModuleException("Could not add new modes!"); - } - - void Implements(char* List) - { - List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1; - } - - virtual ~ModuleStripColor() - { - ServerInstance->Modes->DelMode(usc); - ServerInstance->Modes->DelMode(csc); - DELETE(usc); - DELETE(csc); - } - - virtual void ReplaceLine(std::string &sentence) - { - /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */ - int seq = 0; - std::string::iterator i,safei; - for (i = sentence.begin(); i != sentence.end(); ++i) - { - if ((*i == 3)) - seq = 1; - else if (seq && ( (*i >= '0') && (*i <= '9') || (*i == ',') ) ) - { - seq++; - if ( (seq <= 4) && (*i == ',') ) - seq = 1; - else if (seq > 3) - seq = 0; - } - else - seq = 0; - - if (seq || ((*i == 2) || (*i == 15) || (*i == 22) || (*i == 21) || (*i == 31))) - { - safei = i; - --i; - sentence.erase(safei); - } - } - } - - virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if (!IS_LOCAL(user)) - return 0; - - bool active = false; - if (target_type == TYPE_USER) - { - userrec* t = (userrec*)dest; - active = t->IsModeSet('S'); - } - else if (target_type == TYPE_CHANNEL) - { - chanrec* t = (chanrec*)dest; - - // check if we allow ops to bypass filtering, if we do, check if they're opped accordingly. - // note: short circut logic here, don't wreck it. -- w00t - if (!CHANOPS_EXEMPT(ServerInstance, 'S') || CHANOPS_EXEMPT(ServerInstance, 'S') && t->GetStatus(user) != STATUS_OP) - active = t->IsModeSet('S'); - } - - if (active) - { - this->ReplaceLine(text); - } - - return 0; - } - - virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); - } - -}; - -MODULE_INIT(ModuleStripColor) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides channel +S mode (strip ansi colour) */
/** Handles channel mode +S
*/
class ChannelStripColor : public ModeHandler
{
public:
ChannelStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_CHANNEL, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
if (adding)
{
if (!channel->IsModeSet('S'))
{
channel->SetMode('S',true);
return MODEACTION_ALLOW;
}
}
else
{
if (channel->IsModeSet('S'))
{
channel->SetMode('S',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
/** Handles user mode +S
*/
class UserStripColor : public ModeHandler
{
public:
UserStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_USER, false) { }
ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
{
/* Only opers can change other users modes */
if (source != dest)
return MODEACTION_DENY;
if (adding)
{
if (!dest->IsModeSet('S'))
{
dest->SetMode('S',true);
return MODEACTION_ALLOW;
}
}
else
{
if (dest->IsModeSet('S'))
{
dest->SetMode('S',false);
return MODEACTION_ALLOW;
}
}
return MODEACTION_DENY;
}
};
class ModuleStripColor : public Module
{
bool AllowChanOps;
ChannelStripColor *csc;
UserStripColor *usc;
public:
ModuleStripColor(InspIRCd* Me) : Module(Me)
{
usc = new UserStripColor(ServerInstance);
csc = new ChannelStripColor(ServerInstance);
if (!ServerInstance->AddMode(usc, 'S') || !ServerInstance->AddMode(csc, 'S'))
throw ModuleException("Could not add new modes!");
}
void Implements(char* List)
{
List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
}
virtual ~ModuleStripColor()
{
ServerInstance->Modes->DelMode(usc);
ServerInstance->Modes->DelMode(csc);
DELETE(usc);
DELETE(csc);
}
virtual void ReplaceLine(std::string &sentence)
{
/* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */
int seq = 0;
std::string::iterator i,safei;
for (i = sentence.begin(); i != sentence.end(); ++i)
{
if ((*i == 3))
seq = 1;
else if (seq && ( (*i >= '0') && (*i <= '9') || (*i == ',') ) )
{
seq++;
if ( (seq <= 4) && (*i == ',') )
seq = 1;
else if (seq > 3)
seq = 0;
}
else
seq = 0;
if (seq || ((*i == 2) || (*i == 15) || (*i == 22) || (*i == 21) || (*i == 31)))
{
safei = i;
--i;
sentence.erase(safei);
}
}
}
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (!IS_LOCAL(user))
return 0;
bool active = false;
if (target_type == TYPE_USER)
{
userrec* t = (userrec*)dest;
active = t->IsModeSet('S');
}
else if (target_type == TYPE_CHANNEL)
{
chanrec* t = (chanrec*)dest;
// check if we allow ops to bypass filtering, if we do, check if they're opped accordingly.
// note: short circut logic here, don't wreck it. -- w00t
if (!CHANOPS_EXEMPT(ServerInstance, 'S') || CHANOPS_EXEMPT(ServerInstance, 'S') && t->GetStatus(user) != STATUS_OP)
active = t->IsModeSet('S');
}
if (active)
{
this->ReplaceLine(text);
}
return 0;
}
virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleStripColor)
\ No newline at end of file diff --git a/src/modules/m_svshold.cpp b/src/modules/m_svshold.cpp index 4058c04d0..f220d1638 100644 --- a/src/modules/m_svshold.cpp +++ b/src/modules/m_svshold.cpp @@ -1,282 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include <algorithm> -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" - -/* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */ - -/** Holds a SVSHold item - */ -class SVSHold : public classbase -{ -public: - std::string nickname; - std::string set_by; - time_t set_on; - long length; - std::string reason; - - SVSHold() - { - } - - SVSHold(const std::string &nn, const std::string &sb, const time_t so, const long ln, const std::string &rs) : nickname(nn), set_by(sb), set_on(so), length(ln), reason(rs) - { - } -}; - - -bool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2); - -typedef std::vector<SVSHold*> SVSHoldlist; -typedef std::map<irc::string, SVSHold*> SVSHoldMap; - -/* SVSHolds is declared here, as our type is right above. Don't try move it. */ -SVSHoldlist SVSHolds; -SVSHoldMap HoldMap; - -/** Handle /SVSHold - */ -class cmd_svshold : public command_t -{ - public: - cmd_svshold(InspIRCd* Me) : command_t(Me, "SVSHOLD", 'o', 1) - { - this->source = "m_svshold.so"; - this->syntax = "<nickname> [<duration> :<reason>]"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec *user) - { - /* syntax: svshold nickname time :reason goes here */ - /* 'time' is a human-readable timestring, like 2d3h2s. */ - - if (!ServerInstance->ULine(user->server)) - { - /* don't allow SVSHOLD from non-ulined clients */ - return CMD_FAILURE; - } - - if (pcnt == 1) - { - SVSHoldMap::iterator n = HoldMap.find(parameters[0]); - if (n != HoldMap.end()) - { - /* form: svshold nickname removes a hold. */ - for (SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++) - { - if (parameters[0] == assign((*iter)->nickname)) - { - unsigned long remaining = 0; - if ((*iter)->length) - { - remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time(); - user->WriteServ( "386 %s %s :Removed SVSHOLD with %lu seconds left before expiry (%s)", user->nick, (*iter)->nickname.c_str(), remaining, (*iter)->reason.c_str()); - } - else - { - user->WriteServ( "386 %s %s :Removed permanent SVSHOLD (%s)", user->nick, (*iter)->nickname.c_str(), (*iter)->reason.c_str()); - } - SVSHolds.erase(iter); - break; - } - } - - HoldMap.erase(n); - delete n->second; - } - } - else if (pcnt >= 2) - { - /* full form to add a SVSHold */ - if (ServerInstance->IsNick(parameters[0])) - { - // parameters[0] = w00t - // parameters[1] = 1h3m2s - // parameters[2] = Registered nickname - - /* Already exists? */ - if (HoldMap.find(parameters[0]) != HoldMap.end()) - { - user->WriteServ( "385 %s %s :SVSHOLD already exists", user->nick, parameters[0]); - return CMD_FAILURE; - } - - long length = ServerInstance->Duration(parameters[1]); - std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied"; - - SVSHold* S = new SVSHold(parameters[0], user->nick, ServerInstance->Time(), length, reason); - SVSHolds.push_back(S); - HoldMap[parameters[0]] = S; - - std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp); - - if(length > 0) - { - user->WriteServ( "385 %s %s :Added %lu second SVSHOLD (%s)", user->nick, parameters[0], length, reason.c_str()); - ServerInstance->WriteOpers("*** %s added %lu second SVSHOLD on %s (%s)", user->nick, length, parameters[0], reason.c_str()); - } - else - { - user->WriteServ( "385 %s %s :Added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], parameters[0], reason.c_str()); - ServerInstance->WriteOpers("*** %s added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], reason.c_str()); - } - } - else - { - /* as this is primarily a Services command, do not provide an error */ - return CMD_FAILURE; - } - } - - return CMD_SUCCESS; - } -}; - -bool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2) -{ - return ((ban1->set_on + ban1->length) < (ban2->set_on + ban2->length)); -} - -class ModuleSVSHold : public Module -{ - cmd_svshold *mycommand; - - - public: - ModuleSVSHold(InspIRCd* Me) : Module(Me) - { - mycommand = new cmd_svshold(Me); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - List[I_OnUserPreNick] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1; - } - - virtual int OnStats(char symbol, userrec* user, string_list &results) - { - ExpireBans(); - - if(symbol == 'S') - { - for(SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++) - { - unsigned long remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time(); - results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+(*iter)->nickname.c_str()+" "+(*iter)->set_by+" "+ConvToStr((*iter)->set_on)+" "+ConvToStr((*iter)->length)+" "+ConvToStr(remaining)+" :"+(*iter)->reason); - } - } - - return 0; - } - - virtual int OnUserPreNick(userrec *user, const std::string &newnick) - { - ExpireBans(); - - /* check SVSHolds in here, and apply as necessary. */ - SVSHoldMap::iterator n = HoldMap.find(assign(newnick)); - if (n != HoldMap.end()) - { - user->WriteServ( "432 %s %s :Reserved nickname: %s", user->nick, newnick.c_str(), n->second->reason.c_str()); - return 1; - } - return 0; - } - - virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable) - { - for(SVSHoldMap::iterator iter = HoldMap.begin(); iter != HoldMap.end(); iter++) - { - proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "SVSHold", EncodeSVSHold(iter->second)); - } - } - - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - if((target_type == TYPE_OTHER) && (extname == "SVSHold")) - { - SVSHold* S = DecodeSVSHold(extdata); /* NOTE: Allocates a new SVSHold* */ - if (HoldMap.find(assign(S->nickname)) == HoldMap.end()) - { - SVSHolds.push_back(S); - HoldMap[assign(S->nickname)] = S; - std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp); - } - else - { - delete S; - } - } - } - - virtual ~ModuleSVSHold() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR|VF_COMMON,API_VERSION); - } - - std::string EncodeSVSHold(const SVSHold* ban) - { - std::ostringstream stream; - stream << ban->nickname << " " << ban->set_by << " " << ban->set_on << " " << ban->length << " :" << ban->reason; - return stream.str(); - } - - SVSHold* DecodeSVSHold(const std::string &data) - { - SVSHold* res = new SVSHold(); - int set_on; - irc::tokenstream tokens(data); - tokens.GetToken(res->nickname); - tokens.GetToken(res->set_by); - tokens.GetToken(set_on); - res->set_on = set_on; - tokens.GetToken(res->length); - tokens.GetToken(res->reason); - return res; - } - - void ExpireBans() - { - SVSHoldlist::iterator iter,safeiter; - for (iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++) - { - /* 0 == permanent, don't mess with them! -- w00t */ - if ((*iter)->length != 0) - { - if ((*iter)->set_on + (*iter)->length <= ServerInstance->Time()) - { - ServerInstance->Log(DEBUG, "m_svshold.so: hold on %s expired, removing...", (*iter)->nickname.c_str()); - ServerInstance->WriteOpers("*** %li second SVSHOLD on %s (%s) set %u seconds ago expired", (*iter)->length, (*iter)->nickname.c_str(), (*iter)->reason.c_str(), ServerInstance->Time() - (*iter)->set_on); - HoldMap.erase(assign((*iter)->nickname)); - delete *iter; - safeiter = iter; - --iter; - SVSHolds.erase(safeiter); - } - } - } - } -}; - -MODULE_INIT(ModuleSVSHold) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include <algorithm>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
/* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */
/** Holds a SVSHold item
*/
class SVSHold : public classbase
{
public:
std::string nickname;
std::string set_by;
time_t set_on;
long length;
std::string reason;
SVSHold()
{
}
SVSHold(const std::string &nn, const std::string &sb, const time_t so, const long ln, const std::string &rs) : nickname(nn), set_by(sb), set_on(so), length(ln), reason(rs)
{
}
};
bool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2);
typedef std::vector<SVSHold*> SVSHoldlist;
typedef std::map<irc::string, SVSHold*> SVSHoldMap;
/* SVSHolds is declared here, as our type is right above. Don't try move it. */
SVSHoldlist SVSHolds;
SVSHoldMap HoldMap;
/** Handle /SVSHold
*/
class cmd_svshold : public command_t
{
public:
cmd_svshold(InspIRCd* Me) : command_t(Me, "SVSHOLD", 'o', 1)
{
this->source = "m_svshold.so";
this->syntax = "<nickname> [<duration> :<reason>]";
}
CmdResult Handle(const char** parameters, int pcnt, userrec *user)
{
/* syntax: svshold nickname time :reason goes here */
/* 'time' is a human-readable timestring, like 2d3h2s. */
if (!ServerInstance->ULine(user->server))
{
/* don't allow SVSHOLD from non-ulined clients */
return CMD_FAILURE;
}
if (pcnt == 1)
{
SVSHoldMap::iterator n = HoldMap.find(parameters[0]);
if (n != HoldMap.end())
{
/* form: svshold nickname removes a hold. */
for (SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
{
if (parameters[0] == assign((*iter)->nickname))
{
unsigned long remaining = 0;
if ((*iter)->length)
{
remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time();
user->WriteServ( "386 %s %s :Removed SVSHOLD with %lu seconds left before expiry (%s)", user->nick, (*iter)->nickname.c_str(), remaining, (*iter)->reason.c_str());
}
else
{
user->WriteServ( "386 %s %s :Removed permanent SVSHOLD (%s)", user->nick, (*iter)->nickname.c_str(), (*iter)->reason.c_str());
}
SVSHolds.erase(iter);
break;
}
}
HoldMap.erase(n);
delete n->second;
}
}
else if (pcnt >= 2)
{
/* full form to add a SVSHold */
if (ServerInstance->IsNick(parameters[0]))
{
// parameters[0] = w00t
// parameters[1] = 1h3m2s
// parameters[2] = Registered nickname
/* Already exists? */
if (HoldMap.find(parameters[0]) != HoldMap.end())
{
user->WriteServ( "385 %s %s :SVSHOLD already exists", user->nick, parameters[0]);
return CMD_FAILURE;
}
long length = ServerInstance->Duration(parameters[1]);
std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";
SVSHold* S = new SVSHold(parameters[0], user->nick, ServerInstance->Time(), length, reason);
SVSHolds.push_back(S);
HoldMap[parameters[0]] = S;
std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);
if(length > 0)
{
user->WriteServ( "385 %s %s :Added %lu second SVSHOLD (%s)", user->nick, parameters[0], length, reason.c_str());
ServerInstance->WriteOpers("*** %s added %lu second SVSHOLD on %s (%s)", user->nick, length, parameters[0], reason.c_str());
}
else
{
user->WriteServ( "385 %s %s :Added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], parameters[0], reason.c_str());
ServerInstance->WriteOpers("*** %s added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], reason.c_str());
}
}
else
{
/* as this is primarily a Services command, do not provide an error */
return CMD_FAILURE;
}
}
return CMD_SUCCESS;
}
};
bool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2)
{
return ((ban1->set_on + ban1->length) < (ban2->set_on + ban2->length));
}
class ModuleSVSHold : public Module
{
cmd_svshold *mycommand;
public:
ModuleSVSHold(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_svshold(Me);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
List[I_OnUserPreNick] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;
}
virtual int OnStats(char symbol, userrec* user, string_list &results)
{
ExpireBans();
if(symbol == 'S')
{
for(SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
{
unsigned long remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time();
results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+(*iter)->nickname.c_str()+" "+(*iter)->set_by+" "+ConvToStr((*iter)->set_on)+" "+ConvToStr((*iter)->length)+" "+ConvToStr(remaining)+" :"+(*iter)->reason);
}
}
return 0;
}
virtual int OnUserPreNick(userrec *user, const std::string &newnick)
{
ExpireBans();
/* check SVSHolds in here, and apply as necessary. */
SVSHoldMap::iterator n = HoldMap.find(assign(newnick));
if (n != HoldMap.end())
{
user->WriteServ( "432 %s %s :Reserved nickname: %s", user->nick, newnick.c_str(), n->second->reason.c_str());
return 1;
}
return 0;
}
virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
{
for(SVSHoldMap::iterator iter = HoldMap.begin(); iter != HoldMap.end(); iter++)
{
proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "SVSHold", EncodeSVSHold(iter->second));
}
}
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
if((target_type == TYPE_OTHER) && (extname == "SVSHold"))
{
SVSHold* S = DecodeSVSHold(extdata); /* NOTE: Allocates a new SVSHold* */
if (HoldMap.find(assign(S->nickname)) == HoldMap.end())
{
SVSHolds.push_back(S);
HoldMap[assign(S->nickname)] = S;
std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);
}
else
{
delete S;
}
}
}
virtual ~ModuleSVSHold()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR|VF_COMMON,API_VERSION);
}
std::string EncodeSVSHold(const SVSHold* ban)
{
std::ostringstream stream;
stream << ban->nickname << " " << ban->set_by << " " << ban->set_on << " " << ban->length << " :" << ban->reason;
return stream.str();
}
SVSHold* DecodeSVSHold(const std::string &data)
{
SVSHold* res = new SVSHold();
int set_on;
irc::tokenstream tokens(data);
tokens.GetToken(res->nickname);
tokens.GetToken(res->set_by);
tokens.GetToken(set_on);
res->set_on = set_on;
tokens.GetToken(res->length);
tokens.GetToken(res->reason);
return res;
}
void ExpireBans()
{
SVSHoldlist::iterator iter,safeiter;
for (iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
{
/* 0 == permanent, don't mess with them! -- w00t */
if ((*iter)->length != 0)
{
if ((*iter)->set_on + (*iter)->length <= ServerInstance->Time())
{
ServerInstance->Log(DEBUG, "m_svshold.so: hold on %s expired, removing...", (*iter)->nickname.c_str());
ServerInstance->WriteOpers("*** %li second SVSHOLD on %s (%s) set %u seconds ago expired", (*iter)->length, (*iter)->nickname.c_str(), (*iter)->reason.c_str(), ServerInstance->Time() - (*iter)->set_on);
HoldMap.erase(assign((*iter)->nickname));
delete *iter;
safeiter = iter;
--iter;
SVSHolds.erase(safeiter);
}
}
}
}
};
MODULE_INIT(ModuleSVSHold)
\ No newline at end of file diff --git a/src/modules/m_swhois.cpp b/src/modules/m_swhois.cpp index d635654a5..5df5fe4eb 100644 --- a/src/modules/m_swhois.cpp +++ b/src/modules/m_swhois.cpp @@ -1,267 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides the SWHOIS command which allows setting of arbitary WHOIS lines */ - -/** Handle /SWHOIS - */ -class cmd_swhois : public command_t -{ - - public: - cmd_swhois (InspIRCd* Instance) : command_t(Instance,"SWHOIS",'o',2) - { - this->source = "m_swhois.so"; - syntax = "<nick> <swhois>"; - } - - CmdResult Handle(const char** parameters, int pcnt, userrec* user) - { - userrec* dest = ServerInstance->FindNick(parameters[0]); - - if (!dest) - { - user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]); - return CMD_FAILURE; - } - - if (!*parameters[1]) - { - user->WriteServ("NOTICE %s :*** SWHOIS: Whois line must be specified", user->nick); - return CMD_FAILURE; - } - - std::string line; - for (int i = 1; i < pcnt; i++) - { - if (i != 1) - line.append(" "); - - line.append(parameters[i]); - } - - std::string* text; - dest->GetExt("swhois", text); - - if (text) - { - // We already had it set... - - if (!ServerInstance->ULine(user->server)) - // Ulines set SWHOISes silently - ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois from '%s' to '%s'", user->nick, dest->nick, text->c_str(), line.c_str()); - - dest->Shrink("swhois"); - DELETE(text); - } - else if (!ServerInstance->ULine(user->server)) - { - // Ulines set SWHOISes silently - ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois to '%s'", user->nick, dest->nick, line.c_str()); - } - - text = new std::string(line); - dest->Extend("swhois", text); - - return CMD_SUCCESS; - } - -}; - -class ModuleSWhois : public Module -{ - cmd_swhois* mycommand; - - ConfigReader* Conf; - - public: - ModuleSWhois(InspIRCd* Me) : Module(Me) - { - - Conf = new ConfigReader(ServerInstance); - mycommand = new cmd_swhois(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - void OnRehash(userrec* user, const std::string ¶meter) - { - DELETE(Conf); - Conf = new ConfigReader(ServerInstance); - } - - void Implements(char* List) - { - List[I_OnDecodeMetaData] = List[I_OnWhoisLine] = List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnRehash] = List[I_OnPostCommand] = 1; - } - - // :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games. - int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text) - { - /* We use this and not OnWhois because this triggers for remote, too */ - if (numeric == 312) - { - /* Insert our numeric before 312 */ - std::string* swhois; - dest->GetExt("swhois", swhois); - if (swhois) - { - ServerInstance->SendWhoisLine(user, dest, 320, "%s %s :%s",user->nick,dest->nick,swhois->c_str()); - } - } - /* Dont block anything */ - return 0; - } - - // Whenever the linking module wants to send out data, but doesnt know what the data - // represents (e.g. it is metadata, added to a userrec or chanrec by a module) then - // this method is called. We should use the ProtoSendMetaData function after we've - // corrected decided how the data should look, to send the metadata on its way if - // it is ours. - virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable) - { - // check if the linking module wants to know about OUR metadata - if (extname == "swhois") - { - // check if this user has an swhois field to send - std::string* swhois; - user->GetExt("swhois", swhois); - if (swhois) - { - // call this function in the linking module, let it format the data how it - // sees fit, and send it on its way. We dont need or want to know how. - proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*swhois); - } - } - } - - // when a user quits, tidy up their metadata - virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message) - { - std::string* swhois; - user->GetExt("swhois", swhois); - if (swhois) - { - user->Shrink("swhois"); - DELETE(swhois); - } - } - - // if the module is unloaded, tidy up all our dangling metadata - virtual void OnCleanup(int target_type, void* item) - { - if (target_type == TYPE_USER) - { - userrec* user = (userrec*)item; - std::string* swhois; - user->GetExt("swhois", swhois); - if (swhois) - { - user->Shrink("swhois"); - DELETE(swhois); - } - } - } - - // Whenever the linking module receives metadata from another server and doesnt know what - // to do with it (of course, hence the 'meta') it calls this method, and it is up to each - // module in turn to figure out if this metadata key belongs to them, and what they want - // to do with it. - // In our case we're only sending a single string around, so we just construct a std::string. - // Some modules will probably get much more complex and format more detailed structs and classes - // in a textual way for sending over the link. - virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) - { - // check if its our metadata key, and its associated with a user - if ((target_type == TYPE_USER) && (extname == "swhois")) - { - userrec* dest = (userrec*)target; - // if they dont already have an swhois field, accept the remote server's - std::string* text; - if (!dest->GetExt("swhois", text)) - { - std::string* text = new std::string(extdata); - dest->Extend("swhois",text); - } - } - } - - virtual void OnPostCommand(const std::string &command, const char **params, int pcnt, userrec *user, CmdResult result, const std::string &original_line) - { - if ((command != "OPER") || (result != CMD_SUCCESS)) - return; - - std::string swhois; - - for (int i = 0; i < Conf->Enumerate("oper"); i++) - { - std::string name = Conf->ReadValue("oper", "name", i); - - if (name == params[0]) - { - swhois = Conf->ReadValue("oper", "swhois", i); - break; - } - } - - if (!swhois.length()) - { - for (int i = 0; i < Conf->Enumerate("type"); i++) - { - std::string type = Conf->ReadValue("type", "name", i); - - if (type == user->oper) - { - swhois = Conf->ReadValue("type", "swhois", i); - break; - } - } - } - - std::string *old; - if (user->GetExt("swhois", old)) - { - user->Shrink("swhois"); - DELETE(old); - } - - if (!swhois.length()) - return; - - std::string *text = new std::string(swhois); - user->Extend("swhois", text); - std::deque<std::string>* metadata = new std::deque<std::string>; - metadata->push_back(user->nick); - metadata->push_back("swhois"); // The metadata id - metadata->push_back(*text); // The value to send - Event event((char*)metadata,(Module*)this,"send_metadata"); - event.Send(ServerInstance); - delete metadata; - } - - virtual ~ModuleSWhois() - { - DELETE(Conf); - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleSWhois) +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides the SWHOIS command which allows setting of arbitary WHOIS lines */
/** Handle /SWHOIS
*/
class cmd_swhois : public command_t
{
public:
cmd_swhois (InspIRCd* Instance) : command_t(Instance,"SWHOIS",'o',2)
{
this->source = "m_swhois.so";
syntax = "<nick> <swhois>";
}
CmdResult Handle(const char** parameters, int pcnt, userrec* user)
{
userrec* dest = ServerInstance->FindNick(parameters[0]);
if (!dest)
{
user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
return CMD_FAILURE;
}
if (!*parameters[1])
{
user->WriteServ("NOTICE %s :*** SWHOIS: Whois line must be specified", user->nick);
return CMD_FAILURE;
}
std::string line;
for (int i = 1; i < pcnt; i++)
{
if (i != 1)
line.append(" ");
line.append(parameters[i]);
}
std::string* text;
dest->GetExt("swhois", text);
if (text)
{
// We already had it set...
if (!ServerInstance->ULine(user->server))
// Ulines set SWHOISes silently
ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois from '%s' to '%s'", user->nick, dest->nick, text->c_str(), line.c_str());
dest->Shrink("swhois");
DELETE(text);
}
else if (!ServerInstance->ULine(user->server))
{
// Ulines set SWHOISes silently
ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois to '%s'", user->nick, dest->nick, line.c_str());
}
text = new std::string(line);
dest->Extend("swhois", text);
return CMD_SUCCESS;
}
};
class ModuleSWhois : public Module
{
cmd_swhois* mycommand;
ConfigReader* Conf;
public:
ModuleSWhois(InspIRCd* Me) : Module(Me)
{
Conf = new ConfigReader(ServerInstance);
mycommand = new cmd_swhois(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
void OnRehash(userrec* user, const std::string ¶meter)
{
DELETE(Conf);
Conf = new ConfigReader(ServerInstance);
}
void Implements(char* List)
{
List[I_OnDecodeMetaData] = List[I_OnWhoisLine] = List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnRehash] = List[I_OnPostCommand] = 1;
}
// :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games.
int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)
{
/* We use this and not OnWhois because this triggers for remote, too */
if (numeric == 312)
{
/* Insert our numeric before 312 */
std::string* swhois;
dest->GetExt("swhois", swhois);
if (swhois)
{
ServerInstance->SendWhoisLine(user, dest, 320, "%s %s :%s",user->nick,dest->nick,swhois->c_str());
}
}
/* Dont block anything */
return 0;
}
// Whenever the linking module wants to send out data, but doesnt know what the data
// represents (e.g. it is metadata, added to a userrec or chanrec by a module) then
// this method is called. We should use the ProtoSendMetaData function after we've
// corrected decided how the data should look, to send the metadata on its way if
// it is ours.
virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
{
// check if the linking module wants to know about OUR metadata
if (extname == "swhois")
{
// check if this user has an swhois field to send
std::string* swhois;
user->GetExt("swhois", swhois);
if (swhois)
{
// call this function in the linking module, let it format the data how it
// sees fit, and send it on its way. We dont need or want to know how.
proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*swhois);
}
}
}
// when a user quits, tidy up their metadata
virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
{
std::string* swhois;
user->GetExt("swhois", swhois);
if (swhois)
{
user->Shrink("swhois");
DELETE(swhois);
}
}
// if the module is unloaded, tidy up all our dangling metadata
virtual void OnCleanup(int target_type, void* item)
{
if (target_type == TYPE_USER)
{
userrec* user = (userrec*)item;
std::string* swhois;
user->GetExt("swhois", swhois);
if (swhois)
{
user->Shrink("swhois");
DELETE(swhois);
}
}
}
// Whenever the linking module receives metadata from another server and doesnt know what
// to do with it (of course, hence the 'meta') it calls this method, and it is up to each
// module in turn to figure out if this metadata key belongs to them, and what they want
// to do with it.
// In our case we're only sending a single string around, so we just construct a std::string.
// Some modules will probably get much more complex and format more detailed structs and classes
// in a textual way for sending over the link.
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
// check if its our metadata key, and its associated with a user
if ((target_type == TYPE_USER) && (extname == "swhois"))
{
userrec* dest = (userrec*)target;
// if they dont already have an swhois field, accept the remote server's
std::string* text;
if (!dest->GetExt("swhois", text))
{
std::string* text = new std::string(extdata);
dest->Extend("swhois",text);
}
}
}
virtual void OnPostCommand(const std::string &command, const char **params, int pcnt, userrec *user, CmdResult result, const std::string &original_line)
{
if ((command != "OPER") || (result != CMD_SUCCESS))
return;
std::string swhois;
for (int i = 0; i < Conf->Enumerate("oper"); i++)
{
std::string name = Conf->ReadValue("oper", "name", i);
if (name == params[0])
{
swhois = Conf->ReadValue("oper", "swhois", i);
break;
}
}
if (!swhois.length())
{
for (int i = 0; i < Conf->Enumerate("type"); i++)
{
std::string type = Conf->ReadValue("type", "name", i);
if (type == user->oper)
{
swhois = Conf->ReadValue("type", "swhois", i);
break;
}
}
}
std::string *old;
if (user->GetExt("swhois", old))
{
user->Shrink("swhois");
DELETE(old);
}
if (!swhois.length())
return;
std::string *text = new std::string(swhois);
user->Extend("swhois", text);
std::deque<std::string>* metadata = new std::deque<std::string>;
metadata->push_back(user->nick);
metadata->push_back("swhois"); // The metadata id
metadata->push_back(*text); // The value to send
Event event((char*)metadata,(Module*)this,"send_metadata");
event.Send(ServerInstance);
delete metadata;
}
virtual ~ModuleSWhois()
{
DELETE(Conf);
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleSWhois)
\ No newline at end of file diff --git a/src/modules/m_taxonomy.cpp b/src/modules/m_taxonomy.cpp index 79dc8e23f..edae9ccf6 100644 --- a/src/modules/m_taxonomy.cpp +++ b/src/modules/m_taxonomy.cpp @@ -1,99 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides the /TAXONOMY command, used to view all metadata attached to a user */ - -/** Handle /WOOT - */ -class cmd_taxonomy : public command_t -{ - Module* Creator; - bool& claimed; - public: - /* Command 'taxonomy', takes no parameters and needs no special modes */ - cmd_taxonomy (InspIRCd* Instance, Module* maker, bool &claim) : command_t(Instance,"TAXONOMY", 'o', 1), Creator(maker), claimed(claim) - { - this->source = "m_taxonomy.so"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* dest = ServerInstance->FindNick(parameters[0]); - if (dest) - { - std::deque<std::string> list; - list.clear(); - user->GetExtList(list); - user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY ITEMS " + std::string(dest->nick) + " " +ConvToStr(list.size())); - for (unsigned int j = 0; j < list.size(); j++) - { - claimed = false; - FOREACH_MOD(I_OnSyncUserMetaData, OnSyncUserMetaData(user, Creator, dest, list[j], true)); - if (!claimed) - { - user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY METADATA " + list[j] + " = <unknown>"); - } - } - user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY END"); - } - return CMD_FAILURE; - } -}; - -class ModuleTaxonomy : public Module -{ - cmd_taxonomy* newcommand; - bool claimed; - public: - ModuleTaxonomy(InspIRCd* Me) - : Module(Me) - { - - // Create a new command - newcommand = new cmd_taxonomy(ServerInstance, this, claimed); - ServerInstance->AddCommand(newcommand); - } - - void Implements(char* List) - { - List[I_ProtoSendMetaData] = 1; - } - - void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata) - { - if (target_type == TYPE_USER) - { - userrec* spool = (userrec*)opaque; - std::string taxstr = "304 " + std::string(spool->nick) + ":TAXONOMY METADATA "+extname+" = "+extdata; - spool->WriteServ(taxstr); - claimed = true; - } - } - - virtual ~ModuleTaxonomy() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleTaxonomy) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides the /TAXONOMY command, used to view all metadata attached to a user */
/** Handle /WOOT
*/
class cmd_taxonomy : public command_t
{
Module* Creator;
bool& claimed;
public:
/* Command 'taxonomy', takes no parameters and needs no special modes */
cmd_taxonomy (InspIRCd* Instance, Module* maker, bool &claim) : command_t(Instance,"TAXONOMY", 'o', 1), Creator(maker), claimed(claim)
{
this->source = "m_taxonomy.so";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* dest = ServerInstance->FindNick(parameters[0]);
if (dest)
{
std::deque<std::string> list;
list.clear();
user->GetExtList(list);
user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY ITEMS " + std::string(dest->nick) + " " +ConvToStr(list.size()));
for (unsigned int j = 0; j < list.size(); j++)
{
claimed = false;
FOREACH_MOD(I_OnSyncUserMetaData, OnSyncUserMetaData(user, Creator, dest, list[j], true));
if (!claimed)
{
user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY METADATA " + list[j] + " = <unknown>");
}
}
user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY END");
}
return CMD_FAILURE;
}
};
class ModuleTaxonomy : public Module
{
cmd_taxonomy* newcommand;
bool claimed;
public:
ModuleTaxonomy(InspIRCd* Me)
: Module(Me)
{
// Create a new command
newcommand = new cmd_taxonomy(ServerInstance, this, claimed);
ServerInstance->AddCommand(newcommand);
}
void Implements(char* List)
{
List[I_ProtoSendMetaData] = 1;
}
void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)
{
if (target_type == TYPE_USER)
{
userrec* spool = (userrec*)opaque;
std::string taxstr = "304 " + std::string(spool->nick) + ":TAXONOMY METADATA "+extname+" = "+extdata;
spool->WriteServ(taxstr);
claimed = true;
}
}
virtual ~ModuleTaxonomy()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleTaxonomy)
\ No newline at end of file diff --git a/src/modules/m_testcommand.cpp b/src/modules/m_testcommand.cpp index 6ec197eb6..0733fd0f0 100644 --- a/src/modules/m_testcommand.cpp +++ b/src/modules/m_testcommand.cpp @@ -1,67 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides a pointless /dalinfo command, demo module */ - -/** Handle /DALINFO - */ -class cmd_dalinfo : public command_t -{ - public: - /* Command 'dalinfo', takes no parameters and needs no special modes */ - cmd_dalinfo (InspIRCd* Instance) : command_t(Instance,"DALINFO", 0, 0) - { - this->source = "m_testcommand.so"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - user->WriteServ("NOTICE %s :*** DALNet had nothing to do with it.", user->nick); - return CMD_FAILURE; - } -}; - -class ModuleTestCommand : public Module -{ - cmd_dalinfo* newcommand; - public: - ModuleTestCommand(InspIRCd* Me) - : Module(Me) - { - // Create a new command - newcommand = new cmd_dalinfo(ServerInstance); - ServerInstance->AddCommand(newcommand); - } - - void Implements(char* List) - { - } - - virtual ~ModuleTestCommand() - { - delete newcommand; - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleTestCommand) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides a pointless /dalinfo command, demo module */
/** Handle /DALINFO
*/
class cmd_dalinfo : public command_t
{
public:
/* Command 'dalinfo', takes no parameters and needs no special modes */
cmd_dalinfo (InspIRCd* Instance) : command_t(Instance,"DALINFO", 0, 0)
{
this->source = "m_testcommand.so";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
user->WriteServ("NOTICE %s :*** DALNet had nothing to do with it.", user->nick);
return CMD_FAILURE;
}
};
class ModuleTestCommand : public Module
{
cmd_dalinfo* newcommand;
public:
ModuleTestCommand(InspIRCd* Me)
: Module(Me)
{
// Create a new command
newcommand = new cmd_dalinfo(ServerInstance);
ServerInstance->AddCommand(newcommand);
}
void Implements(char* List)
{
}
virtual ~ModuleTestCommand()
{
delete newcommand;
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleTestCommand)
\ No newline at end of file diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp index ae3da7549..f705a1f95 100644 --- a/src/modules/m_timedbans.cpp +++ b/src/modules/m_timedbans.cpp @@ -1,204 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Adds timed bans */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" -#include "configreader.h" - -/** Holds a timed ban - */ -class TimedBan : public classbase -{ - public: - std::string channel; - std::string mask; - time_t expire; -}; - -typedef std::vector<TimedBan> timedbans; -timedbans TimedBanList; - -/** Handle /TBAN - */ -class cmd_tban : public command_t -{ - public: - cmd_tban (InspIRCd* Instance) : command_t(Instance,"TBAN", 0, 3) - { - this->source = "m_timedbans.so"; - syntax = "<channel> <duration> <banmask>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - chanrec* channel = ServerInstance->FindChan(parameters[0]); - if (channel) - { - int cm = channel->GetStatus(user); - if ((cm == STATUS_HOP) || (cm == STATUS_OP)) - { - if (!ServerInstance->IsValidMask(parameters[2])) - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban mask"); - return CMD_FAILURE; - } - for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++) - { - if (!strcasecmp(i->data,parameters[2])) - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :The ban "+std::string(parameters[2])+" is already on the banlist of "+std::string(parameters[0])); - return CMD_FAILURE; - } - } - TimedBan T; - std::string channelname = parameters[0]; - long duration = ServerInstance->Duration(parameters[1]); - unsigned long expire = duration + time(NULL); - if (duration < 1) - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban time"); - return CMD_FAILURE; - } - std::string mask = parameters[2]; - const char *setban[32]; - setban[0] = parameters[0]; - setban[1] = "+b"; - setban[2] = parameters[2]; - // use CallCommandHandler to make it so that the user sets the mode - // themselves - ServerInstance->CallCommandHandler("MODE",setban,3,user); - /* Check if the ban was actually added (e.g. banlist was NOT full) */ - bool was_added = false; - for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++) - if (!strcasecmp(i->data,mask.c_str())) - was_added = true; - if (was_added) - { - T.channel = channelname; - T.mask = mask; - T.expire = expire; - TimedBanList.push_back(T); - channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s added a timed ban on %s lasting for %ld seconds.", channel->name, user->nick, mask.c_str(), duration); - return CMD_SUCCESS; - } - return CMD_FAILURE; - } - else user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, channel->name); - return CMD_FAILURE; - } - user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]); - return CMD_FAILURE; - } -}; - -class ModuleTimedBans : public Module -{ - cmd_tban* mycommand; - public: - ModuleTimedBans(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_tban(ServerInstance); - ServerInstance->AddCommand(mycommand); - TimedBanList.clear(); - } - - virtual ~ModuleTimedBans() - { - TimedBanList.clear(); - } - - void Implements(char* List) - { - List[I_OnDelBan] = List[I_OnBackgroundTimer] = 1; - } - - virtual int OnDelBan(userrec* source, chanrec* chan, const std::string &banmask) - { - irc::string listitem = banmask.c_str(); - irc::string thischan = chan->name; - for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++) - { - irc::string target = i->mask.c_str(); - irc::string tchan = i->channel.c_str(); - if ((listitem == target) && (tchan == thischan)) - { - TimedBanList.erase(i); - break; - } - } - return 0; - } - - virtual void OnBackgroundTimer(time_t curtime) - { - bool again = true; - while (again) - { - again = false; - for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++) - { - if (curtime > i->expire) - { - chanrec* cr = ServerInstance->FindChan(i->channel); - again = true; - if (cr) - { - cr->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :Timed ban on %s expired.", cr->name, i->mask.c_str()); - const char *setban[3]; - setban[0] = i->channel.c_str(); - setban[1] = "-b"; - setban[2] = i->mask.c_str(); - // kludge alert! - // ::SendMode expects a userrec* to send the numeric replies - // back to, so we create it a fake user that isnt in the user - // hash and set its descriptor to FD_MAGIC_NUMBER so the data - // falls into the abyss :p - userrec* temp = new userrec(ServerInstance); - temp->SetFd(FD_MAGIC_NUMBER); - /* FIX: Send mode remotely*/ - std::deque<std::string> n; - n.push_back(setban[0]); - n.push_back("-b"); - n.push_back(setban[2]); - ServerInstance->SendMode(setban,3,temp); - Event rmode((char *)&n, NULL, "send_mode"); - rmode.Send(ServerInstance); - DELETE(temp); - } - else - { - /* Where the hell did our channel go?! */ - TimedBanList.erase(i); - } - // we used to delete the item here, but we dont need to as the servermode above does it for us, - break; - } - } - } - } - - virtual Version GetVersion() - { - return Version(1,1,0,0,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleTimedBans) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Adds timed bans */
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
#include "configreader.h"
/** Holds a timed ban
*/
class TimedBan : public classbase
{
public:
std::string channel;
std::string mask;
time_t expire;
};
typedef std::vector<TimedBan> timedbans;
timedbans TimedBanList;
/** Handle /TBAN
*/
class cmd_tban : public command_t
{
public:
cmd_tban (InspIRCd* Instance) : command_t(Instance,"TBAN", 0, 3)
{
this->source = "m_timedbans.so";
syntax = "<channel> <duration> <banmask>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
chanrec* channel = ServerInstance->FindChan(parameters[0]);
if (channel)
{
int cm = channel->GetStatus(user);
if ((cm == STATUS_HOP) || (cm == STATUS_OP))
{
if (!ServerInstance->IsValidMask(parameters[2]))
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban mask");
return CMD_FAILURE;
}
for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
{
if (!strcasecmp(i->data,parameters[2]))
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :The ban "+std::string(parameters[2])+" is already on the banlist of "+std::string(parameters[0]));
return CMD_FAILURE;
}
}
TimedBan T;
std::string channelname = parameters[0];
long duration = ServerInstance->Duration(parameters[1]);
unsigned long expire = duration + time(NULL);
if (duration < 1)
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban time");
return CMD_FAILURE;
}
std::string mask = parameters[2];
const char *setban[32];
setban[0] = parameters[0];
setban[1] = "+b";
setban[2] = parameters[2];
// use CallCommandHandler to make it so that the user sets the mode
// themselves
ServerInstance->CallCommandHandler("MODE",setban,3,user);
/* Check if the ban was actually added (e.g. banlist was NOT full) */
bool was_added = false;
for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
if (!strcasecmp(i->data,mask.c_str()))
was_added = true;
if (was_added)
{
T.channel = channelname;
T.mask = mask;
T.expire = expire;
TimedBanList.push_back(T);
channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s added a timed ban on %s lasting for %ld seconds.", channel->name, user->nick, mask.c_str(), duration);
return CMD_SUCCESS;
}
return CMD_FAILURE;
}
else user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, channel->name);
return CMD_FAILURE;
}
user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]);
return CMD_FAILURE;
}
};
class ModuleTimedBans : public Module
{
cmd_tban* mycommand;
public:
ModuleTimedBans(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_tban(ServerInstance);
ServerInstance->AddCommand(mycommand);
TimedBanList.clear();
}
virtual ~ModuleTimedBans()
{
TimedBanList.clear();
}
void Implements(char* List)
{
List[I_OnDelBan] = List[I_OnBackgroundTimer] = 1;
}
virtual int OnDelBan(userrec* source, chanrec* chan, const std::string &banmask)
{
irc::string listitem = banmask.c_str();
irc::string thischan = chan->name;
for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++)
{
irc::string target = i->mask.c_str();
irc::string tchan = i->channel.c_str();
if ((listitem == target) && (tchan == thischan))
{
TimedBanList.erase(i);
break;
}
}
return 0;
}
virtual void OnBackgroundTimer(time_t curtime)
{
bool again = true;
while (again)
{
again = false;
for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++)
{
if (curtime > i->expire)
{
chanrec* cr = ServerInstance->FindChan(i->channel);
again = true;
if (cr)
{
cr->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :Timed ban on %s expired.", cr->name, i->mask.c_str());
const char *setban[3];
setban[0] = i->channel.c_str();
setban[1] = "-b";
setban[2] = i->mask.c_str();
// kludge alert!
// ::SendMode expects a userrec* to send the numeric replies
// back to, so we create it a fake user that isnt in the user
// hash and set its descriptor to FD_MAGIC_NUMBER so the data
// falls into the abyss :p
userrec* temp = new userrec(ServerInstance);
temp->SetFd(FD_MAGIC_NUMBER);
/* FIX: Send mode remotely*/
std::deque<std::string> n;
n.push_back(setban[0]);
n.push_back("-b");
n.push_back(setban[2]);
ServerInstance->SendMode(setban,3,temp);
Event rmode((char *)&n, NULL, "send_mode");
rmode.Send(ServerInstance);
DELETE(temp);
}
else
{
/* Where the hell did our channel go?! */
TimedBanList.erase(i);
}
// we used to delete the item here, but we dont need to as the servermode above does it for us,
break;
}
}
}
}
virtual Version GetVersion()
{
return Version(1,1,0,0,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleTimedBans)
\ No newline at end of file diff --git a/src/modules/m_tline.cpp b/src/modules/m_tline.cpp index 834cb7f4c..dd13a965c 100644 --- a/src/modules/m_tline.cpp +++ b/src/modules/m_tline.cpp @@ -1,95 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "wildcard.h" - -/* $ModDesc: Provides /tline command used to test who a mask matches */ - -/** Handle /TLINE - */ -class cmd_tline : public command_t -{ - public: - cmd_tline (InspIRCd* Instance) : command_t(Instance,"TLINE", 'o', 1) - { - this->source = "m_tline.so"; - this->syntax = "<mask>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - float n_counted = 0; - float n_matched = 0; - float n_match_host = 0; - float n_match_ip = 0; - - for (user_hash::const_iterator u = ServerInstance->clientlist->begin(); u != ServerInstance->clientlist->end(); u++) - { - n_counted++; - if (match(u->second->GetFullRealHost(),parameters[0])) - { - n_matched++; - n_match_host++; - } - else - { - char host[MAXBUF]; - snprintf(host, MAXBUF, "%s@%s", u->second->ident, u->second->GetIPString()); - if (match(host, parameters[0], true)) - { - n_matched++; - n_match_ip++; - } - } - } - if (n_matched) - user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against %0.0f user(s) (%0.2f%% of the userbase). %0.0f by hostname and %0.0f by IP address.",user->nick, n_counted, parameters[0], n_matched, (n_matched/n_counted)*100, n_match_host, n_match_ip); - else - user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against no user(s).", user->nick, n_counted, parameters[0]); - - return CMD_LOCALONLY; - } -}; - -class ModuleTLine : public Module -{ - cmd_tline* newcommand; - public: - ModuleTLine(InspIRCd* Me) - : Module(Me) - { - - newcommand = new cmd_tline(ServerInstance); - ServerInstance->AddCommand(newcommand); - } - - void Implements(char* List) - { - } - - virtual ~ModuleTLine() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(ModuleTLine) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "wildcard.h"
/* $ModDesc: Provides /tline command used to test who a mask matches */
/** Handle /TLINE
*/
class cmd_tline : public command_t
{
public:
cmd_tline (InspIRCd* Instance) : command_t(Instance,"TLINE", 'o', 1)
{
this->source = "m_tline.so";
this->syntax = "<mask>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
float n_counted = 0;
float n_matched = 0;
float n_match_host = 0;
float n_match_ip = 0;
for (user_hash::const_iterator u = ServerInstance->clientlist->begin(); u != ServerInstance->clientlist->end(); u++)
{
n_counted++;
if (match(u->second->GetFullRealHost(),parameters[0]))
{
n_matched++;
n_match_host++;
}
else
{
char host[MAXBUF];
snprintf(host, MAXBUF, "%s@%s", u->second->ident, u->second->GetIPString());
if (match(host, parameters[0], true))
{
n_matched++;
n_match_ip++;
}
}
}
if (n_matched)
user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against %0.0f user(s) (%0.2f%% of the userbase). %0.0f by hostname and %0.0f by IP address.",user->nick, n_counted, parameters[0], n_matched, (n_matched/n_counted)*100, n_match_host, n_match_ip);
else
user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against no user(s).", user->nick, n_counted, parameters[0]);
return CMD_LOCALONLY;
}
};
class ModuleTLine : public Module
{
cmd_tline* newcommand;
public:
ModuleTLine(InspIRCd* Me)
: Module(Me)
{
newcommand = new cmd_tline(ServerInstance);
ServerInstance->AddCommand(newcommand);
}
void Implements(char* List)
{
}
virtual ~ModuleTLine()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleTLine)
\ No newline at end of file diff --git a/src/modules/m_uhnames.cpp b/src/modules/m_uhnames.cpp index 6794f4643..61b58f302 100644 --- a/src/modules/m_uhnames.cpp +++ b/src/modules/m_uhnames.cpp @@ -1,98 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -static const char* dummy = "ON"; - -/* $ModDesc: Provides aliases of commands. */ - -class ModuleUHNames : public Module -{ - CUList nl; - public: - - ModuleUHNames(InspIRCd* Me) - : Module(Me) - { - } - - void Implements(char* List) - { - List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1; - } - - virtual ~ModuleUHNames() - { - } - - void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable) - { - if ((displayable) && (extname == "UHNAMES")) - proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled"); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - - virtual void On005Numeric(std::string &output) - { - output.append(" UHNAMES"); - } - - Priority Prioritize() - { - return (Priority)ServerInstance->PriorityBefore("m_namesx.so"); - } - - virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) - { - irc::string c = command.c_str(); - /* We don't actually create a proper command handler class for PROTOCTL, - * because other modules might want to have PROTOCTL hooks too. - * Therefore, we just hook its as an unvalidated command therefore we - * can capture it even if it doesnt exist! :-) - */ - if (c == "PROTOCTL") - { - if ((pcnt) && (!strcasecmp(parameters[0],"UHNAMES"))) - { - user->Extend("UHNAMES",dummy); - return 1; - } - } - return 0; - } - - /* IMPORTANT: This must be prioritized above NAMESX! */ - virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist) - { - if (user->GetExt("UHNAMES")) - { - if (!ulist) - ulist = Ptr->GetUsers(); - - for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) - i->second = i->first->GetFullHost(); - } - return 0; - } -}; - -MODULE_INIT(ModuleUHNames) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
static const char* dummy = "ON";
/* $ModDesc: Provides aliases of commands. */
class ModuleUHNames : public Module
{
CUList nl;
public:
ModuleUHNames(InspIRCd* Me)
: Module(Me)
{
}
void Implements(char* List)
{
List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1;
}
virtual ~ModuleUHNames()
{
}
void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)
{
if ((displayable) && (extname == "UHNAMES"))
proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled");
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
virtual void On005Numeric(std::string &output)
{
output.append(" UHNAMES");
}
Priority Prioritize()
{
return (Priority)ServerInstance->PriorityBefore("m_namesx.so");
}
virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
{
irc::string c = command.c_str();
/* We don't actually create a proper command handler class for PROTOCTL,
* because other modules might want to have PROTOCTL hooks too.
* Therefore, we just hook its as an unvalidated command therefore we
* can capture it even if it doesnt exist! :-)
*/
if (c == "PROTOCTL")
{
if ((pcnt) && (!strcasecmp(parameters[0],"UHNAMES")))
{
user->Extend("UHNAMES",dummy);
return 1;
}
}
return 0;
}
/* IMPORTANT: This must be prioritized above NAMESX! */
virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist)
{
if (user->GetExt("UHNAMES"))
{
if (!ulist)
ulist = Ptr->GetUsers();
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
i->second = i->first->GetFullHost();
}
return 0;
}
};
MODULE_INIT(ModuleUHNames)
\ No newline at end of file diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp index ab748663c..bcf18b308 100644 --- a/src/modules/m_uninvite.cpp +++ b/src/modules/m_uninvite.cpp @@ -1,107 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -/* $ModDesc: Provides the UNINVITE command which lets users un-invite other users from channels (!) */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "configreader.h" - -/** Handle /UNINVITE - */ -class cmd_uninvite : public command_t -{ - public: - cmd_uninvite (InspIRCd* Instance) : command_t(Instance,"UNINVITE", 0, 2) - { - this->source = "m_uninvite.so"; - syntax = "<nick> <channel>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - userrec* u = ServerInstance->FindNick(parameters[0]); - chanrec* c = ServerInstance->FindChan(parameters[1]); - - if ((!c) || (!u)) - { - if (!c) - { - user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]); - } - else - { - user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]); - } - - return CMD_FAILURE; - } - - if (c->modes[CM_INVITEONLY]) - { - if (c->GetStatus(user) < STATUS_HOP) - { - user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name); - return CMD_FAILURE; - } - } - - irc::string xname(c->name); - - if (!u->IsInvited(xname)) - { - user->WriteServ("491 %s %s %s :Is not invited to channel %s",user->nick,u->nick,c->name,c->name); - return CMD_FAILURE; - } - if (!c->HasUser(user)) - { - user->WriteServ("492 %s %s :You're not on that channel!",user->nick, c->name); - return CMD_FAILURE; - } - - u->RemoveInvite(xname); - user->WriteServ("494 %s %s %s :Uninvited",user->nick,c->name,u->nick); - u->WriteServ("493 %s :You were uninvited from %s by %s",u->nick,c->name,user->nick); - c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s uninvited %s.", c->name, user->nick, u->nick); - - return CMD_SUCCESS; - } -}; - -class ModuleUninvite : public Module -{ - cmd_uninvite *mycommand; - - public: - - ModuleUninvite(InspIRCd* Me) : Module(Me) - { - - mycommand = new cmd_uninvite(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleUninvite() - { - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } -}; - -MODULE_INIT(ModuleUninvite) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
/* $ModDesc: Provides the UNINVITE command which lets users un-invite other users from channels (!) */
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "configreader.h"
/** Handle /UNINVITE
*/
class cmd_uninvite : public command_t
{
public:
cmd_uninvite (InspIRCd* Instance) : command_t(Instance,"UNINVITE", 0, 2)
{
this->source = "m_uninvite.so";
syntax = "<nick> <channel>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
userrec* u = ServerInstance->FindNick(parameters[0]);
chanrec* c = ServerInstance->FindChan(parameters[1]);
if ((!c) || (!u))
{
if (!c)
{
user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);
}
else
{
user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
}
return CMD_FAILURE;
}
if (c->modes[CM_INVITEONLY])
{
if (c->GetStatus(user) < STATUS_HOP)
{
user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);
return CMD_FAILURE;
}
}
irc::string xname(c->name);
if (!u->IsInvited(xname))
{
user->WriteServ("491 %s %s %s :Is not invited to channel %s",user->nick,u->nick,c->name,c->name);
return CMD_FAILURE;
}
if (!c->HasUser(user))
{
user->WriteServ("492 %s %s :You're not on that channel!",user->nick, c->name);
return CMD_FAILURE;
}
u->RemoveInvite(xname);
user->WriteServ("494 %s %s %s :Uninvited",user->nick,c->name,u->nick);
u->WriteServ("493 %s :You were uninvited from %s by %s",u->nick,c->name,user->nick);
c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s uninvited %s.", c->name, user->nick, u->nick);
return CMD_SUCCESS;
}
};
class ModuleUninvite : public Module
{
cmd_uninvite *mycommand;
public:
ModuleUninvite(InspIRCd* Me) : Module(Me)
{
mycommand = new cmd_uninvite(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleUninvite()
{
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
};
MODULE_INIT(ModuleUninvite)
\ No newline at end of file diff --git a/src/modules/m_userip.cpp b/src/modules/m_userip.cpp index 296d52300..979ee6112 100644 --- a/src/modules/m_userip.cpp +++ b/src/modules/m_userip.cpp @@ -1,86 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides support for USERIP command */ - -/** Handle /USERIP - */ -class cmd_userip : public command_t -{ - public: - cmd_userip (InspIRCd* Instance) : command_t(Instance,"USERIP", 'o', 1) - { - this->source = "m_userip.so"; - syntax = "<nick>{,<nick>}"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - std::string retbuf = std::string("340 ") + user->nick + " :"; - - for (int i = 0; i < pcnt; i++) - { - userrec *u = ServerInstance->FindNick(parameters[i]); - if ((u) && (u->registered == REG_ALL)) - { - retbuf = retbuf + u->nick + (IS_OPER(u) ? "*" : "") + "=+" + u->ident + "@" + u->GetIPString() + " "; - } - } - - user->WriteServ(retbuf); - - /* Dont send to the network */ - return CMD_FAILURE; - } -}; - -class ModuleUserIP : public Module -{ - cmd_userip* mycommand; - public: - ModuleUserIP(InspIRCd* Me) - : Module(Me) - { - - mycommand = new cmd_userip(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - void Implements(char* List) - { - List[I_On005Numeric] = 1; - } - - virtual void On005Numeric(std::string &output) - { - output = output + std::string(" USERIP"); - } - - virtual ~ModuleUserIP() - { - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleUserIP) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides support for USERIP command */
/** Handle /USERIP
*/
class cmd_userip : public command_t
{
public:
cmd_userip (InspIRCd* Instance) : command_t(Instance,"USERIP", 'o', 1)
{
this->source = "m_userip.so";
syntax = "<nick>{,<nick>}";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
std::string retbuf = std::string("340 ") + user->nick + " :";
for (int i = 0; i < pcnt; i++)
{
userrec *u = ServerInstance->FindNick(parameters[i]);
if ((u) && (u->registered == REG_ALL))
{
retbuf = retbuf + u->nick + (IS_OPER(u) ? "*" : "") + "=+" + u->ident + "@" + u->GetIPString() + " ";
}
}
user->WriteServ(retbuf);
/* Dont send to the network */
return CMD_FAILURE;
}
};
class ModuleUserIP : public Module
{
cmd_userip* mycommand;
public:
ModuleUserIP(InspIRCd* Me)
: Module(Me)
{
mycommand = new cmd_userip(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
void Implements(char* List)
{
List[I_On005Numeric] = 1;
}
virtual void On005Numeric(std::string &output)
{
output = output + std::string(" USERIP");
}
virtual ~ModuleUserIP()
{
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleUserIP)
\ No newline at end of file diff --git a/src/modules/m_vhost.cpp b/src/modules/m_vhost.cpp index c77a3f85f..10fc76f05 100644 --- a/src/modules/m_vhost.cpp +++ b/src/modules/m_vhost.cpp @@ -1,95 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" - -/* $ModDesc: Provides masking of user hostnames via traditional /VHOST command */ - -static ConfigReader* Conf; - -/** Handle /VHOST - */ -class cmd_vhost : public command_t -{ - public: - cmd_vhost (InspIRCd* Instance) : command_t(Instance,"VHOST", 0, 2) - { - this->source = "m_vhost.so"; - syntax = "<username> <password>"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - for (int index = 0; index < Conf->Enumerate("vhost"); index++) - { - std::string mask = Conf->ReadValue("vhost","host",index); - std::string username = Conf->ReadValue("vhost","user",index); - std::string pass = Conf->ReadValue("vhost","pass",index); - if ((!strcmp(parameters[0],username.c_str())) && (!strcmp(parameters[1],pass.c_str()))) - { - if (!mask.empty()) - { - user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your VHost: " + mask); - user->ChangeDisplayedHost(mask.c_str()); - return CMD_FAILURE; - } - } - } - user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid username or password."); - return CMD_FAILURE; - } -}; - -class ModuleVHost : public Module -{ - private: - - cmd_vhost* mycommand; - - public: - ModuleVHost(InspIRCd* Me) : Module(Me) - { - - Conf = new ConfigReader(ServerInstance); - mycommand = new cmd_vhost(ServerInstance); - ServerInstance->AddCommand(mycommand); - } - - virtual ~ModuleVHost() - { - DELETE(Conf); - } - - void Implements(char* List) - { - List[I_OnRehash] = 1; - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - DELETE(Conf); - Conf = new ConfigReader(ServerInstance); - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } - -}; - -MODULE_INIT(ModuleVHost) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
/* $ModDesc: Provides masking of user hostnames via traditional /VHOST command */
static ConfigReader* Conf;
/** Handle /VHOST
*/
class cmd_vhost : public command_t
{
public:
cmd_vhost (InspIRCd* Instance) : command_t(Instance,"VHOST", 0, 2)
{
this->source = "m_vhost.so";
syntax = "<username> <password>";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
for (int index = 0; index < Conf->Enumerate("vhost"); index++)
{
std::string mask = Conf->ReadValue("vhost","host",index);
std::string username = Conf->ReadValue("vhost","user",index);
std::string pass = Conf->ReadValue("vhost","pass",index);
if ((!strcmp(parameters[0],username.c_str())) && (!strcmp(parameters[1],pass.c_str())))
{
if (!mask.empty())
{
user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your VHost: " + mask);
user->ChangeDisplayedHost(mask.c_str());
return CMD_FAILURE;
}
}
}
user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid username or password.");
return CMD_FAILURE;
}
};
class ModuleVHost : public Module
{
private:
cmd_vhost* mycommand;
public:
ModuleVHost(InspIRCd* Me) : Module(Me)
{
Conf = new ConfigReader(ServerInstance);
mycommand = new cmd_vhost(ServerInstance);
ServerInstance->AddCommand(mycommand);
}
virtual ~ModuleVHost()
{
DELETE(Conf);
}
void Implements(char* List)
{
List[I_OnRehash] = 1;
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
DELETE(Conf);
Conf = new ConfigReader(ServerInstance);
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(ModuleVHost)
\ No newline at end of file diff --git a/src/modules/m_watch.cpp b/src/modules/m_watch.cpp index 552e3317a..2f847661e 100644 --- a/src/modules/m_watch.cpp +++ b/src/modules/m_watch.cpp @@ -1,472 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" - -/* $ModDesc: Provides support for the /WATCH command */ - -/* This module has been refactored to provide a very efficient (in terms of cpu time) - * implementation of /WATCH. - * - * To improve the efficiency of watch, many lists are kept. The first primary list is - * a hash_map of who's being watched by who. For example: - * - * KEY: Brain ---> Watched by: Boo, w00t, Om - * KEY: Boo ---> Watched by: Brain, w00t - * - * This is used when we want to tell all the users that are watching someone that - * they are now available or no longer available. For example, if the hash was - * populated as shown above, then when Brain signs on, messages are sent to Boo, w00t - * and Om by reading their 'watched by' list. When this occurs, their online status - * in each of these users lists (see below) is also updated. - * - * Each user also has a seperate (smaller) map attached to their userrec whilst they - * have any watch entries, which is managed by class Extensible. When they add or remove - * a watch entry from their list, it is inserted here, as well as the main list being - * maintained. This map also contains the user's online status. For users that are - * offline, the key points at an empty string, and for users that are online, the key - * points at a string containing "users-ident users-host users-signon-time". This is - * stored in this manner so that we don't have to FindUser() to fetch this info, the - * users signon can populate the field for us. - * - * For example, going again on the example above, this would be w00t's watchlist: - * - * KEY: Boo ---> Status: "Boo brains.sexy.babe 535342348" - * KEY: Brain ---> Status: "" - * - * In this list we can see that Boo is online, and Brain is offline. We can then - * use this list for 'WATCH L', and 'WATCH S' can be implemented as a combination - * of the above two data structures, with minimum CPU penalty for doing so. - * - * In short, the least efficient this ever gets is O(n), and thats only because - * there are parts that *must* loop (e.g. telling all users that are watching a - * nick that the user online), however this is a *major* improvement over the - * 1.0 implementation, which in places had O(n^n) and worse in it, because this - * implementation scales based upon the sizes of the watch entries, whereas the - * old system would scale (or not as the case may be) according to the total number - * of users using WATCH. - */ - -/* - * Before you start screaming, this definition is only used here, so moving it to a header is pointless. - * Yes, it's horrid. Blame cl for being different. -- w00t - */ -#ifdef WINDOWS -typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash_compare<irc::string, less<irc::string> > > watchentries; -#else -typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash<irc::string> > watchentries; -#endif -typedef std::map<irc::string, std::string> watchlist; - -/* Who's watching each nickname. - * NOTE: We do NOT iterate this to display a user's WATCH list! - * See the comments above! - */ -watchentries* whos_watching_me; - -/** Handle /WATCH - */ -class cmd_watch : public command_t -{ - unsigned int& MAX_WATCH; - public: - CmdResult remove_watch(userrec* user, const char* nick) - { - // removing an item from the list - if (!ServerInstance->IsNick(nick)) - { - user->WriteServ("942 %s %s :Invalid nickname", user->nick, nick); - return CMD_FAILURE; - } - - watchlist* wl; - if (user->GetExt("watchlist", wl)) - { - /* Yup, is on my list */ - watchlist::iterator n = wl->find(nick); - if (n != wl->end()) - { - if (!n->second.empty()) - user->WriteServ("602 %s %s %s :stopped watching", user->nick, n->first.c_str(), n->second.c_str()); - else - user->WriteServ("602 %s %s * * 0 :stopped watching", user->nick, nick); - - wl->erase(n); - } - - if (!wl->size()) - { - user->Shrink("watchlist"); - delete wl; - } - - watchentries::iterator x = whos_watching_me->find(nick); - if (x != whos_watching_me->end()) - { - /* People are watching this user, am i one of them? */ - std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user); - if (n != x->second.end()) - /* I'm no longer watching you... */ - x->second.erase(n); - - if (!x->second.size()) - whos_watching_me->erase(nick); - } - } - - /* This might seem confusing, but we return CMD_FAILURE - * to indicate that this message shouldnt be routed across - * the network to other linked servers. - */ - return CMD_FAILURE; - } - - CmdResult add_watch(userrec* user, const char* nick) - { - if (!ServerInstance->IsNick(nick)) - { - user->WriteServ("942 %s %s :Invalid nickname",user->nick,nick); - return CMD_FAILURE; - } - - watchlist* wl; - if (!user->GetExt("watchlist", wl)) - { - wl = new watchlist(); - user->Extend("watchlist", wl); - } - - if (wl->size() == MAX_WATCH) - { - user->WriteServ("512 %s %s :Too many WATCH entries", user->nick, nick); - return CMD_FAILURE; - } - - watchlist::iterator n = wl->find(nick); - if (n == wl->end()) - { - /* Don't already have the user on my watch list, proceed */ - watchentries::iterator x = whos_watching_me->find(nick); - if (x != whos_watching_me->end()) - { - /* People are watching this user, add myself */ - x->second.push_back(user); - } - else - { - std::deque<userrec*> newlist; - newlist.push_back(user); - (*(whos_watching_me))[nick] = newlist; - } - - userrec* target = ServerInstance->FindNick(nick); - if (target) - { - if (target->Visibility && !target->Visibility->VisibleTo(user)) - { - (*wl)[nick] = ""; - user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick); - return CMD_FAILURE; - } - - (*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age)); - user->WriteServ("604 %s %s %s :is online",user->nick, nick, (*wl)[nick].c_str()); - } - else - { - (*wl)[nick] = ""; - user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick); - } - } - - return CMD_FAILURE; - } - - cmd_watch (InspIRCd* Instance, unsigned int &maxwatch) : command_t(Instance,"WATCH",0,0), MAX_WATCH(maxwatch) - { - this->source = "m_watch.so"; - syntax = "[C|L|S]|[+|-<nick>]"; - } - - CmdResult Handle (const char** parameters, int pcnt, userrec *user) - { - if (!pcnt) - { - watchlist* wl; - if (user->GetExt("watchlist", wl)) - { - for (watchlist::iterator q = wl->begin(); q != wl->end(); q++) - { - if (!q->second.empty()) - user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str()); - } - } - user->WriteServ("607 %s :End of WATCH list",user->nick); - } - else if (pcnt > 0) - { - for (int x = 0; x < pcnt; x++) - { - const char *nick = parameters[x]; - if (!strcasecmp(nick,"C")) - { - // watch clear - watchlist* wl; - if (user->GetExt("watchlist", wl)) - { - for (watchlist::iterator i = wl->begin(); i != wl->end(); i++) - { - watchentries::iterator x = whos_watching_me->find(i->first); - if (x != whos_watching_me->end()) - { - /* People are watching this user, am i one of them? */ - std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user); - if (n != x->second.end()) - /* I'm no longer watching you... */ - x->second.erase(n); - - if (!x->second.size()) - whos_watching_me->erase(user->nick); - } - } - - delete wl; - user->Shrink("watchlist"); - } - } - else if (!strcasecmp(nick,"L")) - { - watchlist* wl; - if (user->GetExt("watchlist", wl)) - { - for (watchlist::iterator q = wl->begin(); q != wl->end(); q++) - { - if (!q->second.empty()) - user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str()); - else - user->WriteServ("605 %s %s * * 0 :is offline", user->nick, q->first.c_str()); - } - } - user->WriteServ("607 %s :End of WATCH list",user->nick); - } - else if (!strcasecmp(nick,"S")) - { - watchlist* wl; - int you_have = 0; - int youre_on = 0; - std::string list; - - if (user->GetExt("watchlist", wl)) - { - for (watchlist::iterator q = wl->begin(); q != wl->end(); q++) - list.append(q->first.c_str()).append(" "); - you_have = wl->size(); - } - - watchentries::iterator x = whos_watching_me->find(user->nick); - if (x != whos_watching_me->end()) - youre_on = x->second.size(); - - user->WriteServ("603 %s :You have %d and are on %d WATCH entries", user->nick, you_have, youre_on); - user->WriteServ("606 %s :%s",user->nick, list.c_str()); - user->WriteServ("607 %s :End of WATCH S",user->nick); - } - else if (nick[0] == '-') - { - nick++; - remove_watch(user, nick); - } - else if (nick[0] == '+') - { - nick++; - add_watch(user, nick); - } - } - } - /* So that spanningtree doesnt pass the WATCH commands to the network! */ - return CMD_FAILURE; - } -}; - -class Modulewatch : public Module -{ - cmd_watch* mycommand; - unsigned int maxwatch; - public: - - Modulewatch(InspIRCd* Me) - : Module(Me), maxwatch(32) - { - OnRehash(NULL, ""); - whos_watching_me = new watchentries(); - mycommand = new cmd_watch(ServerInstance, maxwatch); - ServerInstance->AddCommand(mycommand); - } - - virtual void OnRehash(userrec* user, const std::string ¶meter) - { - ConfigReader Conf(ServerInstance); - maxwatch = Conf.ReadInteger("watch", "maxentries", 0, true); - if (!maxwatch) - maxwatch = 32; - } - - void Implements(char* List) - { - List[I_OnRehash] = List[I_OnGarbageCollect] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_OnPostConnect] = List[I_OnUserPostNick] = List[I_On005Numeric] = 1; - } - - virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message) - { - watchentries::iterator x = whos_watching_me->find(user->nick); - if (x != whos_watching_me->end()) - { - for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++) - { - if (!user->Visibility || user->Visibility->VisibleTo(user)) - (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick ,user->nick, user->ident, user->dhost, ServerInstance->Time()); - - watchlist* wl; - if ((*n)->GetExt("watchlist", wl)) - /* We were on somebody's notify list, set ourselves offline */ - (*wl)[user->nick] = ""; - } - } - - /* Now im quitting, if i have a notify list, im no longer watching anyone */ - watchlist* wl; - if (user->GetExt("watchlist", wl)) - { - /* Iterate every user on my watch list, and take me out of the whos_watching_me map for each one we're watching */ - for (watchlist::iterator i = wl->begin(); i != wl->end(); i++) - { - watchentries::iterator x = whos_watching_me->find(i->first); - if (x != whos_watching_me->end()) - { - /* People are watching this user, am i one of them? */ - std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user); - if (n != x->second.end()) - /* I'm no longer watching you... */ - x->second.erase(n); - - if (!x->second.size()) - whos_watching_me->erase(user->nick); - } - } - - /* User's quitting, we're done with this. */ - delete wl; - } - } - - virtual void OnGarbageCollect() - { - watchentries* old_watch = whos_watching_me; - whos_watching_me = new watchentries(); - - for (watchentries::const_iterator n = old_watch->begin(); n != old_watch->end(); n++) - whos_watching_me->insert(*n); - - delete old_watch; - } - - virtual void OnCleanup(int target_type, void* item) - { - if (target_type == TYPE_USER) - { - watchlist* wl; - userrec* user = (userrec*)item; - - if (user->GetExt("watchlist", wl)) - { - user->Shrink("watchlist"); - delete wl; - } - } - } - - virtual void OnPostConnect(userrec* user) - { - watchentries::iterator x = whos_watching_me->find(user->nick); - if (x != whos_watching_me->end()) - { - for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++) - { - if (!user->Visibility || user->Visibility->VisibleTo(user)) - (*n)->WriteServ("600 %s %s %s %s %lu :arrived online", (*n)->nick, user->nick, user->ident, user->dhost, user->age); - - watchlist* wl; - if ((*n)->GetExt("watchlist", wl)) - /* We were on somebody's notify list, set ourselves online */ - (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age)); - } - } - } - - virtual void OnUserPostNick(userrec* user, const std::string &oldnick) - { - watchentries::iterator new_online = whos_watching_me->find(user->nick); - watchentries::iterator new_offline = whos_watching_me->find(assign(oldnick)); - - if (new_online != whos_watching_me->end()) - { - for (std::deque<userrec*>::iterator n = new_online->second.begin(); n != new_online->second.end(); n++) - { - watchlist* wl; - if ((*n)->GetExt("watchlist", wl)) - { - (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age)); - if (!user->Visibility || user->Visibility->VisibleTo(user)) - (*n)->WriteServ("600 %s %s %s :arrived online", (*n)->nick, user->nick, (*wl)[user->nick].c_str()); - } - } - } - - if (new_offline != whos_watching_me->end()) - { - for (std::deque<userrec*>::iterator n = new_offline->second.begin(); n != new_offline->second.end(); n++) - { - watchlist* wl; - if ((*n)->GetExt("watchlist", wl)) - { - if (!user->Visibility || user->Visibility->VisibleTo(user)) - (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick, oldnick.c_str(), user->ident, user->dhost, user->age); - (*wl)[oldnick.c_str()] = ""; - } - } - } - } - - virtual void On005Numeric(std::string &output) - { - // we don't really have a limit... - output = output + " WATCH=" + ConvToStr(maxwatch); - } - - virtual ~Modulewatch() - { - delete whos_watching_me; - } - - virtual Version GetVersion() - { - return Version(1,1,0,1,VF_VENDOR,API_VERSION); - } -}; - -MODULE_INIT(Modulewatch) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
/* $ModDesc: Provides support for the /WATCH command */
/* This module has been refactored to provide a very efficient (in terms of cpu time)
* implementation of /WATCH.
*
* To improve the efficiency of watch, many lists are kept. The first primary list is
* a hash_map of who's being watched by who. For example:
*
* KEY: Brain ---> Watched by: Boo, w00t, Om
* KEY: Boo ---> Watched by: Brain, w00t
*
* This is used when we want to tell all the users that are watching someone that
* they are now available or no longer available. For example, if the hash was
* populated as shown above, then when Brain signs on, messages are sent to Boo, w00t
* and Om by reading their 'watched by' list. When this occurs, their online status
* in each of these users lists (see below) is also updated.
*
* Each user also has a seperate (smaller) map attached to their userrec whilst they
* have any watch entries, which is managed by class Extensible. When they add or remove
* a watch entry from their list, it is inserted here, as well as the main list being
* maintained. This map also contains the user's online status. For users that are
* offline, the key points at an empty string, and for users that are online, the key
* points at a string containing "users-ident users-host users-signon-time". This is
* stored in this manner so that we don't have to FindUser() to fetch this info, the
* users signon can populate the field for us.
*
* For example, going again on the example above, this would be w00t's watchlist:
*
* KEY: Boo ---> Status: "Boo brains.sexy.babe 535342348"
* KEY: Brain ---> Status: ""
*
* In this list we can see that Boo is online, and Brain is offline. We can then
* use this list for 'WATCH L', and 'WATCH S' can be implemented as a combination
* of the above two data structures, with minimum CPU penalty for doing so.
*
* In short, the least efficient this ever gets is O(n), and thats only because
* there are parts that *must* loop (e.g. telling all users that are watching a
* nick that the user online), however this is a *major* improvement over the
* 1.0 implementation, which in places had O(n^n) and worse in it, because this
* implementation scales based upon the sizes of the watch entries, whereas the
* old system would scale (or not as the case may be) according to the total number
* of users using WATCH.
*/
/*
* Before you start screaming, this definition is only used here, so moving it to a header is pointless.
* Yes, it's horrid. Blame cl for being different. -- w00t
*/
#ifdef WINDOWS
typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash_compare<irc::string, less<irc::string> > > watchentries;
#else
typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash<irc::string> > watchentries;
#endif
typedef std::map<irc::string, std::string> watchlist;
/* Who's watching each nickname.
* NOTE: We do NOT iterate this to display a user's WATCH list!
* See the comments above!
*/
watchentries* whos_watching_me;
/** Handle /WATCH
*/
class cmd_watch : public command_t
{
unsigned int& MAX_WATCH;
public:
CmdResult remove_watch(userrec* user, const char* nick)
{
// removing an item from the list
if (!ServerInstance->IsNick(nick))
{
user->WriteServ("942 %s %s :Invalid nickname", user->nick, nick);
return CMD_FAILURE;
}
watchlist* wl;
if (user->GetExt("watchlist", wl))
{
/* Yup, is on my list */
watchlist::iterator n = wl->find(nick);
if (n != wl->end())
{
if (!n->second.empty())
user->WriteServ("602 %s %s %s :stopped watching", user->nick, n->first.c_str(), n->second.c_str());
else
user->WriteServ("602 %s %s * * 0 :stopped watching", user->nick, nick);
wl->erase(n);
}
if (!wl->size())
{
user->Shrink("watchlist");
delete wl;
}
watchentries::iterator x = whos_watching_me->find(nick);
if (x != whos_watching_me->end())
{
/* People are watching this user, am i one of them? */
std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
if (n != x->second.end())
/* I'm no longer watching you... */
x->second.erase(n);
if (!x->second.size())
whos_watching_me->erase(nick);
}
}
/* This might seem confusing, but we return CMD_FAILURE
* to indicate that this message shouldnt be routed across
* the network to other linked servers.
*/
return CMD_FAILURE;
}
CmdResult add_watch(userrec* user, const char* nick)
{
if (!ServerInstance->IsNick(nick))
{
user->WriteServ("942 %s %s :Invalid nickname",user->nick,nick);
return CMD_FAILURE;
}
watchlist* wl;
if (!user->GetExt("watchlist", wl))
{
wl = new watchlist();
user->Extend("watchlist", wl);
}
if (wl->size() == MAX_WATCH)
{
user->WriteServ("512 %s %s :Too many WATCH entries", user->nick, nick);
return CMD_FAILURE;
}
watchlist::iterator n = wl->find(nick);
if (n == wl->end())
{
/* Don't already have the user on my watch list, proceed */
watchentries::iterator x = whos_watching_me->find(nick);
if (x != whos_watching_me->end())
{
/* People are watching this user, add myself */
x->second.push_back(user);
}
else
{
std::deque<userrec*> newlist;
newlist.push_back(user);
(*(whos_watching_me))[nick] = newlist;
}
userrec* target = ServerInstance->FindNick(nick);
if (target)
{
if (target->Visibility && !target->Visibility->VisibleTo(user))
{
(*wl)[nick] = "";
user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);
return CMD_FAILURE;
}
(*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age));
user->WriteServ("604 %s %s %s :is online",user->nick, nick, (*wl)[nick].c_str());
}
else
{
(*wl)[nick] = "";
user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);
}
}
return CMD_FAILURE;
}
cmd_watch (InspIRCd* Instance, unsigned int &maxwatch) : command_t(Instance,"WATCH",0,0), MAX_WATCH(maxwatch)
{
this->source = "m_watch.so";
syntax = "[C|L|S]|[+|-<nick>]";
}
CmdResult Handle (const char** parameters, int pcnt, userrec *user)
{
if (!pcnt)
{
watchlist* wl;
if (user->GetExt("watchlist", wl))
{
for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
{
if (!q->second.empty())
user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());
}
}
user->WriteServ("607 %s :End of WATCH list",user->nick);
}
else if (pcnt > 0)
{
for (int x = 0; x < pcnt; x++)
{
const char *nick = parameters[x];
if (!strcasecmp(nick,"C"))
{
// watch clear
watchlist* wl;
if (user->GetExt("watchlist", wl))
{
for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)
{
watchentries::iterator x = whos_watching_me->find(i->first);
if (x != whos_watching_me->end())
{
/* People are watching this user, am i one of them? */
std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
if (n != x->second.end())
/* I'm no longer watching you... */
x->second.erase(n);
if (!x->second.size())
whos_watching_me->erase(user->nick);
}
}
delete wl;
user->Shrink("watchlist");
}
}
else if (!strcasecmp(nick,"L"))
{
watchlist* wl;
if (user->GetExt("watchlist", wl))
{
for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
{
if (!q->second.empty())
user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());
else
user->WriteServ("605 %s %s * * 0 :is offline", user->nick, q->first.c_str());
}
}
user->WriteServ("607 %s :End of WATCH list",user->nick);
}
else if (!strcasecmp(nick,"S"))
{
watchlist* wl;
int you_have = 0;
int youre_on = 0;
std::string list;
if (user->GetExt("watchlist", wl))
{
for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
list.append(q->first.c_str()).append(" ");
you_have = wl->size();
}
watchentries::iterator x = whos_watching_me->find(user->nick);
if (x != whos_watching_me->end())
youre_on = x->second.size();
user->WriteServ("603 %s :You have %d and are on %d WATCH entries", user->nick, you_have, youre_on);
user->WriteServ("606 %s :%s",user->nick, list.c_str());
user->WriteServ("607 %s :End of WATCH S",user->nick);
}
else if (nick[0] == '-')
{
nick++;
remove_watch(user, nick);
}
else if (nick[0] == '+')
{
nick++;
add_watch(user, nick);
}
}
}
/* So that spanningtree doesnt pass the WATCH commands to the network! */
return CMD_FAILURE;
}
};
class Modulewatch : public Module
{
cmd_watch* mycommand;
unsigned int maxwatch;
public:
Modulewatch(InspIRCd* Me)
: Module(Me), maxwatch(32)
{
OnRehash(NULL, "");
whos_watching_me = new watchentries();
mycommand = new cmd_watch(ServerInstance, maxwatch);
ServerInstance->AddCommand(mycommand);
}
virtual void OnRehash(userrec* user, const std::string ¶meter)
{
ConfigReader Conf(ServerInstance);
maxwatch = Conf.ReadInteger("watch", "maxentries", 0, true);
if (!maxwatch)
maxwatch = 32;
}
void Implements(char* List)
{
List[I_OnRehash] = List[I_OnGarbageCollect] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_OnPostConnect] = List[I_OnUserPostNick] = List[I_On005Numeric] = 1;
}
virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
{
watchentries::iterator x = whos_watching_me->find(user->nick);
if (x != whos_watching_me->end())
{
for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)
{
if (!user->Visibility || user->Visibility->VisibleTo(user))
(*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick ,user->nick, user->ident, user->dhost, ServerInstance->Time());
watchlist* wl;
if ((*n)->GetExt("watchlist", wl))
/* We were on somebody's notify list, set ourselves offline */
(*wl)[user->nick] = "";
}
}
/* Now im quitting, if i have a notify list, im no longer watching anyone */
watchlist* wl;
if (user->GetExt("watchlist", wl))
{
/* Iterate every user on my watch list, and take me out of the whos_watching_me map for each one we're watching */
for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)
{
watchentries::iterator x = whos_watching_me->find(i->first);
if (x != whos_watching_me->end())
{
/* People are watching this user, am i one of them? */
std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
if (n != x->second.end())
/* I'm no longer watching you... */
x->second.erase(n);
if (!x->second.size())
whos_watching_me->erase(user->nick);
}
}
/* User's quitting, we're done with this. */
delete wl;
}
}
virtual void OnGarbageCollect()
{
watchentries* old_watch = whos_watching_me;
whos_watching_me = new watchentries();
for (watchentries::const_iterator n = old_watch->begin(); n != old_watch->end(); n++)
whos_watching_me->insert(*n);
delete old_watch;
}
virtual void OnCleanup(int target_type, void* item)
{
if (target_type == TYPE_USER)
{
watchlist* wl;
userrec* user = (userrec*)item;
if (user->GetExt("watchlist", wl))
{
user->Shrink("watchlist");
delete wl;
}
}
}
virtual void OnPostConnect(userrec* user)
{
watchentries::iterator x = whos_watching_me->find(user->nick);
if (x != whos_watching_me->end())
{
for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)
{
if (!user->Visibility || user->Visibility->VisibleTo(user))
(*n)->WriteServ("600 %s %s %s %s %lu :arrived online", (*n)->nick, user->nick, user->ident, user->dhost, user->age);
watchlist* wl;
if ((*n)->GetExt("watchlist", wl))
/* We were on somebody's notify list, set ourselves online */
(*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));
}
}
}
virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
{
watchentries::iterator new_online = whos_watching_me->find(user->nick);
watchentries::iterator new_offline = whos_watching_me->find(assign(oldnick));
if (new_online != whos_watching_me->end())
{
for (std::deque<userrec*>::iterator n = new_online->second.begin(); n != new_online->second.end(); n++)
{
watchlist* wl;
if ((*n)->GetExt("watchlist", wl))
{
(*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));
if (!user->Visibility || user->Visibility->VisibleTo(user))
(*n)->WriteServ("600 %s %s %s :arrived online", (*n)->nick, user->nick, (*wl)[user->nick].c_str());
}
}
}
if (new_offline != whos_watching_me->end())
{
for (std::deque<userrec*>::iterator n = new_offline->second.begin(); n != new_offline->second.end(); n++)
{
watchlist* wl;
if ((*n)->GetExt("watchlist", wl))
{
if (!user->Visibility || user->Visibility->VisibleTo(user))
(*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick, oldnick.c_str(), user->ident, user->dhost, user->age);
(*wl)[oldnick.c_str()] = "";
}
}
}
}
virtual void On005Numeric(std::string &output)
{
// we don't really have a limit...
output = output + " WATCH=" + ConvToStr(maxwatch);
}
virtual ~Modulewatch()
{
delete whos_watching_me;
}
virtual Version GetVersion()
{
return Version(1,1,0,1,VF_VENDOR,API_VERSION);
}
};
MODULE_INIT(Modulewatch)
\ No newline at end of file diff --git a/src/modules/m_xmlsocket.cpp b/src/modules/m_xmlsocket.cpp index 7f37f66c9..12da3762e 100644 --- a/src/modules/m_xmlsocket.cpp +++ b/src/modules/m_xmlsocket.cpp @@ -1,170 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "inspircd.h" -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" - -/* $ModDesc: Provides XMLSocket support for clients */ - -class ModuleXMLSocket : public Module -{ - ConfigReader* Conf; - std::vector<int> listenports; - - public: - - ModuleXMLSocket(InspIRCd* Me) - : Module(Me) - { - OnRehash(NULL,""); - } - - virtual void OnRehash(userrec* user, const std::string ¶m) - { - - Conf = new ConfigReader(ServerInstance); - - for (unsigned int i = 0; i < listenports.size(); i++) - { - ServerInstance->Config->DelIOHook(listenports[i]); - } - - listenports.clear(); - - for (int i = 0; i < Conf->Enumerate("bind"); i++) - { - // For each <bind> tag - std::string x = Conf->ReadValue("bind", "type", i); - if (((x.empty()) || (x == "clients")) && (Conf->ReadFlag("bind", "xmlsocket", i))) - { - // Get the port we're meant to be listening on with SSL - std::string port = Conf->ReadValue("bind", "port", i); - irc::portparser portrange(port, false); - long portno = -1; - while ((portno = portrange.GetToken())) - { - try - { - if (ServerInstance->Config->AddIOHook(portno, this)) - { - listenports.push_back(portno); - for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++) - if (ServerInstance->Config->ports[i]->GetPort() == portno) - ServerInstance->Config->ports[i]->SetDescription("xml"); - } - else - { - ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d, maybe you have another similar module loaded?", portno); - } - } - catch (ModuleException &e) - { - ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another similar module loaded?", portno, e.GetReason()); - } - } - } - } - - DELETE(Conf); - } - - virtual ~ModuleXMLSocket() - { - } - - virtual void OnUnloadModule(Module* mod, const std::string &name) - { - if (mod == this) - { - for(unsigned int i = 0; i < listenports.size(); i++) - { - ServerInstance->Config->DelIOHook(listenports[i]); - for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++) - if (ServerInstance->Config->ports[j]->GetPort() == listenports[i]) - ServerInstance->Config->ports[j]->SetDescription("plaintext"); - } - } - } - - virtual Version GetVersion() - { - return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION); - } - - void Implements(char* List) - { - List[I_OnUnloadModule] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnRehash] = 1; - } - - virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) - { - userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd)); - - if (user == NULL) - return -1; - - int result = user->ReadData(buffer, count); - - if ((result == -1) && (errno == EAGAIN)) - return -1; - else if (result < 1) - return 0; - - /* XXX: The core is more than happy to split lines purely on an \n - * rather than a \r\n. This is good for us as it means that the size - * of data we are receiving is exactly the same as the size of data - * we asked for, and we dont need to re-implement our own socket - * buffering (See below) - */ - for (int n = 0; n < result; n++) - if (buffer[n] == 0) - buffer[n] = '\n'; - - readresult = result; - return result; - } - - virtual int OnRawSocketWrite(int fd, const char* buffer, int count) - { - userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd)); - - if (user == NULL) - return -1; - - /* We want to alter the buffer, so we have to make a copy */ - char * tmpbuffer = new char[count + 1]; - memcpy(tmpbuffer, buffer, count); - - /* XXX: This will actually generate lines "looking\0\0like\0\0this" - * rather than lines "looking\0like\0this". This shouldnt be a problem - * to the client, but it saves us a TON of processing and the need - * to re-implement socket buffering, as the data we are sending is - * exactly the same length as the data we are receiving. - */ - for (int n = 0; n < count; n++) - if ((tmpbuffer[n] == '\r') || (tmpbuffer[n] == '\n')) - tmpbuffer[n] = 0; - - user->AddWriteBuf(std::string(tmpbuffer,count)); - delete [] tmpbuffer; - - return 1; - } - -}; - -MODULE_INIT(ModuleXMLSocket) - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "hashcomp.h"
/* $ModDesc: Provides XMLSocket support for clients */
class ModuleXMLSocket : public Module
{
ConfigReader* Conf;
std::vector<int> listenports;
public:
ModuleXMLSocket(InspIRCd* Me)
: Module(Me)
{
OnRehash(NULL,"");
}
virtual void OnRehash(userrec* user, const std::string ¶m)
{
Conf = new ConfigReader(ServerInstance);
for (unsigned int i = 0; i < listenports.size(); i++)
{
ServerInstance->Config->DelIOHook(listenports[i]);
}
listenports.clear();
for (int i = 0; i < Conf->Enumerate("bind"); i++)
{
// For each <bind> tag
std::string x = Conf->ReadValue("bind", "type", i);
if (((x.empty()) || (x == "clients")) && (Conf->ReadFlag("bind", "xmlsocket", i)))
{
// Get the port we're meant to be listening on with SSL
std::string port = Conf->ReadValue("bind", "port", i);
irc::portparser portrange(port, false);
long portno = -1;
while ((portno = portrange.GetToken()))
{
try
{
if (ServerInstance->Config->AddIOHook(portno, this))
{
listenports.push_back(portno);
for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
if (ServerInstance->Config->ports[i]->GetPort() == portno)
ServerInstance->Config->ports[i]->SetDescription("xml");
}
else
{
ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d, maybe you have another similar module loaded?", portno);
}
}
catch (ModuleException &e)
{
ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another similar module loaded?", portno, e.GetReason());
}
}
}
}
DELETE(Conf);
}
virtual ~ModuleXMLSocket()
{
}
virtual void OnUnloadModule(Module* mod, const std::string &name)
{
if (mod == this)
{
for(unsigned int i = 0; i < listenports.size(); i++)
{
ServerInstance->Config->DelIOHook(listenports[i]);
for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])
ServerInstance->Config->ports[j]->SetDescription("plaintext");
}
}
}
virtual Version GetVersion()
{
return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
List[I_OnUnloadModule] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnRehash] = 1;
}
virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
{
userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd));
if (user == NULL)
return -1;
int result = user->ReadData(buffer, count);
if ((result == -1) && (errno == EAGAIN))
return -1;
else if (result < 1)
return 0;
/* XXX: The core is more than happy to split lines purely on an \n
* rather than a \r\n. This is good for us as it means that the size
* of data we are receiving is exactly the same as the size of data
* we asked for, and we dont need to re-implement our own socket
* buffering (See below)
*/
for (int n = 0; n < result; n++)
if (buffer[n] == 0)
buffer[n] = '\n';
readresult = result;
return result;
}
virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
{
userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd));
if (user == NULL)
return -1;
/* We want to alter the buffer, so we have to make a copy */
char * tmpbuffer = new char[count + 1];
memcpy(tmpbuffer, buffer, count);
/* XXX: This will actually generate lines "looking\0\0like\0\0this"
* rather than lines "looking\0like\0this". This shouldnt be a problem
* to the client, but it saves us a TON of processing and the need
* to re-implement socket buffering, as the data we are sending is
* exactly the same length as the data we are receiving.
*/
for (int n = 0; n < count; n++)
if ((tmpbuffer[n] == '\r') || (tmpbuffer[n] == '\n'))
tmpbuffer[n] = 0;
user->AddWriteBuf(std::string(tmpbuffer,count));
delete [] tmpbuffer;
return 1;
}
};
MODULE_INIT(ModuleXMLSocket)
\ No newline at end of file diff --git a/src/modules/transport.h b/src/modules/transport.h index ba8e3973b..d92cf0376 100644 --- a/src/modules/transport.h +++ b/src/modules/transport.h @@ -1,231 +1 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#ifndef __TRANSPORT_H__ -#define __TRANSPORT_H__ - -#include <map> -#include <string> - -/** A generic container for certificate data - */ -typedef std::map<std::string,std::string> ssl_data; - -/** A shorthand way of representing an iterator into ssl_data - */ -typedef ssl_data::iterator ssl_data_iter; - -/** ssl_cert is a class which abstracts SSL certificate - * and key information. - * - * Because gnutls and openssl represent key information in - * wildly different ways, this class allows it to be accessed - * in a unified manner. These classes are attached to ssl- - * connected local users using Extensible::Extend() and the - * key 'ssl_cert'. - */ -class ssl_cert -{ - /** Always contains an empty string - */ - const std::string empty; - - public: - /** The data for this certificate - */ - ssl_data data; - - /** Default constructor, initializes 'empty' - */ - ssl_cert() : empty("") - { - } - - /** Get certificate distinguished name - * @return Certificate DN - */ - const std::string& GetDN() - { - ssl_data_iter ssldi = data.find("dn"); - - if (ssldi != data.end()) - return ssldi->second; - else - return empty; - } - - /** Get Certificate issuer - * @return Certificate issuer - */ - const std::string& GetIssuer() - { - ssl_data_iter ssldi = data.find("issuer"); - - if (ssldi != data.end()) - return ssldi->second; - else - return empty; - } - - /** Get error string if an error has occured - * @return The error associated with this users certificate, - * or an empty string if there is no error. - */ - const std::string& GetError() - { - ssl_data_iter ssldi = data.find("error"); - - if (ssldi != data.end()) - return ssldi->second; - else - return empty; - } - - /** Get key fingerprint. - * @return The key fingerprint as a hex string. - */ - const std::string& GetFingerprint() - { - ssl_data_iter ssldi = data.find("fingerprint"); - - if (ssldi != data.end()) - return ssldi->second; - else - return empty; - } - - /** Get trust status - * @return True if this is a trusted certificate - * (the certificate chain validates) - */ - bool IsTrusted() - { - ssl_data_iter ssldi = data.find("trusted"); - - if (ssldi != data.end()) - return (ssldi->second == "1"); - else - return false; - } - - /** Get validity status - * @return True if the certificate itself is - * correctly formed. - */ - bool IsInvalid() - { - ssl_data_iter ssldi = data.find("invalid"); - - if (ssldi != data.end()) - return (ssldi->second == "1"); - else - return false; - } - - /** Get signer status - * @return True if the certificate appears to be - * self-signed. - */ - bool IsUnknownSigner() - { - ssl_data_iter ssldi = data.find("unknownsigner"); - - if (ssldi != data.end()) - return (ssldi->second == "1"); - else - return false; - } - - /** Get revokation status. - * @return True if the certificate is revoked. - * Note that this only works properly for GnuTLS - * right now. - */ - bool IsRevoked() - { - ssl_data_iter ssldi = data.find("revoked"); - - if (ssldi != data.end()) - return (ssldi->second == "1"); - else - return false; - } -}; - -/** Used to represent a request to a transport provider module - */ -class ISHRequest : public Request -{ - public: - InspSocket* Sock; - - ISHRequest(Module* Me, Module* Target, const char* rtype, InspSocket* sock) : Request(Me, Target, rtype), Sock(sock) - { - } -}; - -/** Used to represent a request to attach a cert to an InspSocket - */ -class InspSocketAttachCertRequest : public ISHRequest -{ - public: - /** Initialize the request as an attach cert message */ - InspSocketAttachCertRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_ATTACH", is) - { - } -}; - -/** Used to check if a handshake is complete on an InspSocket yet - */ -class InspSocketHSCompleteRequest : public ISHRequest -{ - public: - /** Initialize the request as a 'handshake complete?' message */ - InspSocketHSCompleteRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HSDONE", is) - { - } -}; - -/** Used to hook a transport provider to an InspSocket - */ -class InspSocketHookRequest : public ISHRequest -{ - public: - /** Initialize request as a hook message */ - InspSocketHookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HOOK", is) - { - } -}; - -/** Used to unhook a transport provider from an InspSocket - */ -class InspSocketUnhookRequest : public ISHRequest -{ - public: - /** Initialize request as an unhook message */ - InspSocketUnhookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_UNHOOK", is) - { - } -}; - -class InspSocketNameRequest : public ISHRequest -{ - public: - /** Initialize request as a get name message */ - InspSocketNameRequest(Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_NAME", NULL) - { - } -}; - -#endif - +/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2007 InspIRCd Development Team
* See: http://www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#ifndef __TRANSPORT_H__
#define __TRANSPORT_H__
#include <map>
#include <string>
/** A generic container for certificate data
*/
typedef std::map<std::string,std::string> ssl_data;
/** A shorthand way of representing an iterator into ssl_data
*/
typedef ssl_data::iterator ssl_data_iter;
/** ssl_cert is a class which abstracts SSL certificate
* and key information.
*
* Because gnutls and openssl represent key information in
* wildly different ways, this class allows it to be accessed
* in a unified manner. These classes are attached to ssl-
* connected local users using Extensible::Extend() and the
* key 'ssl_cert'.
*/
class ssl_cert
{
/** Always contains an empty string
*/
const std::string empty;
public:
/** The data for this certificate
*/
ssl_data data;
/** Default constructor, initializes 'empty'
*/
ssl_cert() : empty("")
{
}
/** Get certificate distinguished name
* @return Certificate DN
*/
const std::string& GetDN()
{
ssl_data_iter ssldi = data.find("dn");
if (ssldi != data.end())
return ssldi->second;
else
return empty;
}
/** Get Certificate issuer
* @return Certificate issuer
*/
const std::string& GetIssuer()
{
ssl_data_iter ssldi = data.find("issuer");
if (ssldi != data.end())
return ssldi->second;
else
return empty;
}
/** Get error string if an error has occured
* @return The error associated with this users certificate,
* or an empty string if there is no error.
*/
const std::string& GetError()
{
ssl_data_iter ssldi = data.find("error");
if (ssldi != data.end())
return ssldi->second;
else
return empty;
}
/** Get key fingerprint.
* @return The key fingerprint as a hex string.
*/
const std::string& GetFingerprint()
{
ssl_data_iter ssldi = data.find("fingerprint");
if (ssldi != data.end())
return ssldi->second;
else
return empty;
}
/** Get trust status
* @return True if this is a trusted certificate
* (the certificate chain validates)
*/
bool IsTrusted()
{
ssl_data_iter ssldi = data.find("trusted");
if (ssldi != data.end())
return (ssldi->second == "1");
else
return false;
}
/** Get validity status
* @return True if the certificate itself is
* correctly formed.
*/
bool IsInvalid()
{
ssl_data_iter ssldi = data.find("invalid");
if (ssldi != data.end())
return (ssldi->second == "1");
else
return false;
}
/** Get signer status
* @return True if the certificate appears to be
* self-signed.
*/
bool IsUnknownSigner()
{
ssl_data_iter ssldi = data.find("unknownsigner");
if (ssldi != data.end())
return (ssldi->second == "1");
else
return false;
}
/** Get revokation status.
* @return True if the certificate is revoked.
* Note that this only works properly for GnuTLS
* right now.
*/
bool IsRevoked()
{
ssl_data_iter ssldi = data.find("revoked");
if (ssldi != data.end())
return (ssldi->second == "1");
else
return false;
}
};
/** Used to represent a request to a transport provider module
*/
class ISHRequest : public Request
{
public:
InspSocket* Sock;
ISHRequest(Module* Me, Module* Target, const char* rtype, InspSocket* sock) : Request(Me, Target, rtype), Sock(sock)
{
}
};
/** Used to represent a request to attach a cert to an InspSocket
*/
class InspSocketAttachCertRequest : public ISHRequest
{
public:
/** Initialize the request as an attach cert message */
InspSocketAttachCertRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_ATTACH", is)
{
}
};
/** Used to check if a handshake is complete on an InspSocket yet
*/
class InspSocketHSCompleteRequest : public ISHRequest
{
public:
/** Initialize the request as a 'handshake complete?' message */
InspSocketHSCompleteRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HSDONE", is)
{
}
};
/** Used to hook a transport provider to an InspSocket
*/
class InspSocketHookRequest : public ISHRequest
{
public:
/** Initialize request as a hook message */
InspSocketHookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HOOK", is)
{
}
};
/** Used to unhook a transport provider from an InspSocket
*/
class InspSocketUnhookRequest : public ISHRequest
{
public:
/** Initialize request as an unhook message */
InspSocketUnhookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_UNHOOK", is)
{
}
};
class InspSocketNameRequest : public ISHRequest
{
public:
/** Initialize request as a get name message */
InspSocketNameRequest(Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_NAME", NULL)
{
}
};
#endif
\ No newline at end of file |