--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+
+#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;
+ }
+ }
+ }
+ }
+}
+
--- /dev/null
+#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
--- /dev/null
+
+#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);
+}
+
+
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+
+#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);
+ }
+}
--- /dev/null
+#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