From 141da4b456ef687d778854e7fb54e822aed7a71c Mon Sep 17 00:00:00 2001 From: ThoNohT Date: Fri, 15 May 2026 14:01:17 +0200 Subject: [PATCH] opds: Send full xml structure with TODO placeholders --- src/main.c | 96 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/src/main.c b/src/main.c index a66a296..56c1433 100644 --- a/src/main.c +++ b/src/main.c @@ -15,11 +15,13 @@ This will ignore any auth headers and always log in with username demo. Noh_Arena temp; -static enum MHD_Result send_response(struct MHD_Connection *connection, int status, SV message) { +static enum MHD_Result send_response(struct MHD_Connection *connection, int status, SV message, bool xml) { struct MHD_Response *response = MHD_create_response_from_buffer( - message.count, (void*)message.elems, MHD_RESPMEM_PERSISTENT); + message.count, (void*)message.elems, MHD_RESPMEM_MUST_COPY); if (!response) return MHD_NO; + if (xml) MHD_add_response_header(response, "content-type", "application/xml"); + enum MHD_Result ret = MHD_queue_response(connection, status, response); MHD_destroy_response(response); return ret; @@ -28,6 +30,7 @@ static enum MHD_Result send_response(struct MHD_Connection *connection, int stat typedef struct { bool is_dir; SV name; + SV full_path; struct tm modified_at; } Library_Entry; @@ -75,6 +78,48 @@ bool create_entry(struct dirent *dir_entry, const char *parent_path, Library_Ent return true; } +char *format_library_entry(Library_Entry entry, char time_buffer[80]) { + strftime(time_buffer, 80, "%Y-%m-%d %H:%M:%S", &entry.modified_at); + + return noh_arena_sprintf( + &temp, + "Entry: %s \npath:'"Nsv_Fmt"'\nName: '"Nsv_Fmt"'\nModified at: %s.\n", + entry.is_dir ? "Dir" : "File", + Nsv_Arg(entry.full_path), + Nsv_Arg(entry.name), + time_buffer); +} + +static void append_entry(Noh_String *response, Library_Entry entry) { + noh_string_append_cstr(response, ""); + noh_string_append_cstr(response, "TODO"); + noh_string_append_cstr(response, "TODO"); + noh_string_append_cstr(response, "TODO"); + if (entry.is_dir) { + noh_string_append_cstr(response, ""); + } else { + noh_string_append_cstr(response, ""); + } + noh_string_append_cstr(response, ""); +} + +static Noh_String create_feed_response(Library_Entry self_path, Library_Entries list) { + (void)self_path; + Noh_String response = {0}; + + noh_string_append_cstr(&response, ""); + noh_string_append_cstr(&response, "TODO"); + noh_string_append_cstr(&response, "TODO"); + noh_string_append_cstr(&response, "TODO"); + noh_string_append_cstr(&response, ""); + noh_string_append_cstr(&response, ""); + + for (size_t i = 0; i < list.count; i++) append_entry(&response, list.elems[i]); + noh_string_append_cstr(&response, ""); + + return response; +} + static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV base_path, SV username) { Noh_String fs_path = {0}; noh_string_append_sv(&fs_path, base_path); @@ -84,12 +129,20 @@ static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV noh_string_append_sv(&fs_path, url); noh_string_append_null(&fs_path); - noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(fs_path)); + Library_Entry self_entry = { + .is_dir = true, + .full_path = noh_sv_from_string(&fs_path), + .modified_at = {0}, + }; + (void)self_entry; + + noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(self_entry.name)); DIR *dir = opendir(fs_path.elems); if (dir) { Library_Entries list = {0}; + // Build up list of entries. noh_arena_save(&temp); struct dirent *entry = noh_arena_alloc(&temp, sizeof(struct dirent)); while ((entry = readdir(dir)) != NULL) { @@ -100,42 +153,33 @@ static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV // Sort entries, folders first, then by name. if (list.count > 1) qsort(list.elems, list.count, sizeof(list.elems[0]), compare_library_entries); - // Print sorted entries. - Noh_String response = {0}; - char *time_buffer = noh_arena_alloc(&temp, 80); - for (size_t i = 0; i < list.count; i++) { - Library_Entry *le = &list.elems[i]; - strftime(time_buffer, 80, "%Y-%m-%d %H:%M:%S", &le->modified_at); - noh_string_append_cstr(&response, - noh_arena_sprintf( - &temp, - "Entry: %s '"Nsv_Fmt"' (modified at %s).\n", le->is_dir ? "Dir" : "File", Nsv_Arg(le->name), time_buffer)); - } - - return send_response(connection, 200, noh_sv_from_string(&response)); + // Create and send response. + Noh_String response = create_feed_response(self_entry, list); + bool result = send_response(connection, 200, noh_sv_from_string(&response), true); + // Cleanup. noh_da_free(&list); + noh_string_free(&response); noh_arena_reset(&temp); - closedir(dir); + return result; + } else if (errno == ENOENT) { closedir(dir); - return send_response(connection, 404, sv("")); + return send_response(connection, 404, sv(""), false); } else { noh_log(NOH_ERROR, "Opening directory failed."); - return send_response(connection, 500, sv("")); + return send_response(connection, 500, sv(""), false); } - - return send_response(connection, 200, sv("TODO: OPDS\n")); } static enum MHD_Result handle_get(struct MHD_Connection *connection, SV url, SV base_path, SV username) { (void)url; (void)username; (void)base_path; - return send_response(connection, 200, sv("TODO: Get\n")); + return send_response(connection, 200, sv("TODO: Get\n"), false); } bool is_slash(const char c) { return c == '/'; } @@ -156,18 +200,18 @@ static enum MHD_Result request_handler( username = sv("demo"); #else struct MHD_BasicAuthInfo *auth = MHD_basic_auth_get_username_password3(connection); - if (!auth) return send_response(connection, 401, sv("")); + if (!auth) return send_response(connection, 401, sv(""), false); username = (SV){ .elems = auth->username, .count = auth->username_len }; SV password = { .elems = auth->password, .count = auth->password_len }; // TODO: Read username from user config. - if (!noh_sv_eq(password, sv("jaja"))) return send_response(connection, 401, sv("")); + if (!noh_sv_eq(password, sv("jaja"))) return send_response(connection, 401, sv(""), false); #endif noh_log(NOH_INFO, "Authenticated as "Nsv_Fmt, Nsv_Arg(username)); - if (strcmp(method, "GET") != 0) return send_response(connection, 405, sv("")); + if (strcmp(method, "GET") != 0) return send_response(connection, 405, sv(""), false); SV url = sv(_url); noh_sv_trim_left(&url, is_slash); @@ -175,7 +219,7 @@ static enum MHD_Result request_handler( if (noh_sv_eq_ci(controller, sv("opds"))) return handle_opds(connection, url, base_path, username); if (noh_sv_eq_ci(controller, sv("get"))) return handle_get(connection, url, base_path, username); - return send_response(connection, 404, sv("")); + return send_response(connection, 404, sv(""), false); } void show_usage(char *program_name, char *error) {