X-Git-Url: https://git.hcoop.net/clinton/bobotpp.git/blobdiff_plain/6530edbf15c57acffc224cdc864f0dd611d0fa3f..17f13c7ac1b386279a5da43c0fef7c2dbc11ce8a:/source/Bot.C diff --git a/source/Bot.C b/source/Bot.C index 45e5c6e..868fbee 100644 --- a/source/Bot.C +++ b/source/Bot.C @@ -1,6 +1,6 @@ // Bot.C -*- C++ -*- // Copyright (c) 1997, 1998 Etienne BERNARD -// Copyright (C) 2002 Clinton Ebadi +// Copyright (C) 2002,2003,2005 Clinton Ebadi // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -14,25 +14,55 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. -#include -#include -#include #include #include #include + +#include +#include +#include + +#include #include #include +#include #include +#ifdef USESCRIPTS +#include +#endif + #include "Bot.H" #include "DCCConnection.H" -#include "StringTokenizer.H" +#include "DCCChatConnection.H" +#include "ChannelList.H" +#include "DCCManager.H" +#include "DCCPerson.H" +#include "Parser.H" +#include "Person.H" +#include "Server.H" #include "ServerConnection.H" -#include "Utils.H" +#include "ServerList.H" +#include "ShitList.H" +#include "StringTokenizer.H" +#include "User.H" #include "UserCommands.H" -#include "DCCManager.H" +#include "UserList.H" +#include "Utils.H" + + +#ifdef USESCRIPTS +#include "BotInterp.H" +#include "Interp.H" +#endif + +unsigned int Bot::MAX_MESSAGES = 2; +unsigned int Bot::MAX_NICKLENGTH = 9; + +const std::string Bot::release_revision = VERSION; #define DEFAULT_NICKNAME "Bobot" #define DEFAULT_USERNAME "bobot" @@ -58,22 +88,29 @@ Bot::Bot(String filename, bool debug_on) userHost(""), localIP(""), commandChar(DEFAULT_COMMANDCHAR), - configFileName(filename), userListFileName(DEFAULT_USERLISTFILENAME), shitListFileName(DEFAULT_SHITLISTFILENAME), - logFileName(DEFAULT_LOGFILENAME), - logs_dir (DEFAULT_LOGDIR), helpFileName(DEFAULT_HELPFILENAME), initFileName(DEFAULT_INITFILENAME), + connected(false), + debug(debug_on), + stop(false), + sentPing(false), + startTime(time(NULL)), + currentTime(startTime), + lastNickNameChange(startTime), + lastChannelJoin(startTime), + serverConnection(0), + sentUserhostID(0), + receivedUserhostID(0), + logFileName(DEFAULT_LOGFILENAME), + logs_dir (DEFAULT_LOGDIR), + configFileName (filename), + version_mutex(true) #ifdef USESCRIPTS - scriptLogFileName(DEFAULT_SCRIPTLOGFILENAME), - autoexecFileName(DEFAULT_AUTOEXECFILENAME), + ,scriptLogFileName(DEFAULT_SCRIPTLOGFILENAME), + autoexecFileName(DEFAULT_AUTOEXECFILENAME) #endif - connected(false), - debug(debug_on), stop(false), sentPing(false), - startTime(time(NULL)), currentTime(startTime), - lastNickNameChange(startTime), lastChannelJoin(startTime), - serverConnection(0), sentUserhostID(0), receivedUserhostID(0) { #ifdef HAVE_STL_CLEAR wantedChannels.clear(); @@ -93,45 +130,61 @@ Bot::Bot(String filename, bool debug_on) readConfig(); userList = new UserList(userListFileName); shitList = new ShitList(shitListFileName); - todoList = new TodoList(); dccConnections = new DCCManager (); // Let's read the alias file - std::ifstream initFile(initFileName); + std::ifstream initFile(initFileName.c_str ()); - if (initFile) { - String temp, alias, command; - int line = 0; - while (initFile >> temp, temp.length() != 0) { - line++; - StringTokenizer st(temp); - temp = temp.trim(); - if (temp[0]=='#') continue; - if (st.countTokens(' ') != 2) { - std::cerr << "Error when reading alias file (" << initFileName - << ") line " << line << "...\n"; - continue; - } - alias = st.nextToken().toUpper(); - command = st.nextToken().toUpper(); - - // Does the function already exist ? - if (!userFunctions[alias]) + if (initFile) + { + // FIXME: these variables are current String instead of + // std::string because String>> reads an entire line. This code + // needs to be rewritten to use std::string and std::getline (or + // better yet, be removed entirely once BotConfig is in place) + String temp, alias, command; + int line = 0; + + while (initFile >> temp, temp.length() != 0) { - if (userFunction *u = userFunctions[command]) - userFunctions[alias] = - new - userFunction(u->function, - u->minLevel, - u->needsChannelName); + StringTokenizer st(temp); + + line++; + temp = Utils::trim_str (temp); + + if (temp[0]=='#') + { + continue; + } + + if (st.count_tokens (' ') != 2) + { + std::cerr << "Error when reading alias file (" << initFileName + << ") line " << line << "...\n"; + continue; + } + + alias = Utils::to_upper (st.next_token()); + command = Utils::to_upper (st.next_token()); + + // Does the function already exist ? + if (!userFunctions[alias]) + { + if (userFunction *u = userFunctions[command]) + userFunctions[alias] = + new + userFunction(u->function, + u->minLevel, + u->needsChannelName); + } } } - } std::srand (std::time (0)); // srand for bot-random + #ifdef USESCRIPTS botInterp = new BotInterp(this, logs_dir + scriptLogFileName); + Interp::Startup2 (this); botInterp->LoadScript(autoexecFileName); #endif } @@ -157,7 +210,6 @@ Bot::~Bot() shitList->save(); delete channelList; delete userList; - delete todoList; delete serverList; delete shitList; delete serverConnection; @@ -186,7 +238,7 @@ Bot::logLine(String line) void Bot::readConfig() { - std::ifstream file(configFileName); + std::ifstream file(configFileName.c_str ()); String temp; int line = 1; @@ -199,14 +251,14 @@ Bot::readConfig() file >> temp; - if (temp.length() == 0 || temp[0] == '#') { + if (temp.length() == 0 || temp[(unsigned int)0] == '#') { line++; continue; } StringTokenizer st(temp); - String command = st.nextToken('=').trim().toUpper(); - String parameters = st.nextToken('=').trim(); + String command = Utils::to_upper (Utils::trim_str (st.next_token('='))); + String parameters = Utils::trim_str (st.next_token('=')); if (command == "NICK" || command == "NICKNAME") nickName = wantedNickName = parameters; @@ -215,7 +267,7 @@ Bot::readConfig() else if (command == "IRCNAME" || command == "REALNAME") ircName = parameters; else if (command == "CMDCHAR" || command == "COMMAND") - commandChar = parameters[0]; + commandChar = parameters[(unsigned int)0]; else if (command == "USERLIST") userListFileName = parameters; else if (command == "SHITLIST") @@ -227,15 +279,15 @@ Bot::readConfig() << " I will use compatibility mode, but you're really" << " missing something.\n"; StringTokenizer st2(parameters); - String name = st2.nextToken().toLower(); - String key = st2.nextToken(); + String name = Utils::to_lower (st2.next_token()); + String key = st2.next_token(); wantedChannels[name] = new wantedChannel("", "", key); } else { StringTokenizer st2(parameters); - String name = st2.nextToken(':').toLower(); - String mode = st2.nextToken(':'); - String keep = st2.nextToken(':'); - String key = st2.nextToken(':'); + String name = Utils::to_lower (st2.next_token(':')); + String mode = st2.next_token(':'); + String keep = st2.next_token(':'); + String key = st2.next_token(':'); wantedChannels[name] = new wantedChannel(mode, keep, key); } } @@ -243,10 +295,22 @@ Bot::readConfig() { if (parameters != logFileName) { - if (parameters[0] == '/') + if (parameters[(unsigned int)0] == '/') { - set_log_dir ("/"); - set_log_file (parameters.subString (1)); + StringTokenizer log_st (parameters); + std::string log_dir = "/"; + + for (unsigned int m = log_st.count_tokens ('/'); + --m; + m > 0) + { + log_dir += log_st.next_token ('/') + "/"; + } + + std::cerr << "==" << log_dir << std::endl; + + set_log_dir (log_dir); + set_log_file (log_st.rest ()); } else set_log_file (parameters); @@ -262,18 +326,24 @@ Bot::readConfig() initFileName = parameters; else if (command == "LOCALIP") localIP = parameters; + else if (command == "MAXNICKLENGTH") + MAX_NICKLENGTH = std::atoi (parameters.c_str ()); else if (command == "SERVER") { if (parameters.indexOf(' ') == -1) serverList->addServer(new Server(parameters)); else { StringTokenizer st2(parameters); - String name = st2.nextToken(); - int port = std::atoi(st2.nextToken()); + String name = st2.next_token(); + int port = std::atoi(st2.next_token().c_str()); serverList->addServer(new Server(name, port, - st2.nextToken())); + st2.next_token())); } } + else if (command == "") + { + // do nothing + } else { logLine(String("Syntax error in file ") + configFileName + ", line " + String((long)line)); @@ -292,12 +362,26 @@ Bot::run() { nextServer(); - while (!stop) { - waitForInput(); // This is the main event loop - dccConnections->checkStale (); - if (!serverConnection->queue->flush()) - nextServer(); - } + while (!stop) + { + waitForInput(); // This is the main event loop + dccConnections->checkStale (); + + if (!serverConnection->queue->flush()) + { + // Disconnected +#ifdef USESCRIPTS + // Run hooks/disconnect + this->botInterp->RunHooks + (Hook::DISCONNECT, + serverConnection->server->getHostName (), + scm_list_n + (Utils::str2scm (serverConnection->server->getHostName ()), + SCM_BOOL_F)); +#endif + nextServer(); + } + } } void @@ -320,10 +404,10 @@ Bot::waitForInput() FD_SET(sock, &rd); #endif - DCC_MAP* dccmap = dccConnections->MAP (); + DCC_MAP* dccmap = &dccConnections->dcc_map; for (DCC_MAP::iterator it = dccmap->begin (); it != dccmap->end(); ++it) { - int s = it->second->DCC()->getFileDescriptor(); + int s = it->second->dcc->getFileDescriptor(); #ifdef _HPUX_SOURCE rd |= s; #else @@ -350,51 +434,36 @@ Bot::waitForInput() if (serverConnection->handleInput()) nextServer(); -// std::list::iterator it = dccConnections.begin(); -// std::list::iterator it2; - -// while (it != dccConnections.end()) { -// it2 = it; -// ++it; -// #ifdef _HPUX_SOURCE -// if (rd & (*it2)->getFileDescriptor()) { -// #else -// if (FD_ISSET((*it2)->getFileDescriptor(), &rd)) { -// #endif -// if ((*it2)->handleInput()) { -// delete *it2; -// dccConnections.erase(it2); -// } -// } -// } -// } dccConnections->checkInput (rd); } - if (currentTime < std::time(NULL)) { // Actions that we do each second - currentTime = std::time(NULL); + if (currentTime < std::time(0)) { // Actions that we do each second + currentTime = std::time(0); for (std::map >::iterator it = ignoredUserhosts.begin(); it != ignoredUserhosts.end(); ++it) if ((*it).second > 0) (*it).second--; - String line; - while ((line = todoList->getNext()) != "") { - serverConnection->queue->sendChannelMode(line); - } + for (std::map >::iterator it = channelList->begin (); + it != channelList->end (); + ++it) + { + it->second->purge_expired_bans (); + } #ifdef USESCRIPTS botInterp->RunTimers(currentTime); -#endif -#ifdef USESCRIPTS tm *thisTime = localtime(¤tTime); - if (thisTime->tm_sec == 0) { - char s[6]; - sprintf(s, "%2d:%2d", thisTime->tm_hour, thisTime->tm_min); - botInterp->RunHooks(Hook::TIMER, String(s), - gh_list(Utils::string2SCM(String(s)), SCM_UNDEFINED)); - } + if (thisTime->tm_sec == 0) + { + char s[6]; + std::snprintf(s, 6, "%02d:%02d", thisTime->tm_hour, thisTime->tm_min); + + botInterp->RunHooks(Hook::TIMER, String(s), + scm_list_n (Utils::str2scm (std::string (s)), + SCM_UNDEFINED)); + } #endif } @@ -414,27 +483,19 @@ Bot::waitForInput() serverConnection->queue->sendJoin((*it).first, (*it).second->key); } -// std::list::iterator it2; - -// for (std::list::iterator it = dccConnections.begin(); -// it != dccConnections.end(); ) { -// it2 = it; -// ++it; -// if ((*it2)->autoRemove && currentTime >= (std::time_t)((*it2)->lastSpoken + Bot::DCC_DELAY)) { -// delete *it2; -// dccConnections.erase(it2); -// } -// } - - if (currentTime >= (std::time_t)(serverConnection->serverLastSpoken + Bot::PING_TIME) && !sentPing) { - serverConnection->queue->sendPing("Testing connection"); - sentPing = true; - } + if (currentTime >= (std::time_t)(serverConnection->serverLastSpoken + + Bot::PING_TIME) && !sentPing) + { + serverConnection->queue->sendPing("Testing connection"); + sentPing = true; + } - if (currentTime >= (std::time_t)(serverConnection->serverLastSpoken + Bot::TIMEOUT)) { - sentPing = false; - nextServer(); - } + if (currentTime >= (std::time_t)(serverConnection->serverLastSpoken + + Bot::TIMEOUT)) + { + sentPing = false; + nextServer(); + } } // We can change server if we will not lose op on a channel @@ -449,8 +510,8 @@ Bot::canChangeServer() it != channelList->end(); ++it) { channel = (*it).first; c = channelList->getChannel(channel); - if (c->countOp == 1 && - c->count > 1 && this->iAmOp(channel)) + if (c->operator_count () == 1 && + c->user_count () > 1 && this->iAmOp(channel)) return false; } return true; @@ -520,16 +581,26 @@ Bot::connect(int serverNumber) } void -Bot::addDCC(Person * from, unsigned long address, int port) +Bot::addDCC(Person * from, unsigned long address, int port, int type) { - DCCConnection * d = new DCCConnection(this, from->getAddress (), - address, port); + DCCConnection *d = 0; + + if (type == CHAT) + { + d = new DCCChatConnection(this, from->getAddress (), + address, port); + } + else + { + return; + } if (!d->connect()) { logLine ("DCC Connection failed from " + from->getAddress ()); return; } + logLine ("DCC CHAT accepted from" + from->getAddress ()); dccConnections->addConnection (d); } @@ -557,7 +628,7 @@ Bot::getUserhost(String channel, String nick) if (c && c->hasNick(nick)) - return c->getUser(nick)->userhost; + return c->getUser(nick).userhost; unsigned long num = sentUserhostID++; @@ -579,8 +650,7 @@ Bot::getUserhost(String channel, String nick) bool Bot::iAmOp(String channel) { - User * me = channelList->getChannel(channel)->getUser(nickName); - return (me->mode & User::OP_MODE); + return channelList->getChannel(channel)->getUser(nickName).mode & User::OP_MODE; } void @@ -643,6 +713,8 @@ Bot::init_user_functions () userFunctions["SERVER"] = uf (UserCommands::Server, User::FRIEND, false); userFunctions["SERVERLIST"] = uf (UserCommands::ServerList, User::FRIEND, false); + userFunctions["SETFLOODRATE"] = + uf (UserCommands::SetFloodRate, User::MASTER, false); userFunctions["SETVERSION"] = uf (UserCommands::SetVersion, User::MASTER, false); userFunctions["SHITLIST"] = @@ -687,10 +759,10 @@ Bot::set_log_file (String name) logFile.close (); logFile.clear (); #if HAVE_IOSBASE - logFile.open(logs_dir + logFileName, std::ios_base::out | + logFile.open((logs_dir + logFileName).c_str (), std::ios_base::out | std::ios_base::ate | std::ios_base::app); #else - logFile.open(logs_dir + logFileName, ios::out | ios::ate + logFile.open((logs_dir + logFileName).c_str (), ios::out | ios::ate | ios::app); #endif @@ -701,4 +773,31 @@ void Bot::set_log_dir (String dir) { logs_dir = dir; + + DIR *temp = opendir (logs_dir.c_str ()); + + if (!temp) + { + mkdir (logs_dir.c_str (), S_IRWXU); + } + else + { + closedir (temp); + } +} + +void +Bot::set_version (String new_version) +{ + BotLock setter_lock (version_mutex); + + versionString = new_version; +} + +String +Bot::get_version () const +{ + BotLock getter_lock (version_mutex); + + return versionString; }