[[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:

+ + + +

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:

+ + + +

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:

+ + + +

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.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SyntaxDefault valueMeaning
NICK=<nickname>
+ NICKNAME=<nickname>
BobotThis is the nickname of the bot
USERNAME=<username>botThe 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.usersThe userlist file
LOGFILE=<file name>logThe log file (may be set to /dev/null if you do + not want to log...
SERVER=<server name> [<port> [<password>]]NoneThe 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>]NoneThe 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> + + + + + + + + + + + + + + + + + + + + +
0No level - Impossible to execute commands. This is + for bots, for example.
1User level - Will be able to execute many of the + commands, but will not be able to use masks on kicks + and on bans.
2Trusted user level - Exactly the same commands as + the ``User'' level, except that the user will be able + to use masks on bans and kicks.
3Friend level - Can do everything on the bot, except + stopping it. Be careful of who your friends are :-)
4Master level - Can do everything on the bot.
+
<protection> + + + + + + + + + + + + + + + + +
0No protection - for nearly everybody.
1No ban - it will be impossible to ban the user, + directly or indirectly.
2No kick - if the user is kicked, there will be a + revenge.
3No deop - The bot will insure that the user can not + be deopped. Useful for bots.
+
<aop> + + + + + + + + +
0No auto-op on join.
1Auto-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 reasonThis will kick foo out of channel + #test1.
#test1> !kick #test1 foo reasonThis will also kick foo out of channel + #test1.
#test1> !kick #test2 foo reasonThis will kick foo out of channel + #test2.
-> *bot* !kick #test1 foo reasonThis will kick foo out of channel + #test1.
-> *bot* !kick #test2 foo reasonThis will kick foo out of channel + #test2.
-> *bot* !kick foo reasonThis 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++:

+ + + +

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 +#include + +#include "User.H" +#include "Person.H" +#include "ServerConnection.H" +#include "BanEntry.H" + +class Bot; +class Parser; +class Commands; +class UserCommands; + +#define DEFAULT_KEEPMODES "iklmnpst" + +// This struct is used to keep information about +// the channel we want to join, the modes we +// want to set/keep on these channels, and the +// channel keys +struct wantedChannel { + String mode; + String keep; + String key; + + wantedChannel(String m, String kp, String ky) + : mode(m), keep(kp), key(ky) { } +}; + +class Channel { + String channelName; + String channelTopic; + bool lockedTopic; + int channelMode; + int channelLimit; + String channelKey; + String keepModes; + String wantedModes; + + int count; + int countOp; + bool joined; + bool doMode; + bool gotWho; + std::map > channelMemory; + std::vector channelBanlist; + ServerConnection * cnx; + +public: + + enum { + PRIVATE = 1, // +p + SECRET = 2, // +s + INVITE_ONLY = 4, // +i + TOPIC_RESTRICTED = 8, // +t + EXTMSG_RESTRICTED = 16, // +n + MODERATED = 32, // +m + HAS_KEY = 64, // +k + IS_LIMITED = 128 // +l + }; + + Channel(ServerConnection *, String, String); + ~Channel(); + + void addNick(String, String, int, UserList *, bool = false); + void delNick(String); + void changeNick(String, String); + bool hasNick(String); + User * getUser(String); + + void addBan(String, std::time_t = -1); + void delBan(String); + + void parseMode(Person *, String); + void resynchModes(); + + friend class Bot; + friend class Parser; + friend class Commands; + friend class UserCommands; +}; + +#endif hunk ./source/ChannelList.C 1 +// ChannelList.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 "ChannelList.H" +#ifdef USESCRIPTS +#include "Interp.H" +#endif + +ChannelList::ChannelList() +{ +#ifdef HAVE_STL_CLEAR + channel_list.clear(); +#endif +} + +ChannelList::~ChannelList() +{ + Channel *c; + std::map >::iterator it; + + while (channel_list.size()!=0) { + it = channel_list.begin(); + c = (*it).second; + channel_list.erase(it); + delete c; + } +} + +void +ChannelList::addChannel(ServerConnection *cnx, String name, String wantedModes) +{ + name = name.toLower(); + channel_list[name] = new Channel(cnx, name, wantedModes); +} + +void +ChannelList::delChannel(String name) +{ + name = name.toLower(); + Channel *c = channel_list[name]; + if (c != 0) { + channel_list.erase(name); + delete c; + } +} + +Channel * +ChannelList::getChannel(String name) +{ + name = name.toLower(); + Channel *c = channel_list[name]; + + if (c) + return c; + + channel_list.erase(name); + return 0; +} + +void +ChannelList::clear() +{ + Channel *c; + std::map >::iterator it; + + while (channel_list.size() != 0) { + it = channel_list.begin(); + c = (*it).second; + channel_list.erase(it); + delete c; + } +} hunk ./source/ChannelList.H 1 +// ChannelList.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 CHANNELLIST_H +#define CHANNELLIST_H + +#include + +#include "String.H" +#include "ServerConnection.H" +#include "Channel.H" + +class Utils; +class UserCommands; + +class ChannelList { + std::map > channel_list; + +public: + ChannelList(); + ~ChannelList(); + + void addChannel(ServerConnection *, String, String = ""); + void delChannel(String); + + Channel * getChannel(String); + + void clear(); + + std::map >::iterator begin() + { return channel_list.begin(); } + std::map >::iterator end() + { return channel_list.end(); } + + friend class Utils; + friend class UserCommands; +}; + +#endif hunk ./source/Commands.C 1 +// Commands.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 +// 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 "Macros.H" +#include "Message.H" +#include "Commands.H" +#include "Utils.H" + +#define Ok (Message(0, "")) +#define NotOnChannel(c) (Message(-1, String("I am not on channel ") + (c))) +#define NotChannelOp(c) (Message(-2, String("I am not channel op on ") + (c))) +#define UserNotFound(w, c) (Message(-3, (w) + " is not on channel " + (c))) +#define UserNotOp(w, c) (Message(-4, (w) + " is not channel op on " + (c))) +#define UserProtected(w, c) (Message(-5, (w) + " is protected on " + (c))) +#define InvalidNick(n) (Message(-6, (n) + " is not a valid nickname")) +#define InvalidChannel(c) (Message(-7, (c) + " is not a valid channel name")) +#define MassOpNotAllowed (Message(-8, "Mass op is not allowed.")) +#define UserOnShitList(w) (Message(-9, String("User ") + w + " is on my shitlist")) +#define CanNotChangeTopic(c) (Message(-10, String("I can not change topic on ") + (c))) +#define TopicLocked(c) (Message(-11, String("Topic is locked on ") + (c))) +#define InvalidPort(p) (Message(-12, String((long)(p)) + " is an invalid port number")) +#define InvalidTime(t) (Message(-13, String((long)(t)) + " is an invalid time")) +#define CanNotChangeServer (Message(-14, "I cannot change server without loosing op on one of my channels")) +#define EmptyServerList (Message(-15, "Server list is empty")) +#define InvalidServerNumber(n) (Message(-16, String((long)(n)) + " is an invalid server number")) +#define InvalidParameters (Message(-17, "Invalid parameters")) +#define NotFound(w) (Message(-18, String("I can not find ") + (w))); +#define NotInUserlist(w) (Message(-19, (w) + " is not in my userlist")) +#define NotInShitlist(w) (Message(-20, (w) + " is not in my shitlist")) +#define AlreadyInUserlist(m, mc) (Message(-21, (m) + " is already in userlist on channel(s) " + (mc))) +#define AlreadyInShitlist(m, mc) (Message(-22, (m) + " is already in shitlist on channel(s) " + (mc))) +#define EmptyMessage (Message(-23, "Can not send an empty message")) +#define EmptyAddressee (Message(-24, "Can not send to nobody")) +#define NotToChannel (Message(-25, "Can not send to a channel. Use \"say\" instead.")) +#define NotConnected (Message(-26, "Not connected.")) + +#define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected + +Message +Commands::Action(Bot *bot, String channel, String message) +{ + CHECK_CONNECTION; + + if (!CHANNEL(channel)) + return NotOnChannel(channel); + + if (message.length() == 0) + return InvalidParameters; + + QUEUE->sendPrivmsg(channel, String("\001ACTION ") + + message + "\001"); + + return Ok; +} + +Message +Commands::AddUser(Bot *bot, String who, String maskChannel, int level, + int prot, bool aop, std::time_t expire, String password) +{ + // Gah, fix this (makes bot segfault) + if (who.length() == 0 || + maskChannel.length() == 0 || + level < 0 || + level > User::FRIEND || + prot < 0 || + prot > User::NO_DEOP) + return InvalidParameters; + + String mask; + + if (!Utils::isWildcard(who)) + { + mask = bot->getUserhost("", who); + if (mask.length() == 0) + return NotFound(who); + } + // Aha! This was before the brace...segfault gone + mask = Utils::makeWildcard(mask); + + if (bot->userList->isInUserList(mask, maskChannel)) + return AlreadyInUserlist(mask, maskChannel); + + bot->userList->addUser(mask, maskChannel, level, prot, aop, + expire, password); + bot->rehash(); + + return Ok; +} + + +Message +Commands::AddServer(Bot *bot, String servername, int port) +{ + if (port <= 0) + return InvalidPort(port); + + bot->serverList->addServer(new class Server(servername, port)); + + return Ok; +} + + +Message +Commands::AddShit(Bot *bot, String mask, String maskChannel, + int level, time_t expiration, String reason) +{ + if (mask.length() == 0 || maskChannel.length() == 0 || + level < 0 || level > ShitEntry::SHIT_NODEBAN) + return InvalidParameters; + + if (reason == "") + reason = "You're on my shitlist, lamer"; + + String who = mask; + + if (!Utils::isWildcard(mask)) { + mask = bot->getUserhost("", who); + if (mask.length() == 0) + return NotFound(who); + mask = Utils::makeWildcard(mask); + if (bot->shitList->getShit(mask, maskChannel)) + return AlreadyInShitlist(mask, maskChannel); + } + + if (bot->userList->getMaxProt(mask, maskChannel) > 0) + return UserProtected(who, maskChannel); + + bot->shitList->addShit(mask, maskChannel, level, expiration, reason); + + return Ok; +} + + +Message +Commands::Ban(Bot *bot, String channel, String who) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + String dest; + + if (!Utils::isWildcard(who)) + dest = bot->getUserhost(channel, who); + else + dest = who; + + if (dest.length() == 0) + return NotFound(who); + + dest = Utils::makeWildcard(dest); + Mask m(dest); + + for (std::list::iterator it = bot->userList->l.begin(); + it != bot->userList->l.end(); + it++) + if (m.matches((*it)->mask) && + (*it)->channelMask.matches(channel) && + (*it)->prot >= User::NO_BAN) + return UserProtected(who, channel); + + for (std::vector::iterator it = c->channelBanlist.begin(); + it != c->channelBanlist.end(); ++it) + if (m.matches((*it)->banMask) && (*it)->banMask.getMask() != m.getMask()) + QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask()); + + QUEUE->sendChannelMode(channel, "+b", dest); + + return Ok; +} + +Message +Commands::Cycle(Bot *bot, String channel) +{ + CHECK_CONNECTION; + + if (!CHANNEL(channel)) + return NotOnChannel(channel); + + QUEUE->sendPart(channel); + QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key); + + return Ok; +} + +Message +Commands::Deban(Bot *bot, String channel, String who) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + String dest; + + if (!Utils::isWildcard(who)) + dest = bot->getUserhost(channel, who); + else + dest = who; + + if (dest.length() == 0) + return UserNotFound(who, channel); + + dest = Utils::makeWildcard(dest); + Mask m(dest); + + for (std::vector::iterator it = c->channelBanlist.begin(); + it != c->channelBanlist.end(); ++it) + if (m.matches((*it)->getMask())) { + // Let's see if the ban is in the shitlist + ShitEntry *se = bot->shitList->getShit((*it)->getMask(), channel); + if (!se || !se->isStillValid() || + se->getShitLevel() < ShitEntry::SHIT_NODEBAN) + QUEUE->sendChannelMode(channel, "-b", (*it)->getMask()); + } + + return Ok; +} + +Message +Commands::DelServer(Bot *bot, int number) +{ + if (number < 0 || number >= bot->serverList->size()) + return InvalidServerNumber(number); + + bot->serverList->delServer(number); + + return Ok; +} + +Message +Commands::DelUser(Bot *bot, String who, String maskChannel) +{ + if (who.length() == 0 || maskChannel.length() == 0) + return InvalidParameters; + + String dest; + + if (!Utils::isWildcard(who)) { + dest = bot->getUserhost("", who); + if (dest.length() == 0) + return NotFound(who); + dest = Utils::makeWildcard(who); + } + + if (!bot->userList->isInUserList(dest, maskChannel)) + return NotInUserlist(who); + + bot->userList->removeUser(dest, maskChannel); + bot->rehash(); + + return Ok; +} + +Message +Commands::DelShit(Bot *bot, String who, String maskChannel) +{ + if (who.length() == 0 || maskChannel.length() == 0) + return InvalidParameters; + + String dest; + + if (!Utils::isWildcard(who)) { + dest = bot->getUserhost("", who); + if (dest.length() == 0) + return NotFound(who); + dest = Utils::makeWildcard(who); + } + + if (!bot->shitList->getShit(dest, maskChannel)) + return NotInShitlist(who); + + bot->shitList->delShit(dest, maskChannel); + + return Ok; +} + +Message +Commands::Deop(Bot *bot, String channel, String who) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + if (!Utils::isWildcard(who)) { + User *u = c->getUser(who); + if (!u) + return UserNotFound(who, channel); + if (!(u->mode & User::OP_MODE)) + return UserNotOp(who, channel); + if (u->getProt() >= User::NO_DEOP) + return UserProtected(who, channel); + QUEUE->sendChannelMode(channel, "-o", who); + } else { + Mask m(who); + for (std::map >::iterator + it = c->channelMemory.begin(); + it != c->channelMemory.end(); ++it) { + if (m.matches((*it).second->nick + "!" + + (*it).second->userhost) && + (*it).second->getProt() < User::NO_DEOP && + ((*it).second->mode & User::OP_MODE)) + QUEUE->sendChannelMode(channel, "-o", (*it).second->nick); + } + } + + return Ok; +} + +Message +Commands::Die(Bot *bot, String reason) +{ + CHECK_CONNECTION; + + QUEUE->sendQuit(reason); + bot->stop = true; + + return Ok; +} + +Message +Commands::Do(Bot *bot, String command) +{ + CHECK_CONNECTION; + + QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER); + return Ok; +} + +Message +Commands::Invite(Bot *bot, String channel, String who) +{ + CHECK_CONNECTION; + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + QUEUE->sendInvite(channel, who); + + return Ok; +} + +Message +Commands::Join(Bot *bot, String channel, String key) +{ + CHECK_CONNECTION; + + if (!Utils::isValidChannelName(channel)) + return InvalidChannel(channel); + + // We change the key only if we are not on the channel. + // We don't trust the user... + if (!CHANNEL(channel)) { + if (bot->wantedChannels[channel]) + bot->wantedChannels[channel]->key = key; + else { + bot->wantedChannels[channel] = new wantedChannel("", "", key); + } + } + QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key); + + return Ok; +} + +Message +Commands::Keep(Bot *bot, String channel, String modes) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + c->keepModes = modes; + + return Ok; +} + +Message +Commands::Kick(Bot *bot, String channel, String who, String reason) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + if (Utils::isWildcard(who)) { + Mask m(who); + for (std::map >::iterator it = + c->channelMemory.begin(); + it != c->channelMemory.end(); + ++it) + if (m.matches((*it).second->nick + "!" + + (*it).second->userhost) && + (*it).second->getProt() < User::NO_KICK) + QUEUE->sendKick(channel, (*it).second->nick, reason); + } else { + User * u = c->getUser(who); + if (!u) + return UserNotFound(who, channel); + if (u->getProt() < User::NO_KICK) + QUEUE->sendKick(channel, who, reason); + else + return UserProtected(who, channel); + } + + return Ok; +} + +Message +Commands::KickBan(Bot *bot, String channel, String who, String reason) +{ + CHECK_CONNECTION; + + Message m = Commands::Ban(bot, channel, who); + + if (m.getCode() == 0) + m = Commands::Kick(bot, channel, who, reason); + + return m; +} + +Message +Commands::Lock(Bot *bot, String channel) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + c->lockedTopic = true; + + return Ok; +} + +Message +Commands::Mode(Bot *bot, String channel, String mode) +{ + CHECK_CONNECTION; + + if (!CHANNEL(channel)) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode); + + return Ok; +} + +Message +Commands::Msg(Bot *bot, String who, String message) +{ + CHECK_CONNECTION; + + if (who == "") + return EmptyAddressee; + + if (Utils::isChannel(who)) + return NotToChannel; + + if (message == "") + return EmptyMessage; + + QUEUE->sendPrivmsg(who, message); + + return Ok; +} + +Message +Commands::NextServer(Bot *bot) +{ + CHECK_CONNECTION; + + if (bot->serverList->size() == 0) + return EmptyServerList; + + if (!bot->canChangeServer()) + return CanNotChangeServer; + + QUEUE->sendQuit("Changing server"); + bot->nextServer(); + + return Ok; +} + +Message +Commands::Nick(Bot *bot, String nick) +{ + CHECK_CONNECTION; + + if (nick == "" || !Utils::isValidNickName(nick)) + return InvalidNick(nick); + + bot->wantedNickName = nick; + QUEUE->sendNick(nick); + + return Ok; +} + +Message +Commands::Notice(Bot *bot, String who, String message) +{ + CHECK_CONNECTION; + + if (who == "") + return EmptyAddressee; + + if (Utils::isChannel(who)) + return NotToChannel; + + if (message == "") + return EmptyMessage; + + QUEUE->sendNotice(who, message); + + return Ok; +} + +Message +Commands::Op(Bot *bot, String channel, String who) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + if (Utils::isWildcard(who)) + return MassOpNotAllowed; + + User *u = c->getUser(who); + if (!u) + return UserNotFound(who, channel); + + ShitEntry *se = bot->shitList->getShit(who, channel); + if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP) + return UserOnShitList(who); + + QUEUE->sendChannelMode(channel, "+o", who); + + return Ok; +} + + +Message +Commands::Part(Bot *bot, String channel) +{ + CHECK_CONNECTION; + + if (!CHANNEL(channel)) + return NotOnChannel(channel); + + wantedChannel *w = bot->wantedChannels[channel]; + bot->wantedChannels.erase(channel); + delete w; + QUEUE->sendPart(channel); + + return Ok; +} + +Message +Commands::Reconnect(Bot *bot) +{ + CHECK_CONNECTION; + + if (!bot->canChangeServer()) + return CanNotChangeServer; + + QUEUE->sendQuit("Reconnecting"); + bot->reconnect(); + + return Ok; +} + +Message +Commands::Say(Bot *bot, String channel, String message) +{ + CHECK_CONNECTION; + +// if (!CHANNEL(channel)) +// return NotOnChannel(channel); + + QUEUE->sendPrivmsg(channel, message); + + return Ok; +} + + +Message +Commands::Server(Bot *bot, int number) +{ + CHECK_CONNECTION; + + if (number < 0 || number >= bot->serverList->size()) + return InvalidServerNumber(number); + + if (!bot->canChangeServer()) + return CanNotChangeServer; + + QUEUE->sendQuit("Changing server"); + QUEUE->flush(); + bot->connect(number); + + return Ok; +} + +Message +Commands::SetVersion(Bot *bot, String str) +{ + if (str.length() == 0) + return InvalidParameters; + + bot->versionString = str; + return Ok; +} + +Message +Commands::TBan(Bot *bot, String channel, String who, int seconds) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel)) + return NotChannelOp(channel); + + if (seconds <= 0) + return InvalidTime(seconds); + + String dest; + + if (!Utils::isWildcard(who)) + dest = bot->getUserhost(channel, who); + else + dest = who; + + if (dest.length() == 0) + return UserNotFound(who, channel); + + dest = Utils::makeWildcard(dest); + Mask m(dest); + + for (std::list::iterator it = bot->userList->l.begin(); + it != bot->userList->l.end(); + it++) + if (m.matches((*it)->mask) && + (*it)->channelMask.matches(channel) && + (*it)->prot >= User::NO_BAN) + return UserProtected(who, channel); + + for (std::vector::iterator it = c->channelBanlist.begin(); + it != c->channelBanlist.end(); ++it) + if (m.matches((*it)->banMask)) + QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask()); + + CHANNEL(channel)->addBan(dest, seconds); + QUEUE->sendChannelMode(channel, "+b", dest); + bot->todoList->addDeban(channel, dest, seconds); +} + + +Message +Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason) +{ + CHECK_CONNECTION; + + Message m = Commands::TBan(bot, channel, who, seconds); + + if (m.getCode() == 0) + m = Commands::Kick(bot, channel, who, reason); + + return m; +} + + +Message +Commands::Topic(Bot *bot, String channel, String topic) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED)) + return CanNotChangeTopic(channel); + + if (c->lockedTopic) + return TopicLocked(channel); + + QUEUE->sendTopic(channel, topic); + + return Ok; +} + + +Message +Commands::Unlock(Bot *bot, String channel) +{ + CHECK_CONNECTION; + + Channel *c = CHANNEL(channel); + + if (!c) + return NotOnChannel(channel); + + c->lockedTopic = false; + + return Ok; +} hunk ./source/Commands.H 1 +// Commands.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 COMMANDS_H +#define COMMANDS_H + +#include + +#include "String.H" +#include "Message.H" +#include "Bot.H" +#include "ServerConnection.H" + +class Commands { +public: + static Message Action(Bot *, String, String); + static Message AddUser(Bot *, String, String, int, int, bool, + std::time_t, String); + static Message AddServer(Bot *, String, int); + static Message AddShit(Bot *, String, String, int, std::time_t, String); + static Message AddServer(Bot *, String, String); + static Message Ban(Bot *, String, String); + static Message ChangeLevel(Bot *, String, String, int); + static Message Cycle(Bot *, String); + static Message Deban(Bot *, String, String); + static Message DelServer(Bot *, int); + static Message DelUser(Bot *, String, String); + static Message DelShit(Bot *, String, String); + static Message Deop(Bot *, String, String); + static Message Die(Bot *, String = "Leaving"); + static Message Do(Bot *, String); + static Message Invite(Bot *, String, String); + static Message Join(Bot *, String, String = ""); + static Message Keep(Bot *, String, String); + static Message Kick(Bot *, String, String, String); + static Message KickBan(Bot *, String, String, String); + static Message Lock(Bot *, String); + static Message Mode(Bot *, String, String); + static Message Msg(Bot *, String, String); + static Message NextServer(Bot *); + static Message Nick(Bot *, String); + static Message Notice(Bot *, String, String); + static Message Op(Bot *, String, String); + static Message Part(Bot *, String); + static Message Reconnect(Bot *); + static Message Say(Bot *, String, String); + static Message Server(Bot *, int); + static Message SetVersion(Bot *, String); + static Message TBan(Bot *, String, String, int); + static Message TKBan(Bot *, String, String, int, String); + static Message Topic(Bot *, String, String); + static Message Unlock(Bot *, String); +}; + +#endif hunk ./source/Connection.C 1 +// Connection.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 "Connection.H" + +Connection::Connection(String h, int p, String lip) +{ + socket.setRemoteHostname(h); + socket.setRemotePort(p); + if (lip != "") + socket.setLocalHostname(lip); +} + +Connection::Connection(unsigned long a, int p) +{ + socket.setRemoteIP(a); + socket.setRemotePort(p); +} + +Connection::~Connection() +{ } + +int +Connection::getFileDescriptor() const +{ + return socket.getFileDescriptor(); +} hunk ./source/Connection.H 1 +// Connection.H -*- 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. + +#ifndef CONNECTION_H +#define CONNECTION_H + +#include "String.H" +#include "Socket.H" + +class Connection { +public: + Connection(String, int, String); + Connection(unsigned long, int); + + virtual ~Connection(); + + int getFileDescriptor() const; + + virtual bool connect() = 0; + virtual bool handleInput() = 0; + +protected: + Socket socket; +}; + +#endif hunk ./source/DCCConnection.C 1 +// DCCConnection.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 +// 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 "Socket.H" +#include "DCCParser.H" +#include "DCCConnection.H" + +DCCConnection::DCCConnection(Bot *b, String n, unsigned long address, int port) + : Connection(address, port), bot(b), nuh(n), + lastSpoken(time(0)), autoRemove(true) +{ } + +bool +DCCConnection::connect() +{ + if (!socket.connect()) + return false; + + return true; +} + +bool +DCCConnection::handleInput() +{ + String line = socket.readLine(); + + lastSpoken = time(0); + + if (line.length() == 0) + return true; + + if (bot->debug) + std::cout << "DCC: <" << line << ">" << std::endl; + + DCCParser::parseLine(this, line); + + return false; +} + +void +DCCConnection::sendNotice(String message) +{ + socket.write(message, true); +} hunk ./source/DCCConnection.H 1 +// DCCConnection.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 +// 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 DCCCONNECTION_H +#define DCCCONNECTION_H + +#include + +#include "Connection.H" +#include "Bot.H" + +class DCCPerson; +class UserCommands; + +class DCCConnection : public Connection { + Bot *bot; + String nuh; + std::time_t lastSpoken; + bool autoRemove; + +public: + DCCConnection(Bot *, String, unsigned long, int); + + bool connect(); + bool handleInput(); + + void sendNotice(String); + + friend class Bot; + friend class DCCPerson; + friend class DCCParser; + friend class UserCommands; +}; + +#endif hunk ./source/DCCParser.C 1 +// DCCParser.C -*- C++ -*- +// Copyright (c) 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 "DCCParser.H" +#include "DCCPerson.H" +#include "Macros.H" +#include "Parser.H" +#include "Bot.H" + +void +DCCParser::parseLine(DCCConnection *cnx, String line) +{ + Person * from = new DCCPerson(cnx); + Parser::parseMessage(cnx->bot->serverConnection, from, cnx->bot->nickName, + line); + delete from; +} hunk ./source/DCCParser.H 1 +// DCCParser.H -*- 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. + +#ifndef DCCPARSER_H +#define DCCPARSER_H + +#include "String.H" +#include "DCCConnection.H" + +class DCCParser { +public: + static void parseLine(DCCConnection *, String); +}; + +#endif hunk ./source/DCCPerson.C 1 +// DCCPerson.C -*- C++ -*- +// Copyright (c) 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 "DCCPerson.H" + +DCCPerson::DCCPerson(DCCConnection *cnx) + : Person(cnx->bot, cnx->nuh), dcc(cnx) +{ } + +DCCPerson::DCCPerson(DCCPerson &p) + : Person(p), dcc(p.dcc) +{ } + +void +DCCPerson::sendNotice(String message) +{ + dcc->sendNotice(message); +} + +Person * +DCCPerson::copy() +{ + return (Person *)(new DCCPerson(*this)); +} + +void +DCCPerson::keepAlive() +{ + dcc->autoRemove = false; +} hunk ./source/DCCPerson.H 1 +// DCCPerson.H -*- C++ -*- +// Copyright (c) 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. + +#ifndef DCCPERSON_H +#define DCCPERSON_H + +#include "String.H" +#include "Person.H" +#include "DCCConnection.H" + +class DCCPerson : public Person { + DCCConnection *dcc; +public: + DCCPerson(DCCConnection *); + DCCPerson(DCCPerson &); + + Person * copy(); + + String getNick() const; + String getAddress() const; + + void keepAlive(); + + void sendNotice(String); +}; + +#endif hunk ./source/Interp.C 1 +// Interp.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 + +#ifdef USESCRIPTS + +#include "Macros.H" +#include "Commands.H" +#include "Interp.H" +#include "BotInterp.H" + +#include + +Bot * Interp::bot = 0; +#ifdef MULTITHREAD +pthread_mutex_t Interp::mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +typedef SCM (*SCMFunc)(); + +SCM +scm_apply_wrapper(void *data) +{ + wrapper_data * wd = static_cast (data); + scm_apply(wd->func, wd->args, SCM_EOL); + return SCM_BOOL_T; +} + +#define bot_new_procedure(a, b, c, d, e) scm_c_define_gsubr (a, c, d, e, b) + +void +Interp::Startup() +{ +// scm_primitive_load_path(scm_makfrom0str("ice-9/boot-9.scm")); + + bot_new_procedure ("bot-action", (SCMFunc)ScriptCommands::Action, 2, 0, 0); + scm_c_define_gsubr ("bot-adduser", 5, 2, 0, + (SCMFunc)ScriptCommands::AddUser); + bot_new_procedure ("bot-addserver", (SCMFunc)ScriptCommands::Action, + 3, 4, 0); + scm_c_define_gsubr ("bot-addshit", 3, 2, 0, + (SCMFunc)ScriptCommands::AddShit); + bot_new_procedure ("bot-ban", (SCMFunc)ScriptCommands::Action, 2, 0, 0); + bot_new_procedure ("bot-cycle", (SCMFunc)ScriptCommands::Action, 1, 0, 0); + bot_new_procedure ("bot-deban", (SCMFunc)ScriptCommands::Deban, 2, 0, 0); + bot_new_procedure ("bot-delserver", (SCMFunc)ScriptCommands::DelServer, + 1, 0, 0); + bot_new_procedure ("bot-deluser", (SCMFunc)ScriptCommands::DelUser, 2, 0, 0); + bot_new_procedure ("bot-delshit", (SCMFunc)ScriptCommands::DelShit, 2, 0, 0); + bot_new_procedure ("bot-deop", (SCMFunc)ScriptCommands::Deop, 2, 0, 0); + bot_new_procedure ("bot-die", (SCMFunc)ScriptCommands::Die, 1, 0, 0); + bot_new_procedure ("bot-do", (SCMFunc)ScriptCommands::Do, 1, 0, 0); + bot_new_procedure ("bot-invite", (SCMFunc)ScriptCommands::Invite, 2, 0, 0); + bot_new_procedure ("bot-join", (SCMFunc)ScriptCommands::Join, 1, 1, 0); + bot_new_procedure ("bot-keep", (SCMFunc)ScriptCommands::Keep, 2, 0, 0); + bot_new_procedure ("bot-kick", (SCMFunc)ScriptCommands::Kick, 2, 1, 0); + bot_new_procedure ("bot-kickban", (SCMFunc)ScriptCommands::KickBan, 2, 1, 0); + bot_new_procedure ("bot-lock", (SCMFunc)ScriptCommands::Lock, 1, 0, 0); + bot_new_procedure ("bot-logport", (SCMFunc)ScriptCommands::LogPort, 0, 0, 0); + bot_new_procedure ("bot-mode", (SCMFunc)ScriptCommands::Mode, 2, 0, 0); + bot_new_procedure ("bot-msg", (SCMFunc)ScriptCommands::Msg, 2, 0, 0); + bot_new_procedure ("bot-nextserver", (SCMFunc)ScriptCommands::NextServer, + 0, 0, 0); + bot_new_procedure ("bot-nick", (SCMFunc)ScriptCommands::Nick, 1, 0, 0); + bot_new_procedure ("bot-op", (SCMFunc)ScriptCommands::Op, 2, 0, 0); + bot_new_procedure ("bot-part", (SCMFunc)ScriptCommands::Part, 1, 0, 0); + bot_new_procedure ("bot-reconnect", (SCMFunc)ScriptCommands::Reconnect, + 0, 0, 0); + bot_new_procedure ("bot-say", (SCMFunc)ScriptCommands::Say, 2, 0, 0); + bot_new_procedure ("bot-server", (SCMFunc)ScriptCommands::Server, 1, 0, 0); + bot_new_procedure ("bot-setversion", (SCMFunc)ScriptCommands::SetVersion, + 1, 0, 0); + bot_new_procedure ("bot-tban", (SCMFunc)ScriptCommands::TBan, 3, 0, 0); + bot_new_procedure ("bot-tkban", (SCMFunc)ScriptCommands::TKBan, 3, 1, 0); + bot_new_procedure ("bot-topic", (SCMFunc)ScriptCommands::Topic, 2, 0, 0); + bot_new_procedure ("bot-unlock", (SCMFunc)ScriptCommands::Unlock, 1, 0, 0); + + bot_new_procedure ("bot-getnickname", (SCMFunc)ScriptCommands::getNickname, + 0, 0, 0); + bot_new_procedure ("bot-getserver", (SCMFunc)ScriptCommands::getServer, + 0, 0, 0); + bot_new_procedure ("bot-getserverlist", + (SCMFunc)ScriptCommands::getServerList, 0, 0, 0); + bot_new_procedure ("bot-flush", (SCMFunc)ScriptCommands::flushQueue, + 0, 0, 0); + bot_new_procedure ("bot-flushport", (SCMFunc)ScriptCommands::flushPort, + 0, 0, 0); + bot_new_procedure ("bot-random", (SCMFunc)ScriptCommands::random, + 1, 0, 0); + bot_new_procedure ("bot-addcommand", (SCMFunc)ScriptCommands::addCommand, + 5, 0, 0); + bot_new_procedure ("bot-delcommand", (SCMFunc)ScriptCommands::delCommand, + 1, 0, 0); + bot_new_procedure ("bot-addhook", (SCMFunc)ScriptCommands::AddHook, + 3, 2, 0); + bot_new_procedure ("bot-addtimer", (SCMFunc)ScriptCommands::AddTimer, + 2, 0, 0); + bot_new_procedure ("bot-deltimer", (SCMFunc)ScriptCommands::DelTimer, + 1, 0, 0); + scm_c_define ("hooks/action", scm_long2num(Hook::ACTION)); + scm_c_define ("hooks/nickname", scm_long2num(Hook::NICKNAME)); + scm_c_define ("hooks/signoff", scm_long2num(Hook::SIGNOFF)); + scm_c_define ("hooks/ctcp", scm_long2num(Hook::CTCP)); + scm_c_define ("hooks/ctcp-reply", scm_long2num(Hook::CTCP_REPLY)); + scm_c_define ("hooks/disconnect", scm_long2num(Hook::DISCONNECT)); + scm_c_define ("hooks/flood", scm_long2num(Hook::FLOOD)); + scm_c_define ("hooks/invite", scm_long2num(Hook::INVITE)); + scm_c_define ("hooks/join", scm_long2num(Hook::JOIN)); + scm_c_define ("hooks/kick", scm_long2num(Hook::KICK)); + scm_c_define ("hooks/leave", scm_long2num(Hook::LEAVE)); + scm_c_define ("hooks/part", scm_long2num(Hook::LEAVE)); + scm_c_define ("hooks/mode", scm_long2num(Hook::MODE)); + scm_c_define ("hooks/message", scm_long2num(Hook::MESSAGE)); + // scm_c_define ("hooks/names", scm_long2num(Hook::NAMES)); + scm_c_define ("hooks/notice", scm_long2num(Hook::NOTICE)); + scm_c_define ("hooks/public", scm_long2num(Hook::PUBLIC)); + scm_c_define ("hooks/public-notice", scm_long2num(Hook::PUBLIC_NOTICE)); + scm_c_define ("hooks/raw", scm_long2num(Hook::RAW)); + scm_c_define ("hooks/timer", scm_long2num(Hook::TIMER)); + scm_c_define ("hooks/topic", scm_long2num(Hook::TOPIC)); +} + +void +Interp::Shutdown() +{ } + +void +Interp::Execute(Bot *b, String command) +{ +#ifdef MULTITHREAD + // We get the lock + pthread_mutex_lock(&mutex); +#endif + bot = b; + gh_eval_str_with_catch(command, ErrorHandler); +#ifdef MULTITHREAD + // We release the lock + pthread_mutex_unlock(&mutex); +#endif +} + +void +Interp::LoadScript(Bot *b, String filename) +{ +#ifdef MULTITHREAD + // We get the lock + pthread_mutex_lock(&mutex); +#endif + bot = b; + gh_eval_file_with_catch(filename, ErrorHandler); +#ifdef MULTITHREAD + // We release the lock + pthread_mutex_unlock(&mutex); +#endif +} + +SCM +Interp::ErrorHandler(void *data, SCM tag, SCM throw_args) +{ + bot->botInterp->ScriptLog(throw_args); + return SCM_BOOL_F; +} + +#endif hunk ./source/Interp.H 1 +// Interp.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 INTERP_H +#define INTERP_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef USESCRIPTS + +#ifdef MULTITHREAD +#include +#endif + +#include "Bot.H" +#include "ScriptCommands.H" +#include + +struct wrapper_data { + SCM func; + SCM args; +}; + +SCM scm_apply_wrapper(void *); + +class Interp { +public: + static Bot *bot; +#ifdef MULTITHREAD +private: + static pthread_mutex_t mutex; +#endif +public: + static void Startup(); + static void Shutdown(); + static void Execute(Bot *, String); + static void LoadScript(Bot *, String); + static SCM ErrorHandler(void *, SCM, SCM); +}; + +#endif +#endif hunk ./source/Macros.H 1 +// Macros.H -*- 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. + +#ifndef MACROS_H +#define MACROS_H + +#define QUEUE bot->serverConnection->queue +#define CHANNEL(channelName) bot->channelList->getChannel(channelName) +#define INTERP bot->botInterp + +#endif hunk ./source/Main.C 1 +// Main.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 +#include +#include +#include + +#ifdef USESCRIPTS +#include "Interp.H" +#endif + +#include "Bot.H" + +Bot *b; + +void sig_hup(int) { + if (b) { + b->userList->read(); + b->userList->addUserFirst("bidon", "bidon", 0, 0, false, 0, ""); + b->reconnect(); + } +} + +void printUsage(char *name) +{ + std::cout << "Usage: " << name << " [-h] [-b] [-f file] [-d dir] [-D]\n" + " -h Shows this help.\n" + " -b Do not run in background.\n" + " -f file Use file as config file.\n" + " -d dir Use dir as current dir.\n" + " -D Debug mode (input/output printing and no background mode.\n"; +} + +static void real_main(void* DONOTUSE, int argc, char **argv) +{ + int opt; + extern char *optarg; + bool background = true; + String configFile = "bot.conf"; + String directory = ""; + bool debug = false; + + std::signal(SIGPIPE, SIG_IGN); + std::signal(SIGALRM, SIG_IGN); + std::signal(SIGHUP, sig_hup); + + // We parse the command line options + while ((opt = getopt(argc,argv,"hbf:d:D")) != EOF) + switch (opt) { + case 'h': + printUsage(argv[0]); exit(0); + case 'b': + background = false; + break; + case 'f': + configFile = optarg; + break; + case 'd': + directory = optarg; + break; + case 'D': + debug = true; + break; + default: + printUsage(argv[0]); exit(1); + } + + if ((directory != "") && (chdir((const char *)directory)<0)) + std::perror("Warning: "); + + std::cout << COPYRIGHT_STRING << + "\n"PACKAGE" comes with ABSOLUTELY NO WARRANTY\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions; See the COPYING file for details.\n"; + + if (!debug) { + if (background) + switch (fork()) { + case -1: + std::cout << "Could not run in the background. Exiting...\n"; + perror("fork"); + exit(1); + case 0: + break; + default: + std::cout << "Running in the background...\n"; + exit(0); + } + } + +#ifdef USESCRIPTS + Interp::Startup(); +#endif + + b = new Bot(configFile, debug); + b->run(); + delete b; + +#ifdef USESCRIPTS + Interp::Shutdown(); +#endif +} + +int main(int argc, char **argv) { +#ifdef USESCRIPTS + scm_boot_guile (argc, argv, real_main, 0); +#else + real_main(0, argc, argv); +#endif + + return 0; +} hunk ./source/Makefile.am 1 - +bin_PROGRAMS = bobotpp + +bobotpp_SOURCES = BanEntry.C \ + Bot.C \ + BotInterp.C \ + Channel.C \ + ChannelList.C \ + Commands.C \ + Connection.C \ + DCCConnection.C \ + DCCParser.C \ + DCCPerson.C \ + Interp.C \ + Main.C \ + Mask.C \ + Parser.C \ + Person.C \ + Queue.C \ + ScriptCommands.C \ + Server.C \ + ServerConnection.C \ + ServerList.C \ + ServerQueue.C \ + ServerQueueItem.C \ + ShitEntry.C \ + ShitList.C \ + Socket.C \ + String.C \ + StringTokenizer.C \ + TodoList.C \ + User.C \ + UserCommands.C \ + UserList.C \ + Utils.C \ + BanEntry.H \ + Bot.H \ + BotInterp.H \ + Channel.H \ + ChannelList.H \ + Commands.H \ + Connection.H \ + DCCConnection.H \ + DCCParser.H \ + DCCPerson.H \ + Interp.H \ + Mask.H \ + Parser.H \ + Person.H \ + Queue.H \ + ScriptCommands.H \ + Server.H \ + ServerConnection.H \ + ServerList.H \ + ServerQueue.H \ + ServerQueueItem.H \ + ShitEntry.H \ + ShitList.H \ + Socket.H \ + String.H \ + StringTokenizer.H \ + TodoList.H \ + User.H \ + UserCommands.H \ + UserList.H \ + Utils.H \ + Message.H \ + UserListItem.H \ + Macros.H +# TelnetServer.C \ +# TelnetServer.H + +## what is up with telnet stuff? + +bobotpp_LDADD = @GUILE_LDFLAGS@ hunk ./source/Makefile.in 1 +# Makefile.in generated automatically by automake 1.5 from Makefile.am. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AMTAR = @AMTAR@ +AWK = @AWK@ +CXX = @CXX@ +DEPDIR = @DEPDIR@ +EXEEXT = @EXEEXT@ +GUILE = @GUILE@ +GUILE_CFLAGS = @GUILE_CFLAGS@ +GUILE_CONFIG = @GUILE_CONFIG@ +GUILE_LDFLAGS = @GUILE_LDFLAGS@ +GUILE_SITE = @GUILE_SITE@ +GUILE_TOOLS = @GUILE_TOOLS@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ + +bin_PROGRAMS = bobotpp + +bobotpp_SOURCES = BanEntry.C \ + Bot.C \ + BotInterp.C \ + Channel.C \ + ChannelList.C \ + Commands.C \ + Connection.C \ + DCCConnection.C \ + DCCParser.C \ + DCCPerson.C \ + Interp.C \ + Main.C \ + Mask.C \ + Parser.C \ + Person.C \ + Queue.C \ + ScriptCommands.C \ + Server.C \ + ServerConnection.C \ + ServerList.C \ + ServerQueue.C \ + ServerQueueItem.C \ + ShitEntry.C \ + ShitList.C \ + Socket.C \ + String.C \ + StringTokenizer.C \ + TodoList.C \ + User.C \ + UserCommands.C \ + UserList.C \ + Utils.C \ + BanEntry.H \ + Bot.H \ + BotInterp.H \ + Channel.H \ + ChannelList.H \ + Commands.H \ + Connection.H \ + DCCConnection.H \ + DCCParser.H \ + DCCPerson.H \ + Interp.H \ + Mask.H \ + Parser.H \ + Person.H \ + Queue.H \ + ScriptCommands.H \ + Server.H \ + ServerConnection.H \ + ServerList.H \ + ServerQueue.H \ + ServerQueueItem.H \ + ShitEntry.H \ + ShitList.H \ + Socket.H \ + String.H \ + StringTokenizer.H \ + TodoList.H \ + User.H \ + UserCommands.H \ + UserList.H \ + Utils.H \ + Message.H \ + UserListItem.H \ + Macros.H + + +# TelnetServer.C \ +# TelnetServer.H +bobotpp_LDADD = @GUILE_LDFLAGS@ +subdir = source +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +bin_PROGRAMS = bobotpp$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) + +am_bobotpp_OBJECTS = BanEntry.$(OBJEXT) Bot.$(OBJEXT) \ + BotInterp.$(OBJEXT) Channel.$(OBJEXT) ChannelList.$(OBJEXT) \ + Commands.$(OBJEXT) Connection.$(OBJEXT) DCCConnection.$(OBJEXT) \ + DCCParser.$(OBJEXT) DCCPerson.$(OBJEXT) Interp.$(OBJEXT) \ + Main.$(OBJEXT) Mask.$(OBJEXT) Parser.$(OBJEXT) Person.$(OBJEXT) \ + Queue.$(OBJEXT) ScriptCommands.$(OBJEXT) Server.$(OBJEXT) \ + ServerConnection.$(OBJEXT) ServerList.$(OBJEXT) \ + ServerQueue.$(OBJEXT) ServerQueueItem.$(OBJEXT) \ + ShitEntry.$(OBJEXT) ShitList.$(OBJEXT) Socket.$(OBJEXT) \ + String.$(OBJEXT) StringTokenizer.$(OBJEXT) TodoList.$(OBJEXT) \ + User.$(OBJEXT) UserCommands.$(OBJEXT) UserList.$(OBJEXT) \ + Utils.$(OBJEXT) +bobotpp_OBJECTS = $(am_bobotpp_OBJECTS) +bobotpp_DEPENDENCIES = +bobotpp_LDFLAGS = + +DEFS = @DEFS@ +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/BanEntry.Po $(DEPDIR)/Bot.Po \ +@AMDEP_TRUE@ $(DEPDIR)/BotInterp.Po $(DEPDIR)/Channel.Po \ +@AMDEP_TRUE@ $(DEPDIR)/ChannelList.Po $(DEPDIR)/Commands.Po \ +@AMDEP_TRUE@ $(DEPDIR)/Connection.Po $(DEPDIR)/DCCConnection.Po \ +@AMDEP_TRUE@ $(DEPDIR)/DCCParser.Po $(DEPDIR)/DCCPerson.Po \ +@AMDEP_TRUE@ $(DEPDIR)/Interp.Po $(DEPDIR)/Main.Po \ +@AMDEP_TRUE@ $(DEPDIR)/Mask.Po $(DEPDIR)/Parser.Po \ +@AMDEP_TRUE@ $(DEPDIR)/Person.Po $(DEPDIR)/Queue.Po \ +@AMDEP_TRUE@ $(DEPDIR)/ScriptCommands.Po $(DEPDIR)/Server.Po \ +@AMDEP_TRUE@ $(DEPDIR)/ServerConnection.Po \ +@AMDEP_TRUE@ $(DEPDIR)/ServerList.Po $(DEPDIR)/ServerQueue.Po \ +@AMDEP_TRUE@ $(DEPDIR)/ServerQueueItem.Po $(DEPDIR)/ShitEntry.Po \ +@AMDEP_TRUE@ $(DEPDIR)/ShitList.Po $(DEPDIR)/Socket.Po \ +@AMDEP_TRUE@ $(DEPDIR)/String.Po $(DEPDIR)/StringTokenizer.Po \ +@AMDEP_TRUE@ $(DEPDIR)/TodoList.Po $(DEPDIR)/User.Po \ +@AMDEP_TRUE@ $(DEPDIR)/UserCommands.Po $(DEPDIR)/UserList.Po \ +@AMDEP_TRUE@ $(DEPDIR)/Utils.Po +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +CXXFLAGS = @CXXFLAGS@ +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(bobotpp_SOURCES) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(bobotpp_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .C .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu source/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && \ + CONFIG_HEADERS= CONFIG_LINKS= \ + CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +bobotpp$(EXEEXT): $(bobotpp_OBJECTS) $(bobotpp_DEPENDENCIES) + @rm -f bobotpp$(EXEEXT) + $(CXXLINK) $(bobotpp_LDFLAGS) $(bobotpp_OBJECTS) $(bobotpp_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/BanEntry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Bot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/BotInterp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Channel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ChannelList.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Commands.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Connection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/DCCConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/DCCParser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/DCCPerson.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Interp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Mask.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Parser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Person.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Queue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ScriptCommands.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ServerConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ServerList.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ServerQueue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ServerQueueItem.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ShitEntry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ShitList.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Socket.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/String.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/StringTokenizer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/TodoList.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/User.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/UserCommands.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/UserList.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/Utils.Po@am__quote@ + +distclean-depend: + -rm -rf $(DEPDIR) + +.C.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CXXCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$< + +.C.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CXXCOMPILE) -c -o $@ `cygpath -w $<` +CXXDEPMODE = @CXXDEPMODE@ +uninstall-info-am: + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) + +GTAGS: + here=`CDPATH=: && cd $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + $(mkinstalldirs) "$(distdir)/$$dir"; \ + fi; \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir) \ + || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am + +.PHONY: GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic distclean distclean-compile distclean-depend \ + distclean-generic distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: hunk ./source/Mask.C 1 +// Mask.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 + +#include "Mask.H" + +Mask::Mask(String s) + : mask(s) +{ } + +String +Mask::getMask() +{ + return mask; +} + +bool +Mask::matches(String s) +{ + return match((const char *)mask, (const char *)s); +} + +bool +Mask::matches(Mask & m) +{ + return match((const char *)mask, (const char *)m.mask); +} + +bool +Mask::match(const char * m, const char * n) +{ + if (!*m) { + if (!*n) + return true; + else + return false; + } else + if (!*n) + return false; + + if (m[0] == '*') { + while (*m && (m[0] == '*' || m[0] == '?')) + m++; + + if (*m == '\0') + return true; + + const char *c = n; + while ((c = strchr(c, *m)) != 0) { + if (match(m, c)) + return 1; + c++; + } + } + + if ((m[0] == n[0]) || + (m[0] == '?') || + ((m[0] == '\\') && ((m[1] == '?' && n[0] == '?') || + (m[1] == '*' && n[0] == '*')))) + return match(++m, ++n); + + return false; +} hunk ./source/Mask.H 1 +// Mask.H -*- 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. + +#ifndef MASK_H +#define MASK_H + +#include "String.H" + +class Mask { + String mask; + +public: + Mask(String); + Mask(Mask &); + + String getMask(); + + bool matches(String); + bool matches(Mask &); + +protected: + bool match(const char *, const char *); +}; + +#endif hunk ./source/Message.H 1 +// Message.H -*- 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. + +#ifndef MESSAGE_H +#define MESSAGE_H + +#include "String.H" + +struct Message { + int code; + String description; + + Message(int c, String d) : code(c), description(d) { } + int getCode() const { return code; } + String getMessage() const { return description; } +}; + +#endif hunk ./source/Parser.C 1 +// Parser.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 +#include + +#include "StringTokenizer.H" +#include "Parser.H" +#include "UserCommands.H" +#include "Macros.H" +#include "Utils.H" +#include "ShitList.H" + +struct { + char *name; + void (*function)(ServerConnection *, Person *, String); +} functions[] = +{ + { "001", Parser::parse001 }, /* RPL_WELCOME */ + { "302", Parser::parse302 }, /* RPL_USERHOST */ + { "311", Parser::parse311 }, /* RPL_WHOISUSER */ + { "315", Parser::parse315 }, /* RPL_ENDOFWHO */ + { "324", Parser::parse324 }, /* RPL_CHANNELMODEIS */ + { "332", Parser::parse332 }, /* RPL_TOPIC */ + { "352", Parser::parse352 }, /* RPL_WHOREPLY */ + { "353", Parser::parse353 }, /* RPL_NAMESREPLY */ + { "366", Parser::parse366 }, /* RPL_ENDOFNAMES */ + { "367", Parser::parse367 }, /* RPL_BANLIST */ + { "401", Parser::parse401 }, /* ERR_NOSUCHNICK */ + { "433", Parser::parse433 }, /* ERR_NICKNAMEINUSE */ + { "437", Parser::parse433 }, /* ERR_UNAVAILRESOURCE */ + { "471", Parser::parse473 }, /* ERR_CHANNELISFULL */ + { "473", Parser::parse473 }, /* ERR_INVITEONLYCHAN */ + { "474", Parser::parse473 }, /* ERR_BANNEDFROMCHAN */ + { "475", Parser::parse473 }, /* ERR_BADCHANNELKEY */ + { "ERROR", Parser::parseError }, + { "INVITE", Parser::parseInvite }, + { "JOIN", Parser::parseJoin }, + { "KICK", Parser::parseKick }, + { "MODE", Parser::parseMode }, + { "NICK", Parser::parseNick }, + { "NOTICE", Parser::parseNotice }, + { "PART", Parser::parsePart }, + { "PING", Parser::parsePing }, + { "PONG", Parser::parsePong }, + { "PRIVMSG", Parser::parsePrivmsg }, + { "QUIT", Parser::parseQuit }, + { "TOPIC", Parser::parseTopic }, + { "", Parser::parseError }, + { 0, 0 } +}; + + +void +Parser::parseLine(ServerConnection * cnx, String line) +{ + StringTokenizer st(line); + Person * from = 0; + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::RAW, line, + scm_listify (Utils::string2SCM(line), + SCM_UNDEFINED)); +#endif + + if (line[0] == ':') { + String fromMask = st.nextToken().subString(1); + if (fromMask.find('!') != -1) + from = new Person(cnx->bot, fromMask); + } + + String command = st.nextToken(); + String rest = st.rest(); + + for (int i = 0; functions[i].name != 0; i++) + if (command == functions[i].name) { + functions[i].function(cnx, from, rest); + break; + } + + delete from; +} + +void +Parser::parse001(ServerConnection * cnx, + Person *from, String rest) +{ + String temp = ""; + StringTokenizer st(rest); + String realNick = st.nextToken(); + + if ((cnx->bot->nickName).toLower() != realNick) { + // Yes, this can happen, and it was a very subtle bug + cnx->bot->nickName = realNick; + cnx->bot->userList->removeFirst(); + cnx->bot->userList->addUserFirst(realNick + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, ""); + cnx->bot->lastNickNameChange = time(0); + cnx->bot->rehash(); + } + + cnx->bot->connected = true; + + cnx->queue->sendUserMode(cnx->bot->nickName, "+i"); + cnx->queue->sendWhois(cnx->bot->nickName); + + for (std::map >::iterator + it = cnx->bot->wantedChannels.begin(); + it != cnx->bot->wantedChannels.end(); ++it) + cnx->queue->sendJoin((*it).first, (*it).second->key); + + cnx->bot->logLine(String("Connected to server ") + + cnx->bot->serverList->currentServer()->getHostName() + + " (" + String((long)cnx->bot->serverList->currentServer()->getPort()) + + ")."); +} + +void +Parser::parse302(ServerConnection *cnx, + Person *from, String rest) +{ + unsigned long num = cnx->bot->receivedUserhostID++; + StringTokenizer st(rest); + + st.nextToken(':'); + + if (st.rest().length()) { + st.nextToken('='); + String parameters = st.rest(); + parameters = parameters.subString(1); + cnx->bot->userhostMap[num] = parameters; + } else + cnx->bot->userhostMap[num] = ""; +} + +void +Parser::parse311(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String nuh = st.nextToken() + "!"; + String uh = st.nextToken() + "@"; + uh = uh + st.nextToken(); + nuh = nuh + uh; + cnx->bot->userList->addUserFirst(nuh, "*", 0, 3, true, -1, ""); + cnx->bot->userHost = uh; +} + +void +Parser::parse315(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String channel = st.nextToken(); + Channel *c = cnx->bot->channelList->getChannel(channel); + if (!c) + return; + c->gotWho = true; +} + +void +Parser::parse324(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String channel = st.nextToken(); + if (Channel *c = cnx->bot->channelList->getChannel(channel)) + if (c) c->parseMode(from, st.rest()); +} + +void +Parser::parse332(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String channel = st.nextToken(); + if (Channel *c = cnx->bot->channelList->getChannel(channel)) + if (c) c->channelTopic = st.rest().subString(1); +} + +void +Parser::parse352(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String ch = st.nextToken(); + String uh = st.nextToken() + "@"; + uh = uh + st.nextToken(); + st.nextToken(); + String n = st.nextToken(); + String m = st.nextToken(); + int mode = 0; + + for (int i = 0; i < m.length(); i++) + switch (m[i]) { + case 'H': break; + case 'G': mode |= User::AWAY_MODE; break; + case '*': mode |= User::IRCOP_MODE; break; + case '@': mode |= User::OP_MODE; break; + case '+': mode |= User::VOICE_MODE; break; + } + if (Channel *c = cnx->bot->channelList->getChannel(ch)) + if (c) c->addNick(n, uh, mode, cnx->bot->userList); +} + +void +Parser::parse353(ServerConnection *cnx, + Person *from, String rest) +{ + int mode = 0; + String nick; + + StringTokenizer st(rest); + st.nextToken(); st.nextToken(); + + Channel * c = cnx->bot->channelList->getChannel(st.nextToken()); + if (!c) return; + StringTokenizer st2(st.nextToken(':')); + + while (st2.hasMoreTokens()) { + nick = st2.nextToken(); + if (nick[0] == '@') { + mode = User::OP_MODE; + nick = nick.subString(1); + } else if (nick[0] == '+') { + mode = User::VOICE_MODE; + nick = nick.subString(1); + } + c->addNick(nick, "", mode, 0, true); + } +} + +void +Parser::parse366(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String ch = st.nextToken(); + if (Channel *c = cnx->bot->channelList->getChannel(ch)) + c->joined = true; +} + +void +Parser::parse367(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String ch = st.nextToken(); + if (Channel *c = cnx->bot->channelList->getChannel(ch)) + c->addBan(st.nextToken(), -1); +} + +void +Parser::parse401(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + String nick = st.nextToken(); + + if (cnx->bot->spyList.find(nick) != cnx->bot->spyList.end()) { + delete cnx->bot->spyList[nick]; + cnx->bot->spyList.erase(nick); + } +} + +void +Parser::parse433(ServerConnection *cnx, + Person *from, String rest) +{ + if (cnx->bot->connected) + return; + + if (cnx->bot->nickName.length() == 9) { + int i; + for (i = 0; i < cnx->bot->nickName.length() && cnx->bot->nickName[i] == '_'; i++) + ; + if (i < cnx->bot->nickName.length()) + cnx->bot->nickName = cnx->bot->nickName.subString(0, i-1) + "_" + cnx->bot->nickName.subString(i+1); + else + cnx->bot->nickName = cnx->bot->nickName.subString(0, 4) + + String((long)(rand() % 10000)); + } + else + cnx->bot->nickName = cnx->bot->nickName + "_"; + + cnx->queue->sendNick(cnx->bot->nickName); +} + +void +Parser::parse473(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + st.nextToken(); + + cnx->bot->logLine(String("Unable to join channel ") + + st.nextToken() + "."); +} + +void +Parser::parseError(ServerConnection *cnx, + Person *from, String rest) +{ + cnx->bot->logLine(String("Error from server ") + + cnx->bot->serverList->currentServer()->getHostName() + + " (" + String((long)cnx->bot->serverList->currentServer()->getPort()) + + ")."); + cnx->bot->nextServer(); +} + +void +Parser::parseInvite(ServerConnection *cnx, + Person *from, String rest) +{ + String nick = from->getNick(); + StringTokenizer st(rest); + st.nextToken(':'); + String channel = st.rest(); + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::INVITE, nick + " " + channel, + scm_listify (Utils::string2SCM(nick), + Utils::string2SCM(channel), + SCM_UNDEFINED)); +#endif + + if (cnx->bot->wantedChannels.find(channel) != + cnx->bot->wantedChannels.end()) + cnx->queue->sendJoin(channel, cnx->bot->wantedChannels[channel]->key); +} + +void +Parser::parseJoin(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(from->getAddress()); + String n = st.nextToken('!'); + String uh = st.nextToken(); + StringTokenizer st2(rest); + String c = st2.nextToken(':'); + String mode; + bool joinAndMode = false; + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::JOIN, n + " " + c, + scm_listify (Utils::string2SCM(n), + Utils::string2SCM(c), + SCM_UNDEFINED)); +#endif + + // This part of code is for the combined JOIN & MODE of ircd 2.9 + if (c.find('\007') >= 0) { + joinAndMode = true; + StringTokenizer st3(c); + c = st3.nextToken('\007'); + String m = st3.rest(); + mode = c + " +" + m; + for (int i = 0; i < m.length(); i++) + mode = mode + " " + n; + } + + if (n == cnx->bot->nickName) { + cnx->bot->logLine(String("Joined channel ") + c + "."); + if (cnx->bot->wantedChannels.find(c) != cnx->bot->wantedChannels.end()) + cnx->bot->channelList->addChannel(cnx, c, cnx->bot->wantedChannels[c]->keep); + else + cnx->bot->channelList->addChannel(cnx, c); + cnx->queue->sendWho(c); + cnx->queue->sendChannelMode(String("MODE ") + c + " b"); + cnx->queue->sendChannelMode(String("MODE ") + c); + } else { + Channel * ch = cnx->bot->channelList->getChannel(c); + if (!ch) + return; + ShitEntry * se = cnx->bot->shitList->getShit(n+"!"+uh, c); + if (se && se->isStillValid() && + se->getShitLevel() >= ShitEntry::SHIT_NOJOIN) { + cnx->queue->sendChannelMode(c, "+b", se->getMask()); + cnx->queue->sendKick(c, n, se->getShitReason()); + return; + } + ch->addNick(n, uh, 0, cnx->bot->userList); + if (ch->getUser(n)->getAop() && !(ch->getUser(n)->mode & User::OP_MODE) && cnx->bot->iAmOp(c)) { + // This is a part of the antispoof code + ch->getUser(n)->userkey = Utils::getKey(); + cnx->queue->sendCTCP(n, "PING", ch->getUser(n)->userkey + " " + c); + } + } + + if (joinAndMode) + parseMode(cnx, 0, mode); +} + +void +Parser::parseKick(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + String channel = st.nextToken(); + String target = st.nextToken(); + String reason = st.rest().subString(1); + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::KICK, target + " " + from->getNick() + " " + + channel + " " + reason, + scm_listify (Utils::string2SCM(target), + Utils::string2SCM(from->getNick()), + Utils::string2SCM(channel), + Utils::string2SCM(reason), + SCM_UNDEFINED)); +#endif + + if (target == cnx->bot->nickName) { + cnx->bot->logLine(from->getAddress() + " kicked me out of channel " + + channel + " (" + reason + ")."); + cnx->queue->sendJoin(channel, cnx->bot->channelList->getChannel(channel)->channelKey); + cnx->bot->channelList->delChannel(channel); + } else { + if (!cnx->bot->channelList->getChannel(channel)) return; + User *u = cnx->bot->channelList->getChannel(channel)->getUser(target); + if (u && u->getProt() >= User::NO_KICK) { + String fromNick = from->getNick(); + User *v = cnx->bot->channelList->getChannel(channel)->getUser(fromNick); + if (v->getProt() < User::NO_KICK) { + cnx->bot->logLine(from->getAddress() + " kicked " + target + + " (protected) out of channel " + channel + + " (" + reason + ")."); + cnx->queue->sendKick(channel, fromNick, + target + " \002is protected !\002"); + } + } + cnx->bot->channelList->getChannel(channel)->delNick(target); + } +} + +void +Parser::parseMode(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + String ch = st.nextToken(); + String modes = st.rest(); + +#ifdef USESCRIPTS + if (from) + cnx->bot->botInterp->RunHooks(Hook::MODE, from->getNick() + " " + ch + + " " + modes, + scm_listify (Utils::string2SCM(from->getNick()), + Utils::string2SCM(ch), + Utils::string2SCM(modes), + SCM_UNDEFINED)); +#endif + + + if (Utils::isChannel(ch)) { + Channel *c = cnx->bot->channelList->getChannel(ch); + if (!c) + return; + if (from) + c->parseMode(from, modes); + else + c->parseMode(0, modes); + } +} + +void +Parser::parseNick(ServerConnection *cnx, + Person *from, String rest) +{ + String on_orig = from->getNick(); + String on = on_orig.toLower(); + String nn = rest.subString(1); + String nn_lower = nn.toLower(); + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::NICKNAME, on_orig + " " + nn, + scm_listify (Utils::string2SCM(on_orig), + Utils::string2SCM(nn), + SCM_UNDEFINED)); +#endif + + if ((cnx->bot->nickName).toLower() == on) { + cnx->bot->userList->removeFirst(); + cnx->bot->userList->addUserFirst(nn + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, ""); + cnx->bot->lastNickNameChange = time(0); + cnx->bot->nickName = nn; + cnx->bot->rehash(); + } + + if (cnx->bot->spyList.find(on) != cnx->bot->spyList.end()) { + cnx->bot->spyList[nn_lower] = cnx->bot->spyList[on]; + cnx->bot->spyList.erase(on); + } + + for (std::map >::iterator it = + cnx->bot->channelList->begin(); + it != cnx->bot->channelList->end(); + ++it) + if ((*it).second->hasNick(on)) + (*it).second->changeNick(on, nn_lower); +} + +void +Parser::parseNotice(ServerConnection *cnx, + Person *from, String rest) +{ + String nick = ""; + + if (from) + nick = from->getNick(); + + StringTokenizer st(rest); + String to = st.nextToken(); + + rest = st.rest().subString(1); + + if (rest[0] != '\001') { +#ifdef USESCRIPTS + if (Utils::isChannel(to)) + cnx->bot->botInterp->RunHooks(Hook::PUBLIC_NOTICE, nick + " " + + to + " " + rest, + scm_listify (Utils::string2SCM(nick), + Utils::string2SCM(to), + Utils::string2SCM(rest), + SCM_UNDEFINED)); + else + cnx->bot->botInterp->RunHooks(Hook::NOTICE, nick + " " + rest, + scm_listify (Utils::string2SCM(nick), + Utils::string2SCM(rest), + SCM_UNDEFINED)); +#endif + return; + } + + rest = rest.subString(1, rest.length() - 2); + StringTokenizer st2(rest); + String command = st2.nextToken(); + rest = st2.rest(); + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::CTCP_REPLY, nick + " " + command + + " " + rest, + scm_listify (Utils::string2SCM(nick), + Utils::string2SCM(command), + Utils::string2SCM(rest), + SCM_UNDEFINED)); +#endif + + if (command == "PING") { + StringTokenizer st3(rest); + rest = st3.nextToken(); + String c = st3.rest(); + if (cnx->bot->channelList->getChannel(c) && + cnx->bot->channelList->getChannel(c)->getUser(nick) && + cnx->bot->channelList->getChannel(c)->getUser(nick)->getAop() && + !(cnx->bot->channelList->getChannel(c)->getUser(nick)->mode & User::OP_MODE) + && cnx->bot->channelList->getChannel(c)->getUser(nick)->userkey == rest) + cnx->queue->sendChannelMode(c, "+o", nick); + } +} + +void +Parser::parsePrivmsg(ServerConnection *cnx, + Person *from, String rest) +{ + String nick = from->getNick(); + + StringTokenizer st(rest); + String to = st.nextToken(); + String fromUserhost = Utils::getUserhost(from->getAddress()); + + rest = st.rest().subString(1); + + if (++(cnx->bot->ignoredUserhosts[fromUserhost]) + > Bot::MAX_MESSAGES) { + if (cnx->bot->ignoredUserhosts[fromUserhost] + == Bot::MAX_MESSAGES+1) { +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::FLOOD, nick, + scm_listify (Utils::string2SCM(nick), + SCM_UNDEFINED)); +#endif + cnx->bot->ignoredUserhosts[fromUserhost] += Bot::IGNORE_DELAY; + cnx->bot->logLine(from->getAddress() + + " is flooding me. We will ignore him/her/it."); + if (!Utils::isChannel(to)) + from->sendNotice(String("\002You are now being ignored for ") + + String((long)Bot::IGNORE_DELAY) + " seconds.\002"); + } + // The following lines reset the counter if you use the + // command "!sorry" (if '!' is your command char). + // This is not documented, I know. But one probably does + // not want that every users can bypass the flood control + // Of course, if you want this feature to remain 'secret', + // do not use it in public. + if (rest.toUpper() == String(cnx->bot->commandChar) + "SORRY") { + cnx->bot->ignoredUserhosts[fromUserhost] = 0; + from->sendNotice("\002Don't do it again!\002"); + } + return; + } + + if (rest[0] == '\001') { + rest = rest.subString(1, rest.length() - 2); + if (!Utils::isChannel(to)) + for (std::map >::iterator it = + cnx->bot->spyList.begin(); it != cnx->bot->spyList.end(); ++it) + (*it).second->sendNotice(String("CTCP From ") + nick + + ": " + rest); + Parser::parseCTCP(cnx, from, to, rest); + } + else { + if ((rest.length() < 5 || + rest.subString(1, 5).toUpper() != "IDENT") && + (rest.length() < 8 || + rest.subString(1, 8).toUpper() != "PASSWORD") && + !Utils::isChannel(to)) + for (std::map >::iterator it = + cnx->bot->spyList.begin(); it != cnx->bot->spyList.end(); ++it) + (*it).second->sendNotice(String("*") + nick + "* " + rest); + Parser::parseMessage(cnx, from, to, rest); + } +} + +void +Parser::parsePart(ServerConnection *cnx, + Person *from, String rest) +{ + String n = from->getNick(); + StringTokenizer st(rest); + String channel = st.nextToken(); + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::LEAVE, n + " " + channel, + scm_listify (Utils::string2SCM(n), + Utils::string2SCM(channel), + SCM_UNDEFINED)); +#endif + + if (n.toLower() == cnx->bot->nickName.toLower()) { + cnx->bot->logLine(String("Leaved channel ") + channel + "."); + cnx->bot->channelList->delChannel(channel); + } else { + Channel * c = cnx->bot->channelList->getChannel(channel); + if (!c) return; + c->delNick(n); + if (c->countOp == 0 && c->count == 1) { + cnx->queue->sendPart(channel); + cnx->queue->sendJoin(channel, cnx->bot->wantedChannels[channel]->key); + } + } +} + +void +Parser::parsePing(ServerConnection * cnx, + Person *from, String rest) +{ + cnx->queue->sendPong(rest); +} + +void +Parser::parsePong(ServerConnection *cnx, + Person *from, String rest) +{ + cnx->lag = (cnx->lag + 2 * (time(NULL) - cnx->pingTime)) / 3; + cnx->bot->sentPing = false; +} + +void +Parser::parseQuit(ServerConnection *cnx, + Person *from, String rest) +{ + String n = from->getNick(); + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::SIGNOFF, n + " " + rest, + scm_listify (Utils::string2SCM(n), + Utils::string2SCM(rest), + SCM_UNDEFINED)); +#endif + + if (n == cnx->bot->nickName) + cnx->bot->stop = true; + + for (std::map >::iterator it = + cnx->bot->channelList->begin(); + it != cnx->bot->channelList->end(); + ++it) + (*it).second->delNick(n); +} + +void +Parser::parseTopic(ServerConnection *cnx, + Person *from, String rest) +{ + StringTokenizer st(rest); + String channel = st.nextToken(); + String newTopic = st.rest().subString(1); + Channel *c = cnx->bot->channelList->getChannel(channel); + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::TOPIC, from->getNick() + " " + channel + + " " + newTopic, + scm_listify (Utils::string2SCM(from->getNick()), + Utils::string2SCM(channel), + Utils::string2SCM(newTopic), + SCM_UNDEFINED)); +#endif + + if (!c) return; + + if (c->lockedTopic && from->getNick() != cnx->bot->nickName) + cnx->queue->sendTopic(channel, c->channelTopic); + + c->channelTopic = newTopic; +} + +void +Parser::parseCTCP(ServerConnection *cnx, + Person *from, String to, + String parameters) +{ + StringTokenizer st(parameters); + String command = st.nextToken().toUpper(); + String nick = from->getNick(); + String rest; + + if (st.hasMoreTokens()) + rest = st.rest(); + else + rest = ""; + +#ifdef USESCRIPTS + cnx->bot->botInterp->RunHooks(Hook::CTCP, nick + " " + to + " " + + command + " " + rest, + scm_listify (Utils::string2SCM(nick), + Utils::string2SCM(to), + Utils::string2SCM(command), + Utils::string2SCM(rest), + SCM_UNDEFINED)); +#endif + + if (command == "PING") + cnx->queue->sendCTCPReply(nick, "PING", rest); + else if (command == "VERSION") + cnx->queue->sendCTCPReply(nick, "VERSION", cnx->bot->versionString); + + else if (command == "CLOCK") { + time_t diff = time(NULL) - cnx->bot->startTime; + cnx->queue->sendCTCPReply(nick, "CLOCK", String("elapsed time: ") + + String((long)(diff / 86400)) + "d" + + String((long)(diff % 86400) / 3600) + + "h" + String((long)(diff % 3600) / 60) + + "m" + String((long)(diff % 60)) + "s"); + } else if (command == "COMMAND") + cnx->queue->sendCTCPReply(nick, + "COMMAND", + String(cnx->bot->commandChar)); + else if (command == "LAG") + cnx->queue->sendCTCPReply(nick, "LAG", + String((long)cnx->lag) + " second(s)"); + else if (command == "DCC") { + StringTokenizer st2(rest); + command = st2.nextToken().toUpper(); + if (command == "CHAT") { + // FIXME: Re-activate and debug DCC +// st2.nextToken(); +// unsigned long address = +// htonl(strtoul((const char *)st2.nextToken(), 0, 0)); +// int port = atoi((const char *)st2.rest()); +// if (port >= 1024 && Utils::getLevel(cnx->bot, from->getAddress())) +// cnx->bot->addDCC(from, address, port); + } + } +#ifdef USESCRIPTS + else if (command == "ACTION") { + cnx->bot->botInterp->RunHooks(Hook::ACTION, from->getAddress() + " " + + to + " " + rest, + scm_listify (Utils::string2SCM(from->getAddress()), + Utils::string2SCM(to), + Utils::string2SCM(rest), + SCM_UNDEFINED)); + } +#endif +} + +struct userFunctionsStruct userFunctionsInit[] = + +{ + { "ACTION", UserCommands::Action, User::USER, true }, + { "ADDUSER", UserCommands::AddUser, User::FRIEND, false }, + { "ADDSERVER", UserCommands::AddServer, User::FRIEND, false }, + { "ADDSHIT", UserCommands::AddShit, User::FRIEND, false }, + { "ALIAS", UserCommands::Alias, User::MASTER, false }, + { "BAN", UserCommands::Ban, User::USER, true }, + { "BANLIST", UserCommands::BanList, User::USER, true }, + // { "CHANGELEVEL", UserCommands::ChangeLevel, User::FRIEND, false }, + { "CHANNELS", UserCommands::Channels, User::FRIEND, false }, + { "CYCLE", UserCommands::Cycle, User::FRIEND, true }, + { "DCCLIST", UserCommands::DCCList, User::FRIEND, false }, + { "DEBAN", UserCommands::Deban, User::USER, true }, + { "DELSERVER", UserCommands::DelServer, User::FRIEND, false }, + { "DELUSER", UserCommands::DelUser, User::FRIEND, false }, + { "DELSHIT", UserCommands::DelShit, User::FRIEND, false }, + { "DEOP", UserCommands::Deop, User::TRUSTED_USER, true }, + { "DIE", UserCommands::Die, User::MASTER, false }, + { "DO", UserCommands::Do, User::MASTER, false }, +#ifdef USESCRIPTS + { "EXECUTE", UserCommands::Execute, User::MASTER, false }, +#endif + { "HELP", UserCommands::Help, User::NONE, false }, + { "IDENT", UserCommands::Ident, User::NONE, true }, + { "INVITE", UserCommands::Invite, User::USER, true }, + { "JOIN", UserCommands::Join, User::FRIEND, false }, + { "KEEP", UserCommands::Keep, User::FRIEND, true }, + { "KICK", UserCommands::Kick, User::USER, true }, + { "KICKBAN", UserCommands::KickBan, User::USER, true }, + { "LOAD", UserCommands::Load, User::FRIEND, false }, +#ifdef USESCRIPTS + { "LOADSCRIPT", UserCommands::LoadScript, User::MASTER, false }, +#endif + { "LOCK", UserCommands::Lock, User::FRIEND, true }, + { "MODE", UserCommands::Mode, User::FRIEND, true }, + { "MSG", UserCommands::Msg, User::USER, false }, + { "NAMES", UserCommands::Names, User::USER, true }, + { "NEXTSERVER", UserCommands::NextServer, User::FRIEND, false }, + { "NICK", UserCommands::Nick, User::FRIEND, false }, + { "NSLOOKUP", UserCommands::NsLookup, User::USER, false }, + { "OP", UserCommands::Op, User::TRUSTED_USER, true }, + { "PART", UserCommands::Part, User::FRIEND, true }, + { "PASSWORD", UserCommands::Password, User::USER, true }, + { "RECONNECT", UserCommands::Reconnect, User::FRIEND, false }, + { "RSPYMESSAGE", UserCommands::RSpyMessage, User::USER, false }, + { "SAVE", UserCommands::Save, User::FRIEND, false }, + { "SAY", UserCommands::Say, User::USER, true }, + { "SERVER", UserCommands::Server, User::FRIEND, false }, + { "SERVERLIST", UserCommands::ServerList, User::FRIEND, false }, + { "SETVERSION", UserCommands::SetVersion, User::MASTER, false }, + { "SHITLIST", UserCommands::ShitList, User::FRIEND, false }, + { "SPYLIST", UserCommands::SpyList, User::USER, false }, + { "SPYMESSAGE", UserCommands::SpyMessage, User::USER, false }, + { "STATS", UserCommands::Stats, User::FRIEND, true }, + { "TBAN", UserCommands::TBan, User::USER, true }, + { "TKBAN", UserCommands::TKBan, User::USER, true }, + { "TOPIC", UserCommands::Topic, User::USER, true }, + { "UNLOCK", UserCommands::Unlock, User::FRIEND, true }, + { "USERLIST", UserCommands::UserList, User::FRIEND, false }, + { "WHO", UserCommands::Who, User::NONE, true }, + { "WHOIS", UserCommands::Whois, User::FRIEND, true }, + { "", 0, 0, false } +}; + +void +Parser::parseMessage(ServerConnection *cnx, + Person *from, String to, + String parameters) +{ +#ifdef USESCRIPTS + if (Utils::isChannel(to)) + cnx->bot->botInterp->RunHooks(Hook::PUBLIC, from->getNick() + " " + + to + " " + parameters, + scm_listify (Utils::string2SCM(from->getNick()), + Utils::string2SCM(to), + Utils::string2SCM(parameters), + SCM_UNDEFINED)); + else + cnx->bot->botInterp->RunHooks(Hook::MESSAGE, from->getNick() + " " + parameters, + scm_listify (Utils::string2SCM(from->getNick()), + Utils::string2SCM(parameters), + SCM_UNDEFINED)); +#endif + + if (parameters[0] != cnx->bot->commandChar) + return; + + StringTokenizer st(parameters); + + String command = st.nextToken().subString(1).toUpper(); + String rest = st.rest().trim(); + int level; + bool identified = false; + + std::list::iterator it; + for (it = cnx->bot->userFunctions.begin(); + it != cnx->bot->userFunctions.end(); + ++it) + if (command == (*it)->name) { + if ((*it)->needsChannelName) { + if (Utils::isChannel(rest)) { + StringTokenizer st2(rest); + to = st.nextToken(); + rest = st.rest(); + } + if (!Utils::isChannel(to)) { + from->sendNotice("\002You need to supply a channel name" + " for this command\002"); + return; + } + if (!cnx->bot->channelList->getChannel(to)) { + from->sendNotice(String("\002I am not on channel\002 ") + + to); + return; + } + level = Utils::getLevel(cnx->bot, from->getAddress(), to); + User * u = 0; + if (Channel *c = cnx->bot->channelList->getChannel(to)) + u = c->getUser(from->getNick()); + if (!u || !u->userListItem) + identified = true; + else + identified = u->userListItem->passwd == "" || u->userListItem->identified > 0; + } else { + level = Utils::getLevel(cnx->bot, from->getAddress()); + identified = true; + } + if (level >= (*it)->minLevel) { + cnx->bot->logLine(from->getAddress() + " did " + command + + " " + rest); +#ifdef USESCRIPTS + if ((*it)->argsCount != -1) { + Parser::parseScriptFunction(cnx, to, (*it)->needsChannelName, + (*it)->scmFunc, (*it)->argsCount, rest); + } else { + (*it)->function(cnx, from, to, rest); + } +#else + (*it)->function(cnx, from, to, rest); +#endif + break; + } else { + if (!identified) + from->sendNotice(String("\002You are not identified on channel\002 ")+to); + } + } +} + +#ifdef USESCRIPTS +void +Parser::parseScriptFunction(ServerConnection *cnx, String channel, + bool needsChannelName, SCM scmFunc, + int argsCount, String parameters) +{ + String param; + SCM args_list = scm_listify (SCM_UNDEFINED); + + if (needsChannelName) { + args_list = gh_append2(args_list, + scm_listify (Utils::string2SCM(channel), + SCM_UNDEFINED)); + argsCount--; + } + + StringTokenizer st(parameters); + for (int i = argsCount; i > 0; i--) { + if (i == 1) + param = st.rest(); + else + param = st.nextToken(); + args_list = gh_append2(args_list, + scm_listify (Utils::string2SCM(param), + SCM_UNDEFINED)); + } + + struct wrapper_data wd; + wd.func = scmFunc; + wd.args = args_list; + + gh_catch(SCM_BOOL_T, (scm_catch_body_t) scm_apply_wrapper, + (void *)&wd, (scm_catch_handler_t) Interp::ErrorHandler, + 0); +} +#endif hunk ./source/Parser.H 1 +// Parser.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 PARSER_H +#define PARSER_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "String.H" +#include "Person.H" +#include "ServerConnection.H" + +#ifdef USESCRIPTS +#include "Interp.H" +#include +#endif + +struct userFunctionsStruct { + String name; + void (*function)(ServerConnection *, Person *, String, String); + int minLevel; + bool needsChannelName; +}; + +class userFunction { +public: + String name; + void (*function)(ServerConnection *, Person *, String, String); + int minLevel; + bool needsChannelName; +#ifdef USESCRIPTS + int argsCount; + SCM scmFunc; +#endif + + userFunction(String na, + void (*f)(ServerConnection *, Person *, + String, String), + int m, bool n +#ifdef USESCRIPTS + , int a = -1, SCM scm_f = 0 +#endif + ) + : name(na), function(f), minLevel(m), needsChannelName(n) +#ifdef USESCRIPTS + ,argsCount(a), scmFunc(scm_f) +#endif + { +#ifdef USESCRIPTS +// scm_protect_object(scm_f); +#endif + } + +#ifdef USESCRIPTS +// ~userFunction() +// { scm_unprotect_object(scmFunc); }; +#endif +}; + +class Parser { +public: + static void parseLine(ServerConnection *, String); + + static void parse001(ServerConnection *, Person *, String); + static void parse302(ServerConnection *, Person *, String); + static void parse311(ServerConnection *, Person *, String); + static void parse315(ServerConnection *, Person *, String); + static void parse324(ServerConnection *, Person *, String); + static void parse332(ServerConnection *, Person *, String); + static void parse352(ServerConnection *, Person *, String); + static void parse353(ServerConnection *, Person *, String); + static void parse366(ServerConnection *, Person *, String); + static void parse367(ServerConnection *, Person *, String); + static void parse401(ServerConnection *, Person *, String); + static void parse433(ServerConnection *, Person *, String); + static void parse473(ServerConnection *, Person *, String); + static void parseError(ServerConnection *, Person *, String); + static void parseInvite(ServerConnection *, Person *, String); + static void parseJoin(ServerConnection *, Person *, String); + static void parseKick(ServerConnection *, Person *, String); + static void parseMode(ServerConnection *, Person *, String); + static void parseNick(ServerConnection *, Person *, String); + static void parseNotice(ServerConnection *, Person *, String); + static void parsePart(ServerConnection *, Person *, String); + static void parsePing(ServerConnection *, Person *, String); + static void parsePong(ServerConnection *, Person *, String); + static void parsePrivmsg(ServerConnection *, Person *, String); + static void parseQuit(ServerConnection *, Person *, String); + static void parseTopic(ServerConnection *, Person *, String); + + static void parseCTCP(ServerConnection *, Person *, String, + String); + static void parseMessage(ServerConnection *, Person *, String, + String); +#ifdef USESCRIPTS + static void parseScriptFunction(ServerConnection *, String, bool, + SCM, int, String); +#endif + + static void sendNotice(Person *, String); +}; + +#endif hunk ./source/Person.C 1 +// Person.C -*- C++ -*- +// Copyright (c) 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 "Utils.H" +#include "Person.H" + +Person::Person(Bot *b, String a) + : bot(b), address(a) +{ } + +Person::Person(Person &p) + : bot(p.bot), address(p.address) +{ } + +Person * +Person::copy() +{ + return new Person(*this); +} + +String +Person::getNick() const +{ + return Utils::getNick(address); +} + +String +Person::getAddress() const +{ + return address; +} + +Person & +Person::operator=(const String & a) +{ + address = a; + return *this; +} + +void +Person::sendNotice(String message) +{ + bot->serverConnection->queue->sendNotice(getNick(), message); +} hunk ./source/Person.H 1 +// Person.H -*- C++ -*- +// Copyright (c) 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. + +#ifndef PERSON_H +#define PERSON_H + +#include "String.H" + +class Bot; + +class Person { +protected: + Bot *bot; + String address; +public: + Person(Bot *, String = ""); + Person(Person &); + + virtual ~Person() { } + + virtual Person * copy(); + + String getNick() const; + String getAddress() const; + + virtual void keepAlive() { } + + virtual void sendNotice(String); + + Person & operator=(const String &); +}; + +#endif hunk ./source/Queue.C 1 +// Queue.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 + +#include "Queue.H" + +Queue::Queue(Socket * s, bool d) + : sock(s), debug(d) +{ } + +Queue::~Queue() +{ } + +bool +Queue::sendLine(String s) +{ + if (debug) + std::cout << "=> " << s << std::endl; + return sock->write(s); +} hunk ./source/Queue.H 1 +// Queue.H -*- 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. + +#ifndef QUEUE_H +#define QUEUE_H + +#include "Socket.H" + +class Queue { + Socket * sock; + bool debug; +public: + Queue(Socket *, bool=false); + virtual ~Queue(); + + virtual bool sendLine(String); +}; + +#endif hunk ./source/ScriptCommands.C 1 +// ScriptCommands.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 +// 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 + +#ifdef USESCRIPTS + +#include "Utils.H" +#include "Server.H" +#include "ServerList.H" +#include "ScriptCommands.H" +#include "Interp.H" +#include + +#define VERIFY_STRING(par) if (!SCM_STRINGP((par))) \ + return scm_long2num(-17) + +#define VERIFY_NUMBER(par) if (!SCM_NUMBERP((par))) \ + return scm_long2num(-17) + +SCM +ScriptCommands::Action(SCM channel, SCM message) +{ + VERIFY_STRING(channel); + VERIFY_STRING(message); + Message m = Commands::Action(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(message)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::AddUser(SCM who, SCM maskChannel, SCM level, + SCM prot, SCM aop, SCM expire, SCM password) +{ + // It segfaults when not online, but otherwise appears to work + VERIFY_STRING (who); + VERIFY_STRING (maskChannel); + VERIFY_NUMBER (level); + + String wwho = Utils::scm2String (who); + String mask = Utils::scm2String (maskChannel); + String passwd; + std::time_t eexpire; + + if (SCM_UNBNDP (password)) + passwd = ""; + else + { + VERIFY_STRING (password); + passwd = Utils::scm2String (password); + } + if (SCM_UNBNDP (expire)) + eexpire = -1; + else + { + VERIFY_STRING (expire); + eexpire = Utils::strToTime (Utils::scm2String (expire)); + if (!eexpire) eexpire = -1; + } + + int protect = scm_num2int (prot, SCM_ARG1, "ScriptCommands::AddUser"); + bool aaop = SCM_NFALSEP (aop); + int llevel = scm_num2int (level, SCM_ARG1, + "ScriptCommands::AddUser"); + + Message m = Commands::AddUser (Interp::bot, wwho, mask, llevel, + protect, aaop, eexpire, passwd); + + return scm_long2num(m.getCode ()); +} + +SCM +ScriptCommands::AddServer(SCM servername, SCM port) +{ + int p = 6667; + if (SCM_NUMBERP(port)) + p = scm_num2long(port, SCM_ARG1, "ScriptCommands::AddServer"); + Message m = Commands::AddServer(Interp::bot, + Utils::scm2String(servername), + p); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::AddShit(SCM mask, SCM maskChannel, SCM level, + SCM expiration, SCM reason) +{ + // This appears to work...not much testing though + VERIFY_STRING (mask); + VERIFY_STRING (maskChannel); + VERIFY_NUMBER (level); + String mmask = Utils::scm2String (mask); + String mmaskChannel = Utils::scm2String (maskChannel); + int llevel = scm_num2int (level, SCM_ARG1, "ScriptCommands::AddShit"); + std::time_t expire; + String rreason; + + if (SCM_UNBNDP (expiration)) + expire = -1; + else + { + VERIFY_STRING (expiration); + expire = Utils::strToTime (Utils::scm2String (expiration)); + if (!expire) expire = -1; + } + if (SCM_UNBNDP (reason)) + rreason = "You're on my shitlist, lamer"; + else + { + VERIFY_STRING (reason); + rreason = Utils::scm2String (reason); + } + Message m = Commands::AddShit (Interp::bot, mmask, mmaskChannel, + llevel, expire, rreason); + + return scm_long2num(m.getCode ()); +} + +SCM +ScriptCommands::Ban(SCM channel, SCM who) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + Message m = Commands::Ban(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Cycle(SCM channel) +{ + VERIFY_STRING(channel); + Message m = Commands::Cycle(Interp::bot, Utils::scm2String(channel)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Deban(SCM channel, SCM who) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + Message m = Commands::Deban(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::DelServer(SCM number) +{ + VERIFY_NUMBER(number); + Message m = Commands::DelServer(Interp::bot, + scm_num2long(number, SCM_ARG1, + "ScriptCommands::DelServer")); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::DelUser(SCM who, SCM maskChannel) +{ + VERIFY_STRING(who); + VERIFY_STRING(maskChannel); + Message m = Commands::DelUser(Interp::bot, Utils::scm2String(who), + Utils::scm2String(maskChannel)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::DelShit(SCM who, SCM maskChannel) +{ + VERIFY_STRING(who); + VERIFY_STRING(maskChannel); + Message m = Commands::DelShit(Interp::bot, Utils::scm2String(who), + Utils::scm2String(maskChannel)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Deop(SCM channel, SCM who) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + Message m = Commands::Deop(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Die(SCM reason) +{ + String r = "Leaving"; + if (SCM_STRINGP(reason)) + r = Utils::scm2String(reason); + Message m = Commands::Die(Interp::bot, r); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Do(SCM command) +{ + VERIFY_STRING(command); + Message m = Commands::Do(Interp::bot, Utils::scm2String(command)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Invite(SCM channel, SCM who) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + Message m = Commands::Invite(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Join(SCM channel, SCM key) +{ + VERIFY_STRING(channel); + String k = ""; + if (SCM_STRINGP(key)) + k = Utils::scm2String(key); + Message m = Commands::Join(Interp::bot, Utils::scm2String(channel), + k); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Keep(SCM channel, SCM modes) +{ + VERIFY_STRING(channel); + VERIFY_STRING(modes); + Message m = Commands::Keep(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(modes)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Kick(SCM channel, SCM who, SCM reason) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + + String r = ""; + if (SCM_STRINGP(reason)) + r = Utils::scm2String(reason); + + Message m = Commands::Kick(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who), r); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::KickBan(SCM channel, SCM who, SCM reason) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + String r = ""; + if (SCM_STRINGP(reason)) + r = Utils::scm2String(reason); + Message m = Commands::KickBan(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who), r); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Lock(SCM channel) +{ + VERIFY_STRING(channel); + Message m = Commands::Lock(Interp::bot, Utils::scm2String(channel)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::LogPort(void) +{ + return Interp::bot->botInterp->logPort; +} + +SCM +ScriptCommands::Mode(SCM channel, SCM mode) +{ + VERIFY_STRING(channel); + VERIFY_STRING(mode); + Message m = Commands::Mode(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(mode)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Msg(SCM nick, SCM message) +{ + VERIFY_STRING(nick); + VERIFY_STRING(message); + Message m = Commands::Msg(Interp::bot, Utils::scm2String(nick), + Utils::scm2String(message)); + return scm_long2num(m.getCode()); + +} + +SCM +ScriptCommands::NextServer(void) +{ + Message m = Commands::NextServer(Interp::bot); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Nick(SCM nick) +{ + VERIFY_STRING(nick); + Message m = Commands::Nick(Interp::bot, Utils::scm2String(nick)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Op(SCM channel, SCM who) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + Message m = Commands::Op(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Part(SCM channel) +{ + VERIFY_STRING(channel); + Message m = Commands::Part(Interp::bot, Utils::scm2String(channel)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Reconnect(void) +{ + Message m = Commands::Reconnect(Interp::bot); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Say(SCM channel, SCM message) +{ + VERIFY_STRING(channel); + VERIFY_STRING(message); + Message m = Commands::Say(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(message)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Server(SCM number) +{ + VERIFY_NUMBER(number); + Message m = Commands::Server(Interp::bot, gh_scm2long(number)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::SetVersion(SCM version) +{ + Message m = Commands::SetVersion(Interp::bot, Utils::scm2String(version)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::TBan(SCM channel, SCM who, SCM seconds) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + VERIFY_NUMBER(seconds); + Message m = Commands::TBan(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who), gh_scm2long(seconds)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::TKBan(SCM channel, SCM who, SCM seconds, SCM reason) +{ + VERIFY_STRING(channel); + VERIFY_STRING(who); + VERIFY_NUMBER(seconds); + String r = ""; + if (SCM_STRINGP(reason)) + r = Utils::scm2String(reason); + Message m = Commands::TKBan(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(who), + gh_scm2long(seconds), r); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Topic(SCM channel, SCM topic) +{ + VERIFY_STRING(channel); + VERIFY_STRING(topic); + Message m = Commands::Topic(Interp::bot, Utils::scm2String(channel), + Utils::scm2String(topic)); + return scm_long2num(m.getCode()); +} + +SCM +ScriptCommands::Unlock(SCM channel) +{ + VERIFY_STRING(channel); + Message m = Commands::Unlock(Interp::bot, Utils::scm2String(channel)); + return scm_long2num(m.getCode()); +} + + + + +SCM +ScriptCommands::getNickname(void) +{ + return Utils::string2SCM(Interp::bot->nickName); +} + +SCM +ScriptCommands::getServer(void) +{ + ::Server *serv = Interp::bot->serverList->currentServer(); + int serverNumber = Interp::bot->serverList->currentNumber; + + return gh_list(scm_long2num(serverNumber), + Utils::string2SCM(serv->getHostName()), + scm_long2num(serv->getPort()), + Utils::string2SCM(serv->getPassword()), + SCM_UNDEFINED); +} + +SCM +ScriptCommands::getServerList(void) +{ + SCM res = gh_list(SCM_UNDEFINED); + ::Server *s; + int i = 0; + std::vector::iterator it = Interp::bot->serverList->begin(); + + for ( ; it != Interp::bot->serverList->end(); ++it) { + s = (*it); + res = gh_append2(res, + gh_list(gh_list(scm_long2num(i++), + Utils::string2SCM(s->getHostName()), + scm_long2num(s->getPort()), + Utils::string2SCM(s->getPassword()), + SCM_UNDEFINED), SCM_UNDEFINED)); + } + return res; +} + +SCM +ScriptCommands::flushQueue(void) +{ + if (!Interp::bot->serverConnection) + return SCM_BOOL_F; + Interp::bot->serverConnection->queue->flush(); + return SCM_BOOL_T; +} + +SCM +ScriptCommands::flushPort(void) +{ + scm_flush(Interp::bot->botInterp->logPort); + return SCM_BOOL_T; +} + +SCM +ScriptCommands::random(SCM scm_max) +{ + int max = 0; + //srand(time(NULL)); + if (SCM_NUMBERP(scm_max)) + max = gh_scm2int(scm_max); + return scm_long2num(max ? rand() % max : 0); +} + +SCM +ScriptCommands::addCommand(SCM scm_commandName, SCM scm_function, + SCM scm_needsChannel, SCM scm_args, + SCM scm_minLevel) +{ + // We check that commandName is a string + if (!SCM_STRINGP(scm_commandName)) + return SCM_BOOL_F; + + // We check that the command does not exist + String commandName = Utils::scm2String(scm_commandName).toUpper(); + std::list::iterator it = + Interp::bot->userFunctions.begin(); + for ( ; it != Interp::bot->userFunctions.end(); ++it) { + if ((*it)->name == commandName) + return SCM_BOOL_F; + } + + // Next we check that needsChannel is a boolean + if (!gh_boolean_p(scm_needsChannel)) + return SCM_BOOL_F; + bool needsChannel = (bool)gh_scm2bool(scm_needsChannel); + + // We check that minLevel is an integer and that it's + // a valid level + if (!SCM_NUMBERP(scm_minLevel)) + return SCM_BOOL_F; + + int minLevel = gh_scm2long(scm_minLevel); + if (minLevel < User::NONE || minLevel > User::MASTER) + return SCM_BOOL_F; + + // We check that "scm_function" is a Scheme procedure + if (!gh_procedure_p(scm_function)) + return SCM_BOOL_F; + + // We check that args is an integer and is between 0 and 20 (arbitrary limit) + if (!SCM_NUMBERP(scm_args)) + return SCM_BOOL_F; + + int args = gh_scm2long(scm_args); + if (args < 0 || args > 20) + return SCM_BOOL_F; + + // We add the command in the commands list + Interp::bot->userFunctions.push_back(new userFunction(commandName, +(void (*)(ServerConnection *, Person *, String, String))0, minLevel, needsChannel, args, scm_function)); + + return SCM_BOOL_T; +} + +SCM +ScriptCommands::delCommand(SCM scm_commandName) +{ + // We check that commandName is a string + if (!SCM_STRINGP(scm_commandName)) + return SCM_BOOL_F; + + // We check that the command does exist + String commandName = Utils::scm2String(scm_commandName).toUpper(); + std::list::iterator it = + Interp::bot->userFunctions.begin(); + for ( ; it != Interp::bot->userFunctions.end(); ++it) { + if ((*it)->name == commandName) + break; + } + + if (it == Interp::bot->userFunctions.end()) + return SCM_BOOL_F; + + // We delete the command + Interp::bot->userFunctions.erase(it); + delete (*it); + + return SCM_BOOL_T; +} + +SCM +ScriptCommands::AddHook(SCM type, SCM regex, SCM function, SCM pri, SCM fall) +{ + int priority = 0; + bool fallt = false; // does this hook fall through? + + if (!SCM_UNBNDP (pri)) + priority = scm_num2int (pri, SCM_ARG1, "ScriptCommands::AddHook"); + if (!SCM_UNBNDP (fall)) + fallt = SCM_NFALSEP (fall); + return SCM_BOOL (Interp::bot->botInterp->AddHook(gh_scm2long(type), + regex, function, + priority, fallt)); +} + +SCM +ScriptCommands::AddTimer(SCM when, SCM function) +{ + return Interp::bot->botInterp->AddTimer(gh_scm2long(when), function); +} + +SCM +ScriptCommands::DelTimer(SCM timer) +{ + return gh_bool2scm(Interp::bot->botInterp->DelTimer(timer)); +} + +#endif hunk ./source/ScriptCommands.H 1 +// ScriptCommands.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 +// 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 SCRIPTCOMMANDS_H +#define SCRIPTCOMMANDS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef USESCRIPTS + +#include +#include "Commands.H" + +class ScriptCommands { +public: + static SCM Action(SCM, SCM); + static SCM AddUser(SCM, SCM, SCM, SCM, SCM, SCM, SCM); + static SCM AddServer(SCM, SCM); + static SCM AddShit(SCM, SCM, SCM, SCM, SCM); + static SCM Ban(SCM, SCM); + static SCM ChangeLevel(SCM, SCM, SCM); + static SCM Cycle(SCM); + static SCM Deban(SCM, SCM); + static SCM DelServer(SCM); + static SCM DelUser(SCM, SCM); + static SCM DelShit(SCM, SCM); + static SCM Deop(SCM, SCM); + static SCM Die(SCM); + static SCM Do(SCM); + static SCM Invite(SCM, SCM); + static SCM Join(SCM, SCM); + static SCM Keep(SCM, SCM); + static SCM Kick(SCM, SCM, SCM); + static SCM KickBan(SCM, SCM, SCM); + static SCM Lock(SCM); + static SCM LogPort(void); + static SCM Mode(SCM, SCM); + static SCM Msg(SCM, SCM); + static SCM NextServer(void); + static SCM Nick(SCM); + static SCM Op(SCM, SCM); + static SCM Part(SCM); + static SCM Reconnect(void); + static SCM Say(SCM, SCM); + static SCM Server(SCM); // ACK NAMING CLASH + static SCM SetVersion(SCM); + static SCM TBan(SCM, SCM, SCM); + static SCM TKBan(SCM, SCM, SCM, SCM); + static SCM Topic(SCM, SCM); + static SCM Unlock(SCM); + + static SCM getNickname(void); + static SCM getServer(void); + static SCM getServerList(void); + static SCM flushQueue(void); + static SCM flushPort(void); + static SCM random(SCM); + static SCM addCommand(SCM, SCM, SCM, SCM, SCM); + static SCM delCommand(SCM); + static SCM AddHook(SCM, SCM, SCM, SCM, SCM); + static SCM AddTimer(SCM, SCM); + static SCM DelTimer(SCM); +}; + +#endif +#endif hunk ./source/Server.C 1 +// Server.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 "Server.H" + +Server::Server(String h, int p, String pass) + : hostName(h), port(p), password(pass) +{ } + +String +Server::getHostName() const +{ + return hostName; +} + +int +Server::getPort() const +{ + return port; +} + +String +Server::getPassword() const +{ + return password; +} hunk ./source/Server.H 1 +// Server.H -*- 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. + +#ifndef SERVER_H +#define SERVER_H + +#include "String.H" + +class Server { + + String hostName; + int port; + String password; + +public: + Server(String, int = 6667, String = ""); + + String getHostName() const; + int getPort() const; + String getPassword() const; +}; + +#endif hunk ./source/ServerConnection.C 1 +// ServerConnection.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 "ServerConnection.H" +#include "Parser.H" +#include "Bot.H" + +ServerConnection::ServerConnection(Bot *b, Server *s, String localIP) + : Connection(s->getHostName(), + s->getPort(), localIP), + server(s), + bot(b), + queue(new ServerQueue(&socket, b->debug)), + pingTime(0), lag(0), serverLastSpoken(time(0)), + debug(b->debug) +{ + b->connected = false; +} + +ServerConnection::~ServerConnection() +{ + delete queue; +} + +bool +ServerConnection::connect() +{ + if (!socket.connect()) + return false; + + socket.setNonBlocking(); + + if (server->getPassword().length() != 0) + queue->sendPass(server->getPassword()); + queue->sendNick(bot->wantedNickName); + queue->sendUser(bot->userName, bot->ircName); + + queue->flush(); + + return true; +} + +bool +ServerConnection::handleInput() +{ + String line = socket.readLine(); + + if (line.length() == 0) + return true; + + if (bot->debug) + std::cout << line << "\n"; + + serverLastSpoken = time(0); + + Parser::parseLine(this, line); + + return false; +} hunk ./source/ServerConnection.H 1 +// ServerConnection.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 SERVERCONNECTION_H +#define SERVERCONNECTION_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "Server.H" +#include "ServerQueue.H" +#include "Connection.H" + +class Bot; +class Parser; +class Channel; +class Commands; +class UserCommands; +#ifdef USESCRIPTS +class Interp; +class BotInterp; +class ScriptCommands; +#endif + +class ServerConnection : public Connection { + Server * server; + Bot * bot; + ServerQueue * queue; + std::time_t pingTime; + int lag; + std::time_t serverLastSpoken; + bool debug; + +public: + ServerConnection(Bot *, Server *, String); + ~ServerConnection(); + + bool connect(); + bool handleInput(); + + friend class Bot; + friend class Person; + friend class Parser; + friend class Channel; + friend class Commands; + friend class UserCommands; +#ifdef USESCRIPTS + friend class Interp; + friend class BotInterp; + friend class ScriptCommands; +#endif +}; + +#endif hunk ./source/ServerList.C 1 +// ServerList.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 "ServerList.H" + +ServerList::ServerList() + : it(v.end()), current(0), currentNumber(0) +{ } + +ServerList::~ServerList() +{ + Server *s; + for (it = v.begin(); it != v.end(); ++it) { + s = *it; + delete s; + } +} + +void +ServerList::addServer(Server *s) +{ + v.push_back(s); + it = v.end(); // move to end because iterators are invalidated +} + +void +ServerList::delServer(int n) +{ + v.erase(v.begin () + n); +} + +Server * +ServerList::nextServer() +{ + if (v.empty()) + return 0; + + if (it == v.end()) { + it = v.begin(); + currentNumber = 0; + } else + currentNumber++; + + return current = *(it++); +} + +Server * +ServerList::currentServer() +{ + return current; +} hunk ./source/ServerList.H 1 +// ServerList.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 SERVERLIST_H +#define SERVERLIST_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "Server.H" + +#ifdef USESCRIPTS +class ScriptCommands; +#endif +class UserCommands; + +class ServerList { + std::vector v; + std::vector::iterator it; + Server * current; + int currentNumber; + + std::vector::iterator begin() + { return v.begin(); } + std::vector::iterator end() + { return v.end(); } + +public: + ServerList(); + ~ServerList(); + + void addServer(Server *); + void delServer(int); + + Server * nextServer(); + Server * currentServer(); + + Server * get(int n) const { return v[n]; } + int size() { return v.size(); } + +#ifdef USESCRIPTS + friend class ScriptCommands; +#endif + friend class UserCommands; +}; + +#endif hunk ./source/ServerQueue.C 1 +// ServerQueue.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 +#include "ServerQueue.H" + +ServerQueue::ServerQueue(Socket * s, bool d) + : Queue(s,d), penalty(0) +{ +#ifdef HAVE_STL_CLEAR + serverQueue.clear(); +#endif +} + +ServerQueue::~ServerQueue() +{ + penalty = INT_MIN; + flush(); +} + +void +ServerQueue::addItem(ServerQueueItem *sqi) +{ + std::list::iterator it, it2; + + for (it = serverQueue.begin(); it != serverQueue.end(); ++it) { + if ((*it)->priority > sqi->priority) + break; + } + it2 = it; --it2; + if (it2 != serverQueue.end() && *it2) { + // All right, we try to merge this item to the previous + if ((*it2)->merge(sqi)) { + delete sqi; + return; + } + } + serverQueue.insert(it, sqi); +} + +void +ServerQueue::addLine(String l, int pr, int pen, int t) +{ + ServerQueueOtherItem * sqoi = + new ServerQueueOtherItem(l, pr, pen, t); + addItem(sqoi); +} + +bool +ServerQueue::flush() +{ + // Called every second, we decrement the penalty + if (penalty > 0) + penalty--; + + while (!serverQueue.empty() && (penalty < 5)) { + ServerQueueItem * sqi = (*serverQueue.begin()); + penalty += sqi->penalty + sqi->getLine().length()/100 + 1; + bool res = sendLine(sqi->getLine()); + serverQueue.erase(serverQueue.begin()); + delete sqi; + if (!res) + return false; + } + return true; +} + +void +ServerQueue::sendCTCP(String to, String command, + String message) +{ + sendPrivmsg(to, String("\001") + command + " " + message + "\001"); +} + +void +ServerQueue::sendCTCPReply(String to, String command, + String message) +{ + sendNotice(to, String("\001") + command + " " + + message + "\001"); +} + +void +ServerQueue::sendChannelMode(String mode) +{ + addLine(mode, CHANNELMODE_PRIORITY, CHANNELMODE_PENALTY, + ServerQueueItem::CHANNELMODE); +} + +void +ServerQueue::sendChannelMode(String channel, String mode, String parameters) +{ + ServerQueueChannelModeItem * sqcmi = + new ServerQueueChannelModeItem(channel, mode, parameters); + addItem(sqcmi); +} + +void +ServerQueue::sendInvite(String channel, String nick) +{ + addLine(String("INVITE ") + nick + " " + channel, + INVITE_PRIORITY, INVITE_PENALTY, ServerQueueItem::INVITE); +} + +void +ServerQueue::sendJoin(String channel, String key) +{ + addLine(String("JOIN ") + channel + " " + key, + JOIN_PRIORITY, JOIN_PENALTY, ServerQueueItem::JOIN); +} + +void +ServerQueue::sendKick(String channel, String nick, String reason) +{ + ServerQueueKickItem * sqki = + new ServerQueueKickItem(channel, nick, reason); + addItem(sqki); +} + +void +ServerQueue::sendNick(String nick) +{ + addLine(String("NICK ") + nick, + NICK_PRIORITY, NICK_PENALTY, ServerQueueItem::NICK); +} + +void +ServerQueue::sendNotice(String to, String message) +{ + ServerQueueNoticeItem *sqni = + new ServerQueueNoticeItem(to, message); + addItem(sqni); +} + +void +ServerQueue::sendPart(String channel) +{ + addLine(String("PART ") + channel, + PART_PRIORITY, PART_PENALTY, ServerQueueItem::PART); +} + +void +ServerQueue::sendPass(String pass) +{ + addLine(String("PASS ") + pass, + NICK_PRIORITY, NICK_PENALTY, ServerQueueItem::PASS); +} + +void +ServerQueue::sendPing(String server) +{ + addLine(String("PING :") + server, + PING_PRIORITY, PING_PENALTY, ServerQueueItem::PING); +} + +void +ServerQueue::sendPong(String crap) +{ + addLine(String("PONG ") + crap, + PONG_PRIORITY, PONG_PENALTY, ServerQueueItem::PONG); +} + +void +ServerQueue::sendPrivmsg(String dest, String message) +{ + addLine(String("PRIVMSG ") + dest + " :" + message, + PRIVMSG_PRIORITY, PRIVMSG_PENALTY, ServerQueueItem::PRIVMSG); +} + +void +ServerQueue::sendQuit(String reason) +{ + addLine(String("QUIT :") + reason, + QUIT_PRIORITY, QUIT_PENALTY, ServerQueueItem::QUIT); +} + +void +ServerQueue::sendTopic(String channel, String topic) +{ + addLine(String("TOPIC ") + channel + " :" + topic, + TOPIC_PRIORITY, TOPIC_PENALTY, ServerQueueItem::TOPIC); +} + +void +ServerQueue::sendUser(String username, String ircname) +{ + addLine(String("USER ") + username + " . . :" + ircname, + NICK_PRIORITY, NICK_PENALTY, ServerQueueItem::USER); +} + +void +ServerQueue::sendUserMode(String nick, String mode) +{ + addLine(String("MODE ") + nick + " " + mode, + USERMODE_PRIORITY, USERMODE_PENALTY, + ServerQueueItem::USERMODE); +} + +void +ServerQueue::sendUserhost(String nick) +{ + addLine(String("USERHOST ") + nick, + USERHOST_PRIORITY, USERHOST_PENALTY, ServerQueueItem::USERHOST); +} + +void +ServerQueue::sendWho(String who) +{ + addLine(String("WHO ") + who, + WHO_PRIORITY, WHO_PENALTY, ServerQueueItem::WHO); +} + +void +ServerQueue::sendWhois(String nick) +{ + addLine(String("WHOIS ") + nick, + NICK_PRIORITY, WHOIS_PENALTY, ServerQueueItem::WHOIS); +} hunk ./source/ServerQueue.H 1 +// ServerQueue.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 SERVERQUEUE_H +#define SERVERQUEUE_H + +#include + +#include "String.H" +#include "Queue.H" +#include "ServerQueueItem.H" + +enum { + QUIT_PRIORITY, USERMODE_PRIORITY, CHANNELMODE_PRIORITY, + KICK_PRIORITY, PONG_PRIORITY, TOPIC_PRIORITY, PART_PRIORITY, + NICK_PRIORITY, USERHOST_PRIORITY, WHO_PRIORITY, + JOIN_PRIORITY, PING_PRIORITY, INVITE_PRIORITY, PRIVMSG_PRIORITY, + NOTICE_PRIORITY +}; + +static const int QUIT_PENALTY = 1; +static const int USERMODE_PENALTY = 2; +static const int CHANNELMODE_PENALTY = 2; +static const int KICK_PENALTY = 2; +static const int PONG_PENALTY = 1; +static const int TOPIC_PENALTY = 2; +static const int PART_PENALTY = 1; +static const int JOIN_PENALTY = 1; +static const int USERHOST_PENALTY = 1; +static const int WHO_PENALTY = 4; +static const int WHOIS_PENALTY = 1; +static const int NICK_PENALTY = 1; +static const int PING_PENALTY = 1; +static const int INVITE_PENALTY = 1; +static const int PRIVMSG_PENALTY = 1; +static const int NOTICE_PENALTY = 1; + + +class ServerQueue : public Queue { + + std::list serverQueue; + int penalty; + +public: + ServerQueue(Socket *, bool); + ~ServerQueue(); + void addItem(ServerQueueItem *); + void addLine(String, int, int, int); + bool flush(); + + void sendCTCP(String, String, String); + void sendCTCPReply(String, String, String); + void sendChannelMode(String); + void sendChannelMode(String, String, String); + void sendInvite(String, String); + void sendJoin(String, String); + void sendKick(String, String, String); + void sendNick(String); + void sendNotice(String, String); + void sendPart(String); + void sendPass(String); + void sendPing(String); + void sendPong(String); + void sendPrivmsg(String, String); + void sendQuit(String); + void sendTopic(String, String); + void sendUser(String, String); + void sendUserMode(String, String); + void sendUserhost(String); + void sendWho(String); + void sendWhois(String); +}; + +#endif hunk ./source/ServerQueueItem.C 1 +// ServerQueueItem.C -*- C++ -*- +// Copyright (c) 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 "StringTokenizer.H" +#include "ServerQueue.H" +#include "ServerQueueItem.H" + +ServerQueueItem::ServerQueueItem(int pr, int pen, int t) + : priority(pr), penalty(pen), type(t) +{ } + + + +ServerQueueOtherItem::ServerQueueOtherItem(String l, int pr, + int pen, int t) + : ServerQueueItem(pr, pen, t), line(l) +{ } + +String +ServerQueueOtherItem::getLine() +{ + return line; +} + + + +ServerQueueChannelModeItem::ServerQueueChannelModeItem(String c, String m, String p) + : ServerQueueItem(CHANNELMODE_PRIORITY, + CHANNELMODE_PENALTY, + CHANNELMODE), + channel(c), mode(m), parameters(p) +{ + StringTokenizer st(p); + paramcount = st.countTokens(); +} + +bool +ServerQueueChannelModeItem::merge(ServerQueueItem *sqi) +{ + if (sqi->type != CHANNELMODE) + return false; + + ServerQueueChannelModeItem * sqcmi = (ServerQueueChannelModeItem *)sqi; + + if (sqcmi->channel != channel || (paramcount + sqcmi->paramcount > 3)) + return false; + + char sign = '+'; + char c; + + for (int i = 0; i < mode.length(); i++) { + c = mode[i]; + switch (c) { + case '+': + case '-': + sign = c; + } + } + + char othersign = '+'; + + for (int i = 0; i < sqcmi->mode.length(); i++) { + c = sqcmi->mode[i]; + switch (c) { + case '+': + case '-': + othersign = c; + break; + default: + if (othersign == sign) + mode = mode + String(c); + else { + mode = mode + String(othersign) + String(c); + sign = othersign; + } + } + } + + parameters = parameters + " " + sqcmi->parameters; + paramcount += sqcmi->paramcount; + penalty += sqcmi->penalty; + + return true; +} + +String +ServerQueueChannelModeItem::getLine() +{ + return String("MODE ") + channel + " " + mode + " " + parameters; +} + + + +ServerQueueKickItem::ServerQueueKickItem(String c, String w, String r) + : ServerQueueItem(KICK_PRIORITY, + KICK_PENALTY, + KICK), + channel(c), who(w), reason(r), count(1) +{ } + +bool +ServerQueueKickItem::merge(ServerQueueItem *sqi) +{ + if (sqi->type != KICK) + return false; + ServerQueueKickItem * sqki = (ServerQueueKickItem *)sqi; + if (sqki->channel != channel) + return false; + if (count + sqki->count > 4) + return false; + who = who + "," + sqki->who; + if (reason != sqki->reason) + reason = "Mixed kick ! Top efficiency"; + penalty += sqki->penalty; + count += sqki->count; + + return true; +} + +String +ServerQueueKickItem::getLine() +{ + return String("KICK ") + channel + " " + who + " :" + reason; +} + +ServerQueueNoticeItem::ServerQueueNoticeItem(String d, String m) + : ServerQueueItem(NOTICE_PRIORITY, + NOTICE_PENALTY, + NOTICE), + dest(d), message(m), count(1) +{ } + +bool +ServerQueueNoticeItem::merge(ServerQueueItem *sqi) +{ + if (sqi->type != NOTICE) + return false; + ServerQueueNoticeItem * sqni = (ServerQueueNoticeItem *)sqi; + if (sqni->message != message) + return false; + if (count + sqni->count > 4) + return false; + dest = dest + "," + sqni->dest; + penalty += sqni->penalty; + count += sqni->count; + + return true; +} + +String +ServerQueueNoticeItem::getLine() +{ + return String("NOTICE ") + dest + " :" + message; +} hunk ./source/ServerQueueItem.H 1 +// ServerQueueItem.H -*- C++ -*- +// Copyright (c) 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. + +#ifndef SERVERQUEUEITEM_H +#define SERVERQUEUEITEM_H + +class ServerQueueItem { +public: + int priority, penalty, type; + + enum { + CHANNELMODE, USERMODE, INVITE, JOIN, KICK, + NICK, NOTICE, PART, PASS, PING, PONG, PRIVMSG, + QUIT, TOPIC, USER, USERHOST, WHO, WHOIS, OTHER + }; + + ServerQueueItem(int, int, int); + virtual ~ServerQueueItem() { } + + virtual bool merge(ServerQueueItem *) { return false; } + virtual String getLine() = 0; + + friend class ServerQueue; + +private: + ServerQueueItem(const ServerQueueItem &); +}; + + +class ServerQueueOtherItem : public ServerQueueItem { +public: + String line; + + ServerQueueOtherItem(String, int, int, int); + String getLine(); +}; + +class ServerQueueChannelModeItem : public ServerQueueItem { +public: + String channel; + String mode; + String parameters; + int paramcount; + + ServerQueueChannelModeItem(String, String, String); + bool merge(ServerQueueItem *); + String getLine(); +}; + +class ServerQueueKickItem : public ServerQueueItem { +public: + String channel; + String who; + String reason; + int count; + + ServerQueueKickItem(String, String, String); + bool merge(ServerQueueItem *); + String getLine(); +}; + +class ServerQueueNoticeItem : public ServerQueueItem { +public: + String dest; + String message; + int count; + + ServerQueueNoticeItem(String, String); + bool merge(ServerQueueItem *); + String getLine(); +}; + +#endif hunk ./source/ShitEntry.C 1 +// ShitEntry.C -*- C++ -*- +// Copyright (c) 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 "ShitEntry.H" + +ShitEntry::ShitEntry(String m, String mc, int l, time_t e, String r) + : shitMask(m), shitChannelMask(mc), shitLevel(l), expirationDate(e), shitReason(r) +{ } + +bool +ShitEntry::matches(String m, String mc) { + return shitMask.matches(m) && shitChannelMask.matches(mc); +} + +bool +ShitEntry::isStillValid() { + return expirationDate == -1 || time(0) <= expirationDate; +} + +String +ShitEntry::getMask() +{ + return shitMask.getMask(); +} + +String +ShitEntry::getChannelMask() +{ + return shitChannelMask.getMask(); +} + +int +ShitEntry::getShitLevel() const +{ + return shitLevel; +} + +time_t +ShitEntry::getExpirationDate() const +{ + return expirationDate; +} + +String +ShitEntry::getShitReason() const +{ + return shitReason; +} hunk ./source/ShitEntry.H 1 +// ShitEntry.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 +// 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 SHITENTRY_H +#define SHITENTRY_H + +#include + +#include "Mask.H" + +class ShitList; +class UserCommands; + +class ShitEntry { + Mask shitMask; + Mask shitChannelMask; + int shitLevel; + std::time_t expirationDate; + String shitReason; + +public: + + enum { + SHIT_NOSHIT = 0, + SHIT_NOOP = 1, + SHIT_NOJOIN = 2, + SHIT_NODEBAN = 3 + }; + + ShitEntry(String, String, int, std::time_t, String); + + bool matches(String, String); + bool isStillValid(); + + String getMask(); + String getChannelMask(); + + int getShitLevel() const; + time_t getExpirationDate() const; + String getShitReason() const; + + friend class ShitList; + friend class UserCommands; +}; + +#endif hunk ./source/ShitList.C 1 +// ShitList.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 +// 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 + +#include "ShitList.H" +#include "StringTokenizer.H" + +ShitList::ShitList(String filename) + : listFileName(filename) +{ +#ifdef HAVE_STL_CLEAR + l.clear(); +#endif + read(); +} + +ShitList::~ShitList() +{ + clear(); +} + +void +ShitList::read() +{ + std::ifstream file(listFileName); + String temp; + int line = 1; + + clear(); + + if (!file) { + std::cerr << "I cannot find the file " << listFileName << std::endl; + return; + } + + while (file >> temp, temp.length() != 0) { + StringTokenizer st(temp); + String mask = st.nextToken(':'); + String channelMask = st.nextToken(':'); + String level = st.nextToken(':'); + String expiration = st.nextToken(':'); + String reason = st.rest().trim(); + l.push_back (new ShitEntry(mask, channelMask, std::atoi(level), + std::atol(expiration), reason)); + line++; + } + file.close(); +} + +void +ShitList::save() +{ + std::list::iterator it = l.begin(); + std::ofstream file(listFileName); + + if (!file) + return; + + for ( ; it != l.end(); ++it) + if ((*it)->isStillValid()) { + file << (*it)->shitMask.getMask() << ":" + << (*it)->shitChannelMask.getMask() << ":" + << (*it)->shitLevel << ":" + << (*it)->expirationDate << ":" + << (*it)->shitReason << std::endl; + } +} + +void +ShitList::clear() +{ + ShitEntry *se; + + while (!l.empty()) { + se = (*l.begin()); + l.erase(l.begin()); + delete se; + } +} + +void +ShitList::addShit(String m, String mc, int lev, time_t e, String r) +{ + l.push_back (new ShitEntry(m, mc, lev, e, r)); +} + + +void +ShitList::delShit(String mask, String channelMask) +{ + for (std::list::iterator it = l.begin(); + it != l.end(); + ++it) + if ((*it)->shitMask.getMask() == mask && + (*it)->shitChannelMask.getMask() == channelMask) { + delete (*it); + l.erase(it); + return; + } +} + +ShitEntry * +ShitList::getShit(String nuh, String channel) +{ + for (std::list::iterator it = l.begin(); + it != l.end(); + ++it) + if ((*it)->matches(nuh, channel)) { + return (*it); + } + + return 0; +} hunk ./source/ShitList.H 1 +// ShitList.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 SHITLIST_H +#define SHITLIST_H + +#include +#include + +#include "String.H" +#include "ShitEntry.H" + +class UserCommands; + +class ShitList { + String listFileName; + std::list l; + +public: + ShitList(String); + ~ShitList(); + + void addShit(String, String, int, std::time_t, String); + void delShit(String, String); + + ShitEntry * getShit(String, String); + + void read(); + void save(); + void clear(); + + friend class UserCommands; +}; + +#endif hunk ./source/Socket.C 1 +// Socket.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 "Socket.H" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Socket::Socket() + : remotePort(0), remoteAddress(0), + localPort(0), localAddress(0) +{ + fd = new s_fd; + fd->fd = socket(AF_INET, SOCK_STREAM, 0); +} + +Socket::Socket(int newfd, unsigned long newAddress, int newPort) + : remotePort(newPort), remoteAddress(newAddress), + localPort(0), localAddress(0) +{ + fd = new s_fd; + fd->fd = newfd; +} + +Socket::Socket(const Socket &s) + : remotePort(s.remotePort), remoteAddress(s.remoteAddress), + localPort(s.localPort), localAddress(s.localAddress) +{ + s.fd->n++; + fd = s.fd; +} + +Socket::~Socket() +{ + if (--fd->n == 0) { + close(); + delete fd; + } +} + +int +Socket::getRemotePort() const +{ + return remotePort; +} + +int +Socket::getLocalPort() const +{ + return localPort; +} + +int +Socket::getFileDescriptor() const +{ + return fd->fd; +} + +bool +Socket::isConnected() +{ + return fd->fd != -1; +} + +bool +Socket::setRemoteHostname(String hostname) +{ + struct hostent *host; + + if ((host = gethostbyname((const char *)hostname)) == 0) + return false; + + memcpy(&remoteAddress, host->h_addr, host->h_length); + remoteAddress = ntohl(remoteAddress); + + return true; +} + +bool +Socket::setRemoteIP(unsigned long address) +{ + remoteAddress = address; + return true; +} + +bool +Socket::setRemotePort(int p) +{ + remotePort = p; + + return true; +} + +bool +Socket::setLocalHostname(String hostname) +{ + struct hostent *host; + + if ((host = gethostbyname((const char *)hostname)) == 0) + return false; + + memcpy(&localAddress, host->h_addr, host->h_length); + + struct sockaddr_in local_addr; + local_addr.sin_family = AF_INET; + local_addr.sin_port = htons(localPort); + local_addr.sin_addr.s_addr = htonl(localAddress); + if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0) + return false; + + return true; +} + +bool +Socket::setLocalIP(unsigned long address) +{ + localAddress = address; + + struct sockaddr_in local_addr; + local_addr.sin_family = AF_INET; + local_addr.sin_port = htons(localPort); + local_addr.sin_addr.s_addr = htonl(localAddress); + if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0) + return false; + + return true; +} + +bool +Socket::setLocalPort(int p) +{ + localPort = p; + + struct sockaddr_in local_addr; + local_addr.sin_family = AF_INET; + local_addr.sin_port = htons(localPort); + local_addr.sin_addr.s_addr = htonl(localAddress); + if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0) + return false; + + return true; +} + +bool +Socket::setNonBlocking(bool nonblock) +{ + long flags; + + if (fd->fd == -1) + return false; + + // We first get the file descriptor's flags + if (!fcntl(fd->fd, F_GETFL, &flags)) + return false; + + if (nonblock) + return fcntl(fd->fd, F_SETFL, flags | O_NONBLOCK); + else + return fcntl(fd->fd, F_SETFL, flags & ~O_NONBLOCK); +} + +bool +Socket::connect() +{ + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(remoteAddress); + addr.sin_port = htons(remotePort); + if (::connect(fd->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + return false; + + return true; +} + +bool +Socket::listen(int backlog) +{ + return ::listen(fd->fd, backlog) == 0; +} + +Socket +Socket::accept() +{ + struct sockaddr_in addr; + socklen_t addrlen=sizeof(addr); + int newfd = ::accept(fd->fd, (sockaddr *)&addr, &addrlen); + if (newfd == -1) + return Socket(-1, 0, 0); + unsigned long newRemoteAddress = ntohl(addr.sin_addr.s_addr); + int newRemotePort = ntohs(addr.sin_port); + return Socket(newfd, newRemoteAddress, newRemotePort); +} + +void +Socket::close() +{ + ::close(fd->fd); + fd->fd = -1; +} + +bool +Socket::write(String s, bool m) +{ + if (fd->fd == -1) + return false; + + if (m) { + if (::write(fd->fd, (const char *)s, s.length()) + + ::write(fd->fd, "\n", 1) != s.length() + 1) + return false; + } + else + if (::write(fd->fd, (const char *)s, s.length()) + + ::write(fd->fd, "\r\n", 2) != s.length() + 2) + return false; + + return true; +} + +String +Socket::readLine() +{ + static char buf[512]; + int pos = 0, nb; + char r; + + do { + nb = ::read(fd->fd, &r, 1); + switch (nb) { + case 0: + return String(""); + case -1: + if (errno != EINTR && errno != EAGAIN) + return String(""); + sleep(1); + } + + if (nb != -1) + buf[pos++] = r; + } while (r != '\n'); + + if (pos > 1 && buf[pos-2] == '\r') + buf[pos-2] = '\0'; + else + buf[pos-1] = '\0'; + + return String(buf); +} + +String +Socket::readChar() +{ + char r[2]; + int nb; + nb = ::read(fd->fd, &r, 1); + switch (nb) { + case 0: + return String(""); + case -1: + if(errno != EINTR && errno != EAGAIN) + return String(""); + sleep(1); + } + r[1] = '\0'; + return String(r); +} + + +// // Here we use a circular buffer to read from the socket +// String +// Socket::readLine() +// { +// // The result string +// char result[512]; +// // Position in the result string +// int pos = 0; +// // Number of chars read from the socket +// int nb; + +// // First, we read from the socket +// beginning: +// if (end <= begin) { +// nb = ::read(fd->fd, buf+end, begin - end); +// } else { +// nb = ::read(fd->fd, buf+end, 1024 - end); +// } + +// if (nb == -1 && errno != EINTR && errno != EAGAIN) +// return String(""); + +// end = (end + nb) % 1024; + +// // Fine, now we read our string from the buffer +// while (buf[begin] != '\r' && buf[begin] != '\n') { +// result[pos++] = buf[begin++]; +// begin %= 1024; +// if (begin == end) +// goto beginning; +// } + +// result[pos] = '\0'; + +// // Now we skip the final '\r' and '\n' +// if (buf[begin] == '\r') +// begin = (begin + 1) % 1024; +// if (buf[begin] == '\n') +// begin = (begin + 1) % 1024; + +// // And we return the result +// return String(result); +// } + +// bool +// Socket::hasData() +// { +// cout << "DEBUG hasData = " << (begin != end) << endl; +// return begin != end; +// } hunk ./source/Socket.H 1 +// Socket.H -*- 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. + +#ifndef SOCKET_H +#define SOCKET_H + + +#include "String.H" + +class Socket { + struct s_fd { + int fd; // the data + int n; // reference counter + s_fd() { n = 1; } + }; + s_fd *fd; + + int remotePort; + unsigned long remoteAddress; + + int localPort; + unsigned long localAddress; + + int begin, end; + + char buf[1024]; + +public: + Socket(); + Socket(int, unsigned long, int); + Socket(const Socket &); + + ~Socket(); + + int getRemotePort() const; + int getLocalPort() const; + int getFileDescriptor() const; + + bool isConnected(); + + bool setRemoteHostname(String); + bool setRemoteIP(unsigned long); + bool setRemotePort(int); + + bool setLocalHostname(String); + bool setLocalIP(unsigned long); + bool setLocalPort(int); + + bool setNonBlocking(bool = true); + + bool connect(); + bool listen(int = 5); + Socket accept(); + void close(); + + bool write(String, bool = false); + String readLine(); + String readChar(); + bool hasData(); +private: + Socket(Socket &); +}; + +#endif hunk ./source/String.C 1 +// String.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 "String.H" + +#include +#include +#include + +String::String() +{ + p = new srep; + len = 0; + p->s = 0; +} + +String::String(const char *s) +{ + p = new srep; + len = strlen(s); + p->s = new char[len + 1]; + std::strcpy(p->s, s); +} + +String::String(const std::string & s) +{ + p = new srep; + len = s.length (); + p->s = new char[len + 1]; + std::strcpy (p->s, s.c_str ()); +} + +String::String(const String & s) +{ + s.p->n++; + p = s.p; + len = s.len; +} + +String::String(long i) +{ + std::ostringstream temp; + temp << i; + + p = new srep; + len = strlen(temp.str().c_str ()); + p->s = new char[len + 1]; + strcpy(p->s, temp.str().c_str ()); +} + +String::String(char c) +{ + p = new srep; + p->s = new char[2]; + p->s[0] = c; + p->s[1] = '\0'; + len = 1; +} + +String::~String() +{ + if (--p->n == 0) { + delete[] p->s; + delete p; + } +} + +String & +String::operator=(const char *s) +{ + if (p->n > 1) { + p->n--; + p = new srep; + } + else + delete[] p->s; + + len = strlen(s); + p->s = new char[len + 1]; + strcpy(p->s, s); + + return *this; +} + +String & +String::operator=(const String & s) +{ + s.p->n++; // protection contre st = st + if (--p->n == 0) { + delete[] p->s; + delete p; + } + p = s.p; + len = s.len; + return *this; +} + +String & +String::operator=(const std::string & s) +{ + if (p->n > 1) { + p->n--; + p = new srep; + } + else + delete[] p->s; + + len = s.length (); + p->s = new char[len + 1]; + strcpy(p->s, s.c_str ()); + + return *this; +} + +int +String::length() const +{ + return len; +} + +int +String::find(char c) +{ + if (!strchr(p->s, c)) + return -1; + + return (int)(strchr(p->s, c) - p->s); +} + +void +String::fill(char c) +{ + for (char * s = p->s; *s; s++) + *s = c; +} + +String +String::pad(int n) +{ + int l = len; + + if (n <= l) + return subString(0, n-1); + + char *temp = new char[n+1]; + strcpy(temp, p->s); + + for (int i = l; i < n; i++) + temp[i] = ' '; + temp[n] = '\0'; + + String res(temp); + delete temp; + + return res; +} + +String +String::subString(int debut, int fin) +{ + if (fin < debut) return ""; + + char * temp = new char[fin-debut+2]; + strncpy(temp, p->s + debut, fin - debut + 1); + temp[fin - debut + 1] = '\0'; + String res(temp); + delete temp; + return res; +} + +String +String::subString(int debut) +{ + return subString(debut, len - 1); +} + +String +String::toLower() +{ + char *temp = new char[len + 1]; + + for (int i = 0; i < len + 1; i++) + if (isupper(p->s[i])) + temp[i] = tolower(p->s[i]); + else + temp[i] = p->s[i]; + + String res(temp); + delete temp; + return res; +} + +String +String::toUpper() +{ + char *temp = new char[len + 1]; + + for (int i = 0; i < len + 1; i++) + if (islower(p->s[i])) + temp[i] = toupper(p->s[i]); + else + temp[i] = p->s[i]; + + String res(temp); + delete temp; + return res; +} + +String +String::trim() +{ + int i = 0, j = len - 1; + + while (i < j && (p->s[i] == ' ' || p->s[i] == '\t' || p->s[i] == '\r')) + i++; + + while (j > 0 && (p->s[j] == ' ' || p->s[j] == '\t' || p->s[i] == '\r')) + j--; + + return subString(i, j); +} + +int +String::indexOf(char c) +{ + char *s = std::strchr(p->s, c); + if (s) + return p->s - s; + + return -1; +} + +char & +String::operator[](int i) +{ + if (i < 0 || len < i) { + std::cerr << "String index out of range\n"; + std::exit(1); + } + return p->s[i]; +} + +const char & +String::operator[](int i) const +{ + if (i < 0 || len < i) { + std::cerr << "String index out of range\n"; + exit(1); + } + return p->s[i]; +} + +bool +String::operator==(const char *s) const +{ + return std::strcmp(p->s, s) == 0; +} + +bool +String::operator==(const String & s) const +{ + return (p == s.p) || (std::strcmp(p->s, s.p->s) == 0); +} + +bool +String::operator==(const std::string & s) const +{ + return (p->s == s.c_str ()) || (std::strcmp (p->s, s.c_str()) == 0); +} + +bool +String::operator!=(const char *s) const +{ + return std::strcmp(p->s, s) != 0; +} + +bool +String::operator!=(const String & s) const +{ + return std::strcmp(p->s, s.p->s) != 0; +} + +bool +String::operator!=(const std::string & s) const +{ + return ! (*this == s); +} + +bool +String::operator<(const String & s) const +{ + return std::strcmp(p->s, s.p->s) < 0; +} + +bool +String::operator<(const std::string & s) const +{ + return std::strcmp(p->s, s.c_str ()) < 0; +} + +bool +String::operator>(const String & s) const +{ + return std::strcmp(p->s, s.p->s) > 0; +} + +bool +String::operator<=(const String & s) const +{ + return std::strcmp(p->s, s.p->s) <= 0; +} + +bool +String::operator<=(const std::string & s) const +{ + return (*this < s) || (*this == s); +} + +bool +String::operator>=(const String & s) const +{ + return std::strcmp(p->s, s.p->s) >= 0; +} + +bool String::operator>=(const std::string & s) const +{ + return ! (*this < s); +} + +String +String::operator+(const char *s) +{ + char *temp = new char[len + std::strlen(s) + 1]; + + std::strcpy(temp, p->s); + std::strcat(temp, s); + + String res(temp); + delete temp; + + return res; +} + +String +String::operator+(const String & s) +{ + char * temp = new char[len + s.len + 1]; + + std::strcpy(temp, p->s); + std::strcat(temp, s.p->s); + + String res(temp); + delete temp; + + return res; +} + +String +String::operator+(const std::string & s) +{ + char * temp = new char[len + s.length () + 1]; + std::strcpy (temp, p->s); + std::strcat (temp, s.c_str ()); + + String res (temp); + delete temp; + + return res; +} + +String::operator const char *() const +{ + return p->s; +} + +String::operator std::string () const +{ + return std::string (p->s); +} + +std::ostream & +operator<<(std::ostream & s, const String & st) +{ + return s << st.p->s; +} + +std::istream & +operator>>(std::istream & s, String & st) +{ + if (st.p->n > 1) { + st.p->n--; + st.p = new String::srep; + } + else + delete[] st.p->s; + + char buf[2048]; + char c; + + s.getline (buf, 2048, '\n'); + //s.get(c); + + st.len = strlen(buf); + st.p->s = new char[st.len + 1]; + strcpy(st.p->s, buf); + + return s; +} + +std::string operator+(const std::string & s, const String & p) +{ + std::string temp = s; + temp += p.p->s; + return temp; +} + +bool operator==(const std::string & s, const String & p) +{ + return p == s; +} + +bool operator!=(const std::string & s, const String & p) +{ + return p != s; +} + +bool operator>(const std::string & s, const String & p) +{ + return p <= s; +} + +bool operator<(const std::string & s, const String & p) +{ + return p >= s; +} + +bool operator<=(const std::string & s, const String & p) +{ + return p > s; +} + +bool operator>=(const std::string & s, const String & p) +{ + return p < s; +} hunk ./source/String.H 1 +// String.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 STRING_H +#define STRING_H + +#include +#include + +class String { + + struct srep { + char *s; // pointer on the data + int n; // reference counter + srep() + { n = 1; } + }; + srep *p; + int len; + +public: + String(); + String(const char *); + String(const String &); + String(const std::string &); + String(long); + String(char); + + String & operator=(const char *); + String & operator=(const String &); + String & operator=(const std::string &); + + ~String(); + + int length() const; + int find(char); + void fill(char); + String pad(int); + + String subString(int); + String subString(int, int); + + String toLower(); + String toUpper(); + String trim(); + int indexOf(char); + + char & operator[](int); + const char & operator[](int) const; + + bool operator==(const char *) const; + bool operator==(const String &) const; + bool operator==(const std::string &) const; + + bool operator!=(const char *) const; + bool operator!=(const String &) const; + bool operator!=(const std::string &) const; + + bool operator<(const String &) const; + bool operator>(const String &) const; + bool operator<(const std::string &) const; + + bool operator<=(const String &) const; + bool operator<=(const std::string &) const; + bool operator>=(const String &) const; + bool operator>=(const std::string &) const; + + String operator+(const char *); + String operator+(const String &); + String operator+(const std::string &); + + friend std::string operator+(const std::string &, const String &); + + operator const char *() const; + operator std::string () const; + + friend std::ostream & operator<<(std::ostream &, const String &); + friend std::istream & operator>>(std::istream &, String &); +}; + +bool operator==(const std::string &, const String &); +bool operator!=(const std::string &, const String &); +bool operator>(const std::string &, const String &); +bool operator<(const std::string &, const String &); +bool operator<=(const std::string &, const String &); +bool operator>=(const std::string &, const String &); + +#endif hunk ./source/StringTokenizer.C 1 +// StringTokenizer.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 "StringTokenizer.H" + +StringTokenizer::StringTokenizer(String string) + : st(string), pos(0) +{ } + +bool +StringTokenizer::hasMoreTokens() +{ + if (pos == st.length()) + return false; + + for (int i = pos; i < st.length(); i++) + if (st[i] != ' ' && st[i] != '\t') + return true; + + return false; +} + +bool +StringTokenizer::hasMoreTokens(char c) +{ + if (pos == st.length()) + return false; + + for (int i = pos; i < st.length(); i++) + if (st[i] != c) + return true; + + return false; +} + +int +StringTokenizer::countTokens() +{ + int i = 0; + StringTokenizer s(st); + + while (s.hasMoreTokens()) { + s.nextToken(); + i++; + } + + return i; +} + +int +StringTokenizer::countTokens(char c) +{ + int i = 0; + StringTokenizer s(st); + + while (s.hasMoreTokens(c)) { + s.nextToken(c); + i++; + } + + return i; +} + +String +StringTokenizer::nextToken() +{ + int i = pos; + + while (i < st.length() && (st[i] == ' ' || st[i] == '\t')) + i++; + + for (int j = i; j < st.length(); j++) + if (st[j] == ' ' || st[j] == '\t') { + pos = j + 1; + return st.subString(i, j - 1); + } + + pos = st.length(); + return st.subString(i, st.length() - 1); +} + +String +StringTokenizer::nextToken(char c, bool empty) +{ + int i = pos; + + while (i < st.length() && (st[i] == c)) + i++; + for (int j = i; j < st.length(); j++) + if (st[j] == c) { + pos = j + 1; + return st.subString(i, j - 1); + } + + if (empty) + return ""; + + pos = st.length(); + return st.subString(i, st.length() - 1); +} + +String +StringTokenizer::rest() +{ + if (pos == st.length()) + return ""; + + while (pos < st.length() && (st[pos] == ' ' || st[pos] == '\t')) + pos++; + + return st.subString(pos, st.length() - 1); +} hunk ./source/StringTokenizer.H 1 +// StringTokenizer.H -*- 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. + +#ifndef STRINGTOKENIZER_H +#define STRINGTOKENIZER_H + +#include "String.H" + +class StringTokenizer { + String st; + int pos; +public: + StringTokenizer(String); + StringTokenizer(StringTokenizer &); + + bool hasMoreTokens(); + bool hasMoreTokens(char); + + int countTokens(); + int countTokens(char); + + String nextToken(); + String nextToken(char, bool = false); + + String rest(); +}; + +#endif hunk ./source/TodoList.C 1 +// TodoList.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. + +#include "TodoList.H" + +TodoList::TodoList() +{ +#ifdef HAVE_STL_CLEAR + todoQueue.clear(); +#endif +} + +TodoList::~TodoList() +{ } + +void +TodoList::addDeban(String channel, String mask, time_t when) +{ + TodoListItem tdli(String("MODE ") + channel + + " -b " + mask, when); + todoQueue.insert(tdli); +} + +String +TodoList::getNext() +{ + std::multiset >::iterator it; + std::time_t current_time = time(0); + + it = todoQueue.begin(); + + if (it == todoQueue.end() || (*it).when > current_time) + return ""; + + String result = (*it).line; + todoQueue.erase(it); + + return result; +} hunk ./source/TodoList.H 1 +// TodoList.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 TODOLIST_H +#define TODOLIST_H + +#include +#include +#include + +#include "String.H" + +class TodoList; + +class TodoListItem { + String line; + std::time_t when; +public: + TodoListItem(String l, std::time_t w) + : line(l), when(w) { } + + bool operator<(const TodoListItem &t) const + { return when < t.when; } + + friend class TodoList; +}; + +class TodoList { + + std::multiset > todoQueue; + +public: + TodoList(); + ~TodoList(); + + void addDeban(String, String, std::time_t); + + String getNext(); +}; + +#endif hunk ./source/User.C 1 +// User.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 "Utils.H" +#include "User.H" + +User::User(String n, String uh, String channel, int mode, UserList *ul) + : mode(mode), floodNum(0), + userListItem(ul->getUserListItem(n + "!" + uh, channel)), + nick(n), userhost(uh), + userkey("") +{ } + +User::User(String n, int mode) + : mode(mode), floodNum(0), + userListItem(0), nick(n), userhost("") +{ } + +int +User::getLevel() +{ + if (userListItem && userListItem->identified && + (userListItem->expirationDate == -1 || + userListItem->expirationDate > time(0))) + return userListItem->level; + return 0; +} + +int +User::getProt() +{ + if (userListItem && userListItem->identified && + (userListItem->expirationDate == -1 || + userListItem->expirationDate > time(0))) + return userListItem->prot; + return 0; +} + +bool +User::getAop() +{ + if (userListItem && userListItem->identified && + (userListItem->expirationDate == -1 || + userListItem->expirationDate < time(0))) + return userListItem->aop; + return false; +} hunk ./source/User.H 1 +// User.H -*- 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. + +#ifndef USER_H +#define USER_H + +#include "UserList.H" +#include "UserListItem.H" + +class Bot; +class Utils; +class Parser; +class Channel; +class Commands; +class UserCommands; + +class User { + + int mode; + int floodNum; + UserListItem * userListItem; + String nick; + String userhost; + String userkey; + +public: + enum { + OP_MODE = 1, + VOICE_MODE = 2, + AWAY_MODE = 4, + IRCOP_MODE = 8 + }; + + enum { + NONE = 0, + USER = 1, + TRUSTED_USER = 2, + FRIEND = 3, + MASTER = 4 + }; + + enum { + NO_PROT = 0, + NO_BAN = 1, + NO_KICK = 2, + NO_DEOP = 3 + }; + + User(String, String, String, int, UserList *); + User(String, int); + + int getLevel(); + int getProt(); + bool getAop(); + + friend class Bot; + friend class Utils; + friend class Parser; + friend class Channel; + friend class Commands; + friend class UserCommands; +}; + +#endif hunk ./source/UserCommands.C 1 +// UserCommands.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 +#include +#include +#include +#include +#include +#include +#ifndef _X_OPEN_SOURCE +#define _X_OPEN_SOURCE +#endif +#ifndef _X_OPEN_SOURCE_EXTENDED +#define _X_OPEN_SOURCE_EXTENDED 1 +#endif +#ifndef __USE_XOPEN +#define __USE_XOPEN +#endif +#include + +#include "Commands.H" +#include "UserCommands.H" +#include "DCCConnection.H" +#include "Parser.H" +#include "Macros.H" +#include "StringTokenizer.H" +#include "Utils.H" +#include "ServerList.H" +#include "Server.H" + +#ifdef NOCRYPT +char * crypt(const char *p, const char *s) { return p; } +#endif + +void +UserCommands::Action(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + Message m = Commands::Action(cnx->bot, channel, rest); + if (m.getCode() != 0) + from->sendNotice(m.getMessage()); +} + +void +UserCommands::AddUser(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + String mask, who, maskChannel, level, prot, + aop, expiration, passwd; + + mask = who = st.nextToken(); + maskChannel = st.nextToken(); + level = st.nextToken(); + prot = st.nextToken(); + aop = st.nextToken(); + expiration = st.nextToken(); + passwd = st.nextToken(); + + if (mask == "" || maskChannel == "" || level == "" || + prot == "" || aop == "") { + from->sendNotice("\002Invalid syntax for this command.\002"); + return; + } + +// if (!Utils::isWildcard(mask)) { +// mask = cnx->bot->getUserhost(channel, who); +// if (mask == "") { +// from->sendNotice(String("\002I can not find\002 ") + who); +// return; +// } +// mask = Utils::makeWildcard(mask); +// } + +// if (cnx->bot->userList->isInUserList(mask, maskChannel)) { +// from->sendNotice(who + " \002is already in userlist on channel(s)\002 " + +// maskChannel); +// return; +// } + + int l, p; + bool a; + time_t e; + + l = atoi((const char *)level); + if (l < 0 || l > User::FRIEND) + return; + if (l > Utils::getLevel(cnx->bot, from->getAddress())) { + from->sendNotice("\002You can not give a level greater than yours.\002"); + return; + } + p = atoi((const char *)prot); + if (p < 0 || p > User::NO_DEOP) + return; + a = (bool)atoi((const char *)aop); + if (a != 0 && a != 1) + return; + + e = Utils::strToTime(expiration); + + if (!e) + e = -1; + + // cnx->bot->userList->addUser(mask, maskChannel, l, p, a, e, passwd); + + Message m = + Commands::AddUser (cnx->bot, who, maskChannel, l, p, a, e, passwd); + if (!m.getCode ()) + { + from->sendNotice(String("\002Added\002 ") + mask + + " \002on channels\002 " + maskChannel); + from->sendNotice(String("\002Level:\002 ") + + Utils::levelToStr(l) + + " \002Protection:\002 " + + Utils::protToStr(p) + + " \002Auto-op:\002 " + + Utils::boolToStr(a)); + } + else + from->sendNotice(m.getMessage ()); + + // cnx->bot->rehash(); +} + +void +UserCommands::AddServer(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() == 0) { + from->sendNotice("\002You must supply a server name.\002"); + return; + } + + StringTokenizer st(rest); + String serverName = st.nextToken(); + int port = 6667; + + if (st.hasMoreTokens()) { + String temp = st.nextToken(); + port = atoi((const char *)temp); + } + + Message m = Commands::AddServer(cnx->bot, serverName, port); + if (m.getCode() != 0) + from->sendNotice(m.getMessage()); + else + from->sendNotice(String("\002Server\002 ") + + serverName + " \002on port\002 " + + String((long)port) + " \002has been added " + "to the server list.\002"); +} + +// FIXME: does this work now +void +UserCommands::AddShit(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + String mask, who, maskChannel, level, expiration, reason; + + mask = who = st.nextToken(); + maskChannel = st.nextToken(); + level = st.nextToken(); + expiration = st.nextToken(); + reason = st.rest().trim(); + + /* if (mask == "" || maskChannel == "" || level == "") { + from->sendNotice("\002Invalid syntax for this command.\002"); + return; + } + */ + + /* + if (reason == "") + reason = "You're on my shitlist, lamer"; + */ + + /* + if (!Utils::isWildcard(mask)) { + mask = cnx->bot->getUserhost(channel, who); + if (mask == "") { + from->sendNotice(String("\002I can not find\002 ") + who); + return; + } + mask = Utils::makeWildcard(mask); + if (cnx->bot->shitList->getShit(mask, maskChannel)) { + from->sendNotice(mask + " \002is already in shitlist on channel(s)\002 " + + maskChannel); + return; + } + } + */ + int l; + time_t e; + + l = atoi((const char *)level); + if (l < 0 || l > ShitEntry::SHIT_NODEBAN) + return; + + e = Utils::strToTime(expiration); + + if (!e) + e = -1; + + /* + if (cnx->bot->userList->getMaxProt(mask, maskChannel) > 0) { + from->sendNotice(String("\002I can not add\002 ") + who + + " \002into the shitlist (protection)."); + return; + } + + cnx->bot->shitList->addShit(mask, maskChannel, l, e, reason); + */ + + Message M = Commands::AddShit (cnx->bot, mask, maskChannel, l, e, reason); + if (!M.getCode ()) + from->sendNotice(String("\002Added\002 ") + mask + + " \002on channels\002 " + maskChannel + + " \002into the shitlist.\002"); + else + from->sendNotice (M.getMessage ()); +} + +// FIXME: Convert (and change ?) +void +UserCommands::Alias(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + String newF = st.nextToken().toUpper(); + String oldF = st.nextToken().toUpper(); + std::list::iterator it; + + if (newF == "" || oldF == "") { + from->sendNotice("\002Invalid syntax for this command.\002"); + return; + } + + // First, we check that the "new" function does not exist + for (it = cnx->bot->userFunctions.begin(); it != + cnx->bot->userFunctions.end(); ++it) + if (newF == (*it)->name) { + from->sendNotice(newF + " \002is already an alias.\002"); + return; + } + + // Next, we check that the "old" function exist + bool found = false; + userFunction *u; + for (it = cnx->bot->userFunctions.begin(); it != + cnx->bot->userFunctions.end(); ++it) + if (oldF == (*it)->name) { + found = true; + u = *it; + break; + } + if (!found) { + from->sendNotice(String("\002I don't know the\002 ") + oldF + + " \002command."); + return; + } + + // Fine, we do the binding + cnx->bot->userFunctions.push_back(new + userFunction((char *)(const char + *)newF, + u->function, + u->minLevel, + u->needsChannelName)); + + from->sendNotice("\002Alias added.\002"); +} + +void +UserCommands::Ban(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() == 0) { + if (from) + from->sendNotice("\002No nick/mask specified.\002"); + return; + } + + Message m = Commands::Ban(cnx->bot, channel, rest); + if (m.getCode() != 0 && from) + from->sendNotice(m.getMessage()); +} + +void +UserCommands::BanList(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + time_t current = time(0); + Channel *c = cnx->bot->channelList->getChannel(channel); + from->sendNotice(String("\002Banlist for channel\002 ") + + channel + "\002:\002"); + from->sendNotice("\002Mask Expires (seconds)\002"); + for (std::vector::iterator it = c->channelBanlist.begin(); + it != c->channelBanlist.end(); ++it) + if ((*it)->getExpirationDate() == -1) + from->sendNotice((*it)->getMask().pad(30) + " -1"); + else + from->sendNotice((*it)->getMask().pad(30) + " " + + String((long)((*it)->getExpirationDate()-current))); + from->sendNotice("\002End of banlist.\002"); +} + +// void +// UserCommands::ChangeLevel(ServerConnection *cnx, Person *from, +// String channel, String rest) +// { +// StringTokenizer st(rest); + +// String who; +// String mask = who = st.nextToken(); +// String maskChannel = st.nextToken(); +// String level = st.nextToken(); + +// if (mask == "" || maskChannel == "" || level == "") { +// from->sendNotice("\002Invalid syntax for this command.\002"); +// return; +// } + +// if (!Utils::isWildcard(mask)) { +// mask = cnx->bot->getUserhost(channel, who); +// if (mask == "") { +// from->sendNotice(String("\002I can not find\002 ") + who); +// return; +// } +// mask = from->getNick() + "!" + mask; +// } + +// UserListItem *uli = cnx->bot->userList->getUserListItem(mask, maskChannel); + +// if (!uli) { +// from->sendNotice(String("\002I can not find\002 ") + who + +// " \002on channel(s)\002 " + maskChannel + +// " \002in my userlist.\002"); +// return; +// } + +// int l = atoi((const char *)level); + +// if (l < User::NONE || l > User::MASTER) { +// from->sendNotice("\002This is not a valid level.\002"); +// return; +// } + +// if (l > Utils::getLevel(cnx->bot, from->getAddress())) { +// from->sendNotice("\002You can not give a level greater than yours.\002"); +// return; +// } + +// if (Utils::getLevel(cnx->bot, from->getAddress()) < uli->level) { +// from->sendNotice("\002You can not change the level for a person " +// "whose level is greater than yours.\002"); +// return; +// } + +// uli->level = l; +// from->sendNotice("\002Level changed.\002"); +// cnx->bot->rehash(); +// } + +void +UserCommands::Channels(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String result = ""; + + for (std::map >::iterator it = + cnx->bot->channelList->begin(); + it != cnx->bot->channelList->end(); ++it) + result = result + (*it).first + " "; + + if (result == "") + from->sendNotice("\002I am not on any channel.\002"); + else + from->sendNotice(String("\002I am currently on channel(s):\002 ") + + + result); +} + +void +UserCommands::Cycle(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + Message m = Commands::Cycle(cnx->bot, channel); + if (m.getCode() != 0) + from->sendNotice(m.getMessage()); +} + +void +UserCommands::DCCList(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + time_t current_time = time(0); + + from->sendNotice("\002DCClist:\002"); + from->sendNotice("\002Hostname Last used\002"); + + for (std::list::iterator it = + cnx->bot->dccConnections.begin(); + it != cnx->bot->dccConnections.end(); + ++it) { + from->sendNotice((*it)->nuh.pad(32) + " " + + String((long)(current_time - + (*it)->lastSpoken))); + } + + from->sendNotice("\002End of dcclist.\002"); +} + +void +UserCommands::Deban(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() == 0) { + from->sendNotice("\002No nick/mask specified.\002"); + return; + } + + Message m = Commands::Deban(cnx->bot, channel, rest); + if (m.getCode() != 0) + from->sendNotice(m.getMessage()); +} + +void +UserCommands::DelServer(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() == 0) { + from->sendNotice("\002You need to supply a server number" + " for this command.\002"); + return; + } + + int serverNumber = atoi(rest); + + Message m = Commands::DelServer(cnx->bot, serverNumber); + if (m.getCode() != 0) + from->sendNotice(m.getMessage()); + else + from->sendNotice(String("Deleted server ") + + cnx->bot->serverList->get(serverNumber)->getHostName() + + " (" + String((long)cnx->bot->serverList->get(serverNumber)->getPort()) + + ")."); +} + +// FIXME: Convert +void +UserCommands::DelUser(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + + String who; + String mask = who = st.nextToken(); + String maskChannel = st.nextToken(); + + if (mask == "" || maskChannel == "") { + from->sendNotice("\002Invalid syntax for this command.\002"); + return; + } + + if (!Utils::isWildcard(mask)) { + mask = cnx->bot->getUserhost(channel, who); + if (mask == "") { + from->sendNotice(String("\002I can not find\002 ") + who); + return; + } + mask = Utils::makeWildcard(mask); + } + + if (!cnx->bot->userList->isInUserList(mask, maskChannel)) { + from->sendNotice(mask + " \002is not in userlist on channel(s)\002 " + + maskChannel); + return; + } + + cnx->bot->userList->removeUser(mask, maskChannel); + from->sendNotice(who + " \002has been removed from the userlist.\002"); + cnx->bot->rehash(); +} + +// FIXME: Convert +void +UserCommands::DelShit(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + + String who; + String mask = who = st.nextToken(); + String maskChannel = st.nextToken(); + + if (mask == "" || maskChannel == "") { + from->sendNotice("\002Invalid syntax for this command.\002"); + return; + } + + if (!Utils::isWildcard(mask)) { + mask = cnx->bot->getUserhost(channel, who); + if (mask == "") { + from->sendNotice(String("\002I can not find\002 ") + who); + return; + } + mask = Utils::makeWildcard(mask); + } + + if (!cnx->bot->shitList->getShit(mask, maskChannel)) { + from->sendNotice(mask + " \002is not in shitlist on channel(s)\002 " + + maskChannel); + return; + } + + cnx->bot->shitList->delShit(mask, maskChannel); + from->sendNotice(who + " \002has been removed from the shitlist.\002"); +} + +void +UserCommands::Deop(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String target = rest; + + if (target.length() == 0) + target = from->getNick(); + + Message m = Commands::Deop(cnx->bot, channel, target); + if (m.getCode() != 0) + from->sendNotice(m.getMessage()); +} + +void +UserCommands::Die(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String reason; + + if (rest.length() == 0) + reason = "Leaving"; + else + reason = rest; + + Commands::Die(cnx->bot, reason); +} + +void +UserCommands::Do(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() != 0) + Commands::Do(cnx->bot, rest); +} + +#ifdef USESCRIPTS +void +UserCommands::Execute(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() != 0) + Interp::Execute(cnx->bot, rest); +} +#endif + +void +UserCommands::Help(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() == 0) { + from->sendNotice("\002Available topics for you are:\002"); + int level = Utils::getLevel(cnx->bot, from->getAddress()); + String result = ""; + int length = 0; + std::list::iterator it; + for (it = cnx->bot->userFunctions.begin(); it != cnx->bot->userFunctions.end(); ++it) + if ((*it)->minLevel <= level) { + result = result + (*it)->name + " "; + length += strlen((*it)->name) + 1; + if (length >= 256) { + from->sendNotice(result); + result = ""; length = 0; + } + } + if (result != "") + from->sendNotice(result); + from->sendNotice("\002Use\002 HELP \002for" + " help about\002 "); + return; + } + + StringTokenizer st(rest); + String command = st.nextToken().toUpper(); + std::ifstream helpFile(cnx->bot->helpFileName); + + if (!helpFile) { + from->sendNotice(String("\002Error: I can not find the " + "help file\002 ") + + cnx->bot->helpFileName); + return; + } + + String buf; + while (!helpFile.eof()) { + helpFile >> buf; + if (buf.subString(0, command.length()) == String(":") + command) { + buf = buf.subString(1); + from->sendNotice(String("\002Help for\002 ") + command + + "\002:\002"); + while (buf != "") { + from->sendNotice(buf); + helpFile >> buf; + } + from->sendNotice("\002End of help.\002"); + return; + } + } + + from->sendNotice(String("\002No such topic (\002") + + command + "\002).\002"); +} + +void +UserCommands::Ident(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + Channel *c = cnx->bot->channelList->getChannel(channel); + + if (rest.length() <= 2) { + from->sendNotice("\002No password specified or password " + "too short.\002"); + return; + } + + User * u = c->getUser(from->getNick()); + if (!u) { + from->sendNotice(String("\002You can identify yourself on" + " channel\002 ") + channel + + " \002only if you are on the channel.\002"); + return; + } + + if (u->userListItem && u->userListItem->identified) { + from->sendNotice(String("\002You are already identified on" + " channel\002 ") + channel); + return; + } + + if (!u->userListItem) { + from->sendNotice("\002You are not in my userlist.\002"); + return; + } + + if (u->userListItem->passwd == + crypt((const char *)rest, (const char *)u->userListItem->passwd)) { + // For each channel, we increment identification counter + for (std::map >::iterator it = + cnx->bot->channelList->begin(); + it != cnx->bot->channelList->end(); ++it) + u->userListItem->identified++; + + from->sendNotice("\002You are now identified.\002"); + } else + from->sendNotice("\002This is a wrong password.\002"); +} + +void +UserCommands::Invite(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + Message m = Commands::Invite(cnx->bot, channel, rest); + if (m.getCode() < 0) + from->sendNotice(m.getMessage()); + from->sendNotice(String("\002Inviting\002 ") + rest + " \002on channel\002 " + channel); +} + +// FIXME: Convert +void +UserCommands::Join(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + channel = st.nextToken(); + + if (!Utils::isValidChannelName(channel)) { + from->sendNotice(String("\002") + channel + + " is not a valid channel name\002"); + return; + } + + // We change the key only if we are not on the channel. We don't trust + // the user... + if (!cnx->bot->channelList->getChannel(channel)) { + if (cnx->bot->wantedChannels[channel]) + cnx->bot->wantedChannels[channel]->key = st.rest(); + else { + cnx->bot->wantedChannels[channel] = new wantedChannel("", "", st.rest()); + } + } + cnx->queue->sendJoin(channel, cnx->bot->wantedChannels[channel]->key); +} + +// FIXME: Convert +void +UserCommands::Keep(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + if (rest.length() == 0) { + from->sendNotice("\002No channel modes specified.\002"); + return; + } + + cnx->bot->channelList->getChannel(channel)->keepModes = rest; + from->sendNotice(String("\002Keeping modes\002 ") + + rest + " \002on channel\002 " + + channel); +} + +// FIXME: Convert +void +UserCommands::Kick(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + Channel * c = cnx->bot->channelList->getChannel(channel); + + if (rest.length() == 0) { + from->sendNotice("\002No nick specified.\002"); + return; + } + + StringTokenizer st(rest); + String who = st.nextToken(); + + if (Utils::isWildcard(who)) { + User * u = c->getUser(nick); + if (!u) + return; + if (u->getLevel() < User::TRUSTED_USER) { + from->sendNotice("\002You need an higher level to " + "use wildcards.\002"); + return; + } + } + + if (!cnx->bot->iAmOp(channel)) { + from->sendNotice(String("\002I am not channel op on\002 ") + + channel); + return; + } + + if (Utils::isWildcard(who)) { + Mask m(who); + for (std::map >::iterator it = + c->channelMemory.begin(); + it != c->channelMemory.end(); + ++it) + if (m.matches((*it).second->nick + "!" + + (*it).second->userhost) && + (*it).second->getProt() < User::NO_KICK) + cnx->queue->sendKick(channel, (*it).second->nick, st.rest()); + } else { + User * u = c->getUser(who); + if (!u) { + from->sendNotice(String("\002I can not find\002 ") + + who + " \002on\002 " + channel); + return; + } + if (u->getProt() < User::NO_KICK) + cnx->queue->sendKick(channel, who, st.rest()); + else + from->sendNotice(String("\002I can not kick\002 ") + + who + " \002on\002 " + channel + + " \002(protected).\002"); + } +} + +// FIXME: Convert +void +UserCommands::KickBan(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + + Ban(cnx, 0, channel, st.nextToken()); + Kick(cnx, from, channel, rest); +} + +void +UserCommands::Load(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + cnx->bot->shitList->read(); + cnx->bot->userList->read(); + cnx->bot->userList->addUserFirst(cnx->bot->nickName + "!" + cnx->bot->userHost, "*", 0, 3, true, -1, ""); + cnx->bot->rehash(); + from->sendNotice("\002Userlist and shitlist loaded.\002"); +} + +#ifdef USESCRIPTS +void +UserCommands::LoadScript(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() != 0) + Interp::LoadScript(cnx->bot, rest); +} +#endif + +// FIXME: Convert +void +UserCommands::Lock(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + cnx->bot->channelList->getChannel(channel)->lockedTopic = true; + from->sendNotice(String("\002Locking topic for channel\002 ") + + channel); +} + +// FIXME: Convert +void +UserCommands::Mode(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + if (rest.length() == 0) { + from->sendNotice("\002I need a parameter for this command.\002"); + return; + } + + if (!cnx->bot->iAmOp(channel)) { + from->sendNotice(String("\002I am not channel op on\002 ") + + channel); + return; + } + + cnx->queue->sendChannelMode(String("MODE ") + channel + " " + rest); +} + +void +UserCommands::Msg(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + String who = st.nextToken(); + String message = st.rest(); + + Message m = Commands::Msg(cnx->bot, who, message); + if (m.getCode() != 0) + from->sendNotice(m.getMessage()); +} + +void +UserCommands::Names(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + String result = ""; + int length = 0; + Channel *c = cnx->bot->channelList->getChannel(channel); + std::map >::iterator it; + + from->sendNotice(String("\002Names on ") + + channel + ":\002"); + + for (it = c->channelMemory.begin(); + it != c->channelMemory.end(); ++it) { + result = result + + ((*it).second->mode & User::OP_MODE ? "@" : + ((*it).second->mode & User::VOICE_MODE ? "+" : "")) + + (*it).second->nick + " "; + length += (*it).first.length() + 1; + if (length >= 256) { + from->sendNotice(result); + result = ""; length = 0; + } + } + + if (result != "") + from->sendNotice(result); + + from->sendNotice("\002End of names.\002"); +} + +// FIXME: Convert +void +UserCommands::NextServer(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (cnx->bot->serverList->size() == 0) { + from->sendNotice("\002Server list is empty !\002"); + return; + } + + if (cnx->bot->serverList->size() == 1) { + from->sendNotice("\002Server list has only one item. Use" + " \"reconnect\" to force reconnection.\002"); + return; + } + + if (cnx->bot->canChangeServer()) { + cnx->queue->sendQuit("Changing server"); + cnx->bot->nextServer(); + } + else + from->sendNotice("\002I can not change server without" + " losing op on a channel I am on.\002"); +} + +// FIXME: Convert +void +UserCommands::Nick(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + // We parse the parameters + StringTokenizer st(rest); + String nick = st.nextToken(); + + if (rest == "") { + from->sendNotice(String("\002No nickname given.\002")); + return; + } + + if (!Utils::isValidNickName(nick)) { + from->sendNotice(String("\002") + nick + + " is not a valid nickname\002"); + return; + } + + cnx->bot->wantedNickName = nick; + cnx->queue->sendNick(nick); +} + +void +UserCommands::NsLookup(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String target; + + if (rest.length() == 0) { + from->sendNotice("\002You need to supply a nick or an " + "host for this command.\002"); + return; + } + + if (rest.find('.') == -1) { + StringTokenizer st(cnx->bot->getUserhost("", rest)); + st.nextToken('@'); + target = st.rest(); + if (target.length() == 0) { + from->sendNotice(String("\002I could not find\002 ") + + target); + return; + } + } else + target = rest; + + struct hostent * host; + struct in_addr iaddr; + + if (isdigit(target[0])) { // An IP ? + iaddr.s_addr = inet_addr((const char *)target); + host = gethostbyaddr((char *)(&iaddr), + sizeof(struct in_addr), + AF_INET); + if (host) { + from->sendNotice(target + + " \002is the IP address of\002 " + + host->h_name); + return; + } + } else { + host = gethostbyname((const char *)target); + if (host) { + memcpy((char *)&iaddr, (char *)host->h_addr, + host->h_length); + from->sendNotice(target + " \002has\002 " + + inet_ntoa(iaddr) + " \002for IP address.\002"); + return; + } + } + + from->sendNotice(String("\002I could not find host\002 ") + + target); +} + +// FIXME: Convert +void +UserCommands::Op(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + if (!cnx->bot->iAmOp(channel)) { + from->sendNotice(String("\002I am not channel op on\002 ") + + channel); + return; + } + + if (Utils::isWildcard(rest)) { + from->sendNotice("\002Mass op is not allowed.\002"); + return; + } + + String target; + + if (rest.length() == 0) + target = nick; + else + target = rest; + + User *u = cnx->bot->channelList->getChannel(channel)->getUser(target); + if (!u) { + from->sendNotice(String("\002I cannot find\002 ") + target + " \002on channel\002 " + channel); + return; + } + + ShitEntry *se = cnx->bot->shitList->getShit(target, channel); + if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP) { + from->sendNotice(String("\002I can not op\002 ")+target+" \002on channel\002 "+channel+" \002(shitlist).\002"); + return; + } + + if (!(u->mode & User::OP_MODE)) + cnx->queue->sendChannelMode(channel, "+o", target); + else { + if (target == nick) + from->sendNotice(String("\002You are already channel " + "operator on\002 ") + channel); + else + from->sendNotice(target + " \002is already channel " + "operator on\002 " + channel); + } +} + +// FIXME: Convert +void +UserCommands::Part(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + wantedChannel *w = cnx->bot->wantedChannels[channel]; + cnx->bot->wantedChannels.erase(channel); + delete w; + cnx->queue->sendPart(channel); +} + +void +UserCommands::Password(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + Channel *c = cnx->bot->channelList->getChannel(channel); + + if (rest.length() == 0) { + from->sendNotice("\002No password.\002"); + return; + } + + User * u = c->getUser(from->getNick()); + if (!u) { + from->sendNotice(String("\002To change your password for\002") + + channel + "\002, you need to be on the " + "channel.\002"); + return; + } + + if (!u->userListItem) { + from->sendNotice("\002You are not in my userlist.\002"); + return; + } + + if (rest.toLower() == "none") { + u->userListItem->passwd = ""; + from->sendNotice("\002Password cleared.\002"); + return; + } + + static char saltChars[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; + char salt[3]; + srand(time(0)); + salt[0] = saltChars[rand() % 64]; + salt[1] = saltChars[rand() % 64]; + salt[2] = '\0'; + + u->userListItem->passwd = crypt((const char *)rest, salt); + from->sendNotice("\002Password changed.\002"); +} + +void +UserCommands::Save(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + cnx->bot->userList->save(); + cnx->bot->shitList->save(); + from->sendNotice("\002Userlist and shitlist saved.\002"); +} + +// FIXME: Convert +void +UserCommands::Say(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + if (rest.length() != 0) + cnx->queue->sendPrivmsg(channel, rest); +} + +// FIXME: Convert +void +UserCommands::Server(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + int serverNumber; + String nick = from->getNick(); + + if (rest.length() == 0) { + from->sendNotice("\002You need to supply a server number for this command.\002"); + return; + } + + serverNumber = atoi(rest); + + if (serverNumber < 0 || serverNumber >= cnx->bot->serverList->size()) { + from->sendNotice(String((long)serverNumber) + + " \002is an invalid server number (see the serverlist).\002"); + return; + } + + if (cnx->bot->canChangeServer()) { + cnx->queue->sendQuit("Changing server"); + cnx->queue->flush(); + cnx->bot->connect(serverNumber); + } + else + from->sendNotice("\002I can not change server without losing op on a channel I am on.\002"); +} + +void +UserCommands::ServerList(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + from->sendNotice("\002Server list:\002"); + long l = 0; + String s; + for (std::vector::iterator it = + cnx->bot->serverList->v.begin(); + it != cnx->bot->serverList->v.end(); + ++it) { + s = (*it) == cnx->server ? "\026" : ""; + from->sendNotice(s + String(l++) + s + " " + + (*it)->getHostName() + + " (" + String((long)((*it)->getPort())) + + ")"); + } + from->sendNotice("\002End of server list.\002"); +} + +void +UserCommands::SetVersion(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + Message m = Commands::SetVersion(cnx->bot, rest); + if (m.getCode() < 0) + from->sendNotice(m.getMessage()); +} + +void +UserCommands::ShitList(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + from->sendNotice("\002Shitlist:\002"); + from->sendNotice("\002Mask Channel Level Expires Reason\002"); + + for (std::list::iterator it = cnx->bot->shitList->l.begin(); + it != cnx->bot->shitList->l.end(); + it++) + from->sendNotice((*it)->shitMask.getMask().pad(25) + " " + + (*it)->shitChannelMask.getMask().pad(10) + " " + + String((long)(*it)->shitLevel).pad(9) + " " + + String((long)(*it)->expirationDate).pad(9) + " " + + (*it)->shitReason); + + from->sendNotice("\002End of shitlist.\002"); +} + +void +UserCommands::SpyList(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + from->sendNotice("\002Spy list:\002"); + + for (std::map >::iterator it = + cnx->bot->spyList.begin(); it != cnx->bot->spyList.end(); ++it) + from->sendNotice((*it).first); + + from->sendNotice("\002End of spy list.\002"); +} + +void +UserCommands::SpyMessage(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + if (cnx->bot->spyList.find(nick) != cnx->bot->spyList.end()) { + from->sendNotice("\002You are already spying messages.\002"); + return; + } + + Person *f = from->copy(); + f->keepAlive(); + cnx->bot->spyList[nick.toLower()] = f; + from->sendNotice("\002You have been added to the spy list.\002"); +} + +// FIXME: Convert +void +UserCommands::Reconnect(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + if (cnx->bot->canChangeServer()) { + cnx->queue->sendQuit("Reconnecting"); + cnx->bot->reconnect(); + } + else + from->sendNotice("\002I can not change server without losing op on a channel I am on.\002"); +} + +void +UserCommands::RSpyMessage(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick().toLower(); + + if (cnx->bot->spyList.find(nick) == cnx->bot->spyList.end()) { + from->sendNotice("\002You are not in the spy list.\002"); + return; + } + + delete cnx->bot->spyList[nick]; + cnx->bot->spyList.erase(nick); + from->sendNotice("\002You have been removed from the " + "spy list.\002"); +} + +// FIXME: Convert +void +UserCommands::Unlock(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + cnx->bot->channelList->getChannel(channel)->lockedTopic = false; + from->sendNotice(String("\002Unlocking topic for channel\002 ") + + channel); +} + +void +UserCommands::Stats(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + from->sendNotice(String("\002Keeping modes\002 ") + + cnx->bot->channelList->getChannel(channel)->keepModes + " \002on channel\002 " + + channel); +} + +// FIXME: Convert +void +UserCommands::TBan(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + Channel * c = cnx->bot->channelList->getChannel(channel); + + StringTokenizer st(rest); + String who = st.nextToken(); + String t = st.nextToken(); + String dest; + + if (who == "" || t == "") { + if (from) + from->sendNotice("\002Invalid syntax for this command.\002"); + return; + } + + if (Utils::isWildcard(who) && from) { + User * u = c->getUser(from->getNick()); + if (u && u->getLevel() < User::TRUSTED_USER) { + if (from) + from->sendNotice("\002You need an higher level to use" + " wildcards.\002"); + return; + } + } + + if (!cnx->bot->iAmOp(channel)) { + if (from) + from->sendNotice(String("\002I am not channel op on\002 ") + + channel); + return; + } + + if (!Utils::isWildcard(who)) + dest = cnx->bot->getUserhost(channel, who); + else + dest = who; + + if (dest == "") { + if (from) + from->sendNotice(String("\002I can not find\002 ") + who); + return; + } + + time_t w; + + if ((w = Utils::strToTime(t)) == 0) { + if (from) + from->sendNotice(t + " \002is an invalid time.\002"); + return; + } + + dest = Utils::makeWildcard(dest); + Mask m(dest); + + for (std::list::iterator it = cnx->bot->userList->l.begin(); + it != cnx->bot->userList->l.end(); + it++) + if (m.matches((*it)->mask) && + (*it)->channelMask.matches(channel) && + (*it)->prot >= User::NO_BAN) { + if (from) + from->sendNotice(String("\002I can not ban\002 ") + + who + " \002on channel\002 " + + channel + " \002(protection).\002"); + return; + } + + for (std::vector::iterator it = c->channelBanlist.begin(); + it != c->channelBanlist.end(); ++it) + if (m.matches((*it)->banMask)) + cnx->queue->sendChannelMode(channel, "-b", (*it)->banMask.getMask()); + + cnx->bot->channelList->getChannel(channel)->addBan(dest, w); + cnx->queue->sendChannelMode(channel, "+b", dest); + cnx->bot->todoList->addDeban(channel, dest, (time_t)w); +} + +// FIXME: Convert +void +UserCommands::TKBan(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + StringTokenizer st(rest); + String who = st.nextToken(); + String t = st.nextToken(); + + TBan(cnx, 0, channel, who + " " + t); + Kick(cnx, from, channel, who + " " + st.rest()); +} + +// FIXME: Convert +void +UserCommands::Topic(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + if (rest.length() == 0) { + if (cnx->bot->channelList->getChannel(channel)->channelTopic == "") + from->sendNotice(String("\002No topic is set for channel\002 ") + + channel + "\002.\002"); + else + from->sendNotice(String("\002Topic for\002 ") + + channel + " \002is:\002 " + + cnx->bot->channelList->getChannel(channel)->channelTopic); + } else { + if (cnx->bot->channelList->getChannel(channel)->lockedTopic) + from->sendNotice(String("\002Topic is locked on channel\002 ") + + channel); + else + cnx->queue->sendTopic(channel, rest); + } +} + +void +UserCommands::UserList(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + from->sendNotice("\002Userlist:\002"); + from->sendNotice("\002Mask Channel Level Prot Aop Expires\002"); + + for (std::list::iterator it = cnx->bot->userList->l.begin(); + it != cnx->bot->userList->l.end(); + it++) + from->sendNotice((*it)->mask.getMask().pad(25) + " " + + (*it)->channelMask.getMask().pad(10) + " " + + Utils::levelToStr((*it)->level).pad(12) + " " + + Utils::protToStr((*it)->prot).pad(7) + " " + + Utils::boolToStr((*it)->aop).pad(5) + " " + + String((long)(*it)->expirationDate)); + + from->sendNotice("\002End of userlist.\002"); +} + +void +UserCommands::Who(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + User * u = cnx->bot->channelList->getChannel(channel)->getUser(nick); + UserListItem * uli; + + if (u) + uli = u->userListItem; + else + uli = cnx->bot->userList->getUserListItem(from->getAddress(), + channel); + + if (uli) { + from->sendNotice(String("\002You are\002 ") + + uli->mask.getMask() + " \002on\002 " + + uli->channelMask.getMask()); + from->sendNotice(String("\002Lvl:\002 ") + + Utils::levelToStr(uli->level) + + " \002Prot:\002 " + + Utils::protToStr(uli->prot) + + " \002Aop:\002 " + + Utils::boolToStr(uli->aop) + + " \002Expired:\002 " + + Utils::boolToStr(!uli->isStillValid()) + + " \002Ident:\002 " + + (uli && !uli->identified ? "\026" : "") + + Utils::boolToStr(uli && uli->identified) + + (uli && !uli->identified ? "\026" : "")); + } else + from->sendNotice(String("\002You are not in the userlist for\002 ") + + channel); +} + +void +UserCommands::Whois(ServerConnection *cnx, Person *from, + String channel, String rest) +{ + String nick = from->getNick(); + + if (!rest.length()) { + from->sendNotice("\002No nick specified.\002"); + return; + } + + StringTokenizer st(rest); + String otherNick = st.nextToken(); + + User * u = cnx->bot->channelList->getChannel(channel)->getUser(otherNick); + UserListItem * uli; + + if (u) + uli = u->userListItem; + else + uli = cnx->bot->userList->getUserListItem(otherNick + "!" + + cnx->bot->getUserhost(channel, + otherNick), + channel); + + if (uli) { + from->sendNotice(otherNick + + " \002is\002 " + uli->mask.getMask() + + " \002on\002 " + uli->channelMask.getMask()); + from->sendNotice(String("\002Lvl:\002 ") + + Utils::levelToStr(uli->level) + + " \002Prot:\002 " + + Utils::protToStr(uli->prot) + + " \002Aop:\002 " + + Utils::boolToStr(uli->aop) + + " \002Expired:\002 " + + Utils::boolToStr(!uli->isStillValid()) + + " \002Ident:\002 " + + Utils::boolToStr(uli && uli->identified)); + } else + from->sendNotice(otherNick + + " \002is not in the userlist for\002 " + + channel); +} hunk ./source/UserCommands.H 1 +// UserCommands.H -*- 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. + +#ifndef USERCOMMANDS_H +#define USERCOMMANDS_H + +#include "String.H" +#include "Person.H" +#include "ServerConnection.H" + +#ifdef USESCRIPTS +#include "Interp.H" +#endif + +class UserCommands { +public: + static void Action(ServerConnection *, Person *, String, String); + static void AddUser(ServerConnection *, Person *, String, String); + static void AddServer(ServerConnection *, Person *, String, String); + static void AddShit(ServerConnection *, Person *, String, String); + static void Alias(ServerConnection *, Person *, String, String); + static void Ban(ServerConnection *, Person *, String, String); + static void BanList(ServerConnection *, Person *, String, String); + static void ChangeLevel(ServerConnection *, Person *, String, String); + static void Channels(ServerConnection *, Person *, String, String); + static void Cycle(ServerConnection *, Person *, String, String); + static void DCCList(ServerConnection *, Person *, String, String); + static void Deban(ServerConnection *, Person *, String, String); + static void DelServer(ServerConnection *, Person *, String, String); + static void DelUser(ServerConnection *, Person *, String, String); + static void DelShit(ServerConnection *, Person *, String, String); + static void Deop(ServerConnection *, Person *, String, String); + static void Die(ServerConnection *, Person *, String, String); + static void Do(ServerConnection *, Person *, String, String); +#ifdef USESCRIPTS + static void Execute(ServerConnection *, Person *, String, String); +#endif + static void Help(ServerConnection *, Person *, String, String); + static void Ident(ServerConnection *, Person *, String, String); + static void Invite(ServerConnection *, Person *, String, String); + static void Join(ServerConnection *, Person *, String, String); + static void Keep(ServerConnection *, Person *, String, String); + static void Kick(ServerConnection *, Person *, String, String); + static void KickBan(ServerConnection *, Person *, String, String); + static void Load(ServerConnection *, Person *, String, String); +#ifdef USESCRIPTS + static void LoadScript(ServerConnection *, Person *, String, String); +#endif + static void Lock(ServerConnection *, Person *, String, String); + static void Mode(ServerConnection *, Person *, String, String); + static void Msg(ServerConnection *, Person *, String, String); + static void Names(ServerConnection *, Person *, String, String); + static void NextServer(ServerConnection *, Person *, String, String); + static void Nick(ServerConnection *, Person *, String, String); + static void NsLookup(ServerConnection *, Person *, String, String); + static void Op(ServerConnection *, Person *, String, String); + static void Part(ServerConnection *, Person *, String, String); + static void Password(ServerConnection *, Person *, String, String); + static void Reconnect(ServerConnection *, Person *, String, String); + static void RSpyMessage(ServerConnection *, Person *, String, String); + static void Save(ServerConnection *, Person *, String, String); + static void Say(ServerConnection *, Person *, String, String); + static void Server(ServerConnection *, Person *, String, String); + static void ServerList(ServerConnection *, Person *, String, String); + static void SetVersion(ServerConnection *, Person *, String, String); + static void ShitList(ServerConnection *, Person *, String, String); + static void SpyList(ServerConnection *, Person *, String, String); + static void SpyMessage(ServerConnection *, Person *, String, String); + static void Stats(ServerConnection *, Person *, String, String); + static void TBan(ServerConnection *, Person *, String, String); + static void TKBan(ServerConnection *, Person *, String, String); + static void Topic(ServerConnection *, Person *, String, String); + static void Unlock(ServerConnection *, Person *, String, String); + static void UserList(ServerConnection *, Person *, String, String); + static void Who(ServerConnection *, Person *, String, String); + static void Whois(ServerConnection *, Person *, String, String); +}; + +#endif hunk ./source/UserList.C 1 +// Userlist.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 "UserList.H" +#include "StringTokenizer.H" + +UserList::UserList(String filename) + : listFilename(filename) +{ + read(); +} + +UserList::~UserList() +{ + clear(); +} + +void +UserList::read() +{ + std::ifstream file(listFilename); + String temp, empty = ""; + int line = 1; + + clear(); + + if (!file) { + std::cerr << "I cannot find the file " << listFilename << std::endl; + return; + } + + while (file >> temp, temp.length() != 0) { + StringTokenizer st(temp); + if (st.countTokens(':') != 7) { + std::cerr << "Error when reading userlist (" << listFilename << + ") line " << line << "...\n"; + return; + } + String mask = st.nextToken(':'); + String maskChannel = st.nextToken(':'); + String level = st.nextToken(':'); + String prot = st.nextToken(':'); + String aop = st.nextToken(':'); + String expiration = st.nextToken(':'); + String password = st.rest().trim(); + if (password == "*NONE*") + password = ""; + l.push_back(new UserListItem(mask, maskChannel, atoi(level), + atoi(prot), atoi(aop), + atol(expiration), password)); + line++; + } + file.close(); +} + +void +UserList::save() +{ + std::list::iterator it = l.begin(); + std::ofstream file(listFilename); + + if (!file) + return; + + ++it; // We skip the bot's entry + for ( ; it != l.end(); ++it) + if ((*it)->isStillValid()) { + file << (*it)->mask.getMask() << ":" + << (*it)->channelMask.getMask() << ":" + << (*it)->level << ":" + << (*it)->prot << ":" + << (*it)->aop << ":" + << (*it)->expirationDate << ":"; + if ((*it)->passwd == "") + file << "*NONE*"; + else + file << (*it)->passwd; + file << std::endl; + } +} + +void +UserList::clear() +{ + UserListItem *uli; + + while (!l.empty()) { + uli = (*l.begin()); + l.erase(l.begin()); + delete uli; + } +} + +void +UserList::addUser(String m, String mc, int lev, int p, bool a, + std::time_t e, String pa) +{ + l.push_back (new UserListItem(m, mc, lev, p, a, e, pa)); +} + +void +UserList::addUserFirst(String m, String mc, int lev, int p, + bool a, std::time_t e, String pa) +{ + l.push_front (new UserListItem(m, mc, lev, p, a, e, pa, true)); +} + +UserListItem * +UserList::getUserListItem(String nuh, String channel) +{ + for (std::list::iterator it = l.begin(); + it != l.end(); ++it) + if ((*it)->matches(nuh, channel)) { + return (*it); + } + + return 0; +} + +int +UserList::getMaxLevel(String nuh) +{ + int level = -1; + std::time_t current_time = std::time (0); + + for (std::list::iterator it = l.begin(); + it != l.end(); it++) + if ((*it)->matches(nuh) && level < (*it)->level && + ((*it)->expirationDate == -1 || + (*it)->expirationDate > current_time) && + ((*it)->passwd == "" || (*it)->identified > 0)) + level = (*it)->level; + + return level; +} + +int +UserList::getLevel(String nuh, String channel) +{ + if (UserListItem *uli = getUserListItem(nuh, channel)) + return uli->level; + + return -1; +} + +int +UserList::getMaxProt(String nuh, String channel) +{ + int prot = -1; + std::time_t current_time = std::time (0); + + for (std::list::iterator it = l.begin(); + it != l.end(); it++) { + Mask m(nuh), mc(channel), msc((*it)->channelMask.getMask()); + if (m.matches((*it)->mask) && + (mc.matches((*it)->channelMask) || msc.matches(channel)) && + prot < (*it)->prot && + ((*it)->expirationDate == -1 || + (*it)->expirationDate > current_time)) { + prot = (*it)->prot; + } + } + return prot; +} + +bool +UserList::isInUserList(String nuh, String maskChannel) +{ + for (std::list::iterator it = l.begin(); + it != l.end(); + ++it) + if ((*it)->matches(nuh, maskChannel)) + return true; + + return false; +} + +void +UserList::removeFirst() +{ + UserListItem * uli = *(l.begin()); + if (uli->autoEntry) { + l.erase(l.begin()); + delete uli; + }; +} + +void +UserList::removeUser(String mask, String maskChannel) +{ + for (std::list::iterator it = l.begin(); + it != l.end(); + ++it) + if ((*it)->mask.getMask() == mask && + (*it)->channelMask.getMask() == maskChannel) { + delete (*it); + l.erase(it); + return; + } +} hunk ./source/UserList.H 1 +// UserList.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 USERLIST_H +#define USERLIST_H + +#include +#include + +#include "String.H" +#include "UserListItem.H" + +class Commands; +class UserCommands; + +class UserList { + String listFilename; + std::list l; + +public: + UserList(String); + ~UserList(); + + void read(); + void save(); + void clear(); + + void addUser(String, String, int, int, bool, + std::time_t = -1, String = ""); + void addUserFirst(String, String, int, int, bool, + std::time_t = -1, String = ""); + void removeFirst(); + void removeUser(String, String); + + UserListItem * getUserListItem(String, String); + + int getMaxLevel(String); + int getLevel(String, String); + + int getMaxProt(String, String); + + bool isInUserList(String, String = ""); + + friend class Commands; + friend class UserCommands; +}; + +#endif hunk ./source/UserListItem.H 1 +// UserListItem.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. + +// An UserListItem object is the object that is stored in the UserList. + +#ifndef USERLISTITEM_H +#define USERLISTITEM_H + +#include + +#include "Mask.H" + +class User; +class Utils; +class UserList; +class Commands; +class UserCommands; + +class UserListItem { + // Mask on the user + Mask mask; + // Mask on the channel + Mask channelMask; + // Level (from 0 to 4) + int level; + // Protection (from 0 to 2) + int prot; + // Auto-op + bool aop; + // Date until which the UserListItem is valid + time_t expirationDate; + // Password + String passwd; + // How many channels are we identified on ? + int identified; + // Is this item automatically added ? + bool autoEntry; + +public: + UserListItem(String m, String mc, int l, int p, bool a, + std::time_t e = -1, String pass= "", bool ae = false) + : mask(m), channelMask(mc), level(l), prot(p), aop(a), + expirationDate(e), passwd(pass), identified(0), autoEntry(ae) { } + + // Returns true if it matches on channel(s) + bool matches(String m, String mc) + { if (mc.length()==0) return mask.matches(m); + else return mask.matches(m) && channelMask.matches(mc); } + + // Returns true if it matches + bool matches(String m) + { return mask.matches(m); } + + // Is the item still valid ? (-1 means infinity) + bool isStillValid() + { return expirationDate == -1 || std::time(NULL) <= expirationDate; } + + friend class User; + friend class Utils; + friend class Parser; + friend class Channel; + friend class UserList; + friend class Commands; + friend class UserCommands; +}; + +#endif hunk ./source/Utils.C 1 +// Utils.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. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "Utils.H" +#include "StringTokenizer.H" + +String +Utils::getNick(String nuh) +{ + StringTokenizer st(nuh); + return st.nextToken('!'); +} + +String +Utils::getUserhost(String nuh) +{ + StringTokenizer st(nuh); + st.nextToken('@'); + return st.rest(); +} + +String +Utils::getKey() +{ + return String((long)rand()); +} + +bool +Utils::isIP(String host) +{ + for (int i = 0; i < host.length(); i++) + if (!isdigit(host[i]) && host[i]!='.') + return false; + return true; +} + +String +Utils::makeWildcard(String mask) +{ + StringTokenizer st(mask); + + st.nextToken('!', true); + String nick = "*"; + + String user = st.nextToken('@', true); + if (user[0] == '~' || user[0] == '^' || + user[0] == '+' || user[0] == '-' || + user[0] == '*') + user = user.subString(1); + if (user.length() < 10) + user = String("*") + user; + + String host = st.rest(); + StringTokenizer st2(host); + if (!isWildcard(host)) { + if (isIP(host)) { + host = st2.nextToken('.') + "."; + host = host + st2.nextToken('.') + "."; + host = host + st2.nextToken('.') + ".*"; + } else { + st2.nextToken('.', true); + if (st2.countTokens('.') > 1) + host = String("*.") + st2.rest(); + } + } else { + if (host == "") host = "*"; + } + + std::cout << nick + "!" + user + "@" + host << std::endl; + + return nick + "!" + user + "@" + host; +} + +bool +Utils::isChannel(String c) +{ + return (c[0] == '#' || c[0] == '&'); +} + +bool +Utils::isWildcard(String c) +{ + return (c.find('*') != -1); +} + +bool +Utils::isValidChannelName(String c) +{ + return isChannel(c) && c.find(',') == -1; +} + +#define isvalid(c) (((c) >= 'A' && (c) <= '~') || isdigit(c) || (c) == '-') + +bool +Utils::isValidNickName(String n) +{ + if (n[0] == '-' || isdigit(n[0]) || n.length() > 9) + return false; + + for (int i = 0; i < n.length(); i++) + if (!isvalid(n[i]) || isspace(n[i])) + return false; + + return true; +} + +int +Utils::getLevel(Bot * b, String nuh) +{ + return b->userList->getMaxLevel(nuh); +} + +int +Utils::getLevel(Bot * b, String nuh, String channel) +{ + if (!isChannel(channel)) + return getLevel(b, nuh); + + if (Channel * c = b->channelList->getChannel(channel)) { + User * u = c->getUser(getNick(nuh)); + if (u) + return u->getLevel(); + } else { + return -1; + } + + return b->userList->getLevel(nuh, channel); +} + +String +Utils::levelToStr(int l) +{ + switch (l) { + case User::USER: return "User"; + case User::TRUSTED_USER: return "Trusted User"; + case User::FRIEND: return "Friend"; + case User::MASTER: return "Master"; + } + return "None"; +} + +String +Utils::protToStr(int p) +{ + switch (p) { + case User::NO_BAN: return "No ban"; + case User::NO_KICK: return "No kick"; + case User::NO_DEOP: return "No deop"; + } + return "None"; +} + +String +Utils::boolToStr(bool b) +{ + return b ? "True" : "False"; +} + +time_t +Utils::strToTime(String str) +{ + char num[512]; + int len = 0; + time_t ans = 0; + + num[0]='\0'; + + if (str.toLower() == "Inf") + return -1; + + if (!isdigit(str[0])) + return 0; + + for (int i = 0; i < str.length(); i++) { + switch (str[i]) { + case 'y': + case 'Y': + num[len] = '\0'; + len = 0; + ans += (atoi(num) * 31557600); + break; + case 'M': + num[len] = '\0'; + len = 0; + ans += (atoi(num) * 2629800); + break; + case 'd': + case 'D': + num[len] = '\0'; + len = 0; + ans += (atoi(num) * 86400); + break; + case 'h': + case 'H': + num[len] = '\0'; + len = 0; + ans += (atoi(num) * 3600); + break; + case 'm': + num[len] = '\0'; + len = 0; + ans += (atoi(num) * 60); + break; + case 's': + case 'S': + num[len] = '\0'; + len = 0; + ans += atoi(num); + default: + if (isdigit(str[i])) { + num[len++] = str[i]; + num[len] = '\0'; + } else + return 0; + } + } + + if (len) + ans += atoi(num); + + return time(0) + ans; +} + +#ifdef USESCRIPTS +// Returns a String from an SCM argument +String +Utils::scm2String(SCM s) +{ + char *tmp = gh_scm2newstr(s, 0); + String temp(tmp); + free(tmp); + return temp; +} + +// Returns a SCM from an String argument +SCM +Utils::string2SCM(String s) +{ + return gh_str02scm((char *)(const char *)s); +} +#endif hunk ./source/Utils.H 1 +// Utils.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 UTILS_H +#define UTILS_H + +#ifndef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "String.H" +#include "Bot.H" + +#ifdef USESCRIPTS +#include +#endif + +class Utils { +public: + static String getNick(String); + static String getUserhost(String); + static String getKey(); + static String makeWildcard(String); + + static bool isChannel(String); + static bool isWildcard(String); + static bool isValidChannelName(String); + static bool isValidNickName(String); + static bool isIP(String); + + static int getLevel(Bot *, String); + static int getLevel(Bot *, String, String); + + static String levelToStr(int); + static String protToStr(int); + static String boolToStr(bool); + + static std::time_t strToTime(String); + +#ifdef USESCRIPTS + static String scm2String(SCM); + static SCM string2SCM(String); +#endif +}; + +#endif }