diff options
Diffstat (limited to 'wiki.c')
-rw-r--r-- | wiki.c | 332 |
1 files changed, 0 insertions, 332 deletions
@@ -1,332 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#define _GNU_SOURCE - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <glob.h> -#include <libgen.h> -#include <time.h> -#include <unistd.h> -#include <sys/stat.h> - -#include <marxup.h> - -#include "config.h" - -static const char *badchars = "\\?%:|\"<> "; - -int writable(char *path) { - struct stat s; - if(!stat(path, &s)) { - if(S_ISREG(s.st_mode)) - return !eaccess(path, W_OK); - else if(S_ISDIR(s.st_mode)) - return 0; - } - char *dir = dirname(strdup(path)); - if(!stat(dir, &s)) { - if(S_ISDIR(s.st_mode)) - return !eaccess(dir, W_OK); - } - return 0; -} - -void head(char *page, char *link, char *what) { - printf("Content-Type: text/html; charset=utf-8\n\n"); - printf("<!doctype html>\n"); - printf("<title>%s · %s</title>\n", title, page); - printf("<link rel='stylesheet' type='text/css' href='%s/wiki.css'>\n", base); - printf("<script src='%s/wiki.js'></script>\n", base); - printf("<h1>"); - if(link && what && !strcmp(what, "rediger")) - printf("<a data-text='%s' href='%s'>%s</a>", what, link, page); - else if(link && what) - printf("<a data-text='%s' href='%s/%s'>%s</a>", what, base, link, page); - else - printf("%s", page); - printf("</h1>\n"); -} - -void foot(int file) { - printf("<hr>\n"); - printf("<p>"); - for(int i = 0; *links[i]; i++) { - if(*links[i][1] == '/' || strstr(links[i][1], "://")) - printf("<a href='%s'>%s</a> ", links[i][1], links[i][0]); - else - printf("<a href='%s/%s'>%s</a> ", script, links[i][1], links[i][0]); - } - if(!file) return; - printf("<span class='f'>%s <a href='?t'>text/plain</a></span>\n", id); -} - -char *clean(char *p) { - char *dup = strdup(basename(p)); - char *x = dup; - while(*x) { - if(*x == '-') *x = ' '; - x++; - } - return dup; -} - -int legit(char *page) { - if(!page) return 0; - if(!strcmp(page, "/")) return 0; - if(strstr(page, "..")) return 0; - if(strcspn(page, badchars) < strlen(page)) return 0; - // strlen(page) - return 1; -} - -int problem(int status, char *message) { - printf("Status: %d\n", status); - printf("Content-Type: text/plain\n\n"); - printf("%s\n", message); - return 1; -} - -int redirect(char *path, char *prefix) { - printf("Status: 303\n"); - switch(*path) { - case '?': printf("Location: %s\n\n", path); break; - case '#': - printf("Location: %s/%s?m=", script, path); - // skrive ut ++path - printf("\n"); - default: - if(prefix) { - printf("Location: %s/%s/%s\n\n", script, prefix, path); break; - } else { - printf("Location: %s/%s\n\n", script, path); break; - } - } - return 0; -} - -int unauthorized(int status) { - printf("Status: %d\n", status); - if(status == 401) - printf("WWW-Authenticate: Basic realm='%s'\n", realm); - printf("Content-Type: text/plain; charset=utf-8\n\n"); - printf("No.\n"); - return 1; -} - -int edit(char *path) { - if(!writable(path)) return unauthorized(403); - FILE *fp = fopen(path, "r"); - fp ? head(path, path, "vis") : head(path, NULL, NULL); - char buffer[sysconf(_SC_PAGESIZE)]; - printf("<form method='post'>\n"); - printf("<p class='edit'>\n"); - if(orz) - printf("<a id='orz' href='#'>@picto</a><br>\n"); - printf("<textarea name=t rows=24 cols=72>"); - if(fp) - while(fgets(buffer, sizeof(buffer), fp)) - printf("%s", buffer); - printf("</textarea>\n"); - printf("<p><input type=submit value=Update>"); - printf("</form>"); - foot(1); - if(fp) fclose(fp); - return 0; -} - -// v fæl -int store(char *raw, int len) { - char *dir = dirname(strdup(raw)); - char *id = basename(strdup(raw)); - if(chdir(dir)) - return problem(404, "Not found"); - char path[strlen(loft) + strlen(id) + 256]; - int epoch = time(NULL); - snprintf(path, strlen(loft) + strlen(id) + 256, "%s/%s.%d", loft, id, epoch); - FILE *fp = fopen(path, "w"); - if(!fp) return redirect("fff", NULL); - int pos = 0; - unsigned int decoded; - char buffer[3] = { 0 }; - for(int i = 0; i < len; i++) { - buffer[pos] = getchar(); - if(buffer[pos] == '+') buffer[pos] = ' '; - if(buffer[pos] == '&') { buffer[pos] = '\0'; break; } - if(pos == 2) { - if(buffer[0] == '%' && isxdigit(buffer[1]) && isxdigit(buffer[2])) { - sscanf(buffer, "%%%2x", &decoded); - fprintf(fp, "%c", decoded); - memset(buffer, 0, 3); - pos = 0; - } else { - fprintf(fp, "%c", buffer[0]); - memmove(buffer, &buffer[1], 2); - buffer[2] = 0; - } - } - else pos++; - } - fprintf(fp, "%.3s", buffer); - fputc('\0', fp); - fclose(fp); - unlink(id); - symlink(path, id); - return 0; -} - -int post(char *path) { - char *header; - int clen; - header = getenv("CONTENT_LENGTH"); - if(!header) return redirect(path, NULL); - clen = atoi(header); - while(clen > 1) - if(clen--, getchar() == 't') - if(clen--, getchar() == '=') - store(path, clen); - return redirect(path, NULL); -} - -// gjør denne penere! -int list(char *raw, int dir, int inc) { - int len = strlen(raw); - char *pattern = malloc(len + 3); - if(len > 0 && raw[len - 1] == '/') - raw[len - 1] = '\0'; - if(dir) - snprintf(pattern, len + 3, "%s/*", raw); - else - snprintf(pattern, len + 1, "%s", raw); - glob_t res; - if(glob(pattern, GLOB_MARK, NULL, &res)) { - if(!inc) { - head("ingen treff", NULL, NULL); - foot(0); - } - return 0; - } - if(!inc) - head("treff", NULL, NULL); - char *path; - printf("<ul class='glob'>"); - for(int i = 0; i < res.gl_pathc; i++) { - path = res.gl_pathv[i]; - if(*path == '.' && *path + 1 == '/') path += 2; - printf("<li><a href='%s/%s'>%s</a>", script, path, path); - } - printf("</ul>"); - if(!inc) - foot(0); - free(pattern); - return 0; -} - -int text(char *path, char *type) { - FILE *fp = fopen(path, "r"); - if(fp) { - char buffer[sysconf(_SC_PAGESIZE)]; - printf("Content-Type: %s; charset=utf-8\n\n", type); - while(fgets(buffer, sizeof(buffer), fp)) - printf("%s", buffer); - } - fclose(fp); - return 0; -} - -void include(FILE *out, char *path) { - struct stat s; - int plain = 0; - if(*path == 't') - plain = 1, path++; - while(isspace(*path)) path++; - if(!legit(path)) return; - if(*path == '/') return; - stat(path, &s); - if(S_ISDIR(s.st_mode)) { - list(path, 1, 1); - return; - } - FILE *fp = fopen(path, "r"); - if(!fp) return; - if(plain) { - printf("<pre>"); - int c; - while((c = fgetc(fp)) != EOF) { - switch(c) { - case '&': printf("&"); break; - case '<': printf("<"); break; - case '>': printf(">"); break; - default: putc(c, stdout); - } - } - printf("</pre>"); - } else { - marxup(fp, out, NULL); - } - fclose(fp); -} - -void magic(FILE *out, char *line) { - switch(*line++) { - case 'i': include(out, line); break; - default: fprintf(out, "WHAT: %s\n", line); return; - } -} - -int view(char *path) { - struct stat s; - stat(path, &s); - if(S_ISDIR(s.st_mode)) { - if(dirlist) - return list(path, 1, 0); - return redirect(home, path); - } - FILE *fp = fopen(path, "r"); - if(!fp) return redirect("?e", NULL); - writable(path) ? head(path, "?e", "rediger") : head(path, NULL, NULL); - marxup(fp, stdout, magic); - foot(1); - return 0; -} - -int main(int argc, char **argv) { - char *page = getenv("PATH_INFO"); - char *qstr = getenv("QUERY_STRING"); - char *verb = getenv("REQUEST_METHOD"); - - if(!page && argc > 1) page = argv[1]; - if(!qstr && argc > 2) qstr = argv[2]; - - if(!verb) verb = "GET"; - - if(!script) script = getenv("SCRIPT_NAME"); - if(!script) script = ""; - if(!base) base = strdup(dirname(strdup(script))); - - if(authenticate && !(id = authenticate())) return unauthorized(401); - if(!legit(page++)) return redirect(home, NULL); - - setenv("MARXUP_HEADER", "2", 1); - setenv("MARXUP_PREFIX", base, 1); - setenv("MARXUP_WIKI", "1", 1); - - if(chdir(pages)) - return problem(503, "Service unavailable"); - - if(!strncmp(verb, "POST", 4)) return post(page); - if(strchr(page, '*')) - return list(page, 0, 0); - - while(qstr && *qstr) { - switch(*qstr) { - case 'e': return edit(page); - case 't': return text(page, "text/plain"); - case 'c': return text(page, "text/css"); - } - qstr++; - } - return view(page); -} - |