]> PatchyGit - patchyircd.git/commitdiff
add a proper irc parser
authorEgor <egor@patchysicp.xyz>
Mon, 2 May 2022 18:58:45 +0000 (21:58 +0300)
committerEgor <egor@patchysicp.xyz>
Mon, 2 May 2022 18:58:45 +0000 (21:58 +0300)
irc.c
main.c
util.c
util.h

diff --git a/irc.c b/irc.c
index 1b461a6..fc5f5bc 100644 (file)
--- a/irc.c
+++ b/irc.c
 
 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; i<CLIENTS; i++)
                        if(clients[i] && clients[i]->nick[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; i<CLIENTS; i++)
                        if(clients[i] && clients[i]->nick[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;i<size;i++){
-               // CR/^M
-               if(nickname[i] == 13) {
-                       nickname[i] = 0;
-                       break;
-               }
-               // Newline
-               if(nickname[i] == 10) {
-                       nickname[i] = 0;
-                       break;
-               }
                // Space
                if(nickname[i] == ' ') {
                        nickname[i] = 0;
                        break;
                }
-               // NULL
-               if(nickname[i] == 0) {
-                       nickname[i] = 0;
-                       break;
-               }
        }
 
        // Start GitHub Copilot
@@ -263,9 +268,7 @@ void setNick(struct client_data *client, char* nickname, size_t size) {
                if(strncmp(clients[i]->nick, 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 (file)
--- 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 (file)
--- 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 (file)
--- 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);