itvote.c: implement voting functionality - vote - simple cgi voting system for web and gopher Err mx1.adamsgaard.dk 70 hgit clone git://src.adamsgaard.dk/vote URL:git://src.adamsgaard.dk/vote mx1.adamsgaard.dk 70 1Log /src/vote/log.gph mx1.adamsgaard.dk 70 1Files /src/vote/files.gph mx1.adamsgaard.dk 70 1Refs /src/vote/refs.gph mx1.adamsgaard.dk 70 1README /src/vote/file/README.gph mx1.adamsgaard.dk 70 1LICENSE /src/vote/file/LICENSE.gph mx1.adamsgaard.dk 70 i--- Err mx1.adamsgaard.dk 70 1commit 0b3501599120c01cca8c2e8532fcd31e781f48ec /src/vote/commit/0b3501599120c01cca8c2e8532fcd31e781f48ec.gph mx1.adamsgaard.dk 70 1parent d5823861bfb88b89fc65a8844cd7e9a623bb0690 /src/vote/commit/d5823861bfb88b89fc65a8844cd7e9a623bb0690.gph mx1.adamsgaard.dk 70 hAuthor: Anders Damsgaard URL:mailto:anders@adamsgaard.dk mx1.adamsgaard.dk 70 iDate: Mon, 28 Sep 2020 14:09:43 +0200 Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 ivote.c: implement voting functionality Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 iDiffstat: Err mx1.adamsgaard.dk 70 i M vote.c | 91 +++++++++++++++++++++---------- Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i1 file changed, 62 insertions(+), 29 deletions(-) Err mx1.adamsgaard.dk 70 i--- Err mx1.adamsgaard.dk 70 1diff --git a/vote.c b/vote.c /src/vote/file/vote.c.gph mx1.adamsgaard.dk 70 it@@ -12,7 +12,6 @@ Err mx1.adamsgaard.dk 70 i #include "util.h" Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i #define LEN(s) (sizeof(s) / sizeof(s[0])) Err mx1.adamsgaard.dk 70 i-#define OUT(s) (fputs((s), stdout)) Err mx1.adamsgaard.dk 70 i #define POLLS_DIR "polls" Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i static char fname[PATH_MAX]; Err mx1.adamsgaard.dk 70 it@@ -20,23 +19,24 @@ static char poll[1024]; Err mx1.adamsgaard.dk 70 i static char create[2]; Err mx1.adamsgaard.dk 70 i static char question[4096]; Err mx1.adamsgaard.dk 70 i static char options[4096]; Err mx1.adamsgaard.dk 70 i+static char choice[16]; Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i void Err mx1.adamsgaard.dk 70 i http_status(int statuscode) Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i switch(statuscode) { Err mx1.adamsgaard.dk 70 i case 401: Err mx1.adamsgaard.dk 70 i- OUT("Status: 401 Bad Request\r\n\r\n"); Err mx1.adamsgaard.dk 70 i+ printf("Status: 401 Bad Request\r\n\r\n"); Err mx1.adamsgaard.dk 70 i break; Err mx1.adamsgaard.dk 70 i case 404: Err mx1.adamsgaard.dk 70 i- OUT("Status: 404 Not Found\r\n\r\n"); Err mx1.adamsgaard.dk 70 i+ printf("Status: 404 Not Found\r\n\r\n"); Err mx1.adamsgaard.dk 70 i break; Err mx1.adamsgaard.dk 70 i case 500: Err mx1.adamsgaard.dk 70 i- OUT("Status: 500 Internal Server Error\r\n\r\n"); Err mx1.adamsgaard.dk 70 i+ printf("Status: 500 Internal Server Error\r\n\r\n"); Err mx1.adamsgaard.dk 70 i break; Err mx1.adamsgaard.dk 70 i default: Err mx1.adamsgaard.dk 70 i err(1, "unknown status code %d\n", statuscode); Err mx1.adamsgaard.dk 70 i- OUT("Status: 500 Internal Server Error\r\n\r\n"); Err mx1.adamsgaard.dk 70 i+ printf("Status: 500 Internal Server Error\r\n\r\n"); Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 it@@ -60,8 +60,8 @@ pollfile(const char *poll_name, const char *postfix) Err mx1.adamsgaard.dk 70 i void Err mx1.adamsgaard.dk 70 i print_html_head() Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i- OUT("Content-type: text/html; charset=utf-8\r\n\r\n"); Err mx1.adamsgaard.dk 70 i- OUT("\n" Err mx1.adamsgaard.dk 70 i+ printf("Content-type: text/html; charset=utf-8\r\n\r\n"); Err mx1.adamsgaard.dk 70 i+ printf("\n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i "\n"); Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 it@@ -69,33 +69,45 @@ print_html_head() Err mx1.adamsgaard.dk 70 i void Err mx1.adamsgaard.dk 70 i print_html_foot() Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i- OUT("\n" Err mx1.adamsgaard.dk 70 i+ printf("\n" Err mx1.adamsgaard.dk 70 i "\n"); Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i int Err mx1.adamsgaard.dk 70 i-print_poll_line(char *line, int intable) Err mx1.adamsgaard.dk 70 i+print_poll_line(char *line, size_t *i, int intable, int vote) Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i size_t c; Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i if (sscanf(line, "%ld\t%s", &c, options) == 2) { Err mx1.adamsgaard.dk 70 i- if (!intable) Err mx1.adamsgaard.dk 70 i- puts("
"); Err mx1.adamsgaard.dk 70 i- printf("\n", c, options); Err mx1.adamsgaard.dk 70 i+ if (!intable) { Err mx1.adamsgaard.dk 70 i+ puts("

