From: Egor Date: Mon, 2 May 2022 18:58:45 +0000 (+0300) Subject: add a proper irc parser X-Git-Url: https://git.patchysicp.xyz/?a=commitdiff_plain;h=af44f3b1f2b76e5747f0c510732054ae9822c183;p=patchyircd.git add a proper irc parser --- diff --git a/irc.c b/irc.c index 1b461a6..fc5f5bc 100644 --- a/irc.c +++ b/irc.c @@ -2,104 +2,140 @@ struct dynarr databuf; +const char *hostname = "irc.patchysicp.xyz"; int processPacket(struct client_data *client) { - char *packet = client->buf; - //size_t packetLen = client->bufLen; + char *source = NULL; + char *command = NULL; + char *args[16] = {0}; + int argc = 0; + { + char *p = client->buf; + { // remove \r + char *end = strchr(p, '\n'); + if (!end) { + killConnection(client, false); + return 1; // null detected + } + if (end > p && end[-1] == '\r') + end[-1] = '\n'; + if (strchr(p, '\r')) { + killConnection(client, false); + return 1; // internal \r detected + } + } + if (*p == ':') { + source = p; + while (*p != ' ' && *p != '\n') + p++; + if (*p++ == '\n') { + killConnection(client, true); + return 1; // no command + } + p[-1] = '\0'; + } + command = p; + while (*p != ' ' && *p != '\n') + p++; + int more_args = *p++ != '\n'; + p[-1] = '\0'; + stringupper(command); + while (more_args) { + if (argc == 15) // too many arguments + break; + while (*p == ' ') + p++; + if (*p == '\n') + break; + int is_colon = *p == ':'; + args[argc++] = p += is_colon; + if (is_colon) { + if (*p == '\n') + argc--; // empty trailing argument + while (*p != '\n') + p++; + *p = '\0'; + break; + } else { + while (*p != ' ' && *p != '\n') + p++; + more_args = *p++ != '\n'; + p[-1] = '\0'; + } + } + args[argc] = NULL; + } + printf("parsed message: %s", command); + for (int i = 0; i < argc; i++){ + printf(" %d:%s", i, args[i]); + if (i == argc-1) + printf("\n"); + } databuf.len = 0; - if(strncmp(packet, "PING", 4) == 0) { - append_str(&databuf, ":irc.patchysicp.xyz PONG irc.patchysicp.xyz :"); - append_str(&databuf, packet+5); + if(strcmp(command, "PING") == 0) { + if (!args[0]) // FIXME: error message + return 0; + append_strf(&databuf, ":%s PONG %s :%s", hostname, hostname, args[0]); send_log(client->FD, databuf.buf, databuf.len, 0); - } else if(strncmp(packet, "NICK ", 5) == 0) { + } else if(strcmp(command, "NICK") == 0) { // User now registered - setNick(client, packet+5, 32); + if (!args[0]) // FIXME: error message + return 0; + setNick(client, args[0], 32); printf("USER SET NICKNAME %s\n", client->nick); fflush(stdout); - } else if(strncmp(packet, "USER ", 5) == 0) { + } else if(strcmp(command, "USER") == 0) { // Send welcome newUser(client); - } else if(strncmp(packet, "MOTD", 4) == 0) { + } else if(strcmp(command, "MOTD") == 0) { // Send welcome sendMOTD(client); - // Horrible join but it works and its funny - } else if(strncmp(packet, "JOIN ", 5) == 0) { - char *i; - append_str(&databuf, ":"); - append_str(&databuf, client->nick); - append_str(&databuf, " JOIN :"); - // Start GitHub Copilot - if(packet[5] == ':') { - i = packet+6; - } else { - i = packet+5; - } - append_str(&databuf, i); - i = databuf.buf+8+client->nickLen; - while(*i != '\0') { - // Fuck you and multiple channels at once - // TODO: actually implement multiple channels - if(*i == ' ' || *i == ',') { - *i = '\n'; - *(i+1) = 0; + } else if(strcmp(command, "JOIN") == 0) { + if (!args[0]) // FIXME: error message + return 0; + for (char *p = args[0]; *p; p++) // TODO: multiple channels + if (*p == ',') { + *p = '\0'; break; } - i++; - } - databuf.len = strlen(databuf.buf); + append_strf(&databuf, ":%s JOIN :%s\n", client->nick, args[0]); // End GitHub Copilot send_log(client->FD, databuf.buf, databuf.len, 0); sendall_log(client->FD, databuf.buf, databuf.len, 0); - *strchr(packet, '\n') = '\0'; for(int i=0; inick[0]) { databuf.len = 0; - append_strf(&databuf, ":irc.patchysicp.xyz 353 %s = %s :%s\n", client->nick, packet+5+(packet[5]==':'), clients[i]->nick); + append_strf(&databuf, ":%s 353 %s = %s :%s\n", hostname, client->nick, args[0], clients[i]->nick); send_log(client->FD, databuf.buf, databuf.len, 0); } databuf.len = 0; - append_strf(&databuf, ":irc.patchysicp.xyz 366 %s :End of /NAMES list\n", client->nick); + append_strf(&databuf, ":%s 366 %s :End of /NAMES list\n", hostname, client->nick); send_log(client->FD, databuf.buf, databuf.len, 0); - } else if(strncmp(packet, "PRIVMSG ", 8) == 0) { - append_str(&databuf, ":"); - append_str(&databuf, client->nick); - append_str(&databuf, " "); - append_str(&databuf, packet); + } else if(strcmp(command, "PRIVMSG") == 0) { + if (argc < 2) // FIXME: error message + return 0; + append_strf(&databuf, ":%s PRIVMSG %s :%s\n", client->nick, args[0], args[1]); sendall_log(client->FD, databuf.buf, databuf.len, 0); // Start GitHub Copilot - this shit actually be copy pasting my code lmao - } else if(strncmp(packet, "QUIT", 4) == 0) { - append_str(&databuf, ":"); - append_str(&databuf, client->nick); - append_str(&databuf, " QUIT :"); - if(packet[4] == ' ') { - if(packet[5] == ':') { - append_str(&databuf, packet+6); - } else { - append_str(&databuf, packet+5); - } - } else { - append_str(&databuf, "Client Quit\n"); - } + } else if(strcmp(command, "QUIT") == 0) { + append_strf(&databuf, ":%s QUIT :%s\n", client->nick, args[0] ? args[0] : "Client Quit"); sendall_log(client->FD, databuf.buf, databuf.len, 0); killConnection(client, true); return 1; - } else if(strncmp(packet, "PONG", 4) == 0) { + } else if(strcmp(command, "PONG") == 0) { // Do nothing - } else if(strncmp(packet, "MODE ", 5) == 0) { - char *p = packet+5; - char *start_nick = p; - while (*p != ' ' && *p != '\n') - p++; - char *end_nick = p; - if (*end_nick == '\n') { // get mode - *end_nick = '\0'; - if (*start_nick != '#') { - struct client_data *cl = findClient(start_nick); + } else if(strcmp(command, "MODE") == 0) { + if (argc == 0) // FIXME: error message + return 0; + char *nick = args[0]; + if (argc == 1) { // get mode + if (*nick != '#') { + struct client_data *cl = findClient(nick); if (!cl) { - append_strf(&databuf, ":irc.patchysicp.xyz 401 %s %s :No such nick/channel\n", client->nick, start_nick-1); + append_strf(&databuf, ":%s 401 %s %s :No such nick/channel\n", hostname, client->nick, nick); send_log(client->FD, databuf.buf, databuf.len, 0); return 0; } - append_strf(&databuf, ":irc.patchysicp.xyz 221 %s +", client->nick); + append_strf(&databuf, ":%s 221 %s +", hostname, client->nick); if (cl->umode & UMODE_INVISIBLE) append_str(&databuf, "i"); if (cl->umode & UMODE_OPER) append_str(&databuf, "o"); if (cl->umode & UMODE_LOPER) append_str(&databuf, "O"); @@ -108,78 +144,69 @@ int processPacket(struct client_data *client) { append_str(&databuf, "\n"); send_log(client->FD, databuf.buf, databuf.len, 0); } else { - append_strf(&databuf, ":irc.patchysicp.xyz 324 %s %s +nt\n", client->nick, start_nick); + append_strf(&databuf, ":%s 324 %s %s +nt\n", hostname, client->nick, nick); send_log(client->FD, databuf.buf, databuf.len, 0); } } else { // set mode - *end_nick = '\0'; - if (*start_nick != '#') { - struct client_data *cl = findClient(start_nick); + if (*nick != '#') { + struct client_data *cl = findClient(nick); if (!cl) { - append_strf(&databuf, ":irc.patchysicp.xyz 401 %s %s :No such nick/channel\n", client->nick, start_nick-1); + append_strf(&databuf, ":%s 401 %s %s :No such nick/channel\n", hostname, client->nick, nick); send_log(client->FD, databuf.buf, databuf.len, 0); return 0; } if (client->FD != cl->FD) { - append_strf(&databuf, ":irc.patchysicp.xyz 502 %s :Can't change mode for other users\n", client->nick); + append_strf(&databuf, ":%s 502 %s :Can't change mode for other users\n", hostname, client->nick); send_log(client->FD, databuf.buf, databuf.len, 0); return 0; } - if (*++p == ':') - p++; int off; + char *p = args[1]; switch (*p++) { case '+': off = 0; break; case '-': off = 1; break; - default: - *end_nick = ' '; - goto unknown; + default: goto unknown; } - while (*p != ' ' && *p != '\n') { + while (*p) { databuf.len = 0; switch (*p) { case 'i': if (off) { - append_strf(&databuf, ":irc.patchysicp.xyz MODE %s -i\n", client->nick); + append_strf(&databuf, ":%s MODE %s -i\n", hostname, client->nick); cl->umode &= ~UMODE_INVISIBLE; } else { - append_strf(&databuf, ":irc.patchysicp.xyz MODE %s +i\n", client->nick); + append_strf(&databuf, ":%s MODE %s +i\n", hostname, client->nick); cl->umode |= UMODE_INVISIBLE; } send_log(client->FD, databuf.buf, databuf.len, 0); break; default: - append_strf(&databuf, ":irc.patchysicp.xyz 501 %s :Unknown MODE flag\n", client->nick); + append_strf(&databuf, ":%s 501 %s :Unknown MODE flag\n", hostname, client->nick); send_log(client->FD, databuf.buf, databuf.len, 0); } p++; } } else { - *end_nick = ' '; goto unknown; } } - } else if(strncmp(packet, "NAMES ", 6) == 0) { + } else if(strcmp(command, "NAMES") == 0) { // TODO: actual channel support - char *p = strchr(packet+6, '\n'); - *p = '\0'; + if (argc == 0) // FIXME: error message + return 0; for(int i=0; inick[0]) { databuf.len = 0; - append_strf(&databuf, ":irc.patchysicp.xyz 353 %s = %s :%s\n", client->nick, packet+6, clients[i]->nick); + append_strf(&databuf, ":%s 353 %s = %s :%s\n", hostname, client->nick, args[0], clients[i]->nick); send_log(client->FD, databuf.buf, databuf.len, 0); } databuf.len = 0; - append_strf(&databuf, ":irc.patchysicp.xyz 366 %s :End of /NAMES list\n", client->nick); + append_strf(&databuf, ":%s 366 %s :End of /NAMES list\n", hostname, client->nick); send_log(client->FD, databuf.buf, databuf.len, 0); } else { unknown: - printf("Unknown packet: %s", packet); // Inform user of error - append_str(&databuf, ":irc.patchysicp.xyz 421 "); - append_str(&databuf, client->nick); - append_str(&databuf, " :Unknown command, "); - append_str(&databuf, packet); + append_strf(&databuf, ":%s 421 %s :Unknown command %s\n", hostname, client->nick, command); send_log(client->FD, databuf.buf, databuf.len, 0); fflush(stdout); } @@ -187,45 +214,38 @@ unknown: } void newUser(struct client_data *client) { - char data[1024]; // Copy in basics - strcpy(data, ":irc.patchysicp.xyz 001 "); - strcpy(data+24, client->nick); - strcpy(data+24+client->nickLen, " :Welcome to PatchyIRCD!!!\n"); - //send_log(client->FD, data, (26+client->nickLen+27), 0); - send_log(client->FD, data, strlen(data), 0); - data[22] = '2'; - strcpy(data+26+client->nickLen, "Your host is PatchyIRCD V0.0.1\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '3'; - strcpy(data+26+client->nickLen, "This server was created when I had cybersex with your mother.\n"); - send_log(client->FD, data, strlen(data), 0); - data[20] = '2'; - data[21] = '5'; - data[22] = '1'; - strcpy(data+26+client->nickLen, "This server exists\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '2'; - strcpy(data+26+client->nickLen, "Jannies don't exist\n"); - send_log(client->FD, data, strlen(data), 0); + databuf.len = 0; + append_strf(&databuf, ":%s 001 %s :Welcome to PatchyIRCD!!!\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); + databuf.len = 0; + append_strf(&databuf, ":%s 002 %s :Your host is PatchyIRCD V0.0.1\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); + databuf.len = 0; + append_strf(&databuf, ":%s 003 %s :This server was created when I had cybersex with your mother.\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); + databuf.len = 0; + append_strf(&databuf, ":%s 251 %s :This server exists\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); + databuf.len = 0; + append_strf(&databuf, ":%s 252 %s :Jannies don't exist\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); sendMOTD(client); } void sendMOTD(struct client_data *client) { - char data[1024]; - // Copy in basics - strcpy(data, ":irc.patchysicp.xyz 375 "); - strcpy(data+24, client->nick); - strcpy(data+24+client->nickLen, " :PatchySICP /MOTD\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '2'; - strcpy(data+26+client->nickLen, "Welcome to Montreal!\n"); - send_log(client->FD, data, strlen(data), 0); - strcpy(data+26+client->nickLen, "You are retarded and I will have cybersex with your mom.\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '6'; - strcpy(data+26+client->nickLen, "/MOTD over\n"); - send_log(client->FD, data, strlen(data), 0); + databuf.len = 0; + append_strf(&databuf, ":%s 375 %s :PatchySICP /MOTD\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); + databuf.len = 0; + append_strf(&databuf, ":%s 372 %s :Welcome to Montreal!\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); + databuf.len = 0; + append_strf(&databuf, ":%s 372 %s :You are retarded and I will have cybersex with your mom.\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); + databuf.len = 0; + append_strf(&databuf, ":%s 376 %s :/MOTD over\n", hostname, client->nick); + send_log(client->FD, databuf.buf, databuf.len, 0); } void setNick(struct client_data *client, char* nickname, size_t size) { @@ -234,26 +254,11 @@ void setNick(struct client_data *client, char* nickname, size_t size) { // Remove newline for(i=0;inick, nickname, size) == 0) { // Nickname is already taken databuf.len = 0; - append_str(&databuf, ":irc.patchysicp.xyz 443 * "); - append_str(&databuf, nickname); - append_str(&databuf, " :Nickname is already in use\n"); + append_strf(&databuf, ":%s 443 * %s :Nickname is already in use\n", hostname, nickname); send_log(client->FD, databuf.buf, databuf.len, 0); return; } @@ -275,11 +278,7 @@ void setNick(struct client_data *client, char* nickname, size_t size) { // Update nickname if(client->nickLen) { databuf.len = 0; - append_str(&databuf, ":"); - append_str(&databuf, client->nick); - append_str(&databuf, " NICK "); - append_str(&databuf, nickname); - append_str(&databuf, "\n"); + append_strf(&databuf, ":%s NICK %s\n", client->nick, nickname); send_log(client->FD, databuf.buf, databuf.len, 0); sendall_log(client->FD, databuf.buf, databuf.len, 0); } diff --git a/main.c b/main.c index be5ceec..4dd5c04 100644 --- a/main.c +++ b/main.c @@ -88,7 +88,7 @@ int main() { SOCKET SD; int i; char client_addr[100]; - char *welcomeMessage = ":irc.patchysicp.xyz NOTICE * :Hello welcome to PatchyIRCD!\n"; + char *welcomeMessage = ":irc.patchysicp.xyz NOTICE * :Hello welcome to PatchyIRCD!\n"; // TODO: don't hardcode hostname puts("[PatchyIRCD]: Starting up..."); fflush(stdout); diff --git a/util.c b/util.c index 20f6881..0468b00 100644 --- a/util.c +++ b/util.c @@ -41,3 +41,17 @@ void append_strf(struct dynarr *d, const char *s, ...){ } va_end(ap); } +void stringupper(char *s) { + while (*s) { + if (*s >= 'a' && *s <= '~') + *s &= ~0x20; + s++; + } +} +void stringlower(char *s) { + while (*s) { + if (*s >= 'A' && *s <= '^') + *s |= 0x20; + s++; + } +} diff --git a/util.h b/util.h index 1c0d235..c84345e 100644 --- a/util.h +++ b/util.h @@ -8,3 +8,5 @@ struct dynarr { void append_str(struct dynarr *d, const char *s); void append_strf(struct dynarr *d, const char *s, ...); +void stringupper(char *s); +void stringlower(char *s);