From b5d638bbc939d67cef9c660f936db70af32e79bd Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Tue, 16 Dec 2025 16:40:18 +0200 Subject: [PATCH] ui: server message --- TODO.md | 5 ++++ src/client.c | 4 +-- src/connection.c | 3 ++ src/file_processor.c | 6 ++-- src/main.c | 2 +- src/main.h | 27 +++++++++++------ src/query.c | 29 ++++++++++-------- src/server.c | 48 +++++++++++++++--------------- src/ui/app.c | 23 +++++++++------ src/ui/modals/ask_server_addr.c | 1 + src/ui/modals/server_message.c | 52 +++++++++++++++++++++++++++++++++ src/ui/modals/server_message.h | 9 ++++++ src/ui/widget/dialogue.c | 2 +- 13 files changed, 151 insertions(+), 60 deletions(-) create mode 100644 src/ui/modals/server_message.c create mode 100644 src/ui/modals/server_message.h diff --git a/TODO.md b/TODO.md index 010957e..ed94ff1 100644 --- a/TODO.md +++ b/TODO.md @@ -8,3 +8,8 @@ TODO: - [ ] Group elements as lists - [ ] Process arrows - [ ] active_id -> просто указатель на элемент + +INPUT: +- [ ] hidden text for passwords +- [ ] move cursor through the text in input + diff --git a/src/client.c b/src/client.c index 74db12b..1424ec0 100644 --- a/src/client.c +++ b/src/client.c @@ -10,14 +10,14 @@ int process_client_command(char *line, int l_len, query_args_t *q_args) { /* FILE LIST */ if (!strncmp(line, "file list", sizeof("file list") - 1)) { write(q_args->sd, "file list", sizeof("file list") - 1); - q_args->state = STATE_FILE_LIST; + q_args->state = S_FILE_LIST; return 0; } /* FILE UPLOAD */ if (!strncmp(line, "file upload", sizeof("file upload") - 1)) { if (!file_upload_request(line, q_args)) { - q_args->state = STATE_UPLOAD_REQUESTED; + q_args->state = S_UPLOAD_REQUESTED; } else { print_prompt(q_args->params); q_args->state = WAIT_CLIENT; diff --git a/src/connection.c b/src/connection.c index 18b0223..3895a84 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1,6 +1,7 @@ #include "main.h" #include "ui/app.h" #include +#include #include #include #include @@ -22,6 +23,7 @@ void connect_to_server(app_t *app) { destroy_app(app); exit(2); } + app->params->is_connected = TRUE; } void init_params(params_t *params) { @@ -30,6 +32,7 @@ void init_params(params_t *params) { params->uname = NULL; params->privileges = 0; params->port = htons(SERVER_PORT); + params->is_connected = FALSE; } void clear_params(params_t *params) { diff --git a/src/file_processor.c b/src/file_processor.c index 685dbea..6fc8ea5 100644 --- a/src/file_processor.c +++ b/src/file_processor.c @@ -35,7 +35,7 @@ void file_list(file_args_t *f_args, query_args_t *q_args) { while ((qlen = query_extract_from_buf(q_args->buf, &(q_args->buf_used), &query))) { if (!strcmp("list_end\n", query)) { - q_args->state = STATE_FILE_SELECT; + q_args->state = S_FILE_SELECT; idx = 1; break; } @@ -71,7 +71,7 @@ void file_select(file_args_t *f_args, query_args_t *q_args) { if (!(sscanf(buf, "%u", &filenum))) { write(q_args->sd, buf, strlen(buf)); - q_args->state = STATE_FILE_LIST; + q_args->state = S_FILE_LIST; fl_clear(&f_args->l_start, &f_args->l_current); return; } @@ -111,7 +111,7 @@ void file_select(file_args_t *f_args, query_args_t *q_args) { } qlen = sprintf(send_buf, "file download %s\n", f_selected->name); write(q_args->sd, send_buf, qlen); - q_args->state = STATE_FILE_DOWNLOAD; + q_args->state = S_FILE_DOWNLOAD; free(file_path); } diff --git a/src/main.c b/src/main.c index 8a63bc1..6fa0fa7 100644 --- a/src/main.c +++ b/src/main.c @@ -49,7 +49,7 @@ int main(int argc, char **argv) { app->query_args->state = S_ASK_SEVER_IP; } else { connect_to_server(app); - app->query_args->state = S_ASK_LOGIN_TYPE; + app->query_args->state = S_WAIT_SERVER; } query_loop(app); diff --git a/src/main.h b/src/main.h index 79cfd19..69ca55b 100644 --- a/src/main.h +++ b/src/main.h @@ -11,7 +11,7 @@ #define INBUFSIZE 1024 #define DOWNLOADS_DIR "./Downloads" #define DIALOGUE_TITLE 64 -#define DIALOGUE_TEXT 128 +#define DIALOGUE_TEXT 4096 #define INPUT_TEXT DIALOGUE_TITLE typedef struct params { @@ -21,6 +21,7 @@ typedef struct params { char *pass; char privileges; int32_t sd; + uint32_t is_connected : 1; } params_t; enum state { @@ -28,20 +29,22 @@ enum state { S_ASK_SEVER_IP, S_ASK_LOGIN_TYPE, S_ASK_LOGIN_USER, + S_WAIT_SERVER, + S_PRINT_SERVER_MESSAGE, + S_FILE_LIST, + S_FILE_SELECT, + S_FILE_DOWNLOAD, + S_UPLOAD_PARAMS, + S_UPLOAD_FILE, + S_UPLOAD_REQUESTED, + S_ASK_USER_BEFORE_LOGIN, + S_ERR, WAIT_SERVER_INIT, WAIT_SERVER, WAIT_REGISTER, WAIT_REGISTER_CONFIRMATION, WAIT_CLIENT, UPLOAD_FILE, - STATE_FILE_LIST, - STATE_FILE_SELECT, - STATE_FILE_DOWNLOAD, - STATE_UPLOAD_PARAMS, - STATE_UPLOAD_FILE, - STATE_UPLOAD_REQUESTED, - STATE_ASK_USER_BEFORE_LOGIN, - STATE_ERR, }; typedef struct p_file { @@ -74,6 +77,12 @@ typedef struct query_args { char *buf; char from_server; params_t *params; + char *next_server_command; + struct { + char *text; + uint64_t capacity; + uint64_t size; + } server_message; } query_args_t; #endif \ No newline at end of file diff --git a/src/query.c b/src/query.c index 8bb7c13..a753073 100644 --- a/src/query.c +++ b/src/query.c @@ -49,8 +49,8 @@ void query_loop(app_t *app) { FD_ZERO(&readfds); FD_SET(STDIN_FILENO, &readfds); FD_SET(sd, &readfds); - int maxfd = sd; - if (query_args->state == STATE_UPLOAD_FILE) { + int maxfd = app->params->is_connected ? sd : STDIN_FILENO; + if (query_args->state == S_UPLOAD_FILE) { if (query_args->file != NULL) { FD_SET(query_args->file->fd, &readfds); if (query_args->file->fd > maxfd) @@ -122,35 +122,36 @@ int process_query(query_args_t *query_args, file_args_t *file_args) { case WAIT_SERVER: case WAIT_SERVER_INIT: case WAIT_CLIENT: + case S_WAIT_SERVER: case WAIT_REGISTER_CONFIRMATION: wait_side(query_args); break; case UPLOAD_FILE: - case STATE_ERR: + case S_ERR: break; - case STATE_FILE_LIST: + case S_FILE_LIST: file_list(file_args, query_args); break; - case STATE_FILE_SELECT: + case S_FILE_SELECT: if (query_args->from_server) { wait_side(query_args); } else { file_select(file_args, query_args); } break; - case STATE_FILE_DOWNLOAD: + case S_FILE_DOWNLOAD: file_download(file_args, query_args); break; - case STATE_UPLOAD_REQUESTED: + case S_UPLOAD_REQUESTED: if (!file_upload_start(query_args)) { - query_args->state = STATE_UPLOAD_FILE; + query_args->state = S_UPLOAD_FILE; } else { print_prompt(query_args->params); query_args->state = WAIT_CLIENT; } break; - case STATE_UPLOAD_PARAMS: - case STATE_UPLOAD_FILE: + case S_UPLOAD_PARAMS: + case S_UPLOAD_FILE: if (file_upload(query_args)) { /* upload finishes */ user_request_description(query_args); @@ -158,7 +159,7 @@ int process_query(query_args_t *query_args, file_args_t *file_args) { query_args->state = WAIT_CLIENT; } break; - case STATE_ASK_USER_BEFORE_LOGIN: + case S_ASK_USER_BEFORE_LOGIN: break; case WAIT_REGISTER: wait_register(query_args); @@ -215,7 +216,7 @@ static void wait_side(query_args_t *q_args) { char *query = NULL; if (q_args->state == WAIT_SERVER || q_args->state == WAIT_SERVER_INIT || - q_args->from_server) { + q_args->from_server || q_args->state == S_WAIT_SERVER) { while ((qlen = query_extract_from_buf(q_args->buf, &buf_used, &query))) { process_server_command(query, qlen, q_args); free(query); @@ -238,6 +239,10 @@ void init_query_args(query_args_t *q_args, params_t *params) { q_args->params = params; q_args->file = NULL; q_args->from_server = 0; + q_args->server_message.text = NULL; + q_args->server_message.capacity = 0; + q_args->server_message.size = 0; + q_args->next_server_command = NULL; } void user_request_description(query_args_t *q_args) { diff --git a/src/server.c b/src/server.c index 37bd40a..9f4e73e 100644 --- a/src/server.c +++ b/src/server.c @@ -21,6 +21,7 @@ int process_server_command(char *line, int l_len, query_args_t *q_args) { params_t *params = q_args->params; const char *login_options[] = {"Username", "Anonymous", "Register", NULL}; uint32_t answer; + uint64_t new_capacity; char *cptr = strchr(line, ' '); if (cptr != NULL && cptr > line) @@ -28,27 +29,11 @@ int process_server_command(char *line, int l_len, query_args_t *q_args) { /* LOGIN */ if (!strncmp(line, "login>", ws_pos)) { - // if (params->uname == NULL) { - // fflush(stdout); - // answer = print_ask_list("Select login type:", login_options); - // switch (answer) { - // case 1: - // ask_uname_and_password(q_args->params); - // break; - // case 2: - // params->uname = malloc(sizeof("anonymous")); - // strcpy(params->uname, "anonymous"); - // q_args->state = WAIT_CLIENT; - // break; - // case 3: - // wait_register(q_args); - // return 3; - // default: - // return -1; - // } - // } - // write(q_args->sd, params->uname, strlen(params->uname)); - + if (q_args->server_message.size > 0) { + q_args->state = S_PRINT_SERVER_MESSAGE; + q_args->next_server_command = malloc(l_len + 1); + strcpy(q_args->next_server_command, line); + } return 0; } @@ -99,8 +84,25 @@ int process_server_command(char *line, int l_len, query_args_t *q_args) { return 0; } - if (q_args->state == WAIT_SERVER_INIT) { - write(STDOUT_FILENO, line, l_len); + if (q_args->state == S_WAIT_SERVER) { + if (q_args->server_message.text == NULL) { + q_args->server_message.text = malloc(l_len + 1); + memcpy(q_args->server_message.text, line, l_len); + q_args->server_message.text[l_len] = 0; + q_args->server_message.size = l_len + 1; + q_args->server_message.capacity = l_len + 1; + } else { + if (q_args->server_message.size + l_len > + q_args->server_message.capacity) { + new_capacity = (l_len + q_args->server_message.capacity) * 2; + q_args->server_message.text = + realloc(q_args->server_message.text, new_capacity); + q_args->server_message.capacity = new_capacity; + } + q_args->server_message.size += l_len; + strncat(q_args->server_message.text, line, l_len); + q_args->server_message.text[q_args->server_message.size+l_len] = 0; + } } else { char buf[INBUFSIZE + sizeof("server: ")] = "server: "; strcat(buf, line); diff --git a/src/ui/app.c b/src/ui/app.c index a8752c1..4587580 100644 --- a/src/ui/app.c +++ b/src/ui/app.c @@ -2,6 +2,8 @@ #include "modals/ask_server_addr.h" #include "modals/login_credentials.h" #include "modals/login_option.h" +#include "modals/server_message.h" +// #include "modals/server_message.h" // #include "action.h" #include #include @@ -128,20 +130,24 @@ void app_draw_modal(app_t *app) { case S_ASK_LOGIN_USER: init_login_credentials_modal(app); break; + case S_PRINT_SERVER_MESSAGE: + init_server_message_modal(app); + break; case WAIT_SERVER_INIT: case WAIT_SERVER: case WAIT_REGISTER: case WAIT_REGISTER_CONFIRMATION: case WAIT_CLIENT: case UPLOAD_FILE: - case STATE_FILE_LIST: - case STATE_FILE_SELECT: - case STATE_FILE_DOWNLOAD: - case STATE_UPLOAD_PARAMS: - case STATE_UPLOAD_FILE: - case STATE_UPLOAD_REQUESTED: - case STATE_ASK_USER_BEFORE_LOGIN: - case STATE_ERR: + case S_FILE_LIST: + case S_FILE_SELECT: + case S_FILE_DOWNLOAD: + case S_UPLOAD_PARAMS: + case S_UPLOAD_FILE: + case S_UPLOAD_REQUESTED: + case S_ASK_USER_BEFORE_LOGIN: + case S_ERR: + case S_WAIT_SERVER: case S_N_D: return; } @@ -151,6 +157,5 @@ void app_draw_modal(app_t *app) { void destroy_app(app_t *app) { delwin(app->win); - // free(app); endwin(); } diff --git a/src/ui/modals/ask_server_addr.c b/src/ui/modals/ask_server_addr.c index c5652a0..8c1957a 100644 --- a/src/ui/modals/ask_server_addr.c +++ b/src/ui/modals/ask_server_addr.c @@ -31,6 +31,7 @@ void asa_modal_dialogue_callback(callback_args_t *args) { get_ip_port(app->params, in_ip->value, in_port->value); connect_to_server(app); destroy_dialogue(d); + app->query_args->state = S_WAIT_SERVER; break; case 1: destroy_app(app); diff --git a/src/ui/modals/server_message.c b/src/ui/modals/server_message.c new file mode 100644 index 0000000..2386841 --- /dev/null +++ b/src/ui/modals/server_message.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include "../app.h" +#include "../widget/dialogue.h" +#include "../widget/group.h" + +typedef struct { + button_t *element; + enum w_type type; +} group_bt_t; + +void server_message_modal_cb(callback_args_t *args) { + int32_t response; + callback_args_t d_args; + app_t *app = args->app; + dialogue_t *d = (dialogue_t *)args->widget; + memcpy(&d_args, args, sizeof(callback_args_t)); + d_args.app = NULL; + d_args.resp_data = &response; + dialogue_default_callback(&d_args); + if (response > -1) { + switch (response) { + case 0: + destroy_dialogue(d); + // TODO: macros + free(app->query_args->server_message.text); + app->query_args->server_message.capacity = 0; + app->query_args->server_message.size = 0; + app->query_args->state = S_ASK_LOGIN_USER; + break; + } + } +} + +void *init_server_message_modal(app_t *app) { + if (app == NULL) + return NULL; + group_el_init_t children[] = { + {.type = w_button, .label = "OK", .is_default = 1}, {.type = w_end}}; + + init_dialogue(&(app->modal), "Server response", + app->query_args->server_message.text, &(app->coordinates)); + app->modal.g_action = + init_group(&(app->modal.win), &(app->modal.w), children, horizontal); + app->modal.w.callback = server_message_modal_cb; + dialogue_init_active_id(&(app->modal)); + + return NULL; +} \ No newline at end of file diff --git a/src/ui/modals/server_message.h b/src/ui/modals/server_message.h new file mode 100644 index 0000000..e4abf49 --- /dev/null +++ b/src/ui/modals/server_message.h @@ -0,0 +1,9 @@ +#ifndef SERVER_MESSAGE_H +#define SERVER_MESSAGE_H + +#include "../widget/dialogue.h" +#include "../app.h" + +void *init_server_message_modal(app_t *app); + +#endif \ No newline at end of file diff --git a/src/ui/widget/dialogue.c b/src/ui/widget/dialogue.c index 3f54427..5b73cdb 100644 --- a/src/ui/widget/dialogue.c +++ b/src/ui/widget/dialogue.c @@ -155,7 +155,7 @@ void dialogue_init_active_id(dialogue_t *dialogue) { group->w.m_y = y; \ if (line_max_len < group->w.x) { \ line_max_len = group->w.x; \ - group->w.m_x = 0; /* when uses box */ \ + group->w.m_x = 0; \ } else { \ group->w.m_x = (line_max_len - group->w.x) / 2; \ } \