X-Git-Url: https://git.hcoop.net/clinton/bobotpp.git/blobdiff_plain/91dddabdc921689e3da24b73497f9613bb03a1de..6b7614a8f1ae00cb470a620af4e0b6ffbbaa1951:/source/Bot.C diff --git a/source/Bot.C b/source/Bot.C index 0a9f3b4..af8cb31 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,7 +14,7 @@ // 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 @@ -28,10 +28,16 @@ #include "Bot.H" #include "DCCConnection.H" +#include "DCCChatConnection.H" #include "StringTokenizer.H" #include "ServerConnection.H" #include "Utils.H" #include "UserCommands.H" +#include "DCCManager.H" + + +unsigned int Bot::MAX_MESSAGES = 2; +unsigned int Bot::MAX_NICKLENGTH = 9; #define DEFAULT_NICKNAME "Bobot" #define DEFAULT_USERNAME "bobot" @@ -57,22 +63,28 @@ 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), #ifdef USESCRIPTS scriptLogFileName(DEFAULT_SCRIPTLOGFILENAME), - autoexecFileName(DEFAULT_AUTOEXECFILENAME), + 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,41 +105,58 @@ Bot::Bot(String filename, bool debug_on) userList = new UserList(userListFileName); shitList = new ShitList(shitListFileName); todoList = new TodoList(); + dccConnections = new DCCManager (); // Let's read the alias file std::ifstream initFile(initFileName); - 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(); + 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; - // Does the function already exist ? - if (!userFunctions[alias]) + 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); botInterp->LoadScript(autoexecFileName); @@ -136,21 +165,13 @@ Bot::Bot(String filename, bool debug_on) Bot::~Bot() { - // TODO: is it ok to delete iterators!?! - Person *p; while (spyList.size() != 0) { p = (*spyList.begin()).second; spyList.erase(spyList.begin()); delete p; } - DCCConnection *d; - while (dccConnections.size() != 0) { - d = *dccConnections.begin(); - dccConnections.erase(dccConnections.begin()); - delete d; - } - + delete dccConnections; destroy_user_functions (); wantedChannel *w; @@ -205,14 +226,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; @@ -221,7 +242,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") @@ -233,27 +254,30 @@ 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); } } else if (command == "LOGFILE") { - if (parameters[0] == '/') + if (parameters != logFileName) { - set_log_dir ("/"); - set_log_file (parameters.subString (1)); + if (parameters[(unsigned int)0] == '/') + { + set_log_dir ("/"); + set_log_file (parameters.subString (1)); + } + else + set_log_file (parameters); } - else - set_log_file (parameters); } #ifdef USESCRIPTS else if (command == "SCRIPTLOGFILE") @@ -265,16 +289,18 @@ Bot::readConfig() initFileName = parameters; else if (command == "LOCALIP") localIP = parameters; + else if (command == "MAXNICKLENGTH") + MAX_NICKLENGTH = std::atoi (parameters); 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 { @@ -295,11 +321,25 @@ Bot::run() { nextServer(); - while (!stop) { - waitForInput(); // This is the main event loop - 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/disconnected + this->botInterp->RunHooks + (Hook::DISCONNECT, + serverConnection->server->getHostName (), + scm_list_n + (Utils::str2scm (serverConnection->server->getHostName ()))); +#endif + nextServer(); + } + } } void @@ -322,9 +362,10 @@ Bot::waitForInput() FD_SET(sock, &rd); #endif - for (std::list::iterator it = dccConnections.begin(); - it != dccConnections.end(); ++it) { - int s = (*it)->getFileDescriptor(); + DCC_MAP* dccmap = &dccConnections->dcc_map; + for (DCC_MAP::iterator it = dccmap->begin (); + it != dccmap->end(); ++it) { + int s = it->second->dcc->getFileDescriptor(); #ifdef _HPUX_SOURCE rd |= s; #else @@ -351,27 +392,11 @@ 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) @@ -384,16 +409,17 @@ Bot::waitForInput() } #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 } @@ -413,27 +439,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 @@ -519,21 +537,35 @@ 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()) - return; + { + logLine ("DCC Connection failed from " + from->getAddress ()); + return; + } - dccConnections.push_back(d); + logLine ("DCC CHAT accepted from" + from->getAddress ()); + dccConnections->addConnection (d); } void Bot::rehash() { - for (std::map >::iterator it = channelList->begin(); + for (std::map >::iterator it = + channelList->begin(); it != channelList->end(); ++it) serverConnection->queue->sendWho((*it).first); } @@ -638,6 +670,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"] = @@ -679,6 +713,8 @@ void Bot::set_log_file (String name) { logFileName = name; + logFile.close (); + logFile.clear (); #if HAVE_IOSBASE logFile.open(logs_dir + logFileName, std::ios_base::out | std::ios_base::ate | std::ios_base::app);