diff options
| author | Raymaekers Luca <luca@keyfried.com> | 2025-10-12 15:27:05 +0200 |
|---|---|---|
| committer | Raymaekers Luca <luca@spacehb.net> | 2025-10-12 15:27:05 +0200 |
| commit | 5c973160b2fa7f097f06b496343f99cd276e7370 (patch) | |
| tree | 1863aa38323c04c7c41148582b4ba29e10226e14 /source/chatty.c | |
| parent | 961a87eb0ca089a1dd130af774f970b600588d19 (diff) | |
| parent | 90099147cf34336ffd621f35f550e32977b97e2f (diff) | |
checkpoint
Diffstat (limited to 'source/chatty.c')
| -rw-r--r-- | source/chatty.c | 528 |
1 files changed, 264 insertions, 264 deletions
diff --git a/source/chatty.c b/source/chatty.c index 32a4431..01d450b 100644 --- a/source/chatty.c +++ b/source/chatty.c @@ -15,7 +15,7 @@ #define TIMEOUT_RECONNECT 1 #define MAX_INPUT_LEN 512 // Filepath where user ID is stored -#define ID_FILE "_id" +#define ID_FILE ".chatty_id" // Filepath where logged #define LOGFILE "chatty.log" // enable logging @@ -26,10 +26,10 @@ #ifndef Assert #ifdef DEBUG #define Assert(expr) if (!(expr)) \ - { \ - tb_shutdown(); \ - raise(SIGTRAP); \ - } +{ \ +tb_shutdown(); \ +raise(SIGTRAP); \ +} #else #define Assert(expr) ; #endif // DEBUG @@ -49,10 +49,10 @@ #include "ui.h" enum { FDS_BI = 0, // for one-way communication with the server (eg. TextMessage) - FDS_UNI, // For two-way communication with the server (eg. IDMessage) - FDS_TTY, - FDS_RESIZE, - FDS_MAX }; + FDS_UNI, // For two-way communication with the server (eg. IDMessage) + FDS_TTY, + FDS_RESIZE, + FDS_MAX }; typedef struct { u8 Author[AUTHOR_LEN]; @@ -96,7 +96,7 @@ get_user_by_id(Arena* clientsArena, ID id) { // User is not in the clientsArena if (id == user.ID) return &user; - + User* clients = clientsArena->addr; for (u64 i = 0; i < (clientsArena->pos / sizeof(*clients)); i++) { @@ -117,16 +117,16 @@ add_user_info(Arena* clientsArena, s32 fd, u64 id) IDMessage message = {id}; s32 nsend = sendAnyMessage(fd, header, &message); Assert(nsend != -1); - + // Wait for response IntroductionMessage introduction_message; recvAnyMessageType(fd, &header, &introduction_message, HEADER_TYPE_INTRODUCTION); - + // Add the information User* client = ArenaPush(clientsArena, sizeof(*client)); memcpy(client->Author, introduction_message.author, AUTHOR_LEN); client->ID = id; - + LoggingF("Got " USER_FMT "\n", USER_ARG((*client))); return client; } @@ -137,10 +137,10 @@ get_connection(struct sockaddr_in* address) { s32 fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) return -1; - + s32 err = connect(fd, (struct sockaddr*)address, sizeof(*address)); if (err) return -1; - + return fd; } @@ -157,14 +157,14 @@ authenticate(User* user, s32 fd) IDMessage message = {user->ID}; s32 nsend = sendAnyMessage(fd, header, &message); Assert(nsend != -1); - + ErrorMessage error_message; s32 nrecv = recvAnyMessageType(fd, &header, &error_message, HEADER_TYPE_ERROR); Assert(nrecv != -1); // TODO: handle not found if (nrecv == 0) return 0; - + if (error_message.type == ERROR_TYPE_SUCCESS) return 1; else @@ -178,7 +178,7 @@ authenticate(User* user, s32 fd) memcpy(message.author, user->Author, AUTHOR_LEN); s32 nsend = sendAnyMessage(fd, header, &message); Assert(nsend != -1); - + IDMessage id_message; s32 nrecv = recvAnyMessageType(fd, &header, &id_message, HEADER_TYPE_ID); Assert(nrecv != -1); @@ -205,7 +205,7 @@ thread_reconnect(void* fds_ptr) { // timeout nanosleep(&t, &t); - + bifd = get_connection(&address); if (bifd == -1) { @@ -219,27 +219,27 @@ thread_reconnect(void* fds_ptr) close(bifd); continue; } - + LoggingF("Reconnect succeeded (%d, %d), authenticating\n", unifd, bifd); - + if (authenticate(&user, bifd) && authenticate(&user, unifd)) { break; } - + close(bifd); close(unifd); - + LoggingF("Failed, retrying...\n"); } - + fds[FDS_BI].fd = bifd; fds[FDS_UNI].fd = unifd; - + // Redraw screen raise(SIGWINCH); - + return 0; } @@ -247,31 +247,31 @@ command_output run_command_get_output(char *Command, char *Argv[], u8 *OutputBuffer, int Len) { command_output Result = {0}; - + int CommandPipe[2]; int Error = pipe(CommandPipe); Assert(Error != -1); - + int Pid = fork(); Assert(Pid != -1); - + // Run command in child if (!Pid) { dup2(CommandPipe[1], STDOUT_FILENO); //redirect stdout to Pipe close(CommandPipe[0]); close(CommandPipe[1]); - + int fd = open("/dev/null", O_WRONLY); dup2(fd, STDERR_FILENO); - + execvp(Command, Argv); } - + // Wait for child int statval; waitpid(Pid, &statval, 0); - + if(WIFEXITED(statval)) { int ExitCode = WEXITSTATUS(statval); @@ -285,12 +285,12 @@ run_command_get_output(char *Command, char *Argv[], u8 *OutputBuffer, int Len) Result.Error = 1; return Result; } - + close(CommandPipe[1]); - + Result.NumRead = read(CommandPipe[0], OutputBuffer, Len); Assert(Result.NumRead != -1); - + return Result; } @@ -308,49 +308,49 @@ DisplayChat(Arena* ScratchArena, }; u32 FreeHeight = global.height - TextBox.H; TextBox.Y = FreeHeight; - + #define MIN_TEXT_WIDTH_FOR_WRAPPING 20 s32 MinBoxWidth = TEXTBOX_MIN_WIDTH; s32 InputBoxTextWidth = TextBox.W - MinBoxWidth + 2; bool ShouldIncreaseSize = ( - (s32)InputLen >= InputBoxTextWidth && - InputBoxTextWidth > MIN_TEXT_WIDTH_FOR_WRAPPING - ); + (s32)InputLen >= InputBoxTextWidth && + InputBoxTextWidth > MIN_TEXT_WIDTH_FOR_WRAPPING + ); if (ShouldIncreaseSize) { TextBox.H++; } #undef MIN_TEXT_WIDTH_FOR_WRAPPING - + rect TextR = { TextBox.X + 2, TextBox.Y + 1, TextBox.W - 2*TEXTBOX_PADDING_X - 2*TEXTBOX_BORDER_WIDTH, TextBox.H - 2*TEXTBOX_BORDER_WIDTH }; - + if (global.height < TextBox.H || global.width < TextBox.W) { tb_hide_cursor(); return; } - + bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]); global.cursor_x = TextR.X; global.cursor_y = TextR.Y; DrawBox(TextBox, 0); DrawTextBox(TextR, Input, InputLen); - + // Print vertical bar s32 VerticalBarOffset = TIMESTAMP_LEN + AUTHOR_LEN + 2; for (u32 Y = 0; Y < FreeHeight; Y++) tb_print(VerticalBarOffset, Y, 0, 0, "│"); - + // show error popup if server disconnected if (fds[FDS_UNI].fd == -1 || fds[FDS_BI].fd == -1) { popup(TB_RED, TB_BLACK, (u8*)"Server disconnected."); } - + // Print messages in msgsArena, if there are too many to display, start printing from an offset. // Looks like this: // 03:24:29 [1234567890ab] hello homes how are @@ -358,53 +358,53 @@ DisplayChat(Arena* ScratchArena, // 03:24:33 [TlasT] │ I am fine // 03:24:33 [Fin] │ I am too { - + // If there is not enough space to draw, do not draw if (FreeHeight <= 0) return; - + // Used to go to the next message in MessagesArena by incrementing with the messages' size. u8* MessageAddress = MessagesArena->addr; Assert(MessageAddress != 0); - + // Skip messages if there is not enough space to display them all u32 MessagesOffset = (MessagesNum > FreeHeight) ? MessagesNum - FreeHeight : 0; for (u32 MessageIndex = 0; MessageIndex < MessagesOffset; MessageIndex++) { HeaderMessage* header = (HeaderMessage*)MessageAddress; MessageAddress += sizeof(*header); - + switch (header->type) { - case HEADER_TYPE_TEXT: - { - TextMessage* message = (TextMessage*)MessageAddress; - MessageAddress += TEXTMESSAGE_SIZE; - MessageAddress += message->len * sizeof(*message->text); - break; - } - case HEADER_TYPE_PRESENCE: + case HEADER_TYPE_TEXT: + { + TextMessage* message = (TextMessage*)MessageAddress; + MessageAddress += TEXTMESSAGE_SIZE; + MessageAddress += message->len * sizeof(*message->text); + break; + } + case HEADER_TYPE_PRESENCE: MessageAddress += sizeof(PresenceMessage); break; - case HEADER_TYPE_HISTORY: + case HEADER_TYPE_HISTORY: MessageAddress += sizeof(HistoryMessage); break; - default: + default: // unhandled message type Assert(0); } } - + u32 MessageY = 0; - + for (u32 i = MessagesOffset; - i < MessagesNum; - i++) + i < MessagesNum; + i++) { if (MessageY >= FreeHeight) break; - + HeaderMessage* header = (HeaderMessage*)MessageAddress; MessageAddress += sizeof(*header); - + User* client = get_user_by_id(ClientsArena, header->id); if (!client) { @@ -412,84 +412,84 @@ DisplayChat(Arena* ScratchArena, client = add_user_info(ClientsArena, fds[FDS_BI].fd, header->id); } Assert(client); - + switch (header->type) { - case HEADER_TYPE_TEXT: - { - TextMessage* message = (TextMessage*)MessageAddress; - - - // Color own messages - u32 fg = 0; - if (user.ID == header->id) - { - fg = TB_CYAN; - } - else - { - fg = TB_MAGENTA; - } - - // prefix is of format "HH:MM:SS [<author>] ", create it - u8 timestamp[TIMESTAMP_LEN]; - formatTimestamp(timestamp, message->timestamp); - - tb_printf(0, MessageY, TB_WHITE, 0, "%s", timestamp); - tb_printf(TIMESTAMP_LEN, MessageY, fg, 0, "[%s]", client->Author); - - // Only display when there is enough space - if (global.width > VerticalBarOffset + 2) + case HEADER_TYPE_TEXT: { - raw_result RawText = markdown_to_raw(ScratchArena, (wchar_t*)&message->text, message->len); - markdown_formatoptions MDFormat = preprocess_markdown(ScratchArena, - (wchar_t*)&message->text, - message->len); - - u32 timesWrapped = tb_print_wrapped_with_markdown(VerticalBarOffset + 2, MessageY, fg, 0, - RawText.Text, RawText.Len, - global.width, global.height, MDFormat); - - // Free the memory - ScratchArena->pos = 0; - - MessageY += timesWrapped; - } - else + TextMessage* message = (TextMessage*)MessageAddress; + + + // Color own messages + u32 fg = 0; + if (user.ID == header->id) + { + fg = TB_CYAN; + } + else + { + fg = TB_MAGENTA; + } + + // prefix is of format "HH:MM:SS [<author>] ", create it + u8 timestamp[TIMESTAMP_LEN]; + formatTimestamp(timestamp, message->timestamp); + + tb_printf(0, MessageY, TB_WHITE, 0, "%s", timestamp); + tb_printf(TIMESTAMP_LEN, MessageY, fg, 0, "[%s]", client->Author); + + // Only display when there is enough space + if (global.width > VerticalBarOffset + 2) + { + raw_result RawText = markdown_to_raw(ScratchArena, (wchar_t*)&message->text, message->len); + markdown_formatoptions MDFormat = preprocess_markdown(ScratchArena, + (wchar_t*)&message->text, + message->len); + + u32 timesWrapped = tb_print_wrapped_with_markdown(VerticalBarOffset + 2, MessageY, fg, 0, + RawText.Text, RawText.Len, + global.width, global.height, MDFormat); + + // Free the memory + ScratchArena->pos = 0; + + MessageY += timesWrapped; + } + else + { + // We still displayed the timestamp so we need to increment the Y. + MessageY++; + } + + u32 message_size = TEXTMESSAGE_SIZE + message->len * sizeof(*message->text); + MessageAddress += message_size; + } break; + case HEADER_TYPE_PRESENCE: { - // We still displayed the timestamp so we need to increment the Y. + PresenceMessage* message = (PresenceMessage*)MessageAddress; + tb_printf(TIMESTAMP_LEN, MessageY, TB_MAGENTA, 0, "[%s]", client->Author); + + // Wrap Text in '*' + u8 *Text = presenceTypeString(message->type); + u32 Len = 0; + while(Text[Len]) Len++; + u32 FormattedText[Len+2]; + FormattedText[0] = '*'; + FormattedText[Len+1] = '*'; + for (u32 i = 1; i < Len + 1; i++) FormattedText[i] = Text[i-1]; + + tb_print_markdown(VerticalBarOffset + 2, MessageY, 0, 0, FormattedText, Len + 2); + MessageY++; - } - - u32 message_size = TEXTMESSAGE_SIZE + message->len * sizeof(*message->text); - MessageAddress += message_size; - } break; - case HEADER_TYPE_PRESENCE: - { - PresenceMessage* message = (PresenceMessage*)MessageAddress; - tb_printf(TIMESTAMP_LEN, MessageY, TB_MAGENTA, 0, "[%s]", client->Author); - - // Wrap Text in '*' - u8 *Text = presenceTypeString(message->type); - u32 Len = 0; - while(Text[Len]) Len++; - u32 FormattedText[Len+2]; - FormattedText[0] = '*'; - FormattedText[Len+1] = '*'; - for (u32 i = 1; i < Len + 1; i++) FormattedText[i] = Text[i-1]; - - tb_print_markdown(VerticalBarOffset + 2, MessageY, 0, 0, FormattedText, Len + 2); - - MessageY++; - MessageAddress += sizeof(*message); - } break; - case HEADER_TYPE_HISTORY: - { - HistoryMessage* message = (HistoryMessage*)MessageAddress; - MessageAddress += sizeof(*message); - // TODO: implement - } break; - default: + MessageAddress += sizeof(*message); + } break; + case HEADER_TYPE_HISTORY: + { + HistoryMessage* message = (HistoryMessage*)MessageAddress; + MessageAddress += sizeof(*message); + // TODO: implement + } break; + default: tb_printf(0, MessageY, 0, 0, "%s", headerTypeString(header->type)); MessageY++; break; @@ -507,40 +507,40 @@ main(int argc, char** argv) fprintf(stderr, "usage: chatty <username>\n"); return 1; } - + u32 arg_len = strlen(argv[1]); Assert(arg_len <= AUTHOR_LEN - 1); memcpy(user.Author, argv[1], arg_len); user.Author[arg_len] = '\0'; - + s32 err = 0; // error code for functions - + u32 MessagesNum = 0; // Number of messages in msgsArena s32 nrecv = 0; // number of bytes received - + wchar_t Input[MAX_INPUT_LEN] = {0}; // input buffer u32 InputIndex = 0; // number of characters in input - + Arena ScratchArena; Arena MessagesArena; Arena ClientsArena; ArenaAlloc(&MessagesArena, Megabytes(64)); // Messages received & sent ArenaAlloc(&ClientsArena, Megabytes(1)); // Arena for storing clients ArenaAlloc(&ScratchArena, Megabytes(1)); // Arena for storing clients - + struct tb_event ev; // event fork keypress & resize u8 quit = 0; // boolean to indicate if we want to quit the main loop u8* quitmsg = 0; // this string will be printed before returning from main - + pthread_t thr_rec; // thread for reconnecting to server when disconnected - + #ifdef LOGGING LogFD = open(LOGFILE, O_RDWR | O_CREAT | O_TRUNC, 0600); Assert(LogFD != -1); #else logfd = 2; // stderr #endif - + // poopoo C cannot infer type struct pollfd fds[FDS_MAX] = { {-1, POLLIN, 0}, // FDS_BI @@ -548,18 +548,18 @@ main(int argc, char** argv) {-1, POLLIN, 0}, // FDS_TTY {-1, POLLIN, 0}, // FDS_RESIZE }; - + address = (struct sockaddr_in){ AF_INET, htons(PORT), {0}, {0}, }; - + #ifdef IMPORT_ID // File for storing the user's ID. u32 idfile = open(ID_FILE, O_RDWR | O_CREAT, 0600); - s32 nread = read(idfile, &user.id, sizeof(user.id)); + s32 nread = read(idfile, &user.ID, sizeof(user.ID)); Assert(nread != -1); #endif /* Authentication */ @@ -591,43 +591,43 @@ main(int argc, char** argv) fds[FDS_BI].fd = bifd; fds[FDS_UNI].fd = unifd; } - + #ifdef IMPORT_ID // Save id - write(idfile, &user.id, sizeof(user.id)); + write(idfile, &user.ID, sizeof(user.ID)); #endif - + LoggingF("Got ID: %lu\n", user.ID); - + // for wide character printing Assert(setlocale(LC_ALL, "")); - + // init tb_init(); tb_get_fds(&fds[FDS_TTY].fd, &fds[FDS_RESIZE].fd); - + DisplayChat(&ScratchArena, &MessagesArena, MessagesNum, &ClientsArena, fds, Input, InputIndex); tb_present(); - + // main loop while (!quit) { err = poll(fds, FDS_MAX, TIMEOUT_POLL); // ignore resize events and use them to redraw the screen Assert(err != -1 || errno == EINTR); - + tb_clear(); - + if (fds[FDS_UNI].revents & POLLIN) { // got data from server HeaderMessage header; nrecv = recv(fds[FDS_UNI].fd, &header, sizeof(header), 0); Assert(nrecv != -1); - + // Server disconnects if (nrecv == 0) { @@ -646,39 +646,39 @@ main(int argc, char** argv) LoggingF("Header received does not match version\n"); continue; } - + void* addr = ArenaPush(&MessagesArena, sizeof(header)); memcpy(addr, &header, sizeof(header)); - + // Messages handled from server switch (header.type) { - case HEADER_TYPE_TEXT: + case HEADER_TYPE_TEXT: recvTextMessage(&MessagesArena, fds[FDS_UNI].fd); MessagesNum++; break; - case HEADER_TYPE_PRESENCE:; + case HEADER_TYPE_PRESENCE:; PresenceMessage* message = ArenaPush(&MessagesArena, sizeof(*message)); nrecv = recv(fds[FDS_UNI].fd, message, sizeof(*message), 0); Assert(nrecv != -1); Assert(nrecv == sizeof(*message)); MessagesNum++; break; - default: + default: LoggingF("Got unhandled message: %s\n", headerTypeString(header.type)); break; } } } - + if (fds[FDS_TTY].revents & POLLIN) { // got a key event tb_poll_event(&ev); - + switch (ev.key) { - case TB_KEY_CTRL_W: + case TB_KEY_CTRL_W: // delete consecutive whitespace while (InputIndex) { @@ -700,111 +700,111 @@ main(int argc, char** argv) InputIndex--; } break; - case TB_KEY_CTRL_Z: - { - pid_t pid = getpid(); - tb_shutdown(); - kill(pid, SIGSTOP); - tb_init(); - } break; - case TB_KEY_CTRL_Y: // Paste clipboard contents to input - { - u32 OutputBufferLen = MAX_INPUT_LEN - InputIndex; - if (OutputBufferLen <= 0) break; - - u8 OutputBuffer[OutputBufferLen]; - - char *PathName = "xclip"; - char *Argv[] = {PathName, "-o", "-sel", "c", 0}; - - command_output Output = run_command_get_output(PathName, Argv, OutputBuffer, OutputBufferLen - 1); - if (Output.Error) break; - - // Remove trailing whitespace - int BufferIndex = Output.NumRead - 1; - while (BufferIndex > 0 && - (OutputBuffer[BufferIndex] == '\n' || - OutputBuffer[BufferIndex] == '\t')) + case TB_KEY_CTRL_Z: { - OutputBuffer[BufferIndex] = 0; - BufferIndex--; - } - - // Append to output - for (s32 BufferIndex = 0; BufferIndex < Output.NumRead; BufferIndex++) + pid_t pid = getpid(); + tb_shutdown(); + kill(pid, SIGSTOP); + tb_init(); + } break; + case TB_KEY_CTRL_Y: // Paste clipboard contents to input { - // convert u8 to u32 - u32 ch = OutputBuffer[BufferIndex]; - Input[InputIndex] = ch; - InputIndex++; - } - - } break; - case TB_KEY_CTRL_I: - { - for (u32 i = 0; - i < TAB_WIDTH && InputIndex < MAX_INPUT_LEN - 1; - i++) + u32 OutputBufferLen = MAX_INPUT_LEN - InputIndex; + if (OutputBufferLen <= 0) break; + + u8 OutputBuffer[OutputBufferLen]; + + char *PathName = "xclip"; + char *Argv[] = {PathName, "-o", "-sel", "c", 0}; + + command_output Output = run_command_get_output(PathName, Argv, OutputBuffer, OutputBufferLen - 1); + if (Output.Error) break; + + // Remove trailing whitespace + int BufferIndex = Output.NumRead - 1; + while (BufferIndex > 0 && + (OutputBuffer[BufferIndex] == '\n' || + OutputBuffer[BufferIndex] == '\t')) + { + OutputBuffer[BufferIndex] = 0; + BufferIndex--; + } + + // Append to output + for (s32 BufferIndex = 0; BufferIndex < Output.NumRead; BufferIndex++) + { + // convert u8 to u32 + u32 ch = OutputBuffer[BufferIndex]; + Input[InputIndex] = ch; + InputIndex++; + } + + } break; + case TB_KEY_CTRL_I: { - Input[InputIndex] = L' '; - InputIndex++; - } - } break; - case TB_KEY_BACKSPACE2: + for (u32 i = 0; + i < TAB_WIDTH && InputIndex < MAX_INPUT_LEN - 1; + i++) + { + Input[InputIndex] = L' '; + InputIndex++; + } + } break; + case TB_KEY_BACKSPACE2: if (InputIndex) InputIndex--; Input[InputIndex] = 0; break; - case TB_KEY_CTRL_D: - case TB_KEY_CTRL_C: + case TB_KEY_CTRL_D: + case TB_KEY_CTRL_C: quit = 1; break; - case TB_KEY_CTRL_M: // send message - { - raw_result RawText = markdown_to_raw(0, Input, InputIndex); - - if (RawText.Len == 0) - // do not send empty message - break; - if (fds[FDS_UNI].fd == -1) - // do not send message to disconnected server - break; - - // null terminate - Input[InputIndex] = 0; - InputIndex++; - - // Save header - HeaderMessage* header = ArenaPush(&MessagesArena, sizeof(*header)); - header->version = PROTOCOL_VERSION; - header->type = HEADER_TYPE_TEXT; - header->id = user.ID; - - // Save message - TextMessage* sendmsg = ArenaPush(&MessagesArena, TEXTMESSAGE_SIZE); - sendmsg->timestamp = time(0); - sendmsg->len = InputIndex; - - u32 text_size = InputIndex * sizeof(*Input); - ArenaPush(&MessagesArena, text_size); - memcpy(&sendmsg->text, Input, text_size); - - sendAnyMessage(fds[FDS_UNI].fd, *header, sendmsg); - - MessagesNum++; - // also clear input - } // fallthrough - case TB_KEY_CTRL_U: // clear input + case TB_KEY_CTRL_M: // send message + { + raw_result RawText = markdown_to_raw(0, Input, InputIndex); + + if (RawText.Len == 0) + // do not send empty message + break; + if (fds[FDS_UNI].fd == -1) + // do not send message to disconnected server + break; + + // null terminate + Input[InputIndex] = 0; + InputIndex++; + + // Save header + HeaderMessage* header = ArenaPush(&MessagesArena, sizeof(*header)); + header->version = PROTOCOL_VERSION; + header->type = HEADER_TYPE_TEXT; + header->id = user.ID; + + // Save message + TextMessage* sendmsg = ArenaPush(&MessagesArena, TEXTMESSAGE_SIZE); + sendmsg->timestamp = time(0); + sendmsg->len = InputIndex; + + u32 text_size = InputIndex * sizeof(*Input); + ArenaPush(&MessagesArena, text_size); + memcpy(&sendmsg->text, Input, text_size); + + sendAnyMessage(fds[FDS_UNI].fd, *header, sendmsg); + + MessagesNum++; + // also clear input + } // fallthrough + case TB_KEY_CTRL_U: // clear input bzero(Input, InputIndex * sizeof(*Input)); InputIndex = 0; break; - default: + default: if (ev.ch == 0) break; - + // TODO: show error if (InputIndex == MAX_INPUT_LEN - 1) // last byte reserved for \0 break; - + // append key to input buffer Input[InputIndex] = ev.ch; InputIndex++; @@ -812,23 +812,23 @@ main(int argc, char** argv) if (quit) break; } - + // These are used to redraw the screen from threads if (fds[FDS_RESIZE].revents & POLLIN) { // ignore tb_poll_event(&ev); } - + DisplayChat(&ScratchArena, &MessagesArena, MessagesNum, &ClientsArena, fds, Input, InputIndex); - + tb_present(); } - + tb_shutdown(); - + if (quitmsg != 0) printf("%s\n", quitmsg); - + return 0; } |
