[[project @ 2002-07-07 02:33:51 by unknown_lamer]
unknown_lamer**20020707023351
Initial import into CVS
] {
adddir ./doc
addfile ./doc/index.html
adddir ./scripts
addfile ./scripts/bobot-utils.scm
addfile ./scripts/boulet
addfile ./scripts/country
addfile ./scripts/eval
addfile ./scripts/hello
addfile ./scripts/scheme_add_user
addfile ./scripts/scripts.load
addfile ./scripts/tamere
addfile ./scripts/uname
addfile ./scripts/uptime
adddir ./scripts/stupid_stuff
addfile ./scripts/stupid_stuff/insert_saying.scm
addfile ./scripts/stupid_stuff/sayings
addfile ./scripts/stupid_stuff/sayings.sh
addfile ./scripts/stupid_stuff/stupid_stuff
adddir ./source
addfile ./source/BanEntry.C
addfile ./source/BanEntry.H
addfile ./source/Bot.C
addfile ./source/Bot.H
addfile ./source/BotInterp.C
addfile ./source/BotInterp.H
addfile ./source/Channel.C
addfile ./source/Channel.H
addfile ./source/ChannelList.C
addfile ./source/ChannelList.H
addfile ./source/Commands.C
addfile ./source/Commands.H
addfile ./source/Connection.C
addfile ./source/Connection.H
addfile ./source/DCCConnection.C
addfile ./source/DCCConnection.H
addfile ./source/DCCParser.C
addfile ./source/DCCParser.H
addfile ./source/DCCPerson.C
addfile ./source/DCCPerson.H
addfile ./source/Interp.C
addfile ./source/Interp.H
addfile ./source/Macros.H
addfile ./source/Main.C
addfile ./source/Makefile.am
addfile ./source/Makefile.in
addfile ./source/Mask.C
addfile ./source/Mask.H
addfile ./source/Message.H
addfile ./source/Parser.C
addfile ./source/Parser.H
addfile ./source/Person.C
addfile ./source/Person.H
addfile ./source/Queue.C
addfile ./source/Queue.H
addfile ./source/ScriptCommands.C
addfile ./source/ScriptCommands.H
addfile ./source/Server.C
addfile ./source/Server.H
addfile ./source/ServerConnection.C
addfile ./source/ServerConnection.H
addfile ./source/ServerList.C
addfile ./source/ServerList.H
addfile ./source/ServerQueue.C
addfile ./source/ServerQueue.H
addfile ./source/ServerQueueItem.C
addfile ./source/ServerQueueItem.H
addfile ./source/ShitEntry.C
addfile ./source/ShitEntry.H
addfile ./source/ShitList.C
addfile ./source/ShitList.H
addfile ./source/Socket.C
addfile ./source/Socket.H
addfile ./source/String.C
addfile ./source/String.H
addfile ./source/StringTokenizer.C
addfile ./source/StringTokenizer.H
addfile ./source/TodoList.C
addfile ./source/TodoList.H
addfile ./source/User.C
addfile ./source/User.H
addfile ./source/UserCommands.C
addfile ./source/UserCommands.H
addfile ./source/UserList.C
addfile ./source/UserList.H
addfile ./source/UserListItem.H
addfile ./source/Utils.C
addfile ./source/Utils.H
hunk ./doc/index.html 1
+
+
+
+ Bobot++ - an IRC bot
+
+
+
+ Bobot++ - an IRC bot
+
+ First, if you don't know what is a bot or if you don't know what
+ is IRC, you're at the wrong place, sorry :-)
+
+ Introduction
+
+ The bobot++ is an IRC bot written in C++. This is the
+ evolution of the bobot
+ that I wrote in C with Bartman.
+
+ The bobot was a powerful bot, but it was limited to an
+ unique channel, and an unique bot per process. The
+ bobot++ is designed to support as many channels as you
+ want (in the limit of 20 channels, but this limit is set by the
+ servers). Moreover, it will support multithreading easily (all
+ the objects are thread-safe).
+
+ Here is a non comprehensive list of the bobot++'s
+ features:
+
+
+ - No backdoor: there is no backdoors in the
+ bobot++. You are free to believe me or not, but
+ unlike many other bots, this one has no backdoor. Note that
+ there is an hidden command, but this command is not designed to
+ take control of the bot,
+ - Multichannel: A bobot++ can join as many channels
+ as you want,
+ - Flood control: It will ignore people flooding it,
+ - Output rate control and priority handling: The
+ bobot++ will send its commands to the server at the
+ highest possible rate (ie as fast as possible without making
+ an ``excess flood''). The most important commands (MODE's,
+ etc.) are sent first,
+ - Time dependant commands: you can ban people for a fixed
+ amount of time. This is really useful in order not to fill the
+ banlist, [NOT YET FINISHED]
+ - Complex online help system: each user can have the list of
+ the commands he can execute. Each command has its description
+ in the help system,
+ - Four user levels (user, trusted user, friend and master),
+ three different protections (no kick, no ban and no deop) and
+ possible auto-op. Note that trusted user is created to permit
+ the use of wildcards on dangerous commands such as
+ kick, or ban,
+ - Support for combined join and channel op of 2.9 servers on
+ IRCNet (this feature will be suppressed from the servers, but
+ it may remain useful...),
+ - Logging of commands and events,
+ - ``Intelligent'' ban and deban,
+ - Password protection on accounts, expiration dates on user
+ accounts,
+ - Anti-spoof: one can not acquire operator priviledges spoofing
+ the bot
+
+
+ Downloading the bobot++
+
+ You can get the latest version of the bobot++ from this site
+ only. Here is the current version:
+
+ Download the 1.0 version
+ Download the 1.2 version
+ Download the 1.4 version
+
+ Note that revision numbers 1.1 and 1.3 were development
+ versions only.
+
+ Change log
+
+ Changes since version 1.2:
+
+
+ - Fixed a memory leak in the UserList::load()
+ function.
+ - Added antispoofing code (the bot pings before
+ auto-opping)
+ - Added password protection of user accounts.
+ - Added expiration on user accounts
+
+
+ Compiling the bobot++
+
+ Compiling the bobot++ is rather simple. You will only
+ need an Un*x-like system and a C++ compiler supporting the
+ Standard Template Library (STL).
+
+ The bobot++ compiles fine under the following
+ operating systems:
+
+
+ - Linux 2.0.x and g++ version 2.7.2.3,
+ - HP-UX version 9.x and 10.x and g++ version 2.7.2,
+ - SunOS 4.1 and g++.
+
+
+ It should compile easily on many other POSIX compliant
+ systems.
+
+ First, you will have to edit the Makefile if your C++
+ compiler is not g++. Change the line:
+
+ CXX=g++
+
+ With some Un*ces, you will have to link the program with some
+ extra libraries. Change the line:
+
+ LIBS=
+
+ For example, you will need this line with Solaris:
+
+ LIBS=-lsocket -lnsl
+
+ Then you should be ready to compile the program. Type
+ make at the prompt. If you get an error, please try and
+ fix it before emailing me...
+
+ Now, you should have a executable file named bobot++
+ in the directory. This is it! We will have to configure the bot,
+ now...
+
+ Configuring the bobot++
+
+ General configuration
+
+ Edit the example file bot.conf to suit your needs. The
+ comments in the file should be self explanatory...
+
+ Here is an example:
+
+ nick = Bobot
+username = bot
+cmdchar = !
+userlist = bot.users
+logfile = log
+server = irc.eurecom.fr
+server = irc.emn.fr
+server = irc.enst.fr
+server = salambo.enserb.u-bordeaux.fr
+channel = #test1
+channel = #test2 key
+
+ The bot will be named Bobot, more precisely
+ Bobot!bot@your.machine.com. Its command char will be
+ '!'. It will find its user list in the file bot.users,
+ and it will have three servers in its server list. The log will
+ be written to the file log. It will join two channels:
+ #test1 and #test2 with key as the channel key
+ (remember, the +k mode for channels...).
+
+ If you omit one of these configuration options, a default value
+ will be used.
+
+ Comments begin with ``#'' (at the first column only), and here
+ is the meaning of all configuration options. Note that there are
+ synonyms.
+
+
+
+ | Syntax |
+ Default value |
+ Meaning |
+
+
+ NICK=<nickname>
+ NICKNAME=<nickname> |
+ Bobot |
+ This is the nickname of the bot |
+
+
+ | USERNAME=<username> |
+ bot |
+ The username of the bot, if there is no identd daemon |
+
+
+ IRCNAME=<ircname>
+ REALNAME=<ircname> |
+ I'm a bobot++! |
+ The ircname of the bot |
+
+
+ CMDCHAR=<command char>
+ COMMAND=<command char> |
+ ! |
+ The command char of the bot |
+
+
+ | USERLIST=<file name> |
+ bot.users |
+ The userlist file |
+
+
+ | LOGFILE=<file name> |
+ log |
+ The log file (may be set to /dev/null if you do
+ not want to log... |
+
+
+ | SERVER=<server name> [<port> [<password>]] |
+ None |
+ The server the bot will try to connect to, on the port
+ specified, and optionally with a password. You can put any
+ number of SERVER lines |
+
+
+ | CHANNEL=<channel name> [<channel key>] |
+ None |
+ The channel the bot will join on startup. You can put any
+ number of CHANNEL lines |
+
+
+
+ You are the master of the bot
+
+ Yes! But the bot does not know who you are yet. Edit the file
+ bot.users (or whatever your userlist file is) and put
+ in a line like this one:
+
+ <your adress>:#*:4:0:0:-1:*NONE*
+
+ where <your adress> is composed with your IRC address. It
+ should be something like that:
+
+ *!*username@*.domain.com
+
+ if you connect on IRC from machine.domaine.com, with
+ username as login.
+
+ For me, this is *!*bernard@*.cma.fr.
+
+ Now, you can run the bot:
+
+ ./bobot++
+
+ Note that there are certain command line options that you can
+ see with:
+
+ ./bobot++ -h
+
+ Using the bobot++
+
+ Adding people on the userlist
+
+ Of course, you will want to add people on the userlist, as well
+ as other bots. The adduser command is for you, then!
+ Its syntax is:
+
+ !adduser <nick>|<mask> <channel mask> <level> <prot> <aop>
+
+ Note that ``!'' is the command char of the bot, and it may be
+ different according to the configuration you chose.
+ The meaning of the different options is rather simple:
+
+
+
+ | <nick> |
+ The nickname of the person to add. The bot will generate a
+ mask matching this person. If the mask is not accurate
+ enough, you should use... |
+
+
+ | <mask> |
+ ...to select the mask you really want. I remind you that
+ the mask is a regular expression designed to match
+ nick!username@hostname |
+
+
+ | <channel mask> |
+ This is a mask representing channels where this account is
+ available. You can put ``*'' for every channels, ``#*'' for
+ every non-local channels, etc. |
+
+
+ | <level> |
+
+
+ | 0 |
+ No level - Impossible to execute commands. This is
+ for bots, for example. |
+
+
+ | 1 |
+ User level - Will be able to execute many of the
+ commands, but will not be able to use masks on kicks
+ and on bans. |
+
+
+ | 2 |
+ Trusted user level - Exactly the same commands as
+ the ``User'' level, except that the user will be able
+ to use masks on bans and kicks. |
+
+
+ | 3 |
+ Friend level - Can do everything on the bot, except
+ stopping it. Be careful of who your friends are :-) |
+
+
+ | 4 |
+ Master level - Can do everything on the bot. |
+
+
+ |
+
+
+ | <protection> |
+
+
+ | 0 |
+ No protection - for nearly everybody. |
+
+
+ | 1 |
+ No ban - it will be impossible to ban the user,
+ directly or indirectly. |
+
+
+ | 2 |
+ No kick - if the user is kicked, there will be a
+ revenge. |
+
+
+ | 3 |
+ No deop - The bot will insure that the user can not
+ be deopped. Useful for bots. |
+
+
+ |
+
+
+ | <aop> |
+
+
+ | 0 |
+ No auto-op on join. |
+
+
+ | 1 |
+ Auto-op on join. For bots, and optionnaly other
+ users. It depends on the policy of your channel. |
+
+
+ |
+
+
+
+ Here are two examples:
+
+ !adduser eb #* 2 1 0
+!adduser *!*test@138.195.*.* #test 0 3 1
+!save
+
+ We first add ``eb'' (me!) to the userlist, for every non-local
+ channel, at level 2 (trusted user), with no-ban protection and
+ no auto-op.
+
+ Then we add every user matching ``*!*test@138.195.*.*'' to the
+ userlist for channel ``#test'', with level 0 (no level),
+ protection 3 (no-deop) and auto-op on join. It is probably
+ another bot.
+
+ Finally, we save the changes to the userlist. Note that this is
+ not mandatory, since the userlist is saved when the bot
+ !dies, but if the bot is killed or if there is a bug
+ (yes, there are bugs :-), all your changes would not
+ have been saved.
+
+ Issuing a command (like for example a kick)
+
+ The bobot++ supports two types of commands: those who
+ affect a channel (kick, ban, topic...) and those who don't.
+
+ For commands which need a channel name, the channel name can be
+ optionnaly put after the name of the command. This is mandatory
+ if the command is made directly to the bot, with a private
+ message.
+
+ Suppose the bot is on two channels, #test1 and
+ #test2. You are on channel #test1. Here is the
+ behavior of the bot:
+
+
+
+ | #test1> !kick foo reason |
+ This will kick foo out of channel
+ #test1. |
+
+
+ | #test1> !kick #test1 foo reason |
+ This will also kick foo out of channel
+ #test1. |
+
+
+ | #test1> !kick #test2 foo reason |
+ This will kick foo out of channel
+ #test2. |
+
+
+ | -> *bot* !kick #test1 foo reason |
+ This will kick foo out of channel
+ #test1. |
+
+
+ | -> *bot* !kick #test2 foo reason |
+ This will kick foo out of channel
+ #test2. |
+
+
+ | -> *bot* !kick foo reason |
+ This will not work. The bot has no way to know to
+ which channel this command applies to.
+ |
+
+
+ Is this clear enough? This is rather compelling, I know, but I
+ have not found a better way to do this.
+
+ Spying the bot
+
+ I hate people that kick others via the bots, and using
+ a private message to the bot. There is no good way to really
+ know what others do. Furthermore, some private messages can be
+ sent to the bot and this can be funny. That is why I made a
+ command to spy bot's private messages.
+
+ There is a ``spylist'' on the bot that every user can read with
+ the command !spylist. To be added to the spylist, you
+ should use the !spymessage command. To be removed, this
+ is the !rspymessage command.
+
+ Note that password control on the bot is not yet implemented,
+ so there is no danger of knowing the password of other people. I
+ will improve the spylist later in order not to be able to see
+ others' password.
+
+ Intelligent ban and deban
+
+ Note what happens if you try:
+
+ !ban *.a.a
+!ban *.b.a
+!ban *.c.a
+!ban *.d.a
+
+ Then
+
+ !ban *.a
+
+ Fine, isn't it? If we didn't do that, the server would not
+ accept the last ban. Try also !deban * (use it when the
+ banlist is full!).
+
+ Getting help on other commands
+
+ The !help command without arguments will give you all
+ the commands you can issue. For a master, this will give
+ you (this may change in the future):
+
+ -Bobot- Available topics for you are:
+-Bobot- ACTION ADDUSER ADDSERVER BAN CHANNELS CYCLE DEBAN DELSERVER DEOP
+ DIE HELP INVITE JOIN KICK KICKBAN LOCK NAMES NEXTSERVER NICK
+ NSLOOKUP OP PART RECONNECT RSPYMESSAGE SAVE SAY SERVER SERVERLIST
+ SPYLIST SPYMESSAGE TOPIC UNLOCK USERLIST WHO WHOIS
+-Bobot- Use HELP <command> for help about <command>
+
+ If you want help about the !kick command, use
+ !help kick:
+
+ -Bobot- Help for KICK:
+-Bobot- KICK [<channel>] <mask>|<nick> [<reason>]
+-Bobot- Kicks <mask> or <nick> out of <channel>, because of <reason>.
+-Bobot- You need to be a trusted user to use a <mask>.
+-Bobot- End of help.
+
+ Then you have the tools to explore the bobot++ in
+ details. Good luck!
+
+ Bugs, questions, etc.
+
+ If you find a bug or a strange behaviour of the bot, please try
+ to reproduce it, and then send me a mail describing the problem
+ in details.
+
+ If you have suggestions about new features, please tell
+ me. If you added features yourself, send me your patch!
+
+ Note that I will not answer to configuration or compilation
+ problems...
+
+ Plans for the future
+
+ Here is what I plan to add to the bobot++:
+
+
+ - Scripting support with Guile, the GNU Scheme
+ interpreter;
+ - Bot control via telnet, or a java applet;
+ - DCC Send and Get (we will be able to use the bot as a
+ file server);
+ - Shitlist, like on the bobot;
+ - Dynamic settings;
+ - Other ideas?
+
+
+ Why use Guile?
+
+ Guile is the GNU Scheme interpreter. In a future release of the
+ bobot++, I plan to add scripting support using this
+ interpreter.
+
+ So, why did I chose Guile, instead of Tcl or Python?
+
+ One of the main features of Guile is that it will be easy to
+ extend the interpreter in order to translate Python, Tcl or
+ Perl to Scheme code. So, you will have the choice of the
+ language! If you prefer Python instead of Perl or Tcl, use
+ Python. If you prefer CTax (a language similar to C), all right!
+ I hope that religious wars opposing those languages will soon be
+ over...
+
+ Moreover, as Guile is GNU code, it is really a free
+ software, and will keep this status.
+
+ Finally, it is an excellent product, so why shouldn't we use
+ it?
+
+
+
+ Etienne
+ BERNARD
+
+
+
+Last modified: Sat Mar 21 13:32:54 CET 1998
+
+
+
hunk ./scripts/bobot-utils.scm 1
-
+;;; this is a library of stuff that bobot++ scripts would probably
+;;; want to use.
+
+;;; This file is covered by the GPL version 2 or (at your option) any
+;;; later version
+
+;;; Why the GPL? Technically anything that uses Bobot++'s functions
+;;; must be GPLed, so all of your scripts have to be GPLed anyway
+;;; because you are really linking with Bobot++, a GPLed program!
+
+;;; REGEX UTILS
+
+;;; match-not-channel adds a prefix regex to your regex so it doesn't
+;;; match the sender or channel in a PUBLIC message
+(define (match-not-channel regex)
+ (string-append "[[:graph:]]* [+!][^ ,\a]+ [[:graph:][:space:]]*" regex))
+
+;;; match-to-me matches text that was addressed to the bot with a
+;;; ':',',', or nothing after the bot name
+(define (match-to-me regex)
+ (string-append (match-not-channel (bot-getnickname))
+ "[:,]*[[:space:][:graph:]]*" regex))
+
+
+;;;; string-utils
+(define str-app string-append) ; shorter
+
+
+;;;; Misc UTILS
+
+;;; bot-log: Write as many messages as you want to the log. If the
+;;; arg is a procedure it will be executed and it's output will be
+;;; written to the log
+(define (bot-log . messages)
+ (map
+ (lambda (x)
+ (if (procedure? x)
+ (display (x) (bot-logport))
+ (display x (bot-logport))))
+ messages )
+ (bot-flushport))
hunk ./scripts/boulet 1
-
+;;; Activate or desactivate the bot
+(define talk 1)
+(define (shutup)
+ (set! talk 0)
+ )
+(bot-addcommand "shutup" shutup #f 0 2)
+(define (dotalk)
+ (set! talk 1)
+ )
+(bot-addcommand "talk" dotalk #f 0 2)
+
+;;; Miscellaneous list functions
+(define (removeChannel c l)
+ (if (null? l)
+ (list)
+ (let ((deb (car l)))
+ (if (string-ci=? c (car deb))
+ (cdr l)
+ (append (list deb) (removeChannel c (cdr l)))
+ )
+ )
+ )
+ )
+
+(define (changeChannel c n l)
+ (if (null? l)
+ (list)
+ (let ((deb (car l)))
+ (if (string-ci=? c (car deb))
+ (append (list (list c n)) (cdr l))
+ (append (list deb) (changeChannel c n (cdr l)))
+ )
+ )
+ )
+)
+
+(define (addChannel c n l)
+ (append l (list (list c n)))
+)
+
+;;; When someone joins a channel
+(define dumbTimer (list))
+(define (joinLourd n c)
+ (if (string-ci=? n (bot-getnickname))
+ (begin
+ (if (= 1 talk) (bot-say c "salut les gars, vous parlez de quoi ?"))
+ (set! dumbTimer (addChannel c (bot-addtimer (+ 600 (bot-random 3000)) (dumbLourd c)) dumbTimer))
+ )
+ (if (= 1 talk) (bot-say c (string-append "euh humm euh..., " n "... une ptite question...")))
+ )
+ )
+(bot-addhook hooks/join ".*" joinLourd)
+
+;;; When someone leaves the channel
+(define (partLourd n c)
+ (bot-flushport)
+ (if (not (string-ci=? n (bot-getnickname)))
+ (if (= 1 talk) (bot-msg n "hey, reviens, on s'amusait bien"))
+ (let* ((timer (assoc c dumbTimer)))
+ (bot-deltimer (cadr timer))
+ (set! dumbTimer (removeChannel c dumbTimer))
+ )
+ )
+ )
+(bot-addhook hooks/part ".*" partLourd)
+
+;;; Random action to say something dumb
+(define dumbList
+ (list "errr... umm umm !!"
+ "ahum. err... p'tite question !"
+ "putain, php c'est vraiment de la merde"
+ "quelle daube mysql !"
+ "xml ça sert vraiment à rien..."
+ "c'est moi ou orion ne marche pas ?"
+ "mais euh ça sert à quoi le palm pilot ?"
+ "je ne comprends pas, j'ai fait copier coller, et ça ne marche pas..."
+ "dites les gars, c'est quoi l'avenir d'internet ?")
+ )
+(define (dumbLourd c)
+ (lambda ()
+ (if (= 1 talk) (bot-say c (list-ref dumbList (bot-random (length dumbList)))))
+ (set! dumbTimer (changeChannel c (bot-addtimer (+ 600 (bot-random 3000)) (dumbLourd c)) dumbTimer))
+ )
+ )
+
+;;; Misc
+(bot-addhook hooks/public "oracle" (lambda (f t p) (if (= 1 talk) (bot-say t "oracle ! Un truc de dinosaures, ça !"))))
+(bot-addhook hooks/public "linux" (lambda (f t p) (if (= 1 talk) (bot-say t (string-append f ", j'ai installé une Mandrake chez moi ce week-end, et j'ai réussi à faire marcher l'imprimante")))))
+(bot-addhook hooks/public "boulet" (lambda (f t p) (if (= 1 talk) (bot-say t "on parle de moi ?"))))
+(bot-addhook hooks/public "lourd" (lambda (f t p) (if (= 1 talk) (bot-say t "vous le dites si je suis lourd !"))))
+(bot-addhook hooks/public "csn" (lambda (f t p) (if (= 1 talk) (bot-say t "ahahah, je ne partirai jamais !"))))
+(bot-addhook hooks/public "manger|pizza|pasta" (lambda (f t p) (if (= 1 talk) (bot-say t "je peux venir manger avec vous ?"))))
+(bot-addhook hooks/public "regarde" (lambda (f t p) (if (= 1 talk) (bot-action t "se lève pour regarder..."))))
+
+;;; 9h00, on arrive au boulot
+(define (newDay l)
+ (if (not (null? l))
+ (begin
+ (bot-say (caar l) "Bonjour les gars")
+ (newDay (cdr l))
+ )
+ )
+)
+(bot-addhook hooks/timer "09:00" (lambda (h) (newDay dumbTimer) (talk)))
+
+;;; 18h00, il est temps de rentrer
+(define (timeToGo l)
+ (if (not (null? l))
+ (begin
+ (bot-say (caar l) "à demain !")
+ (bot-action (caar l) "rentre chez lui...")
+ (timeToGo (cdr l))
+ )
+ )
+)
+(bot-addhook hooks/timer "18:00" (lambda (h) (timeToGo dumbTimer) (shutup)))
hunk ./scripts/country 1
+(define countries
+ (list (list "AF" "AFGHANISTAN")
+ (list "AL" "ALBANIA")
+ (list "DZ" "ALGERIA")
+ (list "AS" "AMERICAN SAMOA")
+ (list "AD" "ANDORRA")
+ (list "AO" "ANGOLA")
+ (list "AI" "ANGUILLA")
+ (list "AQ" "ANTARCTICA")
+ (list "AG" "ANTIGUA AND BARBUDA")
+ (list "AR" "ARGENTINA")
+ (list "AM" "ARMENIA")
+ (list "AW" "ARUBA")
+ (list "AU" "AUSTRALIA")
+ (list "AT" "AUSTRIA")
+ (list "AZ" "AZERBAIJAN")
+ (list "BS" "BAHAMAS")
+ (list "BH" "BAHRAIN")
+ (list "BD" "BANGLADESH")
+ (list "BB" "BARBADOS")
+ (list "BY" "BELARUS")
+ (list "BE" "BELGIUM")
+ (list "BZ" "BELIZE")
+ (list "BJ" "BENIN")
+ (list "BM" "BERMUDA")
+ (list "BT" "BHUTAN")
+ (list "BO" "BOLIVIA")
+ (list "BA" "BOSNIA AND HERZEGOWINA")
+ (list "BW" "BOTSWANA")
+ (list "BV" "BOUVET ISLAND")
+ (list "BR" "BRAZIL")
+ (list "IO" "BRITISH INDIAN OCEAN TERRITORY")
+ (list "BN" "BRUNEI DARUSSALAM")
+ (list "BG" "BULGARIA")
+ (list "BF" "BURKINA FASO")
+ (list "BI" "BURUNDI")
+ (list "KH" "CAMBODIA")
+ (list "CM" "CAMEROON")
+ (list "CA" "CANADA")
+ (list "CV" "CAPE VERDE")
+ (list "KY" "CAYMAN ISLANDS")
+ (list "CF" "CENTRAL AFRICAN REPUBLIC")
+ (list "TD" "CHAD")
+ (list "CL" "CHILE")
+ (list "CN" "CHINA")
+ (list "CX" "CHRISTMAS ISLAND")
+ (list "CC" "COCOS (KEELING) ISLANDS")
+ (list "CO" "COLOMBIA")
+ (list "KM" "COMOROS")
+ (list "CG" "CONGO")
+ (list "CD" "CONGO, THE DEMOCRATIC REPUBLIC OF THE")
+ (list "CK" "COOK ISLANDS")
+ (list "CR" "COSTA RICA")
+ (list "CI" "COTE D'IVOIRE")
+ (list "HR" "CROATIA (local name: Hrvatska)")
+ (list "CU" "CUBA")
+ (list "CY" "CYPRUS")
+ (list "CZ" "CZECH REPUBLIC")
+ (list "DK" "DENMARK")
+ (list "DJ" "DJIBOUTI")
+ (list "DM" "DOMINICA")
+ (list "DO" "DOMINICAN REPUBLIC")
+ (list "TP" "EAST TIMOR")
+ (list "EC" "ECUADOR")
+ (list "EG" "EGYPT")
+ (list "SV" "EL SALVADOR")
+ (list "GQ" "EQUATORIAL GUINEA")
+ (list "ER" "ERITREA")
+ (list "EE" "ESTONIA")
+ (list "ET" "ETHIOPIA")
+ (list "FK" "FALKLAND ISLANDS (MALVINAS)")
+ (list "FO" "FAROE ISLANDS")
+ (list "FJ" "FIJI")
+ (list "FI" "FINLAND")
+ (list "FR" "FRANCE")
+ (list "FX" "FRANCE, METROPOLITAN")
+ (list "GF" "FRENCH GUIANA")
+ (list "PF" "FRENCH POLYNESIA")
+ (list "TF" "FRENCH SOUTHERN TERRITORIES")
+ (list "GA" "GABON")
+ (list "GM" "GAMBIA")
+ (list "GE" "GEORGIA")
+ (list "DE" "GERMANY")
+ (list "GH" "GHANA")
+ (list "GI" "GIBRALTAR")
+ (list "GR" "GREECE")
+ (list "GL" "GREENLAND")
+ (list "GD" "GRENADA")
+ (list "GP" "GUADELOUPE")
+ (list "GU" "GUAM")
+ (list "GT" "GUATEMALA")
+ (list "GN" "GUINEA")
+ (list "GW" "GUINEA-BISSAU")
+ (list "GY" "GUYANA")
+ (list "HT" "HAITI")
+ (list "HM" "HEARD AND MC DONALD ISLANDS")
+ (list "VA" "HOLY SEE (VATICAN CITY STATE)")
+ (list "HN" "HONDURAS")
+ (list "HK" "HONG KONG")
+ (list "HU" "HUNGARY")
+ (list "IS" "ICELAND")
+ (list "IN" "INDIA")
+ (list "ID" "INDONESIA")
+ (list "IR" "IRAN (ISLAMIC REPUBLIC OF)")
+ (list "IQ" "IRAQ")
+ (list "IE" "IRELAND")
+ (list "IL" "ISRAEL")
+ (list "IT" "ITALY")
+ (list "JM" "JAMAICA")
+ (list "JP" "JAPAN")
+ (list "JO" "JORDAN")
+ (list "KZ" "KAZAKHSTAN")
+ (list "KE" "KENYA")
+ (list "KI" "KIRIBATI")
+ (list "KP" "KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF")
+ (list "KR" "KOREA, REPUBLIC OF")
+ (list "KW" "KUWAIT")
+ (list "KG" "KYRGYZSTAN")
+ (list "LA" "LAO PEOPLE'S DEMOCRATIC REPUBLIC")
+ (list "LV" "LATVIA")
+ (list "LB" "LEBANON")
+ (list "LS" "LESOTHO")
+ (list "LR" "LIBERIA")
+ (list "LY" "LIBYAN ARAB JAMAHIRIYA")
+ (list "LI" "LIECHTENSTEIN")
+ (list "LT" "LITHUANIA")
+ (list "LU" "LUXEMBOURG")
+ (list "MO" "MACAU")
+ (list "MK" "MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF")
+ (list "MG" "MADAGASCAR")
+ (list "MW" "MALAWI")
+ (list "MY" "MALAYSIA")
+ (list "MV" "MALDIVES")
+ (list "ML" "MALI")
+ (list "MT" "MALTA")
+ (list "MH" "MARSHALL ISLANDS")
+ (list "MQ" "MARTINIQUE")
+ (list "MR" "MAURITANIA")
+ (list "MU" "MAURITIUS")
+ (list "YT" "MAYOTTE")
+ (list "MX" "MEXICO")
+ (list "FM" "MICRONESIA, FEDERATED STATES OF")
+ (list "MD" "MOLDOVA, REPUBLIC OF")
+ (list "MC" "MONACO")
+ (list "MN" "MONGOLIA")
+ (list "MS" "MONTSERRAT")
+ (list "MA" "MOROCCO")
+ (list "MZ" "MOZAMBIQUE")
+ (list "MM" "MYANMAR")
+ (list "NA" "NAMIBIA")
+ (list "NR" "NAURU")
+ (list "NP" "NEPAL")
+ (list "NL" "NETHERLANDS")
+ (list "AN" "NETHERLANDS ANTILLES")
+ (list "NC" "NEW CALEDONIA")
+ (list "NZ" "NEW ZEALAND")
+ (list "NI" "NICARAGUA")
+ (list "NE" "NIGER")
+ (list "NG" "NIGERIA")
+ (list "NU" "NIUE")
+ (list "NF" "NORFOLK ISLAND")
+ (list "MP" "NORTHERN MARIANA ISLANDS")
+ (list "NO" "NORWAY")
+ (list "OM" "OMAN")
+ (list "PK" "PAKISTAN")
+ (list "PW" "PALAU")
+ (list "PA" "PANAMA")
+ (list "PG" "PAPUA NEW GUINEA")
+ (list "PY" "PARAGUAY")
+ (list "PE" "PERU")
+ (list "PH" "PHILIPPINES")
+ (list "PN" "PITCAIRN")
+ (list "PL" "POLAND")
+ (list "PT" "PORTUGAL")
+ (list "PR" "PUERTO RICO")
+ (list "QA" "QATAR")
+ (list "RE" "REUNION")
+ (list "RO" "ROMANIA")
+ (list "RU" "RUSSIAN FEDERATION")
+ (list "RW" "RWANDA")
+ (list "KN" "SAINT KITTS AND NEVIS")
+ (list "LC" "SAINT LUCIA")
+ (list "VC" "SAINT VINCENT AND THE GRENADINES")
+ (list "WS" "SAMOA")
+ (list "SM" "SAN MARINO")
+ (list "ST" "SAO TOME AND PRINCIPE")
+ (list "SA" "SAUDI ARABIA")
+ (list "SN" "SENEGAL")
+ (list "SC" "SEYCHELLES")
+ (list "SL" "SIERRA LEONE")
+ (list "SG" "SINGAPORE")
+ (list "SK" "SLOVAKIA (Slovak Republic)")
+ (list "SI" "SLOVENIA")
+ (list "SB" "SOLOMON ISLANDS")
+ (list "SO" "SOMALIA")
+ (list "ZA" "SOUTH AFRICA")
+ (list "GS" "SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS")
+ (list "ES" "SPAIN")
+ (list "LK" "SRI LANKA")
+ (list "SH" "ST. HELENA")
+ (list "PM" "ST. PIERRE AND MIQUELON")
+ (list "SD" "SUDAN")
+ (list "SR" "SURINAME")
+ (list "SJ" "SVALBARD AND JAN MAYEN ISLANDS")
+ (list "SZ" "SWAZILAND")
+ (list "SE" "SWEDEN")
+ (list "CH" "SWITZERLAND")
+ (list "SY" "SYRIAN ARAB REPUBLIC")
+ (list "TW" "TAIWAN, PROVINCE OF CHINA")
+ (list "TJ" "TAJIKISTAN")
+ (list "TZ" "TANZANIA, UNITED REPUBLIC OF")
+ (list "TH" "THAILAND")
+ (list "TG" "TOGO")
+ (list "TK" "TOKELAU")
+ (list "TO" "TONGA")
+ (list "TT" "TRINIDAD AND TOBAGO")
+ (list "TN" "TUNISIA")
+ (list "TR" "TURKEY")
+ (list "TM" "TURKMENISTAN")
+ (list "TC" "TURKS AND CAICOS ISLANDS")
+ (list "TV" "TUVALU")
+ (list "UG" "UGANDA")
+ (list "UA" "UKRAINE")
+ (list "AE" "UNITED ARAB EMIRATES")
+ (list "GB" "UNITED KINGDOM")
+ (list "US" "UNITED STATES")
+ (list "UM" "UNITED STATES MINOR OUTLYING ISLANDS")
+ (list "UY" "URUGUAY")
+ (list "UZ" "UZBEKISTAN")
+ (list "VU" "VANUATU")
+ (list "VE" "VENEZUELA")
+ (list "VN" "VIET NAM")
+ (list "VG" "VIRGIN ISLANDS (BRITISH)")
+ (list "VI" "VIRGIN ISLANDS (U.S.)")
+ (list "WF" "WALLIS AND FUTUNA ISLANDS")
+ (list "EH" "WESTERN SAHARA")
+ (list "YE" "YEMEN")
+ (list "YU" "YUGOSLAVIA")
+ (list "ZM" "ZAMBIA")
+ (list "ZW" "ZIMBABWE")))
+
+(define (get-country channel ext)
+ (let ((t (assoc (string-upcase! ext) countries)))
+ (if t
+ (bot-say channel (string-append ext " is " (cadr t)))
+ (bot-say channel (string-append "I don't know which country stands for " ext)))))
+
+(bot-addcommand "country" get-country #t 2 1)
hunk ./scripts/eval 1
-
+; -*- guile-scheme -*-
+(use-modules (ice-9 slib))
+
+(require 'coerce)
+
+(define (bot-eval channel str)
+ (bot-say channel
+ (coerce
+ (eval-string str) 'string)))
+
+(bot-addcommand "eval" bot-eval #t 2 4)
hunk ./scripts/hello 1
+(define (hello c n)
+ (if (string=? n "")
+ (bot-say c "Hello world !")
+ (bot-say c (string-append "Hello " n " !"))
+ )
+)
+
+(bot-addcommand "hello" hello #t 2 0)
hunk ./scripts/scheme_add_user 1
-
+;;; -*- guile-scheme -*-
+;;; test of bot-adduser
+(load "bobot-utils.scm")
+
+;;; test this!
+(define (scheme-adduser who channel level protect aop expire passwd)
+ (let ((level (string->number level))
+ (protect (string->number protect))
+ (aop
+ (if (= 1 (string->number aop))
+ #t #f ))
+ (expire (string->number expire)))
+ (bot-adduser who channel level protect aop expire passwd)))
+
+(bot-addcommand "sadduser" scheme-adduser #f 7 4)
+
+(define (test-adduser)
+ (bot-log "Adding lap_r_g\n")
+ (bot-adduser "lap_r_g" "#*" 4 0 #f)
+ (bot-log "Adding CowBot\n")
+ (bot-adduser "CowBot" "#*" 2 0 #f "2M18H")
+ (bot-log "Adding ZugBut\n")
+ (bot-adduser "ZugBot" "#*" 2 0 #f "1Y" "moo")
+ (bot-log "Done...\n"))
+
+(bot-addcommand "testadduser" test-adduser #f 0 4)
+
+(define (test-addshit)
+ (bot-log "Adding root")
+ (bot-addshit "*!root@*.*" "*" 2))
+
+;(bot-addcommand "testaddshit" test-addshit #f 0 4)
hunk ./scripts/scripts.load 1
-
+stupid_stuff/stupid_stuff
+country
+hello
+tamere
+uname
+uptime
+eval
hunk ./scripts/stupid_stuff/insert_saying.scm 1
-
+#!/usr/local/bin/guile -s
+!#
+
+(use-modules (database simplesql)
+ (ice-9 rdelim))
+
+(display "Enter one saying per line. End the list with EOF\n")
+
+(define db (simplesql-open 'postgresql "bot_sayings"))
+
+(let loop ((saying (read-line)))
+ (cond ((not (eof-object? saying))
+ (simplesql-query
+ db
+ (string-append "INSERT INTO sayings VALUES ('"
+ (simplesql-escape saying) "');"))
+ (loop (read-line)))
+ (else
+ (simplesql-close db))))
hunk ./scripts/stupid_stuff/sayings 1
+Arf!
+errr... umm umm !!
+I think the real issue here is how do you make juice-juice?
+I like to eat cows.
+MySQL is stupid
+I used to speak french
+c'est moi ou orion ne marche pas ?
+1 4m m0r3 l33t th4n j00!
+BITCH, WUT?
+vergil gives wicked hummers!
+Ahh! Snakes!
+I like limos and people who drive them.
+Eat Cows today!
+Over [5] customers served since 1996!
+I think I'll go and hang myself now!
+I'd leap off a third floor balcony for ice cream!
+I am immune to all forms of temptation and seduction. Except for Cute.
+I am a kernel whore.
+Doesn't is just suck when you get soap in your orange juice?
hunk ./scripts/stupid_stuff/sayings.sh 1
-
+#!/bin/sh
+
+createdb bot_sayings
+psql bot_sayings -c "CREATE TABLE sayings ( saying text, id serial);"
hunk ./scripts/stupid_stuff/stupid_stuff 1
-
+;;; -*- guile-scheme -*-
+;;; this shows off some interesting things...(based on boulet)
+;;; This is unknown_lamer's bot DumbBot
+
+;;; To use this run:
+;;; sh sayings.sh
+;;; cat sayings | guile -s insert_saying.scm
+;;; Then load this file.
+;;; To add a new saying to the bot db just run insert_saying.scm
+
+;;; yes, this uses a sql db!
+(use-modules (database simplesql)
+ (ice-9 debug))
+(load "../bobot-utils.scm")
+
+;;; Activate or desactivate the bot
+(define talk 1)
+
+(define (shutup)
+ (set! talk 0))
+(bot-addcommand "shutup" shutup #f 0 2)
+
+(define (dotalk)
+ (set! talk 1))
+(bot-addcommand "talk" dotalk #f 0 2)
+
+
+;;; Miscellaneous list functions
+(define (removeChannel c l)
+ (if (null? l)
+ (list)
+ (let ((deb (car l)))
+ (if (string-ci=? c (car deb))
+ (cdr l)
+ (append (list deb) (removeChannel c (cdr l)))))))
+
+(define (changeChannel c n l)
+ (if (null? l)
+ (list)
+ (let ((deb (car l)))
+ (if (string-ci=? c (car deb))
+ (append (list (list c n)) (cdr l))
+ (append (list deb) (changeChannel c n (cdr l)))))))
+
+(define (addChannel c n l)
+ (append l (list (list c n))))
+
+;;; When someone joins a channel
+(define dumbTimer (list))
+(define (joinLourd n c)
+ (if (string-ci=? n (bot-getnickname))
+ (begin
+ (if (= 1 talk) (bot-say c "I like limos"))
+ (set! dumbTimer
+ (addChannel c (bot-addtimer (+ 600 (bot-random 300))
+ (dumbLourd c)) dumbTimer)))
+ (if (= 1 talk) (bot-say c (string-append "Arf Moo Arf! " n
+ " I like pizza...")))))
+(bot-addhook hooks/join ".*" joinLourd)
+
+;;; When someone leaves the channel
+(define (partLourd n c)
+ (bot-flushport)
+ (if (not (string-ci=? n (bot-getnickname)))
+ (if (= 1 talk) (bot-msg n "I HATED YOU ANYWAY"))
+ (let* ((timer (assoc c dumbTimer)))
+ (bot-deltimer (cadr timer))
+ (set! dumbTimer (removeChannel c dumbTimer)))))
+(bot-addhook hooks/part ".*" partLourd)
+
+;;; Random action to say something dumb
+ (define (dumbLourd c)
+ (lambda ()
+ (if (= 1 talk)
+ (bot-say
+ c
+ (vector-ref (list-ref dumbList (bot-random (length dumbList))) 0)))
+ (set! dumbTimer
+ (changeChannel
+ c
+ (bot-addtimer (+ 600 (bot-random 300)) (dumbLourd c)) dumbTimer))))
+
+
+(define dumbDB (simplesql-open 'postgresql "bot_sayings"))
+;(define dumbList #f)
+; (define (reload-sayings)
+; (set! dumbList (cdr (simplesql-query dumbDB "SELECT saying FROM sayings")))
+; (display "Reloaded sayings from db\n" (bot-logport))
+; (bot-flushport))
+; (bot-addcommand "reloadsayings" reload-sayings #f 0 4)
+; (reload-sayings)
+
+(define (_length db)
+ (let ((length (+ 1
+ (vector-ref
+ (list-ref (cdr
+ (simplesql-query
+ db
+ "SELECT count(saying) FROM sayings")) 0) 0))))
+ length ))
+
+(define (_select db entry)
+ (list-ref
+ (cdr
+ (simplesql-query db
+ (str-app "SELECT saying FROM sayings "
+ "WHERE id = "
+ (number->string entry)))) 0))
+
+
+
+
+(define (random-saying)
+ (vector-ref (_select dumbDB (bot-random (_length dumbDB))) 0))
+
+;;; Misc
+;;; note that public hooks match the channel name too!
+;;; match-not-channel prevents this
+
+;;; this should be the first so it doesn't clobber the other hooks
+(bot-addhook
+ hooks/public (match-to-me "")
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-say t
+ (string-append f ": " (random-saying))))) -50 #f)
+
+
+(bot-addhook hooks/public (match-not-channel "oracle")
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-say t "Oracle is evil! Use Postgres instead!"))))
+
+(define (add-gnu word)
+ (bot-addhook hooks/public (match-not-channel word)
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-say t
+ (string-append f ": I hope you meant GNU!"))))))
+(map add-gnu '("[^/g]linux" "microsoft" "bsd"))
+
+(bot-addhook hooks/public (match-not-channel "boulet")
+ (lambda (f t p)
+ (if (= 1 talk) (bot-say t "on parle de moi ?"))))
+
+(bot-addhook hooks/public (match-not-channel "arf")
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-say t (random-saying)))))
+
+(bot-addhook hooks/public (match-not-channel "csn")
+ (lambda (f t p)
+ (if (= 1 talk) (bot-say t "???"))))
+
+(bot-addhook hooks/public (match-not-channel "pizza|pasta|soda")
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-say t (string-append f ": give me one too!")))))
+
+(define (add-foul word)
+ (bot-addhook hooks/public (match-not-channel word)
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-action
+ t (string-append "hits " f
+ " for having a potty mouth"))))))
+(map add-foul '("bitch" "fuck" "whore" "cunt" "tit" "shit" "dick" "cock"))
+
+(bot-addhook hooks/public (match-not-channel "anal sex")
+ (lambda (f t p)
+ (if (= 1 talk)
+ (if (not (string-match "unknown_lamer" f))
+ (bot-action
+ t (string-append "grabs " f
+ " and buggers " f " up the ass"))))))
+
+(bot-addhook
+ hooks/public (match-not-channel "[[:space:]]*lame[[:space:]]+")
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-say t
+ (string-append f ": NO NO YOU ARE THE LAMER")))))
+
+(bot-addhook hooks/public (match-to-me "burn")
+ (lambda (f t p)
+ (if (= 1 talk)
+ (bot-say
+ t
+ (string-append "How about you burn " f "?")))))
+
+
+;;; 9h00, on arrive au boulot
+;(define (newDay l)
+; (if (not (null? l))
+; (begin
+; (bot-say (caar l) "What is up my homey g-d0g?")
+; (newDay (cdr l))
+; )
+; )
+;)
+
+;(bot-addhook hooks/timer "09:00" (lambda (h) (newDay dumbTimer) (talk)))
+
+;;; 18h00, il est temps de rentrer
+;(define (timeToGo l)
+; (if (not (null? l))
+; (begin
+; (bot-say (caar l) "Give me food")
+; (bot-action (caar l) "I'm bored")
+; (timeToGo (cdr l))
+; )
+; )
+;)
+;(bot-addhook hooks/timer "18:00" (lambda (h) (timeToGo dumbTimer) (shutup)))
hunk ./scripts/tamere 1
+(define where
+ (list "en short" "en string" "en tongues" "en rollers"
+ "à poil" "en jpeg" "en gif" "en scooter" "à vélo"
+ "à mobylette" "en babouches" "en Twingo" "en kilt"
+ "en string" "en charentaises" "en bermuda"
+ "elle fait le poirier" "elle fait des quiches"
+ "elle mange du thon" "elle recompile son noyau"
+ "elle conduit une motocrottes" "elle se fait bouillir"
+ "elle vient te chercher"))
+
+(define how
+ (list "au prisu" "sur Vénus" "sur la Voie Lactée" "dans la cuisine"
+ "dans l'ascenseur" "chez Sabatier" "à NX" "au commissariat"
+ "au stade de France" "au Bât'ens" "à la Bourboule"
+ "à la foire du trône" "la tête en bas" "au monoprix"))
+
+(define (tamere w)
+ (string-append w
+ ", ta mère "
+ (list-ref where (bot-random (length where))) " "
+ (list-ref how (bot-random (length how)))))
+
+(define (bot-tamere c w)
+ (bot-say c (tamere w)))
+
+(bot-addcommand "tamere" bot-tamere #t 2 1)
hunk ./scripts/uname 1
+(use-modules (ice-9 popen))
+
+(define (uname c)
+ (let* ((p (open-input-pipe "/bin/uname -a"))
+ (s (read-line p)))
+ (close-pipe p)
+ (bot-say c s)))
+
+(bot-addcommand "uname" uname #t 0 1)
hunk ./scripts/uptime 1
+(use-modules (ice-9 popen))
+
+(define (uptime c)
+ (let* ((p (open-input-pipe "/usr/bin/uptime"))
+ (s (read-line p)))
+ (close-pipe p)
+ (bot-say c s)))
+
+(bot-addcommand "uptime" uptime #t 0 1)
hunk ./source/BanEntry.C 1
+// BanEntry.C -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#include "BanEntry.H"
+
+BanEntry::BanEntry(String m, time_t e)
+ : banMask(m), expirationDate(e)
+{ }
+
+time_t
+BanEntry::getExpirationDate() const
+{
+ return expirationDate;
+}
+
+void
+BanEntry::setExpirationDate(time_t exp)
+{
+ expirationDate = exp;
+}
+
+String
+BanEntry::getMask()
+{
+ return banMask.getMask();
+}
hunk ./source/BanEntry.H 1
+// BanEntry.H -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2002 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
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#ifndef BANENTRY_H
+#define BANENTRY_H
+
+#include
+
+#include "Mask.H"
+
+class Commands;
+class UserCommands;
+
+class BanEntry {
+ Mask banMask;
+ std::time_t expirationDate;
+
+public:
+
+ BanEntry(String, std::time_t);
+
+ std::time_t getExpirationDate() const;
+ void setExpirationDate(std::time_t);
+
+ String getMask();
+
+ friend class Commands;
+ friend class UserCommands;
+};
+
+#endif
hunk ./source/Bot.C 1
+// Bot.C -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2002 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
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Bot.H"
+#include "DCCConnection.H"
+#include "StringTokenizer.H"
+#include "ServerConnection.H"
+#include "Utils.H"
+
+#define DEFAULT_NICKNAME "Bobot"
+#define DEFAULT_USERNAME "bobot"
+#define DEFAULT_IRCNAME "I'm a bobot++!"
+#define DEFAULT_COMMANDCHAR '!'
+#define DEFAULT_USERLISTFILENAME "bot.users"
+#define DEFAULT_SHITLISTFILENAME "bot.shit"
+#define DEFAULT_HELPFILENAME "bot.help"
+#define DEFAULT_SCRIPTLOGFILENAME "script.log"
+#define DEFAULT_LOGFILENAME "bot.log"
+#define DEFAULT_INITFILENAME "bot.init"
+#ifdef USESCRIPTS
+#define DEFAULT_AUTOEXECFILENAME "bot.autoexec"
+#endif
+
+Bot::Bot(String filename, bool debug_on)
+ : nickName(DEFAULT_NICKNAME),
+ wantedNickName(DEFAULT_NICKNAME),
+ userName(DEFAULT_USERNAME),
+ ircName(DEFAULT_IRCNAME),
+ versionString(VERSION_STRING),
+ userHost(""),
+ localIP(""),
+ commandChar(DEFAULT_COMMANDCHAR),
+ configFileName(filename),
+ userListFileName(DEFAULT_USERLISTFILENAME),
+ shitListFileName(DEFAULT_SHITLISTFILENAME),
+ logFileName(DEFAULT_LOGFILENAME),
+ helpFileName(DEFAULT_HELPFILENAME),
+ initFileName(DEFAULT_INITFILENAME),
+#ifdef USESCRIPTS
+ 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)
+{
+ extern userFunctionsStruct userFunctionsInit[];
+
+#ifdef HAVE_STL_CLEAR
+ wantedChannels.clear();
+ ignoredUserhosts.clear();
+ spyList.clear();
+ userhostMap.clear();
+#endif
+
+ for (int i = 0; userFunctionsInit[i].name[0] != '\0'; i++) {
+ userFunctions.push_back(new
+ userFunction(String(userFunctionsInit[i].name),
+ userFunctionsInit[i].function,
+ userFunctionsInit[i].minLevel,
+ userFunctionsInit[i].needsChannelName));
+ }
+
+#if HAVE_IOSBASE
+ logFile.open(logFileName, std::ios_base::out | std::ios_base::ate
+ | std::ios_base::app);
+#else
+ logFile.open(logFileName, ios::out | ios::ate
+ | ios::app);
+#endif
+ logLine("Starting log.");
+ channelList = new ChannelList();
+ serverList = new ServerList();
+ readConfig();
+ userList = new UserList(userListFileName);
+ shitList = new ShitList(shitListFileName);
+ todoList = new TodoList();
+
+ // Let's read the alias file
+ std::ifstream initFile(initFileName);
+
+ if (initFile) {
+ String temp, alias, command;
+ std::list::iterator it;
+ bool found = false;
+ userFunction *u;
+ 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 ?
+ found = false;
+ for (it = userFunctions.begin(); it != userFunctions.end(); ++it)
+ if (alias == (*it)->name) {
+ found = true;
+ break;
+ }
+ if (found) continue;
+
+ // Check that the command exists
+ found = false;
+ for (it = userFunctions.begin(); it != userFunctions.end(); ++it)
+ if (command == (*it)->name) {
+ found = true;
+ u = *it;
+ break;
+ }
+ if (!found) continue;
+
+ userFunctions.push_back (new
+ userFunction((char *)(const char *)alias,
+ u->function,
+ u->minLevel,
+ u->needsChannelName));
+ }
+ }
+
+ std::srand (std::time (0)); // srand for bot-random
+#ifdef USESCRIPTS
+ botInterp = new BotInterp(this, scriptLogFileName);
+ botInterp->LoadScript(autoexecFileName);
+#endif
+}
+
+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;
+ }
+ userFunction *u;
+ while (userFunctions.size() != 0) {
+ u = *userFunctions.begin();
+ userFunctions.erase(userFunctions.begin());
+ delete u;
+ }
+ wantedChannel *w;
+ while (wantedChannels.size() != 0) {
+ w = (*wantedChannels.begin()).second;
+ wantedChannels.erase(wantedChannels.begin());
+ delete w;
+ }
+ userList->save();
+ shitList->save();
+ delete channelList;
+ delete userList;
+ delete todoList;
+ delete serverList;
+ delete shitList;
+ delete serverConnection;
+ logLine("Stopping log.");
+ logFile.close();
+}
+
+void
+Bot::logLine(String line)
+{
+ tm *d;
+ std::time_t current_time = time(0);
+
+ d = localtime(¤t_time);
+ logFile << "[" << std::setfill('0') << std::setw(2)
+ << d->tm_mday << "/" << std::setfill('0') << std::setw(2)
+ << d->tm_mon + 1 << "/"
+ << d->tm_year + 1900 << " - " << std::setfill('0') << std::setw(2)
+ << d->tm_hour << ":" << std::setfill('0') << std::setw(2)
+ << d->tm_min << ":" << std::setfill('0') << std::setw(2)
+ << d->tm_sec << "] "
+ << line
+ << std::endl;
+}
+
+void
+Bot::readConfig()
+{
+ std::ifstream file(configFileName);
+ String temp;
+ int line = 1;
+
+ if (!file) {
+ logLine(String("I cannot find the file ") + configFileName);
+ return;
+ }
+
+ while (!file.eof()) {
+
+ file >> temp;
+
+ if (temp.length() == 0 || temp[0] == '#') {
+ line++;
+ continue;
+ }
+
+ StringTokenizer st(temp);
+ String command = st.nextToken('=').trim().toUpper();
+ String parameters = st.nextToken('=').trim();
+
+ if (command == "NICK" || command == "NICKNAME")
+ nickName = wantedNickName = parameters;
+ else if (command == "USERNAME")
+ userName = parameters;
+ else if (command == "IRCNAME" || command == "REALNAME")
+ ircName = parameters;
+ else if (command == "CMDCHAR" || command == "COMMAND")
+ commandChar = parameters[0];
+ else if (command == "USERLIST")
+ userListFileName = parameters;
+ else if (command == "SHITLIST")
+ shitListFileName = parameters;
+ else if (command == "CHANNEL") {
+ if (parameters.indexOf(':') == -1) {
+ std::cout << "Warning. The 'channel' syntax has changed."
+ << " Please see the README file for more information."
+ << " I will use compatibility mode, but you're really"
+ << " missing something.\n";
+ StringTokenizer st2(parameters);
+ String name = st2.nextToken().toLower();
+ String key = st2.nextToken();
+ 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(':');
+ wantedChannels[name] = new wantedChannel(mode, keep, key);
+ }
+ }
+ else if (command == "LOGFILE")
+ logFileName = parameters;
+#ifdef USESCRIPTS
+ else if (command == "SCRIPTLOGFILE")
+ scriptLogFileName = parameters;
+ else if (command == "AUTOEXECFILE")
+ autoexecFileName = parameters;
+#endif
+ else if (command == "INITFILE")
+ initFileName = parameters;
+ else if (command == "LOCALIP")
+ localIP = 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());
+ serverList->addServer(new Server(name,
+ port,
+ st2.nextToken()));
+ }
+ }
+ else {
+ logLine(String("Syntax error in file ") + configFileName +
+ ", line " + String((long)line));
+ file.close();
+ std::exit(1);
+ }
+
+ line++;
+ }
+
+ file.close();
+}
+
+void
+Bot::run()
+{
+ nextServer();
+
+ while (!stop) {
+ waitForInput(); // This is the main event loop
+ if (!serverConnection->queue->flush())
+ nextServer();
+ }
+}
+
+void
+Bot::waitForInput()
+{
+#ifdef _HPUX_SOURCE
+ int rd;
+#else
+ fd_set rd;
+#endif
+ struct timeval timer;
+
+ int sock = serverConnection->getFileDescriptor();
+ int maxSocketNumber = sock;
+
+#ifdef _HPUX_SOURCE
+ rd = sock;
+#else
+ FD_ZERO(&rd);
+ FD_SET(sock, &rd);
+#endif
+
+ for (std::list::iterator it = dccConnections.begin();
+ it != dccConnections.end(); ++it) {
+ int s = (*it)->getFileDescriptor();
+#ifdef _HPUX_SOURCE
+ rd |= s;
+#else
+ FD_SET(s, &rd);
+#endif
+ if (s > maxSocketNumber)
+ maxSocketNumber = s;
+ }
+
+ timer.tv_sec = 1;
+ timer.tv_usec = 0;
+
+ switch (select(maxSocketNumber + 1, &rd, NULL, NULL, &timer)) {
+ case 0: /* timeout */
+ break;
+ case -1: /* error */
+ break;
+ default: /* normal */
+#ifdef _HPUX_SOURCE
+ if (rd & sock)
+#else
+ if (FD_ISSET(sock, &rd))
+#endif
+ 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);
+ }
+ }
+ }
+ }
+
+ if (currentTime < std::time(NULL)) { // Actions that we do each second
+ currentTime = std::time(NULL);
+ 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);
+ }
+#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));
+ }
+#endif
+
+ }
+
+ if (currentTime >= (time_t)(lastNickNameChange + Bot::NICK_CHANGE) &&
+ nickName != wantedNickName) {
+ lastNickNameChange = currentTime;
+ serverConnection->queue->sendNick(wantedNickName);
+ }
+
+ if (currentTime >= (std::time_t)(lastChannelJoin + Bot::CHANNEL_JOIN)) {
+ lastChannelJoin = currentTime;
+ for (std::map >::iterator it =
+ wantedChannels.begin(); it != wantedChannels.end();
+ ++it)
+ if (channelList->getChannel((*it).first) == 0)
+ 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::TIMEOUT)) {
+ sentPing = false;
+ nextServer();
+ }
+}
+
+// We can change server if we will not lose op on a channel
+bool
+Bot::canChangeServer()
+{
+ String channel;
+ Channel *c;
+
+ for (std::map >::iterator it =
+ channelList->begin();
+ it != channelList->end(); ++it) {
+ channel = (*it).first;
+ c = channelList->getChannel(channel);
+ if (c->countOp == 1 &&
+ c->count > 1 && this->iAmOp(channel))
+ return false;
+ }
+ return true;
+}
+
+void
+Bot::nextServer()
+{
+ bool cont = false;
+
+ if (channelList)
+ channelList->clear();
+
+ if (serverConnection)
+ userList->removeFirst();
+
+ delete serverConnection;
+
+ do {
+ Server * s = serverList->nextServer();
+ if (!s) {
+ std::cout << "No server found. Exiting..." << std::endl;
+ std::exit(1);
+ }
+ serverConnection = new ServerConnection(this, s, localIP);
+ if (!serverConnection->connect()) {
+ cont = true;
+ // We sleep 10 seconds, to avoid connection flood
+ sleep(10);
+ delete serverConnection;
+ } else {
+ cont = false;
+ }
+ } while (cont);
+}
+
+void
+Bot::reconnect()
+{
+ if (channelList)
+ channelList->clear();
+
+ userList->removeFirst();
+
+ delete serverConnection;
+
+ serverConnection =
+ new ServerConnection(this, serverList->currentServer(), localIP);
+
+ serverConnection->connect();
+}
+
+void
+Bot::connect(int serverNumber)
+{
+ if (channelList)
+ channelList->clear();
+
+ userList->removeFirst();
+
+ delete serverConnection;
+
+ serverConnection =
+ new ServerConnection(this, serverList->get(serverNumber), localIP);
+
+ serverConnection->connect();
+}
+
+void
+Bot::addDCC(Person * from, unsigned long address, int port)
+{
+ DCCConnection * d = new DCCConnection(this, from->getAddress(),
+ address, port);
+
+ if (!d->connect())
+ return;
+
+ dccConnections.push_back(d);
+}
+
+void
+Bot::rehash()
+{
+ for (std::map >::iterator it = channelList->begin();
+ it != channelList->end(); ++it)
+ serverConnection->queue->sendWho((*it).first);
+}
+
+String
+Bot::getUserhost(String channel, String nick)
+{
+ Channel *c;
+
+ if (channel == "")
+ c = 0;
+ else
+ c = channelList->getChannel(channel);
+
+ nick = nick.toLower();
+
+
+ if (c && c->hasNick(nick))
+ return c->getUser(nick)->userhost;
+
+ unsigned long num = sentUserhostID++;
+
+ serverConnection->queue->sendUserhost(nick);
+ userhostMap[num] = "+";
+
+ while (userhostMap[num] == "+") {
+ waitForInput();
+ serverConnection->queue->flush();
+ }
+
+ // We have got our answer
+ String res = userhostMap[num];
+ userhostMap.erase(num);
+
+ return res;
+}
+
+bool
+Bot::iAmOp(String channel)
+{
+ User * me = channelList->getChannel(channel)->getUser(nickName);
+ return (me->mode & User::OP_MODE);
+}
hunk ./source/Bot.H 1
+// Bot.H -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (c) 2002 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
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#ifndef BOT_H
+#define BOT_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+
+#include "String.H"
+#include "Person.H"
+#include "ServerList.H"
+#include "ChannelList.H"
+#include "UserList.H"
+#include "ShitList.H"
+#include "TodoList.H"
+#include "Parser.H"
+
+#ifdef USESCRIPTS
+#include "BotInterp.H"
+#include
+// FIXME: remove guile/gh once transition is complete
+// This is the last reference to this header!
+#include
+#endif
+
+#define VERSION_STRING PACKAGE" version "VERSION" by unknown_lamer@OPN \n1.97 and below by eb@IRCNet "
+#define COPYRIGHT_STRING PACKAGE" version "VERSION", Copyright (C) 1997-2000 Etienne BERNARD\nCopyright (C) 2002 Clinton Ebadi"
+
+class Channel;
+class DCCConnection;
+class Parser;
+class DCCParser;
+class ServerConnection;
+class Commands;
+class UserCommands;
+class Utils;
+
+class Bot {
+public:
+ String nickName;
+ String wantedNickName;
+ String userName;
+ String ircName;
+ String versionString;
+ String userHost;
+ String localIP;
+ char commandChar;
+
+ String configFileName;
+ String userListFileName;
+ String shitListFileName;
+ String logFileName;
+ String helpFileName;
+ String initFileName;
+#ifdef USESCRIPTS
+ String scriptLogFileName;
+ String autoexecFileName;
+#endif
+
+ std::ofstream logFile;
+
+ bool connected;
+ bool debug;
+ bool stop;
+ bool sentPing;
+
+ ChannelList * channelList;
+ UserList * userList;
+ ShitList * shitList;
+ ServerList * serverList;
+ TodoList * todoList;
+#ifdef USESCRIPTS
+ BotInterp * botInterp;
+#endif
+ std::list userFunctions;
+
+ std::map > wantedChannels;
+
+ std::map > ignoredUserhosts;
+ std::map > spyList;
+
+ std::time_t startTime, currentTime, lastNickNameChange, lastChannelJoin;
+
+ ServerConnection * serverConnection;
+ std::list dccConnections;
+
+ std::map > userhostMap;
+ unsigned long sentUserhostID;
+ unsigned long receivedUserhostID;
+
+ static const unsigned int MAX_MESSAGES = 2;
+ static const std::time_t NICK_CHANGE = 60;
+ static const std::time_t CHANNEL_JOIN = 60;
+ static const std::time_t IGNORE_DELAY = 180;
+ static const std::time_t DCC_DELAY = 300;
+ static const std::time_t PING_TIME = 90;
+ static const std::time_t TIMEOUT = 120;
+
+public:
+
+ Bot(String, bool=false);
+ ~Bot();
+
+ void run();
+
+ void waitForInput();
+
+ void logLine(String);
+ void readConfig();
+
+ void reconnect();
+
+ friend class Parser;
+ friend class DCCParser;
+ friend class Person;
+ friend class Channel;
+ friend class Utils;
+ friend class ServerConnection;
+ friend class UserCommands;
+ friend class Commands;
+
+private:
+ bool canChangeServer();
+ void nextServer();
+ void connect(int);
+
+ void addDCC(Person *, unsigned long, int);
+
+ void rehash();
+ String getUserhost(String, String);
+ bool iAmOp(String);
+};
+
+#endif
hunk ./source/BotInterp.C 1
+// BotInterp.C -*- C++ -*-
+// Copyright (c) 1998 Etienne BERNARD
+// Copyright (C) 2002 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
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "Utils.H"
+#include "Bot.H"
+#include "BotInterp.H"
+
+#ifdef USESCRIPTS
+
+#include
+extern "C"
+{
+#include
+}
+
+BotInterp::BotInterp(Bot *b, String fn)
+ : bot(b), counter(0)
+{
+ logPort = scm_open_file(Utils::string2SCM(fn),
+ Utils::string2SCM("a"));
+ scm_gc_protect_object(logPort);
+}
+
+void
+BotInterp::Execute(String command)
+{
+ Interp::Execute(bot, command);
+}
+
+void
+BotInterp::LoadScript(String filename)
+{
+ Interp::LoadScript(bot, filename);
+}
+
+void
+BotInterp::ScriptLog(SCM throw_args)
+{
+ scm_display_error_message(SCM_CADR (throw_args),
+ SCM_CADDR (throw_args),
+ logPort);
+ scm_flush(logPort);
+}
+
+bool
+BotInterp::AddHook(int hooktype, SCM regex, SCM function, int pri, bool fall) {
+ if (scm_string_p(regex) == SCM_BOOL_F)
+ return false;
+ String rx = Utils::scm2String(regex).toUpper();
+ SCM r = scm_make_regexp(regex,
+ scm_listify (gh_lookup("regexp/icase"),
+ SCM_UNDEFINED));
+ scm_gc_protect_object(r);
+ scm_gc_protect_object(function);
+ // First, we check if an hook doesn't exist yet
+ std::list::iterator it = hooksMap[hooktype].begin();
+ std::list::iterator it2 = hooksMap[hooktype].end();
+ for ( ; it != it2; ++it)
+ // It exists, we replace it.
+ if ((*it)->regex_str == rx) {
+ scm_gc_unprotect_object((*it)->function);
+ scm_gc_unprotect_object (r);
+ (*it)->function = function;
+ (*it)->priority = pri;
+ (*it)->fallthru = fall;
+ hooksMap[hooktype].sort ();
+ return true;
+ }
+ // It does not exist, we create it
+ hooksMap[hooktype].push_back (new Hook(hooktype, rx, r,
+ function, pri, fall));
+ hooksMap[hooktype].sort ();
+ return true;
+}
+
+bool
+BotInterp::RunHooks(int hooktype, String match, SCM args)
+{
+ SCM result;
+ std::list::iterator it = hooksMap[hooktype].begin();
+ std::list::iterator it2 = hooksMap[hooktype].end();
+ wrapper_data wd;
+ wd.args = args;
+ for ( ; it != it2; ++it) {
+ if (scm_regexp_exec((*it)->regex, Utils::string2SCM(match),
+ SCM_UNDEFINED, SCM_UNDEFINED) != SCM_BOOL_F)
+ {
+ wd.func = (*it)->function;
+ result = gh_catch(SCM_BOOL_T,
+ (scm_t_catch_body) scm_apply_wrapper,
+ static_cast (&wd),
+ (scm_t_catch_handler) Interp::ErrorHandler, 0);
+ if (! (*it)->fallthru)
+ break;
+ }
+ }
+ return true;
+}
+
+SCM
+BotInterp::AddTimer(int delay, SCM function)
+{
+ int when = time(NULL) + delay;
+ int c = ++counter;
+ scm_gc_protect_object(function);
+ Timer *t = new Timer(c, when, function);
+ timersList.push_back(t);
+ return scm_long2num (c);
+}
+
+bool
+BotInterp::DelTimer(SCM timer)
+{
+ int count = scm_num2long(timer, SCM_ARG1, "BotInterp::DelTimer");
+ std::list::iterator it = timersList.begin();
+ std::list::iterator it2 = timersList.end();
+
+ for ( ; it != it2; ++it) {
+ if ((*it)->count == count) {
+ scm_gc_unprotect_object((*it)->function);
+ delete (*it);
+ timersList.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+BotInterp::RunTimers(int now)
+{
+ std::list::iterator it = timersList.begin();
+ std::list::iterator it2 = timersList.end();
+ std::list::iterator it3;
+ Timer *t;
+ struct wrapper_data wd;
+ wd.args = scm_listify (SCM_UNDEFINED);
+
+ while (it != it2) {
+ if ((*it)->when <= now) {
+ wd.func = (*it)->function;
+ gh_catch(SCM_BOOL_T, (scm_t_catch_body) scm_apply_wrapper,
+ (void *)&wd, (scm_t_catch_handler) Interp::ErrorHandler, 0);
+ scm_gc_unprotect_object(wd.func);
+ it3 = it;
+ ++it3;
+ delete (*it);
+ timersList.erase(it);
+ it = it3;
+ } else {
+ ++it;
+ }
+ }
+ return true;
+}
+
+#endif
hunk ./source/BotInterp.H 1
+// BotInterp.H -*- C++ -*-
+// Copyright (c) 1998 Etienne BERNARD
+// Copyright (C) 2002 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
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#ifndef BOTINTERP_H
+#define BOTINTERP_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USESCRIPTS
+
+#include
+#include
+#include "String.H"
+
+class Bot;
+
+struct Hook {
+ int type;
+ int priority;
+ bool fallthru;
+
+ String regex_str;
+ SCM regex;
+ SCM function;
+
+ Hook(int t, String rs, SCM r, SCM f, int p, bool ft)
+ : type(t), regex_str(rs), regex(r), function(f),
+ priority (p), fallthru (ft) { }
+
+ bool operator< (const Hook &h) const
+ {
+ if (fallthru && h.fallthru)
+ return priority < h.priority;
+ // fallthru-thru is > non-fallthru thru ALWAYS
+ else if (fallthru && !h.fallthru)
+ return false;
+ else if (!fallthru && h.fallthru)
+ return true;
+ else
+ return priority < h.priority;
+ }
+
+ enum {
+ ACTION, NICKNAME, SIGNOFF, CTCP, CTCP_REPLY,
+ DISCONNECT, FLOOD, INVITE, JOIN, KICK, LEAVE,
+ MODE, MESSAGE, NAMES, NOTICE, PUBLIC,
+ PUBLIC_NOTICE, RAW, TIMER, TOPIC
+ };
+};
+
+struct Timer {
+ int count;
+ std::time_t when;
+ SCM function;
+
+ Timer(int c, std::time_t t, SCM f)
+ : count(c), when(t), function(f) { }
+};
+
+class BotInterp {
+ Bot * bot;
+ SCM logPort;
+ std::map, std::less > hooksMap;
+ std::list timersList;
+ int counter;
+
+public:
+ BotInterp(Bot *, String);
+
+ void ScriptLog(SCM);
+
+ void Execute(String);
+ void LoadScript(String);
+
+ bool AddHook(int, SCM, SCM, int, bool);
+ bool RunHooks(int, String, SCM);
+
+ SCM AddTimer(int, SCM);
+ bool DelTimer(SCM);
+ bool RunTimers(int);
+
+ friend class Interp;
+ friend class ScriptCommands;
+};
+
+#endif
+#endif
hunk ./source/Channel.C 1
+// Channel.C -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2002 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
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "Macros.H"
+#include "Utils.H"
+#include "Channel.H"
+#include "StringTokenizer.H"
+#ifdef USESCRIPTS
+#include "Interp.H"
+#endif
+
+Channel::Channel(ServerConnection *c,
+ String name, String wanted = "")
+ : channelName(name.toLower()), channelTopic(""),
+ lockedTopic(false), channelMode(0), channelLimit(0),
+ channelKey(""), keepModes(DEFAULT_KEEPMODES), wantedModes(wanted), count(0),
+ countOp(0), joined(false), doMode(true), gotWho(false), cnx(c)
+{
+#ifdef HAVE_STL_CLEAR
+ channelMemory.clear();
+ channelBanlist.clear();
+#endif
+ if (c->bot->wantedChannels[channelName])
+ {
+ if (c->bot->wantedChannels[channelName]->keep != "")
+ keepModes = c->bot->wantedChannels[channelName]->keep;
+
+ if (c->bot->wantedChannels[channelName]->mode != "")
+ wantedModes = c->bot->wantedChannels[channelName]->mode;
+ }
+}
+
+Channel::~Channel()
+{
+ User *u;
+ std::map >::iterator it;
+
+ while (channelMemory.size() != 0) {
+ it = channelMemory.begin();
+ u = (*it).second;
+ if (u && u->userListItem && u->userListItem->identified > 0)
+ u->userListItem->identified--;
+ channelMemory.erase(it);
+ delete u;
+ }
+
+ BanEntry *b;
+ std::vector::iterator it2;
+
+ while (channelBanlist.size() != 0) {
+ it2 = channelBanlist.begin();
+ b = *it2;
+ channelBanlist.erase(it2);
+ delete b;
+ }
+}
+
+void
+Channel::addNick(String n, String uh, int mode, UserList *ul,
+ bool names)
+{
+ if (User * u = getUser(n.toLower())) {
+ count--;
+ if (u->mode & User::OP_MODE)
+ countOp--;
+ channelMemory.erase(n.toLower());
+ delete u;
+ }
+
+ User *u;
+
+ if (names)
+ u = new User(n, mode);
+ else
+ u = new User(n, uh, channelName, mode, ul);
+
+ channelMemory[n.toLower()] = u;
+
+ if (u->userListItem) {
+ if (u->userListItem->identified)
+ u->userListItem->identified++;
+ else {
+ if (u->userListItem->passwd == "")
+ u->userListItem->identified = 1;
+ }
+ }
+
+ count++;
+ if (u->mode & User::OP_MODE)
+ countOp++;
+}
+
+void
+Channel::delNick(String n)
+{
+ n = n.toLower();
+ User *u = getUser(n);
+
+ if (!u)
+ return;
+
+ if (channelMemory[n]!=0) {
+ channelMemory.erase(n);
+ }
+
+ count--;
+ if (u->mode & User::OP_MODE)
+ countOp--;
+ if (u->userListItem && u->userListItem->identified > 0)
+ u->userListItem->identified--;
+ delete u;
+}
+
+void
+Channel::changeNick(String on, String nn)
+{
+ on = on.toLower();
+ User *u = getUser(on);
+ channelMemory.erase(on);
+ channelMemory[nn.toLower()] = u;
+}
+
+bool
+Channel::hasNick(String n)
+{
+ return getUser(n.toLower()) != 0;
+}
+
+User *
+Channel::getUser(String n)
+{
+ User *u;
+
+ n = n.toLower();
+
+ if ((u = channelMemory[n]) == 0) {
+ channelMemory.erase(n);
+ return 0;
+ }
+
+ return u;
+}
+
+void
+Channel::addBan(String mask, std::time_t expiration)
+{
+ for (std::vector::iterator it = channelBanlist.begin();
+ it != channelBanlist.end(); ++it)
+ if ((*it)->getMask() == mask) {
+ if (expiration > (*it)->getExpirationDate())
+ (*it)->setExpirationDate(expiration);
+ return;
+ }
+ channelBanlist.push_back(new BanEntry(mask, expiration));
+}
+
+void
+Channel::delBan(String mask)
+{
+ for (std::vector::iterator it = channelBanlist.begin();
+ it != channelBanlist.end(); ++it)
+ if (mask == (*it)->getMask()) {
+ BanEntry *b = *it;
+ channelBanlist.erase(it);
+ delete b;
+ break;
+ }
+}
+
+void
+Channel::resynchModes()
+{
+ cnx->queue->sendChannelMode(String("MODE ") + channelName +
+ " +" + cnx->bot->wantedChannels[channelName]->mode);
+}
+
+void
+Channel::parseMode(Person *from, String mode)
+{
+ char sign = '-';
+ StringTokenizer st(mode);
+ String m = st.nextToken(), n;
+ User *u = 0;
+ if (from)
+ u = getUser(from->getNick());
+ // u == 0 if it's a server mode
+ bool doNotObey = !u || (u->getProt() <= User::NO_PROT);
+ if (!gotWho)
+ doNotObey = false;
+
+ for (int i = 0; i < m.length(); i++)
+ switch(m[i]) {
+ case '+':
+ case '-':
+ sign = m[i];
+ break;
+ case 'p': sign =='+' ? channelMode |= PRIVATE :
+ channelMode &= ~PRIVATE;
+ if (keepModes.find('p') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('p') != -1)
+ cnx->queue->sendChannelMode(channelName, "+p", "");
+ else
+ cnx->queue->sendChannelMode(channelName, "-p", "");
+ }
+ break;
+ case 's': sign =='+' ? channelMode |= SECRET :
+ channelMode &= ~SECRET;
+ if (keepModes.find('s') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('s') != -1)
+ cnx->queue->sendChannelMode(channelName, "+s", "");
+ else
+ cnx->queue->sendChannelMode(channelName, "-s", "");
+ }
+ break;
+ case 'i': sign =='+' ? channelMode |= INVITE_ONLY :
+ channelMode &= ~INVITE_ONLY;
+ if (keepModes.find('i') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('i') != -1)
+ cnx->queue->sendChannelMode(channelName, "+i", "");
+ else
+ cnx->queue->sendChannelMode(channelName, "-i", "");
+ }
+ break;
+ case 't': sign =='+' ? channelMode |= TOPIC_RESTRICTED :
+ channelMode &= ~TOPIC_RESTRICTED;
+ if (keepModes.find('t') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('t') != -1)
+ cnx->queue->sendChannelMode(channelName, "+t", "");
+ else
+ cnx->queue->sendChannelMode(channelName, "-t", "");
+ }
+ break;
+ case 'n': sign =='+' ? channelMode |= EXTMSG_RESTRICTED :
+ channelMode &= ~EXTMSG_RESTRICTED;
+ if (keepModes.find('n') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('n') != -1)
+ cnx->queue->sendChannelMode(channelName, "+n", "");
+ else
+ cnx->queue->sendChannelMode(channelName, "-n", "");
+ }
+ break;
+ case 'm': sign =='+' ? channelMode |= MODERATED :
+ channelMode &= ~MODERATED;
+ if (keepModes.find('m') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('m') != -1)
+ cnx->queue->sendChannelMode(channelName, "+m", "");
+ else
+ cnx->queue->sendChannelMode(channelName, "-m", "");
+ }
+ break;
+ case 'l':
+ if (keepModes.find('l') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('l') != -1)
+ cnx->queue->sendChannelMode(channelName, "+l",
+ String((long)channelLimit));
+ else
+ cnx->queue->sendChannelMode(channelName, "-l", "");
+ }
+ channelLimit = (sign == '+' ? atoi(st.nextToken()) :
+ channelLimit = 0);
+ break;
+ case 'k':
+ channelKey = st.nextToken();
+ if (keepModes.find('k') != -1 && doNotObey) {
+ if (sign == '-' && wantedModes.find('k') != -1)
+ cnx->queue->sendChannelMode(channelName, "+k", channelKey);
+ else
+ cnx->queue->sendChannelMode(channelName, "-k", channelKey);
+ }
+ cnx->bot->wantedChannels[channelName]->key = (sign == '+' ? channelKey :
+ String(""));
+ break;
+ case 'o':
+ n = st.nextToken();
+ u = getUser(n);
+ if (joined)
+ sign == '+' ? countOp++ : countOp--;
+ if (!u)
+ break;
+ sign == '+' ? (u->mode |= User::OP_MODE) :
+ (u->mode &= ~User::OP_MODE);
+ if (sign == '-' && u->getProt() >= User::NO_DEOP) {
+ String fromNick = from->getNick();
+ User * v = getUser(fromNick);
+ if (u == v)
+ return;
+ if (v->getProt() < User::NO_DEOP)
+ cnx->queue->sendChannelMode(channelName, "-o", fromNick);
+ cnx->queue->sendChannelMode(channelName, "+o", n);
+ }
+ if (sign == '+') {
+ if (doNotObey && !from &&
+ u->getProt() < User::NO_DEOP && !u->getAop())
+ cnx->queue->sendChannelMode(channelName, "-o", n);
+ ShitEntry * se =
+ cnx->bot->shitList->getShit(n+"!"+cnx->bot->getUserhost(channelName, n),
+ channelName);
+ if (se && se->isStillValid() &&
+ se->getShitLevel() >= ShitEntry::SHIT_NOOP)
+ cnx->queue->sendChannelMode(channelName, "-o", n);
+ if (n.toLower() == cnx->bot->nickName.toLower() && doMode) {
+ doMode = false;
+ resynchModes();
+ }
+ }
+ break;
+ case 'v':
+ u = getUser(st.nextToken());
+ u->mode = (sign == '+' ? u->mode |= User::VOICE_MODE :
+ u->mode &= ~User::VOICE_MODE);
+ break;
+ case 'b':
+ String m = st.nextToken();
+ sign == '+' ? addBan(m) : delBan(m);
+ if (sign == '-') {
+ ShitEntry * se =
+ cnx->bot->shitList->getShit(m, channelName);
+ if (se && se->isStillValid() &&
+ se->getShitLevel() >= ShitEntry::SHIT_NODEBAN)
+ cnx->queue->sendChannelMode(channelName, "+b", m);
+ }
+ }
+}
hunk ./source/Channel.H 1
+// Channel.H -*- C++ -*-
+// Copyright (c) 1997, 1998 Etienne BERNARD
+// Copyright (C) 2002 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
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// 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.
+
+#ifndef CHANNEL_H
+#define CHANNEL_H
+
+#include
+#include