diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..5a804e9 --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + CompilationDatabase: build \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 059ac86..055906d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,8 @@ add_executable(zbbs-server) set_property(TARGET zbbs-server PROPERTY C_STANDARD 23) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + find_package(PostgreSQL REQUIRED) if(NOT PostgreSQL_FOUND) message(FATAL_ERROR "PostgreSQL not found. Please install libpq-dev or set PostgreSQL_ROOT.") diff --git a/src/client.c b/src/client.c index 901eb6f..8a0dee6 100644 --- a/src/client.c +++ b/src/client.c @@ -12,15 +12,16 @@ void process_client_command(char *line, session *sess, server_data_t *s_d) { char arg_1[32]; char arg_2[32]; uint32_t res; - uint32_t limit, page; + i_file_list_t fl_args; + fl_args.name = NULL; sscanf(line, "%s %s", arg_1, arg_2); if (!strcmp(arg_1, "file")) { /* LIST */ if (!strcmp(arg_2, "list")) { - sscanf(line, "%*s %*s %u %u", &limit, &page); - file_list(sess, s_d, limit, page); + sscanf(line, "%*s %*s %u %u", &(fl_args.limit), &(fl_args.page)); + file_list(sess, s_d, &fl_args); return; } @@ -39,6 +40,20 @@ void process_client_command(char *line, session *sess, server_data_t *s_d) { sess->state = OP_DOWNLOAD; return; } + + /* SEARCH */ + if (!strcmp(arg_2, "search")) { + char *s_type = arg_1; /* since we don't need the contents of arg_1 and arg_2 variables */ + char *s_val = arg_2; + sscanf(line, "%*s %*s %s %s %u %u", s_type, s_val, &(fl_args.limit), &(fl_args.page)); + + /* by name */ + if (!strcmp(s_type, "name")) { + fl_args.name = s_val; + } + + file_list(sess, s_d, &fl_args); + } } if (!strncmp(line, "exit", sizeof "exit")) { diff --git a/src/db.c b/src/db.c index d65e7eb..3f68fcc 100644 --- a/src/db.c +++ b/src/db.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -126,7 +127,7 @@ int32_t db_user_auth(i_auth_t *c, o_auth_t *r) { return exit_query(1); const char *pass = PQgetvalue(res, 0, 2); - string_to_SHA256( c->pass, passHashed); + string_to_SHA256(c->pass, passHashed); if (pass == NULL) { /* TODO: return */ } @@ -276,13 +277,15 @@ uint64_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start, char query[512]; char sort_by[16] = "id"; char sort_dir[5] = "ASC"; - const char *paramValues[2]; - int paramLengths[2]; - int paramFormats[2]; + const char *paramValues[3]; + int paramLengths[3]; + int paramFormats[3]; int i; uint64_t count; uint64_t n_limit = htobe64(arg->limit); uint64_t n_offset = htobe64(arg->offset); + bool by_name = strlen(arg->name) > 0; + uint32_t params_num = 3; switch (arg->sort_by) { case NAME: @@ -305,21 +308,35 @@ uint64_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start, paramValues[0] = (char *)&n_limit; paramValues[1] = (char *)&n_offset; + paramValues[2] = arg->name; paramLengths[0] = sizeof(n_limit); paramLengths[1] = sizeof(n_offset); + paramLengths[2] = strlen(arg->name); paramFormats[0] = BIN; paramFormats[1] = BIN; + paramFormats[2] = TEXT; - sprintf(query, - "SELECT files.id, user_id, name, size, description, permissions, " - "hash, username " - "FROM files JOIN users ON user_id = users.id " - "ORDER BY files.%s %s LIMIT $1 OFFSET $2", - sort_by, sort_dir); + if (!by_name) { + params_num = 2; + sprintf(query, + "SELECT files.id, user_id, name, size, description, permissions, " + "hash, username " + "FROM files JOIN users ON user_id = users.id " + "ORDER BY files.%s %s LIMIT $1 OFFSET $2", + sort_by, sort_dir); + } else { + sprintf(query, + "SELECT files.id, user_id, name, size, description, permissions, " + "hash, username " + "FROM files JOIN users ON user_id = users.id " + "WHERE name ILIKE '%%' || $3 || '%%'" + "ORDER BY files.%s %s LIMIT $1 OFFSET $2", + sort_by, sort_dir); + } - res = PQexecParams(conn, query, 2, NULL, paramValues, paramLengths, + res = PQexecParams(conn, query, params_num, NULL, paramValues, paramLengths, paramFormats, TEXT); if (PQresultStatus(res) != PGRES_TUPLES_OK && !PQntuples(res)) @@ -355,8 +372,17 @@ uint64_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start, clearRes(); - res = PQexec(conn, "SELECT COUNT(id) " - "FROM files "); + if (by_name) { + res = PQexecParams(conn, + "SELECT COUNT(id) " + "FROM files " + "WHERE name ILIKE '%%' || $1 || '%%'", + 1, NULL, paramValues + 2, paramLengths + 2, + paramFormats + 2, TEXT); + } else { + res = PQexec(conn, "SELECT COUNT(id) " + "FROM files "); + } if (PQresultStatus(res) != PGRES_TUPLES_OK && !PQntuples(res)) return exit_query_2(0); diff --git a/src/file_p.c b/src/file_p.c index da79cc8..7de4b45 100644 --- a/src/file_p.c +++ b/src/file_p.c @@ -1,11 +1,11 @@ #include "file_p.h" #include "db.h" -#include #include "main.h" #include "session.h" #include #include #include +#include #include #include #include @@ -39,7 +39,7 @@ void clear_list(fl_t *start) { } } -void file_list(session *sess, server_data_t *s_d, uint32_t limit, uint32_t page) { +void file_list(session *sess, server_data_t *s_d, i_file_list_t *f_args) { fl_t *fl_start, *fl_current; char item_h[256]; i_get_files_db args; @@ -54,25 +54,32 @@ void file_list(session *sess, server_data_t *s_d, uint32_t limit, uint32_t page) sess->fl_current = NULL; } - args.limit = limit; - args.offset = limit * (page - 1); + args.limit = f_args->limit; + args.offset = f_args->limit * (f_args->page - 1); args.sort_by = ID; args.sort_direction = ASC; + if (f_args->name != NULL) { + strcpy(args.name, f_args->name); + } else { + args.name[0] = '\0'; + } count = db_get_files_data(&args, &fl_start, &full_count); char page_info[256]; - pages_count = full_count / limit; + pages_count = full_count / f_args->limit; if (!pages_count) pages_count = 1; - if (pages_count % limit) + if (pages_count % f_args->limit) pages_count++; - sprintf(page_info, ":END: PAGE %u/%lu COUNT: %lu/%lu\n", page, pages_count, - count, full_count - (page - 1) * limit); + sprintf(page_info, ":END: PAGE %u/%lu COUNT: %lu/%lu\n", f_args->page, + pages_count, count, full_count - (f_args->page - 1) * f_args->limit); - if (!fl_start) + if (!fl_start) { + write(sess->sd, page_info, strlen(page_info)); return; + } fl_current = fl_start; diff --git a/src/file_p.h b/src/file_p.h index 461adee..394ab5d 100644 --- a/src/file_p.h +++ b/src/file_p.h @@ -1,8 +1,14 @@ #ifndef FILEP_H #define FILEP_H #include "main.h" +#include void clear_list(fl_t *start); -void file_list(session *, server_data_t *, uint32_t limit, uint32_t page); +typedef struct { + uint32_t page; + uint32_t limit; + char *name; +} i_file_list_t; +void file_list(session *, server_data_t *, i_file_list_t *l_args); int file_send_prepare(session *, char *, server_data_t *); enum f_actions { F_UPLOAD,