tried to reorder the program structure and build process
authorpk910 <philipp@zoelle1.de>
Sat, 1 Oct 2011 22:33:13 +0000 (00:33 +0200)
committerpk910 <philipp@zoelle1.de>
Sun, 2 Oct 2011 00:05:34 +0000 (02:05 +0200)
244 files changed:
.gitignore
BanNode.c [deleted file]
BanNode.h [deleted file]
ChanNode.c [deleted file]
ChanNode.h [deleted file]
ChanUser.c [deleted file]
ChanUser.h [deleted file]
ClientSocket.c [deleted file]
ClientSocket.h [deleted file]
DBHelper.c [deleted file]
DBHelper.h [deleted file]
EventLogger.c [deleted file]
EventLogger.h [deleted file]
HandleInfoHandler.c [deleted file]
HandleInfoHandler.h [deleted file]
IRCEvents.c [deleted file]
IRCEvents.h [deleted file]
IRCParser.c [deleted file]
IRCParser.h [deleted file]
Makefile [deleted file]
Makefile.am [new file with mode: 0644]
ModeNode.c [deleted file]
ModeNode.h [deleted file]
UserNode.c [deleted file]
UserNode.h [deleted file]
WHOHandler.c [deleted file]
WHOHandler.h [deleted file]
autogen.sh [new file with mode: 0644]
bot_NeonServ.c [deleted file]
bot_NeonServ.h [deleted file]
bots.c [deleted file]
bots.h [deleted file]
cmd_neonserv.h [deleted file]
cmd_neonserv_access.c [deleted file]
cmd_neonserv_addban.c [deleted file]
cmd_neonserv_addtimeban.c [deleted file]
cmd_neonserv_adduser.c [deleted file]
cmd_neonserv_ban.c [deleted file]
cmd_neonserv_bans.c [deleted file]
cmd_neonserv_bind.c [deleted file]
cmd_neonserv_chanservsync.c [deleted file]
cmd_neonserv_clvl.c [deleted file]
cmd_neonserv_command.c [deleted file]
cmd_neonserv_csuspend.c [deleted file]
cmd_neonserv_cunsuspend.c [deleted file]
cmd_neonserv_delban.c [deleted file]
cmd_neonserv_delme.c [deleted file]
cmd_neonserv_deluser.c [deleted file]
cmd_neonserv_deop.c [deleted file]
cmd_neonserv_deopall.c [deleted file]
cmd_neonserv_devoice.c [deleted file]
cmd_neonserv_devoiceall.c [deleted file]
cmd_neonserv_down.c [deleted file]
cmd_neonserv_downall.c [deleted file]
cmd_neonserv_emote.c [deleted file]
cmd_neonserv_events.c [deleted file]
cmd_neonserv_giveowner.c [deleted file]
cmd_neonserv_god.c [deleted file]
cmd_neonserv_help.c [deleted file]
cmd_neonserv_invite.c [deleted file]
cmd_neonserv_inviteme.c [deleted file]
cmd_neonserv_kick.c [deleted file]
cmd_neonserv_kickban.c [deleted file]
cmd_neonserv_mdeluser.c [deleted file]
cmd_neonserv_mode.c [deleted file]
cmd_neonserv_move.c [deleted file]
cmd_neonserv_myaccess.c [deleted file]
cmd_neonserv_netinfo.c [deleted file]
cmd_neonserv_notice.c [deleted file]
cmd_neonserv_op.c [deleted file]
cmd_neonserv_opall.c [deleted file]
cmd_neonserv_oplog.c [deleted file]
cmd_neonserv_peek.c [deleted file]
cmd_neonserv_raw.c [deleted file]
cmd_neonserv_recover.c [deleted file]
cmd_neonserv_register.c [deleted file]
cmd_neonserv_reloadlang.c [deleted file]
cmd_neonserv_resync.c [deleted file]
cmd_neonserv_say.c [deleted file]
cmd_neonserv_search.c [deleted file]
cmd_neonserv_set.c [deleted file]
cmd_neonserv_setaccess.c [deleted file]
cmd_neonserv_suspend.c [deleted file]
cmd_neonserv_topic.c [deleted file]
cmd_neonserv_trace.c [deleted file]
cmd_neonserv_trim.c [deleted file]
cmd_neonserv_unban.c [deleted file]
cmd_neonserv_unbanall.c [deleted file]
cmd_neonserv_unbanme.c [deleted file]
cmd_neonserv_unbind.c [deleted file]
cmd_neonserv_unregister.c [deleted file]
cmd_neonserv_unsuspend.c [deleted file]
cmd_neonserv_up.c [deleted file]
cmd_neonserv_upall.c [deleted file]
cmd_neonserv_users.c [deleted file]
cmd_neonserv_uset.c [deleted file]
cmd_neonserv_version.c [deleted file]
cmd_neonserv_voice.c [deleted file]
cmd_neonserv_voiceall.c [deleted file]
cmd_neonserv_wipeinfo.c [deleted file]
config.h.example [deleted file]
configure.ac [new file with mode: 0644]
event_neonserv_ctcp.c [deleted file]
event_neonserv_invite.c [deleted file]
event_neonserv_join.c [deleted file]
event_neonserv_notice.c [deleted file]
event_neonserv_part.c [deleted file]
event_neonserv_quit.c [deleted file]
event_neonserv_topic.c [deleted file]
lang.c [deleted file]
lang.h [deleted file]
main.c [deleted file]
main.h [deleted file]
modcmd.c [deleted file]
modcmd.h [deleted file]
mysqlConfig.h.example [new file with mode: 0644]
mysqlConn.c [deleted file]
mysqlConn.h [deleted file]
src/BanNode.c [new file with mode: 0644]
src/BanNode.h [new file with mode: 0644]
src/ChanNode.c [new file with mode: 0644]
src/ChanNode.h [new file with mode: 0644]
src/ChanUser.c [new file with mode: 0644]
src/ChanUser.h [new file with mode: 0644]
src/ClientSocket.c [new file with mode: 0644]
src/ClientSocket.h [new file with mode: 0644]
src/DATABASE.txt [new file with mode: 0644]
src/DBHelper.c [new file with mode: 0644]
src/DBHelper.h [new file with mode: 0644]
src/EventLogger.c [new file with mode: 0644]
src/EventLogger.h [new file with mode: 0644]
src/HandleInfoHandler.c [new file with mode: 0644]
src/HandleInfoHandler.h [new file with mode: 0644]
src/IRCEvents.c [new file with mode: 0644]
src/IRCEvents.h [new file with mode: 0644]
src/IRCParser.c [new file with mode: 0644]
src/IRCParser.h [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/ModeNode.c [new file with mode: 0644]
src/ModeNode.h [new file with mode: 0644]
src/UserNode.c [new file with mode: 0644]
src/UserNode.h [new file with mode: 0644]
src/WHOHandler.c [new file with mode: 0644]
src/WHOHandler.h [new file with mode: 0644]
src/bot_NeonServ.c [new file with mode: 0644]
src/bot_NeonServ.h [new file with mode: 0644]
src/bots.c [new file with mode: 0644]
src/bots.h [new file with mode: 0644]
src/cmd_neonserv.h [new file with mode: 0644]
src/cmd_neonserv_access.c [new file with mode: 0644]
src/cmd_neonserv_addban.c [new file with mode: 0644]
src/cmd_neonserv_addtimeban.c [new file with mode: 0644]
src/cmd_neonserv_adduser.c [new file with mode: 0644]
src/cmd_neonserv_ban.c [new file with mode: 0644]
src/cmd_neonserv_bans.c [new file with mode: 0644]
src/cmd_neonserv_bind.c [new file with mode: 0644]
src/cmd_neonserv_chanservsync.c [new file with mode: 0644]
src/cmd_neonserv_clvl.c [new file with mode: 0644]
src/cmd_neonserv_command.c [new file with mode: 0644]
src/cmd_neonserv_csuspend.c [new file with mode: 0644]
src/cmd_neonserv_cunsuspend.c [new file with mode: 0644]
src/cmd_neonserv_delban.c [new file with mode: 0644]
src/cmd_neonserv_delme.c [new file with mode: 0644]
src/cmd_neonserv_deluser.c [new file with mode: 0644]
src/cmd_neonserv_deop.c [new file with mode: 0644]
src/cmd_neonserv_deopall.c [new file with mode: 0644]
src/cmd_neonserv_devoice.c [new file with mode: 0644]
src/cmd_neonserv_devoiceall.c [new file with mode: 0644]
src/cmd_neonserv_down.c [new file with mode: 0644]
src/cmd_neonserv_downall.c [new file with mode: 0644]
src/cmd_neonserv_emote.c [new file with mode: 0644]
src/cmd_neonserv_events.c [new file with mode: 0644]
src/cmd_neonserv_giveowner.c [new file with mode: 0644]
src/cmd_neonserv_god.c [new file with mode: 0644]
src/cmd_neonserv_help.c [new file with mode: 0644]
src/cmd_neonserv_invite.c [new file with mode: 0644]
src/cmd_neonserv_inviteme.c [new file with mode: 0644]
src/cmd_neonserv_kick.c [new file with mode: 0644]
src/cmd_neonserv_kickban.c [new file with mode: 0644]
src/cmd_neonserv_mdeluser.c [new file with mode: 0644]
src/cmd_neonserv_mode.c [new file with mode: 0644]
src/cmd_neonserv_move.c [new file with mode: 0644]
src/cmd_neonserv_myaccess.c [new file with mode: 0644]
src/cmd_neonserv_netinfo.c [new file with mode: 0644]
src/cmd_neonserv_notice.c [new file with mode: 0644]
src/cmd_neonserv_op.c [new file with mode: 0644]
src/cmd_neonserv_opall.c [new file with mode: 0644]
src/cmd_neonserv_oplog.c [new file with mode: 0644]
src/cmd_neonserv_peek.c [new file with mode: 0644]
src/cmd_neonserv_raw.c [new file with mode: 0644]
src/cmd_neonserv_recover.c [new file with mode: 0644]
src/cmd_neonserv_register.c [new file with mode: 0644]
src/cmd_neonserv_reloadlang.c [new file with mode: 0644]
src/cmd_neonserv_resync.c [new file with mode: 0644]
src/cmd_neonserv_say.c [new file with mode: 0644]
src/cmd_neonserv_search.c [new file with mode: 0644]
src/cmd_neonserv_set.c [new file with mode: 0644]
src/cmd_neonserv_setaccess.c [new file with mode: 0644]
src/cmd_neonserv_suspend.c [new file with mode: 0644]
src/cmd_neonserv_topic.c [new file with mode: 0644]
src/cmd_neonserv_trace.c [new file with mode: 0644]
src/cmd_neonserv_trim.c [new file with mode: 0644]
src/cmd_neonserv_unban.c [new file with mode: 0644]
src/cmd_neonserv_unbanall.c [new file with mode: 0644]
src/cmd_neonserv_unbanme.c [new file with mode: 0644]
src/cmd_neonserv_unbind.c [new file with mode: 0644]
src/cmd_neonserv_unregister.c [new file with mode: 0644]
src/cmd_neonserv_unsuspend.c [new file with mode: 0644]
src/cmd_neonserv_up.c [new file with mode: 0644]
src/cmd_neonserv_upall.c [new file with mode: 0644]
src/cmd_neonserv_users.c [new file with mode: 0644]
src/cmd_neonserv_uset.c [new file with mode: 0644]
src/cmd_neonserv_version.c [new file with mode: 0644]
src/cmd_neonserv_voice.c [new file with mode: 0644]
src/cmd_neonserv_voiceall.c [new file with mode: 0644]
src/cmd_neonserv_wipeinfo.c [new file with mode: 0644]
src/config.h.example [new file with mode: 0644]
src/event_neonserv_ctcp.c [new file with mode: 0644]
src/event_neonserv_invite.c [new file with mode: 0644]
src/event_neonserv_join.c [new file with mode: 0644]
src/event_neonserv_notice.c [new file with mode: 0644]
src/event_neonserv_part.c [new file with mode: 0644]
src/event_neonserv_quit.c [new file with mode: 0644]
src/event_neonserv_topic.c [new file with mode: 0644]
src/lang.c [new file with mode: 0644]
src/lang.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/main.h [new file with mode: 0644]
src/modcmd.c [new file with mode: 0644]
src/modcmd.h [new file with mode: 0644]
src/mysqlConn.c [new file with mode: 0644]
src/mysqlConn.h [new file with mode: 0644]
src/timeq.c [new file with mode: 0644]
src/timeq.h [new file with mode: 0644]
src/tools.c [new file with mode: 0644]
src/tools.h [new file with mode: 0644]
src/version.h [new file with mode: 0644]
src/version.sh [new file with mode: 0644]
timeq.c [deleted file]
timeq.h [deleted file]
tools.c [deleted file]
tools.h [deleted file]
version.h [deleted file]
version.sh [deleted file]

index 57678a92d860d7e34d790d22e17a06c47352293e..4e8b61dbba9062ce986935a82c6afd2e807c7742 100644 (file)
@@ -1,2 +1,2 @@
-config.h
-version.c
\ No newline at end of file
+mysqlConfig.h
+src/version.c
\ No newline at end of file
diff --git a/BanNode.c b/BanNode.c
deleted file mode 100644 (file)
index c1601f1..0000000
--- a/BanNode.c
+++ /dev/null
@@ -1,66 +0,0 @@
-
-#include "BanNode.h"
-#include "ChanNode.h"
-#include "tools.h"
-
-struct BanNode* addChannelBan(struct ChanNode *chan, char *mask) {
-    struct BanNode *ban = malloc(sizeof(*ban));
-    ban->chan = chan;
-    ban->mask = strdup(mask);
-    ban->next = chan->bans;
-    chan->bans = ban;
-    return ban;
-}
-
-struct BanNode* getMatchingChannelBan(struct ChanNode *chan, char *mask) {
-    struct BanNode *cban;
-    for(cban = chan->bans; cban; cban = cban->next) {
-        if(!match(cban->mask, mask)) {
-            return cban;
-        }
-    }
-    return NULL;
-}
-
-void removeChannelBanMask(struct ChanNode *chan, char *mask) {
-    struct BanNode *cban, *last = NULL;
-    for(cban = chan->bans; cban; cban = cban->next) {
-        if(!strcmp(cban->mask, mask)) {
-            if(last)
-                last->next = cban->next;
-            else
-                chan->bans = cban->next;
-            free(cban->mask);
-            free(cban);
-            break;
-        } else 
-            last = cban;
-    }
-}
-
-void removeChannelBan(struct BanNode *ban) {
-    struct BanNode *cban, *last = NULL;
-    struct ChanNode *chan = ban->chan;
-    for(cban = chan->bans; cban; cban = cban->next) {
-        if(cban == ban) {
-            if(last)
-                last->next = ban->next;
-            else
-                chan->bans = ban->next;
-            free(ban->mask);
-            free(ban);
-            break;
-        } else 
-            last = cban;
-    }
-}
-
-void removeChannelBans(struct ChanNode *chan) {
-    struct BanNode *ban, *next;
-    for(ban = chan->bans; ban; ban = next) {
-        next = ban->next;
-        free(ban->mask);
-        free(ban);
-    }
-    chan->bans = NULL;
-}
diff --git a/BanNode.h b/BanNode.h
deleted file mode 100644 (file)
index a699e3f..0000000
--- a/BanNode.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _BanNode_h
-#define _BanNode_h
-#include "main.h"
-
-struct ChanNode;
-
-struct BanNode {
-    char *mask;
-    struct ChanNode *chan;
-    
-    struct BanNode *next;
-};
-
-struct BanNode* addChannelBan(struct ChanNode *chan, char *mask);
-struct BanNode* getMatchingChannelBan(struct ChanNode *chan, char *mask);
-void removeChannelBanMask(struct ChanNode *chan, char *mask);
-void removeChannelBan(struct BanNode *ban);
-void removeChannelBans(struct ChanNode *chan);
-
-#endif
\ No newline at end of file
diff --git a/ChanNode.c b/ChanNode.c
deleted file mode 100644 (file)
index 73adbf6..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "UserNode.h"
-#include "BanNode.h"
-#include "modcmd.h"
-#include "ModeNode.h"
-
-static struct ChanNode **chanList;
-
-void init_ChanNode() {
-    /*
-     len pos chars 
-     26  0   a-z
-     10  26  0-9
-     10  36  {|}~[\]^_`
-     1   46  *everything else*
-     ---------------------------
-     = 47
-    */
-    #define CHANNEL_LIST_SIZE 47
-    chanList = calloc(CHANNEL_LIST_SIZE, sizeof(*chanList));
-}
-
-void free_ChanNode() {
-    //kamikaze free all channels and chanusers
-    int i;
-    struct ChanNode *chan, *next;
-    struct ChanUser *chanuser, *next_chanuser;
-    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
-        for(chan = chanList[i]; chan; chan = next) {
-            next = chan->next;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next_chanuser) {
-                next_chanuser = getChannelUsers(chan, chanuser);
-                free(chanuser);
-            }
-            freeChanNode(chan);
-        }
-    }
-    free(chanList);
-}
-
-int is_valid_chan(const char *name) {
-    unsigned int ii;
-    if (*name !='#')
-        return 0;
-    for (ii=1; name[ii]; ++ii) {
-        if ((name[ii] > 0) && (name[ii] <= 32))
-            return 0;
-        if (name[ii] == ',')
-            return 0;
-        if (name[ii] == '\xa0')
-            return 0;
-    }
-    return 1;
-}
-
-static int get_chanlist_entry(int name) {
-    if((name > 0 && name <= 32) || name == ',' || name == '\xa0') return -1; //invalid name
-    if(tolower(name) >= 97 && tolower(name) <= 122) {
-        return (tolower(name) - 97);
-    }
-    if(tolower(name) >= 48 && tolower(name) <= 57) {
-        return (tolower(name) - 48 + 26);
-    }
-    /* {|}~[\]^_` */
-    if(name == '{') return 36;
-    if(name == '|') return 37;
-    if(name == '}') return 38;
-    if(name == '~') return 39;
-    if(name == '[') return 40;
-    if(name == '\\') return 41;
-    if(name == ']') return 42;
-    if(name == '^') return 43;
-    if(name == '_') return 44;
-    if(name == '`') return 45;
-    return 46;
-}
-
-struct ChanNode* getChanByName(const char *name) { //case insensitive
-    int chanListIndex = get_chanlist_entry(name[1]);
-    if(chanListIndex == -1 || chanList[chanListIndex] == NULL)
-        return NULL;
-    struct ChanNode *chan;
-    for(chan = chanList[chanListIndex]; chan; chan = chan->next) {
-        if(!stricmp(name, chan->name))
-            return chan;
-    }
-    return NULL;
-}
-
-struct ChanNode* addChannel(const char *name) {
-    int chanListIndex = get_chanlist_entry(name[1]);
-    if(chanListIndex == -1 || !is_valid_chan(name))
-        return NULL;
-    struct ChanNode *chan = malloc(sizeof(*chan));
-    if (!chan)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    strcpy(chan->name, name);
-    chan->user = NULL;
-    chan->bans = NULL;
-    chan->usercount = 0;
-    chan->chanbot = NULL;
-    chan->topic[0] = 0;
-    chan->flags = 0;
-    /* mode lists */
-    chan->modes = createModeNode(chan);
-    chan->trigger = NULL;
-    
-    chan->next = chanList[chanListIndex];
-    chanList[chanListIndex] = chan;
-    return chan;
-}
-
-int getChannelCount() {
-    int i, count = 0;
-    struct ChanNode *chan;
-    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
-        for(chan = chanList[i]; chan; chan = chan->next) {
-            count++;
-        }
-    }
-    return count;
-}
-
-int getChanUserCount() {
-    int i, count = 0;
-    struct ChanNode *chan;
-    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
-        for(chan = chanList[i]; chan; chan = chan->next) {
-            count += chan->usercount;
-        }
-    }
-    return count;
-}
-
-int getChanBanCount() {
-    int i, count = 0;
-    struct ChanNode *chan;
-    struct BanNode *ban;
-    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
-        for(chan = chanList[i]; chan; chan = chan->next) {
-            for(ban = chan->bans; ban; ban = ban->next)
-                count ++;
-        }
-    }
-    return count;
-}
-
-void delChannel(struct ChanNode* chan, int freeChan) {
-    int chanListIndex = get_chanlist_entry(chan->name[1]);
-    if(chanListIndex == -1) return;
-    struct ChanNode *cchan, *last_chan = NULL;
-    for(cchan = chanList[chanListIndex]; cchan; cchan = cchan->next) {
-        if(cchan == chan) {
-            if(last_chan)
-                last_chan->next = chan->next;
-            else
-                chanList[chanListIndex] = chan->next;
-            break;
-        } else
-            last_chan = cchan;
-    }
-    if(chan->user) {
-        //free all chanusers
-        struct ChanUser *chanuser, *next;
-        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
-            next = getChannelUsers(chan, chanuser);
-            removeChanUserFromLists(chanuser, 0, 1, 1);
-        }
-    }
-    if(freeChan)
-        freeChanNode(chan);
-    else
-        chan->next = NULL;
-}
-
-void freeChanNode(struct ChanNode* chan) {
-    if(chan->trigger) {
-        struct trigger_cache *trigger, *next_trigger;
-        for(trigger = chan->trigger; trigger; trigger = next_trigger) {
-            next_trigger = trigger->next;
-            free(trigger->trigger);
-            free(trigger);
-        }
-    }
-    freeModeNode(chan->modes);
-    if(chan->bans)
-        removeChannelBans(chan);
-    free(chan);
-}
-
-void checkChannelVisibility(struct ChanNode* chan) {
-    struct ChanUser *chanuser, *next;
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if(chanuser->user->flags & USERFLAG_ISBOT) {
-            chan->chanbot = chanuser->user;
-            return;
-        }
-    }
-    //free the channel...
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
-        next = getChannelUsers(chan, chanuser);
-        //remove the channel from the user's channel-list
-        removeChanUserFromLists(chanuser, 0, 1, 0);
-        if(!chanuser->user->channel) {
-            //free the user (no more channels)
-            delUser(chanuser->user, 1);
-        }
-        free(chanuser);
-    }
-    chan->user = NULL;
-    delChannel(chan, 1);
-}
diff --git a/ChanNode.h b/ChanNode.h
deleted file mode 100644 (file)
index 7847dea..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _ChanNode_h
-#define _ChanNode_h
-#include "main.h"
-
-struct ChanUser;
-struct trigger_cache;
-struct ModeNode;
-
-#define CHANFLAG_RECEIVED_USERLIST  0x01
-#define CHANFLAG_REQUESTED_CHANINFO 0x02
-#define CHANFLAG_CHAN_REGISTERED    0x04
-#define CHANFLAG_HAVE_INVISIBLES    0x08
-
-struct ChanNode {
-    char name[CHANNELLEN+1];
-    char topic[TOPICLEN+1];
-    struct ChanUser *user;
-    unsigned int usercount;
-    unsigned char flags;
-    struct ModeNode *modes;
-    struct BanNode *bans;
-    
-    struct UserNode *chanbot;
-    struct trigger_cache *trigger;
-    int channel_id;
-       
-    struct ChanNode *next;
-};
-
-void init_ChanNode();
-void free_ChanNode();
-int is_valid_chan(const char *name);
-struct ChanNode* getChanByName(const char *name);
-struct ChanNode* addChannel(const char *chan);
-int getChannelCount();
-int getChanUserCount();
-int getChanBanCount();
-void delChannel(struct ChanNode* chan, int freeChan);
-void freeChanNode(struct ChanNode* chan);
-void checkChannelVisibility(struct ChanNode* chan);
-
-#endif
\ No newline at end of file
diff --git a/ChanUser.c b/ChanUser.c
deleted file mode 100644 (file)
index c31e202..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-
-#include "ChanUser.h"
-#include "ChanNode.h"
-#include "UserNode.h"
-
-struct ChanUser* addChanUser(struct ChanNode *chan, struct UserNode *user) {
-    struct ChanUser *chanuser = malloc(sizeof(*chan));
-    if (!chanuser)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    chanuser->flags = 0;
-    chanuser->user = user;
-    chanuser->chan = chan;
-    
-    chanuser->changeTime = 0;
-
-    chanuser->next_user = chan->user;
-    chan->user = chanuser;
-    chan->usercount++;
-
-    chanuser->next_chan = user->channel;
-    user->channel = chanuser;
-
-    return chanuser;
-}
-
-struct ChanUser* addInvisibleChanUser(struct ChanNode *chan, struct UserNode *user) {
-    struct ChanUser *chanuser = malloc(sizeof(*chan));
-    if (!chanuser)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    chanuser->flags = CHANUSERFLAG_INVISIBLE;
-    chanuser->user = user;
-    chanuser->chan = chan;
-    
-    chanuser->changeTime = 0;
-
-    chanuser->next_user = chan->user;
-    chan->user = chanuser;
-    chan->usercount++;
-
-    return chanuser;
-}
-
-int isUserOnChan(struct UserNode *user, struct ChanNode *chan) {
-    struct ChanUser *chanuser;
-    for(chanuser = user->channel; chanuser; chanuser = chanuser->next_chan) {
-        if(chanuser->chan == chan)
-            return 1;
-    }
-    return 0;
-}
-
-struct ChanUser* getChanUser(struct UserNode *user, struct ChanNode *chan) {
-    struct ChanUser *chanuser;
-    for(chanuser = user->channel; chanuser; chanuser = chanuser->next_chan) {
-        if(chanuser->chan == chan)
-            return chanuser;
-    }
-    return NULL;
-}
-
-struct ChanUser* getChannelUsers(struct ChanNode *chan, struct ChanUser *last) {
-    if(last == NULL)
-        return chan->user;
-    else
-        return last->next_user;
-}
-
-struct ChanUser* getUserChannels(struct UserNode *user, struct ChanUser *last) {
-    if(last == NULL)
-        return user->channel;
-    else
-        return last->next_chan;
-}
-
-void delChanUser(struct ChanUser *chanuser, int freeChanUser) {
-    struct ChanUser *cchanuser, *last;
-    //remove it from the user's channel-list
-    if(!(chanuser->flags & CHANUSERFLAG_INVISIBLE)) {
-        last = NULL;
-        for(cchanuser = chanuser->user->channel; cchanuser; cchanuser = cchanuser->next_chan) {
-            if(cchanuser == chanuser) {
-                if(last) 
-                    last->next_chan = chanuser->next_chan;
-                else
-                    chanuser->user->channel = chanuser->next_chan;
-                break;
-            } else
-                last = cchanuser;
-        }
-    }
-
-    //remove it from the channel's user-list
-    last = NULL;
-    for(cchanuser = chanuser->chan->user; cchanuser; cchanuser = cchanuser->next_user) {
-        if(cchanuser == chanuser) {
-            chanuser->chan->usercount--;
-            if(last) 
-                last->next_user = chanuser->next_user;
-            else
-                chanuser->chan->user = chanuser->next_user;
-            break;
-        } else
-            last = cchanuser;
-    }
-    
-    if(freeChanUser)
-        free(chanuser);
-    else {
-        chanuser->next_chan = NULL;
-        chanuser->next_user = NULL;
-    }
-}
-
-void removeChanUserFromLists(struct ChanUser *chanuser, int remove_from_userlist, int remove_from_channellist, int freeChanUser) {
-    struct ChanUser *cchanuser, *last;
-    if(remove_from_userlist) {
-        //remove it from the channel's user-list
-        last = NULL;
-        for(cchanuser = chanuser->chan->user; cchanuser; cchanuser = cchanuser->next_user) {
-            if(cchanuser == chanuser) {
-                chanuser->chan->usercount--;
-                if(last) 
-                    last->next_user = chanuser->next_user;
-                else
-                    chanuser->chan->user = chanuser->next_user;
-                break;
-            } else
-                last = cchanuser;
-        }
-        chanuser->next_user = NULL;
-    }
-    if(remove_from_channellist) {
-        //remove it from the user's channel-list
-        last = NULL;
-        for(cchanuser = chanuser->user->channel; cchanuser; cchanuser = cchanuser->next_chan) {
-            if(cchanuser == chanuser) {
-                if(last) 
-                    last->next_chan = chanuser->next_chan;
-                else
-                    chanuser->user->channel = chanuser->next_chan;
-                break;
-            } else
-                last = cchanuser;
-        }
-        chanuser->next_chan = NULL;
-    }
-    
-    if(freeChanUser)
-        free(chanuser);
-}
-
diff --git a/ChanUser.h b/ChanUser.h
deleted file mode 100644 (file)
index 076b7f7..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _ChanUser_h
-#define _ChanUser_h
-#include "main.h"
-
-#define CHANUSERFLAG_OPPED  0x01
-#define CHANUSERFLAG_VOICED 0x02
-#define CHANUSERFLAG_INVISIBLE 0x04
-
-#define CHANUSERFLAG_OPPED_OR_VOICED (CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED)
-
-struct ChanNode;
-struct UserNode;
-
-struct ChanUser {
-    unsigned char flags;
-    struct ChanNode *chan;
-    struct UserNode *user;
-    
-    int chageEvents;
-    time_t changeTime;
-    
-    struct ChanUser *next_user;
-    struct ChanUser *next_chan;
-};
-
-struct ChanUser* addChanUser(struct ChanNode *chan, struct UserNode *user);
-struct ChanUser* addInvisibleChanUser(struct ChanNode *chan, struct UserNode *user);
-int isUserOnChan(struct UserNode *user, struct ChanNode *chan);
-struct ChanUser* getChanUser(struct UserNode *user, struct ChanNode *chan);
-struct ChanUser* getChannelUsers(struct ChanNode *chan, struct ChanUser *last);
-struct ChanUser* getUserChannels(struct UserNode *user, struct ChanUser *last);
-void delChanUser(struct ChanUser *chanuser, int freeChanUser);
-void removeChanUserFromLists(struct ChanUser *chanuser, int remove_from_userlist, int remove_from_channellist, int freeChanUser);
-
-#endif
\ No newline at end of file
diff --git a/ClientSocket.c b/ClientSocket.c
deleted file mode 100644 (file)
index 62e367d..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-
-#include "ClientSocket.h"
-#include "IRCParser.h"
-#include "UserNode.h"
-
-struct socket_list {
-    struct ClientSocket *data;
-    unsigned count;
-};
-
-//the magic list :P
-static struct socket_list *sockets = NULL;
-static char buffer[BUF_SIZ];
-
-static void init_sockets() {
-    sockets = malloc(sizeof(*sockets));
-    if (!sockets)
-    {
-        perror("malloc() failed");
-        return;
-    }
-    sockets->data = NULL;
-    sockets->count = 0;
-}
-
-struct ClientSocket* create_socket(char *host, int port, char *pass, struct UserNode *user) {
-    if(sockets == NULL) init_sockets();
-    struct ClientSocket *client = malloc(sizeof(*client));
-    if (!client)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    client->host = strdup(host);
-    client->port = port;
-    printf("Connect: %s:%d", client->host, client->port);
-    client->pass = (pass == NULL ? NULL : strdup(pass));
-    client->user = user;
-    client->flags = 0;
-    client->bufferpos = 0;
-    client->traffic_in = 0;
-    client->traffic_out = 0;
-    client->connection_time = 0;
-       client->botid = 0;
-    client->clientid = 0;
-    client->next = sockets->data;
-    sockets->data = client;
-    return client;
-}
-
-int connect_socket(struct ClientSocket *client) {
-    if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
-    struct hostent *host;
-    struct sockaddr_in addr;
-    int sock;
-    if (!inet_aton(client->host, &addr.sin_addr))
-    {
-        host = gethostbyname(client->host);
-        if (!host)
-        {
-            herror("gethostbyname() failed");
-            return 0;
-        }
-        addr.sin_addr = *(struct in_addr*)host->h_addr;
-    }
-    sock = socket(PF_INET, SOCK_STREAM, 0);
-    if (sock == -1)
-    {
-        perror("socket() failed");
-        return 0;
-    }
-
-    addr.sin_port = htons(client->port);
-    addr.sin_family = AF_INET;
-
-    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
-    {
-        perror("connect() failed");
-        return 0;
-    }
-
-    client->sock = sock;
-    client->flags |= SOCKET_FLAG_CONNECTED;
-    client->connection_time = time(0);
-
-    //send the IRC Headers
-    char sendBuf[512];
-    int len;
-
-    if(client->pass) {
-        len = sprintf(sendBuf, "PASS :%s\n", client->pass);
-        write_socket(client, sendBuf, len);
-    }
-    len = sprintf(sendBuf, "USER %s 0 0 :%s\n", client->user->ident, client->user->realname);
-    write_socket(client, sendBuf, len);
-    len = sprintf(sendBuf, "NICK %s\n", client->user->nick);
-    write_socket(client, sendBuf, len);
-
-    return 1;
-}
-
-int close_socket(struct ClientSocket *client) {
-    if(client == NULL) return 0;
-    if((client->flags & SOCKET_FLAG_CONNECTED))
-        close(client->sock);
-    struct ClientSocket *sock, *last_sock = NULL;
-    for (sock = sockets->data; sock; sock = sock->next) {
-        if(sock == client) {
-            if(last_sock)
-                last_sock->next = sock->next;
-            else
-                sockets->data = sock->next;
-            sockets->count--;
-        } else
-            last_sock = sock;
-    }
-    free(client->host);
-    free(client->pass);
-    free(client);
-    return 1;
-}
-
-int write_socket(struct ClientSocket *client, char* msg, int len) {
-    if(!(client->flags & SOCKET_FLAG_CONNECTED)) return 0;
-    printf("[send %d] %s", len, msg);
-    write(client->sock, msg, len);
-    client->traffic_out += len;
-    return 1;
-}
-
-void socket_loop(int timeout_seconds) {
-    if(sockets == NULL) return;
-    fd_set fds;
-    struct timeval timeout;
-    struct ClientSocket *sock;
-    int ret = 0, bytes, i;
-    
-    FD_ZERO(&fds);
-    for (sock = sockets->data; sock; sock = sock->next) {
-        if(!(sock->flags & SOCKET_FLAG_CONNECTED)) continue; //skip disconnected sockets
-        FD_SET(sock->sock, &fds);
-        if(sock->sock > ret)
-            ret = sock->sock;
-    }
-    timeout.tv_sec = timeout_seconds;
-    timeout.tv_usec = 0;
-    ret = select(ret + 1, &fds, NULL, NULL, &timeout);
-    if(ret == 0) return;
-    for (sock = sockets->data; sock; sock = sock->next) {
-        if((sock->flags & SOCKET_FLAG_CONNECTED) && FD_ISSET(sock->sock, &fds)) {
-            if(sock->bufferpos != 0) {
-                bytes = read(sock->sock, buffer, sizeof(buffer));
-                if(bytes > 0) {
-                    for(i = 0; i < bytes; i++) {
-                        if(sock->bufferpos + i == BUF_SIZ*2) break; //buffer overflow
-                        sock->buffer[sock->bufferpos + i] = buffer[i];
-                    }
-                    sock->bufferpos += i;
-                }
-            } else {
-                bytes = read(sock->sock, sock->buffer, sizeof(sock->buffer));
-                if(bytes > 0)
-                    sock->bufferpos = bytes;
-            }
-            if(bytes <= 0) {
-                //error
-                sock->flags &= ~(SOCKET_FLAG_CONNECTED | SOCKET_FLAG_READY);
-                bot_disconnect(sock);
-            } else {
-                sock->traffic_in += bytes;
-                int used = parse_lines(sock, sock->buffer, sock->bufferpos);
-                if(used == sock->bufferpos + 1) {
-                    //used all bytes so just reset the bufferpos
-                    sock->bufferpos = 0;
-                } else {
-                    for(i = 0; i < sock->bufferpos - used; i++) {
-                        sock->buffer[i] = sock->buffer[i+used];
-                    }
-                    sock->bufferpos -= used;
-                }
-            }
-        }
-    }
-}
-
-void
-putsock(struct ClientSocket *client, const char *text, ...)
-{
-    va_list arg_list;
-    char sendBuf[MAXLEN];
-    int pos;
-    if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
-    sendBuf[0] = '\0';
-    va_start(arg_list, text);
-    pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
-    va_end(arg_list);
-    if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
-    sendBuf[pos] = '\n';
-    sendBuf[pos+1] = '\0';
-    write_socket(client, sendBuf, pos+1);
-}
-
-struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot) {
-    struct ClientSocket *sock = (last_bot ? last_bot->next : sockets->data);
-    if(sock == NULL) return NULL;
-    for (; sock; sock = sock->next) {
-        if(!flags || (sock->flags & flags) == flags)
-            return sock;
-    }
-    return NULL;
-}
-
-void free_sockets() {
-    if(!sockets) return;
-    struct ClientSocket *client, *next;
-    for (client = sockets->data; client; client = next) {
-        next = client->next;
-        if((client->flags & SOCKET_FLAG_CONNECTED))
-            close(client->sock);
-        free(client->host);
-        free(client->pass);
-        free(client);
-    }
-    free(sockets);
-    sockets = NULL;
-}
diff --git a/ClientSocket.h b/ClientSocket.h
deleted file mode 100644 (file)
index 380e051..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _ClientSocket_h
-#define _ClientSocket_h
-
-#include "main.h"
-
-#define SOCKET_FLAG_DEAD      0x01
-#define SOCKET_FLAG_CONNECTED 0x02
-#define SOCKET_FLAG_READY     0x04
-#define SOCKET_FLAG_PREFERRED  0x08 /* prefered bot to send datas to the IRC World (NOTICE's WHO's etc pp) */
-
-#define BUF_SIZ 512
-
-struct UserNode;
-struct trigger_cache;
-
-struct ClientSocket {
-    int sock;
-    unsigned char flags;
-    char buffer[BUF_SIZ*2]; //we need to store up to 2 full commands at once
-    unsigned int bufferpos;
-    char *host;
-    int port;
-    char *pass;
-    struct UserNode *user;
-    unsigned long traffic_in;
-    unsigned long traffic_out;
-    time_t connection_time;
-       
-       int botid : 16;
-    int clientid : 16;
-    
-    struct ClientSocket *next;
-};
-
-struct ClientSocket* create_socket(char *host, int port, char *pass, struct UserNode *user);
-int connect_socket(struct ClientSocket *client);
-int close_socket(struct ClientSocket *client);
-int write_socket(struct ClientSocket *client, char* msg, int len);
-void socket_loop(int timeout_seconds);
-void putsock(struct ClientSocket *client, const char *text, ...) PRINTF_LIKE(2, 3);
-struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot);
-void free_sockets();
-
-#endif
\ No newline at end of file
diff --git a/DBHelper.c b/DBHelper.c
deleted file mode 100644 (file)
index 181fff6..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-
-#include "DBHelper.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "mysqlConn.h"
-#include "lang.h"
-#include "tools.h"
-
-void _loadUserSettings(struct UserNode *user) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `user_lang`, `user_reply_privmsg`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        user->language = get_language_by_tag(row[0]);
-        if(user->language == NULL) user->language = get_default_language();
-        if(strcmp(row[1], "0"))
-            user->flags |= USERFLAG_REPLY_PRIVMSG;
-        if(strcmp(row[2], "0"))
-            user->flags |= USERFLAG_GOD_MODE;
-    } else
-        user->language = get_default_language();
-    user->flags |= USERFLAG_LOADED_SETTINGS;
-}
-
-int isGodMode(struct UserNode *user) {
-    loadUserSettings(user);
-    return (user->flags & USERFLAG_GOD_MODE);
-}
-
-int getChannelAccess(struct UserNode *user, struct ChanNode *chan, int override) {
-    if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int caccess = 0;
-    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        if(strcmp(row[2], "0") && override) 
-            caccess = atoi(row[1]);
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%s' AND `chanuser_cid` = '%d'", row[0], chan->channel_id);
-        //
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            int cflags = atoi(row[1]);
-            if(!(cflags & DB_CHANUSER_SUSPENDED) && atoi(row[0]) > caccess)
-                caccess = atoi(row[0]);
-        }
-        return caccess;
-    }
-    return 0;
-}
-
-char *getChanDefault(char *channel_setting) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", channel_setting);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return "";
-    return row[0];
-}
-
-int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *channel_setting, int allow_override, int allow_501) {
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
-    if((user->flags & USERFLAG_ISIRCOP)) return 1;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", channel_setting, chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return 0;
-    int require_access = atoi((row[0] ? row[0] : getChanDefault(channel_setting)));
-    if(require_access == 0) return 1;
-    if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
-    int caccess = 0;
-    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%s' AND `chanuser_cid` = '%d'", row[0], chan->channel_id);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            int cflags = atoi(row[1]);
-            if(!(cflags & DB_CHANUSER_SUSPENDED))
-                caccess = atoi(row[0]);
-        }
-    }
-    if(caccess >= require_access) return 1;
-    if(caccess == 500 && require_access == 501 && allow_501) return 1;
-    return 0;
-}
-
-void _loadChannelSettings(struct ChanNode *chan) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(chan->name));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        chan->flags |= CHANFLAG_CHAN_REGISTERED;
-        chan->channel_id = atoi(row[0]);
-    }
-    chan->flags |= CHANFLAG_REQUESTED_CHANINFO;
-}
-
-//TODO: fix performance: we should cache the user access
-int isUserProtected(struct ChanNode *chan, struct UserNode *victim, struct UserNode *issuer) {
-    /* Don't protect if someone is attacking himself, or if the aggressor is an IRC Operator. */
-    if(victim == issuer || (issuer->flags & USERFLAG_ISIRCOP)) return 0;
-    
-    /* Don't protect if no one is to be protected. */
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    char protection;
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
-    printf_mysql_query("SELECT `channel_protect` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if(!(row = mysql_fetch_row(res))) return 0;
-    if(row[0]) {
-        protection = (char) atoi(row[0]);
-    } else {
-         printf_mysql_query("SELECT `channel_protect` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-        protection = (char) atoi(row[0]);
-    }
-    if(protection == 3) return 0;
-    
-    /* Don't protect if the victim isn't added to the channel, unless we are to protect non-users also. */
-    int victim_access = getChannelAccess(victim, chan, 0);
-    if (!victim_access && protection != 0) return 0;
-    
-    /* Protect if the aggressor isn't a user because at this point, the aggressor can only be less than or equal to the victim. */
-    int issuer_access = getChannelAccess(issuer, chan, 0);
-    if (!issuer_access) return 1;
-    
-    /* If the aggressor was a user, then the victim can't be helped. */
-    if(!victim_access) return 0;
-    
-    switch(protection) {
-        case 0:
-        case 1:
-            if(victim_access >= issuer_access) return 1;
-            break;
-        case 2:
-            if(victim_access > issuer_access) return 1;
-            break;
-    }
-    return 0;
-}
-
-char *getBanAffectingMask(struct ChanNode *chan, char *mask) {
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `ban_mask` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
-    res = mysql_use();
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(!match(row[0], mask))
-            return row[0];
-    }
-    return NULL;
-}
diff --git a/DBHelper.h b/DBHelper.h
deleted file mode 100644 (file)
index 8378040..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _DBHelper_h
-#define _DBHelper_h
-
-#include "main.h"
-struct UserNode;
-struct ChanNode;
-
-#define DB_CHANUSER_SUSPENDED 0x01
-#define DB_CHANUSER_AUTOINVITE 0x02
-#define DB_CHANUSER_NOAUTOOP 0x04
-
-void _loadUserSettings(struct UserNode* user);
-#define loadUserSettings(USER) if((USER->flags & USERFLAG_ISAUTHED) && !(USER->flags & USERFLAG_LOADED_SETTINGS)) _loadUserSettings(USER)
-int isGodMode(struct UserNode *user);
-char *getChanDefault(char *channel_setting);
-int getChannelAccess(struct UserNode *user, struct ChanNode *chan, int override);
-int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *channel_setting, int allow_override, int allow_501);
-void _loadChannelSettings(struct ChanNode *chan);
-#define loadChannelSettings(CHAN) if(!(CHAN->flags & CHANFLAG_REQUESTED_CHANINFO)) _loadChannelSettings(CHAN)
-int isUserProtected(struct ChanNode *chan, struct UserNode *victim, struct UserNode *issuer);
-
-char *getBanAffectingMask(struct ChanNode *chan, char *mask); //returns bans that match a given mask   eg. *!*@ab*  if you pass  *!*@abcdefg.*
-
-#endif
\ No newline at end of file
diff --git a/EventLogger.c b/EventLogger.c
deleted file mode 100644 (file)
index d0b61bd..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-
-#include "EventLogger.h"
-#include "modcmd.h"
-#include "mysqlConn.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "DBHelper.h"
-
-static struct Event *first_event = NULL, *last_event = NULL;
-
-struct Event *createEvent(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char **args, int argc, int flags) {
-    struct Event *event = malloc(sizeof(*event));
-    if (!event)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    event->client = client;
-    event->user = user;
-    event->chan = chan;
-    event->event_time = time(0);
-    event->command = strdup(command);
-    char arguments[MAXLEN];
-    int argpos = 0;
-    int i;
-    for(i = 0; i < argc; i++)
-        argpos += sprintf(arguments + argpos, "%s ", args[i]);
-    arguments[(argpos ? argpos-1 : 0)] = '\0';
-    event->arguments = strdup(arguments);
-    event->flags = flags;
-    event->next = NULL;
-    if(last_event) {
-        last_event->next = event;
-        last_event = event;
-    } else {
-        last_event = event;
-        first_event = event;
-    }
-    return event;
-}
-
-void logEvent(struct Event *event) {
-    char fullcmd[MAXLEN];
-    sprintf(fullcmd, "%s %s", event->command, event->arguments);
-    if((event->flags & CMDFLAG_LOG) && event->chan) {
-        char *auth = ((event->user->flags & USERFLAG_ISAUTHED) ? event->user->auth : "*");
-        loadChannelSettings(event->chan);
-        if((event->chan->flags & CHANFLAG_CHAN_REGISTERED))
-            printf_mysql_query("INSERT INTO `events` (`cid`, `nick`, `auth`, `time`, `command`) VALUES ('%d', '%s', '%s', UNIX_TIMESTAMP(), '%s')", event->chan->channel_id, escape_string(event->user->nick), auth, escape_string(fullcmd));
-    }
-    if((event->flags & CMDFLAG_OPLOG)) {
-        MYSQL_RES *res;
-        MYSQL_ROW row;
-        int userid;
-        char *auth = ((event->user->flags & USERFLAG_ISAUTHED) ? event->user->auth : "*");
-        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) == NULL) 
-            userid = 0;
-        else
-            userid = atoi(row[0]);
-        loadChannelSettings(event->chan);
-        if((event->chan->flags & CHANFLAG_CHAN_REGISTERED))
-            printf_mysql_query("INSERT INTO `godlog` (`godlog_cid`, `godlog_uid`, `godlog_time`, `godlog_cmd`) VALUES ('%d', '%d', UNIX_TIMESTAMP(), '%s')", event->chan->channel_id, userid, escape_string(fullcmd));
-    }
-}
-
-static void destroyEvent(struct Event *event) {
-    if(event == first_event)
-        first_event = event->next;
-    if(event == last_event) {
-        struct Event *last;
-        for(last = first_event; last; last = last->next)
-            if(last->next == NULL) break;
-        last_event = last;
-    }
-    free(event->command);
-    free(event->arguments);
-    free(event);
-}
-
-void destroyEvents() {
-    time_t now = time(0);
-    while(first_event && now - first_event->event_time >= 60) {
-        destroyEvent(first_event);
-    }
-}
diff --git a/EventLogger.h b/EventLogger.h
deleted file mode 100644 (file)
index 71da262..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef _EventLogger_h
-#define _EventLogger_h
-
-#include "main.h"
-struct ClientSocket;
-struct UserNode;
-struct ChanNode;
-
-struct Event {
-    struct ClientSocket *client;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    time_t event_time;
-    char *command;
-    char *arguments;
-    unsigned int flags; /* defined in modcmd.h */
-    
-    struct Event *next;
-};
-
-struct Event *createEvent(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char **args, int argc, int flags);
-void logEvent(struct Event *event);
-void destroyEvents();
-
-#endif
\ No newline at end of file
diff --git a/HandleInfoHandler.c b/HandleInfoHandler.c
deleted file mode 100644 (file)
index bda467e..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-
-#include "HandleInfoHandler.h"
-#include "ClientSocket.h"
-#include "UserNode.h"
-#include "IRCEvents.h"
-#include "tools.h"
-
-#define AUTHSERV_NICK "AuthServ"
-
-struct HandleInfoQueueEntry {
-    struct ClientSocket *client;
-    void *callback;
-    void *data;
-    
-    struct HandleInfoQueueEntry *next;
-};
-
-static struct HandleInfoQueueEntry *first_entry = NULL, *last_entry = NULL;
-
-static struct HandleInfoQueueEntry* addHandleInfoQueueEntry(struct ClientSocket *client) {
-    struct HandleInfoQueueEntry *entry = malloc(sizeof(*entry));
-    if (!entry)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    entry->next = NULL;
-    entry->client = client;
-    if(last_entry)
-        last_entry->next = entry;
-    else
-        last_entry = entry;
-    if(!first_entry)
-        first_entry = entry;
-    return entry;
-}
-
-static struct HandleInfoQueueEntry* getNextHandleInfoQueueEntry(struct ClientSocket *client, int freeEntry) {
-    if(!first_entry) return NULL;
-    struct HandleInfoQueueEntry *entry;
-    for(entry = first_entry; entry; entry = entry->next) {
-        if(entry->client == client)
-            break;
-    }
-    if(entry == NULL) return NULL;
-    if(freeEntry) {
-        if(entry == first_entry)
-            first_entry = entry->next;
-        if(entry == last_entry) {
-            struct HandleInfoQueueEntry *last;
-            for(last = first_entry; last; last = last->next)
-                if(last->next == NULL) break;
-            last_entry = last;
-        }
-    }
-    return entry;
-}
-
-void lookup_authname(char *auth, authlookup_callback_t callback, void *data) {
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->flags & SOCKET_FLAG_PREFERRED)
-            break;
-    }
-    if(bot == NULL) return;
-    struct HandleInfoQueueEntry* entry = addHandleInfoQueueEntry(bot);
-    entry->callback = callback;
-    entry->data = data;
-    putsock(bot, "PRIVMSG " AUTHSERV_NICK " :ACCOUNTINFO *%s", auth);
-}
-
-static void recv_notice(struct UserNode *user, struct UserNode *target, char *message) {
-    if(stricmp(user->nick, AUTHSERV_NICK)) return;
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->user == target) break;
-    }
-    if(!bot) return;
-    char *auth = NULL;
-    int do_match = 0, exists = 0;
-    char *tmp;
-    //messages to parse:
-    //  Account * has not been registered.
-    //  Account information for Skynet:
-    if(!match("Account * has not been registered.", message)) {
-        do_match = 1;
-        tmp = strstr(message, "\002");
-        auth = tmp+1;
-        tmp = strstr(auth, "\002");
-        *tmp = '\0';
-    }
-    if(!match("Account information for *", message)) {
-        do_match = 1;
-        exists = 1;
-        tmp = strstr(message, "\002");
-        auth = tmp+1;
-        tmp = strstr(auth, "\002");
-        *tmp = '\0';
-    }
-    if(do_match) {
-        struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, 1);
-        authlookup_callback_t *callback = entry->callback;
-        callback(auth, exists, entry->data);
-        free(entry);
-    }
-}
-
-void init_handleinfohandler() {
-    bind_privnotice(recv_notice);
-}
-
-void free_handleinfohandler() {
-    struct HandleInfoQueueEntry *entry, *next;
-    for(entry = first_entry; entry; entry = next) {
-        next = entry->next;
-        free(entry);
-    }
-    first_entry = NULL;
-    last_entry = NULL;
-}
diff --git a/HandleInfoHandler.h b/HandleInfoHandler.h
deleted file mode 100644 (file)
index e51fe8d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _HandleInfoHandler_h
-#define _HandleInfoHandler_h
-
-#include "main.h"
-
-struct ClientSocket;
-struct UserNode;
-
-#define AUTHLOOKUP_CALLBACK(NAME) void NAME(UNUSED_ARG(char *auth), UNUSED_ARG(int exists), UNUSED_ARG(void *data))
-typedef AUTHLOOKUP_CALLBACK(authlookup_callback_t);
-
-void lookup_authname(char *auth, authlookup_callback_t callback, void *data);
-void init_handleinfohandler();
-void free_handleinfohandler();
-
-#endif
\ No newline at end of file
diff --git a/IRCEvents.c b/IRCEvents.c
deleted file mode 100644 (file)
index 58efd37..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-
-#include "IRCEvents.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "ClientSocket.h"
-#include "mysqlConn.h"
-
-struct binding {
-    void *func;
-    struct binding *next;
-};
-
-static void **binds;
-#define BIND_TYPE_JOIN       0
-#define BIND_TYPE_NICK       1
-#define BIND_TYPE_PART       2
-#define BIND_TYPE_QUIT       3
-#define BIND_TYPE_KICK       4
-#define BIND_TYPE_TOPIC      5
-#define BIND_TYPE_MODE       6
-#define BIND_TYPE_CHANMSG    7
-#define BIND_TYPE_PRIVMSG    8
-#define BIND_TYPE_CHANNOTICE 9
-#define BIND_TYPE_PRIVNOTICE 10
-#define BIND_TYPE_CHANCTCP   11
-#define BIND_TYPE_PRIVCTCP   12
-#define BIND_TYPE_INVITE     13
-#define BIND_TYPE_RAW        14
-#define BIND_TYPE_BOT_READY  15
-
-#define TOTAL_BIND_TYPES     16
-
-void init_bind() {
-    binds = calloc(TOTAL_BIND_TYPES, sizeof(*binds));
-}
-
-void free_bind() {
-    struct binding *cbind, *next;
-    int i;
-    for(i = 0; i < TOTAL_BIND_TYPES; i++) {
-        for(cbind = binds[i]; cbind; cbind = next) {
-            next = cbind->next;
-            free(cbind);
-        }
-    }
-    free(binds);
-}
-
-static int is_bound(unsigned char type, void *func) {
-    struct binding *cbind;
-    for(cbind = binds[type]; cbind; cbind = cbind->next) {
-        if(cbind->func == func) 
-            return 1;
-    }
-    return 0;
-}
-
-#define FUNC_BIND(NAME,FUNCTYPE,TYPE) \
-int bind_##NAME(FUNCTYPE *func) { \
-    if(!is_bound(TYPE, func)) { \
-        struct binding *cbind = malloc(sizeof(*cbind)); \
-        if (!cbind) { \
-            perror("malloc() failed"); \
-            return 0; \
-        } \
-        cbind->func = func; \
-        cbind->next = binds[TYPE]; \
-        binds[TYPE] = cbind; \
-        return 1; \
-    } \
-    return 0; \
-}
-
-#define FUNC_UNBIND(NAME,FUNCTYPE,TYPE) \
-void unbind_##NAME(FUNCTYPE *func) { \
-    struct binding *cbind, *last = NULL, *next; \
-    for(cbind = binds[TYPE]; cbind; cbind = next) { \
-        next = cbind->next; \
-        if(cbind->func == func) { \
-            if(last) \
-                last->next = cbind->next; \
-            else \
-                binds[TYPE] = cbind->next; \
-            free(cbind); \
-        } else \
-            last = cbind; \
-    } \
-}
-
-#define FUNC_EVENT(NAME,FUNCTYPE,TYPE,PDECLARATION,PLIST) \
-int event_##NAME PDECLARATION { \
-    struct binding *cbind; \
-    pre_event(TYPE); \
-    for(cbind = binds[TYPE]; cbind; cbind = cbind->next) { \
-        FUNCTYPE *func = cbind->func; \
-        func PLIST; \
-    } \
-    post_event(TYPE); \
-    return 1; \
-}
-
-void pre_event(UNUSED_ARG(int type)) {
-
-}
-
-void post_event(UNUSED_ARG(int type)) {
-    mysql_free();
-}
-
-//EVENTS
-
-FUNC_BIND(join, join_func_t, BIND_TYPE_JOIN)
-FUNC_UNBIND(join, join_func_t, BIND_TYPE_JOIN)
-FUNC_EVENT(join, join_func_t, BIND_TYPE_JOIN, (struct ChanUser *chanuser), (chanuser))
-
-FUNC_BIND(nick, nick_func_t, BIND_TYPE_NICK)
-FUNC_UNBIND(nick, nick_func_t, BIND_TYPE_NICK)
-FUNC_EVENT(nick, nick_func_t, BIND_TYPE_NICK, (struct UserNode *user, char *new_nick), (user, new_nick))
-
-FUNC_BIND(part, part_func_t, BIND_TYPE_PART)
-FUNC_UNBIND(part, part_func_t, BIND_TYPE_PART)
-FUNC_EVENT(part, part_func_t, BIND_TYPE_PART, (struct ChanUser *chanuser, char *reason), (chanuser, reason))
-
-FUNC_BIND(quit, quit_func_t, BIND_TYPE_QUIT)
-FUNC_UNBIND(quit, quit_func_t, BIND_TYPE_QUIT)
-FUNC_EVENT(quit, quit_func_t, BIND_TYPE_QUIT, (struct UserNode *user, char *reason), (user, reason))
-
-FUNC_BIND(kick, kick_func_t, BIND_TYPE_KICK)
-FUNC_UNBIND(kick, kick_func_t, BIND_TYPE_KICK)
-FUNC_EVENT(kick, kick_func_t, BIND_TYPE_KICK, (struct UserNode *user, struct ChanUser *target, char *reason), (user, target, reason))
-
-FUNC_BIND(topic, topic_func_t, BIND_TYPE_TOPIC)
-FUNC_UNBIND(topic, topic_func_t, BIND_TYPE_TOPIC)
-FUNC_EVENT(topic, topic_func_t, BIND_TYPE_TOPIC, (struct UserNode *user, struct ChanNode *chan, const char *new_topic), (user, chan, new_topic))
-
-FUNC_BIND(mode, mode_func_t, BIND_TYPE_MODE)
-FUNC_UNBIND(mode, mode_func_t, BIND_TYPE_MODE)
-FUNC_EVENT(mode, mode_func_t, BIND_TYPE_MODE, (struct UserNode *user, struct ChanNode *chan, char *modes, char **args, int argc), (user, chan, modes, args, argc))
-
-FUNC_BIND(chanmsg, chanmsg_func_t, BIND_TYPE_CHANMSG)
-FUNC_UNBIND(chanmsg, chanmsg_func_t, BIND_TYPE_CHANMSG)
-FUNC_EVENT(chanmsg, chanmsg_func_t, BIND_TYPE_CHANMSG, (struct UserNode *user, struct ChanNode *chan, char *message), (user, chan, message))
-
-FUNC_BIND(privmsg, privmsg_func_t, BIND_TYPE_PRIVMSG)
-FUNC_UNBIND(privmsg, privmsg_func_t, BIND_TYPE_PRIVMSG)
-FUNC_EVENT(privmsg, privmsg_func_t, BIND_TYPE_PRIVMSG, (struct UserNode *user, struct UserNode *target, char *message), (user, target, message))
-
-FUNC_BIND(channotice, channotice_func_t, BIND_TYPE_CHANNOTICE)
-FUNC_UNBIND(channotice, channotice_func_t, BIND_TYPE_CHANNOTICE)
-FUNC_EVENT(channotice, channotice_func_t, BIND_TYPE_CHANNOTICE, (struct UserNode *user, struct ChanNode *chan, char *message), (user, chan, message))
-
-FUNC_BIND(privnotice, privnotice_func_t, BIND_TYPE_PRIVNOTICE)
-FUNC_UNBIND(privnotice, privnotice_func_t, BIND_TYPE_PRIVNOTICE)
-FUNC_EVENT(privnotice, privnotice_func_t, BIND_TYPE_PRIVNOTICE, (struct UserNode *user, struct UserNode *target, char *message), (user, target, message))
-
-FUNC_BIND(chanctcp, chanctcp_func_t, BIND_TYPE_CHANCTCP)
-FUNC_UNBIND(chanctcp, chanctcp_func_t, BIND_TYPE_CHANCTCP)
-FUNC_EVENT(chanctcp, chanctcp_func_t, BIND_TYPE_CHANCTCP, (struct UserNode *user, struct ChanNode *chan, char *command, char *text), (user, chan, command, text))
-
-FUNC_BIND(privctcp, privctcp_func_t, BIND_TYPE_PRIVCTCP)
-FUNC_UNBIND(privctcp, privctcp_func_t, BIND_TYPE_PRIVCTCP)
-FUNC_EVENT(privctcp, privctcp_func_t, BIND_TYPE_PRIVCTCP, (struct UserNode *user, struct UserNode *target, char *command, char *text), (user, target, command, text))
-
-FUNC_BIND(invite, invite_func_t, BIND_TYPE_INVITE)
-FUNC_UNBIND(invite, invite_func_t, BIND_TYPE_INVITE)
-FUNC_EVENT(invite, invite_func_t, BIND_TYPE_INVITE, (struct ClientSocket *client, struct UserNode *user, char *channel), (client, user, channel))
-
-FUNC_BIND(raw, raw_func_t, BIND_TYPE_RAW)
-FUNC_UNBIND(raw, raw_func_t, BIND_TYPE_RAW)
-FUNC_EVENT(raw, raw_func_t, BIND_TYPE_RAW, (struct ClientSocket *client, char *from, char *cmd, char **argv, int argc), (client, from, cmd, argv, argc))
-
-FUNC_BIND(bot_ready, bot_ready_func_t, BIND_TYPE_BOT_READY)
-FUNC_UNBIND(bot_ready, bot_ready_func_t, BIND_TYPE_BOT_READY)
-FUNC_EVENT(bot_ready, bot_ready_func_t, BIND_TYPE_BOT_READY, (struct ClientSocket *client), (client))
diff --git a/IRCEvents.h b/IRCEvents.h
deleted file mode 100644 (file)
index e08803e..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef _IRCEvents_h
-#define _IRCEvents_h
-
-#include "main.h"
-
-struct UserNode;
-struct ChanNode;
-struct ChanUser;
-struct ClientSocket;
-
-void init_bind();
-void free_bind();
-
-typedef void join_func_t(struct ChanUser *chanuser);
-int bind_join(join_func_t *func);
-void unbind_join(join_func_t *func);
-int event_join(struct ChanUser *chanuser);
-
-typedef void nick_func_t(struct UserNode *user, char *new_nick);
-int bind_nick(nick_func_t *func);
-void unbind_nick(nick_func_t *func);
-int event_nick(struct UserNode *user, char *new_nick);
-
-typedef void part_func_t(struct ChanUser *chanuser, char *reason);
-int bind_part(part_func_t *func);
-void unbind_part(part_func_t *func);
-int event_part(struct ChanUser *chanuser, char *reason);
-
-typedef void quit_func_t(struct UserNode *user, char *reason);
-int bind_quit(quit_func_t *func);
-void unbind_quit(quit_func_t *func);
-int event_quit(struct UserNode *user, char *reason);
-
-typedef void kick_func_t(struct UserNode *user, struct ChanUser *target, char *reason);
-int bind_kick(kick_func_t *func);
-void unbind_kick(kick_func_t *func);
-int event_kick(struct UserNode *user, struct ChanUser *target, char *reason);
-
-typedef void topic_func_t(struct UserNode *user, struct ChanNode *chan, const char *new_topic);
-int bind_topic(topic_func_t *func);
-void unbind_topic(topic_func_t *func);
-int event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic);
-
-typedef void mode_func_t(struct UserNode *user, struct ChanNode *chan, char *modes, char **argv, int argc);
-int bind_mode(mode_func_t *func);
-void unbind_mode(mode_func_t *func);
-int event_mode(struct UserNode *user, struct ChanNode *chan, char *modes, char **argv, int argc);
-
-typedef void chanmsg_func_t(struct UserNode *user, struct ChanNode *chan, char *message);
-int bind_chanmsg(chanmsg_func_t *func);
-void unbind_chanmsg(chanmsg_func_t *func);
-int event_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message);
-
-typedef void privmsg_func_t(struct UserNode *user, struct UserNode *target, char *message);
-int bind_privmsg(privmsg_func_t *func);
-void unbind_privmsg(privmsg_func_t *func);
-int event_privmsg(struct UserNode *user, struct UserNode *target, char *message);
-
-typedef void channotice_func_t(struct UserNode *user, struct ChanNode *chan, char *message);
-int bind_channotice(channotice_func_t *func);
-void unbind_channotice(channotice_func_t *func);
-int event_channotice(struct UserNode *user, struct ChanNode *chan, char *message);
-
-typedef void privnotice_func_t(struct UserNode *user, struct UserNode *target, char *message);
-int bind_privnotice(privnotice_func_t *func);
-void unbind_privnotice(privnotice_func_t *func);
-int event_privnotice(struct UserNode *user, struct UserNode *target, char *message);
-
-typedef void chanctcp_func_t(struct UserNode *user, struct ChanNode *chan, char *command, char *text);
-int bind_chanctcp(chanctcp_func_t *func);
-void unbind_chanctcp(chanctcp_func_t *func);
-int event_chanctcp(struct UserNode *user, struct ChanNode *chan, char *command, char *text);
-
-typedef void privctcp_func_t(struct UserNode *user, struct UserNode *target, char *command, char *text);
-int bind_privctcp(privctcp_func_t *func);
-void unbind_privctcp(privctcp_func_t *func);
-int event_privctcp(struct UserNode *user, struct UserNode *target, char *command, char *text);
-
-typedef void invite_func_t(struct ClientSocket *client, struct UserNode *user, char *channel);
-int bind_invite(invite_func_t *func);
-void unbind_invite(invite_func_t *func);
-int event_invite(struct ClientSocket *client, struct UserNode *user, char *channel);
-
-typedef void raw_func_t(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
-int bind_raw(raw_func_t *func);
-void unbind_raw(raw_func_t *func);
-int event_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
-
-typedef void bot_ready_func_t(struct ClientSocket *client);
-int bind_bot_ready(bot_ready_func_t *func);
-void unbind_bot_ready(bot_ready_func_t *func);
-int event_bot_ready(struct ClientSocket *client);
-
-
-
-#endif
\ No newline at end of file
diff --git a/IRCParser.c b/IRCParser.c
deleted file mode 100644 (file)
index 8662f6d..0000000
+++ /dev/null
@@ -1,427 +0,0 @@
-
-#include "IRCParser.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "IRCEvents.h"
-#include "ClientSocket.h"
-#include "WHOHandler.h"
-#include "lang.h"
-#include "DBHelper.h"
-#include "BanNode.h"
-#include "ModeNode.h"
-
-struct irc_cmd *irc_commands = NULL;
-
-static void parse_line(struct ClientSocket *client, char *line);
-static void register_irc_function(char *command, irc_cmd_t *func);
-static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
-
-int parse_lines(struct ClientSocket *client, char *lines, int len) {
-    int i, used = 0;
-    char *line = lines;
-    for(i = 0; i < len; i++) {
-        if(lines[i] == '\r') //just zero it out :D
-            lines[i] = 0;
-        if(lines[i] == '\n') {
-            lines[i] = 0;
-            parse_line(client, line);
-            line = lines+(i+1);
-            used = i+1;
-        }
-    }
-    return used;
-}
-
-static void parse_line(struct ClientSocket *client, char *line) {
-    int argc = 0;
-    char *argv[MAXNUMPARAMS];
-    printf("[recv %lu] %s\n", (unsigned long) strlen(line), line);
-    if(line[0] == ':')
-        line++;
-    else
-        argv[argc++] = NULL;
-    while(*line) {
-        //skip leading spaces
-        while (*line == ' ')
-            *line++ = 0;
-        if (*line == ':') {
-           //the rest is a single parameter
-           argv[argc++] = line + 1;
-           break;
-        }
-        argv[argc++] = line;
-        if (argc >= MAXNUMPARAMS)
-            break;
-        while (*line != ' ' && *line)
-            line++;
-    }
-    if(argc >= 2) {
-        parse_raw(client, argv[0], argv[1], argv+2, argc-2);
-    }
-}
-
-static void register_irc_function(char *command, irc_cmd_t *func) {
-    struct irc_cmd *irc_cmd = malloc(sizeof(*irc_cmd));
-    if (!irc_cmd)
-    {
-        perror("malloc() failed");
-        return;
-    }
-    irc_cmd->cmd = command;
-    irc_cmd->func = func;
-    irc_cmd->next = irc_commands;
-    irc_commands = irc_cmd;
-}
-
-static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc) {
-    struct irc_cmd *irc_cmd;
-    int ret = 0;
-    for(irc_cmd = irc_commands; irc_cmd; irc_cmd = irc_cmd->next) {
-        if(!stricmp(irc_cmd->cmd, cmd)) {
-            ret = irc_cmd->func(client, from, argv, argc);
-            break;
-        }
-    }
-    if(!irc_cmd) {
-        event_raw(client, from, cmd, argv, argc);
-    } else if(!ret) {
-        fprintf(stderr,"PARSE ERROR: %s\n", cmd);
-    }
-}
-
-static USERLIST_CALLBACK(got_channel_userlist) {
-    struct ChanUser *chanuser = data;
-    event_join(chanuser);
-}
-
-static IRC_CMD(raw_001) {
-    client->flags |= SOCKET_FLAG_READY;
-    event_bot_ready(client);
-    return 1;
-}
-
-static IRC_CMD(raw_join) {
-    if(from == NULL || argc < 1) return 0;
-    struct UserNode *user = getUserByMask(from);
-    struct ChanNode *chan = getChanByName(argv[0]);
-    if(!chan && !(user->flags & USERFLAG_ISBOT)) return 0;
-    if(user == NULL) {
-        user = addUserMask(from);
-    }
-    if(chan == NULL) {
-        chan = addChannel(argv[0]);
-        //request member list
-        chan->chanbot = user;
-        struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot
-        get_userlist(chan, got_channel_userlist, chanuser);
-        putsock(client, "MODE %s", chan->name);
-        putsock(client, "MODE %s +b", chan->name);
-    } else if(!isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
-        struct ChanUser *chanuser = addChanUser(chan, user);
-        event_join(chanuser);
-    }
-    return 1;
-}
-
-static IRC_CMD(raw_part) {
-    if(from == NULL || argc < 1) return 0;
-    struct UserNode *user = getUserByMask(from);
-    if(user == NULL) return 0;
-    struct ChanNode *chan = getChanByName(argv[0]);
-    if(chan == NULL) return 0;
-    if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
-        struct ChanUser *chanuser = getChanUser(user, chan);
-        delChanUser(chanuser, 0); //we need to free the chanuser manually!
-        event_part(chanuser, (argc > 1 ? argv[1] : NULL));
-        free(chanuser);
-        if(chan->chanbot == user) {
-            //check if theres another bot in the channel - otherwise free it
-            checkChannelVisibility(chan);
-        }
-    }
-    if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
-        //remove the user
-        delUser(user, 1);
-    }
-    return 1;
-}
-
-static IRC_CMD(raw_quit) {
-    if(from == NULL || argc < 1) return 0;
-    struct UserNode *user = getUserByMask(from);
-    if(user == NULL) return 0;
-    delUser(user, 0); //a little bit crazy, but we want to delete the user on the channel's userlists - but not the users channel list
-    event_quit(user, argv[0]);
-    if(user->flags & USERFLAG_ISBOT) {
-        //check if there are other bots in the users channel - otherwise free them
-        struct ChanUser *chanuser, *next;
-        for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
-            next = getUserChannels(user, chanuser);
-            checkChannelVisibility(chanuser->chan);
-        }
-    }
-    delUser(user, 1); //now we fully free the user
-    return 1;
-}
-
-void bot_disconnect(struct ClientSocket *client) {
-    struct UserNode *user = client->user;
-    struct ChanUser *chanuser, *next;
-    delUser(user, 0);
-    event_quit(user, "disconnected");
-    for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
-        next = getUserChannels(user, chanuser);
-        checkChannelVisibility(chanuser->chan);
-        free(chanuser);
-    }
-    user->channel = NULL;
-}
-
-static IRC_CMD(raw_kick) {
-    if(from == NULL || argc < 3) return 0;
-    struct UserNode *user = getUserByMask(from);
-    struct UserNode *target = getUserByNick(argv[1]);
-    struct ChanNode *chan = getChanByName(argv[0]);
-    if(chan == NULL || target == NULL) return 0;
-    if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
-        if(user == NULL) {
-            user = createTempUser(from);
-            user->flags |= USERFLAG_ISTMPUSER;
-        }
-        struct ChanUser *chanuser = getChanUser(target, chan);
-        delChanUser(chanuser, 0); //we need to free the chanuser manually!
-        event_kick(user, chanuser, argv[1]);
-        free(chanuser);
-        if(target->flags & USERFLAG_ISBOT) {
-            //check if theres another bot in the channel - otherwise free it
-            checkChannelVisibility(chan);
-        }
-    }
-    if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) {
-        //remove the user
-        delUser(target, 1);
-    }
-    return 1;
-}
-
-static IRC_CMD(raw_topic) {
-    if(from == NULL || argc < 2) return 0;
-    struct UserNode *user = getUserByMask(from);
-    struct ChanNode *chan = getChanByName(argv[0]);
-    if(chan == NULL) return 0;
-    if(chan->chanbot != client->user) return 1; //just ignore it to prevent event duplicates
-    if(user == NULL) {
-        user = createTempUser(from);
-        user->flags |= USERFLAG_ISTMPUSER;
-    }
-    event_topic(user, chan, argv[1]);
-    strcpy(chan->topic, argv[1]);
-    return 1;
-}
-
-static IRC_CMD(raw_privmsg) {
-    if(from == NULL || argc < 2) return 0;
-    struct UserNode *user = getUserByMask(from);
-    if(user == NULL) {
-        user = createTempUser(from);
-        user->flags |= USERFLAG_ISTMPUSER;
-    }
-    if(argv[0][0] == '#') { //Channel message
-        struct ChanNode *chan = getChanByName(argv[0]);
-        if(chan && chan->chanbot == client->user) {
-            if(argv[1][0] == '\001') {
-                char *cmd = &argv[1][1];
-                char *text = strstr(cmd, " ");
-                if(text) {
-                    *text = '\0';
-                    text++;
-                    if(strlen(text) && text[strlen(text)-1] == '\001')
-                        text[strlen(text)-1] = '\0';
-                } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
-                    cmd[strlen(cmd)-1] = '\0';
-                event_chanctcp(user, chan, cmd, text);
-            } else
-                event_chanmsg(user, chan, argv[1]);
-        }
-    } else {
-        struct UserNode *target = getUserByNick(argv[0]);
-        if(target) {
-            if(argv[1][0] == '\001') {
-                char *cmd = &argv[1][1];
-                char *text = strstr(cmd, " ");
-                if(text) {
-                    *text = '\0';
-                    text++;
-                    if(strlen(text) && text[strlen(text)-1] == '\001')
-                        text[strlen(text)-1] = '\0';
-                } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
-                    cmd[strlen(cmd)-1] = '\0';
-                event_privctcp(user, target, cmd, text);
-            } else
-                event_privmsg(user, target, argv[1]);
-        }
-    }
-    return 1;
-}
-
-static IRC_CMD(raw_notice) {
-    if(from == NULL || argc < 2) return 0;
-    struct UserNode *user = getUserByMask(from);
-    if(user == NULL) {
-        user = createTempUser(from);
-        user->flags |= USERFLAG_ISTMPUSER;
-    }
-    if(argv[0][0] == '#') { //Channel notice
-        struct ChanNode *chan = getChanByName(argv[0]);
-        if(chan && chan->chanbot == client->user)
-            event_channotice(user, chan, argv[1]);
-    } else {
-        struct UserNode *target = getUserByNick(argv[0]);
-        if(target)
-            event_privnotice(user, target, argv[1]);
-    }
-    return 1;
-}
-
-static IRC_CMD(raw_nick) {
-    if(from == NULL || argc == 0) return 0;
-    struct UserNode *user = getUserByMask(from);
-    if(user == NULL) return 0;
-    event_nick(user, argv[0]);
-    renameUser(user, argv[0]);
-    return 1;
-}
-
-static IRC_CMD(raw_ping) {
-    if(argc == 0) return 0;
-    putsock(client, "PONG :%s", argv[0]);
-    return 1;
-}
-
-static IRC_CMD(raw_354) {
-    recv_whohandler_354(client, argv, argc);
-    return 1;
-}
-
-static IRC_CMD(raw_315) {
-    recv_whohandler_315(client, argv, argc);
-    return 1;
-}
-
-static IRC_CMD(raw_324) { //MODE LIST
-    //Watchcat #pktest +stnzN
-    if(from == NULL || argc < 3) return 0;
-    struct ChanNode *chan = getChanByName(argv[1]);
-    if(chan == NULL) return 0;
-    parseModes(chan->modes, argv[2], argv+3, argc-3);
-    return 1;
-}
-
-static IRC_CMD(raw_invite) {
-    if(from == NULL || argc < 2) return 0;
-    struct UserNode *user = getUserByMask(from);
-    if(user == NULL) {
-        user = createTempUser(from);
-        user->flags |= USERFLAG_ISTMPUSER;
-    }
-    event_invite(client, user, argv[1]);
-    return 1;
-}
-
-static IRC_CMD(raw_mode) {
-    if(from == NULL || argc < 2) return 0;
-    struct UserNode *user = getUserByMask(from);
-    if(user == NULL) {
-        user = createTempUser(from);
-        user->flags |= USERFLAG_ISTMPUSER;
-    }
-    if(argv[0][0] == '#') {
-        //ChannelMode
-        struct ChanNode *chan = getChanByName(argv[0]);
-        if(!chan) return 0;
-        if(chan->chanbot != client->user) return 1;
-        event_mode(user, chan, argv[1], argv+2, argc-2);
-        parseModes(chan->modes, argv[1], argv+2, argc-2);
-    } else {
-        //UserMode
-    }
-    return 1;
-}
-
-static IRC_CMD(raw_367) {
-    //Watchcat #pktest pk911!*@* TestBot!~bot@pktest.user.WebGamesNet 1315863279
-    struct ChanNode *chan = getChanByName(argv[1]);
-    if(!chan) return 0;
-    struct BanNode *ban;
-    while((ban = getMatchingChannelBan(chan, argv[2]))) {
-        removeChannelBan(ban);
-    }
-    addChannelBan(chan, argv[2]);
-    return 1;
-}
-
-void init_parser() {
-    //all the raws we receive...
-    register_irc_function("001", raw_001);
-    register_irc_function("324", raw_324);
-    register_irc_function("367", raw_367);
-    register_irc_function("INVITE", raw_invite);
-    register_irc_function("NOTICE", raw_notice);
-    register_irc_function("TOPIC", raw_topic);
-    register_irc_function("KICK", raw_kick);
-    register_irc_function("PART", raw_part);
-    register_irc_function("QUIT", raw_quit);
-    register_irc_function("JOIN", raw_join);
-    register_irc_function("MODE", raw_mode);
-    register_irc_function("NICK", raw_nick);
-    register_irc_function("354", raw_354);
-    register_irc_function("315", raw_315);
-    register_irc_function("PING", raw_ping);
-    register_irc_function("PRIVMSG", raw_privmsg);
-}
-
-void free_parser() {
-    struct irc_cmd *cmd, *next;
-    for(cmd = irc_commands; cmd; cmd = next) {
-        next = cmd->next;
-        free(cmd);
-    }
-}
-
-void reply(struct ClientSocket *client, struct UserNode *user, const char *text, ...) {
-    const char *reply_format = get_language_string(user, text);
-    if(reply_format == NULL)
-        reply_format = text;
-    loadUserSettings(user);
-    char formatBuf[MAXLEN];
-    sprintf(formatBuf, "%s %s :%s", ((user->flags & USERFLAG_REPLY_PRIVMSG) ? "PRIVMSG" : "NOTICE"), user->nick, reply_format);
-    va_list arg_list;
-    char sendBuf[MAXLEN];
-    int pos;
-    if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
-    sendBuf[0] = '\0';
-    va_start(arg_list, text);
-    pos = vsnprintf(sendBuf, MAXLEN - 2, formatBuf, arg_list);
-    va_end(arg_list);
-    if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
-    sendBuf[pos] = '\n';
-    sendBuf[pos+1] = '\0';
-    write_socket(client, sendBuf, pos+1);
-}
-
-char* merge_argv(char **argv, int start, int end) {
-    return merge_argv_char(argv, start, end, ' ');
-}
-
-char* merge_argv_char(char **argv, int start, int end, char seperator) {
-    int i;
-    char *p = NULL;
-    for(i = start; i < end; i++) {
-        p = argv[i];
-        while(*p) p++;
-        *p = seperator;
-    }
-    if(p) *p = '\0';
-    return argv[start];
-}
diff --git a/IRCParser.h b/IRCParser.h
deleted file mode 100644 (file)
index ac2b376..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef _IRCParser_h
-#define _IRCParser_h
-
-#include "main.h"
-
-struct ClientSocket;
-struct UserNode;
-
-#define IRC_CMD(NAME) int NAME(struct ClientSocket *client, UNUSED_ARG(const char *from), UNUSED_ARG(char **argv), UNUSED_ARG(unsigned int argc))
-typedef IRC_CMD(irc_cmd_t);
-
-struct irc_cmd {
-    char *cmd;
-    irc_cmd_t *func;
-    struct irc_cmd *next;
-};
-
-int parse_lines(struct ClientSocket *client, char *lines, int len);
-void bot_disconnect(struct ClientSocket *client);
-void init_parser();
-void free_parser();
-void reply(struct ClientSocket *client, struct UserNode *user, const char *text, ...);
-char* merge_argv(char **argv, int start, int end);
-char* merge_argv_char(char **argv, int start, int end, char seperator);
-
-#endif
\ No newline at end of file
diff --git a/Makefile b/Makefile
deleted file mode 100644 (file)
index 10825e2..0000000
--- a/Makefile
+++ /dev/null
@@ -1,119 +0,0 @@
-CC = gcc
-SRC = EventLogger.c \
-      IRCEvents.c \
-      main.c \
-      ChanNode.c \
-      IRCParser.c \
-      ClientSocket.c \
-      UserNode.c \
-      ChanUser.c \
-      ModeNode.c \
-      BanNode.c \
-      WHOHandler.c \
-      modcmd.c \
-      mysqlConn.c \
-      lang.c \
-      HandleInfoHandler.c \
-      tools.c \
-      timeq.c \
-      DBHelper.c \
-      bots.c \
-      bot_NeonServ.c
-CMD = cmd_neonserv_access.c \
-      cmd_neonserv_addban.c \
-      cmd_neonserv_addtimeban.c \
-      cmd_neonserv_adduser.c \
-      cmd_neonserv_ban.c \
-      cmd_neonserv_bans.c \
-      cmd_neonserv_bind.c \
-      cmd_neonserv_chanservsync.c \
-      cmd_neonserv_clvl.c \
-      cmd_neonserv_command.c \
-      cmd_neonserv_csuspend.c \
-      cmd_neonserv_cunsuspend.c \
-      cmd_neonserv_delban.c \
-      cmd_neonserv_delme.c \
-      cmd_neonserv_deluser.c \
-      cmd_neonserv_deop.c \
-      cmd_neonserv_deopall.c \
-      cmd_neonserv_devoice.c \
-      cmd_neonserv_devoiceall.c \
-      cmd_neonserv_down.c \
-      cmd_neonserv_downall.c \
-      cmd_neonserv_emote.c \
-      cmd_neonserv_events.c \
-      cmd_neonserv_giveowner.c \
-      cmd_neonserv_god.c \
-      cmd_neonserv_help.c \
-      cmd_neonserv_invite.c \
-      cmd_neonserv_inviteme.c \
-      cmd_neonserv_kick.c \
-      cmd_neonserv_kickban.c \
-      cmd_neonserv_mdeluser.c \
-      cmd_neonserv_mode.c \
-      cmd_neonserv_move.c \
-      cmd_neonserv_myaccess.c \
-      cmd_neonserv_netinfo.c \
-      cmd_neonserv_notice.c \
-      cmd_neonserv_op.c \
-      cmd_neonserv_opall.c \
-      cmd_neonserv_oplog.c \
-      cmd_neonserv_peek.c \
-      cmd_neonserv_raw.c \
-      cmd_neonserv_recover.c \
-      cmd_neonserv_register.c \
-      cmd_neonserv_reloadlang.c \
-      cmd_neonserv_resync.c \
-      cmd_neonserv_say.c \
-      cmd_neonserv_search.c \
-      cmd_neonserv_set.c \
-      cmd_neonserv_setaccess.c \
-      cmd_neonserv_suspend.c \
-      cmd_neonserv_topic.c \
-      cmd_neonserv_trace.c \
-      cmd_neonserv_trim.c \
-      cmd_neonserv_unban.c \
-      cmd_neonserv_unbanall.c \
-      cmd_neonserv_unbanme.c \
-      cmd_neonserv_unbind.c \
-      cmd_neonserv_unregister.c \
-      cmd_neonserv_unsuspend.c \
-      cmd_neonserv_up.c \
-      cmd_neonserv_upall.c \
-      cmd_neonserv_users.c \
-      cmd_neonserv_uset.c \
-      cmd_neonserv_version.c \
-      cmd_neonserv_voice.c \
-      cmd_neonserv_voiceall.c \
-      cmd_neonserv_wipeinfo.c
-CMD_DEPS = main.h modcmd.h IRCParser.h UserNode.h ChanNode.h ChanUser.h ModeNode.h \
-           ClientSocket.h mysqlConn.h lang.h HandleInfoHandler.h WHOHandler.h DBHelper.h \
-           tools.h timeq.h version.h EventLogger.h bot_NeonServ.h IRCEvents.h BanNode.h
-OBJS = ${SRC:%.c=%.o} ${CMD:%.c=%.o}
-CFLAGS=-g -O2 -Wall -Wshadow -Werror
-LIBS=-I. -I/usr/include/mysql
-LINK=-lmysqlclient
-
-all: $(OBJS)
-
-install: $(OBJS)
-       chmod +x version.sh
-       ./version.sh
-       $(CC) $(LIBS) -c version.c $(CFLAGS)
-       $(CC) $(LIBS) -o neonserv $(OBJS) version.o $(CFLAGS) $(LINK)
-
-%.o: %.c
-       $(CC) $(LIBS) -c $< $(CFLAGS)
-
-clean:
-       rm $(OBJS) version.o
-
-depend: $(SRC)
-       mv Makefile Makefile.bak
-       grep -A1 -B10000 '^# DEPENDINGS' Makefile.bak > Makefile
-       $(CC) $(CFLAGS) -MM $(LIBS) $(SRC) >> Makefile
-       rm Makefile.bak
-
-# DEPENDINGS -- generated by make depend
-
-
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..409b9be
--- /dev/null
@@ -0,0 +1,101 @@
+AUTOMAKE_OPTIONS = foreign
+AM_CFLAGS = $(MYSQL_CFLAGS)
+
+CFLAGS = -g -O2 -Wall -Wshadow -Werror
+
+BUILT_SOURCES = version.c
+version.c: checkversion
+checkversion:
+       cd src && chmod +x version.sh && ./version.sh && cd ..
+
+bin_PROGRAMS = neonserv
+neonserv_SOURCES = src/version.c \
+      src/EventLogger.c \
+      src/IRCEvents.c \
+      src/main.c \
+      src/ChanNode.c \
+      src/IRCParser.c \
+      src/ClientSocket.c \
+      src/UserNode.c \
+      src/ChanUser.c \
+      src/ModeNode.c \
+      src/BanNode.c \
+      src/WHOHandler.c \
+      src/modcmd.c \
+      src/mysqlConn.c \
+      src/lang.c \
+      src/HandleInfoHandler.c \
+      src/tools.c \
+      src/timeq.c \
+      src/DBHelper.c \
+      src/bots.c \
+      src/bot_NeonServ.c \
+      src/cmd_neonserv_access.c \
+      src/cmd_neonserv_addban.c \
+      src/cmd_neonserv_addtimeban.c \
+      src/cmd_neonserv_adduser.c \
+      src/cmd_neonserv_ban.c \
+      src/cmd_neonserv_bans.c \
+      src/cmd_neonserv_bind.c \
+      src/cmd_neonserv_chanservsync.c \
+      src/cmd_neonserv_clvl.c \
+      src/cmd_neonserv_command.c \
+      src/cmd_neonserv_csuspend.c \
+      src/cmd_neonserv_cunsuspend.c \
+      src/cmd_neonserv_delban.c \
+      src/cmd_neonserv_delme.c \
+      src/cmd_neonserv_deluser.c \
+      src/cmd_neonserv_deop.c \
+      src/cmd_neonserv_deopall.c \
+      src/cmd_neonserv_devoice.c \
+      src/cmd_neonserv_devoiceall.c \
+      src/cmd_neonserv_down.c \
+      src/cmd_neonserv_downall.c \
+      src/cmd_neonserv_emote.c \
+      src/cmd_neonserv_events.c \
+      src/cmd_neonserv_giveowner.c \
+      src/cmd_neonserv_god.c \
+      src/cmd_neonserv_help.c \
+      src/cmd_neonserv_invite.c \
+      src/cmd_neonserv_inviteme.c \
+      src/cmd_neonserv_kick.c \
+      src/cmd_neonserv_kickban.c \
+      src/cmd_neonserv_mdeluser.c \
+      src/cmd_neonserv_mode.c \
+      src/cmd_neonserv_move.c \
+      src/cmd_neonserv_myaccess.c \
+      src/cmd_neonserv_netinfo.c \
+      src/cmd_neonserv_notice.c \
+      src/cmd_neonserv_op.c \
+      src/cmd_neonserv_opall.c \
+      src/cmd_neonserv_oplog.c \
+      src/cmd_neonserv_peek.c \
+      src/cmd_neonserv_raw.c \
+      src/cmd_neonserv_recover.c \
+      src/cmd_neonserv_register.c \
+      src/cmd_neonserv_reloadlang.c \
+      src/cmd_neonserv_resync.c \
+      src/cmd_neonserv_say.c \
+      src/cmd_neonserv_search.c \
+      src/cmd_neonserv_set.c \
+      src/cmd_neonserv_setaccess.c \
+      src/cmd_neonserv_suspend.c \
+      src/cmd_neonserv_topic.c \
+      src/cmd_neonserv_trace.c \
+      src/cmd_neonserv_trim.c \
+      src/cmd_neonserv_unban.c \
+      src/cmd_neonserv_unbanall.c \
+      src/cmd_neonserv_unbanme.c \
+      src/cmd_neonserv_unbind.c \
+      src/cmd_neonserv_unregister.c \
+      src/cmd_neonserv_unsuspend.c \
+      src/cmd_neonserv_up.c \
+      src/cmd_neonserv_upall.c \
+      src/cmd_neonserv_users.c \
+      src/cmd_neonserv_uset.c \
+      src/cmd_neonserv_version.c \
+      src/cmd_neonserv_voice.c \
+      src/cmd_neonserv_voiceall.c \
+      src/cmd_neonserv_wipeinfo.c
+
+neonserv_LDADD = $(MYSQL_LIBS)
\ No newline at end of file
diff --git a/ModeNode.c b/ModeNode.c
deleted file mode 100644 (file)
index 0afe6f2..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-#include "ModeNode.h"
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "UserNode.h"
-#include "BanNode.h"
-
-static int modes_with_strarg, modes_with_intarg, modes_count;
-
-unsigned int valid_modes[] = { /* Thats our mode list :P */
-    1,  'b', CHANNEL_MODE_TYPE_A,
-    2,  'o', CHANNEL_MODE_TYPE_A,
-    3,  'v', CHANNEL_MODE_TYPE_A,
-    4,  'k', CHANNEL_MODE_TYPE_B | CHANNEL_MODE_VALUE_STRING | CHANNEL_MODE_KEY,
-    5,  'a', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
-    6,  'l', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
-    7,  'f', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
-    8,  'F', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
-    9,  'c', CHANNEL_MODE_TYPE_D,
-    10, 'C', CHANNEL_MODE_TYPE_D,
-    11, 'i', CHANNEL_MODE_TYPE_D,
-    12, 'm', CHANNEL_MODE_TYPE_D,
-    13, 'M', CHANNEL_MODE_TYPE_D,
-    14, 'n', CHANNEL_MODE_TYPE_D,
-    15, 'N', CHANNEL_MODE_TYPE_D,
-    16, 'p', CHANNEL_MODE_TYPE_D,
-    17, 'r', CHANNEL_MODE_TYPE_D,
-    18, 's', CHANNEL_MODE_TYPE_D,
-    19, 't', CHANNEL_MODE_TYPE_D,
-    20, 'u', CHANNEL_MODE_TYPE_D,
-    21, 'D', CHANNEL_MODE_TYPE_D,
-    22, 'd', CHANNEL_MODE_TYPE_D,
-    23, 'R', CHANNEL_MODE_TYPE_D,
-    24, 'z', CHANNEL_MODE_TYPE_D,
-//  ^ maximum is 32!!!
-    0x00, 0x00, 0x00
-};
-
-void init_ModeNode() {
-    unsigned int *mode, flag = 1;
-    modes_with_strarg = 0;
-    modes_with_intarg = 0;
-    modes_count = 0;
-    for (mode = valid_modes; mode[1]; mode += 3) {
-        if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING) {
-            mode[2] |= modes_with_strarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
-            modes_with_strarg++;
-        }
-        if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER) {
-            mode[2] |= modes_with_intarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
-            modes_with_intarg++;
-        }
-        modes_count++;
-        mode[0] = flag;
-        flag = flag << 1;
-    }
-}
-
-struct ModeNode *createModeNode(struct ChanNode *chan) {
-    struct ModeNode *modes = malloc(sizeof(*modes));
-    if (!modes)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    modes->chan = chan;
-    modes->modes = 0;
-    modes->allmodes = 0;
-    modes->mode_str_args = calloc(modes_with_strarg, sizeof(char*));
-    modes->mode_int_args = calloc(modes_with_intarg, sizeof(int));
-    return modes;
-}
-
-void freeModeNode(struct ModeNode *modes) {
-    int i;
-    for(i = 0; i < modes_with_strarg; i++) {
-        if(modes->mode_str_args[i])
-            free(modes->mode_str_args[i]);
-    }
-    free(modes->mode_str_args);
-    free(modes->mode_int_args);
-    free(modes);
-}
-
-static unsigned int* getModeOptions(char mode) {
-    unsigned int *cmode;
-    for (cmode = valid_modes; cmode[1]; cmode += 3) {
-        if(cmode[1] == mode)
-            return cmode;
-    }
-    return NULL;
-}
-
-int isModeSet(struct ModeNode* modes, char modeChar) {
-    unsigned int *modeOpt = getModeOptions(modeChar);
-    return (modes->modes & modeOpt[0]);
-}
-
-int isModeAffected(struct ModeNode* modes, char modeChar) {
-    unsigned int *modeOpt = getModeOptions(modeChar);
-    return (modes->allmodes & modeOpt[0]);
-}
-
-void* getModeValue(struct ModeNode* modes, char modeChar) {
-    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
-    unsigned int *modeOpt = getModeOptions(modeChar);
-    if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING)
-        return modes->mode_str_args[MODE_VALUE_INDEX];
-    if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER)
-        return &modes->mode_int_args[MODE_VALUE_INDEX];
-    return NULL;
-    #undef MODE_VALUE_INDEX
-}
-
-unsigned int getModeType(struct ModeNode* modes, char modeChar) {
-    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
-    unsigned int *modeOpt = getModeOptions(modeChar);
-    if(!modeOpt) return 0;
-    return modeOpt[2];
-    #undef MODE_VALUE_INDEX
-}
-
-static void parseModesUserPriv(struct ModeNode* modes, unsigned char flag, int add, char *nick) {
-    if(modes->chan == NULL) return;
-    struct UserNode *user = getUserByNick(nick);
-    if(user == NULL) return;
-    struct ChanUser *chanuser = getChanUser(user, modes->chan);
-    if(chanuser == NULL) return;
-    if(add)
-        chanuser->flags |= flag;
-    else
-        chanuser->flags &= ~flag;
-}
-
-static void parseModesBan(struct ModeNode* modes, int add, char *mask) {
-    if(modes->chan == NULL) return;
-    if(add)
-        addChannelBan(modes->chan, mask);
-    else
-        removeChannelBanMask(modes->chan, mask);
-}
-
-void parseModes(struct ModeNode* modes, char *modeStr, char **argv, int argc) {
-    int i, argpos = 0, add = 1;
-    #define MODE_TYPE (modeOpt[2] & CHANNEL_MODE_TYPE)
-    #define MODE_VALUE (modeOpt[2] & CHANNEL_MODE_VALUE)
-    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
-    unsigned int *modeOpt;
-    for(i = 0; i < strlen(modeStr); i++) {
-        if(modeStr[i] == '+') {
-            add = 1;
-            continue;
-        }
-        if(modeStr[i] == '-') {
-            add = 0;
-            continue;
-        }
-        modeOpt = getModeOptions(modeStr[i]);
-        if(!modeOpt) continue; // unknown mode?
-        if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
-            if(argpos == argc) continue;
-            //special mode ;)
-            switch(modeStr[i]) {
-                case 'o':
-                    parseModesUserPriv(modes, CHANUSERFLAG_OPPED, add, argv[argpos]);
-                    break;
-                case 'v':
-                    parseModesUserPriv(modes, CHANUSERFLAG_VOICED, add, argv[argpos]);
-                    break;
-                case 'b':
-                    parseModesBan(modes, add, argv[argpos]);
-                    break;
-                default:
-                    //we have an unknown TYPE_A mode???
-                    break;
-            }
-            argpos++;
-            continue;
-        }
-        if(add) {
-            if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
-                if(argpos == argc) continue;
-                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
-                    if(modes->mode_str_args[MODE_VALUE_INDEX])
-                        free(modes->mode_str_args[MODE_VALUE_INDEX]);
-                    modes->mode_str_args[MODE_VALUE_INDEX] = strdup(argv[argpos++]);
-                } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
-                    modes->mode_int_args[MODE_VALUE_INDEX] = atoi(argv[argpos++]);
-                else
-                    argpos++; //we simply don't know what to do with the argument...
-            }
-            modes->modes |= modeOpt[0];
-            modes->allmodes |= modeOpt[0];
-        } else {
-            modes->modes &= ~modeOpt[0];
-            modes->allmodes |= modeOpt[0];
-            if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
-                if(argpos == argc) continue;
-                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
-                    free(modes->mode_str_args[MODE_VALUE_INDEX]);
-                    modes->mode_str_args[MODE_VALUE_INDEX] = NULL;
-                } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
-                    modes->mode_int_args[MODE_VALUE_INDEX] = 0;
-                argpos++; //we don't need the argument when unsetting a mode...
-            }
-        }
-    }
-    #undef MODE_TYPE
-    #undef MODE_VALUE
-    #undef MODE_VALUE_INDEX
-}
-
-void parseModeString(struct ModeNode* modes, char *modeStr) {
-    int argc = 0;
-    char *args[modes_count+1];
-    char *a, *b = modeStr;
-    do {
-        a = strstr(b, " ");
-        if(a) *a = '\0';
-        args[argc++] = b;
-        if(a) b = a+1;
-    } while(a);
-    parseModes(modes, args[0], args+1, argc-1);
-}
-
-int parseMode(struct ModeNode* modes, int add, char mode, char *param) {
-    #define MODE_TYPE (modeOpt[2] & CHANNEL_MODE_TYPE)
-    #define MODE_VALUE (modeOpt[2] & CHANNEL_MODE_VALUE)
-    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
-    unsigned int *modeOpt = getModeOptions(mode);
-    if(!modeOpt) return 0;
-    if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
-        if(!param) return 0;
-        //special mode ;)
-        switch(mode) {
-            case 'o':
-                parseModesUserPriv(modes, CHANUSERFLAG_OPPED, add, param);
-                break;
-            case 'v':
-                parseModesUserPriv(modes, CHANUSERFLAG_VOICED, add, param);
-                break;
-            case 'b':
-                parseModesBan(modes, add, param);
-                break;
-            default:
-                return 0; //we have an unknown TYPE_A mode???
-        }
-    }
-    if(add) {
-        if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
-            if(!param) return 0;
-            if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
-                if(modes->mode_str_args[MODE_VALUE_INDEX])
-                    free(modes->mode_str_args[MODE_VALUE_INDEX]);
-                modes->mode_str_args[MODE_VALUE_INDEX] = strdup(param);
-            } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
-                modes->mode_int_args[MODE_VALUE_INDEX] = atoi(param);
-        }
-        modes->modes |= modeOpt[0];
-        modes->allmodes |= modeOpt[0];
-    } else {
-        modes->modes &= ~modeOpt[0];
-        modes->allmodes |= modeOpt[0];
-        if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
-            if(!param) return 0;
-            if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
-                free(modes->mode_str_args[MODE_VALUE_INDEX]);
-                modes->mode_str_args[MODE_VALUE_INDEX] = NULL;
-            } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
-                modes->mode_int_args[MODE_VALUE_INDEX] = 0;
-        }
-    }
-    #undef MODE_TYPE
-    #undef MODE_VALUE
-    #undef MODE_VALUE_INDEX
-    return 1;
-}
-
-void getModeString(struct ModeNode* modes, char *modesStr) {
-    #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
-    #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
-    #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
-    char paramStr[MAXLEN];
-    modesStr[0] = '+';
-    unsigned int *mode;
-    int modePos = 1;
-    int paramPos = 0;
-    for (mode = valid_modes; mode[1]; mode += 3) {
-        if(modes->modes & mode[0]) {
-            modesStr[modePos++] = (char) mode[1];
-            if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
-                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
-                    paramPos += sprintf(paramStr + paramPos, " %s", modes->mode_str_args[MODE_VALUE_INDEX]);
-                else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
-                    paramPos += sprintf(paramStr + paramPos, " %d", modes->mode_int_args[MODE_VALUE_INDEX]);
-            }
-        }
-    }
-    paramStr[paramPos] = '\0';
-    strcpy(modesStr + modePos, paramStr);
-    #undef MODE_TYPE
-    #undef MODE_VALUE
-    #undef MODE_VALUE_INDEX
-}
-
-void getFullModeString(struct ModeNode* modes, char *modesStr) {
-    #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
-    #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
-    #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
-    char addMode[modes_count+1];
-    int addModePos = 0;
-    char addParams[MAXLEN];
-    addParams[0] = '\0';
-    int addParamsPos = 0;
-    char delMode[modes_count+1];
-    int delModePos = 0;
-    unsigned int *mode;
-    for (mode = valid_modes; mode[1]; mode += 3) {
-        if(modes->allmodes & mode[0]) {
-            if(modes->modes & mode[0]) {
-                addMode[addModePos++] = (char) mode[1];
-                if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
-                    if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
-                        addParamsPos += sprintf(addParams + addParamsPos, " %s", modes->mode_str_args[MODE_VALUE_INDEX]);
-                    else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
-                        addParamsPos += sprintf(addParams + addParamsPos, " %d", modes->mode_int_args[MODE_VALUE_INDEX]);
-                }
-            } else {
-                delMode[delModePos++] = (char) mode[1];
-            }
-        }
-    }
-    addMode[addModePos] = '\0';
-    delMode[delModePos] = '\0';
-    addParams[addParamsPos] = '\0';
-    sprintf(modesStr, "%s%s%s%s%s", (addModePos ? "+" : ""), addMode, (delModePos ? "-" : ""), delMode, addParams);
-    if(*modesStr == '\0') {
-        sprintf(modesStr, "+");
-    }
-    #undef MODE_TYPE
-    #undef MODE_VALUE
-    #undef MODE_VALUE_INDEX
-}
diff --git a/ModeNode.h b/ModeNode.h
deleted file mode 100644 (file)
index 6d2d5d9..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _ModeNode_h
-#define _ModeNode_h
-#include "main.h"
-
-struct ChanNode;
-
-//Types: http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
-#define CHANNEL_MODE_TYPE_A        0x01 /* ... special (addresses or users) ... */
-#define CHANNEL_MODE_TYPE_B        0x02 /* These modes always take a parameter. */
-#define CHANNEL_MODE_TYPE_C        0x03 /* These modes take a parameter only when set. */
-#define CHANNEL_MODE_TYPE_D        0x04 /* These modes never take a parameter. */
-#define CHANNEL_MODE_TYPE          0x07 /* bit mask to get the type */
-
-#define CHANNEL_MODE_VALUE_STRING  0x10
-#define CHANNEL_MODE_VALUE_INTEGER 0x20
-#define CHANNEL_MODE_VALUE         0x30 /* bit mask to get the value */
-
-#define CHANNEL_MODE_KEY           0x40 /* mode is a key - automatically add the current key as parameter on unset */
-
-#define CHANNEL_MODE_VALUE_INDEX_SHIFT 8
-#define CHANNEL_MODE_VALUE_INDEX_MASK  (0xff << CHANNEL_MODE_VALUE_INDEX_SHIFT) /* this "bitrange" is reserved for storing the array indexes of the mode values */
-
-struct ModeNode {
-    struct ChanNode *chan;
-    unsigned int modes;
-    unsigned int allmodes;
-    char **mode_str_args;
-    int *mode_int_args;
-};
-
-extern unsigned int valid_modes[];
-
-void init_ModeNode();
-struct ModeNode *createModeNode(struct ChanNode *chan);
-void freeModeNode(struct ModeNode *modes);
-int isModeSet(struct ModeNode* modes, char modeChar);
-int isModeAffected(struct ModeNode* modes, char modeChar);
-void* getModeValue(struct ModeNode* modes, char modeChar);
-unsigned int getModeType(struct ModeNode* modes, char modeChar);
-void parseModes(struct ModeNode* modes, char *modeStr, char **argv, int argc);
-void parseModeString(struct ModeNode* modes, char *modeStr);
-int parseMode(struct ModeNode* modes, int add, char mode, char *param);
-void getModeString(struct ModeNode* modes, char *modesStr);
-void getFullModeString(struct ModeNode* modes, char *modesStr);
-
-#endif
\ No newline at end of file
diff --git a/UserNode.c b/UserNode.c
deleted file mode 100644 (file)
index 2ced2eb..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-#include "UserNode.h"
-#include "ChanUser.h"
-#include "tools.h"
-
-static struct UserNode **userList;
-
-void init_UserNode() {
-    userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
-}
-
-void free_UserNode() {
-    //kamikaze free all users
-    //chanusers will be destroyed in free_ChanNode()
-    int i;
-    struct UserNode *user, *next;
-    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
-        for(user = userList[i]; user; user = next) {
-            next = user->next;
-            free(user);
-        }
-    }
-    free(userList);
-}
-
-int is_valid_nick(const char *nick) {
-    unsigned int i;
-    //first char must be one of: a-zA-Z{|}~[\]^_`
-    if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
-        return 0;
-    //all other chars must be one of: a-zA-Z0-9{|}~[\]^_`
-    for (i = 0; nick[i]; ++i)
-        if (!strchr(VALID_NICK_CHARS, nick[i]))
-            return 0;
-    if (strlen(nick) > NICKLEN)
-        return 0;
-    return 1;
-}
-
-static int get_nicklist_entry(int nick) {
-    int i;
-    char *valid_chars = VALID_NICK_CHARS_FIRST;
-    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
-        if(valid_chars[i] == nick)
-            return i;
-    }
-    return -1; //ERROR!
-}
-
-struct UserNode* getUserByNick(const char *nick) { //case sensitive
-    int userListIndex = get_nicklist_entry(*nick);
-    if(userListIndex == -1 || userList[userListIndex] == NULL)
-        return NULL;
-    struct UserNode *user;
-    for(user = userList[userListIndex]; user; user = user->next) {
-        if(!stricmp(nick, user->nick))
-            return user;
-    }
-    return NULL;
-}
-
-struct UserNode* getUserByMask(const char *mask) { //case sensitive
-    char cmask[strlen(mask)+1];
-    strcpy(cmask, mask);
-    int i;
-    struct UserNode *user = NULL;
-    for(i = 0; i < strlen(mask); i++) {
-        if(cmask[i] == '!') {
-            cmask[i] = 0;
-            user = getUserByNick(&cmask[0]);
-            return user;
-        } else if(cmask[i] == '.') {
-            //it's a server
-            return NULL;
-        }
-    }
-    return NULL;
-}
-
-struct UserNode* searchUserByNick(const char *nick) { //case insensitive
-    if(!isalpha(*nick)) 
-        return getUserByNick(nick);
-
-    int userListIndex;
-    struct UserNode *user;
-
-    //search in the lower case "section"
-    userListIndex = get_nicklist_entry(tolower(*nick));
-    if(userListIndex != -1 && userList[userListIndex] != NULL) {
-        for(user = userList[userListIndex]; user; user = user->next) {
-            if(!stricmp(nick, user->nick))
-                return user;
-        }
-    }
-    //search in the upper case "section"
-    userListIndex = get_nicklist_entry(toupper(*nick));
-    if(userListIndex != -1 && userList[userListIndex] != NULL) {
-        for(user = userList[userListIndex]; user; user = user->next) {
-            if(!stricmp(nick, user->nick))
-                return user;
-        }
-    }
-    return NULL;
-}
-
-int countUsersWithHost(char *host) {
-    int i, count = 0;
-    struct UserNode *user;
-    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
-        for(user = userList[i]; user; user = user->next) {
-            if(!strcmp(user->host, host)) {
-                count++;
-            }
-        }
-    }
-    return count;
-}
-
-char *getAuthFakehost(char *auth) {
-    int i;
-    struct UserNode *user;
-    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
-        for(user = userList[i]; user; user = user->next) {
-            if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
-                return user->host;
-            }
-        }
-    }
-    return NULL;
-}
-
-struct UserNode* getAllUsers(struct UserNode *last) {
-    if(last == NULL || last->next == NULL) {
-        int cindex;
-        if(last == NULL)
-            cindex = 0;
-        else
-            cindex = get_nicklist_entry(last->nick[0]) + 1;
-        while(userList[cindex] == NULL && cindex <= VALID_NICK_CHARS_FIRST_LEN)
-            cindex++;
-        if(cindex > VALID_NICK_CHARS_FIRST_LEN) return NULL;
-        return userList[cindex];
-    } else
-        return last->next;
-}
-
-int getUserCount() {
-    int i, count = 0;
-    struct UserNode *user;
-    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
-        for(user = userList[i]; user; user = user->next) {
-            count++;
-        }
-    }
-    return count;
-}
-
-struct UserNode* addUser(const char *nick) {
-    int userListIndex = get_nicklist_entry(*nick);
-    if(userListIndex == -1 || !is_valid_nick(nick))
-        return NULL;
-    struct UserNode *user = malloc(sizeof(*user));
-    if (!user)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    strcpy(user->nick, nick);
-    user->created = time(0);
-    user->ident[0] = 0;
-    user->host[0] = 0;
-    user->realname[0] = 0;
-    user->flags = 0;
-    user->channel = NULL;
-    user->next = userList[userListIndex];
-    userList[userListIndex] = user;
-    return user;
-}
-
-struct UserNode* addUserMask(const char *mask) {
-    char cmask[strlen(mask)+1];
-    strcpy(cmask, mask);
-    int i, ii = 0;
-    struct UserNode *user = NULL;
-    for(i = 0; i < strlen(mask)+1; i++) {
-        if(cmask[i] == '!') {
-            cmask[i] = 0;
-            user = addUser(cmask);
-            if(user == NULL) return NULL;
-            ii = i+1;
-        } else if(cmask[i] == '.' && !user) {
-            //it's a server
-            return NULL;
-        } else if(cmask[i] == '@') {
-            if(user == NULL) return NULL;
-            cmask[i] = 0;
-            strcpy(user->ident, &cmask[ii]);
-            ii = i+1;
-        } else if(cmask[i] == '\0') {
-            if(user == NULL) return NULL;
-            strcpy(user->host, &cmask[ii]);
-        }
-    }
-    return user;
-}
-
-struct UserNode* createTempUser(const char *mask) {
-    //note: it could also be a server we have to create a temponary user for...
-    char cmask[strlen(mask)+1];
-    strcpy(cmask, mask);
-    int i, ii = 0;
-    struct UserNode *user = NULL;
-    for(i = 0; i < strlen(mask)+1; i++) {
-        if(cmask[i] == '!') {
-            cmask[i] = 0;
-            user = malloc(sizeof(*user));
-            if (!user)
-            {
-                perror("malloc() failed");
-                return NULL;
-            }
-            strcpy(user->nick, cmask);
-            user->created = time(0);
-            user->ident[0] = 0;
-            user->host[0] = 0;
-            user->realname[0] = 0;
-            user->flags = 0;
-            user->channel = NULL;
-            ii = i+1;
-        } else if(cmask[i] == '.' && !user) {
-            //it's a server
-            user = malloc(sizeof(*user));
-            if (!user)
-            {
-                perror("malloc() failed");
-                return NULL;
-            }
-            strcpy(user->host, cmask);
-            user->created = time(0);
-            user->ident[0] = 0;
-            user->host[0] = 0;
-            user->realname[0] = 0;
-            user->flags = USERFLAG_ISSERVER;
-            user->channel = NULL;
-            return user;
-        } else if(cmask[i] == '@') {
-            if(user == NULL) return NULL;
-            cmask[i] = 0;
-            strcpy(user->ident, &cmask[ii]);
-            ii = i+1;
-        } else if(cmask[i] == '\0') {
-            if(user == NULL) {
-                //nick only
-                user = malloc(sizeof(*user));
-                if (!user)
-                {
-                    perror("malloc() failed");
-                    return NULL;
-                }
-                strcpy(user->nick, cmask);
-                user->created = time(0);
-                user->ident[0] = 0;
-                user->host[0] = 0;
-                user->realname[0] = 0;
-                user->flags = 0;
-                user->channel = NULL;
-                return user;
-            }
-            strcpy(user->host, &cmask[ii]);
-        }
-    }
-    return user;
-}
-
-int renameUser(struct UserNode* user, const char *new_nick) {
-    if(!is_valid_nick(new_nick))
-        return 0;
-    if(user->nick[0] == *new_nick) {
-        strcpy(user->nick, new_nick);
-        return 1;
-    }
-    int userListIndex = get_nicklist_entry(*new_nick);
-    delUser(user, 0);
-    strcpy(user->nick, new_nick);
-    user->next = userList[userListIndex];
-    userList[userListIndex] = user;
-    return 1;
-}
-
-void delUser(struct UserNode* user, int freeUser) {
-    int userListIndex = get_nicklist_entry(user->nick[0]);
-    if(userListIndex == -1) return;
-    struct UserNode *cuser, *last_user = NULL;
-    for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
-        if(cuser == user) {
-            if(last_user)
-                last_user->next = user->next;
-            else
-                userList[userListIndex] = user->next;
-            break;
-        } else
-            last_user = cuser;
-    }
-    if(user->channel) {
-        struct ChanUser *chanUser, *next;
-        for(chanUser = user->channel; chanUser; chanUser = next) {
-            next = chanUser->next_chan;
-            removeChanUserFromLists(chanUser, 1, 0, freeUser);
-        }
-    }
-    if(freeUser)
-        free(user);
-    else
-        user->next = NULL;
-}
-
-void clearTempUsers() {
-    int userListIndex = TEMPUSER_LIST_INDEX;
-    struct UserNode *cuser, *last_user = NULL, *next;
-    time_t now = time(0);
-    for(cuser = userList[userListIndex]; cuser; cuser = next) {
-        next = cuser->next;
-        if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
-            if(last_user)
-                last_user->next = cuser->next;
-            else
-                userList[userListIndex] = cuser->next;
-            break;
-        } else
-            last_user = cuser;
-    }
-}
diff --git a/UserNode.h b/UserNode.h
deleted file mode 100644 (file)
index f905437..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _UserNode_h
-#define _UserNode_h
-#include "main.h"
-
-#define USERFLAG_ISBOT              0x0001
-#define USERFLAG_ISAUTHED           0x0002
-#define USERFLAG_ISIRCOP            0x0004
-#define USERFLAG_ISTMPUSER          0x0008
-#define USERFLAG_ISSERVER           0x0010
-#define USERFLAG_FREETMPUSER        0x0020
-#define USERFLAG_LOADED_SETTINGS    0x0040
-#define USERFLAG_REPLY_PRIVMSG      0x0080
-#define USERFLAG_GOD_MODE           0x0100
-
-#define USERFLAG_SCRIPTFLAG1        0x40000000
-#define USERFLAG_SCRIPTFLAG2        0x80000000
-
-struct ChanUser;
-struct language;
-
-struct UserNode {
-    char nick[NICKLEN+1];
-    char ident[USERLEN+1];
-    char host[HOSTLEN+1];
-    char realname[REALLEN+1];
-    char auth[AUTHLEN+1];
-    unsigned int flags;
-    time_t created;
-    struct ChanUser *channel;
-    struct language *language;
-    
-    struct UserNode *next;
-};
-
-#define isNetworkService(USER) (USER->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP))
-
-void init_UserNode();
-void free_UserNode();
-int is_valid_nick(const char *nick);
-struct UserNode* getUserByNick(const char *nick);
-struct UserNode* getUserByMask(const char *mask);
-int countUsersWithHost(char *host);
-char *getAuthFakehost(char *auth);
-struct UserNode* searchUserByNick(const char *nick);
-struct UserNode* getAllUsers(struct UserNode *last);
-int getUserCount();
-struct UserNode* addUser(const char *nick);
-struct UserNode* addUserMask(const char *mask);
-struct UserNode* createTempUser(const char *mask);
-int renameUser(struct UserNode* user, const char *new_nick);
-void delUser(struct UserNode* user, int freeUser);
-void clearTempUsers();
-
-#endif
diff --git a/WHOHandler.c b/WHOHandler.c
deleted file mode 100644 (file)
index f924e46..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-
-#include "WHOHandler.h"
-#include "ChanNode.h"
-#include "UserNode.h"
-#include "ChanUser.h"
-#include "ClientSocket.h"
-
-#define WHOQUEUETYPE_ISONQUEUE 0x01
-#define WHOQUEUETYPE_USERLIST  0x02
-#define WHOQUEUETYPE_USERAUTH  0x04
-#define WHOQUEUETYPE_CHECKTYPE 0x07
-#define WHOQUEUETYPE_FOUND     0x08
-
-struct WHOQueueEntry {
-    char type;
-    struct ClientSocket *client;
-    struct ChanNode *chan;
-    struct UserNode *user;
-    struct WHOQueueEntry *next;
-    void *callback;
-    void *data;
-};
-
-static struct WHOQueueEntry *first_entry = NULL, *last_entry = NULL;
-
-static struct WHOQueueEntry* addWHOQueueEntry(struct ClientSocket *client) {
-    struct WHOQueueEntry *entry = malloc(sizeof(*entry));
-    if (!entry)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    entry->next = NULL;
-    entry->client = client;
-    if(last_entry) {
-        last_entry->next = entry;
-        last_entry = entry;
-    } else {
-        last_entry = entry;
-        first_entry = entry;
-    }
-    return entry;
-}
-
-static struct WHOQueueEntry* getNextWHOQueueEntry(struct ClientSocket *client, int freeEntry) {
-    if(!first_entry) return NULL;
-    struct WHOQueueEntry *entry;
-    for(entry = first_entry; entry; entry = entry->next) {
-        if(entry->client == client)
-            break;
-    }
-    if(entry == NULL) return NULL;
-    if(freeEntry) {
-        if(entry == first_entry)
-            first_entry = entry->next;
-        if(entry == last_entry) {
-            struct WHOQueueEntry *last;
-            for(last = first_entry; last; last = last->next)
-                if(last->next == NULL) break;
-            last_entry = last;
-        }
-    }
-    return entry;
-}
-
-void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data) {
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(isUserOnChan(bot->user, chan))
-            break;
-    }
-    if(bot == NULL) return;
-    struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
-    entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
-    entry->chan = chan;
-    entry->callback = callback;
-    entry->data = data;
-    //WHO ".$channel->getName().",".$id." d%tuhnaf,".$id
-    putsock(bot, "WHO %s,%d %%tuhnaf,%d", chan->name, entry->type, entry->type);
-}
-
-void get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t callback, void *data) {
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(isUserOnChan(bot->user, chan))
-            break;
-    }
-    if(bot == NULL) return;
-    struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
-    entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
-    entry->chan = chan;
-    entry->callback = callback;
-    entry->data = data;
-    //WHO ".$channel->getName().",".$id." d%tuhnaf,".$id
-    putsock(bot, "WHO %s,%d d%%tuhnaf,%d", chan->name, entry->type, entry->type);
-}
-
-void get_userauth(struct UserNode *user, userauth_callback_t callback, void *data) {
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->flags & SOCKET_FLAG_PREFERRED)
-            break;
-    }
-    if(bot == NULL) bot = getBots(SOCKET_FLAG_READY, NULL);
-    struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
-    entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERAUTH;
-    entry->user = user;
-    entry->callback = callback;
-    entry->data = data;
-    //WHO ".$user->getNick().",".$id." %tuhna,".$id
-    putsock(bot, "WHO %s,%d %%tuhna,%d", user->nick, entry->type, entry->type);
-}
-
-void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc) {
-    int i;
-    if(argc < 2) return;
-    int type = atoi(argv[1]);
-    if(!(type & WHOQUEUETYPE_ISONQUEUE)) return;
-    struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, 0);
-    if(entry == NULL || (entry->type & WHOQUEUETYPE_CHECKTYPE) != (type & WHOQUEUETYPE_CHECKTYPE)) return;
-    if(type & WHOQUEUETYPE_USERLIST) {
-        if(argc < 7) return;
-        //:OGN2.OnlineGamesNet.net 354 skynet 1 pk910 2001:41d0:2:1d3b::babe skynet H@ pk910
-        struct ChanNode *chan = entry->chan;
-        //add the user toe the channel if he isn't added, yet and update its user data
-        //parse flags
-        int userflags = 0;
-        int chanuserflags = 0;
-        for(i = 0; i < strlen(argv[5]); i++) {
-            switch (argv[5][i]) {
-                case '@':
-                    chanuserflags |= CHANUSERFLAG_OPPED;
-                    break;
-                case '+':
-                    chanuserflags |= CHANUSERFLAG_VOICED;
-                    break;
-                case '*':
-                    userflags |= USERFLAG_ISIRCOP;
-                    break;
-                case '<':
-                    chanuserflags |= CHANUSERFLAG_INVISIBLE;
-                    break;
-                default:
-                    break;
-            }
-        }
-        
-        struct UserNode *user;
-        if(chanuserflags & CHANUSERFLAG_INVISIBLE) {
-            user = createTempUser(argv[4]);
-            user->flags |= USERFLAG_ISTMPUSER;
-            chan->flags |= CHANFLAG_HAVE_INVISIBLES;
-            struct ChanUser *chanuser = addInvisibleChanUser(chan, user);
-            chanuser->flags = (chanuser->flags & ~CHANUSERFLAG_OPPED_OR_VOICED) | chanuserflags;
-        } else {
-            user = getUserByNick(argv[4]);
-            if(user == NULL) {
-                user = addUser(argv[4]);
-            }
-            if(!isUserOnChan(user, chan)) {
-                struct ChanUser *chanuser = addChanUser(chan, user);
-                chanuser->flags = (chanuser->flags & ~CHANUSERFLAG_OPPED_OR_VOICED) | chanuserflags;
-            }
-        }
-        user->flags = (user->flags & ~USERFLAG_ISIRCOP) | userflags;
-        if(!*user->ident)
-            strcpy(user->ident, argv[2]);
-        if(!*user->host)
-            strcpy(user->host, argv[3]);
-        if(!(user->flags & USERFLAG_ISAUTHED) && strcmp(argv[6], "0")) {
-            strcpy(user->auth, argv[6]);
-            user->flags |= USERFLAG_ISAUTHED;
-        }
-    } else if(type & WHOQUEUETYPE_USERAUTH) {
-        //:OGN2.OnlineGamesNet.net 354 Skynet 1 pk910 2001:41d0:2:1d3b::babe Skynet pk910
-        entry->type |= WHOQUEUETYPE_FOUND;
-        if(strcmp(argv[5], "0") && !(entry->user->flags & USERFLAG_ISAUTHED)) {
-            strcpy(entry->user->auth, argv[5]);
-            entry->user->flags |= USERFLAG_ISAUTHED;
-        }
-        userauth_callback_t *callback = entry->callback;
-        callback(client, entry->user->nick, entry->user, entry->data);
-    }
-}
-
-void recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc) {
-    if(argc < 2) return;
-    char *typestr = strstr(argv[1], ",") + 1;
-    int type = atoi(typestr);
-    if(!(type & WHOQUEUETYPE_ISONQUEUE)) return;
-    struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, 1);
-    if(entry == NULL || (entry->type & WHOQUEUETYPE_CHECKTYPE) != (type & WHOQUEUETYPE_CHECKTYPE)) return;
-    if(type & WHOQUEUETYPE_USERLIST) {
-        //:OGN2.OnlineGamesNet.net 315 skynet #pk910,1 :End of /WHO list.
-        entry->chan->flags |= CHANFLAG_RECEIVED_USERLIST;
-        userlist_callback_t *callback = entry->callback;
-        callback(client, entry->chan, entry->data);
-        if(entry->chan->flags & CHANFLAG_HAVE_INVISIBLES) {
-            //remove all invisible users again
-            struct ChanUser *chanuser, *next;
-            for(chanuser = getChannelUsers(entry->chan, NULL); chanuser; chanuser = next) {
-                next = getChannelUsers(entry->chan, chanuser);
-                if(chanuser->flags & CHANUSERFLAG_INVISIBLE) {
-                    delChanUser(chanuser, 1);
-                }
-            }
-        }
-    } else if(type & WHOQUEUETYPE_USERAUTH) {
-        if(!(entry->type & WHOQUEUETYPE_FOUND)) {
-            userauth_callback_t *callback = entry->callback;
-            callback(client, entry->user->nick, NULL, entry->data);
-        }
-    }
-    free(entry);
-}
-
-void free_whoqueue() {
-    struct WHOQueueEntry *entry, *next;
-    for(entry = first_entry; entry; entry = next) {
-        next = entry->next;
-        free(entry);
-    }
-    first_entry = NULL;
-    last_entry = NULL;
-}
diff --git a/WHOHandler.h b/WHOHandler.h
deleted file mode 100644 (file)
index 31485f8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _WHOHandler_h
-#define _WHOHandler_h
-
-#include "main.h"
-
-struct ClientSocket;
-struct ChanNode;
-struct UserNode;
-
-#define USERLIST_CALLBACK(NAME) void NAME(UNUSED_ARG(struct ClientSocket *client), UNUSED_ARG(struct ChanNode *chan), UNUSED_ARG(void *data))
-typedef USERLIST_CALLBACK(userlist_callback_t);
-
-#define USERAUTH_CALLBACK(NAME) void NAME(UNUSED_ARG(struct ClientSocket *client), UNUSED_ARG(char *user_nick), UNUSED_ARG(struct UserNode *user), UNUSED_ARG(void *data))
-typedef USERAUTH_CALLBACK(userauth_callback_t);
-
-void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc);
-void recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc);
-void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data);
-void get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t callback, void *data);
-void get_userauth(struct UserNode *user, userauth_callback_t callback, void *data);
-void free_whoqueue();
-
-#endif
\ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
new file mode 100644 (file)
index 0000000..01c075c
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo "Generating configure files... may take a while."
+
+autoreconf --install --force && \
+  echo "Preparing was successful if there was no error messages above." && \
+  echo "Now type:" && \
+  echo "  ./configure && make"  && \
+  echo "Run './configure --help' for more information"
diff --git a/bot_NeonServ.c b/bot_NeonServ.c
deleted file mode 100644 (file)
index 71f5942..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-
-#include "bot_NeonServ.h"
-#include "modcmd.h"
-#include "IRCEvents.h"
-#include "IRCParser.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "BanNode.h"
-#include "ModeNode.h"
-#include "ClientSocket.h"
-#include "mysqlConn.h"
-#include "lang.h"
-#include "HandleInfoHandler.h"
-#include "WHOHandler.h"
-#include "DBHelper.h"
-#include "tools.h"
-#include "timeq.h"
-#include "version.h"
-#include "EventLogger.h"
-#include "cmd_neonserv.h"
-
-#define BOTID 1
-
-static const struct default_language_entry msgtab[] = {
-    {"NS_USER_UNKNOWN", "User with nick $b%s$b does not exist."}, /* {ARGS: "TestUser"} */
-    {"NS_AUTH_UNKNOWN", "Account $b%s$b has not been registered."}, /* {ARGS: "TestAuth"} */
-    {"NS_USER_NEED_AUTH", "%s must first authenticate with $bAuthServ$b."}, /* {ARGS: "TestUser"} */
-    {"NS_YOU_NEED_AUTH", "You must first authenticate with $bAuthServ$b."},
-    {"NS_INVALID_ACCESS", "$b%d$b is an invalid access level."}, /* {ARGS: 1337} */
-    {"NS_ADDUSER_ALREADY_ADDED", "%s is already on the $b%s$b user list (with access %d)."}, /* {ARGS: "TestUser", "#TestChan", 123} */
-    {"NS_ADDUSER_DONE", "Added %s to the %s user list with access %d."}, /* {ARGS: "TestUser", "#TestChan", 123} */
-    {"NS_NOT_ON_USERLIST", "%s lacks access to $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_NOT_ON_USERLIST_YOU", "You lack access to $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_NOT_ON_CHANNEL", "%s isn't currently in $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_NOT_ON_CHANNEL_YOU", "You aren't currently in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_DELUSER_DONE", "Deleted %s (with access %d) from the %s user list."}, /* {ARGS: "TestUser", 123, "#TestChan"} */
-    {"NS_ACCESS_OUTRANKED", "You cannot give users access greater than or equal to your own."},
-    {"NS_USER_OUTRANKED", "$b%s$b outranks you (command has no effect)."}, /* {ARGS: "TestUser"} */
-    {"NS_ACCESS_DENIED", "Access denied."},
-    {"NS_NO_ACCESS", "You lack sufficient access to use this command."},
-    {"NS_USER_PROTECTED", "Sorry, $b%s$b is protected."}, /* {ARGS: "TestUser"} */
-    {"NS_SERVICE_IMMUNE", "$b%s$b may not be kicked, killed, banned, or deopped."}, /* {ARGS: "TestUser"} */
-    {"NS_TABLE_NONE", "   None"},
-    {"NS_TABLE_COUNT", "Found $b%d$b matches."}, /* {ARGS: 5} */
-    {"NS_BAN_ALREADY_ADDED", "$b%s$b is already banned in %s."}, /* {ARGS: "*!*@moeeep.*", "#TestChan"} */
-    {"NS_INVALID_ACCESS_RANGE", "Invalid access range; minimum (%d) must be lower than maximum (%d)."}, /* {ARGS: 450, 400} */
-    {"NS_CLVL_DONE", "%s now has access $b%d$b in %s."}, /* {ARGS: "TestUser", 123, "#TestChan"} */
-    {"NS_A_LACKS_ACCESS_BUT_GOD_NICK", "%s lacks access to %s but has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", "#TestChan"} */
-    {"NS_A_LACKS_ACCESS_BUT_GOD_AUTH", "%s (%s) lacks access to %s but has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", "TestUser", "#TestChan"} */
-    {"NS_A_ACCESS_NICK", "%s has access $b%d$b in %s."}, /* {ARGS: "TestAuth", 123, "#TestChan"} */
-    {"NS_A_ACCESS_AUTH", "%s (%s) has access $b%d$b in %s."}, /* {ARGS: "TestAuth", "TestUser", 123, "#TestChan"} */
-    {"NS_A_ACCESS_NICK_GOD", "%s has access $b%d$b in %s and has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", 123, "#TestChan"} */
-    {"NS_A_ACCESS_AUTH_GOD", "%s (%s) has access $b%d$b in %s and has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", "TestUser", 123, "#TestChan"} */
-    {"NS_A_SUSPENDED", "$b%s$b's access to %s has been suspended."}, /* {ARGS: "TestAuth", "#TestChan"} */
-    {"NS_A_IS_IRCOP", "%s is an $bIRC operator$b."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_USERS_HEADER", "%s users from level %d to %d:"}, /* {ARGS: "#TestChan", 1, 500} */
-    {"NS_USERS_HEADER_MATCH", "%s users from level %d to %d matching %s:"}, /* {ARGS: "#TestChan", 1, 500, "Test*"} */
-    {"NS_USERS_HEADER_ACCESS", "Access"},
-    {"NS_USERS_HEADER_ACCOUNT", "Accout"},
-    {"NS_USERS_HEADER_SEEN", "Last Seen"},
-    {"NS_USERS_HEADER_STATE", "Status"},
-    {"NS_USERS_COUNT", "There are $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
-    {"NS_USERS_COUNT_1", "There is $b%d$b user in %s."}, /* {ARGS: 1, "#TestChan"} */
-    {"NS_USERS_COUNT_MATCH", "There are $b%d$b users in %s. ($b%d$b matching your request)"}, /* {ARGS: 20, "#TestChan", 5} */
-    {"NS_USERS_COUNT_MATCH_1", "There is $b%d$b user in %s. ($b%d$b matching your request)"}, /* {ARGS: 1, "#TestChan", 1} */
-    {"NS_USERS_SEEN_HERE", "Here"},
-    {"NS_USERS_SEEN_INVISIBLE", "Here (invisible)"},
-    {"NS_USERS_SEEN_NEVER", "Never"},
-    {"NS_USERS_STATE_SUSPENDED", "Suspended"},
-    {"NS_USERS_STATE_NORMAL", "Normal"},
-    {"NS_SUSPEND_ALREADY", "$b%s$b is already suspended." }, /* {ARGS: "TestUser"} */
-    {"NS_SUSPEND_NOT", "$b%s$b is not suspended." }, /* {ARGS: "TestUser"} */
-    {"NS_SUSPEND_DONE", "$b%s$b's access to $b%s$b has been suspended." }, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_SUSPEND_RESTORED", "$b%s$b's access to $b%s$b has been restored." }, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_DELME_KEY", "To really remove yourself, you must use 'deleteme %s'."}, /* {ARGS: "abc123"} */
-    {"NS_DELME_DONE", "Your $b%d$b access has been deleted from $b%s$b."}, /* {ARGS: 123, "#TestChan"} */
-    {"NS_MYACCESS_HEADER", "Showing all channel entries for account $b%s$b:"}, /* {ARGS: "TestAuth"} */
-    {"NS_MYACCESS_HEADER_MATCH", "Showing all channel entries for account $b%s$b matching %s:"}, /* {ARGS: "TestAuth", "#Test*"} */
-    {"NS_MYACCESS_HEADER_NAME", "Name"},
-    {"NS_MYACCESS_HEADER_ACCESS", "Access"},
-    {"NS_MYACCESS_HEADER_FLAGS", "Flags"},
-    {"NS_MYACCESS_HEADER_INFO", "Info"},
-    {"NS_MYACCESS_COUNT", "%s has access in $b%d$b channel(s) and is owner of $b%d$b channel(s)."}, /* {ARGS: "TestUser", 15, 5} */
-    {"NS_MYACCESS_COUNT_MATCH", "%s has access in $b%d$b channel(s) and is owner of $b%d$b channel(s) ($b%d$b channels matching your request)."}, /* {ARGS: "TestUser", 15, 5, 7} */
-    {"NS_UP_ALREADY_OP", "You are already opped in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_UP_ALREADY_VOICE", "You are already voiced in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_DOWN_ALREADY", "You are not opped or voiced in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_MDELUSER_DONE", "Deleted $b%d$b account(s) matching $b%s$b with access from $b%d$b to $b%d$b from the %s user list."}, /* {ARGS: 10, "Test*", 1, 200, "#TestChan"} */
-    {"NS_TRIM_DURATION_TOO_SHORT", "You must include a minimum inactivity duration of at least %d seconds to trim."},
-    {"NS_TRIM_DONE", "Trimmed $b%d users$b with access from %d to %d from the %s user list who were inactive for at least %s."}, /* {ARGS: 10, 1, 100, "#TestChan", "10 days"} */
-    {"NS_GIVEOWNER_SELF", "You cannot give ownership to your own account."},
-    {"NS_GIVEOWNER_TIMEOUT", "You must wait %s before you can give ownership of $b%s$b to someone else."}, /* {ARGS: "5 hours", "#TestChan"} */
-    {"NS_GIVEOWNER_CONFIRM", "To really give ownership to $b%1$s$b, you must use 'giveownership *%1$s %2$s'."}, /* {ARGS: "TestUser", "abc123"} */
-    {"NS_GIVEOWNER_DONE", "Ownership of $b%s$b has been transferred to account $b%s$b."}, /* {ARGS: "#TestChan", "TestUser"} */
-    {"NS_OP_FAIL", "$b%s$b could not op some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_OP_DONE", "Opped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_VOICE_FAIL", "$b%s$b could not voice some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_VOICE_DONE", "Voiced users in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_DEOP_FAIL", "$b%s$b could not deop some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_DEOP_DONE", "Deopped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_DEVOICE_FAIL", "$b%s$b could not devoice some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_DEVOICE_DONE", "Devoiced users in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_OPALL_SECURITY", "$bWARNING$b: Opping all users on a channel is very insecure! If you still want do op all users on %s use: '$bopall FORCE$b [nick mask]'"},
-    {"NS_OPALL_DONE", "Opped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
-    {"NS_VOICEALL_DONE", "Voiced $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
-    {"NS_DEOPALL_DONE", "Deopped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
-    {"NS_DEVOICEALL_DONE", "Devoiced $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
-    {"NS_KICK_DONE", "Kicked $b%d$b users from %s"}, /* {ARGS: 20, "#TestChan"} */
-    {"NS_KICK_FAIL", "$b%s$b could not kick some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_KICKBAN_DONE", "KickBanned $b%d$b users from %s"}, /* {ARGS: 10, "#TestChan"} */
-    {"NS_KICKBAN_FAIL", "$b%s$b could not kickban some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_BAN_DONE", "$b%d$b masks added to the %s ban list. (matching %d users)"}, /* {ARGS: 5, "#TestChan", 15} */
-    {"NS_BAN_FAIL", "$b%s$b could not ban some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_LAME_MASK", "$b%s$b is a little too general. Try making it more specific."}, /* {ARGS: "*!*@*"} */
-    {"NS_SET_HEADER", "Channel Settings for %s:"}, /* {ARGS: "#TestChan"} */
-    {"NS_SET_ON", "on"},
-    {"NS_SET_OFF", "off"},
-    {"NS_SET_UNKNOWN_SETTING", "$b%s$b is an unknown channel setting."}, /* {ARGS: "TestSetting"} */
-    {"NS_SET_CANNOT_SET", "That setting is above your current level, so you cannot change it."},
-    {"NS_SET_BADLEVEL", "You cannot change any setting to above your level."},
-    {"NS_SET_INVALID_OPTION", "$b%d$b is not a valid choice.  Choose one:"}, /* {ARGS: 5} */
-    {"NS_SET_INVALID_BOOLEAN", "$b%s$b is an invalid binary value."}, /* {ARGS: 2} */
-    {"NS_SET_DEFAULTS_OWNER", "You must have access 500 in %s to reset it to the default options."}, /* {ARGS: "#TestChan"} */
-    {"NS_SET_DEFAULTS_CODE", "To reset %s's settings to the defaults, you must use 'set defaults %s'."}, /* {ARGS: "#TestChan", "abc123"} */
-    {"NS_SET_DEFAULTS_DONE", "All settings for %s have been reset to default values."}, /* {ARGS: "#TestChan"} */
-    {"NS_SET_TRIGGER_OWNER", "You must have access 500 in %s to change the channel trigger."}, /* {ARGS: "#TestChan"} */
-    {"NS_SET_HELP_USERINFO","(access to set the userinfo)"},
-    {"NS_SET_HELP_WIPEINFO","(access to clear the userinfo of other users)"},
-    {"NS_SET_HELP_INVITEME","(access to get invited by the bot)"},
-    {"NS_SET_HELP_ENFVOICE","(access to give voice to other users)"},
-    {"NS_SET_HELP_ENFOPS","(access to give op to their users)"},
-    {"NS_SET_HELP_GIVEOPS","(access to get op by the bot)"},
-    {"NS_SET_HELP_GIVEVOICE","(access to get voice by the bot)"},
-    {"NS_SET_HELP_KICK","(access to kick other users from the channel)"},
-    {"NS_SET_HELP_BAN","(access to ban other users from the channel)"},
-    {"NS_SET_HELP_STATICBAN","(access to add static bans to the channel banlist  e.g. +addban)"},
-    {"NS_SET_HELP_PUBCMD","(access to do public commands in the channel  e.g. +users)"},
-    {"NS_SET_HELP_ENFMODES","(access to override the modelock)"},
-    {"NS_SET_HELP_ENFTOPIC","(access to override the topicmask)"},
-    {"NS_SET_HELP_TOPICSNARF","(access to set the default topic by changing the topic with /TOPIC)"},
-    {"NS_SET_HELP_CHANGETOPIC","(access to change the topic)"},
-    {"NS_SET_HELP_SETTERS","(access to change this settings)"},
-    {"NS_SET_HELP_ADDUSER","(access to add an user to the userlist)"},
-    {"NS_SET_HELP_DELUSER","(access to delete an user from the userlist)"},
-    {"NS_SET_HELP_CLVL","(access to change the access of an user in the userlist)"},
-    {"NS_SET_HELP_RESYNC","(access to synchronize the channelrights (@,+) with the userlist)"},
-    {"NS_SET_HELP_SUSPEND","(access to suspend an user on the userlist)"},
-    {"NS_SET_OPTION_CTCPREACTION_0","Kick on disallowed CTCPs"},
-    {"NS_SET_OPTION_CTCPREACTION_1","Kickban on disallowed CTCPs"},
-    {"NS_SET_OPTION_CTCPREACTION_2","Short timed ban on disallowed CTCPs"},
-    {"NS_SET_OPTION_CTCPREACTION_3","Long timed ban on disallowed CTCPs"},
-    {"NS_SET_OPTION_NOTICEREACTION_0","Kick on disallowed NOTICEs"},
-    {"NS_SET_OPTION_NOTICEREACTION_1","Kickban on disallowed NOTICEs"},
-    {"NS_SET_OPTION_NOTICEREACTION_2","Short timed ban on disallowed NOTICEs"},
-    {"NS_SET_OPTION_NOTICEREACTION_3","Long timed ban on disallowed NOTICEs"},
-    {"NS_SET_OPTION_PROTECT_0","All users will be protected from users with equal or lower access."},
-    {"NS_SET_OPTION_PROTECT_1","All users with access will be protected from users with equal or lower access."},
-    {"NS_SET_OPTION_PROTECT_2","All users with access will be protected from user with lower access."},
-    {"NS_SET_OPTION_PROTECT_3","Nobody will be protected."},
-    {"NS_SET_OPTION_TOYS_0","Funcommands can't be used."},
-    {"NS_SET_OPTION_TOYS_1","Funcommands are possible but the reply will be sent as a notice."},
-    {"NS_SET_OPTION_TOYS_2","Funcommands are possible and the reply will be sent to the channel."},
-    {"NS_SET_OPTION_DYNLIMIT_0","off"},
-    {"NS_SET_OPTION_NODELETE_0","off  (only bot masters)"},
-    {"NS_SET_OPTION_NODELETE_1","on  (only bot masters)"},
-    {"NS_WIPEINFO_DONE", "Removed $b%s$b's infoline in $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_TRACE_HEADER", "The following users were found:"},
-    {"NS_ADDBAN_DONE", "$b%s$b permantly added to the %s ban list. (matching %d users)"}, /* {ARGS: "*!*@Test.*", "#TestChan", 4} */
-    {"NS_BANS_HEADER_MASK", "Mask"},
-    {"NS_BANS_HEADER_SETBY", "Set By"},
-    {"NS_BANS_HEADER_TRIGGERED", "Triggered"},
-    {"NS_BANS_HEADER_EXPIRES", "Expires"},
-    {"NS_BANS_HEADER_REASON", "Reason"},
-    {"NS_DELBAN_BANNED_BY", "%s is banned by %s."}, /* {ARGS: "*!*@bla*", "*!*@b*"} */
-    {"NS_DELBAN_FAIL", "Sorry, no ban found for $b%s$b."}, /* {ARGS: "*!*@bla*"} */
-    {"NS_DELBAN_DONE", "Removed $b%s$b from the %s ban list."}, /* {ARGS: "*!*@bla.*", "#TestChan"} */
-    {"NS_NETINFO_HEADER", "$bNetwork information$b"},
-    {"NS_NETINFO_BOTS", "Bots:"},
-    {"NS_NETINFO_UPTIME", "Uptime:"},
-    {"NS_NETINFO_TRAFFIC", "Traffic:"},
-    {"NS_NETINFO_CACHE", "Cache:"},
-    {"NS_NETINFO_DATABASE", "Database:"},
-    {"NS_NETINFO_CHANNEL", "  Channel:"},
-    {"NS_NETINFO_CHANNEL_BAN", "    Bans:"},
-    {"NS_NETINFO_USER", "  User:"},
-    {"NS_NETINFO_CHANUSER", "  Channel-User:"},
-    {"NS_NETINFO_OTHER", "  Other:"},
-    {"NS_NETINFO_VERSION", "Version:"},
-    {"NS_NETINFO_CODE", "Code:"},
-    {"NS_NETINFO_CODE_VALUE", "%s lines c code (view it at http://git.pk910.de/?p=NeonServV5.git;a=summary)"}, /* {ARGS: 20} */
-    {"NS_NETINFO_COMPILER", "Compiler:"},
-    {"NS_NETINFO_COMPILER_VALUE", "%s  (%s)"}, /* {ARGS: "GCC 4.4.5", "Sun Sep 18 2011 at 05:21:33 CEST"} */
-    {"NS_EXTTOPIC_INVALID_ID", "ADVANCEDTOPIC is enabled and $b%s$b is an invalid TOPIC ID. Valid topic id's are: 1-9"}, /* {ARGS: 10} */
-    {"NS_EXTTOPIC_TOPICID", "Topic %d: %s"}, /* {ARGS: 5, "topic"} */
-    {"NS_TOPIC_DONE", "Topic is now '%s'."}, /* {ARGS: "i like you :D"} */
-    {"NS_CHANSERVSYNC_UNSUPPORTED", "\0034WARNING\003: the user list style of %s is not known. %s can try to synchronize the userlist, but there is no guarantee that it is successful!"}, /* {ARGS: "CowBot"} */
-    {"NS_CHANSERVSYNC_KEY", "If you really want to synchronize the %s userlist with %s use: chanservsync %s %s"}, /* {ARGS: "#TestChan", "CowBot", "CowBot", "abc123"} */
-    {"NS_CHANSERVSYNC_INUSE", "$bchanservsync$b is already in use by someone else. Please try again in a few seconds..."},
-    {"NS_CHANSERVSYNC_SYNCHRONIZING", "Synchronizing userlist in %s with $b%s$b..."}, /* {ARGS: "#TestChan", "CowBot"} */
-    {"NS_CHANSERVSYNC_SYNCHRONIZED", "Synchronized user $b%s$b: access $b%d$b"}, /* {ARGS: "TestUser", 123} */
-    {"NS_REGISTER_ALREADY", "%s is already registered with %s."}, /* {ARGS: "#TestChan", "NeonServ"} */
-    {"NS_INVALID_CHANNEL_NAME", "%s is not a valid channel name."}, /* {ARGS: "#invalid"} */
-    {"NS_REGISTER_FULL", "the bot can not join more channels."},
-    {"NS_REGISTER_DISCONNECTED", "%s has been registered with a Bot, that is currently NOT connected. The Bot should join the channel, when it reconnects to the IRC-Network."}, /* {ARGS: "#TestChan"} */
-    {"NS_REGISTER_DONE", "$b%s$b is now registered to $b%s$b."}, /* {ARGS: "#TestChan", "TestUser"} */
-    {"NS_UNREGISTER_NOT_REGISTERED", "$b%s$b is not registered with %s."}, /* {ARGS: "#TestChan", "NeonServ"} */
-    {"NS_UNREGISTER_DONE", "$b%s$b unregistered."}, /* {ARGS: "#TestChan"} */
-    {"NS_RECOVER_DONE", "$b%s$b has been recovered."}, /* {ARGS: "#TestChan"} */
-    {"NS_RESYNC_DONE", "Synchronized users in $b%s$b with the userlist."}, /* {ARGS: "#TestChan"} */
-    {"NS_TIMEBAN_DURATION_TOO_SHORT", "You must specify a ban duration of at least %d seconds."}, /* {ARGS: 30} */
-    {"NS_TIMEBAN_DONE", "Banned $b%s$b from %s for %s. (matching %d users)"}, /* {ARGS: "*!*@bla*", "#TestChan", "2 hours", 5} */
-    {"NS_MODE_INVALID", "$b%c$b is an invalid set of channel modes."}, /* {ARGS: "+xyz"} */
-    {"NS_MODE_LOCKED", "Modes conflicting with $b%s$b are not allowed in %s."}, /* {ARGS: "+xyz", "#TestChan"} */
-    {"NS_MODE_DONE", "Channel modes are now $b%s$b."}, /* {ARGS: "+xyz"} */
-    {"NS_MODE_ENFOPS", "You may not op or deop users on $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_MODE_ENFVOICE", "You may not voice or devoice users on $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_MODE_CANBAN", "You may not ban or unban users on $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_GOD_ON", "Security override has been enabled."},
-    {"NS_GOD_OFF", "Security override has been disabled."},
-    {"NS_PEEK_HEADER", "$b%s$b Status:"}, /* {ARGS: "#TestChan"} */
-    {"NS_PEEK_TOPIC", "Topic:       %s"}, /* {ARGS: "TOPIC"} */
-    {"NS_PEEK_MODES", "Modes:       %s"}, /* {ARGS: "+xyz"} */
-    {"NS_PEEK_USERS", "Total Users: %d (%d ops, %d voices, %d regulars, %d invisible)"}, /* {ARGS: 20, 4, 6, 8, 2} */
-    {"NS_PEEK_OPS", "Ops:"},
-    {"NS_USET_GLOBAL", "$b--- Global ---$b"},
-    {"NS_USET_CHANNEL", "$b--- User options (channel) ---$b"},
-    {"NS_USET_NO_ACCESS", "no access"},
-    {"NS_USET_UNKNOWN_SETTING", "$b%s$b is an unknown uset setting."}, /* {ARGS: "TestSetting"} */
-    {"NS_RELOADLANG_UNKNOWN", "$b%s$b is an unknown language tag."}, /* {ARGS: "de"} */
-    {"NS_RELOADLANG_DONE", "$b%s$b (%s) reloaded."}, /* {ARGS: "Deutsch", "de"} */
-    {"NS_UNBAN_DONE", "$b%d$b masks removed from the %s ban list."}, /* {ARGS: 5, "#TestChan"} */
-    {"NS_UNBAN_FAIL", "$b%s$b could not unban some of the masks you provided."}, /* {ARGS: "NeonServ"} */
-    {"NS_UNBANALL_DONE", "all $b%d$b masks removed from the %s ban list."}, /* {ARGS: 5, "#TestChan"} */
-    {"NS_UNBANALL_FAIL", "$b%s$b could not find any bans in %s."}, /* {ARGS: "NeonServ", "#TestChan"} */
-    {"NS_UNBANME_DONE", "removed $b%d$b masks from the %s ban list."}, /* {ARGS: 5, "#TestChan"} */
-    {"NS_UNBANME_FAIL", "$b%s$b could not find any bans matching %s."}, /* {ARGS: "NeonServ", "TestUser!TestIdent@TestUser.user.WebGamesNet"} */
-    {"NS_INVITE_RESTRICTION", "%s doesn't want to be invited to %s."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_INVITE_TIMEOUT", "%s has already been invited to $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_INVITE_ON_CHAN", "%s is already in $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_INVITE_DONE_USER", "You have been invited to join $b%s$b by %s. (Do $b/msg %s %1$s uset noinvite 1$b if you don't want to be invited to %1$s anymore.)"}, /* {ARGS: "#TestChan", "TestUser", "NeonServ"} */
-    {"NS_INVITE_DONE", "Invited $b%s$b to join %s."}, /* {ARGS: "TestUser", "#TestChan"} */
-    {"NS_INVITEME_ON_CHAN", "You are already in $b%s$b."}, /* {ARGS: "#TestChan"} */
-    {"NS_INVITEME_DONE", "You have been invited to join %s."}, /* {ARGS: "#TestChan"} */
-    {"NS_HELP_TOPIC", "No help on that topic."},
-    {"NS_CSUSPEND_ALREADY", "$b%s$b is already suspended."}, /* {ARGS: "#TestChan"} */
-    {"NS_CSUSPEND_DONE", "Channel $b%s$b has been temporarily suspended."}, /* {ARGS: "#TestChan"} */
-    {"NS_CUNSUSPEND_NOT", "$b%s$b is not suspended."}, /* {ARGS: "#TestChan"} */
-    {"NS_CUNSUSPEND_DONE", "Channel $b%s$b has been restored."}, /* {ARGS: "#TestChan"} */
-    {"NS_MOVE_SUSPENDED", "Moving cannot be performed if the source channel is suspended."},
-    {"NS_MOVE_SELF", "Moving cannot be performed if the source and target channels are the same."},
-    {"NS_MOVE_DONE", "Channel $b%s$b has been moved to $b%s$b."}, /* {ARGS: "#TestChan", "#NewTestChan"} */
-    {"NS_BIND_ALREADY", "$b%s$b is already bound to %s."}, /* {ARGS: "TestCommand", "TestFunction"} */
-    {"NS_BIND_UNKNOWN", "$b%s$b is an undefined function."}, /* {ARGS: "TestFunction"} */
-    {"NS_BIND_DONE", "New command $b%s$b bound to %s."}, /* {ARGS: "TestCommand", "TestFunction"} */
-    {"NS_UNBIND_NOT_FOUND", "There is no command called $b%s$b bound."}, /* {ARGS: "TestCommand"} */
-    {"NS_UNBIND_DONE", "Unbound command $b%s$b."}, /* {ARGS: "TestCommand"} */
-    {"NS_EVENTS_HEADER", "The following channel events were found:"},
-    {"NS_OPLOG_HEADER", "The following oper events were found:"},
-    {"NS_SEARCH_HEADER", "The following channels were found:"},
-    {"NS_COMMAND_BINDING", "$b%s$b is a binding of %s %s"}, /* {ARGS: "TestCommand", "TestFunction", "TestParameters"} */
-    {"NS_COMMAND_ACCESS", "You need at least %d channel access and %d oper access to execute this command."}, /* {ARGS: 500, 100} */
-    {"NS_TOPIC_ACCESS", "You lack sufficient access in %s to change the topic."}, /* {ARGS: "#TestChan"} */
-    {"NS_BOTWAR_DETECTED", "$b$k4BOTWAR DETECTED!$k Please check the channel configuration!$b"},
-    {"NS_BOTWAR_REPORTED", "A supporter has been informed to help you preventing botwars in the future."},
-    {"NS_BOTWAR_ALERT", "$b$k4BOTWAR ALERT:$k$b Botwar in $b%s$b detected. (opponent: $b%s$b) Please join and help them preventing Botwars."}, /* {ARGS: "#TestChan", "OtherBot"} */
-    {"NS_INVITE_FAIL", "$b%s$b is not registered with %s or suspended."}, /* {ARGS: "#TestChan", "NeonServ"} */
-    {"NS_SETACCESS_DONE", "$b%s$b has now %d global access."},
-    {NULL, NULL}
-};
-
-/* TODO: 
-trim bans
-cmd_neonserv_open.c
-cmd_neonserv_info.c
-parse, check and set modelock
-cmd_neonserv_modcmd.c
-cmd_neonserv_allowregister.c
-cmd_neonserv_noregister.c
-cmd_neonserv_expire.c
-cmd_neonserv_unvisited.c
-cmd_neonserv_merge.c
-cmd_neonserv_dnrsearch.c
-cmd_neonserv_rename.c
-cmd_neonserv_iplocate.c
-cmd_neonserv_calc.c
-*/
-//EVENTS
-#include "event_neonserv_join.c"
-#include "event_neonserv_part.c"
-#include "event_neonserv_quit.c"
-//#include "event_neonserv_kick.c"
-//#include "event_neonserv_mode.c"
-#include "event_neonserv_ctcp.c"
-#include "event_neonserv_notice.c"
-#include "event_neonserv_invite.c"
-#include "event_neonserv_topic.c"
-
-struct ClientSocket *getBotForChannel(struct ChanNode *chan) {
-    struct ClientSocket *bot, *use_bot = NULL, *second_bot = NULL, *third_bot = NULL;
-    struct ChanUser *chanuser;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->botid != BOTID) continue;
-        if((chanuser = getChanUser(bot->user, chan)) != NULL) {
-            if((chanuser->flags & CHANUSERFLAG_OPPED)) {
-                use_bot = bot;
-                if(bot->flags & SOCKET_FLAG_PREFERRED) break;
-            } else if(bot->flags & SOCKET_FLAG_PREFERRED)
-                second_bot = bot;
-            else
-                third_bot = bot;
-        }
-    }
-    if(!use_bot) use_bot = second_bot;
-    if(!use_bot) use_bot = third_bot;
-    return use_bot;
-}
-
-static void neonserv_bot_ready(struct ClientSocket *client) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    
-    printf_mysql_query("SELECT `automodes` FROM `bots` WHERE `id` = '%d'", client->clientid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        putsock(client, "MODE %s +%s", client->user->nick, row[0]);
-    }
-    
-    printf_mysql_query("SELECT `channel_name`, `channel_key` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `botid` = '%d' AND `suspended` = '0'", client->clientid);
-    res = mysql_use();
-    
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        putsock(client, "JOIN %s %s", row[0], row[1]);
-    }
-}
-
-static void neonserv_trigger_callback(struct ChanNode *chan, char *trigger) {
-    strcpy(trigger, "+");
-}
-
-static void start_bots() {
-    struct UserNode *user;
-    struct ClientSocket *client;
-    MYSQL_RES *res, *res2;
-    MYSQL_ROW row;
-    
-    printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
-    res = mysql_use();
-    
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        
-        user = addUser(row[0]);
-        strcpy(user->ident, row[1]);
-        strcpy(user->realname, row[2]);
-        user->flags |= USERFLAG_ISBOT;
-        client = create_socket(row[3], atoi(row[4]), row[5], user);
-        client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
-        client->botid = BOTID;
-        client->clientid = atoi(row[7]);
-        connect_socket(client);
-        printf_mysql_query("SELECT `command`, `function`, `parameters`, `global_access`, `chan_access` FROM `bot_binds` WHERE `botclass` = '%d'", client->botid);
-        res2 = mysql_use();
-        while ((row = mysql_fetch_row(res2)) != NULL) {
-            if(bind_cmd_to_command(BOTID, row[0], row[1])) {
-                if(row[2] && strcmp(row[2], "")) {
-                    bind_set_parameters(BOTID, row[0], row[2]);
-                }
-                if(row[3]) {
-                    bind_set_global_access(BOTID, row[0], atoi(row[3]));
-                }
-                if(row[4]) {
-                    bind_set_channel_access(BOTID, row[0], row[4]);
-                }
-            }
-        }
-    }
-    
-    //load all timed bans
-    printf_mysql_query("SELECT `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_timeout` > 0");
-    res = mysql_use();
-    char nameBuf[20];
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(atol(row[1]) - time(0) > 0) {
-            sprintf(nameBuf, "ban_%s", row[0]);
-            timeq_add_name(nameBuf, atol(row[1]) - time(0), channel_ban_timeout, strdup(row[0]));
-        } else {
-            //timed out
-            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[0]);
-        }
-    }
-}
-
-TIMEQ_CALLBACK(channel_ban_timeout) {
-    char *str_banid = data;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `ban_mask`, `channel_name` FROM `bans` LEFT JOIN `channels` ON `ban_channel` = `channel_id` WHERE `ban_id` = '%s'", str_banid);
-    res = mysql_use();
-    struct ChanNode *chan;
-    if((row = mysql_fetch_row(res)) != NULL && (chan = getChanByName(row[1])) != NULL) {
-        struct ClientSocket *use_bot = getBotForChannel(chan);
-        if(use_bot) {
-            putsock(use_bot, "MODE %s -b %s", chan->name, row[0]);
-        }
-        printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", str_banid);
-    }
-    free(str_banid);
-}
-
-void init_NeonServ() {
-    
-    #define USER_COMMAND(NAME,FUNCTION,PARAMCOUNT,PRIVS,FLAGS) register_command(BOTID, NAME, FUNCTION, PARAMCOUNT, PRIVS, 0, FLAGS)
-    //               NAME              FUNCTION        PARAMS     PRIVS                FLAGS
-    USER_COMMAND("adduser",      neonserv_cmd_adduser,   2, "#channel_canadd",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("deluser",      neonserv_cmd_deluser,   1, "#channel_candel",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("clvl",         neonserv_cmd_clvl,      2, "#channel_canclvl",     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("access",       neonserv_cmd_access,    0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_LOG);
-    USER_COMMAND("users",        neonserv_cmd_users,     0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
-    USER_COMMAND("suspend",      neonserv_cmd_suspend,   1, "#channel_cansuspend",  CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("unsuspend",    neonserv_cmd_unsuspend, 1, "#channel_cansuspend",  CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("delme",        neonserv_cmd_delme,     0,  "1",                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("myaccess",     neonserv_cmd_myaccess,  0, NULL,                   CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
-    USER_COMMAND("up",           neonserv_cmd_up,        0, "#channel_getop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("down",         neonserv_cmd_down,      0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_LOG);
-    USER_COMMAND("upall",        neonserv_cmd_upall,     0, NULL,                   CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("downall",      neonserv_cmd_downall,   0, NULL,                   CMDFLAG_LOG);
-    USER_COMMAND("mdeluser",     neonserv_cmd_mdeluser,  2, "#channel_candel",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("trim",         neonserv_cmd_trim,      2, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("giveowner",    neonserv_cmd_giveowner, 1, "500",                  CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("op",           neonserv_cmd_op,        1, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("deop",         neonserv_cmd_deop,      1, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("voice",        neonserv_cmd_voice,     1, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("devoice",      neonserv_cmd_devoice,   1, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("opall",        neonserv_cmd_opall,     0, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("deopall",      neonserv_cmd_deopall,   0, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("voiceall",     neonserv_cmd_voiceall,  0, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("devoiceall",   neonserv_cmd_devoiceall,0, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("set",          neonserv_cmd_set,       0, "#channel_setters",     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("kick",         neonserv_cmd_kick,      1, "#channel_cankick",     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("kickban",      neonserv_cmd_kickban,   1, "#channel_cankick,#channel_canban", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("ban",          neonserv_cmd_ban,       1, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("wipeinfo",     neonserv_cmd_wipeinfo,  1, "#channel_wipeinfo",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("addban",       neonserv_cmd_addban,    1, "#channel_staticban",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("bans",         neonserv_cmd_bans,      0, "1",                    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
-    USER_COMMAND("delban",       neonserv_cmd_delban,    1, "#channel_staticban",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("netinfo",      neonserv_cmd_netinfo,   0, NULL,                   0);
-    USER_COMMAND("topic",        neonserv_cmd_topic,     0, "#channel_changetopic", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("chanservsync", neonserv_cmd_chanservsync, 0,"500",                CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("resync",       neonserv_cmd_resync,    0, "#channel_canresync",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("addtimeban",   neonserv_cmd_addtimeban,2, "#channel_staticban",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("mode",         neonserv_cmd_mode,      1, "#channel_getop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("version",      neonserv_cmd_version,   0, NULL,                   0);
-    USER_COMMAND("peek",         neonserv_cmd_peek,      0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
-    USER_COMMAND("uset",         neonserv_cmd_uset,      0, NULL,                   CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
-    USER_COMMAND("unban",        neonserv_cmd_unban,     1, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("unbanall",     neonserv_cmd_unbanall,  0, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("unbanme",      neonserv_cmd_unbanme,   0, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("invite",       neonserv_cmd_invite,    1, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("inviteme",     neonserv_cmd_inviteme,  0, "#channel_getinvite",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
-    USER_COMMAND("help",         neonserv_cmd_help,      0, NULL,                   0);
-    USER_COMMAND("events",       neonserv_cmd_events,    0, "1",                    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
-    USER_COMMAND("command",      neonserv_cmd_command,   1, NULL,                   0);
-    #undef USER_COMMAND
-    
-    #define OPER_COMMAND(NAME,FUNCTION,PARAMCOUNT,GACCESS,FLAGS) register_command(BOTID, NAME, FUNCTION, PARAMCOUNT, NULL, GACCESS, FLAGS)
-    //            NAME            FUNCTION              PARAMS  ACCS  FLAGS
-    OPER_COMMAND("trace",        neonserv_cmd_trace,     1,     400,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
-    OPER_COMMAND("register",     neonserv_cmd_register,  2,     200,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("unregister",   neonserv_cmd_unregister,1,     200,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("recover",      neonserv_cmd_recover,   1,     200,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("say",          neonserv_cmd_say,       2,     600,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("emote",        neonserv_cmd_emote,     2,     600,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("notice",       neonserv_cmd_notice,    2,     600,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("raw",          neonserv_cmd_raw,       1,     800,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
-    OPER_COMMAND("god",          neonserv_cmd_god,       0,     1,    CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
-    OPER_COMMAND("reloadlang",   neonserv_cmd_reloadlang,1,     500,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
-    OPER_COMMAND("csuspend",     neonserv_cmd_csuspend,  1,     100,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("cunsuspend",   neonserv_cmd_cunsuspend,1,     100,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("move",         neonserv_cmd_move,      2,     300,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
-    OPER_COMMAND("bind",         neonserv_cmd_bind,      2,     900,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
-    OPER_COMMAND("unbind",       neonserv_cmd_unbind,    1,     900,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
-    OPER_COMMAND("oplog",        neonserv_cmd_oplog,     0,     1,    CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
-    OPER_COMMAND("search",       neonserv_cmd_search,    1,     400,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
-    OPER_COMMAND("setaccess",    neonserv_cmd_setaccess, 2,     1000, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
-    #undef OPER_COMMAND
-    
-    start_bots();
-    
-    //register events
-    bind_bot_ready(neonserv_bot_ready);
-    bind_join(neonserv_event_join);
-    bind_part(neonserv_event_part);
-    bind_quit(neonserv_event_quit);
-    bind_chanctcp(neonserv_event_chanctcp);
-    bind_privctcp(neonserv_event_privctcp);
-    bind_channotice(neonserv_event_channotice);
-    bind_topic(neonserv_event_topic);
-    bind_invite(neonserv_event_invite);
-    
-    set_trigger_callback(BOTID, neonserv_trigger_callback);
-    
-    register_default_language_table(msgtab);
-}
-
-void loop_NeonServ() {
-    
-}
-
-void free_NeonServ() {
-    
-}
-
-#undef BOTID
diff --git a/bot_NeonServ.h b/bot_NeonServ.h
deleted file mode 100644 (file)
index 90bd696..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _bot_NeonServ_h
-#define _bot_NeonServ_h
-
-#include "main.h"
-#include "timeq.h"
-
-struct ChanNode;
-
-void init_NeonServ();
-void loop_NeonServ();
-void free_NeonServ();
-
-TIMEQ_CALLBACK(channel_ban_timeout);
-struct ClientSocket *getBotForChannel(struct ChanNode *chan);
-
-#endif
\ No newline at end of file
diff --git a/bots.c b/bots.c
deleted file mode 100644 (file)
index b957a19..0000000
--- a/bots.c
+++ /dev/null
@@ -1,16 +0,0 @@
-
-#include "bots.h"
-
-#include "bot_NeonServ.h"
-
-void init_bots() {
-    init_NeonServ();
-}
-
-void loop_bots() {
-    loop_NeonServ();
-}
-
-void free_bots() {
-    free_NeonServ();
-}
diff --git a/bots.h b/bots.h
deleted file mode 100644 (file)
index a24b158..0000000
--- a/bots.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _bots_h
-#define _bots_h
-
-#include "main.h"
-
-void init_bots();
-void loop_bots();
-void free_bots();
-
-#endif
\ No newline at end of file
diff --git a/cmd_neonserv.h b/cmd_neonserv.h
deleted file mode 100644 (file)
index 6b8fee1..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef _cmd_neonserv_h
-#define _cmd_neonserv_h
-#include "main.h"
-#include "modcmd.h"
-#include "IRCParser.h"
-#include "IRCEvents.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "ModeNode.h"
-#include "BanNode.h"
-#include "ClientSocket.h"
-#include "mysqlConn.h"
-#include "lang.h"
-#include "HandleInfoHandler.h"
-#include "WHOHandler.h"
-#include "DBHelper.h"
-#include "tools.h"
-#include "timeq.h"
-#include "version.h"
-#include "EventLogger.h"
-#include "bot_NeonServ.h"
-
-CMD_BIND(neonserv_cmd_access);
-CMD_BIND(neonserv_cmd_addban);
-CMD_BIND(neonserv_cmd_addtimeban);
-CMD_BIND(neonserv_cmd_adduser);
-CMD_BIND(neonserv_cmd_ban);
-CMD_BIND(neonserv_cmd_bans);
-CMD_BIND(neonserv_cmd_bind);
-CMD_BIND(neonserv_cmd_chanservsync);
-CMD_BIND(neonserv_cmd_clvl);
-CMD_BIND(neonserv_cmd_command);
-CMD_BIND(neonserv_cmd_csuspend);
-CMD_BIND(neonserv_cmd_cunsuspend);
-CMD_BIND(neonserv_cmd_delban);
-CMD_BIND(neonserv_cmd_delme);
-CMD_BIND(neonserv_cmd_deluser);
-CMD_BIND(neonserv_cmd_deop);
-CMD_BIND(neonserv_cmd_deopall);
-CMD_BIND(neonserv_cmd_devoice);
-CMD_BIND(neonserv_cmd_devoiceall);
-CMD_BIND(neonserv_cmd_down);
-CMD_BIND(neonserv_cmd_downall);
-CMD_BIND(neonserv_cmd_emote);
-CMD_BIND(neonserv_cmd_events);
-CMD_BIND(neonserv_cmd_giveowner);
-CMD_BIND(neonserv_cmd_god);
-CMD_BIND(neonserv_cmd_help);
-CMD_BIND(neonserv_cmd_invite);
-CMD_BIND(neonserv_cmd_inviteme);
-CMD_BIND(neonserv_cmd_kick);
-CMD_BIND(neonserv_cmd_kickban);
-CMD_BIND(neonserv_cmd_mdeluser);
-CMD_BIND(neonserv_cmd_mode);
-CMD_BIND(neonserv_cmd_move);
-CMD_BIND(neonserv_cmd_myaccess);
-CMD_BIND(neonserv_cmd_netinfo);
-CMD_BIND(neonserv_cmd_notice);
-CMD_BIND(neonserv_cmd_op);
-CMD_BIND(neonserv_cmd_opall);
-CMD_BIND(neonserv_cmd_oplog);
-CMD_BIND(neonserv_cmd_peek);
-CMD_BIND(neonserv_cmd_raw);
-CMD_BIND(neonserv_cmd_recover);
-CMD_BIND(neonserv_cmd_register);
-CMD_BIND(neonserv_cmd_reloadlang);
-CMD_BIND(neonserv_cmd_resync);
-CMD_BIND(neonserv_cmd_say);
-CMD_BIND(neonserv_cmd_search);
-CMD_BIND(neonserv_cmd_set);
-CMD_BIND(neonserv_cmd_setaccess);
-CMD_BIND(neonserv_cmd_suspend);
-CMD_BIND(neonserv_cmd_topic);
-CMD_BIND(neonserv_cmd_trace);
-CMD_BIND(neonserv_cmd_trim);
-CMD_BIND(neonserv_cmd_unban);
-CMD_BIND(neonserv_cmd_unbanall);
-CMD_BIND(neonserv_cmd_unbanme);
-CMD_BIND(neonserv_cmd_unbind);
-CMD_BIND(neonserv_cmd_unregister);
-CMD_BIND(neonserv_cmd_unsuspend);
-CMD_BIND(neonserv_cmd_up);
-CMD_BIND(neonserv_cmd_upall);
-CMD_BIND(neonserv_cmd_users);
-CMD_BIND(neonserv_cmd_uset);
-CMD_BIND(neonserv_cmd_version);
-CMD_BIND(neonserv_cmd_voice);
-CMD_BIND(neonserv_cmd_voiceall);
-CMD_BIND(neonserv_cmd_wipeinfo);
-
-#endif
\ No newline at end of file
diff --git a/cmd_neonserv_access.c b/cmd_neonserv_access.c
deleted file mode 100644 (file)
index aa11b00..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_access_nick_lookup);
-static void neonserv_cmd_access_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, struct UserNode *target);
-
-struct neonserv_cmd_access_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    char *nick;
-};
-
-CMD_BIND(neonserv_cmd_access) {
-    if(argc == 0) {
-        if(!(user->flags & USERFLAG_ISAUTHED)) {
-            struct neonserv_cmd_access_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->nick = strdup(user->nick);
-            get_userauth(user, neonserv_cmd_access_nick_lookup, cache);
-        } else
-            neonserv_cmd_access_async1(client, getTextBot(), user, chan, user->nick, user->auth, user);
-    }
-    else if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        neonserv_cmd_access_async1(client, getTextBot(), user, chan, NULL, argv[0], NULL);
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_access_async1(client, getTextBot(), user, chan, argv[0], cuser->auth, cuser);
-        } else {
-            struct neonserv_cmd_access_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->nick = strdup(argv[0]);
-            get_userauth(cuser, neonserv_cmd_access_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_access_nick_lookup) {
-    struct neonserv_cmd_access_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        if(!strcmp(cache->nick, cache->user->nick))
-            reply(cache->textclient, cache->user, "NS_YOU_NEED_AUTH");
-        else
-            reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_access_async1(cache->client, cache->textclient, cache->user, cache->chan, user->nick, user->auth, user);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_access_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, struct UserNode *target) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW user_row, chanuser_row;
-    int userid;
-    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((user_row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(user_row[0]);
-        //check if the user is already added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags`, `chanuser_infoline` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((chanuser_row = mysql_fetch_row(res)) != NULL) {
-            //access output
-            if(nick)
-                reply(textclient, user, (strcmp(user_row[2], "1") ? "NS_A_ACCESS_AUTH" : "NS_A_ACCESS_AUTH_GOD"), nick, auth, atoi(chanuser_row[0]), chan->name);
-            else
-                reply(textclient, user, (strcmp(user_row[2], "1") ? "NS_A_ACCESS_NICK" : "NS_A_ACCESS_NICK_GOD"), auth, atoi(chanuser_row[0]), chan->name);
-            int cflags = atoi(chanuser_row[1]);
-            if(cflags & DB_CHANUSER_SUSPENDED)
-                reply(textclient, user, "NS_A_SUSPENDED", (nick ? nick : auth), chan->name);
-            if(chanuser_row[2] && strcmp(chanuser_row[2], ""))
-                reply(textclient, user, "[%s] %s", (nick ? nick : auth), chanuser_row[2]);
-        } else if(!strcmp(user_row[2], "1")) {
-            if(nick)
-                reply(textclient, user, "NS_A_LACKS_ACCESS_BUT_GOD_AUTH", nick, auth, chan->name);
-            else
-                reply(textclient, user, "NS_A_LACKS_ACCESS_BUT_GOD_NICK", auth, chan->name);
-        } else
-            reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-    } else
-        reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-    if(target && (target->flags & USERFLAG_ISIRCOP))
-        reply(textclient, user, "NS_A_IS_IRCOP", nick);
-}
diff --git a/cmd_neonserv_addban.c b/cmd_neonserv_addban.c
deleted file mode 100644 (file)
index b799c4b..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    nick|*auth|*!*@mask
-* argv[1-*]  reason
-*/
-static USERLIST_CALLBACK(neonserv_cmd_addban_userlist_lookup);
-static void neonserv_cmd_addban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mas, char *reason);
-
-struct neonserv_cmd_addban_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *mask;
-    char *reason;
-};
-
-CMD_BIND(neonserv_cmd_addban) {
-    struct neonserv_cmd_addban_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->mask = strdup(argv[0]);
-    if(argc > 1) {
-        cache->reason = strdup(merge_argv(argv, 1, argc));
-    } else
-        cache->reason = NULL;
-    get_userlist(chan, neonserv_cmd_addban_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_addban_userlist_lookup) {
-    struct neonserv_cmd_addban_cache *cache = data;
-    neonserv_cmd_addban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mask, (cache->reason ? cache->reason : "Bye."));
-    free(cache->mask);
-    if(cache->reason)
-        free(cache->reason);
-    free(cache);
-}
-
-static void neonserv_cmd_addban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, char *reason) {
-    int match_count = 0;
-    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
-    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    mask = make_banmask(mask, hostmask_buffer);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        cuser = chanuser->user;
-        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-        if(!match(mask, usermask)) {
-            if(isNetworkService(chanuser->user)) {
-                reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                return;
-            }
-            if(isUserProtected(chan, cuser, user)) {
-                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                return;
-            }
-            match_count++;
-            if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
-                reply(textclient, user, "NS_LAME_MASK", mask);
-                return;
-            }
-        }
-    }
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    //check if the provided mask is already banned by another ban
-    char *ban = getBanAffectingMask(chan, mask);
-    if(ban != NULL) {
-        reply(textclient, user, "NS_BAN_ALREADY_ADDED", mask, chan->name);
-        return;
-    }
-    //check if the provided mask affects any existing bans
-    printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
-    res = mysql_use();
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(!match(mask, row[0])) {
-            //remove the ban
-            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
-        }
-    }
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    int userid;
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL)
-        userid = atoi(row[0]);
-    else
-        return;
-    //add the ban
-    printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%d', '%s')", chan->channel_id, escape_string(mask), userid, escape_string(reason));
-    putsock(client, "MODE %s +b %s", chan->name, mask);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        cuser = chanuser->user;
-        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-        if(!match(mask, usermask)) {
-            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
-        }
-    }
-    reply(textclient, user, "NS_ADDBAN_DONE", mask, chan->name, match_count);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_addtimeban.c b/cmd_neonserv_addtimeban.c
deleted file mode 100644 (file)
index 8a8d567..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    nick|*auth|*!*@mask
-* argv[1]    time
-* argv[2-*]  reason
-*/
-static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup);
-static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason);
-
-struct neonserv_cmd_addtimeban_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *mask;
-    int duration;
-    char *reason;
-};
-
-CMD_BIND(neonserv_cmd_addtimeban) {
-    int duration = strToTime(user, argv[1]);
-    if(duration < 30) {
-        reply(getTextBot(), user, "NS_TIMEBAN_DURATION_TOO_SHORT", 30);
-        return;
-    }
-    struct neonserv_cmd_addtimeban_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->mask = strdup(argv[0]);
-    cache->duration = duration;
-    if(argc > 2) {
-        cache->reason = strdup(merge_argv(argv, 2, argc));
-    } else
-        cache->reason = NULL;
-    get_userlist(chan, neonserv_cmd_addtimeban_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup) {
-    struct neonserv_cmd_addtimeban_cache *cache = data;
-    neonserv_cmd_addtimeban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mask, cache->duration, (cache->reason ? cache->reason : "Bye."));
-    free(cache->mask);
-    if(cache->reason)
-        free(cache->reason);
-    free(cache);
-}
-
-static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason) {
-    int match_count = 0;
-    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
-    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    mask = make_banmask(mask, hostmask_buffer);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        cuser = chanuser->user;
-        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-        if(!match(mask, usermask)) {
-            if(isNetworkService(chanuser->user)) {
-                reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                return;
-            }
-            if(isUserProtected(chan, cuser, user)) {
-                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                return;
-            }
-            match_count++;
-            if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
-                reply(textclient, user, "NS_LAME_MASK", mask);
-                return;
-            }
-        }
-    }
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    //check if the provided mask is already banned by another ban
-    char *ban = getBanAffectingMask(chan, mask);
-    if(ban != NULL) {
-        reply(textclient, user, "NS_BAN_ALREADY_ADDED", mask, chan->name);
-        return;
-    }
-    //check if the provided mask affects any existing bans
-    printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
-    res = mysql_use();
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(!match(mask, row[0])) {
-            //remove the ban
-            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
-        }
-    }
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    int userid;
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL)
-        userid = atoi(row[0]);
-    else
-        return;
-    //add the ban
-    printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(mask), (unsigned long) (time(0) + duration), userid, escape_string(reason));
-    int banid = (int) mysql_insert_id(mysql_conn);
-    putsock(client, "MODE %s +b %s", chan->name, mask);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        cuser = chanuser->user;
-        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-        if(!match(mask, usermask)) {
-            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
-        }
-    }
-    char nameBuf[MAXLEN];
-    char banidBuf[20];
-    sprintf(nameBuf, "ban_%d", banid);
-    sprintf(banidBuf, "%d", banid);
-    timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
-    reply(textclient, user, "NS_TIMEBAN_DONE", mask, chan->name, timeToStr(user, duration, 2, nameBuf), match_count);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_adduser.c b/cmd_neonserv_adduser.c
deleted file mode 100644 (file)
index c63c176..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-* argv[1] - chan access
-*/
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_adduser_auth_lookup);
-static USERAUTH_CALLBACK(neonserv_cmd_adduser_nick_lookup);
-static void neonserv_cmd_adduser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int access);
-
-struct neonserv_cmd_adduser_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    int access;
-    char *nick;
-};
-
-CMD_BIND(neonserv_cmd_adduser) {
-    int caccess;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    caccess = atoi(argv[1]);
-    if(caccess <= 0 || caccess > 500) {
-        reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
-        return;
-    }
-    if(caccess >= getChannelAccess(user, chan, 0)) {
-        if(isGodMode(user)) {
-            event->flags |= CMDFLAG_OPLOG;
-        } else {
-            reply(getTextBot(), user, "NS_ACCESS_OUTRANKED");
-            return;
-        }
-    }
-    //check own access
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        printf_mysql_query("SELECT `user_user` FROM `users` WHERE `user_user` = '%s'", escape_string(argv[0]));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            neonserv_cmd_adduser_async1(client, getTextBot(), user, chan, event, argv[0], row[0], caccess);
-        } else {
-            //we need to create a new user...
-            //but first lookup the auth to check if it really exists
-            struct neonserv_cmd_adduser_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->access = caccess;
-            cache->nick = strdup(argv[0]);
-            lookup_authname(argv[0], neonserv_cmd_adduser_auth_lookup, cache);
-        }
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_adduser_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth, caccess);
-        } else {
-            struct neonserv_cmd_adduser_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->access = caccess;
-            cache->nick = strdup(argv[0]);
-            get_userauth(cuser, neonserv_cmd_adduser_nick_lookup, cache);
-        }
-    }
-}
-
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_adduser_auth_lookup) {
-    struct neonserv_cmd_adduser_cache *cache = data;
-    if(!exists) {
-        //AUTH_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_AUTH_UNKNOWN", cache->nick);
-    } else
-        neonserv_cmd_adduser_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, cache->nick, auth, cache->access);
-    free(cache->nick);
-    free(cache);
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_adduser_nick_lookup) {
-    struct neonserv_cmd_adduser_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_adduser_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth, cache->access);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_adduser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int caccess) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is already added
-        printf_mysql_query("SELECT `chanuser_access` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            reply(textclient, user, "NS_ADDUSER_ALREADY_ADDED", nick, chan->name, atoi(row[0]));
-            return;
-        }
-    } else {
-        printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(auth));
-        userid = (int) mysql_insert_id(mysql_conn);
-    }
-    printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chan->channel_id, userid, caccess);
-    reply(textclient, user, "NS_ADDUSER_DONE", nick, chan->name, caccess);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_ban.c b/cmd_neonserv_ban.c
deleted file mode 100644 (file)
index eec7326..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nick[,*auth[,*!*@mask[...]]]
-*/
-static USERLIST_CALLBACK(neonserv_cmd_ban_userlist_lookup);
-static void neonserv_cmd_ban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *masks);
-
-struct neonserv_cmd_ban_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *masks;
-};
-
-CMD_BIND(neonserv_cmd_ban) {
-    struct neonserv_cmd_ban_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->masks = strdup(merge_argv_char(argv, 0, argc, ','));
-    get_userlist_with_invisible(chan, neonserv_cmd_ban_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_ban_userlist_lookup) {
-    struct neonserv_cmd_ban_cache *cache = data;
-    neonserv_cmd_ban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->masks);
-    free(cache->masks);
-    free(cache);
-}
-
-static void neonserv_cmd_ban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *masks) {
-    int done_masks = 0, provided_masks = 0, skip, match_count, total_match;
-    char *mask, *nextmask;
-    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
-    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    nextmask = masks;
-    while((mask = nextmask)) {
-        nextmask = strstr(mask, ",");
-        if(nextmask) {
-            *nextmask = '\0';
-            nextmask++;
-        }
-        provided_masks++;
-        skip = 0;
-        match_count = 0;
-        mask = make_banmask(mask, hostmask_buffer);
-        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-            cuser = chanuser->user;
-            sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-            if(!match(mask, usermask)) {
-                cuser->flags |= USERFLAG_SCRIPTFLAG1; //we mark the user as 'matching'
-                if(isNetworkService(chanuser->user)) {
-                    reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                    skip = 1;
-                    break;
-                }
-                if(isUserProtected(chan, cuser, user)) {
-                    reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                    skip = 1;
-                    break;
-                }
-                match_count++;
-                if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
-                    skip = 1;
-                    reply(textclient, user, "NS_LAME_MASK", mask);
-                    break;
-                }
-            }
-        }
-        if(!skip) {
-            done_masks++;
-            modeBufferBan(modeBuf, mask);
-        }
-    }
-    total_match = 0; // count all users marked as 'matching'
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        cuser = chanuser->user;
-        if(cuser->flags & USERFLAG_SCRIPTFLAG1) {
-            cuser->flags &= ~USERFLAG_SCRIPTFLAG1;
-            total_match++;
-        }
-    }
-    freeModeBuffer(modeBuf);
-    if(done_masks == provided_masks)
-        reply(getTextBot(), user, "NS_BAN_DONE", done_masks, chan->name, total_match);
-    else
-        reply(getTextBot(), user, "NS_BAN_FAIL", client->user->nick);
-    if(done_masks)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_bans.c b/cmd_neonserv_bans.c
deleted file mode 100644 (file)
index 31231d4..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    (optional) mask
-*/
-CMD_BIND(neonserv_cmd_bans) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    //ban list
-    int i, with_expire = 0, cindex = 0;
-    char triggered_str[MAXLEN], expires_str[MAXLEN];
-    struct Table *table;
-    printf_mysql_query("SELECT `ban_mask`, `user_user`, `ban_triggered`, `ban_timeout`, `ban_reason` FROM `bans` LEFT JOIN `users` ON `ban_owner` = `user_id` WHERE `ban_channel` = '%d'", chan->channel_id);
-    res = mysql_use();
-    table = table_init(5, mysql_num_rows(res) + 1, 0);
-    char *content[5];
-    //add a NULL row (we add values later)
-    content[0] = NULL;
-    content[1] = NULL;
-    content[2] = NULL;
-    content[3] = NULL;
-    content[4] = NULL;
-    table_add(table, content);
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(argc > 0 && match(argv[0], row[0])) continue;
-        content[0] = row[0];
-        content[1] = row[1];
-        content[2] = (strcmp(row[2], "0") ? timeToStr(user, (time(0) - atoi(row[2])), 2, triggered_str) : get_language_string(user, "NS_USERS_SEEN_NEVER"));
-        if(strcmp(row[3], "0")) {
-            if(!with_expire) {
-                //we're using expire times now...
-                for(i = 0; i < cindex; i++)
-                    table_change_field(table, i+1, 3, get_language_string(user, "NS_USERS_SEEN_NEVER"));
-                with_expire = 1;
-            }
-            content[3] = timeToStr(user, (atoi(row[3]) - time(0)), 2, expires_str);
-        } else
-            content[3] = (with_expire ? get_language_string(user, "NS_USERS_SEEN_NEVER") : NULL);
-        content[4] = row[4];
-        cindex++;
-        table_add(table, content);
-    }
-    //now we add the table header
-    content[0] = get_language_string(user, "NS_BANS_HEADER_MASK");
-    content[1] = get_language_string(user, "NS_BANS_HEADER_SETBY");
-    content[2] = get_language_string(user, "NS_BANS_HEADER_TRIGGERED");
-    content[3] = (with_expire ? get_language_string(user, "NS_BANS_HEADER_EXPIRES") : NULL);
-    content[4] = get_language_string(user, "NS_BANS_HEADER_REASON");
-    table_change(table, 0, content);
-    char **table_lines = table_end(table);
-    for(i = 0; i < table->entrys; i++) {
-        reply(getTextBot(), user, table_lines[i]);
-    }
-    if(!cindex)
-        reply(getTextBot(), user, "NS_TABLE_NONE");
-    reply(getTextBot(), user, "NS_TABLE_COUNT", cindex);
-    table_free(table);
-}
diff --git a/cmd_neonserv_bind.c b/cmd_neonserv_bind.c
deleted file mode 100644 (file)
index 3c80478..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]   command name
-* argv[1]   command function
-* argv[2-*] parameters (optional)
-*/
-
-CMD_BIND(neonserv_cmd_bind) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `function` FROM `bot_binds` WHERE `botclass` = '%d' AND `command` = '%s'", client->botid, escape_string(argv[0]));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        reply(getTextBot(), user, "NS_BIND_ALREADY", argv[0], row[0]);
-        return;
-    }
-    char *params;
-    if(argc > 2)
-        params = merge_argv(argv, 2, argc);
-    else
-        params = "";
-    struct cmd_function *function = find_cmd_function(client->botid, argv[1]);
-    if(!function) {
-        reply(getTextBot(), user, "NS_BIND_UNKNOWN", argv[1]);
-        return;
-    }
-    bind_cmd_to_function(client->botid, argv[0], function);
-    if(*params)
-        bind_set_parameters(client->botid, argv[0], params);
-    printf_mysql_query("INSERT INTO `bot_binds` (`botclass`, `command`, `function`, `parameters`) VALUES ('%d', '%s', '%s', '%s')", client->botid, escape_string(argv[0]), escape_string(function->name), params);
-    reply(getTextBot(), user, "NS_BIND_DONE", argv[0], function->name);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_chanservsync.c b/cmd_neonserv_chanservsync.c
deleted file mode 100644 (file)
index 5603300..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - botnick
-* argv[1] - key
-*/
-#define CHANSERVSYNC_END_TIMEOUT 5
-
-static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message);
-static void neonserv_cmd_chanservsync_free_cache();
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_chanservsync_auth_lookup);
-static void neonserv_cmd_chanservsync_synchronize_user(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *username, int userid, int caccess, time_t seen, int flags, int new);
-
-struct neonserv_cmd_chanservsync_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    char *botnick;
-    time_t last_response;
-};
-
-struct neonserv_cmd_chanservsync_auth_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    int caccess;
-    time_t seen;
-    int flags;
-};
-
-struct neonserv_cmd_chanservsync_cache *neonserv_cmd_chanservsync_used = NULL;
-const char* neonserv_cmd_chanservsync_supported[] = {"ChanServ", NULL};
-
-CMD_BIND(neonserv_cmd_chanservsync) {
-    if(neonserv_cmd_chanservsync_used && time(0) - neonserv_cmd_chanservsync_used->last_response < CHANSERVSYNC_END_TIMEOUT) {
-        reply(getTextBot(), user, "NS_CHANSERVSYNC_INUSE");
-        return;
-    }
-    if(neonserv_cmd_chanservsync_used) {
-        neonserv_cmd_chanservsync_free_cache();
-    }
-    char *botnick = "ChanServ";
-    char *key = "";
-    if(argc) {
-        if(argv[0][0] == '!') {
-            key = argv[0];
-        } else {
-            botnick = argv[0];
-            if(argc > 1)
-                key = argv[1];
-        }
-    }
-    int seed = 0;
-    char *tmp;
-    char synckey[18];
-    for(tmp = user->auth; *tmp; tmp++)
-        seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-    for(tmp = chan->name; *tmp; tmp++)
-        seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-    for(tmp = botnick; *tmp; tmp++)
-        seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-    sprintf(synckey, "!%08x!", seed);
-    if(strcmp(synckey, key)) {
-        int f = 0;
-        const char **supp = neonserv_cmd_chanservsync_supported;
-        while(*supp) {
-            if(!stricmp(*supp, botnick)) {
-                f = 1;
-                break;
-            }
-            supp++;
-        }
-        if(!f) {
-            reply(getTextBot(), user, "NS_CHANSERVSYNC_UNSUPPORTED", botnick, client->user->nick);
-        }
-        reply(getTextBot(), user, "NS_CHANSERVSYNC_KEY", client->user->nick, botnick, botnick, synckey);
-        return;
-    }
-    struct neonserv_cmd_chanservsync_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->chan = chan;
-    cache->botnick = strdup(botnick);
-    cache->last_response = time(0);
-    neonserv_cmd_chanservsync_used = cache;
-    putsock(client, "PRIVMSG %s :users %s", botnick, chan->name);
-    bind_privnotice(neonserv_cmd_chanservsync_notice_listener);
-    reply(getTextBot(), user, "NS_CHANSERVSYNC_SYNCHRONIZING", chan->name, botnick);
-    logEvent(event);
-}
-
-static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message) {
-    if(neonserv_cmd_chanservsync_used && neonserv_cmd_chanservsync_used->client->user == target && !stricmp(user->nick, neonserv_cmd_chanservsync_used->botnick)) {
-        //we've got a notice from our bot...
-        //let's try parsing it....
-        char *p = message;
-        char *tokens[MAXLEN];
-        int tokensPos = 0;
-        while(*p == ' ') //skip leading spaces (airb0t)
-            p++;
-        message = p;
-        char *q = p;
-        while(*q) {
-            if(*q < 32) *q = ' ';
-            q++;
-        }
-        while((q = strstr(p, " "))) {
-            *q = '\0';
-            do {
-                q++;
-            } while(*q == ' ');
-            if(*p) {
-                tokens[tokensPos++] = p;
-            }
-            p = q;
-        }
-        if(*p) {
-            tokens[tokensPos++] = p;
-        }
-        int caccess;
-        char *username;
-        if(tokensPos == 1) {
-            //maybe a chip-like userlist
-            if(tokens[0][0] == '@') {
-                caccess = 200;
-                username = &tokens[0][1];
-            } else if(tokens[0][0] == '+') {
-                caccess = 100;
-                username = &tokens[0][1];
-            } else
-                return;
-        } else if(tokensPos >= 2) {
-            caccess = atoi(tokens[0]);
-            username = tokens[1];
-        } else
-            return;
-        if(caccess < 1 || caccess > 500) return;
-        int flags = 0;
-        time_t now = time(0);
-        time_t seen_time = now; //now - now = 0 (never)
-        neonserv_cmd_chanservsync_used->last_response = now;
-        if(strlen(username) < 3) return;
-        //ok we have access and username... maybe there is something else we can parse???
-        char *seen = NULL;
-        char *status = NULL;
-        if(tokensPos > 2) {
-            if(!stricmp("normal", tokens[2]) || !stricmp("suspended", tokens[2]) || !stricmp("bot", tokens[2])) {
-                status = tokens[2];
-                if (tokensPos > 3) {
-                    seen = merge_argv(tokens, 3, tokensPos);
-                }
-            } else if (tokensPos > 3) {
-                if(!stricmp("normal", tokens[tokensPos-1]) || !stricmp("suspended", tokens[tokensPos-1]) || !stricmp("bot", tokens[tokensPos-1])) {
-                    status = tokens[tokensPos-1];
-                    seen = merge_argv(tokens, 2, tokensPos-1);
-                } else {
-                    seen = merge_argv(tokens, 2, tokensPos);
-                }
-            } else {
-                seen = merge_argv(tokens, 2, tokensPos);
-            }
-        }
-        if(status && !stricmp(status, "suspended")) {
-            flags |= DB_CHANUSER_SUSPENDED;
-        }
-        if(seen) {
-            if(!stricmp(seen, "here"))
-                seen_time = 0;
-            else if(stricmp(seen, "never"))
-                seen_time = strToTime(user, seen);
-        }
-        seen_time = now - seen_time;
-        //we've collected all information now. synchronize the user (use the higher access if the user is already added)
-        MYSQL_RES *res;
-        MYSQL_ROW row;
-        int userid;
-        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(username));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            userid = atoi(row[0]);
-            neonserv_cmd_chanservsync_synchronize_user(neonserv_cmd_chanservsync_used->client, neonserv_cmd_chanservsync_used->textclient, neonserv_cmd_chanservsync_used->user, neonserv_cmd_chanservsync_used->chan, username, userid, caccess, seen_time, flags, 0);
-        } else if(!stricmp(user->nick, "chanserv")) {
-            printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(username));
-            userid = (int) mysql_insert_id(mysql_conn);
-            neonserv_cmd_chanservsync_synchronize_user(neonserv_cmd_chanservsync_used->client, neonserv_cmd_chanservsync_used->textclient, neonserv_cmd_chanservsync_used->user, neonserv_cmd_chanservsync_used->chan, username, userid, caccess, seen_time, flags, 1);
-        } else {
-            //lookup auth
-            struct neonserv_cmd_chanservsync_auth_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = neonserv_cmd_chanservsync_used->client;
-            cache->textclient = neonserv_cmd_chanservsync_used->textclient;
-            cache->user = neonserv_cmd_chanservsync_used->user;
-            cache->chan = neonserv_cmd_chanservsync_used->chan;
-            cache->caccess = caccess;
-            cache->seen = seen_time;
-            cache->flags = flags;
-            lookup_authname(username, neonserv_cmd_chanservsync_auth_lookup, cache);
-        }
-    }
-}
-
-static void neonserv_cmd_chanservsync_free_cache() {
-    free(neonserv_cmd_chanservsync_used->botnick);
-    free(neonserv_cmd_chanservsync_used);
-    unbind_privnotice(neonserv_cmd_chanservsync_notice_listener);
-    neonserv_cmd_chanservsync_used = NULL;
-}
-
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_chanservsync_auth_lookup) {
-    struct neonserv_cmd_chanservsync_auth_cache *cache = data;
-    if(exists) {
-        printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(auth));
-        int userid = (int) mysql_insert_id(mysql_conn);
-        neonserv_cmd_chanservsync_synchronize_user(cache->client, cache->textclient, cache->user, cache->chan, auth, userid, cache->caccess, cache->seen, cache->flags, 1);
-    }
-    free(cache);
-}
-
-static void neonserv_cmd_chanservsync_synchronize_user(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *username, int userid, int caccess, time_t seen, int flags, int new) {
-    //just sync the user with the given userid with the providet information
-    if(caccess == 500) caccess = 499;
-    if(new) {
-        //just add
-        printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`, `chanuser_seen`, `chanuser_flags`) VALUES ('%d', '%d', '%d', '%lu', '%d')", chan->channel_id, userid, caccess, (unsigned long) seen, flags);
-    } else {
-        MYSQL_RES *res;
-        MYSQL_ROW row;
-        //check if already added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            //clvl
-            if(atoi(row[0]) >= caccess) return;
-            if(atol(row[2]) > seen) seen = atol(row[2]);
-            printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '%d', `chanuser_seen` = '%lu' WHERE `chanuser_id` = '%s'", caccess, (unsigned long) seen, row[1]);
-        } else 
-            printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`, `chanuser_seen`, `chanuser_flags`) VALUES ('%d', '%d', '%d', '%lu', '%d')", chan->channel_id, userid, caccess, (unsigned long) seen, flags);
-    }
-    reply(textclient, user, "NS_CHANSERVSYNC_SYNCHRONIZED", username, caccess);
-}
diff --git a/cmd_neonserv_clvl.c b/cmd_neonserv_clvl.c
deleted file mode 100644 (file)
index ff386b2..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-* argv[1] - access
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_clvl_nick_lookup);
-static void neonserv_cmd_clvl_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int caccess);
-
-struct neonserv_cmd_clvl_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-    int access;
-};
-
-CMD_BIND(neonserv_cmd_clvl) {
-    int caccess;
-    caccess = atoi(argv[1]);
-    if(caccess <= 0 || caccess > 500) {
-        reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
-        return;
-    }
-    if(caccess >= getChannelAccess(user, chan, 0)) {
-        if(isGodMode(user)) {
-            event->flags |= CMDFLAG_OPLOG;
-        } else {
-            reply(getTextBot(), user, "NS_ACCESS_OUTRANKED");
-            return;
-        }
-    }
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        neonserv_cmd_clvl_async1(client, getTextBot(), user, chan, event, argv[0], argv[0], caccess);
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_clvl_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth, caccess);
-        } else {
-            struct neonserv_cmd_clvl_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[0]);
-            cache->access = caccess;
-            get_userauth(cuser, neonserv_cmd_clvl_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_clvl_nick_lookup) {
-    struct neonserv_cmd_clvl_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_clvl_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth, cache->access);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_clvl_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int caccess) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is already added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            //clvl
-            if(atoi(row[0]) >= getChannelAccess(user, chan, 1)) {
-                reply(textclient, user, "NS_USER_OUTRANKED", nick);
-                return;
-            }
-            printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '%d' WHERE `chanuser_id` = '%s'", caccess, row[1]);
-            reply(textclient, user, "NS_CLVL_DONE", nick, caccess, chan->name);
-            logEvent(event);
-            return;
-        }
-    }
-    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-}
diff --git a/cmd_neonserv_command.c b/cmd_neonserv_command.c
deleted file mode 100644 (file)
index 0f34ea0..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-1]     command
-*/
-static int neonserv_cmd_command_chanaccess(struct cmd_binding *cbind, struct ChanNode *chan);
-static int neonserv_cmd_command_operaccess(struct cmd_binding *cbind);
-
-CMD_BIND(neonserv_cmd_command) {
-    char *ident;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    struct cmd_binding *cbind = find_cmd_binding(client->botid, argv[0]);
-    if (!cbind) {
-        reply(getTextBot(), user, "NS_UNBIND_NOT_FOUND", argv[0]);
-        return;
-    }
-    ident = argv[0];
-    reply(getTextBot(), user, "NS_COMMAND_BINDING", cbind->cmd, cbind->func->name, (cbind->parameters ? cbind->parameters : ""));
-    if(chan)
-        reply(getTextBot(), user, "NS_COMMAND_ACCESS", neonserv_cmd_command_chanaccess(cbind, chan), neonserv_cmd_command_operaccess(cbind));
-    printf_mysql_query("SELECT `user_lang` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    char *lang;
-    if ((row = mysql_fetch_row(res)) != NULL)
-        lang = row[0];
-    else
-        lang = "en";
-    printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = '%s' AND `ident` = '%s'", escape_string(lang), escape_string(ident));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        if(stricmp(lang, "en")) {
-            printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = 'en' AND `ident` = '%s'", escape_string(ident));
-            res = mysql_use();
-        }
-        if ((row = mysql_fetch_row(res)) == NULL) {
-            printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = '%s' AND `ident` = '%s'", escape_string(lang), escape_string(cbind->func->name));
-            res = mysql_use();
-            if ((row = mysql_fetch_row(res)) == NULL) {
-                if(stricmp(lang, "en")) {
-                    printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = 'en' AND `ident` = '%s'", escape_string(cbind->func->name));
-                    res = mysql_use();
-                }
-                if ((row = mysql_fetch_row(res)) == NULL) {
-                    return;
-                }
-            }
-        }
-    }
-    char sendBuf[MAXLEN];
-    int sendBufPos = 0;
-    int i;
-    for(i = 0; i < strlen(row[0]); i++) {
-        switch(row[0][i]) {
-            case '\n':
-                if(sendBufPos) {
-                    sendBuf[sendBufPos] = '\0';
-                    reply(getTextBot(), user, "%s", sendBuf);
-                    sendBufPos = 0;
-                }
-                break;
-            case '$':
-                switch(row[0][i+1]) {
-                    case 'b':
-                        sendBuf[sendBufPos++] = '\002';
-                        i++;
-                        break;
-                    case 'k':
-                        sendBuf[sendBufPos++] = '\003';
-                        i++;
-                        break;
-                    case 'u':
-                        sendBuf[sendBufPos++] = '\031';
-                        i++;
-                        break;
-                    case 'C':
-                    case 'S':
-                        sendBufPos += sprintf(sendBuf + sendBufPos, "%s", client->user->nick);
-                        i++;
-                        break;
-                    default:
-                        sendBuf[sendBufPos++] = '$';
-                        break;
-                }
-                break;
-            default:
-                sendBuf[sendBufPos++] = row[0][i];
-                break;
-        }
-    }
-    if(sendBufPos) {
-        sendBuf[sendBufPos] = '\0';
-        reply(getTextBot(), user, "%s", sendBuf);
-        sendBufPos = 0;
-    }
-}
-
-static int neonserv_cmd_command_chanaccess(struct cmd_binding *cbind, struct ChanNode *chan) {
-    char access_list[256];
-    int access_pos = 0;
-    int access_count = 0;
-    int minaccess = 0;
-    char *str_a, *str_b = cbind->func->channel_access, *str_c;
-    if(cbind->flags & CMDFLAG_OVERRIDE_CHANNEL_ACCESS)
-        str_b = cbind->channel_access;
-    access_list[0] = '\0';
-    if(str_b) {
-        str_c = strdup(str_b);
-        str_b = str_c;
-        while((str_a = str_b)) {
-            str_b = strstr(str_a, ",");
-            if(str_b) {
-                *str_b = '\0';
-                str_b++;
-            }
-            if(*str_a == '#') {
-                str_a++;
-                access_pos += sprintf(access_list+access_pos, (access_pos ? ", `%s`" : "`%s`"), str_a);
-                access_count++;
-            } else {
-               if(atoi(str_a) > minaccess)
-                     minaccess = atoi(str_a);
-            }
-        }
-        free(str_c);
-    }
-    if(access_count) {
-        MYSQL_RES *res;
-        MYSQL_ROW row, defaults = NULL;
-        printf_mysql_query("SELECT %s FROM `channels` WHERE `channel_name` = '%s'", access_list, escape_string(chan->name));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            int i, caccess;
-            for(i = 0; i < access_count; i++) {
-                if(!row[i] && !defaults) {
-                    printf_mysql_query("SELECT %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
-                    defaults = mysql_fetch_row(mysql_use());
-                }
-                caccess = (row[i] ? atoi(row[i]) : atoi(defaults[i]));
-                if(caccess > minaccess)
-                     minaccess = caccess;
-            }
-        }
-    }
-    return minaccess;
-}
-
-static int neonserv_cmd_command_operaccess(struct cmd_binding *cbind) {
-    return ((cbind->flags & CMDFLAG_OVERRIDE_GLOBAL_ACCESS) ? cbind->global_access : cbind->func->global_access);
-}
diff --git a/cmd_neonserv_csuspend.c b/cmd_neonserv_csuspend.c
deleted file mode 100644 (file)
index 23b2381..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - channel
-*/
-CMD_BIND(neonserv_cmd_csuspend) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    char *channel = argv[0];
-    if(!is_valid_chan(channel)) {
-        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
-        return;
-    }
-    int chanid;
-    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        chanid = atoi(row[0]);
-    } else {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    if(!strcmp(row[2], "1")) {
-        reply(getTextBot(), user, "NS_CSUSPEND_ALREADY", channel);
-        return;
-    }
-    int botid = atoi(row[0]);
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid)
-            break;
-    }
-    if(bot) {
-        putsock(bot, "PART %s :Channel suspended.", channel);
-    }
-    printf_mysql_query("UPDATE `bot_channels` SET `suspended` = '1' WHERE `id` = '%s'", row[1]);
-    reply(getTextBot(), user, "NS_CSUSPEND_DONE", channel);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_cunsuspend.c b/cmd_neonserv_cunsuspend.c
deleted file mode 100644 (file)
index 0902ff2..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - channel
-*/
-CMD_BIND(neonserv_cmd_cunsuspend) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    char *channel = argv[0];
-    if(!is_valid_chan(channel)) {
-        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
-        return;
-    }
-    int chanid;
-    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        chanid = atoi(row[0]);
-    } else {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    if(!strcmp(row[2], "0")) {
-        reply(getTextBot(), user, "NS_CUNSUSPEND_NOT", channel);
-        return;
-    }
-    int botid = atoi(row[0]);
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid)
-            break;
-    }
-    if(bot) {
-        putsock(bot, "JOIN %s", channel);
-    }
-    printf_mysql_query("UPDATE `bot_channels` SET `suspended` = '0' WHERE `id` = '%s'", row[1]);
-    reply(getTextBot(), user, "NS_CUNSUSPEND_DONE", channel);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_delban.c b/cmd_neonserv_delban.c
deleted file mode 100644 (file)
index ac8b696..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    nick|*auth|*!*@mask
-*/
-
-CMD_BIND(neonserv_cmd_delban) {
-    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
-    char *mask = make_banmask(argv[0], hostmask_buffer);
-    int matching_bans = 0;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    //check if the provided mask is already banned by another ban
-    char *ban = getBanAffectingMask(chan, mask);
-    if(ban != NULL) {
-        reply(getTextBot(), user, "NS_DELBAN_BANNED_BY", mask, ban);
-        return;
-    }
-    //check if the provided mask affects any existing bans
-    char nameBuf[20];
-    printf_mysql_query("SELECT `ban_mask`, `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
-    res = mysql_use();
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(!match(mask, row[0])) {
-            //remove the ban
-            if(strcmp(row[2], "0")) {
-                sprintf(nameBuf, "ban_%s", row[1]);
-                timeq_del_name(nameBuf);
-            }
-            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
-            matching_bans++;
-        }
-    }
-    if(matching_bans) {
-        putsock(client, "MODE %s -b %s", chan->name, mask);
-        reply(getTextBot(), user, "NS_DELBAN_DONE", mask, chan->name);
-        logEvent(event);
-    } else
-        reply(getTextBot(), user, "NS_DELBAN_FAIL", mask);
-}
diff --git a/cmd_neonserv_delme.c b/cmd_neonserv_delme.c
deleted file mode 100644 (file)
index daf6ff4..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - key
-*/
-
-CMD_BIND(neonserv_cmd_delme) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            //check key
-            int seed = 0;
-            char *tmp;
-            static char unregkey[16];
-            for(tmp = user->auth; *tmp; tmp++)
-                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-            for(tmp = chan->name; *tmp; tmp++)
-                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-            sprintf(unregkey, "%08x", seed);
-            if(argc < 1 || strcmp(argv[0], unregkey)) {
-                reply(getTextBot(), user, "NS_DELME_KEY", unregkey);
-                return;
-            } else {
-                //delete
-                printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[1]);
-                reply(getTextBot(), user, "NS_DELME_DONE", atoi(row[0]), chan->name);
-                logEvent(event);
-                return;
-            }
-        }
-    }
-    reply(getTextBot(), user, "NS_NOT_ON_USERLIST_YOU", chan->name);
-}
diff --git a/cmd_neonserv_deluser.c b/cmd_neonserv_deluser.c
deleted file mode 100644 (file)
index b6ff283..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_deluser_nick_lookup);
-static void neonserv_cmd_deluser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
-
-struct neonserv_cmd_deluser_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-};
-
-CMD_BIND(neonserv_cmd_deluser) {
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        neonserv_cmd_deluser_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_deluser_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
-        } else {
-            struct neonserv_cmd_deluser_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[0]);
-            get_userauth(cuser, neonserv_cmd_deluser_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_deluser_nick_lookup) {
-    struct neonserv_cmd_deluser_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_deluser_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_deluser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is already added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
-                if(isGodMode(user)) {
-                    event->flags |= CMDFLAG_OPLOG;
-                } else {
-                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
-                    return;
-                }
-            }
-            //delete
-            printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[1]);
-            reply(textclient, user, "NS_DELUSER_DONE", nick, atoi(row[0]), chan->name);
-            logEvent(event);
-            return;
-        }
-    }
-    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-}
diff --git a/cmd_neonserv_deop.c b/cmd_neonserv_deop.c
deleted file mode 100644 (file)
index d0ee75e..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nicks
-*/
-static USERLIST_CALLBACK(neonserv_cmd_deop_userlist_lookup);
-static void neonserv_cmd_deop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc);
-
-struct neonserv_cmd_deop_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char **argv;
-    int argc;
-};
-
-CMD_BIND(neonserv_cmd_deop) {
-    struct neonserv_cmd_deop_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->argv = calloc(argc, sizeof(char*));
-    int i;
-    for(i = 0; i < argc; i++) {
-        cache->argv[i] = strdup(argv[i]);
-    }
-    cache->argc = argc;
-    get_userlist(chan, neonserv_cmd_deop_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_deop_userlist_lookup) {
-    struct neonserv_cmd_deop_cache *cache = data;
-    neonserv_cmd_deop_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->argv, cache->argc);
-    int i;
-    for(i = 0; i < cache->argc; i++) {
-        free(cache->argv[i]);
-    }
-    free(cache);
-}
-
-static void neonserv_cmd_deop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc) {
-    int i, done_users = 0;
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    for(i = 0; i < argc; i++) {
-        cuser = searchUserByNick(argv[i]);
-        if(!cuser) continue;
-        chanuser = getChanUser(cuser, chan);
-        if(!chanuser) continue;
-        if(isNetworkService(cuser)) {
-            reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
-            continue;
-        }
-        if(isUserProtected(chan, cuser, user)) {
-            reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-            continue;
-        }
-        done_users++;
-        if(!(chanuser->flags & CHANUSERFLAG_OPPED)) continue;
-        modeBufferDeop(modeBuf, argv[i]);
-    }
-    freeModeBuffer(modeBuf);
-    if(done_users == argc)
-        reply(textclient, user, "NS_DEOP_DONE", chan->name);
-    else
-        reply(textclient, user, "NS_DEOP_FAIL", client->user->nick);
-    if(done_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_deopall.c b/cmd_neonserv_deopall.c
deleted file mode 100644 (file)
index f9ee763..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    (optional) nick mask
-*/
-static USERLIST_CALLBACK(neonserv_cmd_deopall_userlist_lookup);
-static void neonserv_cmd_deopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc);
-
-struct neonserv_cmd_deopall_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char **argv;
-    int argc;
-};
-
-CMD_BIND(neonserv_cmd_deopall) {
-    struct neonserv_cmd_deopall_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->argv = calloc(argc, sizeof(char*));
-    int i;
-    for(i = 0; i < argc; i++) {
-        cache->argv[i] = strdup(argv[i]);
-    }
-    cache->argc = argc;
-    get_userlist(chan, neonserv_cmd_deopall_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_deopall_userlist_lookup) {
-    struct neonserv_cmd_deopall_cache *cache = data;
-    neonserv_cmd_deopall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->argv, cache->argc);
-    int i;
-    for(i = 0; i < cache->argc; i++) {
-        free(cache->argv[i]);
-    }
-    free(cache);
-}
-
-static void neonserv_cmd_deopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc) {
-    int issuer_access, victim_access, done_users = 0;
-    char *nickmask = NULL;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    if(argc > 0)
-        nickmask = argv[0];
-    modeBuf = initModeBuffer(client, chan);
-    issuer_access = getChannelAccess(user, chan, 0);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
-        victim_access = getChannelAccess(user, chan, 0);
-        if(victim_access >= issuer_access) continue;
-        if(!(chanuser->flags & CHANUSERFLAG_OPPED)) continue;
-        modeBufferDeop(modeBuf, chanuser->user->nick);
-        done_users++;
-    }
-    freeModeBuffer(modeBuf);
-    reply(getTextBot(), user, "NS_DEOPALL_DONE", done_users, chan->name);
-    if(done_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_devoice.c b/cmd_neonserv_devoice.c
deleted file mode 100644 (file)
index 6994679..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nicks
-*/
-
-CMD_BIND(neonserv_cmd_devoice) {
-    int i, done_users = 0;
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    for(i = 0; i < argc; i++) {
-        cuser = searchUserByNick(argv[i]);
-        if(!cuser) continue;
-        chanuser = getChanUser(cuser, chan);
-        if(!chanuser) continue;
-        if(isUserProtected(chan, cuser, user)) {
-            reply(getTextBot(), user, "NS_USER_PROTECTED", cuser->nick);
-            continue;
-        }
-        done_users++;
-        if(!(chanuser->flags & CHANUSERFLAG_VOICED)) continue;
-        modeBufferDevoice(modeBuf, argv[i]);
-    }
-    freeModeBuffer(modeBuf);
-    if(done_users == argc)
-        reply(getTextBot(), user, "NS_DEVOICE_DONE", chan->name);
-    else
-        reply(getTextBot(), user, "NS_DEVOICE_FAIL", client->user->nick);
-    if(done_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_devoiceall.c b/cmd_neonserv_devoiceall.c
deleted file mode 100644 (file)
index 3c201af..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    (optional) nick mask
-*/
-
-CMD_BIND(neonserv_cmd_devoiceall) {
-    int issuer_access, victim_access, done_users = 0;
-    char *nickmask = NULL;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    check_mysql();
-    if(!checkChannelAccess(user, chan, "channel_canvoice", 1, 0)) {
-        reply(getTextBot(), user, "NS_ACCESS_DENIED");
-        return;
-    }
-    if(argc > 0)
-        nickmask = argv[0];
-    modeBuf = initModeBuffer(client, chan);
-    issuer_access = getChannelAccess(user, chan, 0);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
-        victim_access = getChannelAccess(user, chan, 0);
-        if(victim_access >= issuer_access) continue;
-        if(!(chanuser->flags & CHANUSERFLAG_VOICED)) continue;
-        modeBufferDevoice(modeBuf, chanuser->user->nick);
-        done_users++;
-    }
-    freeModeBuffer(modeBuf);
-    reply(getTextBot(), user, "NS_DEVOICEALL_DONE", done_users, chan->name);
-    if(done_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_down.c b/cmd_neonserv_down.c
deleted file mode 100644 (file)
index e504070..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no arguments
-*/
-
-CMD_BIND(neonserv_cmd_down) {
-    struct ChanUser *chanuser = getChanUser(user, chan);
-    if(!chanuser) {
-        reply(getTextBot(), user, "NS_NOT_ON_CHANNEL_YOU", chan->name);
-        return;
-    }
-    if((chanuser->flags & CHANUSERFLAG_OPPED)) {
-        putsock(client, "MODE %s -ov %s %s", chan->name, user->nick, user->nick);
-        logEvent(event);
-    } else if((chanuser->flags & CHANUSERFLAG_VOICED)) {
-        putsock(client, "MODE %s -v %s", chan->name, user->nick);
-        logEvent(event);
-    } else
-        reply(getTextBot(), user, "NS_DOWN_ALREADY", chan->name);
-}
diff --git a/cmd_neonserv_downall.c b/cmd_neonserv_downall.c
deleted file mode 100644 (file)
index 1d001c9..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no arguments
-*/
-
-CMD_BIND(neonserv_cmd_downall) {
-    struct ChanUser *chanuser;
-    for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = getUserChannels(user, chanuser)) {
-        chan = chanuser->chan;
-        loadChannelSettings(chan);
-        if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) continue;
-        printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, client->botid);
-        if (mysql_fetch_row(mysql_use()) == NULL) continue;
-        int done = 0;
-        if((chanuser->flags & CHANUSERFLAG_OPPED)) {
-            putsock(client, "MODE %s -o %s", chan->name, user->nick);
-            done = 1;
-        }
-        if((chanuser->flags & CHANUSERFLAG_VOICED)) {
-            putsock(client, "MODE %s -v %s", chan->name, user->nick);
-            done = 1;
-        }
-        if(done) {
-            //event hack
-            event->chan = chan;
-            logEvent(event);
-        }
-    }
-}
diff --git a/cmd_neonserv_emote.c b/cmd_neonserv_emote.c
deleted file mode 100644 (file)
index 427a30f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    target
-* argv[1-*]  message
-*/
-
-CMD_BIND(neonserv_cmd_emote) {
-    char *message = merge_argv(argv, 1, argc);
-    putsock(client, "PRIVMSG %s :\001ACTION %s\001", argv[0], message);
-}
\ No newline at end of file
diff --git a/cmd_neonserv_events.c b/cmd_neonserv_events.c
deleted file mode 100644 (file)
index 23ecf3c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]     time
-* argv[1-*]   match
-*/
-
-CMD_BIND(neonserv_cmd_events) {
-    char *str_match;
-    int duration = (argc ? strToTime(user, argv[0]) : 0);
-    if(argc > (duration ? 1 : 0))
-        str_match = merge_argv(argv, (duration ? 1 : 0), argc);
-    else
-        str_match = "";
-    if(!duration) duration = (60*60*24);
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `time`, `auth`, `nick`, `command` FROM `events` WHERE `cid` = '%d' AND `time` > '%lu' ORDER BY `time` ASC", chan->channel_id, ((unsigned long) time(0) - duration));
-    res = mysql_use();
-    int skip = mysql_num_rows(res) - 100;
-    int count = 0;
-    char timeBuf[50];
-    struct tm *timeinfo;
-    time_t event_time;
-    if(skip < 0) skip = 0;
-    reply(getTextBot(), user, "NS_EVENTS_HEADER");
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(skip) {
-            skip--;
-            continue;
-        }
-        if(*str_match && match(str_match, row[3])) continue;
-        count++;
-        event_time = (time_t) atol(row[0]);
-        timeinfo = localtime(&event_time);
-        strftime(timeBuf, 80, "%X %x", timeinfo);
-        reply(getTextBot(), user, "[%s] [%s:%s]: %s", timeBuf, row[2], row[1], row[3]);
-    }
-    reply(getTextBot(), user, "NS_TABLE_COUNT", count);
-}
diff --git a/cmd_neonserv_giveowner.c b/cmd_neonserv_giveowner.c
deleted file mode 100644 (file)
index 8f173ac..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-* argv[1] - key
-*/
-
-#define GIVEOWNER_TIMEOUT 86400 /* 60*60*24 = 86400 */
-
-static USERAUTH_CALLBACK(neonserv_cmd_giveowner_nick_lookup);
-static void neonserv_cmd_giveowner_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, char *key);
-
-struct neonserv_cmd_giveowner_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-    char *key;
-};
-
-CMD_BIND(neonserv_cmd_giveowner) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `channel_lastgiveowner` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return;
-    if(strcmp(row[0], "0") && (atoi(row[0]) + GIVEOWNER_TIMEOUT) > time(0)) {
-        char timeBuf[MAXLEN];
-        reply(getTextBot(), user, "NS_GIVEOWNER_TIMEOUT", timeToStr(user, (GIVEOWNER_TIMEOUT - (time(0) - atoi(row[0]))), 2, timeBuf), chan->name);
-        return;
-    }
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        neonserv_cmd_giveowner_async1(client, getTextBot(), user, chan, event, argv[0], argv[0], (argc != 1 ? argv[1] : NULL));
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_giveowner_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth, (argc != 1 ? argv[1] : NULL));
-        } else {
-            struct neonserv_cmd_giveowner_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[0]);
-            cache->key = (argc != 1 ? strdup(argv[1]) : NULL);
-            get_userauth(cuser, neonserv_cmd_giveowner_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_giveowner_nick_lookup) {
-    struct neonserv_cmd_giveowner_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_giveowner_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth, cache->key);
-    free(cache->nick);
-    if(cache->key)
-        free(cache->key);
-    free(cache);
-}
-
-static void neonserv_cmd_giveowner_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, char *key) {
-    //we've got a valid auth now...
-    if(!stricmp(user->auth, auth)) {
-        reply(textclient, user, "NS_GIVEOWNER_SELF");
-        return;
-    }
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is already added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            int seed = 0;
-            char *tmp;
-            char giveownerkey[16];
-            for(tmp = user->auth; *tmp; tmp++)
-                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-            for(tmp = chan->name; *tmp; tmp++)
-                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-            sprintf(giveownerkey, "%08x", seed);
-            if(key && !stricmp(giveownerkey, key)) {
-                //give ownership
-                printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '500' WHERE `chanuser_id` = '%s'", row[1]);
-                printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '499' WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = (SELECT `user_id` FROM `users` WHERE `user_user` = '%s')", chan->channel_id, escape_string(user->auth));
-                printf_mysql_query("INSERT INTO `owner_history` (`owner_history_cid`, `owner_history_uid`, `owner_history_time`) VALUE ('%d', '%d', UNIX_TIMESTAMP())", chan->channel_id, userid);
-                reply(textclient, user, "NS_GIVEOWNER_DONE", chan->name, auth);
-                logEvent(event);
-            } else {
-                reply(textclient, user, "NS_GIVEOWNER_CONFIRM", auth, giveownerkey);
-            }
-            return;
-        }
-    }
-    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-}
diff --git a/cmd_neonserv_god.c b/cmd_neonserv_god.c
deleted file mode 100644 (file)
index 96abaa6..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    (optional) on/off
-*/
-
-CMD_BIND(neonserv_cmd_god) {
-    if(argc > 0) {
-        if(!strcmp(argv[0], "0") || !stricmp(argv[0], "off") || !stricmp(argv[0], get_language_string(user, "NS_SET_OFF"))) {
-            if(isGodMode(user)) {
-                printf_mysql_query("UPDATE `users` SET `user_god` = '0' WHERE `user_user` = '%s'", escape_string(user->auth));
-                user->flags &= ~USERFLAG_GOD_MODE;
-            }
-            reply(getTextBot(), user, "NS_GOD_OFF");
-        } else if(!strcmp(argv[0], "1") || !stricmp(argv[0], "on") || !stricmp(argv[0], get_language_string(user, "NS_SET_ON"))) {
-            if(!isGodMode(user)) {
-                printf_mysql_query("UPDATE `users` SET `user_god` = '1' WHERE `user_user` = '%s'", escape_string(user->auth));
-                user->flags |= USERFLAG_GOD_MODE;
-            }
-            reply(getTextBot(), user, "NS_GOD_ON");
-        } else {
-            reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argv[0]);
-            return;
-        }
-    } else {
-        if(isGodMode(user)) {
-            printf_mysql_query("UPDATE `users` SET `user_god` = '0' WHERE `user_user` = '%s'", escape_string(user->auth));
-            user->flags &= ~USERFLAG_GOD_MODE;
-            reply(getTextBot(), user, "NS_GOD_OFF");
-        } else {
-            printf_mysql_query("UPDATE `users` SET `user_god` = '1' WHERE `user_user` = '%s'", escape_string(user->auth));
-            user->flags |= USERFLAG_GOD_MODE;
-            reply(getTextBot(), user, "NS_GOD_ON");
-        }
-    }
-}
\ No newline at end of file
diff --git a/cmd_neonserv_help.c b/cmd_neonserv_help.c
deleted file mode 100644 (file)
index 081fc22..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]     index
-*/
-
-CMD_BIND(neonserv_cmd_help) {
-    char *ident;
-    if(argc)
-        ident = merge_argv(argv, 0, argc);
-    else
-        ident = "0";
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `user_lang` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    char *lang;
-    if ((row = mysql_fetch_row(res)) != NULL)
-        lang = row[0];
-    else
-        lang = "en";
-    printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = '%s' AND `ident` = '%s'", escape_string(lang), escape_string(ident));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        if(stricmp(lang, "en")) {
-            printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = 'en' AND `ident` = '%s'", escape_string(ident));
-            res = mysql_use();
-        }
-        if ((row = mysql_fetch_row(res)) == NULL) {
-            reply(getTextBot(), user, "NS_HELP_TOPIC");
-            return;
-        }
-    }
-    char sendBuf[MAXLEN];
-    int sendBufPos = 0;
-    int i;
-    for(i = 0; i < strlen(row[0]); i++) {
-        switch(row[0][i]) {
-            case '\n':
-                if(sendBufPos) {
-                    sendBuf[sendBufPos] = '\0';
-                    reply(getTextBot(), user, "%s", sendBuf);
-                    sendBufPos = 0;
-                }
-                break;
-            case '$':
-                switch(row[0][i+1]) {
-                    case 'b':
-                        sendBuf[sendBufPos++] = '\002';
-                        i++;
-                        break;
-                    case 'k':
-                        sendBuf[sendBufPos++] = '\003';
-                        i++;
-                        break;
-                    case 'u':
-                        sendBuf[sendBufPos++] = '\031';
-                        i++;
-                        break;
-                    case 'C':
-                    case 'S':
-                        sendBufPos += sprintf(sendBuf + sendBufPos, "%s", client->user->nick);
-                        i++;
-                        break;
-                    default:
-                        sendBuf[sendBufPos++] = '$';
-                        break;
-                }
-                break;
-            default:
-                sendBuf[sendBufPos++] = row[0][i];
-                break;
-        }
-    }
-    if(sendBufPos) {
-        sendBuf[sendBufPos] = '\0';
-        reply(getTextBot(), user, "%s", sendBuf);
-        sendBufPos = 0;
-    }
-}
diff --git a/cmd_neonserv_invite.c b/cmd_neonserv_invite.c
deleted file mode 100644 (file)
index f7fcd62..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_invite_nick_lookup);
-static void neonserv_cmd_invite_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
-static TIMEQ_CALLBACK(neonserv_cmd_invite_timeout_timeout);
-static struct neonserv_cmd_invite_timeout* neonserv_cmd_invite_add_timeout(char *nick, char *chan);
-static int neonserv_cmd_invite_is_timeout(char *nick, char *chan);
-static void neonserv_cmd_invite_del_timeout(struct neonserv_cmd_invite_timeout *timeout);
-
-
-struct neonserv_cmd_invite_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-};
-
-struct neonserv_cmd_invite_timeout {
-    char *nick;
-    char *chan;
-    
-    struct neonserv_cmd_invite_timeout *next;
-};
-
-static struct neonserv_cmd_invite_timeout *first_timeout = NULL, *last_timeout = NULL;
-
-CMD_BIND(neonserv_cmd_invite) {
-    if(neonserv_cmd_invite_is_timeout(argv[0], chan->name)) {
-        reply(getTextBot(), user, "NS_INVITE_TIMEOUT", argv[0], chan->name);
-        return;
-    }
-    struct UserNode *cuser = getUserByNick(argv[0]);
-    if(!cuser) {
-        cuser = createTempUser(argv[0]);
-        cuser->flags |= USERFLAG_ISTMPUSER;
-    } else if(getChanUser(cuser, chan)) {
-        reply(getTextBot(), user, "NS_INVITE_ON_CHAN", cuser->nick, chan->name);
-        /* BUG
-         This check does not work if the user is invisible (CHMODE +D/+d)
-         to fix this we'd need to request the full userlist...
-         this is really senseless to invite a simple user so we simply mark this bug as unsolvable.
-        */
-        return;
-    }
-    if(cuser->flags & USERFLAG_ISAUTHED) {
-        neonserv_cmd_invite_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
-    } else {
-        struct neonserv_cmd_invite_cache *cache = malloc(sizeof(*cache));
-        if (!cache) {
-            perror("malloc() failed");
-            return;
-        }
-        cache->client = client;
-        cache->textclient = getTextBot();
-        cache->user = user;
-        cache->chan = chan;
-        cache->event = event;
-        cache->nick = strdup(argv[0]);
-        get_userauth(cuser, neonserv_cmd_invite_nick_lookup, cache);
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_invite_nick_lookup) {
-    struct neonserv_cmd_invite_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    } else
-        neonserv_cmd_invite_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, ((user->flags & USERFLAG_ISAUTHED) ? user->auth : NULL));
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_invite_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
-    if(auth) {
-        MYSQL_RES *res;
-        MYSQL_ROW row;
-        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            //check if the user has set noinvite
-            printf_mysql_query("SELECT `id` FROM `noinvite` WHERE `uid` = '%s' AND `cid` = '%d'", row[0], chan->channel_id);
-            res = mysql_use();
-            if ((row = mysql_fetch_row(res)) != NULL) {
-                reply(textclient, user, "NS_INVITE_RESTRICTION", nick, chan->name);
-                return;
-            }
-        }
-    }
-    struct neonserv_cmd_invite_timeout *timeout = neonserv_cmd_invite_add_timeout(nick, chan->name);
-    timeq_add(INVITE_TIMEOUT, neonserv_cmd_invite_timeout_timeout, timeout);
-    putsock(client, "INVITE %s %s", nick, chan->name);
-    struct UserNode *tmpu = getUserByNick(nick);
-    if(!tmpu) {
-        tmpu = createTempUser(nick);
-        tmpu->flags |= USERFLAG_ISTMPUSER | (auth ? USERFLAG_ISAUTHED : 0);
-        if(auth)
-            strcpy(tmpu->auth, auth);
-    }
-    reply(textclient, tmpu, "NS_INVITE_DONE_USER", chan->name, user->nick, client->user->nick);
-    reply(textclient, user, "NS_INVITE_DONE", nick, chan->name);
-}
-
-static TIMEQ_CALLBACK(neonserv_cmd_invite_timeout_timeout) {
-    struct neonserv_cmd_invite_timeout *entry = data;
-    neonserv_cmd_invite_del_timeout(entry);
-}
-
-static struct neonserv_cmd_invite_timeout* neonserv_cmd_invite_add_timeout(char *nick, char *chan) {
-    struct neonserv_cmd_invite_timeout *entry = malloc(sizeof(*entry));
-    if (!entry) {
-        perror("malloc() failed");
-        return NULL;
-    }
-    entry->next = NULL;
-    entry->nick = strdup(nick);
-    entry->chan = strdup(chan);
-    if(last_timeout) {
-        last_timeout->next = entry;
-        last_timeout = entry;
-    } else {
-        last_timeout = entry;
-        first_timeout = entry;
-    }
-    return entry;
-}
-
-static int neonserv_cmd_invite_is_timeout(char *nick, char *chan) {
-    if(!first_timeout) return 0;
-    struct neonserv_cmd_invite_timeout *entry;
-    for(entry = first_timeout; entry; entry = entry->next) {
-        if(!stricmp(entry->nick, nick) && !stricmp(entry->chan, chan))
-            return 1;
-    }
-    return 0;
-}
-
-static void neonserv_cmd_invite_del_timeout(struct neonserv_cmd_invite_timeout *timeout) {
-    struct neonserv_cmd_invite_timeout *entry, *prev = NULL;
-    for(entry = first_timeout; entry; entry = entry->next) {
-        if(entry == timeout) {
-            if(prev)
-                prev->next = entry->next;
-            else
-                first_timeout = entry->next;
-            break;
-        } else
-            prev = entry;
-    }
-    if(last_timeout == timeout)
-        last_timeout = prev;
-    free(timeout->nick);
-    free(timeout->chan);
-    free(timeout);
-}
diff --git a/cmd_neonserv_inviteme.c b/cmd_neonserv_inviteme.c
deleted file mode 100644 (file)
index a5c3f16..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no arguments
-*/
-
-CMD_BIND(neonserv_cmd_inviteme) {
-    if(getChanUser(user, chan)) {
-        reply(getTextBot(), user, "NS_INVITEME_ON_CHAN", chan->name);
-        /* BUG
-         This check does not work if the user is invisible (CHMODE +D/+d)
-         to fix this we'd need to request the full userlist...
-         this is really senseless to invite a simple user so we simply mark this bug as unsolvable.
-        */
-        return;
-    }
-    putsock(client, "INVITE %s %s", user->nick, chan->name);
-    reply(getTextBot(), user, "NS_INVITEME_DONE", chan->name);
-}
diff --git a/cmd_neonserv_kick.c b/cmd_neonserv_kick.c
deleted file mode 100644 (file)
index 373881c..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    nick[,*auth[,*!*@mask[...]]]
-* argv[1-*]  reason
-*/
-static USERLIST_CALLBACK(neonserv_cmd_kick_userlist_lookup);
-static void neonserv_cmd_kick_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason);
-
-struct neonserv_cmd_kick_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *nicks;
-    char *reason;
-};
-
-CMD_BIND(neonserv_cmd_kick) {
-    struct neonserv_cmd_kick_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->nicks = strdup(argv[0]);
-    if(argc > 1) {
-        cache->reason = strdup(merge_argv(argv, 1, argc));
-    } else
-        cache->reason = NULL;
-    get_userlist_with_invisible(chan, neonserv_cmd_kick_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_kick_userlist_lookup) {
-    struct neonserv_cmd_kick_cache *cache = data;
-    neonserv_cmd_kick_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks, (cache->reason ? cache->reason : "Bye."));
-    free(cache->nicks);
-    if(cache->reason)
-        free(cache->reason);
-    free(cache);
-}
-
-static void neonserv_cmd_kick_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason) {
-    int i, kicked_users = 0, provided_nicks = 0;
-    char *nick, *nextnick;
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    nextnick = nicks;
-    while((nick = nextnick)) {
-        nextnick = strstr(nick, ",");
-        if(nextnick) {
-            *nextnick = '\0';
-            nextnick++;
-        }
-        if(!*nick) continue;
-        if(is_ircmask(nick)) {
-            //KICK HOSTMASK
-            char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-            struct ChanUser *kick_chanuser[chan->usercount];
-            int kick_chanuser_pos = 0;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                cuser = chanuser->user;
-                sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-                if(!match(nick, usermask)) {
-                    provided_nicks++;
-                    if(isNetworkService(chanuser->user)) {
-                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                        continue;
-                    }
-                    if(isUserProtected(chan, cuser, user)) {
-                        reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                        continue;
-                    }
-                    kick_chanuser[kick_chanuser_pos++] = chanuser;
-                    if(kick_chanuser_pos > 4 && (kick_chanuser_pos * 3) > chan->usercount && !isGodMode(user)) {
-                        kick_chanuser_pos = 0;
-                        reply(textclient, user, "NS_LAME_MASK", nick);
-                        break;
-                    }
-                }
-            }
-            for(i = 0; i < kick_chanuser_pos; i++) {
-                kicked_users++;
-                putsock(client, "KICK %s %s :%s", chan->name, kick_chanuser[i]->user->nick, reason);
-            }
-        } else if(*nick == '*') {
-            //KICK AUTH
-            nick++;
-            cuser = NULL;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !stricmp(chanuser->user->auth, nick)) {
-                    provided_nicks++;
-                    if(isNetworkService(chanuser->user)) {
-                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                        continue;
-                    }
-                    if(!cuser) {
-                        //check if the user is protected
-                        if(isUserProtected(chan, chanuser->user, user)) {
-                            reply(textclient, user, "NS_USER_PROTECTED", chanuser->user->nick);
-                            break; //all other users are also protected...
-                        }
-                        cuser = chanuser->user;
-                    }
-                    kicked_users++;
-                    putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
-                }
-            }
-        } else {
-            provided_nicks++;
-            cuser = NULL;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                if(!stricmp(chanuser->user->nick, nick)) {
-                    cuser = chanuser->user;
-                }
-            }
-            if(!cuser) continue;
-            if(isNetworkService(cuser)) {
-                reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
-                continue;
-            }
-            if(isUserProtected(chan, cuser, user)) {
-                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                continue;
-            }
-            kicked_users++;
-            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
-        }
-    }
-    if(kicked_users == provided_nicks)
-        reply(getTextBot(), user, "NS_KICK_DONE", kicked_users, chan->name);
-    else
-        reply(getTextBot(), user, "NS_KICK_FAIL", client->user->nick);
-    if(kicked_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_kickban.c b/cmd_neonserv_kickban.c
deleted file mode 100644 (file)
index 1907706..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    nick[,*auth[,*!*@mask[...]]]
-* argv[1-*]  reason
-*/
-static USERLIST_CALLBACK(neonserv_cmd_kickban_userlist_lookup);
-static void neonserv_cmd_kickban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason);
-
-struct neonserv_cmd_kickban_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *nicks;
-    char *reason;
-};
-
-CMD_BIND(neonserv_cmd_kickban) {
-    struct neonserv_cmd_kickban_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->nicks = strdup(argv[0]);
-    if(argc > 1) {
-        cache->reason = strdup(merge_argv(argv, 1, argc));
-    } else
-        cache->reason = NULL;
-    get_userlist_with_invisible(chan, neonserv_cmd_kickban_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_kickban_userlist_lookup) {
-    struct neonserv_cmd_kickban_cache *cache = data;
-    neonserv_cmd_kickban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks, (cache->reason ? cache->reason : "Bye."));
-    free(cache->nicks);
-    if(cache->reason)
-        free(cache->reason);
-    free(cache);
-}
-
-static void neonserv_cmd_kickban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason) {
-    int i, kicked_users = 0, provided_nicks = 0;
-    char *nick, *nextnick;
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-    nextnick = nicks;
-    while((nick = nextnick)) {
-        nextnick = strstr(nick, ",");
-        if(nextnick) {
-            *nextnick = '\0';
-            nextnick++;
-        }
-        if(!*nick) continue;
-        if(is_ircmask(nick)) {
-            //KICK HOSTMASK
-            struct ChanUser *kickban_chanuser[chan->usercount];
-            int kick_chanuser_pos = 0;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                cuser = chanuser->user;
-                sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-                if(!match(nick, usermask)) {
-                    provided_nicks++;
-                    if(isNetworkService(chanuser->user)) {
-                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                        continue;
-                    }
-                    if(isUserProtected(chan, cuser, user)) {
-                        reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                        continue;
-                    }
-                    kickban_chanuser[kick_chanuser_pos++] = chanuser;
-                    if(kick_chanuser_pos > 4 && (kick_chanuser_pos * 3) > chan->usercount && !isGodMode(user)) {
-                        kick_chanuser_pos = 0;
-                        reply(textclient, user, "NS_LAME_MASK", nick);
-                        break;
-                    }
-                }
-            }
-            for(i = 0; i < kick_chanuser_pos; i++) {
-                if(i == 0) {
-                    putsock(client, "MODE %s +b %s", chan->name, nick);
-                }
-                kicked_users++;
-                putsock(client, "KICK %s %s :%s", chan->name, kickban_chanuser[i]->user->nick, reason);
-            }
-        } else if(*nick == '*') {
-            //KICK AUTH
-            nick++;
-            cuser = NULL;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !stricmp(chanuser->user->auth, nick)) {
-                    provided_nicks++;
-                    if(isNetworkService(chanuser->user)) {
-                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                        continue;
-                    }
-                    if(!cuser) {
-                        //check if the user is protected
-                        if(isUserProtected(chan, chanuser->user, user)) {
-                            reply(textclient, user, "NS_USER_PROTECTED", chanuser->user->nick);
-                            break; //all other users are also protected...
-                        }
-                        cuser = chanuser->user;
-                    }
-                    kicked_users++;
-                    putsock(client, "MODE %s +b %s", chan->name, generate_banmask(cuser, usermask));
-                    putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
-                }
-            }
-        } else {
-            provided_nicks++;
-            cuser = searchUserByNick(nick);
-            if(!cuser) continue;
-            chanuser = getChanUser(cuser, chan);
-            if(!chanuser) continue;
-            if(isNetworkService(cuser)) {
-                reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
-                continue;
-            }
-            if(isUserProtected(chan, cuser, user)) {
-                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                continue;
-            }
-            kicked_users++;
-            putsock(client, "MODE %s +b %s", chan->name, generate_banmask(cuser, usermask));
-            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
-        }
-    }
-    if(kicked_users == provided_nicks)
-        reply(getTextBot(), user, "NS_KICKBAN_DONE", kicked_users, chan->name);
-    else
-        reply(getTextBot(), user, "NS_KICKBAN_FAIL", client->user->nick);
-    if(kicked_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_mdeluser.c b/cmd_neonserv_mdeluser.c
deleted file mode 100644 (file)
index 5b09822..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]  access (format: minaccess-maxaccess)
-* argv[1]  pattern
-*/
-
-CMD_BIND(neonserv_cmd_mdeluser) {
-    if(!checkChannelAccess(user, chan, "channel_candel", 1, 0)) {
-        reply(getTextBot(), user, "NS_ACCESS_DENIED");
-        return;
-    }
-    int min_access, max_access;
-    char *seperator = strstr(argv[0], "-");
-    if(seperator) {
-        *seperator = '\0';
-        seperator++;
-        min_access = atoi(argv[0]);
-        max_access = atoi(seperator);
-        if(max_access > min_access) {
-            reply(getTextBot(), user, "NS_INVALID_ACCESS_RANGE", min_access, max_access);
-            return;
-        }
-    } else {
-        min_access = atoi(argv[0]);
-        max_access = min_access;
-    }
-    if(max_access >= getChannelAccess(user, chan, 1)) {
-        reply(getTextBot(), user, "NS_NO_ACCESS");
-        return;
-    }
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int del_count = 0;
-    printf_mysql_query("SELECT `user_user`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `chanuser_access` >= '%d' AND `chanuser_access` <= '%d'", chan->channel_id, min_access, max_access);
-    res = mysql_use();
-    while((row = mysql_fetch_row(res)) != NULL) {
-        if(!match(argv[1], row[0])) {
-            del_count++;
-            printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[1]);
-        }
-    }
-    reply(getTextBot(), user, "NS_MDELUSER_DONE", del_count, argv[1], min_access, max_access, chan->name);
-    if(del_count)
-        logEvent(event);
-}
-
diff --git a/cmd_neonserv_mode.c b/cmd_neonserv_mode.c
deleted file mode 100644 (file)
index f7f2db1..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - modes
-* argv[1-*] - parameters
-*/
-static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup);
-static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode);
-
-struct neonserv_cmd_mode_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *mode;
-};
-
-CMD_BIND(neonserv_cmd_mode) {
-    struct neonserv_cmd_mode_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->mode = strdup(merge_argv(argv, 0, argc));
-    get_userlist_with_invisible(chan, neonserv_cmd_mode_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup) {
-    struct neonserv_cmd_mode_cache *cache = data;
-    neonserv_cmd_mode_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mode);
-    free(cache->mode);
-    free(cache);
-}
-
-static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode) {
-    MYSQL_ROW row, defaults = NULL;
-    int i, arg, add = 1, skip = 0;
-    unsigned int modetype;
-    int db_canop, db_canvoice, db_canban, db_enfmodes;
-    struct ModeNode *modelock = createModeNode(NULL), *changemodes = createModeNode(NULL);
-    struct ModeBuffer *modeBuf;
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    modeBuf = initModeBuffer(client, chan);
-    printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    row = mysql_fetch_row(mysql_use());
-    if(row[0] == NULL || row[1] == NULL || row[2] == NULL || row[3] == NULL) {
-        printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
-        defaults = mysql_fetch_row(mysql_use());
-    }
-    db_canop = atoi((row[0] ? row[0] : defaults[0]));
-    db_canvoice = atoi((row[1] ? row[1] : defaults[1]));
-    db_canban = atoi((row[2] ? row[2] : defaults[2]));
-    db_enfmodes = atoi((row[3] ? row[3] : defaults[3]));
-    if(row[4])
-        parseModeString(modelock, row[4]);
-    else if(defaults[4])
-        parseModeString(modelock, defaults[4]);
-    int uaccess = getChannelAccess(user, chan, 0);
-    char *a, *b = mode;
-    char *argv[MAXNUMPARAMS];
-    char *carg;
-    char tmp[MAXLEN];
-    int argc = 0;
-    do {
-        a = strstr(b, " ");
-        if(a) *a = '\0';
-        argv[argc++] = b;
-        if(argc == MAXNUMPARAMS) break;
-        if(a) b = a+1;
-    } while(a);
-    arg = 0;
-    while(arg < argc) {
-        char *modeStr = argv[arg++];
-        for(i = 0; i < strlen(modeStr); i++) {
-            switch(modeStr[i]) {
-                case '+':
-                    add = 1;
-                    break;
-                case '-':
-                    add = 0;
-                    break;
-                case 'o':
-                case 'v':
-                    if(arg == argc) {
-                        reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
-                        return;
-                    }
-                    carg = argv[arg++];
-                    if(modeStr[i] == 'o') {
-                        if(uaccess < db_canop) {
-                            reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
-                            db_canop = -1;
-                            break;
-                        }
-                        if(db_canop == -1) break;
-                    } else {
-                        if(uaccess < db_canvoice) {
-                            reply(textclient, user, "NS_MODE_ENFVOICE", chan->name);
-                            db_canvoice = -1;
-                            break;
-                        }
-                        if(db_canvoice == -1) break;
-                    }
-                    cuser = searchUserByNick(carg);
-                    if(!cuser) {
-                        //check for an invisible user
-                        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                            if(!stricmp(chanuser->user->nick, carg)) {
-                                cuser = chanuser->user;
-                                break;
-                            }
-                        }
-                        if(!cuser) break;
-                    } else {
-                        chanuser = getChanUser(cuser, chan);
-                        if(!chanuser) break;
-                    }
-                    if(!(add ^ (chanuser->flags & (modeStr[i] == 'o' ? CHANUSERFLAG_OPPED : CHANUSERFLAG_VOICED)))) break;
-                    if(!add) {
-                        //check protection
-                        if(modeStr[i] == 'o' && isNetworkService(cuser)) {
-                            reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
-                            break;
-                        }
-                        if(isUserProtected(chan, cuser, user)) {
-                            reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                            break;
-                        }
-                    }
-                    modeBufferSet(modeBuf, add, modeStr[i], carg);
-                    break;
-                case 'b':
-                    if(arg == argc) {
-                        reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
-                        return;
-                    }
-                    carg = argv[arg++];
-                    if(uaccess < db_canban) {
-                        reply(textclient, user, "NS_MODE_CANBAN", chan->name);
-                        db_canban = -1;
-                        break;
-                    }
-                    if(db_canban == -1) break;
-                    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
-                    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-                    struct BanNode *ban;
-                    int match_count = 0;
-                    carg = make_banmask(carg, hostmask_buffer);
-                    if(add) {
-                        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                            cuser = chanuser->user;
-                            sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-                            if(!match(carg, usermask)) {
-                                if(isNetworkService(chanuser->user)) {
-                                    reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
-                                    skip = 1;
-                                    break;
-                                }
-                                if(isUserProtected(chan, cuser, user)) {
-                                    reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
-                                    skip = 1;
-                                    break;
-                                }
-                                match_count++;
-                                if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
-                                    skip = 1;
-                                    reply(textclient, user, "NS_LAME_MASK", carg);
-                                    break;
-                                }
-                            }
-                        }
-                    } else {
-                        skip = 1;
-                        for(ban = chan->bans; ban; ban = ban->next) {
-                            if(!match(carg, ban->mask)) {
-                                skip = 0;
-                                break;
-                            }
-                        }
-                    }
-                    if(!skip) {
-                        modeBufferSet(modeBuf, add, 'b', carg);
-                    }
-                    break;
-                default:
-                    modetype = getModeType(modelock, modeStr[i]);
-                    if(modetype == 0) {
-                        reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
-                        return;
-                    }
-                    if(isModeAffected(modelock, modeStr[i]) && add == !isModeSet(modelock, modeStr[i]) && uaccess < db_enfmodes) {
-                        if(isGodMode(user))
-                            event->flags |= CMDFLAG_OPLOG;
-                        else {
-                            getFullModeString(modelock, tmp);
-                            reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
-                            return;
-                        }
-                    }
-                    if(add && (modetype & CHANNEL_MODE_TYPE) != CHANNEL_MODE_TYPE_D) {
-                        if(arg == argc) {
-                            reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
-                            return;
-                        }
-                        carg = argv[arg++];
-                        if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
-                            char *modelock_val = getModeValue(modelock, modeStr[i]);
-                            if(stricmp(carg, modelock_val)) {
-                                if(isGodMode(user))
-                                    event->flags |= CMDFLAG_OPLOG;
-                                else {
-                                    getFullModeString(modelock, tmp);
-                                    reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
-                                    return;
-                                }
-                            }
-                        }
-                        if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
-                            int *modelock_val = getModeValue(modelock, modeStr[i]);
-                            if(atoi(carg) != *modelock_val) {
-                                if(isGodMode(user))
-                                    event->flags |= CMDFLAG_OPLOG;
-                                else {
-                                    getFullModeString(modelock, tmp);
-                                    reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
-                                    return;
-                                }
-                            }
-                        }
-                    } else
-                        carg = NULL;
-                    if((modetype & CHANNEL_MODE_TYPE) == CHANNEL_MODE_TYPE_D && isModeSet(chan->modes, modeStr[i]) == add)
-                        break;
-                    if(!isModeAffected(changemodes, modeStr[i])) {
-                        if(!add && (modetype & CHANNEL_MODE_KEY)) {
-                            if(isModeSet(chan->modes, modeStr[i])) {
-                                char *current_val = getModeValue(chan->modes, modeStr[i]);
-                                carg = current_val;
-                            }
-                        }
-                        if(parseMode(changemodes, add, modeStr[i], carg)) {
-                            if(carg) {
-                                if(add && (modetype & CHANNEL_MODE_KEY) && isModeSet(chan->modes, modeStr[i])) {
-                                    char *current_val = getModeValue(chan->modes, modeStr[i]);
-                                    modeBufferSet(modeBuf, 0, modeStr[i], current_val);
-                                    flushModeBuffer(modeBuf);
-                                }
-                                if(!add && !isModeSet(chan->modes, modeStr[i])) break;
-                                modeBufferSet(modeBuf, add, modeStr[i], carg);
-                            } else {
-                                modeBufferSimpleMode(modeBuf, add, modeStr[i]);
-                            }
-                        } else {
-                            reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
-                            return;
-                        }
-                    }
-                    break;
-            }
-        }
-    }
-    getFullModeString(changemodes, tmp);
-    freeModeBuffer(modeBuf);
-    if(strcmp(tmp, "+"))
-        reply(textclient, user, "NS_MODE_DONE", tmp);
-    
-    logEvent(event);
-    freeModeNode(modelock);
-    freeModeNode(changemodes);
-}
diff --git a/cmd_neonserv_move.c b/cmd_neonserv_move.c
deleted file mode 100644 (file)
index 804954f..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - channel
-* argv[1] - new channel
-*/
-CMD_BIND(neonserv_cmd_move) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    char *channel = argv[0];
-    char *new_channel = argv[1];
-    if(!is_valid_chan(new_channel)) {
-        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", new_channel);
-        return;
-    }
-    if(!stricmp(channel, new_channel)) {
-        reply(getTextBot(), user, "NS_MOVE_SELF");
-        return;
-    }
-    printf_mysql_query("SELECT `channel_id` FROM `bot_channels` LEFT JOIN `channels` ON `channel_id` = `chanid` WHERE `channel_name` = '%s'", escape_string(new_channel));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        reply(getTextBot(), user, "NS_REGISTER_ALREADY", new_channel, client->user->nick);
-        return;
-    }
-    int chanid;
-    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        chanid = atoi(row[0]);
-    } else {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    if(!strcmp(row[2], "1")) {
-        reply(getTextBot(), user, "NS_MOVE_SUSPENDED");
-        return;
-    }
-    int botid = atoi(row[0]);
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid)
-            break;
-    }
-    if(bot) {
-        putsock(bot, "PART %s :Channel moved to %s.", channel, new_channel);
-        putsock(bot, "JOIN %s", new_channel);
-    }
-    printf_mysql_query("DELETE FROM `channels` WHERE `channel_name` = '%s'", escape_string(new_channel));
-    printf_mysql_query("UPDATE `channels` SET `channel_name` = '%s' WHERE `channel_id` = '%s'", escape_string(new_channel), row[1]);
-    struct ChanNode *channode = getChanByName(channel);
-    if(channode && channode->flags & CHANFLAG_REQUESTED_CHANINFO) {
-        channode->flags &= ~CHANFLAG_CHAN_REGISTERED;
-        channode->channel_id = 0;
-    }
-    channode = getChanByName(new_channel);
-    if(channode && channode->flags & CHANFLAG_REQUESTED_CHANINFO) {
-        channode->flags |= CHANFLAG_CHAN_REGISTERED;
-        channode->channel_id = atoi(row[1]);
-    }
-    reply(getTextBot(), user, "NS_MOVE_DONE", channel, new_channel);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_myaccess.c b/cmd_neonserv_myaccess.c
deleted file mode 100644 (file)
index 093e28a..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_myaccess_nick_lookup);
-static void neonserv_cmd_myaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, char *chanmatch);
-
-struct neonserv_cmd_myaccess_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    char *nick;
-    char *chanmatch;
-};
-
-CMD_BIND(neonserv_cmd_myaccess) {
-    char *chanmatch = NULL;
-    if(argc == 0 || argv[0][0] == '#') {
-        if(argc != 0) {
-            chanmatch = argv[0];
-        }
-        if(!(user->flags & USERFLAG_ISAUTHED)) {
-            struct neonserv_cmd_myaccess_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->nick = strdup(argv[0]);
-            cache->chanmatch = (chanmatch ? strdup(chanmatch) : NULL);
-            get_userauth(user, neonserv_cmd_myaccess_nick_lookup, cache);
-        } else
-            neonserv_cmd_myaccess_async1(client, getTextBot(), user, chan, user->nick, user->auth, chanmatch);
-    }
-    else if(argv[0][0] == '*') {
-        //we've got an auth
-        if(argc > 1 && argv[1][0] == '#') {
-            chanmatch = argv[1];
-        }
-        argv[0]++;
-        neonserv_cmd_myaccess_async1(client, getTextBot(), user, chan, NULL, argv[0], chanmatch);
-    } else {
-        if(argc > 1 && argv[1][0] == '#') {
-            chanmatch = argv[1];
-        }
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_myaccess_async1(client, getTextBot(), user, chan, argv[0], cuser->auth, chanmatch);
-        } else {
-            struct neonserv_cmd_myaccess_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->nick = strdup(argv[0]);
-            cache->chanmatch = (chanmatch ? strdup(chanmatch) : NULL);
-            get_userauth(cuser, neonserv_cmd_myaccess_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_myaccess_nick_lookup) {
-    struct neonserv_cmd_myaccess_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        if(!strcmp(cache->nick, cache->user->nick))
-            reply(cache->textclient, cache->user, "NS_YOU_NEED_AUTH");
-        else
-            reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_myaccess_async1(cache->client, cache->textclient, cache->user, cache->chan, user->nick, user->auth, cache->chanmatch);
-    if(cache->chanmatch)
-        free(cache->chanmatch);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_myaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, char *chanmatch) {
-    //we've got a valid auth now...
-    MYSQL_RES *res, *default_res;
-    MYSQL_ROW user_row, chanuser_row, default_chan = NULL;
-    char flagBuf[5];
-    int userid, cflags, caccess, flagPos;
-    int i, total_count, match_count = 0, owner_count = 0;
-    struct Table *table;
-    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    total_count = mysql_num_rows(res);
-    table = table_init(4, total_count + 1, 0);
-    char *content[4];
-    content[0] = get_language_string(user, "NS_MYACCESS_HEADER_NAME");
-    content[1] = get_language_string(user, "NS_MYACCESS_HEADER_ACCESS");
-    content[2] = get_language_string(user, "NS_MYACCESS_HEADER_FLAGS");
-    content[3] = get_language_string(user, "NS_MYACCESS_HEADER_INFO");
-    table_add(table, content);
-    if(chanmatch)
-        reply(textclient, user, "NS_MYACCESS_HEADER_MATCH", auth, chanmatch);
-    else
-        reply(textclient, user, "NS_MYACCESS_HEADER", auth);
-    if ((user_row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(user_row[0]);
-        //check if the user is already added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags`, `chanuser_infoline`, `channel_name`, `channel_getop`, `channel_getvoice` FROM `chanusers` LEFT JOIN `channels` ON `chanuser_cid` = `channel_id` WHERE `chanuser_uid` = '%d' ORDER BY `chanuser_access` DESC, `channel_name` ASC", userid);
-        res = mysql_use();
-        while ((chanuser_row = mysql_fetch_row(res)) != NULL) {
-            if(!strcmp(chanuser_row[0], "500")) owner_count++;
-            if(chanmatch && match(chanmatch, chanuser_row[0])) continue;
-            match_count++;
-            if((!chanuser_row[4] || !chanuser_row[5]) && !default_chan) {
-                printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
-                default_res = mysql_use();
-                default_chan = mysql_fetch_row(default_res);
-            }
-            flagPos = 0;
-            content[0] = chanuser_row[3];
-            content[1] = chanuser_row[0];
-            cflags = atoi(chanuser_row[1]);
-            caccess = atoi(chanuser_row[0]);
-            if((cflags & DB_CHANUSER_SUSPENDED))
-                flagPos += sprintf(flagBuf + flagPos, "s");
-            if(caccess >= (chanuser_row[4] ? atoi(chanuser_row[4]) : atoi(default_chan[0])))
-                flagPos += sprintf(flagBuf + flagPos, "o");
-            if(caccess >= (chanuser_row[5] ? atoi(chanuser_row[5]) : atoi(default_chan[1])))
-                flagPos += sprintf(flagBuf + flagPos, "v");
-            if((cflags & DB_CHANUSER_AUTOINVITE))
-                flagPos += sprintf(flagBuf + flagPos, "i");
-            content[2] = flagBuf;
-            content[3] = chanuser_row[2];
-            table_add(table, content);
-        }
-    }
-    //send the table
-    char **table_lines = table_end(table);
-    for(i = 0; i < table->entrys; i++) {
-        reply(textclient, user, table_lines[i]);
-    }
-    if(!match_count)
-        reply(textclient, user, "NS_TABLE_NONE");
-    if(chanmatch) {
-        reply(textclient, user, "NS_MYACCESS_COUNT_MATCH", auth, total_count, owner_count, match_count, chanmatch);
-    } else {
-        reply(textclient, user, "NS_MYACCESS_COUNT", auth, total_count, owner_count);
-    }
-}
diff --git a/cmd_neonserv_netinfo.c b/cmd_neonserv_netinfo.c
deleted file mode 100644 (file)
index c8fd1b6..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no args
-*/
-
-CMD_BIND(neonserv_cmd_netinfo) {
-    reply(getTextBot(), user, "NS_NETINFO_HEADER");
-    char tmp[MAXLEN];
-    struct Table *table;
-    table = table_init(2, 18, 0);
-    char *content[2];
-    
-    content[0] = get_language_string(user, "NS_NETINFO_UPTIME");
-    content[1] = timeToStr(user, (time(0) - start_time), 3, tmp);
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_BOTS");
-    struct ClientSocket *cclient;
-    int bot_count = 0, connected_bot_count = 0;
-    float traffic_in = 0, traffic_out = 0;
-    for(cclient = getBots(0, NULL); cclient; cclient = getBots(0, cclient)) {
-        bot_count++;
-        if(cclient->flags & SOCKET_FLAG_READY)
-            connected_bot_count++;
-        traffic_in += cclient->traffic_in;
-        traffic_out += cclient->traffic_out;
-    }
-    sprintf(tmp, "%d (%d connected)", bot_count, connected_bot_count);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_TRAFFIC");
-    sprintf(tmp, "in: %.2f kb  out: %.2f kb", traffic_in / 1024, traffic_out / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    int channel_count = getChannelCount();
-    float channel_memory = channel_count * sizeof(struct ChanNode);
-    int channel_ban_count = getChanBanCount();
-    float channel_ban_memory = channel_ban_count * sizeof(struct BanNode);
-    int user_count = getUserCount();
-    float user_memory = user_count * sizeof(struct UserNode);
-    int chanuser_count = getChanUserCount();
-    float chanuser_memory = chanuser_count * sizeof(struct ChanUser);
-    float total_memory = channel_memory + channel_ban_memory + user_memory + chanuser_memory;
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CACHE");
-    sprintf(tmp, "%.2f kB (%.2f MB)", total_memory / 1024, total_memory / 1024 / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL");
-    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", channel_count, channel_memory / 1024, channel_count, sizeof(struct ChanNode), channel_memory / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL_BAN");
-    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", channel_ban_count, channel_ban_memory / 1024, channel_ban_count, sizeof(struct BanNode), channel_ban_memory / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_USER");
-    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", user_count, user_memory / 1024, user_count, sizeof(struct UserNode), user_memory / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CHANUSER");
-    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", chanuser_count, chanuser_memory / 1024, chanuser_count, sizeof(struct ChanUser), chanuser_memory / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SHOW TABLE STATUS");
-    res = mysql_use();
-    int mysql_entrys[4];
-    float mysql_length[5];
-    total_memory = 0;
-    mysql_entrys[0] = 0; mysql_entrys[1] = 0; mysql_entrys[2] = 0; mysql_entrys[3] = 0;
-    mysql_length[0] = 0; mysql_length[1] = 0; mysql_length[2] = 0; mysql_length[3] = 0; mysql_length[4] = 0;
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(!stricmp(row[0], "channels")) {
-            mysql_entrys[0] = atoi(row[4]);
-            mysql_length[0] = atof(row[6]);
-            total_memory += atof(row[6]);
-        } else if(!stricmp(row[0], "bans")) {
-            mysql_entrys[1] = atoi(row[4]);
-            mysql_length[1] = atof(row[6]);
-            total_memory += atof(row[6]);
-        } else if(!stricmp(row[0], "users")) {
-            mysql_entrys[2] = atoi(row[4]);
-            mysql_length[2] = atof(row[6]);
-            total_memory += atof(row[6]);
-        } else if(!stricmp(row[0], "chanusers")) {
-            mysql_entrys[3] = atoi(row[4]);
-            mysql_length[3] = atof(row[6]);
-            total_memory += atof(row[6]);
-        } else {
-            mysql_length[4] += atof(row[6]);
-            total_memory += atof(row[6]);
-        }
-    }
-    
-    content[0] = get_language_string(user, "NS_NETINFO_DATABASE");
-    sprintf(tmp, "%.2f kB (%.2f MB)", total_memory / 1024, total_memory / 1024 / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL");
-    sprintf(tmp, "%d    %.2f kB", mysql_entrys[0], mysql_length[0] / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL_BAN");
-    sprintf(tmp, "%d    %.2f kB", mysql_entrys[1], mysql_length[1] / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_USER");
-    sprintf(tmp, "%d    %.2f kB", mysql_entrys[2], mysql_length[2] / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CHANUSER");
-    sprintf(tmp, "%d    %.2f kB", mysql_entrys[3], mysql_length[3] / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_OTHER");
-    sprintf(tmp, "*     %.2f kB", mysql_length[4] / 1024);
-    content[1] = tmp;
-    table_add(table, content);
-    
-    if(strcmp(revision, ""))
-        sprintf(tmp, "%s  (%s)", NEONSERV_VERSION, revision);
-    else 
-        strcpy(tmp, NEONSERV_VERSION);
-    content[0] = get_language_string(user, "NS_NETINFO_VERSION");
-    content[1] = tmp;
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_COMPILER");
-    content[1] = build_language_string(user, tmp, "NS_NETINFO_COMPILER_VALUE", COMPILER, creation);
-    table_add(table, content);
-    
-    content[0] = get_language_string(user, "NS_NETINFO_CODE");
-    content[1] = build_language_string(user, tmp, "NS_NETINFO_CODE_VALUE", codelines);
-    table_add(table, content);
-    
-    char **table_lines = table_end(table);
-    int i;
-    for(i = 0; i < table->entrys; i++) {
-        reply(getTextBot(), user, table_lines[i]);
-    }
-    table_free(table);
-}
-
diff --git a/cmd_neonserv_notice.c b/cmd_neonserv_notice.c
deleted file mode 100644 (file)
index 26776c0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    target
-* argv[1-*]  message
-*/
-
-CMD_BIND(neonserv_cmd_notice) {
-    char *message = merge_argv(argv, 1, argc);
-    putsock(client, "NOTICE %s :%s", argv[0], message);
-}
\ No newline at end of file
diff --git a/cmd_neonserv_op.c b/cmd_neonserv_op.c
deleted file mode 100644 (file)
index 2bf69c0..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nicks
-*/
-static USERLIST_CALLBACK(neonserv_cmd_op_userlist_lookup);
-static void neonserv_cmd_op_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks);
-
-struct neonserv_cmd_op_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *nicks;
-};
-
-CMD_BIND(neonserv_cmd_op) {
-    struct neonserv_cmd_op_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->nicks = strdup(merge_argv(argv, 0, argc));
-    get_userlist_with_invisible(chan, neonserv_cmd_op_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_op_userlist_lookup) {
-    struct neonserv_cmd_op_cache *cache = data;
-    neonserv_cmd_op_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks);
-    free(cache->nicks);
-    free(cache);
-}
-
-static void neonserv_cmd_op_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks) {
-    int total_users = 0, done_users = 0;
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    char *a, *b = nicks;
-    do {
-        a = strstr(b, " ");
-        if(a) *a = '\0';
-        total_users++;
-        cuser = searchUserByNick(b);
-        if(!cuser) {
-            //check for an invisible user
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                if(!stricmp(chanuser->user->nick, b)) {
-                    cuser = chanuser->user;
-                    break;
-                }
-            }
-            if(!cuser) continue;
-        } else {
-            chanuser = getChanUser(cuser, chan);
-            if(!chanuser) continue;
-        }
-        done_users++;
-        if(chanuser->flags & CHANUSERFLAG_OPPED) continue;
-        modeBufferOp(modeBuf, b);
-        if(a) {
-            b = a+1;
-        }
-    } while(a);
-    freeModeBuffer(modeBuf);
-    if(done_users == total_users)
-        reply(textclient, user, "NS_OP_DONE", chan->name);
-    else
-        reply(textclient, user, "NS_OP_FAIL", client->user->nick);
-    if(done_users) 
-        logEvent(event);
-}
diff --git a/cmd_neonserv_opall.c b/cmd_neonserv_opall.c
deleted file mode 100644 (file)
index d97feff..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    "force"
-* argv[1]    (optional) nick mask
-*/
-static USERLIST_CALLBACK(neonserv_cmd_opall_userlist_lookup);
-static void neonserv_cmd_opall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask);
-
-struct neonserv_cmd_opall_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *nickmask;
-};
-
-CMD_BIND(neonserv_cmd_opall) {
-    if(!argc || strcmp(argv[0], "FORCE")) {
-        reply(getTextBot(), user, "NS_OPALL_SECURITY", chan->name);
-        return;
-    }
-    struct neonserv_cmd_opall_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    if(argc > 1) {
-        cache->nickmask = strdup(argv[1]);
-    } else
-        cache->nickmask = NULL;
-    get_userlist_with_invisible(chan, neonserv_cmd_opall_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_opall_userlist_lookup) {
-    struct neonserv_cmd_opall_cache *cache = data;
-    neonserv_cmd_opall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask);
-    if(cache->nickmask)
-        free(cache->nickmask);
-    free(cache);
-}
-
-static void neonserv_cmd_opall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask) {
-    int done_users = 0;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
-        if(chanuser->flags & CHANUSERFLAG_OPPED) continue;
-        modeBufferOp(modeBuf, chanuser->user->nick);
-        done_users++;
-    }
-    freeModeBuffer(modeBuf);
-    reply(textclient, user, "NS_OPALL_DONE", done_users, chan->name);
-    if(done_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_oplog.c b/cmd_neonserv_oplog.c
deleted file mode 100644 (file)
index a69c449..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]     time
-* argv[1-*]   match
-*/
-
-CMD_BIND(neonserv_cmd_oplog) {
-    char *str_match;
-    int duration = (argc ? strToTime(user, argv[0]) : 0);
-    if(argc > (duration ? 1 : 0))
-        str_match = merge_argv(argv, (duration ? 1 : 0), argc);
-    else
-        str_match = "";
-    if(!duration) duration = (60*60*24);
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `godlog_time`, `user_user`, `channel_name`, `godlog_cmd` FROM `godlog` LEFT JOIN `channels` ON `godlog_cid` = `channel_id` LEFT JOIN `users` ON `godlog_uid` = `user_id` WHERE `godlog_time` > '%lu' ORDER BY `godlog_time` ASC", ((unsigned long) time(0) - duration));
-    res = mysql_use();
-    int skip = mysql_num_rows(res) - 100;
-    int count = 0;
-    char timeBuf[50];
-    struct tm *timeinfo;
-    time_t event_time;
-    if(skip < 0) skip = 0;
-    reply(getTextBot(), user, "NS_EVENTS_HEADER");
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(skip) {
-            skip--;
-            continue;
-        }
-        if(*str_match && match(str_match, row[3])) continue;
-        count++;
-        event_time = (time_t) atol(row[0]);
-        timeinfo = localtime(&event_time);
-        strftime(timeBuf, 80, "%X %x", timeinfo);
-        reply(getTextBot(), user, "[%s] [%s%s%s]: %s", timeBuf, row[1], (row[2] ? ":" : ""), (row[2] ? row[2] : ""), row[3]);
-    }
-    reply(getTextBot(), user, "NS_TABLE_COUNT", count);
-}
diff --git a/cmd_neonserv_peek.c b/cmd_neonserv_peek.c
deleted file mode 100644 (file)
index 6724403..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no parameters
-*/
-static USERLIST_CALLBACK(neonserv_cmd_peek_userlist_lookup);
-static void neonserv_cmd_peek_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan);
-
-struct neonserv_cmd_peek_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-};
-
-CMD_BIND(neonserv_cmd_peek) {
-    struct neonserv_cmd_peek_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    get_userlist_with_invisible(chan, neonserv_cmd_peek_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_peek_userlist_lookup) {
-    struct neonserv_cmd_peek_cache *cache = data;
-    neonserv_cmd_peek_async1(cache->client, cache->textclient, cache->user, chan);
-    free(cache);
-}
-
-static void neonserv_cmd_peek_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan) {
-    reply(textclient, user, "NS_PEEK_HEADER", chan->name);
-    reply(textclient, user, "NS_PEEK_TOPIC", chan->topic);
-    char tmpStr[MAXLEN];
-    getModeString(chan->modes, tmpStr);
-    reply(textclient, user, "NS_PEEK_MODES", tmpStr);
-    struct ChanUser *chanuser;
-    int op_count = 0, voice_count = 0, normal_count = 0, invi_count = 0;
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if(chanuser->flags & CHANUSERFLAG_OPPED)
-            op_count++;
-        else if(chanuser->flags & CHANUSERFLAG_VOICED)
-            voice_count++;
-        else if(chanuser->flags & CHANUSERFLAG_VOICED)
-            invi_count++;
-        else
-            normal_count++;
-    }
-    reply(textclient, user, "NS_PEEK_USERS", op_count+voice_count+invi_count+normal_count, op_count, voice_count, normal_count, invi_count);
-    int tmpStrPos = 0;
-    int headerlen = 10 + strlen(user->nick);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if(chanuser->flags & CHANUSERFLAG_OPPED) {
-            if(tmpStrPos + headerlen + strlen(chanuser->user->nick) + 2 >= 512) {
-                //clear buffer
-                reply(textclient, user, "%s", tmpStr);
-                tmpStrPos = 0;
-            }
-            tmpStrPos += sprintf(tmpStr + tmpStrPos, (tmpStrPos ? ", %s" : "%s"), chanuser->user->nick);
-        }
-    }
-    if(tmpStrPos) {
-        reply(textclient, user, "%s", tmpStr);
-    }
-}
diff --git a/cmd_neonserv_raw.c b/cmd_neonserv_raw.c
deleted file mode 100644 (file)
index 4ccce79..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    raw
-*/
-
-CMD_BIND(neonserv_cmd_raw) {
-    char *raw = merge_argv(argv, 0, argc);
-    putsock(client, "%s", raw);
-}
\ No newline at end of file
diff --git a/cmd_neonserv_recover.c b/cmd_neonserv_recover.c
deleted file mode 100644 (file)
index b52e5cc..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - channel
-*/
-CMD_BIND(neonserv_cmd_recover) {
-    MYSQL_RES *res;
-    MYSQL_ROW row, row2;
-    char *channel = argv[0];
-    if(!is_valid_chan(channel)) {
-        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
-        return;
-    }
-    printf_mysql_query("SELECT `botid`, `bot_channels`.`id` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, client->botid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        reply(getTextBot(), user, "NS_REGISTER_ALREADY", argv[0], client->user->nick);
-        return;
-    }
-    int chanid;
-    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        chanid = atoi(row[0]);
-    } else {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    printf_mysql_query("SELECT `id`, `max_channels`, `defaulttrigger` FROM `bots` WHERE `botclass` = '%d' ORDER BY `register_priority` DESC", client->botid);
-    res = mysql_use();
-    int botid = 0;
-    char *bottrigger;
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        //check channel count
-        printf_mysql_query("SELECT COUNT(*) FROM `bot_channels` WHERE `botid` = '%s'", row[0]);
-        row2 = mysql_fetch_row(mysql_use());
-        if(atoi(row2[0]) < atoi(row[1])) {
-            botid = atoi(row[0]);
-            bottrigger = row[2];
-            break;
-        }
-    }
-    if(!botid) {
-        reply(getTextBot(), user, "NS_REGISTER_FULL");
-        return;
-    }
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid)
-            break;
-    }
-    if(bot) {
-        putsock(bot, "JOIN %s", channel);
-    } else
-        reply(getTextBot(), user, "NS_REGISTER_DISCONNECTED");
-    printf_mysql_query("INSERT INTO `bot_channels` (`botid`, `chanid`, `trigger`) VALUES ('%d', '%d', '%s')", botid, chanid, bottrigger);
-    reply(getTextBot(), user, "NS_RECOVER_DONE", channel);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_register.c b/cmd_neonserv_register.c
deleted file mode 100644 (file)
index d336d7f..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - channel
-* argv[0/1] - nick / *auth
-*/
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_register_auth_lookup);
-static USERAUTH_CALLBACK(neonserv_cmd_register_nick_lookup);
-static void neonserv_cmd_register_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *channel, char *auth);
-
-struct neonserv_cmd_register_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-    char *channel;
-};
-
-CMD_BIND(neonserv_cmd_register) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    char *channel = argv[0];
-    if(!is_valid_chan(channel)) {
-        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
-        return;
-    }
-    printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `bot_channels`.`chanid` = `channels`.`channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        reply(getTextBot(), user, "NS_REGISTER_ALREADY", argv[0], client->user->nick);
-        return;
-    }
-    //check own access
-    if(argv[1][0] == '*') {
-        //we've got an auth
-        argv[1]++;
-        printf_mysql_query("SELECT `user_user` FROM `users` WHERE `user_user` = '%s'", escape_string(argv[1]));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            neonserv_cmd_register_async1(client, getTextBot(), user, chan, event, channel, row[0]);
-        } else {
-            //we need to create a new user...
-            //but first lookup the auth to check if it really exists
-            struct neonserv_cmd_register_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[1]);
-            cache->channel = strdup(channel);
-            lookup_authname(argv[1], neonserv_cmd_register_auth_lookup, cache);
-        }
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[1]);
-        if(!cuser) {
-            cuser = createTempUser(argv[1]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_register_async1(client, getTextBot(), user, chan, event, channel, cuser->auth);
-        } else {
-            struct neonserv_cmd_register_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[1]);
-            cache->channel = strdup(channel);
-            get_userauth(cuser, neonserv_cmd_register_nick_lookup, cache);
-        }
-    }
-}
-
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_register_auth_lookup) {
-    struct neonserv_cmd_register_cache *cache = data;
-    if(!exists) {
-        //AUTH_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_AUTH_UNKNOWN", cache->nick);
-    } else
-        neonserv_cmd_register_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, cache->channel, auth);
-    free(cache->channel);
-    free(cache->nick);
-    free(cache);
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_register_nick_lookup) {
-    struct neonserv_cmd_register_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_register_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, cache->channel, user->auth);
-    free(cache->channel);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_register_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *channel, char *auth) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row, row2;
-    int userid, adminid;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL)
-        adminid = atoi(row[0]);
-    else
-        adminid = 0;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-    } else {
-        printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(auth));
-        userid = (int) mysql_insert_id(mysql_conn);
-    }
-    printf_mysql_query("SELECT `id`, `max_channels`, `defaulttrigger` FROM `bots` WHERE `botclass` = '%d' ORDER BY `register_priority` DESC", client->botid);
-    res = mysql_use();
-    int botid = 0;
-    char *bottrigger;
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        //check channel count
-        printf_mysql_query("SELECT COUNT(*) FROM `bot_channels` WHERE `botid` = '%s'", row[0]);
-        row2 = mysql_fetch_row(mysql_use());
-        if(atoi(row2[0]) < atoi(row[1])) {
-            botid = atoi(row[0]);
-            bottrigger = row[2];
-            break;
-        }
-    }
-    if(!botid) {
-        reply(textclient, user, "NS_REGISTER_FULL");
-        return;
-    }
-    int chanid;
-    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        chanid = atoi(row[0]);
-        printf_mysql_query("UPDATE `channels` SET `channel_registered` = UNIX_TIMESTAMP(), `channel_registrator` = '%d' WHERE `channel_id` = '%d'", adminid, chanid);
-    } else {
-        printf_mysql_query("INSERT INTO `channels` (`channel_name`, `channel_registered`, `channel_registrator`) VALUES ('%s', UNIX_TIMESTAMP(), '%d')", escape_string(channel), adminid);
-        chanid = (int) mysql_insert_id(mysql_conn);
-    }
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid)
-            break;
-    }
-    if(bot) {
-        putsock(bot, "JOIN %s", channel);
-    } else
-        reply(textclient, user, "NS_REGISTER_DISCONNECTED");
-    printf_mysql_query("INSERT INTO `bot_channels` (`botid`, `chanid`, `trigger`) VALUES ('%d', '%d', '%s')", botid, chanid, bottrigger);
-    printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_cid` = '%d'", chanid);
-    printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chanid, userid, 500);
-    reply(textclient, user, "NS_REGISTER_DONE", channel, auth);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_reloadlang.c b/cmd_neonserv_reloadlang.c
deleted file mode 100644 (file)
index e5c4f6b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    language tag
-*/
-
-CMD_BIND(neonserv_cmd_reloadlang) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `text`, `lang` FROM `language` WHERE `ident` = 'name' AND `lang` = '%s'", escape_string(argv[0]));
-    res = mysql_use();
-    if((row = mysql_fetch_row(res)) != NULL) {
-        load_language(row[1], row[0]);
-        reply(getTextBot(), user, "NS_RELOADLANG_DONE", row[0], row[1]);
-    } else {
-        reply(getTextBot(), user, "NS_RELOADLANG_UNKNOWN", argv[0]);
-    }
-}
\ No newline at end of file
diff --git a/cmd_neonserv_resync.c b/cmd_neonserv_resync.c
deleted file mode 100644 (file)
index c9d4bba..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - usermask
-* argv[1] - min access
-* argv[2] - max access
-*/
-static USERLIST_CALLBACK(neonserv_cmd_resync_userlist_lookup);
-static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access);
-
-struct neonserv_cmd_resync_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    char *usermask;
-    int min_access;
-    int max_access;
-};
-
-CMD_BIND(neonserv_cmd_resync) {
-    int min_access = 0, max_access = 500;
-    char *usermask = NULL;
-    if(argc > 0)
-        usermask = argv[0];
-    if(argc > 2) {
-        min_access = atoi(argv[1]);
-        max_access = atoi(argv[2]);
-    }
-    struct neonserv_cmd_resync_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->usermask = (usermask ? strdup(usermask) : NULL);
-    cache->min_access = min_access;
-    cache->max_access = max_access;
-    get_userlist_with_invisible(chan, neonserv_cmd_resync_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_resync_userlist_lookup) {
-    struct neonserv_cmd_resync_cache *cache = data;
-    neonserv_cmd_resync_async1(cache->client, cache->textclient, cache->user, chan, cache->usermask, cache->min_access, cache->max_access);
-    if(cache->usermask)
-        free(cache->usermask);
-    free(cache);
-}
-
-static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access) {
-    MYSQL_RES *res;
-    MYSQL_ROW row, defaults = NULL;
-    int i;
-    int resync_op = 1;
-    int resync_voice = 1;
-    if(usermask && usermask[0] == '@') {
-        resync_voice = 0;
-        usermask++;
-        if(!*usermask) usermask = NULL;
-    } else if(usermask && usermask[0] == '+') {
-        resync_op = 0;
-        usermask++;
-        if(!*usermask) usermask = NULL;
-    }
-    struct ChanUser *chanuser;
-    int db_enfops, db_enfvoice;
-    printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    row = mysql_fetch_row(mysql_use());
-    if(row[0] == NULL || row[1] == NULL) {
-        printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
-        defaults = mysql_fetch_row(mysql_use());
-    }
-    db_enfops = atoi((row[0] ? row[0] : defaults[0]));
-    db_enfvoice = atoi((row[1] ? row[1] : defaults[1]));
-    printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' ORDER BY `chanuser_access` DESC, `user_user` ASC", chan->channel_id);
-    res = mysql_use();
-    char *db_users[mysql_num_rows(res)];
-    int db_access[mysql_num_rows(res)];
-    int db_flags[mysql_num_rows(res)];
-    int db_count = 0;
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        db_users[db_count] = row[1];
-        db_access[db_count] = atoi(row[0]);
-        db_flags[db_count] = atoi(row[2]);
-        db_count++;
-    }
-    int caccess, cflags;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        caccess = 0;
-        cflags = 0;
-        if((chanuser->user->flags & USERFLAG_ISAUTHED)) {
-            for(i = 0; i < db_count; i++) {
-                if(!stricmp(db_users[i], chanuser->user->auth)) {
-                    caccess = db_access[i];
-                    cflags = db_flags[i];
-                    break;
-                }
-            }
-        }
-        if((usermask && *usermask && match(usermask, row[1])) || caccess < min_access || caccess > max_access) continue;
-        if(caccess >= db_enfops) {
-            if(!(chanuser->flags & CHANUSERFLAG_OPPED) && resync_op)
-                modeBufferOp(modeBuf, chanuser->user->nick);
-        } else if(caccess >= db_enfvoice) {
-            if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
-                modeBufferDeop(modeBuf, chanuser->user->nick);
-            if(!(chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice)
-                modeBufferVoice(modeBuf, chanuser->user->nick);
-        } else {
-            if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
-                modeBufferDeop(modeBuf, chanuser->user->nick);
-            if((chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
-                modeBufferDevoice(modeBuf, chanuser->user->nick);
-        }
-        
-    }
-    freeModeBuffer(modeBuf);
-    reply(textclient, user, "NS_RESYNC_DONE", chan->name);
-}
diff --git a/cmd_neonserv_say.c b/cmd_neonserv_say.c
deleted file mode 100644 (file)
index fdf3c50..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    target
-* argv[1-*]  message
-*/
-
-CMD_BIND(neonserv_cmd_say) {
-    char *message = merge_argv(argv, 1, argc);
-    putsock(client, "PRIVMSG %s :%s", argv[0], message);
-}
\ No newline at end of file
diff --git a/cmd_neonserv_search.c b/cmd_neonserv_search.c
deleted file mode 100644 (file)
index 0691366..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-#define CMD_SEARCH_FLAG_HAS_NODELETE 0x01
-#define CMD_SEARCH_FLAG_NOT_NODELETE 0x02
-#define CMD_SEARCH_FLAG_HAS_SUSPENDED 0x04
-#define CMD_SEARCH_FLAG_NOT_SUSPENDED 0x08
-
-struct neonserv_cmd_search_criteria {
-    char *name;
-    char *registrar;
-    unsigned int flags : 16;
-    unsigned int unvisited;
-    unsigned int registered;
-    unsigned int limit : 16;
-};
-
-CMD_BIND(neonserv_cmd_search) {
-    //ok parse the criterias
-    struct neonserv_cmd_search_criteria *criteria = malloc(sizeof(*criteria));
-    if (!criteria) {
-        perror("malloc() failed");
-        return;
-    }
-    memset(criteria, 0, sizeof(*criteria));
-    criteria->limit = 50;
-    int i, show_chans = 0, positive;
-    if(!stricmp(argv[0], "print")) {
-        show_chans = 1;
-    }
-    for(i = 1; i < argc; i += 2) {
-        if(argc <= i+1) {
-            reply(getTextBot(), user, "MODCMD_LESS_PARAM_COUNT");
-            return;
-        }
-        if(!stricmp(argv[i], "name")) criteria->name = argv[i+1];
-        else if(!stricmp(argv[i], "registrar")) criteria->registrar = argv[i+1];
-        else if(!stricmp(argv[i], "unvisited")) criteria->unvisited = strToTime(user, argv[i+1]);
-        else if(!stricmp(argv[i], "registered")) criteria->registered = strToTime(user, argv[i+1]);
-        else if(!stricmp(argv[i], "flags")) {
-            if(argv[i+1][0] == '+') {
-                positive = 1;
-                argv[i+1]++;
-            } else if(argv[i+1][0] == '-') {
-                positive = 0;
-                argv[i+1]++;
-            } else
-                positive = 1;
-            if(!stricmp(argv[i+1], "nodelete")) {
-                if(positive)
-                    criteria->flags |= CMD_SEARCH_FLAG_HAS_NODELETE;
-                else
-                    criteria->flags |= CMD_SEARCH_FLAG_NOT_NODELETE;
-            } else if(!stricmp(argv[i+1], "suspended")) {
-                if(positive)
-                    criteria->flags |= CMD_SEARCH_FLAG_HAS_SUSPENDED;
-                else
-                    criteria->flags |= CMD_SEARCH_FLAG_NOT_SUSPENDED;
-            }
-        }
-        else if(!stricmp(argv[i], "limit")) {
-            criteria->limit = atoi(argv[i+1]);
-        }
-    }
-    int matches = 0;
-    reply(getTextBot(), user, "NS_SEARCH_HEADER");
-    MYSQL_RES *res, *res2;
-    MYSQL_ROW row, row2;
-    printf_mysql_query("SELECT `channel_name`, `user_user`, `channel_registered`, `channel_nodelete`, `suspended`, `channel_id` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` LEFT JOIN `users` ON `channel_registrator` = `user_id` WHERE `botid` = '%d'", client->botid);
-    res = mysql_use();
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(show_chans && matches == criteria->limit) {
-            //too many
-            break;
-        }
-        if(criteria->name && match(criteria->name, row[0])) continue;
-        if(criteria->registrar && row[1] && match(criteria->registrar, row[1])) continue;
-        if(criteria->unvisited) {
-            printf_mysql_query("SELECT `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%s' ORDER BY `chanuser_seen` DESC LIMIT 1", row[5]);
-            res2 = mysql_use();
-            row2 = mysql_fetch_row(res);
-            if(!row2) continue;
-            if((time(0) - atoi(row2[0])) < criteria->unvisited) continue;
-        }
-        if(criteria->registered && (time(0) - atoi(row[2])) < criteria->registered) continue;
-        
-        if((criteria->flags & CMD_SEARCH_FLAG_HAS_NODELETE) && strcmp(row[3], "1")) continue;
-        if((criteria->flags & CMD_SEARCH_FLAG_NOT_NODELETE) && strcmp(row[3], "0")) continue;
-        if((criteria->flags & CMD_SEARCH_FLAG_HAS_SUSPENDED) && strcmp(row[4], "1")) continue;
-        if((criteria->flags & CMD_SEARCH_FLAG_NOT_SUSPENDED) && strcmp(row[4], "0")) continue;
-        matches++;
-        //output
-        if(show_chans) {
-            reply(getTextBot(), user, "%s", row[0]);
-        }
-    }
-    reply(getTextBot(), user, "NS_TABLE_COUNT", matches);
-}
diff --git a/cmd_neonserv_set.c b/cmd_neonserv_set.c
deleted file mode 100644 (file)
index 2801be7..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-typedef char* neonserv_cmd_set_function(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
-static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *argument);
-static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
-static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
-static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
-static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
-
-#define NS_VALID_FUNCTION 0x01
-#define NS_VALID_STRING   0x02
-#define NS_VALID_ACCESS   0x04
-#define NS_VALID_NO501    0x08
-#define NS_VALID_OPTIONS  0x10
-#define NS_VALID_NUMERIC  0x20
-#define NS_VALID_BOOLEAN  0x40
-
-#define NS_HAS_OPT  0x100 /* options (SET_OPTION_{NAME}_{VALUE}) */
-#define NS_HAS_HELP 0x200 /* help    (SET_HELP_{NAME}) - only shown if help is requested */
-
-static const struct {
-    const char *setting;
-    const char *chanfield;
-    unsigned int valid;
-    void *parameter;
-} channel_settings[] = {
-    {"TRIGGER",         NULL,                   NS_VALID_FUNCTION,                  neonserv_cmd_set_trigger},
-    {"DEFAULTTOPIC",    "channel_defaulttopic", NS_VALID_STRING,                    NULL},
-    {"TOPICMASK",       "channel_topicmask",    NS_VALID_STRING,                    NULL},
-    {"ADVANCEDTOPIC",   "channel_exttopic",     NS_VALID_BOOLEAN | NS_HAS_OPT,      NULL},
-    {"GREETING",        "channel_greeting",     NS_VALID_STRING,                    NULL},
-    {"USERGREETING",    "channel_usergreeting", NS_VALID_STRING,                    NULL},
-    {"USERINFO",        "channel_userinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"WIPEINFO",        "channel_wipeinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"MODES",           "channel_modes",        NS_VALID_FUNCTION,                  neonserv_cmd_set_modes},
-    {"INVITEME",        "channel_getinvite",    NS_VALID_ACCESS,                    NULL},
-    {"GIVEOPS",         "channel_getop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"GIVEVOICE",       "channel_getvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"ENFOPS",          "channel_canop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"ENFVOICE",        "channel_canvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"KICK",            "channel_cankick",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"BAN",             "channel_canban",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"STATICBAN",       "channel_staticban",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"PUBCMD",          "channel_pubcmd",       NS_VALID_ACCESS,                    NULL},
-    {"ENFMODES",        "channel_enfmodes",     NS_VALID_ACCESS,                    NULL},
-    {"ENFTOPIC",        "channel_enftopic",     NS_VALID_ACCESS,                    NULL},
-    {"TOPICSNARF",      "channel_topicsnarf",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"CHANGETOPIC",     "channel_changetopic",  NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"SETTERS",         "channel_setters",      NS_VALID_ACCESS | NS_VALID_NO501 | NS_HAS_HELP, NULL},
-    {"ADDUSER",         "channel_canadd",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"DELUSER",         "channel_candel",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"CLVL",            "channel_canclvl",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"RESYNC",          "channel_canresync",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"SUSPEND",         "channel_cansuspend",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
-    {"NOTICEUSERS",     "channel_notice",       NS_VALID_ACCESS,                    NULL},
-    {"NOTICEREACTION",  "channel_noticereaction", NS_VALID_OPTIONS | NS_HAS_OPT,    "4"},
-    {"CTCPUSERS",       "channel_ctcp",         NS_VALID_ACCESS,                    NULL},
-    {"CTCPREACTION",    "channel_ctcpreaction", NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
-    {"PROTECT",         "channel_protect",      NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
-    {"TOYS",            "channel_toys",         NS_VALID_OPTIONS | NS_HAS_OPT,      "3"},
-    {"DYNLIMIT",        "channel_dynlimit",     NS_VALID_NUMERIC | NS_VALID_FUNCTION | NS_HAS_OPT, neonserv_cmd_set_dynlimit},
-    {"NODELETE",        "channel_nodelete",     NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_nodelete},
-    {NULL, NULL, 0, NULL}
-};
-
-#define MAX_QUERY_LEN 1024
-CMD_BIND(neonserv_cmd_set) {
-    int i, j;
-    if(argc && !strcmp(argv[0], "defaults")) {
-        //reset channel settings
-        int uaccess = getChannelAccess(user, chan, 0);
-        if(uaccess < 500) {
-            if(isGodMode(user)) {
-                event->flags |= CMDFLAG_OPLOG;
-            } else {
-                reply(getTextBot(), user, "NS_SET_DEFAULTS_OWNER", chan->name);
-                return;
-            }
-        }
-        int seed = 0;
-        char *tmp;
-        static char defaultskey[16];
-        for(tmp = user->auth; *tmp; tmp++)
-            seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-        for(tmp = chan->name; *tmp; tmp++)
-            seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
-        sprintf(defaultskey, "%08x", seed);
-        if(argc > 1 && !strcmp(argv[1], defaultskey)) {
-            char query[MAX_QUERY_LEN];
-            int querypos = 0;
-            i = 0;
-            while(channel_settings[i].setting) {
-                if(channel_settings[i].chanfield)
-                    querypos += sprintf(query + querypos, "`%s` = NULL, ", channel_settings[i].chanfield);
-                i++;
-            }
-            if(querypos) {
-                query[querypos-2] = '\0';
-            }
-            printf_mysql_query("UPDATE `channels` SET %s WHERE `channel_id` = '%d'", query, chan->channel_id);
-            reply(getTextBot(), user, "NS_SET_DEFAULTS_DONE", chan->name);
-            logEvent(event);
-        } else {
-            reply(getTextBot(), user, "NS_SET_DEFAULTS_CODE", chan->name, defaultskey);
-        }
-    } else if(argc && strcmp(argv[0], "help")) {
-        //find the correct command
-        i = 0;
-        j = 0;
-        char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
-        while(channel_settings[i].setting) {
-            if(!stricmp(channel_settings[i].setting, argv[0])) {
-                //setting found
-                if(channel_settings[i].valid & NS_VALID_FUNCTION) {
-                    neonserv_cmd_set_function *func = channel_settings[i].parameter;
-                    func(client, user, chan, event, channel_settings[i].setting, args);
-                } else {
-                    neonserv_cmd_set_setting(client, user, chan, event, i, args);
-                }
-                j = 1;
-                break;
-            }
-            i++;
-        }
-        if(j == 0) {
-            //unknown setting
-            reply(getTextBot(), user, "NS_SET_UNKNOWN_SETTING", argv[0]);
-        }
-    } else {
-        char query[MAX_QUERY_LEN], *value, *org_value, *tmp, nameBuf[64];
-        int querypos = 0;
-        MYSQL_RES *res, *defaults_res;
-        MYSQL_ROW row, defaults;
-        struct Table *table;
-        char *content[2];
-        i = 0;
-        while(channel_settings[i].setting) {
-            if(channel_settings[i].chanfield)
-                querypos += sprintf(query + querypos, ", `%s`", channel_settings[i].chanfield);
-            i++;
-        }
-        table = table_init(2, i, 0);
-        table_set_bold(table, 0, 1);
-        printf_mysql_query("SELECT `channel_id` %s FROM `channels` WHERE `channel_name` = 'defaults'", query);
-        defaults_res = mysql_use();
-        defaults = mysql_fetch_row(defaults_res);
-        printf_mysql_query("SELECT `channel_name` %s FROM `channels` WHERE `channel_id` = '%d'", query, chan->channel_id);
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-        i = 0;
-        j = 0;
-        reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
-        while(channel_settings[i].setting) {
-            if(channel_settings[i].chanfield) {
-                j++;
-                org_value = (row[j] ? row[j] : defaults[j]);
-            } else if(channel_settings[i].valid & NS_VALID_FUNCTION) {
-                neonserv_cmd_set_function *func = channel_settings[i].parameter;
-                org_value = func(client, user, chan, event, NULL, NULL);
-            } else
-                org_value = "0";
-            value = org_value;
-            if(channel_settings[i].valid & NS_VALID_BOOLEAN) {
-                if(!strcmp(value, "0"))
-                    value = get_language_string(user, "NS_SET_OFF");
-                else
-                    value = get_language_string(user, "NS_SET_ON");
-            }
-            strcpy(query, value);
-            querypos = strlen(query);
-            if(channel_settings[i].valid & NS_HAS_OPT) {
-                sprintf(nameBuf, "NS_SET_OPTION_%s_%s", channel_settings[i].setting, org_value);
-                tmp = get_language_string(user, nameBuf);
-                if(tmp) {
-                    querypos += sprintf(query+querypos, " - %s", tmp);
-                }
-            }
-            if(argc && channel_settings[i].valid & NS_HAS_HELP) {
-                sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[i].setting);
-                tmp = get_language_string(user, nameBuf);
-                if(tmp) {
-                    querypos += sprintf(query+querypos, " - %s", tmp);
-                }
-            }
-            content[0] = (char*)channel_settings[i].setting;
-            content[1] = query;
-            table_add(table, content);
-            i++;
-        }
-        char **table_lines = table_end(table);
-        for(i = 0; i < table->entrys; i++) {
-            reply(getTextBot(), user, table_lines[i]);
-        }
-        table_free(table);
-    }
-}
-
-static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *args) {
-    char *value;
-    char nameBuf[64];
-    //get current value
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, chan->channel_id);
-    res = mysql_use();
-    row = mysql_fetch_row(res);
-    if(row[0] == NULL) {
-        printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", channel_settings[setting].chanfield);
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-    }
-    value = row[0];
-    if(args) {
-        //change the channel setting
-        //check the new argument
-        int valid = channel_settings[setting].valid;
-        if(valid & NS_VALID_STRING) {
-            if(!strcmp(args, "*")) {
-                args = "";
-            }
-        }
-        if(valid & NS_VALID_ACCESS) {
-            int caccess = atoi(args);
-            int max = ((valid & NS_VALID_NO501) ? 500 : 501);
-            if(caccess < 0 || caccess > max) {
-                reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
-                return;
-            }
-            int uaccess = getChannelAccess(user, chan, 0);
-            if(uaccess == 500) uaccess++;
-            if(atoi(value) > uaccess) {
-                if(isGodMode(user)) {
-                    event->flags |= CMDFLAG_OPLOG;
-                } else {
-                    reply(getTextBot(), user, "NS_SET_CANNOT_SET");
-                    return;
-                }
-            }
-            if(caccess > uaccess) {
-                if(isGodMode(user)) {
-                    event->flags |= CMDFLAG_OPLOG;
-                } else {
-                    reply(getTextBot(), user, "NS_SET_BADLEVEL");
-                    return;
-                }
-            }
-            sprintf(nameBuf, "%d", caccess);
-            args = nameBuf;
-        }
-        if(valid & NS_VALID_OPTIONS) {
-            int options = atoi((char *) channel_settings[setting].parameter);
-            int coption = atoi(args);
-            if(coption < 0 || coption >= options) {
-                reply(getTextBot(), user, "NS_SET_INVALID_OPTION", coption);
-                int i;
-                int nameBufPos = 0;
-                if(valid & NS_HAS_OPT) {
-                    for(i = 0; i < options; i++) {
-                        sprintf(nameBuf, "NS_SET_OPTION_%s_%d", channel_settings[setting].setting, i);
-                        reply(getTextBot(), user, "\002%d\002 - %s", i, get_language_string(user, nameBuf));
-                    }
-                } else {
-                    for(i = 0; i < options; i++) {
-                        nameBufPos += sprintf(nameBuf + nameBufPos, "\002%d\002, ", i);
-                    }
-                    if(nameBufPos) {
-                        nameBuf[nameBufPos-2] = '\0';
-                        reply(getTextBot(), user, nameBuf);
-                    }
-                }
-                return;
-            }
-        }
-        if(valid & NS_VALID_NUMERIC) {
-            sprintf(nameBuf, "%d", atoi(args));
-            args = nameBuf;
-        }
-        if(valid & NS_VALID_BOOLEAN) {
-            if(!strcmp(args, "0") || !stricmp(args, "off") || !stricmp(args, get_language_string(user, "NS_SET_OFF"))) {
-                args = "0";
-            } else if(!strcmp(args, "1") || !stricmp(args, "on") || !stricmp(args, get_language_string(user, "NS_SET_ON"))) {
-                args = "1";
-            } else {
-                reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", args);
-                return;
-            }
-        }
-        //valid - set it
-        value = args;
-        printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, escape_string(value), chan->channel_id);
-        logEvent(event);
-    }
-    reply(getTextBot(), user, "\002%s\002 %s", channel_settings[setting].setting, value);
-    if(channel_settings[setting].valid & NS_HAS_HELP) {
-         sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[setting].setting);
-         reply(getTextBot(), user, "  %s", get_language_string(user, nameBuf));
-    }
-}
-
-static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
-    char *trigger;
-    //get current trigger
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `trigger` FROM `bot_channels` WHERE `chanid` = '%d' AND `botid` = '%d'", chan->channel_id, client->clientid);
-    res = mysql_use();
-    row = mysql_fetch_row(res);
-    trigger = row[0];
-    if(argument) {
-        int uaccess = getChannelAccess(user, chan, 0);
-        if(uaccess < 500) {
-            if(isGodMode(user)) {
-                event->flags |= CMDFLAG_OPLOG;
-            } else {
-                reply(getTextBot(), user, "NS_SET_TRIGGER_OWNER", chan->name);
-                return NULL;
-            }
-        }
-        if(strlen(argument) > 15)
-            argument[15] = '\0';
-        printf_mysql_query("UPDATE `bot_channels` SET `trigger` = '%s' WHERE `chanid` = '%d' AND `botid` = '%d'", escape_string(argument), chan->channel_id, client->clientid);
-        trigger = argument;
-        changeChannelTrigger(client->botid, chan, trigger);
-        logEvent(event);
-    }
-    if(setting) {
-        reply(getTextBot(), user, "\002%s\002 %s", setting, trigger);
-    }
-    return trigger;
-}
-
-static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
-    char *value;
-    //get current value
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    row = mysql_fetch_row(res);
-    if(row[0] == NULL) {
-        printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-    }
-    value = row[0];
-    if(argument) {
-        //change the channel setting
-        //TODO: parse, check and set modelock
-    }
-    if(setting) {
-        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
-    }
-    return value;
-}
-
-static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
-    char *value;
-    char tmp[64];
-    //get current value
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    row = mysql_fetch_row(res);
-    if(row[0] == NULL) {
-        printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-    }
-    value = row[0];
-    if(argument) {
-        //change the channel setting
-        sprintf(tmp, "%d", atoi(argument));
-        argument = tmp;
-        printf_mysql_query("UPDATE `channels` SET `channel_dynlimit` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
-        if(strcmp(argument, "0"))
-            putsock(client, "MODE %s +l %d", chan->name, (chan->usercount + atoi(argument)));
-        else if(isModeSet(chan->modes, 'l'))
-            putsock(client, "MODE %s -l", chan->name);
-        value = argument;
-        logEvent(event);
-    }
-    if(setting) {
-        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
-    }
-    return value;
-}
-
-static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
-    char *value;
-    //get current value
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    row = mysql_fetch_row(res);
-    if(row[0] == NULL) {
-        printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-    }
-    value = row[0];
-    if(argument && isGodMode(user)) {
-        //change the channel setting
-        if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
-            argument = "0";
-        } else if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
-            argument = "1";
-        } else {
-            reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
-            return NULL;
-        }
-        printf_mysql_query("UPDATE `channels` SET `channel_nodelete` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
-        event->flags |= CMDFLAG_OPLOG;
-        value = argument;
-        logEvent(event);
-    }
-    if(setting) {
-        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
-    }
-    return value;
-}
-
-#undef MAX_QUERY_LEN
diff --git a/cmd_neonserv_setaccess.c b/cmd_neonserv_setaccess.c
deleted file mode 100644 (file)
index 37549d2..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-* argv[1] - global access
-*/
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_setaccess_auth_lookup);
-static USERAUTH_CALLBACK(neonserv_cmd_setaccess_nick_lookup);
-static void neonserv_cmd_setaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct Event *event, char *nick, char *auth, int access);
-
-struct neonserv_cmd_setaccess_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    int access;
-    char *nick;
-};
-
-CMD_BIND(neonserv_cmd_setaccess) {
-    int caccess;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    caccess = atoi(argv[1]);
-    if(caccess < 0 || caccess > 1000) {
-        reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
-        return;
-    }
-    printf_mysql_query("SELECT `user_access` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL || atoi(row[0]) < caccess) {
-        reply(getTextBot(), user, "NS_ACCESS_OUTRANKED");
-        return;
-    }
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        printf_mysql_query("SELECT `user_user` FROM `users` WHERE `user_user` = '%s'", escape_string(argv[0]));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            neonserv_cmd_setaccess_async1(client, getTextBot(), user, event, argv[0], row[0], caccess);
-        } else {
-            //we need to create a new user...
-            //but first lookup the auth to check if it really exists
-            struct neonserv_cmd_setaccess_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->event = event;
-            cache->access = caccess;
-            cache->nick = strdup(argv[0]);
-            lookup_authname(argv[0], neonserv_cmd_setaccess_auth_lookup, cache);
-        }
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_setaccess_async1(client, getTextBot(), user, event, argv[0], cuser->auth, caccess);
-        } else {
-            struct neonserv_cmd_setaccess_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->event = event;
-            cache->access = caccess;
-            cache->nick = strdup(argv[0]);
-            get_userauth(cuser, neonserv_cmd_setaccess_nick_lookup, cache);
-        }
-    }
-}
-
-static AUTHLOOKUP_CALLBACK(neonserv_cmd_setaccess_auth_lookup) {
-    struct neonserv_cmd_setaccess_cache *cache = data;
-    if(!exists) {
-        //AUTH_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_AUTH_UNKNOWN", cache->nick);
-    } else
-        neonserv_cmd_setaccess_async1(cache->client, cache->textclient, cache->user, cache->event, cache->nick, auth, cache->access);
-    free(cache->nick);
-    free(cache);
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_setaccess_nick_lookup) {
-    struct neonserv_cmd_setaccess_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_setaccess_async1(cache->client, cache->textclient, cache->user, cache->event, user->nick, user->auth, cache->access);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_setaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct Event *event, char *nick, char *auth, int caccess) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `user_id`, `user_access` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        if(atoi(row[1]) != caccess)
-            printf_mysql_query("UPDATE `users` SET `user_access` = '%d' WHERE `user_id` = '%s'", caccess, row[0]);
-    } else {
-        printf_mysql_query("INSERT INTO `users` (`user_user`, `user_access`) VALUES ('%s', '%d')", escape_string(auth), caccess);
-    }
-    reply(textclient, user, "NS_SETACCESS_DONE", auth, caccess);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_suspend.c b/cmd_neonserv_suspend.c
deleted file mode 100644 (file)
index 4db9a50..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_suspend_nick_lookup);
-static void neonserv_cmd_suspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
-
-struct neonserv_cmd_suspend_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-};
-
-CMD_BIND(neonserv_cmd_suspend) {
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        neonserv_cmd_suspend_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_suspend_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
-        } else {
-            struct neonserv_cmd_suspend_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[0]);
-            get_userauth(cuser, neonserv_cmd_suspend_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_suspend_nick_lookup) {
-    struct neonserv_cmd_suspend_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_suspend_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_suspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid, cflags;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
-                if(isGodMode(user)) {
-                    event->flags |= CMDFLAG_OPLOG;
-                } else {
-                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
-                    return;
-                }
-            }
-            //suspend
-            cflags = atoi(row[2]);
-            if(cflags & DB_CHANUSER_SUSPENDED) {
-                reply(textclient, user, "NS_SUSPEND_ALREADY", nick);
-                return;
-            }
-            cflags |= DB_CHANUSER_SUSPENDED;
-            printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", cflags, row[1]);
-            reply(textclient, user, "NS_SUSPEND_DONE", nick, chan->name);
-            logEvent(event);
-            return;
-        }
-    }
-    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-}
diff --git a/cmd_neonserv_topic.c b/cmd_neonserv_topic.c
deleted file mode 100644 (file)
index 2673f15..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* ADVANCEDTOPIC enabled
-* argv[0]    topic id
-* argv[1-*]  topic
-*
-* ADVANCEDTOPIC disabled
-* argv[0-*]  topic
-*/
-
-#define ADVANCEDTOPIC_MAXID 9
-
-CMD_BIND(neonserv_cmd_topic) {
-    MYSQL_RES *res;
-    MYSQL_ROW row, default_row = NULL;
-    int advanced_topic, i;
-    char *newtopic;
-    char *a,*b;
-    
-    printf_mysql_query("SELECT `channel_exttopic`, `channel_exttopic_topic`, `channel_topicmask`, `channel_enftopic`, `channel_topicsnarf`, `channel_defaulttopic` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    row = mysql_fetch_row(res);
-    if(!row[0] || !row[3] || !row[4]) {
-        printf_mysql_query("SELECT `channel_exttopic`, `channel_enftopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_name` = 'defaults'");
-        default_row = mysql_fetch_row(mysql_use());
-    }
-    
-    if(row[0] == NULL) {
-        advanced_topic = atoi(default_row[0]);
-    } else
-        advanced_topic = atoi(row[0]);
-    if(argc == 0) {
-        //default topic!
-        putsock(client, "TOPIC %s :%s", chan->name, row[5]);
-        reply(getTextBot(), user, "NS_TOPIC_DONE", row[5]);
-        logEvent(event);
-        return;
-    }
-    int uaccess = getChannelAccess(user, chan, 0);
-    if(uaccess >= atoi((row[3] ? row[3] : default_row[1]))) {
-        //just set the topic
-        newtopic = merge_argv(argv, 0, argc);
-        if(uaccess >= atoi((row[4] ? row[4] : default_row[2]))) {
-            //set the default topic
-            printf_mysql_query("UPDATE `channels` SET `channel_defaulttopic` = '%s' WHERE `channel_id` = '%d'", escape_string(newtopic), chan->channel_id);
-        }
-        putsock(client, "TOPIC %s :%s", chan->name, newtopic);
-        reply(getTextBot(), user, "NS_TOPIC_DONE", newtopic);
-        logEvent(event);
-        return;
-    }
-    if(advanced_topic) {
-        char *advtopics[ADVANCEDTOPIC_MAXID];
-        int topic_id = 0;
-        topic_id = atoi(argv[0]);
-        if(!topic_id || topic_id > ADVANCEDTOPIC_MAXID) {
-            reply(getTextBot(), user, "NS_EXTTOPIC_INVALID_ID", argv[0]);
-            return;
-        }
-        //parse topics
-        i = 0;
-        b = row[1];
-        while((a = strstr(b, "\n")) != NULL) {
-            *a = '\0';
-            if(i == ADVANCEDTOPIC_MAXID-1) break;
-            advtopics[i++] = b;
-            b = a+1;
-        }
-        advtopics[i++] = b;
-        for(;i < ADVANCEDTOPIC_MAXID;i++)
-            advtopics[i] = "";
-        if(argc < 2) {
-            //just show the topic with this id
-            reply(getTextBot(), user, "NS_EXTTOPIC_TOPICID", topic_id, advtopics[topic_id-1]);
-            return;
-        }
-        newtopic = merge_argv(argv, 1, argc);
-        if(!strcmp(newtopic, "*")) 
-            newtopic = "";
-        advtopics[topic_id-1] = newtopic;
-        char topiclist[MAXLEN*2];
-        topiclist[0] = '\0';
-        int topiclistpos = 0;
-        for(i = 0; i < ADVANCEDTOPIC_MAXID; i++) {
-            if(topiclistpos + strlen(advtopics[i]) + 2 >= MAXLEN) break;
-            topiclistpos += sprintf(topiclist+topiclistpos, (i ? "\n%s" : "%s"), advtopics[i]);
-        }
-        printf_mysql_query("UPDATE `channels` SET `channel_exttopic_topic` = '%s' WHERE `channel_id` = '%d'", escape_string(topiclist), chan->channel_id);
-        //now build the new topic and set it...
-        topiclistpos = 0;
-        b = row[2];
-        while((a = strstr(b, "%")) != NULL) {
-            *a = '\0';
-            if(isdigit(a[1]) && a[1] - 48 > 0) {
-                topiclistpos += sprintf(topiclist + topiclistpos, "%s%s", b, advtopics[a[1] - 49]);
-                b = a+2;
-            } else {
-                topiclistpos += sprintf(topiclist + topiclistpos, "%s%%", b);
-                b = a+1;
-            }
-        }
-        topiclistpos += sprintf(topiclist + topiclistpos, "%s", b);
-        if(topiclistpos > MAXLEN)
-            topiclist[MAXLEN] = '\0';
-        putsock(client, "TOPIC %s :%s", chan->name, topiclist);
-        reply(getTextBot(), user, "NS_TOPIC_DONE", topiclist);
-        logEvent(event);
-    } else {
-        newtopic = merge_argv(argv, 0, argc);
-        char topiclist[MAXLEN*2];
-        topiclist[0] = '\0';
-        int topiclistpos = 0;
-         b = row[2];
-        while((a = strstr(b, "*")) != NULL) {
-            *a = '\0';
-            topiclistpos += sprintf(topiclist + topiclistpos, "%s%s", b, newtopic);
-            b = a+1;
-        }
-        topiclistpos += sprintf(topiclist + topiclistpos, "%s", b);
-        if(topiclistpos > MAXLEN)
-            topiclist[MAXLEN] = '\0';
-        putsock(client, "TOPIC %s :%s", chan->name, topiclist);
-        reply(getTextBot(), user, "NS_TOPIC_DONE", topiclist);
-        logEvent(event);
-    }
-}
-
-#undef ADVANCEDTOPIC_MAXID
\ No newline at end of file
diff --git a/cmd_neonserv_trace.c b/cmd_neonserv_trace.c
deleted file mode 100644 (file)
index d2568a5..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-#define NS_TRACE_CRITERIA_AUTHED  0x01
-#define NS_TRACE_CRITERIA_NUMCHAN 0x02
-
-struct neonserv_cmd_trace_criteria {
-    char *mask;
-    char *nick;
-    char *ident;
-    char *host;
-    char *account;
-    unsigned int flags : 4;
-    unsigned int authed : 1;
-    unsigned int used_channel : 5; //32 max
-    char *channel[10];
-    unsigned int numchannels;
-    unsigned int limit : 16;
-};
-
-CMD_BIND(neonserv_cmd_trace) {
-    //ok parse the criterias
-    struct neonserv_cmd_trace_criteria *criteria = malloc(sizeof(*criteria));
-    if (!criteria) {
-        perror("malloc() failed");
-        return;
-    }
-    memset(criteria, 0, sizeof(*criteria));
-    criteria->limit = 50;
-    int i, show_user = 0;
-    if(!stricmp(argv[0], "print")) {
-        show_user = 1;
-    }
-    for(i = 1; i < argc; i += 2) {
-        if(argc <= i+1) {
-            reply(getTextBot(), user, "MODCMD_LESS_PARAM_COUNT");
-            return;
-        }
-        if(!stricmp(argv[i], "mask")) criteria->mask = argv[i+1];
-        else if(!stricmp(argv[i], "nick")) criteria->nick = argv[i+1];
-        else if(!stricmp(argv[i], "ident")) criteria->ident = argv[i+1];
-        else if(!stricmp(argv[i], "host")) criteria->host = argv[i+1];
-        else if(!stricmp(argv[i], "account")) criteria->account = argv[i+1];
-        else if(!stricmp(argv[i], "authed")) {
-            if(!strcmp(argv[i+1], "0") || !strcmp(argv[i+1], "off") || !strcmp(argv[i+1], get_language_string(user, "NS_SET_OFF"))) {
-                criteria->authed = 1;
-            } else if(!strcmp(argv[i+1], "0") || !strcmp(argv[i+1], "off") || !strcmp(argv[i+1], get_language_string(user, "NS_SET_OFF"))) {
-                criteria->authed = 0;
-            } else {
-                reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argv[i+1]);
-                return;
-            }
-            criteria->flags |= NS_TRACE_CRITERIA_AUTHED;
-        }
-        else if(!stricmp(argv[i], "channel")) criteria->channel[criteria->used_channel++] = argv[i+1];
-        else if(!stricmp(argv[i], "numchannels")) {
-            criteria->numchannels = atoi(argv[i+1]);
-            criteria->flags |= NS_TRACE_CRITERIA_NUMCHAN;
-        }
-        else if(!stricmp(argv[i], "limit")) {
-            criteria->limit = atoi(argv[i+1]);
-        }
-    }
-    char tmp[MAXLEN];
-    int matches = 0;
-    struct UserNode *cuser;
-    reply(getTextBot(), user, "NS_TRACE_HEADER");
-    for(cuser = getAllUsers(NULL); cuser; cuser = getAllUsers(cuser)) {
-        if(show_user && matches == criteria->limit) {
-            //too many
-            break;
-        }
-        if(criteria->mask) {
-            sprintf(tmp, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
-            if(match(criteria->mask, tmp)) continue;
-        }
-        if(criteria->nick && match(criteria->nick, cuser->nick)) continue;
-        if(criteria->ident && match(criteria->ident, cuser->ident)) continue;
-        if(criteria->host && match(criteria->host, cuser->host)) continue;
-        if(criteria->account && (!(cuser->flags & USERFLAG_ISAUTHED) || match(criteria->account, cuser->auth))) continue;
-        if((criteria->flags & NS_TRACE_CRITERIA_AUTHED) && (criteria->authed ^ (cuser->flags & USERFLAG_ISAUTHED))) continue;
-        if((criteria->flags & NS_TRACE_CRITERIA_NUMCHAN)) {
-            int ccount = 0;
-            struct ChanUser *chanuser;
-            for(chanuser = getUserChannels(cuser, NULL); chanuser; chanuser = getUserChannels(cuser, chanuser))
-                ccount++;
-            if(ccount < criteria->numchannels)
-                continue;
-        }
-        matches++;
-        //output
-        if(show_user) {
-            reply(getTextBot(), user, "%s!%s@%s %s", cuser->nick, cuser->ident, cuser->host, ((cuser->flags & USERFLAG_ISAUTHED) ? cuser->auth : "*"));
-        }
-    }
-    reply(getTextBot(), user, "NS_TABLE_COUNT", matches);
-}
diff --git a/cmd_neonserv_trim.c b/cmd_neonserv_trim.c
deleted file mode 100644 (file)
index 67501a7..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]  target (format: minaccess-maxaccess/users/bans)
-* argv[1]  duration
-*/
-static USERLIST_CALLBACK(neonserv_cmd_trim_userlist_lookup);
-static void neonserv_cmd_trim_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, int min_access, int max_access, int duration);
-
-struct neonserv_cmd_trim_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    int min_access;
-    int max_access;
-    int duration;
-};
-
-CMD_BIND(neonserv_cmd_trim) {
-    if(stricmp(argv[0], "bans") && !checkChannelAccess(user, chan, "channel_candel", 0, 0)) {
-        if(isGodMode(user)) {
-            event->flags |= CMDFLAG_OPLOG;
-        } else {
-            reply(getTextBot(), user, "NS_ACCESS_DENIED");
-            return;
-        }
-    }
-    int min_access, max_access;
-    if(!stricmp(argv[0], "users")) {
-        min_access = 1;
-        max_access = getChannelAccess(user, chan, 0) - 1;
-    } else if(!stricmp(argv[0], "bans")) {
-        if(!checkChannelAccess(user, chan, "channel_staticban", 0, 0)) {
-            if(isGodMode(user)) {
-                event->flags |= CMDFLAG_OPLOG;
-            } else {
-                reply(getTextBot(), user, "NS_ACCESS_DENIED");
-                return;
-            }
-        }
-        //TODO: TRIM BANS
-        return;
-    } else {
-        char *seperator = strstr(argv[0], "-");
-        if(seperator) {
-            *seperator = '\0';
-            seperator++;
-            min_access = atoi(argv[0]);
-            max_access = atoi(seperator);
-            if(max_access < min_access) {
-                reply(getTextBot(), user, "NS_INVALID_ACCESS_RANGE", min_access, max_access);
-                return;
-            }
-        } else {
-            min_access = atoi(argv[0]);
-            max_access = min_access;
-        }
-        if(max_access >= getChannelAccess(user, chan, 0)) {
-            if(isGodMode(user)) {
-                event->flags |= CMDFLAG_OPLOG;
-            } else {
-                reply(getTextBot(), user, "NS_NO_ACCESS");
-                return;
-            }
-        }
-    }
-    //parse duration...
-    int duration = strToTime(user, argv[1]);
-    if(duration < 30) {
-        reply(getTextBot(), user, "NS_TRIM_DURATION_TOO_SHORT", 30);
-        return;
-    }
-    struct neonserv_cmd_trim_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->min_access = min_access;
-    cache->max_access = max_access;
-    cache->duration = duration;
-    get_userlist_with_invisible(chan, neonserv_cmd_trim_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_trim_userlist_lookup) {
-    struct neonserv_cmd_trim_cache *cache = data;
-    //got userlist
-    neonserv_cmd_trim_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->min_access, cache->max_access, cache->duration);
-    free(cache);
-}
-
-static void neonserv_cmd_trim_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, int min_access, int max_access, int duration) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int trim_count = 0, is_here;
-    struct ChanUser *chanuser;
-    printf_mysql_query("SELECT `chanuser_seen`, `user_user`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `chanuser_access` >= '%d' AND `chanuser_access` <= '%d'", chan->channel_id, min_access, max_access);
-    res = mysql_use();
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        if(!strcmp(row[0], "0") || time(0) - atoi(row[0]) >= duration) {
-            //check if the user is currently in the channel
-            is_here = 0;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !strcmp(chanuser->user->auth, row[1])) {
-                    is_here = 1;
-                    break;
-                }
-            }
-            if(!is_here) {
-                //delete the user
-                trim_count++;
-                printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[2]);
-            }
-        }
-    }
-    char timeBuf[MAXLEN];
-    reply(getTextBot(), user, "NS_TRIM_DONE", trim_count, min_access, max_access, chan->name, timeToStr(user, duration, 3, timeBuf));
-    if(trim_count)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_unban.c b/cmd_neonserv_unban.c
deleted file mode 100644 (file)
index 073bf50..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nick[,*auth[,*!*@mask[...]]]
-*/
-struct neonserv_cmd_unban_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    struct ModeBuffer *modeBuf;
-    int provided_masks, done_masks, pending_whos, unbanned_masks;
-};
-
-static USERAUTH_CALLBACK(neonserv_cmd_unban_userauth_lookup);
-static void neonserv_cmd_unban_nick(struct neonserv_cmd_unban_cache *cache, struct UserNode *user);
-static void neonserv_cmd_unban_mask(struct neonserv_cmd_unban_cache *cache, char *mask);
-static void neonserv_cmd_unban_finish(struct neonserv_cmd_unban_cache *cache);
-
-CMD_BIND(neonserv_cmd_unban) {
-    char *mask, *nextmask;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    nextmask = merge_argv_char(argv, 0, argc, ',');
-    struct neonserv_cmd_unban_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->chan = chan;
-    cache->event = event;
-    cache->modeBuf = modeBuf;
-    cache->done_masks = 0;
-    cache->provided_masks = 0;
-    cache->unbanned_masks = 0;
-    while((mask = nextmask)) {
-        nextmask = strstr(mask, ",");
-        if(nextmask) {
-            *nextmask = '\0';
-            nextmask++;
-        }
-        cache->provided_masks++;
-        if(is_valid_nick(mask)) {
-            struct UserNode *cuser = getUserByNick(mask);
-            if(!cuser) {
-                cuser = createTempUser(mask);
-                cuser->flags |= USERFLAG_ISTMPUSER;
-                get_userauth(cuser, neonserv_cmd_unban_userauth_lookup, cache);
-                cache->pending_whos++;
-            } else {
-                neonserv_cmd_unban_nick(cache, cuser);
-            }
-        } else {
-            neonserv_cmd_unban_mask(cache, mask);
-        }
-    }
-    if(!cache->pending_whos)
-        neonserv_cmd_unban_finish(cache);
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_unban_userauth_lookup) {
-    struct neonserv_cmd_unban_cache *cache = data;
-    cache->pending_whos--;
-    if(user)
-        neonserv_cmd_unban_nick(cache, user);
-    else
-        neonserv_cmd_unban_mask(cache, user_nick);
-    if(!cache->pending_whos)
-        neonserv_cmd_unban_finish(cache);
-}
-
-static void neonserv_cmd_unban_nick(struct neonserv_cmd_unban_cache *cache, struct UserNode *user) {
-    int matches = 0;
-    struct BanNode *ban;
-    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-    sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
-    for(ban = cache->chan->bans; ban; ban = ban->next) {
-        if(!match(ban->mask, usermask)) {
-            modeBufferUnban(cache->modeBuf, ban->mask);
-            cache->unbanned_masks++;
-            matches++;
-        }
-    }
-    if(matches)
-        cache->done_masks++;
-}
-
-static void neonserv_cmd_unban_mask(struct neonserv_cmd_unban_cache *cache, char *mask) {
-    char banmask[NICKLEN+USERLEN+HOSTLEN+3];
-    int matches = 0;
-    struct BanNode *ban;
-    mask = make_banmask(mask, banmask);
-    for(ban = cache->chan->bans; ban; ban = ban->next) {
-        if(!match(mask, ban->mask)) {
-            modeBufferUnban(cache->modeBuf, ban->mask);
-            cache->unbanned_masks++;
-            matches++;
-        }
-    }
-    if(matches)
-        cache->done_masks++;
-    else {
-        for(ban = cache->chan->bans; ban; ban = ban->next) {
-            if(!match(ban->mask, mask)) {
-                reply(cache->textclient, cache->user, "NS_DELBAN_BANNED_BY", mask, ban->mask);
-                break;
-            }
-        }
-    }
-}
-
-static void neonserv_cmd_unban_finish(struct neonserv_cmd_unban_cache *cache) {
-    freeModeBuffer(cache->modeBuf);
-    if(cache->done_masks == cache->provided_masks)
-        reply(cache->textclient, cache->user, "NS_UNBAN_DONE", cache->unbanned_masks, cache->chan->name);
-    else
-        reply(cache->textclient, cache->user, "NS_UNBAN_FAIL", cache->client->user->nick);
-    if(cache->done_masks)
-        logEvent(cache->event);
-    free(cache);
-}
-
diff --git a/cmd_neonserv_unbanall.c b/cmd_neonserv_unbanall.c
deleted file mode 100644 (file)
index 1be8251..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nothing
-*/
-
-CMD_BIND(neonserv_cmd_unbanall) {
-    struct ModeBuffer *modeBuf;
-    int bans = 0;
-    struct BanNode *ban;
-    modeBuf = initModeBuffer(client, chan);
-    for(ban = chan->bans; ban; ban = ban->next) {
-        modeBufferUnban(modeBuf, ban->mask);
-        bans++;
-    }
-    freeModeBuffer(modeBuf);
-    if(bans) {
-        reply(getTextBot(), user, "NS_UNBANALL_DONE", bans, chan->name);
-        logEvent(event);
-    } else
-        reply(getTextBot(), user, "NS_UNBANALL_FAIL", client->user->nick, chan->name);
-}
diff --git a/cmd_neonserv_unbanme.c b/cmd_neonserv_unbanme.c
deleted file mode 100644 (file)
index 808a46f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nothing
-*/
-
-CMD_BIND(neonserv_cmd_unbanme) {
-    struct ModeBuffer *modeBuf;
-    int bans = 0;
-    struct BanNode *ban;
-    modeBuf = initModeBuffer(client, chan);
-    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-    sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
-    for(ban = chan->bans; ban; ban = ban->next) {
-        if(!match(ban->mask, usermask)) {
-            modeBufferUnban(modeBuf, ban->mask);
-            bans++;
-        }
-    }
-    freeModeBuffer(modeBuf);
-    if(bans) {
-        reply(getTextBot(), user, "NS_UNBANME_DONE", bans, chan->name);
-        logEvent(event);
-    } else
-        reply(getTextBot(), user, "NS_UNBANME_FAIL", client->user->nick, usermask);
-}
diff --git a/cmd_neonserv_unbind.c b/cmd_neonserv_unbind.c
deleted file mode 100644 (file)
index bc67b83..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]   command name
-*/
-
-CMD_BIND(neonserv_cmd_unbind) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `id` FROM `bot_binds` WHERE `botclass` = '%d' AND `command` = '%s'", client->botid, escape_string(argv[0]));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        reply(getTextBot(), user, "NS_UNBIND_NOT_FOUND", argv[0]);
-        return;
-    }
-    unbind_cmd(client->botid, argv[0]);
-    printf_mysql_query("DELETE FROM `bot_binds` WHERE `id` = '%s'", row[0]);
-    reply(getTextBot(), user, "NS_UNBIND_DONE", argv[0]);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_unregister.c b/cmd_neonserv_unregister.c
deleted file mode 100644 (file)
index 8da366e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - channel
-*/
-CMD_BIND(neonserv_cmd_unregister) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    char *channel = argv[0];
-    if(!is_valid_chan(channel)) {
-        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
-        return;
-    }
-    int chanid;
-    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        chanid = atoi(row[0]);
-    } else {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
-        return;
-    }
-    int botid = atoi(row[0]);
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid)
-            break;
-    }
-    if(bot && strcmp(row[2], "1")) {
-        putsock(bot, "PART %s :Channel unregistered.", channel);
-    }
-    printf_mysql_query("DELETE FROM `bot_channels` WHERE `id` = '%s'", row[1]);
-    reply(getTextBot(), user, "NS_UNREGISTER_DONE", channel);
-    logEvent(event);
-}
diff --git a/cmd_neonserv_unsuspend.c b/cmd_neonserv_unsuspend.c
deleted file mode 100644 (file)
index c9d5aca..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_unsuspend_nick_lookup);
-static void neonserv_cmd_unsuspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
-
-struct neonserv_cmd_unsuspend_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-};
-
-CMD_BIND(neonserv_cmd_unsuspend) {
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        neonserv_cmd_unsuspend_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_unsuspend_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
-        } else {
-            struct neonserv_cmd_unsuspend_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[0]);
-            get_userauth(cuser, neonserv_cmd_unsuspend_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_unsuspend_nick_lookup) {
-    struct neonserv_cmd_unsuspend_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_unsuspend_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_unsuspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid, cflags;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
-                if(isGodMode(user)) {
-                    event->flags |= CMDFLAG_OPLOG;
-                } else {
-                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
-                    return;
-                }
-            }
-            //unsuspend
-            cflags = atoi(row[2]);
-            if(!(cflags & DB_CHANUSER_SUSPENDED)) {
-                reply(textclient, user, "NS_SUSPEND_NOT", nick);
-                return;
-            }
-            cflags &= ~DB_CHANUSER_SUSPENDED;
-            printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", cflags, row[1]);
-            reply(textclient, user, "NS_SUSPEND_RESTORED", nick, chan->name);
-            logEvent(event);
-            return;
-        }
-    }
-    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-}
diff --git a/cmd_neonserv_up.c b/cmd_neonserv_up.c
deleted file mode 100644 (file)
index a81de4a..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no arguments
-*/
-
-CMD_BIND(neonserv_cmd_up) {
-    struct ChanUser *chanuser = getChanUser(user, chan);
-    if(!chanuser) {
-        reply(getTextBot(), user, "NS_NOT_ON_CHANNEL_YOU", chan->name);
-        return;
-    }
-    check_mysql();
-    loadChannelSettings(chan);
-    MYSQL_RES *res, *default_res;
-    MYSQL_ROW row, default_row;
-    int chan_getop, chan_getvoice, caccess;
-    printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return;
-    if(!row[0] || !row[1]) {
-        printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
-        default_res = mysql_use();
-        if ((default_row = mysql_fetch_row(default_res)) == NULL) return;
-        chan_getop = (row[0] ? atoi(row[0]) : atoi(default_row[0]));
-        chan_getvoice = (row[1] ? atoi(row[1]) : atoi(default_row[1]));
-    } else {
-        chan_getop = atoi(row[0]);
-        chan_getvoice = atoi(row[1]);
-    }
-    caccess = getChannelAccess(user, chan, 1);
-    if(caccess >= chan_getop) {
-        if(!(chanuser->flags & CHANUSERFLAG_OPPED)) {
-            putsock(client, "MODE %s +o %s", chan->name, user->nick);
-            logEvent(event);
-        } else
-            reply(getTextBot(), user, "NS_UP_ALREADY_OP", chan->name);
-    } else if(caccess >= chan_getvoice) {
-        if(!(chanuser->flags & CHANUSERFLAG_VOICED)) {
-            putsock(client, "MODE %s +v %s", chan->name, user->nick);
-            logEvent(event);
-        } else
-            reply(getTextBot(), user, "NS_UP_ALREADY_VOICE", chan->name);
-    } else
-        reply(getTextBot(), user, "NS_NOT_ON_USERLIST_YOU", chan->name);
-}
diff --git a/cmd_neonserv_upall.c b/cmd_neonserv_upall.c
deleted file mode 100644 (file)
index bea9325..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no arguments
-*/
-
-CMD_BIND(neonserv_cmd_upall) {
-    MYSQL_RES *res, *default_res;
-    MYSQL_ROW row, default_row;
-    struct ChanUser *chanuser;
-    int userid, chan_getop, chan_getvoice, caccess;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", user->auth);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL)
-        return;
-    userid = atoi(row[0]);
-    printf_mysql_query("SELECT `chanuser_access`, `channel_getop`, `channel_getvoice`, `channel_name`, `channel_id` FROM `chanusers` LEFT JOIN `channels` ON `chanuser_cid` = `channel_id` WHERE `chanuser_uid` = '%d'", userid);
-    res = mysql_use();
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        chan = getChanByName(row[3]);
-        if(!chan) continue;
-        printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%s' AND `botclass` = '%d'", row[4], client->botid);
-        if (mysql_fetch_row(mysql_use()) == NULL) continue;
-        if(!(chanuser = getChanUser(user, chan))) continue;
-        if(!row[1] || !row[2]) {
-            printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
-            default_res = mysql_use();
-            if ((default_row = mysql_fetch_row(default_res)) == NULL) return;
-            chan_getop = (row[1] ? atoi(row[1]) : atoi(default_row[0]));
-            chan_getvoice = (row[2] ? atoi(row[2]) : atoi(default_row[1]));
-        } else {
-            chan_getop = atoi(row[1]);
-            chan_getvoice = atoi(row[2]);
-        }
-        caccess = atoi(row[0]);
-        int done = 0;
-        if(caccess >= chan_getop) {
-            if(!(chanuser->flags & CHANUSERFLAG_OPPED)) {
-                putsock(client, "MODE %s +o %s", chan->name, user->nick);
-                done = 1;
-            }
-        } else if(caccess >= chan_getvoice) {
-            if(!(chanuser->flags & CHANUSERFLAG_VOICED)) {
-                putsock(client, "MODE %s +v %s", chan->name, user->nick);
-                done = 1;
-            }
-        }
-        if(done) {
-            event->chan = chan;
-            logEvent(event);
-        }
-    }
-}
diff --git a/cmd_neonserv_users.c b/cmd_neonserv_users.c
deleted file mode 100644 (file)
index 7834575..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - usermask
-* argv[1] - min access
-* argv[2] - max access
-*/
-static USERLIST_CALLBACK(neonserv_cmd_users_userlist_lookup);
-static void neonserv_cmd_users_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access);
-
-struct neonserv_cmd_users_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    char *usermask;
-    int min_access;
-    int max_access;
-};
-
-CMD_BIND(neonserv_cmd_users) {
-    int min_access = 1, max_access = 500;
-    char *usermask = NULL;
-    if(argc > 0)
-        usermask = argv[0];
-    if(argc > 2) {
-        min_access = atoi(argv[1]);
-        max_access = atoi(argv[2]);
-    }
-    struct neonserv_cmd_users_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->usermask = (usermask ? strdup(usermask) : NULL);
-    cache->min_access = min_access;
-    cache->max_access = max_access;
-    get_userlist_with_invisible(chan, neonserv_cmd_users_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_users_userlist_lookup) {
-    struct neonserv_cmd_users_cache *cache = data;
-    neonserv_cmd_users_async1(cache->client, cache->textclient, cache->user, chan, cache->usermask, cache->min_access, cache->max_access);
-    if(cache->usermask)
-        free(cache->usermask);
-    free(cache);
-}
-
-static void neonserv_cmd_users_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int content_count = 0, cflags, is_here, caccess, i;
-    char seenstr[MAXLEN];
-    struct Table *table;
-    struct ChanUser *chanuser;
-    printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_seen`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' ORDER BY `chanuser_access` DESC, `user_user` ASC", chan->channel_id);
-    res = mysql_use();
-    table = table_init(4, mysql_num_rows(res) + 1, 0);
-    if(usermask)
-        reply(textclient, user, "NS_USERS_HEADER_MATCH", chan->name, min_access, max_access, usermask);
-    else
-        reply(textclient, user, "NS_USERS_HEADER", chan->name, min_access, max_access);
-    char *content[4];
-    content[0] = get_language_string(user, "NS_USERS_HEADER_ACCESS");
-    content[1] = get_language_string(user, "NS_USERS_HEADER_ACCOUNT");
-    content[2] = get_language_string(user, "NS_USERS_HEADER_SEEN");
-    content[3] = get_language_string(user, "NS_USERS_HEADER_STATE");
-    table_add(table, content);
-    while ((row = mysql_fetch_row(res)) != NULL) {
-        caccess = atoi(row[0]);
-        if((!usermask || !match(usermask, row[1])) && caccess >= min_access && caccess <= max_access) {
-            content[0] = row[0];
-            content[1] = row[1];
-            is_here = 0;
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !strcmp(chanuser->user->auth, row[1])) {
-                    if((chanuser->flags & CHANUSERFLAG_INVISIBLE))
-                        is_here = 2;
-                    else {
-                        is_here = 1;
-                        break;
-                    }
-                }
-            }
-            if(is_here) {
-                content[2] = get_language_string(user, (is_here == 2 ? "NS_USERS_SEEN_INVISIBLE" : "NS_USERS_SEEN_HERE"));
-            } else if(!strcmp(row[2], "0")) {
-                content[2] = get_language_string(user, "NS_USERS_SEEN_NEVER");
-            } else {
-                timeToStr(user, (time(0) - atoi(row[2])), 2, seenstr);
-                content[2] = seenstr; //generate time
-            }
-            cflags = atoi(row[3]);
-            if(cflags & DB_CHANUSER_SUSPENDED)
-                content[3] = get_language_string(user, "NS_USERS_STATE_SUSPENDED");
-            else
-                content[3] = get_language_string(user, "NS_USERS_STATE_NORMAL");
-            content_count++;
-            table_add(table, content);
-        }
-    }
-    //send the table
-    char **table_lines = table_end(table);
-    for(i = 0; i < table->entrys; i++) {
-        reply(textclient, user, table_lines[i]);
-    }
-    if(!content_count)
-        reply(textclient, user, "NS_TABLE_NONE");
-    if(usermask || min_access != 1 || max_access != 500)
-        reply(textclient, user, (table->length == 2 ? "NS_USERS_COUNT_MATCH_1" : "NS_USERS_COUNT_MATCH"), table->length - 1, chan->name, content_count);
-    else
-        reply(textclient, user, (table->length == 2 ? "NS_USERS_COUNT_1" : "NS_USERS_COUNT"), table->length - 1, chan->name);
-    table_free(table);
-}
diff --git a/cmd_neonserv_uset.c b/cmd_neonserv_uset.c
deleted file mode 100644 (file)
index 354c08b..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-CMD_BIND(neonserv_cmd_uset) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    loadUserSettings(user);
-    if(argc > 0) {
-        if(!stricmp(argv[0], "language")) {
-            struct language* lang;
-            if(argc > 1) {
-                if((lang = get_language_by_tag(argv[1])) == NULL && (lang = get_language_by_name(argv[1])) == NULL) {
-                    lang = user->language;
-                } else {
-                    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-                    res = mysql_use();
-                    if ((row = mysql_fetch_row(res)) != NULL) {
-                        printf_mysql_query("UPDATE `users` SET `user_lang` = '%s' WHERE `user_id` = '%s'", escape_string(lang->langtag), row[0]);
-                    } else {
-                        printf_mysql_query("INSERT INTO `users` (`user_user`, `user_lang`) VALUES ('%s', '%s')", escape_string(user->auth), escape_string(lang->langtag));
-                    }
-                    struct UserNode *cuser;
-                    for(cuser = getAllUsers(NULL); cuser; cuser = getAllUsers(cuser)) {
-                        if((cuser->flags & USERFLAG_ISAUTHED) && !stricmp(user->auth, cuser->auth))
-                            cuser->language = lang;
-                    }
-                }
-            } else
-                lang = user->language;
-            reply(getTextBot(), user, "\002Language   \002%s", lang->langname);
-            char tmp[MAXLEN];
-            int tmppos = 0;
-            lang = get_default_language();
-            tmppos = sprintf(tmp, "%s (%s)", lang->langname, lang->langtag);
-            printf_mysql_query("SELECT `lang`,`text` FROM `language` WHERE `ident` = 'name'");
-            res = mysql_use();
-            while((row = mysql_fetch_row(res)) != NULL) {
-                tmppos += sprintf(tmp + tmppos, ", %s (%s)", row[1], row[0]);
-            }
-            reply(getTextBot(), user, "  %s", tmp);
-        } else if(!stricmp(argv[0], "noinvite") && chan) {
-            loadChannelSettings(chan);
-            if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) {
-                reply(getTextBot(), user, "MODCMD_CHAN_REQUIRED");
-                return;
-            }
-            printf_mysql_query("SELECT `id` FROM `noinvite` LEFT JOIN `users` ON `uid` = `user_id` WHERE `cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-            res = mysql_use();
-            row = mysql_fetch_row(res);
-            int noinvite = (row ? 1 : 0);
-            if(argc > 1) {
-                if(!strcmp(argv[1], "0") || !stricmp(argv[1], "off") || !stricmp(argv[1], get_language_string(user, "NS_SET_OFF"))) {
-                    if(noinvite) {
-                        printf_mysql_query("DELETE FROM `noinvite` WHERE `id` = '%s'", row[0]);
-                        noinvite = 0;
-                    }
-                } else if(!strcmp(argv[1], "1") || !stricmp(argv[1], "on") || !stricmp(argv[1], get_language_string(user, "NS_SET_ON"))) {
-                    if(!noinvite) {
-                        int userid;
-                        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-                        res = mysql_use();
-                        if ((row = mysql_fetch_row(res)) != NULL) {
-                            userid = atoi(row[0]);
-                        } else {
-                            printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(user->auth));
-                            userid = (int) mysql_insert_id(mysql_conn);
-                        }
-                        printf_mysql_query("INSERT INTO `noinvite` (`uid`, `cid`) VALUES ('%d', '%d')", userid, chan->channel_id);
-                        noinvite = 1;
-                    }
-                }
-            }
-            reply(getTextBot(), user, "\002NoInvite   \002%s", (noinvite ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
-        } else if((!stricmp(argv[0], "autoinvite") || !stricmp(argv[0], "noautoop") || !stricmp(argv[0], "info")) && chan) {
-            loadChannelSettings(chan);
-            if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) {
-                reply(getTextBot(), user, "MODCMD_CHAN_REQUIRED");
-                return;
-            }
-            printf_mysql_query("SELECT `chanuser_flags`, `chanuser_infoline`, `chanuser_access`, `channel_getinvite`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` LEFT JOIN `channels` ON `channel_id` = `chanuser_cid` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-            res = mysql_use();
-            row = mysql_fetch_row(res);
-            if(row) {
-                int flags = atoi(row[0]);
-                if(!stricmp(argv[0], "autoinvite")) {
-                    int getInvite = 0;
-                    if(!row[3] && atoi(row[2]) >= atoi(getChanDefault("channel_getinvite")))
-                        getInvite = 1;
-                    else if(row[3] && atoi(row[2]) >= atoi(row[3]))
-                        getInvite = 1;
-                    if(getInvite && argc > 1) {
-                        if(!strcmp(argv[1], "0") || !stricmp(argv[1], "off") || !stricmp(argv[1], get_language_string(user, "NS_SET_OFF"))) {
-                            if(flags & DB_CHANUSER_AUTOINVITE) {
-                                flags &= ~DB_CHANUSER_AUTOINVITE;
-                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
-                            }
-                        } else if(!strcmp(argv[1], "1") || !stricmp(argv[1], "on") || !stricmp(argv[1], get_language_string(user, "NS_SET_ON"))) {
-                            if(!(flags & DB_CHANUSER_AUTOINVITE)) {
-                                flags |= DB_CHANUSER_AUTOINVITE;
-                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
-                            }
-                        }
-                    }
-                    if(getInvite)
-                        reply(getTextBot(), user, "\002AutoInvite \002%s", ((flags & DB_CHANUSER_AUTOINVITE) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
-                    else
-                        reply(getTextBot(), user, "\002AutoInvite \002%s", get_language_string(user, "NS_USET_NO_ACCESS"));
-                } else if(!stricmp(argv[0], "noautoop")) {
-                    if(argc > 1) {
-                        if(!strcmp(argv[1], "0") || !stricmp(argv[1], "off") || !stricmp(argv[1], get_language_string(user, "NS_SET_OFF"))) {
-                            if(flags & DB_CHANUSER_NOAUTOOP) {
-                                flags &= ~DB_CHANUSER_NOAUTOOP;
-                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
-                            }
-                        } else if(!strcmp(argv[1], "1") || !stricmp(argv[1], "on") || !stricmp(argv[1], get_language_string(user, "NS_SET_ON"))) {
-                            if(!(flags & DB_CHANUSER_NOAUTOOP)) {
-                                flags |= DB_CHANUSER_NOAUTOOP;
-                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
-                            }
-                        }
-                    }
-                    reply(getTextBot(), user, "\002NoAutoOp   \002%s", ((flags & DB_CHANUSER_NOAUTOOP) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
-                } else if(!stricmp(argv[0], "info")) {
-                    char *infoline;
-                    if(argc > 1) {
-                        infoline = merge_argv(argv, 1, argc);
-                        if(!strcmp(infoline, "*"))
-                            infoline = "";
-                        printf_mysql_query("UPDATE `chanusers` SET `chanuser_infoline` = '%s' WHERE `chanuser_id` = '%s'", escape_string(infoline), row[4]);
-                    } else
-                        infoline = row[1];
-                    reply(getTextBot(), user, "\002Info       \002%s", infoline);
-                }
-            } else
-                reply(getTextBot(), user, "NS_NOT_ON_USERLIST_YOU", chan);
-        } else
-            reply(getTextBot(), user, "NS_USET_UNKNOWN_SETTING", argv[0]);
-    } else {
-        //view all options
-        reply(getTextBot(), user, "NS_USET_GLOBAL");
-        reply(getTextBot(), user, "\002Language   \002%s", user->language->langname);
-        if(!chan) return;
-        loadChannelSettings(chan);
-        if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
-        reply(getTextBot(), user, "NS_USET_CHANNEL");
-        printf_mysql_query("SELECT `id` FROM `noinvite` LEFT JOIN `users` ON `uid` = `user_id` WHERE `cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-        reply(getTextBot(), user, "\002NoInvite   \002%s", (row ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
-        printf_mysql_query("SELECT `chanuser_flags`, `chanuser_infoline`, `chanuser_access`, `channel_getinvite` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` LEFT JOIN `channels` ON `channel_id` = `chanuser_cid` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-        res = mysql_use();
-        row = mysql_fetch_row(res);
-        if(row) {
-            int flags = atoi(row[0]);
-            int getInvite = 0;
-            if(!row[3] && atoi(row[2]) >= atoi(getChanDefault("channel_getinvite")))
-                getInvite = 1;
-            else if(row[3] && atoi(row[2]) >= atoi(row[3]))
-                getInvite = 1;
-            if(getInvite)
-                reply(getTextBot(), user, "\002AutoInvite \002%s", ((flags & DB_CHANUSER_AUTOINVITE) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
-            else
-                reply(getTextBot(), user, "\002AutoInvite \002%s", get_language_string(user, "NS_USET_NO_ACCESS"));
-            reply(getTextBot(), user, "\002NoAutoOp   \002%s", ((flags & DB_CHANUSER_NOAUTOOP) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
-            reply(getTextBot(), user, "\002Info       \002%s", row[1]);
-        }
-    }
-}
\ No newline at end of file
diff --git a/cmd_neonserv_version.c b/cmd_neonserv_version.c
deleted file mode 100644 (file)
index ed33d09..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* no args
-*/
-
-CMD_BIND(neonserv_cmd_version) {
-    reply(getTextBot(), user, "\002NeonServ " NEONSERV_VERSION "\002 (%s), written by pk910", (strcmp(revision, "") ? revision : "-"));
-    reply(getTextBot(), user, "Build (#%s) %s (%s lines, " COMPILER ")", compilation, creation, codelines);
-    reply(getTextBot(), user, "NeonServ source can be found on: http://git.pk910.de/?p=NeonServV5.git");
-    //helpers :D
-    reply(getTextBot(), user, "special thanks to:");
-    reply(getTextBot(), user, "  Zer0n, TeaTow  (testing and ideas current version)");
-    reply(getTextBot(), user, "  Buchman, Zer0n  (translating current version)");
-    reply(getTextBot(), user, "  Patschi95, DerGrinch, Darkfly, Zer0n, Buschman  (testing and ideas older versions)");
-    reply(getTextBot(), user, "  Buschman, Georg, richard  (translating older versions)");
-    reply(getTextBot(), user, "and all the other users that reported all these nasty bugs :D");
-    reply(getTextBot(), user, "\002If you found a bug or if you have a good idea report it on http://bugtrack.pk910.de/git_view.php?p=NeonServV5.git\002");
-    
-}
\ No newline at end of file
diff --git a/cmd_neonserv_voice.c b/cmd_neonserv_voice.c
deleted file mode 100644 (file)
index 45a78a9..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0-*]    nicks
-*/
-static USERLIST_CALLBACK(neonserv_cmd_voice_userlist_lookup);
-static void neonserv_cmd_voice_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks);
-
-struct neonserv_cmd_voice_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *nicks;
-};
-
-CMD_BIND(neonserv_cmd_voice) {
-    struct neonserv_cmd_voice_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    cache->nicks = strdup(merge_argv(argv, 0, argc));
-    get_userlist_with_invisible(chan, neonserv_cmd_voice_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_voice_userlist_lookup) {
-    struct neonserv_cmd_voice_cache *cache = data;
-    neonserv_cmd_voice_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks);
-    free(cache->nicks);
-    free(cache);
-}
-
-static void neonserv_cmd_voice_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks) {
-    int total_users = 0, done_users = 0;
-    struct UserNode *cuser;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    char *a, *b = nicks;
-    do {
-        a = strstr(b, " ");
-        if(a) *a = '\0';
-        total_users++;
-        cuser = searchUserByNick(b);
-        if(!cuser) {
-            //check for an invisible user
-            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-                if(!stricmp(chanuser->user->nick, b)) {
-                    cuser = chanuser->user;
-                    break;
-                }
-            }
-            if(!cuser) continue;
-        } else {
-            chanuser = getChanUser(cuser, chan);
-            if(!chanuser) continue;
-        }
-        done_users++;
-        if(chanuser->flags & CHANUSERFLAG_VOICED) continue;
-        modeBufferVoice(modeBuf, b);
-        if(a) {
-            b = a+1;
-        }
-    } while(a);
-    freeModeBuffer(modeBuf);
-    if(done_users == total_users)
-        reply(textclient, user, "NS_VOICE_DONE", chan->name);
-    else
-        reply(textclient, user, "NS_VOICE_FAIL", client->user->nick);
-    if(done_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_voiceall.c b/cmd_neonserv_voiceall.c
deleted file mode 100644 (file)
index e4de009..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0]    (optional) nick mask
-*/
-static USERLIST_CALLBACK(neonserv_cmd_voiceall_userlist_lookup);
-static void neonserv_cmd_voiceall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask);
-
-struct neonserv_cmd_voiceall_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct Event *event;
-    char *nickmask;
-};
-
-CMD_BIND(neonserv_cmd_voiceall) {
-    struct neonserv_cmd_voiceall_cache *cache = malloc(sizeof(*cache));
-    if (!cache) {
-        perror("malloc() failed");
-        return;
-    }
-    cache->client = client;
-    cache->textclient = getTextBot();
-    cache->user = user;
-    cache->event = event;
-    if(argc > 0) {
-        cache->nickmask = strdup(argv[0]);
-    } else
-        cache->nickmask = NULL;
-    get_userlist_with_invisible(chan, neonserv_cmd_voiceall_userlist_lookup, cache);
-}
-
-static USERLIST_CALLBACK(neonserv_cmd_voiceall_userlist_lookup) {
-    struct neonserv_cmd_voiceall_cache *cache = data;
-    neonserv_cmd_voiceall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask);
-    if(cache->nickmask)
-        free(cache->nickmask);
-    free(cache);
-}
-
-static void neonserv_cmd_voiceall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask) {
-    int done_users = 0;
-    struct ChanUser *chanuser;
-    struct ModeBuffer *modeBuf;
-    modeBuf = initModeBuffer(client, chan);
-    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
-        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
-        if(chanuser->flags & CHANUSERFLAG_VOICED) continue;
-        modeBufferVoice(modeBuf, chanuser->user->nick);
-        done_users++;
-    }
-    freeModeBuffer(modeBuf);
-    reply(textclient, user, "NS_VOICEALL_DONE", done_users, chan->name);
-    if(done_users)
-        logEvent(event);
-}
diff --git a/cmd_neonserv_wipeinfo.c b/cmd_neonserv_wipeinfo.c
deleted file mode 100644 (file)
index 81378d6..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-
-#include "cmd_neonserv.h"
-
-/*
-* argv[0] - nick / *auth
-*/
-static USERAUTH_CALLBACK(neonserv_cmd_wipeinfo_nick_lookup);
-static void neonserv_cmd_wipeinfo_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
-
-struct neonserv_cmd_wipeinfo_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    struct Event *event;
-    char *nick;
-};
-
-CMD_BIND(neonserv_cmd_wipeinfo) {
-    if(argv[0][0] == '*') {
-        //we've got an auth
-        argv[0]++;
-        neonserv_cmd_wipeinfo_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
-    } else {
-        struct UserNode *cuser = getUserByNick(argv[0]);
-        if(!cuser) {
-            cuser = createTempUser(argv[0]);
-            cuser->flags |= USERFLAG_ISTMPUSER;
-        }
-        if(cuser->flags & USERFLAG_ISAUTHED) {
-            neonserv_cmd_wipeinfo_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
-        } else {
-            struct neonserv_cmd_wipeinfo_cache *cache = malloc(sizeof(*cache));
-            if (!cache) {
-                perror("malloc() failed");
-                return;
-            }
-            cache->client = client;
-            cache->textclient = getTextBot();
-            cache->user = user;
-            cache->chan = chan;
-            cache->event = event;
-            cache->nick = strdup(argv[0]);
-            get_userauth(cuser, neonserv_cmd_wipeinfo_nick_lookup, cache);
-        }
-    }
-}
-
-static USERAUTH_CALLBACK(neonserv_cmd_wipeinfo_nick_lookup) {
-    struct neonserv_cmd_wipeinfo_cache *cache = data;
-    if(!user) {
-        //USER_DOES_NOT_EXIST
-        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
-    }
-    else if(!(user->flags & USERFLAG_ISAUTHED)) {
-        //USER_NOT_AUTHED
-        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
-    }
-    else
-        neonserv_cmd_wipeinfo_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
-    free(cache->nick);
-    free(cache);
-}
-
-static void neonserv_cmd_wipeinfo_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
-    //we've got a valid auth now...
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int userid;
-    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) != NULL) {
-        userid = atoi(row[0]);
-        //check if the user is already added
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
-                if(isGodMode(user)) {
-                    event->flags |= CMDFLAG_OPLOG;
-                } else {
-                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
-                    return;
-                }
-            }
-            //delete
-            printf_mysql_query("UPDATE `chanusers` SET `chanuser_infoline` = '' WHERE `chanuser_id` = '%s'", row[1]);
-            reply(textclient, user, "NS_WIPEINFO_DONE", nick, chan->name);
-            logEvent(event);
-            return;
-        }
-    }
-    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
-}
diff --git a/config.h.example b/config.h.example
deleted file mode 100644 (file)
index 6d573d4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-#define MYSQL_HOST "127.0.0.1"
-#define MYSQL_PORT 3306
-#define MYSQL_USER "neonserv"
-#define MYSQL_PASS ""
-#define MYSQL_BASE "neonserv"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..308d5f4
--- /dev/null
@@ -0,0 +1,37 @@
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.67])
+AC_INIT([NeonServ], [5.0], [bugs@pk910.de], [neonserv], [http://neonserv.krypton-bouncer.de])
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+AC_CONFIG_HEADERS([config.h])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_AWK
+
+# Checks for libraries.
+# Get MySQL library and include locations
+AC_ARG_WITH([mysql-include-path],
+  [AS_HELP_STRING([--with-mysql-include-path],
+    [location of the MySQL headers, defaults to /usr/include/mysql])],
+  [MYSQL_CFLAGS="-I$withval"],
+  [MYSQL_CFLAGS='-I/usr/include/mysql'])
+AC_SUBST([MYSQL_CFLAGS])
+
+AC_ARG_WITH([mysql-lib-path],
+  [AS_HELP_STRING([--with-mysql-lib-path], [location of the MySQL libraries])],
+  [MYSQL_LIBS="-L$withval -lmysqlclient"],
+  [MYSQL_LIBS='-lmysqlclient'])
+AC_SUBST([MYSQL_LIBS])
+
+# Checks for header files.
+AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_CHECK_FUNCS([gethostbyname memset select socket strchr strdup strstr])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
\ No newline at end of file
diff --git a/event_neonserv_ctcp.c b/event_neonserv_ctcp.c
deleted file mode 100644 (file)
index a8df98e..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-
-struct neonserv_event_ctcp_cache {
-    struct ClientSocket *client;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    char *command;
-    char *text;
-};
-
-static USERAUTH_CALLBACK(neonserv_event_ctcp_nick_lookup);
-static void neonserv_event_ctcp_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char *text);
-static int neonserv_ctcp(char *buffer, char *command, char *text);
-
-static void neonserv_event_chanctcp(struct UserNode *user, struct ChanNode *chan, char *command, char *text) {
-    struct ClientSocket *client = getBotForChannel(chan);
-    if(!client) return; //we can't "see" this event
-    if(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)) return; 
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
-    if(!(user->flags & USERFLAG_ISAUTHED)) {
-        struct neonserv_event_ctcp_cache *cache = malloc(sizeof(*cache));
-        if (!cache) {
-            perror("malloc() failed");
-            return;
-        }
-        cache->client = client;
-        cache->user = user;
-        cache->chan = chan;
-        cache->command = strdup(command);
-        cache->text = (text ? strdup(text) : NULL);
-        get_userauth(user, neonserv_event_ctcp_nick_lookup, cache);
-    } else
-        neonserv_event_ctcp_async1(client, user, chan, command, text);
-}
-
-static USERAUTH_CALLBACK(neonserv_event_ctcp_nick_lookup) {
-    struct neonserv_event_ctcp_cache *cache = data;
-    if(user) {
-        neonserv_event_ctcp_async1(cache->client, cache->user, cache->chan, cache->command, cache->text);
-    }
-    free(cache->command);
-    if(cache->text)
-        free(cache->text);
-    free(cache);
-}
-
-static void neonserv_event_ctcp_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char *text) {
-    MYSQL_RES *res;
-    MYSQL_ROW row, defaultrow = NULL, chanuser;
-    int uaccess = 0;
-    printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return;
-    if(!row[0] || !row[1]) {
-        printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        defaultrow = mysql_fetch_row(res);
-    }
-    int ctcpaccess = atoi((row[0] ? row[0] : defaultrow[0]));
-    if((user->flags & USERFLAG_ISAUTHED)) {
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-        res = mysql_use();
-        chanuser = mysql_fetch_row(res);
-        if(chanuser)
-            uaccess = ((atoi(chanuser[1]) & DB_CHANUSER_SUSPENDED) ? 0 : atoi(chanuser[0]));
-    }
-    int duration = 0;
-    char banmaskBuf[NICKLEN+USERLEN+HOSTLEN+3];
-    char *banmask = NULL;
-    char *reason = "disallowed channel CTCP";
-    if(uaccess < ctcpaccess) {
-        switch(atoi((row[1] ? row[1] : defaultrow[1]))) {
-            case 2: //TIMEBAN: 3min
-                duration = 180;
-            case 3: //TIMEBAN: 1h
-                if(!duration)
-                    duration = 3600;
-                banmask = generate_banmask(user, banmaskBuf);
-                printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(banmask), (unsigned long) (time(0) + duration), 0, escape_string(reason));
-                int banid = (int) mysql_insert_id(mysql_conn);
-                char nameBuf[MAXLEN];
-                char banidBuf[20];
-                sprintf(nameBuf, "ban_%d", banid);
-                sprintf(banidBuf, "%d", banid);
-                timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
-            case 1: //KICKBAN
-                if(!banmask)
-                    banmask = generate_banmask(user, banmaskBuf);
-                putsock(client, "MODE %s +b %s", chan->name, banmask);
-            case 0: //KICK
-                putsock(client, "KICK %s %s :%s", chan->name, user->nick, reason);
-                break;
-        }
-    }
-}
-
-static void neonserv_event_privctcp(struct UserNode *user, struct UserNode *target, char *command, char *text) {
-    char ctcpBuf[MAXLEN];
-    if(neonserv_ctcp(ctcpBuf, command, text)) {
-        struct ClientSocket *bot;
-        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-            if(bot->user == target) break;
-        }
-        if(bot)
-            putsock(bot, "NOTICE %s :\001%s\001", user->nick, ctcpBuf);
-    }
-}
-
-static int neonserv_ctcp(char *buffer, char *command, char *text) {
-    if(!stricmp(command, "VERSION")) {
-        sprintf(buffer, "VERSION NeonServ v" NEONSERV_VERSION " by pk910 (%s)", (strcmp(revision, "") ? revision : "-"));
-        return 1;
-    }
-    if(!stricmp(command, "FINGER")) {
-        sprintf(buffer, "FINGER NeonServ v" NEONSERV_VERSION " (%s) build %s lines C code using " COMPILER " (see +netinfo)", (strcmp(revision, "") ? revision : "-"), codelines);
-        return 1;
-    }
-    if(!stricmp(command, "PING")) {
-        sprintf(buffer, "PING %s", (text ? text : "0"));
-        return 1;
-    }
-    if(!stricmp(command, "TIME")) {
-        time_t rawtime;
-        struct tm *timeinfo;
-        char timeBuf[80];
-        time(&rawtime);
-        timeinfo = localtime(&rawtime);
-        strftime(timeBuf, 80, "%c", timeinfo);
-        sprintf(buffer, "TIME %s", timeBuf);
-        return 1;
-    }
-    return 0;
-}
diff --git a/event_neonserv_invite.c b/event_neonserv_invite.c
deleted file mode 100644 (file)
index c25aff4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-
-static void neonserv_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) {
-        reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick);
-        return;
-    }
-    int botid = atoi(row[0]);
-    struct ClientSocket *bot;
-    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
-        if(bot->clientid == botid)
-            break;
-    }
-    if(bot) {
-        struct ChanNode *chan = getChanByName(channel);
-        if(chan && isUserOnChan(bot->user, chan)) {
-            reply(client, user, "NS_INVITE_ON_CHAN", bot->user->nick, chan->name);
-        } else
-            putsock(bot, "JOIN %s", channel);
-    }
-}
-
diff --git a/event_neonserv_join.c b/event_neonserv_join.c
deleted file mode 100644 (file)
index a117c18..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-
-struct neonserv_event_join_cache {
-    struct ClientSocket *client;
-    struct ChanUser *chanuser;
-};
-
-static USERAUTH_CALLBACK(neonserv_event_join_nick_lookup);
-static void neonserv_event_join_async1(struct ClientSocket *client, struct ChanUser *chanuser);
-static TIMEQ_CALLBACK(neonserv_event_join_dynlimit);
-
-static void neonserv_event_join(struct ChanUser *chanuser) {
-    struct UserNode *user = chanuser->user;
-    struct ClientSocket *client = getBotForChannel(chanuser->chan);
-    if(!client) return; //we can't "see" this event
-    if(user->flags & USERFLAG_ISBOT) {
-        putsock(client, "MODE %s +o %s", chanuser->chan->name, chanuser->user->nick);
-        return;
-    }
-    loadChannelSettings(chanuser->chan);
-    if(!(chanuser->chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
-    char *ban;
-    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
-    sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
-    if((ban = getBanAffectingMask(chanuser->chan, usermask)) != NULL && !(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP))) {
-        MYSQL_RES *res;
-        MYSQL_ROW row;
-        printf_mysql_query("SELECT `ban_reason`, `user_user` FROM `bans` LEFT JOIN `users` ON `ban_owner` = `user_id` WHERE `ban_channel` = '%d' AND `ban_mask` = '%s'", chanuser->chan->channel_id, escape_string(ban));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            putsock(client, "MODE %s +b %s", chanuser->chan->name, ban);
-            putsock(client, "KICK %s %s :(%s) %s", chanuser->chan->name, chanuser->user->nick, (row[1] ? row[1] : client->user->nick), row[0]);
-            return;
-        }
-    }
-    if(!(user->flags & USERFLAG_ISAUTHED)) {
-        struct neonserv_event_join_cache *cache = malloc(sizeof(*cache));
-        if (!cache) {
-            perror("malloc() failed");
-            return;
-        }
-        cache->client = client;
-        cache->chanuser = chanuser;
-        get_userauth(user, neonserv_event_join_nick_lookup, cache);
-    } else
-        neonserv_event_join_async1(client, chanuser);
-}
-
-static USERAUTH_CALLBACK(neonserv_event_join_nick_lookup) {
-    struct neonserv_event_join_cache *cache = data;
-    if(user) {
-        neonserv_event_join_async1(cache->client, cache->chanuser);
-    }
-    free(cache);
-}
-
-static void neonserv_event_join_async1(struct ClientSocket *client, struct ChanUser *chanuser) {
-    struct ClientSocket *textclient = ((client->flags & SOCKET_FLAG_PREFERRED) ? client : get_prefered_bot(client->botid));
-    struct ChanNode *chan = chanuser->chan;
-    struct UserNode *user = chanuser->user;
-    struct ModeBuffer *modeBuf;
-    MYSQL_RES *res;
-    MYSQL_ROW row, chanuserrow, defaultrow = NULL;
-    printf_mysql_query("SELECT `channel_maxusers`, `channel_greeting`, `channel_usergreeting`, `channel_getop`, `channel_getvoice`, `channel_userinfo`, `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return;
-    if(!row[3] || !row[4]) {
-        printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_userinfo` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        defaultrow = mysql_fetch_row(res);
-    }
-    if(chan->usercount > atoi(row[0])) {
-        //update maxusers
-        printf_mysql_query("UPDATE `channels` SET `channel_maxusers` = '%d' WHERE `channel_id` = '%d'", chan->usercount, chan->channel_id);
-    }
-    if((user->flags & USERFLAG_ISAUTHED)) {
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags`, `chanuser_infoline`, `chanuser_seen`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-        res = mysql_use();
-        chanuserrow = mysql_fetch_row(res);
-    } else
-        chanuserrow = NULL;
-    int userflags = (chanuserrow ? atoi(chanuserrow[1]) : 0);
-    int uaccess = ((chanuserrow && !(userflags & DB_CHANUSER_SUSPENDED)) ? atoi(chanuserrow[0]) : 0);
-    //GREETING
-    char greeting[MAXLEN];
-    int greetingPos = 0;
-    char *a, *b = (chanuserrow && *row[2] ? row[2] : row[1]);
-    do {
-        if(!b) break;
-        a = strstr(b, "$");
-        if(a) *a = '\0';
-        greetingPos += sprintf(greeting + greetingPos, "%s", b);
-        if(!a) break;
-        switch(a[1]) {
-            case '\0':
-                a = NULL;
-                break;
-            case 'A':
-                greetingPos += sprintf(greeting + greetingPos, "%d", uaccess);
-                break;
-            case 'B':
-                greetingPos += sprintf(greeting + greetingPos, "%s", client->user->nick);
-                break;
-            case 'N':
-                greetingPos += sprintf(greeting + greetingPos, "%s", user->nick);
-                break;
-            case 'H':
-                greetingPos += sprintf(greeting + greetingPos, "%s@%s", user->ident, user->host);
-                break;
-            case 'U':
-                greetingPos += sprintf(greeting + greetingPos, "%s", ((user->flags & USERFLAG_ISAUTHED) ? user->auth : "*"));
-                break;
-            default:
-                greeting[greetingPos++] = '$';
-                greeting[greetingPos++] = a[1];
-                break;
-        }
-        if(a)
-            b = a+2;
-    } while(a);
-    if(greetingPos)
-        reply(textclient, user, "[%s] %s", chan->name, greeting);
-    //USER RIGHTS
-    if(!(userflags & DB_CHANUSER_NOAUTOOP)) {
-        int getop = atoi((row[3] ? row[3] : defaultrow[0]));
-        int getvoice = atoi((row[4] ? row[4] : defaultrow[1]));
-        modeBuf = initModeBuffer(client, chan);
-        if(uaccess >= getop && uaccess != 0) { //we disallow auto op for all users
-            modeBufferOp(modeBuf, user->nick);
-        } else if(uaccess >= getvoice) {
-            modeBufferVoice(modeBuf, user->nick);
-        }
-        freeModeBuffer(modeBuf);
-    }
-    //INFOLINE
-    int userinfoaccess = atoi((row[5] ? row[5] : defaultrow[2]));
-    if(chanuserrow && strcmp(chanuserrow[2], "") && uaccess > userinfoaccess) {
-        if(!strcmp(chanuserrow[3], "0") || time(0) - atol(chanuserrow[3]) >= 30) {
-            putsock(client, "PRIVMSG %s :[%s] %s", chan->name, user->nick, chanuserrow[2]);
-        }
-    }
-    //SEEN
-    if(chanuserrow) {
-        printf_mysql_query("UPDATE `chanusers` SET `chanuser_seen` = UNIX_TIMESTAMP() WHERE `chanuser_id` = '%s'", chanuserrow[4]);
-    }
-    //DYNLIMIT
-    if(row[6] && strcmp(row[6], "0")) {
-        char nameBuf[CHANNELLEN + 10];
-        sprintf(nameBuf, "dynlimit_%s", chan->name);
-        if(!timeq_name_exists(nameBuf)) {
-            //neonserv_event_join_dynlimit
-            timeq_add_name(nameBuf, 30, neonserv_event_join_dynlimit, strdup(chan->name));
-        }
-    }
-    //AUTOINVITE
-    if(chanuserrow && !strcmp(chanuserrow[3], "0") && time(0) - atol(chanuserrow[3]) >= 30) {
-        //TODO: autoinvite
-    }
-}
-
-static TIMEQ_CALLBACK(neonserv_event_join_dynlimit) {
-    char *chanName = data;
-    struct ChanNode *chan = getChanByName(chanName);
-    free(chanName);
-    struct ClientSocket *client = getBotForChannel(chan);
-    if(!client) return;
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return;
-    if(row[0] && strcmp(row[0], "0")) {
-        putsock(client, "MODE %s +l %d", chan->name, chan->usercount + atoi(row[0]));
-    }
-}
diff --git a/event_neonserv_notice.c b/event_neonserv_notice.c
deleted file mode 100644 (file)
index a566a4e..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-
-struct neonserv_event_notice_cache {
-    struct ClientSocket *client;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    char *message;
-};
-
-static USERAUTH_CALLBACK(neonserv_event_notice_nick_lookup);
-static void neonserv_event_notice_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message);
-
-static void neonserv_event_channotice(struct UserNode *user, struct ChanNode *chan, char *message) {
-    struct ClientSocket *client = getBotForChannel(chan);
-    if(!client) return; //we can't "see" this event
-    if(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)) return; 
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
-    if(!(user->flags & USERFLAG_ISAUTHED)) {
-        struct neonserv_event_notice_cache *cache = malloc(sizeof(*cache));
-        if (!cache) {
-            perror("malloc() failed");
-            return;
-        }
-        cache->client = client;
-        cache->user = user;
-        cache->chan = chan;
-        cache->message = strdup(message);
-        get_userauth(user, neonserv_event_notice_nick_lookup, cache);
-    } else
-        neonserv_event_notice_async1(client, user, chan, message);
-}
-
-static USERAUTH_CALLBACK(neonserv_event_notice_nick_lookup) {
-    struct neonserv_event_notice_cache *cache = data;
-    if(user) {
-        neonserv_event_notice_async1(cache->client, cache->user, cache->chan, cache->message);
-    }
-    free(cache->message);
-    free(cache);
-}
-
-static void neonserv_event_notice_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) {
-    MYSQL_RES *res;
-    MYSQL_ROW row, defaultrow = NULL, chanuser;
-    int uaccess = 0;
-    printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return;
-    if(!row[0] || !row[1]) {
-        printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        defaultrow = mysql_fetch_row(res);
-    }
-    int noticeaccess = atoi((row[0] ? row[0] : defaultrow[0]));
-    if((user->flags & USERFLAG_ISAUTHED)) {
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-        res = mysql_use();
-        chanuser = mysql_fetch_row(res);
-        if(chanuser)
-            uaccess = ((atoi(chanuser[1]) & DB_CHANUSER_SUSPENDED) ? 0 : atoi(chanuser[0]));
-    }
-    int duration = 0;
-    char banmaskBuf[NICKLEN+USERLEN+HOSTLEN+3];
-    char *banmask = NULL;
-    char *reason = "disallowed channel NOTICE";
-    if(uaccess < noticeaccess) {
-        switch(atoi((row[1] ? row[1] : defaultrow[1]))) {
-            case 2: //TIMEBAN: 3min
-                duration = 180;
-            case 3: //TIMEBAN: 1h
-                if(!duration)
-                    duration = 3600;
-                banmask = generate_banmask(user, banmaskBuf);
-                printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(banmask), (unsigned long) (time(0) + duration), 0, escape_string(reason));
-                int banid = (int) mysql_insert_id(mysql_conn);
-                char nameBuf[MAXLEN];
-                char banidBuf[20];
-                sprintf(nameBuf, "ban_%d", banid);
-                sprintf(banidBuf, "%d", banid);
-                timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
-            case 1: //KICKBAN
-                if(!banmask)
-                    banmask = generate_banmask(user, banmaskBuf);
-                putsock(client, "MODE %s +b %s", chan->name, banmask);
-            case 0: //KICK
-                putsock(client, "KICK %s %s :%s", chan->name, user->nick, reason);
-                break;
-        }
-    }
-}
-
diff --git a/event_neonserv_part.c b/event_neonserv_part.c
deleted file mode 100644 (file)
index d02aeef..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-
-static void neonserv_event_part(struct ChanUser *chanuser, char *reason) {
-    struct ChanNode *chan = chanuser->chan;
-    struct UserNode *user = chanuser->user;
-    MYSQL_RES *res;
-    MYSQL_ROW chanuserrow;
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
-    if((user->flags & USERFLAG_ISAUTHED)) {
-        printf_mysql_query("SELECT `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-        res = mysql_use();
-        if((chanuserrow = mysql_fetch_row(res)) != NULL)
-            printf_mysql_query("UPDATE `chanusers` SET `chanuser_seen` = UNIX_TIMESTAMP() WHERE `chanuser_id` = '%s'", chanuserrow[0]);
-    }
-}
diff --git a/event_neonserv_quit.c b/event_neonserv_quit.c
deleted file mode 100644 (file)
index 30d467f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-
-static void neonserv_event_quit(struct UserNode *user, char *reason) {
-    MYSQL_RES *res;
-    MYSQL_ROW chanuserrow;
-    struct ChanUser *chanuser;
-    if((user->flags & USERFLAG_ISAUTHED)) {
-        for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = getUserChannels(user, chanuser)) {
-            printf_mysql_query("SELECT `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` LEFT JOIN `channels` ON `chanuser_cid` = `channel_id` WHERE `channel_name` = '%s' AND `user_user` = '%s'", escape_string(chanuser->chan->name), escape_string(user->auth));
-            res = mysql_use();
-            if((chanuserrow = mysql_fetch_row(res)) != NULL)
-                printf_mysql_query("UPDATE `chanusers` SET `chanuser_seen` = UNIX_TIMESTAMP() WHERE `chanuser_id` = '%s'", chanuserrow[0]);
-        }
-    }
-}
diff --git a/event_neonserv_topic.c b/event_neonserv_topic.c
deleted file mode 100644 (file)
index 1dc2b51..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-
-struct neonserv_event_topic_cache {
-    struct ClientSocket *client;
-    struct UserNode *user;
-    struct ChanNode *chan;
-    char *new_topic;
-};
-
-static USERAUTH_CALLBACK(neonserv_event_topic_nick_lookup);
-static void neonserv_event_topic_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, const char *new_topic);
-
-static void neonserv_event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic) {
-    struct ClientSocket *client = getBotForChannel(chan);
-    if(!client) return; //we can't "see" this event
-    if(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)) return; 
-    loadChannelSettings(chan);
-    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
-    if(!(user->flags & USERFLAG_ISAUTHED)) {
-        struct neonserv_event_topic_cache *cache = malloc(sizeof(*cache));
-        if (!cache) {
-            perror("malloc() failed");
-            return;
-        }
-        cache->client = client;
-        cache->user = user;
-        cache->chan = chan;
-        cache->new_topic = strdup(new_topic);
-        get_userauth(user, neonserv_event_topic_nick_lookup, cache);
-    } else
-        neonserv_event_topic_async1(client, user, chan, new_topic);
-}
-
-static USERAUTH_CALLBACK(neonserv_event_topic_nick_lookup) {
-    struct neonserv_event_topic_cache *cache = data;
-    if(user) {
-        neonserv_event_topic_async1(cache->client, cache->user, cache->chan, cache->new_topic);
-    }
-    free(cache->new_topic);
-    free(cache);
-}
-
-static void neonserv_event_topic_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, const char *new_topic) {
-    MYSQL_RES *res;
-    MYSQL_ROW row, defaultrow = NULL, chanuserrow;
-    int uaccess = 0;
-    printf_mysql_query("SELECT `channel_changetopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
-    res = mysql_use();
-    if ((row = mysql_fetch_row(res)) == NULL) return;
-    if(!row[0] || !row[1]) {
-        printf_mysql_query("SELECT `channel_changetopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_name` = 'defaults'");
-        res = mysql_use();
-        defaultrow = mysql_fetch_row(res);
-    }
-    int changetopic = atoi((row[0] ? row[0] : defaultrow[0]));
-    int topicsnarf = atoi((row[1] ? row[1] : defaultrow[1]));
-    if((user->flags & USERFLAG_ISAUTHED)) {
-        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
-        res = mysql_use();
-        chanuserrow = mysql_fetch_row(res);
-        if(chanuserrow)
-            uaccess = ((atoi(chanuserrow[1]) & DB_CHANUSER_SUSPENDED) ? 0 : atoi(chanuserrow[0]));
-    }
-    if(uaccess < changetopic) {
-        //undo topic change
-        struct ClientSocket *textclient = ((client->flags & SOCKET_FLAG_PREFERRED) ? client : get_prefered_bot(client->botid));
-        struct ChanUser *chanuser = getChanUser(user, chan);
-        if(!chanuser) return; //flying super cow?
-        if(time(0) - chanuser->changeTime > BOTWAR_DETECTION_TIME) {
-            chanuser->changeTime = time(0);
-            chanuser->chageEvents = 1;
-        } else {
-            chanuser->chageEvents++;
-            if(chanuser->chageEvents >= BOTWAR_DETECTION_EVENTS || chanuser->chageEvents < 0) {
-                //BOTWAR!
-                chanuser->changeTime = time(0);
-                if(chanuser->chageEvents > 0) {
-                    putsock(client, "NOTICE @%s :%s %s", chan->name, get_language_string(user, "NS_BOTWAR_DETECTED"), (BOTWAR_ALERT_CHAN ? get_language_string(user, "NS_BOTWAR_REPORTED") : ""));
-                    if(BOTWAR_ALERT_CHAN) {
-                        struct ChanNode *alertchan = getChanByName(BOTWAR_ALERT_CHAN);
-                        struct ClientSocket *alertclient;
-                        if(alertchan && (alertclient = getBotForChannel(chan)) != NULL) {
-                            char msgBuf[MAXLEN];
-                            putsock(alertclient, "PRIVMSG %s :%s", alertchan->name, build_language_string(user, msgBuf, "NS_BOTWAR_ALERT", chan->name, user->nick));
-                        }
-                    }
-                }
-                chanuser->chageEvents = -2;
-                return;
-            }
-        }
-        reply(textclient, user, "NS_TOPIC_ACCESS", chan->name);
-        putsock(client, "TOPIC %s :%s", chan->name, chan->topic);
-    } else if(uaccess >= topicsnarf) {
-        printf_mysql_query("UPDATE `channels` SET `channel_defaulttopic` = '%s' WHERE `channel_id` = '%d'", escape_string(new_topic), chan->channel_id);
-    }
-}
-
diff --git a/lang.c b/lang.c
deleted file mode 100644 (file)
index e50e752..0000000
--- a/lang.c
+++ /dev/null
@@ -1,201 +0,0 @@
-#include "lang.h"
-#include "UserNode.h"
-#include "DBHelper.h"
-#include "mysqlConn.h"
-
-#define DEFAULT_LANG_TAG "EN"
-#define DEFAULT_LANG_NAME "English"
-
-static struct language **langdict;
-static struct language *lang_c;
-
-void init_lang() {
-    langdict = calloc(MAXLANGUAGES, sizeof(*langdict));
-}
-
-void free_lang() {
-    
-}
-
-void load_languages() {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `lang`, `text` FROM `language` WHERE `ident` = 'name'");
-    res = mysql_use();
-    while((row = mysql_fetch_row(res)) != NULL) {
-        load_language(row[0], row[1]);
-    }
-}
-
-static struct language* add_language(char *langtag, char *langname) {
-    int cindex;
-    for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
-        if(langdict[cindex] == NULL) break;
-        if(!strcmp(langdict[cindex]->langname, langname) || !strcmp(langdict[cindex]->langtag, langtag))
-            return langdict[cindex];
-    }
-    if(cindex == MAXLANGUAGES) return NULL;
-    struct language *lang = malloc(sizeof(*lang));
-    if (!lang) {
-        perror("malloc() failed");
-        return NULL;
-    }
-    lang->langtag = strdup(langtag);
-    lang->langname = strdup(langname);
-    struct language_table **entrys = calloc(27, sizeof(*entrys));
-    lang->entrys = entrys;
-    langdict[cindex] = lang;
-    return lang;
-}
-
-static int get_entry_index(const char *ident) {
-    const char *underscore = strstr(ident, "_");
-    if(!underscore || !(underscore[1] >= 65 && underscore[1] <= 90)) return 26;
-    return (underscore[1] - 'A');
-}
-
-void load_language(char *tag, char *name) {
-    struct language *lang = get_language_by_tag(tag);
-    if(lang == get_default_language()) return;
-    if(lang) {
-        //remove all entrys
-        int cindex;
-        struct language_table *entry, *next;
-        for(cindex = 0; cindex < 27; cindex++) {
-            for(entry = lang->entrys[cindex]; entry; entry = next) {
-                next = entry->next;
-                free(entry->ident);
-                free(entry->text);
-                free(entry);
-            }
-            lang->entrys[cindex] = NULL;
-        }
-    } else
-        lang = add_language(tag, name);
-    if(!lang) return;
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    printf_mysql_query("SELECT `ident`, `text` FROM `language` WHERE `lang` = '%s' AND `ident` != 'name'", escape_string(tag));
-    res = mysql_use();
-    while((row = mysql_fetch_row(res)) != NULL) {
-        register_language_string(lang, row[0], row[1]);
-    }
-}
-
-struct language* get_language_by_tag(char *tag) {
-    int cindex;
-    for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
-        if(langdict[cindex] == NULL) break;
-        if(!stricmp(langdict[cindex]->langtag, tag))
-            return langdict[cindex];
-    }
-    return NULL;
-}
-
-struct language* get_language_by_name(char *name) {
-    int cindex;
-    for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
-        if(langdict[cindex] == NULL) break;
-        if(!stricmp(langdict[cindex]->langname, name))
-            return langdict[cindex];
-    }
-    return NULL;
-}
-
-struct language* get_default_language() {
-    if(lang_c == NULL) 
-        lang_c = add_language(DEFAULT_LANG_TAG, DEFAULT_LANG_NAME);
-    return lang_c;
-}
-
-void register_default_language_table(const struct default_language_entry *msgtab) {
-    if(lang_c == NULL) 
-        lang_c = add_language(DEFAULT_LANG_TAG, DEFAULT_LANG_NAME);
-    while(msgtab->ident) {
-        register_language_string(lang_c, msgtab->ident, msgtab->text);
-        msgtab++;
-    }
-}
-
-void register_language_string(struct language *lang, char *ident, char *text) {
-    int cindex = get_entry_index(ident);
-    struct language_table *lang_entry = malloc(sizeof(*lang_entry));
-    if (!lang_entry) {
-        perror("malloc() failed");
-        return;
-    }
-    
-    lang_entry->ident = strdup(ident);
-    //replace all:
-    //$b to \002
-    //$k to \003
-    char txt[MAXLEN];
-    strcpy(txt, text);
-    char tmp[MAXLEN];
-    int tmppos = 0;
-    char *a, *b = txt;
-    do {
-        a = strstr(b, "$");
-        if(a) *a = '\0';
-        tmppos += sprintf(tmp + tmppos, "%s", b);
-        if(a) {
-            switch(a[1]) {
-                case 'b':
-                    tmp[tmppos++] = '\002';
-                    break;
-                case 'k':
-                    tmp[tmppos++] = '\003';
-                    break;
-                default:
-                    //unknown - just write it
-                    tmppos += sprintf(tmp + tmppos, "$%c", a[1]);
-            }
-            b = a+2;
-        }
-    } while(a);
-    lang_entry->text = strdup(tmp);
-    lang_entry->next = lang->entrys[cindex];
-    lang->entrys[cindex] = lang_entry;
-}
-
-char *get_language_string(struct UserNode *user, const char* msg_ident) {
-    struct language* lang;
-    if((user->flags & USERFLAG_ISAUTHED)) {
-        loadUserSettings(user);
-        lang = user->language;
-    } else
-        lang = lang_c;
-    int cindex = get_entry_index(msg_ident);
-    struct language_table* entry;
-    for(entry = lang->entrys[cindex]; entry; entry = entry->next) {
-        if(!strcmp(entry->ident, msg_ident))
-            return entry->text;
-    }
-    if(lang == lang_c) return NULL;
-    for(entry = lang_c->entrys[cindex]; entry; entry = entry->next) {
-        if(!strcmp(entry->ident, msg_ident))
-            return entry->text;
-    }
-    return NULL;
-}
-
-char *build_language_string(struct UserNode *user, char *buffer, const char *msg_ident, ...) {
-    char *formatStr = get_language_string(user, msg_ident);
-    if(!formatStr) return NULL;
-    if(buffer == NULL) {
-        buffer = (char *)malloc((MAXLEN+1) * sizeof(char));
-        if (!buffer) {
-            perror("malloc() failed");
-            return NULL;
-        }
-    }
-    int pos;
-    va_list arg_list;
-    buffer[0] = '\0';
-    va_start(arg_list, msg_ident);
-    pos = vsnprintf(buffer, MAXLEN - 2, formatStr, arg_list);
-    va_end(arg_list);
-    if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
-    buffer[pos] = '\0';
-    return buffer;
-}
diff --git a/lang.h b/lang.h
deleted file mode 100644 (file)
index 4aabc8a..0000000
--- a/lang.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _lang_h
-#define _lang_h
-
-#include "main.h"
-
-struct UserNode;
-
-struct default_language_entry {
-    char *ident;
-    char *text;
-};
-
-struct language_table {
-    char *ident;
-    char *text;
-    
-    struct language_table *next;
-};
-
-struct language {
-    char *langtag;
-    char *langname;
-    struct language_table **entrys;
-};
-
-void init_lang();
-void free_lang();
-struct language* get_language_by_tag(char *tag);
-struct language* get_language_by_name(char *name);
-struct language* get_default_language();
-void load_languages();
-void load_language(char *tag, char *name);
-void register_language_string(struct language *lang, char *ident, char *text);
-void register_default_language_table(const struct default_language_entry *msgtab);
-char *get_language_string(struct UserNode *user, const char* msg_ident);
-char *build_language_string(struct UserNode *user, char *buffer, const char *msg_ident, ...);
-
-#endif
\ No newline at end of file
diff --git a/main.c b/main.c
deleted file mode 100644 (file)
index 2fcc3db..0000000
--- a/main.c
+++ /dev/null
@@ -1,94 +0,0 @@
-
-#include "main.h"
-#include "ClientSocket.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "IRCEvents.h"
-#include "IRCParser.h"
-#include "modcmd.h"
-#include "WHOHandler.h"
-#include "bots.h"
-#include "mysqlConn.h"
-#include "HandleInfoHandler.h"
-#include "lang.h"
-#include "tools.h"
-#include "timeq.h"
-#include "EventLogger.h"
-#include "ModeNode.h"
-
-time_t start_time;
-
-void cleanup() {
-    free_sockets();
-    free_parser();
-    free_UserNode();
-    free_ChanNode();
-    free_bind();
-    free_modcmd();
-    free_whoqueue();
-    free_bots();
-    free_mysql();
-    free_handleinfohandler();
-    free_lang();
-}
-
-int main(void)
-{
-    start_time = time(0);
-    
-    init_mysql();
-    init_lang();
-    init_parser();
-    init_UserNode();
-    init_ChanNode();
-    init_ModeNode();
-    init_bind();
-       init_modcmd();
-    init_handleinfohandler();
-    init_tools();
-    init_bots();
-    
-    load_languages();
-    
-    time_t socket_wait;
-    while(1) {
-        socket_wait = time(0) + SOCKET_SELECT_TIME;
-        do {
-            socket_loop(SOCKET_SELECT_TIME);
-        } while(time(0) < socket_wait);
-        timeq_tick();
-        loop_bots();
-        clearTempUsers();
-        destroyEvents();
-    }
-}
-
-int stricmp (const char *s1, const char *s2)
-{
-   if (s1 == NULL) return s2 == NULL ? 0 : -(*s2);
-   if (s2 == NULL) return *s1;
-   char c1, c2;
-   while ((c1 = tolower (*s1)) == (c2 = tolower (*s2)))
-   {
-     if (*s1 == '\0') break;
-     ++s1; ++s2;
-   }
-   return c1 - c2;
-}
-
-int stricmplen (const char *s1, const char *s2, int len)
-{
-   if (s1 == NULL) return s2 == NULL ? 0 : -(*s2);
-   if (s2 == NULL) return *s1;
-   char c1, c2;
-   int i = 0;
-   while ((c1 = tolower (*s1)) == (c2 = tolower (*s2)))
-   {
-     i++;
-     if (*s1 == '\0') break;
-     ++s1; ++s2;
-     if(i == len) break;
-   }
-   return c1 - c2;
-}
-
diff --git a/main.h b/main.h
deleted file mode 100644 (file)
index 0731781..0000000
--- a/main.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef _main_h
-#define _main_h
-
-#define NEONSERV_VERSION "5.0.1-dev"
-
-#include "config.h"
-#ifndef BOTWAR_ALERT_CHAN
-#define BOTWAR_ALERT_CHAN NULL
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <time.h>
-
-#if __GNUC__
-#define PRINTF_LIKE(M,N) __attribute__((format (printf, M, N)))
-#else
-#define PRINTF_LIKE(M,N)
-#endif
-
-#if __GNUC__ >= 2
-#define UNUSED_ARG(ARG) ARG __attribute__((unused))
-#elif defined(S_SPLINT_S)
-#define UNUSED_ARG(ARG) /*@unused@*/ ARG
-#define const /*@observer@*/ /*@temp@*/
-#else
-#define UNUSED_ARG(ARG) ARG
-#endif
-
-#define STRINGIFY_(x) #x
-#define STRINGIFY(x) STRINGIFY_(x)
-#if defined(__GNUC__)
-#if defined(__GNUC_PATCHLEVEL__)
-#define COMPILER "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__) "." STRINGIFY(__GNUC_PATCHLEVEL__)
-#else
-#define COMPILER "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__)
-#endif
-#elif defined (__IMAGECRAFT__)
-#define COMPILER "ICCAVR"
-#else
-#define COMPILER "Unknown"
-#endif
-
-#define SOCKET_SELECT_TIME 2
-
-#define NICKLEN         30
-#define USERLEN         10
-#define AUTHLEN         32
-#define HOSTLEN         63
-#define REALLEN         50
-#define TOPICLEN        500
-#define CHANNELLEN      200
-#define MAXLEN          512
-#define TRIGGERLEN      50
-#define MAXNUMPARAMS    200 /* maximum number of parameters in one line */
-#define MAXLANGUAGES    5
-#define MAXMODES        6
-#define INVITE_TIMEOUT  30
-#define BOTWAR_DETECTION_TIME 7
-#define BOTWAR_DETECTION_EVENTS 6
-
-//valid nick chars
-#define VALID_NICK_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890{|}~[\\]^-_`"
-//the first char is a little bit different
-//                              0        1         2         3         4         5          6
-//                              1234567890123456789012345678901234567890123456789012345678 9012   62
-#define VALID_NICK_CHARS_FIRST "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~[\\]^_`"
-#define VALID_NICK_CHARS_FIRST_LEN 62
-
-#define TEMPUSER_LIST_INDEX VALID_NICK_CHARS_FIRST_LEN
-
-extern time_t start_time;
-
-int stricmp (const char *s1, const char *s2);
-int stricmplen (const char *s1, const char *s2, int len);
-
-#endif
\ No newline at end of file
diff --git a/modcmd.c b/modcmd.c
deleted file mode 100644 (file)
index 5476d5e..0000000
--- a/modcmd.c
+++ /dev/null
@@ -1,638 +0,0 @@
-
-#include "modcmd.h"
-#include "IRCEvents.h"
-#include "IRCParser.h"
-#include "ClientSocket.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "ChanUser.h"
-#include "WHOHandler.h"
-#include "lang.h"
-#include "mysqlConn.h"
-#include "DBHelper.h"
-#include "EventLogger.h"
-
-struct trigger_callback {
-    int botid;
-    trigger_callback_t *func;
-    
-    struct trigger_callback *next;
-};
-
-struct command_check_user_cache {
-    struct ClientSocket *client, *textclient;
-    struct UserNode *user;
-    struct ChanNode *chan, *sent_chan;
-    char **argv;
-    int argc;
-    char *message;
-    struct cmd_binding *cbind;
-};
-
-static struct cmd_binding **cmd_binds;
-static struct cmd_function *cmd_functions = NULL;
-static struct trigger_callback *trigger_callbacks = NULL;
-static struct ClientSocket *tmp_text_client;
-
-static const struct default_language_entry msgtab[] = {
-    {"MODCMD_LESS_PARAM_COUNT", "This command requires more parameters."},
-    {"MODCMD_CHAN_REQUIRED",    "You must provide the name of a channel that exists and the bot is on."},
-    {"MODCMD_AUTH_REQUIRED",    "You need to be authenticated with AuthServ to use this command."},
-    {"MODCMD_CHAN_SUSPENDED",   "This channel is currently suspended."},
-    {"MODCMD_PRIVILEGED",       "$b%s$b is a privileged command."}, /* {ARGS: "god"} */
-    {"MODCMD_PUBCMD",           "Public commands in $b%s$b are restricted."}, /* {ARGS: "#TestChan"} */
-    {"MODCMD_ACCESS_DENIED",    "Access denied."},
-    {NULL, NULL}
-};
-
-static int get_binds_index(char first_char) {
-    if(tolower(first_char) >= 'a' && tolower(first_char) <= 'z') {
-        return tolower(first_char) - 'a';
-    }
-    return 26;
-}
-
-struct ClientSocket* get_prefered_bot(int botid) {
-    struct ClientSocket *client;
-    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
-        if(client->botid == botid && (client->flags & SOCKET_FLAG_PREFERRED))
-            return client;
-    }
-    return NULL;
-}
-
-static char* get_channel_trigger(int botid, struct ChanNode *chan) {
-    struct trigger_cache *trigger;
-    for(trigger = chan->trigger; trigger; trigger = trigger->next) {
-        if(trigger->botid == botid)
-            return trigger->trigger;
-    }
-    struct trigger_callback *cb;
-    for(cb = trigger_callbacks; cb; cb = cb->next) {
-        if(cb->botid == botid)
-            break;
-    }
-    char triggerStr[TRIGGERLEN];
-    if(cb)
-        cb->func(chan, triggerStr);
-    else
-        strcpy(triggerStr, "+");
-    trigger = malloc(sizeof(*trigger));
-    if (!trigger) {
-        perror("malloc() failed");
-        return 0;
-    }
-    trigger->botid = botid;
-    trigger->trigger = strdup(triggerStr);
-    trigger->next = chan->trigger;
-    chan->trigger = trigger;
-    return trigger->trigger;
-}
-
-static void handle_command_async(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct ChanNode *sent_chan, struct cmd_binding *cbind, char **argv, int argc);
-
-static USERAUTH_CALLBACK(command_checked_auth) {
-    struct command_check_user_cache *cache = data;
-    tmp_text_client = cache->textclient;
-    handle_command_async(cache->client, user, cache->chan, cache->sent_chan, cache->cbind, cache->argv, cache->argc);
-    free(cache->message);
-    free(cache);
-}
-
-static void handle_command(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) {
-    struct ChanNode *sent_chan = chan;
-    if(message[0] == '#') {
-        char *chanName = message;
-        message = strstr(message, " ");
-        if(!message) return;
-        *message = '\0';
-        message++;
-        struct ChanNode *chan2 = getChanByName(chanName);
-        if(chan2)
-            chan = chan2;
-    }
-    message = strdup(message);
-    int bind_index = get_binds_index(message[0]);
-    char *args = strstr(message, " ");
-    if(args) {
-        *args = '\0';
-        args++;
-    }
-    struct cmd_binding *cbind;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == client->botid && stricmp(cbind->cmd, message) == 0) {
-            //get a text bot
-            tmp_text_client = get_prefered_bot(client->botid);
-            //parse the arguments...
-            char *arga[MAXNUMPARAMS];
-            char **argv;
-            int argc = 0;
-            if(args) {
-                while(*args) {
-                    //skip leading spaces
-                    while (*args == ' ')
-                        *args++ = 0;
-                    arga[argc++] = args;
-                    if (argc >= MAXNUMPARAMS)
-                        break;
-                    while (*args != ' ' && *args)
-                        args++;
-                }
-            }
-            argv = arga;
-            if(argc != 0 && argv[0][0] == '#' && !(cbind->func->flags & CMDFLAG_CHAN_PARAM)) {
-                struct ChanNode *chan2 = getChanByName(argv[0]);
-                if(chan2) {
-                    argv += 1;
-                    argc -= 1;
-                    chan = chan2;
-                }
-            }
-            if(cbind->parameters) {
-                //userdefined parameters...
-                char *uargs[MAXNUMPARAMS];
-                int uargc = 0;
-                char *a,*b = cbind->parameters;
-                int allargs, argi;
-                do {
-                    a = strstr(b, " ");
-                    if(a) *a = '\0';
-                    if(b[0] == '%') {
-                        b++;
-                        if(b[strlen(b)-1] == '-') {
-                            allargs = 1;
-                            b[strlen(b)-1] = '\0';
-                            argi = atoi(b);
-                            b[strlen(b)-1] = '-';
-                        } else {
-                            allargs = 0;
-                            argi = atoi(b);
-                        }
-                        if(argi > 0) {
-                            if(argi <= argc) {
-                                uargs[uargc++] = argv[argi-1];
-                                if(allargs) {
-                                    for(argi++; argi <= argc; argi++)
-                                        uargs[uargc++] = argv[argi-1];
-                                }
-                            }
-                        } else if(!strcmp(b, "c")) {
-                            uargs[uargc++] = (chan ? chan->name : NULL);
-                        } else if(!strcmp(b, "n")) {
-                            uargs[uargc++] = user->nick;
-                        }
-                    } else {
-                        uargs[uargc++] = b;
-                    }
-                    if(a) {
-                        *a = ' ';
-                        b = a+1;
-                    }
-                } while(a);
-                argv = uargs;
-                argc = uargc;
-            }
-            if(argc < cbind->func->paramcount) {
-                reply(tmp_text_client, user, "MODCMD_LESS_PARAM_COUNT");
-                break;
-            }
-            if((cbind->func->flags & CMDFLAG_REQUIRE_CHAN) && !chan) {
-                reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
-                break;
-            }
-            if((cbind->func->flags & CMDFLAG_CHECK_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
-                //check auth...
-                struct command_check_user_cache *data = malloc(sizeof(*data));
-                char **temp_argv = malloc(argc*sizeof(*temp_argv));
-                if (!data || !temp_argv) {
-                    perror("malloc() failed");
-                    break;
-                }
-                memcpy(temp_argv, argv, argc*sizeof(*temp_argv));
-                data->argv = temp_argv;
-                data->argc = argc;
-                data->client = client;
-                data->user = user;
-                data->chan = chan;
-                data->sent_chan = sent_chan;
-                data->message = message;
-                data->cbind = cbind;
-                data->textclient = tmp_text_client;
-                get_userauth(user, command_checked_auth, data);
-                return;
-            } else
-                handle_command_async(client, user, chan, sent_chan, cbind, argv, argc);
-            break;
-        }
-    }
-    free(message);
-}
-
-static void handle_command_async(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct ChanNode *sent_chan, struct cmd_binding *cbind, char **argv, int argc) {
-    MYSQL_RES *res;
-    MYSQL_ROW row;
-    int uaccess;
-    int eventflags = (cbind->func->flags & (CMDFLAG_LOG | CMDFLAG_OPLOG));
-    if((cbind->func->flags & CMDFLAG_REQUIRE_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
-        reply(tmp_text_client, user, "MODCMD_AUTH_REQUIRED");
-        return;
-    }
-    if(sent_chan && sent_chan != chan) {
-        //check pubcmd of this channel
-        printf_mysql_query("SELECT `channel_pubcmd` FROM `channels` WHERE `channel_name` = '%s'", escape_string(sent_chan->name));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            uaccess = getChannelAccess(user, sent_chan, 1);
-            if(row[0] && uaccess < atoi(row[0])) { //NOTE: HARDCODED DEFAULT: pubcmd = 0
-                reply(tmp_text_client, user, "MODCMD_PUBCMD", sent_chan->name);
-                return;
-            }
-        }
-    }
-    int global_access = ((cbind->flags & CMDFLAG_OVERRIDE_GLOBAL_ACCESS) ? cbind->global_access : cbind->func->global_access);
-    if(global_access > 0) {
-        int user_global_access = 0;
-        printf_mysql_query("SELECT `user_access` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) != NULL) {
-            user_global_access = atoi(row[0]);
-        }
-        if(user_global_access < global_access) {
-            if(!user_global_access)
-                reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
-            else
-                reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
-            return;
-        }
-    }
-    if((cbind->func->flags & CMDFLAG_REGISTERED_CHAN)) {
-        MYSQL_ROW defaults = NULL;
-        char access_list[256];
-        int access_pos = 0;
-        int access_count = 0;
-        int minaccess = 0;
-        char *str_a, *str_b = cbind->func->channel_access, *str_c;
-        if(cbind->flags & CMDFLAG_OVERRIDE_CHANNEL_ACCESS)
-            str_b = cbind->channel_access;
-        access_list[0] = '\0';
-        if(str_b) {
-            str_c = strdup(str_b);
-            str_b = str_c;
-            while((str_a = str_b)) {
-                str_b = strstr(str_a, ",");
-                if(str_b) {
-                    *str_b = '\0';
-                    str_b++;
-                }
-                if(*str_a == '#') {
-                    str_a++;
-                    access_pos += sprintf(access_list+access_pos, ", `%s`", str_a);
-                    access_count++;
-                } else {
-                    if(atoi(str_a) > minaccess)
-                        minaccess = atoi(str_a);
-                }
-            }
-            free(str_c);
-        }
-        if(!(chan->flags & CHANFLAG_REQUESTED_CHANINFO) || (sent_chan && sent_chan == chan) || access_count || minaccess) {
-            printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = '%s'", access_list, escape_string(chan->name));
-            res = mysql_use();
-            if ((row = mysql_fetch_row(res)) != NULL) {
-                chan->flags |= CHANFLAG_CHAN_REGISTERED;
-                chan->channel_id = atoi(row[0]);
-                if((sent_chan && sent_chan == chan) || access_count || minaccess) {
-                    uaccess = getChannelAccess(user, chan, 0);
-                    if(uaccess < minaccess && isGodMode(user)) {
-                        eventflags |= CMDFLAG_OPLOG;
-                    } else if(uaccess < minaccess) {
-                        //ACCESS DENIED
-                        reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
-                        return;
-                    }
-                    if(!row[1] && !defaults) {
-                        printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
-                        defaults = mysql_fetch_row(mysql_use());
-                    }
-                    if(sent_chan && (sent_chan == chan) && uaccess < (row[1] ? atoi(row[1]) : atoi(defaults[1]))) {
-                        if(isGodMode(user)) {
-                            eventflags |= CMDFLAG_OPLOG;
-                        } else {
-                            //PUBCMD
-                            reply(tmp_text_client, user, "MODCMD_PUBCMD", chan->name);
-                            return;
-                        }
-                    }
-                    int i;
-                    for(i = 0; i < access_count; i++) {
-                        if(!row[2+i] && !defaults) {
-                            printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
-                            defaults = mysql_fetch_row(mysql_use());
-                        }
-                        if(uaccess < (row[2+i] ? atoi(row[2+i]) : atoi(defaults[2+i]))) {
-                            if(isGodMode(user)) {
-                                eventflags |= CMDFLAG_OPLOG;
-                            } else {
-                                reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
-                                return;
-                            }
-                        }
-                    }
-                }
-            }
-            chan->flags |= CHANFLAG_REQUESTED_CHANINFO;
-        }
-        if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) {
-            reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
-            return;
-        }
-        printf_mysql_query("SELECT `botid`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, client->botid);
-        res = mysql_use();
-        if ((row = mysql_fetch_row(res)) == NULL) {
-            reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
-            return;
-        } else if(!strcmp(row[1], "1")) {
-            reply(tmp_text_client, user, "MODCMD_CHAN_SUSPENDED");
-            return;
-        }
-    }
-    if((cbind->func->flags & CMDFLAG_REQUIRE_GOD) && !isGodMode(user)) {
-        reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
-        return;
-    }
-    struct Event *event = createEvent(client, user, chan, cbind->func->name, argv, argc, eventflags);
-    cbind->func->func(client, user, chan, argv, argc, event);
-}
-
-static void got_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) {
-    fd_set fds;
-    char *trigger;
-    struct ClientSocket *client;
-    FD_ZERO(&fds);
-    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
-        if(isUserOnChan(client->user, chan) && (client->flags & SOCKET_FLAG_PREFERRED) && !FD_ISSET(client->botid, &fds)) {
-            FD_SET(client->botid, &fds);
-            trigger = get_channel_trigger(client->botid, chan);
-            if(stricmplen(message, trigger, strlen(trigger)) == 0) {
-                handle_command(client, user, chan, message + strlen(trigger));
-            }
-        }
-    }
-    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
-        if(isUserOnChan(client->user, chan) && !FD_ISSET(client->botid, &fds)) {
-            FD_SET(client->botid, &fds);
-            trigger = get_channel_trigger(client->botid, chan);
-            if(stricmplen(message, trigger, strlen(trigger)) == 0) {
-                handle_command(client, user, chan, message + strlen(trigger));
-            }
-        }
-    }
-}
-
-static void got_privmsg(struct UserNode *user, struct UserNode *target, char *message) {
-    struct ClientSocket *client;
-    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
-        if(client->user == target) {
-            handle_command(client, user, NULL, message);
-        }
-    }
-}
-
-int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, char *channel_access, int global_access, unsigned int flags) {
-    struct cmd_function *cmdfunc;
-    for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
-        if(cmdfunc->botid == botid && strcmp(cmdfunc->name, name) == 0)
-            return 0;
-    }
-    cmdfunc = malloc(sizeof(*cmdfunc));
-    if (!cmdfunc) {
-        perror("malloc() failed");
-        return 0;
-    }
-    cmdfunc->botid = botid;
-    cmdfunc->name = strdup(name);
-    cmdfunc->func = func;
-    cmdfunc->flags = flags;
-    cmdfunc->paramcount = paramcount;
-    cmdfunc->channel_access = channel_access;
-    cmdfunc->global_access = global_access;
-    cmdfunc->next = cmd_functions;
-    cmd_functions = cmdfunc;
-    return 1;
-}
-
-int set_trigger_callback(int botid, trigger_callback_t *func) {
-    static struct trigger_callback *cb = NULL;
-    for(cb = trigger_callbacks; cb; cb = cb->next) {
-        if(cb->botid == botid)
-            break;
-    }
-    if(!cb) {
-        cb = malloc(sizeof(*cb));
-        if (!cb) {
-            perror("malloc() failed");
-            return 0;
-        }
-        cb->botid = botid;
-        cb->next = trigger_callbacks;
-        trigger_callbacks = cb;
-    }
-    cb->func = func;
-    return 1;
-}
-
-int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger) {
-    struct trigger_cache *trigger;
-    for(trigger = chan->trigger; trigger; trigger = trigger->next) {
-        if(trigger->botid == botid) {
-            free(trigger->trigger);
-            trigger->trigger = strdup(new_trigger);
-            return 1;
-        }
-    }
-    return 0;
-}
-
-int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func) {
-    int bind_index = get_binds_index(cmd[0]);
-    struct cmd_binding *cbind;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0)
-            return 0;
-    }
-    cbind = malloc(sizeof(*cbind));
-    if (!cbind) {
-        perror("malloc() failed");
-        return 0;
-    }
-    cbind->botid = botid;
-    cbind->cmd = strdup(cmd);
-    cbind->func = func;
-    cbind->parameters = NULL;
-    cbind->global_access = 0;
-    cbind->channel_access = NULL;
-    cbind->flags = 0;
-    cbind->next = cmd_binds[bind_index];
-    cmd_binds[bind_index] = cbind;
-    return 1;
-}
-
-int bind_cmd_to_command(int botid, char *cmd, char *func) {
-    struct cmd_function *cmdfunc;
-    for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
-        if(cmdfunc->botid == botid && strcmp(cmdfunc->name, func) == 0)
-            break;
-    }
-    if(!cmdfunc) return 0;
-    int bind_index = get_binds_index(cmd[0]);
-    struct cmd_binding *cbind;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0)
-            return 0;
-    }
-    cbind = malloc(sizeof(*cbind));
-    if (!cbind) {
-        perror("malloc() failed");
-        return 0;
-    }
-    cbind->botid = botid;
-    cbind->cmd = strdup(cmd);
-    cbind->func = cmdfunc;
-    cbind->next = cmd_binds[bind_index];
-    cbind->parameters = NULL;
-    cbind->global_access = 0;
-    cbind->channel_access = NULL;
-    cbind->flags = 0;
-    cmd_binds[bind_index] = cbind;
-    return 1;
-}
-
-int unbind_cmd(int botid, char *cmd) {
-    int bind_index = get_binds_index(cmd[0]);
-    struct cmd_binding *cbind, *last = NULL;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
-            if(last)
-                last->next = cbind->next;
-            else
-                cmd_binds[bind_index] = cbind->next;
-            free(cbind->cmd);
-            if(cbind->parameters)
-                free(cbind->parameters);
-            free(cbind);
-            return 1;
-        } else
-            last = cbind;
-    }
-    return 0;
-}
-
-struct cmd_function *find_cmd_function(int botid, char *name) {
-    struct cmd_function *cmdfunc;
-    for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
-        if(cmdfunc->botid == botid && stricmp(cmdfunc->name, name) == 0)
-            break;
-    }
-    return cmdfunc;
-}
-
-struct ClientSocket *getTextBot() {
-    return tmp_text_client;
-}
-
-void init_modcmd() {
-    cmd_binds = calloc(27, sizeof(*cmd_binds));
-    bind_chanmsg(got_chanmsg);
-    bind_privmsg(got_privmsg);
-    register_default_language_table(msgtab);
-}
-
-void free_modcmd() {
-    int i;
-    for(i = 0; i < 27; i++) {
-        struct cmd_binding *cbind, *next;
-        for(cbind = cmd_binds[i]; cbind; cbind = next) {
-            next = cbind->next;
-            free(cbind->cmd);
-            if(cbind->parameters)
-                free(cbind->parameters);
-            if(cbind->channel_access)
-                free(cbind->channel_access);
-            free(cbind);
-        }
-    }
-    free(cmd_binds);
-    struct cmd_function *cmdfunct, *next;
-    for(cmdfunct = cmd_functions; cmdfunct; cmdfunct = next) {
-        next = cmdfunct->next;
-        free(cmdfunct->name);
-        free(cmdfunct);
-    }
-    struct trigger_callback *cb, *next_cb;
-    for(cb = trigger_callbacks; cb; cb = next_cb) {
-        next_cb = cb->next;
-        free(next_cb);
-    }
-    cmd_functions = NULL;
-    trigger_callbacks = NULL;
-}
-
-void bind_set_parameters(int botid, char *cmd, char *parameters) {
-    int bind_index = get_binds_index(cmd[0]);
-    struct cmd_binding *cbind;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
-            if(cbind->parameters)
-                free(cbind->parameters);
-            cbind->parameters = strdup(parameters);
-            return;
-        }
-    }
-}
-
-void bind_set_global_access(int botid, char *cmd, int gaccess) {
-    int bind_index = get_binds_index(cmd[0]);
-    struct cmd_binding *cbind;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
-            if(gaccess > -1) {
-                cbind->global_access = gaccess;
-                cbind->flags |= CMDFLAG_OVERRIDE_GLOBAL_ACCESS;
-            } else {
-                cbind->flags &= ~CMDFLAG_OVERRIDE_GLOBAL_ACCESS;
-            }
-            return;
-        }
-    }
-}
-
-void bind_set_channel_access(int botid, char *cmd, char *chanaccess) {
-    int bind_index = get_binds_index(cmd[0]);
-    struct cmd_binding *cbind;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
-            if(cbind->channel_access)
-                free(cbind->channel_access);
-            if(chanaccess) {
-                cbind->channel_access = strdup(chanaccess);
-                cbind->flags |= CMDFLAG_OVERRIDE_CHANNEL_ACCESS;
-            } else {
-                cbind->channel_access = NULL;
-                cbind->flags &= ~CMDFLAG_OVERRIDE_CHANNEL_ACCESS;
-            }
-            return;
-        }
-    }
-}
-
-struct cmd_binding *find_cmd_binding(int botid, char *cmd) {
-    int bind_index = get_binds_index(cmd[0]);
-    struct cmd_binding *cbind;
-    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
-        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
-            return cbind;
-        }
-    }
-    return NULL;
-}
-
diff --git a/modcmd.h b/modcmd.h
deleted file mode 100644 (file)
index 940ab32..0000000
--- a/modcmd.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef _modcmd_h
-#define _modcmd_h
-#include "main.h"
-
-#define CMDFLAG_REQUIRE_CHAN            0x0001
-#define CMDFLAG_REQUIRE_AUTH            0x0002
-#define CMDFLAG_REQUIRE_GOD             0x0004
-#define CMDFLAG_CHECK_AUTH              0x0008
-#define CMDFLAG_REGISTERED_CHAN         0x0010
-#define CMDFLAG_OVERRIDE_GLOBAL_ACCESS  0x0020
-#define CMDFLAG_OVERRIDE_CHANNEL_ACCESS 0x0040
-#define CMDFLAG_CHAN_PARAM              0x0080
-#define CMDFLAG_LOG                     0x0100
-#define CMDFLAG_OPLOG                   0x0200
-
-struct ClientSocket;
-struct UserNode;
-struct ChanNode;
-struct Event;
-
-#define CMD_BIND(NAME) void NAME(UNUSED_ARG(struct ClientSocket *client), UNUSED_ARG(struct UserNode *user), UNUSED_ARG(struct ChanNode *chan), UNUSED_ARG(char **argv), UNUSED_ARG(char argc), UNUSED_ARG(struct Event *event))
-typedef void cmd_bind_t(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char **argv, char argc, struct Event *event);
-typedef void trigger_callback_t(struct ChanNode *chan, char *trigger);
-
-struct cmd_function {
-    char *name;
-    int botid;
-    cmd_bind_t *func;
-    unsigned int flags;
-    int paramcount;
-    int global_access;
-    char *channel_access;
-    
-    struct cmd_function *next;
-};
-
-struct cmd_binding {
-    char *cmd;
-    int botid;
-    struct cmd_function *func;
-    unsigned int flags;
-    char *parameters;
-    int global_access;
-    char *channel_access;
-    
-    struct cmd_binding *next;
-};
-
-struct trigger_cache {
-    int botid;
-    char *trigger;
-    
-    struct trigger_cache *next;
-};
-
-void init_modcmd();
-void free_modcmd();
-struct ClientSocket* get_prefered_bot(int botid);
-int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, char *channel_access, int global_access, unsigned int flags);
-int set_trigger_callback(int botid, trigger_callback_t *func);
-int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger);
-int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func);
-int bind_cmd_to_command(int botid, char *cmd, char *func);
-int unbind_cmd(int botid, char *cmd);
-struct cmd_function *find_cmd_function(int botid, char *name);
-struct ClientSocket *getTextBot();
-void bind_set_parameters(int botid, char *cmd, char *parameters);
-void bind_set_global_access(int botid, char *cmd, int gaccess);
-void bind_set_channel_access(int botid, char *cmd, char *chanaccess);
-struct cmd_binding *find_cmd_binding(int botid, char *cmd);
-
-#endif
\ No newline at end of file
diff --git a/mysqlConfig.h.example b/mysqlConfig.h.example
new file mode 100644 (file)
index 0000000..6d573d4
--- /dev/null
@@ -0,0 +1,6 @@
+
+#define MYSQL_HOST "127.0.0.1"
+#define MYSQL_PORT 3306
+#define MYSQL_USER "neonserv"
+#define MYSQL_PASS ""
+#define MYSQL_BASE "neonserv"
diff --git a/mysqlConn.c b/mysqlConn.c
deleted file mode 100644 (file)
index 66494e7..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-
-#include "mysqlConn.h"
-
-struct used_result {
-    MYSQL_RES *result;
-    struct used_result *next;
-};
-
-struct escaped_string {
-    char *string;
-    struct escaped_string *next;
-};
-
-MYSQL *mysql_conn = NULL;
-static struct used_result *used_results;
-static struct escaped_string *escaped_strings;
-
-void check_mysql() {
-    int errid;
-    if((errid = mysql_ping(mysql_conn))) {
-        if(mysql_errno(mysql_conn) == CR_SERVER_GONE_ERROR) {
-            if(!mysql_real_connect(mysql_conn, MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_BASE, MYSQL_PORT, NULL, 0)) {
-                show_mysql_error();
-            }
-        } else {
-            //mysql error
-            show_mysql_error();
-        }
-    }
-}
-
-MYSQL_RES *mysql_use() {
-    MYSQL_RES *res = mysql_store_result(mysql_conn);
-    struct used_result *result = malloc(sizeof(*result));
-    if (!result) {
-        mysql_free_result(res);
-        return NULL;
-    }
-    result->result = res;
-    result->next = used_results;
-    used_results = result;
-    return res;
-}
-
-void mysql_free() {
-    struct used_result *result, *next_result;
-    for(result = used_results; result; result = next_result) {
-        next_result = result->next;
-        mysql_free_result(result->result);
-        free(result);
-    }
-    used_results = NULL;
-    struct escaped_string *escaped, *next_escaped;
-    for(escaped = escaped_strings; escaped; escaped = next_escaped) {
-        next_escaped = escaped->next;
-        free(escaped->string);
-        free(escaped);
-    }
-    escaped_strings = NULL;
-}
-
-void init_mysql() {
-    mysql_conn = mysql_init(NULL);
-    if (!mysql_real_connect(mysql_conn, MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_BASE, MYSQL_PORT, NULL, 0)) {
-        //error
-        show_mysql_error();
-    }
-}
-
-void free_mysql() {
-    mysql_close(mysql_conn);
-}
-
-void show_mysql_error() {
-    //show mysql_error()
-    printf("MySQL Error: %s\n", mysql_error(mysql_conn));
-}
-
-void printf_mysql_query(const char *text, ...) {
-    va_list arg_list;
-    char queryBuf[MYSQLMAXLEN];
-    int pos;
-    queryBuf[0] = '\0';
-    va_start(arg_list, text);
-    pos = vsnprintf(queryBuf, MYSQLMAXLEN - 2, text, arg_list);
-    va_end(arg_list);
-    if (pos < 0 || pos > (MYSQLMAXLEN - 2)) pos = MYSQLMAXLEN - 2;
-    queryBuf[pos] = '\0';
-    printf("MySQL: %s\n", queryBuf);
-    if(mysql_query(mysql_conn, queryBuf)) {
-        check_mysql();
-        if(mysql_query(mysql_conn, queryBuf)) {
-            show_mysql_error();
-        }
-    }
-}
-
-char* escape_string(const char *str) {
-    struct escaped_string *escapedstr = malloc(sizeof(*escapedstr));
-    if (!escapedstr) {
-        return NULL;
-    }
-    char escaped[strlen(str)*2+1];
-    mysql_real_escape_string(mysql_conn, escaped, str, strlen(str));
-    escapedstr->string = strdup(escaped);
-    escapedstr->next = escaped_strings;
-    escaped_strings = escapedstr;
-    return escapedstr->string;
-}
diff --git a/mysqlConn.h b/mysqlConn.h
deleted file mode 100644 (file)
index 4ed6655..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _MySQLConn_h
-#define _MySQLConn_h
-
-#include "main.h"
-#include <mysql.h>
-#include <mysql/errmsg.h>
-
-#define MYSQLMAXLEN 1024
-
-extern MYSQL *mysql_conn;
-
-void check_mysql();
-MYSQL_RES *mysql_use();
-void mysql_free();
-void init_mysql();
-void free_mysql();
-void show_mysql_error();
-void printf_mysql_query(const char *text, ...) PRINTF_LIKE(1, 2);
-char* escape_string(const char *str);
-
-#endif
\ No newline at end of file
diff --git a/src/BanNode.c b/src/BanNode.c
new file mode 100644 (file)
index 0000000..c1601f1
--- /dev/null
@@ -0,0 +1,66 @@
+
+#include "BanNode.h"
+#include "ChanNode.h"
+#include "tools.h"
+
+struct BanNode* addChannelBan(struct ChanNode *chan, char *mask) {
+    struct BanNode *ban = malloc(sizeof(*ban));
+    ban->chan = chan;
+    ban->mask = strdup(mask);
+    ban->next = chan->bans;
+    chan->bans = ban;
+    return ban;
+}
+
+struct BanNode* getMatchingChannelBan(struct ChanNode *chan, char *mask) {
+    struct BanNode *cban;
+    for(cban = chan->bans; cban; cban = cban->next) {
+        if(!match(cban->mask, mask)) {
+            return cban;
+        }
+    }
+    return NULL;
+}
+
+void removeChannelBanMask(struct ChanNode *chan, char *mask) {
+    struct BanNode *cban, *last = NULL;
+    for(cban = chan->bans; cban; cban = cban->next) {
+        if(!strcmp(cban->mask, mask)) {
+            if(last)
+                last->next = cban->next;
+            else
+                chan->bans = cban->next;
+            free(cban->mask);
+            free(cban);
+            break;
+        } else 
+            last = cban;
+    }
+}
+
+void removeChannelBan(struct BanNode *ban) {
+    struct BanNode *cban, *last = NULL;
+    struct ChanNode *chan = ban->chan;
+    for(cban = chan->bans; cban; cban = cban->next) {
+        if(cban == ban) {
+            if(last)
+                last->next = ban->next;
+            else
+                chan->bans = ban->next;
+            free(ban->mask);
+            free(ban);
+            break;
+        } else 
+            last = cban;
+    }
+}
+
+void removeChannelBans(struct ChanNode *chan) {
+    struct BanNode *ban, *next;
+    for(ban = chan->bans; ban; ban = next) {
+        next = ban->next;
+        free(ban->mask);
+        free(ban);
+    }
+    chan->bans = NULL;
+}
diff --git a/src/BanNode.h b/src/BanNode.h
new file mode 100644 (file)
index 0000000..a699e3f
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _BanNode_h
+#define _BanNode_h
+#include "main.h"
+
+struct ChanNode;
+
+struct BanNode {
+    char *mask;
+    struct ChanNode *chan;
+    
+    struct BanNode *next;
+};
+
+struct BanNode* addChannelBan(struct ChanNode *chan, char *mask);
+struct BanNode* getMatchingChannelBan(struct ChanNode *chan, char *mask);
+void removeChannelBanMask(struct ChanNode *chan, char *mask);
+void removeChannelBan(struct BanNode *ban);
+void removeChannelBans(struct ChanNode *chan);
+
+#endif
\ No newline at end of file
diff --git a/src/ChanNode.c b/src/ChanNode.c
new file mode 100644 (file)
index 0000000..73adbf6
--- /dev/null
@@ -0,0 +1,216 @@
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "UserNode.h"
+#include "BanNode.h"
+#include "modcmd.h"
+#include "ModeNode.h"
+
+static struct ChanNode **chanList;
+
+void init_ChanNode() {
+    /*
+     len pos chars 
+     26  0   a-z
+     10  26  0-9
+     10  36  {|}~[\]^_`
+     1   46  *everything else*
+     ---------------------------
+     = 47
+    */
+    #define CHANNEL_LIST_SIZE 47
+    chanList = calloc(CHANNEL_LIST_SIZE, sizeof(*chanList));
+}
+
+void free_ChanNode() {
+    //kamikaze free all channels and chanusers
+    int i;
+    struct ChanNode *chan, *next;
+    struct ChanUser *chanuser, *next_chanuser;
+    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
+        for(chan = chanList[i]; chan; chan = next) {
+            next = chan->next;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next_chanuser) {
+                next_chanuser = getChannelUsers(chan, chanuser);
+                free(chanuser);
+            }
+            freeChanNode(chan);
+        }
+    }
+    free(chanList);
+}
+
+int is_valid_chan(const char *name) {
+    unsigned int ii;
+    if (*name !='#')
+        return 0;
+    for (ii=1; name[ii]; ++ii) {
+        if ((name[ii] > 0) && (name[ii] <= 32))
+            return 0;
+        if (name[ii] == ',')
+            return 0;
+        if (name[ii] == '\xa0')
+            return 0;
+    }
+    return 1;
+}
+
+static int get_chanlist_entry(int name) {
+    if((name > 0 && name <= 32) || name == ',' || name == '\xa0') return -1; //invalid name
+    if(tolower(name) >= 97 && tolower(name) <= 122) {
+        return (tolower(name) - 97);
+    }
+    if(tolower(name) >= 48 && tolower(name) <= 57) {
+        return (tolower(name) - 48 + 26);
+    }
+    /* {|}~[\]^_` */
+    if(name == '{') return 36;
+    if(name == '|') return 37;
+    if(name == '}') return 38;
+    if(name == '~') return 39;
+    if(name == '[') return 40;
+    if(name == '\\') return 41;
+    if(name == ']') return 42;
+    if(name == '^') return 43;
+    if(name == '_') return 44;
+    if(name == '`') return 45;
+    return 46;
+}
+
+struct ChanNode* getChanByName(const char *name) { //case insensitive
+    int chanListIndex = get_chanlist_entry(name[1]);
+    if(chanListIndex == -1 || chanList[chanListIndex] == NULL)
+        return NULL;
+    struct ChanNode *chan;
+    for(chan = chanList[chanListIndex]; chan; chan = chan->next) {
+        if(!stricmp(name, chan->name))
+            return chan;
+    }
+    return NULL;
+}
+
+struct ChanNode* addChannel(const char *name) {
+    int chanListIndex = get_chanlist_entry(name[1]);
+    if(chanListIndex == -1 || !is_valid_chan(name))
+        return NULL;
+    struct ChanNode *chan = malloc(sizeof(*chan));
+    if (!chan)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    strcpy(chan->name, name);
+    chan->user = NULL;
+    chan->bans = NULL;
+    chan->usercount = 0;
+    chan->chanbot = NULL;
+    chan->topic[0] = 0;
+    chan->flags = 0;
+    /* mode lists */
+    chan->modes = createModeNode(chan);
+    chan->trigger = NULL;
+    
+    chan->next = chanList[chanListIndex];
+    chanList[chanListIndex] = chan;
+    return chan;
+}
+
+int getChannelCount() {
+    int i, count = 0;
+    struct ChanNode *chan;
+    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
+        for(chan = chanList[i]; chan; chan = chan->next) {
+            count++;
+        }
+    }
+    return count;
+}
+
+int getChanUserCount() {
+    int i, count = 0;
+    struct ChanNode *chan;
+    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
+        for(chan = chanList[i]; chan; chan = chan->next) {
+            count += chan->usercount;
+        }
+    }
+    return count;
+}
+
+int getChanBanCount() {
+    int i, count = 0;
+    struct ChanNode *chan;
+    struct BanNode *ban;
+    for(i = 0; i < CHANNEL_LIST_SIZE; i++) {
+        for(chan = chanList[i]; chan; chan = chan->next) {
+            for(ban = chan->bans; ban; ban = ban->next)
+                count ++;
+        }
+    }
+    return count;
+}
+
+void delChannel(struct ChanNode* chan, int freeChan) {
+    int chanListIndex = get_chanlist_entry(chan->name[1]);
+    if(chanListIndex == -1) return;
+    struct ChanNode *cchan, *last_chan = NULL;
+    for(cchan = chanList[chanListIndex]; cchan; cchan = cchan->next) {
+        if(cchan == chan) {
+            if(last_chan)
+                last_chan->next = chan->next;
+            else
+                chanList[chanListIndex] = chan->next;
+            break;
+        } else
+            last_chan = cchan;
+    }
+    if(chan->user) {
+        //free all chanusers
+        struct ChanUser *chanuser, *next;
+        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
+            next = getChannelUsers(chan, chanuser);
+            removeChanUserFromLists(chanuser, 0, 1, 1);
+        }
+    }
+    if(freeChan)
+        freeChanNode(chan);
+    else
+        chan->next = NULL;
+}
+
+void freeChanNode(struct ChanNode* chan) {
+    if(chan->trigger) {
+        struct trigger_cache *trigger, *next_trigger;
+        for(trigger = chan->trigger; trigger; trigger = next_trigger) {
+            next_trigger = trigger->next;
+            free(trigger->trigger);
+            free(trigger);
+        }
+    }
+    freeModeNode(chan->modes);
+    if(chan->bans)
+        removeChannelBans(chan);
+    free(chan);
+}
+
+void checkChannelVisibility(struct ChanNode* chan) {
+    struct ChanUser *chanuser, *next;
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(chanuser->user->flags & USERFLAG_ISBOT) {
+            chan->chanbot = chanuser->user;
+            return;
+        }
+    }
+    //free the channel...
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = next) {
+        next = getChannelUsers(chan, chanuser);
+        //remove the channel from the user's channel-list
+        removeChanUserFromLists(chanuser, 0, 1, 0);
+        if(!chanuser->user->channel) {
+            //free the user (no more channels)
+            delUser(chanuser->user, 1);
+        }
+        free(chanuser);
+    }
+    chan->user = NULL;
+    delChannel(chan, 1);
+}
diff --git a/src/ChanNode.h b/src/ChanNode.h
new file mode 100644 (file)
index 0000000..7847dea
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _ChanNode_h
+#define _ChanNode_h
+#include "main.h"
+
+struct ChanUser;
+struct trigger_cache;
+struct ModeNode;
+
+#define CHANFLAG_RECEIVED_USERLIST  0x01
+#define CHANFLAG_REQUESTED_CHANINFO 0x02
+#define CHANFLAG_CHAN_REGISTERED    0x04
+#define CHANFLAG_HAVE_INVISIBLES    0x08
+
+struct ChanNode {
+    char name[CHANNELLEN+1];
+    char topic[TOPICLEN+1];
+    struct ChanUser *user;
+    unsigned int usercount;
+    unsigned char flags;
+    struct ModeNode *modes;
+    struct BanNode *bans;
+    
+    struct UserNode *chanbot;
+    struct trigger_cache *trigger;
+    int channel_id;
+       
+    struct ChanNode *next;
+};
+
+void init_ChanNode();
+void free_ChanNode();
+int is_valid_chan(const char *name);
+struct ChanNode* getChanByName(const char *name);
+struct ChanNode* addChannel(const char *chan);
+int getChannelCount();
+int getChanUserCount();
+int getChanBanCount();
+void delChannel(struct ChanNode* chan, int freeChan);
+void freeChanNode(struct ChanNode* chan);
+void checkChannelVisibility(struct ChanNode* chan);
+
+#endif
\ No newline at end of file
diff --git a/src/ChanUser.c b/src/ChanUser.c
new file mode 100644 (file)
index 0000000..c31e202
--- /dev/null
@@ -0,0 +1,157 @@
+
+#include "ChanUser.h"
+#include "ChanNode.h"
+#include "UserNode.h"
+
+struct ChanUser* addChanUser(struct ChanNode *chan, struct UserNode *user) {
+    struct ChanUser *chanuser = malloc(sizeof(*chan));
+    if (!chanuser)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    chanuser->flags = 0;
+    chanuser->user = user;
+    chanuser->chan = chan;
+    
+    chanuser->changeTime = 0;
+
+    chanuser->next_user = chan->user;
+    chan->user = chanuser;
+    chan->usercount++;
+
+    chanuser->next_chan = user->channel;
+    user->channel = chanuser;
+
+    return chanuser;
+}
+
+struct ChanUser* addInvisibleChanUser(struct ChanNode *chan, struct UserNode *user) {
+    struct ChanUser *chanuser = malloc(sizeof(*chan));
+    if (!chanuser)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    chanuser->flags = CHANUSERFLAG_INVISIBLE;
+    chanuser->user = user;
+    chanuser->chan = chan;
+    
+    chanuser->changeTime = 0;
+
+    chanuser->next_user = chan->user;
+    chan->user = chanuser;
+    chan->usercount++;
+
+    return chanuser;
+}
+
+int isUserOnChan(struct UserNode *user, struct ChanNode *chan) {
+    struct ChanUser *chanuser;
+    for(chanuser = user->channel; chanuser; chanuser = chanuser->next_chan) {
+        if(chanuser->chan == chan)
+            return 1;
+    }
+    return 0;
+}
+
+struct ChanUser* getChanUser(struct UserNode *user, struct ChanNode *chan) {
+    struct ChanUser *chanuser;
+    for(chanuser = user->channel; chanuser; chanuser = chanuser->next_chan) {
+        if(chanuser->chan == chan)
+            return chanuser;
+    }
+    return NULL;
+}
+
+struct ChanUser* getChannelUsers(struct ChanNode *chan, struct ChanUser *last) {
+    if(last == NULL)
+        return chan->user;
+    else
+        return last->next_user;
+}
+
+struct ChanUser* getUserChannels(struct UserNode *user, struct ChanUser *last) {
+    if(last == NULL)
+        return user->channel;
+    else
+        return last->next_chan;
+}
+
+void delChanUser(struct ChanUser *chanuser, int freeChanUser) {
+    struct ChanUser *cchanuser, *last;
+    //remove it from the user's channel-list
+    if(!(chanuser->flags & CHANUSERFLAG_INVISIBLE)) {
+        last = NULL;
+        for(cchanuser = chanuser->user->channel; cchanuser; cchanuser = cchanuser->next_chan) {
+            if(cchanuser == chanuser) {
+                if(last) 
+                    last->next_chan = chanuser->next_chan;
+                else
+                    chanuser->user->channel = chanuser->next_chan;
+                break;
+            } else
+                last = cchanuser;
+        }
+    }
+
+    //remove it from the channel's user-list
+    last = NULL;
+    for(cchanuser = chanuser->chan->user; cchanuser; cchanuser = cchanuser->next_user) {
+        if(cchanuser == chanuser) {
+            chanuser->chan->usercount--;
+            if(last) 
+                last->next_user = chanuser->next_user;
+            else
+                chanuser->chan->user = chanuser->next_user;
+            break;
+        } else
+            last = cchanuser;
+    }
+    
+    if(freeChanUser)
+        free(chanuser);
+    else {
+        chanuser->next_chan = NULL;
+        chanuser->next_user = NULL;
+    }
+}
+
+void removeChanUserFromLists(struct ChanUser *chanuser, int remove_from_userlist, int remove_from_channellist, int freeChanUser) {
+    struct ChanUser *cchanuser, *last;
+    if(remove_from_userlist) {
+        //remove it from the channel's user-list
+        last = NULL;
+        for(cchanuser = chanuser->chan->user; cchanuser; cchanuser = cchanuser->next_user) {
+            if(cchanuser == chanuser) {
+                chanuser->chan->usercount--;
+                if(last) 
+                    last->next_user = chanuser->next_user;
+                else
+                    chanuser->chan->user = chanuser->next_user;
+                break;
+            } else
+                last = cchanuser;
+        }
+        chanuser->next_user = NULL;
+    }
+    if(remove_from_channellist) {
+        //remove it from the user's channel-list
+        last = NULL;
+        for(cchanuser = chanuser->user->channel; cchanuser; cchanuser = cchanuser->next_chan) {
+            if(cchanuser == chanuser) {
+                if(last) 
+                    last->next_chan = chanuser->next_chan;
+                else
+                    chanuser->user->channel = chanuser->next_chan;
+                break;
+            } else
+                last = cchanuser;
+        }
+        chanuser->next_chan = NULL;
+    }
+    
+    if(freeChanUser)
+        free(chanuser);
+}
+
diff --git a/src/ChanUser.h b/src/ChanUser.h
new file mode 100644 (file)
index 0000000..076b7f7
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _ChanUser_h
+#define _ChanUser_h
+#include "main.h"
+
+#define CHANUSERFLAG_OPPED  0x01
+#define CHANUSERFLAG_VOICED 0x02
+#define CHANUSERFLAG_INVISIBLE 0x04
+
+#define CHANUSERFLAG_OPPED_OR_VOICED (CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED)
+
+struct ChanNode;
+struct UserNode;
+
+struct ChanUser {
+    unsigned char flags;
+    struct ChanNode *chan;
+    struct UserNode *user;
+    
+    int chageEvents;
+    time_t changeTime;
+    
+    struct ChanUser *next_user;
+    struct ChanUser *next_chan;
+};
+
+struct ChanUser* addChanUser(struct ChanNode *chan, struct UserNode *user);
+struct ChanUser* addInvisibleChanUser(struct ChanNode *chan, struct UserNode *user);
+int isUserOnChan(struct UserNode *user, struct ChanNode *chan);
+struct ChanUser* getChanUser(struct UserNode *user, struct ChanNode *chan);
+struct ChanUser* getChannelUsers(struct ChanNode *chan, struct ChanUser *last);
+struct ChanUser* getUserChannels(struct UserNode *user, struct ChanUser *last);
+void delChanUser(struct ChanUser *chanuser, int freeChanUser);
+void removeChanUserFromLists(struct ChanUser *chanuser, int remove_from_userlist, int remove_from_channellist, int freeChanUser);
+
+#endif
\ No newline at end of file
diff --git a/src/ClientSocket.c b/src/ClientSocket.c
new file mode 100644 (file)
index 0000000..62e367d
--- /dev/null
@@ -0,0 +1,226 @@
+
+#include "ClientSocket.h"
+#include "IRCParser.h"
+#include "UserNode.h"
+
+struct socket_list {
+    struct ClientSocket *data;
+    unsigned count;
+};
+
+//the magic list :P
+static struct socket_list *sockets = NULL;
+static char buffer[BUF_SIZ];
+
+static void init_sockets() {
+    sockets = malloc(sizeof(*sockets));
+    if (!sockets)
+    {
+        perror("malloc() failed");
+        return;
+    }
+    sockets->data = NULL;
+    sockets->count = 0;
+}
+
+struct ClientSocket* create_socket(char *host, int port, char *pass, struct UserNode *user) {
+    if(sockets == NULL) init_sockets();
+    struct ClientSocket *client = malloc(sizeof(*client));
+    if (!client)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    client->host = strdup(host);
+    client->port = port;
+    printf("Connect: %s:%d", client->host, client->port);
+    client->pass = (pass == NULL ? NULL : strdup(pass));
+    client->user = user;
+    client->flags = 0;
+    client->bufferpos = 0;
+    client->traffic_in = 0;
+    client->traffic_out = 0;
+    client->connection_time = 0;
+       client->botid = 0;
+    client->clientid = 0;
+    client->next = sockets->data;
+    sockets->data = client;
+    return client;
+}
+
+int connect_socket(struct ClientSocket *client) {
+    if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
+    struct hostent *host;
+    struct sockaddr_in addr;
+    int sock;
+    if (!inet_aton(client->host, &addr.sin_addr))
+    {
+        host = gethostbyname(client->host);
+        if (!host)
+        {
+            herror("gethostbyname() failed");
+            return 0;
+        }
+        addr.sin_addr = *(struct in_addr*)host->h_addr;
+    }
+    sock = socket(PF_INET, SOCK_STREAM, 0);
+    if (sock == -1)
+    {
+        perror("socket() failed");
+        return 0;
+    }
+
+    addr.sin_port = htons(client->port);
+    addr.sin_family = AF_INET;
+
+    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
+    {
+        perror("connect() failed");
+        return 0;
+    }
+
+    client->sock = sock;
+    client->flags |= SOCKET_FLAG_CONNECTED;
+    client->connection_time = time(0);
+
+    //send the IRC Headers
+    char sendBuf[512];
+    int len;
+
+    if(client->pass) {
+        len = sprintf(sendBuf, "PASS :%s\n", client->pass);
+        write_socket(client, sendBuf, len);
+    }
+    len = sprintf(sendBuf, "USER %s 0 0 :%s\n", client->user->ident, client->user->realname);
+    write_socket(client, sendBuf, len);
+    len = sprintf(sendBuf, "NICK %s\n", client->user->nick);
+    write_socket(client, sendBuf, len);
+
+    return 1;
+}
+
+int close_socket(struct ClientSocket *client) {
+    if(client == NULL) return 0;
+    if((client->flags & SOCKET_FLAG_CONNECTED))
+        close(client->sock);
+    struct ClientSocket *sock, *last_sock = NULL;
+    for (sock = sockets->data; sock; sock = sock->next) {
+        if(sock == client) {
+            if(last_sock)
+                last_sock->next = sock->next;
+            else
+                sockets->data = sock->next;
+            sockets->count--;
+        } else
+            last_sock = sock;
+    }
+    free(client->host);
+    free(client->pass);
+    free(client);
+    return 1;
+}
+
+int write_socket(struct ClientSocket *client, char* msg, int len) {
+    if(!(client->flags & SOCKET_FLAG_CONNECTED)) return 0;
+    printf("[send %d] %s", len, msg);
+    write(client->sock, msg, len);
+    client->traffic_out += len;
+    return 1;
+}
+
+void socket_loop(int timeout_seconds) {
+    if(sockets == NULL) return;
+    fd_set fds;
+    struct timeval timeout;
+    struct ClientSocket *sock;
+    int ret = 0, bytes, i;
+    
+    FD_ZERO(&fds);
+    for (sock = sockets->data; sock; sock = sock->next) {
+        if(!(sock->flags & SOCKET_FLAG_CONNECTED)) continue; //skip disconnected sockets
+        FD_SET(sock->sock, &fds);
+        if(sock->sock > ret)
+            ret = sock->sock;
+    }
+    timeout.tv_sec = timeout_seconds;
+    timeout.tv_usec = 0;
+    ret = select(ret + 1, &fds, NULL, NULL, &timeout);
+    if(ret == 0) return;
+    for (sock = sockets->data; sock; sock = sock->next) {
+        if((sock->flags & SOCKET_FLAG_CONNECTED) && FD_ISSET(sock->sock, &fds)) {
+            if(sock->bufferpos != 0) {
+                bytes = read(sock->sock, buffer, sizeof(buffer));
+                if(bytes > 0) {
+                    for(i = 0; i < bytes; i++) {
+                        if(sock->bufferpos + i == BUF_SIZ*2) break; //buffer overflow
+                        sock->buffer[sock->bufferpos + i] = buffer[i];
+                    }
+                    sock->bufferpos += i;
+                }
+            } else {
+                bytes = read(sock->sock, sock->buffer, sizeof(sock->buffer));
+                if(bytes > 0)
+                    sock->bufferpos = bytes;
+            }
+            if(bytes <= 0) {
+                //error
+                sock->flags &= ~(SOCKET_FLAG_CONNECTED | SOCKET_FLAG_READY);
+                bot_disconnect(sock);
+            } else {
+                sock->traffic_in += bytes;
+                int used = parse_lines(sock, sock->buffer, sock->bufferpos);
+                if(used == sock->bufferpos + 1) {
+                    //used all bytes so just reset the bufferpos
+                    sock->bufferpos = 0;
+                } else {
+                    for(i = 0; i < sock->bufferpos - used; i++) {
+                        sock->buffer[i] = sock->buffer[i+used];
+                    }
+                    sock->bufferpos -= used;
+                }
+            }
+        }
+    }
+}
+
+void
+putsock(struct ClientSocket *client, const char *text, ...)
+{
+    va_list arg_list;
+    char sendBuf[MAXLEN];
+    int pos;
+    if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
+    sendBuf[0] = '\0';
+    va_start(arg_list, text);
+    pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
+    va_end(arg_list);
+    if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
+    sendBuf[pos] = '\n';
+    sendBuf[pos+1] = '\0';
+    write_socket(client, sendBuf, pos+1);
+}
+
+struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot) {
+    struct ClientSocket *sock = (last_bot ? last_bot->next : sockets->data);
+    if(sock == NULL) return NULL;
+    for (; sock; sock = sock->next) {
+        if(!flags || (sock->flags & flags) == flags)
+            return sock;
+    }
+    return NULL;
+}
+
+void free_sockets() {
+    if(!sockets) return;
+    struct ClientSocket *client, *next;
+    for (client = sockets->data; client; client = next) {
+        next = client->next;
+        if((client->flags & SOCKET_FLAG_CONNECTED))
+            close(client->sock);
+        free(client->host);
+        free(client->pass);
+        free(client);
+    }
+    free(sockets);
+    sockets = NULL;
+}
diff --git a/src/ClientSocket.h b/src/ClientSocket.h
new file mode 100644 (file)
index 0000000..380e051
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _ClientSocket_h
+#define _ClientSocket_h
+
+#include "main.h"
+
+#define SOCKET_FLAG_DEAD      0x01
+#define SOCKET_FLAG_CONNECTED 0x02
+#define SOCKET_FLAG_READY     0x04
+#define SOCKET_FLAG_PREFERRED  0x08 /* prefered bot to send datas to the IRC World (NOTICE's WHO's etc pp) */
+
+#define BUF_SIZ 512
+
+struct UserNode;
+struct trigger_cache;
+
+struct ClientSocket {
+    int sock;
+    unsigned char flags;
+    char buffer[BUF_SIZ*2]; //we need to store up to 2 full commands at once
+    unsigned int bufferpos;
+    char *host;
+    int port;
+    char *pass;
+    struct UserNode *user;
+    unsigned long traffic_in;
+    unsigned long traffic_out;
+    time_t connection_time;
+       
+       int botid : 16;
+    int clientid : 16;
+    
+    struct ClientSocket *next;
+};
+
+struct ClientSocket* create_socket(char *host, int port, char *pass, struct UserNode *user);
+int connect_socket(struct ClientSocket *client);
+int close_socket(struct ClientSocket *client);
+int write_socket(struct ClientSocket *client, char* msg, int len);
+void socket_loop(int timeout_seconds);
+void putsock(struct ClientSocket *client, const char *text, ...) PRINTF_LIKE(2, 3);
+struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot);
+void free_sockets();
+
+#endif
\ No newline at end of file
diff --git a/src/DATABASE.txt b/src/DATABASE.txt
new file mode 100644 (file)
index 0000000..62e38fa
--- /dev/null
@@ -0,0 +1,65 @@
+//Database of NeonServ V4 modifications for NeonServ V5
+
+ALTER TABLE `bots` CHANGE `botclass` `botclass` INT( 10 ) NOT NULL;
+
+ALTER TABLE `users` CHANGE `user_lang` `user_lang` VARCHAR( 6 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL;
+ALTER TABLE `users` ADD `user_reply_privmsg` TINYINT( 1 ) NOT NULL ;
+
+CREATE TABLE IF NOT EXISTS `godlog` (
+  `godlog_id` int(11) NOT NULL AUTO_INCREMENT,
+  `godlog_uid` int(11) NOT NULL,
+  `godlog_cid` int(15) NOT NULL,
+  `godlog_time` int(15) NOT NULL,
+  `godlog_cmd` varchar(512) NOT NULL,
+  PRIMARY KEY (`godlog_id`)
+) ENGINE=MyISAM;
+
+ALTER TABLE `channels` ADD `channel_lastgiveowner` INT( 11 ) NOT NULL AFTER `channel_lastvisit`;
+
+CREATE TABLE IF NOT EXISTS `owner_history` (
+`owner_history_id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
+`owner_history_cid` INT( 11 ) NOT NULL ,
+`owner_history_uid` INT( 11 ) NOT NULL ,
+`owner_history_time` INT( 11 ) NOT NULL ,
+INDEX ( `owner_history_cid` )
+) ENGINE = MYISAM ;
+
+ALTER TABLE `chanusers` ADD INDEX ( `chanuser_cid` ) ;
+ALTER TABLE `chanusers` ADD INDEX ( `chanuser_uid` ) ;
+
+ALTER TABLE `bot_binds` ADD `chan_access` VARCHAR( 256 ) NULL DEFAULT NULL AFTER `parameters`;
+
+ALTER TABLE `bot_binds` CHANGE `global_access` `global_access` INT( 3 ) NULL;
+
+ALTER TABLE `bans` CHANGE `ban_owner` `ban_owner` INT( 11 ) NOT NULL;
+
+ALTER TABLE `channels` ADD `channel_exttopic` TINYINT( 1 ) NOT NULL AFTER `channel_topicmask` ,
+ADD `channel_exttopic_topic` VARCHAR( 512 ) NOT NULL AFTER `channel_exttopic`;
+
+ALTER TABLE `bots` ADD `max_channels` INT( 5 ) NOT NULL ;
+
+ALTER TABLE `bot_binds` CHANGE `botid` `botclass` INT( 11 ) NOT NULL;
+ALTER TABLE `bots` DROP `whoisbot` ;
+ALTER TABLE `bots` DROP `bindFrom` ;
+
+CREATE TABLE IF NOT EXISTS `help` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `lang` varchar(6) NOT NULL,
+  `ident` varchar(64) NOT NULL,
+  `text` text NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
+
+CREATE TABLE IF NOT EXISTS `language` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `lang` varchar(5) NOT NULL,
+  `ident` varchar(64) NOT NULL,
+  `text` varchar(256) NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
+
+ALTER TABLE `bot_channels` ADD `suspended` TINYINT( 1 ) NOT NULL;
+
+ALTER TABLE `users` ADD UNIQUE (`user_user`);
+
+ALTER TABLE `noinvite` ADD INDEX ( `cid`, `uid` );
\ No newline at end of file
diff --git a/src/DBHelper.c b/src/DBHelper.c
new file mode 100644 (file)
index 0000000..181fff6
--- /dev/null
@@ -0,0 +1,166 @@
+
+#include "DBHelper.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "mysqlConn.h"
+#include "lang.h"
+#include "tools.h"
+
+void _loadUserSettings(struct UserNode *user) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `user_lang`, `user_reply_privmsg`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        user->language = get_language_by_tag(row[0]);
+        if(user->language == NULL) user->language = get_default_language();
+        if(strcmp(row[1], "0"))
+            user->flags |= USERFLAG_REPLY_PRIVMSG;
+        if(strcmp(row[2], "0"))
+            user->flags |= USERFLAG_GOD_MODE;
+    } else
+        user->language = get_default_language();
+    user->flags |= USERFLAG_LOADED_SETTINGS;
+}
+
+int isGodMode(struct UserNode *user) {
+    loadUserSettings(user);
+    return (user->flags & USERFLAG_GOD_MODE);
+}
+
+int getChannelAccess(struct UserNode *user, struct ChanNode *chan, int override) {
+    if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int caccess = 0;
+    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        if(strcmp(row[2], "0") && override) 
+            caccess = atoi(row[1]);
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%s' AND `chanuser_cid` = '%d'", row[0], chan->channel_id);
+        //
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            int cflags = atoi(row[1]);
+            if(!(cflags & DB_CHANUSER_SUSPENDED) && atoi(row[0]) > caccess)
+                caccess = atoi(row[0]);
+        }
+        return caccess;
+    }
+    return 0;
+}
+
+char *getChanDefault(char *channel_setting) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", channel_setting);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return "";
+    return row[0];
+}
+
+int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *channel_setting, int allow_override, int allow_501) {
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
+    if((user->flags & USERFLAG_ISIRCOP)) return 1;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", channel_setting, chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return 0;
+    int require_access = atoi((row[0] ? row[0] : getChanDefault(channel_setting)));
+    if(require_access == 0) return 1;
+    if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
+    int caccess = 0;
+    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_uid` = '%s' AND `chanuser_cid` = '%d'", row[0], chan->channel_id);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            int cflags = atoi(row[1]);
+            if(!(cflags & DB_CHANUSER_SUSPENDED))
+                caccess = atoi(row[0]);
+        }
+    }
+    if(caccess >= require_access) return 1;
+    if(caccess == 500 && require_access == 501 && allow_501) return 1;
+    return 0;
+}
+
+void _loadChannelSettings(struct ChanNode *chan) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(chan->name));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        chan->flags |= CHANFLAG_CHAN_REGISTERED;
+        chan->channel_id = atoi(row[0]);
+    }
+    chan->flags |= CHANFLAG_REQUESTED_CHANINFO;
+}
+
+//TODO: fix performance: we should cache the user access
+int isUserProtected(struct ChanNode *chan, struct UserNode *victim, struct UserNode *issuer) {
+    /* Don't protect if someone is attacking himself, or if the aggressor is an IRC Operator. */
+    if(victim == issuer || (issuer->flags & USERFLAG_ISIRCOP)) return 0;
+    
+    /* Don't protect if no one is to be protected. */
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    char protection;
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
+    printf_mysql_query("SELECT `channel_protect` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if(!(row = mysql_fetch_row(res))) return 0;
+    if(row[0]) {
+        protection = (char) atoi(row[0]);
+    } else {
+         printf_mysql_query("SELECT `channel_protect` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+        protection = (char) atoi(row[0]);
+    }
+    if(protection == 3) return 0;
+    
+    /* Don't protect if the victim isn't added to the channel, unless we are to protect non-users also. */
+    int victim_access = getChannelAccess(victim, chan, 0);
+    if (!victim_access && protection != 0) return 0;
+    
+    /* Protect if the aggressor isn't a user because at this point, the aggressor can only be less than or equal to the victim. */
+    int issuer_access = getChannelAccess(issuer, chan, 0);
+    if (!issuer_access) return 1;
+    
+    /* If the aggressor was a user, then the victim can't be helped. */
+    if(!victim_access) return 0;
+    
+    switch(protection) {
+        case 0:
+        case 1:
+            if(victim_access >= issuer_access) return 1;
+            break;
+        case 2:
+            if(victim_access > issuer_access) return 1;
+            break;
+    }
+    return 0;
+}
+
+char *getBanAffectingMask(struct ChanNode *chan, char *mask) {
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return 0;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `ban_mask` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(!match(row[0], mask))
+            return row[0];
+    }
+    return NULL;
+}
diff --git a/src/DBHelper.h b/src/DBHelper.h
new file mode 100644 (file)
index 0000000..8378040
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _DBHelper_h
+#define _DBHelper_h
+
+#include "main.h"
+struct UserNode;
+struct ChanNode;
+
+#define DB_CHANUSER_SUSPENDED 0x01
+#define DB_CHANUSER_AUTOINVITE 0x02
+#define DB_CHANUSER_NOAUTOOP 0x04
+
+void _loadUserSettings(struct UserNode* user);
+#define loadUserSettings(USER) if((USER->flags & USERFLAG_ISAUTHED) && !(USER->flags & USERFLAG_LOADED_SETTINGS)) _loadUserSettings(USER)
+int isGodMode(struct UserNode *user);
+char *getChanDefault(char *channel_setting);
+int getChannelAccess(struct UserNode *user, struct ChanNode *chan, int override);
+int checkChannelAccess(struct UserNode *user, struct ChanNode *chan, char *channel_setting, int allow_override, int allow_501);
+void _loadChannelSettings(struct ChanNode *chan);
+#define loadChannelSettings(CHAN) if(!(CHAN->flags & CHANFLAG_REQUESTED_CHANINFO)) _loadChannelSettings(CHAN)
+int isUserProtected(struct ChanNode *chan, struct UserNode *victim, struct UserNode *issuer);
+
+char *getBanAffectingMask(struct ChanNode *chan, char *mask); //returns bans that match a given mask   eg. *!*@ab*  if you pass  *!*@abcdefg.*
+
+#endif
\ No newline at end of file
diff --git a/src/EventLogger.c b/src/EventLogger.c
new file mode 100644 (file)
index 0000000..d0b61bd
--- /dev/null
@@ -0,0 +1,87 @@
+
+#include "EventLogger.h"
+#include "modcmd.h"
+#include "mysqlConn.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "DBHelper.h"
+
+static struct Event *first_event = NULL, *last_event = NULL;
+
+struct Event *createEvent(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char **args, int argc, int flags) {
+    struct Event *event = malloc(sizeof(*event));
+    if (!event)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    event->client = client;
+    event->user = user;
+    event->chan = chan;
+    event->event_time = time(0);
+    event->command = strdup(command);
+    char arguments[MAXLEN];
+    int argpos = 0;
+    int i;
+    for(i = 0; i < argc; i++)
+        argpos += sprintf(arguments + argpos, "%s ", args[i]);
+    arguments[(argpos ? argpos-1 : 0)] = '\0';
+    event->arguments = strdup(arguments);
+    event->flags = flags;
+    event->next = NULL;
+    if(last_event) {
+        last_event->next = event;
+        last_event = event;
+    } else {
+        last_event = event;
+        first_event = event;
+    }
+    return event;
+}
+
+void logEvent(struct Event *event) {
+    char fullcmd[MAXLEN];
+    sprintf(fullcmd, "%s %s", event->command, event->arguments);
+    if((event->flags & CMDFLAG_LOG) && event->chan) {
+        char *auth = ((event->user->flags & USERFLAG_ISAUTHED) ? event->user->auth : "*");
+        loadChannelSettings(event->chan);
+        if((event->chan->flags & CHANFLAG_CHAN_REGISTERED))
+            printf_mysql_query("INSERT INTO `events` (`cid`, `nick`, `auth`, `time`, `command`) VALUES ('%d', '%s', '%s', UNIX_TIMESTAMP(), '%s')", event->chan->channel_id, escape_string(event->user->nick), auth, escape_string(fullcmd));
+    }
+    if((event->flags & CMDFLAG_OPLOG)) {
+        MYSQL_RES *res;
+        MYSQL_ROW row;
+        int userid;
+        char *auth = ((event->user->flags & USERFLAG_ISAUTHED) ? event->user->auth : "*");
+        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) == NULL) 
+            userid = 0;
+        else
+            userid = atoi(row[0]);
+        loadChannelSettings(event->chan);
+        if((event->chan->flags & CHANFLAG_CHAN_REGISTERED))
+            printf_mysql_query("INSERT INTO `godlog` (`godlog_cid`, `godlog_uid`, `godlog_time`, `godlog_cmd`) VALUES ('%d', '%d', UNIX_TIMESTAMP(), '%s')", event->chan->channel_id, userid, escape_string(fullcmd));
+    }
+}
+
+static void destroyEvent(struct Event *event) {
+    if(event == first_event)
+        first_event = event->next;
+    if(event == last_event) {
+        struct Event *last;
+        for(last = first_event; last; last = last->next)
+            if(last->next == NULL) break;
+        last_event = last;
+    }
+    free(event->command);
+    free(event->arguments);
+    free(event);
+}
+
+void destroyEvents() {
+    time_t now = time(0);
+    while(first_event && now - first_event->event_time >= 60) {
+        destroyEvent(first_event);
+    }
+}
diff --git a/src/EventLogger.h b/src/EventLogger.h
new file mode 100644 (file)
index 0000000..71da262
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _EventLogger_h
+#define _EventLogger_h
+
+#include "main.h"
+struct ClientSocket;
+struct UserNode;
+struct ChanNode;
+
+struct Event {
+    struct ClientSocket *client;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    time_t event_time;
+    char *command;
+    char *arguments;
+    unsigned int flags; /* defined in modcmd.h */
+    
+    struct Event *next;
+};
+
+struct Event *createEvent(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char **args, int argc, int flags);
+void logEvent(struct Event *event);
+void destroyEvents();
+
+#endif
\ No newline at end of file
diff --git a/src/HandleInfoHandler.c b/src/HandleInfoHandler.c
new file mode 100644 (file)
index 0000000..bda467e
--- /dev/null
@@ -0,0 +1,120 @@
+
+#include "HandleInfoHandler.h"
+#include "ClientSocket.h"
+#include "UserNode.h"
+#include "IRCEvents.h"
+#include "tools.h"
+
+#define AUTHSERV_NICK "AuthServ"
+
+struct HandleInfoQueueEntry {
+    struct ClientSocket *client;
+    void *callback;
+    void *data;
+    
+    struct HandleInfoQueueEntry *next;
+};
+
+static struct HandleInfoQueueEntry *first_entry = NULL, *last_entry = NULL;
+
+static struct HandleInfoQueueEntry* addHandleInfoQueueEntry(struct ClientSocket *client) {
+    struct HandleInfoQueueEntry *entry = malloc(sizeof(*entry));
+    if (!entry)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    entry->next = NULL;
+    entry->client = client;
+    if(last_entry)
+        last_entry->next = entry;
+    else
+        last_entry = entry;
+    if(!first_entry)
+        first_entry = entry;
+    return entry;
+}
+
+static struct HandleInfoQueueEntry* getNextHandleInfoQueueEntry(struct ClientSocket *client, int freeEntry) {
+    if(!first_entry) return NULL;
+    struct HandleInfoQueueEntry *entry;
+    for(entry = first_entry; entry; entry = entry->next) {
+        if(entry->client == client)
+            break;
+    }
+    if(entry == NULL) return NULL;
+    if(freeEntry) {
+        if(entry == first_entry)
+            first_entry = entry->next;
+        if(entry == last_entry) {
+            struct HandleInfoQueueEntry *last;
+            for(last = first_entry; last; last = last->next)
+                if(last->next == NULL) break;
+            last_entry = last;
+        }
+    }
+    return entry;
+}
+
+void lookup_authname(char *auth, authlookup_callback_t callback, void *data) {
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->flags & SOCKET_FLAG_PREFERRED)
+            break;
+    }
+    if(bot == NULL) return;
+    struct HandleInfoQueueEntry* entry = addHandleInfoQueueEntry(bot);
+    entry->callback = callback;
+    entry->data = data;
+    putsock(bot, "PRIVMSG " AUTHSERV_NICK " :ACCOUNTINFO *%s", auth);
+}
+
+static void recv_notice(struct UserNode *user, struct UserNode *target, char *message) {
+    if(stricmp(user->nick, AUTHSERV_NICK)) return;
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->user == target) break;
+    }
+    if(!bot) return;
+    char *auth = NULL;
+    int do_match = 0, exists = 0;
+    char *tmp;
+    //messages to parse:
+    //  Account * has not been registered.
+    //  Account information for Skynet:
+    if(!match("Account * has not been registered.", message)) {
+        do_match = 1;
+        tmp = strstr(message, "\002");
+        auth = tmp+1;
+        tmp = strstr(auth, "\002");
+        *tmp = '\0';
+    }
+    if(!match("Account information for *", message)) {
+        do_match = 1;
+        exists = 1;
+        tmp = strstr(message, "\002");
+        auth = tmp+1;
+        tmp = strstr(auth, "\002");
+        *tmp = '\0';
+    }
+    if(do_match) {
+        struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, 1);
+        authlookup_callback_t *callback = entry->callback;
+        callback(auth, exists, entry->data);
+        free(entry);
+    }
+}
+
+void init_handleinfohandler() {
+    bind_privnotice(recv_notice);
+}
+
+void free_handleinfohandler() {
+    struct HandleInfoQueueEntry *entry, *next;
+    for(entry = first_entry; entry; entry = next) {
+        next = entry->next;
+        free(entry);
+    }
+    first_entry = NULL;
+    last_entry = NULL;
+}
diff --git a/src/HandleInfoHandler.h b/src/HandleInfoHandler.h
new file mode 100644 (file)
index 0000000..e51fe8d
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _HandleInfoHandler_h
+#define _HandleInfoHandler_h
+
+#include "main.h"
+
+struct ClientSocket;
+struct UserNode;
+
+#define AUTHLOOKUP_CALLBACK(NAME) void NAME(UNUSED_ARG(char *auth), UNUSED_ARG(int exists), UNUSED_ARG(void *data))
+typedef AUTHLOOKUP_CALLBACK(authlookup_callback_t);
+
+void lookup_authname(char *auth, authlookup_callback_t callback, void *data);
+void init_handleinfohandler();
+void free_handleinfohandler();
+
+#endif
\ No newline at end of file
diff --git a/src/IRCEvents.c b/src/IRCEvents.c
new file mode 100644 (file)
index 0000000..58efd37
--- /dev/null
@@ -0,0 +1,175 @@
+
+#include "IRCEvents.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "ClientSocket.h"
+#include "mysqlConn.h"
+
+struct binding {
+    void *func;
+    struct binding *next;
+};
+
+static void **binds;
+#define BIND_TYPE_JOIN       0
+#define BIND_TYPE_NICK       1
+#define BIND_TYPE_PART       2
+#define BIND_TYPE_QUIT       3
+#define BIND_TYPE_KICK       4
+#define BIND_TYPE_TOPIC      5
+#define BIND_TYPE_MODE       6
+#define BIND_TYPE_CHANMSG    7
+#define BIND_TYPE_PRIVMSG    8
+#define BIND_TYPE_CHANNOTICE 9
+#define BIND_TYPE_PRIVNOTICE 10
+#define BIND_TYPE_CHANCTCP   11
+#define BIND_TYPE_PRIVCTCP   12
+#define BIND_TYPE_INVITE     13
+#define BIND_TYPE_RAW        14
+#define BIND_TYPE_BOT_READY  15
+
+#define TOTAL_BIND_TYPES     16
+
+void init_bind() {
+    binds = calloc(TOTAL_BIND_TYPES, sizeof(*binds));
+}
+
+void free_bind() {
+    struct binding *cbind, *next;
+    int i;
+    for(i = 0; i < TOTAL_BIND_TYPES; i++) {
+        for(cbind = binds[i]; cbind; cbind = next) {
+            next = cbind->next;
+            free(cbind);
+        }
+    }
+    free(binds);
+}
+
+static int is_bound(unsigned char type, void *func) {
+    struct binding *cbind;
+    for(cbind = binds[type]; cbind; cbind = cbind->next) {
+        if(cbind->func == func) 
+            return 1;
+    }
+    return 0;
+}
+
+#define FUNC_BIND(NAME,FUNCTYPE,TYPE) \
+int bind_##NAME(FUNCTYPE *func) { \
+    if(!is_bound(TYPE, func)) { \
+        struct binding *cbind = malloc(sizeof(*cbind)); \
+        if (!cbind) { \
+            perror("malloc() failed"); \
+            return 0; \
+        } \
+        cbind->func = func; \
+        cbind->next = binds[TYPE]; \
+        binds[TYPE] = cbind; \
+        return 1; \
+    } \
+    return 0; \
+}
+
+#define FUNC_UNBIND(NAME,FUNCTYPE,TYPE) \
+void unbind_##NAME(FUNCTYPE *func) { \
+    struct binding *cbind, *last = NULL, *next; \
+    for(cbind = binds[TYPE]; cbind; cbind = next) { \
+        next = cbind->next; \
+        if(cbind->func == func) { \
+            if(last) \
+                last->next = cbind->next; \
+            else \
+                binds[TYPE] = cbind->next; \
+            free(cbind); \
+        } else \
+            last = cbind; \
+    } \
+}
+
+#define FUNC_EVENT(NAME,FUNCTYPE,TYPE,PDECLARATION,PLIST) \
+int event_##NAME PDECLARATION { \
+    struct binding *cbind; \
+    pre_event(TYPE); \
+    for(cbind = binds[TYPE]; cbind; cbind = cbind->next) { \
+        FUNCTYPE *func = cbind->func; \
+        func PLIST; \
+    } \
+    post_event(TYPE); \
+    return 1; \
+}
+
+void pre_event(UNUSED_ARG(int type)) {
+
+}
+
+void post_event(UNUSED_ARG(int type)) {
+    mysql_free();
+}
+
+//EVENTS
+
+FUNC_BIND(join, join_func_t, BIND_TYPE_JOIN)
+FUNC_UNBIND(join, join_func_t, BIND_TYPE_JOIN)
+FUNC_EVENT(join, join_func_t, BIND_TYPE_JOIN, (struct ChanUser *chanuser), (chanuser))
+
+FUNC_BIND(nick, nick_func_t, BIND_TYPE_NICK)
+FUNC_UNBIND(nick, nick_func_t, BIND_TYPE_NICK)
+FUNC_EVENT(nick, nick_func_t, BIND_TYPE_NICK, (struct UserNode *user, char *new_nick), (user, new_nick))
+
+FUNC_BIND(part, part_func_t, BIND_TYPE_PART)
+FUNC_UNBIND(part, part_func_t, BIND_TYPE_PART)
+FUNC_EVENT(part, part_func_t, BIND_TYPE_PART, (struct ChanUser *chanuser, char *reason), (chanuser, reason))
+
+FUNC_BIND(quit, quit_func_t, BIND_TYPE_QUIT)
+FUNC_UNBIND(quit, quit_func_t, BIND_TYPE_QUIT)
+FUNC_EVENT(quit, quit_func_t, BIND_TYPE_QUIT, (struct UserNode *user, char *reason), (user, reason))
+
+FUNC_BIND(kick, kick_func_t, BIND_TYPE_KICK)
+FUNC_UNBIND(kick, kick_func_t, BIND_TYPE_KICK)
+FUNC_EVENT(kick, kick_func_t, BIND_TYPE_KICK, (struct UserNode *user, struct ChanUser *target, char *reason), (user, target, reason))
+
+FUNC_BIND(topic, topic_func_t, BIND_TYPE_TOPIC)
+FUNC_UNBIND(topic, topic_func_t, BIND_TYPE_TOPIC)
+FUNC_EVENT(topic, topic_func_t, BIND_TYPE_TOPIC, (struct UserNode *user, struct ChanNode *chan, const char *new_topic), (user, chan, new_topic))
+
+FUNC_BIND(mode, mode_func_t, BIND_TYPE_MODE)
+FUNC_UNBIND(mode, mode_func_t, BIND_TYPE_MODE)
+FUNC_EVENT(mode, mode_func_t, BIND_TYPE_MODE, (struct UserNode *user, struct ChanNode *chan, char *modes, char **args, int argc), (user, chan, modes, args, argc))
+
+FUNC_BIND(chanmsg, chanmsg_func_t, BIND_TYPE_CHANMSG)
+FUNC_UNBIND(chanmsg, chanmsg_func_t, BIND_TYPE_CHANMSG)
+FUNC_EVENT(chanmsg, chanmsg_func_t, BIND_TYPE_CHANMSG, (struct UserNode *user, struct ChanNode *chan, char *message), (user, chan, message))
+
+FUNC_BIND(privmsg, privmsg_func_t, BIND_TYPE_PRIVMSG)
+FUNC_UNBIND(privmsg, privmsg_func_t, BIND_TYPE_PRIVMSG)
+FUNC_EVENT(privmsg, privmsg_func_t, BIND_TYPE_PRIVMSG, (struct UserNode *user, struct UserNode *target, char *message), (user, target, message))
+
+FUNC_BIND(channotice, channotice_func_t, BIND_TYPE_CHANNOTICE)
+FUNC_UNBIND(channotice, channotice_func_t, BIND_TYPE_CHANNOTICE)
+FUNC_EVENT(channotice, channotice_func_t, BIND_TYPE_CHANNOTICE, (struct UserNode *user, struct ChanNode *chan, char *message), (user, chan, message))
+
+FUNC_BIND(privnotice, privnotice_func_t, BIND_TYPE_PRIVNOTICE)
+FUNC_UNBIND(privnotice, privnotice_func_t, BIND_TYPE_PRIVNOTICE)
+FUNC_EVENT(privnotice, privnotice_func_t, BIND_TYPE_PRIVNOTICE, (struct UserNode *user, struct UserNode *target, char *message), (user, target, message))
+
+FUNC_BIND(chanctcp, chanctcp_func_t, BIND_TYPE_CHANCTCP)
+FUNC_UNBIND(chanctcp, chanctcp_func_t, BIND_TYPE_CHANCTCP)
+FUNC_EVENT(chanctcp, chanctcp_func_t, BIND_TYPE_CHANCTCP, (struct UserNode *user, struct ChanNode *chan, char *command, char *text), (user, chan, command, text))
+
+FUNC_BIND(privctcp, privctcp_func_t, BIND_TYPE_PRIVCTCP)
+FUNC_UNBIND(privctcp, privctcp_func_t, BIND_TYPE_PRIVCTCP)
+FUNC_EVENT(privctcp, privctcp_func_t, BIND_TYPE_PRIVCTCP, (struct UserNode *user, struct UserNode *target, char *command, char *text), (user, target, command, text))
+
+FUNC_BIND(invite, invite_func_t, BIND_TYPE_INVITE)
+FUNC_UNBIND(invite, invite_func_t, BIND_TYPE_INVITE)
+FUNC_EVENT(invite, invite_func_t, BIND_TYPE_INVITE, (struct ClientSocket *client, struct UserNode *user, char *channel), (client, user, channel))
+
+FUNC_BIND(raw, raw_func_t, BIND_TYPE_RAW)
+FUNC_UNBIND(raw, raw_func_t, BIND_TYPE_RAW)
+FUNC_EVENT(raw, raw_func_t, BIND_TYPE_RAW, (struct ClientSocket *client, char *from, char *cmd, char **argv, int argc), (client, from, cmd, argv, argc))
+
+FUNC_BIND(bot_ready, bot_ready_func_t, BIND_TYPE_BOT_READY)
+FUNC_UNBIND(bot_ready, bot_ready_func_t, BIND_TYPE_BOT_READY)
+FUNC_EVENT(bot_ready, bot_ready_func_t, BIND_TYPE_BOT_READY, (struct ClientSocket *client), (client))
diff --git a/src/IRCEvents.h b/src/IRCEvents.h
new file mode 100644 (file)
index 0000000..e08803e
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef _IRCEvents_h
+#define _IRCEvents_h
+
+#include "main.h"
+
+struct UserNode;
+struct ChanNode;
+struct ChanUser;
+struct ClientSocket;
+
+void init_bind();
+void free_bind();
+
+typedef void join_func_t(struct ChanUser *chanuser);
+int bind_join(join_func_t *func);
+void unbind_join(join_func_t *func);
+int event_join(struct ChanUser *chanuser);
+
+typedef void nick_func_t(struct UserNode *user, char *new_nick);
+int bind_nick(nick_func_t *func);
+void unbind_nick(nick_func_t *func);
+int event_nick(struct UserNode *user, char *new_nick);
+
+typedef void part_func_t(struct ChanUser *chanuser, char *reason);
+int bind_part(part_func_t *func);
+void unbind_part(part_func_t *func);
+int event_part(struct ChanUser *chanuser, char *reason);
+
+typedef void quit_func_t(struct UserNode *user, char *reason);
+int bind_quit(quit_func_t *func);
+void unbind_quit(quit_func_t *func);
+int event_quit(struct UserNode *user, char *reason);
+
+typedef void kick_func_t(struct UserNode *user, struct ChanUser *target, char *reason);
+int bind_kick(kick_func_t *func);
+void unbind_kick(kick_func_t *func);
+int event_kick(struct UserNode *user, struct ChanUser *target, char *reason);
+
+typedef void topic_func_t(struct UserNode *user, struct ChanNode *chan, const char *new_topic);
+int bind_topic(topic_func_t *func);
+void unbind_topic(topic_func_t *func);
+int event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic);
+
+typedef void mode_func_t(struct UserNode *user, struct ChanNode *chan, char *modes, char **argv, int argc);
+int bind_mode(mode_func_t *func);
+void unbind_mode(mode_func_t *func);
+int event_mode(struct UserNode *user, struct ChanNode *chan, char *modes, char **argv, int argc);
+
+typedef void chanmsg_func_t(struct UserNode *user, struct ChanNode *chan, char *message);
+int bind_chanmsg(chanmsg_func_t *func);
+void unbind_chanmsg(chanmsg_func_t *func);
+int event_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message);
+
+typedef void privmsg_func_t(struct UserNode *user, struct UserNode *target, char *message);
+int bind_privmsg(privmsg_func_t *func);
+void unbind_privmsg(privmsg_func_t *func);
+int event_privmsg(struct UserNode *user, struct UserNode *target, char *message);
+
+typedef void channotice_func_t(struct UserNode *user, struct ChanNode *chan, char *message);
+int bind_channotice(channotice_func_t *func);
+void unbind_channotice(channotice_func_t *func);
+int event_channotice(struct UserNode *user, struct ChanNode *chan, char *message);
+
+typedef void privnotice_func_t(struct UserNode *user, struct UserNode *target, char *message);
+int bind_privnotice(privnotice_func_t *func);
+void unbind_privnotice(privnotice_func_t *func);
+int event_privnotice(struct UserNode *user, struct UserNode *target, char *message);
+
+typedef void chanctcp_func_t(struct UserNode *user, struct ChanNode *chan, char *command, char *text);
+int bind_chanctcp(chanctcp_func_t *func);
+void unbind_chanctcp(chanctcp_func_t *func);
+int event_chanctcp(struct UserNode *user, struct ChanNode *chan, char *command, char *text);
+
+typedef void privctcp_func_t(struct UserNode *user, struct UserNode *target, char *command, char *text);
+int bind_privctcp(privctcp_func_t *func);
+void unbind_privctcp(privctcp_func_t *func);
+int event_privctcp(struct UserNode *user, struct UserNode *target, char *command, char *text);
+
+typedef void invite_func_t(struct ClientSocket *client, struct UserNode *user, char *channel);
+int bind_invite(invite_func_t *func);
+void unbind_invite(invite_func_t *func);
+int event_invite(struct ClientSocket *client, struct UserNode *user, char *channel);
+
+typedef void raw_func_t(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
+int bind_raw(raw_func_t *func);
+void unbind_raw(raw_func_t *func);
+int event_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
+
+typedef void bot_ready_func_t(struct ClientSocket *client);
+int bind_bot_ready(bot_ready_func_t *func);
+void unbind_bot_ready(bot_ready_func_t *func);
+int event_bot_ready(struct ClientSocket *client);
+
+
+
+#endif
\ No newline at end of file
diff --git a/src/IRCParser.c b/src/IRCParser.c
new file mode 100644 (file)
index 0000000..8662f6d
--- /dev/null
@@ -0,0 +1,427 @@
+
+#include "IRCParser.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "IRCEvents.h"
+#include "ClientSocket.h"
+#include "WHOHandler.h"
+#include "lang.h"
+#include "DBHelper.h"
+#include "BanNode.h"
+#include "ModeNode.h"
+
+struct irc_cmd *irc_commands = NULL;
+
+static void parse_line(struct ClientSocket *client, char *line);
+static void register_irc_function(char *command, irc_cmd_t *func);
+static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
+
+int parse_lines(struct ClientSocket *client, char *lines, int len) {
+    int i, used = 0;
+    char *line = lines;
+    for(i = 0; i < len; i++) {
+        if(lines[i] == '\r') //just zero it out :D
+            lines[i] = 0;
+        if(lines[i] == '\n') {
+            lines[i] = 0;
+            parse_line(client, line);
+            line = lines+(i+1);
+            used = i+1;
+        }
+    }
+    return used;
+}
+
+static void parse_line(struct ClientSocket *client, char *line) {
+    int argc = 0;
+    char *argv[MAXNUMPARAMS];
+    printf("[recv %lu] %s\n", (unsigned long) strlen(line), line);
+    if(line[0] == ':')
+        line++;
+    else
+        argv[argc++] = NULL;
+    while(*line) {
+        //skip leading spaces
+        while (*line == ' ')
+            *line++ = 0;
+        if (*line == ':') {
+           //the rest is a single parameter
+           argv[argc++] = line + 1;
+           break;
+        }
+        argv[argc++] = line;
+        if (argc >= MAXNUMPARAMS)
+            break;
+        while (*line != ' ' && *line)
+            line++;
+    }
+    if(argc >= 2) {
+        parse_raw(client, argv[0], argv[1], argv+2, argc-2);
+    }
+}
+
+static void register_irc_function(char *command, irc_cmd_t *func) {
+    struct irc_cmd *irc_cmd = malloc(sizeof(*irc_cmd));
+    if (!irc_cmd)
+    {
+        perror("malloc() failed");
+        return;
+    }
+    irc_cmd->cmd = command;
+    irc_cmd->func = func;
+    irc_cmd->next = irc_commands;
+    irc_commands = irc_cmd;
+}
+
+static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc) {
+    struct irc_cmd *irc_cmd;
+    int ret = 0;
+    for(irc_cmd = irc_commands; irc_cmd; irc_cmd = irc_cmd->next) {
+        if(!stricmp(irc_cmd->cmd, cmd)) {
+            ret = irc_cmd->func(client, from, argv, argc);
+            break;
+        }
+    }
+    if(!irc_cmd) {
+        event_raw(client, from, cmd, argv, argc);
+    } else if(!ret) {
+        fprintf(stderr,"PARSE ERROR: %s\n", cmd);
+    }
+}
+
+static USERLIST_CALLBACK(got_channel_userlist) {
+    struct ChanUser *chanuser = data;
+    event_join(chanuser);
+}
+
+static IRC_CMD(raw_001) {
+    client->flags |= SOCKET_FLAG_READY;
+    event_bot_ready(client);
+    return 1;
+}
+
+static IRC_CMD(raw_join) {
+    if(from == NULL || argc < 1) return 0;
+    struct UserNode *user = getUserByMask(from);
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(!chan && !(user->flags & USERFLAG_ISBOT)) return 0;
+    if(user == NULL) {
+        user = addUserMask(from);
+    }
+    if(chan == NULL) {
+        chan = addChannel(argv[0]);
+        //request member list
+        chan->chanbot = user;
+        struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot
+        get_userlist(chan, got_channel_userlist, chanuser);
+        putsock(client, "MODE %s", chan->name);
+        putsock(client, "MODE %s +b", chan->name);
+    } else if(!isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
+        struct ChanUser *chanuser = addChanUser(chan, user);
+        event_join(chanuser);
+    }
+    return 1;
+}
+
+static IRC_CMD(raw_part) {
+    if(from == NULL || argc < 1) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) return 0;
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(chan == NULL) return 0;
+    if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
+        struct ChanUser *chanuser = getChanUser(user, chan);
+        delChanUser(chanuser, 0); //we need to free the chanuser manually!
+        event_part(chanuser, (argc > 1 ? argv[1] : NULL));
+        free(chanuser);
+        if(chan->chanbot == user) {
+            //check if theres another bot in the channel - otherwise free it
+            checkChannelVisibility(chan);
+        }
+    }
+    if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
+        //remove the user
+        delUser(user, 1);
+    }
+    return 1;
+}
+
+static IRC_CMD(raw_quit) {
+    if(from == NULL || argc < 1) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) return 0;
+    delUser(user, 0); //a little bit crazy, but we want to delete the user on the channel's userlists - but not the users channel list
+    event_quit(user, argv[0]);
+    if(user->flags & USERFLAG_ISBOT) {
+        //check if there are other bots in the users channel - otherwise free them
+        struct ChanUser *chanuser, *next;
+        for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
+            next = getUserChannels(user, chanuser);
+            checkChannelVisibility(chanuser->chan);
+        }
+    }
+    delUser(user, 1); //now we fully free the user
+    return 1;
+}
+
+void bot_disconnect(struct ClientSocket *client) {
+    struct UserNode *user = client->user;
+    struct ChanUser *chanuser, *next;
+    delUser(user, 0);
+    event_quit(user, "disconnected");
+    for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
+        next = getUserChannels(user, chanuser);
+        checkChannelVisibility(chanuser->chan);
+        free(chanuser);
+    }
+    user->channel = NULL;
+}
+
+static IRC_CMD(raw_kick) {
+    if(from == NULL || argc < 3) return 0;
+    struct UserNode *user = getUserByMask(from);
+    struct UserNode *target = getUserByNick(argv[1]);
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(chan == NULL || target == NULL) return 0;
+    if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
+        if(user == NULL) {
+            user = createTempUser(from);
+            user->flags |= USERFLAG_ISTMPUSER;
+        }
+        struct ChanUser *chanuser = getChanUser(target, chan);
+        delChanUser(chanuser, 0); //we need to free the chanuser manually!
+        event_kick(user, chanuser, argv[1]);
+        free(chanuser);
+        if(target->flags & USERFLAG_ISBOT) {
+            //check if theres another bot in the channel - otherwise free it
+            checkChannelVisibility(chan);
+        }
+    }
+    if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) {
+        //remove the user
+        delUser(target, 1);
+    }
+    return 1;
+}
+
+static IRC_CMD(raw_topic) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    struct ChanNode *chan = getChanByName(argv[0]);
+    if(chan == NULL) return 0;
+    if(chan->chanbot != client->user) return 1; //just ignore it to prevent event duplicates
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    event_topic(user, chan, argv[1]);
+    strcpy(chan->topic, argv[1]);
+    return 1;
+}
+
+static IRC_CMD(raw_privmsg) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    if(argv[0][0] == '#') { //Channel message
+        struct ChanNode *chan = getChanByName(argv[0]);
+        if(chan && chan->chanbot == client->user) {
+            if(argv[1][0] == '\001') {
+                char *cmd = &argv[1][1];
+                char *text = strstr(cmd, " ");
+                if(text) {
+                    *text = '\0';
+                    text++;
+                    if(strlen(text) && text[strlen(text)-1] == '\001')
+                        text[strlen(text)-1] = '\0';
+                } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
+                    cmd[strlen(cmd)-1] = '\0';
+                event_chanctcp(user, chan, cmd, text);
+            } else
+                event_chanmsg(user, chan, argv[1]);
+        }
+    } else {
+        struct UserNode *target = getUserByNick(argv[0]);
+        if(target) {
+            if(argv[1][0] == '\001') {
+                char *cmd = &argv[1][1];
+                char *text = strstr(cmd, " ");
+                if(text) {
+                    *text = '\0';
+                    text++;
+                    if(strlen(text) && text[strlen(text)-1] == '\001')
+                        text[strlen(text)-1] = '\0';
+                } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
+                    cmd[strlen(cmd)-1] = '\0';
+                event_privctcp(user, target, cmd, text);
+            } else
+                event_privmsg(user, target, argv[1]);
+        }
+    }
+    return 1;
+}
+
+static IRC_CMD(raw_notice) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    if(argv[0][0] == '#') { //Channel notice
+        struct ChanNode *chan = getChanByName(argv[0]);
+        if(chan && chan->chanbot == client->user)
+            event_channotice(user, chan, argv[1]);
+    } else {
+        struct UserNode *target = getUserByNick(argv[0]);
+        if(target)
+            event_privnotice(user, target, argv[1]);
+    }
+    return 1;
+}
+
+static IRC_CMD(raw_nick) {
+    if(from == NULL || argc == 0) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) return 0;
+    event_nick(user, argv[0]);
+    renameUser(user, argv[0]);
+    return 1;
+}
+
+static IRC_CMD(raw_ping) {
+    if(argc == 0) return 0;
+    putsock(client, "PONG :%s", argv[0]);
+    return 1;
+}
+
+static IRC_CMD(raw_354) {
+    recv_whohandler_354(client, argv, argc);
+    return 1;
+}
+
+static IRC_CMD(raw_315) {
+    recv_whohandler_315(client, argv, argc);
+    return 1;
+}
+
+static IRC_CMD(raw_324) { //MODE LIST
+    //Watchcat #pktest +stnzN
+    if(from == NULL || argc < 3) return 0;
+    struct ChanNode *chan = getChanByName(argv[1]);
+    if(chan == NULL) return 0;
+    parseModes(chan->modes, argv[2], argv+3, argc-3);
+    return 1;
+}
+
+static IRC_CMD(raw_invite) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    event_invite(client, user, argv[1]);
+    return 1;
+}
+
+static IRC_CMD(raw_mode) {
+    if(from == NULL || argc < 2) return 0;
+    struct UserNode *user = getUserByMask(from);
+    if(user == NULL) {
+        user = createTempUser(from);
+        user->flags |= USERFLAG_ISTMPUSER;
+    }
+    if(argv[0][0] == '#') {
+        //ChannelMode
+        struct ChanNode *chan = getChanByName(argv[0]);
+        if(!chan) return 0;
+        if(chan->chanbot != client->user) return 1;
+        event_mode(user, chan, argv[1], argv+2, argc-2);
+        parseModes(chan->modes, argv[1], argv+2, argc-2);
+    } else {
+        //UserMode
+    }
+    return 1;
+}
+
+static IRC_CMD(raw_367) {
+    //Watchcat #pktest pk911!*@* TestBot!~bot@pktest.user.WebGamesNet 1315863279
+    struct ChanNode *chan = getChanByName(argv[1]);
+    if(!chan) return 0;
+    struct BanNode *ban;
+    while((ban = getMatchingChannelBan(chan, argv[2]))) {
+        removeChannelBan(ban);
+    }
+    addChannelBan(chan, argv[2]);
+    return 1;
+}
+
+void init_parser() {
+    //all the raws we receive...
+    register_irc_function("001", raw_001);
+    register_irc_function("324", raw_324);
+    register_irc_function("367", raw_367);
+    register_irc_function("INVITE", raw_invite);
+    register_irc_function("NOTICE", raw_notice);
+    register_irc_function("TOPIC", raw_topic);
+    register_irc_function("KICK", raw_kick);
+    register_irc_function("PART", raw_part);
+    register_irc_function("QUIT", raw_quit);
+    register_irc_function("JOIN", raw_join);
+    register_irc_function("MODE", raw_mode);
+    register_irc_function("NICK", raw_nick);
+    register_irc_function("354", raw_354);
+    register_irc_function("315", raw_315);
+    register_irc_function("PING", raw_ping);
+    register_irc_function("PRIVMSG", raw_privmsg);
+}
+
+void free_parser() {
+    struct irc_cmd *cmd, *next;
+    for(cmd = irc_commands; cmd; cmd = next) {
+        next = cmd->next;
+        free(cmd);
+    }
+}
+
+void reply(struct ClientSocket *client, struct UserNode *user, const char *text, ...) {
+    const char *reply_format = get_language_string(user, text);
+    if(reply_format == NULL)
+        reply_format = text;
+    loadUserSettings(user);
+    char formatBuf[MAXLEN];
+    sprintf(formatBuf, "%s %s :%s", ((user->flags & USERFLAG_REPLY_PRIVMSG) ? "PRIVMSG" : "NOTICE"), user->nick, reply_format);
+    va_list arg_list;
+    char sendBuf[MAXLEN];
+    int pos;
+    if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
+    sendBuf[0] = '\0';
+    va_start(arg_list, text);
+    pos = vsnprintf(sendBuf, MAXLEN - 2, formatBuf, arg_list);
+    va_end(arg_list);
+    if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
+    sendBuf[pos] = '\n';
+    sendBuf[pos+1] = '\0';
+    write_socket(client, sendBuf, pos+1);
+}
+
+char* merge_argv(char **argv, int start, int end) {
+    return merge_argv_char(argv, start, end, ' ');
+}
+
+char* merge_argv_char(char **argv, int start, int end, char seperator) {
+    int i;
+    char *p = NULL;
+    for(i = start; i < end; i++) {
+        p = argv[i];
+        while(*p) p++;
+        *p = seperator;
+    }
+    if(p) *p = '\0';
+    return argv[start];
+}
diff --git a/src/IRCParser.h b/src/IRCParser.h
new file mode 100644 (file)
index 0000000..ac2b376
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _IRCParser_h
+#define _IRCParser_h
+
+#include "main.h"
+
+struct ClientSocket;
+struct UserNode;
+
+#define IRC_CMD(NAME) int NAME(struct ClientSocket *client, UNUSED_ARG(const char *from), UNUSED_ARG(char **argv), UNUSED_ARG(unsigned int argc))
+typedef IRC_CMD(irc_cmd_t);
+
+struct irc_cmd {
+    char *cmd;
+    irc_cmd_t *func;
+    struct irc_cmd *next;
+};
+
+int parse_lines(struct ClientSocket *client, char *lines, int len);
+void bot_disconnect(struct ClientSocket *client);
+void init_parser();
+void free_parser();
+void reply(struct ClientSocket *client, struct UserNode *user, const char *text, ...);
+char* merge_argv(char **argv, int start, int end);
+char* merge_argv_char(char **argv, int start, int end, char seperator);
+
+#endif
\ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..10825e2
--- /dev/null
@@ -0,0 +1,119 @@
+CC = gcc
+SRC = EventLogger.c \
+      IRCEvents.c \
+      main.c \
+      ChanNode.c \
+      IRCParser.c \
+      ClientSocket.c \
+      UserNode.c \
+      ChanUser.c \
+      ModeNode.c \
+      BanNode.c \
+      WHOHandler.c \
+      modcmd.c \
+      mysqlConn.c \
+      lang.c \
+      HandleInfoHandler.c \
+      tools.c \
+      timeq.c \
+      DBHelper.c \
+      bots.c \
+      bot_NeonServ.c
+CMD = cmd_neonserv_access.c \
+      cmd_neonserv_addban.c \
+      cmd_neonserv_addtimeban.c \
+      cmd_neonserv_adduser.c \
+      cmd_neonserv_ban.c \
+      cmd_neonserv_bans.c \
+      cmd_neonserv_bind.c \
+      cmd_neonserv_chanservsync.c \
+      cmd_neonserv_clvl.c \
+      cmd_neonserv_command.c \
+      cmd_neonserv_csuspend.c \
+      cmd_neonserv_cunsuspend.c \
+      cmd_neonserv_delban.c \
+      cmd_neonserv_delme.c \
+      cmd_neonserv_deluser.c \
+      cmd_neonserv_deop.c \
+      cmd_neonserv_deopall.c \
+      cmd_neonserv_devoice.c \
+      cmd_neonserv_devoiceall.c \
+      cmd_neonserv_down.c \
+      cmd_neonserv_downall.c \
+      cmd_neonserv_emote.c \
+      cmd_neonserv_events.c \
+      cmd_neonserv_giveowner.c \
+      cmd_neonserv_god.c \
+      cmd_neonserv_help.c \
+      cmd_neonserv_invite.c \
+      cmd_neonserv_inviteme.c \
+      cmd_neonserv_kick.c \
+      cmd_neonserv_kickban.c \
+      cmd_neonserv_mdeluser.c \
+      cmd_neonserv_mode.c \
+      cmd_neonserv_move.c \
+      cmd_neonserv_myaccess.c \
+      cmd_neonserv_netinfo.c \
+      cmd_neonserv_notice.c \
+      cmd_neonserv_op.c \
+      cmd_neonserv_opall.c \
+      cmd_neonserv_oplog.c \
+      cmd_neonserv_peek.c \
+      cmd_neonserv_raw.c \
+      cmd_neonserv_recover.c \
+      cmd_neonserv_register.c \
+      cmd_neonserv_reloadlang.c \
+      cmd_neonserv_resync.c \
+      cmd_neonserv_say.c \
+      cmd_neonserv_search.c \
+      cmd_neonserv_set.c \
+      cmd_neonserv_setaccess.c \
+      cmd_neonserv_suspend.c \
+      cmd_neonserv_topic.c \
+      cmd_neonserv_trace.c \
+      cmd_neonserv_trim.c \
+      cmd_neonserv_unban.c \
+      cmd_neonserv_unbanall.c \
+      cmd_neonserv_unbanme.c \
+      cmd_neonserv_unbind.c \
+      cmd_neonserv_unregister.c \
+      cmd_neonserv_unsuspend.c \
+      cmd_neonserv_up.c \
+      cmd_neonserv_upall.c \
+      cmd_neonserv_users.c \
+      cmd_neonserv_uset.c \
+      cmd_neonserv_version.c \
+      cmd_neonserv_voice.c \
+      cmd_neonserv_voiceall.c \
+      cmd_neonserv_wipeinfo.c
+CMD_DEPS = main.h modcmd.h IRCParser.h UserNode.h ChanNode.h ChanUser.h ModeNode.h \
+           ClientSocket.h mysqlConn.h lang.h HandleInfoHandler.h WHOHandler.h DBHelper.h \
+           tools.h timeq.h version.h EventLogger.h bot_NeonServ.h IRCEvents.h BanNode.h
+OBJS = ${SRC:%.c=%.o} ${CMD:%.c=%.o}
+CFLAGS=-g -O2 -Wall -Wshadow -Werror
+LIBS=-I. -I/usr/include/mysql
+LINK=-lmysqlclient
+
+all: $(OBJS)
+
+install: $(OBJS)
+       chmod +x version.sh
+       ./version.sh
+       $(CC) $(LIBS) -c version.c $(CFLAGS)
+       $(CC) $(LIBS) -o neonserv $(OBJS) version.o $(CFLAGS) $(LINK)
+
+%.o: %.c
+       $(CC) $(LIBS) -c $< $(CFLAGS)
+
+clean:
+       rm $(OBJS) version.o
+
+depend: $(SRC)
+       mv Makefile Makefile.bak
+       grep -A1 -B10000 '^# DEPENDINGS' Makefile.bak > Makefile
+       $(CC) $(CFLAGS) -MM $(LIBS) $(SRC) >> Makefile
+       rm Makefile.bak
+
+# DEPENDINGS -- generated by make depend
+
+
diff --git a/src/ModeNode.c b/src/ModeNode.c
new file mode 100644 (file)
index 0000000..0afe6f2
--- /dev/null
@@ -0,0 +1,342 @@
+#include "ModeNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "UserNode.h"
+#include "BanNode.h"
+
+static int modes_with_strarg, modes_with_intarg, modes_count;
+
+unsigned int valid_modes[] = { /* Thats our mode list :P */
+    1,  'b', CHANNEL_MODE_TYPE_A,
+    2,  'o', CHANNEL_MODE_TYPE_A,
+    3,  'v', CHANNEL_MODE_TYPE_A,
+    4,  'k', CHANNEL_MODE_TYPE_B | CHANNEL_MODE_VALUE_STRING | CHANNEL_MODE_KEY,
+    5,  'a', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
+    6,  'l', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_INTEGER,
+    7,  'f', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
+    8,  'F', CHANNEL_MODE_TYPE_C | CHANNEL_MODE_VALUE_STRING,
+    9,  'c', CHANNEL_MODE_TYPE_D,
+    10, 'C', CHANNEL_MODE_TYPE_D,
+    11, 'i', CHANNEL_MODE_TYPE_D,
+    12, 'm', CHANNEL_MODE_TYPE_D,
+    13, 'M', CHANNEL_MODE_TYPE_D,
+    14, 'n', CHANNEL_MODE_TYPE_D,
+    15, 'N', CHANNEL_MODE_TYPE_D,
+    16, 'p', CHANNEL_MODE_TYPE_D,
+    17, 'r', CHANNEL_MODE_TYPE_D,
+    18, 's', CHANNEL_MODE_TYPE_D,
+    19, 't', CHANNEL_MODE_TYPE_D,
+    20, 'u', CHANNEL_MODE_TYPE_D,
+    21, 'D', CHANNEL_MODE_TYPE_D,
+    22, 'd', CHANNEL_MODE_TYPE_D,
+    23, 'R', CHANNEL_MODE_TYPE_D,
+    24, 'z', CHANNEL_MODE_TYPE_D,
+//  ^ maximum is 32!!!
+    0x00, 0x00, 0x00
+};
+
+void init_ModeNode() {
+    unsigned int *mode, flag = 1;
+    modes_with_strarg = 0;
+    modes_with_intarg = 0;
+    modes_count = 0;
+    for (mode = valid_modes; mode[1]; mode += 3) {
+        if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING) {
+            mode[2] |= modes_with_strarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
+            modes_with_strarg++;
+        }
+        if((mode[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER) {
+            mode[2] |= modes_with_intarg << CHANNEL_MODE_VALUE_INDEX_SHIFT;
+            modes_with_intarg++;
+        }
+        modes_count++;
+        mode[0] = flag;
+        flag = flag << 1;
+    }
+}
+
+struct ModeNode *createModeNode(struct ChanNode *chan) {
+    struct ModeNode *modes = malloc(sizeof(*modes));
+    if (!modes)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    modes->chan = chan;
+    modes->modes = 0;
+    modes->allmodes = 0;
+    modes->mode_str_args = calloc(modes_with_strarg, sizeof(char*));
+    modes->mode_int_args = calloc(modes_with_intarg, sizeof(int));
+    return modes;
+}
+
+void freeModeNode(struct ModeNode *modes) {
+    int i;
+    for(i = 0; i < modes_with_strarg; i++) {
+        if(modes->mode_str_args[i])
+            free(modes->mode_str_args[i]);
+    }
+    free(modes->mode_str_args);
+    free(modes->mode_int_args);
+    free(modes);
+}
+
+static unsigned int* getModeOptions(char mode) {
+    unsigned int *cmode;
+    for (cmode = valid_modes; cmode[1]; cmode += 3) {
+        if(cmode[1] == mode)
+            return cmode;
+    }
+    return NULL;
+}
+
+int isModeSet(struct ModeNode* modes, char modeChar) {
+    unsigned int *modeOpt = getModeOptions(modeChar);
+    return (modes->modes & modeOpt[0]);
+}
+
+int isModeAffected(struct ModeNode* modes, char modeChar) {
+    unsigned int *modeOpt = getModeOptions(modeChar);
+    return (modes->allmodes & modeOpt[0]);
+}
+
+void* getModeValue(struct ModeNode* modes, char modeChar) {
+    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+    unsigned int *modeOpt = getModeOptions(modeChar);
+    if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING)
+        return modes->mode_str_args[MODE_VALUE_INDEX];
+    if((modeOpt[2] & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_INTEGER)
+        return &modes->mode_int_args[MODE_VALUE_INDEX];
+    return NULL;
+    #undef MODE_VALUE_INDEX
+}
+
+unsigned int getModeType(struct ModeNode* modes, char modeChar) {
+    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+    unsigned int *modeOpt = getModeOptions(modeChar);
+    if(!modeOpt) return 0;
+    return modeOpt[2];
+    #undef MODE_VALUE_INDEX
+}
+
+static void parseModesUserPriv(struct ModeNode* modes, unsigned char flag, int add, char *nick) {
+    if(modes->chan == NULL) return;
+    struct UserNode *user = getUserByNick(nick);
+    if(user == NULL) return;
+    struct ChanUser *chanuser = getChanUser(user, modes->chan);
+    if(chanuser == NULL) return;
+    if(add)
+        chanuser->flags |= flag;
+    else
+        chanuser->flags &= ~flag;
+}
+
+static void parseModesBan(struct ModeNode* modes, int add, char *mask) {
+    if(modes->chan == NULL) return;
+    if(add)
+        addChannelBan(modes->chan, mask);
+    else
+        removeChannelBanMask(modes->chan, mask);
+}
+
+void parseModes(struct ModeNode* modes, char *modeStr, char **argv, int argc) {
+    int i, argpos = 0, add = 1;
+    #define MODE_TYPE (modeOpt[2] & CHANNEL_MODE_TYPE)
+    #define MODE_VALUE (modeOpt[2] & CHANNEL_MODE_VALUE)
+    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+    unsigned int *modeOpt;
+    for(i = 0; i < strlen(modeStr); i++) {
+        if(modeStr[i] == '+') {
+            add = 1;
+            continue;
+        }
+        if(modeStr[i] == '-') {
+            add = 0;
+            continue;
+        }
+        modeOpt = getModeOptions(modeStr[i]);
+        if(!modeOpt) continue; // unknown mode?
+        if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
+            if(argpos == argc) continue;
+            //special mode ;)
+            switch(modeStr[i]) {
+                case 'o':
+                    parseModesUserPriv(modes, CHANUSERFLAG_OPPED, add, argv[argpos]);
+                    break;
+                case 'v':
+                    parseModesUserPriv(modes, CHANUSERFLAG_VOICED, add, argv[argpos]);
+                    break;
+                case 'b':
+                    parseModesBan(modes, add, argv[argpos]);
+                    break;
+                default:
+                    //we have an unknown TYPE_A mode???
+                    break;
+            }
+            argpos++;
+            continue;
+        }
+        if(add) {
+            if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
+                if(argpos == argc) continue;
+                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+                    if(modes->mode_str_args[MODE_VALUE_INDEX])
+                        free(modes->mode_str_args[MODE_VALUE_INDEX]);
+                    modes->mode_str_args[MODE_VALUE_INDEX] = strdup(argv[argpos++]);
+                } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                    modes->mode_int_args[MODE_VALUE_INDEX] = atoi(argv[argpos++]);
+                else
+                    argpos++; //we simply don't know what to do with the argument...
+            }
+            modes->modes |= modeOpt[0];
+            modes->allmodes |= modeOpt[0];
+        } else {
+            modes->modes &= ~modeOpt[0];
+            modes->allmodes |= modeOpt[0];
+            if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
+                if(argpos == argc) continue;
+                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+                    free(modes->mode_str_args[MODE_VALUE_INDEX]);
+                    modes->mode_str_args[MODE_VALUE_INDEX] = NULL;
+                } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                    modes->mode_int_args[MODE_VALUE_INDEX] = 0;
+                argpos++; //we don't need the argument when unsetting a mode...
+            }
+        }
+    }
+    #undef MODE_TYPE
+    #undef MODE_VALUE
+    #undef MODE_VALUE_INDEX
+}
+
+void parseModeString(struct ModeNode* modes, char *modeStr) {
+    int argc = 0;
+    char *args[modes_count+1];
+    char *a, *b = modeStr;
+    do {
+        a = strstr(b, " ");
+        if(a) *a = '\0';
+        args[argc++] = b;
+        if(a) b = a+1;
+    } while(a);
+    parseModes(modes, args[0], args+1, argc-1);
+}
+
+int parseMode(struct ModeNode* modes, int add, char mode, char *param) {
+    #define MODE_TYPE (modeOpt[2] & CHANNEL_MODE_TYPE)
+    #define MODE_VALUE (modeOpt[2] & CHANNEL_MODE_VALUE)
+    #define MODE_VALUE_INDEX (modeOpt[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+    unsigned int *modeOpt = getModeOptions(mode);
+    if(!modeOpt) return 0;
+    if(MODE_TYPE == CHANNEL_MODE_TYPE_A) {
+        if(!param) return 0;
+        //special mode ;)
+        switch(mode) {
+            case 'o':
+                parseModesUserPriv(modes, CHANUSERFLAG_OPPED, add, param);
+                break;
+            case 'v':
+                parseModesUserPriv(modes, CHANUSERFLAG_VOICED, add, param);
+                break;
+            case 'b':
+                parseModesBan(modes, add, param);
+                break;
+            default:
+                return 0; //we have an unknown TYPE_A mode???
+        }
+    }
+    if(add) {
+        if(MODE_TYPE != CHANNEL_MODE_TYPE_D) { //all other types take parameters when set
+            if(!param) return 0;
+            if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+                if(modes->mode_str_args[MODE_VALUE_INDEX])
+                    free(modes->mode_str_args[MODE_VALUE_INDEX]);
+                modes->mode_str_args[MODE_VALUE_INDEX] = strdup(param);
+            } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                modes->mode_int_args[MODE_VALUE_INDEX] = atoi(param);
+        }
+        modes->modes |= modeOpt[0];
+        modes->allmodes |= modeOpt[0];
+    } else {
+        modes->modes &= ~modeOpt[0];
+        modes->allmodes |= modeOpt[0];
+        if(MODE_TYPE == CHANNEL_MODE_TYPE_B) {
+            if(!param) return 0;
+            if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING) {
+                free(modes->mode_str_args[MODE_VALUE_INDEX]);
+                modes->mode_str_args[MODE_VALUE_INDEX] = NULL;
+            } else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                modes->mode_int_args[MODE_VALUE_INDEX] = 0;
+        }
+    }
+    #undef MODE_TYPE
+    #undef MODE_VALUE
+    #undef MODE_VALUE_INDEX
+    return 1;
+}
+
+void getModeString(struct ModeNode* modes, char *modesStr) {
+    #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
+    #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
+    #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+    char paramStr[MAXLEN];
+    modesStr[0] = '+';
+    unsigned int *mode;
+    int modePos = 1;
+    int paramPos = 0;
+    for (mode = valid_modes; mode[1]; mode += 3) {
+        if(modes->modes & mode[0]) {
+            modesStr[modePos++] = (char) mode[1];
+            if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
+                if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
+                    paramPos += sprintf(paramStr + paramPos, " %s", modes->mode_str_args[MODE_VALUE_INDEX]);
+                else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                    paramPos += sprintf(paramStr + paramPos, " %d", modes->mode_int_args[MODE_VALUE_INDEX]);
+            }
+        }
+    }
+    paramStr[paramPos] = '\0';
+    strcpy(modesStr + modePos, paramStr);
+    #undef MODE_TYPE
+    #undef MODE_VALUE
+    #undef MODE_VALUE_INDEX
+}
+
+void getFullModeString(struct ModeNode* modes, char *modesStr) {
+    #define MODE_TYPE (mode[2] & CHANNEL_MODE_TYPE)
+    #define MODE_VALUE (mode[2] & CHANNEL_MODE_VALUE)
+    #define MODE_VALUE_INDEX (mode[2] & CHANNEL_MODE_VALUE_INDEX_MASK) >> CHANNEL_MODE_VALUE_INDEX_SHIFT
+    char addMode[modes_count+1];
+    int addModePos = 0;
+    char addParams[MAXLEN];
+    addParams[0] = '\0';
+    int addParamsPos = 0;
+    char delMode[modes_count+1];
+    int delModePos = 0;
+    unsigned int *mode;
+    for (mode = valid_modes; mode[1]; mode += 3) {
+        if(modes->allmodes & mode[0]) {
+            if(modes->modes & mode[0]) {
+                addMode[addModePos++] = (char) mode[1];
+                if(MODE_TYPE != CHANNEL_MODE_TYPE_D) {
+                    if(MODE_VALUE == CHANNEL_MODE_VALUE_STRING)
+                        addParamsPos += sprintf(addParams + addParamsPos, " %s", modes->mode_str_args[MODE_VALUE_INDEX]);
+                    else if(MODE_VALUE == CHANNEL_MODE_VALUE_INTEGER)
+                        addParamsPos += sprintf(addParams + addParamsPos, " %d", modes->mode_int_args[MODE_VALUE_INDEX]);
+                }
+            } else {
+                delMode[delModePos++] = (char) mode[1];
+            }
+        }
+    }
+    addMode[addModePos] = '\0';
+    delMode[delModePos] = '\0';
+    addParams[addParamsPos] = '\0';
+    sprintf(modesStr, "%s%s%s%s%s", (addModePos ? "+" : ""), addMode, (delModePos ? "-" : ""), delMode, addParams);
+    if(*modesStr == '\0') {
+        sprintf(modesStr, "+");
+    }
+    #undef MODE_TYPE
+    #undef MODE_VALUE
+    #undef MODE_VALUE_INDEX
+}
diff --git a/src/ModeNode.h b/src/ModeNode.h
new file mode 100644 (file)
index 0000000..6d2d5d9
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _ModeNode_h
+#define _ModeNode_h
+#include "main.h"
+
+struct ChanNode;
+
+//Types: http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
+#define CHANNEL_MODE_TYPE_A        0x01 /* ... special (addresses or users) ... */
+#define CHANNEL_MODE_TYPE_B        0x02 /* These modes always take a parameter. */
+#define CHANNEL_MODE_TYPE_C        0x03 /* These modes take a parameter only when set. */
+#define CHANNEL_MODE_TYPE_D        0x04 /* These modes never take a parameter. */
+#define CHANNEL_MODE_TYPE          0x07 /* bit mask to get the type */
+
+#define CHANNEL_MODE_VALUE_STRING  0x10
+#define CHANNEL_MODE_VALUE_INTEGER 0x20
+#define CHANNEL_MODE_VALUE         0x30 /* bit mask to get the value */
+
+#define CHANNEL_MODE_KEY           0x40 /* mode is a key - automatically add the current key as parameter on unset */
+
+#define CHANNEL_MODE_VALUE_INDEX_SHIFT 8
+#define CHANNEL_MODE_VALUE_INDEX_MASK  (0xff << CHANNEL_MODE_VALUE_INDEX_SHIFT) /* this "bitrange" is reserved for storing the array indexes of the mode values */
+
+struct ModeNode {
+    struct ChanNode *chan;
+    unsigned int modes;
+    unsigned int allmodes;
+    char **mode_str_args;
+    int *mode_int_args;
+};
+
+extern unsigned int valid_modes[];
+
+void init_ModeNode();
+struct ModeNode *createModeNode(struct ChanNode *chan);
+void freeModeNode(struct ModeNode *modes);
+int isModeSet(struct ModeNode* modes, char modeChar);
+int isModeAffected(struct ModeNode* modes, char modeChar);
+void* getModeValue(struct ModeNode* modes, char modeChar);
+unsigned int getModeType(struct ModeNode* modes, char modeChar);
+void parseModes(struct ModeNode* modes, char *modeStr, char **argv, int argc);
+void parseModeString(struct ModeNode* modes, char *modeStr);
+int parseMode(struct ModeNode* modes, int add, char mode, char *param);
+void getModeString(struct ModeNode* modes, char *modesStr);
+void getFullModeString(struct ModeNode* modes, char *modesStr);
+
+#endif
\ No newline at end of file
diff --git a/src/UserNode.c b/src/UserNode.c
new file mode 100644 (file)
index 0000000..2ced2eb
--- /dev/null
@@ -0,0 +1,331 @@
+#include "UserNode.h"
+#include "ChanUser.h"
+#include "tools.h"
+
+static struct UserNode **userList;
+
+void init_UserNode() {
+    userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
+}
+
+void free_UserNode() {
+    //kamikaze free all users
+    //chanusers will be destroyed in free_ChanNode()
+    int i;
+    struct UserNode *user, *next;
+    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
+        for(user = userList[i]; user; user = next) {
+            next = user->next;
+            free(user);
+        }
+    }
+    free(userList);
+}
+
+int is_valid_nick(const char *nick) {
+    unsigned int i;
+    //first char must be one of: a-zA-Z{|}~[\]^_`
+    if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
+        return 0;
+    //all other chars must be one of: a-zA-Z0-9{|}~[\]^_`
+    for (i = 0; nick[i]; ++i)
+        if (!strchr(VALID_NICK_CHARS, nick[i]))
+            return 0;
+    if (strlen(nick) > NICKLEN)
+        return 0;
+    return 1;
+}
+
+static int get_nicklist_entry(int nick) {
+    int i;
+    char *valid_chars = VALID_NICK_CHARS_FIRST;
+    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
+        if(valid_chars[i] == nick)
+            return i;
+    }
+    return -1; //ERROR!
+}
+
+struct UserNode* getUserByNick(const char *nick) { //case sensitive
+    int userListIndex = get_nicklist_entry(*nick);
+    if(userListIndex == -1 || userList[userListIndex] == NULL)
+        return NULL;
+    struct UserNode *user;
+    for(user = userList[userListIndex]; user; user = user->next) {
+        if(!stricmp(nick, user->nick))
+            return user;
+    }
+    return NULL;
+}
+
+struct UserNode* getUserByMask(const char *mask) { //case sensitive
+    char cmask[strlen(mask)+1];
+    strcpy(cmask, mask);
+    int i;
+    struct UserNode *user = NULL;
+    for(i = 0; i < strlen(mask); i++) {
+        if(cmask[i] == '!') {
+            cmask[i] = 0;
+            user = getUserByNick(&cmask[0]);
+            return user;
+        } else if(cmask[i] == '.') {
+            //it's a server
+            return NULL;
+        }
+    }
+    return NULL;
+}
+
+struct UserNode* searchUserByNick(const char *nick) { //case insensitive
+    if(!isalpha(*nick)) 
+        return getUserByNick(nick);
+
+    int userListIndex;
+    struct UserNode *user;
+
+    //search in the lower case "section"
+    userListIndex = get_nicklist_entry(tolower(*nick));
+    if(userListIndex != -1 && userList[userListIndex] != NULL) {
+        for(user = userList[userListIndex]; user; user = user->next) {
+            if(!stricmp(nick, user->nick))
+                return user;
+        }
+    }
+    //search in the upper case "section"
+    userListIndex = get_nicklist_entry(toupper(*nick));
+    if(userListIndex != -1 && userList[userListIndex] != NULL) {
+        for(user = userList[userListIndex]; user; user = user->next) {
+            if(!stricmp(nick, user->nick))
+                return user;
+        }
+    }
+    return NULL;
+}
+
+int countUsersWithHost(char *host) {
+    int i, count = 0;
+    struct UserNode *user;
+    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
+        for(user = userList[i]; user; user = user->next) {
+            if(!strcmp(user->host, host)) {
+                count++;
+            }
+        }
+    }
+    return count;
+}
+
+char *getAuthFakehost(char *auth) {
+    int i;
+    struct UserNode *user;
+    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
+        for(user = userList[i]; user; user = user->next) {
+            if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
+                return user->host;
+            }
+        }
+    }
+    return NULL;
+}
+
+struct UserNode* getAllUsers(struct UserNode *last) {
+    if(last == NULL || last->next == NULL) {
+        int cindex;
+        if(last == NULL)
+            cindex = 0;
+        else
+            cindex = get_nicklist_entry(last->nick[0]) + 1;
+        while(userList[cindex] == NULL && cindex <= VALID_NICK_CHARS_FIRST_LEN)
+            cindex++;
+        if(cindex > VALID_NICK_CHARS_FIRST_LEN) return NULL;
+        return userList[cindex];
+    } else
+        return last->next;
+}
+
+int getUserCount() {
+    int i, count = 0;
+    struct UserNode *user;
+    for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
+        for(user = userList[i]; user; user = user->next) {
+            count++;
+        }
+    }
+    return count;
+}
+
+struct UserNode* addUser(const char *nick) {
+    int userListIndex = get_nicklist_entry(*nick);
+    if(userListIndex == -1 || !is_valid_nick(nick))
+        return NULL;
+    struct UserNode *user = malloc(sizeof(*user));
+    if (!user)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    strcpy(user->nick, nick);
+    user->created = time(0);
+    user->ident[0] = 0;
+    user->host[0] = 0;
+    user->realname[0] = 0;
+    user->flags = 0;
+    user->channel = NULL;
+    user->next = userList[userListIndex];
+    userList[userListIndex] = user;
+    return user;
+}
+
+struct UserNode* addUserMask(const char *mask) {
+    char cmask[strlen(mask)+1];
+    strcpy(cmask, mask);
+    int i, ii = 0;
+    struct UserNode *user = NULL;
+    for(i = 0; i < strlen(mask)+1; i++) {
+        if(cmask[i] == '!') {
+            cmask[i] = 0;
+            user = addUser(cmask);
+            if(user == NULL) return NULL;
+            ii = i+1;
+        } else if(cmask[i] == '.' && !user) {
+            //it's a server
+            return NULL;
+        } else if(cmask[i] == '@') {
+            if(user == NULL) return NULL;
+            cmask[i] = 0;
+            strcpy(user->ident, &cmask[ii]);
+            ii = i+1;
+        } else if(cmask[i] == '\0') {
+            if(user == NULL) return NULL;
+            strcpy(user->host, &cmask[ii]);
+        }
+    }
+    return user;
+}
+
+struct UserNode* createTempUser(const char *mask) {
+    //note: it could also be a server we have to create a temponary user for...
+    char cmask[strlen(mask)+1];
+    strcpy(cmask, mask);
+    int i, ii = 0;
+    struct UserNode *user = NULL;
+    for(i = 0; i < strlen(mask)+1; i++) {
+        if(cmask[i] == '!') {
+            cmask[i] = 0;
+            user = malloc(sizeof(*user));
+            if (!user)
+            {
+                perror("malloc() failed");
+                return NULL;
+            }
+            strcpy(user->nick, cmask);
+            user->created = time(0);
+            user->ident[0] = 0;
+            user->host[0] = 0;
+            user->realname[0] = 0;
+            user->flags = 0;
+            user->channel = NULL;
+            ii = i+1;
+        } else if(cmask[i] == '.' && !user) {
+            //it's a server
+            user = malloc(sizeof(*user));
+            if (!user)
+            {
+                perror("malloc() failed");
+                return NULL;
+            }
+            strcpy(user->host, cmask);
+            user->created = time(0);
+            user->ident[0] = 0;
+            user->host[0] = 0;
+            user->realname[0] = 0;
+            user->flags = USERFLAG_ISSERVER;
+            user->channel = NULL;
+            return user;
+        } else if(cmask[i] == '@') {
+            if(user == NULL) return NULL;
+            cmask[i] = 0;
+            strcpy(user->ident, &cmask[ii]);
+            ii = i+1;
+        } else if(cmask[i] == '\0') {
+            if(user == NULL) {
+                //nick only
+                user = malloc(sizeof(*user));
+                if (!user)
+                {
+                    perror("malloc() failed");
+                    return NULL;
+                }
+                strcpy(user->nick, cmask);
+                user->created = time(0);
+                user->ident[0] = 0;
+                user->host[0] = 0;
+                user->realname[0] = 0;
+                user->flags = 0;
+                user->channel = NULL;
+                return user;
+            }
+            strcpy(user->host, &cmask[ii]);
+        }
+    }
+    return user;
+}
+
+int renameUser(struct UserNode* user, const char *new_nick) {
+    if(!is_valid_nick(new_nick))
+        return 0;
+    if(user->nick[0] == *new_nick) {
+        strcpy(user->nick, new_nick);
+        return 1;
+    }
+    int userListIndex = get_nicklist_entry(*new_nick);
+    delUser(user, 0);
+    strcpy(user->nick, new_nick);
+    user->next = userList[userListIndex];
+    userList[userListIndex] = user;
+    return 1;
+}
+
+void delUser(struct UserNode* user, int freeUser) {
+    int userListIndex = get_nicklist_entry(user->nick[0]);
+    if(userListIndex == -1) return;
+    struct UserNode *cuser, *last_user = NULL;
+    for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
+        if(cuser == user) {
+            if(last_user)
+                last_user->next = user->next;
+            else
+                userList[userListIndex] = user->next;
+            break;
+        } else
+            last_user = cuser;
+    }
+    if(user->channel) {
+        struct ChanUser *chanUser, *next;
+        for(chanUser = user->channel; chanUser; chanUser = next) {
+            next = chanUser->next_chan;
+            removeChanUserFromLists(chanUser, 1, 0, freeUser);
+        }
+    }
+    if(freeUser)
+        free(user);
+    else
+        user->next = NULL;
+}
+
+void clearTempUsers() {
+    int userListIndex = TEMPUSER_LIST_INDEX;
+    struct UserNode *cuser, *last_user = NULL, *next;
+    time_t now = time(0);
+    for(cuser = userList[userListIndex]; cuser; cuser = next) {
+        next = cuser->next;
+        if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
+            if(last_user)
+                last_user->next = cuser->next;
+            else
+                userList[userListIndex] = cuser->next;
+            break;
+        } else
+            last_user = cuser;
+    }
+}
diff --git a/src/UserNode.h b/src/UserNode.h
new file mode 100644 (file)
index 0000000..f905437
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _UserNode_h
+#define _UserNode_h
+#include "main.h"
+
+#define USERFLAG_ISBOT              0x0001
+#define USERFLAG_ISAUTHED           0x0002
+#define USERFLAG_ISIRCOP            0x0004
+#define USERFLAG_ISTMPUSER          0x0008
+#define USERFLAG_ISSERVER           0x0010
+#define USERFLAG_FREETMPUSER        0x0020
+#define USERFLAG_LOADED_SETTINGS    0x0040
+#define USERFLAG_REPLY_PRIVMSG      0x0080
+#define USERFLAG_GOD_MODE           0x0100
+
+#define USERFLAG_SCRIPTFLAG1        0x40000000
+#define USERFLAG_SCRIPTFLAG2        0x80000000
+
+struct ChanUser;
+struct language;
+
+struct UserNode {
+    char nick[NICKLEN+1];
+    char ident[USERLEN+1];
+    char host[HOSTLEN+1];
+    char realname[REALLEN+1];
+    char auth[AUTHLEN+1];
+    unsigned int flags;
+    time_t created;
+    struct ChanUser *channel;
+    struct language *language;
+    
+    struct UserNode *next;
+};
+
+#define isNetworkService(USER) (USER->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP))
+
+void init_UserNode();
+void free_UserNode();
+int is_valid_nick(const char *nick);
+struct UserNode* getUserByNick(const char *nick);
+struct UserNode* getUserByMask(const char *mask);
+int countUsersWithHost(char *host);
+char *getAuthFakehost(char *auth);
+struct UserNode* searchUserByNick(const char *nick);
+struct UserNode* getAllUsers(struct UserNode *last);
+int getUserCount();
+struct UserNode* addUser(const char *nick);
+struct UserNode* addUserMask(const char *mask);
+struct UserNode* createTempUser(const char *mask);
+int renameUser(struct UserNode* user, const char *new_nick);
+void delUser(struct UserNode* user, int freeUser);
+void clearTempUsers();
+
+#endif
diff --git a/src/WHOHandler.c b/src/WHOHandler.c
new file mode 100644 (file)
index 0000000..f924e46
--- /dev/null
@@ -0,0 +1,225 @@
+
+#include "WHOHandler.h"
+#include "ChanNode.h"
+#include "UserNode.h"
+#include "ChanUser.h"
+#include "ClientSocket.h"
+
+#define WHOQUEUETYPE_ISONQUEUE 0x01
+#define WHOQUEUETYPE_USERLIST  0x02
+#define WHOQUEUETYPE_USERAUTH  0x04
+#define WHOQUEUETYPE_CHECKTYPE 0x07
+#define WHOQUEUETYPE_FOUND     0x08
+
+struct WHOQueueEntry {
+    char type;
+    struct ClientSocket *client;
+    struct ChanNode *chan;
+    struct UserNode *user;
+    struct WHOQueueEntry *next;
+    void *callback;
+    void *data;
+};
+
+static struct WHOQueueEntry *first_entry = NULL, *last_entry = NULL;
+
+static struct WHOQueueEntry* addWHOQueueEntry(struct ClientSocket *client) {
+    struct WHOQueueEntry *entry = malloc(sizeof(*entry));
+    if (!entry)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    entry->next = NULL;
+    entry->client = client;
+    if(last_entry) {
+        last_entry->next = entry;
+        last_entry = entry;
+    } else {
+        last_entry = entry;
+        first_entry = entry;
+    }
+    return entry;
+}
+
+static struct WHOQueueEntry* getNextWHOQueueEntry(struct ClientSocket *client, int freeEntry) {
+    if(!first_entry) return NULL;
+    struct WHOQueueEntry *entry;
+    for(entry = first_entry; entry; entry = entry->next) {
+        if(entry->client == client)
+            break;
+    }
+    if(entry == NULL) return NULL;
+    if(freeEntry) {
+        if(entry == first_entry)
+            first_entry = entry->next;
+        if(entry == last_entry) {
+            struct WHOQueueEntry *last;
+            for(last = first_entry; last; last = last->next)
+                if(last->next == NULL) break;
+            last_entry = last;
+        }
+    }
+    return entry;
+}
+
+void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data) {
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(isUserOnChan(bot->user, chan))
+            break;
+    }
+    if(bot == NULL) return;
+    struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
+    entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
+    entry->chan = chan;
+    entry->callback = callback;
+    entry->data = data;
+    //WHO ".$channel->getName().",".$id." d%tuhnaf,".$id
+    putsock(bot, "WHO %s,%d %%tuhnaf,%d", chan->name, entry->type, entry->type);
+}
+
+void get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t callback, void *data) {
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(isUserOnChan(bot->user, chan))
+            break;
+    }
+    if(bot == NULL) return;
+    struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
+    entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
+    entry->chan = chan;
+    entry->callback = callback;
+    entry->data = data;
+    //WHO ".$channel->getName().",".$id." d%tuhnaf,".$id
+    putsock(bot, "WHO %s,%d d%%tuhnaf,%d", chan->name, entry->type, entry->type);
+}
+
+void get_userauth(struct UserNode *user, userauth_callback_t callback, void *data) {
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->flags & SOCKET_FLAG_PREFERRED)
+            break;
+    }
+    if(bot == NULL) bot = getBots(SOCKET_FLAG_READY, NULL);
+    struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
+    entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERAUTH;
+    entry->user = user;
+    entry->callback = callback;
+    entry->data = data;
+    //WHO ".$user->getNick().",".$id." %tuhna,".$id
+    putsock(bot, "WHO %s,%d %%tuhna,%d", user->nick, entry->type, entry->type);
+}
+
+void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc) {
+    int i;
+    if(argc < 2) return;
+    int type = atoi(argv[1]);
+    if(!(type & WHOQUEUETYPE_ISONQUEUE)) return;
+    struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, 0);
+    if(entry == NULL || (entry->type & WHOQUEUETYPE_CHECKTYPE) != (type & WHOQUEUETYPE_CHECKTYPE)) return;
+    if(type & WHOQUEUETYPE_USERLIST) {
+        if(argc < 7) return;
+        //:OGN2.OnlineGamesNet.net 354 skynet 1 pk910 2001:41d0:2:1d3b::babe skynet H@ pk910
+        struct ChanNode *chan = entry->chan;
+        //add the user toe the channel if he isn't added, yet and update its user data
+        //parse flags
+        int userflags = 0;
+        int chanuserflags = 0;
+        for(i = 0; i < strlen(argv[5]); i++) {
+            switch (argv[5][i]) {
+                case '@':
+                    chanuserflags |= CHANUSERFLAG_OPPED;
+                    break;
+                case '+':
+                    chanuserflags |= CHANUSERFLAG_VOICED;
+                    break;
+                case '*':
+                    userflags |= USERFLAG_ISIRCOP;
+                    break;
+                case '<':
+                    chanuserflags |= CHANUSERFLAG_INVISIBLE;
+                    break;
+                default:
+                    break;
+            }
+        }
+        
+        struct UserNode *user;
+        if(chanuserflags & CHANUSERFLAG_INVISIBLE) {
+            user = createTempUser(argv[4]);
+            user->flags |= USERFLAG_ISTMPUSER;
+            chan->flags |= CHANFLAG_HAVE_INVISIBLES;
+            struct ChanUser *chanuser = addInvisibleChanUser(chan, user);
+            chanuser->flags = (chanuser->flags & ~CHANUSERFLAG_OPPED_OR_VOICED) | chanuserflags;
+        } else {
+            user = getUserByNick(argv[4]);
+            if(user == NULL) {
+                user = addUser(argv[4]);
+            }
+            if(!isUserOnChan(user, chan)) {
+                struct ChanUser *chanuser = addChanUser(chan, user);
+                chanuser->flags = (chanuser->flags & ~CHANUSERFLAG_OPPED_OR_VOICED) | chanuserflags;
+            }
+        }
+        user->flags = (user->flags & ~USERFLAG_ISIRCOP) | userflags;
+        if(!*user->ident)
+            strcpy(user->ident, argv[2]);
+        if(!*user->host)
+            strcpy(user->host, argv[3]);
+        if(!(user->flags & USERFLAG_ISAUTHED) && strcmp(argv[6], "0")) {
+            strcpy(user->auth, argv[6]);
+            user->flags |= USERFLAG_ISAUTHED;
+        }
+    } else if(type & WHOQUEUETYPE_USERAUTH) {
+        //:OGN2.OnlineGamesNet.net 354 Skynet 1 pk910 2001:41d0:2:1d3b::babe Skynet pk910
+        entry->type |= WHOQUEUETYPE_FOUND;
+        if(strcmp(argv[5], "0") && !(entry->user->flags & USERFLAG_ISAUTHED)) {
+            strcpy(entry->user->auth, argv[5]);
+            entry->user->flags |= USERFLAG_ISAUTHED;
+        }
+        userauth_callback_t *callback = entry->callback;
+        callback(client, entry->user->nick, entry->user, entry->data);
+    }
+}
+
+void recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc) {
+    if(argc < 2) return;
+    char *typestr = strstr(argv[1], ",") + 1;
+    int type = atoi(typestr);
+    if(!(type & WHOQUEUETYPE_ISONQUEUE)) return;
+    struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, 1);
+    if(entry == NULL || (entry->type & WHOQUEUETYPE_CHECKTYPE) != (type & WHOQUEUETYPE_CHECKTYPE)) return;
+    if(type & WHOQUEUETYPE_USERLIST) {
+        //:OGN2.OnlineGamesNet.net 315 skynet #pk910,1 :End of /WHO list.
+        entry->chan->flags |= CHANFLAG_RECEIVED_USERLIST;
+        userlist_callback_t *callback = entry->callback;
+        callback(client, entry->chan, entry->data);
+        if(entry->chan->flags & CHANFLAG_HAVE_INVISIBLES) {
+            //remove all invisible users again
+            struct ChanUser *chanuser, *next;
+            for(chanuser = getChannelUsers(entry->chan, NULL); chanuser; chanuser = next) {
+                next = getChannelUsers(entry->chan, chanuser);
+                if(chanuser->flags & CHANUSERFLAG_INVISIBLE) {
+                    delChanUser(chanuser, 1);
+                }
+            }
+        }
+    } else if(type & WHOQUEUETYPE_USERAUTH) {
+        if(!(entry->type & WHOQUEUETYPE_FOUND)) {
+            userauth_callback_t *callback = entry->callback;
+            callback(client, entry->user->nick, NULL, entry->data);
+        }
+    }
+    free(entry);
+}
+
+void free_whoqueue() {
+    struct WHOQueueEntry *entry, *next;
+    for(entry = first_entry; entry; entry = next) {
+        next = entry->next;
+        free(entry);
+    }
+    first_entry = NULL;
+    last_entry = NULL;
+}
diff --git a/src/WHOHandler.h b/src/WHOHandler.h
new file mode 100644 (file)
index 0000000..31485f8
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _WHOHandler_h
+#define _WHOHandler_h
+
+#include "main.h"
+
+struct ClientSocket;
+struct ChanNode;
+struct UserNode;
+
+#define USERLIST_CALLBACK(NAME) void NAME(UNUSED_ARG(struct ClientSocket *client), UNUSED_ARG(struct ChanNode *chan), UNUSED_ARG(void *data))
+typedef USERLIST_CALLBACK(userlist_callback_t);
+
+#define USERAUTH_CALLBACK(NAME) void NAME(UNUSED_ARG(struct ClientSocket *client), UNUSED_ARG(char *user_nick), UNUSED_ARG(struct UserNode *user), UNUSED_ARG(void *data))
+typedef USERAUTH_CALLBACK(userauth_callback_t);
+
+void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc);
+void recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc);
+void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data);
+void get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t callback, void *data);
+void get_userauth(struct UserNode *user, userauth_callback_t callback, void *data);
+void free_whoqueue();
+
+#endif
\ No newline at end of file
diff --git a/src/bot_NeonServ.c b/src/bot_NeonServ.c
new file mode 100644 (file)
index 0000000..71f5942
--- /dev/null
@@ -0,0 +1,513 @@
+
+#include "bot_NeonServ.h"
+#include "modcmd.h"
+#include "IRCEvents.h"
+#include "IRCParser.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "BanNode.h"
+#include "ModeNode.h"
+#include "ClientSocket.h"
+#include "mysqlConn.h"
+#include "lang.h"
+#include "HandleInfoHandler.h"
+#include "WHOHandler.h"
+#include "DBHelper.h"
+#include "tools.h"
+#include "timeq.h"
+#include "version.h"
+#include "EventLogger.h"
+#include "cmd_neonserv.h"
+
+#define BOTID 1
+
+static const struct default_language_entry msgtab[] = {
+    {"NS_USER_UNKNOWN", "User with nick $b%s$b does not exist."}, /* {ARGS: "TestUser"} */
+    {"NS_AUTH_UNKNOWN", "Account $b%s$b has not been registered."}, /* {ARGS: "TestAuth"} */
+    {"NS_USER_NEED_AUTH", "%s must first authenticate with $bAuthServ$b."}, /* {ARGS: "TestUser"} */
+    {"NS_YOU_NEED_AUTH", "You must first authenticate with $bAuthServ$b."},
+    {"NS_INVALID_ACCESS", "$b%d$b is an invalid access level."}, /* {ARGS: 1337} */
+    {"NS_ADDUSER_ALREADY_ADDED", "%s is already on the $b%s$b user list (with access %d)."}, /* {ARGS: "TestUser", "#TestChan", 123} */
+    {"NS_ADDUSER_DONE", "Added %s to the %s user list with access %d."}, /* {ARGS: "TestUser", "#TestChan", 123} */
+    {"NS_NOT_ON_USERLIST", "%s lacks access to $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_NOT_ON_USERLIST_YOU", "You lack access to $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_NOT_ON_CHANNEL", "%s isn't currently in $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_NOT_ON_CHANNEL_YOU", "You aren't currently in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_DELUSER_DONE", "Deleted %s (with access %d) from the %s user list."}, /* {ARGS: "TestUser", 123, "#TestChan"} */
+    {"NS_ACCESS_OUTRANKED", "You cannot give users access greater than or equal to your own."},
+    {"NS_USER_OUTRANKED", "$b%s$b outranks you (command has no effect)."}, /* {ARGS: "TestUser"} */
+    {"NS_ACCESS_DENIED", "Access denied."},
+    {"NS_NO_ACCESS", "You lack sufficient access to use this command."},
+    {"NS_USER_PROTECTED", "Sorry, $b%s$b is protected."}, /* {ARGS: "TestUser"} */
+    {"NS_SERVICE_IMMUNE", "$b%s$b may not be kicked, killed, banned, or deopped."}, /* {ARGS: "TestUser"} */
+    {"NS_TABLE_NONE", "   None"},
+    {"NS_TABLE_COUNT", "Found $b%d$b matches."}, /* {ARGS: 5} */
+    {"NS_BAN_ALREADY_ADDED", "$b%s$b is already banned in %s."}, /* {ARGS: "*!*@moeeep.*", "#TestChan"} */
+    {"NS_INVALID_ACCESS_RANGE", "Invalid access range; minimum (%d) must be lower than maximum (%d)."}, /* {ARGS: 450, 400} */
+    {"NS_CLVL_DONE", "%s now has access $b%d$b in %s."}, /* {ARGS: "TestUser", 123, "#TestChan"} */
+    {"NS_A_LACKS_ACCESS_BUT_GOD_NICK", "%s lacks access to %s but has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", "#TestChan"} */
+    {"NS_A_LACKS_ACCESS_BUT_GOD_AUTH", "%s (%s) lacks access to %s but has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", "TestUser", "#TestChan"} */
+    {"NS_A_ACCESS_NICK", "%s has access $b%d$b in %s."}, /* {ARGS: "TestAuth", 123, "#TestChan"} */
+    {"NS_A_ACCESS_AUTH", "%s (%s) has access $b%d$b in %s."}, /* {ARGS: "TestAuth", "TestUser", 123, "#TestChan"} */
+    {"NS_A_ACCESS_NICK_GOD", "%s has access $b%d$b in %s and has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", 123, "#TestChan"} */
+    {"NS_A_ACCESS_AUTH_GOD", "%s (%s) has access $b%d$b in %s and has $bsecurity override$b enabled."}, /* {ARGS: "TestAuth", "TestUser", 123, "#TestChan"} */
+    {"NS_A_SUSPENDED", "$b%s$b's access to %s has been suspended."}, /* {ARGS: "TestAuth", "#TestChan"} */
+    {"NS_A_IS_IRCOP", "%s is an $bIRC operator$b."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_USERS_HEADER", "%s users from level %d to %d:"}, /* {ARGS: "#TestChan", 1, 500} */
+    {"NS_USERS_HEADER_MATCH", "%s users from level %d to %d matching %s:"}, /* {ARGS: "#TestChan", 1, 500, "Test*"} */
+    {"NS_USERS_HEADER_ACCESS", "Access"},
+    {"NS_USERS_HEADER_ACCOUNT", "Accout"},
+    {"NS_USERS_HEADER_SEEN", "Last Seen"},
+    {"NS_USERS_HEADER_STATE", "Status"},
+    {"NS_USERS_COUNT", "There are $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
+    {"NS_USERS_COUNT_1", "There is $b%d$b user in %s."}, /* {ARGS: 1, "#TestChan"} */
+    {"NS_USERS_COUNT_MATCH", "There are $b%d$b users in %s. ($b%d$b matching your request)"}, /* {ARGS: 20, "#TestChan", 5} */
+    {"NS_USERS_COUNT_MATCH_1", "There is $b%d$b user in %s. ($b%d$b matching your request)"}, /* {ARGS: 1, "#TestChan", 1} */
+    {"NS_USERS_SEEN_HERE", "Here"},
+    {"NS_USERS_SEEN_INVISIBLE", "Here (invisible)"},
+    {"NS_USERS_SEEN_NEVER", "Never"},
+    {"NS_USERS_STATE_SUSPENDED", "Suspended"},
+    {"NS_USERS_STATE_NORMAL", "Normal"},
+    {"NS_SUSPEND_ALREADY", "$b%s$b is already suspended." }, /* {ARGS: "TestUser"} */
+    {"NS_SUSPEND_NOT", "$b%s$b is not suspended." }, /* {ARGS: "TestUser"} */
+    {"NS_SUSPEND_DONE", "$b%s$b's access to $b%s$b has been suspended." }, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_SUSPEND_RESTORED", "$b%s$b's access to $b%s$b has been restored." }, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_DELME_KEY", "To really remove yourself, you must use 'deleteme %s'."}, /* {ARGS: "abc123"} */
+    {"NS_DELME_DONE", "Your $b%d$b access has been deleted from $b%s$b."}, /* {ARGS: 123, "#TestChan"} */
+    {"NS_MYACCESS_HEADER", "Showing all channel entries for account $b%s$b:"}, /* {ARGS: "TestAuth"} */
+    {"NS_MYACCESS_HEADER_MATCH", "Showing all channel entries for account $b%s$b matching %s:"}, /* {ARGS: "TestAuth", "#Test*"} */
+    {"NS_MYACCESS_HEADER_NAME", "Name"},
+    {"NS_MYACCESS_HEADER_ACCESS", "Access"},
+    {"NS_MYACCESS_HEADER_FLAGS", "Flags"},
+    {"NS_MYACCESS_HEADER_INFO", "Info"},
+    {"NS_MYACCESS_COUNT", "%s has access in $b%d$b channel(s) and is owner of $b%d$b channel(s)."}, /* {ARGS: "TestUser", 15, 5} */
+    {"NS_MYACCESS_COUNT_MATCH", "%s has access in $b%d$b channel(s) and is owner of $b%d$b channel(s) ($b%d$b channels matching your request)."}, /* {ARGS: "TestUser", 15, 5, 7} */
+    {"NS_UP_ALREADY_OP", "You are already opped in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_UP_ALREADY_VOICE", "You are already voiced in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_DOWN_ALREADY", "You are not opped or voiced in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_MDELUSER_DONE", "Deleted $b%d$b account(s) matching $b%s$b with access from $b%d$b to $b%d$b from the %s user list."}, /* {ARGS: 10, "Test*", 1, 200, "#TestChan"} */
+    {"NS_TRIM_DURATION_TOO_SHORT", "You must include a minimum inactivity duration of at least %d seconds to trim."},
+    {"NS_TRIM_DONE", "Trimmed $b%d users$b with access from %d to %d from the %s user list who were inactive for at least %s."}, /* {ARGS: 10, 1, 100, "#TestChan", "10 days"} */
+    {"NS_GIVEOWNER_SELF", "You cannot give ownership to your own account."},
+    {"NS_GIVEOWNER_TIMEOUT", "You must wait %s before you can give ownership of $b%s$b to someone else."}, /* {ARGS: "5 hours", "#TestChan"} */
+    {"NS_GIVEOWNER_CONFIRM", "To really give ownership to $b%1$s$b, you must use 'giveownership *%1$s %2$s'."}, /* {ARGS: "TestUser", "abc123"} */
+    {"NS_GIVEOWNER_DONE", "Ownership of $b%s$b has been transferred to account $b%s$b."}, /* {ARGS: "#TestChan", "TestUser"} */
+    {"NS_OP_FAIL", "$b%s$b could not op some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_OP_DONE", "Opped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_VOICE_FAIL", "$b%s$b could not voice some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_VOICE_DONE", "Voiced users in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_DEOP_FAIL", "$b%s$b could not deop some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_DEOP_DONE", "Deopped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_DEVOICE_FAIL", "$b%s$b could not devoice some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_DEVOICE_DONE", "Devoiced users in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_OPALL_SECURITY", "$bWARNING$b: Opping all users on a channel is very insecure! If you still want do op all users on %s use: '$bopall FORCE$b [nick mask]'"},
+    {"NS_OPALL_DONE", "Opped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
+    {"NS_VOICEALL_DONE", "Voiced $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
+    {"NS_DEOPALL_DONE", "Deopped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
+    {"NS_DEVOICEALL_DONE", "Devoiced $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
+    {"NS_KICK_DONE", "Kicked $b%d$b users from %s"}, /* {ARGS: 20, "#TestChan"} */
+    {"NS_KICK_FAIL", "$b%s$b could not kick some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_KICKBAN_DONE", "KickBanned $b%d$b users from %s"}, /* {ARGS: 10, "#TestChan"} */
+    {"NS_KICKBAN_FAIL", "$b%s$b could not kickban some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_BAN_DONE", "$b%d$b masks added to the %s ban list. (matching %d users)"}, /* {ARGS: 5, "#TestChan", 15} */
+    {"NS_BAN_FAIL", "$b%s$b could not ban some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_LAME_MASK", "$b%s$b is a little too general. Try making it more specific."}, /* {ARGS: "*!*@*"} */
+    {"NS_SET_HEADER", "Channel Settings for %s:"}, /* {ARGS: "#TestChan"} */
+    {"NS_SET_ON", "on"},
+    {"NS_SET_OFF", "off"},
+    {"NS_SET_UNKNOWN_SETTING", "$b%s$b is an unknown channel setting."}, /* {ARGS: "TestSetting"} */
+    {"NS_SET_CANNOT_SET", "That setting is above your current level, so you cannot change it."},
+    {"NS_SET_BADLEVEL", "You cannot change any setting to above your level."},
+    {"NS_SET_INVALID_OPTION", "$b%d$b is not a valid choice.  Choose one:"}, /* {ARGS: 5} */
+    {"NS_SET_INVALID_BOOLEAN", "$b%s$b is an invalid binary value."}, /* {ARGS: 2} */
+    {"NS_SET_DEFAULTS_OWNER", "You must have access 500 in %s to reset it to the default options."}, /* {ARGS: "#TestChan"} */
+    {"NS_SET_DEFAULTS_CODE", "To reset %s's settings to the defaults, you must use 'set defaults %s'."}, /* {ARGS: "#TestChan", "abc123"} */
+    {"NS_SET_DEFAULTS_DONE", "All settings for %s have been reset to default values."}, /* {ARGS: "#TestChan"} */
+    {"NS_SET_TRIGGER_OWNER", "You must have access 500 in %s to change the channel trigger."}, /* {ARGS: "#TestChan"} */
+    {"NS_SET_HELP_USERINFO","(access to set the userinfo)"},
+    {"NS_SET_HELP_WIPEINFO","(access to clear the userinfo of other users)"},
+    {"NS_SET_HELP_INVITEME","(access to get invited by the bot)"},
+    {"NS_SET_HELP_ENFVOICE","(access to give voice to other users)"},
+    {"NS_SET_HELP_ENFOPS","(access to give op to their users)"},
+    {"NS_SET_HELP_GIVEOPS","(access to get op by the bot)"},
+    {"NS_SET_HELP_GIVEVOICE","(access to get voice by the bot)"},
+    {"NS_SET_HELP_KICK","(access to kick other users from the channel)"},
+    {"NS_SET_HELP_BAN","(access to ban other users from the channel)"},
+    {"NS_SET_HELP_STATICBAN","(access to add static bans to the channel banlist  e.g. +addban)"},
+    {"NS_SET_HELP_PUBCMD","(access to do public commands in the channel  e.g. +users)"},
+    {"NS_SET_HELP_ENFMODES","(access to override the modelock)"},
+    {"NS_SET_HELP_ENFTOPIC","(access to override the topicmask)"},
+    {"NS_SET_HELP_TOPICSNARF","(access to set the default topic by changing the topic with /TOPIC)"},
+    {"NS_SET_HELP_CHANGETOPIC","(access to change the topic)"},
+    {"NS_SET_HELP_SETTERS","(access to change this settings)"},
+    {"NS_SET_HELP_ADDUSER","(access to add an user to the userlist)"},
+    {"NS_SET_HELP_DELUSER","(access to delete an user from the userlist)"},
+    {"NS_SET_HELP_CLVL","(access to change the access of an user in the userlist)"},
+    {"NS_SET_HELP_RESYNC","(access to synchronize the channelrights (@,+) with the userlist)"},
+    {"NS_SET_HELP_SUSPEND","(access to suspend an user on the userlist)"},
+    {"NS_SET_OPTION_CTCPREACTION_0","Kick on disallowed CTCPs"},
+    {"NS_SET_OPTION_CTCPREACTION_1","Kickban on disallowed CTCPs"},
+    {"NS_SET_OPTION_CTCPREACTION_2","Short timed ban on disallowed CTCPs"},
+    {"NS_SET_OPTION_CTCPREACTION_3","Long timed ban on disallowed CTCPs"},
+    {"NS_SET_OPTION_NOTICEREACTION_0","Kick on disallowed NOTICEs"},
+    {"NS_SET_OPTION_NOTICEREACTION_1","Kickban on disallowed NOTICEs"},
+    {"NS_SET_OPTION_NOTICEREACTION_2","Short timed ban on disallowed NOTICEs"},
+    {"NS_SET_OPTION_NOTICEREACTION_3","Long timed ban on disallowed NOTICEs"},
+    {"NS_SET_OPTION_PROTECT_0","All users will be protected from users with equal or lower access."},
+    {"NS_SET_OPTION_PROTECT_1","All users with access will be protected from users with equal or lower access."},
+    {"NS_SET_OPTION_PROTECT_2","All users with access will be protected from user with lower access."},
+    {"NS_SET_OPTION_PROTECT_3","Nobody will be protected."},
+    {"NS_SET_OPTION_TOYS_0","Funcommands can't be used."},
+    {"NS_SET_OPTION_TOYS_1","Funcommands are possible but the reply will be sent as a notice."},
+    {"NS_SET_OPTION_TOYS_2","Funcommands are possible and the reply will be sent to the channel."},
+    {"NS_SET_OPTION_DYNLIMIT_0","off"},
+    {"NS_SET_OPTION_NODELETE_0","off  (only bot masters)"},
+    {"NS_SET_OPTION_NODELETE_1","on  (only bot masters)"},
+    {"NS_WIPEINFO_DONE", "Removed $b%s$b's infoline in $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_TRACE_HEADER", "The following users were found:"},
+    {"NS_ADDBAN_DONE", "$b%s$b permantly added to the %s ban list. (matching %d users)"}, /* {ARGS: "*!*@Test.*", "#TestChan", 4} */
+    {"NS_BANS_HEADER_MASK", "Mask"},
+    {"NS_BANS_HEADER_SETBY", "Set By"},
+    {"NS_BANS_HEADER_TRIGGERED", "Triggered"},
+    {"NS_BANS_HEADER_EXPIRES", "Expires"},
+    {"NS_BANS_HEADER_REASON", "Reason"},
+    {"NS_DELBAN_BANNED_BY", "%s is banned by %s."}, /* {ARGS: "*!*@bla*", "*!*@b*"} */
+    {"NS_DELBAN_FAIL", "Sorry, no ban found for $b%s$b."}, /* {ARGS: "*!*@bla*"} */
+    {"NS_DELBAN_DONE", "Removed $b%s$b from the %s ban list."}, /* {ARGS: "*!*@bla.*", "#TestChan"} */
+    {"NS_NETINFO_HEADER", "$bNetwork information$b"},
+    {"NS_NETINFO_BOTS", "Bots:"},
+    {"NS_NETINFO_UPTIME", "Uptime:"},
+    {"NS_NETINFO_TRAFFIC", "Traffic:"},
+    {"NS_NETINFO_CACHE", "Cache:"},
+    {"NS_NETINFO_DATABASE", "Database:"},
+    {"NS_NETINFO_CHANNEL", "  Channel:"},
+    {"NS_NETINFO_CHANNEL_BAN", "    Bans:"},
+    {"NS_NETINFO_USER", "  User:"},
+    {"NS_NETINFO_CHANUSER", "  Channel-User:"},
+    {"NS_NETINFO_OTHER", "  Other:"},
+    {"NS_NETINFO_VERSION", "Version:"},
+    {"NS_NETINFO_CODE", "Code:"},
+    {"NS_NETINFO_CODE_VALUE", "%s lines c code (view it at http://git.pk910.de/?p=NeonServV5.git;a=summary)"}, /* {ARGS: 20} */
+    {"NS_NETINFO_COMPILER", "Compiler:"},
+    {"NS_NETINFO_COMPILER_VALUE", "%s  (%s)"}, /* {ARGS: "GCC 4.4.5", "Sun Sep 18 2011 at 05:21:33 CEST"} */
+    {"NS_EXTTOPIC_INVALID_ID", "ADVANCEDTOPIC is enabled and $b%s$b is an invalid TOPIC ID. Valid topic id's are: 1-9"}, /* {ARGS: 10} */
+    {"NS_EXTTOPIC_TOPICID", "Topic %d: %s"}, /* {ARGS: 5, "topic"} */
+    {"NS_TOPIC_DONE", "Topic is now '%s'."}, /* {ARGS: "i like you :D"} */
+    {"NS_CHANSERVSYNC_UNSUPPORTED", "\0034WARNING\003: the user list style of %s is not known. %s can try to synchronize the userlist, but there is no guarantee that it is successful!"}, /* {ARGS: "CowBot"} */
+    {"NS_CHANSERVSYNC_KEY", "If you really want to synchronize the %s userlist with %s use: chanservsync %s %s"}, /* {ARGS: "#TestChan", "CowBot", "CowBot", "abc123"} */
+    {"NS_CHANSERVSYNC_INUSE", "$bchanservsync$b is already in use by someone else. Please try again in a few seconds..."},
+    {"NS_CHANSERVSYNC_SYNCHRONIZING", "Synchronizing userlist in %s with $b%s$b..."}, /* {ARGS: "#TestChan", "CowBot"} */
+    {"NS_CHANSERVSYNC_SYNCHRONIZED", "Synchronized user $b%s$b: access $b%d$b"}, /* {ARGS: "TestUser", 123} */
+    {"NS_REGISTER_ALREADY", "%s is already registered with %s."}, /* {ARGS: "#TestChan", "NeonServ"} */
+    {"NS_INVALID_CHANNEL_NAME", "%s is not a valid channel name."}, /* {ARGS: "#invalid"} */
+    {"NS_REGISTER_FULL", "the bot can not join more channels."},
+    {"NS_REGISTER_DISCONNECTED", "%s has been registered with a Bot, that is currently NOT connected. The Bot should join the channel, when it reconnects to the IRC-Network."}, /* {ARGS: "#TestChan"} */
+    {"NS_REGISTER_DONE", "$b%s$b is now registered to $b%s$b."}, /* {ARGS: "#TestChan", "TestUser"} */
+    {"NS_UNREGISTER_NOT_REGISTERED", "$b%s$b is not registered with %s."}, /* {ARGS: "#TestChan", "NeonServ"} */
+    {"NS_UNREGISTER_DONE", "$b%s$b unregistered."}, /* {ARGS: "#TestChan"} */
+    {"NS_RECOVER_DONE", "$b%s$b has been recovered."}, /* {ARGS: "#TestChan"} */
+    {"NS_RESYNC_DONE", "Synchronized users in $b%s$b with the userlist."}, /* {ARGS: "#TestChan"} */
+    {"NS_TIMEBAN_DURATION_TOO_SHORT", "You must specify a ban duration of at least %d seconds."}, /* {ARGS: 30} */
+    {"NS_TIMEBAN_DONE", "Banned $b%s$b from %s for %s. (matching %d users)"}, /* {ARGS: "*!*@bla*", "#TestChan", "2 hours", 5} */
+    {"NS_MODE_INVALID", "$b%c$b is an invalid set of channel modes."}, /* {ARGS: "+xyz"} */
+    {"NS_MODE_LOCKED", "Modes conflicting with $b%s$b are not allowed in %s."}, /* {ARGS: "+xyz", "#TestChan"} */
+    {"NS_MODE_DONE", "Channel modes are now $b%s$b."}, /* {ARGS: "+xyz"} */
+    {"NS_MODE_ENFOPS", "You may not op or deop users on $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_MODE_ENFVOICE", "You may not voice or devoice users on $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_MODE_CANBAN", "You may not ban or unban users on $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_GOD_ON", "Security override has been enabled."},
+    {"NS_GOD_OFF", "Security override has been disabled."},
+    {"NS_PEEK_HEADER", "$b%s$b Status:"}, /* {ARGS: "#TestChan"} */
+    {"NS_PEEK_TOPIC", "Topic:       %s"}, /* {ARGS: "TOPIC"} */
+    {"NS_PEEK_MODES", "Modes:       %s"}, /* {ARGS: "+xyz"} */
+    {"NS_PEEK_USERS", "Total Users: %d (%d ops, %d voices, %d regulars, %d invisible)"}, /* {ARGS: 20, 4, 6, 8, 2} */
+    {"NS_PEEK_OPS", "Ops:"},
+    {"NS_USET_GLOBAL", "$b--- Global ---$b"},
+    {"NS_USET_CHANNEL", "$b--- User options (channel) ---$b"},
+    {"NS_USET_NO_ACCESS", "no access"},
+    {"NS_USET_UNKNOWN_SETTING", "$b%s$b is an unknown uset setting."}, /* {ARGS: "TestSetting"} */
+    {"NS_RELOADLANG_UNKNOWN", "$b%s$b is an unknown language tag."}, /* {ARGS: "de"} */
+    {"NS_RELOADLANG_DONE", "$b%s$b (%s) reloaded."}, /* {ARGS: "Deutsch", "de"} */
+    {"NS_UNBAN_DONE", "$b%d$b masks removed from the %s ban list."}, /* {ARGS: 5, "#TestChan"} */
+    {"NS_UNBAN_FAIL", "$b%s$b could not unban some of the masks you provided."}, /* {ARGS: "NeonServ"} */
+    {"NS_UNBANALL_DONE", "all $b%d$b masks removed from the %s ban list."}, /* {ARGS: 5, "#TestChan"} */
+    {"NS_UNBANALL_FAIL", "$b%s$b could not find any bans in %s."}, /* {ARGS: "NeonServ", "#TestChan"} */
+    {"NS_UNBANME_DONE", "removed $b%d$b masks from the %s ban list."}, /* {ARGS: 5, "#TestChan"} */
+    {"NS_UNBANME_FAIL", "$b%s$b could not find any bans matching %s."}, /* {ARGS: "NeonServ", "TestUser!TestIdent@TestUser.user.WebGamesNet"} */
+    {"NS_INVITE_RESTRICTION", "%s doesn't want to be invited to %s."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_INVITE_TIMEOUT", "%s has already been invited to $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_INVITE_ON_CHAN", "%s is already in $b%s$b."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_INVITE_DONE_USER", "You have been invited to join $b%s$b by %s. (Do $b/msg %s %1$s uset noinvite 1$b if you don't want to be invited to %1$s anymore.)"}, /* {ARGS: "#TestChan", "TestUser", "NeonServ"} */
+    {"NS_INVITE_DONE", "Invited $b%s$b to join %s."}, /* {ARGS: "TestUser", "#TestChan"} */
+    {"NS_INVITEME_ON_CHAN", "You are already in $b%s$b."}, /* {ARGS: "#TestChan"} */
+    {"NS_INVITEME_DONE", "You have been invited to join %s."}, /* {ARGS: "#TestChan"} */
+    {"NS_HELP_TOPIC", "No help on that topic."},
+    {"NS_CSUSPEND_ALREADY", "$b%s$b is already suspended."}, /* {ARGS: "#TestChan"} */
+    {"NS_CSUSPEND_DONE", "Channel $b%s$b has been temporarily suspended."}, /* {ARGS: "#TestChan"} */
+    {"NS_CUNSUSPEND_NOT", "$b%s$b is not suspended."}, /* {ARGS: "#TestChan"} */
+    {"NS_CUNSUSPEND_DONE", "Channel $b%s$b has been restored."}, /* {ARGS: "#TestChan"} */
+    {"NS_MOVE_SUSPENDED", "Moving cannot be performed if the source channel is suspended."},
+    {"NS_MOVE_SELF", "Moving cannot be performed if the source and target channels are the same."},
+    {"NS_MOVE_DONE", "Channel $b%s$b has been moved to $b%s$b."}, /* {ARGS: "#TestChan", "#NewTestChan"} */
+    {"NS_BIND_ALREADY", "$b%s$b is already bound to %s."}, /* {ARGS: "TestCommand", "TestFunction"} */
+    {"NS_BIND_UNKNOWN", "$b%s$b is an undefined function."}, /* {ARGS: "TestFunction"} */
+    {"NS_BIND_DONE", "New command $b%s$b bound to %s."}, /* {ARGS: "TestCommand", "TestFunction"} */
+    {"NS_UNBIND_NOT_FOUND", "There is no command called $b%s$b bound."}, /* {ARGS: "TestCommand"} */
+    {"NS_UNBIND_DONE", "Unbound command $b%s$b."}, /* {ARGS: "TestCommand"} */
+    {"NS_EVENTS_HEADER", "The following channel events were found:"},
+    {"NS_OPLOG_HEADER", "The following oper events were found:"},
+    {"NS_SEARCH_HEADER", "The following channels were found:"},
+    {"NS_COMMAND_BINDING", "$b%s$b is a binding of %s %s"}, /* {ARGS: "TestCommand", "TestFunction", "TestParameters"} */
+    {"NS_COMMAND_ACCESS", "You need at least %d channel access and %d oper access to execute this command."}, /* {ARGS: 500, 100} */
+    {"NS_TOPIC_ACCESS", "You lack sufficient access in %s to change the topic."}, /* {ARGS: "#TestChan"} */
+    {"NS_BOTWAR_DETECTED", "$b$k4BOTWAR DETECTED!$k Please check the channel configuration!$b"},
+    {"NS_BOTWAR_REPORTED", "A supporter has been informed to help you preventing botwars in the future."},
+    {"NS_BOTWAR_ALERT", "$b$k4BOTWAR ALERT:$k$b Botwar in $b%s$b detected. (opponent: $b%s$b) Please join and help them preventing Botwars."}, /* {ARGS: "#TestChan", "OtherBot"} */
+    {"NS_INVITE_FAIL", "$b%s$b is not registered with %s or suspended."}, /* {ARGS: "#TestChan", "NeonServ"} */
+    {"NS_SETACCESS_DONE", "$b%s$b has now %d global access."},
+    {NULL, NULL}
+};
+
+/* TODO: 
+trim bans
+cmd_neonserv_open.c
+cmd_neonserv_info.c
+parse, check and set modelock
+cmd_neonserv_modcmd.c
+cmd_neonserv_allowregister.c
+cmd_neonserv_noregister.c
+cmd_neonserv_expire.c
+cmd_neonserv_unvisited.c
+cmd_neonserv_merge.c
+cmd_neonserv_dnrsearch.c
+cmd_neonserv_rename.c
+cmd_neonserv_iplocate.c
+cmd_neonserv_calc.c
+*/
+//EVENTS
+#include "event_neonserv_join.c"
+#include "event_neonserv_part.c"
+#include "event_neonserv_quit.c"
+//#include "event_neonserv_kick.c"
+//#include "event_neonserv_mode.c"
+#include "event_neonserv_ctcp.c"
+#include "event_neonserv_notice.c"
+#include "event_neonserv_invite.c"
+#include "event_neonserv_topic.c"
+
+struct ClientSocket *getBotForChannel(struct ChanNode *chan) {
+    struct ClientSocket *bot, *use_bot = NULL, *second_bot = NULL, *third_bot = NULL;
+    struct ChanUser *chanuser;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->botid != BOTID) continue;
+        if((chanuser = getChanUser(bot->user, chan)) != NULL) {
+            if((chanuser->flags & CHANUSERFLAG_OPPED)) {
+                use_bot = bot;
+                if(bot->flags & SOCKET_FLAG_PREFERRED) break;
+            } else if(bot->flags & SOCKET_FLAG_PREFERRED)
+                second_bot = bot;
+            else
+                third_bot = bot;
+        }
+    }
+    if(!use_bot) use_bot = second_bot;
+    if(!use_bot) use_bot = third_bot;
+    return use_bot;
+}
+
+static void neonserv_bot_ready(struct ClientSocket *client) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    
+    printf_mysql_query("SELECT `automodes` FROM `bots` WHERE `id` = '%d'", client->clientid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        putsock(client, "MODE %s +%s", client->user->nick, row[0]);
+    }
+    
+    printf_mysql_query("SELECT `channel_name`, `channel_key` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `botid` = '%d' AND `suspended` = '0'", client->clientid);
+    res = mysql_use();
+    
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        putsock(client, "JOIN %s %s", row[0], row[1]);
+    }
+}
+
+static void neonserv_trigger_callback(struct ChanNode *chan, char *trigger) {
+    strcpy(trigger, "+");
+}
+
+static void start_bots() {
+    struct UserNode *user;
+    struct ClientSocket *client;
+    MYSQL_RES *res, *res2;
+    MYSQL_ROW row;
+    
+    printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID);
+    res = mysql_use();
+    
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        
+        user = addUser(row[0]);
+        strcpy(user->ident, row[1]);
+        strcpy(user->realname, row[2]);
+        user->flags |= USERFLAG_ISBOT;
+        client = create_socket(row[3], atoi(row[4]), row[5], user);
+        client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0);
+        client->botid = BOTID;
+        client->clientid = atoi(row[7]);
+        connect_socket(client);
+        printf_mysql_query("SELECT `command`, `function`, `parameters`, `global_access`, `chan_access` FROM `bot_binds` WHERE `botclass` = '%d'", client->botid);
+        res2 = mysql_use();
+        while ((row = mysql_fetch_row(res2)) != NULL) {
+            if(bind_cmd_to_command(BOTID, row[0], row[1])) {
+                if(row[2] && strcmp(row[2], "")) {
+                    bind_set_parameters(BOTID, row[0], row[2]);
+                }
+                if(row[3]) {
+                    bind_set_global_access(BOTID, row[0], atoi(row[3]));
+                }
+                if(row[4]) {
+                    bind_set_channel_access(BOTID, row[0], row[4]);
+                }
+            }
+        }
+    }
+    
+    //load all timed bans
+    printf_mysql_query("SELECT `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_timeout` > 0");
+    res = mysql_use();
+    char nameBuf[20];
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(atol(row[1]) - time(0) > 0) {
+            sprintf(nameBuf, "ban_%s", row[0]);
+            timeq_add_name(nameBuf, atol(row[1]) - time(0), channel_ban_timeout, strdup(row[0]));
+        } else {
+            //timed out
+            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[0]);
+        }
+    }
+}
+
+TIMEQ_CALLBACK(channel_ban_timeout) {
+    char *str_banid = data;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `ban_mask`, `channel_name` FROM `bans` LEFT JOIN `channels` ON `ban_channel` = `channel_id` WHERE `ban_id` = '%s'", str_banid);
+    res = mysql_use();
+    struct ChanNode *chan;
+    if((row = mysql_fetch_row(res)) != NULL && (chan = getChanByName(row[1])) != NULL) {
+        struct ClientSocket *use_bot = getBotForChannel(chan);
+        if(use_bot) {
+            putsock(use_bot, "MODE %s -b %s", chan->name, row[0]);
+        }
+        printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", str_banid);
+    }
+    free(str_banid);
+}
+
+void init_NeonServ() {
+    
+    #define USER_COMMAND(NAME,FUNCTION,PARAMCOUNT,PRIVS,FLAGS) register_command(BOTID, NAME, FUNCTION, PARAMCOUNT, PRIVS, 0, FLAGS)
+    //               NAME              FUNCTION        PARAMS     PRIVS                FLAGS
+    USER_COMMAND("adduser",      neonserv_cmd_adduser,   2, "#channel_canadd",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("deluser",      neonserv_cmd_deluser,   1, "#channel_candel",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("clvl",         neonserv_cmd_clvl,      2, "#channel_canclvl",     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("access",       neonserv_cmd_access,    0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_LOG);
+    USER_COMMAND("users",        neonserv_cmd_users,     0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
+    USER_COMMAND("suspend",      neonserv_cmd_suspend,   1, "#channel_cansuspend",  CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("unsuspend",    neonserv_cmd_unsuspend, 1, "#channel_cansuspend",  CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("delme",        neonserv_cmd_delme,     0,  "1",                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("myaccess",     neonserv_cmd_myaccess,  0, NULL,                   CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
+    USER_COMMAND("up",           neonserv_cmd_up,        0, "#channel_getop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("down",         neonserv_cmd_down,      0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_LOG);
+    USER_COMMAND("upall",        neonserv_cmd_upall,     0, NULL,                   CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("downall",      neonserv_cmd_downall,   0, NULL,                   CMDFLAG_LOG);
+    USER_COMMAND("mdeluser",     neonserv_cmd_mdeluser,  2, "#channel_candel",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("trim",         neonserv_cmd_trim,      2, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("giveowner",    neonserv_cmd_giveowner, 1, "500",                  CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("op",           neonserv_cmd_op,        1, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("deop",         neonserv_cmd_deop,      1, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("voice",        neonserv_cmd_voice,     1, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("devoice",      neonserv_cmd_devoice,   1, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("opall",        neonserv_cmd_opall,     0, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("deopall",      neonserv_cmd_deopall,   0, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("voiceall",     neonserv_cmd_voiceall,  0, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("devoiceall",   neonserv_cmd_devoiceall,0, "#channel_canvoice",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("set",          neonserv_cmd_set,       0, "#channel_setters",     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("kick",         neonserv_cmd_kick,      1, "#channel_cankick",     CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("kickban",      neonserv_cmd_kickban,   1, "#channel_cankick,#channel_canban", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("ban",          neonserv_cmd_ban,       1, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("wipeinfo",     neonserv_cmd_wipeinfo,  1, "#channel_wipeinfo",    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("addban",       neonserv_cmd_addban,    1, "#channel_staticban",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("bans",         neonserv_cmd_bans,      0, "1",                    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
+    USER_COMMAND("delban",       neonserv_cmd_delban,    1, "#channel_staticban",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("netinfo",      neonserv_cmd_netinfo,   0, NULL,                   0);
+    USER_COMMAND("topic",        neonserv_cmd_topic,     0, "#channel_changetopic", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("chanservsync", neonserv_cmd_chanservsync, 0,"500",                CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("resync",       neonserv_cmd_resync,    0, "#channel_canresync",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("addtimeban",   neonserv_cmd_addtimeban,2, "#channel_staticban",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("mode",         neonserv_cmd_mode,      1, "#channel_getop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("version",      neonserv_cmd_version,   0, NULL,                   0);
+    USER_COMMAND("peek",         neonserv_cmd_peek,      0, NULL,                   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN);
+    USER_COMMAND("uset",         neonserv_cmd_uset,      0, NULL,                   CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
+    USER_COMMAND("unban",        neonserv_cmd_unban,     1, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("unbanall",     neonserv_cmd_unbanall,  0, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("unbanme",      neonserv_cmd_unbanme,   0, "#channel_canban",      CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("invite",       neonserv_cmd_invite,    1, "#channel_canop",       CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("inviteme",     neonserv_cmd_inviteme,  0, "#channel_getinvite",   CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+    USER_COMMAND("help",         neonserv_cmd_help,      0, NULL,                   0);
+    USER_COMMAND("events",       neonserv_cmd_events,    0, "1",                    CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
+    USER_COMMAND("command",      neonserv_cmd_command,   1, NULL,                   0);
+    #undef USER_COMMAND
+    
+    #define OPER_COMMAND(NAME,FUNCTION,PARAMCOUNT,GACCESS,FLAGS) register_command(BOTID, NAME, FUNCTION, PARAMCOUNT, NULL, GACCESS, FLAGS)
+    //            NAME            FUNCTION              PARAMS  ACCS  FLAGS
+    OPER_COMMAND("trace",        neonserv_cmd_trace,     1,     400,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
+    OPER_COMMAND("register",     neonserv_cmd_register,  2,     200,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("unregister",   neonserv_cmd_unregister,1,     200,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("recover",      neonserv_cmd_recover,   1,     200,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("say",          neonserv_cmd_say,       2,     600,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("emote",        neonserv_cmd_emote,     2,     600,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("notice",       neonserv_cmd_notice,    2,     600,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("raw",          neonserv_cmd_raw,       1,     800,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
+    OPER_COMMAND("god",          neonserv_cmd_god,       0,     1,    CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
+    OPER_COMMAND("reloadlang",   neonserv_cmd_reloadlang,1,     500,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
+    OPER_COMMAND("csuspend",     neonserv_cmd_csuspend,  1,     100,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("cunsuspend",   neonserv_cmd_cunsuspend,1,     100,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("move",         neonserv_cmd_move,      2,     300,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG);
+    OPER_COMMAND("bind",         neonserv_cmd_bind,      2,     900,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
+    OPER_COMMAND("unbind",       neonserv_cmd_unbind,    1,     900,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
+    OPER_COMMAND("oplog",        neonserv_cmd_oplog,     0,     1,    CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
+    OPER_COMMAND("search",       neonserv_cmd_search,    1,     400,  CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH);
+    OPER_COMMAND("setaccess",    neonserv_cmd_setaccess, 2,     1000, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_OPLOG);
+    #undef OPER_COMMAND
+    
+    start_bots();
+    
+    //register events
+    bind_bot_ready(neonserv_bot_ready);
+    bind_join(neonserv_event_join);
+    bind_part(neonserv_event_part);
+    bind_quit(neonserv_event_quit);
+    bind_chanctcp(neonserv_event_chanctcp);
+    bind_privctcp(neonserv_event_privctcp);
+    bind_channotice(neonserv_event_channotice);
+    bind_topic(neonserv_event_topic);
+    bind_invite(neonserv_event_invite);
+    
+    set_trigger_callback(BOTID, neonserv_trigger_callback);
+    
+    register_default_language_table(msgtab);
+}
+
+void loop_NeonServ() {
+    
+}
+
+void free_NeonServ() {
+    
+}
+
+#undef BOTID
diff --git a/src/bot_NeonServ.h b/src/bot_NeonServ.h
new file mode 100644 (file)
index 0000000..90bd696
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _bot_NeonServ_h
+#define _bot_NeonServ_h
+
+#include "main.h"
+#include "timeq.h"
+
+struct ChanNode;
+
+void init_NeonServ();
+void loop_NeonServ();
+void free_NeonServ();
+
+TIMEQ_CALLBACK(channel_ban_timeout);
+struct ClientSocket *getBotForChannel(struct ChanNode *chan);
+
+#endif
\ No newline at end of file
diff --git a/src/bots.c b/src/bots.c
new file mode 100644 (file)
index 0000000..b957a19
--- /dev/null
@@ -0,0 +1,16 @@
+
+#include "bots.h"
+
+#include "bot_NeonServ.h"
+
+void init_bots() {
+    init_NeonServ();
+}
+
+void loop_bots() {
+    loop_NeonServ();
+}
+
+void free_bots() {
+    free_NeonServ();
+}
diff --git a/src/bots.h b/src/bots.h
new file mode 100644 (file)
index 0000000..a24b158
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _bots_h
+#define _bots_h
+
+#include "main.h"
+
+void init_bots();
+void loop_bots();
+void free_bots();
+
+#endif
\ No newline at end of file
diff --git a/src/cmd_neonserv.h b/src/cmd_neonserv.h
new file mode 100644 (file)
index 0000000..6b8fee1
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _cmd_neonserv_h
+#define _cmd_neonserv_h
+#include "main.h"
+#include "modcmd.h"
+#include "IRCParser.h"
+#include "IRCEvents.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "ModeNode.h"
+#include "BanNode.h"
+#include "ClientSocket.h"
+#include "mysqlConn.h"
+#include "lang.h"
+#include "HandleInfoHandler.h"
+#include "WHOHandler.h"
+#include "DBHelper.h"
+#include "tools.h"
+#include "timeq.h"
+#include "version.h"
+#include "EventLogger.h"
+#include "bot_NeonServ.h"
+
+CMD_BIND(neonserv_cmd_access);
+CMD_BIND(neonserv_cmd_addban);
+CMD_BIND(neonserv_cmd_addtimeban);
+CMD_BIND(neonserv_cmd_adduser);
+CMD_BIND(neonserv_cmd_ban);
+CMD_BIND(neonserv_cmd_bans);
+CMD_BIND(neonserv_cmd_bind);
+CMD_BIND(neonserv_cmd_chanservsync);
+CMD_BIND(neonserv_cmd_clvl);
+CMD_BIND(neonserv_cmd_command);
+CMD_BIND(neonserv_cmd_csuspend);
+CMD_BIND(neonserv_cmd_cunsuspend);
+CMD_BIND(neonserv_cmd_delban);
+CMD_BIND(neonserv_cmd_delme);
+CMD_BIND(neonserv_cmd_deluser);
+CMD_BIND(neonserv_cmd_deop);
+CMD_BIND(neonserv_cmd_deopall);
+CMD_BIND(neonserv_cmd_devoice);
+CMD_BIND(neonserv_cmd_devoiceall);
+CMD_BIND(neonserv_cmd_down);
+CMD_BIND(neonserv_cmd_downall);
+CMD_BIND(neonserv_cmd_emote);
+CMD_BIND(neonserv_cmd_events);
+CMD_BIND(neonserv_cmd_giveowner);
+CMD_BIND(neonserv_cmd_god);
+CMD_BIND(neonserv_cmd_help);
+CMD_BIND(neonserv_cmd_invite);
+CMD_BIND(neonserv_cmd_inviteme);
+CMD_BIND(neonserv_cmd_kick);
+CMD_BIND(neonserv_cmd_kickban);
+CMD_BIND(neonserv_cmd_mdeluser);
+CMD_BIND(neonserv_cmd_mode);
+CMD_BIND(neonserv_cmd_move);
+CMD_BIND(neonserv_cmd_myaccess);
+CMD_BIND(neonserv_cmd_netinfo);
+CMD_BIND(neonserv_cmd_notice);
+CMD_BIND(neonserv_cmd_op);
+CMD_BIND(neonserv_cmd_opall);
+CMD_BIND(neonserv_cmd_oplog);
+CMD_BIND(neonserv_cmd_peek);
+CMD_BIND(neonserv_cmd_raw);
+CMD_BIND(neonserv_cmd_recover);
+CMD_BIND(neonserv_cmd_register);
+CMD_BIND(neonserv_cmd_reloadlang);
+CMD_BIND(neonserv_cmd_resync);
+CMD_BIND(neonserv_cmd_say);
+CMD_BIND(neonserv_cmd_search);
+CMD_BIND(neonserv_cmd_set);
+CMD_BIND(neonserv_cmd_setaccess);
+CMD_BIND(neonserv_cmd_suspend);
+CMD_BIND(neonserv_cmd_topic);
+CMD_BIND(neonserv_cmd_trace);
+CMD_BIND(neonserv_cmd_trim);
+CMD_BIND(neonserv_cmd_unban);
+CMD_BIND(neonserv_cmd_unbanall);
+CMD_BIND(neonserv_cmd_unbanme);
+CMD_BIND(neonserv_cmd_unbind);
+CMD_BIND(neonserv_cmd_unregister);
+CMD_BIND(neonserv_cmd_unsuspend);
+CMD_BIND(neonserv_cmd_up);
+CMD_BIND(neonserv_cmd_upall);
+CMD_BIND(neonserv_cmd_users);
+CMD_BIND(neonserv_cmd_uset);
+CMD_BIND(neonserv_cmd_version);
+CMD_BIND(neonserv_cmd_voice);
+CMD_BIND(neonserv_cmd_voiceall);
+CMD_BIND(neonserv_cmd_wipeinfo);
+
+#endif
\ No newline at end of file
diff --git a/src/cmd_neonserv_access.c b/src/cmd_neonserv_access.c
new file mode 100644 (file)
index 0000000..aa11b00
--- /dev/null
@@ -0,0 +1,115 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_access_nick_lookup);
+static void neonserv_cmd_access_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, struct UserNode *target);
+
+struct neonserv_cmd_access_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    char *nick;
+};
+
+CMD_BIND(neonserv_cmd_access) {
+    if(argc == 0) {
+        if(!(user->flags & USERFLAG_ISAUTHED)) {
+            struct neonserv_cmd_access_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->nick = strdup(user->nick);
+            get_userauth(user, neonserv_cmd_access_nick_lookup, cache);
+        } else
+            neonserv_cmd_access_async1(client, getTextBot(), user, chan, user->nick, user->auth, user);
+    }
+    else if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        neonserv_cmd_access_async1(client, getTextBot(), user, chan, NULL, argv[0], NULL);
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_access_async1(client, getTextBot(), user, chan, argv[0], cuser->auth, cuser);
+        } else {
+            struct neonserv_cmd_access_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->nick = strdup(argv[0]);
+            get_userauth(cuser, neonserv_cmd_access_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_access_nick_lookup) {
+    struct neonserv_cmd_access_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        if(!strcmp(cache->nick, cache->user->nick))
+            reply(cache->textclient, cache->user, "NS_YOU_NEED_AUTH");
+        else
+            reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_access_async1(cache->client, cache->textclient, cache->user, cache->chan, user->nick, user->auth, user);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_access_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, struct UserNode *target) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW user_row, chanuser_row;
+    int userid;
+    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((user_row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(user_row[0]);
+        //check if the user is already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags`, `chanuser_infoline` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((chanuser_row = mysql_fetch_row(res)) != NULL) {
+            //access output
+            if(nick)
+                reply(textclient, user, (strcmp(user_row[2], "1") ? "NS_A_ACCESS_AUTH" : "NS_A_ACCESS_AUTH_GOD"), nick, auth, atoi(chanuser_row[0]), chan->name);
+            else
+                reply(textclient, user, (strcmp(user_row[2], "1") ? "NS_A_ACCESS_NICK" : "NS_A_ACCESS_NICK_GOD"), auth, atoi(chanuser_row[0]), chan->name);
+            int cflags = atoi(chanuser_row[1]);
+            if(cflags & DB_CHANUSER_SUSPENDED)
+                reply(textclient, user, "NS_A_SUSPENDED", (nick ? nick : auth), chan->name);
+            if(chanuser_row[2] && strcmp(chanuser_row[2], ""))
+                reply(textclient, user, "[%s] %s", (nick ? nick : auth), chanuser_row[2]);
+        } else if(!strcmp(user_row[2], "1")) {
+            if(nick)
+                reply(textclient, user, "NS_A_LACKS_ACCESS_BUT_GOD_AUTH", nick, auth, chan->name);
+            else
+                reply(textclient, user, "NS_A_LACKS_ACCESS_BUT_GOD_NICK", auth, chan->name);
+        } else
+            reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+    } else
+        reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+    if(target && (target->flags & USERFLAG_ISIRCOP))
+        reply(textclient, user, "NS_A_IS_IRCOP", nick);
+}
diff --git a/src/cmd_neonserv_addban.c b/src/cmd_neonserv_addban.c
new file mode 100644 (file)
index 0000000..b799c4b
--- /dev/null
@@ -0,0 +1,108 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    nick|*auth|*!*@mask
+* argv[1-*]  reason
+*/
+static USERLIST_CALLBACK(neonserv_cmd_addban_userlist_lookup);
+static void neonserv_cmd_addban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mas, char *reason);
+
+struct neonserv_cmd_addban_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *mask;
+    char *reason;
+};
+
+CMD_BIND(neonserv_cmd_addban) {
+    struct neonserv_cmd_addban_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->mask = strdup(argv[0]);
+    if(argc > 1) {
+        cache->reason = strdup(merge_argv(argv, 1, argc));
+    } else
+        cache->reason = NULL;
+    get_userlist(chan, neonserv_cmd_addban_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_addban_userlist_lookup) {
+    struct neonserv_cmd_addban_cache *cache = data;
+    neonserv_cmd_addban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mask, (cache->reason ? cache->reason : "Bye."));
+    free(cache->mask);
+    if(cache->reason)
+        free(cache->reason);
+    free(cache);
+}
+
+static void neonserv_cmd_addban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, char *reason) {
+    int match_count = 0;
+    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    mask = make_banmask(mask, hostmask_buffer);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        cuser = chanuser->user;
+        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+        if(!match(mask, usermask)) {
+            if(isNetworkService(chanuser->user)) {
+                reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                return;
+            }
+            if(isUserProtected(chan, cuser, user)) {
+                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                return;
+            }
+            match_count++;
+            if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
+                reply(textclient, user, "NS_LAME_MASK", mask);
+                return;
+            }
+        }
+    }
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    //check if the provided mask is already banned by another ban
+    char *ban = getBanAffectingMask(chan, mask);
+    if(ban != NULL) {
+        reply(textclient, user, "NS_BAN_ALREADY_ADDED", mask, chan->name);
+        return;
+    }
+    //check if the provided mask affects any existing bans
+    printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(!match(mask, row[0])) {
+            //remove the ban
+            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
+        }
+    }
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    int userid;
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL)
+        userid = atoi(row[0]);
+    else
+        return;
+    //add the ban
+    printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%d', '%s')", chan->channel_id, escape_string(mask), userid, escape_string(reason));
+    putsock(client, "MODE %s +b %s", chan->name, mask);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        cuser = chanuser->user;
+        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+        if(!match(mask, usermask)) {
+            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+        }
+    }
+    reply(textclient, user, "NS_ADDBAN_DONE", mask, chan->name, match_count);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_addtimeban.c b/src/cmd_neonserv_addtimeban.c
new file mode 100644 (file)
index 0000000..8a8d567
--- /dev/null
@@ -0,0 +1,122 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    nick|*auth|*!*@mask
+* argv[1]    time
+* argv[2-*]  reason
+*/
+static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup);
+static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason);
+
+struct neonserv_cmd_addtimeban_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *mask;
+    int duration;
+    char *reason;
+};
+
+CMD_BIND(neonserv_cmd_addtimeban) {
+    int duration = strToTime(user, argv[1]);
+    if(duration < 30) {
+        reply(getTextBot(), user, "NS_TIMEBAN_DURATION_TOO_SHORT", 30);
+        return;
+    }
+    struct neonserv_cmd_addtimeban_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->mask = strdup(argv[0]);
+    cache->duration = duration;
+    if(argc > 2) {
+        cache->reason = strdup(merge_argv(argv, 2, argc));
+    } else
+        cache->reason = NULL;
+    get_userlist(chan, neonserv_cmd_addtimeban_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup) {
+    struct neonserv_cmd_addtimeban_cache *cache = data;
+    neonserv_cmd_addtimeban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mask, cache->duration, (cache->reason ? cache->reason : "Bye."));
+    free(cache->mask);
+    if(cache->reason)
+        free(cache->reason);
+    free(cache);
+}
+
+static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason) {
+    int match_count = 0;
+    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    mask = make_banmask(mask, hostmask_buffer);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        cuser = chanuser->user;
+        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+        if(!match(mask, usermask)) {
+            if(isNetworkService(chanuser->user)) {
+                reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                return;
+            }
+            if(isUserProtected(chan, cuser, user)) {
+                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                return;
+            }
+            match_count++;
+            if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
+                reply(textclient, user, "NS_LAME_MASK", mask);
+                return;
+            }
+        }
+    }
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    //check if the provided mask is already banned by another ban
+    char *ban = getBanAffectingMask(chan, mask);
+    if(ban != NULL) {
+        reply(textclient, user, "NS_BAN_ALREADY_ADDED", mask, chan->name);
+        return;
+    }
+    //check if the provided mask affects any existing bans
+    printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(!match(mask, row[0])) {
+            //remove the ban
+            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
+        }
+    }
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    int userid;
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL)
+        userid = atoi(row[0]);
+    else
+        return;
+    //add the ban
+    printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(mask), (unsigned long) (time(0) + duration), userid, escape_string(reason));
+    int banid = (int) mysql_insert_id(mysql_conn);
+    putsock(client, "MODE %s +b %s", chan->name, mask);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        cuser = chanuser->user;
+        sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+        if(!match(mask, usermask)) {
+            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+        }
+    }
+    char nameBuf[MAXLEN];
+    char banidBuf[20];
+    sprintf(nameBuf, "ban_%d", banid);
+    sprintf(banidBuf, "%d", banid);
+    timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
+    reply(textclient, user, "NS_TIMEBAN_DONE", mask, chan->name, timeToStr(user, duration, 2, nameBuf), match_count);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_adduser.c b/src/cmd_neonserv_adduser.c
new file mode 100644 (file)
index 0000000..c63c176
--- /dev/null
@@ -0,0 +1,139 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+* argv[1] - chan access
+*/
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_adduser_auth_lookup);
+static USERAUTH_CALLBACK(neonserv_cmd_adduser_nick_lookup);
+static void neonserv_cmd_adduser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int access);
+
+struct neonserv_cmd_adduser_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    int access;
+    char *nick;
+};
+
+CMD_BIND(neonserv_cmd_adduser) {
+    int caccess;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    caccess = atoi(argv[1]);
+    if(caccess <= 0 || caccess > 500) {
+        reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
+        return;
+    }
+    if(caccess >= getChannelAccess(user, chan, 0)) {
+        if(isGodMode(user)) {
+            event->flags |= CMDFLAG_OPLOG;
+        } else {
+            reply(getTextBot(), user, "NS_ACCESS_OUTRANKED");
+            return;
+        }
+    }
+    //check own access
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        printf_mysql_query("SELECT `user_user` FROM `users` WHERE `user_user` = '%s'", escape_string(argv[0]));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            neonserv_cmd_adduser_async1(client, getTextBot(), user, chan, event, argv[0], row[0], caccess);
+        } else {
+            //we need to create a new user...
+            //but first lookup the auth to check if it really exists
+            struct neonserv_cmd_adduser_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->access = caccess;
+            cache->nick = strdup(argv[0]);
+            lookup_authname(argv[0], neonserv_cmd_adduser_auth_lookup, cache);
+        }
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_adduser_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth, caccess);
+        } else {
+            struct neonserv_cmd_adduser_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->access = caccess;
+            cache->nick = strdup(argv[0]);
+            get_userauth(cuser, neonserv_cmd_adduser_nick_lookup, cache);
+        }
+    }
+}
+
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_adduser_auth_lookup) {
+    struct neonserv_cmd_adduser_cache *cache = data;
+    if(!exists) {
+        //AUTH_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_AUTH_UNKNOWN", cache->nick);
+    } else
+        neonserv_cmd_adduser_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, cache->nick, auth, cache->access);
+    free(cache->nick);
+    free(cache);
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_adduser_nick_lookup) {
+    struct neonserv_cmd_adduser_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_adduser_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth, cache->access);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_adduser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int caccess) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is already added
+        printf_mysql_query("SELECT `chanuser_access` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            reply(textclient, user, "NS_ADDUSER_ALREADY_ADDED", nick, chan->name, atoi(row[0]));
+            return;
+        }
+    } else {
+        printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(auth));
+        userid = (int) mysql_insert_id(mysql_conn);
+    }
+    printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chan->channel_id, userid, caccess);
+    reply(textclient, user, "NS_ADDUSER_DONE", nick, chan->name, caccess);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_ban.c b/src/cmd_neonserv_ban.c
new file mode 100644 (file)
index 0000000..eec7326
--- /dev/null
@@ -0,0 +1,101 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nick[,*auth[,*!*@mask[...]]]
+*/
+static USERLIST_CALLBACK(neonserv_cmd_ban_userlist_lookup);
+static void neonserv_cmd_ban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *masks);
+
+struct neonserv_cmd_ban_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *masks;
+};
+
+CMD_BIND(neonserv_cmd_ban) {
+    struct neonserv_cmd_ban_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->masks = strdup(merge_argv_char(argv, 0, argc, ','));
+    get_userlist_with_invisible(chan, neonserv_cmd_ban_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_ban_userlist_lookup) {
+    struct neonserv_cmd_ban_cache *cache = data;
+    neonserv_cmd_ban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->masks);
+    free(cache->masks);
+    free(cache);
+}
+
+static void neonserv_cmd_ban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *masks) {
+    int done_masks = 0, provided_masks = 0, skip, match_count, total_match;
+    char *mask, *nextmask;
+    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    nextmask = masks;
+    while((mask = nextmask)) {
+        nextmask = strstr(mask, ",");
+        if(nextmask) {
+            *nextmask = '\0';
+            nextmask++;
+        }
+        provided_masks++;
+        skip = 0;
+        match_count = 0;
+        mask = make_banmask(mask, hostmask_buffer);
+        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+            cuser = chanuser->user;
+            sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+            if(!match(mask, usermask)) {
+                cuser->flags |= USERFLAG_SCRIPTFLAG1; //we mark the user as 'matching'
+                if(isNetworkService(chanuser->user)) {
+                    reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                    skip = 1;
+                    break;
+                }
+                if(isUserProtected(chan, cuser, user)) {
+                    reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                    skip = 1;
+                    break;
+                }
+                match_count++;
+                if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
+                    skip = 1;
+                    reply(textclient, user, "NS_LAME_MASK", mask);
+                    break;
+                }
+            }
+        }
+        if(!skip) {
+            done_masks++;
+            modeBufferBan(modeBuf, mask);
+        }
+    }
+    total_match = 0; // count all users marked as 'matching'
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        cuser = chanuser->user;
+        if(cuser->flags & USERFLAG_SCRIPTFLAG1) {
+            cuser->flags &= ~USERFLAG_SCRIPTFLAG1;
+            total_match++;
+        }
+    }
+    freeModeBuffer(modeBuf);
+    if(done_masks == provided_masks)
+        reply(getTextBot(), user, "NS_BAN_DONE", done_masks, chan->name, total_match);
+    else
+        reply(getTextBot(), user, "NS_BAN_FAIL", client->user->nick);
+    if(done_masks)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_bans.c b/src/cmd_neonserv_bans.c
new file mode 100644 (file)
index 0000000..31231d4
--- /dev/null
@@ -0,0 +1,59 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    (optional) mask
+*/
+CMD_BIND(neonserv_cmd_bans) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    //ban list
+    int i, with_expire = 0, cindex = 0;
+    char triggered_str[MAXLEN], expires_str[MAXLEN];
+    struct Table *table;
+    printf_mysql_query("SELECT `ban_mask`, `user_user`, `ban_triggered`, `ban_timeout`, `ban_reason` FROM `bans` LEFT JOIN `users` ON `ban_owner` = `user_id` WHERE `ban_channel` = '%d'", chan->channel_id);
+    res = mysql_use();
+    table = table_init(5, mysql_num_rows(res) + 1, 0);
+    char *content[5];
+    //add a NULL row (we add values later)
+    content[0] = NULL;
+    content[1] = NULL;
+    content[2] = NULL;
+    content[3] = NULL;
+    content[4] = NULL;
+    table_add(table, content);
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(argc > 0 && match(argv[0], row[0])) continue;
+        content[0] = row[0];
+        content[1] = row[1];
+        content[2] = (strcmp(row[2], "0") ? timeToStr(user, (time(0) - atoi(row[2])), 2, triggered_str) : get_language_string(user, "NS_USERS_SEEN_NEVER"));
+        if(strcmp(row[3], "0")) {
+            if(!with_expire) {
+                //we're using expire times now...
+                for(i = 0; i < cindex; i++)
+                    table_change_field(table, i+1, 3, get_language_string(user, "NS_USERS_SEEN_NEVER"));
+                with_expire = 1;
+            }
+            content[3] = timeToStr(user, (atoi(row[3]) - time(0)), 2, expires_str);
+        } else
+            content[3] = (with_expire ? get_language_string(user, "NS_USERS_SEEN_NEVER") : NULL);
+        content[4] = row[4];
+        cindex++;
+        table_add(table, content);
+    }
+    //now we add the table header
+    content[0] = get_language_string(user, "NS_BANS_HEADER_MASK");
+    content[1] = get_language_string(user, "NS_BANS_HEADER_SETBY");
+    content[2] = get_language_string(user, "NS_BANS_HEADER_TRIGGERED");
+    content[3] = (with_expire ? get_language_string(user, "NS_BANS_HEADER_EXPIRES") : NULL);
+    content[4] = get_language_string(user, "NS_BANS_HEADER_REASON");
+    table_change(table, 0, content);
+    char **table_lines = table_end(table);
+    for(i = 0; i < table->entrys; i++) {
+        reply(getTextBot(), user, table_lines[i]);
+    }
+    if(!cindex)
+        reply(getTextBot(), user, "NS_TABLE_NONE");
+    reply(getTextBot(), user, "NS_TABLE_COUNT", cindex);
+    table_free(table);
+}
diff --git a/src/cmd_neonserv_bind.c b/src/cmd_neonserv_bind.c
new file mode 100644 (file)
index 0000000..3c80478
--- /dev/null
@@ -0,0 +1,35 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]   command name
+* argv[1]   command function
+* argv[2-*] parameters (optional)
+*/
+
+CMD_BIND(neonserv_cmd_bind) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `function` FROM `bot_binds` WHERE `botclass` = '%d' AND `command` = '%s'", client->botid, escape_string(argv[0]));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        reply(getTextBot(), user, "NS_BIND_ALREADY", argv[0], row[0]);
+        return;
+    }
+    char *params;
+    if(argc > 2)
+        params = merge_argv(argv, 2, argc);
+    else
+        params = "";
+    struct cmd_function *function = find_cmd_function(client->botid, argv[1]);
+    if(!function) {
+        reply(getTextBot(), user, "NS_BIND_UNKNOWN", argv[1]);
+        return;
+    }
+    bind_cmd_to_function(client->botid, argv[0], function);
+    if(*params)
+        bind_set_parameters(client->botid, argv[0], params);
+    printf_mysql_query("INSERT INTO `bot_binds` (`botclass`, `command`, `function`, `parameters`) VALUES ('%d', '%s', '%s', '%s')", client->botid, escape_string(argv[0]), escape_string(function->name), params);
+    reply(getTextBot(), user, "NS_BIND_DONE", argv[0], function->name);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_chanservsync.c b/src/cmd_neonserv_chanservsync.c
new file mode 100644 (file)
index 0000000..5603300
--- /dev/null
@@ -0,0 +1,249 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - botnick
+* argv[1] - key
+*/
+#define CHANSERVSYNC_END_TIMEOUT 5
+
+static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message);
+static void neonserv_cmd_chanservsync_free_cache();
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_chanservsync_auth_lookup);
+static void neonserv_cmd_chanservsync_synchronize_user(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *username, int userid, int caccess, time_t seen, int flags, int new);
+
+struct neonserv_cmd_chanservsync_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    char *botnick;
+    time_t last_response;
+};
+
+struct neonserv_cmd_chanservsync_auth_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    int caccess;
+    time_t seen;
+    int flags;
+};
+
+struct neonserv_cmd_chanservsync_cache *neonserv_cmd_chanservsync_used = NULL;
+const char* neonserv_cmd_chanservsync_supported[] = {"ChanServ", NULL};
+
+CMD_BIND(neonserv_cmd_chanservsync) {
+    if(neonserv_cmd_chanservsync_used && time(0) - neonserv_cmd_chanservsync_used->last_response < CHANSERVSYNC_END_TIMEOUT) {
+        reply(getTextBot(), user, "NS_CHANSERVSYNC_INUSE");
+        return;
+    }
+    if(neonserv_cmd_chanservsync_used) {
+        neonserv_cmd_chanservsync_free_cache();
+    }
+    char *botnick = "ChanServ";
+    char *key = "";
+    if(argc) {
+        if(argv[0][0] == '!') {
+            key = argv[0];
+        } else {
+            botnick = argv[0];
+            if(argc > 1)
+                key = argv[1];
+        }
+    }
+    int seed = 0;
+    char *tmp;
+    char synckey[18];
+    for(tmp = user->auth; *tmp; tmp++)
+        seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+    for(tmp = chan->name; *tmp; tmp++)
+        seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+    for(tmp = botnick; *tmp; tmp++)
+        seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+    sprintf(synckey, "!%08x!", seed);
+    if(strcmp(synckey, key)) {
+        int f = 0;
+        const char **supp = neonserv_cmd_chanservsync_supported;
+        while(*supp) {
+            if(!stricmp(*supp, botnick)) {
+                f = 1;
+                break;
+            }
+            supp++;
+        }
+        if(!f) {
+            reply(getTextBot(), user, "NS_CHANSERVSYNC_UNSUPPORTED", botnick, client->user->nick);
+        }
+        reply(getTextBot(), user, "NS_CHANSERVSYNC_KEY", client->user->nick, botnick, botnick, synckey);
+        return;
+    }
+    struct neonserv_cmd_chanservsync_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->chan = chan;
+    cache->botnick = strdup(botnick);
+    cache->last_response = time(0);
+    neonserv_cmd_chanservsync_used = cache;
+    putsock(client, "PRIVMSG %s :users %s", botnick, chan->name);
+    bind_privnotice(neonserv_cmd_chanservsync_notice_listener);
+    reply(getTextBot(), user, "NS_CHANSERVSYNC_SYNCHRONIZING", chan->name, botnick);
+    logEvent(event);
+}
+
+static void neonserv_cmd_chanservsync_notice_listener(struct UserNode *user, struct UserNode *target, char *message) {
+    if(neonserv_cmd_chanservsync_used && neonserv_cmd_chanservsync_used->client->user == target && !stricmp(user->nick, neonserv_cmd_chanservsync_used->botnick)) {
+        //we've got a notice from our bot...
+        //let's try parsing it....
+        char *p = message;
+        char *tokens[MAXLEN];
+        int tokensPos = 0;
+        while(*p == ' ') //skip leading spaces (airb0t)
+            p++;
+        message = p;
+        char *q = p;
+        while(*q) {
+            if(*q < 32) *q = ' ';
+            q++;
+        }
+        while((q = strstr(p, " "))) {
+            *q = '\0';
+            do {
+                q++;
+            } while(*q == ' ');
+            if(*p) {
+                tokens[tokensPos++] = p;
+            }
+            p = q;
+        }
+        if(*p) {
+            tokens[tokensPos++] = p;
+        }
+        int caccess;
+        char *username;
+        if(tokensPos == 1) {
+            //maybe a chip-like userlist
+            if(tokens[0][0] == '@') {
+                caccess = 200;
+                username = &tokens[0][1];
+            } else if(tokens[0][0] == '+') {
+                caccess = 100;
+                username = &tokens[0][1];
+            } else
+                return;
+        } else if(tokensPos >= 2) {
+            caccess = atoi(tokens[0]);
+            username = tokens[1];
+        } else
+            return;
+        if(caccess < 1 || caccess > 500) return;
+        int flags = 0;
+        time_t now = time(0);
+        time_t seen_time = now; //now - now = 0 (never)
+        neonserv_cmd_chanservsync_used->last_response = now;
+        if(strlen(username) < 3) return;
+        //ok we have access and username... maybe there is something else we can parse???
+        char *seen = NULL;
+        char *status = NULL;
+        if(tokensPos > 2) {
+            if(!stricmp("normal", tokens[2]) || !stricmp("suspended", tokens[2]) || !stricmp("bot", tokens[2])) {
+                status = tokens[2];
+                if (tokensPos > 3) {
+                    seen = merge_argv(tokens, 3, tokensPos);
+                }
+            } else if (tokensPos > 3) {
+                if(!stricmp("normal", tokens[tokensPos-1]) || !stricmp("suspended", tokens[tokensPos-1]) || !stricmp("bot", tokens[tokensPos-1])) {
+                    status = tokens[tokensPos-1];
+                    seen = merge_argv(tokens, 2, tokensPos-1);
+                } else {
+                    seen = merge_argv(tokens, 2, tokensPos);
+                }
+            } else {
+                seen = merge_argv(tokens, 2, tokensPos);
+            }
+        }
+        if(status && !stricmp(status, "suspended")) {
+            flags |= DB_CHANUSER_SUSPENDED;
+        }
+        if(seen) {
+            if(!stricmp(seen, "here"))
+                seen_time = 0;
+            else if(stricmp(seen, "never"))
+                seen_time = strToTime(user, seen);
+        }
+        seen_time = now - seen_time;
+        //we've collected all information now. synchronize the user (use the higher access if the user is already added)
+        MYSQL_RES *res;
+        MYSQL_ROW row;
+        int userid;
+        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(username));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            userid = atoi(row[0]);
+            neonserv_cmd_chanservsync_synchronize_user(neonserv_cmd_chanservsync_used->client, neonserv_cmd_chanservsync_used->textclient, neonserv_cmd_chanservsync_used->user, neonserv_cmd_chanservsync_used->chan, username, userid, caccess, seen_time, flags, 0);
+        } else if(!stricmp(user->nick, "chanserv")) {
+            printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(username));
+            userid = (int) mysql_insert_id(mysql_conn);
+            neonserv_cmd_chanservsync_synchronize_user(neonserv_cmd_chanservsync_used->client, neonserv_cmd_chanservsync_used->textclient, neonserv_cmd_chanservsync_used->user, neonserv_cmd_chanservsync_used->chan, username, userid, caccess, seen_time, flags, 1);
+        } else {
+            //lookup auth
+            struct neonserv_cmd_chanservsync_auth_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = neonserv_cmd_chanservsync_used->client;
+            cache->textclient = neonserv_cmd_chanservsync_used->textclient;
+            cache->user = neonserv_cmd_chanservsync_used->user;
+            cache->chan = neonserv_cmd_chanservsync_used->chan;
+            cache->caccess = caccess;
+            cache->seen = seen_time;
+            cache->flags = flags;
+            lookup_authname(username, neonserv_cmd_chanservsync_auth_lookup, cache);
+        }
+    }
+}
+
+static void neonserv_cmd_chanservsync_free_cache() {
+    free(neonserv_cmd_chanservsync_used->botnick);
+    free(neonserv_cmd_chanservsync_used);
+    unbind_privnotice(neonserv_cmd_chanservsync_notice_listener);
+    neonserv_cmd_chanservsync_used = NULL;
+}
+
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_chanservsync_auth_lookup) {
+    struct neonserv_cmd_chanservsync_auth_cache *cache = data;
+    if(exists) {
+        printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(auth));
+        int userid = (int) mysql_insert_id(mysql_conn);
+        neonserv_cmd_chanservsync_synchronize_user(cache->client, cache->textclient, cache->user, cache->chan, auth, userid, cache->caccess, cache->seen, cache->flags, 1);
+    }
+    free(cache);
+}
+
+static void neonserv_cmd_chanservsync_synchronize_user(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *username, int userid, int caccess, time_t seen, int flags, int new) {
+    //just sync the user with the given userid with the providet information
+    if(caccess == 500) caccess = 499;
+    if(new) {
+        //just add
+        printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`, `chanuser_seen`, `chanuser_flags`) VALUES ('%d', '%d', '%d', '%lu', '%d')", chan->channel_id, userid, caccess, (unsigned long) seen, flags);
+    } else {
+        MYSQL_RES *res;
+        MYSQL_ROW row;
+        //check if already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            //clvl
+            if(atoi(row[0]) >= caccess) return;
+            if(atol(row[2]) > seen) seen = atol(row[2]);
+            printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '%d', `chanuser_seen` = '%lu' WHERE `chanuser_id` = '%s'", caccess, (unsigned long) seen, row[1]);
+        } else 
+            printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`, `chanuser_seen`, `chanuser_flags`) VALUES ('%d', '%d', '%d', '%lu', '%d')", chan->channel_id, userid, caccess, (unsigned long) seen, flags);
+    }
+    reply(textclient, user, "NS_CHANSERVSYNC_SYNCHRONIZED", username, caccess);
+}
diff --git a/src/cmd_neonserv_clvl.c b/src/cmd_neonserv_clvl.c
new file mode 100644 (file)
index 0000000..ff386b2
--- /dev/null
@@ -0,0 +1,106 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+* argv[1] - access
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_clvl_nick_lookup);
+static void neonserv_cmd_clvl_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int caccess);
+
+struct neonserv_cmd_clvl_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+    int access;
+};
+
+CMD_BIND(neonserv_cmd_clvl) {
+    int caccess;
+    caccess = atoi(argv[1]);
+    if(caccess <= 0 || caccess > 500) {
+        reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
+        return;
+    }
+    if(caccess >= getChannelAccess(user, chan, 0)) {
+        if(isGodMode(user)) {
+            event->flags |= CMDFLAG_OPLOG;
+        } else {
+            reply(getTextBot(), user, "NS_ACCESS_OUTRANKED");
+            return;
+        }
+    }
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        neonserv_cmd_clvl_async1(client, getTextBot(), user, chan, event, argv[0], argv[0], caccess);
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_clvl_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth, caccess);
+        } else {
+            struct neonserv_cmd_clvl_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[0]);
+            cache->access = caccess;
+            get_userauth(cuser, neonserv_cmd_clvl_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_clvl_nick_lookup) {
+    struct neonserv_cmd_clvl_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_clvl_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth, cache->access);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_clvl_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, int caccess) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            //clvl
+            if(atoi(row[0]) >= getChannelAccess(user, chan, 1)) {
+                reply(textclient, user, "NS_USER_OUTRANKED", nick);
+                return;
+            }
+            printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '%d' WHERE `chanuser_id` = '%s'", caccess, row[1]);
+            reply(textclient, user, "NS_CLVL_DONE", nick, caccess, chan->name);
+            logEvent(event);
+            return;
+        }
+    }
+    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+}
diff --git a/src/cmd_neonserv_command.c b/src/cmd_neonserv_command.c
new file mode 100644 (file)
index 0000000..0f34ea0
--- /dev/null
@@ -0,0 +1,151 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-1]     command
+*/
+static int neonserv_cmd_command_chanaccess(struct cmd_binding *cbind, struct ChanNode *chan);
+static int neonserv_cmd_command_operaccess(struct cmd_binding *cbind);
+
+CMD_BIND(neonserv_cmd_command) {
+    char *ident;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    struct cmd_binding *cbind = find_cmd_binding(client->botid, argv[0]);
+    if (!cbind) {
+        reply(getTextBot(), user, "NS_UNBIND_NOT_FOUND", argv[0]);
+        return;
+    }
+    ident = argv[0];
+    reply(getTextBot(), user, "NS_COMMAND_BINDING", cbind->cmd, cbind->func->name, (cbind->parameters ? cbind->parameters : ""));
+    if(chan)
+        reply(getTextBot(), user, "NS_COMMAND_ACCESS", neonserv_cmd_command_chanaccess(cbind, chan), neonserv_cmd_command_operaccess(cbind));
+    printf_mysql_query("SELECT `user_lang` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    char *lang;
+    if ((row = mysql_fetch_row(res)) != NULL)
+        lang = row[0];
+    else
+        lang = "en";
+    printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = '%s' AND `ident` = '%s'", escape_string(lang), escape_string(ident));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        if(stricmp(lang, "en")) {
+            printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = 'en' AND `ident` = '%s'", escape_string(ident));
+            res = mysql_use();
+        }
+        if ((row = mysql_fetch_row(res)) == NULL) {
+            printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = '%s' AND `ident` = '%s'", escape_string(lang), escape_string(cbind->func->name));
+            res = mysql_use();
+            if ((row = mysql_fetch_row(res)) == NULL) {
+                if(stricmp(lang, "en")) {
+                    printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = 'en' AND `ident` = '%s'", escape_string(cbind->func->name));
+                    res = mysql_use();
+                }
+                if ((row = mysql_fetch_row(res)) == NULL) {
+                    return;
+                }
+            }
+        }
+    }
+    char sendBuf[MAXLEN];
+    int sendBufPos = 0;
+    int i;
+    for(i = 0; i < strlen(row[0]); i++) {
+        switch(row[0][i]) {
+            case '\n':
+                if(sendBufPos) {
+                    sendBuf[sendBufPos] = '\0';
+                    reply(getTextBot(), user, "%s", sendBuf);
+                    sendBufPos = 0;
+                }
+                break;
+            case '$':
+                switch(row[0][i+1]) {
+                    case 'b':
+                        sendBuf[sendBufPos++] = '\002';
+                        i++;
+                        break;
+                    case 'k':
+                        sendBuf[sendBufPos++] = '\003';
+                        i++;
+                        break;
+                    case 'u':
+                        sendBuf[sendBufPos++] = '\031';
+                        i++;
+                        break;
+                    case 'C':
+                    case 'S':
+                        sendBufPos += sprintf(sendBuf + sendBufPos, "%s", client->user->nick);
+                        i++;
+                        break;
+                    default:
+                        sendBuf[sendBufPos++] = '$';
+                        break;
+                }
+                break;
+            default:
+                sendBuf[sendBufPos++] = row[0][i];
+                break;
+        }
+    }
+    if(sendBufPos) {
+        sendBuf[sendBufPos] = '\0';
+        reply(getTextBot(), user, "%s", sendBuf);
+        sendBufPos = 0;
+    }
+}
+
+static int neonserv_cmd_command_chanaccess(struct cmd_binding *cbind, struct ChanNode *chan) {
+    char access_list[256];
+    int access_pos = 0;
+    int access_count = 0;
+    int minaccess = 0;
+    char *str_a, *str_b = cbind->func->channel_access, *str_c;
+    if(cbind->flags & CMDFLAG_OVERRIDE_CHANNEL_ACCESS)
+        str_b = cbind->channel_access;
+    access_list[0] = '\0';
+    if(str_b) {
+        str_c = strdup(str_b);
+        str_b = str_c;
+        while((str_a = str_b)) {
+            str_b = strstr(str_a, ",");
+            if(str_b) {
+                *str_b = '\0';
+                str_b++;
+            }
+            if(*str_a == '#') {
+                str_a++;
+                access_pos += sprintf(access_list+access_pos, (access_pos ? ", `%s`" : "`%s`"), str_a);
+                access_count++;
+            } else {
+               if(atoi(str_a) > minaccess)
+                     minaccess = atoi(str_a);
+            }
+        }
+        free(str_c);
+    }
+    if(access_count) {
+        MYSQL_RES *res;
+        MYSQL_ROW row, defaults = NULL;
+        printf_mysql_query("SELECT %s FROM `channels` WHERE `channel_name` = '%s'", access_list, escape_string(chan->name));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            int i, caccess;
+            for(i = 0; i < access_count; i++) {
+                if(!row[i] && !defaults) {
+                    printf_mysql_query("SELECT %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
+                    defaults = mysql_fetch_row(mysql_use());
+                }
+                caccess = (row[i] ? atoi(row[i]) : atoi(defaults[i]));
+                if(caccess > minaccess)
+                     minaccess = caccess;
+            }
+        }
+    }
+    return minaccess;
+}
+
+static int neonserv_cmd_command_operaccess(struct cmd_binding *cbind) {
+    return ((cbind->flags & CMDFLAG_OVERRIDE_GLOBAL_ACCESS) ? cbind->global_access : cbind->func->global_access);
+}
diff --git a/src/cmd_neonserv_csuspend.c b/src/cmd_neonserv_csuspend.c
new file mode 100644 (file)
index 0000000..23b2381
--- /dev/null
@@ -0,0 +1,46 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - channel
+*/
+CMD_BIND(neonserv_cmd_csuspend) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    char *channel = argv[0];
+    if(!is_valid_chan(channel)) {
+        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
+        return;
+    }
+    int chanid;
+    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        chanid = atoi(row[0]);
+    } else {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    if(!strcmp(row[2], "1")) {
+        reply(getTextBot(), user, "NS_CSUSPEND_ALREADY", channel);
+        return;
+    }
+    int botid = atoi(row[0]);
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->clientid == botid)
+            break;
+    }
+    if(bot) {
+        putsock(bot, "PART %s :Channel suspended.", channel);
+    }
+    printf_mysql_query("UPDATE `bot_channels` SET `suspended` = '1' WHERE `id` = '%s'", row[1]);
+    reply(getTextBot(), user, "NS_CSUSPEND_DONE", channel);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_cunsuspend.c b/src/cmd_neonserv_cunsuspend.c
new file mode 100644 (file)
index 0000000..0902ff2
--- /dev/null
@@ -0,0 +1,46 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - channel
+*/
+CMD_BIND(neonserv_cmd_cunsuspend) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    char *channel = argv[0];
+    if(!is_valid_chan(channel)) {
+        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
+        return;
+    }
+    int chanid;
+    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        chanid = atoi(row[0]);
+    } else {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    if(!strcmp(row[2], "0")) {
+        reply(getTextBot(), user, "NS_CUNSUSPEND_NOT", channel);
+        return;
+    }
+    int botid = atoi(row[0]);
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->clientid == botid)
+            break;
+    }
+    if(bot) {
+        putsock(bot, "JOIN %s", channel);
+    }
+    printf_mysql_query("UPDATE `bot_channels` SET `suspended` = '0' WHERE `id` = '%s'", row[1]);
+    reply(getTextBot(), user, "NS_CUNSUSPEND_DONE", channel);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_delban.c b/src/cmd_neonserv_delban.c
new file mode 100644 (file)
index 0000000..ac8b696
--- /dev/null
@@ -0,0 +1,41 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    nick|*auth|*!*@mask
+*/
+
+CMD_BIND(neonserv_cmd_delban) {
+    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
+    char *mask = make_banmask(argv[0], hostmask_buffer);
+    int matching_bans = 0;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    //check if the provided mask is already banned by another ban
+    char *ban = getBanAffectingMask(chan, mask);
+    if(ban != NULL) {
+        reply(getTextBot(), user, "NS_DELBAN_BANNED_BY", mask, ban);
+        return;
+    }
+    //check if the provided mask affects any existing bans
+    char nameBuf[20];
+    printf_mysql_query("SELECT `ban_mask`, `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(!match(mask, row[0])) {
+            //remove the ban
+            if(strcmp(row[2], "0")) {
+                sprintf(nameBuf, "ban_%s", row[1]);
+                timeq_del_name(nameBuf);
+            }
+            printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
+            matching_bans++;
+        }
+    }
+    if(matching_bans) {
+        putsock(client, "MODE %s -b %s", chan->name, mask);
+        reply(getTextBot(), user, "NS_DELBAN_DONE", mask, chan->name);
+        logEvent(event);
+    } else
+        reply(getTextBot(), user, "NS_DELBAN_FAIL", mask);
+}
diff --git a/src/cmd_neonserv_delme.c b/src/cmd_neonserv_delme.c
new file mode 100644 (file)
index 0000000..daf6ff4
--- /dev/null
@@ -0,0 +1,42 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - key
+*/
+
+CMD_BIND(neonserv_cmd_delme) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            //check key
+            int seed = 0;
+            char *tmp;
+            static char unregkey[16];
+            for(tmp = user->auth; *tmp; tmp++)
+                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+            for(tmp = chan->name; *tmp; tmp++)
+                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+            sprintf(unregkey, "%08x", seed);
+            if(argc < 1 || strcmp(argv[0], unregkey)) {
+                reply(getTextBot(), user, "NS_DELME_KEY", unregkey);
+                return;
+            } else {
+                //delete
+                printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[1]);
+                reply(getTextBot(), user, "NS_DELME_DONE", atoi(row[0]), chan->name);
+                logEvent(event);
+                return;
+            }
+        }
+    }
+    reply(getTextBot(), user, "NS_NOT_ON_USERLIST_YOU", chan->name);
+}
diff --git a/src/cmd_neonserv_deluser.c b/src/cmd_neonserv_deluser.c
new file mode 100644 (file)
index 0000000..b6ff283
--- /dev/null
@@ -0,0 +1,93 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_deluser_nick_lookup);
+static void neonserv_cmd_deluser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
+
+struct neonserv_cmd_deluser_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+};
+
+CMD_BIND(neonserv_cmd_deluser) {
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        neonserv_cmd_deluser_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_deluser_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
+        } else {
+            struct neonserv_cmd_deluser_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[0]);
+            get_userauth(cuser, neonserv_cmd_deluser_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_deluser_nick_lookup) {
+    struct neonserv_cmd_deluser_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_deluser_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_deluser_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
+                    return;
+                }
+            }
+            //delete
+            printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[1]);
+            reply(textclient, user, "NS_DELUSER_DONE", nick, atoi(row[0]), chan->name);
+            logEvent(event);
+            return;
+        }
+    }
+    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+}
diff --git a/src/cmd_neonserv_deop.c b/src/cmd_neonserv_deop.c
new file mode 100644 (file)
index 0000000..d0ee75e
--- /dev/null
@@ -0,0 +1,77 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nicks
+*/
+static USERLIST_CALLBACK(neonserv_cmd_deop_userlist_lookup);
+static void neonserv_cmd_deop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc);
+
+struct neonserv_cmd_deop_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char **argv;
+    int argc;
+};
+
+CMD_BIND(neonserv_cmd_deop) {
+    struct neonserv_cmd_deop_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->argv = calloc(argc, sizeof(char*));
+    int i;
+    for(i = 0; i < argc; i++) {
+        cache->argv[i] = strdup(argv[i]);
+    }
+    cache->argc = argc;
+    get_userlist(chan, neonserv_cmd_deop_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_deop_userlist_lookup) {
+    struct neonserv_cmd_deop_cache *cache = data;
+    neonserv_cmd_deop_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->argv, cache->argc);
+    int i;
+    for(i = 0; i < cache->argc; i++) {
+        free(cache->argv[i]);
+    }
+    free(cache);
+}
+
+static void neonserv_cmd_deop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc) {
+    int i, done_users = 0;
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    for(i = 0; i < argc; i++) {
+        cuser = searchUserByNick(argv[i]);
+        if(!cuser) continue;
+        chanuser = getChanUser(cuser, chan);
+        if(!chanuser) continue;
+        if(isNetworkService(cuser)) {
+            reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
+            continue;
+        }
+        if(isUserProtected(chan, cuser, user)) {
+            reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+            continue;
+        }
+        done_users++;
+        if(!(chanuser->flags & CHANUSERFLAG_OPPED)) continue;
+        modeBufferDeop(modeBuf, argv[i]);
+    }
+    freeModeBuffer(modeBuf);
+    if(done_users == argc)
+        reply(textclient, user, "NS_DEOP_DONE", chan->name);
+    else
+        reply(textclient, user, "NS_DEOP_FAIL", client->user->nick);
+    if(done_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_deopall.c b/src/cmd_neonserv_deopall.c
new file mode 100644 (file)
index 0000000..f9ee763
--- /dev/null
@@ -0,0 +1,68 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    (optional) nick mask
+*/
+static USERLIST_CALLBACK(neonserv_cmd_deopall_userlist_lookup);
+static void neonserv_cmd_deopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc);
+
+struct neonserv_cmd_deopall_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char **argv;
+    int argc;
+};
+
+CMD_BIND(neonserv_cmd_deopall) {
+    struct neonserv_cmd_deopall_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->argv = calloc(argc, sizeof(char*));
+    int i;
+    for(i = 0; i < argc; i++) {
+        cache->argv[i] = strdup(argv[i]);
+    }
+    cache->argc = argc;
+    get_userlist(chan, neonserv_cmd_deopall_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_deopall_userlist_lookup) {
+    struct neonserv_cmd_deopall_cache *cache = data;
+    neonserv_cmd_deopall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->argv, cache->argc);
+    int i;
+    for(i = 0; i < cache->argc; i++) {
+        free(cache->argv[i]);
+    }
+    free(cache);
+}
+
+static void neonserv_cmd_deopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc) {
+    int issuer_access, victim_access, done_users = 0;
+    char *nickmask = NULL;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    if(argc > 0)
+        nickmask = argv[0];
+    modeBuf = initModeBuffer(client, chan);
+    issuer_access = getChannelAccess(user, chan, 0);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+        victim_access = getChannelAccess(user, chan, 0);
+        if(victim_access >= issuer_access) continue;
+        if(!(chanuser->flags & CHANUSERFLAG_OPPED)) continue;
+        modeBufferDeop(modeBuf, chanuser->user->nick);
+        done_users++;
+    }
+    freeModeBuffer(modeBuf);
+    reply(getTextBot(), user, "NS_DEOPALL_DONE", done_users, chan->name);
+    if(done_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_devoice.c b/src/cmd_neonserv_devoice.c
new file mode 100644 (file)
index 0000000..6994679
--- /dev/null
@@ -0,0 +1,34 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nicks
+*/
+
+CMD_BIND(neonserv_cmd_devoice) {
+    int i, done_users = 0;
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    for(i = 0; i < argc; i++) {
+        cuser = searchUserByNick(argv[i]);
+        if(!cuser) continue;
+        chanuser = getChanUser(cuser, chan);
+        if(!chanuser) continue;
+        if(isUserProtected(chan, cuser, user)) {
+            reply(getTextBot(), user, "NS_USER_PROTECTED", cuser->nick);
+            continue;
+        }
+        done_users++;
+        if(!(chanuser->flags & CHANUSERFLAG_VOICED)) continue;
+        modeBufferDevoice(modeBuf, argv[i]);
+    }
+    freeModeBuffer(modeBuf);
+    if(done_users == argc)
+        reply(getTextBot(), user, "NS_DEVOICE_DONE", chan->name);
+    else
+        reply(getTextBot(), user, "NS_DEVOICE_FAIL", client->user->nick);
+    if(done_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_devoiceall.c b/src/cmd_neonserv_devoiceall.c
new file mode 100644 (file)
index 0000000..3c201af
--- /dev/null
@@ -0,0 +1,34 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    (optional) nick mask
+*/
+
+CMD_BIND(neonserv_cmd_devoiceall) {
+    int issuer_access, victim_access, done_users = 0;
+    char *nickmask = NULL;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    check_mysql();
+    if(!checkChannelAccess(user, chan, "channel_canvoice", 1, 0)) {
+        reply(getTextBot(), user, "NS_ACCESS_DENIED");
+        return;
+    }
+    if(argc > 0)
+        nickmask = argv[0];
+    modeBuf = initModeBuffer(client, chan);
+    issuer_access = getChannelAccess(user, chan, 0);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+        victim_access = getChannelAccess(user, chan, 0);
+        if(victim_access >= issuer_access) continue;
+        if(!(chanuser->flags & CHANUSERFLAG_VOICED)) continue;
+        modeBufferDevoice(modeBuf, chanuser->user->nick);
+        done_users++;
+    }
+    freeModeBuffer(modeBuf);
+    reply(getTextBot(), user, "NS_DEVOICEALL_DONE", done_users, chan->name);
+    if(done_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_down.c b/src/cmd_neonserv_down.c
new file mode 100644 (file)
index 0000000..e504070
--- /dev/null
@@ -0,0 +1,22 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no arguments
+*/
+
+CMD_BIND(neonserv_cmd_down) {
+    struct ChanUser *chanuser = getChanUser(user, chan);
+    if(!chanuser) {
+        reply(getTextBot(), user, "NS_NOT_ON_CHANNEL_YOU", chan->name);
+        return;
+    }
+    if((chanuser->flags & CHANUSERFLAG_OPPED)) {
+        putsock(client, "MODE %s -ov %s %s", chan->name, user->nick, user->nick);
+        logEvent(event);
+    } else if((chanuser->flags & CHANUSERFLAG_VOICED)) {
+        putsock(client, "MODE %s -v %s", chan->name, user->nick);
+        logEvent(event);
+    } else
+        reply(getTextBot(), user, "NS_DOWN_ALREADY", chan->name);
+}
diff --git a/src/cmd_neonserv_downall.c b/src/cmd_neonserv_downall.c
new file mode 100644 (file)
index 0000000..1d001c9
--- /dev/null
@@ -0,0 +1,31 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no arguments
+*/
+
+CMD_BIND(neonserv_cmd_downall) {
+    struct ChanUser *chanuser;
+    for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = getUserChannels(user, chanuser)) {
+        chan = chanuser->chan;
+        loadChannelSettings(chan);
+        if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) continue;
+        printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, client->botid);
+        if (mysql_fetch_row(mysql_use()) == NULL) continue;
+        int done = 0;
+        if((chanuser->flags & CHANUSERFLAG_OPPED)) {
+            putsock(client, "MODE %s -o %s", chan->name, user->nick);
+            done = 1;
+        }
+        if((chanuser->flags & CHANUSERFLAG_VOICED)) {
+            putsock(client, "MODE %s -v %s", chan->name, user->nick);
+            done = 1;
+        }
+        if(done) {
+            //event hack
+            event->chan = chan;
+            logEvent(event);
+        }
+    }
+}
diff --git a/src/cmd_neonserv_emote.c b/src/cmd_neonserv_emote.c
new file mode 100644 (file)
index 0000000..427a30f
--- /dev/null
@@ -0,0 +1,12 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    target
+* argv[1-*]  message
+*/
+
+CMD_BIND(neonserv_cmd_emote) {
+    char *message = merge_argv(argv, 1, argc);
+    putsock(client, "PRIVMSG %s :\001ACTION %s\001", argv[0], message);
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_events.c b/src/cmd_neonserv_events.c
new file mode 100644 (file)
index 0000000..23ecf3c
--- /dev/null
@@ -0,0 +1,41 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]     time
+* argv[1-*]   match
+*/
+
+CMD_BIND(neonserv_cmd_events) {
+    char *str_match;
+    int duration = (argc ? strToTime(user, argv[0]) : 0);
+    if(argc > (duration ? 1 : 0))
+        str_match = merge_argv(argv, (duration ? 1 : 0), argc);
+    else
+        str_match = "";
+    if(!duration) duration = (60*60*24);
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `time`, `auth`, `nick`, `command` FROM `events` WHERE `cid` = '%d' AND `time` > '%lu' ORDER BY `time` ASC", chan->channel_id, ((unsigned long) time(0) - duration));
+    res = mysql_use();
+    int skip = mysql_num_rows(res) - 100;
+    int count = 0;
+    char timeBuf[50];
+    struct tm *timeinfo;
+    time_t event_time;
+    if(skip < 0) skip = 0;
+    reply(getTextBot(), user, "NS_EVENTS_HEADER");
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(skip) {
+            skip--;
+            continue;
+        }
+        if(*str_match && match(str_match, row[3])) continue;
+        count++;
+        event_time = (time_t) atol(row[0]);
+        timeinfo = localtime(&event_time);
+        strftime(timeBuf, 80, "%X %x", timeinfo);
+        reply(getTextBot(), user, "[%s] [%s:%s]: %s", timeBuf, row[2], row[1], row[3]);
+    }
+    reply(getTextBot(), user, "NS_TABLE_COUNT", count);
+}
diff --git a/src/cmd_neonserv_giveowner.c b/src/cmd_neonserv_giveowner.c
new file mode 100644 (file)
index 0000000..8f173ac
--- /dev/null
@@ -0,0 +1,121 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+* argv[1] - key
+*/
+
+#define GIVEOWNER_TIMEOUT 86400 /* 60*60*24 = 86400 */
+
+static USERAUTH_CALLBACK(neonserv_cmd_giveowner_nick_lookup);
+static void neonserv_cmd_giveowner_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, char *key);
+
+struct neonserv_cmd_giveowner_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+    char *key;
+};
+
+CMD_BIND(neonserv_cmd_giveowner) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_lastgiveowner` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return;
+    if(strcmp(row[0], "0") && (atoi(row[0]) + GIVEOWNER_TIMEOUT) > time(0)) {
+        char timeBuf[MAXLEN];
+        reply(getTextBot(), user, "NS_GIVEOWNER_TIMEOUT", timeToStr(user, (GIVEOWNER_TIMEOUT - (time(0) - atoi(row[0]))), 2, timeBuf), chan->name);
+        return;
+    }
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        neonserv_cmd_giveowner_async1(client, getTextBot(), user, chan, event, argv[0], argv[0], (argc != 1 ? argv[1] : NULL));
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_giveowner_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth, (argc != 1 ? argv[1] : NULL));
+        } else {
+            struct neonserv_cmd_giveowner_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[0]);
+            cache->key = (argc != 1 ? strdup(argv[1]) : NULL);
+            get_userauth(cuser, neonserv_cmd_giveowner_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_giveowner_nick_lookup) {
+    struct neonserv_cmd_giveowner_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_giveowner_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth, cache->key);
+    free(cache->nick);
+    if(cache->key)
+        free(cache->key);
+    free(cache);
+}
+
+static void neonserv_cmd_giveowner_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth, char *key) {
+    //we've got a valid auth now...
+    if(!stricmp(user->auth, auth)) {
+        reply(textclient, user, "NS_GIVEOWNER_SELF");
+        return;
+    }
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            int seed = 0;
+            char *tmp;
+            char giveownerkey[16];
+            for(tmp = user->auth; *tmp; tmp++)
+                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+            for(tmp = chan->name; *tmp; tmp++)
+                seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+            sprintf(giveownerkey, "%08x", seed);
+            if(key && !stricmp(giveownerkey, key)) {
+                //give ownership
+                printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '500' WHERE `chanuser_id` = '%s'", row[1]);
+                printf_mysql_query("UPDATE `chanusers` SET `chanuser_access` = '499' WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = (SELECT `user_id` FROM `users` WHERE `user_user` = '%s')", chan->channel_id, escape_string(user->auth));
+                printf_mysql_query("INSERT INTO `owner_history` (`owner_history_cid`, `owner_history_uid`, `owner_history_time`) VALUE ('%d', '%d', UNIX_TIMESTAMP())", chan->channel_id, userid);
+                reply(textclient, user, "NS_GIVEOWNER_DONE", chan->name, auth);
+                logEvent(event);
+            } else {
+                reply(textclient, user, "NS_GIVEOWNER_CONFIRM", auth, giveownerkey);
+            }
+            return;
+        }
+    }
+    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+}
diff --git a/src/cmd_neonserv_god.c b/src/cmd_neonserv_god.c
new file mode 100644 (file)
index 0000000..96abaa6
--- /dev/null
@@ -0,0 +1,37 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    (optional) on/off
+*/
+
+CMD_BIND(neonserv_cmd_god) {
+    if(argc > 0) {
+        if(!strcmp(argv[0], "0") || !stricmp(argv[0], "off") || !stricmp(argv[0], get_language_string(user, "NS_SET_OFF"))) {
+            if(isGodMode(user)) {
+                printf_mysql_query("UPDATE `users` SET `user_god` = '0' WHERE `user_user` = '%s'", escape_string(user->auth));
+                user->flags &= ~USERFLAG_GOD_MODE;
+            }
+            reply(getTextBot(), user, "NS_GOD_OFF");
+        } else if(!strcmp(argv[0], "1") || !stricmp(argv[0], "on") || !stricmp(argv[0], get_language_string(user, "NS_SET_ON"))) {
+            if(!isGodMode(user)) {
+                printf_mysql_query("UPDATE `users` SET `user_god` = '1' WHERE `user_user` = '%s'", escape_string(user->auth));
+                user->flags |= USERFLAG_GOD_MODE;
+            }
+            reply(getTextBot(), user, "NS_GOD_ON");
+        } else {
+            reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argv[0]);
+            return;
+        }
+    } else {
+        if(isGodMode(user)) {
+            printf_mysql_query("UPDATE `users` SET `user_god` = '0' WHERE `user_user` = '%s'", escape_string(user->auth));
+            user->flags &= ~USERFLAG_GOD_MODE;
+            reply(getTextBot(), user, "NS_GOD_OFF");
+        } else {
+            printf_mysql_query("UPDATE `users` SET `user_god` = '1' WHERE `user_user` = '%s'", escape_string(user->auth));
+            user->flags |= USERFLAG_GOD_MODE;
+            reply(getTextBot(), user, "NS_GOD_ON");
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_help.c b/src/cmd_neonserv_help.c
new file mode 100644 (file)
index 0000000..081fc22
--- /dev/null
@@ -0,0 +1,81 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]     index
+*/
+
+CMD_BIND(neonserv_cmd_help) {
+    char *ident;
+    if(argc)
+        ident = merge_argv(argv, 0, argc);
+    else
+        ident = "0";
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `user_lang` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    char *lang;
+    if ((row = mysql_fetch_row(res)) != NULL)
+        lang = row[0];
+    else
+        lang = "en";
+    printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = '%s' AND `ident` = '%s'", escape_string(lang), escape_string(ident));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        if(stricmp(lang, "en")) {
+            printf_mysql_query("SELECT `text` FROM `help` WHERE `lang` = 'en' AND `ident` = '%s'", escape_string(ident));
+            res = mysql_use();
+        }
+        if ((row = mysql_fetch_row(res)) == NULL) {
+            reply(getTextBot(), user, "NS_HELP_TOPIC");
+            return;
+        }
+    }
+    char sendBuf[MAXLEN];
+    int sendBufPos = 0;
+    int i;
+    for(i = 0; i < strlen(row[0]); i++) {
+        switch(row[0][i]) {
+            case '\n':
+                if(sendBufPos) {
+                    sendBuf[sendBufPos] = '\0';
+                    reply(getTextBot(), user, "%s", sendBuf);
+                    sendBufPos = 0;
+                }
+                break;
+            case '$':
+                switch(row[0][i+1]) {
+                    case 'b':
+                        sendBuf[sendBufPos++] = '\002';
+                        i++;
+                        break;
+                    case 'k':
+                        sendBuf[sendBufPos++] = '\003';
+                        i++;
+                        break;
+                    case 'u':
+                        sendBuf[sendBufPos++] = '\031';
+                        i++;
+                        break;
+                    case 'C':
+                    case 'S':
+                        sendBufPos += sprintf(sendBuf + sendBufPos, "%s", client->user->nick);
+                        i++;
+                        break;
+                    default:
+                        sendBuf[sendBufPos++] = '$';
+                        break;
+                }
+                break;
+            default:
+                sendBuf[sendBufPos++] = row[0][i];
+                break;
+        }
+    }
+    if(sendBufPos) {
+        sendBuf[sendBufPos] = '\0';
+        reply(getTextBot(), user, "%s", sendBuf);
+        sendBufPos = 0;
+    }
+}
diff --git a/src/cmd_neonserv_invite.c b/src/cmd_neonserv_invite.c
new file mode 100644 (file)
index 0000000..f7fcd62
--- /dev/null
@@ -0,0 +1,160 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_invite_nick_lookup);
+static void neonserv_cmd_invite_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
+static TIMEQ_CALLBACK(neonserv_cmd_invite_timeout_timeout);
+static struct neonserv_cmd_invite_timeout* neonserv_cmd_invite_add_timeout(char *nick, char *chan);
+static int neonserv_cmd_invite_is_timeout(char *nick, char *chan);
+static void neonserv_cmd_invite_del_timeout(struct neonserv_cmd_invite_timeout *timeout);
+
+
+struct neonserv_cmd_invite_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+};
+
+struct neonserv_cmd_invite_timeout {
+    char *nick;
+    char *chan;
+    
+    struct neonserv_cmd_invite_timeout *next;
+};
+
+static struct neonserv_cmd_invite_timeout *first_timeout = NULL, *last_timeout = NULL;
+
+CMD_BIND(neonserv_cmd_invite) {
+    if(neonserv_cmd_invite_is_timeout(argv[0], chan->name)) {
+        reply(getTextBot(), user, "NS_INVITE_TIMEOUT", argv[0], chan->name);
+        return;
+    }
+    struct UserNode *cuser = getUserByNick(argv[0]);
+    if(!cuser) {
+        cuser = createTempUser(argv[0]);
+        cuser->flags |= USERFLAG_ISTMPUSER;
+    } else if(getChanUser(cuser, chan)) {
+        reply(getTextBot(), user, "NS_INVITE_ON_CHAN", cuser->nick, chan->name);
+        /* BUG
+         This check does not work if the user is invisible (CHMODE +D/+d)
+         to fix this we'd need to request the full userlist...
+         this is really senseless to invite a simple user so we simply mark this bug as unsolvable.
+        */
+        return;
+    }
+    if(cuser->flags & USERFLAG_ISAUTHED) {
+        neonserv_cmd_invite_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
+    } else {
+        struct neonserv_cmd_invite_cache *cache = malloc(sizeof(*cache));
+        if (!cache) {
+            perror("malloc() failed");
+            return;
+        }
+        cache->client = client;
+        cache->textclient = getTextBot();
+        cache->user = user;
+        cache->chan = chan;
+        cache->event = event;
+        cache->nick = strdup(argv[0]);
+        get_userauth(cuser, neonserv_cmd_invite_nick_lookup, cache);
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_invite_nick_lookup) {
+    struct neonserv_cmd_invite_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    } else
+        neonserv_cmd_invite_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, ((user->flags & USERFLAG_ISAUTHED) ? user->auth : NULL));
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_invite_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
+    if(auth) {
+        MYSQL_RES *res;
+        MYSQL_ROW row;
+        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            //check if the user has set noinvite
+            printf_mysql_query("SELECT `id` FROM `noinvite` WHERE `uid` = '%s' AND `cid` = '%d'", row[0], chan->channel_id);
+            res = mysql_use();
+            if ((row = mysql_fetch_row(res)) != NULL) {
+                reply(textclient, user, "NS_INVITE_RESTRICTION", nick, chan->name);
+                return;
+            }
+        }
+    }
+    struct neonserv_cmd_invite_timeout *timeout = neonserv_cmd_invite_add_timeout(nick, chan->name);
+    timeq_add(INVITE_TIMEOUT, neonserv_cmd_invite_timeout_timeout, timeout);
+    putsock(client, "INVITE %s %s", nick, chan->name);
+    struct UserNode *tmpu = getUserByNick(nick);
+    if(!tmpu) {
+        tmpu = createTempUser(nick);
+        tmpu->flags |= USERFLAG_ISTMPUSER | (auth ? USERFLAG_ISAUTHED : 0);
+        if(auth)
+            strcpy(tmpu->auth, auth);
+    }
+    reply(textclient, tmpu, "NS_INVITE_DONE_USER", chan->name, user->nick, client->user->nick);
+    reply(textclient, user, "NS_INVITE_DONE", nick, chan->name);
+}
+
+static TIMEQ_CALLBACK(neonserv_cmd_invite_timeout_timeout) {
+    struct neonserv_cmd_invite_timeout *entry = data;
+    neonserv_cmd_invite_del_timeout(entry);
+}
+
+static struct neonserv_cmd_invite_timeout* neonserv_cmd_invite_add_timeout(char *nick, char *chan) {
+    struct neonserv_cmd_invite_timeout *entry = malloc(sizeof(*entry));
+    if (!entry) {
+        perror("malloc() failed");
+        return NULL;
+    }
+    entry->next = NULL;
+    entry->nick = strdup(nick);
+    entry->chan = strdup(chan);
+    if(last_timeout) {
+        last_timeout->next = entry;
+        last_timeout = entry;
+    } else {
+        last_timeout = entry;
+        first_timeout = entry;
+    }
+    return entry;
+}
+
+static int neonserv_cmd_invite_is_timeout(char *nick, char *chan) {
+    if(!first_timeout) return 0;
+    struct neonserv_cmd_invite_timeout *entry;
+    for(entry = first_timeout; entry; entry = entry->next) {
+        if(!stricmp(entry->nick, nick) && !stricmp(entry->chan, chan))
+            return 1;
+    }
+    return 0;
+}
+
+static void neonserv_cmd_invite_del_timeout(struct neonserv_cmd_invite_timeout *timeout) {
+    struct neonserv_cmd_invite_timeout *entry, *prev = NULL;
+    for(entry = first_timeout; entry; entry = entry->next) {
+        if(entry == timeout) {
+            if(prev)
+                prev->next = entry->next;
+            else
+                first_timeout = entry->next;
+            break;
+        } else
+            prev = entry;
+    }
+    if(last_timeout == timeout)
+        last_timeout = prev;
+    free(timeout->nick);
+    free(timeout->chan);
+    free(timeout);
+}
diff --git a/src/cmd_neonserv_inviteme.c b/src/cmd_neonserv_inviteme.c
new file mode 100644 (file)
index 0000000..a5c3f16
--- /dev/null
@@ -0,0 +1,20 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no arguments
+*/
+
+CMD_BIND(neonserv_cmd_inviteme) {
+    if(getChanUser(user, chan)) {
+        reply(getTextBot(), user, "NS_INVITEME_ON_CHAN", chan->name);
+        /* BUG
+         This check does not work if the user is invisible (CHMODE +D/+d)
+         to fix this we'd need to request the full userlist...
+         this is really senseless to invite a simple user so we simply mark this bug as unsolvable.
+        */
+        return;
+    }
+    putsock(client, "INVITE %s %s", user->nick, chan->name);
+    reply(getTextBot(), user, "NS_INVITEME_DONE", chan->name);
+}
diff --git a/src/cmd_neonserv_kick.c b/src/cmd_neonserv_kick.c
new file mode 100644 (file)
index 0000000..373881c
--- /dev/null
@@ -0,0 +1,139 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    nick[,*auth[,*!*@mask[...]]]
+* argv[1-*]  reason
+*/
+static USERLIST_CALLBACK(neonserv_cmd_kick_userlist_lookup);
+static void neonserv_cmd_kick_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason);
+
+struct neonserv_cmd_kick_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *nicks;
+    char *reason;
+};
+
+CMD_BIND(neonserv_cmd_kick) {
+    struct neonserv_cmd_kick_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->nicks = strdup(argv[0]);
+    if(argc > 1) {
+        cache->reason = strdup(merge_argv(argv, 1, argc));
+    } else
+        cache->reason = NULL;
+    get_userlist_with_invisible(chan, neonserv_cmd_kick_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_kick_userlist_lookup) {
+    struct neonserv_cmd_kick_cache *cache = data;
+    neonserv_cmd_kick_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks, (cache->reason ? cache->reason : "Bye."));
+    free(cache->nicks);
+    if(cache->reason)
+        free(cache->reason);
+    free(cache);
+}
+
+static void neonserv_cmd_kick_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason) {
+    int i, kicked_users = 0, provided_nicks = 0;
+    char *nick, *nextnick;
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    nextnick = nicks;
+    while((nick = nextnick)) {
+        nextnick = strstr(nick, ",");
+        if(nextnick) {
+            *nextnick = '\0';
+            nextnick++;
+        }
+        if(!*nick) continue;
+        if(is_ircmask(nick)) {
+            //KICK HOSTMASK
+            char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+            struct ChanUser *kick_chanuser[chan->usercount];
+            int kick_chanuser_pos = 0;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                cuser = chanuser->user;
+                sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+                if(!match(nick, usermask)) {
+                    provided_nicks++;
+                    if(isNetworkService(chanuser->user)) {
+                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                        continue;
+                    }
+                    if(isUserProtected(chan, cuser, user)) {
+                        reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                        continue;
+                    }
+                    kick_chanuser[kick_chanuser_pos++] = chanuser;
+                    if(kick_chanuser_pos > 4 && (kick_chanuser_pos * 3) > chan->usercount && !isGodMode(user)) {
+                        kick_chanuser_pos = 0;
+                        reply(textclient, user, "NS_LAME_MASK", nick);
+                        break;
+                    }
+                }
+            }
+            for(i = 0; i < kick_chanuser_pos; i++) {
+                kicked_users++;
+                putsock(client, "KICK %s %s :%s", chan->name, kick_chanuser[i]->user->nick, reason);
+            }
+        } else if(*nick == '*') {
+            //KICK AUTH
+            nick++;
+            cuser = NULL;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !stricmp(chanuser->user->auth, nick)) {
+                    provided_nicks++;
+                    if(isNetworkService(chanuser->user)) {
+                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                        continue;
+                    }
+                    if(!cuser) {
+                        //check if the user is protected
+                        if(isUserProtected(chan, chanuser->user, user)) {
+                            reply(textclient, user, "NS_USER_PROTECTED", chanuser->user->nick);
+                            break; //all other users are also protected...
+                        }
+                        cuser = chanuser->user;
+                    }
+                    kicked_users++;
+                    putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+                }
+            }
+        } else {
+            provided_nicks++;
+            cuser = NULL;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if(!stricmp(chanuser->user->nick, nick)) {
+                    cuser = chanuser->user;
+                }
+            }
+            if(!cuser) continue;
+            if(isNetworkService(cuser)) {
+                reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
+                continue;
+            }
+            if(isUserProtected(chan, cuser, user)) {
+                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                continue;
+            }
+            kicked_users++;
+            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+        }
+    }
+    if(kicked_users == provided_nicks)
+        reply(getTextBot(), user, "NS_KICK_DONE", kicked_users, chan->name);
+    else
+        reply(getTextBot(), user, "NS_KICK_FAIL", client->user->nick);
+    if(kicked_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_kickban.c b/src/cmd_neonserv_kickban.c
new file mode 100644 (file)
index 0000000..1907706
--- /dev/null
@@ -0,0 +1,141 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    nick[,*auth[,*!*@mask[...]]]
+* argv[1-*]  reason
+*/
+static USERLIST_CALLBACK(neonserv_cmd_kickban_userlist_lookup);
+static void neonserv_cmd_kickban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason);
+
+struct neonserv_cmd_kickban_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *nicks;
+    char *reason;
+};
+
+CMD_BIND(neonserv_cmd_kickban) {
+    struct neonserv_cmd_kickban_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->nicks = strdup(argv[0]);
+    if(argc > 1) {
+        cache->reason = strdup(merge_argv(argv, 1, argc));
+    } else
+        cache->reason = NULL;
+    get_userlist_with_invisible(chan, neonserv_cmd_kickban_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_kickban_userlist_lookup) {
+    struct neonserv_cmd_kickban_cache *cache = data;
+    neonserv_cmd_kickban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks, (cache->reason ? cache->reason : "Bye."));
+    free(cache->nicks);
+    if(cache->reason)
+        free(cache->reason);
+    free(cache);
+}
+
+static void neonserv_cmd_kickban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks, char *reason) {
+    int i, kicked_users = 0, provided_nicks = 0;
+    char *nick, *nextnick;
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    nextnick = nicks;
+    while((nick = nextnick)) {
+        nextnick = strstr(nick, ",");
+        if(nextnick) {
+            *nextnick = '\0';
+            nextnick++;
+        }
+        if(!*nick) continue;
+        if(is_ircmask(nick)) {
+            //KICK HOSTMASK
+            struct ChanUser *kickban_chanuser[chan->usercount];
+            int kick_chanuser_pos = 0;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                cuser = chanuser->user;
+                sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+                if(!match(nick, usermask)) {
+                    provided_nicks++;
+                    if(isNetworkService(chanuser->user)) {
+                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                        continue;
+                    }
+                    if(isUserProtected(chan, cuser, user)) {
+                        reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                        continue;
+                    }
+                    kickban_chanuser[kick_chanuser_pos++] = chanuser;
+                    if(kick_chanuser_pos > 4 && (kick_chanuser_pos * 3) > chan->usercount && !isGodMode(user)) {
+                        kick_chanuser_pos = 0;
+                        reply(textclient, user, "NS_LAME_MASK", nick);
+                        break;
+                    }
+                }
+            }
+            for(i = 0; i < kick_chanuser_pos; i++) {
+                if(i == 0) {
+                    putsock(client, "MODE %s +b %s", chan->name, nick);
+                }
+                kicked_users++;
+                putsock(client, "KICK %s %s :%s", chan->name, kickban_chanuser[i]->user->nick, reason);
+            }
+        } else if(*nick == '*') {
+            //KICK AUTH
+            nick++;
+            cuser = NULL;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !stricmp(chanuser->user->auth, nick)) {
+                    provided_nicks++;
+                    if(isNetworkService(chanuser->user)) {
+                        reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                        continue;
+                    }
+                    if(!cuser) {
+                        //check if the user is protected
+                        if(isUserProtected(chan, chanuser->user, user)) {
+                            reply(textclient, user, "NS_USER_PROTECTED", chanuser->user->nick);
+                            break; //all other users are also protected...
+                        }
+                        cuser = chanuser->user;
+                    }
+                    kicked_users++;
+                    putsock(client, "MODE %s +b %s", chan->name, generate_banmask(cuser, usermask));
+                    putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+                }
+            }
+        } else {
+            provided_nicks++;
+            cuser = searchUserByNick(nick);
+            if(!cuser) continue;
+            chanuser = getChanUser(cuser, chan);
+            if(!chanuser) continue;
+            if(isNetworkService(cuser)) {
+                reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
+                continue;
+            }
+            if(isUserProtected(chan, cuser, user)) {
+                reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                continue;
+            }
+            kicked_users++;
+            putsock(client, "MODE %s +b %s", chan->name, generate_banmask(cuser, usermask));
+            putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+        }
+    }
+    if(kicked_users == provided_nicks)
+        reply(getTextBot(), user, "NS_KICKBAN_DONE", kicked_users, chan->name);
+    else
+        reply(getTextBot(), user, "NS_KICKBAN_FAIL", client->user->nick);
+    if(kicked_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_mdeluser.c b/src/cmd_neonserv_mdeluser.c
new file mode 100644 (file)
index 0000000..5b09822
--- /dev/null
@@ -0,0 +1,48 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]  access (format: minaccess-maxaccess)
+* argv[1]  pattern
+*/
+
+CMD_BIND(neonserv_cmd_mdeluser) {
+    if(!checkChannelAccess(user, chan, "channel_candel", 1, 0)) {
+        reply(getTextBot(), user, "NS_ACCESS_DENIED");
+        return;
+    }
+    int min_access, max_access;
+    char *seperator = strstr(argv[0], "-");
+    if(seperator) {
+        *seperator = '\0';
+        seperator++;
+        min_access = atoi(argv[0]);
+        max_access = atoi(seperator);
+        if(max_access > min_access) {
+            reply(getTextBot(), user, "NS_INVALID_ACCESS_RANGE", min_access, max_access);
+            return;
+        }
+    } else {
+        min_access = atoi(argv[0]);
+        max_access = min_access;
+    }
+    if(max_access >= getChannelAccess(user, chan, 1)) {
+        reply(getTextBot(), user, "NS_NO_ACCESS");
+        return;
+    }
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int del_count = 0;
+    printf_mysql_query("SELECT `user_user`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `chanuser_access` >= '%d' AND `chanuser_access` <= '%d'", chan->channel_id, min_access, max_access);
+    res = mysql_use();
+    while((row = mysql_fetch_row(res)) != NULL) {
+        if(!match(argv[1], row[0])) {
+            del_count++;
+            printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[1]);
+        }
+    }
+    reply(getTextBot(), user, "NS_MDELUSER_DONE", del_count, argv[1], min_access, max_access, chan->name);
+    if(del_count)
+        logEvent(event);
+}
+
diff --git a/src/cmd_neonserv_mode.c b/src/cmd_neonserv_mode.c
new file mode 100644 (file)
index 0000000..f7f2db1
--- /dev/null
@@ -0,0 +1,275 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - modes
+* argv[1-*] - parameters
+*/
+static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup);
+static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode);
+
+struct neonserv_cmd_mode_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *mode;
+};
+
+CMD_BIND(neonserv_cmd_mode) {
+    struct neonserv_cmd_mode_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->mode = strdup(merge_argv(argv, 0, argc));
+    get_userlist_with_invisible(chan, neonserv_cmd_mode_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup) {
+    struct neonserv_cmd_mode_cache *cache = data;
+    neonserv_cmd_mode_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mode);
+    free(cache->mode);
+    free(cache);
+}
+
+static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode) {
+    MYSQL_ROW row, defaults = NULL;
+    int i, arg, add = 1, skip = 0;
+    unsigned int modetype;
+    int db_canop, db_canvoice, db_canban, db_enfmodes;
+    struct ModeNode *modelock = createModeNode(NULL), *changemodes = createModeNode(NULL);
+    struct ModeBuffer *modeBuf;
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    modeBuf = initModeBuffer(client, chan);
+    printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    row = mysql_fetch_row(mysql_use());
+    if(row[0] == NULL || row[1] == NULL || row[2] == NULL || row[3] == NULL) {
+        printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
+        defaults = mysql_fetch_row(mysql_use());
+    }
+    db_canop = atoi((row[0] ? row[0] : defaults[0]));
+    db_canvoice = atoi((row[1] ? row[1] : defaults[1]));
+    db_canban = atoi((row[2] ? row[2] : defaults[2]));
+    db_enfmodes = atoi((row[3] ? row[3] : defaults[3]));
+    if(row[4])
+        parseModeString(modelock, row[4]);
+    else if(defaults[4])
+        parseModeString(modelock, defaults[4]);
+    int uaccess = getChannelAccess(user, chan, 0);
+    char *a, *b = mode;
+    char *argv[MAXNUMPARAMS];
+    char *carg;
+    char tmp[MAXLEN];
+    int argc = 0;
+    do {
+        a = strstr(b, " ");
+        if(a) *a = '\0';
+        argv[argc++] = b;
+        if(argc == MAXNUMPARAMS) break;
+        if(a) b = a+1;
+    } while(a);
+    arg = 0;
+    while(arg < argc) {
+        char *modeStr = argv[arg++];
+        for(i = 0; i < strlen(modeStr); i++) {
+            switch(modeStr[i]) {
+                case '+':
+                    add = 1;
+                    break;
+                case '-':
+                    add = 0;
+                    break;
+                case 'o':
+                case 'v':
+                    if(arg == argc) {
+                        reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
+                        return;
+                    }
+                    carg = argv[arg++];
+                    if(modeStr[i] == 'o') {
+                        if(uaccess < db_canop) {
+                            reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
+                            db_canop = -1;
+                            break;
+                        }
+                        if(db_canop == -1) break;
+                    } else {
+                        if(uaccess < db_canvoice) {
+                            reply(textclient, user, "NS_MODE_ENFVOICE", chan->name);
+                            db_canvoice = -1;
+                            break;
+                        }
+                        if(db_canvoice == -1) break;
+                    }
+                    cuser = searchUserByNick(carg);
+                    if(!cuser) {
+                        //check for an invisible user
+                        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                            if(!stricmp(chanuser->user->nick, carg)) {
+                                cuser = chanuser->user;
+                                break;
+                            }
+                        }
+                        if(!cuser) break;
+                    } else {
+                        chanuser = getChanUser(cuser, chan);
+                        if(!chanuser) break;
+                    }
+                    if(!(add ^ (chanuser->flags & (modeStr[i] == 'o' ? CHANUSERFLAG_OPPED : CHANUSERFLAG_VOICED)))) break;
+                    if(!add) {
+                        //check protection
+                        if(modeStr[i] == 'o' && isNetworkService(cuser)) {
+                            reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
+                            break;
+                        }
+                        if(isUserProtected(chan, cuser, user)) {
+                            reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                            break;
+                        }
+                    }
+                    modeBufferSet(modeBuf, add, modeStr[i], carg);
+                    break;
+                case 'b':
+                    if(arg == argc) {
+                        reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
+                        return;
+                    }
+                    carg = argv[arg++];
+                    if(uaccess < db_canban) {
+                        reply(textclient, user, "NS_MODE_CANBAN", chan->name);
+                        db_canban = -1;
+                        break;
+                    }
+                    if(db_canban == -1) break;
+                    char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
+                    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+                    struct BanNode *ban;
+                    int match_count = 0;
+                    carg = make_banmask(carg, hostmask_buffer);
+                    if(add) {
+                        for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                            cuser = chanuser->user;
+                            sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+                            if(!match(carg, usermask)) {
+                                if(isNetworkService(chanuser->user)) {
+                                    reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+                                    skip = 1;
+                                    break;
+                                }
+                                if(isUserProtected(chan, cuser, user)) {
+                                    reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+                                    skip = 1;
+                                    break;
+                                }
+                                match_count++;
+                                if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
+                                    skip = 1;
+                                    reply(textclient, user, "NS_LAME_MASK", carg);
+                                    break;
+                                }
+                            }
+                        }
+                    } else {
+                        skip = 1;
+                        for(ban = chan->bans; ban; ban = ban->next) {
+                            if(!match(carg, ban->mask)) {
+                                skip = 0;
+                                break;
+                            }
+                        }
+                    }
+                    if(!skip) {
+                        modeBufferSet(modeBuf, add, 'b', carg);
+                    }
+                    break;
+                default:
+                    modetype = getModeType(modelock, modeStr[i]);
+                    if(modetype == 0) {
+                        reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
+                        return;
+                    }
+                    if(isModeAffected(modelock, modeStr[i]) && add == !isModeSet(modelock, modeStr[i]) && uaccess < db_enfmodes) {
+                        if(isGodMode(user))
+                            event->flags |= CMDFLAG_OPLOG;
+                        else {
+                            getFullModeString(modelock, tmp);
+                            reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
+                            return;
+                        }
+                    }
+                    if(add && (modetype & CHANNEL_MODE_TYPE) != CHANNEL_MODE_TYPE_D) {
+                        if(arg == argc) {
+                            reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
+                            return;
+                        }
+                        carg = argv[arg++];
+                        if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
+                            char *modelock_val = getModeValue(modelock, modeStr[i]);
+                            if(stricmp(carg, modelock_val)) {
+                                if(isGodMode(user))
+                                    event->flags |= CMDFLAG_OPLOG;
+                                else {
+                                    getFullModeString(modelock, tmp);
+                                    reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
+                                    return;
+                                }
+                            }
+                        }
+                        if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
+                            int *modelock_val = getModeValue(modelock, modeStr[i]);
+                            if(atoi(carg) != *modelock_val) {
+                                if(isGodMode(user))
+                                    event->flags |= CMDFLAG_OPLOG;
+                                else {
+                                    getFullModeString(modelock, tmp);
+                                    reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
+                                    return;
+                                }
+                            }
+                        }
+                    } else
+                        carg = NULL;
+                    if((modetype & CHANNEL_MODE_TYPE) == CHANNEL_MODE_TYPE_D && isModeSet(chan->modes, modeStr[i]) == add)
+                        break;
+                    if(!isModeAffected(changemodes, modeStr[i])) {
+                        if(!add && (modetype & CHANNEL_MODE_KEY)) {
+                            if(isModeSet(chan->modes, modeStr[i])) {
+                                char *current_val = getModeValue(chan->modes, modeStr[i]);
+                                carg = current_val;
+                            }
+                        }
+                        if(parseMode(changemodes, add, modeStr[i], carg)) {
+                            if(carg) {
+                                if(add && (modetype & CHANNEL_MODE_KEY) && isModeSet(chan->modes, modeStr[i])) {
+                                    char *current_val = getModeValue(chan->modes, modeStr[i]);
+                                    modeBufferSet(modeBuf, 0, modeStr[i], current_val);
+                                    flushModeBuffer(modeBuf);
+                                }
+                                if(!add && !isModeSet(chan->modes, modeStr[i])) break;
+                                modeBufferSet(modeBuf, add, modeStr[i], carg);
+                            } else {
+                                modeBufferSimpleMode(modeBuf, add, modeStr[i]);
+                            }
+                        } else {
+                            reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
+                            return;
+                        }
+                    }
+                    break;
+            }
+        }
+    }
+    getFullModeString(changemodes, tmp);
+    freeModeBuffer(modeBuf);
+    if(strcmp(tmp, "+"))
+        reply(textclient, user, "NS_MODE_DONE", tmp);
+    
+    logEvent(event);
+    freeModeNode(modelock);
+    freeModeNode(changemodes);
+}
diff --git a/src/cmd_neonserv_move.c b/src/cmd_neonserv_move.c
new file mode 100644 (file)
index 0000000..804954f
--- /dev/null
@@ -0,0 +1,70 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - channel
+* argv[1] - new channel
+*/
+CMD_BIND(neonserv_cmd_move) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    char *channel = argv[0];
+    char *new_channel = argv[1];
+    if(!is_valid_chan(new_channel)) {
+        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", new_channel);
+        return;
+    }
+    if(!stricmp(channel, new_channel)) {
+        reply(getTextBot(), user, "NS_MOVE_SELF");
+        return;
+    }
+    printf_mysql_query("SELECT `channel_id` FROM `bot_channels` LEFT JOIN `channels` ON `channel_id` = `chanid` WHERE `channel_name` = '%s'", escape_string(new_channel));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        reply(getTextBot(), user, "NS_REGISTER_ALREADY", new_channel, client->user->nick);
+        return;
+    }
+    int chanid;
+    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        chanid = atoi(row[0]);
+    } else {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    if(!strcmp(row[2], "1")) {
+        reply(getTextBot(), user, "NS_MOVE_SUSPENDED");
+        return;
+    }
+    int botid = atoi(row[0]);
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->clientid == botid)
+            break;
+    }
+    if(bot) {
+        putsock(bot, "PART %s :Channel moved to %s.", channel, new_channel);
+        putsock(bot, "JOIN %s", new_channel);
+    }
+    printf_mysql_query("DELETE FROM `channels` WHERE `channel_name` = '%s'", escape_string(new_channel));
+    printf_mysql_query("UPDATE `channels` SET `channel_name` = '%s' WHERE `channel_id` = '%s'", escape_string(new_channel), row[1]);
+    struct ChanNode *channode = getChanByName(channel);
+    if(channode && channode->flags & CHANFLAG_REQUESTED_CHANINFO) {
+        channode->flags &= ~CHANFLAG_CHAN_REGISTERED;
+        channode->channel_id = 0;
+    }
+    channode = getChanByName(new_channel);
+    if(channode && channode->flags & CHANFLAG_REQUESTED_CHANINFO) {
+        channode->flags |= CHANFLAG_CHAN_REGISTERED;
+        channode->channel_id = atoi(row[1]);
+    }
+    reply(getTextBot(), user, "NS_MOVE_DONE", channel, new_channel);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_myaccess.c b/src/cmd_neonserv_myaccess.c
new file mode 100644 (file)
index 0000000..093e28a
--- /dev/null
@@ -0,0 +1,162 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_myaccess_nick_lookup);
+static void neonserv_cmd_myaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, char *chanmatch);
+
+struct neonserv_cmd_myaccess_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    char *nick;
+    char *chanmatch;
+};
+
+CMD_BIND(neonserv_cmd_myaccess) {
+    char *chanmatch = NULL;
+    if(argc == 0 || argv[0][0] == '#') {
+        if(argc != 0) {
+            chanmatch = argv[0];
+        }
+        if(!(user->flags & USERFLAG_ISAUTHED)) {
+            struct neonserv_cmd_myaccess_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->nick = strdup(argv[0]);
+            cache->chanmatch = (chanmatch ? strdup(chanmatch) : NULL);
+            get_userauth(user, neonserv_cmd_myaccess_nick_lookup, cache);
+        } else
+            neonserv_cmd_myaccess_async1(client, getTextBot(), user, chan, user->nick, user->auth, chanmatch);
+    }
+    else if(argv[0][0] == '*') {
+        //we've got an auth
+        if(argc > 1 && argv[1][0] == '#') {
+            chanmatch = argv[1];
+        }
+        argv[0]++;
+        neonserv_cmd_myaccess_async1(client, getTextBot(), user, chan, NULL, argv[0], chanmatch);
+    } else {
+        if(argc > 1 && argv[1][0] == '#') {
+            chanmatch = argv[1];
+        }
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_myaccess_async1(client, getTextBot(), user, chan, argv[0], cuser->auth, chanmatch);
+        } else {
+            struct neonserv_cmd_myaccess_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->nick = strdup(argv[0]);
+            cache->chanmatch = (chanmatch ? strdup(chanmatch) : NULL);
+            get_userauth(cuser, neonserv_cmd_myaccess_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_myaccess_nick_lookup) {
+    struct neonserv_cmd_myaccess_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        if(!strcmp(cache->nick, cache->user->nick))
+            reply(cache->textclient, cache->user, "NS_YOU_NEED_AUTH");
+        else
+            reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_myaccess_async1(cache->client, cache->textclient, cache->user, cache->chan, user->nick, user->auth, cache->chanmatch);
+    if(cache->chanmatch)
+        free(cache->chanmatch);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_myaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nick, char *auth, char *chanmatch) {
+    //we've got a valid auth now...
+    MYSQL_RES *res, *default_res;
+    MYSQL_ROW user_row, chanuser_row, default_chan = NULL;
+    char flagBuf[5];
+    int userid, cflags, caccess, flagPos;
+    int i, total_count, match_count = 0, owner_count = 0;
+    struct Table *table;
+    printf_mysql_query("SELECT `user_id`, `user_access`, `user_god` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    total_count = mysql_num_rows(res);
+    table = table_init(4, total_count + 1, 0);
+    char *content[4];
+    content[0] = get_language_string(user, "NS_MYACCESS_HEADER_NAME");
+    content[1] = get_language_string(user, "NS_MYACCESS_HEADER_ACCESS");
+    content[2] = get_language_string(user, "NS_MYACCESS_HEADER_FLAGS");
+    content[3] = get_language_string(user, "NS_MYACCESS_HEADER_INFO");
+    table_add(table, content);
+    if(chanmatch)
+        reply(textclient, user, "NS_MYACCESS_HEADER_MATCH", auth, chanmatch);
+    else
+        reply(textclient, user, "NS_MYACCESS_HEADER", auth);
+    if ((user_row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(user_row[0]);
+        //check if the user is already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags`, `chanuser_infoline`, `channel_name`, `channel_getop`, `channel_getvoice` FROM `chanusers` LEFT JOIN `channels` ON `chanuser_cid` = `channel_id` WHERE `chanuser_uid` = '%d' ORDER BY `chanuser_access` DESC, `channel_name` ASC", userid);
+        res = mysql_use();
+        while ((chanuser_row = mysql_fetch_row(res)) != NULL) {
+            if(!strcmp(chanuser_row[0], "500")) owner_count++;
+            if(chanmatch && match(chanmatch, chanuser_row[0])) continue;
+            match_count++;
+            if((!chanuser_row[4] || !chanuser_row[5]) && !default_chan) {
+                printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
+                default_res = mysql_use();
+                default_chan = mysql_fetch_row(default_res);
+            }
+            flagPos = 0;
+            content[0] = chanuser_row[3];
+            content[1] = chanuser_row[0];
+            cflags = atoi(chanuser_row[1]);
+            caccess = atoi(chanuser_row[0]);
+            if((cflags & DB_CHANUSER_SUSPENDED))
+                flagPos += sprintf(flagBuf + flagPos, "s");
+            if(caccess >= (chanuser_row[4] ? atoi(chanuser_row[4]) : atoi(default_chan[0])))
+                flagPos += sprintf(flagBuf + flagPos, "o");
+            if(caccess >= (chanuser_row[5] ? atoi(chanuser_row[5]) : atoi(default_chan[1])))
+                flagPos += sprintf(flagBuf + flagPos, "v");
+            if((cflags & DB_CHANUSER_AUTOINVITE))
+                flagPos += sprintf(flagBuf + flagPos, "i");
+            content[2] = flagBuf;
+            content[3] = chanuser_row[2];
+            table_add(table, content);
+        }
+    }
+    //send the table
+    char **table_lines = table_end(table);
+    for(i = 0; i < table->entrys; i++) {
+        reply(textclient, user, table_lines[i]);
+    }
+    if(!match_count)
+        reply(textclient, user, "NS_TABLE_NONE");
+    if(chanmatch) {
+        reply(textclient, user, "NS_MYACCESS_COUNT_MATCH", auth, total_count, owner_count, match_count, chanmatch);
+    } else {
+        reply(textclient, user, "NS_MYACCESS_COUNT", auth, total_count, owner_count);
+    }
+}
diff --git a/src/cmd_neonserv_netinfo.c b/src/cmd_neonserv_netinfo.c
new file mode 100644 (file)
index 0000000..c8fd1b6
--- /dev/null
@@ -0,0 +1,159 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no args
+*/
+
+CMD_BIND(neonserv_cmd_netinfo) {
+    reply(getTextBot(), user, "NS_NETINFO_HEADER");
+    char tmp[MAXLEN];
+    struct Table *table;
+    table = table_init(2, 18, 0);
+    char *content[2];
+    
+    content[0] = get_language_string(user, "NS_NETINFO_UPTIME");
+    content[1] = timeToStr(user, (time(0) - start_time), 3, tmp);
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_BOTS");
+    struct ClientSocket *cclient;
+    int bot_count = 0, connected_bot_count = 0;
+    float traffic_in = 0, traffic_out = 0;
+    for(cclient = getBots(0, NULL); cclient; cclient = getBots(0, cclient)) {
+        bot_count++;
+        if(cclient->flags & SOCKET_FLAG_READY)
+            connected_bot_count++;
+        traffic_in += cclient->traffic_in;
+        traffic_out += cclient->traffic_out;
+    }
+    sprintf(tmp, "%d (%d connected)", bot_count, connected_bot_count);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_TRAFFIC");
+    sprintf(tmp, "in: %.2f kb  out: %.2f kb", traffic_in / 1024, traffic_out / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    int channel_count = getChannelCount();
+    float channel_memory = channel_count * sizeof(struct ChanNode);
+    int channel_ban_count = getChanBanCount();
+    float channel_ban_memory = channel_ban_count * sizeof(struct BanNode);
+    int user_count = getUserCount();
+    float user_memory = user_count * sizeof(struct UserNode);
+    int chanuser_count = getChanUserCount();
+    float chanuser_memory = chanuser_count * sizeof(struct ChanUser);
+    float total_memory = channel_memory + channel_ban_memory + user_memory + chanuser_memory;
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CACHE");
+    sprintf(tmp, "%.2f kB (%.2f MB)", total_memory / 1024, total_memory / 1024 / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL");
+    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", channel_count, channel_memory / 1024, channel_count, sizeof(struct ChanNode), channel_memory / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL_BAN");
+    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", channel_ban_count, channel_ban_memory / 1024, channel_ban_count, sizeof(struct BanNode), channel_ban_memory / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_USER");
+    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", user_count, user_memory / 1024, user_count, sizeof(struct UserNode), user_memory / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CHANUSER");
+    sprintf(tmp, "%d    %.2f kB (%d * %lu B = %.2f kB)", chanuser_count, chanuser_memory / 1024, chanuser_count, sizeof(struct ChanUser), chanuser_memory / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SHOW TABLE STATUS");
+    res = mysql_use();
+    int mysql_entrys[4];
+    float mysql_length[5];
+    total_memory = 0;
+    mysql_entrys[0] = 0; mysql_entrys[1] = 0; mysql_entrys[2] = 0; mysql_entrys[3] = 0;
+    mysql_length[0] = 0; mysql_length[1] = 0; mysql_length[2] = 0; mysql_length[3] = 0; mysql_length[4] = 0;
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(!stricmp(row[0], "channels")) {
+            mysql_entrys[0] = atoi(row[4]);
+            mysql_length[0] = atof(row[6]);
+            total_memory += atof(row[6]);
+        } else if(!stricmp(row[0], "bans")) {
+            mysql_entrys[1] = atoi(row[4]);
+            mysql_length[1] = atof(row[6]);
+            total_memory += atof(row[6]);
+        } else if(!stricmp(row[0], "users")) {
+            mysql_entrys[2] = atoi(row[4]);
+            mysql_length[2] = atof(row[6]);
+            total_memory += atof(row[6]);
+        } else if(!stricmp(row[0], "chanusers")) {
+            mysql_entrys[3] = atoi(row[4]);
+            mysql_length[3] = atof(row[6]);
+            total_memory += atof(row[6]);
+        } else {
+            mysql_length[4] += atof(row[6]);
+            total_memory += atof(row[6]);
+        }
+    }
+    
+    content[0] = get_language_string(user, "NS_NETINFO_DATABASE");
+    sprintf(tmp, "%.2f kB (%.2f MB)", total_memory / 1024, total_memory / 1024 / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL");
+    sprintf(tmp, "%d    %.2f kB", mysql_entrys[0], mysql_length[0] / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CHANNEL_BAN");
+    sprintf(tmp, "%d    %.2f kB", mysql_entrys[1], mysql_length[1] / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_USER");
+    sprintf(tmp, "%d    %.2f kB", mysql_entrys[2], mysql_length[2] / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CHANUSER");
+    sprintf(tmp, "%d    %.2f kB", mysql_entrys[3], mysql_length[3] / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_OTHER");
+    sprintf(tmp, "*     %.2f kB", mysql_length[4] / 1024);
+    content[1] = tmp;
+    table_add(table, content);
+    
+    if(strcmp(revision, ""))
+        sprintf(tmp, "%s  (%s)", NEONSERV_VERSION, revision);
+    else 
+        strcpy(tmp, NEONSERV_VERSION);
+    content[0] = get_language_string(user, "NS_NETINFO_VERSION");
+    content[1] = tmp;
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_COMPILER");
+    content[1] = build_language_string(user, tmp, "NS_NETINFO_COMPILER_VALUE", COMPILER, creation);
+    table_add(table, content);
+    
+    content[0] = get_language_string(user, "NS_NETINFO_CODE");
+    content[1] = build_language_string(user, tmp, "NS_NETINFO_CODE_VALUE", codelines);
+    table_add(table, content);
+    
+    char **table_lines = table_end(table);
+    int i;
+    for(i = 0; i < table->entrys; i++) {
+        reply(getTextBot(), user, table_lines[i]);
+    }
+    table_free(table);
+}
+
diff --git a/src/cmd_neonserv_notice.c b/src/cmd_neonserv_notice.c
new file mode 100644 (file)
index 0000000..26776c0
--- /dev/null
@@ -0,0 +1,12 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    target
+* argv[1-*]  message
+*/
+
+CMD_BIND(neonserv_cmd_notice) {
+    char *message = merge_argv(argv, 1, argc);
+    putsock(client, "NOTICE %s :%s", argv[0], message);
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_op.c b/src/cmd_neonserv_op.c
new file mode 100644 (file)
index 0000000..2bf69c0
--- /dev/null
@@ -0,0 +1,77 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nicks
+*/
+static USERLIST_CALLBACK(neonserv_cmd_op_userlist_lookup);
+static void neonserv_cmd_op_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks);
+
+struct neonserv_cmd_op_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *nicks;
+};
+
+CMD_BIND(neonserv_cmd_op) {
+    struct neonserv_cmd_op_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->nicks = strdup(merge_argv(argv, 0, argc));
+    get_userlist_with_invisible(chan, neonserv_cmd_op_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_op_userlist_lookup) {
+    struct neonserv_cmd_op_cache *cache = data;
+    neonserv_cmd_op_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks);
+    free(cache->nicks);
+    free(cache);
+}
+
+static void neonserv_cmd_op_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks) {
+    int total_users = 0, done_users = 0;
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    char *a, *b = nicks;
+    do {
+        a = strstr(b, " ");
+        if(a) *a = '\0';
+        total_users++;
+        cuser = searchUserByNick(b);
+        if(!cuser) {
+            //check for an invisible user
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if(!stricmp(chanuser->user->nick, b)) {
+                    cuser = chanuser->user;
+                    break;
+                }
+            }
+            if(!cuser) continue;
+        } else {
+            chanuser = getChanUser(cuser, chan);
+            if(!chanuser) continue;
+        }
+        done_users++;
+        if(chanuser->flags & CHANUSERFLAG_OPPED) continue;
+        modeBufferOp(modeBuf, b);
+        if(a) {
+            b = a+1;
+        }
+    } while(a);
+    freeModeBuffer(modeBuf);
+    if(done_users == total_users)
+        reply(textclient, user, "NS_OP_DONE", chan->name);
+    else
+        reply(textclient, user, "NS_OP_FAIL", client->user->nick);
+    if(done_users) 
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_opall.c b/src/cmd_neonserv_opall.c
new file mode 100644 (file)
index 0000000..d97feff
--- /dev/null
@@ -0,0 +1,62 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    "force"
+* argv[1]    (optional) nick mask
+*/
+static USERLIST_CALLBACK(neonserv_cmd_opall_userlist_lookup);
+static void neonserv_cmd_opall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask);
+
+struct neonserv_cmd_opall_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *nickmask;
+};
+
+CMD_BIND(neonserv_cmd_opall) {
+    if(!argc || strcmp(argv[0], "FORCE")) {
+        reply(getTextBot(), user, "NS_OPALL_SECURITY", chan->name);
+        return;
+    }
+    struct neonserv_cmd_opall_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    if(argc > 1) {
+        cache->nickmask = strdup(argv[1]);
+    } else
+        cache->nickmask = NULL;
+    get_userlist_with_invisible(chan, neonserv_cmd_opall_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_opall_userlist_lookup) {
+    struct neonserv_cmd_opall_cache *cache = data;
+    neonserv_cmd_opall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask);
+    if(cache->nickmask)
+        free(cache->nickmask);
+    free(cache);
+}
+
+static void neonserv_cmd_opall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask) {
+    int done_users = 0;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+        if(chanuser->flags & CHANUSERFLAG_OPPED) continue;
+        modeBufferOp(modeBuf, chanuser->user->nick);
+        done_users++;
+    }
+    freeModeBuffer(modeBuf);
+    reply(textclient, user, "NS_OPALL_DONE", done_users, chan->name);
+    if(done_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_oplog.c b/src/cmd_neonserv_oplog.c
new file mode 100644 (file)
index 0000000..a69c449
--- /dev/null
@@ -0,0 +1,41 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]     time
+* argv[1-*]   match
+*/
+
+CMD_BIND(neonserv_cmd_oplog) {
+    char *str_match;
+    int duration = (argc ? strToTime(user, argv[0]) : 0);
+    if(argc > (duration ? 1 : 0))
+        str_match = merge_argv(argv, (duration ? 1 : 0), argc);
+    else
+        str_match = "";
+    if(!duration) duration = (60*60*24);
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `godlog_time`, `user_user`, `channel_name`, `godlog_cmd` FROM `godlog` LEFT JOIN `channels` ON `godlog_cid` = `channel_id` LEFT JOIN `users` ON `godlog_uid` = `user_id` WHERE `godlog_time` > '%lu' ORDER BY `godlog_time` ASC", ((unsigned long) time(0) - duration));
+    res = mysql_use();
+    int skip = mysql_num_rows(res) - 100;
+    int count = 0;
+    char timeBuf[50];
+    struct tm *timeinfo;
+    time_t event_time;
+    if(skip < 0) skip = 0;
+    reply(getTextBot(), user, "NS_EVENTS_HEADER");
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(skip) {
+            skip--;
+            continue;
+        }
+        if(*str_match && match(str_match, row[3])) continue;
+        count++;
+        event_time = (time_t) atol(row[0]);
+        timeinfo = localtime(&event_time);
+        strftime(timeBuf, 80, "%X %x", timeinfo);
+        reply(getTextBot(), user, "[%s] [%s%s%s]: %s", timeBuf, row[1], (row[2] ? ":" : ""), (row[2] ? row[2] : ""), row[3]);
+    }
+    reply(getTextBot(), user, "NS_TABLE_COUNT", count);
+}
diff --git a/src/cmd_neonserv_peek.c b/src/cmd_neonserv_peek.c
new file mode 100644 (file)
index 0000000..6724403
--- /dev/null
@@ -0,0 +1,67 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no parameters
+*/
+static USERLIST_CALLBACK(neonserv_cmd_peek_userlist_lookup);
+static void neonserv_cmd_peek_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan);
+
+struct neonserv_cmd_peek_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+};
+
+CMD_BIND(neonserv_cmd_peek) {
+    struct neonserv_cmd_peek_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    get_userlist_with_invisible(chan, neonserv_cmd_peek_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_peek_userlist_lookup) {
+    struct neonserv_cmd_peek_cache *cache = data;
+    neonserv_cmd_peek_async1(cache->client, cache->textclient, cache->user, chan);
+    free(cache);
+}
+
+static void neonserv_cmd_peek_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan) {
+    reply(textclient, user, "NS_PEEK_HEADER", chan->name);
+    reply(textclient, user, "NS_PEEK_TOPIC", chan->topic);
+    char tmpStr[MAXLEN];
+    getModeString(chan->modes, tmpStr);
+    reply(textclient, user, "NS_PEEK_MODES", tmpStr);
+    struct ChanUser *chanuser;
+    int op_count = 0, voice_count = 0, normal_count = 0, invi_count = 0;
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(chanuser->flags & CHANUSERFLAG_OPPED)
+            op_count++;
+        else if(chanuser->flags & CHANUSERFLAG_VOICED)
+            voice_count++;
+        else if(chanuser->flags & CHANUSERFLAG_VOICED)
+            invi_count++;
+        else
+            normal_count++;
+    }
+    reply(textclient, user, "NS_PEEK_USERS", op_count+voice_count+invi_count+normal_count, op_count, voice_count, normal_count, invi_count);
+    int tmpStrPos = 0;
+    int headerlen = 10 + strlen(user->nick);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(chanuser->flags & CHANUSERFLAG_OPPED) {
+            if(tmpStrPos + headerlen + strlen(chanuser->user->nick) + 2 >= 512) {
+                //clear buffer
+                reply(textclient, user, "%s", tmpStr);
+                tmpStrPos = 0;
+            }
+            tmpStrPos += sprintf(tmpStr + tmpStrPos, (tmpStrPos ? ", %s" : "%s"), chanuser->user->nick);
+        }
+    }
+    if(tmpStrPos) {
+        reply(textclient, user, "%s", tmpStr);
+    }
+}
diff --git a/src/cmd_neonserv_raw.c b/src/cmd_neonserv_raw.c
new file mode 100644 (file)
index 0000000..4ccce79
--- /dev/null
@@ -0,0 +1,11 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    raw
+*/
+
+CMD_BIND(neonserv_cmd_raw) {
+    char *raw = merge_argv(argv, 0, argc);
+    putsock(client, "%s", raw);
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_recover.c b/src/cmd_neonserv_recover.c
new file mode 100644 (file)
index 0000000..b52e5cc
--- /dev/null
@@ -0,0 +1,60 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - channel
+*/
+CMD_BIND(neonserv_cmd_recover) {
+    MYSQL_RES *res;
+    MYSQL_ROW row, row2;
+    char *channel = argv[0];
+    if(!is_valid_chan(channel)) {
+        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
+        return;
+    }
+    printf_mysql_query("SELECT `botid`, `bot_channels`.`id` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, client->botid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        reply(getTextBot(), user, "NS_REGISTER_ALREADY", argv[0], client->user->nick);
+        return;
+    }
+    int chanid;
+    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        chanid = atoi(row[0]);
+    } else {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    printf_mysql_query("SELECT `id`, `max_channels`, `defaulttrigger` FROM `bots` WHERE `botclass` = '%d' ORDER BY `register_priority` DESC", client->botid);
+    res = mysql_use();
+    int botid = 0;
+    char *bottrigger;
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        //check channel count
+        printf_mysql_query("SELECT COUNT(*) FROM `bot_channels` WHERE `botid` = '%s'", row[0]);
+        row2 = mysql_fetch_row(mysql_use());
+        if(atoi(row2[0]) < atoi(row[1])) {
+            botid = atoi(row[0]);
+            bottrigger = row[2];
+            break;
+        }
+    }
+    if(!botid) {
+        reply(getTextBot(), user, "NS_REGISTER_FULL");
+        return;
+    }
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->clientid == botid)
+            break;
+    }
+    if(bot) {
+        putsock(bot, "JOIN %s", channel);
+    } else
+        reply(getTextBot(), user, "NS_REGISTER_DISCONNECTED");
+    printf_mysql_query("INSERT INTO `bot_channels` (`botid`, `chanid`, `trigger`) VALUES ('%d', '%d', '%s')", botid, chanid, bottrigger);
+    reply(getTextBot(), user, "NS_RECOVER_DONE", channel);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_register.c b/src/cmd_neonserv_register.c
new file mode 100644 (file)
index 0000000..d336d7f
--- /dev/null
@@ -0,0 +1,176 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - channel
+* argv[0/1] - nick / *auth
+*/
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_register_auth_lookup);
+static USERAUTH_CALLBACK(neonserv_cmd_register_nick_lookup);
+static void neonserv_cmd_register_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *channel, char *auth);
+
+struct neonserv_cmd_register_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+    char *channel;
+};
+
+CMD_BIND(neonserv_cmd_register) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    char *channel = argv[0];
+    if(!is_valid_chan(channel)) {
+        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
+        return;
+    }
+    printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `bot_channels`.`chanid` = `channels`.`channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        reply(getTextBot(), user, "NS_REGISTER_ALREADY", argv[0], client->user->nick);
+        return;
+    }
+    //check own access
+    if(argv[1][0] == '*') {
+        //we've got an auth
+        argv[1]++;
+        printf_mysql_query("SELECT `user_user` FROM `users` WHERE `user_user` = '%s'", escape_string(argv[1]));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            neonserv_cmd_register_async1(client, getTextBot(), user, chan, event, channel, row[0]);
+        } else {
+            //we need to create a new user...
+            //but first lookup the auth to check if it really exists
+            struct neonserv_cmd_register_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[1]);
+            cache->channel = strdup(channel);
+            lookup_authname(argv[1], neonserv_cmd_register_auth_lookup, cache);
+        }
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[1]);
+        if(!cuser) {
+            cuser = createTempUser(argv[1]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_register_async1(client, getTextBot(), user, chan, event, channel, cuser->auth);
+        } else {
+            struct neonserv_cmd_register_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[1]);
+            cache->channel = strdup(channel);
+            get_userauth(cuser, neonserv_cmd_register_nick_lookup, cache);
+        }
+    }
+}
+
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_register_auth_lookup) {
+    struct neonserv_cmd_register_cache *cache = data;
+    if(!exists) {
+        //AUTH_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_AUTH_UNKNOWN", cache->nick);
+    } else
+        neonserv_cmd_register_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, cache->channel, auth);
+    free(cache->channel);
+    free(cache->nick);
+    free(cache);
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_register_nick_lookup) {
+    struct neonserv_cmd_register_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_register_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, cache->channel, user->auth);
+    free(cache->channel);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_register_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *channel, char *auth) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row, row2;
+    int userid, adminid;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL)
+        adminid = atoi(row[0]);
+    else
+        adminid = 0;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+    } else {
+        printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(auth));
+        userid = (int) mysql_insert_id(mysql_conn);
+    }
+    printf_mysql_query("SELECT `id`, `max_channels`, `defaulttrigger` FROM `bots` WHERE `botclass` = '%d' ORDER BY `register_priority` DESC", client->botid);
+    res = mysql_use();
+    int botid = 0;
+    char *bottrigger;
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        //check channel count
+        printf_mysql_query("SELECT COUNT(*) FROM `bot_channels` WHERE `botid` = '%s'", row[0]);
+        row2 = mysql_fetch_row(mysql_use());
+        if(atoi(row2[0]) < atoi(row[1])) {
+            botid = atoi(row[0]);
+            bottrigger = row[2];
+            break;
+        }
+    }
+    if(!botid) {
+        reply(textclient, user, "NS_REGISTER_FULL");
+        return;
+    }
+    int chanid;
+    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        chanid = atoi(row[0]);
+        printf_mysql_query("UPDATE `channels` SET `channel_registered` = UNIX_TIMESTAMP(), `channel_registrator` = '%d' WHERE `channel_id` = '%d'", adminid, chanid);
+    } else {
+        printf_mysql_query("INSERT INTO `channels` (`channel_name`, `channel_registered`, `channel_registrator`) VALUES ('%s', UNIX_TIMESTAMP(), '%d')", escape_string(channel), adminid);
+        chanid = (int) mysql_insert_id(mysql_conn);
+    }
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->clientid == botid)
+            break;
+    }
+    if(bot) {
+        putsock(bot, "JOIN %s", channel);
+    } else
+        reply(textclient, user, "NS_REGISTER_DISCONNECTED");
+    printf_mysql_query("INSERT INTO `bot_channels` (`botid`, `chanid`, `trigger`) VALUES ('%d', '%d', '%s')", botid, chanid, bottrigger);
+    printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_cid` = '%d'", chanid);
+    printf_mysql_query("INSERT INTO `chanusers` (`chanuser_cid`, `chanuser_uid`, `chanuser_access`) VALUES ('%d', '%d', '%d')", chanid, userid, 500);
+    reply(textclient, user, "NS_REGISTER_DONE", channel, auth);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_reloadlang.c b/src/cmd_neonserv_reloadlang.c
new file mode 100644 (file)
index 0000000..e5c4f6b
--- /dev/null
@@ -0,0 +1,19 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    language tag
+*/
+
+CMD_BIND(neonserv_cmd_reloadlang) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `text`, `lang` FROM `language` WHERE `ident` = 'name' AND `lang` = '%s'", escape_string(argv[0]));
+    res = mysql_use();
+    if((row = mysql_fetch_row(res)) != NULL) {
+        load_language(row[1], row[0]);
+        reply(getTextBot(), user, "NS_RELOADLANG_DONE", row[0], row[1]);
+    } else {
+        reply(getTextBot(), user, "NS_RELOADLANG_UNKNOWN", argv[0]);
+    }
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_resync.c b/src/cmd_neonserv_resync.c
new file mode 100644 (file)
index 0000000..c9d4bba
--- /dev/null
@@ -0,0 +1,122 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - usermask
+* argv[1] - min access
+* argv[2] - max access
+*/
+static USERLIST_CALLBACK(neonserv_cmd_resync_userlist_lookup);
+static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access);
+
+struct neonserv_cmd_resync_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    char *usermask;
+    int min_access;
+    int max_access;
+};
+
+CMD_BIND(neonserv_cmd_resync) {
+    int min_access = 0, max_access = 500;
+    char *usermask = NULL;
+    if(argc > 0)
+        usermask = argv[0];
+    if(argc > 2) {
+        min_access = atoi(argv[1]);
+        max_access = atoi(argv[2]);
+    }
+    struct neonserv_cmd_resync_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->usermask = (usermask ? strdup(usermask) : NULL);
+    cache->min_access = min_access;
+    cache->max_access = max_access;
+    get_userlist_with_invisible(chan, neonserv_cmd_resync_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_resync_userlist_lookup) {
+    struct neonserv_cmd_resync_cache *cache = data;
+    neonserv_cmd_resync_async1(cache->client, cache->textclient, cache->user, chan, cache->usermask, cache->min_access, cache->max_access);
+    if(cache->usermask)
+        free(cache->usermask);
+    free(cache);
+}
+
+static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access) {
+    MYSQL_RES *res;
+    MYSQL_ROW row, defaults = NULL;
+    int i;
+    int resync_op = 1;
+    int resync_voice = 1;
+    if(usermask && usermask[0] == '@') {
+        resync_voice = 0;
+        usermask++;
+        if(!*usermask) usermask = NULL;
+    } else if(usermask && usermask[0] == '+') {
+        resync_op = 0;
+        usermask++;
+        if(!*usermask) usermask = NULL;
+    }
+    struct ChanUser *chanuser;
+    int db_enfops, db_enfvoice;
+    printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    row = mysql_fetch_row(mysql_use());
+    if(row[0] == NULL || row[1] == NULL) {
+        printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
+        defaults = mysql_fetch_row(mysql_use());
+    }
+    db_enfops = atoi((row[0] ? row[0] : defaults[0]));
+    db_enfvoice = atoi((row[1] ? row[1] : defaults[1]));
+    printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' ORDER BY `chanuser_access` DESC, `user_user` ASC", chan->channel_id);
+    res = mysql_use();
+    char *db_users[mysql_num_rows(res)];
+    int db_access[mysql_num_rows(res)];
+    int db_flags[mysql_num_rows(res)];
+    int db_count = 0;
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        db_users[db_count] = row[1];
+        db_access[db_count] = atoi(row[0]);
+        db_flags[db_count] = atoi(row[2]);
+        db_count++;
+    }
+    int caccess, cflags;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        caccess = 0;
+        cflags = 0;
+        if((chanuser->user->flags & USERFLAG_ISAUTHED)) {
+            for(i = 0; i < db_count; i++) {
+                if(!stricmp(db_users[i], chanuser->user->auth)) {
+                    caccess = db_access[i];
+                    cflags = db_flags[i];
+                    break;
+                }
+            }
+        }
+        if((usermask && *usermask && match(usermask, row[1])) || caccess < min_access || caccess > max_access) continue;
+        if(caccess >= db_enfops) {
+            if(!(chanuser->flags & CHANUSERFLAG_OPPED) && resync_op)
+                modeBufferOp(modeBuf, chanuser->user->nick);
+        } else if(caccess >= db_enfvoice) {
+            if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
+                modeBufferDeop(modeBuf, chanuser->user->nick);
+            if(!(chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice)
+                modeBufferVoice(modeBuf, chanuser->user->nick);
+        } else {
+            if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
+                modeBufferDeop(modeBuf, chanuser->user->nick);
+            if((chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
+                modeBufferDevoice(modeBuf, chanuser->user->nick);
+        }
+        
+    }
+    freeModeBuffer(modeBuf);
+    reply(textclient, user, "NS_RESYNC_DONE", chan->name);
+}
diff --git a/src/cmd_neonserv_say.c b/src/cmd_neonserv_say.c
new file mode 100644 (file)
index 0000000..fdf3c50
--- /dev/null
@@ -0,0 +1,12 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    target
+* argv[1-*]  message
+*/
+
+CMD_BIND(neonserv_cmd_say) {
+    char *message = merge_argv(argv, 1, argc);
+    putsock(client, "PRIVMSG %s :%s", argv[0], message);
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_search.c b/src/cmd_neonserv_search.c
new file mode 100644 (file)
index 0000000..0691366
--- /dev/null
@@ -0,0 +1,98 @@
+
+#include "cmd_neonserv.h"
+
+#define CMD_SEARCH_FLAG_HAS_NODELETE 0x01
+#define CMD_SEARCH_FLAG_NOT_NODELETE 0x02
+#define CMD_SEARCH_FLAG_HAS_SUSPENDED 0x04
+#define CMD_SEARCH_FLAG_NOT_SUSPENDED 0x08
+
+struct neonserv_cmd_search_criteria {
+    char *name;
+    char *registrar;
+    unsigned int flags : 16;
+    unsigned int unvisited;
+    unsigned int registered;
+    unsigned int limit : 16;
+};
+
+CMD_BIND(neonserv_cmd_search) {
+    //ok parse the criterias
+    struct neonserv_cmd_search_criteria *criteria = malloc(sizeof(*criteria));
+    if (!criteria) {
+        perror("malloc() failed");
+        return;
+    }
+    memset(criteria, 0, sizeof(*criteria));
+    criteria->limit = 50;
+    int i, show_chans = 0, positive;
+    if(!stricmp(argv[0], "print")) {
+        show_chans = 1;
+    }
+    for(i = 1; i < argc; i += 2) {
+        if(argc <= i+1) {
+            reply(getTextBot(), user, "MODCMD_LESS_PARAM_COUNT");
+            return;
+        }
+        if(!stricmp(argv[i], "name")) criteria->name = argv[i+1];
+        else if(!stricmp(argv[i], "registrar")) criteria->registrar = argv[i+1];
+        else if(!stricmp(argv[i], "unvisited")) criteria->unvisited = strToTime(user, argv[i+1]);
+        else if(!stricmp(argv[i], "registered")) criteria->registered = strToTime(user, argv[i+1]);
+        else if(!stricmp(argv[i], "flags")) {
+            if(argv[i+1][0] == '+') {
+                positive = 1;
+                argv[i+1]++;
+            } else if(argv[i+1][0] == '-') {
+                positive = 0;
+                argv[i+1]++;
+            } else
+                positive = 1;
+            if(!stricmp(argv[i+1], "nodelete")) {
+                if(positive)
+                    criteria->flags |= CMD_SEARCH_FLAG_HAS_NODELETE;
+                else
+                    criteria->flags |= CMD_SEARCH_FLAG_NOT_NODELETE;
+            } else if(!stricmp(argv[i+1], "suspended")) {
+                if(positive)
+                    criteria->flags |= CMD_SEARCH_FLAG_HAS_SUSPENDED;
+                else
+                    criteria->flags |= CMD_SEARCH_FLAG_NOT_SUSPENDED;
+            }
+        }
+        else if(!stricmp(argv[i], "limit")) {
+            criteria->limit = atoi(argv[i+1]);
+        }
+    }
+    int matches = 0;
+    reply(getTextBot(), user, "NS_SEARCH_HEADER");
+    MYSQL_RES *res, *res2;
+    MYSQL_ROW row, row2;
+    printf_mysql_query("SELECT `channel_name`, `user_user`, `channel_registered`, `channel_nodelete`, `suspended`, `channel_id` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` LEFT JOIN `users` ON `channel_registrator` = `user_id` WHERE `botid` = '%d'", client->botid);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(show_chans && matches == criteria->limit) {
+            //too many
+            break;
+        }
+        if(criteria->name && match(criteria->name, row[0])) continue;
+        if(criteria->registrar && row[1] && match(criteria->registrar, row[1])) continue;
+        if(criteria->unvisited) {
+            printf_mysql_query("SELECT `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%s' ORDER BY `chanuser_seen` DESC LIMIT 1", row[5]);
+            res2 = mysql_use();
+            row2 = mysql_fetch_row(res);
+            if(!row2) continue;
+            if((time(0) - atoi(row2[0])) < criteria->unvisited) continue;
+        }
+        if(criteria->registered && (time(0) - atoi(row[2])) < criteria->registered) continue;
+        
+        if((criteria->flags & CMD_SEARCH_FLAG_HAS_NODELETE) && strcmp(row[3], "1")) continue;
+        if((criteria->flags & CMD_SEARCH_FLAG_NOT_NODELETE) && strcmp(row[3], "0")) continue;
+        if((criteria->flags & CMD_SEARCH_FLAG_HAS_SUSPENDED) && strcmp(row[4], "1")) continue;
+        if((criteria->flags & CMD_SEARCH_FLAG_NOT_SUSPENDED) && strcmp(row[4], "0")) continue;
+        matches++;
+        //output
+        if(show_chans) {
+            reply(getTextBot(), user, "%s", row[0]);
+        }
+    }
+    reply(getTextBot(), user, "NS_TABLE_COUNT", matches);
+}
diff --git a/src/cmd_neonserv_set.c b/src/cmd_neonserv_set.c
new file mode 100644 (file)
index 0000000..2801be7
--- /dev/null
@@ -0,0 +1,425 @@
+
+#include "cmd_neonserv.h"
+
+typedef char* neonserv_cmd_set_function(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *argument);
+static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+
+#define NS_VALID_FUNCTION 0x01
+#define NS_VALID_STRING   0x02
+#define NS_VALID_ACCESS   0x04
+#define NS_VALID_NO501    0x08
+#define NS_VALID_OPTIONS  0x10
+#define NS_VALID_NUMERIC  0x20
+#define NS_VALID_BOOLEAN  0x40
+
+#define NS_HAS_OPT  0x100 /* options (SET_OPTION_{NAME}_{VALUE}) */
+#define NS_HAS_HELP 0x200 /* help    (SET_HELP_{NAME}) - only shown if help is requested */
+
+static const struct {
+    const char *setting;
+    const char *chanfield;
+    unsigned int valid;
+    void *parameter;
+} channel_settings[] = {
+    {"TRIGGER",         NULL,                   NS_VALID_FUNCTION,                  neonserv_cmd_set_trigger},
+    {"DEFAULTTOPIC",    "channel_defaulttopic", NS_VALID_STRING,                    NULL},
+    {"TOPICMASK",       "channel_topicmask",    NS_VALID_STRING,                    NULL},
+    {"ADVANCEDTOPIC",   "channel_exttopic",     NS_VALID_BOOLEAN | NS_HAS_OPT,      NULL},
+    {"GREETING",        "channel_greeting",     NS_VALID_STRING,                    NULL},
+    {"USERGREETING",    "channel_usergreeting", NS_VALID_STRING,                    NULL},
+    {"USERINFO",        "channel_userinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"WIPEINFO",        "channel_wipeinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"MODES",           "channel_modes",        NS_VALID_FUNCTION,                  neonserv_cmd_set_modes},
+    {"INVITEME",        "channel_getinvite",    NS_VALID_ACCESS,                    NULL},
+    {"GIVEOPS",         "channel_getop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"GIVEVOICE",       "channel_getvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"ENFOPS",          "channel_canop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"ENFVOICE",        "channel_canvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"KICK",            "channel_cankick",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"BAN",             "channel_canban",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"STATICBAN",       "channel_staticban",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"PUBCMD",          "channel_pubcmd",       NS_VALID_ACCESS,                    NULL},
+    {"ENFMODES",        "channel_enfmodes",     NS_VALID_ACCESS,                    NULL},
+    {"ENFTOPIC",        "channel_enftopic",     NS_VALID_ACCESS,                    NULL},
+    {"TOPICSNARF",      "channel_topicsnarf",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"CHANGETOPIC",     "channel_changetopic",  NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"SETTERS",         "channel_setters",      NS_VALID_ACCESS | NS_VALID_NO501 | NS_HAS_HELP, NULL},
+    {"ADDUSER",         "channel_canadd",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"DELUSER",         "channel_candel",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"CLVL",            "channel_canclvl",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"RESYNC",          "channel_canresync",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"SUSPEND",         "channel_cansuspend",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"NOTICEUSERS",     "channel_notice",       NS_VALID_ACCESS,                    NULL},
+    {"NOTICEREACTION",  "channel_noticereaction", NS_VALID_OPTIONS | NS_HAS_OPT,    "4"},
+    {"CTCPUSERS",       "channel_ctcp",         NS_VALID_ACCESS,                    NULL},
+    {"CTCPREACTION",    "channel_ctcpreaction", NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
+    {"PROTECT",         "channel_protect",      NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
+    {"TOYS",            "channel_toys",         NS_VALID_OPTIONS | NS_HAS_OPT,      "3"},
+    {"DYNLIMIT",        "channel_dynlimit",     NS_VALID_NUMERIC | NS_VALID_FUNCTION | NS_HAS_OPT, neonserv_cmd_set_dynlimit},
+    {"NODELETE",        "channel_nodelete",     NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_nodelete},
+    {NULL, NULL, 0, NULL}
+};
+
+#define MAX_QUERY_LEN 1024
+CMD_BIND(neonserv_cmd_set) {
+    int i, j;
+    if(argc && !strcmp(argv[0], "defaults")) {
+        //reset channel settings
+        int uaccess = getChannelAccess(user, chan, 0);
+        if(uaccess < 500) {
+            if(isGodMode(user)) {
+                event->flags |= CMDFLAG_OPLOG;
+            } else {
+                reply(getTextBot(), user, "NS_SET_DEFAULTS_OWNER", chan->name);
+                return;
+            }
+        }
+        int seed = 0;
+        char *tmp;
+        static char defaultskey[16];
+        for(tmp = user->auth; *tmp; tmp++)
+            seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+        for(tmp = chan->name; *tmp; tmp++)
+            seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+        sprintf(defaultskey, "%08x", seed);
+        if(argc > 1 && !strcmp(argv[1], defaultskey)) {
+            char query[MAX_QUERY_LEN];
+            int querypos = 0;
+            i = 0;
+            while(channel_settings[i].setting) {
+                if(channel_settings[i].chanfield)
+                    querypos += sprintf(query + querypos, "`%s` = NULL, ", channel_settings[i].chanfield);
+                i++;
+            }
+            if(querypos) {
+                query[querypos-2] = '\0';
+            }
+            printf_mysql_query("UPDATE `channels` SET %s WHERE `channel_id` = '%d'", query, chan->channel_id);
+            reply(getTextBot(), user, "NS_SET_DEFAULTS_DONE", chan->name);
+            logEvent(event);
+        } else {
+            reply(getTextBot(), user, "NS_SET_DEFAULTS_CODE", chan->name, defaultskey);
+        }
+    } else if(argc && strcmp(argv[0], "help")) {
+        //find the correct command
+        i = 0;
+        j = 0;
+        char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
+        while(channel_settings[i].setting) {
+            if(!stricmp(channel_settings[i].setting, argv[0])) {
+                //setting found
+                if(channel_settings[i].valid & NS_VALID_FUNCTION) {
+                    neonserv_cmd_set_function *func = channel_settings[i].parameter;
+                    func(client, user, chan, event, channel_settings[i].setting, args);
+                } else {
+                    neonserv_cmd_set_setting(client, user, chan, event, i, args);
+                }
+                j = 1;
+                break;
+            }
+            i++;
+        }
+        if(j == 0) {
+            //unknown setting
+            reply(getTextBot(), user, "NS_SET_UNKNOWN_SETTING", argv[0]);
+        }
+    } else {
+        char query[MAX_QUERY_LEN], *value, *org_value, *tmp, nameBuf[64];
+        int querypos = 0;
+        MYSQL_RES *res, *defaults_res;
+        MYSQL_ROW row, defaults;
+        struct Table *table;
+        char *content[2];
+        i = 0;
+        while(channel_settings[i].setting) {
+            if(channel_settings[i].chanfield)
+                querypos += sprintf(query + querypos, ", `%s`", channel_settings[i].chanfield);
+            i++;
+        }
+        table = table_init(2, i, 0);
+        table_set_bold(table, 0, 1);
+        printf_mysql_query("SELECT `channel_id` %s FROM `channels` WHERE `channel_name` = 'defaults'", query);
+        defaults_res = mysql_use();
+        defaults = mysql_fetch_row(defaults_res);
+        printf_mysql_query("SELECT `channel_name` %s FROM `channels` WHERE `channel_id` = '%d'", query, chan->channel_id);
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+        i = 0;
+        j = 0;
+        reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
+        while(channel_settings[i].setting) {
+            if(channel_settings[i].chanfield) {
+                j++;
+                org_value = (row[j] ? row[j] : defaults[j]);
+            } else if(channel_settings[i].valid & NS_VALID_FUNCTION) {
+                neonserv_cmd_set_function *func = channel_settings[i].parameter;
+                org_value = func(client, user, chan, event, NULL, NULL);
+            } else
+                org_value = "0";
+            value = org_value;
+            if(channel_settings[i].valid & NS_VALID_BOOLEAN) {
+                if(!strcmp(value, "0"))
+                    value = get_language_string(user, "NS_SET_OFF");
+                else
+                    value = get_language_string(user, "NS_SET_ON");
+            }
+            strcpy(query, value);
+            querypos = strlen(query);
+            if(channel_settings[i].valid & NS_HAS_OPT) {
+                sprintf(nameBuf, "NS_SET_OPTION_%s_%s", channel_settings[i].setting, org_value);
+                tmp = get_language_string(user, nameBuf);
+                if(tmp) {
+                    querypos += sprintf(query+querypos, " - %s", tmp);
+                }
+            }
+            if(argc && channel_settings[i].valid & NS_HAS_HELP) {
+                sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[i].setting);
+                tmp = get_language_string(user, nameBuf);
+                if(tmp) {
+                    querypos += sprintf(query+querypos, " - %s", tmp);
+                }
+            }
+            content[0] = (char*)channel_settings[i].setting;
+            content[1] = query;
+            table_add(table, content);
+            i++;
+        }
+        char **table_lines = table_end(table);
+        for(i = 0; i < table->entrys; i++) {
+            reply(getTextBot(), user, table_lines[i]);
+        }
+        table_free(table);
+    }
+}
+
+static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *args) {
+    char *value;
+    char nameBuf[64];
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", channel_settings[setting].chanfield);
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(args) {
+        //change the channel setting
+        //check the new argument
+        int valid = channel_settings[setting].valid;
+        if(valid & NS_VALID_STRING) {
+            if(!strcmp(args, "*")) {
+                args = "";
+            }
+        }
+        if(valid & NS_VALID_ACCESS) {
+            int caccess = atoi(args);
+            int max = ((valid & NS_VALID_NO501) ? 500 : 501);
+            if(caccess < 0 || caccess > max) {
+                reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
+                return;
+            }
+            int uaccess = getChannelAccess(user, chan, 0);
+            if(uaccess == 500) uaccess++;
+            if(atoi(value) > uaccess) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(getTextBot(), user, "NS_SET_CANNOT_SET");
+                    return;
+                }
+            }
+            if(caccess > uaccess) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(getTextBot(), user, "NS_SET_BADLEVEL");
+                    return;
+                }
+            }
+            sprintf(nameBuf, "%d", caccess);
+            args = nameBuf;
+        }
+        if(valid & NS_VALID_OPTIONS) {
+            int options = atoi((char *) channel_settings[setting].parameter);
+            int coption = atoi(args);
+            if(coption < 0 || coption >= options) {
+                reply(getTextBot(), user, "NS_SET_INVALID_OPTION", coption);
+                int i;
+                int nameBufPos = 0;
+                if(valid & NS_HAS_OPT) {
+                    for(i = 0; i < options; i++) {
+                        sprintf(nameBuf, "NS_SET_OPTION_%s_%d", channel_settings[setting].setting, i);
+                        reply(getTextBot(), user, "\002%d\002 - %s", i, get_language_string(user, nameBuf));
+                    }
+                } else {
+                    for(i = 0; i < options; i++) {
+                        nameBufPos += sprintf(nameBuf + nameBufPos, "\002%d\002, ", i);
+                    }
+                    if(nameBufPos) {
+                        nameBuf[nameBufPos-2] = '\0';
+                        reply(getTextBot(), user, nameBuf);
+                    }
+                }
+                return;
+            }
+        }
+        if(valid & NS_VALID_NUMERIC) {
+            sprintf(nameBuf, "%d", atoi(args));
+            args = nameBuf;
+        }
+        if(valid & NS_VALID_BOOLEAN) {
+            if(!strcmp(args, "0") || !stricmp(args, "off") || !stricmp(args, get_language_string(user, "NS_SET_OFF"))) {
+                args = "0";
+            } else if(!strcmp(args, "1") || !stricmp(args, "on") || !stricmp(args, get_language_string(user, "NS_SET_ON"))) {
+                args = "1";
+            } else {
+                reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", args);
+                return;
+            }
+        }
+        //valid - set it
+        value = args;
+        printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, escape_string(value), chan->channel_id);
+        logEvent(event);
+    }
+    reply(getTextBot(), user, "\002%s\002 %s", channel_settings[setting].setting, value);
+    if(channel_settings[setting].valid & NS_HAS_HELP) {
+         sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[setting].setting);
+         reply(getTextBot(), user, "  %s", get_language_string(user, nameBuf));
+    }
+}
+
+static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *trigger;
+    //get current trigger
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `trigger` FROM `bot_channels` WHERE `chanid` = '%d' AND `botid` = '%d'", chan->channel_id, client->clientid);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    trigger = row[0];
+    if(argument) {
+        int uaccess = getChannelAccess(user, chan, 0);
+        if(uaccess < 500) {
+            if(isGodMode(user)) {
+                event->flags |= CMDFLAG_OPLOG;
+            } else {
+                reply(getTextBot(), user, "NS_SET_TRIGGER_OWNER", chan->name);
+                return NULL;
+            }
+        }
+        if(strlen(argument) > 15)
+            argument[15] = '\0';
+        printf_mysql_query("UPDATE `bot_channels` SET `trigger` = '%s' WHERE `chanid` = '%d' AND `botid` = '%d'", escape_string(argument), chan->channel_id, client->clientid);
+        trigger = argument;
+        changeChannelTrigger(client->botid, chan, trigger);
+        logEvent(event);
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, trigger);
+    }
+    return trigger;
+}
+
+static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *value;
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(argument) {
+        //change the channel setting
+        //TODO: parse, check and set modelock
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
+    }
+    return value;
+}
+
+static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *value;
+    char tmp[64];
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(argument) {
+        //change the channel setting
+        sprintf(tmp, "%d", atoi(argument));
+        argument = tmp;
+        printf_mysql_query("UPDATE `channels` SET `channel_dynlimit` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
+        if(strcmp(argument, "0"))
+            putsock(client, "MODE %s +l %d", chan->name, (chan->usercount + atoi(argument)));
+        else if(isModeSet(chan->modes, 'l'))
+            putsock(client, "MODE %s -l", chan->name);
+        value = argument;
+        logEvent(event);
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
+    }
+    return value;
+}
+
+static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *value;
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(argument && isGodMode(user)) {
+        //change the channel setting
+        if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
+            argument = "0";
+        } else if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
+            argument = "1";
+        } else {
+            reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
+            return NULL;
+        }
+        printf_mysql_query("UPDATE `channels` SET `channel_nodelete` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
+        event->flags |= CMDFLAG_OPLOG;
+        value = argument;
+        logEvent(event);
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
+    }
+    return value;
+}
+
+#undef MAX_QUERY_LEN
diff --git a/src/cmd_neonserv_setaccess.c b/src/cmd_neonserv_setaccess.c
new file mode 100644 (file)
index 0000000..37549d2
--- /dev/null
@@ -0,0 +1,124 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+* argv[1] - global access
+*/
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_setaccess_auth_lookup);
+static USERAUTH_CALLBACK(neonserv_cmd_setaccess_nick_lookup);
+static void neonserv_cmd_setaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct Event *event, char *nick, char *auth, int access);
+
+struct neonserv_cmd_setaccess_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    int access;
+    char *nick;
+};
+
+CMD_BIND(neonserv_cmd_setaccess) {
+    int caccess;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    caccess = atoi(argv[1]);
+    if(caccess < 0 || caccess > 1000) {
+        reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
+        return;
+    }
+    printf_mysql_query("SELECT `user_access` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL || atoi(row[0]) < caccess) {
+        reply(getTextBot(), user, "NS_ACCESS_OUTRANKED");
+        return;
+    }
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        printf_mysql_query("SELECT `user_user` FROM `users` WHERE `user_user` = '%s'", escape_string(argv[0]));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            neonserv_cmd_setaccess_async1(client, getTextBot(), user, event, argv[0], row[0], caccess);
+        } else {
+            //we need to create a new user...
+            //but first lookup the auth to check if it really exists
+            struct neonserv_cmd_setaccess_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->event = event;
+            cache->access = caccess;
+            cache->nick = strdup(argv[0]);
+            lookup_authname(argv[0], neonserv_cmd_setaccess_auth_lookup, cache);
+        }
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_setaccess_async1(client, getTextBot(), user, event, argv[0], cuser->auth, caccess);
+        } else {
+            struct neonserv_cmd_setaccess_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->event = event;
+            cache->access = caccess;
+            cache->nick = strdup(argv[0]);
+            get_userauth(cuser, neonserv_cmd_setaccess_nick_lookup, cache);
+        }
+    }
+}
+
+static AUTHLOOKUP_CALLBACK(neonserv_cmd_setaccess_auth_lookup) {
+    struct neonserv_cmd_setaccess_cache *cache = data;
+    if(!exists) {
+        //AUTH_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_AUTH_UNKNOWN", cache->nick);
+    } else
+        neonserv_cmd_setaccess_async1(cache->client, cache->textclient, cache->user, cache->event, cache->nick, auth, cache->access);
+    free(cache->nick);
+    free(cache);
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_setaccess_nick_lookup) {
+    struct neonserv_cmd_setaccess_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_setaccess_async1(cache->client, cache->textclient, cache->user, cache->event, user->nick, user->auth, cache->access);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_setaccess_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct Event *event, char *nick, char *auth, int caccess) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `user_id`, `user_access` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        if(atoi(row[1]) != caccess)
+            printf_mysql_query("UPDATE `users` SET `user_access` = '%d' WHERE `user_id` = '%s'", caccess, row[0]);
+    } else {
+        printf_mysql_query("INSERT INTO `users` (`user_user`, `user_access`) VALUES ('%s', '%d')", escape_string(auth), caccess);
+    }
+    reply(textclient, user, "NS_SETACCESS_DONE", auth, caccess);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_suspend.c b/src/cmd_neonserv_suspend.c
new file mode 100644 (file)
index 0000000..4db9a50
--- /dev/null
@@ -0,0 +1,99 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_suspend_nick_lookup);
+static void neonserv_cmd_suspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
+
+struct neonserv_cmd_suspend_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+};
+
+CMD_BIND(neonserv_cmd_suspend) {
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        neonserv_cmd_suspend_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_suspend_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
+        } else {
+            struct neonserv_cmd_suspend_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[0]);
+            get_userauth(cuser, neonserv_cmd_suspend_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_suspend_nick_lookup) {
+    struct neonserv_cmd_suspend_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_suspend_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_suspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid, cflags;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
+                    return;
+                }
+            }
+            //suspend
+            cflags = atoi(row[2]);
+            if(cflags & DB_CHANUSER_SUSPENDED) {
+                reply(textclient, user, "NS_SUSPEND_ALREADY", nick);
+                return;
+            }
+            cflags |= DB_CHANUSER_SUSPENDED;
+            printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", cflags, row[1]);
+            reply(textclient, user, "NS_SUSPEND_DONE", nick, chan->name);
+            logEvent(event);
+            return;
+        }
+    }
+    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+}
diff --git a/src/cmd_neonserv_topic.c b/src/cmd_neonserv_topic.c
new file mode 100644 (file)
index 0000000..2673f15
--- /dev/null
@@ -0,0 +1,130 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* ADVANCEDTOPIC enabled
+* argv[0]    topic id
+* argv[1-*]  topic
+*
+* ADVANCEDTOPIC disabled
+* argv[0-*]  topic
+*/
+
+#define ADVANCEDTOPIC_MAXID 9
+
+CMD_BIND(neonserv_cmd_topic) {
+    MYSQL_RES *res;
+    MYSQL_ROW row, default_row = NULL;
+    int advanced_topic, i;
+    char *newtopic;
+    char *a,*b;
+    
+    printf_mysql_query("SELECT `channel_exttopic`, `channel_exttopic_topic`, `channel_topicmask`, `channel_enftopic`, `channel_topicsnarf`, `channel_defaulttopic` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(!row[0] || !row[3] || !row[4]) {
+        printf_mysql_query("SELECT `channel_exttopic`, `channel_enftopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_name` = 'defaults'");
+        default_row = mysql_fetch_row(mysql_use());
+    }
+    
+    if(row[0] == NULL) {
+        advanced_topic = atoi(default_row[0]);
+    } else
+        advanced_topic = atoi(row[0]);
+    if(argc == 0) {
+        //default topic!
+        putsock(client, "TOPIC %s :%s", chan->name, row[5]);
+        reply(getTextBot(), user, "NS_TOPIC_DONE", row[5]);
+        logEvent(event);
+        return;
+    }
+    int uaccess = getChannelAccess(user, chan, 0);
+    if(uaccess >= atoi((row[3] ? row[3] : default_row[1]))) {
+        //just set the topic
+        newtopic = merge_argv(argv, 0, argc);
+        if(uaccess >= atoi((row[4] ? row[4] : default_row[2]))) {
+            //set the default topic
+            printf_mysql_query("UPDATE `channels` SET `channel_defaulttopic` = '%s' WHERE `channel_id` = '%d'", escape_string(newtopic), chan->channel_id);
+        }
+        putsock(client, "TOPIC %s :%s", chan->name, newtopic);
+        reply(getTextBot(), user, "NS_TOPIC_DONE", newtopic);
+        logEvent(event);
+        return;
+    }
+    if(advanced_topic) {
+        char *advtopics[ADVANCEDTOPIC_MAXID];
+        int topic_id = 0;
+        topic_id = atoi(argv[0]);
+        if(!topic_id || topic_id > ADVANCEDTOPIC_MAXID) {
+            reply(getTextBot(), user, "NS_EXTTOPIC_INVALID_ID", argv[0]);
+            return;
+        }
+        //parse topics
+        i = 0;
+        b = row[1];
+        while((a = strstr(b, "\n")) != NULL) {
+            *a = '\0';
+            if(i == ADVANCEDTOPIC_MAXID-1) break;
+            advtopics[i++] = b;
+            b = a+1;
+        }
+        advtopics[i++] = b;
+        for(;i < ADVANCEDTOPIC_MAXID;i++)
+            advtopics[i] = "";
+        if(argc < 2) {
+            //just show the topic with this id
+            reply(getTextBot(), user, "NS_EXTTOPIC_TOPICID", topic_id, advtopics[topic_id-1]);
+            return;
+        }
+        newtopic = merge_argv(argv, 1, argc);
+        if(!strcmp(newtopic, "*")) 
+            newtopic = "";
+        advtopics[topic_id-1] = newtopic;
+        char topiclist[MAXLEN*2];
+        topiclist[0] = '\0';
+        int topiclistpos = 0;
+        for(i = 0; i < ADVANCEDTOPIC_MAXID; i++) {
+            if(topiclistpos + strlen(advtopics[i]) + 2 >= MAXLEN) break;
+            topiclistpos += sprintf(topiclist+topiclistpos, (i ? "\n%s" : "%s"), advtopics[i]);
+        }
+        printf_mysql_query("UPDATE `channels` SET `channel_exttopic_topic` = '%s' WHERE `channel_id` = '%d'", escape_string(topiclist), chan->channel_id);
+        //now build the new topic and set it...
+        topiclistpos = 0;
+        b = row[2];
+        while((a = strstr(b, "%")) != NULL) {
+            *a = '\0';
+            if(isdigit(a[1]) && a[1] - 48 > 0) {
+                topiclistpos += sprintf(topiclist + topiclistpos, "%s%s", b, advtopics[a[1] - 49]);
+                b = a+2;
+            } else {
+                topiclistpos += sprintf(topiclist + topiclistpos, "%s%%", b);
+                b = a+1;
+            }
+        }
+        topiclistpos += sprintf(topiclist + topiclistpos, "%s", b);
+        if(topiclistpos > MAXLEN)
+            topiclist[MAXLEN] = '\0';
+        putsock(client, "TOPIC %s :%s", chan->name, topiclist);
+        reply(getTextBot(), user, "NS_TOPIC_DONE", topiclist);
+        logEvent(event);
+    } else {
+        newtopic = merge_argv(argv, 0, argc);
+        char topiclist[MAXLEN*2];
+        topiclist[0] = '\0';
+        int topiclistpos = 0;
+         b = row[2];
+        while((a = strstr(b, "*")) != NULL) {
+            *a = '\0';
+            topiclistpos += sprintf(topiclist + topiclistpos, "%s%s", b, newtopic);
+            b = a+1;
+        }
+        topiclistpos += sprintf(topiclist + topiclistpos, "%s", b);
+        if(topiclistpos > MAXLEN)
+            topiclist[MAXLEN] = '\0';
+        putsock(client, "TOPIC %s :%s", chan->name, topiclist);
+        reply(getTextBot(), user, "NS_TOPIC_DONE", topiclist);
+        logEvent(event);
+    }
+}
+
+#undef ADVANCEDTOPIC_MAXID
\ No newline at end of file
diff --git a/src/cmd_neonserv_trace.c b/src/cmd_neonserv_trace.c
new file mode 100644 (file)
index 0000000..d2568a5
--- /dev/null
@@ -0,0 +1,97 @@
+
+#include "cmd_neonserv.h"
+
+#define NS_TRACE_CRITERIA_AUTHED  0x01
+#define NS_TRACE_CRITERIA_NUMCHAN 0x02
+
+struct neonserv_cmd_trace_criteria {
+    char *mask;
+    char *nick;
+    char *ident;
+    char *host;
+    char *account;
+    unsigned int flags : 4;
+    unsigned int authed : 1;
+    unsigned int used_channel : 5; //32 max
+    char *channel[10];
+    unsigned int numchannels;
+    unsigned int limit : 16;
+};
+
+CMD_BIND(neonserv_cmd_trace) {
+    //ok parse the criterias
+    struct neonserv_cmd_trace_criteria *criteria = malloc(sizeof(*criteria));
+    if (!criteria) {
+        perror("malloc() failed");
+        return;
+    }
+    memset(criteria, 0, sizeof(*criteria));
+    criteria->limit = 50;
+    int i, show_user = 0;
+    if(!stricmp(argv[0], "print")) {
+        show_user = 1;
+    }
+    for(i = 1; i < argc; i += 2) {
+        if(argc <= i+1) {
+            reply(getTextBot(), user, "MODCMD_LESS_PARAM_COUNT");
+            return;
+        }
+        if(!stricmp(argv[i], "mask")) criteria->mask = argv[i+1];
+        else if(!stricmp(argv[i], "nick")) criteria->nick = argv[i+1];
+        else if(!stricmp(argv[i], "ident")) criteria->ident = argv[i+1];
+        else if(!stricmp(argv[i], "host")) criteria->host = argv[i+1];
+        else if(!stricmp(argv[i], "account")) criteria->account = argv[i+1];
+        else if(!stricmp(argv[i], "authed")) {
+            if(!strcmp(argv[i+1], "0") || !strcmp(argv[i+1], "off") || !strcmp(argv[i+1], get_language_string(user, "NS_SET_OFF"))) {
+                criteria->authed = 1;
+            } else if(!strcmp(argv[i+1], "0") || !strcmp(argv[i+1], "off") || !strcmp(argv[i+1], get_language_string(user, "NS_SET_OFF"))) {
+                criteria->authed = 0;
+            } else {
+                reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argv[i+1]);
+                return;
+            }
+            criteria->flags |= NS_TRACE_CRITERIA_AUTHED;
+        }
+        else if(!stricmp(argv[i], "channel")) criteria->channel[criteria->used_channel++] = argv[i+1];
+        else if(!stricmp(argv[i], "numchannels")) {
+            criteria->numchannels = atoi(argv[i+1]);
+            criteria->flags |= NS_TRACE_CRITERIA_NUMCHAN;
+        }
+        else if(!stricmp(argv[i], "limit")) {
+            criteria->limit = atoi(argv[i+1]);
+        }
+    }
+    char tmp[MAXLEN];
+    int matches = 0;
+    struct UserNode *cuser;
+    reply(getTextBot(), user, "NS_TRACE_HEADER");
+    for(cuser = getAllUsers(NULL); cuser; cuser = getAllUsers(cuser)) {
+        if(show_user && matches == criteria->limit) {
+            //too many
+            break;
+        }
+        if(criteria->mask) {
+            sprintf(tmp, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+            if(match(criteria->mask, tmp)) continue;
+        }
+        if(criteria->nick && match(criteria->nick, cuser->nick)) continue;
+        if(criteria->ident && match(criteria->ident, cuser->ident)) continue;
+        if(criteria->host && match(criteria->host, cuser->host)) continue;
+        if(criteria->account && (!(cuser->flags & USERFLAG_ISAUTHED) || match(criteria->account, cuser->auth))) continue;
+        if((criteria->flags & NS_TRACE_CRITERIA_AUTHED) && (criteria->authed ^ (cuser->flags & USERFLAG_ISAUTHED))) continue;
+        if((criteria->flags & NS_TRACE_CRITERIA_NUMCHAN)) {
+            int ccount = 0;
+            struct ChanUser *chanuser;
+            for(chanuser = getUserChannels(cuser, NULL); chanuser; chanuser = getUserChannels(cuser, chanuser))
+                ccount++;
+            if(ccount < criteria->numchannels)
+                continue;
+        }
+        matches++;
+        //output
+        if(show_user) {
+            reply(getTextBot(), user, "%s!%s@%s %s", cuser->nick, cuser->ident, cuser->host, ((cuser->flags & USERFLAG_ISAUTHED) ? cuser->auth : "*"));
+        }
+    }
+    reply(getTextBot(), user, "NS_TABLE_COUNT", matches);
+}
diff --git a/src/cmd_neonserv_trim.c b/src/cmd_neonserv_trim.c
new file mode 100644 (file)
index 0000000..67501a7
--- /dev/null
@@ -0,0 +1,124 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]  target (format: minaccess-maxaccess/users/bans)
+* argv[1]  duration
+*/
+static USERLIST_CALLBACK(neonserv_cmd_trim_userlist_lookup);
+static void neonserv_cmd_trim_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, int min_access, int max_access, int duration);
+
+struct neonserv_cmd_trim_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    int min_access;
+    int max_access;
+    int duration;
+};
+
+CMD_BIND(neonserv_cmd_trim) {
+    if(stricmp(argv[0], "bans") && !checkChannelAccess(user, chan, "channel_candel", 0, 0)) {
+        if(isGodMode(user)) {
+            event->flags |= CMDFLAG_OPLOG;
+        } else {
+            reply(getTextBot(), user, "NS_ACCESS_DENIED");
+            return;
+        }
+    }
+    int min_access, max_access;
+    if(!stricmp(argv[0], "users")) {
+        min_access = 1;
+        max_access = getChannelAccess(user, chan, 0) - 1;
+    } else if(!stricmp(argv[0], "bans")) {
+        if(!checkChannelAccess(user, chan, "channel_staticban", 0, 0)) {
+            if(isGodMode(user)) {
+                event->flags |= CMDFLAG_OPLOG;
+            } else {
+                reply(getTextBot(), user, "NS_ACCESS_DENIED");
+                return;
+            }
+        }
+        //TODO: TRIM BANS
+        return;
+    } else {
+        char *seperator = strstr(argv[0], "-");
+        if(seperator) {
+            *seperator = '\0';
+            seperator++;
+            min_access = atoi(argv[0]);
+            max_access = atoi(seperator);
+            if(max_access < min_access) {
+                reply(getTextBot(), user, "NS_INVALID_ACCESS_RANGE", min_access, max_access);
+                return;
+            }
+        } else {
+            min_access = atoi(argv[0]);
+            max_access = min_access;
+        }
+        if(max_access >= getChannelAccess(user, chan, 0)) {
+            if(isGodMode(user)) {
+                event->flags |= CMDFLAG_OPLOG;
+            } else {
+                reply(getTextBot(), user, "NS_NO_ACCESS");
+                return;
+            }
+        }
+    }
+    //parse duration...
+    int duration = strToTime(user, argv[1]);
+    if(duration < 30) {
+        reply(getTextBot(), user, "NS_TRIM_DURATION_TOO_SHORT", 30);
+        return;
+    }
+    struct neonserv_cmd_trim_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->min_access = min_access;
+    cache->max_access = max_access;
+    cache->duration = duration;
+    get_userlist_with_invisible(chan, neonserv_cmd_trim_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_trim_userlist_lookup) {
+    struct neonserv_cmd_trim_cache *cache = data;
+    //got userlist
+    neonserv_cmd_trim_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->min_access, cache->max_access, cache->duration);
+    free(cache);
+}
+
+static void neonserv_cmd_trim_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, int min_access, int max_access, int duration) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int trim_count = 0, is_here;
+    struct ChanUser *chanuser;
+    printf_mysql_query("SELECT `chanuser_seen`, `user_user`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `chanuser_access` >= '%d' AND `chanuser_access` <= '%d'", chan->channel_id, min_access, max_access);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        if(!strcmp(row[0], "0") || time(0) - atoi(row[0]) >= duration) {
+            //check if the user is currently in the channel
+            is_here = 0;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !strcmp(chanuser->user->auth, row[1])) {
+                    is_here = 1;
+                    break;
+                }
+            }
+            if(!is_here) {
+                //delete the user
+                trim_count++;
+                printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_id` = '%s'", row[2]);
+            }
+        }
+    }
+    char timeBuf[MAXLEN];
+    reply(getTextBot(), user, "NS_TRIM_DONE", trim_count, min_access, max_access, chan->name, timeToStr(user, duration, 3, timeBuf));
+    if(trim_count)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_unban.c b/src/cmd_neonserv_unban.c
new file mode 100644 (file)
index 0000000..073bf50
--- /dev/null
@@ -0,0 +1,126 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nick[,*auth[,*!*@mask[...]]]
+*/
+struct neonserv_cmd_unban_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    struct ModeBuffer *modeBuf;
+    int provided_masks, done_masks, pending_whos, unbanned_masks;
+};
+
+static USERAUTH_CALLBACK(neonserv_cmd_unban_userauth_lookup);
+static void neonserv_cmd_unban_nick(struct neonserv_cmd_unban_cache *cache, struct UserNode *user);
+static void neonserv_cmd_unban_mask(struct neonserv_cmd_unban_cache *cache, char *mask);
+static void neonserv_cmd_unban_finish(struct neonserv_cmd_unban_cache *cache);
+
+CMD_BIND(neonserv_cmd_unban) {
+    char *mask, *nextmask;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    nextmask = merge_argv_char(argv, 0, argc, ',');
+    struct neonserv_cmd_unban_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->chan = chan;
+    cache->event = event;
+    cache->modeBuf = modeBuf;
+    cache->done_masks = 0;
+    cache->provided_masks = 0;
+    cache->unbanned_masks = 0;
+    while((mask = nextmask)) {
+        nextmask = strstr(mask, ",");
+        if(nextmask) {
+            *nextmask = '\0';
+            nextmask++;
+        }
+        cache->provided_masks++;
+        if(is_valid_nick(mask)) {
+            struct UserNode *cuser = getUserByNick(mask);
+            if(!cuser) {
+                cuser = createTempUser(mask);
+                cuser->flags |= USERFLAG_ISTMPUSER;
+                get_userauth(cuser, neonserv_cmd_unban_userauth_lookup, cache);
+                cache->pending_whos++;
+            } else {
+                neonserv_cmd_unban_nick(cache, cuser);
+            }
+        } else {
+            neonserv_cmd_unban_mask(cache, mask);
+        }
+    }
+    if(!cache->pending_whos)
+        neonserv_cmd_unban_finish(cache);
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_unban_userauth_lookup) {
+    struct neonserv_cmd_unban_cache *cache = data;
+    cache->pending_whos--;
+    if(user)
+        neonserv_cmd_unban_nick(cache, user);
+    else
+        neonserv_cmd_unban_mask(cache, user_nick);
+    if(!cache->pending_whos)
+        neonserv_cmd_unban_finish(cache);
+}
+
+static void neonserv_cmd_unban_nick(struct neonserv_cmd_unban_cache *cache, struct UserNode *user) {
+    int matches = 0;
+    struct BanNode *ban;
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
+    for(ban = cache->chan->bans; ban; ban = ban->next) {
+        if(!match(ban->mask, usermask)) {
+            modeBufferUnban(cache->modeBuf, ban->mask);
+            cache->unbanned_masks++;
+            matches++;
+        }
+    }
+    if(matches)
+        cache->done_masks++;
+}
+
+static void neonserv_cmd_unban_mask(struct neonserv_cmd_unban_cache *cache, char *mask) {
+    char banmask[NICKLEN+USERLEN+HOSTLEN+3];
+    int matches = 0;
+    struct BanNode *ban;
+    mask = make_banmask(mask, banmask);
+    for(ban = cache->chan->bans; ban; ban = ban->next) {
+        if(!match(mask, ban->mask)) {
+            modeBufferUnban(cache->modeBuf, ban->mask);
+            cache->unbanned_masks++;
+            matches++;
+        }
+    }
+    if(matches)
+        cache->done_masks++;
+    else {
+        for(ban = cache->chan->bans; ban; ban = ban->next) {
+            if(!match(ban->mask, mask)) {
+                reply(cache->textclient, cache->user, "NS_DELBAN_BANNED_BY", mask, ban->mask);
+                break;
+            }
+        }
+    }
+}
+
+static void neonserv_cmd_unban_finish(struct neonserv_cmd_unban_cache *cache) {
+    freeModeBuffer(cache->modeBuf);
+    if(cache->done_masks == cache->provided_masks)
+        reply(cache->textclient, cache->user, "NS_UNBAN_DONE", cache->unbanned_masks, cache->chan->name);
+    else
+        reply(cache->textclient, cache->user, "NS_UNBAN_FAIL", cache->client->user->nick);
+    if(cache->done_masks)
+        logEvent(cache->event);
+    free(cache);
+}
+
diff --git a/src/cmd_neonserv_unbanall.c b/src/cmd_neonserv_unbanall.c
new file mode 100644 (file)
index 0000000..1be8251
--- /dev/null
@@ -0,0 +1,23 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nothing
+*/
+
+CMD_BIND(neonserv_cmd_unbanall) {
+    struct ModeBuffer *modeBuf;
+    int bans = 0;
+    struct BanNode *ban;
+    modeBuf = initModeBuffer(client, chan);
+    for(ban = chan->bans; ban; ban = ban->next) {
+        modeBufferUnban(modeBuf, ban->mask);
+        bans++;
+    }
+    freeModeBuffer(modeBuf);
+    if(bans) {
+        reply(getTextBot(), user, "NS_UNBANALL_DONE", bans, chan->name);
+        logEvent(event);
+    } else
+        reply(getTextBot(), user, "NS_UNBANALL_FAIL", client->user->nick, chan->name);
+}
diff --git a/src/cmd_neonserv_unbanme.c b/src/cmd_neonserv_unbanme.c
new file mode 100644 (file)
index 0000000..808a46f
--- /dev/null
@@ -0,0 +1,27 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nothing
+*/
+
+CMD_BIND(neonserv_cmd_unbanme) {
+    struct ModeBuffer *modeBuf;
+    int bans = 0;
+    struct BanNode *ban;
+    modeBuf = initModeBuffer(client, chan);
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
+    for(ban = chan->bans; ban; ban = ban->next) {
+        if(!match(ban->mask, usermask)) {
+            modeBufferUnban(modeBuf, ban->mask);
+            bans++;
+        }
+    }
+    freeModeBuffer(modeBuf);
+    if(bans) {
+        reply(getTextBot(), user, "NS_UNBANME_DONE", bans, chan->name);
+        logEvent(event);
+    } else
+        reply(getTextBot(), user, "NS_UNBANME_FAIL", client->user->nick, usermask);
+}
diff --git a/src/cmd_neonserv_unbind.c b/src/cmd_neonserv_unbind.c
new file mode 100644 (file)
index 0000000..bc67b83
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]   command name
+*/
+
+CMD_BIND(neonserv_cmd_unbind) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `id` FROM `bot_binds` WHERE `botclass` = '%d' AND `command` = '%s'", client->botid, escape_string(argv[0]));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        reply(getTextBot(), user, "NS_UNBIND_NOT_FOUND", argv[0]);
+        return;
+    }
+    unbind_cmd(client->botid, argv[0]);
+    printf_mysql_query("DELETE FROM `bot_binds` WHERE `id` = '%s'", row[0]);
+    reply(getTextBot(), user, "NS_UNBIND_DONE", argv[0]);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_unregister.c b/src/cmd_neonserv_unregister.c
new file mode 100644 (file)
index 0000000..8da366e
--- /dev/null
@@ -0,0 +1,42 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - channel
+*/
+CMD_BIND(neonserv_cmd_unregister) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    char *channel = argv[0];
+    if(!is_valid_chan(channel)) {
+        reply(getTextBot(), user, "NS_INVALID_CHANNEL_NAME", argv[0]);
+        return;
+    }
+    int chanid;
+    printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        chanid = atoi(row[0]);
+    } else {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
+        return;
+    }
+    int botid = atoi(row[0]);
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->clientid == botid)
+            break;
+    }
+    if(bot && strcmp(row[2], "1")) {
+        putsock(bot, "PART %s :Channel unregistered.", channel);
+    }
+    printf_mysql_query("DELETE FROM `bot_channels` WHERE `id` = '%s'", row[1]);
+    reply(getTextBot(), user, "NS_UNREGISTER_DONE", channel);
+    logEvent(event);
+}
diff --git a/src/cmd_neonserv_unsuspend.c b/src/cmd_neonserv_unsuspend.c
new file mode 100644 (file)
index 0000000..c9d5aca
--- /dev/null
@@ -0,0 +1,99 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_unsuspend_nick_lookup);
+static void neonserv_cmd_unsuspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
+
+struct neonserv_cmd_unsuspend_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+};
+
+CMD_BIND(neonserv_cmd_unsuspend) {
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        neonserv_cmd_unsuspend_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_unsuspend_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
+        } else {
+            struct neonserv_cmd_unsuspend_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[0]);
+            get_userauth(cuser, neonserv_cmd_unsuspend_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_unsuspend_nick_lookup) {
+    struct neonserv_cmd_unsuspend_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_unsuspend_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_unsuspend_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid, cflags;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id`, `chanuser_flags` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
+                    return;
+                }
+            }
+            //unsuspend
+            cflags = atoi(row[2]);
+            if(!(cflags & DB_CHANUSER_SUSPENDED)) {
+                reply(textclient, user, "NS_SUSPEND_NOT", nick);
+                return;
+            }
+            cflags &= ~DB_CHANUSER_SUSPENDED;
+            printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", cflags, row[1]);
+            reply(textclient, user, "NS_SUSPEND_RESTORED", nick, chan->name);
+            logEvent(event);
+            return;
+        }
+    }
+    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+}
diff --git a/src/cmd_neonserv_up.c b/src/cmd_neonserv_up.c
new file mode 100644 (file)
index 0000000..a81de4a
--- /dev/null
@@ -0,0 +1,47 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no arguments
+*/
+
+CMD_BIND(neonserv_cmd_up) {
+    struct ChanUser *chanuser = getChanUser(user, chan);
+    if(!chanuser) {
+        reply(getTextBot(), user, "NS_NOT_ON_CHANNEL_YOU", chan->name);
+        return;
+    }
+    check_mysql();
+    loadChannelSettings(chan);
+    MYSQL_RES *res, *default_res;
+    MYSQL_ROW row, default_row;
+    int chan_getop, chan_getvoice, caccess;
+    printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return;
+    if(!row[0] || !row[1]) {
+        printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
+        default_res = mysql_use();
+        if ((default_row = mysql_fetch_row(default_res)) == NULL) return;
+        chan_getop = (row[0] ? atoi(row[0]) : atoi(default_row[0]));
+        chan_getvoice = (row[1] ? atoi(row[1]) : atoi(default_row[1]));
+    } else {
+        chan_getop = atoi(row[0]);
+        chan_getvoice = atoi(row[1]);
+    }
+    caccess = getChannelAccess(user, chan, 1);
+    if(caccess >= chan_getop) {
+        if(!(chanuser->flags & CHANUSERFLAG_OPPED)) {
+            putsock(client, "MODE %s +o %s", chan->name, user->nick);
+            logEvent(event);
+        } else
+            reply(getTextBot(), user, "NS_UP_ALREADY_OP", chan->name);
+    } else if(caccess >= chan_getvoice) {
+        if(!(chanuser->flags & CHANUSERFLAG_VOICED)) {
+            putsock(client, "MODE %s +v %s", chan->name, user->nick);
+            logEvent(event);
+        } else
+            reply(getTextBot(), user, "NS_UP_ALREADY_VOICE", chan->name);
+    } else
+        reply(getTextBot(), user, "NS_NOT_ON_USERLIST_YOU", chan->name);
+}
diff --git a/src/cmd_neonserv_upall.c b/src/cmd_neonserv_upall.c
new file mode 100644 (file)
index 0000000..bea9325
--- /dev/null
@@ -0,0 +1,54 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no arguments
+*/
+
+CMD_BIND(neonserv_cmd_upall) {
+    MYSQL_RES *res, *default_res;
+    MYSQL_ROW row, default_row;
+    struct ChanUser *chanuser;
+    int userid, chan_getop, chan_getvoice, caccess;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", user->auth);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL)
+        return;
+    userid = atoi(row[0]);
+    printf_mysql_query("SELECT `chanuser_access`, `channel_getop`, `channel_getvoice`, `channel_name`, `channel_id` FROM `chanusers` LEFT JOIN `channels` ON `chanuser_cid` = `channel_id` WHERE `chanuser_uid` = '%d'", userid);
+    res = mysql_use();
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        chan = getChanByName(row[3]);
+        if(!chan) continue;
+        printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%s' AND `botclass` = '%d'", row[4], client->botid);
+        if (mysql_fetch_row(mysql_use()) == NULL) continue;
+        if(!(chanuser = getChanUser(user, chan))) continue;
+        if(!row[1] || !row[2]) {
+            printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
+            default_res = mysql_use();
+            if ((default_row = mysql_fetch_row(default_res)) == NULL) return;
+            chan_getop = (row[1] ? atoi(row[1]) : atoi(default_row[0]));
+            chan_getvoice = (row[2] ? atoi(row[2]) : atoi(default_row[1]));
+        } else {
+            chan_getop = atoi(row[1]);
+            chan_getvoice = atoi(row[2]);
+        }
+        caccess = atoi(row[0]);
+        int done = 0;
+        if(caccess >= chan_getop) {
+            if(!(chanuser->flags & CHANUSERFLAG_OPPED)) {
+                putsock(client, "MODE %s +o %s", chan->name, user->nick);
+                done = 1;
+            }
+        } else if(caccess >= chan_getvoice) {
+            if(!(chanuser->flags & CHANUSERFLAG_VOICED)) {
+                putsock(client, "MODE %s +v %s", chan->name, user->nick);
+                done = 1;
+            }
+        }
+        if(done) {
+            event->chan = chan;
+            logEvent(event);
+        }
+    }
+}
diff --git a/src/cmd_neonserv_users.c b/src/cmd_neonserv_users.c
new file mode 100644 (file)
index 0000000..7834575
--- /dev/null
@@ -0,0 +1,116 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - usermask
+* argv[1] - min access
+* argv[2] - max access
+*/
+static USERLIST_CALLBACK(neonserv_cmd_users_userlist_lookup);
+static void neonserv_cmd_users_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access);
+
+struct neonserv_cmd_users_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    char *usermask;
+    int min_access;
+    int max_access;
+};
+
+CMD_BIND(neonserv_cmd_users) {
+    int min_access = 1, max_access = 500;
+    char *usermask = NULL;
+    if(argc > 0)
+        usermask = argv[0];
+    if(argc > 2) {
+        min_access = atoi(argv[1]);
+        max_access = atoi(argv[2]);
+    }
+    struct neonserv_cmd_users_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->usermask = (usermask ? strdup(usermask) : NULL);
+    cache->min_access = min_access;
+    cache->max_access = max_access;
+    get_userlist_with_invisible(chan, neonserv_cmd_users_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_users_userlist_lookup) {
+    struct neonserv_cmd_users_cache *cache = data;
+    neonserv_cmd_users_async1(cache->client, cache->textclient, cache->user, chan, cache->usermask, cache->min_access, cache->max_access);
+    if(cache->usermask)
+        free(cache->usermask);
+    free(cache);
+}
+
+static void neonserv_cmd_users_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *usermask, int min_access, int max_access) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int content_count = 0, cflags, is_here, caccess, i;
+    char seenstr[MAXLEN];
+    struct Table *table;
+    struct ChanUser *chanuser;
+    printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_seen`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' ORDER BY `chanuser_access` DESC, `user_user` ASC", chan->channel_id);
+    res = mysql_use();
+    table = table_init(4, mysql_num_rows(res) + 1, 0);
+    if(usermask)
+        reply(textclient, user, "NS_USERS_HEADER_MATCH", chan->name, min_access, max_access, usermask);
+    else
+        reply(textclient, user, "NS_USERS_HEADER", chan->name, min_access, max_access);
+    char *content[4];
+    content[0] = get_language_string(user, "NS_USERS_HEADER_ACCESS");
+    content[1] = get_language_string(user, "NS_USERS_HEADER_ACCOUNT");
+    content[2] = get_language_string(user, "NS_USERS_HEADER_SEEN");
+    content[3] = get_language_string(user, "NS_USERS_HEADER_STATE");
+    table_add(table, content);
+    while ((row = mysql_fetch_row(res)) != NULL) {
+        caccess = atoi(row[0]);
+        if((!usermask || !match(usermask, row[1])) && caccess >= min_access && caccess <= max_access) {
+            content[0] = row[0];
+            content[1] = row[1];
+            is_here = 0;
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if((chanuser->user->flags & USERFLAG_ISAUTHED) && !strcmp(chanuser->user->auth, row[1])) {
+                    if((chanuser->flags & CHANUSERFLAG_INVISIBLE))
+                        is_here = 2;
+                    else {
+                        is_here = 1;
+                        break;
+                    }
+                }
+            }
+            if(is_here) {
+                content[2] = get_language_string(user, (is_here == 2 ? "NS_USERS_SEEN_INVISIBLE" : "NS_USERS_SEEN_HERE"));
+            } else if(!strcmp(row[2], "0")) {
+                content[2] = get_language_string(user, "NS_USERS_SEEN_NEVER");
+            } else {
+                timeToStr(user, (time(0) - atoi(row[2])), 2, seenstr);
+                content[2] = seenstr; //generate time
+            }
+            cflags = atoi(row[3]);
+            if(cflags & DB_CHANUSER_SUSPENDED)
+                content[3] = get_language_string(user, "NS_USERS_STATE_SUSPENDED");
+            else
+                content[3] = get_language_string(user, "NS_USERS_STATE_NORMAL");
+            content_count++;
+            table_add(table, content);
+        }
+    }
+    //send the table
+    char **table_lines = table_end(table);
+    for(i = 0; i < table->entrys; i++) {
+        reply(textclient, user, table_lines[i]);
+    }
+    if(!content_count)
+        reply(textclient, user, "NS_TABLE_NONE");
+    if(usermask || min_access != 1 || max_access != 500)
+        reply(textclient, user, (table->length == 2 ? "NS_USERS_COUNT_MATCH_1" : "NS_USERS_COUNT_MATCH"), table->length - 1, chan->name, content_count);
+    else
+        reply(textclient, user, (table->length == 2 ? "NS_USERS_COUNT_1" : "NS_USERS_COUNT"), table->length - 1, chan->name);
+    table_free(table);
+}
diff --git a/src/cmd_neonserv_uset.c b/src/cmd_neonserv_uset.c
new file mode 100644 (file)
index 0000000..354c08b
--- /dev/null
@@ -0,0 +1,168 @@
+
+#include "cmd_neonserv.h"
+
+CMD_BIND(neonserv_cmd_uset) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    loadUserSettings(user);
+    if(argc > 0) {
+        if(!stricmp(argv[0], "language")) {
+            struct language* lang;
+            if(argc > 1) {
+                if((lang = get_language_by_tag(argv[1])) == NULL && (lang = get_language_by_name(argv[1])) == NULL) {
+                    lang = user->language;
+                } else {
+                    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+                    res = mysql_use();
+                    if ((row = mysql_fetch_row(res)) != NULL) {
+                        printf_mysql_query("UPDATE `users` SET `user_lang` = '%s' WHERE `user_id` = '%s'", escape_string(lang->langtag), row[0]);
+                    } else {
+                        printf_mysql_query("INSERT INTO `users` (`user_user`, `user_lang`) VALUES ('%s', '%s')", escape_string(user->auth), escape_string(lang->langtag));
+                    }
+                    struct UserNode *cuser;
+                    for(cuser = getAllUsers(NULL); cuser; cuser = getAllUsers(cuser)) {
+                        if((cuser->flags & USERFLAG_ISAUTHED) && !stricmp(user->auth, cuser->auth))
+                            cuser->language = lang;
+                    }
+                }
+            } else
+                lang = user->language;
+            reply(getTextBot(), user, "\002Language   \002%s", lang->langname);
+            char tmp[MAXLEN];
+            int tmppos = 0;
+            lang = get_default_language();
+            tmppos = sprintf(tmp, "%s (%s)", lang->langname, lang->langtag);
+            printf_mysql_query("SELECT `lang`,`text` FROM `language` WHERE `ident` = 'name'");
+            res = mysql_use();
+            while((row = mysql_fetch_row(res)) != NULL) {
+                tmppos += sprintf(tmp + tmppos, ", %s (%s)", row[1], row[0]);
+            }
+            reply(getTextBot(), user, "  %s", tmp);
+        } else if(!stricmp(argv[0], "noinvite") && chan) {
+            loadChannelSettings(chan);
+            if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) {
+                reply(getTextBot(), user, "MODCMD_CHAN_REQUIRED");
+                return;
+            }
+            printf_mysql_query("SELECT `id` FROM `noinvite` LEFT JOIN `users` ON `uid` = `user_id` WHERE `cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+            res = mysql_use();
+            row = mysql_fetch_row(res);
+            int noinvite = (row ? 1 : 0);
+            if(argc > 1) {
+                if(!strcmp(argv[1], "0") || !stricmp(argv[1], "off") || !stricmp(argv[1], get_language_string(user, "NS_SET_OFF"))) {
+                    if(noinvite) {
+                        printf_mysql_query("DELETE FROM `noinvite` WHERE `id` = '%s'", row[0]);
+                        noinvite = 0;
+                    }
+                } else if(!strcmp(argv[1], "1") || !stricmp(argv[1], "on") || !stricmp(argv[1], get_language_string(user, "NS_SET_ON"))) {
+                    if(!noinvite) {
+                        int userid;
+                        printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+                        res = mysql_use();
+                        if ((row = mysql_fetch_row(res)) != NULL) {
+                            userid = atoi(row[0]);
+                        } else {
+                            printf_mysql_query("INSERT INTO `users` (`user_user`) VALUES ('%s')", escape_string(user->auth));
+                            userid = (int) mysql_insert_id(mysql_conn);
+                        }
+                        printf_mysql_query("INSERT INTO `noinvite` (`uid`, `cid`) VALUES ('%d', '%d')", userid, chan->channel_id);
+                        noinvite = 1;
+                    }
+                }
+            }
+            reply(getTextBot(), user, "\002NoInvite   \002%s", (noinvite ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
+        } else if((!stricmp(argv[0], "autoinvite") || !stricmp(argv[0], "noautoop") || !stricmp(argv[0], "info")) && chan) {
+            loadChannelSettings(chan);
+            if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) {
+                reply(getTextBot(), user, "MODCMD_CHAN_REQUIRED");
+                return;
+            }
+            printf_mysql_query("SELECT `chanuser_flags`, `chanuser_infoline`, `chanuser_access`, `channel_getinvite`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` LEFT JOIN `channels` ON `channel_id` = `chanuser_cid` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+            res = mysql_use();
+            row = mysql_fetch_row(res);
+            if(row) {
+                int flags = atoi(row[0]);
+                if(!stricmp(argv[0], "autoinvite")) {
+                    int getInvite = 0;
+                    if(!row[3] && atoi(row[2]) >= atoi(getChanDefault("channel_getinvite")))
+                        getInvite = 1;
+                    else if(row[3] && atoi(row[2]) >= atoi(row[3]))
+                        getInvite = 1;
+                    if(getInvite && argc > 1) {
+                        if(!strcmp(argv[1], "0") || !stricmp(argv[1], "off") || !stricmp(argv[1], get_language_string(user, "NS_SET_OFF"))) {
+                            if(flags & DB_CHANUSER_AUTOINVITE) {
+                                flags &= ~DB_CHANUSER_AUTOINVITE;
+                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
+                            }
+                        } else if(!strcmp(argv[1], "1") || !stricmp(argv[1], "on") || !stricmp(argv[1], get_language_string(user, "NS_SET_ON"))) {
+                            if(!(flags & DB_CHANUSER_AUTOINVITE)) {
+                                flags |= DB_CHANUSER_AUTOINVITE;
+                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
+                            }
+                        }
+                    }
+                    if(getInvite)
+                        reply(getTextBot(), user, "\002AutoInvite \002%s", ((flags & DB_CHANUSER_AUTOINVITE) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
+                    else
+                        reply(getTextBot(), user, "\002AutoInvite \002%s", get_language_string(user, "NS_USET_NO_ACCESS"));
+                } else if(!stricmp(argv[0], "noautoop")) {
+                    if(argc > 1) {
+                        if(!strcmp(argv[1], "0") || !stricmp(argv[1], "off") || !stricmp(argv[1], get_language_string(user, "NS_SET_OFF"))) {
+                            if(flags & DB_CHANUSER_NOAUTOOP) {
+                                flags &= ~DB_CHANUSER_NOAUTOOP;
+                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
+                            }
+                        } else if(!strcmp(argv[1], "1") || !stricmp(argv[1], "on") || !stricmp(argv[1], get_language_string(user, "NS_SET_ON"))) {
+                            if(!(flags & DB_CHANUSER_NOAUTOOP)) {
+                                flags |= DB_CHANUSER_NOAUTOOP;
+                                printf_mysql_query("UPDATE `chanusers` SET `chanuser_flags` = '%d' WHERE `chanuser_id` = '%s'", flags, row[4]);
+                            }
+                        }
+                    }
+                    reply(getTextBot(), user, "\002NoAutoOp   \002%s", ((flags & DB_CHANUSER_NOAUTOOP) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
+                } else if(!stricmp(argv[0], "info")) {
+                    char *infoline;
+                    if(argc > 1) {
+                        infoline = merge_argv(argv, 1, argc);
+                        if(!strcmp(infoline, "*"))
+                            infoline = "";
+                        printf_mysql_query("UPDATE `chanusers` SET `chanuser_infoline` = '%s' WHERE `chanuser_id` = '%s'", escape_string(infoline), row[4]);
+                    } else
+                        infoline = row[1];
+                    reply(getTextBot(), user, "\002Info       \002%s", infoline);
+                }
+            } else
+                reply(getTextBot(), user, "NS_NOT_ON_USERLIST_YOU", chan);
+        } else
+            reply(getTextBot(), user, "NS_USET_UNKNOWN_SETTING", argv[0]);
+    } else {
+        //view all options
+        reply(getTextBot(), user, "NS_USET_GLOBAL");
+        reply(getTextBot(), user, "\002Language   \002%s", user->language->langname);
+        if(!chan) return;
+        loadChannelSettings(chan);
+        if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+        reply(getTextBot(), user, "NS_USET_CHANNEL");
+        printf_mysql_query("SELECT `id` FROM `noinvite` LEFT JOIN `users` ON `uid` = `user_id` WHERE `cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+        reply(getTextBot(), user, "\002NoInvite   \002%s", (row ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
+        printf_mysql_query("SELECT `chanuser_flags`, `chanuser_infoline`, `chanuser_access`, `channel_getinvite` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` LEFT JOIN `channels` ON `channel_id` = `chanuser_cid` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+        if(row) {
+            int flags = atoi(row[0]);
+            int getInvite = 0;
+            if(!row[3] && atoi(row[2]) >= atoi(getChanDefault("channel_getinvite")))
+                getInvite = 1;
+            else if(row[3] && atoi(row[2]) >= atoi(row[3]))
+                getInvite = 1;
+            if(getInvite)
+                reply(getTextBot(), user, "\002AutoInvite \002%s", ((flags & DB_CHANUSER_AUTOINVITE) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
+            else
+                reply(getTextBot(), user, "\002AutoInvite \002%s", get_language_string(user, "NS_USET_NO_ACCESS"));
+            reply(getTextBot(), user, "\002NoAutoOp   \002%s", ((flags & DB_CHANUSER_NOAUTOOP) ? get_language_string(user, "NS_SET_ON") : get_language_string(user, "NS_SET_OFF")));
+            reply(getTextBot(), user, "\002Info       \002%s", row[1]);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_version.c b/src/cmd_neonserv_version.c
new file mode 100644 (file)
index 0000000..ed33d09
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* no args
+*/
+
+CMD_BIND(neonserv_cmd_version) {
+    reply(getTextBot(), user, "\002NeonServ " NEONSERV_VERSION "\002 (%s), written by pk910", (strcmp(revision, "") ? revision : "-"));
+    reply(getTextBot(), user, "Build (#%s) %s (%s lines, " COMPILER ")", compilation, creation, codelines);
+    reply(getTextBot(), user, "NeonServ source can be found on: http://git.pk910.de/?p=NeonServV5.git");
+    //helpers :D
+    reply(getTextBot(), user, "special thanks to:");
+    reply(getTextBot(), user, "  Zer0n, TeaTow  (testing and ideas current version)");
+    reply(getTextBot(), user, "  Buchman, Zer0n  (translating current version)");
+    reply(getTextBot(), user, "  Patschi95, DerGrinch, Darkfly, Zer0n, Buschman  (testing and ideas older versions)");
+    reply(getTextBot(), user, "  Buschman, Georg, richard  (translating older versions)");
+    reply(getTextBot(), user, "and all the other users that reported all these nasty bugs :D");
+    reply(getTextBot(), user, "\002If you found a bug or if you have a good idea report it on http://bugtrack.pk910.de/git_view.php?p=NeonServV5.git\002");
+    
+}
\ No newline at end of file
diff --git a/src/cmd_neonserv_voice.c b/src/cmd_neonserv_voice.c
new file mode 100644 (file)
index 0000000..45a78a9
--- /dev/null
@@ -0,0 +1,77 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*]    nicks
+*/
+static USERLIST_CALLBACK(neonserv_cmd_voice_userlist_lookup);
+static void neonserv_cmd_voice_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks);
+
+struct neonserv_cmd_voice_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *nicks;
+};
+
+CMD_BIND(neonserv_cmd_voice) {
+    struct neonserv_cmd_voice_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    cache->nicks = strdup(merge_argv(argv, 0, argc));
+    get_userlist_with_invisible(chan, neonserv_cmd_voice_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_voice_userlist_lookup) {
+    struct neonserv_cmd_voice_cache *cache = data;
+    neonserv_cmd_voice_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks);
+    free(cache->nicks);
+    free(cache);
+}
+
+static void neonserv_cmd_voice_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks) {
+    int total_users = 0, done_users = 0;
+    struct UserNode *cuser;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    char *a, *b = nicks;
+    do {
+        a = strstr(b, " ");
+        if(a) *a = '\0';
+        total_users++;
+        cuser = searchUserByNick(b);
+        if(!cuser) {
+            //check for an invisible user
+            for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+                if(!stricmp(chanuser->user->nick, b)) {
+                    cuser = chanuser->user;
+                    break;
+                }
+            }
+            if(!cuser) continue;
+        } else {
+            chanuser = getChanUser(cuser, chan);
+            if(!chanuser) continue;
+        }
+        done_users++;
+        if(chanuser->flags & CHANUSERFLAG_VOICED) continue;
+        modeBufferVoice(modeBuf, b);
+        if(a) {
+            b = a+1;
+        }
+    } while(a);
+    freeModeBuffer(modeBuf);
+    if(done_users == total_users)
+        reply(textclient, user, "NS_VOICE_DONE", chan->name);
+    else
+        reply(textclient, user, "NS_VOICE_FAIL", client->user->nick);
+    if(done_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_voiceall.c b/src/cmd_neonserv_voiceall.c
new file mode 100644 (file)
index 0000000..e4de009
--- /dev/null
@@ -0,0 +1,57 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0]    (optional) nick mask
+*/
+static USERLIST_CALLBACK(neonserv_cmd_voiceall_userlist_lookup);
+static void neonserv_cmd_voiceall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask);
+
+struct neonserv_cmd_voiceall_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct Event *event;
+    char *nickmask;
+};
+
+CMD_BIND(neonserv_cmd_voiceall) {
+    struct neonserv_cmd_voiceall_cache *cache = malloc(sizeof(*cache));
+    if (!cache) {
+        perror("malloc() failed");
+        return;
+    }
+    cache->client = client;
+    cache->textclient = getTextBot();
+    cache->user = user;
+    cache->event = event;
+    if(argc > 0) {
+        cache->nickmask = strdup(argv[0]);
+    } else
+        cache->nickmask = NULL;
+    get_userlist_with_invisible(chan, neonserv_cmd_voiceall_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_voiceall_userlist_lookup) {
+    struct neonserv_cmd_voiceall_cache *cache = data;
+    neonserv_cmd_voiceall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask);
+    if(cache->nickmask)
+        free(cache->nickmask);
+    free(cache);
+}
+
+static void neonserv_cmd_voiceall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask) {
+    int done_users = 0;
+    struct ChanUser *chanuser;
+    struct ModeBuffer *modeBuf;
+    modeBuf = initModeBuffer(client, chan);
+    for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+        if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+        if(chanuser->flags & CHANUSERFLAG_VOICED) continue;
+        modeBufferVoice(modeBuf, chanuser->user->nick);
+        done_users++;
+    }
+    freeModeBuffer(modeBuf);
+    reply(textclient, user, "NS_VOICEALL_DONE", done_users, chan->name);
+    if(done_users)
+        logEvent(event);
+}
diff --git a/src/cmd_neonserv_wipeinfo.c b/src/cmd_neonserv_wipeinfo.c
new file mode 100644 (file)
index 0000000..81378d6
--- /dev/null
@@ -0,0 +1,93 @@
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] - nick / *auth
+*/
+static USERAUTH_CALLBACK(neonserv_cmd_wipeinfo_nick_lookup);
+static void neonserv_cmd_wipeinfo_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth);
+
+struct neonserv_cmd_wipeinfo_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    struct Event *event;
+    char *nick;
+};
+
+CMD_BIND(neonserv_cmd_wipeinfo) {
+    if(argv[0][0] == '*') {
+        //we've got an auth
+        argv[0]++;
+        neonserv_cmd_wipeinfo_async1(client, getTextBot(), user, chan, event, argv[0], argv[0]);
+    } else {
+        struct UserNode *cuser = getUserByNick(argv[0]);
+        if(!cuser) {
+            cuser = createTempUser(argv[0]);
+            cuser->flags |= USERFLAG_ISTMPUSER;
+        }
+        if(cuser->flags & USERFLAG_ISAUTHED) {
+            neonserv_cmd_wipeinfo_async1(client, getTextBot(), user, chan, event, argv[0], cuser->auth);
+        } else {
+            struct neonserv_cmd_wipeinfo_cache *cache = malloc(sizeof(*cache));
+            if (!cache) {
+                perror("malloc() failed");
+                return;
+            }
+            cache->client = client;
+            cache->textclient = getTextBot();
+            cache->user = user;
+            cache->chan = chan;
+            cache->event = event;
+            cache->nick = strdup(argv[0]);
+            get_userauth(cuser, neonserv_cmd_wipeinfo_nick_lookup, cache);
+        }
+    }
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_wipeinfo_nick_lookup) {
+    struct neonserv_cmd_wipeinfo_cache *cache = data;
+    if(!user) {
+        //USER_DOES_NOT_EXIST
+        reply(cache->textclient, cache->user, "NS_USER_UNKNOWN", cache->nick);
+    }
+    else if(!(user->flags & USERFLAG_ISAUTHED)) {
+        //USER_NOT_AUTHED
+        reply(cache->textclient, cache->user, "NS_USER_NEED_AUTH", cache->nick);
+    }
+    else
+        neonserv_cmd_wipeinfo_async1(cache->client, cache->textclient, cache->user, cache->chan, cache->event, user->nick, user->auth);
+    free(cache->nick);
+    free(cache);
+}
+
+static void neonserv_cmd_wipeinfo_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nick, char *auth) {
+    //we've got a valid auth now...
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int userid;
+    printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) != NULL) {
+        userid = atoi(row[0]);
+        //check if the user is already added
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_id` FROM `chanusers` WHERE `chanuser_cid` = '%d' AND `chanuser_uid` = '%d'", chan->channel_id, userid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            if(atoi(row[0]) >= getChannelAccess(user, chan, 0)) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(textclient, user, "NS_USER_OUTRANKED", nick);
+                    return;
+                }
+            }
+            //delete
+            printf_mysql_query("UPDATE `chanusers` SET `chanuser_infoline` = '' WHERE `chanuser_id` = '%s'", row[1]);
+            reply(textclient, user, "NS_WIPEINFO_DONE", nick, chan->name);
+            logEvent(event);
+            return;
+        }
+    }
+    reply(textclient, user, "NS_NOT_ON_USERLIST", nick, chan->name);
+}
diff --git a/src/config.h.example b/src/config.h.example
new file mode 100644 (file)
index 0000000..6d573d4
--- /dev/null
@@ -0,0 +1,6 @@
+
+#define MYSQL_HOST "127.0.0.1"
+#define MYSQL_PORT 3306
+#define MYSQL_USER "neonserv"
+#define MYSQL_PASS ""
+#define MYSQL_BASE "neonserv"
diff --git a/src/event_neonserv_ctcp.c b/src/event_neonserv_ctcp.c
new file mode 100644 (file)
index 0000000..a8df98e
--- /dev/null
@@ -0,0 +1,133 @@
+
+struct neonserv_event_ctcp_cache {
+    struct ClientSocket *client;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    char *command;
+    char *text;
+};
+
+static USERAUTH_CALLBACK(neonserv_event_ctcp_nick_lookup);
+static void neonserv_event_ctcp_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char *text);
+static int neonserv_ctcp(char *buffer, char *command, char *text);
+
+static void neonserv_event_chanctcp(struct UserNode *user, struct ChanNode *chan, char *command, char *text) {
+    struct ClientSocket *client = getBotForChannel(chan);
+    if(!client) return; //we can't "see" this event
+    if(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)) return; 
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+    if(!(user->flags & USERFLAG_ISAUTHED)) {
+        struct neonserv_event_ctcp_cache *cache = malloc(sizeof(*cache));
+        if (!cache) {
+            perror("malloc() failed");
+            return;
+        }
+        cache->client = client;
+        cache->user = user;
+        cache->chan = chan;
+        cache->command = strdup(command);
+        cache->text = (text ? strdup(text) : NULL);
+        get_userauth(user, neonserv_event_ctcp_nick_lookup, cache);
+    } else
+        neonserv_event_ctcp_async1(client, user, chan, command, text);
+}
+
+static USERAUTH_CALLBACK(neonserv_event_ctcp_nick_lookup) {
+    struct neonserv_event_ctcp_cache *cache = data;
+    if(user) {
+        neonserv_event_ctcp_async1(cache->client, cache->user, cache->chan, cache->command, cache->text);
+    }
+    free(cache->command);
+    if(cache->text)
+        free(cache->text);
+    free(cache);
+}
+
+static void neonserv_event_ctcp_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *command, char *text) {
+    MYSQL_RES *res;
+    MYSQL_ROW row, defaultrow = NULL, chanuser;
+    int uaccess = 0;
+    printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return;
+    if(!row[0] || !row[1]) {
+        printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        defaultrow = mysql_fetch_row(res);
+    }
+    int ctcpaccess = atoi((row[0] ? row[0] : defaultrow[0]));
+    if((user->flags & USERFLAG_ISAUTHED)) {
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+        res = mysql_use();
+        chanuser = mysql_fetch_row(res);
+        if(chanuser)
+            uaccess = ((atoi(chanuser[1]) & DB_CHANUSER_SUSPENDED) ? 0 : atoi(chanuser[0]));
+    }
+    int duration = 0;
+    char banmaskBuf[NICKLEN+USERLEN+HOSTLEN+3];
+    char *banmask = NULL;
+    char *reason = "disallowed channel CTCP";
+    if(uaccess < ctcpaccess) {
+        switch(atoi((row[1] ? row[1] : defaultrow[1]))) {
+            case 2: //TIMEBAN: 3min
+                duration = 180;
+            case 3: //TIMEBAN: 1h
+                if(!duration)
+                    duration = 3600;
+                banmask = generate_banmask(user, banmaskBuf);
+                printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(banmask), (unsigned long) (time(0) + duration), 0, escape_string(reason));
+                int banid = (int) mysql_insert_id(mysql_conn);
+                char nameBuf[MAXLEN];
+                char banidBuf[20];
+                sprintf(nameBuf, "ban_%d", banid);
+                sprintf(banidBuf, "%d", banid);
+                timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
+            case 1: //KICKBAN
+                if(!banmask)
+                    banmask = generate_banmask(user, banmaskBuf);
+                putsock(client, "MODE %s +b %s", chan->name, banmask);
+            case 0: //KICK
+                putsock(client, "KICK %s %s :%s", chan->name, user->nick, reason);
+                break;
+        }
+    }
+}
+
+static void neonserv_event_privctcp(struct UserNode *user, struct UserNode *target, char *command, char *text) {
+    char ctcpBuf[MAXLEN];
+    if(neonserv_ctcp(ctcpBuf, command, text)) {
+        struct ClientSocket *bot;
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(bot->user == target) break;
+        }
+        if(bot)
+            putsock(bot, "NOTICE %s :\001%s\001", user->nick, ctcpBuf);
+    }
+}
+
+static int neonserv_ctcp(char *buffer, char *command, char *text) {
+    if(!stricmp(command, "VERSION")) {
+        sprintf(buffer, "VERSION NeonServ v" NEONSERV_VERSION " by pk910 (%s)", (strcmp(revision, "") ? revision : "-"));
+        return 1;
+    }
+    if(!stricmp(command, "FINGER")) {
+        sprintf(buffer, "FINGER NeonServ v" NEONSERV_VERSION " (%s) build %s lines C code using " COMPILER " (see +netinfo)", (strcmp(revision, "") ? revision : "-"), codelines);
+        return 1;
+    }
+    if(!stricmp(command, "PING")) {
+        sprintf(buffer, "PING %s", (text ? text : "0"));
+        return 1;
+    }
+    if(!stricmp(command, "TIME")) {
+        time_t rawtime;
+        struct tm *timeinfo;
+        char timeBuf[80];
+        time(&rawtime);
+        timeinfo = localtime(&rawtime);
+        strftime(timeBuf, 80, "%c", timeinfo);
+        sprintf(buffer, "TIME %s", timeBuf);
+        return 1;
+    }
+    return 0;
+}
diff --git a/src/event_neonserv_invite.c b/src/event_neonserv_invite.c
new file mode 100644 (file)
index 0000000..c25aff4
--- /dev/null
@@ -0,0 +1,25 @@
+
+static void neonserv_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) {
+        reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick);
+        return;
+    }
+    int botid = atoi(row[0]);
+    struct ClientSocket *bot;
+    for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+        if(bot->clientid == botid)
+            break;
+    }
+    if(bot) {
+        struct ChanNode *chan = getChanByName(channel);
+        if(chan && isUserOnChan(bot->user, chan)) {
+            reply(client, user, "NS_INVITE_ON_CHAN", bot->user->nick, chan->name);
+        } else
+            putsock(bot, "JOIN %s", channel);
+    }
+}
+
diff --git a/src/event_neonserv_join.c b/src/event_neonserv_join.c
new file mode 100644 (file)
index 0000000..a117c18
--- /dev/null
@@ -0,0 +1,176 @@
+
+struct neonserv_event_join_cache {
+    struct ClientSocket *client;
+    struct ChanUser *chanuser;
+};
+
+static USERAUTH_CALLBACK(neonserv_event_join_nick_lookup);
+static void neonserv_event_join_async1(struct ClientSocket *client, struct ChanUser *chanuser);
+static TIMEQ_CALLBACK(neonserv_event_join_dynlimit);
+
+static void neonserv_event_join(struct ChanUser *chanuser) {
+    struct UserNode *user = chanuser->user;
+    struct ClientSocket *client = getBotForChannel(chanuser->chan);
+    if(!client) return; //we can't "see" this event
+    if(user->flags & USERFLAG_ISBOT) {
+        putsock(client, "MODE %s +o %s", chanuser->chan->name, chanuser->user->nick);
+        return;
+    }
+    loadChannelSettings(chanuser->chan);
+    if(!(chanuser->chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+    char *ban;
+    char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+    sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
+    if((ban = getBanAffectingMask(chanuser->chan, usermask)) != NULL && !(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP))) {
+        MYSQL_RES *res;
+        MYSQL_ROW row;
+        printf_mysql_query("SELECT `ban_reason`, `user_user` FROM `bans` LEFT JOIN `users` ON `ban_owner` = `user_id` WHERE `ban_channel` = '%d' AND `ban_mask` = '%s'", chanuser->chan->channel_id, escape_string(ban));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            putsock(client, "MODE %s +b %s", chanuser->chan->name, ban);
+            putsock(client, "KICK %s %s :(%s) %s", chanuser->chan->name, chanuser->user->nick, (row[1] ? row[1] : client->user->nick), row[0]);
+            return;
+        }
+    }
+    if(!(user->flags & USERFLAG_ISAUTHED)) {
+        struct neonserv_event_join_cache *cache = malloc(sizeof(*cache));
+        if (!cache) {
+            perror("malloc() failed");
+            return;
+        }
+        cache->client = client;
+        cache->chanuser = chanuser;
+        get_userauth(user, neonserv_event_join_nick_lookup, cache);
+    } else
+        neonserv_event_join_async1(client, chanuser);
+}
+
+static USERAUTH_CALLBACK(neonserv_event_join_nick_lookup) {
+    struct neonserv_event_join_cache *cache = data;
+    if(user) {
+        neonserv_event_join_async1(cache->client, cache->chanuser);
+    }
+    free(cache);
+}
+
+static void neonserv_event_join_async1(struct ClientSocket *client, struct ChanUser *chanuser) {
+    struct ClientSocket *textclient = ((client->flags & SOCKET_FLAG_PREFERRED) ? client : get_prefered_bot(client->botid));
+    struct ChanNode *chan = chanuser->chan;
+    struct UserNode *user = chanuser->user;
+    struct ModeBuffer *modeBuf;
+    MYSQL_RES *res;
+    MYSQL_ROW row, chanuserrow, defaultrow = NULL;
+    printf_mysql_query("SELECT `channel_maxusers`, `channel_greeting`, `channel_usergreeting`, `channel_getop`, `channel_getvoice`, `channel_userinfo`, `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return;
+    if(!row[3] || !row[4]) {
+        printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_userinfo` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        defaultrow = mysql_fetch_row(res);
+    }
+    if(chan->usercount > atoi(row[0])) {
+        //update maxusers
+        printf_mysql_query("UPDATE `channels` SET `channel_maxusers` = '%d' WHERE `channel_id` = '%d'", chan->usercount, chan->channel_id);
+    }
+    if((user->flags & USERFLAG_ISAUTHED)) {
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags`, `chanuser_infoline`, `chanuser_seen`, `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+        res = mysql_use();
+        chanuserrow = mysql_fetch_row(res);
+    } else
+        chanuserrow = NULL;
+    int userflags = (chanuserrow ? atoi(chanuserrow[1]) : 0);
+    int uaccess = ((chanuserrow && !(userflags & DB_CHANUSER_SUSPENDED)) ? atoi(chanuserrow[0]) : 0);
+    //GREETING
+    char greeting[MAXLEN];
+    int greetingPos = 0;
+    char *a, *b = (chanuserrow && *row[2] ? row[2] : row[1]);
+    do {
+        if(!b) break;
+        a = strstr(b, "$");
+        if(a) *a = '\0';
+        greetingPos += sprintf(greeting + greetingPos, "%s", b);
+        if(!a) break;
+        switch(a[1]) {
+            case '\0':
+                a = NULL;
+                break;
+            case 'A':
+                greetingPos += sprintf(greeting + greetingPos, "%d", uaccess);
+                break;
+            case 'B':
+                greetingPos += sprintf(greeting + greetingPos, "%s", client->user->nick);
+                break;
+            case 'N':
+                greetingPos += sprintf(greeting + greetingPos, "%s", user->nick);
+                break;
+            case 'H':
+                greetingPos += sprintf(greeting + greetingPos, "%s@%s", user->ident, user->host);
+                break;
+            case 'U':
+                greetingPos += sprintf(greeting + greetingPos, "%s", ((user->flags & USERFLAG_ISAUTHED) ? user->auth : "*"));
+                break;
+            default:
+                greeting[greetingPos++] = '$';
+                greeting[greetingPos++] = a[1];
+                break;
+        }
+        if(a)
+            b = a+2;
+    } while(a);
+    if(greetingPos)
+        reply(textclient, user, "[%s] %s", chan->name, greeting);
+    //USER RIGHTS
+    if(!(userflags & DB_CHANUSER_NOAUTOOP)) {
+        int getop = atoi((row[3] ? row[3] : defaultrow[0]));
+        int getvoice = atoi((row[4] ? row[4] : defaultrow[1]));
+        modeBuf = initModeBuffer(client, chan);
+        if(uaccess >= getop && uaccess != 0) { //we disallow auto op for all users
+            modeBufferOp(modeBuf, user->nick);
+        } else if(uaccess >= getvoice) {
+            modeBufferVoice(modeBuf, user->nick);
+        }
+        freeModeBuffer(modeBuf);
+    }
+    //INFOLINE
+    int userinfoaccess = atoi((row[5] ? row[5] : defaultrow[2]));
+    if(chanuserrow && strcmp(chanuserrow[2], "") && uaccess > userinfoaccess) {
+        if(!strcmp(chanuserrow[3], "0") || time(0) - atol(chanuserrow[3]) >= 30) {
+            putsock(client, "PRIVMSG %s :[%s] %s", chan->name, user->nick, chanuserrow[2]);
+        }
+    }
+    //SEEN
+    if(chanuserrow) {
+        printf_mysql_query("UPDATE `chanusers` SET `chanuser_seen` = UNIX_TIMESTAMP() WHERE `chanuser_id` = '%s'", chanuserrow[4]);
+    }
+    //DYNLIMIT
+    if(row[6] && strcmp(row[6], "0")) {
+        char nameBuf[CHANNELLEN + 10];
+        sprintf(nameBuf, "dynlimit_%s", chan->name);
+        if(!timeq_name_exists(nameBuf)) {
+            //neonserv_event_join_dynlimit
+            timeq_add_name(nameBuf, 30, neonserv_event_join_dynlimit, strdup(chan->name));
+        }
+    }
+    //AUTOINVITE
+    if(chanuserrow && !strcmp(chanuserrow[3], "0") && time(0) - atol(chanuserrow[3]) >= 30) {
+        //TODO: autoinvite
+    }
+}
+
+static TIMEQ_CALLBACK(neonserv_event_join_dynlimit) {
+    char *chanName = data;
+    struct ChanNode *chan = getChanByName(chanName);
+    free(chanName);
+    struct ClientSocket *client = getBotForChannel(chan);
+    if(!client) return;
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return;
+    if(row[0] && strcmp(row[0], "0")) {
+        putsock(client, "MODE %s +l %d", chan->name, chan->usercount + atoi(row[0]));
+    }
+}
diff --git a/src/event_neonserv_notice.c b/src/event_neonserv_notice.c
new file mode 100644 (file)
index 0000000..a566a4e
--- /dev/null
@@ -0,0 +1,91 @@
+
+struct neonserv_event_notice_cache {
+    struct ClientSocket *client;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    char *message;
+};
+
+static USERAUTH_CALLBACK(neonserv_event_notice_nick_lookup);
+static void neonserv_event_notice_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message);
+
+static void neonserv_event_channotice(struct UserNode *user, struct ChanNode *chan, char *message) {
+    struct ClientSocket *client = getBotForChannel(chan);
+    if(!client) return; //we can't "see" this event
+    if(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)) return; 
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+    if(!(user->flags & USERFLAG_ISAUTHED)) {
+        struct neonserv_event_notice_cache *cache = malloc(sizeof(*cache));
+        if (!cache) {
+            perror("malloc() failed");
+            return;
+        }
+        cache->client = client;
+        cache->user = user;
+        cache->chan = chan;
+        cache->message = strdup(message);
+        get_userauth(user, neonserv_event_notice_nick_lookup, cache);
+    } else
+        neonserv_event_notice_async1(client, user, chan, message);
+}
+
+static USERAUTH_CALLBACK(neonserv_event_notice_nick_lookup) {
+    struct neonserv_event_notice_cache *cache = data;
+    if(user) {
+        neonserv_event_notice_async1(cache->client, cache->user, cache->chan, cache->message);
+    }
+    free(cache->message);
+    free(cache);
+}
+
+static void neonserv_event_notice_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) {
+    MYSQL_RES *res;
+    MYSQL_ROW row, defaultrow = NULL, chanuser;
+    int uaccess = 0;
+    printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return;
+    if(!row[0] || !row[1]) {
+        printf_mysql_query("SELECT `channel_ctcp`, `channel_ctcpreaction` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        defaultrow = mysql_fetch_row(res);
+    }
+    int noticeaccess = atoi((row[0] ? row[0] : defaultrow[0]));
+    if((user->flags & USERFLAG_ISAUTHED)) {
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+        res = mysql_use();
+        chanuser = mysql_fetch_row(res);
+        if(chanuser)
+            uaccess = ((atoi(chanuser[1]) & DB_CHANUSER_SUSPENDED) ? 0 : atoi(chanuser[0]));
+    }
+    int duration = 0;
+    char banmaskBuf[NICKLEN+USERLEN+HOSTLEN+3];
+    char *banmask = NULL;
+    char *reason = "disallowed channel NOTICE";
+    if(uaccess < noticeaccess) {
+        switch(atoi((row[1] ? row[1] : defaultrow[1]))) {
+            case 2: //TIMEBAN: 3min
+                duration = 180;
+            case 3: //TIMEBAN: 1h
+                if(!duration)
+                    duration = 3600;
+                banmask = generate_banmask(user, banmaskBuf);
+                printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(banmask), (unsigned long) (time(0) + duration), 0, escape_string(reason));
+                int banid = (int) mysql_insert_id(mysql_conn);
+                char nameBuf[MAXLEN];
+                char banidBuf[20];
+                sprintf(nameBuf, "ban_%d", banid);
+                sprintf(banidBuf, "%d", banid);
+                timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
+            case 1: //KICKBAN
+                if(!banmask)
+                    banmask = generate_banmask(user, banmaskBuf);
+                putsock(client, "MODE %s +b %s", chan->name, banmask);
+            case 0: //KICK
+                putsock(client, "KICK %s %s :%s", chan->name, user->nick, reason);
+                break;
+        }
+    }
+}
+
diff --git a/src/event_neonserv_part.c b/src/event_neonserv_part.c
new file mode 100644 (file)
index 0000000..d02aeef
--- /dev/null
@@ -0,0 +1,15 @@
+
+static void neonserv_event_part(struct ChanUser *chanuser, char *reason) {
+    struct ChanNode *chan = chanuser->chan;
+    struct UserNode *user = chanuser->user;
+    MYSQL_RES *res;
+    MYSQL_ROW chanuserrow;
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+    if((user->flags & USERFLAG_ISAUTHED)) {
+        printf_mysql_query("SELECT `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+        res = mysql_use();
+        if((chanuserrow = mysql_fetch_row(res)) != NULL)
+            printf_mysql_query("UPDATE `chanusers` SET `chanuser_seen` = UNIX_TIMESTAMP() WHERE `chanuser_id` = '%s'", chanuserrow[0]);
+    }
+}
diff --git a/src/event_neonserv_quit.c b/src/event_neonserv_quit.c
new file mode 100644 (file)
index 0000000..30d467f
--- /dev/null
@@ -0,0 +1,14 @@
+
+static void neonserv_event_quit(struct UserNode *user, char *reason) {
+    MYSQL_RES *res;
+    MYSQL_ROW chanuserrow;
+    struct ChanUser *chanuser;
+    if((user->flags & USERFLAG_ISAUTHED)) {
+        for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = getUserChannels(user, chanuser)) {
+            printf_mysql_query("SELECT `chanuser_id` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` LEFT JOIN `channels` ON `chanuser_cid` = `channel_id` WHERE `channel_name` = '%s' AND `user_user` = '%s'", escape_string(chanuser->chan->name), escape_string(user->auth));
+            res = mysql_use();
+            if((chanuserrow = mysql_fetch_row(res)) != NULL)
+                printf_mysql_query("UPDATE `chanusers` SET `chanuser_seen` = UNIX_TIMESTAMP() WHERE `chanuser_id` = '%s'", chanuserrow[0]);
+        }
+    }
+}
diff --git a/src/event_neonserv_topic.c b/src/event_neonserv_topic.c
new file mode 100644 (file)
index 0000000..1dc2b51
--- /dev/null
@@ -0,0 +1,97 @@
+
+struct neonserv_event_topic_cache {
+    struct ClientSocket *client;
+    struct UserNode *user;
+    struct ChanNode *chan;
+    char *new_topic;
+};
+
+static USERAUTH_CALLBACK(neonserv_event_topic_nick_lookup);
+static void neonserv_event_topic_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, const char *new_topic);
+
+static void neonserv_event_topic(struct UserNode *user, struct ChanNode *chan, const char *new_topic) {
+    struct ClientSocket *client = getBotForChannel(chan);
+    if(!client) return; //we can't "see" this event
+    if(user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)) return; 
+    loadChannelSettings(chan);
+    if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) return;
+    if(!(user->flags & USERFLAG_ISAUTHED)) {
+        struct neonserv_event_topic_cache *cache = malloc(sizeof(*cache));
+        if (!cache) {
+            perror("malloc() failed");
+            return;
+        }
+        cache->client = client;
+        cache->user = user;
+        cache->chan = chan;
+        cache->new_topic = strdup(new_topic);
+        get_userauth(user, neonserv_event_topic_nick_lookup, cache);
+    } else
+        neonserv_event_topic_async1(client, user, chan, new_topic);
+}
+
+static USERAUTH_CALLBACK(neonserv_event_topic_nick_lookup) {
+    struct neonserv_event_topic_cache *cache = data;
+    if(user) {
+        neonserv_event_topic_async1(cache->client, cache->user, cache->chan, cache->new_topic);
+    }
+    free(cache->new_topic);
+    free(cache);
+}
+
+static void neonserv_event_topic_async1(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, const char *new_topic) {
+    MYSQL_RES *res;
+    MYSQL_ROW row, defaultrow = NULL, chanuserrow;
+    int uaccess = 0;
+    printf_mysql_query("SELECT `channel_changetopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    if ((row = mysql_fetch_row(res)) == NULL) return;
+    if(!row[0] || !row[1]) {
+        printf_mysql_query("SELECT `channel_changetopic`, `channel_topicsnarf` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        defaultrow = mysql_fetch_row(res);
+    }
+    int changetopic = atoi((row[0] ? row[0] : defaultrow[0]));
+    int topicsnarf = atoi((row[1] ? row[1] : defaultrow[1]));
+    if((user->flags & USERFLAG_ISAUTHED)) {
+        printf_mysql_query("SELECT `chanuser_access`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' AND `user_user` = '%s'", chan->channel_id, escape_string(user->auth));
+        res = mysql_use();
+        chanuserrow = mysql_fetch_row(res);
+        if(chanuserrow)
+            uaccess = ((atoi(chanuserrow[1]) & DB_CHANUSER_SUSPENDED) ? 0 : atoi(chanuserrow[0]));
+    }
+    if(uaccess < changetopic) {
+        //undo topic change
+        struct ClientSocket *textclient = ((client->flags & SOCKET_FLAG_PREFERRED) ? client : get_prefered_bot(client->botid));
+        struct ChanUser *chanuser = getChanUser(user, chan);
+        if(!chanuser) return; //flying super cow?
+        if(time(0) - chanuser->changeTime > BOTWAR_DETECTION_TIME) {
+            chanuser->changeTime = time(0);
+            chanuser->chageEvents = 1;
+        } else {
+            chanuser->chageEvents++;
+            if(chanuser->chageEvents >= BOTWAR_DETECTION_EVENTS || chanuser->chageEvents < 0) {
+                //BOTWAR!
+                chanuser->changeTime = time(0);
+                if(chanuser->chageEvents > 0) {
+                    putsock(client, "NOTICE @%s :%s %s", chan->name, get_language_string(user, "NS_BOTWAR_DETECTED"), (BOTWAR_ALERT_CHAN ? get_language_string(user, "NS_BOTWAR_REPORTED") : ""));
+                    if(BOTWAR_ALERT_CHAN) {
+                        struct ChanNode *alertchan = getChanByName(BOTWAR_ALERT_CHAN);
+                        struct ClientSocket *alertclient;
+                        if(alertchan && (alertclient = getBotForChannel(chan)) != NULL) {
+                            char msgBuf[MAXLEN];
+                            putsock(alertclient, "PRIVMSG %s :%s", alertchan->name, build_language_string(user, msgBuf, "NS_BOTWAR_ALERT", chan->name, user->nick));
+                        }
+                    }
+                }
+                chanuser->chageEvents = -2;
+                return;
+            }
+        }
+        reply(textclient, user, "NS_TOPIC_ACCESS", chan->name);
+        putsock(client, "TOPIC %s :%s", chan->name, chan->topic);
+    } else if(uaccess >= topicsnarf) {
+        printf_mysql_query("UPDATE `channels` SET `channel_defaulttopic` = '%s' WHERE `channel_id` = '%d'", escape_string(new_topic), chan->channel_id);
+    }
+}
+
diff --git a/src/lang.c b/src/lang.c
new file mode 100644 (file)
index 0000000..e50e752
--- /dev/null
@@ -0,0 +1,201 @@
+#include "lang.h"
+#include "UserNode.h"
+#include "DBHelper.h"
+#include "mysqlConn.h"
+
+#define DEFAULT_LANG_TAG "EN"
+#define DEFAULT_LANG_NAME "English"
+
+static struct language **langdict;
+static struct language *lang_c;
+
+void init_lang() {
+    langdict = calloc(MAXLANGUAGES, sizeof(*langdict));
+}
+
+void free_lang() {
+    
+}
+
+void load_languages() {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `lang`, `text` FROM `language` WHERE `ident` = 'name'");
+    res = mysql_use();
+    while((row = mysql_fetch_row(res)) != NULL) {
+        load_language(row[0], row[1]);
+    }
+}
+
+static struct language* add_language(char *langtag, char *langname) {
+    int cindex;
+    for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
+        if(langdict[cindex] == NULL) break;
+        if(!strcmp(langdict[cindex]->langname, langname) || !strcmp(langdict[cindex]->langtag, langtag))
+            return langdict[cindex];
+    }
+    if(cindex == MAXLANGUAGES) return NULL;
+    struct language *lang = malloc(sizeof(*lang));
+    if (!lang) {
+        perror("malloc() failed");
+        return NULL;
+    }
+    lang->langtag = strdup(langtag);
+    lang->langname = strdup(langname);
+    struct language_table **entrys = calloc(27, sizeof(*entrys));
+    lang->entrys = entrys;
+    langdict[cindex] = lang;
+    return lang;
+}
+
+static int get_entry_index(const char *ident) {
+    const char *underscore = strstr(ident, "_");
+    if(!underscore || !(underscore[1] >= 65 && underscore[1] <= 90)) return 26;
+    return (underscore[1] - 'A');
+}
+
+void load_language(char *tag, char *name) {
+    struct language *lang = get_language_by_tag(tag);
+    if(lang == get_default_language()) return;
+    if(lang) {
+        //remove all entrys
+        int cindex;
+        struct language_table *entry, *next;
+        for(cindex = 0; cindex < 27; cindex++) {
+            for(entry = lang->entrys[cindex]; entry; entry = next) {
+                next = entry->next;
+                free(entry->ident);
+                free(entry->text);
+                free(entry);
+            }
+            lang->entrys[cindex] = NULL;
+        }
+    } else
+        lang = add_language(tag, name);
+    if(!lang) return;
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `ident`, `text` FROM `language` WHERE `lang` = '%s' AND `ident` != 'name'", escape_string(tag));
+    res = mysql_use();
+    while((row = mysql_fetch_row(res)) != NULL) {
+        register_language_string(lang, row[0], row[1]);
+    }
+}
+
+struct language* get_language_by_tag(char *tag) {
+    int cindex;
+    for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
+        if(langdict[cindex] == NULL) break;
+        if(!stricmp(langdict[cindex]->langtag, tag))
+            return langdict[cindex];
+    }
+    return NULL;
+}
+
+struct language* get_language_by_name(char *name) {
+    int cindex;
+    for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
+        if(langdict[cindex] == NULL) break;
+        if(!stricmp(langdict[cindex]->langname, name))
+            return langdict[cindex];
+    }
+    return NULL;
+}
+
+struct language* get_default_language() {
+    if(lang_c == NULL) 
+        lang_c = add_language(DEFAULT_LANG_TAG, DEFAULT_LANG_NAME);
+    return lang_c;
+}
+
+void register_default_language_table(const struct default_language_entry *msgtab) {
+    if(lang_c == NULL) 
+        lang_c = add_language(DEFAULT_LANG_TAG, DEFAULT_LANG_NAME);
+    while(msgtab->ident) {
+        register_language_string(lang_c, msgtab->ident, msgtab->text);
+        msgtab++;
+    }
+}
+
+void register_language_string(struct language *lang, char *ident, char *text) {
+    int cindex = get_entry_index(ident);
+    struct language_table *lang_entry = malloc(sizeof(*lang_entry));
+    if (!lang_entry) {
+        perror("malloc() failed");
+        return;
+    }
+    
+    lang_entry->ident = strdup(ident);
+    //replace all:
+    //$b to \002
+    //$k to \003
+    char txt[MAXLEN];
+    strcpy(txt, text);
+    char tmp[MAXLEN];
+    int tmppos = 0;
+    char *a, *b = txt;
+    do {
+        a = strstr(b, "$");
+        if(a) *a = '\0';
+        tmppos += sprintf(tmp + tmppos, "%s", b);
+        if(a) {
+            switch(a[1]) {
+                case 'b':
+                    tmp[tmppos++] = '\002';
+                    break;
+                case 'k':
+                    tmp[tmppos++] = '\003';
+                    break;
+                default:
+                    //unknown - just write it
+                    tmppos += sprintf(tmp + tmppos, "$%c", a[1]);
+            }
+            b = a+2;
+        }
+    } while(a);
+    lang_entry->text = strdup(tmp);
+    lang_entry->next = lang->entrys[cindex];
+    lang->entrys[cindex] = lang_entry;
+}
+
+char *get_language_string(struct UserNode *user, const char* msg_ident) {
+    struct language* lang;
+    if((user->flags & USERFLAG_ISAUTHED)) {
+        loadUserSettings(user);
+        lang = user->language;
+    } else
+        lang = lang_c;
+    int cindex = get_entry_index(msg_ident);
+    struct language_table* entry;
+    for(entry = lang->entrys[cindex]; entry; entry = entry->next) {
+        if(!strcmp(entry->ident, msg_ident))
+            return entry->text;
+    }
+    if(lang == lang_c) return NULL;
+    for(entry = lang_c->entrys[cindex]; entry; entry = entry->next) {
+        if(!strcmp(entry->ident, msg_ident))
+            return entry->text;
+    }
+    return NULL;
+}
+
+char *build_language_string(struct UserNode *user, char *buffer, const char *msg_ident, ...) {
+    char *formatStr = get_language_string(user, msg_ident);
+    if(!formatStr) return NULL;
+    if(buffer == NULL) {
+        buffer = (char *)malloc((MAXLEN+1) * sizeof(char));
+        if (!buffer) {
+            perror("malloc() failed");
+            return NULL;
+        }
+    }
+    int pos;
+    va_list arg_list;
+    buffer[0] = '\0';
+    va_start(arg_list, msg_ident);
+    pos = vsnprintf(buffer, MAXLEN - 2, formatStr, arg_list);
+    va_end(arg_list);
+    if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
+    buffer[pos] = '\0';
+    return buffer;
+}
diff --git a/src/lang.h b/src/lang.h
new file mode 100644 (file)
index 0000000..4aabc8a
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _lang_h
+#define _lang_h
+
+#include "main.h"
+
+struct UserNode;
+
+struct default_language_entry {
+    char *ident;
+    char *text;
+};
+
+struct language_table {
+    char *ident;
+    char *text;
+    
+    struct language_table *next;
+};
+
+struct language {
+    char *langtag;
+    char *langname;
+    struct language_table **entrys;
+};
+
+void init_lang();
+void free_lang();
+struct language* get_language_by_tag(char *tag);
+struct language* get_language_by_name(char *name);
+struct language* get_default_language();
+void load_languages();
+void load_language(char *tag, char *name);
+void register_language_string(struct language *lang, char *ident, char *text);
+void register_default_language_table(const struct default_language_entry *msgtab);
+char *get_language_string(struct UserNode *user, const char* msg_ident);
+char *build_language_string(struct UserNode *user, char *buffer, const char *msg_ident, ...);
+
+#endif
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..2fcc3db
--- /dev/null
@@ -0,0 +1,94 @@
+
+#include "main.h"
+#include "ClientSocket.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "IRCEvents.h"
+#include "IRCParser.h"
+#include "modcmd.h"
+#include "WHOHandler.h"
+#include "bots.h"
+#include "mysqlConn.h"
+#include "HandleInfoHandler.h"
+#include "lang.h"
+#include "tools.h"
+#include "timeq.h"
+#include "EventLogger.h"
+#include "ModeNode.h"
+
+time_t start_time;
+
+void cleanup() {
+    free_sockets();
+    free_parser();
+    free_UserNode();
+    free_ChanNode();
+    free_bind();
+    free_modcmd();
+    free_whoqueue();
+    free_bots();
+    free_mysql();
+    free_handleinfohandler();
+    free_lang();
+}
+
+int main(void)
+{
+    start_time = time(0);
+    
+    init_mysql();
+    init_lang();
+    init_parser();
+    init_UserNode();
+    init_ChanNode();
+    init_ModeNode();
+    init_bind();
+       init_modcmd();
+    init_handleinfohandler();
+    init_tools();
+    init_bots();
+    
+    load_languages();
+    
+    time_t socket_wait;
+    while(1) {
+        socket_wait = time(0) + SOCKET_SELECT_TIME;
+        do {
+            socket_loop(SOCKET_SELECT_TIME);
+        } while(time(0) < socket_wait);
+        timeq_tick();
+        loop_bots();
+        clearTempUsers();
+        destroyEvents();
+    }
+}
+
+int stricmp (const char *s1, const char *s2)
+{
+   if (s1 == NULL) return s2 == NULL ? 0 : -(*s2);
+   if (s2 == NULL) return *s1;
+   char c1, c2;
+   while ((c1 = tolower (*s1)) == (c2 = tolower (*s2)))
+   {
+     if (*s1 == '\0') break;
+     ++s1; ++s2;
+   }
+   return c1 - c2;
+}
+
+int stricmplen (const char *s1, const char *s2, int len)
+{
+   if (s1 == NULL) return s2 == NULL ? 0 : -(*s2);
+   if (s2 == NULL) return *s1;
+   char c1, c2;
+   int i = 0;
+   while ((c1 = tolower (*s1)) == (c2 = tolower (*s2)))
+   {
+     i++;
+     if (*s1 == '\0') break;
+     ++s1; ++s2;
+     if(i == len) break;
+   }
+   return c1 - c2;
+}
+
diff --git a/src/main.h b/src/main.h
new file mode 100644 (file)
index 0000000..b1452e7
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef _main_h
+#define _main_h
+
+#define NEONSERV_VERSION "5.0.1-dev"
+
+#include "../mysqlConfig.h"
+#ifndef BOTWAR_ALERT_CHAN
+#define BOTWAR_ALERT_CHAN NULL
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <time.h>
+
+#if __GNUC__
+#define PRINTF_LIKE(M,N) __attribute__((format (printf, M, N)))
+#else
+#define PRINTF_LIKE(M,N)
+#endif
+
+#if __GNUC__ >= 2
+#define UNUSED_ARG(ARG) ARG __attribute__((unused))
+#elif defined(S_SPLINT_S)
+#define UNUSED_ARG(ARG) /*@unused@*/ ARG
+#define const /*@observer@*/ /*@temp@*/
+#else
+#define UNUSED_ARG(ARG) ARG
+#endif
+
+#define STRINGIFY_(x) #x
+#define STRINGIFY(x) STRINGIFY_(x)
+#if defined(__GNUC__)
+#if defined(__GNUC_PATCHLEVEL__)
+#define COMPILER "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__) "." STRINGIFY(__GNUC_PATCHLEVEL__)
+#else
+#define COMPILER "GCC" " " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__)
+#endif
+#elif defined (__IMAGECRAFT__)
+#define COMPILER "ICCAVR"
+#else
+#define COMPILER "Unknown"
+#endif
+
+#define SOCKET_SELECT_TIME 2
+
+#define NICKLEN         30
+#define USERLEN         10
+#define AUTHLEN         32
+#define HOSTLEN         63
+#define REALLEN         50
+#define TOPICLEN        500
+#define CHANNELLEN      200
+#define MAXLEN          512
+#define TRIGGERLEN      50
+#define MAXNUMPARAMS    200 /* maximum number of parameters in one line */
+#define MAXLANGUAGES    5
+#define MAXMODES        6
+#define INVITE_TIMEOUT  30
+#define BOTWAR_DETECTION_TIME 7
+#define BOTWAR_DETECTION_EVENTS 6
+
+//valid nick chars
+#define VALID_NICK_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890{|}~[\\]^-_`"
+//the first char is a little bit different
+//                              0        1         2         3         4         5          6
+//                              1234567890123456789012345678901234567890123456789012345678 9012   62
+#define VALID_NICK_CHARS_FIRST "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~[\\]^_`"
+#define VALID_NICK_CHARS_FIRST_LEN 62
+
+#define TEMPUSER_LIST_INDEX VALID_NICK_CHARS_FIRST_LEN
+
+extern time_t start_time;
+
+int stricmp (const char *s1, const char *s2);
+int stricmplen (const char *s1, const char *s2, int len);
+
+#endif
\ No newline at end of file
diff --git a/src/modcmd.c b/src/modcmd.c
new file mode 100644 (file)
index 0000000..5476d5e
--- /dev/null
@@ -0,0 +1,638 @@
+
+#include "modcmd.h"
+#include "IRCEvents.h"
+#include "IRCParser.h"
+#include "ClientSocket.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "ChanUser.h"
+#include "WHOHandler.h"
+#include "lang.h"
+#include "mysqlConn.h"
+#include "DBHelper.h"
+#include "EventLogger.h"
+
+struct trigger_callback {
+    int botid;
+    trigger_callback_t *func;
+    
+    struct trigger_callback *next;
+};
+
+struct command_check_user_cache {
+    struct ClientSocket *client, *textclient;
+    struct UserNode *user;
+    struct ChanNode *chan, *sent_chan;
+    char **argv;
+    int argc;
+    char *message;
+    struct cmd_binding *cbind;
+};
+
+static struct cmd_binding **cmd_binds;
+static struct cmd_function *cmd_functions = NULL;
+static struct trigger_callback *trigger_callbacks = NULL;
+static struct ClientSocket *tmp_text_client;
+
+static const struct default_language_entry msgtab[] = {
+    {"MODCMD_LESS_PARAM_COUNT", "This command requires more parameters."},
+    {"MODCMD_CHAN_REQUIRED",    "You must provide the name of a channel that exists and the bot is on."},
+    {"MODCMD_AUTH_REQUIRED",    "You need to be authenticated with AuthServ to use this command."},
+    {"MODCMD_CHAN_SUSPENDED",   "This channel is currently suspended."},
+    {"MODCMD_PRIVILEGED",       "$b%s$b is a privileged command."}, /* {ARGS: "god"} */
+    {"MODCMD_PUBCMD",           "Public commands in $b%s$b are restricted."}, /* {ARGS: "#TestChan"} */
+    {"MODCMD_ACCESS_DENIED",    "Access denied."},
+    {NULL, NULL}
+};
+
+static int get_binds_index(char first_char) {
+    if(tolower(first_char) >= 'a' && tolower(first_char) <= 'z') {
+        return tolower(first_char) - 'a';
+    }
+    return 26;
+}
+
+struct ClientSocket* get_prefered_bot(int botid) {
+    struct ClientSocket *client;
+    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
+        if(client->botid == botid && (client->flags & SOCKET_FLAG_PREFERRED))
+            return client;
+    }
+    return NULL;
+}
+
+static char* get_channel_trigger(int botid, struct ChanNode *chan) {
+    struct trigger_cache *trigger;
+    for(trigger = chan->trigger; trigger; trigger = trigger->next) {
+        if(trigger->botid == botid)
+            return trigger->trigger;
+    }
+    struct trigger_callback *cb;
+    for(cb = trigger_callbacks; cb; cb = cb->next) {
+        if(cb->botid == botid)
+            break;
+    }
+    char triggerStr[TRIGGERLEN];
+    if(cb)
+        cb->func(chan, triggerStr);
+    else
+        strcpy(triggerStr, "+");
+    trigger = malloc(sizeof(*trigger));
+    if (!trigger) {
+        perror("malloc() failed");
+        return 0;
+    }
+    trigger->botid = botid;
+    trigger->trigger = strdup(triggerStr);
+    trigger->next = chan->trigger;
+    chan->trigger = trigger;
+    return trigger->trigger;
+}
+
+static void handle_command_async(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct ChanNode *sent_chan, struct cmd_binding *cbind, char **argv, int argc);
+
+static USERAUTH_CALLBACK(command_checked_auth) {
+    struct command_check_user_cache *cache = data;
+    tmp_text_client = cache->textclient;
+    handle_command_async(cache->client, user, cache->chan, cache->sent_chan, cache->cbind, cache->argv, cache->argc);
+    free(cache->message);
+    free(cache);
+}
+
+static void handle_command(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) {
+    struct ChanNode *sent_chan = chan;
+    if(message[0] == '#') {
+        char *chanName = message;
+        message = strstr(message, " ");
+        if(!message) return;
+        *message = '\0';
+        message++;
+        struct ChanNode *chan2 = getChanByName(chanName);
+        if(chan2)
+            chan = chan2;
+    }
+    message = strdup(message);
+    int bind_index = get_binds_index(message[0]);
+    char *args = strstr(message, " ");
+    if(args) {
+        *args = '\0';
+        args++;
+    }
+    struct cmd_binding *cbind;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == client->botid && stricmp(cbind->cmd, message) == 0) {
+            //get a text bot
+            tmp_text_client = get_prefered_bot(client->botid);
+            //parse the arguments...
+            char *arga[MAXNUMPARAMS];
+            char **argv;
+            int argc = 0;
+            if(args) {
+                while(*args) {
+                    //skip leading spaces
+                    while (*args == ' ')
+                        *args++ = 0;
+                    arga[argc++] = args;
+                    if (argc >= MAXNUMPARAMS)
+                        break;
+                    while (*args != ' ' && *args)
+                        args++;
+                }
+            }
+            argv = arga;
+            if(argc != 0 && argv[0][0] == '#' && !(cbind->func->flags & CMDFLAG_CHAN_PARAM)) {
+                struct ChanNode *chan2 = getChanByName(argv[0]);
+                if(chan2) {
+                    argv += 1;
+                    argc -= 1;
+                    chan = chan2;
+                }
+            }
+            if(cbind->parameters) {
+                //userdefined parameters...
+                char *uargs[MAXNUMPARAMS];
+                int uargc = 0;
+                char *a,*b = cbind->parameters;
+                int allargs, argi;
+                do {
+                    a = strstr(b, " ");
+                    if(a) *a = '\0';
+                    if(b[0] == '%') {
+                        b++;
+                        if(b[strlen(b)-1] == '-') {
+                            allargs = 1;
+                            b[strlen(b)-1] = '\0';
+                            argi = atoi(b);
+                            b[strlen(b)-1] = '-';
+                        } else {
+                            allargs = 0;
+                            argi = atoi(b);
+                        }
+                        if(argi > 0) {
+                            if(argi <= argc) {
+                                uargs[uargc++] = argv[argi-1];
+                                if(allargs) {
+                                    for(argi++; argi <= argc; argi++)
+                                        uargs[uargc++] = argv[argi-1];
+                                }
+                            }
+                        } else if(!strcmp(b, "c")) {
+                            uargs[uargc++] = (chan ? chan->name : NULL);
+                        } else if(!strcmp(b, "n")) {
+                            uargs[uargc++] = user->nick;
+                        }
+                    } else {
+                        uargs[uargc++] = b;
+                    }
+                    if(a) {
+                        *a = ' ';
+                        b = a+1;
+                    }
+                } while(a);
+                argv = uargs;
+                argc = uargc;
+            }
+            if(argc < cbind->func->paramcount) {
+                reply(tmp_text_client, user, "MODCMD_LESS_PARAM_COUNT");
+                break;
+            }
+            if((cbind->func->flags & CMDFLAG_REQUIRE_CHAN) && !chan) {
+                reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
+                break;
+            }
+            if((cbind->func->flags & CMDFLAG_CHECK_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
+                //check auth...
+                struct command_check_user_cache *data = malloc(sizeof(*data));
+                char **temp_argv = malloc(argc*sizeof(*temp_argv));
+                if (!data || !temp_argv) {
+                    perror("malloc() failed");
+                    break;
+                }
+                memcpy(temp_argv, argv, argc*sizeof(*temp_argv));
+                data->argv = temp_argv;
+                data->argc = argc;
+                data->client = client;
+                data->user = user;
+                data->chan = chan;
+                data->sent_chan = sent_chan;
+                data->message = message;
+                data->cbind = cbind;
+                data->textclient = tmp_text_client;
+                get_userauth(user, command_checked_auth, data);
+                return;
+            } else
+                handle_command_async(client, user, chan, sent_chan, cbind, argv, argc);
+            break;
+        }
+    }
+    free(message);
+}
+
+static void handle_command_async(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct ChanNode *sent_chan, struct cmd_binding *cbind, char **argv, int argc) {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    int uaccess;
+    int eventflags = (cbind->func->flags & (CMDFLAG_LOG | CMDFLAG_OPLOG));
+    if((cbind->func->flags & CMDFLAG_REQUIRE_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
+        reply(tmp_text_client, user, "MODCMD_AUTH_REQUIRED");
+        return;
+    }
+    if(sent_chan && sent_chan != chan) {
+        //check pubcmd of this channel
+        printf_mysql_query("SELECT `channel_pubcmd` FROM `channels` WHERE `channel_name` = '%s'", escape_string(sent_chan->name));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            uaccess = getChannelAccess(user, sent_chan, 1);
+            if(row[0] && uaccess < atoi(row[0])) { //NOTE: HARDCODED DEFAULT: pubcmd = 0
+                reply(tmp_text_client, user, "MODCMD_PUBCMD", sent_chan->name);
+                return;
+            }
+        }
+    }
+    int global_access = ((cbind->flags & CMDFLAG_OVERRIDE_GLOBAL_ACCESS) ? cbind->global_access : cbind->func->global_access);
+    if(global_access > 0) {
+        int user_global_access = 0;
+        printf_mysql_query("SELECT `user_access` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) != NULL) {
+            user_global_access = atoi(row[0]);
+        }
+        if(user_global_access < global_access) {
+            if(!user_global_access)
+                reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
+            else
+                reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
+            return;
+        }
+    }
+    if((cbind->func->flags & CMDFLAG_REGISTERED_CHAN)) {
+        MYSQL_ROW defaults = NULL;
+        char access_list[256];
+        int access_pos = 0;
+        int access_count = 0;
+        int minaccess = 0;
+        char *str_a, *str_b = cbind->func->channel_access, *str_c;
+        if(cbind->flags & CMDFLAG_OVERRIDE_CHANNEL_ACCESS)
+            str_b = cbind->channel_access;
+        access_list[0] = '\0';
+        if(str_b) {
+            str_c = strdup(str_b);
+            str_b = str_c;
+            while((str_a = str_b)) {
+                str_b = strstr(str_a, ",");
+                if(str_b) {
+                    *str_b = '\0';
+                    str_b++;
+                }
+                if(*str_a == '#') {
+                    str_a++;
+                    access_pos += sprintf(access_list+access_pos, ", `%s`", str_a);
+                    access_count++;
+                } else {
+                    if(atoi(str_a) > minaccess)
+                        minaccess = atoi(str_a);
+                }
+            }
+            free(str_c);
+        }
+        if(!(chan->flags & CHANFLAG_REQUESTED_CHANINFO) || (sent_chan && sent_chan == chan) || access_count || minaccess) {
+            printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = '%s'", access_list, escape_string(chan->name));
+            res = mysql_use();
+            if ((row = mysql_fetch_row(res)) != NULL) {
+                chan->flags |= CHANFLAG_CHAN_REGISTERED;
+                chan->channel_id = atoi(row[0]);
+                if((sent_chan && sent_chan == chan) || access_count || minaccess) {
+                    uaccess = getChannelAccess(user, chan, 0);
+                    if(uaccess < minaccess && isGodMode(user)) {
+                        eventflags |= CMDFLAG_OPLOG;
+                    } else if(uaccess < minaccess) {
+                        //ACCESS DENIED
+                        reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
+                        return;
+                    }
+                    if(!row[1] && !defaults) {
+                        printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
+                        defaults = mysql_fetch_row(mysql_use());
+                    }
+                    if(sent_chan && (sent_chan == chan) && uaccess < (row[1] ? atoi(row[1]) : atoi(defaults[1]))) {
+                        if(isGodMode(user)) {
+                            eventflags |= CMDFLAG_OPLOG;
+                        } else {
+                            //PUBCMD
+                            reply(tmp_text_client, user, "MODCMD_PUBCMD", chan->name);
+                            return;
+                        }
+                    }
+                    int i;
+                    for(i = 0; i < access_count; i++) {
+                        if(!row[2+i] && !defaults) {
+                            printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
+                            defaults = mysql_fetch_row(mysql_use());
+                        }
+                        if(uaccess < (row[2+i] ? atoi(row[2+i]) : atoi(defaults[2+i]))) {
+                            if(isGodMode(user)) {
+                                eventflags |= CMDFLAG_OPLOG;
+                            } else {
+                                reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+            chan->flags |= CHANFLAG_REQUESTED_CHANINFO;
+        }
+        if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) {
+            reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
+            return;
+        }
+        printf_mysql_query("SELECT `botid`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, client->botid);
+        res = mysql_use();
+        if ((row = mysql_fetch_row(res)) == NULL) {
+            reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
+            return;
+        } else if(!strcmp(row[1], "1")) {
+            reply(tmp_text_client, user, "MODCMD_CHAN_SUSPENDED");
+            return;
+        }
+    }
+    if((cbind->func->flags & CMDFLAG_REQUIRE_GOD) && !isGodMode(user)) {
+        reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
+        return;
+    }
+    struct Event *event = createEvent(client, user, chan, cbind->func->name, argv, argc, eventflags);
+    cbind->func->func(client, user, chan, argv, argc, event);
+}
+
+static void got_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) {
+    fd_set fds;
+    char *trigger;
+    struct ClientSocket *client;
+    FD_ZERO(&fds);
+    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
+        if(isUserOnChan(client->user, chan) && (client->flags & SOCKET_FLAG_PREFERRED) && !FD_ISSET(client->botid, &fds)) {
+            FD_SET(client->botid, &fds);
+            trigger = get_channel_trigger(client->botid, chan);
+            if(stricmplen(message, trigger, strlen(trigger)) == 0) {
+                handle_command(client, user, chan, message + strlen(trigger));
+            }
+        }
+    }
+    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
+        if(isUserOnChan(client->user, chan) && !FD_ISSET(client->botid, &fds)) {
+            FD_SET(client->botid, &fds);
+            trigger = get_channel_trigger(client->botid, chan);
+            if(stricmplen(message, trigger, strlen(trigger)) == 0) {
+                handle_command(client, user, chan, message + strlen(trigger));
+            }
+        }
+    }
+}
+
+static void got_privmsg(struct UserNode *user, struct UserNode *target, char *message) {
+    struct ClientSocket *client;
+    for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
+        if(client->user == target) {
+            handle_command(client, user, NULL, message);
+        }
+    }
+}
+
+int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, char *channel_access, int global_access, unsigned int flags) {
+    struct cmd_function *cmdfunc;
+    for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
+        if(cmdfunc->botid == botid && strcmp(cmdfunc->name, name) == 0)
+            return 0;
+    }
+    cmdfunc = malloc(sizeof(*cmdfunc));
+    if (!cmdfunc) {
+        perror("malloc() failed");
+        return 0;
+    }
+    cmdfunc->botid = botid;
+    cmdfunc->name = strdup(name);
+    cmdfunc->func = func;
+    cmdfunc->flags = flags;
+    cmdfunc->paramcount = paramcount;
+    cmdfunc->channel_access = channel_access;
+    cmdfunc->global_access = global_access;
+    cmdfunc->next = cmd_functions;
+    cmd_functions = cmdfunc;
+    return 1;
+}
+
+int set_trigger_callback(int botid, trigger_callback_t *func) {
+    static struct trigger_callback *cb = NULL;
+    for(cb = trigger_callbacks; cb; cb = cb->next) {
+        if(cb->botid == botid)
+            break;
+    }
+    if(!cb) {
+        cb = malloc(sizeof(*cb));
+        if (!cb) {
+            perror("malloc() failed");
+            return 0;
+        }
+        cb->botid = botid;
+        cb->next = trigger_callbacks;
+        trigger_callbacks = cb;
+    }
+    cb->func = func;
+    return 1;
+}
+
+int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger) {
+    struct trigger_cache *trigger;
+    for(trigger = chan->trigger; trigger; trigger = trigger->next) {
+        if(trigger->botid == botid) {
+            free(trigger->trigger);
+            trigger->trigger = strdup(new_trigger);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func) {
+    int bind_index = get_binds_index(cmd[0]);
+    struct cmd_binding *cbind;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0)
+            return 0;
+    }
+    cbind = malloc(sizeof(*cbind));
+    if (!cbind) {
+        perror("malloc() failed");
+        return 0;
+    }
+    cbind->botid = botid;
+    cbind->cmd = strdup(cmd);
+    cbind->func = func;
+    cbind->parameters = NULL;
+    cbind->global_access = 0;
+    cbind->channel_access = NULL;
+    cbind->flags = 0;
+    cbind->next = cmd_binds[bind_index];
+    cmd_binds[bind_index] = cbind;
+    return 1;
+}
+
+int bind_cmd_to_command(int botid, char *cmd, char *func) {
+    struct cmd_function *cmdfunc;
+    for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
+        if(cmdfunc->botid == botid && strcmp(cmdfunc->name, func) == 0)
+            break;
+    }
+    if(!cmdfunc) return 0;
+    int bind_index = get_binds_index(cmd[0]);
+    struct cmd_binding *cbind;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0)
+            return 0;
+    }
+    cbind = malloc(sizeof(*cbind));
+    if (!cbind) {
+        perror("malloc() failed");
+        return 0;
+    }
+    cbind->botid = botid;
+    cbind->cmd = strdup(cmd);
+    cbind->func = cmdfunc;
+    cbind->next = cmd_binds[bind_index];
+    cbind->parameters = NULL;
+    cbind->global_access = 0;
+    cbind->channel_access = NULL;
+    cbind->flags = 0;
+    cmd_binds[bind_index] = cbind;
+    return 1;
+}
+
+int unbind_cmd(int botid, char *cmd) {
+    int bind_index = get_binds_index(cmd[0]);
+    struct cmd_binding *cbind, *last = NULL;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
+            if(last)
+                last->next = cbind->next;
+            else
+                cmd_binds[bind_index] = cbind->next;
+            free(cbind->cmd);
+            if(cbind->parameters)
+                free(cbind->parameters);
+            free(cbind);
+            return 1;
+        } else
+            last = cbind;
+    }
+    return 0;
+}
+
+struct cmd_function *find_cmd_function(int botid, char *name) {
+    struct cmd_function *cmdfunc;
+    for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
+        if(cmdfunc->botid == botid && stricmp(cmdfunc->name, name) == 0)
+            break;
+    }
+    return cmdfunc;
+}
+
+struct ClientSocket *getTextBot() {
+    return tmp_text_client;
+}
+
+void init_modcmd() {
+    cmd_binds = calloc(27, sizeof(*cmd_binds));
+    bind_chanmsg(got_chanmsg);
+    bind_privmsg(got_privmsg);
+    register_default_language_table(msgtab);
+}
+
+void free_modcmd() {
+    int i;
+    for(i = 0; i < 27; i++) {
+        struct cmd_binding *cbind, *next;
+        for(cbind = cmd_binds[i]; cbind; cbind = next) {
+            next = cbind->next;
+            free(cbind->cmd);
+            if(cbind->parameters)
+                free(cbind->parameters);
+            if(cbind->channel_access)
+                free(cbind->channel_access);
+            free(cbind);
+        }
+    }
+    free(cmd_binds);
+    struct cmd_function *cmdfunct, *next;
+    for(cmdfunct = cmd_functions; cmdfunct; cmdfunct = next) {
+        next = cmdfunct->next;
+        free(cmdfunct->name);
+        free(cmdfunct);
+    }
+    struct trigger_callback *cb, *next_cb;
+    for(cb = trigger_callbacks; cb; cb = next_cb) {
+        next_cb = cb->next;
+        free(next_cb);
+    }
+    cmd_functions = NULL;
+    trigger_callbacks = NULL;
+}
+
+void bind_set_parameters(int botid, char *cmd, char *parameters) {
+    int bind_index = get_binds_index(cmd[0]);
+    struct cmd_binding *cbind;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
+            if(cbind->parameters)
+                free(cbind->parameters);
+            cbind->parameters = strdup(parameters);
+            return;
+        }
+    }
+}
+
+void bind_set_global_access(int botid, char *cmd, int gaccess) {
+    int bind_index = get_binds_index(cmd[0]);
+    struct cmd_binding *cbind;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
+            if(gaccess > -1) {
+                cbind->global_access = gaccess;
+                cbind->flags |= CMDFLAG_OVERRIDE_GLOBAL_ACCESS;
+            } else {
+                cbind->flags &= ~CMDFLAG_OVERRIDE_GLOBAL_ACCESS;
+            }
+            return;
+        }
+    }
+}
+
+void bind_set_channel_access(int botid, char *cmd, char *chanaccess) {
+    int bind_index = get_binds_index(cmd[0]);
+    struct cmd_binding *cbind;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
+            if(cbind->channel_access)
+                free(cbind->channel_access);
+            if(chanaccess) {
+                cbind->channel_access = strdup(chanaccess);
+                cbind->flags |= CMDFLAG_OVERRIDE_CHANNEL_ACCESS;
+            } else {
+                cbind->channel_access = NULL;
+                cbind->flags &= ~CMDFLAG_OVERRIDE_CHANNEL_ACCESS;
+            }
+            return;
+        }
+    }
+}
+
+struct cmd_binding *find_cmd_binding(int botid, char *cmd) {
+    int bind_index = get_binds_index(cmd[0]);
+    struct cmd_binding *cbind;
+    for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+        if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
+            return cbind;
+        }
+    }
+    return NULL;
+}
+
diff --git a/src/modcmd.h b/src/modcmd.h
new file mode 100644 (file)
index 0000000..940ab32
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _modcmd_h
+#define _modcmd_h
+#include "main.h"
+
+#define CMDFLAG_REQUIRE_CHAN            0x0001
+#define CMDFLAG_REQUIRE_AUTH            0x0002
+#define CMDFLAG_REQUIRE_GOD             0x0004
+#define CMDFLAG_CHECK_AUTH              0x0008
+#define CMDFLAG_REGISTERED_CHAN         0x0010
+#define CMDFLAG_OVERRIDE_GLOBAL_ACCESS  0x0020
+#define CMDFLAG_OVERRIDE_CHANNEL_ACCESS 0x0040
+#define CMDFLAG_CHAN_PARAM              0x0080
+#define CMDFLAG_LOG                     0x0100
+#define CMDFLAG_OPLOG                   0x0200
+
+struct ClientSocket;
+struct UserNode;
+struct ChanNode;
+struct Event;
+
+#define CMD_BIND(NAME) void NAME(UNUSED_ARG(struct ClientSocket *client), UNUSED_ARG(struct UserNode *user), UNUSED_ARG(struct ChanNode *chan), UNUSED_ARG(char **argv), UNUSED_ARG(char argc), UNUSED_ARG(struct Event *event))
+typedef void cmd_bind_t(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char **argv, char argc, struct Event *event);
+typedef void trigger_callback_t(struct ChanNode *chan, char *trigger);
+
+struct cmd_function {
+    char *name;
+    int botid;
+    cmd_bind_t *func;
+    unsigned int flags;
+    int paramcount;
+    int global_access;
+    char *channel_access;
+    
+    struct cmd_function *next;
+};
+
+struct cmd_binding {
+    char *cmd;
+    int botid;
+    struct cmd_function *func;
+    unsigned int flags;
+    char *parameters;
+    int global_access;
+    char *channel_access;
+    
+    struct cmd_binding *next;
+};
+
+struct trigger_cache {
+    int botid;
+    char *trigger;
+    
+    struct trigger_cache *next;
+};
+
+void init_modcmd();
+void free_modcmd();
+struct ClientSocket* get_prefered_bot(int botid);
+int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, char *channel_access, int global_access, unsigned int flags);
+int set_trigger_callback(int botid, trigger_callback_t *func);
+int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger);
+int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func);
+int bind_cmd_to_command(int botid, char *cmd, char *func);
+int unbind_cmd(int botid, char *cmd);
+struct cmd_function *find_cmd_function(int botid, char *name);
+struct ClientSocket *getTextBot();
+void bind_set_parameters(int botid, char *cmd, char *parameters);
+void bind_set_global_access(int botid, char *cmd, int gaccess);
+void bind_set_channel_access(int botid, char *cmd, char *chanaccess);
+struct cmd_binding *find_cmd_binding(int botid, char *cmd);
+
+#endif
\ No newline at end of file
diff --git a/src/mysqlConn.c b/src/mysqlConn.c
new file mode 100644 (file)
index 0000000..66494e7
--- /dev/null
@@ -0,0 +1,109 @@
+
+#include "mysqlConn.h"
+
+struct used_result {
+    MYSQL_RES *result;
+    struct used_result *next;
+};
+
+struct escaped_string {
+    char *string;
+    struct escaped_string *next;
+};
+
+MYSQL *mysql_conn = NULL;
+static struct used_result *used_results;
+static struct escaped_string *escaped_strings;
+
+void check_mysql() {
+    int errid;
+    if((errid = mysql_ping(mysql_conn))) {
+        if(mysql_errno(mysql_conn) == CR_SERVER_GONE_ERROR) {
+            if(!mysql_real_connect(mysql_conn, MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_BASE, MYSQL_PORT, NULL, 0)) {
+                show_mysql_error();
+            }
+        } else {
+            //mysql error
+            show_mysql_error();
+        }
+    }
+}
+
+MYSQL_RES *mysql_use() {
+    MYSQL_RES *res = mysql_store_result(mysql_conn);
+    struct used_result *result = malloc(sizeof(*result));
+    if (!result) {
+        mysql_free_result(res);
+        return NULL;
+    }
+    result->result = res;
+    result->next = used_results;
+    used_results = result;
+    return res;
+}
+
+void mysql_free() {
+    struct used_result *result, *next_result;
+    for(result = used_results; result; result = next_result) {
+        next_result = result->next;
+        mysql_free_result(result->result);
+        free(result);
+    }
+    used_results = NULL;
+    struct escaped_string *escaped, *next_escaped;
+    for(escaped = escaped_strings; escaped; escaped = next_escaped) {
+        next_escaped = escaped->next;
+        free(escaped->string);
+        free(escaped);
+    }
+    escaped_strings = NULL;
+}
+
+void init_mysql() {
+    mysql_conn = mysql_init(NULL);
+    if (!mysql_real_connect(mysql_conn, MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_BASE, MYSQL_PORT, NULL, 0)) {
+        //error
+        show_mysql_error();
+    }
+}
+
+void free_mysql() {
+    mysql_close(mysql_conn);
+}
+
+void show_mysql_error() {
+    //show mysql_error()
+    printf("MySQL Error: %s\n", mysql_error(mysql_conn));
+}
+
+void printf_mysql_query(const char *text, ...) {
+    va_list arg_list;
+    char queryBuf[MYSQLMAXLEN];
+    int pos;
+    queryBuf[0] = '\0';
+    va_start(arg_list, text);
+    pos = vsnprintf(queryBuf, MYSQLMAXLEN - 2, text, arg_list);
+    va_end(arg_list);
+    if (pos < 0 || pos > (MYSQLMAXLEN - 2)) pos = MYSQLMAXLEN - 2;
+    queryBuf[pos] = '\0';
+    printf("MySQL: %s\n", queryBuf);
+    if(mysql_query(mysql_conn, queryBuf)) {
+        check_mysql();
+        if(mysql_query(mysql_conn, queryBuf)) {
+            show_mysql_error();
+        }
+    }
+}
+
+char* escape_string(const char *str) {
+    struct escaped_string *escapedstr = malloc(sizeof(*escapedstr));
+    if (!escapedstr) {
+        return NULL;
+    }
+    char escaped[strlen(str)*2+1];
+    mysql_real_escape_string(mysql_conn, escaped, str, strlen(str));
+    escapedstr->string = strdup(escaped);
+    escapedstr->next = escaped_strings;
+    escaped_strings = escapedstr;
+    return escapedstr->string;
+}
diff --git a/src/mysqlConn.h b/src/mysqlConn.h
new file mode 100644 (file)
index 0000000..4ed6655
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _MySQLConn_h
+#define _MySQLConn_h
+
+#include "main.h"
+#include <mysql.h>
+#include <mysql/errmsg.h>
+
+#define MYSQLMAXLEN 1024
+
+extern MYSQL *mysql_conn;
+
+void check_mysql();
+MYSQL_RES *mysql_use();
+void mysql_free();
+void init_mysql();
+void free_mysql();
+void show_mysql_error();
+void printf_mysql_query(const char *text, ...) PRINTF_LIKE(1, 2);
+char* escape_string(const char *str);
+
+#endif
\ No newline at end of file
diff --git a/src/timeq.c b/src/timeq.c
new file mode 100644 (file)
index 0000000..fe919c8
--- /dev/null
@@ -0,0 +1,100 @@
+
+#include "timeq.h"
+
+static struct timeq_entry *timeq_events;
+
+void timeq_tick() {
+    struct timeq_entry *entry, *next;
+    time_t now = time(0);
+    for(entry = timeq_events; entry; entry = next) {
+        if(entry->execute <= now) {
+            entry->callback(entry->data);
+            next = entry->next;
+            free(entry);
+        } else
+            break;
+    }
+    timeq_events = entry;
+}
+
+struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *data) {
+    time_t now = time(0);
+    struct timeq_entry *entry = malloc(sizeof(*entry));
+    if (!entry)
+    {
+        perror("malloc() failed");
+        return NULL;
+    }
+    entry->execute = now + seconds;
+    entry->callback = callback;
+    entry->data = data;
+    entry->name = NULL;
+    struct timeq_entry *next, *prev = NULL;
+    for(next = timeq_events; next; next = next->next) {
+        if(next->execute >= entry->execute)
+            break;
+        else
+            prev = next;
+    }
+    if(prev == NULL) {
+        entry->next = timeq_events;
+        timeq_events = entry;
+    } else {
+        entry->next = next;
+        prev->next = entry;
+    }
+    return entry;
+}
+
+struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data) {
+    struct timeq_entry *entry = timeq_add(seconds, callback, data);
+    entry->name = strdup(name);
+    return entry;
+}
+
+int timeq_del(struct timeq_entry* entry) {
+    struct timeq_entry *centry, *last = NULL;
+    for(centry = timeq_events; centry; centry = centry->next) {
+        if(centry == entry) {
+            if(last)
+                last->next = centry->next;
+            else
+                timeq_events = centry->next;
+            if(centry->name)
+                free(centry->name);
+            free(centry);
+            return 1;
+        } else {
+            last = centry;
+        }
+    }
+    return 0;
+}
+
+int timeq_del_name(char *name) {
+    struct timeq_entry *centry, *last = NULL;
+    for(centry = timeq_events; centry; centry = centry->next) {
+        if(centry->name && !stricmp(centry->name, name)) {
+            if(last)
+                last->next = centry->next;
+            else
+                timeq_events = centry->next;
+            free(centry->name);
+            free(centry);
+            return 1;
+        } else {
+            last = centry;
+        }
+    }
+    return 0;
+}
+
+int timeq_name_exists(char *name) {
+    struct timeq_entry *centry;
+    for(centry = timeq_events; centry; centry = centry->next) {
+        if(centry->name && !stricmp(centry->name, name)) {
+            return 1;
+        }
+    }
+    return 0;
+}
diff --git a/src/timeq.h b/src/timeq.h
new file mode 100644 (file)
index 0000000..0a06948
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _timeq_h
+#define _timeq_h
+
+#include "main.h"
+
+#define TIMEQ_CALLBACK(NAME) void NAME(UNUSED_ARG(void *data))
+typedef TIMEQ_CALLBACK(timeq_callback_t);
+
+struct timeq_entry {
+    char *name;
+    time_t execute;
+    timeq_callback_t *callback;
+    void *data;
+    
+    struct timeq_entry *next;
+};
+
+void timeq_tick();
+struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *data);
+struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data);
+int timeq_del(struct timeq_entry* entry);
+int timeq_del_name(char *name);
+int timeq_name_exists(char *name);
+
+#endif
\ No newline at end of file
diff --git a/src/tools.c b/src/tools.c
new file mode 100644 (file)
index 0000000..0976848
--- /dev/null
@@ -0,0 +1,498 @@
+#include "tools.h"
+#include "UserNode.h"
+#include "ChanNode.h"
+#include "lang.h"
+#include "ClientSocket.h"
+
+static const struct default_language_entry msgtab[] = {
+    {"TIME_MASK_2_ITEMS", "%s and %s"}, /* {ARGS: "2 days", "1 hour"} */
+    {"TIME_MASK_3_ITEMS", "%s, %s and %s"}, /* {ARGS: "2 days", "1 hour", "20 minutes"} */
+    {"TIME_YEAR", "year"},
+    {"TIME_YEARS", "years"},
+    {"TIME_MONTH", "month"},
+    {"TIME_MONTHS", "months"},
+    {"TIME_WEEK", "week"},
+    {"TIME_WEEKS", "weeks"},
+    {"TIME_DAY", "day"},
+    {"TIME_DAYS", "days"},
+    {"TIME_HOUR", "hour"},
+    {"TIME_HOURS", "hours"},
+    {"TIME_MINUTE", "minute"},
+    {"TIME_MINUTES", "minutes"},
+    {"TIME_SECOND", "second"},
+    {"TIME_SECONDS", "seconds"},
+    {NULL, NULL}
+};
+
+/* copied from IRCU 2.10.12 match.c */
+/*
+ * Compare if a given string (name) matches the given
+ * mask (which can contain wild cards: '*' - match any
+ * number of chars, '?' - match any single character.
+ *
+ * return  0, if match
+ *         1, if no match
+ *
+ *  Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu)
+ *  Rewritten by Timothy Vogelsang (netski), net@astrolink.org
+ */
+int match(const char *mask, const char *name)
+{
+  const char *m = mask, *n = name;
+  const char *m_tmp = mask, *n_tmp = name;
+  int star_p;
+
+  for (;;) switch (*m) {
+  case '\0':
+    if (!*n)
+      return 0;
+  backtrack:
+    if (m_tmp == mask)
+      return 1;
+    m = m_tmp;
+    n = ++n_tmp;
+    if (*n == '\0')
+      return 1;
+    break;
+  case '\\':
+    m++;
+    /* allow escaping to force capitalization */
+    if (*m++ != *n++)
+      goto backtrack;
+    break;
+  case '*': case '?':
+    for (star_p = 0; ; m++) {
+      if (*m == '*')
+        star_p = 1;
+      else if (*m == '?') {
+        if (!*n++)
+          goto backtrack;
+      } else break;
+    }
+    if (star_p) {
+      if (!*m)
+        return 0;
+      else if (*m == '\\') {
+        m_tmp = ++m;
+        if (!*m)
+          return 1;
+        for (n_tmp = n; *n && *n != *m; n++) ;
+      } else {
+        m_tmp = m;
+        for (n_tmp = n; *n && tolower(*n) != tolower(*m); n++) ;
+      }
+    }
+    /* and fall through */
+  default:
+    if (!*n)
+      return *m != '\0';
+    if (tolower(*m) != tolower(*n))
+      goto backtrack;
+    m++;
+    n++;
+    break;
+  }
+}
+
+
+//TABLES
+struct Table *table_init(int width, int length, int flags) {
+    int row;
+    struct Table *table = malloc(sizeof(*table));
+    table->contents = malloc(length * sizeof(*table->contents));
+    for(row = 0; row < length; row++) {
+        table->contents[row] = calloc(width, sizeof(*table->contents[row]));
+    }
+    table->length = length;
+    table->width = width;
+    table->flags = flags;
+    table->col_flags = calloc(length, sizeof(int));
+    table->entrys = 0;
+    table->maxwidth = calloc(length, sizeof(int));
+    table->table_lines = NULL;
+    return table;
+}
+
+int table_add(struct Table *table, char **entry) {
+    int col;
+    if(table->entrys == table->length) return 0;
+    for(col = 0; col < table->width; col++) {
+        table->contents[table->entrys][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
+        if(table->contents[table->entrys][col])
+            table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
+        if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
+            table->maxwidth[col] = strlen(entry[col]);
+    }
+    table->entrys++;
+    return 1;
+}
+
+int table_change(struct Table *table, int row, char **entry) {
+    int col;
+    if(row >= table->length) return 0;
+    for(col = 0; col < table->width; col++) {
+        if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
+            free(table->contents[row][col]);
+        table->contents[row][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
+        if(table->contents[row][col])
+            table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
+        if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
+            table->maxwidth[col] = strlen(entry[col]);
+    }
+    return 1;
+}
+
+int table_change_field(struct Table *table, int row, int col, char *entry) {
+    if(row >= table->length) return 0;
+    if(col >= table->width) return 0;
+    if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
+        free(table->contents[row][col]);
+    table->contents[row][col] = (((table->flags & TABLE_FLAG_USE_POINTER) || !entry) ? entry : strdup(entry));
+    if(table->contents[row][col])
+        table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
+    if(entry && strlen(entry) > table->maxwidth[col])
+        table->maxwidth[col] = strlen(entry);
+    return 1;
+}
+
+int table_set_bold(struct Table *table, int collum, int bold) {
+    if(bold)
+        table->col_flags[collum] |= TABLE_FLAG_COL_BOLD;
+    else
+        table->col_flags[collum] &= ~TABLE_FLAG_COL_BOLD;
+    return 1;
+}
+
+char **table_end(struct Table *table) {
+    int row, col, tablewidth = 0, pos,i;
+    if(!table->entrys) return NULL;
+    for(col = 0; col < table->width; col++) {
+        tablewidth += table->maxwidth[col]+1;
+        if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
+            tablewidth += 2;
+    }
+    table->table_lines = malloc(table->entrys * sizeof(table->table_lines));
+    for(row = 0; row < table->entrys; row++) {
+        table->table_lines[row] = malloc(tablewidth * sizeof(*table->table_lines[row]));
+        pos = 0;
+        for(col = 0; col < table->width; col++) {
+            if(!(table->col_flags[col] & TABLE_FLAG_COL_CONTENTS)) continue;
+            if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
+                table->table_lines[row][pos++] = '\002';
+            for(i = 0; i < strlen(table->contents[row][col]); i++) {
+                table->table_lines[row][pos++] = table->contents[row][col][i];
+            }
+            if(col < table->width-1) {
+                for(;i < table->maxwidth[col]; i++) {
+                    table->table_lines[row][pos++] = ' ';
+                }
+                table->table_lines[row][pos++] = ' ';
+            } else
+                table->table_lines[row][pos++] = '\0';
+            
+            if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
+                table->table_lines[row][pos++] = '\002';
+        }
+    }
+    return table->table_lines;
+}
+
+void table_free(struct Table *table) {
+    int row, col;
+    for(row = 0; row < table->length; row++) {
+        if(!(table->flags & TABLE_FLAG_USE_POINTER) && table->entrys > row) {
+            for(col = 0; col < table->width; col++) {
+                if(table->contents[row][col])
+                    free(table->contents[row][col]);
+            }
+        }
+        free(table->contents[row]);
+    }
+    free(table->contents);
+    free(table->col_flags);
+    free(table->maxwidth);
+    if(table->table_lines) {
+        for(row = 0; row < table->entrys; row++) {
+            free(table->table_lines[row]);
+        }
+        free(table->table_lines);
+    }
+    free(table);
+}
+
+char* timeToStr(struct UserNode *user, int seconds, int items, char *buf) {
+    char item[items][MAXLEN];
+    int tmp, citem = 0;
+    if(citem != items && seconds >= 31536000) { //60*60*24*365 = 31536000
+        
+        tmp = seconds / 31536000;
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_YEAR" : "TIME_YEARS"));
+        seconds -= tmp * 31536000;
+    }
+    if(citem != items && seconds >= 86400) { //60*60*24 = 86400
+        tmp = seconds / 86400;
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_DAY" : "TIME_DAYS"));
+        seconds -= tmp * 86400;
+    }
+    if(citem != items && seconds >= 3600) { //60*60 = 3600
+        tmp = seconds / 3600;
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_HOUR" : "TIME_HOURS"));
+        seconds -= tmp * 3600;
+    }
+    if(citem != items && seconds >= 60) {
+        tmp = seconds / 60;
+        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_MINUTE" : "TIME_MINUTES"));
+        seconds -= tmp * 60;
+    }
+    if(citem != items && seconds >= 1) {
+        sprintf(item[citem++], "%d %s", seconds, get_language_string(user, seconds == 1 ? "TIME_SECOND" : "TIME_SECONDS"));
+    }
+    if(citem == 2) {
+        build_language_string(user, buf, "TIME_MASK_2_ITEMS", item[0], item[1]);
+    } else if(citem == 3) {
+        build_language_string(user, buf, "TIME_MASK_3_ITEMS", item[0], item[1], item[2]);
+    } else {
+        int i, ii, p = 0;
+        for(i = 0; i < citem; i++) {
+            for(ii = 0; ii < strlen(item[i]); ii++) {
+                buf[p++] = item[i][ii];
+            }
+            buf[p++] = ' ';
+        }
+        buf[(p ? p-1 : 0)] = '\0';
+    }
+    return buf;
+}
+
+int strToTime(struct UserNode *user, char *str) {
+    /*
+    * y = year = 365 days
+    * M = month = 30 days
+    * w = week = 7 days
+    * d = day
+    * h = hour
+    * m = minute
+    * (s) = second
+    */
+    int total_time = 0, cvalue;
+    char *p, tmpchar;
+    int unit_multiplikator;
+    while(*str) {
+        p = str;
+        while(*p && !isdigit(*p)) //skip leading chars
+            p++;
+        str = p;
+        while(*p && isdigit(*p)) //get the value
+            p++;
+        tmpchar = *p;
+        *p = '\0';
+        cvalue = isdigit(*str) ? atoi(str) : 0;
+        *p = tmpchar;
+        while(*p == ' ') //skip spaces
+            p++;
+        str = p;
+        while(*p && !isdigit(*p)) //get the unit
+            p++;
+        tmpchar = *p;
+        *p = '\0';
+        if(p - str > 1) { //unit has more than one char
+            if(!stricmp(str, "year") || !stricmp(str, "year") || !stricmp(str, get_language_string(user, "TIME_YEAR")) || !stricmp(str, get_language_string(user, "TIME_YEARS")))
+                unit_multiplikator = 31536000; //60*60*24*365 = 31536000
+            else if(!stricmp(str, "month") || !stricmp(str, "months") || !stricmp(str, get_language_string(user, "TIME_MONTH")) || !stricmp(str, get_language_string(user, "TIME_MONTHS")))
+                unit_multiplikator = 2592000; //60*60*24*30 = 2592000
+            else if(!stricmp(str, "week") || !stricmp(str, "weeks") || !stricmp(str, get_language_string(user, "TIME_WEEK")) || !stricmp(str, get_language_string(user, "TIME_WEEKS")))
+                unit_multiplikator = 604800; //60*60*24*7 = 604800
+            else if(!stricmp(str, "day") || !stricmp(str, "days") || !stricmp(str, get_language_string(user, "TIME_DAY")) || !stricmp(str, get_language_string(user, "TIME_DAYS")))
+                unit_multiplikator = 86400; //60*60*24 = 86400
+            else if(!stricmp(str, "hour") || !stricmp(str, "hours") || !stricmp(str, get_language_string(user, "TIME_HOUR")) || !stricmp(str, get_language_string(user, "TIME_HOURS")))
+                unit_multiplikator = 3600; //60*60 = 3600
+            else if(!stricmp(str, "minute") || !stricmp(str, "minutes") || !stricmp(str, "min") || !stricmp(str, "mins") || !stricmp(str, get_language_string(user, "TIME_MINUTE")) || !stricmp(str, get_language_string(user, "TIME_MINUTES")))
+                unit_multiplikator = 60;
+            else
+                unit_multiplikator = 1;
+        } else {
+            switch(*str) {
+                case 'y':
+                    unit_multiplikator = 31536000; //60*60*24*365 = 31536000
+                    break;
+                case 'M':
+                    unit_multiplikator = 2592000; //60*60*24*30 = 2592000
+                    break;
+                case 'w':
+                    unit_multiplikator = 604800; //60*60*24*7 = 604800
+                    break;
+                case 'd':
+                    unit_multiplikator = 86400; //60*60*24 = 86400
+                    break;
+                case 'h':
+                    unit_multiplikator = 3600; //60*60 = 3600
+                    break;
+                case 'm':
+                    unit_multiplikator = 60;
+                    break;
+                default:
+                    unit_multiplikator = 1;
+                    break;
+            }
+        }
+        total_time += (cvalue * unit_multiplikator);
+        *p = tmpchar;
+        str = p;
+    }
+    return total_time;
+}
+
+struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan) {
+    struct ModeBuffer *modeBuf = malloc(sizeof(*modeBuf));
+    if(!modeBuf) {
+        perror("malloc() failed");
+        return NULL;
+    }
+    modeBuf->client = client;
+    modeBuf->chan = chan;
+    modeBuf->addCount = 0;
+    modeBuf->delCount = 0;
+    return modeBuf;
+}
+
+void modeBufferSet(struct ModeBuffer *modeBuf, int add, char mode, char *param) {
+    if(add) {
+        modeBuf->addModes[modeBuf->addCount] = mode;
+        modeBuf->addModesParams[modeBuf->addCount] = (param ? strdup(param) : NULL);
+        modeBuf->addCount++;
+        modeBuf->addModes[modeBuf->addCount] = '\0';
+    } else {
+        modeBuf->delModes[modeBuf->delCount] = mode;
+        modeBuf->delModesParams[modeBuf->delCount] = (param ? strdup(param) : NULL);
+        modeBuf->delCount++;
+        modeBuf->delModes[modeBuf->delCount] = '\0';
+    }
+    if(modeBuf->addCount + modeBuf->delCount == MAXMODES)
+        flushModeBuffer(modeBuf);
+}
+
+void flushModeBuffer(struct ModeBuffer *modeBuf) {
+    char modeStr[MAXMODES+3];
+    int modePos = 0;
+    char paramStr[MAXLEN];
+    int paramPos = 0;
+    int i;
+    if(modeBuf->addCount) {
+        modeStr[modePos++] = '+';
+        for(i = 0; i < modeBuf->addCount; i++) {
+            modeStr[modePos++] = modeBuf->addModes[i];
+            if(modeBuf->addModesParams[i]) {
+                paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->addModesParams[i]);
+            }
+        }
+        modeBuf->addCount = 0;
+    }
+    if(modeBuf->delCount) {
+        modeStr[modePos++] = '-';
+        for(i = 0; i < modeBuf->delCount; i++) {
+            modeStr[modePos++] = modeBuf->delModes[i];
+            if(modeBuf->delModesParams[i]) {
+                paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->delModesParams[i]);
+            }
+        }
+        modeBuf->delCount = 0;
+    }
+    modeStr[modePos++] = '\0';
+    putsock(modeBuf->client, "MODE %s %s%s", modeBuf->chan->name, modeStr, paramStr);
+}
+
+void freeModeBuffer(struct ModeBuffer *modeBuf) {
+    if(modeBuf->addCount + modeBuf->delCount)
+        flushModeBuffer(modeBuf);
+    free(modeBuf);
+}
+
+int is_ircmask(const char *text) {
+    while (*text && (isalnum((char)*text) || strchr("-_[]|\\`^{}?*", *text)))
+        text++;
+    if (*text++ != '!')
+        return 0;
+    while (*text && *text != '@' && !isspace((char)*text))
+        text++;
+    if (*text++ != '@')
+        return 0;
+    while (*text && !isspace((char)*text))
+        text++;
+    return !*text;
+}
+
+char* generate_banmask(struct UserNode *user, char *buffer) {
+    char *userhost = user->host;
+    
+    if(isFakeHost(user->host)) {
+        sprintf(buffer, "*!*@%s", userhost);
+        return buffer;
+    }
+    
+    //check if the hostname has more than 4 connections (trusted host)
+    if(countUsersWithHost(userhost) > 4) {
+        sprintf(buffer, "*!%s@%s", user->ident, userhost);
+        return buffer;
+    } else {
+        sprintf(buffer, "*!*@%s", userhost);
+        return buffer;
+    }
+}
+
+char* make_banmask(char *input, char* buffer) {
+    char *nick = NULL, *ident = NULL, *host = NULL;
+    char tmp[HOSTLEN];
+    char *p;
+    if((p = strstr(input, "!"))) {
+        nick = input;
+        *p = '\0';
+        ident = p+1;
+        if((p = strstr(ident, "@"))) {
+            *p = '\0';
+            host = p+1;
+        }
+    } else if((p = strstr(input, "@"))) {
+        ident = input;
+        *p = '\0';
+        host = p+1;
+    } else if((p = strstr(input, "."))) {
+        host = input;
+    } else if(*input == '*' && input[1] != '\0' && !strstr(input+1, "*")) {
+        //AUTH MASK
+        p = getAuthFakehost(input+1);
+        if(p)
+            host = p;
+        else {
+            sprintf(tmp, "%s.*", input+1);
+            host = tmp;
+        }
+    } else {
+        struct UserNode *user = searchUserByNick(input);
+        if(user)
+            return generate_banmask(user, buffer);
+        else
+            nick = input;
+    }
+    if(nick && *nick == '\0') nick = NULL;
+    if(ident && *ident == '\0') ident = NULL;
+    if(host && *host == '\0') host = NULL;
+    sprintf(buffer, "%s!%s@%s", (nick ? nick : "*"), (ident ? ident : "*"), (host ? host : "*"));
+    return buffer;
+}
+
+int isFakeHost(char *host) {
+    char *p1, *p2 = host;
+    
+    //find the last dot to identify if the hostmask is a fake host
+    while((p1 = strstr(p2, "."))) {
+        p2 = p1 + 1;
+    }
+    //TLD database: http://www.iana.org/domains/root/db/
+    //the longest TLD i found was 6 chars long (ignoring the stange exotic ones :D)
+    //but we even ignore '.museum' and '.travel' so we can say that the TLD of our mask needs to be less than 4 chars to be a real domain
+    return (strlen(p2+1) > 4);
+}
+
+void init_tools() {
+    register_default_language_table(msgtab);
+}
diff --git a/src/tools.h b/src/tools.h
new file mode 100644 (file)
index 0000000..54a0cfa
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef _tools_h
+#define _tools_h
+
+#include "main.h"
+
+#define TABLE_FLAG_USE_POINTER  0x01
+#define TABLE_FLAG_COL_BOLD     0x02
+#define TABLE_FLAG_COL_CONTENTS 0x04
+
+struct ClientSocket;
+struct UserNode;
+struct ChanNode;
+
+struct Table {
+    char ***contents;
+    int length;
+    int width;
+    int flags;
+    int *col_flags;
+    
+    int entrys;
+    int *maxwidth;
+    
+    char **table_lines; //we just store this to free it in table_free
+};
+
+struct ModeBuffer {
+    struct ClientSocket *client;
+    struct ChanNode *chan;
+    char addModes[MAXMODES];
+    char delModes[MAXMODES];
+    char *addModesParams[MAXMODES];
+    char *delModesParams[MAXMODES];
+    int addCount;
+    int delCount;
+};
+
+int match(const char *mask, const char *name);
+
+struct Table *table_init(int width, int length, int flags);
+int table_add(struct Table *table, char **entry);
+int table_change(struct Table *table, int row, char **entry);
+int table_change_field(struct Table *table, int row, int col, char *entry);
+int table_set_bold(struct Table *table, int collum, int bold);
+char **table_end(struct Table *table);
+void table_free(struct Table *table);
+
+char* timeToStr(struct UserNode *user, int seconds, int items, char *buf);
+int strToTime(struct UserNode *user, char *str);
+
+struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan);
+#define modeBufferSimpleMode(MODEBUF,ADD,MODE) modeBufferSet(MODEBUF, ADD, MODE, NULL) 
+#define modeBufferOp(MODEBUF,USER) modeBufferSet(MODEBUF, 1, 'o', USER)
+#define modeBufferDeop(MODEBUF,USER) modeBufferSet(MODEBUF, 0, 'o', USER) 
+#define modeBufferVoice(MODEBUF,USER) modeBufferSet(MODEBUF, 1, 'v', USER)
+#define modeBufferDevoice(MODEBUF,USER) modeBufferSet(MODEBUF, 0, 'v', USER) 
+#define modeBufferBan(MODEBUF,MASK) modeBufferSet(MODEBUF, 1, 'b', MASK) 
+#define modeBufferUnban(MODEBUF,MASK) modeBufferSet(MODEBUF, 0, 'b', MASK) 
+void modeBufferSet(struct ModeBuffer *modeBuf, int add, char mode, char *param);
+void flushModeBuffer(struct ModeBuffer *modeBuf);
+void freeModeBuffer(struct ModeBuffer *modeBuf);
+
+int is_ircmask(const char *text);
+
+char* generate_banmask(struct UserNode *user, char *buffer); 
+char* make_banmask(char *input, char* buffer);
+int isFakeHost(char *host);
+
+void init_tools();
+
+#endif
\ No newline at end of file
diff --git a/src/version.h b/src/version.h
new file mode 100644 (file)
index 0000000..06f4b0a
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _version_h
+#define _version_h
+
+#include "main.h"
+
+extern const char *compilation;
+extern const char *creation;
+extern const char *revision;
+extern const char *codelines;
+
+#endif
\ No newline at end of file
diff --git a/src/version.sh b/src/version.sh
new file mode 100644 (file)
index 0000000..b5bdc12
--- /dev/null
@@ -0,0 +1,47 @@
+#! /bin/sh
+echo "Extracting version.c ..."
+
+if test -r version.c
+then
+   compilation=`sed -n 's/^const char \*compilation = \"\(.*\)\";/\1/p' < version.c`
+   if test ! "$compilation" ; then compilation=0; fi
+else
+   compilation=0
+fi
+
+compilation=`expr $compilation + 1`
+
+creation=`date | \
+awk '{if (NF == 6) \
+        { print $1 " " $2 " " $3 " " $6 " at " $4 " " $5 } \
+else \
+        { print $1 " " $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
+
+codelines=`find . -type f -regex '\./.*\.h' -or -regex '\./.*\.c' |xargs cat|wc -l`
+
+svn_revision=`svn info | grep Revision | grep -o -E '[0-9]+'`
+if test "x$svn_revision" = "x" ; then
+  svn_revision=`git log -n 1 --pretty="format:%h"`
+  if test "x$svn_revision" = "x" ; then
+    svn_revision="0"
+  else
+    git_commitcount=`git rev-list --all --no-merges | wc -l | sed "s/[ \t]//g"`
+    svn_revision="git-$git_commitcount-$svn_revision"
+  fi
+else
+  svn_revision="svn-$svn_revision"
+fi
+
+
+/bin/cat > version.c <<!SUB!THIS!
+//Auto generated file!
+
+#include "version.h"
+
+const char *compilation = "$compilation";
+const char *creation = "$creation";
+const char *revision = "$svn_revision";
+const char *codelines = "$codelines";
+
+!SUB!THIS!
+
diff --git a/timeq.c b/timeq.c
deleted file mode 100644 (file)
index fe919c8..0000000
--- a/timeq.c
+++ /dev/null
@@ -1,100 +0,0 @@
-
-#include "timeq.h"
-
-static struct timeq_entry *timeq_events;
-
-void timeq_tick() {
-    struct timeq_entry *entry, *next;
-    time_t now = time(0);
-    for(entry = timeq_events; entry; entry = next) {
-        if(entry->execute <= now) {
-            entry->callback(entry->data);
-            next = entry->next;
-            free(entry);
-        } else
-            break;
-    }
-    timeq_events = entry;
-}
-
-struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *data) {
-    time_t now = time(0);
-    struct timeq_entry *entry = malloc(sizeof(*entry));
-    if (!entry)
-    {
-        perror("malloc() failed");
-        return NULL;
-    }
-    entry->execute = now + seconds;
-    entry->callback = callback;
-    entry->data = data;
-    entry->name = NULL;
-    struct timeq_entry *next, *prev = NULL;
-    for(next = timeq_events; next; next = next->next) {
-        if(next->execute >= entry->execute)
-            break;
-        else
-            prev = next;
-    }
-    if(prev == NULL) {
-        entry->next = timeq_events;
-        timeq_events = entry;
-    } else {
-        entry->next = next;
-        prev->next = entry;
-    }
-    return entry;
-}
-
-struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data) {
-    struct timeq_entry *entry = timeq_add(seconds, callback, data);
-    entry->name = strdup(name);
-    return entry;
-}
-
-int timeq_del(struct timeq_entry* entry) {
-    struct timeq_entry *centry, *last = NULL;
-    for(centry = timeq_events; centry; centry = centry->next) {
-        if(centry == entry) {
-            if(last)
-                last->next = centry->next;
-            else
-                timeq_events = centry->next;
-            if(centry->name)
-                free(centry->name);
-            free(centry);
-            return 1;
-        } else {
-            last = centry;
-        }
-    }
-    return 0;
-}
-
-int timeq_del_name(char *name) {
-    struct timeq_entry *centry, *last = NULL;
-    for(centry = timeq_events; centry; centry = centry->next) {
-        if(centry->name && !stricmp(centry->name, name)) {
-            if(last)
-                last->next = centry->next;
-            else
-                timeq_events = centry->next;
-            free(centry->name);
-            free(centry);
-            return 1;
-        } else {
-            last = centry;
-        }
-    }
-    return 0;
-}
-
-int timeq_name_exists(char *name) {
-    struct timeq_entry *centry;
-    for(centry = timeq_events; centry; centry = centry->next) {
-        if(centry->name && !stricmp(centry->name, name)) {
-            return 1;
-        }
-    }
-    return 0;
-}
diff --git a/timeq.h b/timeq.h
deleted file mode 100644 (file)
index 0a06948..0000000
--- a/timeq.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef _timeq_h
-#define _timeq_h
-
-#include "main.h"
-
-#define TIMEQ_CALLBACK(NAME) void NAME(UNUSED_ARG(void *data))
-typedef TIMEQ_CALLBACK(timeq_callback_t);
-
-struct timeq_entry {
-    char *name;
-    time_t execute;
-    timeq_callback_t *callback;
-    void *data;
-    
-    struct timeq_entry *next;
-};
-
-void timeq_tick();
-struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *data);
-struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data);
-int timeq_del(struct timeq_entry* entry);
-int timeq_del_name(char *name);
-int timeq_name_exists(char *name);
-
-#endif
\ No newline at end of file
diff --git a/tools.c b/tools.c
deleted file mode 100644 (file)
index 0976848..0000000
--- a/tools.c
+++ /dev/null
@@ -1,498 +0,0 @@
-#include "tools.h"
-#include "UserNode.h"
-#include "ChanNode.h"
-#include "lang.h"
-#include "ClientSocket.h"
-
-static const struct default_language_entry msgtab[] = {
-    {"TIME_MASK_2_ITEMS", "%s and %s"}, /* {ARGS: "2 days", "1 hour"} */
-    {"TIME_MASK_3_ITEMS", "%s, %s and %s"}, /* {ARGS: "2 days", "1 hour", "20 minutes"} */
-    {"TIME_YEAR", "year"},
-    {"TIME_YEARS", "years"},
-    {"TIME_MONTH", "month"},
-    {"TIME_MONTHS", "months"},
-    {"TIME_WEEK", "week"},
-    {"TIME_WEEKS", "weeks"},
-    {"TIME_DAY", "day"},
-    {"TIME_DAYS", "days"},
-    {"TIME_HOUR", "hour"},
-    {"TIME_HOURS", "hours"},
-    {"TIME_MINUTE", "minute"},
-    {"TIME_MINUTES", "minutes"},
-    {"TIME_SECOND", "second"},
-    {"TIME_SECONDS", "seconds"},
-    {NULL, NULL}
-};
-
-/* copied from IRCU 2.10.12 match.c */
-/*
- * Compare if a given string (name) matches the given
- * mask (which can contain wild cards: '*' - match any
- * number of chars, '?' - match any single character.
- *
- * return  0, if match
- *         1, if no match
- *
- *  Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu)
- *  Rewritten by Timothy Vogelsang (netski), net@astrolink.org
- */
-int match(const char *mask, const char *name)
-{
-  const char *m = mask, *n = name;
-  const char *m_tmp = mask, *n_tmp = name;
-  int star_p;
-
-  for (;;) switch (*m) {
-  case '\0':
-    if (!*n)
-      return 0;
-  backtrack:
-    if (m_tmp == mask)
-      return 1;
-    m = m_tmp;
-    n = ++n_tmp;
-    if (*n == '\0')
-      return 1;
-    break;
-  case '\\':
-    m++;
-    /* allow escaping to force capitalization */
-    if (*m++ != *n++)
-      goto backtrack;
-    break;
-  case '*': case '?':
-    for (star_p = 0; ; m++) {
-      if (*m == '*')
-        star_p = 1;
-      else if (*m == '?') {
-        if (!*n++)
-          goto backtrack;
-      } else break;
-    }
-    if (star_p) {
-      if (!*m)
-        return 0;
-      else if (*m == '\\') {
-        m_tmp = ++m;
-        if (!*m)
-          return 1;
-        for (n_tmp = n; *n && *n != *m; n++) ;
-      } else {
-        m_tmp = m;
-        for (n_tmp = n; *n && tolower(*n) != tolower(*m); n++) ;
-      }
-    }
-    /* and fall through */
-  default:
-    if (!*n)
-      return *m != '\0';
-    if (tolower(*m) != tolower(*n))
-      goto backtrack;
-    m++;
-    n++;
-    break;
-  }
-}
-
-
-//TABLES
-struct Table *table_init(int width, int length, int flags) {
-    int row;
-    struct Table *table = malloc(sizeof(*table));
-    table->contents = malloc(length * sizeof(*table->contents));
-    for(row = 0; row < length; row++) {
-        table->contents[row] = calloc(width, sizeof(*table->contents[row]));
-    }
-    table->length = length;
-    table->width = width;
-    table->flags = flags;
-    table->col_flags = calloc(length, sizeof(int));
-    table->entrys = 0;
-    table->maxwidth = calloc(length, sizeof(int));
-    table->table_lines = NULL;
-    return table;
-}
-
-int table_add(struct Table *table, char **entry) {
-    int col;
-    if(table->entrys == table->length) return 0;
-    for(col = 0; col < table->width; col++) {
-        table->contents[table->entrys][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
-        if(table->contents[table->entrys][col])
-            table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
-        if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
-            table->maxwidth[col] = strlen(entry[col]);
-    }
-    table->entrys++;
-    return 1;
-}
-
-int table_change(struct Table *table, int row, char **entry) {
-    int col;
-    if(row >= table->length) return 0;
-    for(col = 0; col < table->width; col++) {
-        if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
-            free(table->contents[row][col]);
-        table->contents[row][col] = ((table->flags & TABLE_FLAG_USE_POINTER) || !entry[col] ? entry[col] : strdup(entry[col]));
-        if(table->contents[row][col])
-            table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
-        if(entry[col] && strlen(entry[col]) > table->maxwidth[col])
-            table->maxwidth[col] = strlen(entry[col]);
-    }
-    return 1;
-}
-
-int table_change_field(struct Table *table, int row, int col, char *entry) {
-    if(row >= table->length) return 0;
-    if(col >= table->width) return 0;
-    if(table->contents[row][col] && !(table->flags & TABLE_FLAG_USE_POINTER))
-        free(table->contents[row][col]);
-    table->contents[row][col] = (((table->flags & TABLE_FLAG_USE_POINTER) || !entry) ? entry : strdup(entry));
-    if(table->contents[row][col])
-        table->col_flags[col] |= TABLE_FLAG_COL_CONTENTS;
-    if(entry && strlen(entry) > table->maxwidth[col])
-        table->maxwidth[col] = strlen(entry);
-    return 1;
-}
-
-int table_set_bold(struct Table *table, int collum, int bold) {
-    if(bold)
-        table->col_flags[collum] |= TABLE_FLAG_COL_BOLD;
-    else
-        table->col_flags[collum] &= ~TABLE_FLAG_COL_BOLD;
-    return 1;
-}
-
-char **table_end(struct Table *table) {
-    int row, col, tablewidth = 0, pos,i;
-    if(!table->entrys) return NULL;
-    for(col = 0; col < table->width; col++) {
-        tablewidth += table->maxwidth[col]+1;
-        if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
-            tablewidth += 2;
-    }
-    table->table_lines = malloc(table->entrys * sizeof(table->table_lines));
-    for(row = 0; row < table->entrys; row++) {
-        table->table_lines[row] = malloc(tablewidth * sizeof(*table->table_lines[row]));
-        pos = 0;
-        for(col = 0; col < table->width; col++) {
-            if(!(table->col_flags[col] & TABLE_FLAG_COL_CONTENTS)) continue;
-            if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
-                table->table_lines[row][pos++] = '\002';
-            for(i = 0; i < strlen(table->contents[row][col]); i++) {
-                table->table_lines[row][pos++] = table->contents[row][col][i];
-            }
-            if(col < table->width-1) {
-                for(;i < table->maxwidth[col]; i++) {
-                    table->table_lines[row][pos++] = ' ';
-                }
-                table->table_lines[row][pos++] = ' ';
-            } else
-                table->table_lines[row][pos++] = '\0';
-            
-            if(table->col_flags[col] & TABLE_FLAG_COL_BOLD)
-                table->table_lines[row][pos++] = '\002';
-        }
-    }
-    return table->table_lines;
-}
-
-void table_free(struct Table *table) {
-    int row, col;
-    for(row = 0; row < table->length; row++) {
-        if(!(table->flags & TABLE_FLAG_USE_POINTER) && table->entrys > row) {
-            for(col = 0; col < table->width; col++) {
-                if(table->contents[row][col])
-                    free(table->contents[row][col]);
-            }
-        }
-        free(table->contents[row]);
-    }
-    free(table->contents);
-    free(table->col_flags);
-    free(table->maxwidth);
-    if(table->table_lines) {
-        for(row = 0; row < table->entrys; row++) {
-            free(table->table_lines[row]);
-        }
-        free(table->table_lines);
-    }
-    free(table);
-}
-
-char* timeToStr(struct UserNode *user, int seconds, int items, char *buf) {
-    char item[items][MAXLEN];
-    int tmp, citem = 0;
-    if(citem != items && seconds >= 31536000) { //60*60*24*365 = 31536000
-        
-        tmp = seconds / 31536000;
-        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_YEAR" : "TIME_YEARS"));
-        seconds -= tmp * 31536000;
-    }
-    if(citem != items && seconds >= 86400) { //60*60*24 = 86400
-        tmp = seconds / 86400;
-        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_DAY" : "TIME_DAYS"));
-        seconds -= tmp * 86400;
-    }
-    if(citem != items && seconds >= 3600) { //60*60 = 3600
-        tmp = seconds / 3600;
-        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_HOUR" : "TIME_HOURS"));
-        seconds -= tmp * 3600;
-    }
-    if(citem != items && seconds >= 60) {
-        tmp = seconds / 60;
-        sprintf(item[citem++], "%d %s", tmp, get_language_string(user, tmp == 1 ? "TIME_MINUTE" : "TIME_MINUTES"));
-        seconds -= tmp * 60;
-    }
-    if(citem != items && seconds >= 1) {
-        sprintf(item[citem++], "%d %s", seconds, get_language_string(user, seconds == 1 ? "TIME_SECOND" : "TIME_SECONDS"));
-    }
-    if(citem == 2) {
-        build_language_string(user, buf, "TIME_MASK_2_ITEMS", item[0], item[1]);
-    } else if(citem == 3) {
-        build_language_string(user, buf, "TIME_MASK_3_ITEMS", item[0], item[1], item[2]);
-    } else {
-        int i, ii, p = 0;
-        for(i = 0; i < citem; i++) {
-            for(ii = 0; ii < strlen(item[i]); ii++) {
-                buf[p++] = item[i][ii];
-            }
-            buf[p++] = ' ';
-        }
-        buf[(p ? p-1 : 0)] = '\0';
-    }
-    return buf;
-}
-
-int strToTime(struct UserNode *user, char *str) {
-    /*
-    * y = year = 365 days
-    * M = month = 30 days
-    * w = week = 7 days
-    * d = day
-    * h = hour
-    * m = minute
-    * (s) = second
-    */
-    int total_time = 0, cvalue;
-    char *p, tmpchar;
-    int unit_multiplikator;
-    while(*str) {
-        p = str;
-        while(*p && !isdigit(*p)) //skip leading chars
-            p++;
-        str = p;
-        while(*p && isdigit(*p)) //get the value
-            p++;
-        tmpchar = *p;
-        *p = '\0';
-        cvalue = isdigit(*str) ? atoi(str) : 0;
-        *p = tmpchar;
-        while(*p == ' ') //skip spaces
-            p++;
-        str = p;
-        while(*p && !isdigit(*p)) //get the unit
-            p++;
-        tmpchar = *p;
-        *p = '\0';
-        if(p - str > 1) { //unit has more than one char
-            if(!stricmp(str, "year") || !stricmp(str, "year") || !stricmp(str, get_language_string(user, "TIME_YEAR")) || !stricmp(str, get_language_string(user, "TIME_YEARS")))
-                unit_multiplikator = 31536000; //60*60*24*365 = 31536000
-            else if(!stricmp(str, "month") || !stricmp(str, "months") || !stricmp(str, get_language_string(user, "TIME_MONTH")) || !stricmp(str, get_language_string(user, "TIME_MONTHS")))
-                unit_multiplikator = 2592000; //60*60*24*30 = 2592000
-            else if(!stricmp(str, "week") || !stricmp(str, "weeks") || !stricmp(str, get_language_string(user, "TIME_WEEK")) || !stricmp(str, get_language_string(user, "TIME_WEEKS")))
-                unit_multiplikator = 604800; //60*60*24*7 = 604800
-            else if(!stricmp(str, "day") || !stricmp(str, "days") || !stricmp(str, get_language_string(user, "TIME_DAY")) || !stricmp(str, get_language_string(user, "TIME_DAYS")))
-                unit_multiplikator = 86400; //60*60*24 = 86400
-            else if(!stricmp(str, "hour") || !stricmp(str, "hours") || !stricmp(str, get_language_string(user, "TIME_HOUR")) || !stricmp(str, get_language_string(user, "TIME_HOURS")))
-                unit_multiplikator = 3600; //60*60 = 3600
-            else if(!stricmp(str, "minute") || !stricmp(str, "minutes") || !stricmp(str, "min") || !stricmp(str, "mins") || !stricmp(str, get_language_string(user, "TIME_MINUTE")) || !stricmp(str, get_language_string(user, "TIME_MINUTES")))
-                unit_multiplikator = 60;
-            else
-                unit_multiplikator = 1;
-        } else {
-            switch(*str) {
-                case 'y':
-                    unit_multiplikator = 31536000; //60*60*24*365 = 31536000
-                    break;
-                case 'M':
-                    unit_multiplikator = 2592000; //60*60*24*30 = 2592000
-                    break;
-                case 'w':
-                    unit_multiplikator = 604800; //60*60*24*7 = 604800
-                    break;
-                case 'd':
-                    unit_multiplikator = 86400; //60*60*24 = 86400
-                    break;
-                case 'h':
-                    unit_multiplikator = 3600; //60*60 = 3600
-                    break;
-                case 'm':
-                    unit_multiplikator = 60;
-                    break;
-                default:
-                    unit_multiplikator = 1;
-                    break;
-            }
-        }
-        total_time += (cvalue * unit_multiplikator);
-        *p = tmpchar;
-        str = p;
-    }
-    return total_time;
-}
-
-struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan) {
-    struct ModeBuffer *modeBuf = malloc(sizeof(*modeBuf));
-    if(!modeBuf) {
-        perror("malloc() failed");
-        return NULL;
-    }
-    modeBuf->client = client;
-    modeBuf->chan = chan;
-    modeBuf->addCount = 0;
-    modeBuf->delCount = 0;
-    return modeBuf;
-}
-
-void modeBufferSet(struct ModeBuffer *modeBuf, int add, char mode, char *param) {
-    if(add) {
-        modeBuf->addModes[modeBuf->addCount] = mode;
-        modeBuf->addModesParams[modeBuf->addCount] = (param ? strdup(param) : NULL);
-        modeBuf->addCount++;
-        modeBuf->addModes[modeBuf->addCount] = '\0';
-    } else {
-        modeBuf->delModes[modeBuf->delCount] = mode;
-        modeBuf->delModesParams[modeBuf->delCount] = (param ? strdup(param) : NULL);
-        modeBuf->delCount++;
-        modeBuf->delModes[modeBuf->delCount] = '\0';
-    }
-    if(modeBuf->addCount + modeBuf->delCount == MAXMODES)
-        flushModeBuffer(modeBuf);
-}
-
-void flushModeBuffer(struct ModeBuffer *modeBuf) {
-    char modeStr[MAXMODES+3];
-    int modePos = 0;
-    char paramStr[MAXLEN];
-    int paramPos = 0;
-    int i;
-    if(modeBuf->addCount) {
-        modeStr[modePos++] = '+';
-        for(i = 0; i < modeBuf->addCount; i++) {
-            modeStr[modePos++] = modeBuf->addModes[i];
-            if(modeBuf->addModesParams[i]) {
-                paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->addModesParams[i]);
-            }
-        }
-        modeBuf->addCount = 0;
-    }
-    if(modeBuf->delCount) {
-        modeStr[modePos++] = '-';
-        for(i = 0; i < modeBuf->delCount; i++) {
-            modeStr[modePos++] = modeBuf->delModes[i];
-            if(modeBuf->delModesParams[i]) {
-                paramPos += sprintf(paramStr + paramPos, " %s", modeBuf->delModesParams[i]);
-            }
-        }
-        modeBuf->delCount = 0;
-    }
-    modeStr[modePos++] = '\0';
-    putsock(modeBuf->client, "MODE %s %s%s", modeBuf->chan->name, modeStr, paramStr);
-}
-
-void freeModeBuffer(struct ModeBuffer *modeBuf) {
-    if(modeBuf->addCount + modeBuf->delCount)
-        flushModeBuffer(modeBuf);
-    free(modeBuf);
-}
-
-int is_ircmask(const char *text) {
-    while (*text && (isalnum((char)*text) || strchr("-_[]|\\`^{}?*", *text)))
-        text++;
-    if (*text++ != '!')
-        return 0;
-    while (*text && *text != '@' && !isspace((char)*text))
-        text++;
-    if (*text++ != '@')
-        return 0;
-    while (*text && !isspace((char)*text))
-        text++;
-    return !*text;
-}
-
-char* generate_banmask(struct UserNode *user, char *buffer) {
-    char *userhost = user->host;
-    
-    if(isFakeHost(user->host)) {
-        sprintf(buffer, "*!*@%s", userhost);
-        return buffer;
-    }
-    
-    //check if the hostname has more than 4 connections (trusted host)
-    if(countUsersWithHost(userhost) > 4) {
-        sprintf(buffer, "*!%s@%s", user->ident, userhost);
-        return buffer;
-    } else {
-        sprintf(buffer, "*!*@%s", userhost);
-        return buffer;
-    }
-}
-
-char* make_banmask(char *input, char* buffer) {
-    char *nick = NULL, *ident = NULL, *host = NULL;
-    char tmp[HOSTLEN];
-    char *p;
-    if((p = strstr(input, "!"))) {
-        nick = input;
-        *p = '\0';
-        ident = p+1;
-        if((p = strstr(ident, "@"))) {
-            *p = '\0';
-            host = p+1;
-        }
-    } else if((p = strstr(input, "@"))) {
-        ident = input;
-        *p = '\0';
-        host = p+1;
-    } else if((p = strstr(input, "."))) {
-        host = input;
-    } else if(*input == '*' && input[1] != '\0' && !strstr(input+1, "*")) {
-        //AUTH MASK
-        p = getAuthFakehost(input+1);
-        if(p)
-            host = p;
-        else {
-            sprintf(tmp, "%s.*", input+1);
-            host = tmp;
-        }
-    } else {
-        struct UserNode *user = searchUserByNick(input);
-        if(user)
-            return generate_banmask(user, buffer);
-        else
-            nick = input;
-    }
-    if(nick && *nick == '\0') nick = NULL;
-    if(ident && *ident == '\0') ident = NULL;
-    if(host && *host == '\0') host = NULL;
-    sprintf(buffer, "%s!%s@%s", (nick ? nick : "*"), (ident ? ident : "*"), (host ? host : "*"));
-    return buffer;
-}
-
-int isFakeHost(char *host) {
-    char *p1, *p2 = host;
-    
-    //find the last dot to identify if the hostmask is a fake host
-    while((p1 = strstr(p2, "."))) {
-        p2 = p1 + 1;
-    }
-    //TLD database: http://www.iana.org/domains/root/db/
-    //the longest TLD i found was 6 chars long (ignoring the stange exotic ones :D)
-    //but we even ignore '.museum' and '.travel' so we can say that the TLD of our mask needs to be less than 4 chars to be a real domain
-    return (strlen(p2+1) > 4);
-}
-
-void init_tools() {
-    register_default_language_table(msgtab);
-}
diff --git a/tools.h b/tools.h
deleted file mode 100644 (file)
index 54a0cfa..0000000
--- a/tools.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef _tools_h
-#define _tools_h
-
-#include "main.h"
-
-#define TABLE_FLAG_USE_POINTER  0x01
-#define TABLE_FLAG_COL_BOLD     0x02
-#define TABLE_FLAG_COL_CONTENTS 0x04
-
-struct ClientSocket;
-struct UserNode;
-struct ChanNode;
-
-struct Table {
-    char ***contents;
-    int length;
-    int width;
-    int flags;
-    int *col_flags;
-    
-    int entrys;
-    int *maxwidth;
-    
-    char **table_lines; //we just store this to free it in table_free
-};
-
-struct ModeBuffer {
-    struct ClientSocket *client;
-    struct ChanNode *chan;
-    char addModes[MAXMODES];
-    char delModes[MAXMODES];
-    char *addModesParams[MAXMODES];
-    char *delModesParams[MAXMODES];
-    int addCount;
-    int delCount;
-};
-
-int match(const char *mask, const char *name);
-
-struct Table *table_init(int width, int length, int flags);
-int table_add(struct Table *table, char **entry);
-int table_change(struct Table *table, int row, char **entry);
-int table_change_field(struct Table *table, int row, int col, char *entry);
-int table_set_bold(struct Table *table, int collum, int bold);
-char **table_end(struct Table *table);
-void table_free(struct Table *table);
-
-char* timeToStr(struct UserNode *user, int seconds, int items, char *buf);
-int strToTime(struct UserNode *user, char *str);
-
-struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *chan);
-#define modeBufferSimpleMode(MODEBUF,ADD,MODE) modeBufferSet(MODEBUF, ADD, MODE, NULL) 
-#define modeBufferOp(MODEBUF,USER) modeBufferSet(MODEBUF, 1, 'o', USER)
-#define modeBufferDeop(MODEBUF,USER) modeBufferSet(MODEBUF, 0, 'o', USER) 
-#define modeBufferVoice(MODEBUF,USER) modeBufferSet(MODEBUF, 1, 'v', USER)
-#define modeBufferDevoice(MODEBUF,USER) modeBufferSet(MODEBUF, 0, 'v', USER) 
-#define modeBufferBan(MODEBUF,MASK) modeBufferSet(MODEBUF, 1, 'b', MASK) 
-#define modeBufferUnban(MODEBUF,MASK) modeBufferSet(MODEBUF, 0, 'b', MASK) 
-void modeBufferSet(struct ModeBuffer *modeBuf, int add, char mode, char *param);
-void flushModeBuffer(struct ModeBuffer *modeBuf);
-void freeModeBuffer(struct ModeBuffer *modeBuf);
-
-int is_ircmask(const char *text);
-
-char* generate_banmask(struct UserNode *user, char *buffer); 
-char* make_banmask(char *input, char* buffer);
-int isFakeHost(char *host);
-
-void init_tools();
-
-#endif
\ No newline at end of file
diff --git a/version.h b/version.h
deleted file mode 100644 (file)
index 06f4b0a..0000000
--- a/version.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _version_h
-#define _version_h
-
-#include "main.h"
-
-extern const char *compilation;
-extern const char *creation;
-extern const char *revision;
-extern const char *codelines;
-
-#endif
\ No newline at end of file
diff --git a/version.sh b/version.sh
deleted file mode 100644 (file)
index caaff7e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#! /bin/sh
-echo "Extracting version.c ..."
-
-if test -r version.c
-then
-   compilation=`sed -n 's/^const char \*compilation = \"\(.*\)\";/\1/p' < version.c`
-   if test ! "$compilation" ; then compilation=0; fi
-else
-   compilation=0
-fi
-
-compilation=`expr $compilation + 1`
-
-creation=`date | \
-awk '{if (NF == 6) \
-        { print $1 " " $2 " " $3 " " $6 " at " $4 " " $5 } \
-else \
-        { print $1 " " $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
-
-codelines=`find . -type f -regex '\./.*\.h' -or -regex '\./.*\.c' |xargs cat|wc -l`
-
-svn_revision=`svn info | grep Revision | grep -o -E '[0-9]+'`
-if test "x$svn_revision" = "x" ; then
-  svn_revision=`git log -n 1 --pretty="format:%h"`
-  if test "x$svn_revision" = "x" ; then
-    svn_revision="0"
-  else
-    git_commitcount=`git rev-list --all --no-merges | wc -l | sed "s/[ \t]//g"`
-    svn_revision="git-$git_commitcount-$svn_revision"
-  fi
-else
-  svn_revision="svn-$svn_revision"
-fi
-
-
-/bin/cat >version.c <<!SUB!THIS!
-//Auto generated file!
-
-#include "version.h"
-
-const char *compilation = "$compilation";
-const char *creation = "$creation";
-const char *revision = "$svn_revision";
-const char *codelines = "$codelines";
-
-!SUB!THIS!
-