tvote.c: implement voting functionality - vote - simple cgi voting system for web and gopher
(HTM) git clone git://src.adamsgaard.dk/vote
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 0b3501599120c01cca8c2e8532fcd31e781f48ec
(DIR) parent d5823861bfb88b89fc65a8844cd7e9a623bb0690
(HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
Date: Mon, 28 Sep 2020 14:09:43 +0200
vote.c: implement voting functionality
Diffstat:
M vote.c | 91 +++++++++++++++++++++----------
1 file changed, 62 insertions(+), 29 deletions(-)
---
(DIR) diff --git a/vote.c b/vote.c
t@@ -12,7 +12,6 @@
#include "util.h"
#define LEN(s) (sizeof(s) / sizeof(s[0]))
-#define OUT(s) (fputs((s), stdout))
#define POLLS_DIR "polls"
static char fname[PATH_MAX];
t@@ -20,23 +19,24 @@ static char poll[1024];
static char create[2];
static char question[4096];
static char options[4096];
+static char choice[16];
void
http_status(int statuscode)
{
switch(statuscode) {
case 401:
- OUT("Status: 401 Bad Request\r\n\r\n");
+ printf("Status: 401 Bad Request\r\n\r\n");
break;
case 404:
- OUT("Status: 404 Not Found\r\n\r\n");
+ printf("Status: 404 Not Found\r\n\r\n");
break;
case 500:
- OUT("Status: 500 Internal Server Error\r\n\r\n");
+ printf("Status: 500 Internal Server Error\r\n\r\n");
break;
default:
err(1, "unknown status code %d\n", statuscode);
- OUT("Status: 500 Internal Server Error\r\n\r\n");
+ printf("Status: 500 Internal Server Error\r\n\r\n");
}
}
t@@ -60,8 +60,8 @@ pollfile(const char *poll_name, const char *postfix)
void
print_html_head()
{
- OUT("Content-type: text/html; charset=utf-8\r\n\r\n");
- OUT("<!DOCTYPE html>\n"
+ printf("Content-type: text/html; charset=utf-8\r\n\r\n");
+ printf("<!DOCTYPE html>\n"
"<html>\n"
"<body>\n");
}
t@@ -69,33 +69,45 @@ print_html_head()
void
print_html_foot()
{
- OUT("</body>\n"
+ printf("</body>\n"
"</html>\n");
}
int
-print_poll_line(char *line, int intable)
+print_poll_line(char *line, size_t *i, int intable, int vote)
{
size_t c;
if (sscanf(line, "%ld\t%s", &c, options) == 2) {
- if (!intable)
- puts("<br><table>");
- printf("<tr><td>%ld</td><td>%s</td></tr>\n", c, options);
+ if (!intable) {
+ puts("</p>\n<table>");
+ if (vote) {
+ puts("<form method=\"get\" action=\"\">");
+ printf("<input type=\"hidden\" name=\"poll\" "
+ "value=\"%s\" />\n", poll);
+ }
+ }
+ if (vote) {
+ printf("\t<tr><td>");
+ printf("<input type=\"radio\" "
+ "id=\"%ld\" name=\"choice\" value=\"%ld\" />",
+ ++*i, *i);
+ printf("</td><td>%s</td></tr>\n", options);
+ } else
+ printf("\t<tr><td>%ld</td><td>%s</td></tr>\n", c, options);
return 1;
} else {
- if (intable)
- puts("</table>");
+
printf("%s<br>\n", line);
return 0;
}
}
void
-print_poll_file(FILE *fp)
+print_poll_file(FILE *fp, int vote)
{
char *line = NULL;
- size_t linesize = 0, lineno = 0;
+ size_t linesize = 0, lineno = 0, i = 0;
ssize_t linelen;
int intable = 0;
t@@ -107,9 +119,9 @@ print_poll_file(FILE *fp)
if (lineno == 1) {
printf("<h2>");
fwrite(line, linelen, 1, stdout);
- printf("</h2>\n");
+ printf("</h2>\n<p>");
} else {
- intable = print_poll_line(line, intable);
+ intable = print_poll_line(line, &i, intable, vote);
}
}
free(line);
t@@ -117,7 +129,13 @@ print_poll_file(FILE *fp)
http_status(500);
err(1, "print_poll_file: getline");
}
+
puts("</table>");
+ if (vote) {
+ puts("<input type=\"submit\" value=\"Submit\" "
+ "class=\"button\"/>");
+ puts("</form>");
+ }
}
int
t@@ -183,7 +201,7 @@ create_poll_file(const char *name, const char *question, const char *options)
}
void
-show_poll(const char *poll)
+show_poll(const char *poll, int vote)
{
FILE *fp;
t@@ -191,7 +209,7 @@ show_poll(const char *poll)
http_status(404);
exit(1);
} else {
- print_poll_file(fp);
+ print_poll_file(fp, vote);
fclose(fp);
}
}
t@@ -280,28 +298,28 @@ increment_option(char *poll, size_t n)
void
print_poll_create_form()
{
- OUT("<h2>Create new poll</h2>");
- OUT("<form method=\"get\" action=\"\">\n"
+ puts("<h2>Create new poll</h2>");
+ puts("<form method=\"get\" action=\"\">\n"
"<input type=\"hidden\" name=\"create\" value=\"1\" />\n"
"<table class=\"create\" width=\"100%\" border=\"0\" "
"cellpadding=\"0\" cellspacing=\"0\">\n"
"<tr>\n"
" <td width=\"100%\" class=\"input\">\n"
" <input type=\"text\" name=\"poll\" "
- " placeholder=\"Name\" size=\"60\" "
- " autofocus=\"autofocus\" class=\"name\" />\n"
+ "placeholder=\"Name\" size=\"60\" "
+ "autofocus=\"autofocus\" class=\"name\" />\n"
" </td>\n"
"</tr>\n"
"<tr>\n"
" <td width=\"100%\" class=\"input\">\n"
" <input type=\"text\" name=\"question\" "
- " placeholder=\"Question\" size=\"60\" class=\"question\" />\n"
+ "placeholder=\"Question\" size=\"60\" class=\"question\" />\n"
" </td>\n"
"</tr>\n"
"<tr>\n"
" <td width=\"100%\" class=\"input\">\n"
" <textarea rows=\"5\" cols=\"60\" name=\"options\" "
- " placeholder=\"Options (1 per line)\"></textarea>\n"
+ "placeholder=\"Options (1 per line)\"></textarea>\n"
" </td>\n"
"</tr>\n"
"<tr>\n"
t@@ -351,11 +369,20 @@ parse_query()
}
}
+ if ((p = getparam(query, "choice"))) {
+ if (decodeparam(choice, sizeof(create), p) == -1) {
+ http_status(401);
+ exit(1);
+ }
+ }
+
}
int
main()
{
+ size_t c;
+ const char *errstr;
struct stat sb;
if (unveil(getenv("PWD"), NULL) == -1 || unveil(NULL, NULL) == -1) {
t@@ -381,10 +408,16 @@ main()
if (*create) {
if (create_poll_file(poll, question, options) == 0)
- show_poll(poll);
+ show_poll(poll, 0);
} else if (*poll) {
- show_poll(poll);
- increment_option(poll, 2);
+ if (*choice) {
+ c = strtonum(choice, 1, 256, &errstr);
+ if (errstr != NULL)
+ errx(1, "could not parse choice: %s, %s", errstr, choice);
+ increment_option(poll, c);
+ show_poll(poll, 0);
+ } else
+ show_poll(poll, 1);
} else {
list_polls();
print_poll_create_form();