103 lines
4.4 KiB
C
103 lines
4.4 KiB
C
static SV path_to_name(SV path) {
|
|
while (true) {
|
|
SV component = noh_sv_chop_by_delim(&path, '/');
|
|
if (path.count == 0) return component;
|
|
}
|
|
}
|
|
|
|
static void append_entry(Noh_String *response, SV url, Library_Entry entry) {
|
|
noh_string_append_cstr(response, "<entry>");
|
|
noh_string_append_cstr(response, noh_arena_sprintf(&temp, "<id>"Nsv_Fmt"</id>", Nsv_Arg(get_id(entry.full_path))));
|
|
noh_string_append_cstr(response, noh_arena_sprintf(&temp, "<title>"Nsv_Fmt"</title>", entry.name));
|
|
noh_string_append_cstr(response, noh_arena_sprintf(&temp, "<updated>%s</updated>", format_time(entry)));
|
|
if (entry.is_dir) {
|
|
SV opds = sv("opds");
|
|
Noh_String entry_url = build_path(true, false, &opds, &url, &entry.name);
|
|
noh_string_append_cstr(response, noh_arena_sprintf(&temp, "<link rel=\"subsection\" href=\""Nsv_Fmt"\" type=\"application/atom+xml;profile=opds-catalog;kind=navigation\"/>", Nsv_Arg(entry_url)));
|
|
noh_string_free(&entry_url);
|
|
} else {
|
|
SV get = sv("get");
|
|
Noh_String entry_url = build_path(true, false, &get, &url, &entry.name);
|
|
noh_string_append_cstr(response, noh_arena_sprintf(&temp, "<link rel=\"http://opds-spec.org/acquisition\" href=\""Nsv_Fmt"\" type=\"application/epub+zip\"/>", Nsv_Arg(entry_url)));
|
|
noh_string_free(&entry_url);
|
|
}
|
|
noh_string_append_cstr(response, "</entry>");
|
|
}
|
|
|
|
static Noh_String create_feed_response(Library_Entry self_path, SV url, Library_Entries list) {
|
|
(void)self_path;
|
|
Noh_String response = {0};
|
|
|
|
noh_string_append_cstr(&response, "<feed>");
|
|
noh_string_append_cstr(&response, noh_arena_sprintf(&temp, "<id>"Nsv_Fmt"</id>", Nsv_Arg(get_id(self_path.full_path))));
|
|
noh_string_append_cstr(&response, noh_arena_sprintf(&temp, "<title>"Nsv_Fmt"</title>", self_path.name));
|
|
noh_string_append_cstr(&response, noh_arena_sprintf(&temp, "<updated>%s</updated>", format_time(self_path)));
|
|
|
|
SV opds = sv("opds");
|
|
Noh_String self_url = build_path(true, false, &opds, &url);
|
|
noh_string_append_cstr(&response, noh_arena_sprintf(&temp, "<link rel=\"self\" href=\""Nsv_Fmt"\" type=\"application/atom+xml;profile=opds-catalog;kind=navigation\"/>", Nsv_Arg(self_url)));
|
|
noh_string_free(&self_url);
|
|
|
|
noh_string_append_cstr(&response, "<link rel=\"root\" href=\"/opds\" type=\"application/atom+xml;profile=opds-catalog;kind=navigation\"/>");
|
|
|
|
for (size_t i = 0; i < list.count; i++) append_entry(&response, url, list.elems[i]);
|
|
noh_string_append_cstr(&response, "</feed>");
|
|
|
|
return response;
|
|
}
|
|
|
|
static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, Settings settings, SV username) {
|
|
noh_arena_save(&temp);
|
|
Noh_String fs_path = build_path(false, false, &settings.base_path, &username, &url);
|
|
url_decode(&fs_path);
|
|
Noh_String fs_path_cstr = fs_path;
|
|
noh_string_append_null(&fs_path_cstr);
|
|
|
|
Library_Entry self_entry = {
|
|
.is_dir = true,
|
|
.full_path = noh_sv_from_string(fs_path),
|
|
.name = (url.count == 0) ? settings.library_name : path_to_name(noh_sv_from_string(fs_path)),
|
|
.modified_at = {0},
|
|
};
|
|
set_modified_time(&self_entry);
|
|
noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(self_entry.full_path));
|
|
|
|
DIR *dir = opendir(fs_path_cstr.elems);
|
|
if (!dir) {
|
|
if (errno == ENOENT) {
|
|
closedir(dir);
|
|
noh_arena_reset(&temp);
|
|
return send_response(connection, 404, sv(""), false);
|
|
|
|
} else {
|
|
noh_log(NOH_ERROR, "Opening directory failed.");
|
|
noh_arena_reset(&temp);
|
|
return send_response(connection, 500, sv(""), false);
|
|
}
|
|
}
|
|
|
|
Library_Entries list = {0};
|
|
|
|
// Build up list of entries.
|
|
struct dirent *entry = noh_arena_alloc(&temp, sizeof(struct dirent));
|
|
while ((entry = readdir(dir)) != NULL) {
|
|
Library_Entry result = {0};
|
|
if (create_entry(entry, fs_path_cstr.elems, &result)) noh_da_append(&list, result);
|
|
}
|
|
|
|
// Sort entries, folders first, then by name.
|
|
if (list.count > 1) qsort(list.elems, list.count, sizeof(list.elems[0]), compare_library_entries);
|
|
|
|
// Create and send response.
|
|
Noh_String response = create_feed_response(self_entry, url, 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;
|
|
}
|