Allow admins to define their own stylesheet
slcl used to provide a hardcoded stylesheet. However, it would be desirable for some admins to provide a custom stylesheet without having to rebuild the application. Now, slcl creates a default stylesheet, namely style.css, into the target directory, that can be later modified by admins. While this might contradict the suckless philosophy a bit, hopefully some admins might find this new feature useful.
This commit is contained in:
parent
4236c7fc3a
commit
e79e955d93
|
@ -12,6 +12,7 @@ add_executable(${PROJECT_NAME}
|
|||
main.c
|
||||
page.c
|
||||
server.c
|
||||
style.c
|
||||
wildcard_cmp.c
|
||||
)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
||||
|
|
1
Makefile
1
Makefile
|
@ -21,6 +21,7 @@ OBJECTS = \
|
|||
main.o \
|
||||
page.o \
|
||||
server.o \
|
||||
style.o \
|
||||
wildcard_cmp.o \
|
||||
|
||||
all: $(PROJECT)
|
||||
|
|
108
main.c
108
main.c
|
@ -6,6 +6,7 @@
|
|||
#include "hex.h"
|
||||
#include "http.h"
|
||||
#include "page.h"
|
||||
#include "style.h"
|
||||
#include "wildcard_cmp.h"
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
@ -24,6 +25,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define STYLE_PATH "style.css"
|
||||
|
||||
struct form
|
||||
{
|
||||
char *key, *value;
|
||||
|
@ -59,7 +62,32 @@ static int serve_index(const struct http_payload *const p,
|
|||
static int serve_style(const struct http_payload *const p,
|
||||
struct http_response *const r, void *const user)
|
||||
{
|
||||
return page_style(r);
|
||||
int ret = -1;
|
||||
struct auth *const a = user;
|
||||
const char *const dir = auth_dir(a);
|
||||
struct dynstr d;
|
||||
|
||||
dynstr_init(&d);
|
||||
|
||||
if (!dir)
|
||||
{
|
||||
fprintf(stderr, "%s: auth_dir failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(&d, "%s/" STYLE_PATH, dir))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = page_style(r, d.str)))
|
||||
{
|
||||
fprintf(stderr, "%s: page_style failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
dynstr_free(&d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *alloc_form_data(const char *const s, const char **const end)
|
||||
|
@ -1796,6 +1824,81 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dump_default_style(const char *const path)
|
||||
{
|
||||
int ret = -1;
|
||||
FILE *const f = fopen(path, "wb");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
fprintf(stderr, "%s: fopen(3) %s: %s\n",
|
||||
__func__, path, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
else if (!fwrite(style_default, style_default_len, 1, f))
|
||||
{
|
||||
fprintf(stderr, "%s: fwrite(3): %s\n", __func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
printf("Dumped default stylesheet into %s\n", path);
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
if (f && fclose(f))
|
||||
{
|
||||
fprintf(stderr, "%s: fclose(3): %s\n", __func__, strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ensure_style(const char *const dir)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dynstr d;
|
||||
struct stat sb;
|
||||
|
||||
dynstr_init(&d);
|
||||
|
||||
if (dynstr_append(&d, "%s/" STYLE_PATH, dir))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append user failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (stat(d.str, &sb))
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
if (dump_default_style(d.str))
|
||||
{
|
||||
fprintf(stderr, "%s: dump_default_style failed\n",
|
||||
__func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s: stat(2): %s\n", __func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
else if (!S_ISREG(sb.st_mode))
|
||||
{
|
||||
fprintf(stderr, "%s: %s not a regular file\n", __func__, d.str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
dynstr_free(&d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = EXIT_FAILURE;
|
||||
|
@ -1806,6 +1909,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (parse_args(argc, argv, &dir, &port, &tmpdir)
|
||||
|| init_dirs(dir)
|
||||
|| ensure_style(dir)
|
||||
|| !(a = auth_alloc(dir)))
|
||||
goto end;
|
||||
|
||||
|
@ -1819,7 +1923,7 @@ int main(int argc, char *argv[])
|
|||
if (!(h = handler_alloc(&cfg))
|
||||
|| handler_add(h, "/", HTTP_OP_GET, serve_index, a)
|
||||
|| handler_add(h, "/index.html", HTTP_OP_GET, serve_index, a)
|
||||
|| handler_add(h, "/style.css", HTTP_OP_GET, serve_style, NULL)
|
||||
|| handler_add(h, "/style.css", HTTP_OP_GET, serve_style, a)
|
||||
|| handler_add(h, "/user/*", HTTP_OP_GET, getnode, a)
|
||||
|| handler_add(h, "/login", HTTP_OP_POST, login, a)
|
||||
|| handler_add(h, "/logout", HTTP_OP_POST, logout, a)
|
||||
|
|
80
page.c
80
page.c
|
@ -1535,73 +1535,45 @@ int page_bad_request(struct http_response *const r)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int page_style(struct http_response *const r)
|
||||
int page_style(struct http_response *const r, const char *const path)
|
||||
{
|
||||
static const char body[] =
|
||||
"body\n"
|
||||
"{\n"
|
||||
" font-family: 'Courier New', Courier, monospace;\n"
|
||||
"}\n"
|
||||
"td\n"
|
||||
"{\n"
|
||||
" font-size: 14px;\n"
|
||||
"}\n"
|
||||
"a\n"
|
||||
"{\n"
|
||||
" text-decoration: none;\n"
|
||||
"}\n"
|
||||
".userform\n"
|
||||
"{\n"
|
||||
" padding: 4px;\n"
|
||||
"}\n"
|
||||
".loginform\n"
|
||||
"{\n"
|
||||
" display: grid;\n"
|
||||
"}\n"
|
||||
"form, label, table\n"
|
||||
"{\n"
|
||||
" margin: auto;\n"
|
||||
"}\n"
|
||||
"div\n"
|
||||
"{\n"
|
||||
" align-items: center;\n"
|
||||
" display: grid;\n"
|
||||
"}\n"
|
||||
"input, .abutton\n"
|
||||
"{\n"
|
||||
" margin: auto;\n"
|
||||
" border: 1px solid;\n"
|
||||
" border-radius: 8px;\n"
|
||||
"}\n"
|
||||
"header, footer\n"
|
||||
"{\n"
|
||||
" display: flex;\n"
|
||||
" justify-content: center;\n"
|
||||
" text-decoration: auto;\n"
|
||||
"}\n"
|
||||
"table\n"
|
||||
"{\n"
|
||||
" max-width: 50%;\n"
|
||||
"}\n"
|
||||
"tr:nth-child(even)\n"
|
||||
"{\n"
|
||||
" background-color: lightgray;\n"
|
||||
"}\n";
|
||||
FILE *f = NULL;
|
||||
struct stat sb;
|
||||
|
||||
if (stat(path, &sb))
|
||||
{
|
||||
fprintf(stderr, "%s: stat(2): %s\n", __func__, strerror(errno));
|
||||
goto failure;
|
||||
}
|
||||
else if (!(f = fopen(path, "rb")))
|
||||
{
|
||||
fprintf(stderr, "%s: fopen(3) %s: %s\n",
|
||||
__func__, path, strerror(errno));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
*r = (const struct http_response)
|
||||
{
|
||||
.status = HTTP_STATUS_OK,
|
||||
.buf.ro = body,
|
||||
.n = sizeof body - 1
|
||||
.f = f,
|
||||
.n = sb.st_size
|
||||
};
|
||||
|
||||
if (http_response_add_header(r, "Content-Type", "text/css"))
|
||||
{
|
||||
fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
|
||||
return -1;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
|
||||
if (f && fclose(f))
|
||||
fprintf(stderr, "%s: fclose(3) %s: %s\n",
|
||||
__func__, path, strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int page_share(struct http_response *const r, const char *const path)
|
||||
|
|
2
page.h
2
page.h
|
@ -36,7 +36,7 @@ struct page_rm
|
|||
};
|
||||
|
||||
int page_login(struct http_response *r);
|
||||
int page_style(struct http_response *r);
|
||||
int page_style(struct http_response *r, const char *path);
|
||||
int page_failed_login(struct http_response *r);
|
||||
int page_forbidden(struct http_response *r);
|
||||
int page_bad_request(struct http_response *r);
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#include "style.h"
|
||||
#include <stddef.h>
|
||||
|
||||
const char style_default[] =
|
||||
"body\n"
|
||||
"{\n"
|
||||
" font-family: 'Courier New', Courier, monospace;\n"
|
||||
"}\n"
|
||||
"td\n"
|
||||
"{\n"
|
||||
" font-size: 14px;\n"
|
||||
"}\n"
|
||||
"a\n"
|
||||
"{\n"
|
||||
" text-decoration: none;\n"
|
||||
"}\n"
|
||||
".userform\n"
|
||||
"{\n"
|
||||
" padding: 4px;\n"
|
||||
"}\n"
|
||||
".loginform\n"
|
||||
"{\n"
|
||||
" display: grid;\n"
|
||||
"}\n"
|
||||
"form, label, table\n"
|
||||
"{\n"
|
||||
" margin: auto;\n"
|
||||
"}\n"
|
||||
"div\n"
|
||||
"{\n"
|
||||
" align-items: center;\n"
|
||||
" display: grid;\n"
|
||||
"}\n"
|
||||
"input, .abutton\n"
|
||||
"{\n"
|
||||
" margin: auto;\n"
|
||||
" border: 1px solid;\n"
|
||||
" border-radius: 8px;\n"
|
||||
"}\n"
|
||||
"header, footer\n"
|
||||
"{\n"
|
||||
" display: flex;\n"
|
||||
" justify-content: center;\n"
|
||||
" text-decoration: auto;\n"
|
||||
"}\n"
|
||||
"table\n"
|
||||
"{\n"
|
||||
" max-width: 50%;\n"
|
||||
"}\n"
|
||||
"tr:nth-child(even)\n"
|
||||
"{\n"
|
||||
" background-color: lightgray;\n"
|
||||
"}\n";
|
||||
|
||||
const size_t style_default_len = sizeof style_default - 1;
|
Loading…
Reference in New Issue