From: pk910 Date: Sat, 1 Oct 2011 22:33:13 +0000 (+0200) Subject: tried to reorder the program structure and build process X-Git-Tag: v5.3~353 X-Git-Url: http://git.pk910.de/?p=NeonServV5.git;a=commitdiff_plain;h=0f1dc61921eef1db8e404a5a82372e2d1cd55daa tried to reorder the program structure and build process --- diff --git a/.gitignore b/.gitignore index 57678a9..4e8b61d 100644 --- a/.gitignore +++ b/.gitignore @@ -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 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 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 index 73adbf6..0000000 --- a/ChanNode.c +++ /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 index 7847dea..0000000 --- a/ChanNode.h +++ /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 index c31e202..0000000 --- a/ChanUser.c +++ /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 index 076b7f7..0000000 --- a/ChanUser.h +++ /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 index 62e367d..0000000 --- a/ClientSocket.c +++ /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 index 380e051..0000000 --- a/ClientSocket.h +++ /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 index 181fff6..0000000 --- a/DBHelper.c +++ /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 index 8378040..0000000 --- a/DBHelper.h +++ /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 index d0b61bd..0000000 --- a/EventLogger.c +++ /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 index 71da262..0000000 --- a/EventLogger.h +++ /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 index bda467e..0000000 --- a/HandleInfoHandler.c +++ /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 index e51fe8d..0000000 --- a/HandleInfoHandler.h +++ /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 index 58efd37..0000000 --- a/IRCEvents.c +++ /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 index e08803e..0000000 --- a/IRCEvents.h +++ /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 index 8662f6d..0000000 --- a/IRCParser.c +++ /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 index ac2b376..0000000 --- a/IRCParser.h +++ /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 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 index 0000000..409b9be --- /dev/null +++ b/Makefile.am @@ -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 index 0afe6f2..0000000 --- a/ModeNode.c +++ /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 index 6d2d5d9..0000000 --- a/ModeNode.h +++ /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 index 2ced2eb..0000000 --- a/UserNode.c +++ /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 index f905437..0000000 --- a/UserNode.h +++ /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 index f924e46..0000000 --- a/WHOHandler.c +++ /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 index 31485f8..0000000 --- a/WHOHandler.h +++ /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 index 0000000..01c075c --- /dev/null +++ b/autogen.sh @@ -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 index 71f5942..0000000 --- a/bot_NeonServ.c +++ /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 index 90bd696..0000000 --- a/bot_NeonServ.h +++ /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 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 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 index 6b8fee1..0000000 --- a/cmd_neonserv.h +++ /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 index aa11b00..0000000 --- a/cmd_neonserv_access.c +++ /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 index b799c4b..0000000 --- a/cmd_neonserv_addban.c +++ /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 index 8a8d567..0000000 --- a/cmd_neonserv_addtimeban.c +++ /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 index c63c176..0000000 --- a/cmd_neonserv_adduser.c +++ /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 index eec7326..0000000 --- a/cmd_neonserv_ban.c +++ /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 index 31231d4..0000000 --- a/cmd_neonserv_bans.c +++ /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 index 3c80478..0000000 --- a/cmd_neonserv_bind.c +++ /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 index 5603300..0000000 --- a/cmd_neonserv_chanservsync.c +++ /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 index ff386b2..0000000 --- a/cmd_neonserv_clvl.c +++ /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 index 0f34ea0..0000000 --- a/cmd_neonserv_command.c +++ /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 index 23b2381..0000000 --- a/cmd_neonserv_csuspend.c +++ /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 index 0902ff2..0000000 --- a/cmd_neonserv_cunsuspend.c +++ /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 index ac8b696..0000000 --- a/cmd_neonserv_delban.c +++ /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 index daf6ff4..0000000 --- a/cmd_neonserv_delme.c +++ /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 index b6ff283..0000000 --- a/cmd_neonserv_deluser.c +++ /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 index d0ee75e..0000000 --- a/cmd_neonserv_deop.c +++ /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 index f9ee763..0000000 --- a/cmd_neonserv_deopall.c +++ /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 index 6994679..0000000 --- a/cmd_neonserv_devoice.c +++ /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 index 3c201af..0000000 --- a/cmd_neonserv_devoiceall.c +++ /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 index e504070..0000000 --- a/cmd_neonserv_down.c +++ /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 index 1d001c9..0000000 --- a/cmd_neonserv_downall.c +++ /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 index 427a30f..0000000 --- a/cmd_neonserv_emote.c +++ /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 index 23ecf3c..0000000 --- a/cmd_neonserv_events.c +++ /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 index 8f173ac..0000000 --- a/cmd_neonserv_giveowner.c +++ /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 index 96abaa6..0000000 --- a/cmd_neonserv_god.c +++ /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 index 081fc22..0000000 --- a/cmd_neonserv_help.c +++ /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 index f7fcd62..0000000 --- a/cmd_neonserv_invite.c +++ /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 index a5c3f16..0000000 --- a/cmd_neonserv_inviteme.c +++ /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 index 373881c..0000000 --- a/cmd_neonserv_kick.c +++ /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 index 1907706..0000000 --- a/cmd_neonserv_kickban.c +++ /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 index 5b09822..0000000 --- a/cmd_neonserv_mdeluser.c +++ /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 index f7f2db1..0000000 --- a/cmd_neonserv_mode.c +++ /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 index 804954f..0000000 --- a/cmd_neonserv_move.c +++ /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 index 093e28a..0000000 --- a/cmd_neonserv_myaccess.c +++ /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 index c8fd1b6..0000000 --- a/cmd_neonserv_netinfo.c +++ /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 index 26776c0..0000000 --- a/cmd_neonserv_notice.c +++ /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 index 2bf69c0..0000000 --- a/cmd_neonserv_op.c +++ /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 index d97feff..0000000 --- a/cmd_neonserv_opall.c +++ /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 index a69c449..0000000 --- a/cmd_neonserv_oplog.c +++ /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 index 6724403..0000000 --- a/cmd_neonserv_peek.c +++ /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 index 4ccce79..0000000 --- a/cmd_neonserv_raw.c +++ /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 index b52e5cc..0000000 --- a/cmd_neonserv_recover.c +++ /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 index d336d7f..0000000 --- a/cmd_neonserv_register.c +++ /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 index e5c4f6b..0000000 --- a/cmd_neonserv_reloadlang.c +++ /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 index c9d4bba..0000000 --- a/cmd_neonserv_resync.c +++ /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 index fdf3c50..0000000 --- a/cmd_neonserv_say.c +++ /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 index 0691366..0000000 --- a/cmd_neonserv_search.c +++ /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 index 2801be7..0000000 --- a/cmd_neonserv_set.c +++ /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 index 37549d2..0000000 --- a/cmd_neonserv_setaccess.c +++ /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 index 4db9a50..0000000 --- a/cmd_neonserv_suspend.c +++ /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 index 2673f15..0000000 --- a/cmd_neonserv_topic.c +++ /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 index d2568a5..0000000 --- a/cmd_neonserv_trace.c +++ /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 index 67501a7..0000000 --- a/cmd_neonserv_trim.c +++ /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 index 073bf50..0000000 --- a/cmd_neonserv_unban.c +++ /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 index 1be8251..0000000 --- a/cmd_neonserv_unbanall.c +++ /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 index 808a46f..0000000 --- a/cmd_neonserv_unbanme.c +++ /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 index bc67b83..0000000 --- a/cmd_neonserv_unbind.c +++ /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 index 8da366e..0000000 --- a/cmd_neonserv_unregister.c +++ /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 index c9d5aca..0000000 --- a/cmd_neonserv_unsuspend.c +++ /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 index a81de4a..0000000 --- a/cmd_neonserv_up.c +++ /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 index bea9325..0000000 --- a/cmd_neonserv_upall.c +++ /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 index 7834575..0000000 --- a/cmd_neonserv_users.c +++ /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 index 354c08b..0000000 --- a/cmd_neonserv_uset.c +++ /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 index ed33d09..0000000 --- a/cmd_neonserv_version.c +++ /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 index 45a78a9..0000000 --- a/cmd_neonserv_voice.c +++ /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 index e4de009..0000000 --- a/cmd_neonserv_voiceall.c +++ /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 index 81378d6..0000000 --- a/cmd_neonserv_wipeinfo.c +++ /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 index 6d573d4..0000000 --- a/config.h.example +++ /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 index 0000000..308d5f4 --- /dev/null +++ b/configure.ac @@ -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 index a8df98e..0000000 --- a/event_neonserv_ctcp.c +++ /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 index c25aff4..0000000 --- a/event_neonserv_invite.c +++ /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 index a117c18..0000000 --- a/event_neonserv_join.c +++ /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 index a566a4e..0000000 --- a/event_neonserv_notice.c +++ /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 index d02aeef..0000000 --- a/event_neonserv_part.c +++ /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 index 30d467f..0000000 --- a/event_neonserv_quit.c +++ /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 index 1dc2b51..0000000 --- a/event_neonserv_topic.c +++ /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 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 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 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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 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 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 index 0000000..6d573d4 --- /dev/null +++ b/mysqlConfig.h.example @@ -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 index 66494e7..0000000 --- a/mysqlConn.c +++ /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 index 4ed6655..0000000 --- a/mysqlConn.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _MySQLConn_h -#define _MySQLConn_h - -#include "main.h" -#include -#include - -#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 index 0000000..c1601f1 --- /dev/null +++ b/src/BanNode.c @@ -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 index 0000000..a699e3f --- /dev/null +++ b/src/BanNode.h @@ -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 index 0000000..73adbf6 --- /dev/null +++ b/src/ChanNode.c @@ -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 index 0000000..7847dea --- /dev/null +++ b/src/ChanNode.h @@ -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 index 0000000..c31e202 --- /dev/null +++ b/src/ChanUser.c @@ -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 index 0000000..076b7f7 --- /dev/null +++ b/src/ChanUser.h @@ -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 index 0000000..62e367d --- /dev/null +++ b/src/ClientSocket.c @@ -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 index 0000000..380e051 --- /dev/null +++ b/src/ClientSocket.h @@ -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 index 0000000..62e38fa --- /dev/null +++ b/src/DATABASE.txt @@ -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 index 0000000..181fff6 --- /dev/null +++ b/src/DBHelper.c @@ -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 index 0000000..8378040 --- /dev/null +++ b/src/DBHelper.h @@ -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 index 0000000..d0b61bd --- /dev/null +++ b/src/EventLogger.c @@ -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 index 0000000..71da262 --- /dev/null +++ b/src/EventLogger.h @@ -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 index 0000000..bda467e --- /dev/null +++ b/src/HandleInfoHandler.c @@ -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 index 0000000..e51fe8d --- /dev/null +++ b/src/HandleInfoHandler.h @@ -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 index 0000000..58efd37 --- /dev/null +++ b/src/IRCEvents.c @@ -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 index 0000000..e08803e --- /dev/null +++ b/src/IRCEvents.h @@ -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 index 0000000..8662f6d --- /dev/null +++ b/src/IRCParser.c @@ -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 index 0000000..ac2b376 --- /dev/null +++ b/src/IRCParser.h @@ -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 index 0000000..10825e2 --- /dev/null +++ b/src/Makefile @@ -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 index 0000000..0afe6f2 --- /dev/null +++ b/src/ModeNode.c @@ -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 index 0000000..6d2d5d9 --- /dev/null +++ b/src/ModeNode.h @@ -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 index 0000000..2ced2eb --- /dev/null +++ b/src/UserNode.c @@ -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 index 0000000..f905437 --- /dev/null +++ b/src/UserNode.h @@ -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 index 0000000..f924e46 --- /dev/null +++ b/src/WHOHandler.c @@ -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 index 0000000..31485f8 --- /dev/null +++ b/src/WHOHandler.h @@ -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 index 0000000..71f5942 --- /dev/null +++ b/src/bot_NeonServ.c @@ -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 index 0000000..90bd696 --- /dev/null +++ b/src/bot_NeonServ.h @@ -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 index 0000000..b957a19 --- /dev/null +++ b/src/bots.c @@ -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 index 0000000..a24b158 --- /dev/null +++ b/src/bots.h @@ -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 index 0000000..6b8fee1 --- /dev/null +++ b/src/cmd_neonserv.h @@ -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 index 0000000..aa11b00 --- /dev/null +++ b/src/cmd_neonserv_access.c @@ -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 index 0000000..b799c4b --- /dev/null +++ b/src/cmd_neonserv_addban.c @@ -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 index 0000000..8a8d567 --- /dev/null +++ b/src/cmd_neonserv_addtimeban.c @@ -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 index 0000000..c63c176 --- /dev/null +++ b/src/cmd_neonserv_adduser.c @@ -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 index 0000000..eec7326 --- /dev/null +++ b/src/cmd_neonserv_ban.c @@ -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 index 0000000..31231d4 --- /dev/null +++ b/src/cmd_neonserv_bans.c @@ -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 index 0000000..3c80478 --- /dev/null +++ b/src/cmd_neonserv_bind.c @@ -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 index 0000000..5603300 --- /dev/null +++ b/src/cmd_neonserv_chanservsync.c @@ -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 index 0000000..ff386b2 --- /dev/null +++ b/src/cmd_neonserv_clvl.c @@ -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 index 0000000..0f34ea0 --- /dev/null +++ b/src/cmd_neonserv_command.c @@ -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 index 0000000..23b2381 --- /dev/null +++ b/src/cmd_neonserv_csuspend.c @@ -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 index 0000000..0902ff2 --- /dev/null +++ b/src/cmd_neonserv_cunsuspend.c @@ -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 index 0000000..ac8b696 --- /dev/null +++ b/src/cmd_neonserv_delban.c @@ -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 index 0000000..daf6ff4 --- /dev/null +++ b/src/cmd_neonserv_delme.c @@ -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 index 0000000..b6ff283 --- /dev/null +++ b/src/cmd_neonserv_deluser.c @@ -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 index 0000000..d0ee75e --- /dev/null +++ b/src/cmd_neonserv_deop.c @@ -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 index 0000000..f9ee763 --- /dev/null +++ b/src/cmd_neonserv_deopall.c @@ -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 index 0000000..6994679 --- /dev/null +++ b/src/cmd_neonserv_devoice.c @@ -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 index 0000000..3c201af --- /dev/null +++ b/src/cmd_neonserv_devoiceall.c @@ -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 index 0000000..e504070 --- /dev/null +++ b/src/cmd_neonserv_down.c @@ -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 index 0000000..1d001c9 --- /dev/null +++ b/src/cmd_neonserv_downall.c @@ -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 index 0000000..427a30f --- /dev/null +++ b/src/cmd_neonserv_emote.c @@ -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 index 0000000..23ecf3c --- /dev/null +++ b/src/cmd_neonserv_events.c @@ -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 index 0000000..8f173ac --- /dev/null +++ b/src/cmd_neonserv_giveowner.c @@ -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 index 0000000..96abaa6 --- /dev/null +++ b/src/cmd_neonserv_god.c @@ -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 index 0000000..081fc22 --- /dev/null +++ b/src/cmd_neonserv_help.c @@ -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 index 0000000..f7fcd62 --- /dev/null +++ b/src/cmd_neonserv_invite.c @@ -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 index 0000000..a5c3f16 --- /dev/null +++ b/src/cmd_neonserv_inviteme.c @@ -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 index 0000000..373881c --- /dev/null +++ b/src/cmd_neonserv_kick.c @@ -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 index 0000000..1907706 --- /dev/null +++ b/src/cmd_neonserv_kickban.c @@ -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 index 0000000..5b09822 --- /dev/null +++ b/src/cmd_neonserv_mdeluser.c @@ -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 index 0000000..f7f2db1 --- /dev/null +++ b/src/cmd_neonserv_mode.c @@ -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 index 0000000..804954f --- /dev/null +++ b/src/cmd_neonserv_move.c @@ -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 index 0000000..093e28a --- /dev/null +++ b/src/cmd_neonserv_myaccess.c @@ -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 index 0000000..c8fd1b6 --- /dev/null +++ b/src/cmd_neonserv_netinfo.c @@ -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 index 0000000..26776c0 --- /dev/null +++ b/src/cmd_neonserv_notice.c @@ -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 index 0000000..2bf69c0 --- /dev/null +++ b/src/cmd_neonserv_op.c @@ -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 index 0000000..d97feff --- /dev/null +++ b/src/cmd_neonserv_opall.c @@ -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 index 0000000..a69c449 --- /dev/null +++ b/src/cmd_neonserv_oplog.c @@ -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 index 0000000..6724403 --- /dev/null +++ b/src/cmd_neonserv_peek.c @@ -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 index 0000000..4ccce79 --- /dev/null +++ b/src/cmd_neonserv_raw.c @@ -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 index 0000000..b52e5cc --- /dev/null +++ b/src/cmd_neonserv_recover.c @@ -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 index 0000000..d336d7f --- /dev/null +++ b/src/cmd_neonserv_register.c @@ -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 index 0000000..e5c4f6b --- /dev/null +++ b/src/cmd_neonserv_reloadlang.c @@ -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 index 0000000..c9d4bba --- /dev/null +++ b/src/cmd_neonserv_resync.c @@ -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 index 0000000..fdf3c50 --- /dev/null +++ b/src/cmd_neonserv_say.c @@ -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 index 0000000..0691366 --- /dev/null +++ b/src/cmd_neonserv_search.c @@ -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 index 0000000..2801be7 --- /dev/null +++ b/src/cmd_neonserv_set.c @@ -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 index 0000000..37549d2 --- /dev/null +++ b/src/cmd_neonserv_setaccess.c @@ -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 index 0000000..4db9a50 --- /dev/null +++ b/src/cmd_neonserv_suspend.c @@ -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 index 0000000..2673f15 --- /dev/null +++ b/src/cmd_neonserv_topic.c @@ -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 index 0000000..d2568a5 --- /dev/null +++ b/src/cmd_neonserv_trace.c @@ -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 index 0000000..67501a7 --- /dev/null +++ b/src/cmd_neonserv_trim.c @@ -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 index 0000000..073bf50 --- /dev/null +++ b/src/cmd_neonserv_unban.c @@ -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 index 0000000..1be8251 --- /dev/null +++ b/src/cmd_neonserv_unbanall.c @@ -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 index 0000000..808a46f --- /dev/null +++ b/src/cmd_neonserv_unbanme.c @@ -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 index 0000000..bc67b83 --- /dev/null +++ b/src/cmd_neonserv_unbind.c @@ -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 index 0000000..8da366e --- /dev/null +++ b/src/cmd_neonserv_unregister.c @@ -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 index 0000000..c9d5aca --- /dev/null +++ b/src/cmd_neonserv_unsuspend.c @@ -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 index 0000000..a81de4a --- /dev/null +++ b/src/cmd_neonserv_up.c @@ -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 index 0000000..bea9325 --- /dev/null +++ b/src/cmd_neonserv_upall.c @@ -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 index 0000000..7834575 --- /dev/null +++ b/src/cmd_neonserv_users.c @@ -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 index 0000000..354c08b --- /dev/null +++ b/src/cmd_neonserv_uset.c @@ -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 index 0000000..ed33d09 --- /dev/null +++ b/src/cmd_neonserv_version.c @@ -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 index 0000000..45a78a9 --- /dev/null +++ b/src/cmd_neonserv_voice.c @@ -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 index 0000000..e4de009 --- /dev/null +++ b/src/cmd_neonserv_voiceall.c @@ -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 index 0000000..81378d6 --- /dev/null +++ b/src/cmd_neonserv_wipeinfo.c @@ -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 index 0000000..6d573d4 --- /dev/null +++ b/src/config.h.example @@ -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 index 0000000..a8df98e --- /dev/null +++ b/src/event_neonserv_ctcp.c @@ -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 index 0000000..c25aff4 --- /dev/null +++ b/src/event_neonserv_invite.c @@ -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 index 0000000..a117c18 --- /dev/null +++ b/src/event_neonserv_join.c @@ -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 index 0000000..a566a4e --- /dev/null +++ b/src/event_neonserv_notice.c @@ -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 index 0000000..d02aeef --- /dev/null +++ b/src/event_neonserv_part.c @@ -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 index 0000000..30d467f --- /dev/null +++ b/src/event_neonserv_quit.c @@ -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 index 0000000..1dc2b51 --- /dev/null +++ b/src/event_neonserv_topic.c @@ -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 index 0000000..e50e752 --- /dev/null +++ b/src/lang.c @@ -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 index 0000000..4aabc8a --- /dev/null +++ b/src/lang.h @@ -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 index 0000000..2fcc3db --- /dev/null +++ b/src/main.c @@ -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 index 0000000..b1452e7 --- /dev/null +++ b/src/main.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..5476d5e --- /dev/null +++ b/src/modcmd.c @@ -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 index 0000000..940ab32 --- /dev/null +++ b/src/modcmd.h @@ -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 index 0000000..66494e7 --- /dev/null +++ b/src/mysqlConn.c @@ -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 index 0000000..4ed6655 --- /dev/null +++ b/src/mysqlConn.h @@ -0,0 +1,21 @@ +#ifndef _MySQLConn_h +#define _MySQLConn_h + +#include "main.h" +#include +#include + +#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 index 0000000..fe919c8 --- /dev/null +++ b/src/timeq.c @@ -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 index 0000000..0a06948 --- /dev/null +++ b/src/timeq.h @@ -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 index 0000000..0976848 --- /dev/null +++ b/src/tools.c @@ -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 index 0000000..54a0cfa --- /dev/null +++ b/src/tools.h @@ -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 index 0000000..06f4b0a --- /dev/null +++ b/src/version.h @@ -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 index 0000000..b5bdc12 --- /dev/null +++ b/src/version.sh @@ -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 <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 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 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 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 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 index caaff7e..0000000 --- a/version.sh +++ /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 <