*first commit :D*
authorpk910 <philipp@zoelle1.de>
Tue, 9 Aug 2011 23:10:07 +0000 (01:10 +0200)
committerpk910 <philipp@zoelle1.de>
Tue, 9 Aug 2011 23:10:07 +0000 (01:10 +0200)
ChanNode.h [new file with mode: 0644]
ChanUser.h [new file with mode: 0644]
ClientSocket.c [new file with mode: 0644]
ClientSocket.h [new file with mode: 0644]
IRCParser.c [new file with mode: 0644]
IRCParser.h [new file with mode: 0644]
UserNode.c [new file with mode: 0644]
UserNode.h [new file with mode: 0644]
main.c [new file with mode: 0644]
main.h [new file with mode: 0644]

diff --git a/ChanNode.h b/ChanNode.h
new file mode 100644 (file)
index 0000000..63aadca
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _ChanNode_h
+#define _ChanNode_h
+#include "main.h"
+
+struct ChanUser;
+
+struct ChanNode {
+    char name[CHANNELLEN+1];
+    char topic[TOPICLEN+1];
+    struct ChanUser *user;
+    
+    struct ChanNode *next;
+}
+
+/*
+void init_UserNode();
+int is_valid_nick(const char *nick);
+struct UserNode* getUserByNick(const char *nick);
+struct UserNode* addUser(const char *nick);
+int renameUser(struct UserNode* user, const char *new_nick);
+void delUser(struct UserNode* user, int freeUser);
+*/
+
+#endif
\ No newline at end of file
diff --git a/ChanUser.h b/ChanUser.h
new file mode 100644 (file)
index 0000000..b5cdd33
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _ChanUser_h
+#define _ChanUser_h
+
+#define CHANUSERFLAG_OPPED  0x01;
+#define CHANUSERFLAG_VOICED 0x02;
+
+
+#define CHANUSERFLAG_OPPED_OR_VOICED (CHANUSERFLAG_OPPED | CHANUSERFLAG_VOICED);
+
+struct ChanNode;
+struct UserNode;
+
+struct ChanUser {
+    char flags;
+    struct ChanNode *channel;
+    struct UserNode *user;
+    
+    struct ChanUser *next_user;
+    struct ChanUser *next_chan;
+}
+
+#endif
\ No newline at end of file
diff --git a/ClientSocket.c b/ClientSocket.c
new file mode 100644 (file)
index 0000000..002a633
--- /dev/null
@@ -0,0 +1,171 @@
+
+#include "ClientSocket.h"
+#include IRCParser.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 = 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();
+    struct ClientSocket *client = malloc(sizeof(*client));
+    if (!client)
+    {
+        perror("malloc() failed");
+        return;
+    }
+    client->host = strdup(host);
+    client->port = port;
+    client->pass = (pass == NULL ? NULL : strdup(pass));
+    client->user = user;
+    client->flags = 0;
+    client->bufferpos = 0;
+    client->next = sockets->data;
+    sockets->data = client;
+}
+
+int connect_socket(struct ClientSocket *socket) {
+    if((socket->flsgs & SOCKET_FLAG_CONNECTED)) return 1;
+    struct hostent *host;
+    struct sockaddr_in addr;
+    int sock;
+    if (!inet_aton(socket->host, &addr.sin_addr))
+    {
+        host = gethostbyname(socket->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(socket->port);
+    addr.sin_family = AF_INET;
+
+    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
+    {
+        perror("connect() failed");
+        return 0;
+    }
+
+    //send the IRC Headers
+    char sendBuf[512];
+    int len;
+
+    if(socket->pass) {
+        len = sprintf(sendBuf, "PASS :%s\n", socket->pass);
+        write_socket(sock, sendBuf, len);
+    }
+    len = sprintf(sendBuf, "USER %s 0 0 :%s\n", socket->user->ident, socket->user->realname);
+    write_socket(sock, sendBuf, len);
+    len = sprintf(sendBuf, "NICK %s\n", socket->user->nick);
+    write_socket(sock, sendBuf, len);
+
+    socket->socket = sock;
+    socket->flags |= SOCKET_FLAG_CONNECTED;
+    return 1;
+}
+
+int close_socket(struct ClientSocket *socket) {
+    if(socket == NULL) return 0;
+    if((socket->flags & SOCKET_FLAG_CONNECTED))
+        close(socket->sock);
+    struct ClientSocket *sock, *last_sock = NULL;
+    for (sock = sockets->data; sock; sock = sock->next) {
+        if(sock == socket) {
+            if(last_sock)
+                last_sock->next = sock->next;
+            else
+                sockets->data = sock->next;
+            sockets->count--;
+        } else
+            last_sock = sock;
+    }
+    free(socket->host);
+    free(socket->pass);
+    free(socket);
+}
+
+int write_socket(struct ClientSocket *socket, char* msg, int len) {
+    if(!(socket->flags & SOCKET_FLAG_CONNECTED)) return 0;
+    printf("[send %d] %s", len, msg);
+    write(socket->sock, msg, len);
+    return 1;
+}
+
+void socket_loop(int timeout) {
+    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;
+    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);
+            } else {
+                int used = parse_lines(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;
+                }
+            }
+        }
+    }
+}
+
diff --git a/ClientSocket.h b/ClientSocket.h
new file mode 100644 (file)
index 0000000..3fff1e8
--- /dev/null
@@ -0,0 +1,33 @@
+#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 BUF_SIZ 512
+
+struct UserNode;
+
+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;
+    
+    struct ClientSocket *next;
+}
+
+struct ClientSocket* create_socket(char *host, int *port, char *pass, struct UserNode *user);
+int connect_socket(struct ClientSocket *socket);
+int close_socket(struct ClientSocket *socket);
+int write_socket(struct ClientSocket *socket, char* msg, int len);
+void socket_loop(int timeout);
+
+#endif
\ No newline at end of file
diff --git a/IRCParser.c b/IRCParser.c
new file mode 100644 (file)
index 0000000..22a9d95
--- /dev/null
@@ -0,0 +1,83 @@
+
+#include "IRCParser.h"
+#include "ClientSocket.h"
+
+struct irc_cmd *irc_commands = NULL;
+
+int parse_lines(struct ClientSocket *client, char *lines, int len) {
+    int i, startpos = 0;
+    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, lines);
+            startpos = i+1;
+            lines += i-startpos;
+        }
+    }
+    return startpos;
+}
+
+static void parse_line(struct ClientSocket *client, char *line) {
+    int i = 0, argc = 0;
+    char *argv[MAXNUMPARAMS];
+    printf("[recv %s] %s", strlen(line), line);
+    if(line[0] == ':')
+        i = 1;
+    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;
+        }
+        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;
+}
+
+void parser_init() {
+    
+    register_irc_function("001", raw_001);
+    
+}
+
+static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc) {
+    struct irc_cmd *irc_cmd;
+    for(irc_cmd = irc_commands; irc_cmd; irc_cmd = irc_cmd->next) {
+        if(!stricmp(irc_cmd->cmd)) {
+            irc_cmd->func(client, from, argv, argc);
+            break;
+        }
+    }
+}
+
+static IRC_CMD(raw_001) {
+    client->flags |= SOCKET_FLAG_READY;
+    write_socket(client, "PRIVMSG Watchcat :hi\n", 21);
+}
+
+
diff --git a/IRCParser.h b/IRCParser.h
new file mode 100644 (file)
index 0000000..dfeee06
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _IRCParser_h
+#define _IRCParser_h
+
+#include "main.h"
+#include "ClientSocket.h"
+
+#define MAXNUMPARAMS 200 /* maximum number of parameters in one line */
+
+#define IRC_CMD(NAME) int NAME(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 parser_init();
+
+#endif
\ No newline at end of file
diff --git a/UserNode.c b/UserNode.c
new file mode 100644 (file)
index 0000000..0e50b58
--- /dev/null
@@ -0,0 +1,125 @@
+#include "UserNode.h"
+
+static struct UserNode **userList;
+
+void init_UserNode() {
+    userList = calloc(VALID_NICK_CHARS_FIRST_LEN, sizeof(*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(const char *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* 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;
+}
+
+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;
+    }
+    strcpy(user->nick, nick);
+    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;
+}
+
+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);
+    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(freeUser)
+        free(user);
+    else
+        user->next = NULL;
+}
diff --git a/UserNode.h b/UserNode.h
new file mode 100644 (file)
index 0000000..229ac1b
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _UserNode_h
+#define _UserNode_h
+#include "main.h"
+
+#define USERFLAG_ISBOT 0x01;
+struct ChanUser;
+
+struct UserNode {
+    char nick[NICKLEN+1];
+    char ident[USERLEN+1];
+    char host[HOSTLEN+1];
+    char realname[REALLEN+1];
+    char flags;
+    struct ChanUser *channel;
+    
+    struct UserNode *next;
+}
+
+void init_UserNode();
+int is_valid_nick(const char *nick);
+struct UserNode* getUserByNick(const char *nick);
+struct UserNode* searchUserByNick(const char *nick);
+struct UserNode* addUser(const char *nick);
+int renameUser(struct UserNode* user, const char *new_nick);
+void delUser(struct UserNode* user, int freeUser);
+
+#endif
\ No newline at end of file
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..77a8875
--- /dev/null
+++ b/main.c
@@ -0,0 +1,30 @@
+
+#include "main.h"
+#include "ClientSocket.h"
+#include "UserNode.h"
+
+//all c files - so we don't need a big Makefile right now :D
+#include "ClientSocket.c"
+#include "IRCParser.c"
+#include "UserNode.c"
+
+#include "ChanUser.h"
+#include "ChanNode.h"
+
+void just_test_it() {
+    struct UserNode *user = addUser("TestBot");
+    strcpy(user->ident, "test");
+    strcpy(user->realname, "testUser!");
+    user->flags |= USERFLAG_ISBOT;
+    create_socket("pk910.de", 6667, NULL, user);
+}
+
+int main(void)
+{
+    parser_init();
+    init_UserNode();
+    just_test_it();
+    while(1) {
+        socket_loop(1);
+    }
+}
diff --git a/main.h b/main.h
new file mode 100644 (file)
index 0000000..f356769
--- /dev/null
+++ b/main.h
@@ -0,0 +1,31 @@
+#ifndef _main_h
+#define _main_h
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <netdb.h>
+
+
+#define NICKLEN         30
+#define USERLEN         10
+#define HOSTLEN         63
+#define REALLEN         50
+#define TOPICLEN        500
+#define CHANNELLEN      200
+
+//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
+
+#endif
\ No newline at end of file