From 0bf6e710d483638f1311a827ce281bfa26af821b Mon Sep 17 00:00:00 2001 From: Piotr Kozak Date: Tue, 6 Jan 2026 01:15:23 +0100 Subject: [PATCH] Added viewing of saved messages --- client.c | 47 +++++++++++++++++++++++-------- commands.h | 3 +- server.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 109 insertions(+), 24 deletions(-) diff --git a/client.c b/client.c index 9c44db5..3ec05cf 100644 --- a/client.c +++ b/client.c @@ -8,6 +8,7 @@ #include "commands.h" +// Make a macro for this cause I'm not typing sizeof twice every time #define send(queue_id, msgbuf_ptr) \ msgsnd(queue_id, msgbuf_ptr, sizeof(*(msgbuf_ptr)) - sizeof(long), 0) @@ -82,24 +83,30 @@ static void input_loop(int server_queue_id, const char *client_id) { perror("msgsnd(/msg) failed"); } } else if (strncmp(buffer, "/list ", 6) == 0) { - char *offset = buffer + 6; + char *offset = buffer + 6; - if (strcmp(offset, "active") != 0 && strcmp(offset, "all") != 0) { - printf("Invalid list type. Use /list active or /list all\n"); - continue; - } + if (strcmp(offset, "active") != 0 && strcmp(offset, "all") != 0) { + printf("Invalid list type. Use /list active or /list all\n"); + continue; + } - msgbuf_t msg = {.mtype = List_clients, .sender = ""}; - strncpy(msg.sender, client_id, COMMAND_LENGTH - 1); - strncpy(msg.command, offset, COMMAND_LENGTH - 1); - if (send(server_queue_id, &msg) == -1) { - perror("msgsnd(/list) failed"); - } + msgbuf_t msg = {.mtype = List_clients, .sender = ""}; + strncpy(msg.sender, client_id, COMMAND_LENGTH - 1); + strncpy(msg.command, offset, COMMAND_LENGTH - 1); + if (send(server_queue_id, &msg) == -1) { + perror("msgsnd(/list) failed"); + } } else if (strncmp(buffer, "/mute ", 6) == 0) { // handle mute } else if (strcmp(buffer, "/quit") == 0) { // TODO: Would be nice to have a way to gracefully logout and not just // depend on heartbeats, maybe + } else if (strncmp(buffer, "/inbox", 8) == 0) { + msgbuf_t msg = {.mtype = Inbox, .sender = ""}; + strncpy(msg.sender, client_id, COMMAND_LENGTH - 1); + if (send(server_queue_id, &msg) == -1) { + perror("msgsnd(/mailbox) failed"); + } } else { printf("Unknown command\n"); } @@ -161,7 +168,7 @@ int main(int argc, char *argv[]) { return 1; } - printf("Login accepted for id '%s'\n", client_id); + printf("Login accepted. Welcome, %s!\n", resp.command); if (fork() == 0) { heartbeat_loop(server_queue_id, client_id); @@ -200,6 +207,22 @@ int main(int argc, char *argv[]) { } break; } + case Inbox: { + // Upon recieving an inbox message, check the command field for the index + // Index of 0 means that there are messages in the mailbox + if (strcmp(incoming.command, "0") == 0) { + printf("You have messages in your mailbox!\n"); + continue; + } + + // Index of 1 is just the first message so print a header + if (strcmp(incoming.command, "1") == 0) { + printf("Your inbox messages:\n"); + } + printf("[%s] %s: %s\n", incoming.command, incoming.sender, + incoming.message); + break; + } case Signal: // Tell the user if the previous message was accepted and/or delivered if (incoming.stype == ACK_ACCEPTED) { diff --git a/commands.h b/commands.h index 53dbad1..33e61b0 100644 --- a/commands.h +++ b/commands.h @@ -12,7 +12,8 @@ typedef enum { List_clients, Mute, Unmute, - Signal + Signal, + Inbox } CommandType; typedef enum { diff --git a/server.c b/server.c index e490f50..6a2e630 100644 --- a/server.c +++ b/server.c @@ -166,15 +166,23 @@ int main(int argc, char **argv) { client->last_seen = tv.tv_sec; msgbuf_t response = { .mtype = Login, + .command = "", .stype = ACK_ACCEPTED, }; + strncpy(response.command, client->nickname, COMMAND_LENGTH); printf("User accepted: %s\n", msgbuf.sender); send(msg_queue_id, &response); + + // Check if there are any saved messages for this client + if (client->saved_message_count > 0) { + response.mtype = Inbox; + snprintf(response.command, COMMAND_LENGTH, "0"); + send(client->queue_id, &response); + } break; } case Message: { - printf("Recieved message, checking which client\n"); // Find the client that sent the message then forward it to all the // specified recipients Client *client = NULL; @@ -185,12 +193,12 @@ int main(int argc, char **argv) { } } - printf("Received message from client id %s: %s\n", msgbuf.sender, - msgbuf.message); + printf("Received message from client id %s to %s\n", msgbuf.sender, + msgbuf.command); if (client == NULL || !client->logged_in) { // Client not found or not logged in - printf("Client not found or not logged in"); + printf("Sender not found or not logged in"); msgbuf_t response = { .mtype = Message, .stype = ERR_NOT_LOGGED_IN, @@ -217,7 +225,7 @@ int main(int argc, char **argv) { if (target_client == NULL) { // Target client not found or not logged in - printf("Target client %s not found or not logged in\n", target_id); + printf("Target client %s not found\n", target_id); msgbuf_t response = { .mtype = Message, .stype = ERR_USER_NOT_FOUND, @@ -330,13 +338,7 @@ int main(int argc, char **argv) { } } - // TODO: Rethink if we even want to respond in such case if (client == NULL || !client->logged_in) { - msgbuf_t response = { - .mtype = Message, - .stype = ERR_NOT_LOGGED_IN, - }; - send(read_status, &response); continue; } @@ -369,7 +371,66 @@ int main(int argc, char **argv) { send(client->queue_id, &response); break; } + case Inbox: { + Client *client = NULL; + for (int i = 0; i < client_count; i++) { + if (strncmp(clients[i].id, msgbuf.sender, COMMAND_LENGTH) == 0) { + client = &clients[i]; + break; + } + } + if (client == NULL || !client->logged_in) + continue; + + msgbuf_t response = { + .mtype = Inbox, + .sender = "", + .command = "", + .message = "", + }; + + // Now, for all the stored messages, send them one by one, incrementing + // the counter in command + for (int i = 0; i < client->saved_message_count; i++) { + snprintf(response.command, COMMAND_LENGTH, "%d", i + 1); + strncpy(response.sender, client->saved_messages[i].sender, + COMMAND_LENGTH); + strncpy(response.message, client->saved_messages[i].message, + MESSAGE_LENGTH); + send(client->queue_id, &response); + } + + // Now send ACK_DELIVERED to senders + for (int i = 0; i < client->saved_message_count; i++) { + saved_message_t *saved_msg = &client->saved_messages[i]; + Client *original_sender = NULL; + for (int j = 0; j < client_count; j++) { + if (strncmp(clients[j].nickname, saved_msg->sender, COMMAND_LENGTH) == + 0) { + original_sender = &clients[j]; + break; + } + } + + // Technically, the first check should never fail, as we can't remove + // users dynamically but I'll leave it here anyway + if (original_sender == NULL || !original_sender->logged_in) { + continue; + } + + msgbuf_t ack_msg = { + .mtype = Signal, + .sender = "", + .command = "", + .stype = ACK_DELIVERED, + }; + strncpy(ack_msg.sender, client->nickname, COMMAND_LENGTH); + send(original_sender->queue_id, &ack_msg); + } + client->saved_message_count = 0; + break; + } case Mute: case Unmute: break;