Implement file/directory removal
The following workflow has been implemented: - A new checkbox for each object inside a directory is shown. - When one or more objects are selected, the user submits a request through a HTML5 form. - Then, slcl will ask the user for confirmation, listing the selected objects, while reminding the user about the effects. - The user confirms the selection. - slcl removes the selected objects. All objects from non-empty directories are removed, too. - Finally, slcl redirects the user to the directory the request was made from.
This commit is contained in:
parent
74ca76a58f
commit
0822a982ef
332
main.c
332
main.c
|
@ -10,6 +10,7 @@
|
|||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <dynstr.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -1296,6 +1297,335 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int check_rm_input(const struct form *const forms, const size_t n,
|
||||
struct page_rm *const rm, int (**const cb)(struct http_response *))
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
const struct form *const f = &forms[i];
|
||||
|
||||
if (!strcmp(f->key, "dir"))
|
||||
{
|
||||
if (!rm->dir)
|
||||
rm->dir = f->value;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: directory defined more than once\n",
|
||||
__func__);
|
||||
*cb = page_bad_request;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(f->key, "path"))
|
||||
{
|
||||
const char **tmp = realloc(rm->items, (rm->n + 1) * sizeof *tmp);
|
||||
|
||||
if (!tmp)
|
||||
{
|
||||
fprintf(stderr, "%s: realloc(3): %s\n",
|
||||
__func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp[rm->n++] = f->value;
|
||||
rm->items = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rm->dir)
|
||||
{
|
||||
fprintf(stderr, "%s: expected non-null dir\n", __func__);
|
||||
*cb = page_bad_request;
|
||||
return 1;
|
||||
}
|
||||
else if (*rm->dir != '/' || path_isrel(rm->dir))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid directory %s\n", __func__, rm->dir);
|
||||
*cb = page_bad_request;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int confirm_rm(const struct http_payload *const p,
|
||||
struct http_response *const r, void *const user)
|
||||
{
|
||||
int ret = -1;
|
||||
struct auth *const a = user;
|
||||
struct form *forms = NULL;
|
||||
const char **items = NULL;
|
||||
size_t n = 0;
|
||||
int (*f)(struct http_response *);
|
||||
struct page_rm rm = {0};
|
||||
|
||||
if (auth_cookie(a, &p->cookie))
|
||||
{
|
||||
fprintf(stderr, "%s: auth_cookie failed\n", __func__);
|
||||
ret = page_forbidden(r);
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = get_forms(p, &forms, &n)))
|
||||
{
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: get_forms failed\n", __func__);
|
||||
else
|
||||
ret = page_bad_request(r);
|
||||
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = check_rm_input(forms, n, &rm, &f)))
|
||||
{
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: check_rm_input failed\n", __func__);
|
||||
else if ((ret = f(r)))
|
||||
fprintf(stderr, "%s: check_rm_input callback failed\n",
|
||||
__func__);
|
||||
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = page_rm(r, &rm)))
|
||||
{
|
||||
fprintf(stderr, "%s: page_rm failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
forms_free(forms, n);
|
||||
free(items);
|
||||
free(rm.items);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *find_rm_dir(const struct form *const forms, const size_t n,
|
||||
int (**const cb)(struct http_response *))
|
||||
{
|
||||
const char *dir = NULL;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
const struct form *const f = &forms[i];
|
||||
|
||||
if (!strcmp(f->key, "dir"))
|
||||
{
|
||||
if (!dir)
|
||||
dir = f->value;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: directory defined more than once\n",
|
||||
__func__);
|
||||
*cb = page_bad_request;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
static int rm_dir_contents(const char *const fpath,
|
||||
const struct stat *const sb, void *const user)
|
||||
{
|
||||
if (S_ISDIR(sb->st_mode) && rmdir(fpath))
|
||||
{
|
||||
fprintf(stderr, "%s: rmdir(2) %s: %s\n",
|
||||
__func__, fpath, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
else if (S_ISREG(sb->st_mode) && remove(fpath))
|
||||
{
|
||||
fprintf(stderr, "%s: remove(3) %s: %s\n",
|
||||
__func__, fpath, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmdir_r(const char *const path)
|
||||
{
|
||||
int ret = -1;
|
||||
DIR *const d = opendir(path);
|
||||
|
||||
if (!d)
|
||||
{
|
||||
fprintf(stderr, "%s: opendir(3): %s\n", __func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
else if (cftw(path, rm_dir_contents, NULL))
|
||||
{
|
||||
fprintf(stderr, "%s: rm_dir_contents failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (rmdir(path))
|
||||
{
|
||||
fprintf(stderr, "%s: rmdir(2) %s: %s\n",
|
||||
__func__, path, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
if (d && closedir(d))
|
||||
{
|
||||
fprintf(stderr, "%s: closedir(3): %s\n", __func__, strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rm_item(const char *const root, const char *const item)
|
||||
{
|
||||
int ret = -1;
|
||||
struct stat sb;
|
||||
struct dynstr d;
|
||||
|
||||
dynstr_init(&d);
|
||||
|
||||
if (dynstr_append(&d, "%s/%s", root, item))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (stat(d.str, &sb))
|
||||
{
|
||||
fprintf(stderr, "%s: stat(2) %s: %s\n",
|
||||
__func__, d.str, strerror(errno));
|
||||
|
||||
/* This might have already been removed from another request,
|
||||
* and thus this situation should not be considered an error. */
|
||||
if (errno == ENOENT || errno == ENOTDIR)
|
||||
ret = 0;
|
||||
|
||||
goto end;
|
||||
}
|
||||
else if (S_ISDIR(sb.st_mode) && rmdir_r(d.str))
|
||||
{
|
||||
fprintf(stderr, "%s: rmdir_r failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (S_ISREG(sb.st_mode) && remove(d.str))
|
||||
{
|
||||
fprintf(stderr, "%s: remove(3): %s\n", __func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
dynstr_free(&d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_rm(const struct form *const forms, const size_t n,
|
||||
const char *const dir)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
const struct form *const f = &forms[i];
|
||||
|
||||
if (!strcmp(f->key, "path") && rm_item(dir, f->value))
|
||||
{
|
||||
fprintf(stderr, "%s: rm_item failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rm(const struct http_payload *const p,
|
||||
struct http_response *const r, void *const user)
|
||||
{
|
||||
int ret = -1;
|
||||
struct auth *const a = user;
|
||||
struct form *forms = NULL;
|
||||
size_t n = 0;
|
||||
const struct http_cookie *const c = &p->cookie;
|
||||
const char *username = c->field, *adir;
|
||||
struct dynstr d, userdir;
|
||||
|
||||
dynstr_init(&d);
|
||||
dynstr_init(&userdir);
|
||||
|
||||
if (auth_cookie(a, c))
|
||||
{
|
||||
fprintf(stderr, "%s: auth_cookie failed\n", __func__);
|
||||
ret = page_forbidden(r);
|
||||
goto end;
|
||||
}
|
||||
else if (!(adir = auth_dir(a)))
|
||||
{
|
||||
fprintf(stderr, "%s: auth_dir failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = get_forms(p, &forms, &n)))
|
||||
{
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: get_forms failed\n", __func__);
|
||||
else
|
||||
ret = page_bad_request(r);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
int (*f)(struct http_response *);
|
||||
const char *const dir = find_rm_dir(forms, n, &f);
|
||||
|
||||
if (!dir)
|
||||
{
|
||||
fprintf(stderr, "%s: expected non-null directory\n", __func__);
|
||||
ret = f(r);
|
||||
goto end;
|
||||
}
|
||||
else if (*dir != '/' || path_isrel(dir))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid directory %s\n", __func__, dir);
|
||||
ret = page_bad_request(r);
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(&userdir, "%s/user/%s%s", adir, username, dir))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = do_rm(forms, n, userdir.str)))
|
||||
{
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: do_rm failed\n", __func__);
|
||||
else if ((ret = f(r)))
|
||||
fprintf(stderr, "%s: rm callback failed\n", __func__);
|
||||
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(&d, "/user%s", dir))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
*r = (const struct http_response)
|
||||
{
|
||||
.status = HTTP_STATUS_SEE_OTHER
|
||||
};
|
||||
|
||||
if (http_response_add_header(r, "Location", d.str))
|
||||
{
|
||||
fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
dynstr_free(&d);
|
||||
dynstr_free(&userdir);
|
||||
forms_free(forms, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usage(char *const argv[])
|
||||
{
|
||||
fprintf(stderr, "%s [-t tmpdir] [-p port] dir\n", *argv);
|
||||
|
@ -1459,6 +1789,8 @@ int main(int argc, char *argv[])
|
|||
|| handler_add(h, "/share", HTTP_OP_POST, share, a)
|
||||
|| handler_add(h, "/upload", HTTP_OP_POST, upload, a)
|
||||
|| handler_add(h, "/mkdir", HTTP_OP_POST, createdir, a)
|
||||
|| handler_add(h, "/confirm/rm", HTTP_OP_POST, confirm_rm, a)
|
||||
|| handler_add(h, "/rm", HTTP_OP_POST, rm, a)
|
||||
|| handler_listen(h, port))
|
||||
goto end;
|
||||
|
||||
|
|
360
page.c
360
page.c
|
@ -45,6 +45,55 @@
|
|||
" <input type=\"submit\" value=\"Submit\">\n" \
|
||||
" </form>\n"
|
||||
#define MAXSIZEFMT "18446744073709551615.0 XiB"
|
||||
#define RM_FORM_ID "rm"
|
||||
|
||||
static int prepare_rm_checkbox(struct html_node *const n,
|
||||
const struct stat *const sb, const char *const name)
|
||||
{
|
||||
int ret = -1;
|
||||
const char *const sep = S_ISDIR(sb->st_mode) ? "/" : "";
|
||||
struct html_node *input;
|
||||
struct dynstr d;
|
||||
|
||||
dynstr_init(&d);
|
||||
|
||||
if (dynstr_append(&d, "%s%s", name, sep))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(input = html_node_add_child(n, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child input failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_node_add_attr(input, "type", "checkbox"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr type failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_node_add_attr(input, "form", RM_FORM_ID))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr form failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_node_add_attr(input, "name", "path"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr name failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_node_add_attr(input, "value", d.str))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr value failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
dynstr_free(&d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int prepare_name(struct html_node *const n, struct stat *const sb,
|
||||
const char *const dir, const char *const name)
|
||||
|
@ -287,7 +336,7 @@ static int add_element(struct html_node *const n, const char *const dir,
|
|||
const char *const res, const char *const name)
|
||||
{
|
||||
int ret = -1;
|
||||
enum {NAME, SIZE, DATE, SHARE, PREVIEW, COLUMNS};
|
||||
enum {RM_CHECKBOX, NAME, SIZE, DATE, SHARE, PREVIEW, COLUMNS};
|
||||
struct html_node *tr, *td[COLUMNS];
|
||||
struct dynstr path;
|
||||
const char *const sep = res[strlen(res) - 1] != '/' ? "/" : "";
|
||||
|
@ -321,6 +370,12 @@ static int add_element(struct html_node *const n, const char *const dir,
|
|||
__func__, path.str, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
else if (strcmp(name, "..")
|
||||
&& prepare_rm_checkbox(td[RM_CHECKBOX], &sb, name))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_rm_checkbox failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (prepare_name(td[NAME], &sb, dir, name))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_name failed\n", __func__);
|
||||
|
@ -618,6 +673,80 @@ static int prepare_mkdir_form(struct html_node *const n, const char *const dir)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_rm_form(struct html_node *const n, const char *const dir)
|
||||
{
|
||||
struct html_node *div, *form, *hidden, *submit;
|
||||
|
||||
if (!(div = html_node_add_child(n, "div")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child div failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(form = html_node_add_child(div, "form")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child form failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(hidden = html_node_add_child(form, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child hidden failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(submit = html_node_add_child(form, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child submit failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(div, "class", "userform"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr div failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(form, "id", RM_FORM_ID))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr id failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(form, "method", "post"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr method failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(form, "action", "/confirm/rm"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr method failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "type", "hidden"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr hidden failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "name", "dir"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr name failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "value", dir))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr value failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(submit, "type", "submit"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr submit failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(submit, "value", "Remove selected files"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr submit value failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_quota_form(struct html_node *const n,
|
||||
const struct page_quota *const q)
|
||||
{
|
||||
|
@ -957,6 +1086,11 @@ static struct html_node *resource_layout(const char *const dir,
|
|||
fprintf(stderr, "%s: prepare_upload_form failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (prepare_rm_form(body, fdir))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_upload_form failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (q && prepare_quota_form(body, q))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_quota_form failed\n", __func__);
|
||||
|
@ -1782,3 +1916,227 @@ end:
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int append_rm_items(struct html_node *const n,
|
||||
const struct page_rm *const rm)
|
||||
{
|
||||
struct html_node *div, *form, *table, *hidden, *submit;
|
||||
|
||||
if (!(table = html_node_add_child(n, "table")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child table failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(div = html_node_add_child(n, "div")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child div failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(form = html_node_add_child(div, "form")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child form failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(hidden = html_node_add_child(form, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child hidden failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(submit = html_node_add_child(form, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child submit failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(form, "method", "post"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr method failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(form, "action", "/rm"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr action failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(div, "class", "userform"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr class failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "type", "hidden"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr hidden type failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "name", "dir"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr hidden name failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "value", rm->dir))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr hidden value failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(submit, "type", "submit"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr submit type failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(submit, "value", "Confirm"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr submit value failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < rm->n; i++)
|
||||
{
|
||||
const char *const item = rm->items[i];
|
||||
struct html_node *const tr = html_node_add_child(table, "tr"),
|
||||
*const path = html_node_add_child(form, "input"), *td;
|
||||
|
||||
if (!tr)
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child tr failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!path)
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child path failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(td = html_node_add_child(tr, "td")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child td failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_set_value(td, item))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_set_value td failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(path, "type", "hidden"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr path type failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(path, "name", "path"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr path name failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(path, "value", item))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr path value failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int page_rm(struct http_response *r, const struct page_rm *const rm)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dynstr out;
|
||||
struct html_node *const html = html_node_alloc("html"),
|
||||
*p, *p2, *head, *body;
|
||||
static const char question[] = "Are you sure to remove the "
|
||||
"following files and/or directories? Remember that removing a "
|
||||
"directory will remove all of the files and directories inside it.",
|
||||
reminder[] = "This action cannot be undone.";
|
||||
|
||||
dynstr_init(&out);
|
||||
|
||||
if (!html)
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_alloc failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(head = html_node_add_child(html, "head")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child head failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(body = html_node_add_child(html, "body")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child body failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(p = html_node_add_child(body, "p")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child p failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(p2 = html_node_add_child(body, "p")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child p2 failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (common_head(head, NULL))
|
||||
{
|
||||
fprintf(stderr, "%s: common_head failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_node_set_value(p, question))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_set_value question failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_node_set_value(p2, reminder))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_set_value reminder failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (append_rm_items(body, rm))
|
||||
{
|
||||
fprintf(stderr, "%s: append_rm_items failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (prepare_footer(body))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_footer failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(&out, DOCTYPE_TAG))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append out failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_serialize(html, &out))
|
||||
{
|
||||
fprintf(stderr, "%s: html_serialize failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
*r = (const struct http_response)
|
||||
{
|
||||
.status = HTTP_STATUS_OK,
|
||||
.buf.rw = out.str,
|
||||
.n = out.len,
|
||||
.free = free
|
||||
};
|
||||
|
||||
if (http_response_add_header(r, "Content-Type", "text/html"))
|
||||
{
|
||||
fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
html_node_free(html);
|
||||
|
||||
if (ret)
|
||||
dynstr_free(&out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
7
page.h
7
page.h
|
@ -29,6 +29,12 @@ struct page_search
|
|||
size_t n;
|
||||
};
|
||||
|
||||
struct page_rm
|
||||
{
|
||||
const char *dir, **items;
|
||||
size_t n;
|
||||
};
|
||||
|
||||
int page_login(struct http_response *r);
|
||||
int page_style(struct http_response *r);
|
||||
int page_failed_login(struct http_response *r);
|
||||
|
@ -40,5 +46,6 @@ int page_share(struct http_response *r, const char *path);
|
|||
int page_quota_exceeded(struct http_response *r, unsigned long long len,
|
||||
unsigned long long quota);
|
||||
int page_search(struct http_response *r, const struct page_search *s);
|
||||
int page_rm(struct http_response *r, const struct page_rm *rm);
|
||||
|
||||
#endif /* PAGE_H */
|
||||
|
|
Loading…
Reference in New Issue