Factor out sorted list insertion into utility function
[clinton/bobotpp.git] / source / Bot.C
CommitLineData
cb21075d 1// Bot.C -*- C++ -*-
2// Copyright (c) 1997, 1998 Etienne BERNARD
a6339323 3// Copyright (C) 2002,2003,2005 Clinton Ebadi
cb21075d 4
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// any later version.
9
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
133eff7a 17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18// 02110-1301, USA.
cb21075d 19
20#include <fstream>
91dddabd 21#include <algorithm>
cb21075d 22#include <iomanip>
23#include <cstring>
24#include <cstdlib>
25#include <cstdio>
b0e3551b 26#include <dirent.h>
cb21075d 27#include <sys/time.h>
28#include <sys/types.h>
b0e3551b 29#include <sys/stat.h>
cb21075d 30#include <unistd.h>
31
32#include "Bot.H"
33#include "DCCConnection.H"
4edefeb6 34#include "DCCChatConnection.H"
cb21075d 35#include "StringTokenizer.H"
36#include "ServerConnection.H"
37#include "Utils.H"
e07b6b46 38#include "UserCommands.H"
6530edbf 39#include "DCCManager.H"
cb21075d 40
e171dcce 41
42unsigned int Bot::MAX_MESSAGES = 2;
6b7614a8 43unsigned int Bot::MAX_NICKLENGTH = 9;
e171dcce 44
cb21075d 45#define DEFAULT_NICKNAME "Bobot"
46#define DEFAULT_USERNAME "bobot"
47#define DEFAULT_IRCNAME "I'm a bobot++!"
48#define DEFAULT_COMMANDCHAR '!'
49#define DEFAULT_USERLISTFILENAME "bot.users"
50#define DEFAULT_SHITLISTFILENAME "bot.shit"
51#define DEFAULT_HELPFILENAME "bot.help"
52#define DEFAULT_SCRIPTLOGFILENAME "script.log"
53#define DEFAULT_LOGFILENAME "bot.log"
439869bf 54#define DEFAULT_LOGDIR getenv ("HOME") + String("/.bobotpp/logs/")
cb21075d 55#define DEFAULT_INITFILENAME "bot.init"
56#ifdef USESCRIPTS
57#define DEFAULT_AUTOEXECFILENAME "bot.autoexec"
58#endif
59
60Bot::Bot(String filename, bool debug_on)
61 : nickName(DEFAULT_NICKNAME),
62 wantedNickName(DEFAULT_NICKNAME),
63 userName(DEFAULT_USERNAME),
64 ircName(DEFAULT_IRCNAME),
65 versionString(VERSION_STRING),
66 userHost(""),
67 localIP(""),
68 commandChar(DEFAULT_COMMANDCHAR),
cb21075d 69 userListFileName(DEFAULT_USERLISTFILENAME),
70 shitListFileName(DEFAULT_SHITLISTFILENAME),
cb21075d 71 helpFileName(DEFAULT_HELPFILENAME),
72 initFileName(DEFAULT_INITFILENAME),
cf8ea873 73 connected(false),
74 debug(debug_on),
75 stop(false),
76 sentPing(false),
77 startTime(time(NULL)),
78 currentTime(startTime),
79 lastNickNameChange(startTime),
80 lastChannelJoin(startTime),
81 serverConnection(0),
82 sentUserhostID(0),
83 receivedUserhostID(0),
84 logFileName(DEFAULT_LOGFILENAME),
85 logs_dir (DEFAULT_LOGDIR),
4679dc8b 86 configFileName (filename)
cb21075d 87#ifdef USESCRIPTS
4679dc8b 88 ,scriptLogFileName(DEFAULT_SCRIPTLOGFILENAME),
cf8ea873 89 autoexecFileName(DEFAULT_AUTOEXECFILENAME)
cb21075d 90#endif
cb21075d 91{
cb21075d 92#ifdef HAVE_STL_CLEAR
93 wantedChannels.clear();
94 ignoredUserhosts.clear();
95 spyList.clear();
96 userhostMap.clear();
97#endif
98
e07b6b46 99 init_user_functions ();
cb21075d 100
be3612f3 101 set_log_dir (logs_dir);
102 set_log_file (logFileName);
103
104
cb21075d 105 channelList = new ChannelList();
106 serverList = new ServerList();
107 readConfig();
108 userList = new UserList(userListFileName);
109 shitList = new ShitList(shitListFileName);
110 todoList = new TodoList();
6530edbf 111 dccConnections = new DCCManager ();
cb21075d 112
113 // Let's read the alias file
114 std::ifstream initFile(initFileName);
115
0316e2c1 116 if (initFile)
117 {
118 // FIXME: these variables are current String instead of
119 // std::string because String>> reads an entire line. This code
120 // needs to be rewritten to use std::string and std::getline (or
121 // better yet, be removed entirely once BotConfig is in place)
122 String temp, alias, command;
123 int line = 0;
124
125 while (initFile >> temp, temp.length() != 0)
e07b6b46 126 {
0316e2c1 127 StringTokenizer st(temp);
128
129 line++;
130 temp = Utils::trim_str (temp);
131
132 if (temp[0]=='#')
133 {
134 continue;
135 }
136
137 if (st.count_tokens (' ') != 2)
138 {
139 std::cerr << "Error when reading alias file (" << initFileName
140 << ") line " << line << "...\n";
141 continue;
142 }
143
144 alias = Utils::to_upper (st.next_token());
145 command = Utils::to_upper (st.next_token());
146
147 // Does the function already exist ?
148 if (!userFunctions[alias])
149 {
150 if (userFunction *u = userFunctions[command])
151 userFunctions[alias] =
152 new
153 userFunction(u->function,
154 u->minLevel,
155 u->needsChannelName);
156 }
e07b6b46 157 }
cb21075d 158 }
cb21075d 159
e07b6b46 160
cb21075d 161 std::srand (std::time (0)); // srand for bot-random
0316e2c1 162
cb21075d 163#ifdef USESCRIPTS
439869bf 164 botInterp = new BotInterp(this, logs_dir + scriptLogFileName);
db098a03 165 Interp::Startup2 (this);
cb21075d 166 botInterp->LoadScript(autoexecFileName);
167#endif
168}
169
170Bot::~Bot()
171{
cb21075d 172 Person *p;
173 while (spyList.size() != 0) {
174 p = (*spyList.begin()).second;
175 spyList.erase(spyList.begin());
176 delete p;
177 }
6530edbf 178 delete dccConnections;
e07b6b46 179 destroy_user_functions ();
180
cb21075d 181 wantedChannel *w;
182 while (wantedChannels.size() != 0) {
183 w = (*wantedChannels.begin()).second;
184 wantedChannels.erase(wantedChannels.begin());
185 delete w;
186 }
187 userList->save();
188 shitList->save();
189 delete channelList;
190 delete userList;
191 delete todoList;
192 delete serverList;
193 delete shitList;
194 delete serverConnection;
195 logLine("Stopping log.");
196 logFile.close();
197}
198
199void
200Bot::logLine(String line)
201{
202 tm *d;
203 std::time_t current_time = time(0);
204
205 d = localtime(&current_time);
206 logFile << "[" << std::setfill('0') << std::setw(2)
207 << d->tm_mday << "/" << std::setfill('0') << std::setw(2)
208 << d->tm_mon + 1 << "/"
209 << d->tm_year + 1900 << " - " << std::setfill('0') << std::setw(2)
210 << d->tm_hour << ":" << std::setfill('0') << std::setw(2)
211 << d->tm_min << ":" << std::setfill('0') << std::setw(2)
212 << d->tm_sec << "] "
213 << line
214 << std::endl;
215}
216
217void
218Bot::readConfig()
219{
220 std::ifstream file(configFileName);
221 String temp;
222 int line = 1;
223
224 if (!file) {
225 logLine(String("I cannot find the file ") + configFileName);
226 return;
227 }
228
229 while (!file.eof()) {
230
231 file >> temp;
232
cf8ea873 233 if (temp.length() == 0 || temp[(unsigned int)0] == '#') {
cb21075d 234 line++;
235 continue;
236 }
237
238 StringTokenizer st(temp);
a6339323 239 String command = Utils::to_upper (Utils::trim_str (st.next_token('=')));
240 String parameters = Utils::trim_str (st.next_token('='));
cb21075d 241
242 if (command == "NICK" || command == "NICKNAME")
243 nickName = wantedNickName = parameters;
244 else if (command == "USERNAME")
245 userName = parameters;
246 else if (command == "IRCNAME" || command == "REALNAME")
247 ircName = parameters;
248 else if (command == "CMDCHAR" || command == "COMMAND")
cf8ea873 249 commandChar = parameters[(unsigned int)0];
cb21075d 250 else if (command == "USERLIST")
251 userListFileName = parameters;
252 else if (command == "SHITLIST")
253 shitListFileName = parameters;
254 else if (command == "CHANNEL") {
255 if (parameters.indexOf(':') == -1) {
256 std::cout << "Warning. The 'channel' syntax has changed."
257 << " Please see the README file for more information."
258 << " I will use compatibility mode, but you're really"
259 << " missing something.\n";
260 StringTokenizer st2(parameters);
a6339323 261 String name = Utils::to_lower (st2.next_token());
262 String key = st2.next_token();
cb21075d 263 wantedChannels[name] = new wantedChannel("", "", key);
264 } else {
265 StringTokenizer st2(parameters);
a6339323 266 String name = Utils::to_lower (st2.next_token(':'));
267 String mode = st2.next_token(':');
268 String keep = st2.next_token(':');
269 String key = st2.next_token(':');
cb21075d 270 wantedChannels[name] = new wantedChannel(mode, keep, key);
271 }
272 }
273 else if (command == "LOGFILE")
be3612f3 274 {
fd7440f1 275 if (parameters != logFileName)
be3612f3 276 {
cf8ea873 277 if (parameters[(unsigned int)0] == '/')
fd7440f1 278 {
d3f0798d 279 StringTokenizer log_st (parameters);
280 std::string log_dir = "/";
281
282 for (unsigned int m = log_st.count_tokens ('/');
283 --m;
284 m > 0)
285 {
286 log_dir += log_st.next_token ('/') + "/";
287 }
288
289 std::cerr << "==" << log_dir << std::endl;
290
291 set_log_dir (log_dir);
292 set_log_file (log_st.rest ());
fd7440f1 293 }
294 else
295 set_log_file (parameters);
be3612f3 296 }
be3612f3 297 }
cb21075d 298#ifdef USESCRIPTS
299 else if (command == "SCRIPTLOGFILE")
300 scriptLogFileName = parameters;
301 else if (command == "AUTOEXECFILE")
302 autoexecFileName = parameters;
303#endif
304 else if (command == "INITFILE")
305 initFileName = parameters;
306 else if (command == "LOCALIP")
307 localIP = parameters;
6b7614a8 308 else if (command == "MAXNICKLENGTH")
309 MAX_NICKLENGTH = std::atoi (parameters);
cb21075d 310 else if (command == "SERVER") {
311 if (parameters.indexOf(' ') == -1)
312 serverList->addServer(new Server(parameters));
313 else {
314 StringTokenizer st2(parameters);
a6339323 315 String name = st2.next_token();
316 int port = std::atoi(st2.next_token().c_str());
cb21075d 317 serverList->addServer(new Server(name,
318 port,
a6339323 319 st2.next_token()));
cb21075d 320 }
321 }
b0e3551b 322 else if (command == "")
323 {
324 // do nothing
325 }
cb21075d 326 else {
327 logLine(String("Syntax error in file ") + configFileName +
328 ", line " + String((long)line));
329 file.close();
330 std::exit(1);
331 }
332
333 line++;
334 }
335
336 file.close();
337}
338
339void
340Bot::run()
341{
342 nextServer();
343
1520dfbd 344 while (!stop)
345 {
346 waitForInput(); // This is the main event loop
347 dccConnections->checkStale ();
348
349 if (!serverConnection->queue->flush())
350 {
351 // Disconnected
352#ifdef USESCRIPTS
ae97d6ec 353 // Run hooks/disconnect
1520dfbd 354 this->botInterp->RunHooks
355 (Hook::DISCONNECT,
356 serverConnection->server->getHostName (),
357 scm_list_n
ae97d6ec 358 (Utils::str2scm (serverConnection->server->getHostName ()),
359 SCM_BOOL_F));
1520dfbd 360#endif
361 nextServer();
362 }
363 }
cb21075d 364}
365
366void
367Bot::waitForInput()
368{
369#ifdef _HPUX_SOURCE
370 int rd;
371#else
372 fd_set rd;
373#endif
374 struct timeval timer;
375
376 int sock = serverConnection->getFileDescriptor();
377 int maxSocketNumber = sock;
378
379#ifdef _HPUX_SOURCE
380 rd = sock;
381#else
382 FD_ZERO(&rd);
383 FD_SET(sock, &rd);
384#endif
385
c3ecc559 386 DCC_MAP* dccmap = &dccConnections->dcc_map;
6530edbf 387 for (DCC_MAP::iterator it = dccmap->begin ();
388 it != dccmap->end(); ++it) {
c3ecc559 389 int s = it->second->dcc->getFileDescriptor();
cb21075d 390#ifdef _HPUX_SOURCE
391 rd |= s;
392#else
393 FD_SET(s, &rd);
394#endif
395 if (s > maxSocketNumber)
396 maxSocketNumber = s;
397 }
398
399 timer.tv_sec = 1;
400 timer.tv_usec = 0;
401
402 switch (select(maxSocketNumber + 1, &rd, NULL, NULL, &timer)) {
403 case 0: /* timeout */
404 break;
405 case -1: /* error */
406 break;
407 default: /* normal */
408#ifdef _HPUX_SOURCE
409 if (rd & sock)
410#else
411 if (FD_ISSET(sock, &rd))
412#endif
413 if (serverConnection->handleInput())
414 nextServer();
415
6530edbf 416 dccConnections->checkInput (rd);
cb21075d 417 }
418
feb33b96 419 if (currentTime < std::time(0)) { // Actions that we do each second
420 currentTime = std::time(0);
cb21075d 421 for (std::map<String, unsigned int, std::less<String> >::iterator
422 it = ignoredUserhosts.begin();
423 it != ignoredUserhosts.end(); ++it)
424 if ((*it).second > 0)
425 (*it).second--;
426
427 String line;
428 while ((line = todoList->getNext()) != "") {
429 serverConnection->queue->sendChannelMode(line);
430 }
431#ifdef USESCRIPTS
432 botInterp->RunTimers(currentTime);
cb21075d 433
cb21075d 434 tm *thisTime = localtime(&currentTime);
e171dcce 435 if (thisTime->tm_sec == 0)
436 {
437 char s[6];
a756c916 438 std::snprintf(s, 6, "%02d:%02d", thisTime->tm_hour, thisTime->tm_min);
0316e2c1 439
e171dcce 440 botInterp->RunHooks(Hook::TIMER, String(s),
0316e2c1 441 scm_list_n (Utils::str2scm (std::string (s)),
442 SCM_UNDEFINED));
e171dcce 443 }
cb21075d 444#endif
445
446 }
447
448 if (currentTime >= (time_t)(lastNickNameChange + Bot::NICK_CHANGE) &&
449 nickName != wantedNickName) {
450 lastNickNameChange = currentTime;
451 serverConnection->queue->sendNick(wantedNickName);
452 }
453
454 if (currentTime >= (std::time_t)(lastChannelJoin + Bot::CHANNEL_JOIN)) {
455 lastChannelJoin = currentTime;
456 for (std::map<String, wantedChannel *, std::less<String> >::iterator it =
457 wantedChannels.begin(); it != wantedChannels.end();
458 ++it)
459 if (channelList->getChannel((*it).first) == 0)
460 serverConnection->queue->sendJoin((*it).first, (*it).second->key);
461 }
462
0316e2c1 463 if (currentTime >= (std::time_t)(serverConnection->serverLastSpoken
464 + Bot::PING_TIME) && !sentPing)
465 {
466 serverConnection->queue->sendPing("Testing connection");
467 sentPing = true;
468 }
cb21075d 469
0316e2c1 470 if (currentTime >= (std::time_t)(serverConnection->serverLastSpoken
471 + Bot::TIMEOUT))
472 {
473 sentPing = false;
474 nextServer();
475 }
cb21075d 476}
477
478// We can change server if we will not lose op on a channel
479bool
480Bot::canChangeServer()
481{
482 String channel;
483 Channel *c;
484
485 for (std::map<String, Channel *, std::less<String> >::iterator it =
486 channelList->begin();
487 it != channelList->end(); ++it) {
488 channel = (*it).first;
489 c = channelList->getChannel(channel);
490 if (c->countOp == 1 &&
491 c->count > 1 && this->iAmOp(channel))
492 return false;
493 }
494 return true;
495}
496
497void
498Bot::nextServer()
499{
500 bool cont = false;
501
502 if (channelList)
503 channelList->clear();
504
505 if (serverConnection)
506 userList->removeFirst();
507
508 delete serverConnection;
509
510 do {
511 Server * s = serverList->nextServer();
512 if (!s) {
513 std::cout << "No server found. Exiting..." << std::endl;
514 std::exit(1);
515 }
516 serverConnection = new ServerConnection(this, s, localIP);
517 if (!serverConnection->connect()) {
518 cont = true;
519 // We sleep 10 seconds, to avoid connection flood
520 sleep(10);
521 delete serverConnection;
522 } else {
523 cont = false;
524 }
525 } while (cont);
526}
527
528void
529Bot::reconnect()
530{
531 if (channelList)
532 channelList->clear();
533
534 userList->removeFirst();
535
536 delete serverConnection;
537
538 serverConnection =
539 new ServerConnection(this, serverList->currentServer(), localIP);
540
541 serverConnection->connect();
542}
543
544void
545Bot::connect(int serverNumber)
546{
547 if (channelList)
548 channelList->clear();
549
550 userList->removeFirst();
551
552 delete serverConnection;
553
554 serverConnection =
555 new ServerConnection(this, serverList->get(serverNumber), localIP);
556
557 serverConnection->connect();
558}
559
560void
4edefeb6 561Bot::addDCC(Person * from, unsigned long address, int port, int type)
cb21075d 562{
4edefeb6 563 DCCConnection *d = 0;
564
565 if (type == CHAT)
0316e2c1 566 {
567 d = new DCCChatConnection(this, from->getAddress (),
568 address, port);
569 }
4edefeb6 570 else
0316e2c1 571 {
572 return;
573 }
cb21075d 574
575 if (!d->connect())
fd7440f1 576 {
577 logLine ("DCC Connection failed from " + from->getAddress ());
578 return;
579 }
0316e2c1 580
fed59248 581 logLine ("DCC CHAT accepted from" + from->getAddress ());
6530edbf 582 dccConnections->addConnection (d);
cb21075d 583}
584
585void
586Bot::rehash()
587{
fed59248 588 for (std::map<String, Channel *, std::less<String> >::iterator it =
589 channelList->begin();
cb21075d 590 it != channelList->end(); ++it)
591 serverConnection->queue->sendWho((*it).first);
592}
593
594String
595Bot::getUserhost(String channel, String nick)
596{
597 Channel *c;
598
599 if (channel == "")
600 c = 0;
601 else
602 c = channelList->getChannel(channel);
603
604 nick = nick.toLower();
605
606
607 if (c && c->hasNick(nick))
608 return c->getUser(nick)->userhost;
609
610 unsigned long num = sentUserhostID++;
611
612 serverConnection->queue->sendUserhost(nick);
613 userhostMap[num] = "+";
614
615 while (userhostMap[num] == "+") {
616 waitForInput();
617 serverConnection->queue->flush();
618 }
619
620 // We have got our answer
621 String res = userhostMap[num];
622 userhostMap.erase(num);
623
624 return res;
625}
626
627bool
628Bot::iAmOp(String channel)
629{
630 User * me = channelList->getChannel(channel)->getUser(nickName);
631 return (me->mode & User::OP_MODE);
632}
e07b6b46 633
634void
635Bot::init_user_functions ()
636{
637 // User Functions
638#define uf(f, l, b) new userFunction (f, l, b);
639 userFunctions["ACTION"] = uf (UserCommands::Action, User::USER, true);
640 userFunctions["ADDUSER"] = uf (UserCommands::AddUser, User::FRIEND, false);
641 userFunctions["ADDSERVER"] = uf (UserCommands::AddServer, User::FRIEND,
642 false);
643 userFunctions["ADDSHIT"] = uf (UserCommands::AddShit, User::FRIEND, false);
644 userFunctions["ALIAS"] = uf (UserCommands::Alias, User::MASTER, false);
645 userFunctions["BAN"] = uf (UserCommands::Ban, User::USER, true);
646 userFunctions["BANLIST"] = uf (UserCommands::BanList, User::USER, true);
647 userFunctions["CHANNELS"] =
648 uf (UserCommands::Channels, User::FRIEND, false);
649 userFunctions["CYCLE"] = uf (UserCommands::Cycle, User::FRIEND, true);
650 userFunctions["DCCLIST"] = uf (UserCommands::DCCList, User::FRIEND, false);
651 userFunctions["DEBAN"] = uf (UserCommands::Deban, User::USER, true);
652 userFunctions["DELSERVER"] = uf (UserCommands::DelServer, User::FRIEND,
653 false);
654 userFunctions["DELUSER"] = uf (UserCommands::DelUser, User::FRIEND, false);
655 userFunctions["DELSHIT"] = uf (UserCommands::DelShit, User::FRIEND, false);
656 userFunctions["DEOP"] = uf (UserCommands::Deop, User::TRUSTED_USER, true);
657 userFunctions["DIE"] = uf (UserCommands::Die, User::MASTER, false);
658 userFunctions["DO"] = uf (UserCommands::Do, User::MASTER, false);
659#ifdef USESCRIPTS
660 userFunctions["EXECUTE"] = uf (UserCommands::Execute, User::MASTER, false);
661#endif
662 userFunctions["HELP"] = uf (UserCommands::Help, User::NONE, false);
663 userFunctions["IDENT"] = uf (UserCommands::Ident, User::NONE, true);
664 userFunctions["INVITE"] = uf (UserCommands::Invite, User::USER, true);
665 userFunctions["JOIN"] = uf (UserCommands::Join, User::FRIEND, false);
666 userFunctions["KEEP"] = uf (UserCommands::Keep, User::FRIEND, true);
667 userFunctions["KICK"] = uf (UserCommands::Kick, User::USER, true);
668 userFunctions["KICKBAN"] = uf (UserCommands::KickBan, User::USER, true);
669 userFunctions["LOAD"] = uf (UserCommands::Load, User::FRIEND, false);
670#ifdef USESCRIPTS
671 userFunctions["LOADSCRIPT"] = uf (UserCommands::LoadScript, User::MASTER,
672 false);
673#endif
674 userFunctions["LOCK"] = uf (UserCommands::Lock, User::FRIEND, true);
675 userFunctions["MODE"] = uf (UserCommands::Mode, User::FRIEND, true);
676 userFunctions["MSG"] = uf (UserCommands::Msg, User::USER, false);
677 userFunctions["NAMES"] = uf (UserCommands::Names, User::USER, true);
678 userFunctions["NEXTSERVER"] = uf (UserCommands::NextServer, User::FRIEND,
679 false);
680 userFunctions["NICK"] = uf (UserCommands::Nick, User::FRIEND, false);
681 userFunctions["NSLOOKUP"] = uf (UserCommands::NsLookup, User::USER, false);
682 userFunctions["OP"] = uf (UserCommands::Op, User::TRUSTED_USER, true);
683 userFunctions["PART"] = uf (UserCommands::Part, User::FRIEND, true);
684 userFunctions["PASSWORD"] = uf (UserCommands::Password, User::USER, true);
685 userFunctions["RECONNECT"] =
686 uf (UserCommands::Reconnect, User::FRIEND, false);
687 userFunctions["RSPYMESSAGE"] =
688 uf (UserCommands::RSpyMessage, User::USER, false);
689 userFunctions["SAVE"] = uf (UserCommands::Save, User::FRIEND, false);
690 userFunctions["SAY"] = uf (UserCommands::Say, User::USER, true);
691 userFunctions["SERVER"] = uf (UserCommands::Server, User::FRIEND, false);
692 userFunctions["SERVERLIST"] =
693 uf (UserCommands::ServerList, User::FRIEND, false);
e171dcce 694 userFunctions["SETFLOODRATE"] =
695 uf (UserCommands::SetFloodRate, User::MASTER, false);
e07b6b46 696 userFunctions["SETVERSION"] =
697 uf (UserCommands::SetVersion, User::MASTER, false);
698 userFunctions["SHITLIST"] =
699 uf (UserCommands::ShitList, User::FRIEND, false);
700 userFunctions["SPYLIST"] = uf (UserCommands::SpyList, User::USER, false);
701 userFunctions["SPYMESSAGE"] =
702 uf (UserCommands::SpyMessage, User::USER, false);
703 userFunctions["STATS"] = uf (UserCommands::Stats, User::FRIEND, true);
704 userFunctions["TBAN"] = uf (UserCommands::TBan, User::USER, true);
705 userFunctions["TKBAN"] = uf (UserCommands::TKBan, User::USER, true);
706 userFunctions["TOPIC"] = uf (UserCommands::Topic, User::USER, true);
707 userFunctions["UNLOCK"] = uf (UserCommands::Unlock, User::FRIEND, true);
708 userFunctions["USERLIST"] =
709 uf (UserCommands::UserList, User::FRIEND, false);
710 userFunctions["WHO"] = uf (UserCommands::Who, User::NONE, true);
711 userFunctions["WHOIS"] = uf (UserCommands::Whois, User::FRIEND, true);
712#undef uf
713}
714
715namespace
716{
717 void erase_userf (std::pair<std::string, class userFunction*> it)
718 {
719 delete it.second;
720 }
721}
722
723void
724Bot::destroy_user_functions ()
725{
91dddabd 726 std::for_each (userFunctions.begin (),
e07b6b46 727 userFunctions.end (),
728 erase_userf);
729 userFunctions.erase (userFunctions.begin (),
730 userFunctions.end ());
731}
be3612f3 732
733void
734Bot::set_log_file (String name)
735{
736 logFileName = name;
fd7440f1 737 logFile.close ();
738 logFile.clear ();
be3612f3 739#if HAVE_IOSBASE
740 logFile.open(logs_dir + logFileName, std::ios_base::out |
741 std::ios_base::ate | std::ios_base::app);
742#else
743 logFile.open(logs_dir + logFileName, ios::out | ios::ate
744 | ios::app);
745#endif
746
747 logLine("Starting log.");
748}
749
750void
751Bot::set_log_dir (String dir)
752{
753 logs_dir = dir;
b0e3551b 754
755 DIR *temp = opendir (logs_dir);
756
757 if (!temp)
758 {
759 mkdir (logs_dir, S_IRWXU);
760 }
761 else
762 {
763 closedir (temp);
764 }
be3612f3 765}