aboutsummaryrefslogtreecommitdiff
path: root/page.c
diff options
context:
space:
mode:
Diffstat (limited to 'page.c')
-rw-r--r--page.c254
1 files changed, 211 insertions, 43 deletions
diff --git a/page.c b/page.c
index 9776349..970a5bf 100644
--- a/page.c
+++ b/page.c
@@ -3,6 +3,7 @@
#include "page.h"
#include "http.h"
#include "html.h"
+#include "thumbnail.h"
#include <dynstr.h>
#include <dirent.h>
#include <fcntl.h>
@@ -45,7 +46,102 @@
" </form>\n"
#define MAXSIZEFMT "18446744073709551615.0 XiB"
-static int prepare_name(struct html_node *const n, struct stat *const sb,
+static const char *dir_separator(const char *const dir)
+{
+ return dir[strlen(dir) - 1] != '/' ? "/" : "";
+}
+
+static int prepare_thumbnail(struct html_node *const n,
+ const struct stat *const sb,
+ const struct page_resource *const r, const char *const name)
+{
+ int ret = -1, res;
+ const char *const sep = dir_separator(r->res);
+ struct html_node *img;
+ struct dynstr abs, rel;
+ struct stat tsb;
+ struct thumbnail_dim dim;
+ char w[sizeof "18446744073709551615"], h[sizeof w];
+
+ dynstr_init(&abs);
+ dynstr_init(&rel);
+
+ if (!S_ISREG(sb->st_mode))
+ {
+ ret = 0;
+ goto end;
+ }
+ else if (dynstr_append(&rel, "/thumbnails/%s%s%s%s",
+ r->username, r->res, sep, name))
+ {
+ fprintf(stderr, "%s: dynstr_append rel failed\n", __func__);
+ goto end;
+ }
+ else if (dynstr_append(&abs, "%s%s", r->root, rel.str))
+ {
+ fprintf(stderr, "%s: dynstr_append rel failed\n", __func__);
+ goto end;
+ }
+ else if (stat(abs.str, &tsb))
+ {
+ if (errno == ENOENT)
+ ret = 0;
+ else
+ fprintf(stderr, "%s: stat(2): %s\n", __func__, strerror(errno));
+
+ goto end;
+ }
+ else if (thumbnail_dim(abs.str, &dim))
+ {
+ fprintf(stderr, "%s: thumbnail_dim failed\n", __func__);
+ goto end;
+ }
+
+ res = snprintf(w, sizeof w, "%lu", dim.w);
+
+ if (res < 0 || res >= sizeof w)
+ {
+ fprintf(stderr, "%s: snprintf(3) w failed with %d\n", __func__, res);
+ goto end;
+ }
+
+ res = snprintf(h, sizeof h, "%lu", dim.h);
+
+ if (res < 0 || res >= sizeof h)
+ {
+ fprintf(stderr, "%s: snprintf(3) h failed with %d\n", __func__, res);
+ goto end;
+ }
+ else if (!(img = html_node_add_child(n, "img")))
+ {
+ fprintf(stderr, "%s: html_node_add_child failed\n", __func__);
+ goto end;
+ }
+ else if (html_node_add_attr(img, "src", rel.str))
+ {
+ fprintf(stderr, "%s: html_node_add_attr src failed\n", __func__);
+ goto end;
+ }
+ else if (html_node_add_attr(img, "width", w))
+ {
+ fprintf(stderr, "%s: html_node_add_attr w failed\n", __func__);
+ goto end;
+ }
+ else if (html_node_add_attr(img, "height", h))
+ {
+ fprintf(stderr, "%s: html_node_add_attr h failed\n", __func__);
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ dynstr_free(&abs);
+ dynstr_free(&rel);
+ return ret;
+}
+
+static int prepare_name(struct html_node *const n, const struct stat *const sb,
const char *const dir, const char *const name)
{
int ret = -1;
@@ -169,7 +265,7 @@ static int prepare_share(struct html_node *const n,
const struct stat *const sb, const char *const dir, const char *const name)
{
int ret = -1;
- const char *const fdir = dir + strlen("/user");
+ const char *const sep = dir_separator(dir);
struct html_node *form, *file, *submit;
struct dynstr d;
@@ -213,7 +309,7 @@ static int prepare_share(struct html_node *const n,
fprintf(stderr, "%s: html_node_add_attr file name failed\n", __func__);
goto end;
}
- else if (dynstr_append(&d, "%s%s", fdir, name))
+ else if (dynstr_append(&d, "%s%s%s", dir, sep, name))
{
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
goto end;
@@ -243,18 +339,37 @@ end:
return ret;
}
-static int add_element(struct html_node *const n, const char *const dir,
- const char *const res, const char *const name)
+static int user_resource(const struct page_resource *const r,
+ struct dynstr *const d)
+{
+ if (dynstr_append(d, "%s/user/%s%s", r->root, r->username, r->res))
+ {
+ fprintf(stderr, "%s: dynstr_append failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int add_element(const struct page_resource *const r,
+ struct html_node *const n, const char *const absres,
+ const char *const name)
{
int ret = -1;
- enum {NAME, SIZE, DATE, SHARE, COLUMNS};
+ enum {THUMBNAIL, NAME, SIZE, DATE, SHARE, COLUMNS};
+ const char *const sep = dir_separator(r->res);
struct html_node *tr, *td[COLUMNS];
- struct dynstr path;
- const char *const sep = res[strlen(res) - 1] != '/' ? "/" : "";
+ struct dynstr path, rel;
dynstr_init(&path);
+ dynstr_init(&rel);
- if (dynstr_append(&path, "%s%s%s", res, sep, name))
+ if (dynstr_append(&path, "%s%s%s", absres, sep, name))
+ {
+ fprintf(stderr, "%s: dynstr_append failed\n", __func__);
+ goto end;
+ }
+ else if (dynstr_append(&rel, "/user%s%s", r->res, sep))
{
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
goto end;
@@ -266,7 +381,9 @@ static int add_element(struct html_node *const n, const char *const dir,
}
for (size_t i = 0; i < sizeof td / sizeof *td; i++)
- if (!(td[i] = html_node_add_child(tr, "td")))
+ if (i == THUMBNAIL && !thumbnail_configured())
+ continue;
+ else if (!(td[i] = html_node_add_child(tr, "td")))
{
fprintf(stderr, "%s: html_node_add_child td[%zu] failed\n",
__func__, i);
@@ -281,7 +398,13 @@ static int add_element(struct html_node *const n, const char *const dir,
__func__, path.str, strerror(errno));
goto end;
}
- else if (prepare_name(td[NAME], &sb, dir, name))
+ else if (thumbnail_configured()
+ && prepare_thumbnail(td[THUMBNAIL], &sb, r, name))
+ {
+ fprintf(stderr, "%s: prepare_thumbnail failed\n", __func__);
+ goto end;
+ }
+ else if (prepare_name(td[NAME], &sb, rel.str, name))
{
fprintf(stderr, "%s: prepare_name failed\n", __func__);
goto end;
@@ -296,7 +419,7 @@ static int add_element(struct html_node *const n, const char *const dir,
fprintf(stderr, "%s: prepare_date failed\n", __func__);
goto end;
}
- else if (prepare_share(td[SHARE], &sb, dir, name))
+ else if (prepare_share(td[SHARE], &sb, rel.str, name))
{
fprintf(stderr, "%s: prepare_date failed\n", __func__);
goto end;
@@ -306,6 +429,7 @@ static int add_element(struct html_node *const n, const char *const dir,
end:
dynstr_free(&path);
+ dynstr_free(&rel);
return ret;
}
@@ -743,7 +867,6 @@ end:
static struct html_node *resource_layout(const char *const dir,
const struct page_quota *const q, struct html_node **const table)
{
- const char *const fdir = dir + strlen("/user");
struct html_node *const html = html_node_alloc("html"),
*ret = NULL, *head, *body;
@@ -767,17 +890,17 @@ static struct html_node *resource_layout(const char *const dir,
fprintf(stderr, "%s: html_node_add_child table failed\n", __func__);
goto end;
}
- else if (common_head(head, fdir))
+ else if (common_head(head, dir))
{
fprintf(stderr, "%s: common_head failed\n", __func__);
goto end;
}
- else if (prepare_upload_form(body, fdir))
+ else if (prepare_upload_form(body, dir))
{
fprintf(stderr, "%s: prepare_upload_form failed\n", __func__);
goto end;
}
- else if (prepare_mkdir_form(body, fdir))
+ else if (prepare_mkdir_form(body, dir))
{
fprintf(stderr, "%s: prepare_upload_form failed\n", __func__);
goto end;
@@ -808,14 +931,21 @@ end:
return ret;
}
-static int add_elements(const char *const root, const char *const res,
- const char *const dir, struct html_node *const table)
+static int add_elements(const struct page_resource *const r,
+ struct html_node *const table)
{
- int ret = -1;
+ int ret = -1, n = 0;
+ struct dynstr d;
struct dirent **pde = NULL;
- const int n = scandir(res, &pde, NULL, alphasort);
- if (n < 0)
+ dynstr_init(&d);
+
+ if (user_resource(r, &d))
+ {
+ fprintf(stderr, "%s: user_resource failed\n", __func__);
+ goto end;
+ }
+ else if ((n = scandir(d.str, &pde, NULL, alphasort)) < 0)
{
fprintf(stderr, "%s: scandir(3): %s\n", __func__, strerror(errno));
goto end;
@@ -827,9 +957,9 @@ static int add_elements(const char *const root, const char *const res,
const char *const name = de->d_name;
if (!strcmp(name, ".")
- || (!strcmp(name, "..") && !strcmp(root, res)))
+ || (!strcmp(name, "..") && !strcmp(r->user_root, d.str)))
continue;
- else if (add_element(table, dir, res, name))
+ else if (add_element(r, table, d.str, name))
{
fprintf(stderr, "%s: add_element failed\n", __func__);
goto end;
@@ -844,25 +974,25 @@ end:
free(pde[i]);
free(pde);
+ dynstr_free(&d);
return ret;
}
-static int list_dir(struct http_response *const r, const char *const dir,
- const char *const root, const char *const res,
- const struct page_quota *const q)
+static int list_dir(struct http_response *const r,
+ const struct page_resource *const res, const struct page_quota *const q)
{
int ret = -1;
struct dynstr out;
- struct html_node *table, *const html = resource_layout(dir, q, &table);
+ struct html_node *table, *html = NULL;
dynstr_init(&out);
- if (!html)
+ if (!(html = resource_layout(res->res, q, &table)))
{
fprintf(stderr, "%s: resource_layout failed\n", __func__);
goto end;
}
- else if (add_elements(root, res, dir, table))
+ else if (add_elements(res, table))
{
fprintf(stderr, "%s: read_elements failed\n", __func__);
goto end;
@@ -907,14 +1037,14 @@ static int serve_file(struct http_response *const r,
const struct stat *const sb, const char *const res)
{
int ret = -1;
- FILE *const f = fopen(res, "rb");
+ FILE *f = NULL;
struct dynstr b, d;
char *bn;
dynstr_init(&b);
dynstr_init(&d);
- if (!f)
+ if (!(f = fopen(res, "rb")))
{
fprintf(stderr, "%s: fopen(3): %s\n", __func__, strerror(errno));
goto end;
@@ -987,32 +1117,43 @@ static int page_not_found(struct http_response *const r)
return 0;
}
-int page_resource(struct http_response *const r, const char *const dir,
- const char *const root, const char *const res,
- const struct page_quota *const q)
+int page_resource(struct http_response *const r,
+ const struct page_resource *const res, const struct page_quota *const q)
{
+ int ret = -1;
struct stat sb;
+ struct dynstr d;
- if (stat(res, &sb))
+ dynstr_init(&d);
+
+ if (user_resource(res, &d))
+ {
+ fprintf(stderr, "%s: user_resource failed\n", __func__);
+ goto end;
+ }
+ else if (stat(d.str, &sb))
{
fprintf(stderr, "%s: stat(2) %s: %s\n",
- __func__, res, strerror(errno));
+ __func__, res->res, strerror(errno));
if (errno == ENOENT)
- return page_not_found(r);
- else
- return -1;
+ ret = page_not_found(r);
+
+ goto end;
}
const mode_t m = sb.st_mode;
if (S_ISDIR(m))
- return list_dir(r, dir, root, res, q);
+ ret = list_dir(r, res, q);
else if (S_ISREG(m))
- return serve_file(r, &sb, res);
+ ret = serve_file(r, &sb, d.str);
+ else
+ fprintf(stderr, "%s: unexpected st_mode %jd\n", __func__, (intmax_t)m);
- fprintf(stderr, "%s: unexpected st_mode %jd\n", __func__, (intmax_t)m);
- return -1;
+end:
+ dynstr_free(&d);
+ return ret;
}
static char *resolve_link(const char *const res)
@@ -1403,3 +1544,30 @@ end:
return ret;
}
+
+int page_thumbnail(struct http_response *const r, const char *const res)
+{
+ struct stat sb;
+
+ if (stat(res, &sb))
+ {
+ if (errno == ENOENT)
+ return page_not_found(r);
+ else
+ {
+ fprintf(stderr, "%s: stat(2) %s: %s\n",
+ __func__, res, strerror(errno));
+ return -1;
+ }
+ }
+
+ const mode_t m = sb.st_mode;
+
+ if (!S_ISREG(m))
+ {
+ fprintf(stderr, "%s: only regular files are supported\n", __func__);
+ return 1;
+ }
+
+ return serve_file(r, &sb, res);
+}