\n
%ld%s
"); Err mx1.adamsgaard.dk 70 i+ if (vote) { Err mx1.adamsgaard.dk 70 i+ puts(""); Err mx1.adamsgaard.dk 70 i+ printf("\n", poll); Err mx1.adamsgaard.dk 70 i+ } Err mx1.adamsgaard.dk 70 i+ } Err mx1.adamsgaard.dk 70 i+ if (vote) { Err mx1.adamsgaard.dk 70 i+ printf("\t\n", options); Err mx1.adamsgaard.dk 70 i+ } else Err mx1.adamsgaard.dk 70 i+ printf("\t\n", c, options); Err mx1.adamsgaard.dk 70 i return 1; Err mx1.adamsgaard.dk 70 i } else { Err mx1.adamsgaard.dk 70 i- if (intable) Err mx1.adamsgaard.dk 70 i- puts("
"); Err mx1.adamsgaard.dk 70 i+ printf("", Err mx1.adamsgaard.dk 70 i+ ++*i, *i); Err mx1.adamsgaard.dk 70 i+ printf("%s
%ld%s
"); Err mx1.adamsgaard.dk 70 i+ Err mx1.adamsgaard.dk 70 i printf("%s
\n", line); Err mx1.adamsgaard.dk 70 i return 0; Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i void Err mx1.adamsgaard.dk 70 i-print_poll_file(FILE *fp) Err mx1.adamsgaard.dk 70 i+print_poll_file(FILE *fp, int vote) Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i char *line = NULL; Err mx1.adamsgaard.dk 70 i- size_t linesize = 0, lineno = 0; Err mx1.adamsgaard.dk 70 i+ size_t linesize = 0, lineno = 0, i = 0; Err mx1.adamsgaard.dk 70 i ssize_t linelen; Err mx1.adamsgaard.dk 70 i int intable = 0; Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 it@@ -107,9 +119,9 @@ print_poll_file(FILE *fp) Err mx1.adamsgaard.dk 70 i if (lineno == 1) { Err mx1.adamsgaard.dk 70 i printf("

"); Err mx1.adamsgaard.dk 70 i fwrite(line, linelen, 1, stdout); Err mx1.adamsgaard.dk 70 i- printf("

\n"); Err mx1.adamsgaard.dk 70 i+ printf("\n

"); Err mx1.adamsgaard.dk 70 i } else { Err mx1.adamsgaard.dk 70 i- intable = print_poll_line(line, intable); Err mx1.adamsgaard.dk 70 i+ intable = print_poll_line(line, &i, intable, vote); Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i free(line); Err mx1.adamsgaard.dk 70 it@@ -117,7 +129,13 @@ print_poll_file(FILE *fp) Err mx1.adamsgaard.dk 70 i http_status(500); Err mx1.adamsgaard.dk 70 i err(1, "print_poll_file: getline"); Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i+ Err mx1.adamsgaard.dk 70 i puts(""); Err mx1.adamsgaard.dk 70 i+ if (vote) { Err mx1.adamsgaard.dk 70 i+ puts(""); Err mx1.adamsgaard.dk 70 i+ puts(""); Err mx1.adamsgaard.dk 70 i+ } Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i int Err mx1.adamsgaard.dk 70 it@@ -183,7 +201,7 @@ create_poll_file(const char *name, const char *question, const char *options) Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i void Err mx1.adamsgaard.dk 70 i-show_poll(const char *poll) Err mx1.adamsgaard.dk 70 i+show_poll(const char *poll, int vote) Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i FILE *fp; Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 it@@ -191,7 +209,7 @@ show_poll(const char *poll) Err mx1.adamsgaard.dk 70 i http_status(404); Err mx1.adamsgaard.dk 70 i exit(1); Err mx1.adamsgaard.dk 70 i } else { Err mx1.adamsgaard.dk 70 i- print_poll_file(fp); Err mx1.adamsgaard.dk 70 i+ print_poll_file(fp, vote); Err mx1.adamsgaard.dk 70 i fclose(fp); Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 it@@ -280,28 +298,28 @@ increment_option(char *poll, size_t n) Err mx1.adamsgaard.dk 70 i void Err mx1.adamsgaard.dk 70 i print_poll_create_form() Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i- OUT("

