From 1b896f3dd7017397278744a49d2622a76e48f4cb Mon Sep 17 00:00:00 2001 From: thorium1256 Date: Mon, 11 May 2026 23:07:40 +0300 Subject: [PATCH] WIP commit --- include/IRC.h | 50 ++++++++++++++++-- src/IRC.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++- src/main.c | 4 ++ 3 files changed, 192 insertions(+), 6 deletions(-) diff --git a/include/IRC.h b/include/IRC.h index f63cec4..99d221d 100644 --- a/include/IRC.h +++ b/include/IRC.h @@ -1,6 +1,13 @@ #ifndef IRC_H #define IRC_H +#include +typedef enum +{ + PLAIN, + EXTERNAL +} irc_sasl_method_t; + typedef struct { char *nickname; @@ -9,7 +16,6 @@ typedef struct int identlen; char *hostname; int hostlen; - } irc_hostmask_t; typedef struct { @@ -17,13 +23,35 @@ typedef struct { char *source; char *command; char *argv[16]; - int argc; + int argc; } irc_message_t; +typedef struct +{ + irc_hostmask_t hostmask; + char prefix; +} irc_chanuser_t; + +typedef struct +{ + char name[64]; + char topic[512]; + irc_chanuser_t* users; +} irc_channel_t; + +typedef struct +{ + char name[32]; + char args[64]; +} irc_capability_t; + + typedef struct { int sockfd; irc_hostmask_t ownHostmask; + char supportedCapabilities[512]; + char* requestedCapabilities; } irc_client_t; typedef struct { @@ -31,9 +59,23 @@ typedef struct { void (*handler)(irc_message_t *msg, irc_client_t *irc); } command_t; -int IRC_ParseMessage(char* line, irc_message_t *msg); +void IRC_ParseMessage(char* line, irc_message_t *msg); void IRC_ProcessMessage(irc_message_t *msg, irc_client_t *irc); -void IRC_PRIVMSG(char* msg, irc_client_t irc); +// various IRC commands +void IRC_PRIVMSG(char* to, char* msg, irc_client_t *irc); +void IRC_NOTICE(char* to, char* msg, irc_client_t *irc); +void IRC_NICK(char *nick, irc_client_t *irc); +void IRC_USER(char *ident, char* realname, irc_client_t *irc); + +// registration +void IRC_Register(char *nick, char* ident, char *realname, bool saslEnabled, irc_sasl_method_t saslMethod, char *saslUsername, char *saslPassword, irc_client_t *irc); + +// Capability negotiation block +void IRC_StartCapabilityNegotiation(irc_client_t *irc); +void IRC_RequestCapabilities(char* caps, irc_client_t *irc); +void IRC_EndCapabilityNegotiation(irc_client_t *irc); + +int IRC_ParseCapabilities(char* caps, irc_capability_t *capabilities, int capsLength); #endif \ No newline at end of file diff --git a/src/IRC.c b/src/IRC.c index e25fe59..41cd83b 100644 --- a/src/IRC.c +++ b/src/IRC.c @@ -5,7 +5,7 @@ #include #include -int IRC_ParseMessage(char *line, irc_message_t *msg) +void IRC_ParseMessage(char *line, irc_message_t *msg) { strncpy(msg->line, line, sizeof(msg->line) - 1); char *ptr = msg->line; @@ -63,22 +63,110 @@ int IRC_ParseMessage(char *line, irc_message_t *msg) msg->argc++; } +} + +// WIP +int IRC_ParseCapabilities(char *caps, irc_capability_t *capabilities, int capsLength) +{ + char capBak[512]; + strncpy(capBak, caps, sizeof(capBak) - 1); + capBak[sizeof(capBak) - 1] = 0; + + memset(capabilities, 0, sizeof(irc_capability_t) * capsLength); + + char *ptr = capBak; + + int argc = 0; + + while(*ptr && argc <= capsLength) + { + // copy the cap name + strncpy(capabilities[argc].name, ptr, sizeof(capabilities[argc].name) - 1); + capabilities[argc].name[sizeof(capabilities[argc].name) - 1] = 0; + while(*ptr != ' ' && *ptr != '=') ptr++; + + if(*ptr == '=') + { + *ptr++ = 0; + } + else if (*ptr == ' ') + { + if(strlen(capabilities[argc].name) > 0) + { + // the cap has no args + + } + argc++; + } + } return 0; } static void handlePing(irc_message_t *msg, irc_client_t *irc) { - char buf[128]; + char buf[128]; // most pingpongs are usually short, with the servername being short too snprintf(buf, sizeof buf, "PONG :%s", msg->argv[0]); NET_Send(irc->sockfd, buf); } +static void handleCapabilities(irc_message_t *msg, irc_client_t *irc) +{ + // we are willing to tolerate some spaghetti... + if(strncmp(msg->argv[1], "LS", 4) == 0) + { + // add the supported capabilities to our client info + strncpy(irc->supportedCapabilities, msg->argv[2], sizeof irc->supportedCapabilities); + irc->supportedCapabilities[sizeof(irc->supportedCapabilities) - 1] = 0; + // try to find specific requested capabilities in there + + char* caps[64]; + int capCount = 0; + + char* ptr = irc->requestedCapabilities; + + // split the requested caps + while(*ptr && capCount < 64) + { + caps[capCount] = ptr; + + while(*ptr && *ptr != ' ') ptr++; + + if(*ptr) + { + *ptr++ = NUL; + while (*ptr == ' ') ptr++; + } + + capCount++; + } + + char buf[512]; + int bytesWritten = 0; + + for(int i = 0; i < capCount; i++) + { + if(strstr(irc->supportedCapabilities, caps[i]) != NULL) + { + // queue that up for one CAP REQ + bytesWritten += snprintf(buf + bytesWritten, sizeof(buf) - bytesWritten, "%s ", caps[i]); + } + } + + IRC_RequestCapabilities(buf, irc); + } +} + +/* + IRC_ProcessMessage is only used for commands that have no need to be a user-listenable event. + For pollable events, use IRC_PollEvent(&event). +*/ void IRC_ProcessMessage(irc_message_t *msg, irc_client_t *irc) { command_t commands[] = { {"PING", handlePing}, + {"CAP", handleCapabilities}, {NULL, NULL} }; @@ -89,4 +177,56 @@ void IRC_ProcessMessage(irc_message_t *msg, irc_client_t *irc) commands[i].handler(msg, irc); } } +} + +void IRC_PRIVMSG(char *to, char *msg, irc_client_t *irc) +{ + char buf[512]; + snprintf(buf, sizeof buf, "PRIVMSG %s :%s", to, msg); + NET_Send(irc->sockfd, buf); +} + +void IRC_NOTICE(char *to, char *msg, irc_client_t *irc) +{ + char buf[512]; + snprintf(buf, sizeof buf, "NOTICE %s :%s", to, msg); + NET_Send(irc->sockfd, buf); +} + +void IRC_NICK(char *newNick, irc_client_t *irc) +{ + char buf[512]; + snprintf(buf, sizeof buf, "NICK %s", newNick); + NET_Send(irc->sockfd, buf); +} + +void IRC_USER(char *ident, char *realname, irc_client_t *irc) +{ + char buf[512]; + snprintf(buf, sizeof buf, "USER %s 0 * :%s", ident, realname); + NET_Send(irc->sockfd, buf); +} + +void IRC_REGISTER(char *nick, char *ident, char *realname, bool saslEnabled, irc_sasl_method_t saslMethod, char *saslUsername, char *saslPassword, irc_client_t *irc) +{ + IRC_StartCapabilityNegotiation(irc); + IRC_NICK(nick, irc); + IRC_USER(ident, realname, irc); +} + +void IRC_StartCapabilityNegotiation(irc_client_t *irc) +{ + NET_Send(irc->sockfd, "CAP LS 302"); +} + +void IRC_RequestCapabilities(char *caps, irc_client_t *irc) +{ + char buf[512]; + snprintf(buf, sizeof buf, "CAP REQ :%s", caps); + NET_Send(irc->sockfd, buf); +} + +void IRC_EndCapabilityNegotiation(irc_client_t *irc) +{ + NET_Send(irc->sockfd, "CAP END"); } \ No newline at end of file diff --git a/src/main.c b/src/main.c index e596468..e971429 100644 --- a/src/main.c +++ b/src/main.c @@ -72,6 +72,8 @@ int main(int argc, char **argv) irc_message_t msg; IRC_ParseMessage(linebuf, &msg); + IRC_ProcessMessage(&msg, &irc); + // try to print it if(msg.source != NULL) @@ -101,5 +103,7 @@ int main(int argc, char **argv) printf("Connection closed by foreign host.\n"); + NET_Close(sockfd); + return 0; } \ No newline at end of file