From 8f4162305f38ccd49baa923c4b33caa4d2ca2707 Mon Sep 17 00:00:00 2001 From: thorium1256 Date: Mon, 11 May 2026 15:14:22 +0300 Subject: [PATCH] first commit, unfinished wip --- .clangd | 2 + Makefile | 44 +++++++++ README.md | 4 + TODO.md | 5 + bbirc | Bin 0 -> 14656 bytes build/rel_IRC.o | Bin 0 -> 2144 bytes build/rel_main.o | Bin 0 -> 3360 bytes build/rel_netcode.o | Bin 0 -> 3688 bytes compile_commands.json | 19 ++++ include/IRC.h | 39 ++++++++ include/IRC_numerics.h | 203 +++++++++++++++++++++++++++++++++++++++++ include/defines.h | 6 ++ include/netcode.h | 9 ++ src/IRC.c | 92 +++++++++++++++++++ src/main.c | 105 +++++++++++++++++++++ src/netcode.c | 123 +++++++++++++++++++++++++ 16 files changed, 651 insertions(+) create mode 100644 .clangd create mode 100644 Makefile create mode 100644 README.md create mode 100644 TODO.md create mode 100755 bbirc create mode 100644 build/rel_IRC.o create mode 100644 build/rel_main.o create mode 100644 build/rel_netcode.o create mode 100644 compile_commands.json create mode 100644 include/IRC.h create mode 100644 include/IRC_numerics.h create mode 100644 include/defines.h create mode 100644 include/netcode.h create mode 100644 src/IRC.c create mode 100644 src/main.c create mode 100644 src/netcode.c diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..a98c592 --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +Documentation: + CommentFormat: Doxygen \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..db0cebe --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +CC := clang +CFLAGS := -I include -Wall -Wextra +CFLAGS_DBG := $(CFLAGS) -g -O0 +CFLAGS_REL := $(CFLAGS) -O2 + +LDFLAGS := +LDFLAGS_REL := $(LDFLAGS) -s + +BUILD_DIR := build +SRC_DIR := src +INCLUDE_DIR := include + +APPLICATION := bbirc +APPLICATION_DBG := bbirc-debug + +$(shell mkdir -p $(BUILD_DIR)) +SRCS := $(wildcard $(SRC_DIR)/*.c) +DBG_OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/dbg_%.o,$(SRCS)) +REL_OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/rel_%.o,$(SRCS)) + +.PHONY: all debug release clean + +all: release + +debug: $(APPLICATION_DBG) +release: $(APPLICATION) +both: debug release + +$(APPLICATION): $(REL_OBJS) + $(CC) -o $@ $^ $(LDFLAGS_REL) + +$(APPLICATION_DBG): $(DBG_OBJS) + $(CC) -o $@ $^ $(LDFLAGS) + +$(BUILD_DIR)/dbg_%.o: $(SRC_DIR)/%.c + $(CC) -c -o $@ $^ $(CFLAGS_DBG) + +$(BUILD_DIR)/rel_%.o: $(SRC_DIR)/%.c + $(CC) -c -o $@ $^ $(CFLAGS_REL) + +clean: + rm -rf $(BUILD_DIR) + rm -rf $(APPLICATION) + rm -rf $(APPLICATION_DBG) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4830d3e --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# BareBones IRC +An attempt at trying to make an IRC client in pure C with sockets. + +**UNFINISHED!!!** \ No newline at end of file diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..8e50165 --- /dev/null +++ b/TODO.md @@ -0,0 +1,5 @@ +# To-Do + +1. Add actual IRC client functionality +2. Finish the netcode +3. Don't care about the looks of it yet, just have an ANSI command line or something \ No newline at end of file diff --git a/bbirc b/bbirc new file mode 100755 index 0000000000000000000000000000000000000000..d1d132e9082229d44bedd0507f369cbeeda94a23 GIT binary patch literal 14656 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 v{=DCklb0?FV literal 0 HcmV?d00001 diff --git a/build/rel_IRC.o b/build/rel_IRC.o new file mode 100644 index 0000000000000000000000000000000000000000..2ae7e2d30c67c510192c962461fb4563735393bb GIT binary patch literal 2144 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 +#include +#include + +int IRC_ParseMessage(char *line, irc_message_t *msg) +{ + strncpy(msg->line, line, sizeof(msg->line) - 1); + char *ptr = msg->line; + ptr[sizeof(msg->line)] = NUL; + + char *source = NULL; + char *command = NULL; + + // get the source, if it exists (the : at the beginning of an IRC message) + if(*ptr == ':') + { + ptr++; + source = ptr; + + while (*ptr && *ptr != ' ') ptr++; + if (*ptr) *ptr++ = NUL; + + while (*ptr == ' ') ptr++; // skip any extra spaces + } + + msg->source = source; + + // read the command + command = ptr; + + while(*ptr && *ptr != ' ') ptr++; + if (*ptr) *ptr++ = NUL; + + msg->command = command; + + while (*ptr == ' ') ptr++; + + // read its arguments (until we encounter a colon/nullbyte) + msg->argc = 0; + + while(*ptr && msg->argc <= 15) + { + if(*ptr == ':') // if it's a trailing arg + { + ptr++; + msg->argv[msg->argc] = ptr; + msg->argc++; + break; + } + + msg->argv[msg->argc] = ptr; + + while(*ptr && *ptr != ' ') ptr++; + + if (*ptr) + { + *ptr++ = NUL; + while (*ptr == ' ') ptr++; // skip spaces for next arg + } + + msg->argc++; + } + + return 0; +} + +static void handlePing(irc_message_t *msg, irc_client_t *irc) +{ + char buf[128]; + snprintf(buf, sizeof buf, "PONG :%s", msg->argv[0]); + NET_Send(irc->sockfd, buf); +} + +void IRC_ProcessMessage(irc_message_t *msg, irc_client_t *irc) +{ + command_t commands[] = + { + {"PING", handlePing}, + {NULL, NULL} + }; + + for(int i = 0; commands[i].name; i++) + { + if(strcmp(msg->command, commands[i].name) == 0) + { + commands[i].handler(msg, irc); + } + } +} \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e596468 --- /dev/null +++ b/src/main.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IRC.h" +#include "defines.h" +#include "netcode.h" + +int main(int argc, char **argv) +{ + int sockfd = NET_Connect("irc.libera.chat", 6667); + + fd_set readfds; + static char linebuf[1026]; + static size_t lineLen = 0; + char recvline[513]; + char sendline[513]; + + irc_client_t irc; + irc.sockfd = sockfd; + + if(sockfd >= 0) + { + NET_Send(sockfd, "NICK BareBonesDude\r\n"); + NET_Send(sockfd, "USER BareBonesDude 0 * :The Postal Dudesksleton\r\n"); + } + else + { + return 1; + } + + while(1) + { + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + FD_SET(sockfd, &readfds); + + int maxfd = (sockfd > 0) ? sockfd + 1 : 1; + + select(maxfd, &readfds, NULL, NULL, NULL); + + if(FD_ISSET(STDIN_FILENO, &readfds)) + { + fgets(sendline, sizeof(sendline), stdin); + NET_Send(sockfd, sendline); + } + + if(FD_ISSET(sockfd, &readfds)) + { + ssize_t n = recv(sockfd, recvline, sizeof(recvline), 0); + + if(n <= 0) break; + recvline[n] = NUL; + + for(ssize_t i = 0; i < n; i++) + { + linebuf[lineLen++] = recvline[i]; + + if(lineLen >= 2 && linebuf[lineLen - 2] == '\r' && linebuf[lineLen - 1] == '\n') + { + // we found a complete line + linebuf[lineLen] = NUL; + + // parse the message + irc_message_t msg; + IRC_ParseMessage(linebuf, &msg); + + // try to print it + + if(msg.source != NULL) + { + printf("%s: %s ", msg.source, msg.command); + } + else + { + printf("Server: %s ", msg.command); + } + + for(int i = 0; i < msg.argc; i++) + { + printf("%s ", msg.argv[i]); + } + + lineLen = 0; + } + + if(lineLen >= sizeof(linebuf) - 1) + { + lineLen = 0; + } + } + } + } + + printf("Connection closed by foreign host.\n"); + + return 0; +} \ No newline at end of file diff --git a/src/netcode.c b/src/netcode.c new file mode 100644 index 0000000..a5eebaf --- /dev/null +++ b/src/netcode.c @@ -0,0 +1,123 @@ +#include "netcode.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +int NET_Connect(const char *host, int port) +{ + int status; + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + // save us from user or programmer stupidity + if(!host) + { + return -1; + } + + char portNumber[6]; + snprintf(portNumber, 6, "%d", port); + + printf("Looking up %s...\n", host); + + if ((status = getaddrinfo(host, portNumber, &hints, &res)) == -1) + { + fprintf(stderr, "Unable to lookup %s: %s\n", host, gai_strerror(status)); + return -1; + } + + char ipstr[INET6_ADDRSTRLEN]; + int sockfd = -1; + + for(struct addrinfo *p = res; p != NULL; p = p->ai_next) + { + void *addr; + struct sockaddr_in *ipv4; + struct sockaddr_in6 *ipv6; + + if(p->ai_family == AF_INET) + { + ipv4 = (struct sockaddr_in *)p->ai_addr; + addr = &(ipv4->sin_addr); + } + else + { + ipv6 = (struct sockaddr_in6 *)p->ai_addr; + addr = &(ipv6->sin6_addr); + } + + inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); + printf("Connecting to %s (%s)...\n", host, ipstr); + + if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) + { + char perrorMsg[sizeof("Failed to connect to ") + sizeof ipstr]; + snprintf(perrorMsg, sizeof perrorMsg, "Failed to connect to %s", ipstr); + perror(perrorMsg); + continue; + } + + if((connect(sockfd, p->ai_addr, p->ai_addrlen)) == -1) + { + close(sockfd); + char perrorMsg[sizeof("Failed to connect to ") + sizeof ipstr]; + snprintf(perrorMsg, sizeof perrorMsg, "Failed to connect to %s", ipstr); + perror(perrorMsg); + continue; + } + + printf("Connected!\n"); + break; + } + + if(sockfd >= 0) + { + return sockfd; + } + else + { + return -1; + } +} + +void NET_Send(int sockfd, const char *toSend) +{ + size_t bytesSent = 0; + size_t sendLen = strlen(toSend); + + while(bytesSent < sendLen) + { + ssize_t sent = send(sockfd, toSend, sendLen - bytesSent, 0); + if(sent == -1) + { + perror("NET_Send"); + return; + } + + if(sent == 0) + { + fprintf(stderr, "NET_Send: connection closed"); + return; + } + + bytesSent += sent; + } +} + +void NET_Close(int sockfd) +{ + if(sockfd >= 0) + { + shutdown(sockfd, SHUT_RDWR); + close(sockfd); + } +} \ No newline at end of file