@@ -71,3 +71,4 @@ build
|
|||||||
Downloads
|
Downloads
|
||||||
|
|
||||||
deps.mk
|
deps.mk
|
||||||
|
src/deps.mk
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
CFLAGS := -ggdb -Wall -pedantic
|
CFLAGS := -ggdb -Wall -pedantic -lcurses
|
||||||
|
|
||||||
SRC_DIR := src
|
SRC_DIR := src
|
||||||
OBJ_DIR := src/obj
|
OBJ_DIR := src/obj
|
||||||
@@ -7,7 +7,19 @@ BIN_DIR := bin
|
|||||||
SRCS := $(wildcard $(SRC_DIR)/*.c)
|
SRCS := $(wildcard $(SRC_DIR)/*.c)
|
||||||
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
||||||
|
|
||||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/main.h
|
UI_SRCS := $(wildcard $(SRC_DIR)/ui/*.c $(SRC_DIR)/ui/**/*.c)
|
||||||
|
OBJS += $(UI_SRCS:$(SRC_DIR)/ui/%.c=$(OBJ_DIR)/ui/%.o)
|
||||||
|
|
||||||
|
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(OBJ_DIR)/ui/%.o: $(SRC_DIR)/ui/%.c $(SRC_DIR)/ui/%.h
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(OBJ_DIR)/ui/widget/%.o: $(SRC_DIR)/ui/widget/%.c $(SRC_DIR)/ui/widget/%.h
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(OBJ_DIR)/ui/modals/%.o: $(SRC_DIR)/ui/modals/%.c $(SRC_DIR)/ui/modals/%.h
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
bbs-client: $(OBJS)
|
bbs-client: $(OBJS)
|
||||||
@@ -21,7 +33,7 @@ deps.mk: $(SRCS)
|
|||||||
$(CC) -MM $^ > $(SRC_DIR)/$@
|
$(CC) -MM $^ > $(SRC_DIR)/$@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJ_DIR)/*.o $(BIN_DIR)/bbs-client
|
rm -f $(OBJ_DIR)/*.o $(OBJ_DIR)/**/*.o $(OBJ_DIR)/ui/**/*.o $(BIN_DIR)/bbs-client
|
||||||
|
|
||||||
run:
|
run:
|
||||||
$(BIN_DIR)/bbs-client
|
$(BIN_DIR)/bbs-client
|
||||||
|
|||||||
@@ -1,2 +1,19 @@
|
|||||||
TODO:
|
TODO:
|
||||||
|
- [x] More universal Makefile
|
||||||
- [ ] Check and fix registration and login
|
- [ ] Check and fix registration and login
|
||||||
|
- [x] UI: destroy child elements everywhere
|
||||||
|
- [x] use parent widgets pointers to count the margins correctly
|
||||||
|
- [ ] Hotkeys for buttons
|
||||||
|
- [ ] Group elements as lists
|
||||||
|
- [x] Process arrows
|
||||||
|
- [x] Optimize modals re-drawings
|
||||||
|
- [x] Bug with file list on downloading files
|
||||||
|
- [x] Remember page numbers
|
||||||
|
- [ ] "Server message" to notification
|
||||||
|
- [ ] file list -> list template
|
||||||
|
|
||||||
|
UPLOAD:
|
||||||
|
- [x] Progress bar
|
||||||
|
- [x] Show notifications and messages from the server (universal way)
|
||||||
|
use notification or something
|
||||||
|
|
||||||
|
|||||||
@@ -2,3 +2,6 @@
|
|||||||
|
|
||||||
mkdir bin
|
mkdir bin
|
||||||
mkdir Downloads
|
mkdir Downloads
|
||||||
|
mkdir src/obj/ui
|
||||||
|
mkdir src/obj/ui/modals
|
||||||
|
mkdir src/obj/ui/widget
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#include "main.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
print_prompt(q_args->params);
|
|
||||||
q_args->state = WAIT_CLIENT;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FILE DOWNLOAD */
|
|
||||||
if (!strncmp(line, "file download", sizeof("file download") - 1)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EXIT */
|
|
||||||
if (!strncmp(line, "exit", sizeof("exit") - 1)) {
|
|
||||||
close(q_args->sd);
|
|
||||||
printf("Bye!\n");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_prompt(params_t *params) {
|
|
||||||
printf("%s> ", params->uname);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef struct {
|
||||||
|
uint32_t cur_y, cur_x;
|
||||||
|
uint32_t max_y, max_x;
|
||||||
|
} coordinates_t;
|
||||||
|
#endif
|
||||||
+14
-17
@@ -1,5 +1,7 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "ui/app.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <ncurses.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -10,15 +12,18 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
void connect_to_server(int sd, params_t *params) {
|
void connect_to_server(app_t *app) {
|
||||||
struct sockaddr_in server;
|
struct sockaddr_in server;
|
||||||
server.sin_family = AF_INET;
|
server.sin_family = AF_INET;
|
||||||
server.sin_addr.s_addr = params->addr;
|
server.sin_addr.s_addr = app->params->addr;
|
||||||
server.sin_port = params->port;
|
server.sin_port = app->params->port;
|
||||||
if (-1 == connect(sd, (struct sockaddr *)&server, sizeof(server))) {
|
if (-1 ==
|
||||||
|
connect(app->params->sd, (struct sockaddr *)&server, sizeof(server))) {
|
||||||
perror("connect");
|
perror("connect");
|
||||||
exit(2);
|
destroy_app(app, 2);
|
||||||
}
|
}
|
||||||
|
app->params->is_connected = TRUE;
|
||||||
|
print_bars(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_params(params_t *params) {
|
void init_params(params_t *params) {
|
||||||
@@ -27,6 +32,7 @@ void init_params(params_t *params) {
|
|||||||
params->uname = NULL;
|
params->uname = NULL;
|
||||||
params->privileges = 0;
|
params->privileges = 0;
|
||||||
params->port = htons(SERVER_PORT);
|
params->port = htons(SERVER_PORT);
|
||||||
|
params->is_connected = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_params(params_t *params) {
|
void clear_params(params_t *params) {
|
||||||
@@ -41,20 +47,11 @@ void clear_params(params_t *params) {
|
|||||||
params->uname = NULL;
|
params->uname = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_missing_params(params_t *params) {
|
void get_ip_port(params_t *params, char *ip, char *port) {
|
||||||
size_t lsize;
|
|
||||||
char *bufptr = NULL;
|
|
||||||
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
inet_aton(ip, &(addr.sin_addr));
|
||||||
if (!params->addr) {
|
|
||||||
printf("host> ");
|
|
||||||
getline(&bufptr, &lsize, stdin);
|
|
||||||
inet_aton(bufptr, &(addr.sin_addr));
|
|
||||||
params->addr = addr.sin_addr.s_addr;
|
params->addr = addr.sin_addr.s_addr;
|
||||||
free(bufptr);
|
params->port = htons(atoi(port));
|
||||||
bufptr = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_session(int sd) { close(sd); }
|
void close_session(int sd) { close(sd); }
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef CONNECTION_H
|
||||||
|
#define CONNECTION_H
|
||||||
|
#include "main.h"
|
||||||
|
#include "ui/app.h"
|
||||||
|
|
||||||
|
void connect_to_server(app_t *params);
|
||||||
|
void init_params(params_t *restrict);
|
||||||
|
void clear_params(params_t *params);
|
||||||
|
void get_ip_port(params_t *params, char *ip, char *port);
|
||||||
|
void close_session(int sd);
|
||||||
|
int init_client();
|
||||||
|
void analyze_args(int argc, char *argv[], params_t *restrict);
|
||||||
|
|
||||||
|
#endif
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
connection.o: src/connection.c src/main.h src/types.h src/ui/app.h \
|
||||||
|
src/ui/../common.h src/ui/widget.h src/ui/../main.h \
|
||||||
|
src/ui/widget/dialogue.h src/ui/widget/../widget.h \
|
||||||
|
src/ui/widget/../../common.h src/ui/widget/button.h \
|
||||||
|
src/ui/widget/../../main.h src/ui/widget/group.h
|
||||||
|
file_processor.o: src/file_processor.c src/file_processor.h src/main.h \
|
||||||
|
src/types.h src/ui/widget/file_list.h src/ui/widget/../widget.h \
|
||||||
|
src/ui/widget/../../main.h src/query.h src/ui/app.h src/ui/../common.h \
|
||||||
|
src/ui/widget.h src/ui/widget/dialogue.h src/ui/widget/../../common.h \
|
||||||
|
src/ui/widget/button.h src/ui/widget/../../main.h src/ui/widget/group.h \
|
||||||
|
src/ui/widget/dialogue.h src/ui/widget/progress_bar.h
|
||||||
|
fs.o: src/fs.c
|
||||||
|
main.o: src/main.c src/connection.h src/main.h src/types.h src/ui/app.h \
|
||||||
|
src/ui/../common.h src/ui/widget.h src/ui/../main.h \
|
||||||
|
src/ui/widget/dialogue.h src/ui/widget/../widget.h \
|
||||||
|
src/ui/widget/../../common.h src/ui/widget/button.h \
|
||||||
|
src/ui/widget/../../main.h src/ui/widget/group.h src/query.h \
|
||||||
|
src/ui/widget.h src/ui/widget/file_list.h
|
||||||
|
query.o: src/query.c src/connection.h src/main.h src/types.h src/ui/app.h \
|
||||||
|
src/ui/../common.h src/ui/widget.h src/ui/../main.h \
|
||||||
|
src/ui/widget/dialogue.h src/ui/widget/../widget.h \
|
||||||
|
src/ui/widget/../../common.h src/ui/widget/button.h \
|
||||||
|
src/ui/widget/../../main.h src/ui/widget/group.h src/file_processor.h \
|
||||||
|
src/ui/widget/file_list.h src/server.h
|
||||||
|
server.o: src/server.c src/main.h src/types.h src/ui/widget/file_list.h \
|
||||||
|
src/ui/widget/../widget.h src/ui/widget/../../main.h
|
||||||
|
|||||||
+138
-46
@@ -1,4 +1,3 @@
|
|||||||
#include "main.h"
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@@ -15,11 +14,16 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static void fl_add(fl_item_t **cur, fl_item_t **start, char *fname);
|
#include "file_processor.h"
|
||||||
static fl_item_t *fl_select(fl_item_t *start, int num);
|
#include "main.h"
|
||||||
static void fl_clear(fl_item_t **start, fl_item_t **current);
|
#include "query.h"
|
||||||
|
#include "ui/widget/dialogue.h"
|
||||||
|
#include "ui/widget/file_list.h"
|
||||||
|
#include "ui/widget/progress_bar.h"
|
||||||
|
|
||||||
static void clear_file_in_query(query_args_t *q_args);
|
static void fl_add(fl_item_t **cur, fl_item_t **start, char *fname);
|
||||||
|
fl_item_t *fl_select(fl_item_t *start, int num);
|
||||||
|
void fl_clear(fl_item_t **start, fl_item_t **current);
|
||||||
|
|
||||||
void file_list(file_args_t *f_args, query_args_t *q_args) {
|
void file_list(file_args_t *f_args, query_args_t *q_args) {
|
||||||
uint32_t qlen;
|
uint32_t qlen;
|
||||||
@@ -27,56 +31,61 @@ void file_list(file_args_t *f_args, query_args_t *q_args) {
|
|||||||
static uint32_t idx = 1;
|
static uint32_t idx = 1;
|
||||||
static char qbuf[INBUFSIZE * 2];
|
static char qbuf[INBUFSIZE * 2];
|
||||||
static uint32_t qbuf_used = 0;
|
static uint32_t qbuf_used = 0;
|
||||||
|
ui_file_list_t *fui = (ui_file_list_t *)q_args->file_list_ui;
|
||||||
|
dialogue_t *d = (dialogue_t *)q_args->active_dialogue;
|
||||||
|
fui->start = &(f_args->l_start);
|
||||||
|
fui->current = &(f_args->l_current);
|
||||||
|
|
||||||
if (qbuf_used == 0) qbuf[0] = 0;
|
if (qbuf_used == 0)
|
||||||
|
qbuf[0] = 0;
|
||||||
|
|
||||||
while ((qlen = query_extract_from_buf(q_args->buf, &(q_args->buf_used),
|
while ((qlen = query_extract_from_buf(q_args->buf, &(q_args->buf_used),
|
||||||
&query))) {
|
&query))) {
|
||||||
if (!strcmp("list_end\n", query)) {
|
if (!strncmp(":END:", query, sizeof(":END:") - 1)) {
|
||||||
q_args->state = STATE_FILE_SELECT;
|
sscanf(query, ":END: PAGE %u/%u COUNT: %u/%u\n", &fui->current_page,
|
||||||
|
&fui->pages, &fui->current_count, &fui->full_count);
|
||||||
idx = 1;
|
idx = 1;
|
||||||
|
if (d != NULL && d->is_initiated) {
|
||||||
|
d->needs_update = true;
|
||||||
|
}
|
||||||
|
draw_file_list(fui);
|
||||||
|
q_args->state = S_FILE_SELECT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
strcat(qbuf, query);
|
strcat(qbuf, query);
|
||||||
qbuf_used += strlen(qbuf);
|
qbuf_used += strlen(qbuf);
|
||||||
if (strchr(qbuf, '\n') == NULL) continue;
|
if (strchr(qbuf, '\n') == NULL)
|
||||||
|
continue;
|
||||||
fl_add(&(f_args->l_current), &(f_args->l_start), qbuf);
|
fl_add(&(f_args->l_current), &(f_args->l_start), qbuf);
|
||||||
printf("[%d] [%s | %s]\n%s\n", idx++, f_args->l_current->name,
|
fui->current_count++;
|
||||||
f_args->l_current->owner, f_args->l_current->description);
|
|
||||||
free(query);
|
free(query);
|
||||||
query = NULL;
|
query = NULL;
|
||||||
qbuf_used = 0;
|
qbuf_used = 0;
|
||||||
qbuf[0] = 0;
|
qbuf[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((qlen = query_extract_from_buf(q_args->buf, &(q_args->buf_used),
|
|
||||||
&query))) {
|
|
||||||
write(STDOUT_FILENO, query, strlen(query));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* file_select: old function, can be removed in the future */
|
||||||
void file_select(file_args_t *f_args, query_args_t *q_args) {
|
void file_select(file_args_t *f_args, query_args_t *q_args) {
|
||||||
char *buf = q_args->buf;
|
char *buf = q_args->buf;
|
||||||
fl_item_t *l_start = f_args->l_start;
|
fl_item_t *l_start = f_args->l_start;
|
||||||
fl_item_t *l_current = f_args->l_current;
|
// fl_item_t *l_current = f_args->l_current;
|
||||||
fl_item_t *l_selected; /* from the list */
|
fl_item_t *l_selected; /* from the list */
|
||||||
fl_item_t *f_selected =
|
fl_item_t *f_selected =
|
||||||
&(f_args->f_selected); /* new copy of file struct (list be cleared) */
|
&(f_args->f_selected); /* new copy of file struct (list be cleared) */
|
||||||
uint32_t filenum;
|
uint32_t filenum;
|
||||||
uint32_t pagenum;
|
|
||||||
uint32_t qlen;
|
uint32_t qlen;
|
||||||
char send_buf[256];
|
char send_buf[256];
|
||||||
struct stat st = {0};
|
struct stat st = {0};
|
||||||
|
|
||||||
if (!(sscanf(buf, "%d", &filenum))) {
|
if (!(sscanf(buf, "%u", &filenum))) {
|
||||||
write(q_args->sd, buf, strlen(buf));
|
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);
|
fl_clear(&f_args->l_start, &f_args->l_current);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filenum == 0) {
|
if (filenum == 0) {
|
||||||
print_prompt(q_args->params);
|
|
||||||
q_args->state = WAIT_CLIENT;
|
q_args->state = WAIT_CLIENT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -103,27 +112,74 @@ void file_select(file_args_t *f_args, query_args_t *q_args) {
|
|||||||
qlen = sprintf(send_buf, "error: %s\n", f_selected->name);
|
qlen = sprintf(send_buf, "error: %s\n", f_selected->name);
|
||||||
write(q_args->sd, send_buf, qlen);
|
write(q_args->sd, send_buf, qlen);
|
||||||
perror(f_selected->name);
|
perror(f_selected->name);
|
||||||
print_prompt(q_args->params);
|
|
||||||
q_args->state = WAIT_CLIENT;
|
q_args->state = WAIT_CLIENT;
|
||||||
free(file_path);
|
free(file_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qlen = sprintf(send_buf, "file download %s\n", f_selected->name);
|
qlen = sprintf(send_buf, "file download %s\n", f_selected->name);
|
||||||
write(q_args->sd, send_buf, qlen);
|
write(q_args->sd, send_buf, qlen);
|
||||||
q_args->state = STATE_FILE_DOWNLOAD;
|
q_args->state = S_FILE_DOWNLOAD;
|
||||||
free(file_path);
|
free(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t ui_file_select(file_args_t *f_args, query_args_t *q_args, int32_t idx) {
|
||||||
|
fl_item_t *l_selected; /* from the list */
|
||||||
|
fl_item_t *f_selected =
|
||||||
|
&(f_args->f_selected); /* new copy of file struct (list be cleared) */
|
||||||
|
uint32_t qlen;
|
||||||
|
char send_buf[256];
|
||||||
|
struct stat st = {0};
|
||||||
|
|
||||||
|
l_selected = fl_select(f_args->l_start, idx);
|
||||||
|
|
||||||
|
if (l_selected == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(f_selected, l_selected, sizeof(fl_item_t));
|
||||||
|
|
||||||
|
if (stat(DOWNLOADS_DIR, &st) == -1) {
|
||||||
|
mkdir(DOWNLOADS_DIR, 0700);
|
||||||
|
}
|
||||||
|
char *file_path = malloc(sizeof(DOWNLOADS_DIR) + strlen(l_selected->name) +
|
||||||
|
2); // + '/' + '\0'
|
||||||
|
f_selected->name = NULL;
|
||||||
|
sprintf(file_path, "%s/%s", DOWNLOADS_DIR, l_selected->name);
|
||||||
|
f_selected->name = strdup(l_selected->name);
|
||||||
|
fl_clear(&f_args->l_start, &f_args->l_current);
|
||||||
|
f_args->file_d = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
if (f_args->file_d == -1) {
|
||||||
|
qlen = sprintf(send_buf, "error: %s\n", f_selected->name);
|
||||||
|
write(q_args->sd, send_buf, qlen);
|
||||||
|
perror(f_selected->name);
|
||||||
|
q_args->state = WAIT_CLIENT;
|
||||||
|
free(file_path);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
qlen = sprintf(send_buf, "file download %s\n", f_selected->name);
|
||||||
|
write(q_args->sd, send_buf, qlen);
|
||||||
|
q_args->state = S_FILE_DOWNLOAD;
|
||||||
|
free(file_path);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
void file_download(file_args_t *f_args, query_args_t *q_args) {
|
void file_download(file_args_t *f_args, query_args_t *q_args) {
|
||||||
fl_item_t *f_selected = &(f_args->f_selected);
|
fl_item_t *f_selected = &(f_args->f_selected);
|
||||||
static uint32_t it_count = 0;
|
static uint32_t it_count = 0;
|
||||||
static size_t it_interval = 0;
|
static size_t it_interval = 0;
|
||||||
if (it_interval == 0) {
|
if (it_interval == 0) {
|
||||||
it_interval = (f_selected->size / INBUFSIZE / 100) * 10; /* every 10% */
|
it_interval = (f_selected->size / INBUFSIZE / 100) * 5; /* every 1% */
|
||||||
if (it_interval == 0)
|
if (it_interval == 0)
|
||||||
it_interval = 1;
|
it_interval = 1;
|
||||||
}
|
}
|
||||||
|
char answer[256];
|
||||||
|
|
||||||
static size_t size_rest = 0;
|
static size_t size_rest = 0;
|
||||||
|
uint32_t progress = (f_selected->size - size_rest) * 100 / f_selected->size;
|
||||||
|
ui_progress_bar_t *pb = (ui_progress_bar_t *)q_args->progress_bar;
|
||||||
|
dialogue_t *d = (dialogue_t *)q_args->active_dialogue;
|
||||||
|
ui_file_list_t *fui = (ui_file_list_t *)q_args->file_list_ui;
|
||||||
|
uint32_t a_len = 0;
|
||||||
|
|
||||||
if (size_rest == 0)
|
if (size_rest == 0)
|
||||||
size_rest = f_selected->size;
|
size_rest = f_selected->size;
|
||||||
@@ -131,10 +187,11 @@ void file_download(file_args_t *f_args, query_args_t *q_args) {
|
|||||||
if (qlen) {
|
if (qlen) {
|
||||||
it_count++;
|
it_count++;
|
||||||
if (!(it_count % it_interval)) {
|
if (!(it_count % it_interval)) {
|
||||||
printf("%zu / %zu\n", f_selected->size - size_rest, f_selected->size);
|
pb->procent = progress;
|
||||||
}
|
d->needs_update = true;
|
||||||
if (it_count % it_interval)
|
} else {
|
||||||
q_args->buf_used = 0;
|
q_args->buf_used = 0;
|
||||||
|
}
|
||||||
if (size_rest < qlen) {
|
if (size_rest < qlen) {
|
||||||
size_rest = 0;
|
size_rest = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -144,15 +201,21 @@ void file_download(file_args_t *f_args, query_args_t *q_args) {
|
|||||||
it_count = 0;
|
it_count = 0;
|
||||||
it_interval = 0;
|
it_interval = 0;
|
||||||
f_selected->size = 0;
|
f_selected->size = 0;
|
||||||
printf("File %s is downloaded\n", f_selected->name);
|
|
||||||
close(f_args->file_d);
|
close(f_args->file_d);
|
||||||
|
d->needs_destroy = true;
|
||||||
|
sprintf(answer, "File %s is downloaded from the server!",
|
||||||
|
f_selected->name);
|
||||||
|
q_args->notification = malloc(strlen(answer) + 1);
|
||||||
|
strcpy(q_args->notification, answer);
|
||||||
free(f_selected->name);
|
free(f_selected->name);
|
||||||
print_prompt(q_args->params);
|
sprintf(answer, "file list %u %u\n%n", fui->max_lines, fui->current_page,
|
||||||
q_args->state = WAIT_CLIENT;
|
&a_len);
|
||||||
|
write(q_args->sd, answer, a_len);
|
||||||
|
q_args->state = S_FILE_LIST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* obsolete */
|
||||||
int32_t file_upload_request(char *query, query_args_t *q_args) {
|
int32_t file_upload_request(char *query, query_args_t *q_args) {
|
||||||
char qbuf[INBUFSIZE];
|
char qbuf[INBUFSIZE];
|
||||||
char fpath[512];
|
char fpath[512];
|
||||||
@@ -183,6 +246,27 @@ int32_t file_upload_request(char *query, query_args_t *q_args) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t file_upload_open(char *dpath, char *fname, query_args_t *q_args) {
|
||||||
|
char a_perm;
|
||||||
|
q_args->file = malloc(sizeof(p_file_t));
|
||||||
|
q_args->file->path = malloc(strlen(dpath) + strlen(fname) + 2);
|
||||||
|
sprintf(q_args->file->path, "%s/%s", dpath, fname);
|
||||||
|
int fd = open(q_args->file->path, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
perror(q_args->file->path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t fsize = lseek(fd, 0, SEEK_END);
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
q_args->file->fd = fd;
|
||||||
|
q_args->file->name = malloc(strlen(fname) + 1);
|
||||||
|
strcpy(q_args->file->name, fname);
|
||||||
|
q_args->file->size = fsize;
|
||||||
|
q_args->file->rest = fsize;
|
||||||
|
q_args->file->description = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t file_upload_start(query_args_t *q_args) {
|
int32_t file_upload_start(query_args_t *q_args) {
|
||||||
char *query;
|
char *query;
|
||||||
query_extract_from_buf(q_args->buf, &(q_args->buf_used), &query);
|
query_extract_from_buf(q_args->buf, &(q_args->buf_used), &query);
|
||||||
@@ -195,35 +279,44 @@ int32_t file_upload_start(query_args_t *q_args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t file_upload(query_args_t *q_args) {
|
int32_t file_upload(query_args_t *q_args) {
|
||||||
/* static size_t it_int = 0;
|
static uint32_t it_count = 0;
|
||||||
static int it_count = 0;
|
static size_t it_interval = 0;
|
||||||
|
if (it_interval == 0) {
|
||||||
if (it_int == 0) {
|
it_interval = (q_args->file->size / INBUFSIZE / 100) * 5; /* every 1% */
|
||||||
it_int = (q_args->file->size / INBUFSIZE / 100) * 10; // every 10%
|
if (it_interval == 0)
|
||||||
} */
|
it_interval = 1;
|
||||||
|
}
|
||||||
|
uint32_t progress =
|
||||||
|
(q_args->file->size - q_args->file->rest) * 100 / q_args->file->size;
|
||||||
|
ui_progress_bar_t *pb = (ui_progress_bar_t *)q_args->progress_bar;
|
||||||
|
dialogue_t *d = (dialogue_t *)q_args->active_dialogue;
|
||||||
if (q_args->buf_used > 0) {
|
if (q_args->buf_used > 0) {
|
||||||
int wlen = write(q_args->sd, q_args->buf, q_args->buf_used);
|
int wlen = write(q_args->sd, q_args->buf, q_args->buf_used);
|
||||||
if (q_args->buf_used != wlen) {
|
if (q_args->buf_used != wlen) {
|
||||||
/* TODO: ошибка */
|
/* TODO: ошибка */
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
it_count++;
|
||||||
|
if (!(it_count % it_interval)) {
|
||||||
|
pb->procent = progress;
|
||||||
|
d->needs_update = true;
|
||||||
|
}
|
||||||
q_args->buf[0] = 0;
|
q_args->buf[0] = 0;
|
||||||
q_args->buf_used = 0;
|
q_args->buf_used = 0;
|
||||||
q_args->file->rest -= wlen;
|
q_args->file->rest -= wlen;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* file upload is finished */
|
it_count = 0;
|
||||||
printf("Upload of %s is finished.\n", q_args->file->name);
|
it_interval = 0;
|
||||||
/* TODO: ждать ответа от сервера */
|
|
||||||
clear_file_in_query(q_args);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_file_in_query(query_args_t *q_args) {
|
void clear_file_in_query(query_args_t *q_args) {
|
||||||
free(q_args->file->name);
|
free(q_args->file->name);
|
||||||
|
free(q_args->file->path);
|
||||||
|
free(q_args->file->description);
|
||||||
free(q_args->file);
|
free(q_args->file);
|
||||||
q_args->file = NULL;
|
q_args->file = NULL;
|
||||||
}
|
}
|
||||||
@@ -240,7 +333,6 @@ void init_file_args(file_args_t *f_args) {
|
|||||||
/* work with file list */
|
/* work with file list */
|
||||||
static void fl_add(fl_item_t **cur, fl_item_t **start, char *line) {
|
static void fl_add(fl_item_t **cur, fl_item_t **start, char *line) {
|
||||||
char fname[128];
|
char fname[128];
|
||||||
size_t fsize;
|
|
||||||
char fowner[32];
|
char fowner[32];
|
||||||
int h_len;
|
int h_len;
|
||||||
fl_item_t *fitem = malloc(sizeof(fl_item_t));
|
fl_item_t *fitem = malloc(sizeof(fl_item_t));
|
||||||
@@ -271,7 +363,7 @@ static void fl_add(fl_item_t **cur, fl_item_t **start, char *line) {
|
|||||||
*cur = fitem;
|
*cur = fitem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fl_item_t *fl_select(fl_item_t *start, int num) {
|
fl_item_t *fl_select(fl_item_t *start, int num) {
|
||||||
fl_item_t *current = start;
|
fl_item_t *current = start;
|
||||||
for (; num != 1; num--) {
|
for (; num != 1; num--) {
|
||||||
if (current->next != NULL) {
|
if (current->next != NULL) {
|
||||||
@@ -283,7 +375,7 @@ static fl_item_t *fl_select(fl_item_t *start, int num) {
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fl_clear(fl_item_t **start, fl_item_t **arg_current) {
|
void fl_clear(fl_item_t **start, fl_item_t **arg_current) {
|
||||||
if (*start == NULL)
|
if (*start == NULL)
|
||||||
return;
|
return;
|
||||||
fl_item_t *next, *current;
|
fl_item_t *next, *current;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef FILE_PROCESSOR_H
|
||||||
|
#define FILE_PROCESSOR_H
|
||||||
|
#include "main.h"
|
||||||
|
#include "ui/widget/file_list.h"
|
||||||
|
|
||||||
|
void file_list(file_args_t *f_args, query_args_t *q_args);
|
||||||
|
void file_download(file_args_t *f_args, query_args_t *q_args);
|
||||||
|
void file_select(file_args_t *fargs, query_args_t *q_args);
|
||||||
|
void init_file_args(file_args_t *fargs);
|
||||||
|
int file_upload_request(char *, query_args_t *q_args);
|
||||||
|
int file_upload_start(query_args_t *q_args);
|
||||||
|
int file_upload(query_args_t *q_args);
|
||||||
|
int32_t file_upload_open(char *dpath, char *fname, query_args_t *q_args);
|
||||||
|
void fl_clear(fl_item_t **start, fl_item_t **arg_current);
|
||||||
|
int32_t ui_file_select(file_args_t *f_args, query_args_t *q_args, int32_t idx);
|
||||||
|
void clear_file_in_query(query_args_t *q_args);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define BYTES_IN_GB 1073741824
|
||||||
|
#define BYTES_IN_MB 1048576
|
||||||
|
#define BYTES_IN_KB 1024
|
||||||
|
|
||||||
|
#define PRINT_SIZE(text, f_arg, s_arg, unit) \
|
||||||
|
s_arg /= 100; \
|
||||||
|
if (s_arg > 0) { \
|
||||||
|
sprintf(text, "%zu,%zu%s", f_arg, s_arg, unit); \
|
||||||
|
} else { \
|
||||||
|
sprintf(text, "%zu%s", f_arg, unit); \
|
||||||
|
}
|
||||||
|
|
||||||
|
void size_to_text(size_t size, char *text) {
|
||||||
|
size_t kb = 0;
|
||||||
|
size_t mb = 0;
|
||||||
|
size_t gb = 0;
|
||||||
|
|
||||||
|
gb = size / BYTES_IN_GB;
|
||||||
|
mb = size / BYTES_IN_MB;
|
||||||
|
kb = size / BYTES_IN_KB;
|
||||||
|
if (gb > 0) {
|
||||||
|
size = size % BYTES_IN_GB;
|
||||||
|
mb = size / BYTES_IN_MB;
|
||||||
|
PRINT_SIZE(text, gb, mb, "GB");
|
||||||
|
} else if (mb > 0) {
|
||||||
|
size = size % BYTES_IN_MB;
|
||||||
|
kb = size / BYTES_IN_KB;
|
||||||
|
PRINT_SIZE(text, mb, kb, "MB");
|
||||||
|
} else if (kb > 0) {
|
||||||
|
size = size % BYTES_IN_KB;
|
||||||
|
PRINT_SIZE(text, kb, size, "KB");
|
||||||
|
} else {
|
||||||
|
sprintf(text, "%zu B", size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef LOC_FS_H
|
||||||
|
#define LOC_FS_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void size_to_text(size_t size, char *text);
|
||||||
|
|
||||||
|
#endif
|
||||||
+70
-9
@@ -1,23 +1,84 @@
|
|||||||
#include "main.h"
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <ncurses.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* TODO: перед загрузкой файла спрашивать права доступа
|
#include "connection.h"
|
||||||
TODO: сделать при интерфес выбора по пунктам меню */
|
#include "main.h"
|
||||||
|
#include "query.h"
|
||||||
|
#include "ui/app.h"
|
||||||
|
#include "ui/widget.h"
|
||||||
|
#include "ui/widget/file_list.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
uint32_t m_id = 0;
|
||||||
|
|
||||||
|
int32_t process_user_input(app_t *app, callback_args_t *d_args);
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
app_t *app;
|
||||||
params_t params;
|
params_t params;
|
||||||
|
query_args_t *q_args = malloc(sizeof(query_args_t));
|
||||||
|
char buf[INBUFSIZE];
|
||||||
|
|
||||||
|
app = calloc(1, sizeof(app_t));
|
||||||
|
|
||||||
|
init_nc();
|
||||||
|
|
||||||
|
app = init_app();
|
||||||
init_params(¶ms);
|
init_params(¶ms);
|
||||||
|
app->params = ¶ms;
|
||||||
analyze_args(argc, argv, ¶ms);
|
analyze_args(argc, argv, ¶ms);
|
||||||
get_missing_params(¶ms);
|
|
||||||
int sd = init_client();
|
wrefresh(app->left_win);
|
||||||
connect_to_server(sd, ¶ms);
|
wrefresh(app->right_win);
|
||||||
query_loop(sd, ¶ms);
|
|
||||||
|
init_query_args(q_args, app->params);
|
||||||
|
q_args->buf = malloc(INBUFSIZE);
|
||||||
|
app->query_args = q_args;
|
||||||
|
q_args->file_list_ui = init_file_list(&(app->left_win), &(app->right_win));
|
||||||
|
|
||||||
|
/* init client to connect to the server */
|
||||||
|
app->params->sd = init_client();
|
||||||
|
|
||||||
|
if (params.addr == 0) {
|
||||||
|
app->query_args->state = S_ASK_SEVER_IP;
|
||||||
|
} else {
|
||||||
|
connect_to_server(app);
|
||||||
|
app->query_args->state = S_WAIT_SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
app->query_args->sd = app->params->sd;
|
||||||
|
|
||||||
|
query_loop(app);
|
||||||
clear_params(¶ms);
|
clear_params(¶ms);
|
||||||
return 0;
|
destroy_app(app, 0);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t process_user_input(app_t *app, callback_args_t *d_args) {
|
||||||
|
int32_t c;
|
||||||
|
c = wgetch(app->win);
|
||||||
|
switch (c) {
|
||||||
|
case KEY_F(9):
|
||||||
|
destroy_app(app, 0);
|
||||||
|
return OK;
|
||||||
|
case 'U':
|
||||||
|
case 'u':
|
||||||
|
if (!app->modal.is_initiated) {
|
||||||
|
app->query_args->state = S_UPLOAD_FILE_SELECT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
d_args->data = (void *)&c;
|
||||||
|
app->active_callback(d_args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
+45
-38
@@ -1,4 +1,8 @@
|
|||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define LOCAL_PORT 1999
|
#define LOCAL_PORT 1999
|
||||||
@@ -6,6 +10,12 @@
|
|||||||
#define LISTEN_QLEN 32
|
#define LISTEN_QLEN 32
|
||||||
#define INBUFSIZE 1024
|
#define INBUFSIZE 1024
|
||||||
#define DOWNLOADS_DIR "./Downloads"
|
#define DOWNLOADS_DIR "./Downloads"
|
||||||
|
#define DIALOGUE_TITLE 64
|
||||||
|
#define DIALOGUE_TEXT 4096
|
||||||
|
#define INPUT_TEXT DIALOGUE_TITLE
|
||||||
|
#ifndef __USE_GNU
|
||||||
|
#define __USE_GNU 1
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct params {
|
typedef struct params {
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
@@ -13,26 +23,38 @@ typedef struct params {
|
|||||||
char *uname;
|
char *uname;
|
||||||
char *pass;
|
char *pass;
|
||||||
char privileges;
|
char privileges;
|
||||||
|
int32_t sd;
|
||||||
|
uint32_t is_connected : 1;
|
||||||
} params_t;
|
} params_t;
|
||||||
|
|
||||||
enum state {
|
enum state {
|
||||||
|
S_N_D,
|
||||||
|
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_FILE_SELECT,
|
||||||
|
S_UPLOAD_REQUESTED,
|
||||||
|
S_ASK_USER_BEFORE_LOGIN,
|
||||||
|
S_ERR,
|
||||||
|
S_NEXT_ACTION,
|
||||||
WAIT_SERVER_INIT,
|
WAIT_SERVER_INIT,
|
||||||
WAIT_SERVER,
|
WAIT_SERVER,
|
||||||
WAIT_REGISTER,
|
WAIT_REGISTER,
|
||||||
WAIT_REGISTER_CONFIRMATION,
|
WAIT_REGISTER_CONFIRMATION,
|
||||||
WAIT_CLIENT,
|
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,
|
|
||||||
ERR,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct p_file {
|
typedef struct p_file {
|
||||||
char *name;
|
char *name;
|
||||||
|
char *path;
|
||||||
|
char *description;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t rest;
|
size_t rest;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -54,38 +76,23 @@ typedef struct file_args {
|
|||||||
} file_args_t;
|
} file_args_t;
|
||||||
|
|
||||||
typedef struct query_args {
|
typedef struct query_args {
|
||||||
int sd;
|
int32_t sd;
|
||||||
int buf_used;
|
int32_t buf_used;
|
||||||
p_file_t *file;
|
p_file_t *file;
|
||||||
enum state state;
|
enum state state;
|
||||||
char *buf;
|
char *buf;
|
||||||
char from_server;
|
uint32_t from_server : 1;
|
||||||
params_t *params;
|
params_t *params;
|
||||||
|
char *next_server_command;
|
||||||
|
struct {
|
||||||
|
char *text;
|
||||||
|
uint64_t capacity;
|
||||||
|
uint64_t size;
|
||||||
|
} server_message;
|
||||||
|
void *file_list_ui; /* TODO: find solution to insert actual type without void pointers */
|
||||||
|
void *progress_bar;
|
||||||
|
void *active_dialogue;
|
||||||
|
char *notification;
|
||||||
} query_args_t;
|
} query_args_t;
|
||||||
|
|
||||||
void init_params(params_t *restrict);
|
#endif
|
||||||
void analyze_args(int argc, char *argv[], params_t *restrict);
|
|
||||||
void get_missing_params(params_t *restrict);
|
|
||||||
void connect_to_server(int sd, params_t *params);
|
|
||||||
int init_client();
|
|
||||||
void close_session(int sd);
|
|
||||||
void wait_register(query_args_t *q_args);
|
|
||||||
int process_query(query_args_t *query_args, file_args_t *file_args);
|
|
||||||
void query_loop(int sd, params_t *);
|
|
||||||
int query_extract_from_buf(char *buf, int *buf_used, char **output_line);
|
|
||||||
int process_client_command(char *line, int l_len, query_args_t *q_args);
|
|
||||||
int process_server_command(char *line, int l_len, query_args_t *q_args);
|
|
||||||
void ask_register(params_t *params, char *email);
|
|
||||||
|
|
||||||
void clear_params(params_t *params);
|
|
||||||
|
|
||||||
/* file processor */
|
|
||||||
void file_list(file_args_t *f_args, query_args_t *q_args);
|
|
||||||
void file_download(file_args_t *f_args, query_args_t *q_args);
|
|
||||||
void file_select(file_args_t *fargs, query_args_t *q_args);
|
|
||||||
void init_file_args(file_args_t *fargs);
|
|
||||||
int file_upload_request(char *, query_args_t *q_args);
|
|
||||||
int file_upload_start(query_args_t *q_args);
|
|
||||||
int file_upload(query_args_t *q_args);
|
|
||||||
|
|
||||||
void print_prompt(params_t *params);
|
|
||||||
+94
-86
@@ -1,8 +1,9 @@
|
|||||||
#include "main.h"
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <ncurses.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -15,82 +16,109 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static void init_query_args(query_args_t *q_args, int sd, char *buf,
|
#include "connection.h"
|
||||||
enum state state, int buf_used, params_t *params);
|
#include "file_processor.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "ui/app.h"
|
||||||
|
|
||||||
static void wait_side(query_args_t *q_args);
|
static void wait_side(query_args_t *q_args);
|
||||||
void user_request_description(query_args_t *q_args);
|
void user_request_description(query_args_t *q_args);
|
||||||
|
int process_query(query_args_t *query_args, file_args_t *file_args);
|
||||||
|
int32_t process_user_input(app_t *app, callback_args_t *d_args);
|
||||||
|
|
||||||
void query_loop(int sd, params_t *params) {
|
void query_loop(app_t *app) {
|
||||||
|
query_args_t *query_args = app->query_args;
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
|
int32_t sd = app->params->sd;
|
||||||
size_t qlen;
|
size_t qlen;
|
||||||
int sr;
|
int sr;
|
||||||
char buf[INBUFSIZE];
|
|
||||||
char *bufs = buf;
|
|
||||||
static file_args_t file_args;
|
static file_args_t file_args;
|
||||||
static query_args_t query_args;
|
callback_args_t d_args = {
|
||||||
|
.app = app, .element = NULL, .data = NULL, .resp_data = NULL};
|
||||||
|
|
||||||
init_query_args(&query_args, sd, buf, WAIT_SERVER_INIT, 0, params);
|
|
||||||
init_file_args(&file_args);
|
init_file_args(&file_args);
|
||||||
|
query_args->sd = sd;
|
||||||
|
app->file_args = &file_args;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
/* update screen */
|
||||||
|
app_draw_modal(app);
|
||||||
|
app_refresh(app);
|
||||||
|
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_SET(STDIN_FILENO, &readfds);
|
FD_SET(STDIN_FILENO, &readfds);
|
||||||
FD_SET(sd, &readfds);
|
FD_SET(sd, &readfds);
|
||||||
int maxfd = sd;
|
int maxfd = app->params->is_connected ? sd : STDIN_FILENO;
|
||||||
if (query_args.state == STATE_UPLOAD_FILE) {
|
if (query_args->state == S_UPLOAD_FILE) {
|
||||||
if (query_args.file != NULL) {
|
if (query_args->file != NULL) {
|
||||||
FD_SET(query_args.file->fd, &readfds);
|
FD_SET(query_args->file->fd, &readfds);
|
||||||
if (query_args.file->fd > maxfd)
|
if (query_args->file->fd > maxfd)
|
||||||
maxfd = query_args.file->fd;
|
maxfd = query_args->file->fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (query_args->state == S_NEXT_ACTION &&
|
||||||
|
query_args->next_server_command != NULL) {
|
||||||
|
query_args->buf_used = strlen(query_args->next_server_command);
|
||||||
|
memcpy(query_args->buf, query_args->next_server_command,
|
||||||
|
query_args->buf_used);
|
||||||
|
free(query_args->next_server_command);
|
||||||
|
query_args->next_server_command = NULL;
|
||||||
|
query_args->from_server = TRUE;
|
||||||
|
if (ERR == process_query(query_args, &file_args)) {
|
||||||
|
close_session(sd);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
sr = select(maxfd + 1, &readfds, NULL, NULL, NULL);
|
sr = select(maxfd + 1, &readfds, NULL, NULL, NULL);
|
||||||
if (sr == -1) {
|
if (sr == -1) {
|
||||||
perror("select");
|
perror("select");
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (FD_ISSET(sd, &readfds)) {
|
if (FD_ISSET(sd, &readfds)) {
|
||||||
/* process request from the server */
|
/* process request from the server */
|
||||||
qlen = read(sd, buf, INBUFSIZE);
|
qlen = read(sd, query_args->buf, INBUFSIZE);
|
||||||
if (qlen == 0) {
|
if (qlen == 0) {
|
||||||
close_session(sd);
|
close_session(sd);
|
||||||
printf("\n*** server closed the connection. ***\n");
|
printf("\n*** server closed the connection. ***\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
query_args.buf_used = qlen;
|
query_args->buf_used = qlen;
|
||||||
query_args.from_server = 1;
|
query_args->from_server = TRUE;
|
||||||
if (-1 == process_query(&query_args, &file_args)) {
|
if (ERR == process_query(query_args, &file_args)) {
|
||||||
close_session(sd);
|
close_session(sd);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query_args.file && query_args.file->fd > -1 &&
|
if (query_args->file && query_args->file->fd > -1 &&
|
||||||
FD_ISSET(query_args.file->fd, &readfds)) {
|
FD_ISSET(query_args->file->fd, &readfds)) {
|
||||||
/* process upload/download */
|
/* process upload/download */
|
||||||
query_args.buf_used = read(query_args.file->fd, buf, INBUFSIZE);
|
query_args->buf_used =
|
||||||
process_query(&query_args, &file_args);
|
read(query_args->file->fd, query_args->buf, INBUFSIZE);
|
||||||
|
process_query(query_args, &file_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(STDIN_FILENO, &readfds)) {
|
if (FD_ISSET(STDIN_FILENO, &readfds)) {
|
||||||
/* process request from the client */
|
/* process request from the client */
|
||||||
qlen = read(STDIN_FILENO, buf, INBUFSIZE);
|
/* qlen = read(STDIN_FILENO, buf, INBUFSIZE); */
|
||||||
if (qlen == 0) {
|
/* if (qlen == 0) {
|
||||||
close_session(sd);
|
close_session(sd);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else { */
|
||||||
query_args.buf_used = qlen;
|
/* query_args->buf_used = qlen;
|
||||||
query_args.from_server = 0;
|
query_args->from_server = 0; */
|
||||||
if (-1 == process_query(&query_args, &file_args)) {
|
// if (-1 == process_query(&query_args, &file_args)) {
|
||||||
|
if (ERR == process_user_input(app, &d_args)) {
|
||||||
close_session(sd);
|
close_session(sd);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait_register(query_args_t *q_args) {
|
void wait_register(query_args_t *q_args) {
|
||||||
@@ -105,52 +133,58 @@ void wait_register(query_args_t *q_args) {
|
|||||||
|
|
||||||
int process_query(query_args_t *query_args, file_args_t *file_args) {
|
int process_query(query_args_t *query_args, file_args_t *file_args) {
|
||||||
query_args->buf[query_args->buf_used] = 0;
|
query_args->buf[query_args->buf_used] = 0;
|
||||||
|
int32_t res = 0;
|
||||||
switch (query_args->state) {
|
switch (query_args->state) {
|
||||||
case WAIT_SERVER:
|
case WAIT_SERVER:
|
||||||
case WAIT_SERVER_INIT:
|
case WAIT_SERVER_INIT:
|
||||||
case WAIT_CLIENT:
|
case WAIT_CLIENT:
|
||||||
|
case S_NEXT_ACTION:
|
||||||
|
case S_WAIT_SERVER:
|
||||||
case WAIT_REGISTER_CONFIRMATION:
|
case WAIT_REGISTER_CONFIRMATION:
|
||||||
wait_side(query_args);
|
wait_side(query_args);
|
||||||
break;
|
break;
|
||||||
case UPLOAD_FILE:
|
case S_ERR:
|
||||||
case ERR:
|
|
||||||
break;
|
break;
|
||||||
case STATE_FILE_LIST:
|
case S_FILE_LIST:
|
||||||
file_list(file_args, query_args);
|
file_list(file_args, query_args);
|
||||||
break;
|
break;
|
||||||
case STATE_FILE_SELECT:
|
case S_FILE_SELECT:
|
||||||
if (query_args->from_server) {
|
if (query_args->from_server) {
|
||||||
wait_side(query_args);
|
wait_side(query_args);
|
||||||
} else {
|
} else {
|
||||||
file_select(file_args, query_args);
|
file_select(file_args, query_args);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STATE_FILE_DOWNLOAD:
|
case S_FILE_DOWNLOAD:
|
||||||
file_download(file_args, query_args);
|
file_download(file_args, query_args);
|
||||||
break;
|
break;
|
||||||
case STATE_UPLOAD_REQUESTED:
|
case S_UPLOAD_REQUESTED:
|
||||||
if (!file_upload_start(query_args)) {
|
if (!file_upload_start(query_args)) {
|
||||||
query_args->state = STATE_UPLOAD_FILE;
|
query_args->state = S_UPLOAD_FILE;
|
||||||
} else {
|
} else {
|
||||||
print_prompt(query_args->params);
|
|
||||||
query_args->state = WAIT_CLIENT;
|
query_args->state = WAIT_CLIENT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STATE_UPLOAD_PARAMS:
|
case S_UPLOAD_PARAMS:
|
||||||
case STATE_UPLOAD_FILE:
|
case S_UPLOAD_FILE:
|
||||||
if (file_upload(query_args)) {
|
if ((res = file_upload(query_args)) == 1) {
|
||||||
/* upload finishes */
|
/* upload finishes */
|
||||||
user_request_description(query_args);
|
user_request_description(query_args);
|
||||||
print_prompt(query_args->params);
|
clear_file_in_query(query_args);
|
||||||
query_args->state = WAIT_CLIENT;
|
query_args->state = S_WAIT_SERVER;
|
||||||
|
} else if (res == -1) {
|
||||||
|
/* TODO: Error */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STATE_ASK_USER_BEFORE_LOGIN:
|
case S_ASK_USER_BEFORE_LOGIN:
|
||||||
break;
|
break;
|
||||||
case WAIT_REGISTER:
|
case WAIT_REGISTER:
|
||||||
wait_register(query_args);
|
wait_register(query_args);
|
||||||
break;
|
break;
|
||||||
|
case S_ASK_SEVER_IP:
|
||||||
|
case S_ASK_LOGIN_TYPE:
|
||||||
|
case S_N_D:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -198,58 +232,32 @@ static void wait_side(query_args_t *q_args) {
|
|||||||
int buf_used = q_args->buf_used;
|
int buf_used = q_args->buf_used;
|
||||||
char *query = NULL;
|
char *query = NULL;
|
||||||
|
|
||||||
if (q_args->state == WAIT_SERVER || q_args->state == WAIT_SERVER_INIT ||
|
|
||||||
q_args->from_server) {
|
|
||||||
while ((qlen = query_extract_from_buf(q_args->buf, &buf_used, &query))) {
|
while ((qlen = query_extract_from_buf(q_args->buf, &buf_used, &query))) {
|
||||||
process_server_command(query, qlen, q_args);
|
process_server_command(query, qlen, q_args);
|
||||||
free(query);
|
free(query);
|
||||||
query = NULL;
|
query = NULL;
|
||||||
}
|
}
|
||||||
} else if (q_args->state == WAIT_CLIENT) {
|
|
||||||
while ((qlen = query_extract_from_buf(q_args->buf, &buf_used, &query))) {
|
|
||||||
process_client_command(query, qlen, q_args);
|
|
||||||
free(query);
|
|
||||||
query = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_query_args(query_args_t *q_args, int sd, char *buf,
|
void init_query_args(query_args_t *q_args, params_t *params) {
|
||||||
enum state state, int buf_used, params_t *params) {
|
q_args->buf = NULL;
|
||||||
q_args->buf = buf;
|
q_args->sd = -1;
|
||||||
q_args->sd = sd;
|
q_args->state = S_N_D;
|
||||||
q_args->state = state;
|
q_args->buf_used = 0;
|
||||||
q_args->buf_used = buf_used;
|
|
||||||
q_args->params = params;
|
q_args->params = params;
|
||||||
q_args->file = NULL;
|
q_args->file = NULL;
|
||||||
q_args->from_server = 0;
|
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;
|
||||||
|
q_args->progress_bar = NULL;
|
||||||
|
q_args->active_dialogue = NULL;
|
||||||
|
q_args->notification = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void user_request_description(query_args_t *q_args) {
|
void user_request_description(query_args_t *q_args) {
|
||||||
printf("File description > ");
|
strcat(q_args->file->description, "\n\n:END:\n");
|
||||||
fflush(stdout);
|
write(q_args->sd, q_args->file->description,
|
||||||
char buf[INBUFSIZE]; /* пока ограничение на буфер */
|
strlen(q_args->file->description) - 1);
|
||||||
char *line_buf = NULL;
|
|
||||||
int blen = 0;
|
|
||||||
int line_len = 0;
|
|
||||||
size_t ll;
|
|
||||||
while (blen < INBUFSIZE - 6) { /* reserve space for ":END:\n" */
|
|
||||||
line_len = getline(&line_buf, &ll, stdin);
|
|
||||||
if (line_len == 1) {
|
|
||||||
/* free(line); -> не работает */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (blen == 0) {
|
|
||||||
strcpy(buf, line_buf);
|
|
||||||
} else {
|
|
||||||
strcat(buf, line_buf);
|
|
||||||
}
|
|
||||||
free(line_buf);
|
|
||||||
line_buf = NULL;
|
|
||||||
blen += line_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcat(buf, ":END:\n");
|
|
||||||
blen += 6;
|
|
||||||
write(q_args->sd, buf, blen);
|
|
||||||
}
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef QUERY_H
|
||||||
|
#define QUERY_H
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "ui/app.h"
|
||||||
|
|
||||||
|
void query_loop(app_t *);
|
||||||
|
void wait_register(query_args_t *q_args);
|
||||||
|
int process_query(query_args_t *query_args, file_args_t *file_args);
|
||||||
|
int query_extract_from_buf(char *buf, int *buf_used, char **output_line);
|
||||||
|
void init_query_args(query_args_t *q_args, params_t *params);
|
||||||
|
|
||||||
|
#endif
|
||||||
+52
-35
@@ -1,5 +1,5 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "ui.h"
|
#include "ui/widget/file_list.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@@ -15,12 +15,23 @@
|
|||||||
void ask_uname_and_password(params_t *params);
|
void ask_uname_and_password(params_t *params);
|
||||||
void ask_register(params_t *params, char *email);
|
void ask_register(params_t *params, char *email);
|
||||||
|
|
||||||
|
#define PRINT_SRV_MESSAGE(q_args, l_len, line) \
|
||||||
|
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; \
|
||||||
|
}
|
||||||
|
|
||||||
int process_server_command(char *line, int l_len, query_args_t *q_args) {
|
int process_server_command(char *line, int l_len, query_args_t *q_args) {
|
||||||
int ws_pos = l_len;
|
int ws_pos = l_len;
|
||||||
params_t *params = q_args->params;
|
params_t *params = q_args->params;
|
||||||
const char *login_options[] = {"Username", "Anonymous", "Register", NULL};
|
const char *login_options[] = {"Username", "Anonymous", "Register", NULL};
|
||||||
char r_buf[INBUFSIZE];
|
|
||||||
uint32_t answer;
|
uint32_t answer;
|
||||||
|
uint64_t new_capacity;
|
||||||
|
ui_file_list_t *fui = (ui_file_list_t *)q_args->file_list_ui;
|
||||||
|
char query[INBUFSIZE];
|
||||||
|
int32_t q_len = 0;
|
||||||
|
|
||||||
char *cptr = strchr(line, ' ');
|
char *cptr = strchr(line, ' ');
|
||||||
if (cptr != NULL && cptr > line)
|
if (cptr != NULL && cptr > line)
|
||||||
@@ -28,27 +39,14 @@ int process_server_command(char *line, int l_len, query_args_t *q_args) {
|
|||||||
|
|
||||||
/* LOGIN */
|
/* LOGIN */
|
||||||
if (!strncmp(line, "login>", ws_pos)) {
|
if (!strncmp(line, "login>", ws_pos)) {
|
||||||
if (params->uname == NULL) {
|
if (q_args->server_message.size > 0) {
|
||||||
fflush(stdout);
|
PRINT_SRV_MESSAGE(q_args, l_len, line);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
if (q_args->params->uname != NULL && q_args->params->pass != NULL) {
|
||||||
|
write(params->sd, q_args->params->uname, strlen(q_args->params->uname));
|
||||||
|
} else {
|
||||||
|
q_args->state = S_ASK_LOGIN_TYPE;
|
||||||
}
|
}
|
||||||
write(q_args->sd, params->uname, strlen(params->uname));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +65,7 @@ int process_server_command(char *line, int l_len, query_args_t *q_args) {
|
|||||||
free(params->pass);
|
free(params->pass);
|
||||||
params->uname = NULL;
|
params->uname = NULL;
|
||||||
params->pass = NULL;
|
params->pass = NULL;
|
||||||
get_missing_params(params);
|
// get_missing_params(params);
|
||||||
write(q_args->sd, params->uname, strlen(params->uname));
|
write(q_args->sd, params->uname, strlen(params->uname));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -75,9 +73,10 @@ int process_server_command(char *line, int l_len, query_args_t *q_args) {
|
|||||||
/* REGISTER CONFIRMATION */
|
/* REGISTER CONFIRMATION */
|
||||||
if (q_args->state == WAIT_REGISTER_CONFIRMATION) {
|
if (q_args->state == WAIT_REGISTER_CONFIRMATION) {
|
||||||
if (!strcmp(line, "ok")) {
|
if (!strcmp(line, "ok")) {
|
||||||
printf("Welcome, %s\n", q_args->params->uname);
|
sprintf(query, "file list %u %u\n%n", fui->max_lines, fui->current_page,
|
||||||
print_prompt(q_args->params);
|
&q_len);
|
||||||
q_args->state = WAIT_CLIENT;
|
write(q_args->sd, query, q_len);
|
||||||
|
q_args->state = S_FILE_LIST;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
write(STDOUT_FILENO, line, strlen(line));
|
write(STDOUT_FILENO, line, strlen(line));
|
||||||
@@ -93,20 +92,38 @@ int process_server_command(char *line, int l_len, query_args_t *q_args) {
|
|||||||
|
|
||||||
/* WELCOME MES */
|
/* WELCOME MES */
|
||||||
if (!strncmp(line, "Welcome, ", ws_pos)) {
|
if (!strncmp(line, "Welcome, ", ws_pos)) {
|
||||||
printf("%s\n", line);
|
sprintf(query, "file list %u %u\n%n", fui->max_lines, fui->current_page,
|
||||||
print_prompt(q_args->params);
|
&q_len);
|
||||||
q_args->state = WAIT_CLIENT;
|
write(q_args->sd, query, q_len);
|
||||||
|
q_args->state = S_FILE_LIST;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q_args->state == WAIT_SERVER_INIT) {
|
if (q_args->state == S_WAIT_SERVER) {
|
||||||
write(STDOUT_FILENO, line, l_len);
|
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 {
|
} else {
|
||||||
char buf[INBUFSIZE + sizeof("server: ")] = "server: ";
|
if (q_args->server_message.size + l_len >
|
||||||
strcat(buf, line);
|
q_args->server_message.capacity) {
|
||||||
write(STDOUT_FILENO, buf, l_len + sizeof("server: "));
|
new_capacity = (l_len + q_args->server_message.capacity) * 2;
|
||||||
if (q_args->state == WAIT_CLIENT) {
|
q_args->server_message.text =
|
||||||
print_prompt(q_args->params);
|
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;
|
||||||
|
}
|
||||||
|
char *end_char = strchr(q_args->server_message.text,
|
||||||
|
'\04'); /* Search for the end of the notification */
|
||||||
|
if (end_char != NULL) {
|
||||||
|
*end_char = '\0'; /* Don't show this symbol */
|
||||||
|
q_args->state = S_PRINT_SERVER_MESSAGE;
|
||||||
|
q_args->server_message.size--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef SERVER_H
|
||||||
|
#define SERVER_H
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
int process_server_command(char *line, int l_len, query_args_t *q_args);
|
||||||
|
void ask_register(params_t *params, char *email);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
uint32_t print_ask_list(char title[], const char *options[]) {
|
|
||||||
char *option;
|
|
||||||
char c;
|
|
||||||
uint32_t i, answer;
|
|
||||||
|
|
||||||
printf("%s\n", title);
|
|
||||||
|
|
||||||
for (i = 0; options[i] != NULL; i++) {
|
|
||||||
printf("[%u] %s\n", i + 1, options[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
write(STDOUT_FILENO, "> ", sizeof "> ");
|
|
||||||
|
|
||||||
while (!scanf("%u", &answer) || answer > i) {
|
|
||||||
printf("Input format is not correct! You need to specify between 1 and "
|
|
||||||
"%u\n > ",
|
|
||||||
i);
|
|
||||||
}
|
|
||||||
while ((c = getchar()) != '\n' && c != EOF);
|
|
||||||
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
uint32_t print_ask_list(char *title, const char *options[]);
|
|
||||||
+203
@@ -0,0 +1,203 @@
|
|||||||
|
#include "app.h"
|
||||||
|
#include "modals/ask_server_addr.h"
|
||||||
|
#include "modals/download_pr.h"
|
||||||
|
#include "modals/login_credentials.h"
|
||||||
|
#include "modals/login_option.h"
|
||||||
|
#include "modals/notification.h"
|
||||||
|
#include "modals/server_message.h"
|
||||||
|
#include "modals/upload_dialogue.h"
|
||||||
|
#include "modals/upload_props_dialogue.h"
|
||||||
|
#include "widget/dialogue.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void ac_file(WINDOW *win, int is_action_w);
|
||||||
|
|
||||||
|
app_t *init_app() {
|
||||||
|
/* get values from terminal size */
|
||||||
|
int32_t y_max, x_max;
|
||||||
|
getmaxyx(stdscr, y_max, x_max);
|
||||||
|
|
||||||
|
/* allocate app struct memory */
|
||||||
|
app_t *_app = calloc(1, sizeof(app_t));
|
||||||
|
|
||||||
|
/* associate values for screen size */
|
||||||
|
_app->coordinates.max_x = _app->coordinates.cur_x = x_max;
|
||||||
|
_app->coordinates.max_y = _app->coordinates.cur_y = y_max;
|
||||||
|
|
||||||
|
_app->win = newwin(_app->coordinates.cur_y, _app->coordinates.cur_x, 0, 0);
|
||||||
|
|
||||||
|
/* define the width for each sub window */
|
||||||
|
int32_t left_w_x = x_max / 10 * 4;
|
||||||
|
int32_t right_w_x = x_max - left_w_x - 2;
|
||||||
|
|
||||||
|
/* create the menu window */
|
||||||
|
_app->left_win = newwin(y_max - 4, left_w_x, 2, 1);
|
||||||
|
|
||||||
|
/* create the action window */
|
||||||
|
_app->right_win = newwin(y_max - 4, right_w_x, 2, left_w_x + 1);
|
||||||
|
|
||||||
|
/* dialogue */
|
||||||
|
_app->modal.win = NULL;
|
||||||
|
_app->modal.is_initiated = 0;
|
||||||
|
|
||||||
|
/* default win */
|
||||||
|
_app->active_win_type = aw_left;
|
||||||
|
|
||||||
|
/* print decorative bars */
|
||||||
|
print_bars(_app);
|
||||||
|
|
||||||
|
/* here goes box borders */
|
||||||
|
draw_borders(_app);
|
||||||
|
|
||||||
|
keypad(_app->win, TRUE);
|
||||||
|
|
||||||
|
/* refresh the windows */
|
||||||
|
wnoutrefresh(_app->win);
|
||||||
|
wnoutrefresh(_app->left_win);
|
||||||
|
wnoutrefresh(_app->right_win);
|
||||||
|
doupdate();
|
||||||
|
|
||||||
|
return _app;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_nc() {
|
||||||
|
initscr();
|
||||||
|
cbreak();
|
||||||
|
keypad(stdscr, TRUE);
|
||||||
|
noecho();
|
||||||
|
curs_set(false);
|
||||||
|
set_escdelay(50);
|
||||||
|
|
||||||
|
if (!has_colors()) {
|
||||||
|
printf("Your terminal does not support color\n");
|
||||||
|
} else {
|
||||||
|
start_color();
|
||||||
|
init_pair(1, COLOR_RED, COLOR_BLACK);
|
||||||
|
init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
||||||
|
init_pair(modal_color_pair, COLOR_BLUE, COLOR_WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_borders(app_t *app) {
|
||||||
|
if (app->modal.win != NULL && !app->modal.needs_update) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
box(app->win, 0, 0);
|
||||||
|
box(app->left_win, 0, 0);
|
||||||
|
box(app->right_win, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_bars(app_t *app) {
|
||||||
|
char top_text[64] = "Hello!";
|
||||||
|
|
||||||
|
wattrset(app->win, A_REVERSE);
|
||||||
|
|
||||||
|
/* print top and bottom bars */
|
||||||
|
for (int i = 1; i < app->coordinates.cur_x - 1; i++) {
|
||||||
|
mvwprintw(app->win, 1, i, " ");
|
||||||
|
mvwprintw(app->win, app->coordinates.cur_y - 2, i, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add content to the top bar */
|
||||||
|
if (app->params && app->params->is_connected) {
|
||||||
|
uint32_t ip_address = app->params->addr;
|
||||||
|
u_char ip_addr[4];
|
||||||
|
mempcpy(ip_addr, &ip_address, 4);
|
||||||
|
sprintf(top_text, "Connected to %u.%u.%u.%u, user: %s", ip_addr[0],
|
||||||
|
ip_addr[1], ip_addr[2], ip_addr[3], app->params->uname);
|
||||||
|
}
|
||||||
|
mvwprintw(app->win, 1, 2, "%s", top_text);
|
||||||
|
|
||||||
|
/* add content to the bottom bar */
|
||||||
|
mvwprintw(app->win, app->coordinates.cur_y - 2, 2,
|
||||||
|
"F1 - Help | U - upload | F9 - Quit");
|
||||||
|
|
||||||
|
wattroff(app->win, A_REVERSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_refresh(app_t *app) {
|
||||||
|
draw_borders(app);
|
||||||
|
|
||||||
|
wnoutrefresh(app->win);
|
||||||
|
wnoutrefresh(app->left_win);
|
||||||
|
wnoutrefresh(app->right_win);
|
||||||
|
if (app->modal.win != NULL) {
|
||||||
|
if (app->modal.is_initiated != 0) {
|
||||||
|
wnoutrefresh(app->modal.win);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doupdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_draw_modal(app_t *app) {
|
||||||
|
if (app->modal.needs_destroy ||
|
||||||
|
(app->query_args->state == S_WAIT_SERVER && app->modal.is_initiated)) {
|
||||||
|
destroy_dialogue(&(app->modal), app);
|
||||||
|
}
|
||||||
|
if (!app->modal.is_initiated) {
|
||||||
|
switch (app->query_args->state) {
|
||||||
|
case S_ASK_SEVER_IP:
|
||||||
|
init_asa_modal(app);
|
||||||
|
break;
|
||||||
|
case S_ASK_LOGIN_TYPE:
|
||||||
|
init_login_option_modal(app);
|
||||||
|
break;
|
||||||
|
case S_ASK_LOGIN_USER:
|
||||||
|
init_login_credentials_modal(app);
|
||||||
|
break;
|
||||||
|
case S_PRINT_SERVER_MESSAGE:
|
||||||
|
init_server_message_modal(app);
|
||||||
|
break;
|
||||||
|
case S_FILE_DOWNLOAD:
|
||||||
|
init_dwn_pr_modal(app, false);
|
||||||
|
break;
|
||||||
|
case S_UPLOAD_FILE:
|
||||||
|
init_dwn_pr_modal(app, true);
|
||||||
|
break;
|
||||||
|
case S_UPLOAD_FILE_SELECT:
|
||||||
|
init_upload_dialogue_modal(app);
|
||||||
|
break;
|
||||||
|
case S_UPLOAD_PARAMS:
|
||||||
|
init_upload_props_dialogue_modal(app);
|
||||||
|
break;
|
||||||
|
case WAIT_SERVER_INIT:
|
||||||
|
case WAIT_SERVER:
|
||||||
|
case WAIT_REGISTER:
|
||||||
|
case WAIT_REGISTER_CONFIRMATION:
|
||||||
|
case WAIT_CLIENT:
|
||||||
|
case S_FILE_LIST:
|
||||||
|
case S_FILE_SELECT:
|
||||||
|
case S_UPLOAD_REQUESTED:
|
||||||
|
case S_ASK_USER_BEFORE_LOGIN:
|
||||||
|
case S_ERR:
|
||||||
|
case S_WAIT_SERVER:
|
||||||
|
case S_N_D:
|
||||||
|
case S_NEXT_ACTION:
|
||||||
|
if (app->query_args->notification != NULL) {
|
||||||
|
init_notification_modal(app);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app->active_callback = app->modal.w.callback;
|
||||||
|
app->active_win = app->modal.win;
|
||||||
|
app->active_win_type = aw_modal;
|
||||||
|
app->active_widget = &(app->modal);
|
||||||
|
}
|
||||||
|
draw_dialogue(&(app->modal));
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_app(app_t *app, int32_t exit_code) {
|
||||||
|
delwin(app->win);
|
||||||
|
endwin();
|
||||||
|
app->win = NULL;
|
||||||
|
exit(exit_code);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef N_APP_H
|
||||||
|
#define N_APP_H
|
||||||
|
|
||||||
|
#include "../common.h"
|
||||||
|
#include "widget.h"
|
||||||
|
#include "widget/dialogue.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
modal_color_pair = 3,
|
||||||
|
modal_border_color_pair = 4,
|
||||||
|
} color;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
aw_left,
|
||||||
|
aw_right,
|
||||||
|
aw_modal
|
||||||
|
} active_win_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
WINDOW *win;
|
||||||
|
WINDOW *left_win;
|
||||||
|
WINDOW *right_win;
|
||||||
|
dialogue_t modal;
|
||||||
|
params_t *params;
|
||||||
|
coordinates_t coordinates;
|
||||||
|
query_args_t *query_args;
|
||||||
|
file_args_t *file_args;
|
||||||
|
int32_t read_fd;
|
||||||
|
active_win_t active_win_type;
|
||||||
|
void (*active_callback)(callback_args_t *args);
|
||||||
|
WINDOW *active_win;
|
||||||
|
void *active_widget;
|
||||||
|
} app_t;
|
||||||
|
|
||||||
|
app_t *init_app();
|
||||||
|
void init_nc();
|
||||||
|
void destroy_app(app_t *app, int32_t exit_code);
|
||||||
|
void draw_borders(app_t *app);
|
||||||
|
void print_bars(app_t *app);
|
||||||
|
void app_refresh(app_t *app);
|
||||||
|
void app_draw_modal(app_t *app);
|
||||||
|
|
||||||
|
#endif // N_APP_H
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
#include "../../connection.h"
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../widget/group.h"
|
||||||
|
#include "../widget/input.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
button_t *element;
|
||||||
|
enum w_type type;
|
||||||
|
} group_bt_t;
|
||||||
|
|
||||||
|
void asa_modal_dialogue_callback(callback_args_t *args) {
|
||||||
|
int32_t response;
|
||||||
|
callback_args_t d_args;
|
||||||
|
app_t *app = args->app;
|
||||||
|
dialogue_t *d = (dialogue_t *)app->active_widget;
|
||||||
|
memcpy(&d_args, args, sizeof(callback_args_t));
|
||||||
|
d_args.app = NULL;
|
||||||
|
d_args.resp_data = &response;
|
||||||
|
d_args.element = app->active_widget;
|
||||||
|
input_t *in_ip = d->g_content->elements[0].element;
|
||||||
|
input_t *in_port = d->g_content->elements[1].element;
|
||||||
|
dialogue_default_callback(&d_args);
|
||||||
|
if (response > -1) {
|
||||||
|
switch (response) {
|
||||||
|
case 0:
|
||||||
|
get_ip_port(app->params, in_ip->value, in_port->value);
|
||||||
|
connect_to_server(app);
|
||||||
|
d->needs_destroy = true;
|
||||||
|
app->query_args->state = S_WAIT_SERVER;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
destroy_app(app, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogue_t *init_asa_modal(app_t *app) {
|
||||||
|
if (app == NULL)
|
||||||
|
return NULL;
|
||||||
|
group_el_init_t content[] = {
|
||||||
|
{.type = w_input, .label = "Address", .length = 15},
|
||||||
|
{.type = w_input, .label = "Port", .length = 5},
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
group_el_init_t actions[] = {
|
||||||
|
{.type = w_button, .label = "Connect", .is_default = 1},
|
||||||
|
{.type = w_button, .label = "Cancel", .is_default = 0},
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
init_dialogue(&(app->modal), "Connect to server",
|
||||||
|
"There is information needed", &(app->coordinates));
|
||||||
|
dialogue_t *d = &(app->modal);
|
||||||
|
|
||||||
|
d->w.callback = asa_modal_dialogue_callback;
|
||||||
|
d->g_content = init_group(&(d->win), &(d->w), content, horizontal);
|
||||||
|
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal);
|
||||||
|
|
||||||
|
dialogue_init_active_id(d);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef ASK_SERVER_ADDR_H
|
||||||
|
#define ASK_SERVER_ADDR_H
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
|
||||||
|
dialogue_t *init_asa_modal(app_t *app);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../widget/group.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void dwn_pr_modal_cb(callback_args_t *args) {}
|
||||||
|
|
||||||
|
dialogue_t *init_dwn_pr_modal(app_t *app, bool is_upload) {
|
||||||
|
if (app == NULL)
|
||||||
|
return NULL;
|
||||||
|
group_el_init_t content[] = {
|
||||||
|
{.type = w_progress, .label = "", .length = 30}, /* length is ignored */
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
char text[256];
|
||||||
|
sprintf(text, "%s file: %s", is_upload ? "Uploading" : "Downloading",
|
||||||
|
is_upload ? app->query_args->file->name : app->file_args->f_selected.name);
|
||||||
|
group_el_init_t actions[] = {
|
||||||
|
{.type = w_button, .label = "Cancel", .is_default = 1}, {.type = w_end}};
|
||||||
|
|
||||||
|
app->modal.w.parent_win = &app->win;
|
||||||
|
init_dialogue(&(app->modal), is_upload ? "Upload" : "Download", text,
|
||||||
|
&(app->coordinates));
|
||||||
|
dialogue_t *d = &(app->modal);
|
||||||
|
|
||||||
|
d->w.callback = dwn_pr_modal_cb;
|
||||||
|
d->g_content = init_group(&(d->win), &(d->w), content, horizontal);
|
||||||
|
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal);
|
||||||
|
|
||||||
|
app->query_args->progress_bar = d->g_content->elements[0].element;
|
||||||
|
app->query_args->active_dialogue = d;
|
||||||
|
|
||||||
|
dialogue_init_active_id(d);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef DOWNLOAD_PR_H
|
||||||
|
#define DOWNLOAD_PR_H
|
||||||
|
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../app.h"
|
||||||
|
|
||||||
|
dialogue_t *init_dwn_pr_modal(app_t *app, bool is_upload);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../widget/group.h"
|
||||||
|
#include "../widget/input.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
button_t *element;
|
||||||
|
enum w_type type;
|
||||||
|
} group_bt_t;
|
||||||
|
|
||||||
|
void init_login_credentials_modal_cb(callback_args_t *args) {
|
||||||
|
int32_t response;
|
||||||
|
callback_args_t d_args;
|
||||||
|
app_t *app = args->app;
|
||||||
|
dialogue_t *d = (dialogue_t *)app->active_widget;
|
||||||
|
memcpy(&d_args, args, sizeof(callback_args_t));
|
||||||
|
d_args.app = NULL;
|
||||||
|
d_args.resp_data = &response;
|
||||||
|
d_args.element = app->active_widget;
|
||||||
|
input_t *in_name = d->g_content->elements[0].element;
|
||||||
|
input_t *in_pass = d->g_content->elements[1].element;
|
||||||
|
dialogue_default_callback(&d_args);
|
||||||
|
if (response > -1) {
|
||||||
|
switch (response) {
|
||||||
|
case 0:
|
||||||
|
app->params->uname = malloc(in_name->value_len + 1);
|
||||||
|
app->params->pass = malloc(in_pass->value_len + 1);
|
||||||
|
strncpy(app->params->uname, in_name->value, in_name->value_len);
|
||||||
|
app->params->uname[in_name->value_len] = 0;
|
||||||
|
strncpy(app->params->pass, in_pass->value, in_pass->value_len);
|
||||||
|
app->params->pass[in_pass->value_len] = 0;
|
||||||
|
write(app->params->sd, app->params->uname, in_name->value_len);
|
||||||
|
app->query_args->state = S_WAIT_SERVER;
|
||||||
|
d->needs_destroy = true;
|
||||||
|
print_bars(app);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
destroy_app(app, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogue_t *init_login_credentials_modal(app_t *app) {
|
||||||
|
if (app == NULL)
|
||||||
|
return NULL;
|
||||||
|
group_el_init_t content[] = {
|
||||||
|
{.type = w_input, .label = "Username", .length = 15},
|
||||||
|
{.type = w_input,
|
||||||
|
.label = "Password",
|
||||||
|
.length = 15,
|
||||||
|
.is_hidden_value = true},
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
group_el_init_t actions[] = {
|
||||||
|
{.type = w_button, .label = "Login", .is_default = true},
|
||||||
|
{.type = w_button, .label = "Cancel", .is_default = false},
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
init_dialogue(&(app->modal), "Credentials", "There is information needed",
|
||||||
|
&(app->coordinates));
|
||||||
|
dialogue_t *d = &(app->modal);
|
||||||
|
|
||||||
|
d->w.callback = init_login_credentials_modal_cb;
|
||||||
|
d->g_content = init_group(&(d->win), &(d->w), content, horizontal);
|
||||||
|
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal);
|
||||||
|
|
||||||
|
dialogue_init_active_id(d);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef LOGIN_CREDENTIALS_MODAL_H
|
||||||
|
#define LOGIN_CREDENTIALS_MODAL_H
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
|
||||||
|
dialogue_t *init_login_credentials_modal(app_t *app);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../widget/group.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
button_t *element;
|
||||||
|
enum w_type type;
|
||||||
|
} group_bt_t;
|
||||||
|
|
||||||
|
void login_modal_option_cb(callback_args_t *args) {
|
||||||
|
int32_t response;
|
||||||
|
callback_args_t d_args;
|
||||||
|
app_t *app = args->app;
|
||||||
|
dialogue_t *d = (dialogue_t *)app->active_widget;
|
||||||
|
memcpy(&d_args, args, sizeof(callback_args_t));
|
||||||
|
d_args.app = NULL;
|
||||||
|
d_args.resp_data = &response;
|
||||||
|
d_args.element = app->active_widget;
|
||||||
|
dialogue_default_callback(&d_args);
|
||||||
|
if (response > -1) {
|
||||||
|
switch (response) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
d->needs_destroy = true;
|
||||||
|
app->query_args->state = S_ASK_LOGIN_USER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogue_t *init_login_option_modal(app_t *app) {
|
||||||
|
if (app == NULL)
|
||||||
|
return NULL;
|
||||||
|
group_el_init_t children[] = {{.type = w_button, .label = "Anonymous"},
|
||||||
|
{.type = w_button, .label = "User"},
|
||||||
|
{.type = w_button, .label = "Register"},
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
init_dialogue(&(app->modal), "Login",
|
||||||
|
"Select your login "
|
||||||
|
"option",
|
||||||
|
&(app->coordinates));
|
||||||
|
app->modal.g_action =
|
||||||
|
init_group(&(app->modal.win), &(app->modal.w), children,
|
||||||
|
horizontal);
|
||||||
|
app->modal.w.callback = login_modal_option_cb;
|
||||||
|
dialogue_init_active_id(&(app->modal));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef LOGIN_OPTION_MODAL_H
|
||||||
|
#define LOGIN_OPTION_MODAL_H
|
||||||
|
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../app.h"
|
||||||
|
|
||||||
|
dialogue_t *init_login_option_modal(app_t *app);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../widget/group.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
button_t *element;
|
||||||
|
enum w_type type;
|
||||||
|
} group_bt_t;
|
||||||
|
|
||||||
|
void init_notification_modal_cb(callback_args_t *args) {
|
||||||
|
int32_t response;
|
||||||
|
callback_args_t d_args;
|
||||||
|
app_t *app = args->app;
|
||||||
|
dialogue_t *d = (dialogue_t *)app->active_widget;
|
||||||
|
memcpy(&d_args, args, sizeof(callback_args_t));
|
||||||
|
d_args.app = NULL;
|
||||||
|
d_args.resp_data = &response;
|
||||||
|
d_args.element = app->active_widget;
|
||||||
|
dialogue_default_callback(&d_args);
|
||||||
|
|
||||||
|
app->query_args->state = WAIT_CLIENT;
|
||||||
|
d->needs_destroy = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogue_t *init_notification_modal(app_t *app) {
|
||||||
|
if (app == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
group_el_init_t actions[] = {
|
||||||
|
{.type = w_button, .label = "OK", .is_default = 1}, {.type = w_end}};
|
||||||
|
|
||||||
|
init_dialogue(&(app->modal), "Notification", app->query_args->notification,
|
||||||
|
&(app->coordinates));
|
||||||
|
free(app->query_args->notification);
|
||||||
|
app->query_args->notification = NULL;
|
||||||
|
dialogue_t *d = &(app->modal);
|
||||||
|
app->query_args->active_dialogue = d;
|
||||||
|
|
||||||
|
d->w.callback = init_notification_modal_cb;
|
||||||
|
d->g_content = NULL;
|
||||||
|
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal);
|
||||||
|
|
||||||
|
dialogue_init_active_id(d);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef NOTIFICATION_H
|
||||||
|
#define NOTIFICATION_H
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
|
||||||
|
dialogue_t *init_notification_modal(app_t *app);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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 *)app->active_widget;
|
||||||
|
memcpy(&d_args, args, sizeof(callback_args_t));
|
||||||
|
d_args.app = NULL;
|
||||||
|
d_args.resp_data = &response;
|
||||||
|
d_args.element = app->active_widget;
|
||||||
|
dialogue_default_callback(&d_args);
|
||||||
|
if (response > -1) {
|
||||||
|
switch (response) {
|
||||||
|
case 0:
|
||||||
|
d->needs_destroy = true;
|
||||||
|
/* TODO: macros */
|
||||||
|
free(app->query_args->server_message.text);
|
||||||
|
app->query_args->server_message.text = NULL;
|
||||||
|
app->query_args->server_message.capacity = 0;
|
||||||
|
app->query_args->server_message.size = 0;
|
||||||
|
app->query_args->state = S_NEXT_ACTION;
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#include "../../file_processor.h"
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../widget/fs_file_list.h"
|
||||||
|
#include "../widget/group.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void upload_dialogue_modal_cb(callback_args_t *args) {
|
||||||
|
int32_t response = -1;
|
||||||
|
callback_args_t d_args;
|
||||||
|
app_t *app = args->app;
|
||||||
|
dialogue_t *d = (dialogue_t *)app->active_widget;
|
||||||
|
memcpy(&d_args, args, sizeof(callback_args_t));
|
||||||
|
d_args.app = NULL;
|
||||||
|
d_args.resp_data = &response;
|
||||||
|
d_args.element = app->active_widget;
|
||||||
|
dialogue_default_callback(&d_args);
|
||||||
|
ui_fs_file_list_t *fui =
|
||||||
|
(ui_fs_file_list_t *)d->g_content->elements[0].element;
|
||||||
|
switch (response) {
|
||||||
|
case 0:
|
||||||
|
app->query_args->state = S_WAIT_SERVER;
|
||||||
|
d->needs_destroy = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
file_upload_open(fui->d_path, fui->current->name, app->query_args);
|
||||||
|
d->needs_destroy = true;
|
||||||
|
app->query_args->state = S_UPLOAD_PARAMS;
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
d->needs_destroy = true;
|
||||||
|
app->query_args->state = WAIT_CLIENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogue_t *init_upload_dialogue_modal(app_t *app) {
|
||||||
|
if (app == NULL)
|
||||||
|
return NULL;
|
||||||
|
group_el_init_t content[] = {
|
||||||
|
// {.type = w_input, .label = "File description", .length = 30},
|
||||||
|
{.type = w_fs_file_list, .label = "File", .length = 30},
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
group_el_init_t actions[] = {
|
||||||
|
{.type = w_button, .label = "Cancel", .is_default = 0}, {.type = w_end}};
|
||||||
|
|
||||||
|
app->modal.w.parent_win = &app->win;
|
||||||
|
init_dialogue(&(app->modal), "Upload new file", "Enter essential data",
|
||||||
|
&(app->coordinates));
|
||||||
|
dialogue_t *d = &(app->modal);
|
||||||
|
|
||||||
|
d->w.callback = upload_dialogue_modal_cb;
|
||||||
|
d->g_content = init_group(&(d->win), &(d->w), content, horizontal);
|
||||||
|
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal);
|
||||||
|
|
||||||
|
app->query_args->active_dialogue = d;
|
||||||
|
|
||||||
|
dialogue_init_active_id(d);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef UPLOAD_DIALOGUE_H
|
||||||
|
#define UPLOAD_DIALOGUE_H
|
||||||
|
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../app.h"
|
||||||
|
|
||||||
|
dialogue_t *init_upload_dialogue_modal(app_t *app);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#include "../app.h"
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../widget/group.h"
|
||||||
|
#include "../widget/input.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void upload_props_dialogue_modal_cb(callback_args_t *args) {
|
||||||
|
int32_t response = -1;
|
||||||
|
callback_args_t d_args;
|
||||||
|
app_t *app = args->app;
|
||||||
|
dialogue_t *d = (dialogue_t *)app->active_widget;
|
||||||
|
memcpy(&d_args, args, sizeof(callback_args_t));
|
||||||
|
d_args.app = NULL;
|
||||||
|
d_args.resp_data = &response;
|
||||||
|
d_args.element = app->active_widget;
|
||||||
|
dialogue_default_callback(&d_args);
|
||||||
|
char query[256];
|
||||||
|
int32_t query_len = 0;
|
||||||
|
input_t *desc_input = (input_t *)d->g_content->elements[0].element;
|
||||||
|
if (response > -1) {
|
||||||
|
switch (response) {
|
||||||
|
case 0:
|
||||||
|
query_len =
|
||||||
|
sprintf(query, "file upload \"%s\" %zu 1\n",
|
||||||
|
app->query_args->file->name, app->query_args->file->size);
|
||||||
|
app->query_args->file->description =
|
||||||
|
malloc(desc_input->value_len + 9); /* reserve space for \n:END:\n */
|
||||||
|
strcpy(app->query_args->file->description, desc_input->value);
|
||||||
|
d->needs_destroy = true;
|
||||||
|
app->query_args->state = S_UPLOAD_REQUESTED;
|
||||||
|
write(app->query_args->sd, query, query_len);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (app->query_args->file->name != NULL)
|
||||||
|
free(app->query_args->file->name);
|
||||||
|
if (app->query_args->file->path != NULL)
|
||||||
|
free(app->query_args->file->path);
|
||||||
|
free(app->query_args->file);
|
||||||
|
app->query_args->file = NULL;
|
||||||
|
app->query_args->state = S_WAIT_SERVER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogue_t *init_upload_props_dialogue_modal(app_t *app) {
|
||||||
|
if (app == NULL)
|
||||||
|
return NULL;
|
||||||
|
group_el_init_t content[] = {
|
||||||
|
{.type = w_input, .label = "File description", .length = 30},
|
||||||
|
{.type = w_end}};
|
||||||
|
|
||||||
|
group_el_init_t actions[] = {
|
||||||
|
{.type = w_button, .label = "Upload", .is_default = 1},
|
||||||
|
{.type = w_button, .label = "Cancel", .is_default = 0},
|
||||||
|
{.type = w_end},
|
||||||
|
};
|
||||||
|
|
||||||
|
app->modal.w.parent_win = &app->win;
|
||||||
|
init_dialogue(&(app->modal), "Description for the file",
|
||||||
|
"Enter essential data", &(app->coordinates));
|
||||||
|
dialogue_t *d = &(app->modal);
|
||||||
|
|
||||||
|
d->w.callback = upload_props_dialogue_modal_cb;
|
||||||
|
d->g_content = init_group(&(d->win), &(d->w), content, horizontal);
|
||||||
|
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal);
|
||||||
|
|
||||||
|
app->query_args->active_dialogue = d;
|
||||||
|
|
||||||
|
dialogue_init_active_id(d);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef UPLOAD_PROPS_DIALOGUE_H
|
||||||
|
#define UPLOAD_PROPS_DIALOGUE_H
|
||||||
|
|
||||||
|
#include "../widget/dialogue.h"
|
||||||
|
#include "../app.h"
|
||||||
|
|
||||||
|
dialogue_t *init_upload_props_dialogue_modal(app_t *app);
|
||||||
|
|
||||||
|
#endif
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
#include "widget.h"
|
||||||
|
#include "../main.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
extern uint32_t m_id;
|
||||||
|
int32_t rsize_to_value(int32_t size, enum rsize rsize);
|
||||||
|
|
||||||
|
void init_widget(widget_t *w, widget_t *w_parent, WINDOW **win, char *title) {
|
||||||
|
w->id = m_id++;
|
||||||
|
w->x = 0;
|
||||||
|
w->y = 0;
|
||||||
|
w->m_x = 0;
|
||||||
|
w->m_y = 0;
|
||||||
|
w->parent_win = win;
|
||||||
|
w->w_parent = w_parent;
|
||||||
|
w->callback = NULL;
|
||||||
|
strcpy(w->title, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t get_max_line_len(const char *text, uint32_t *line_count) {
|
||||||
|
uint32_t nl_pos = 0; // new line position
|
||||||
|
uint32_t c_start = 0; // current line start position
|
||||||
|
uint32_t c_len = 0; // current line length
|
||||||
|
uint32_t m_len = 0; // max length
|
||||||
|
uint32_t line_num = 1;
|
||||||
|
for (int i = 0; text[i] != '\0'; i++, c_len++) {
|
||||||
|
if (text[i] == '\n') {
|
||||||
|
if (i - nl_pos > c_len || !m_len) {
|
||||||
|
m_len = c_len;
|
||||||
|
}
|
||||||
|
nl_pos = i;
|
||||||
|
c_start = i + 1;
|
||||||
|
c_len = 0;
|
||||||
|
line_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line_count != NULL)
|
||||||
|
*line_count = line_num;
|
||||||
|
if (c_len > m_len) {
|
||||||
|
return c_len;
|
||||||
|
} else {
|
||||||
|
return m_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PRINT_TEXT(win, l_buf, text, i, c_line_len, win_width, line_v_pos, \
|
||||||
|
attrs) \
|
||||||
|
strncpy(l_buf, text + i - c_line_len, c_line_len); \
|
||||||
|
l_buf[c_line_len] = '\0'; \
|
||||||
|
if ((attrs & PMT_ALIGN_CENTER) == PMT_ALIGN_CENTER) { \
|
||||||
|
mvwprintw(win, line_v_pos, (win_width - c_line_len) / 2, "%s", l_buf); \
|
||||||
|
} else if (attrs & PMT_POS_CENTER) { \
|
||||||
|
mvwprintw(win, line_v_pos, (win_width - m_line_len) / 2, "%s", l_buf); \
|
||||||
|
} else { \
|
||||||
|
mvwprintw(win, line_v_pos, x, "%s", l_buf); \
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t print_multiline_text(WINDOW *win, const char *_text,
|
||||||
|
const uint32_t win_width, const uint32_t y,
|
||||||
|
const uint32_t x, const uint16_t attrs) {
|
||||||
|
|
||||||
|
uint16_t line_v_pos = y;
|
||||||
|
int32_t c_line_len = 0;
|
||||||
|
uint32_t m_line_len = 0;
|
||||||
|
uint32_t i = 0;
|
||||||
|
char l_buf[DIALOGUE_TEXT];
|
||||||
|
char *text = malloc(strlen(_text) + 1);
|
||||||
|
strcpy(text, _text);
|
||||||
|
|
||||||
|
uint l_size = 0;
|
||||||
|
for (uint m = 0; text[m] != '\0'; m++) {
|
||||||
|
if (text[m] != '\n') {
|
||||||
|
if (l_size >= win_width) {
|
||||||
|
uint j = m;
|
||||||
|
while (text[j] != ' ') {
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
text[j] = '\n';
|
||||||
|
l_size = 0;
|
||||||
|
} else {
|
||||||
|
l_size++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
l_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs & PMT_POS_CENTER) {
|
||||||
|
m_line_len = get_max_line_len(text, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; text[i]; i++, c_line_len++) {
|
||||||
|
if (text[i] == '\n') {
|
||||||
|
PRINT_TEXT(win, l_buf, text, i, c_line_len, win_width, line_v_pos, attrs)
|
||||||
|
c_line_len = -1;
|
||||||
|
line_v_pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_TEXT(win, l_buf, text, i, c_line_len, win_width, line_v_pos, attrs)
|
||||||
|
|
||||||
|
free(text);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t rsize_to_value(int32_t size, enum rsize rsize) {
|
||||||
|
switch (rsize) {
|
||||||
|
case s_auto:
|
||||||
|
return size;
|
||||||
|
case s_1:
|
||||||
|
return size;
|
||||||
|
case s_1_2:
|
||||||
|
return size / 2;
|
||||||
|
case s_1_3:
|
||||||
|
return size / 3;
|
||||||
|
case s_2_3:
|
||||||
|
return size / 3 * 2;
|
||||||
|
case s_1_4:
|
||||||
|
return size / 4;
|
||||||
|
case s_3_4:
|
||||||
|
return size / 4 * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#ifndef WIDGET_H
|
||||||
|
#define WIDGET_H
|
||||||
|
|
||||||
|
#include "../main.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum w_type {
|
||||||
|
w_end,
|
||||||
|
w_button,
|
||||||
|
w_box,
|
||||||
|
w_group,
|
||||||
|
w_input,
|
||||||
|
w_progress,
|
||||||
|
w_fs_file_list,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *app;
|
||||||
|
void *element;
|
||||||
|
void *data;
|
||||||
|
void *resp_data;
|
||||||
|
uint32_t active_id;
|
||||||
|
} callback_args_t;
|
||||||
|
|
||||||
|
enum rsize {
|
||||||
|
s_auto,
|
||||||
|
s_1,
|
||||||
|
s_1_2,
|
||||||
|
s_1_3,
|
||||||
|
s_2_3,
|
||||||
|
s_1_4,
|
||||||
|
s_3_4,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct widget_t {
|
||||||
|
uint32_t id;
|
||||||
|
char title[DIALOGUE_TITLE];
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
uint32_t m_x;
|
||||||
|
uint32_t m_y;
|
||||||
|
struct {
|
||||||
|
uint32_t y;
|
||||||
|
uint32_t x;
|
||||||
|
} cur;
|
||||||
|
WINDOW *const *parent_win;
|
||||||
|
struct widget_t *w_parent;
|
||||||
|
// enum rsize rsize;
|
||||||
|
void (*callback)(callback_args_t *args);
|
||||||
|
} widget_t;
|
||||||
|
|
||||||
|
typedef void (*callback_t)(callback_args_t *args);
|
||||||
|
|
||||||
|
enum pmt_attrs {
|
||||||
|
PMT_POS_CENTER = 01,
|
||||||
|
PMT_ALIGN_CENTER = 03,
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_widget(widget_t *w, widget_t *w_parent, WINDOW **win, char *title);
|
||||||
|
int32_t get_max_line_len(const char *text, uint32_t *line_count);
|
||||||
|
uint32_t print_multiline_text(WINDOW *win, const char *text, const uint32_t win_width, const uint32_t y,
|
||||||
|
const uint32_t x, const uint16_t attrs);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget.h"
|
||||||
|
#include "button.h"
|
||||||
|
|
||||||
|
button_t *init_button(WINDOW **win, widget_t *w_parent, char *label) {
|
||||||
|
button_t *btn = malloc(sizeof(button_t));
|
||||||
|
init_widget(&(btn->w), w_parent, win, label);
|
||||||
|
btn->is_disabled = 0;
|
||||||
|
btn->w.x = strlen(btn->w.title) + 6; // + "[ ]"
|
||||||
|
btn->w.y = 1; // TODO: detect new line
|
||||||
|
btn->w.cur.y = 0;
|
||||||
|
btn->w.cur.x = 0;
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t draw_button(button_t *btn, uint32_t active_id) {
|
||||||
|
char title[DIALOGUE_TITLE + 6];
|
||||||
|
WINDOW *win = *(btn->w.parent_win);
|
||||||
|
uint32_t margin_y = btn->w.m_y + btn->w.w_parent->m_y;
|
||||||
|
uint32_t margin_x = btn->w.m_x + btn->w.w_parent->m_x;
|
||||||
|
|
||||||
|
if (btn->w.id == active_id) {
|
||||||
|
sprintf(title, "[< %s >]", btn->w.title);
|
||||||
|
wattrset(win, COLOR_PAIR(modal_color_pair) | A_BOLD | A_REVERSE);
|
||||||
|
} else {
|
||||||
|
sprintf(title, "[ %s ]", btn->w.title);
|
||||||
|
wattrset(win, COLOR_PAIR(0) | A_REVERSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
mvwprintw(win, margin_y, margin_x, "%s", title);
|
||||||
|
btn->w.cur.y = margin_y;
|
||||||
|
btn->w.cur.x = margin_x;
|
||||||
|
|
||||||
|
wattroff(win, A_BOLD | A_REVERSE);
|
||||||
|
return strlen(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_button(button_t *btn) { free(btn); }
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef BUTTON_H
|
||||||
|
#define BUTTON_H
|
||||||
|
|
||||||
|
#include "../../main.h"
|
||||||
|
#include "../widget.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
widget_t w;
|
||||||
|
char hotkey;
|
||||||
|
uint32_t is_disabled : 1;
|
||||||
|
} button_t;
|
||||||
|
|
||||||
|
button_t *init_button(WINDOW **win, widget_t *w_parent, char *label);
|
||||||
|
int32_t draw_button(button_t *btn, uint32_t active_id);
|
||||||
|
void destroy_button(button_t *btn);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "dialogue.h"
|
||||||
|
#include "file_list.h"
|
||||||
|
#include "group.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
#define INCR_ACTIVE_ID(d, current, next) \
|
||||||
|
if (d->active.id != d->current->last_id) { \
|
||||||
|
d->active.id = d->active.id + 1; \
|
||||||
|
} else if (d->next != NULL) { \
|
||||||
|
d->active.id = d->next->first_id; \
|
||||||
|
d->active.type = next; \
|
||||||
|
} else { \
|
||||||
|
d->active.id = d->current->first_id; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECR_ACTIVE_ID(d, current, next) \
|
||||||
|
if (d->active.id != d->current->first_id) { \
|
||||||
|
d->active.id = d->active.id - 1; \
|
||||||
|
} else if (d->next != NULL) { \
|
||||||
|
d->active.id = d->next->last_id; \
|
||||||
|
d->active.type = next; \
|
||||||
|
} else { \
|
||||||
|
d->active.id = d->current->last_id; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CH_GROUP(d, current, next) \
|
||||||
|
{ \
|
||||||
|
if (d->active.type == current) { \
|
||||||
|
d->active.type = next; \
|
||||||
|
diff = d->active.id - d->current->first_id; \
|
||||||
|
if (diff > d->next->last_id - d->next->first_id) { \
|
||||||
|
d->active.id = d->next->last_id; \
|
||||||
|
} else { \
|
||||||
|
d->active.id = d->next->first_id + diff; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
widget_t *get_active_widget(dialogue_t *d) {
|
||||||
|
group_t *g;
|
||||||
|
if (d->active.type == g_action) {
|
||||||
|
g = d->g_action;
|
||||||
|
} else {
|
||||||
|
g = d->g_content;
|
||||||
|
}
|
||||||
|
widget_t *w = (widget_t *)g->elements[d->active.id - g->first_id].element;
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dialogue_default_callback(callback_args_t *args) {
|
||||||
|
dialogue_t *d = (void *)args->element;
|
||||||
|
int32_t key = *((int32_t *)args->data);
|
||||||
|
app_t *app = (app_t *)args->app;
|
||||||
|
callback_args_t new_args;
|
||||||
|
int32_t *resp_value = (int32_t *)args->resp_data;
|
||||||
|
group_el_t *default_element = NULL;
|
||||||
|
memcpy(&new_args, args, sizeof(callback_args_t));
|
||||||
|
new_args.active_id = d->active.id;
|
||||||
|
int32_t diff;
|
||||||
|
d->needs_update = true;
|
||||||
|
input_t *input;
|
||||||
|
widget_t *widget;
|
||||||
|
switch (key) {
|
||||||
|
case '\t':
|
||||||
|
if (d->active.type == g_content) {
|
||||||
|
INCR_ACTIVE_ID(d, g_content, g_action);
|
||||||
|
} else if (d->active.type == g_action) {
|
||||||
|
INCR_ACTIVE_ID(d, g_action, g_content);
|
||||||
|
}
|
||||||
|
*resp_value = -1;
|
||||||
|
break;
|
||||||
|
case '\33': /* Esc key */
|
||||||
|
*resp_value = -2;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHT:
|
||||||
|
if (d->active.type == g_content) {
|
||||||
|
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
|
||||||
|
w_input) {
|
||||||
|
input = d->g_content->elements[d->active.id - d->g_content->first_id]
|
||||||
|
.element;
|
||||||
|
if (input->cur_pos > 0) {
|
||||||
|
input->cur_pos -= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
INCR_ACTIVE_ID(d, g_content, g_action);
|
||||||
|
}
|
||||||
|
} else if (d->active.type == g_action) {
|
||||||
|
INCR_ACTIVE_ID(d, g_action, g_content);
|
||||||
|
}
|
||||||
|
*resp_value = -1;
|
||||||
|
break;
|
||||||
|
case KEY_LEFT:
|
||||||
|
if (d->active.type == g_content) {
|
||||||
|
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
|
||||||
|
w_input) {
|
||||||
|
input = d->g_content->elements[d->active.id - d->g_content->first_id]
|
||||||
|
.element;
|
||||||
|
if (input->value_len > input->cur_pos) {
|
||||||
|
input->cur_pos += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DECR_ACTIVE_ID(d, g_content, g_action);
|
||||||
|
}
|
||||||
|
} else if (d->active.type == g_action) {
|
||||||
|
DECR_ACTIVE_ID(d, g_action, g_content);
|
||||||
|
}
|
||||||
|
*resp_value = -1;
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
widget = get_active_widget(d);
|
||||||
|
if (widget->callback != NULL) { /* Existing callback case */
|
||||||
|
new_args.element = widget;
|
||||||
|
widget->callback(&new_args);
|
||||||
|
break;
|
||||||
|
} /* Default cases */
|
||||||
|
if (d->active.type == g_action) {
|
||||||
|
new_args.element = new_args.element = d->g_action;
|
||||||
|
group_default_callback(&new_args);
|
||||||
|
} else if (d->g_action != NULL) {
|
||||||
|
for (int i = 0; i < d->g_action->count; i++) {
|
||||||
|
if (d->g_action->elements[i].is_default) {
|
||||||
|
*resp_value = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* TODO: temp solution, improve */
|
||||||
|
*resp_value = d->active.id - d->g_content->first_id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
|
||||||
|
w_fs_file_list) {
|
||||||
|
new_args.element = d->g_content;
|
||||||
|
group_default_callback(&new_args);
|
||||||
|
} else {
|
||||||
|
CH_GROUP(d, g_action, g_content);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_DOWN:
|
||||||
|
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
|
||||||
|
w_fs_file_list) {
|
||||||
|
new_args.element = d->g_content;
|
||||||
|
group_default_callback(&new_args);
|
||||||
|
} else {
|
||||||
|
CH_GROUP(d, g_content, g_action);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* run callback function */
|
||||||
|
if (d->active.type == g_content) {
|
||||||
|
new_args.element = new_args.element = d->g_content;
|
||||||
|
} else {
|
||||||
|
new_args.element = new_args.element = d->g_action;
|
||||||
|
}
|
||||||
|
group_default_callback(&new_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_dialogue(dialogue_t *dialogue, const char title[], const char text[],
|
||||||
|
coordinates_t *p_coordinates) {
|
||||||
|
dialogue->win = 0;
|
||||||
|
dialogue->g_content = NULL;
|
||||||
|
dialogue->w.x = 0;
|
||||||
|
dialogue->w.y = 0;
|
||||||
|
dialogue->p_coordinates = p_coordinates;
|
||||||
|
dialogue->w.callback = dialogue_default_callback;
|
||||||
|
dialogue->is_initiated = true;
|
||||||
|
dialogue->needs_update = true;
|
||||||
|
dialogue->needs_destroy = false;
|
||||||
|
strcpy(dialogue->w.title, title);
|
||||||
|
strcpy(dialogue->text, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dialogue_init_active_id(dialogue_t *dialogue) {
|
||||||
|
enum w_type widget_type;
|
||||||
|
|
||||||
|
if (dialogue->g_content != NULL) {
|
||||||
|
for (int i = 0; i < dialogue->g_content->count; i++) {
|
||||||
|
widget_type = dialogue->g_content->elements[i].type;
|
||||||
|
if (widget_type == w_button || widget_type == w_input ||
|
||||||
|
widget_type == w_fs_file_list) { /* Add here new types */
|
||||||
|
dialogue->active.type = g_content;
|
||||||
|
widget_t *w = (widget_t *)dialogue->g_content->elements[i].element;
|
||||||
|
dialogue->active.id = w->id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dialogue->g_action != NULL) {
|
||||||
|
for (int i = 0; i < dialogue->g_action->count; i++) {
|
||||||
|
widget_type = dialogue->g_action->elements[i].type;
|
||||||
|
if (widget_type == w_button || widget_type == w_input ||
|
||||||
|
widget_type == w_fs_file_list) {
|
||||||
|
dialogue->active.type = g_action;
|
||||||
|
widget_t *w = (widget_t *)dialogue->g_action->elements[i].element;
|
||||||
|
dialogue->active.id = w->id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// void dialogue_init_active_id(dialogue_t *dialogue) {
|
||||||
|
// enum w_type widget_type;
|
||||||
|
|
||||||
|
// if (dialogue->g_content != NULL) {
|
||||||
|
// for (int i = 0; i < dialogue->g_content->count; i++) {
|
||||||
|
// widget_type = dialogue->g_content->elements[i].type;
|
||||||
|
// if (widget_type == w_button || widget_type == w_input ||
|
||||||
|
// widget_type == w_fs_file_list) { /* Add here new types */
|
||||||
|
// dialogue->active.type = g_content;
|
||||||
|
// widget_t *w = (widget_t *)dialogue->g_content->elements[i].element;
|
||||||
|
// dialogue->active.id = w->id;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else if (dialogue->g_action != NULL) {
|
||||||
|
// for (int i = 0; i < dialogue->g_action->count; i++) {
|
||||||
|
// widget_type = dialogue->g_action->elements[i].type;
|
||||||
|
// if (widget_type == w_button || widget_type == w_input ||
|
||||||
|
// widget_type == w_fs_file_list) {
|
||||||
|
// dialogue->active.type = g_action;
|
||||||
|
// widget_t *w = (widget_t *)dialogue->g_action->elements[i].element;
|
||||||
|
// dialogue->active.id = w->id;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
#define DETECT_GROUP_SIZE(group, line_max_len, y, x) \
|
||||||
|
if (group) { \
|
||||||
|
group->w.m_y = y; \
|
||||||
|
if (line_max_len < group->w.x) { \
|
||||||
|
line_max_len = group->w.x; \
|
||||||
|
group->w.m_x = 0; \
|
||||||
|
} else { \
|
||||||
|
group->w.m_x = (line_max_len - group->w.x) / 2; \
|
||||||
|
} \
|
||||||
|
y += group->w.y; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t draw_dialogue(dialogue_t *d) {
|
||||||
|
if (!d->is_initiated)
|
||||||
|
return -1;
|
||||||
|
else if (!d->needs_update) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
group_el_t *ae_ptr = NULL; /* active element */
|
||||||
|
uint32_t ae_idx; /* active element */
|
||||||
|
/* count dimensions */
|
||||||
|
uint32_t x = 1; /* when uses box */
|
||||||
|
uint32_t y = 1; /* when uses box */
|
||||||
|
|
||||||
|
/* analyze text content */
|
||||||
|
uint32_t line_count = 0;
|
||||||
|
uint32_t line_max_len = 0;
|
||||||
|
line_max_len = get_max_line_len(d->text, &line_count);
|
||||||
|
y += line_count;
|
||||||
|
y += 2; /* margin for text */
|
||||||
|
|
||||||
|
/* analyze groups */
|
||||||
|
DETECT_GROUP_SIZE(d->g_content, line_max_len, y, x);
|
||||||
|
DETECT_GROUP_SIZE(d->g_action, line_max_len, y, x);
|
||||||
|
x += line_max_len;
|
||||||
|
|
||||||
|
x += 1; /* when uses box */
|
||||||
|
y += 1; /* when uses box */
|
||||||
|
|
||||||
|
d->w.x = x;
|
||||||
|
d->w.y = y;
|
||||||
|
d->w.m_y = (d->p_coordinates->max_y - y) / 2;
|
||||||
|
d->w.m_x = (d->p_coordinates->max_x - x) / 2;
|
||||||
|
|
||||||
|
/* render window */
|
||||||
|
if (d->win == NULL) {
|
||||||
|
d->win = newwin(y, x, d->w.m_y, d->w.m_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
wattrset(d->win, COLOR_PAIR(0) | A_BOLD | A_REVERSE);
|
||||||
|
|
||||||
|
/* background */
|
||||||
|
for (int yp = 1; yp < d->w.y - 1; yp++) {
|
||||||
|
mvwprintw(d->win, yp, 1, "%*s", d->w.x, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* title */
|
||||||
|
const uint32_t title_mx_pos = (d->w.x - strlen(d->w.title)) / 2;
|
||||||
|
box(d->win, 0, 0);
|
||||||
|
mvwprintw(d->win, 0, title_mx_pos - 1, " ");
|
||||||
|
mvwprintw(d->win, 0, title_mx_pos, "%s", d->w.title);
|
||||||
|
mvwprintw(d->win, 0, title_mx_pos + strlen(d->w.title), " ");
|
||||||
|
|
||||||
|
/* text */
|
||||||
|
wattroff(d->win, A_BOLD);
|
||||||
|
/* mvwhline(d->win, d->w.y - 3, 1, 0, d->w.x - 2); */
|
||||||
|
print_multiline_text(d->win, d->text, d->w.x, 2, 1, PMT_ALIGN_CENTER);
|
||||||
|
wattroff(d->win, A_REVERSE);
|
||||||
|
|
||||||
|
if (d->g_content != NULL) {
|
||||||
|
draw_group(d->win, d->g_content, d->active.id, &(d->w));
|
||||||
|
}
|
||||||
|
if (d->g_action != NULL) {
|
||||||
|
draw_group(d->win, d->g_action, d->active.id, &(d->w));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move cursor */
|
||||||
|
if (d->g_content != NULL) {
|
||||||
|
FIND_ACTIVE_ELEMENT(d->g_content, d->active.id, ae_ptr, ae_idx);
|
||||||
|
}
|
||||||
|
if (ae_ptr == NULL && d->g_action != NULL)
|
||||||
|
FIND_ACTIVE_ELEMENT(d->g_action, d->active.id, ae_ptr, ae_idx);
|
||||||
|
|
||||||
|
if (ae_ptr != NULL && ae_ptr->id == d->active.id) {
|
||||||
|
if (ae_ptr->type == w_input) {
|
||||||
|
input_t *input = ae_ptr->element;
|
||||||
|
d->w.cur.y = input->w.cur.y;
|
||||||
|
d->w.cur.x = input->w.cur.x + input->value_len;
|
||||||
|
d->w.cur.x -= input->cur_pos;
|
||||||
|
if (d->w.cur.y || d->w.cur.x) {
|
||||||
|
wmove(d->win, d->w.cur.y, d->w.cur.x);
|
||||||
|
curs_set(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
curs_set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d->needs_update = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void destroy_dialogue(dialogue_t *d, void *_app) {
|
||||||
|
app_t *app = (app_t *)_app;
|
||||||
|
if (d->g_content) {
|
||||||
|
destroy_group(d->g_content);
|
||||||
|
}
|
||||||
|
if (d->g_action) {
|
||||||
|
destroy_group(d->g_action);
|
||||||
|
}
|
||||||
|
delwin(d->win);
|
||||||
|
d->win = NULL;
|
||||||
|
d->is_initiated = 0;
|
||||||
|
d->needs_destroy = false;
|
||||||
|
app->active_win_type = aw_left;
|
||||||
|
app->active_win = app->left_win;
|
||||||
|
app->active_callback = file_list_cb;
|
||||||
|
app->query_args->active_dialogue = NULL;
|
||||||
|
app_refresh(app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef DIALOGUE_H
|
||||||
|
#define DIALOGUE_H
|
||||||
|
|
||||||
|
#include "../widget.h"
|
||||||
|
#include "../../common.h"
|
||||||
|
#include "button.h"
|
||||||
|
#include "group.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum g_type { g_content, g_action };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
widget_t w;
|
||||||
|
WINDOW *win;
|
||||||
|
group_t *g_content;
|
||||||
|
group_t *g_action;
|
||||||
|
struct {
|
||||||
|
int32_t id;
|
||||||
|
enum g_type type;
|
||||||
|
} active;
|
||||||
|
char text[DIALOGUE_TEXT];
|
||||||
|
uint32_t is_initiated : 1;
|
||||||
|
uint32_t needs_update : 1;
|
||||||
|
uint32_t needs_destroy: 1;
|
||||||
|
coordinates_t *p_coordinates;
|
||||||
|
} dialogue_t;
|
||||||
|
|
||||||
|
void init_dialogue(dialogue_t *d, const char title[], const char text[],
|
||||||
|
coordinates_t *p_coordinates);
|
||||||
|
int32_t draw_dialogue(dialogue_t *d);
|
||||||
|
void destroy_dialogue(dialogue_t *d, void *app);
|
||||||
|
void dialogue_default_callback(callback_args_t *args);
|
||||||
|
void dialogue_init_active_id(dialogue_t *dialogue);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
#include "file_list.h"
|
||||||
|
#include "../../file_processor.h"
|
||||||
|
#include "../../fs.h"
|
||||||
|
#include "../app.h"
|
||||||
|
#include "progress_bar.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void reset_file_list(ui_file_list_t *fl_ui);
|
||||||
|
|
||||||
|
void file_list_cb(callback_args_t *args) {
|
||||||
|
app_t *app = args->app;
|
||||||
|
ui_file_list_t *fui = app->query_args->file_list_ui;
|
||||||
|
int32_t key = *((int32_t *)args->data);
|
||||||
|
char query[256];
|
||||||
|
int32_t q_len = 0;
|
||||||
|
fl_item_t *f_item;
|
||||||
|
ui_progress_bar_t *pb;
|
||||||
|
switch (key) {
|
||||||
|
case KEY_DOWN:
|
||||||
|
if (fui->current_idx < fui->current_count - 1) {
|
||||||
|
fui->current_idx++;
|
||||||
|
draw_file_list(fui);
|
||||||
|
} else if (fui->current_page < fui->pages) {
|
||||||
|
fl_clear(fui->start, fui->current);
|
||||||
|
app->query_args->state = S_FILE_LIST;
|
||||||
|
sprintf(query, "file list %u %u\n%n", fui->max_lines,
|
||||||
|
fui->current_page + 1, &q_len);
|
||||||
|
write(app->query_args->sd, query, q_len);
|
||||||
|
reset_file_list(fui);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
if (fui->current_idx > 0) {
|
||||||
|
fui->current_idx--;
|
||||||
|
draw_file_list(fui);
|
||||||
|
} else if (fui->current_page > 1) {
|
||||||
|
fl_clear(fui->start, fui->current);
|
||||||
|
app->query_args->state = S_FILE_LIST;
|
||||||
|
sprintf(query, "file list %u %u\n%n", fui->max_lines,
|
||||||
|
fui->current_page - 1, &q_len);
|
||||||
|
write(app->query_args->sd, query, q_len);
|
||||||
|
reset_file_list(fui);
|
||||||
|
fui->activate_last = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
ui_file_select(app->file_args, app->query_args, fui->current_idx + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_file_list_t *init_file_list(WINDOW **win, WINDOW *const *info_win) {
|
||||||
|
ui_file_list_t *fl_ui = malloc(sizeof(ui_file_list_t));
|
||||||
|
init_widget(&(fl_ui->w), NULL, win, "");
|
||||||
|
WINDOW *parent_win = *(fl_ui->w.parent_win);
|
||||||
|
fl_ui->current_idx = 0;
|
||||||
|
fl_ui->current_page = 1;
|
||||||
|
fl_ui->pages = 1;
|
||||||
|
fl_ui->current_count = 0;
|
||||||
|
fl_ui->full_count = 0;
|
||||||
|
fl_ui->activate_last = false;
|
||||||
|
fl_ui->info_win = info_win;
|
||||||
|
fl_ui->max_lines = getmaxy(parent_win) - 3; /* 2+1 (bottom info line) */
|
||||||
|
return fl_ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_file_list(ui_file_list_t *fl_ui) {
|
||||||
|
fl_ui->current_idx = 0;
|
||||||
|
fl_ui->current_page = 0;
|
||||||
|
fl_ui->pages = 0;
|
||||||
|
fl_ui->current_count = 0;
|
||||||
|
fl_ui->full_count = 0;
|
||||||
|
fl_ui->activate_last = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_file_list(ui_file_list_t *fl_ui) {
|
||||||
|
int32_t sz_y, sz_x;
|
||||||
|
int32_t p_y, p_x;
|
||||||
|
WINDOW *parent_win = *(fl_ui->w.parent_win);
|
||||||
|
getmaxyx(parent_win, sz_y, sz_x);
|
||||||
|
int32_t sz_y_f = sz_y - 2; /* TODO: можно заменить на поле max_lines */
|
||||||
|
p_y = 1;
|
||||||
|
p_x = 1;
|
||||||
|
fl_item_t *el = *(fl_ui->start);
|
||||||
|
fl_item_t *active_el = *(fl_ui->start);
|
||||||
|
int32_t cur_el_idx = 0;
|
||||||
|
curs_set(false);
|
||||||
|
|
||||||
|
if (fl_ui->activate_last) {
|
||||||
|
fl_ui->current_idx = fl_ui->current_count - 1;
|
||||||
|
fl_ui->activate_last = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fl_ui->current_idx + 1 >= sz_y_f) {
|
||||||
|
p_y -= fl_ui->current_idx - sz_y_f + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (p_y < 1) {
|
||||||
|
p_y++;
|
||||||
|
cur_el_idx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cur_el_idx == fl_ui->current_idx) {
|
||||||
|
wattrset(parent_win, A_BOLD | A_REVERSE);
|
||||||
|
active_el = el;
|
||||||
|
}
|
||||||
|
p_x = 1;
|
||||||
|
mvwprintw(parent_win, p_y, p_x, "%s%n", el->name, &p_x);
|
||||||
|
mvwprintw(parent_win, p_y, p_x + 1, "%*s", sz_x - p_x, "");
|
||||||
|
if (cur_el_idx == fl_ui->current_idx) {
|
||||||
|
wattroff(parent_win, A_BOLD | A_REVERSE);
|
||||||
|
}
|
||||||
|
p_y++;
|
||||||
|
cur_el_idx++;
|
||||||
|
} while ((el = el->next) != NULL && p_y < sz_y_f);
|
||||||
|
|
||||||
|
p_x = 1;
|
||||||
|
|
||||||
|
for (; p_y < sz_y_f; p_y++) {
|
||||||
|
mvwprintw(parent_win, p_y, p_x, "%*s", sz_x - 1, "");
|
||||||
|
}
|
||||||
|
char p_info[64];
|
||||||
|
uint32_t p_len;
|
||||||
|
p_x = 1;
|
||||||
|
|
||||||
|
sprintf(p_info, "page: %u/%u files: %u left: %u%n", fl_ui->current_page,
|
||||||
|
fl_ui->pages, fl_ui->current_count, fl_ui->full_count, &p_len);
|
||||||
|
|
||||||
|
uint32_t l_pad = (sz_x - p_len) / 2;
|
||||||
|
|
||||||
|
wattrset(parent_win, A_BOLD);
|
||||||
|
mvwprintw(parent_win, p_y, p_x, "%*s%s%*s", l_pad, "", p_info, l_pad, "");
|
||||||
|
wattroff(parent_win, A_BOLD);
|
||||||
|
|
||||||
|
/* draw file info */
|
||||||
|
p_y = 1;
|
||||||
|
p_x = 1;
|
||||||
|
WINDOW *i_win = *fl_ui->info_win;
|
||||||
|
wclear(i_win);
|
||||||
|
|
||||||
|
char size_text[64];
|
||||||
|
size_to_text(active_el->size, size_text);
|
||||||
|
|
||||||
|
mvwprintw(i_win, p_y++, p_x, "Size: %s", size_text);
|
||||||
|
mvwprintw(i_win, p_y++, p_x, "Owner: %s", active_el->owner);
|
||||||
|
mvwprintw(i_win, p_y++, p_x, "Description: ");
|
||||||
|
print_multiline_text(i_win, active_el->description, sz_x, p_y, p_x, 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef FILE_LIST_H
|
||||||
|
#define FILE_LIST_H
|
||||||
|
#include "../widget.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
widget_t w;
|
||||||
|
fl_item_t **current;
|
||||||
|
fl_item_t **start;
|
||||||
|
int32_t current_idx;
|
||||||
|
uint32_t current_count;
|
||||||
|
uint32_t full_count;
|
||||||
|
uint32_t pages;
|
||||||
|
uint32_t current_page;
|
||||||
|
uint32_t max_lines;
|
||||||
|
WINDOW *const* info_win;
|
||||||
|
uint32_t activate_last : 1;
|
||||||
|
} ui_file_list_t;
|
||||||
|
|
||||||
|
void draw_file_list(ui_file_list_t *fl_ui);
|
||||||
|
void redraw_file_list(ui_file_list_t *fl_ui);
|
||||||
|
ui_file_list_t *init_file_list(WINDOW **win, WINDOW *const* info_win);
|
||||||
|
void file_list_cb(callback_args_t *args);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
#include "fs_file_list.h"
|
||||||
|
#include "progress_bar.h"
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void reset_file_list(ui_fs_file_list_t *fl_ui);
|
||||||
|
|
||||||
|
struct fl_args {
|
||||||
|
char *name;
|
||||||
|
u_char d_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void fl_add(fs_fl_item_t **f_start, fs_fl_item_t **f_current,
|
||||||
|
struct fl_args *fargs) {
|
||||||
|
fs_fl_item_t *c_item = malloc(sizeof(fs_fl_item_t));
|
||||||
|
c_item->name = malloc(strlen(fargs->name) + 1);
|
||||||
|
strcpy(c_item->name, fargs->name);
|
||||||
|
c_item->next = NULL;
|
||||||
|
c_item->d_type = fargs->d_type;
|
||||||
|
if (*f_start == NULL) {
|
||||||
|
c_item->prev = NULL;
|
||||||
|
*f_start = c_item;
|
||||||
|
*f_current = c_item;
|
||||||
|
} else {
|
||||||
|
c_item->prev = *f_current;
|
||||||
|
(*f_current)->next = c_item;
|
||||||
|
*f_current = c_item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fl_clear(fs_fl_item_t **start, fs_fl_item_t **arg_current) {
|
||||||
|
if (*start == NULL)
|
||||||
|
return;
|
||||||
|
fs_fl_item_t *next, *current;
|
||||||
|
current = *start;
|
||||||
|
|
||||||
|
do {
|
||||||
|
next = current->next;
|
||||||
|
free(current->name);
|
||||||
|
free(current);
|
||||||
|
} while ((current = next) != NULL);
|
||||||
|
*start = NULL;
|
||||||
|
*arg_current = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_fl_item_t *get_files_from_fs(char *path) {
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *dent;
|
||||||
|
char name[64];
|
||||||
|
struct fl_args f_args;
|
||||||
|
|
||||||
|
fs_fl_item_t *d_start = NULL, *d_current = NULL; /* directories */
|
||||||
|
fs_fl_item_t *f_start = NULL, *f_current = NULL; /* files */
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir) {
|
||||||
|
return NULL;
|
||||||
|
errno = 1;
|
||||||
|
}
|
||||||
|
while ((dent = readdir(dir)) != NULL) {
|
||||||
|
if ((f_args.d_type = dent->d_type) == DT_DIR) {
|
||||||
|
if (!strcmp(dent->d_name, "."))
|
||||||
|
continue;
|
||||||
|
sprintf(name, "/%s", dent->d_name);
|
||||||
|
f_args.name = name;
|
||||||
|
fl_add(&d_start, &d_current, &f_args);
|
||||||
|
} else {
|
||||||
|
f_args.name = dent->d_name;
|
||||||
|
sprintf(name, "%s", dent->d_name);
|
||||||
|
fl_add(&f_start, &f_current, &f_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d_current != NULL)
|
||||||
|
d_current->next = f_start;
|
||||||
|
if (f_start != NULL)
|
||||||
|
f_start->prev = d_current;
|
||||||
|
return d_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void select_item(ui_fs_file_list_t *fui, int32_t *resp_data) {
|
||||||
|
char *bash_case = NULL;
|
||||||
|
char *selection = NULL;
|
||||||
|
size_t dp_current;
|
||||||
|
if (fui->current->d_type == DT_DIR) {
|
||||||
|
if (!strcmp("/..", fui->current->name)) {
|
||||||
|
bash_case = strrchr(fui->d_path, '/');
|
||||||
|
if (bash_case != NULL) {
|
||||||
|
*bash_case = '\0';
|
||||||
|
fl_clear(&(fui->start), &(fui->current));
|
||||||
|
fui->start = get_files_from_fs(fui->d_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dp_current = strlen(fui->d_path);
|
||||||
|
selection = fui->current->name + 1;
|
||||||
|
fui->d_path =
|
||||||
|
realloc(fui->d_path, dp_current + strlen(selection) + 2);
|
||||||
|
sprintf(fui->d_path, "%s/%s", fui->d_path, selection);
|
||||||
|
fl_clear(&(fui->start), &(fui->current));
|
||||||
|
fui->start = get_files_from_fs(fui->d_path);
|
||||||
|
}
|
||||||
|
fui->current = fui->start;
|
||||||
|
fui->current_idx = 0;
|
||||||
|
draw_fs_file_list(fui);
|
||||||
|
} else if (fui->current->d_type == DT_REG) {
|
||||||
|
*resp_data = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_file_list_cb(callback_args_t *args) {
|
||||||
|
ui_fs_file_list_t *fui = args->element;
|
||||||
|
int32_t key = *((int32_t *)args->data);
|
||||||
|
int32_t q_len = 0;
|
||||||
|
fs_fl_item_t *f_item;
|
||||||
|
ui_progress_bar_t *pb;
|
||||||
|
switch (key) {
|
||||||
|
case KEY_DOWN:
|
||||||
|
if (fui->current->next != NULL) {
|
||||||
|
fui->current = fui->current->next;
|
||||||
|
fui->current_idx++;
|
||||||
|
draw_fs_file_list(fui);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_UP:
|
||||||
|
if (fui->current->prev != NULL) {
|
||||||
|
fui->current = fui->current->prev;
|
||||||
|
fui->current_idx--;
|
||||||
|
draw_fs_file_list(fui);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
select_item(fui, (int32_t *) args->resp_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_fs_file_list_t *init_fs_file_list(WINDOW **win, widget_t *w_parent) {
|
||||||
|
ui_fs_file_list_t *fl_ui = malloc(sizeof(ui_fs_file_list_t));
|
||||||
|
WINDOW *win_par = *(w_parent->w_parent->parent_win);
|
||||||
|
init_widget(&(fl_ui->w), w_parent, win, "");
|
||||||
|
fl_ui->current_idx = 0;
|
||||||
|
fl_ui->info_win = NULL;
|
||||||
|
fl_ui->d_path = get_current_dir_name();
|
||||||
|
fl_ui->start = get_files_from_fs(fl_ui->d_path);
|
||||||
|
fl_ui->current = fl_ui->start;
|
||||||
|
fl_ui->w.callback = fs_file_list_cb;
|
||||||
|
fl_ui->w.x = getmaxx(win_par) / 10 * 8;
|
||||||
|
fl_ui->w.y = getmaxy(win_par) / 10 * 8;
|
||||||
|
return fl_ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_fs_file_list(ui_fs_file_list_t *fl_ui) { fl_ui->current_idx = 0; }
|
||||||
|
|
||||||
|
void draw_fs_file_list(ui_fs_file_list_t *fl_ui) {
|
||||||
|
int32_t sz_y, sz_x;
|
||||||
|
int32_t p_y, p_x;
|
||||||
|
WINDOW *win = *(fl_ui->w.parent_win);
|
||||||
|
getmaxyx(win, sz_y, sz_x);
|
||||||
|
int32_t sz_y_f = sz_y - 2; // actual size (without box)
|
||||||
|
int32_t sz_x_f = sz_x - 2; // actual size (without box)
|
||||||
|
p_y = 1;
|
||||||
|
p_x = 1;
|
||||||
|
fs_fl_item_t *el = fl_ui->start;
|
||||||
|
fs_fl_item_t *active_el = fl_ui->start;
|
||||||
|
|
||||||
|
if (fl_ui->current_idx + 1 >= sz_y_f) {
|
||||||
|
p_y -= fl_ui->current_idx - sz_y_f + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
wattrset(win, A_REVERSE); /* Match with modal background */
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (p_y < 1) {
|
||||||
|
p_y++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (el == fl_ui->current) {
|
||||||
|
wattrset(win, COLOR_PAIR(3) | A_BOLD | A_REVERSE);
|
||||||
|
active_el = el;
|
||||||
|
}
|
||||||
|
p_x = 1;
|
||||||
|
mvwprintw(win, p_y, p_x, "%s%n", el->name, &p_x);
|
||||||
|
mvwprintw(win, p_y, p_x + 1, "%*s", sz_x_f - p_x, "");
|
||||||
|
if (el == fl_ui->current) {
|
||||||
|
wattroff(win, COLOR_PAIR(3) | A_BOLD);
|
||||||
|
}
|
||||||
|
p_y++;
|
||||||
|
} while ((el = el->next) != NULL && p_y < sz_y_f);
|
||||||
|
|
||||||
|
p_x = 1;
|
||||||
|
|
||||||
|
for (; p_y < sz_y_f; p_y++) {
|
||||||
|
mvwprintw(win, p_y, p_x, "%*s", sz_x_f - 1, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
wattroff(win, A_BOLD | A_REVERSE);
|
||||||
|
wattrset(win, COLOR_PAIR(0));
|
||||||
|
curs_set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_fs_file_list(ui_fs_file_list_t *fui) {
|
||||||
|
fl_clear(&(fui->start), &(fui->current));
|
||||||
|
free(fui);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef FS_FILE_LIST_H
|
||||||
|
#define FS_FILE_LIST_H
|
||||||
|
#include "../widget.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
typedef struct fs_fl_item {
|
||||||
|
char *name;
|
||||||
|
struct fs_fl_item *next;
|
||||||
|
struct fs_fl_item *prev;
|
||||||
|
u_char d_type;
|
||||||
|
} fs_fl_item_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
widget_t w;
|
||||||
|
fs_fl_item_t *current;
|
||||||
|
fs_fl_item_t *start;
|
||||||
|
int32_t current_idx;
|
||||||
|
WINDOW *const* info_win;
|
||||||
|
char *d_path;
|
||||||
|
} ui_fs_file_list_t;
|
||||||
|
|
||||||
|
void draw_fs_file_list(ui_fs_file_list_t *fl_ui);
|
||||||
|
void redraw_fs_file_list(ui_fs_file_list_t *fl_ui);
|
||||||
|
void destroy_fs_file_list(ui_fs_file_list_t *fl_ui);
|
||||||
|
ui_fs_file_list_t *init_fs_file_list(WINDOW **win, widget_t *w_parent);
|
||||||
|
void fs_file_list_cb(callback_args_t *args);
|
||||||
|
void reset_fs_file_list(ui_fs_file_list_t *fl_ui);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
#include "group.h"
|
||||||
|
#include "button.h"
|
||||||
|
#include "fs_file_list.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "progress_bar.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define MAKE_RESPONSE_M1(args, resp_data, response) \
|
||||||
|
if (args->resp_data != NULL) { \
|
||||||
|
*response = -1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
void group_default_callback(callback_args_t *args) {
|
||||||
|
group_t *g = (group_t *)args->element;
|
||||||
|
int32_t key = *((int32_t *)args->data);
|
||||||
|
int32_t *response = (int32_t *)args->resp_data;
|
||||||
|
input_t *input;
|
||||||
|
widget_t *widget;
|
||||||
|
group_el_t *element_ptr;
|
||||||
|
int32_t element_idx = -1;
|
||||||
|
u_int32_t start_pos = 0;
|
||||||
|
callback_args_t new_args;
|
||||||
|
switch (key) {
|
||||||
|
case '\n': /* Enter */
|
||||||
|
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
|
||||||
|
*response = element_idx;
|
||||||
|
break;
|
||||||
|
case KEY_BACKSPACE:
|
||||||
|
case KEY_DL:
|
||||||
|
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
|
||||||
|
if (element_ptr->type == w_input) {
|
||||||
|
input = (input_t *)element_ptr->element;
|
||||||
|
if (input->value_len) {
|
||||||
|
if (input->cur_pos > 0) {
|
||||||
|
start_pos = input->value_len-- - input->cur_pos;
|
||||||
|
memmove(input->value + start_pos - 1, input->value + start_pos,
|
||||||
|
input->value_len - start_pos + 2);
|
||||||
|
} else {
|
||||||
|
input->value[--input->value_len] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MAKE_RESPONSE_M1(args, resp_data, response);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
|
||||||
|
if (element_ptr->type == w_input) {
|
||||||
|
input = (input_t *)element_ptr->element;
|
||||||
|
if (input->max_len > input->value_len) {
|
||||||
|
if (input->cur_pos > 0) {
|
||||||
|
start_pos = input->value_len++ - input->cur_pos;
|
||||||
|
memmove(input->value + start_pos + 1, input->value + start_pos,
|
||||||
|
input->value_len - start_pos);
|
||||||
|
input->value[start_pos] = key;
|
||||||
|
} else {
|
||||||
|
input->value[input->value_len++] = key;
|
||||||
|
input->value[input->value_len] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
widget = (widget_t *) element_ptr->element;
|
||||||
|
if (widget->callback != NULL) {
|
||||||
|
memccpy(&new_args, args, 1, sizeof(callback_args_t));
|
||||||
|
new_args.element = element_ptr->element;
|
||||||
|
widget->callback(&new_args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MAKE_RESPONSE_M1(args, resp_data, response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
|
||||||
|
enum g_direction direction) {
|
||||||
|
group_t *group = malloc(sizeof(group_t));
|
||||||
|
init_widget(&(group->w), w_parent, win, "");
|
||||||
|
/* count elements */
|
||||||
|
group->count = 0;
|
||||||
|
for (; children[group->count].type != w_end; group->count++)
|
||||||
|
;
|
||||||
|
group->w.w_parent = w_parent;
|
||||||
|
group->w.callback = group_default_callback;
|
||||||
|
if (group->count == 0) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
group->elements = calloc(group->count, sizeof(group_el_t));
|
||||||
|
group_el_t *elements = group->elements;
|
||||||
|
for (int32_t i = 0; i < group->count; i++) {
|
||||||
|
elements[i].type = children[i].type;
|
||||||
|
elements[i].is_default = children[i].is_default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init child elements */
|
||||||
|
for (int32_t i = 0; i < group->count; i++) {
|
||||||
|
widget_t *w;
|
||||||
|
switch (elements[i].type) {
|
||||||
|
case w_button:
|
||||||
|
elements[i].element = init_button(win, &(group->w), children[i].label);
|
||||||
|
w = &(((button_t *)elements[i].element)->w);
|
||||||
|
break;
|
||||||
|
case w_box:
|
||||||
|
case w_group:
|
||||||
|
case w_end:
|
||||||
|
break;
|
||||||
|
case w_input:
|
||||||
|
elements[i].element =
|
||||||
|
init_input(win, &(group->w), children[i].label, children[i].length,
|
||||||
|
children[i].is_hidden_value);
|
||||||
|
w = &(((input_t *)elements[i].element)->w);
|
||||||
|
break;
|
||||||
|
case w_progress:
|
||||||
|
elements[i].element = init_ui_progress_bar(win, &(group->w));
|
||||||
|
w = &(((ui_progress_bar_t *)elements[i].element)->w);
|
||||||
|
break;
|
||||||
|
case w_fs_file_list:
|
||||||
|
elements[i].element = init_fs_file_list(win, &(group->w));
|
||||||
|
w = &(((ui_progress_bar_t *)elements[i].element)->w);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* set dimensions */
|
||||||
|
elements[i].id = w->id;
|
||||||
|
if (direction == horizontal) {
|
||||||
|
w->m_x = group->w.m_x + 1 + group->w.x;
|
||||||
|
w->m_y = group->w.m_y;
|
||||||
|
group->w.x += w->x + 1;
|
||||||
|
if (group->w.y < w->y)
|
||||||
|
group->w.y = w->y;
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
group->first_id = w->id;
|
||||||
|
group->last_id = w->id;
|
||||||
|
} else {
|
||||||
|
group->last_id = w->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_group(WINDOW *win, group_t *group, int32_t active_id,
|
||||||
|
widget_t *dialog_w) {
|
||||||
|
group_el_t *children = group->elements;
|
||||||
|
group_el_t *active_element = NULL;
|
||||||
|
uint32_t active_idx;
|
||||||
|
for (int i = 0; i < group->count; i++) {
|
||||||
|
group_el_t *el = &children[i];
|
||||||
|
switch (el->type) {
|
||||||
|
case w_button:
|
||||||
|
draw_button((button_t *)el->element, active_id);
|
||||||
|
break;
|
||||||
|
case w_box:
|
||||||
|
case w_group:
|
||||||
|
case w_end:
|
||||||
|
break;
|
||||||
|
case w_input:
|
||||||
|
draw_input((input_t *)el->element, active_id);
|
||||||
|
break;
|
||||||
|
case w_progress:
|
||||||
|
draw_ui_progress_bar((ui_progress_bar_t *)el->element);
|
||||||
|
break;
|
||||||
|
case w_fs_file_list:
|
||||||
|
draw_fs_file_list((ui_fs_file_list_t *)el->element);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_group(group_t *group) {
|
||||||
|
group_el_t *children = group->elements;
|
||||||
|
for (int i = 0; i < group->count; i++) {
|
||||||
|
group_el_t *el = &children[i];
|
||||||
|
switch (el->type) {
|
||||||
|
case w_button:
|
||||||
|
destroy_button(el->element);
|
||||||
|
break;
|
||||||
|
case w_box:
|
||||||
|
case w_group:
|
||||||
|
case w_end:
|
||||||
|
break;
|
||||||
|
case w_input:
|
||||||
|
destroy_input(el->element);
|
||||||
|
break;
|
||||||
|
case w_progress:
|
||||||
|
destroy_ui_progress_bar(el->element);
|
||||||
|
break;
|
||||||
|
case w_fs_file_list:
|
||||||
|
destroy_fs_file_list(el->element);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (group->elements != NULL) {
|
||||||
|
free(group->elements);
|
||||||
|
}
|
||||||
|
free(group);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef GROUP_H
|
||||||
|
#define GROUP_H
|
||||||
|
|
||||||
|
#include "../widget.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum g_direction {
|
||||||
|
horizontal,
|
||||||
|
vertical,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id;
|
||||||
|
void *element;
|
||||||
|
enum w_type type;
|
||||||
|
uint32_t is_default : 1;
|
||||||
|
} group_el_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum w_type type;
|
||||||
|
uint32_t is_default : 1;
|
||||||
|
uint32_t is_hidden_value : 1;
|
||||||
|
char label[DIALOGUE_TITLE];
|
||||||
|
uint32_t length;
|
||||||
|
} group_el_init_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
widget_t w;
|
||||||
|
group_el_t *elements;
|
||||||
|
enum g_direction direction;
|
||||||
|
uint32_t count;
|
||||||
|
uint32_t first_id, last_id;
|
||||||
|
} group_t;
|
||||||
|
|
||||||
|
#define FIND_ACTIVE_ELEMENT(g, active_id, element_ptr, element_idx) \
|
||||||
|
element_idx = active_id - g->first_id; \
|
||||||
|
element_ptr = &(g->elements[element_idx]);
|
||||||
|
|
||||||
|
group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
|
||||||
|
enum g_direction dir);
|
||||||
|
void draw_group(WINDOW *win, group_t *group, int32_t active_id,
|
||||||
|
widget_t *dialog_w);
|
||||||
|
void destroy_group(group_t *group);
|
||||||
|
void group_default_callback(callback_args_t *args);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../app.h"
|
||||||
|
#include "../widget.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
|
||||||
|
uint32_t length, uint32_t is_hidden_value) {
|
||||||
|
input_t *input = malloc(sizeof(input_t));
|
||||||
|
init_widget(&(input->w), w_parent, win, label);
|
||||||
|
input->is_disabled = 0;
|
||||||
|
input->w.y = 3; // with borders
|
||||||
|
input->w.x = length + 3; // with borders and extra space for the last element
|
||||||
|
uint32_t t_len = strlen(input->w.title) + 4; // with borders and space
|
||||||
|
if (input->w.x < t_len)
|
||||||
|
input->w.x = t_len;
|
||||||
|
input->w.m_x = 1;
|
||||||
|
input->value[0] = '\0';
|
||||||
|
input->value_len = 0;
|
||||||
|
input->max_len = length;
|
||||||
|
input->is_hidden = is_hidden_value;
|
||||||
|
input->cur_pos = 0;
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t draw_input(input_t *input, uint32_t active_id) {
|
||||||
|
const char stars[] = "*******************";
|
||||||
|
WINDOW *win = *(input->w.parent_win);
|
||||||
|
uint32_t margin_y = input->w.m_y + input->w.w_parent->m_y;
|
||||||
|
uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x;
|
||||||
|
|
||||||
|
wattrset(win, COLOR_PAIR(modal_color_pair));
|
||||||
|
|
||||||
|
mvwhline(win, margin_y, margin_x, 0, input->w.x);
|
||||||
|
mvwhline(win, margin_y + 2, margin_x, 0, input->w.x);
|
||||||
|
|
||||||
|
mvwprintw(win, margin_y, margin_x + 1, " %s ", input->w.title);
|
||||||
|
|
||||||
|
// left
|
||||||
|
mvwvline(win, margin_y, margin_x, ACS_ULCORNER, 1);
|
||||||
|
mvwvline(win, margin_y + 1, margin_x, 0, 1);
|
||||||
|
mvwvline(win, margin_y + 2, margin_x, ACS_LLCORNER, 1);
|
||||||
|
// right
|
||||||
|
mvwvline(win, margin_y, margin_x + input->w.x - 1, ACS_URCORNER, 1);
|
||||||
|
mvwvline(win, margin_y + 1, margin_x + input->w.x - 1, 0, 1);
|
||||||
|
mvwvline(win, margin_y + 2, margin_x + input->w.x - 1, ACS_LRCORNER, 1);
|
||||||
|
|
||||||
|
margin_x++;
|
||||||
|
|
||||||
|
if (input->w.id == active_id) {
|
||||||
|
wattrset(win, COLOR_PAIR(modal_color_pair) | A_BOLD | A_REVERSE);
|
||||||
|
} else {
|
||||||
|
wattrset(win, COLOR_PAIR(0) | A_BOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t x_c = 0;
|
||||||
|
if (input->is_hidden) {
|
||||||
|
mvwprintw(win, margin_y + 1, margin_x, "%.*s%*s", (int) input->value_len, stars,
|
||||||
|
input->w.x - input->value_len - 2, "");
|
||||||
|
} else {
|
||||||
|
mvwprintw(win, margin_y + 1, margin_x, "%s%*s", input->value,
|
||||||
|
input->w.x - input->value_len - 2, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
input->w.cur.y = margin_y + 1;
|
||||||
|
input->w.cur.x = margin_x;
|
||||||
|
|
||||||
|
wattroff(win, A_BOLD | A_REVERSE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_input(input_t *btn) { free(btn); }
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef INPUT_H
|
||||||
|
#define INPUT_H
|
||||||
|
|
||||||
|
#include "../../main.h"
|
||||||
|
#include "../widget.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
widget_t w;
|
||||||
|
char value[INPUT_TEXT];
|
||||||
|
uint32_t cur_pos; /* is relative to the end of a string */
|
||||||
|
uint32_t value_len;
|
||||||
|
uint32_t max_len;
|
||||||
|
uint32_t is_disabled : 1;
|
||||||
|
uint32_t is_hidden : 1;
|
||||||
|
} input_t;
|
||||||
|
|
||||||
|
input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
|
||||||
|
uint32_t size, uint32_t is_hidden_value);
|
||||||
|
int32_t draw_input(input_t *input, uint32_t active_id);
|
||||||
|
void destroy_input(input_t *input);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#include "progress_bar.h"
|
||||||
|
#include "../app.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
ui_progress_bar_t *init_ui_progress_bar(WINDOW **win, widget_t *w_parent) {
|
||||||
|
WINDOW *win_par = *(w_parent->w_parent->parent_win);
|
||||||
|
ui_progress_bar_t *pb = malloc(sizeof(ui_progress_bar_t));
|
||||||
|
init_widget(&pb->w, w_parent, win, "");
|
||||||
|
pb->procent = 0;
|
||||||
|
pb->text[0] = '\0';
|
||||||
|
pb->w.y = 4;
|
||||||
|
pb->w.x = getmaxx(win_par) / 10 * 9;
|
||||||
|
return pb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_ui_progress_bar(ui_progress_bar_t *pb) {
|
||||||
|
WINDOW *win = *(pb->w.w_parent->parent_win);
|
||||||
|
uint32_t margin_y = pb->w.m_y + pb->w.w_parent->m_y;
|
||||||
|
uint32_t margin_x = pb->w.m_x + pb->w.w_parent->m_x + 1;
|
||||||
|
|
||||||
|
wattrset(win, COLOR_PAIR(modal_color_pair));
|
||||||
|
|
||||||
|
mvwhline(win, margin_y, margin_x, 0, pb->w.x - 1);
|
||||||
|
|
||||||
|
float procent = pb->procent;
|
||||||
|
procent /= 100;
|
||||||
|
uint32_t filled_num = procent * pb->w.x;
|
||||||
|
if (filled_num > 2) {
|
||||||
|
filled_num -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < 3; i++) {
|
||||||
|
wattrset(win, COLOR_PAIR(1) | A_REVERSE);
|
||||||
|
mvwprintw(win, margin_y + i, margin_x + 1, "%*s", filled_num, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
wattrset(win, COLOR_PAIR(modal_color_pair));
|
||||||
|
|
||||||
|
// bottom line
|
||||||
|
mvwhline(win, margin_y + 3, margin_x, 0, pb->w.x - 1);
|
||||||
|
// left
|
||||||
|
mvwvline(win, margin_y, margin_x, ACS_ULCORNER, 1);
|
||||||
|
mvwvline(win, margin_y + 1, margin_x, 0, 1);
|
||||||
|
mvwvline(win, margin_y + 2, margin_x, 0, 1);
|
||||||
|
mvwvline(win, margin_y + 3, margin_x, ACS_LLCORNER, 1);
|
||||||
|
// right
|
||||||
|
mvwvline(win, margin_y, margin_x + pb->w.x - 2, ACS_URCORNER, 1);
|
||||||
|
mvwvline(win, margin_y + 1, margin_x + pb->w.x - 2, 0, 1);
|
||||||
|
mvwvline(win, margin_y + 2, margin_x + pb->w.x - 2, 0, 1);
|
||||||
|
mvwvline(win, margin_y + 3, margin_x + pb->w.x - 2, ACS_LRCORNER, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_ui_progress_bar(void *_pb) {
|
||||||
|
ui_progress_bar_t *pb = (ui_progress_bar_t *)_pb;
|
||||||
|
free(pb);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef PROGRESS_BAR_H
|
||||||
|
#define PROGRESS_BAR_H
|
||||||
|
#include "../widget.h"
|
||||||
|
typedef struct {
|
||||||
|
widget_t w;
|
||||||
|
uint32_t procent;
|
||||||
|
char text[24];
|
||||||
|
} ui_progress_bar_t;
|
||||||
|
void destroy_ui_progress_bar(void *_pb);
|
||||||
|
void draw_ui_progress_bar(ui_progress_bar_t *pb);
|
||||||
|
ui_progress_bar_t *init_ui_progress_bar(WINDOW **win, widget_t *w_parent);
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user