Create new poll

"); Err mx1.adamsgaard.dk 70 i- OUT("
\n" Err mx1.adamsgaard.dk 70 i+ puts("

Create new poll

"); Err mx1.adamsgaard.dk 70 i+ puts("\n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i " \n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i " \n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i " \n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 i "\n" Err mx1.adamsgaard.dk 70 it@@ -351,11 +369,20 @@ parse_query() Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i+ if ((p = getparam(query, "choice"))) { Err mx1.adamsgaard.dk 70 i+ if (decodeparam(choice, sizeof(create), p) == -1) { Err mx1.adamsgaard.dk 70 i+ http_status(401); Err mx1.adamsgaard.dk 70 i+ exit(1); Err mx1.adamsgaard.dk 70 i+ } Err mx1.adamsgaard.dk 70 i+ } Err mx1.adamsgaard.dk 70 i+ Err mx1.adamsgaard.dk 70 i } Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i int Err mx1.adamsgaard.dk 70 i main() Err mx1.adamsgaard.dk 70 i { Err mx1.adamsgaard.dk 70 i+ size_t c; Err mx1.adamsgaard.dk 70 i+ const char *errstr; Err mx1.adamsgaard.dk 70 i struct stat sb; Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i if (unveil(getenv("PWD"), NULL) == -1 || unveil(NULL, NULL) == -1) { Err mx1.adamsgaard.dk 70 it@@ -381,10 +408,16 @@ main() Err mx1.adamsgaard.dk 70 i Err mx1.adamsgaard.dk 70 i if (*create) { Err mx1.adamsgaard.dk 70 i if (create_poll_file(poll, question, options) == 0) Err mx1.adamsgaard.dk 70 i- show_poll(poll); Err mx1.adamsgaard.dk 70 i+ show_poll(poll, 0); Err mx1.adamsgaard.dk 70 i } else if (*poll) { Err mx1.adamsgaard.dk 70 i- show_poll(poll); Err mx1.adamsgaard.dk 70 i- increment_option(poll, 2); Err mx1.adamsgaard.dk 70 i+ if (*choice) { Err mx1.adamsgaard.dk 70 i+ c = strtonum(choice, 1, 256, &errstr); Err mx1.adamsgaard.dk 70 i+ if (errstr != NULL) Err mx1.adamsgaard.dk 70 i+ errx(1, "could not parse choice: %s, %s", errstr, choice); Err mx1.adamsgaard.dk 70 i+ increment_option(poll, c); Err mx1.adamsgaard.dk 70 i+ show_poll(poll, 0); Err mx1.adamsgaard.dk 70 i+ } else Err mx1.adamsgaard.dk 70 i+ show_poll(poll, 1); Err mx1.adamsgaard.dk 70 i } else { Err mx1.adamsgaard.dk 70 i list_polls(); Err mx1.adamsgaard.dk 70 i print_poll_create_form(); Err mx1.adamsgaard.dk 70 .
\n" Err mx1.adamsgaard.dk 70 i " \n" Err mx1.adamsgaard.dk 70 i+ "placeholder=\"Name\" size=\"60\" " Err mx1.adamsgaard.dk 70 i+ "autofocus=\"autofocus\" class=\"name\" />\n" Err mx1.adamsgaard.dk 70 i "
\n" Err mx1.adamsgaard.dk 70 i " \n" Err mx1.adamsgaard.dk 70 i+ "placeholder=\"Question\" size=\"60\" class=\"question\" />\n" Err mx1.adamsgaard.dk 70 i "
\n" Err mx1.adamsgaard.dk 70 i " \n" Err mx1.adamsgaard.dk 70 i+ "placeholder=\"Options (1 per line)\">\n" Err mx1.adamsgaard.dk 70 i "