| t@@ -0,0 +1,206 @@
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+int
+uriencode(const char *s, char *buf, size_t bufsiz)
+{
+ static char hex[] = "0123456789ABCDEF";
+ char *d = buf, *e = buf + bufsiz;
+ unsigned char c;
+
+ if (!bufsiz)
+ return 0;
+
+ for (; *s; ++s) {
+ c = (unsigned char)*s;
+ if (d + 4 >= e)
+ return 0;
+ if (c == ' ' || c == '#' || c == '%' || c == '?' || c == '"' ||
+ c == '&' || c == '<' || c <= 0x1f || c >= 0x7f) {
+ *d++ = '%';
+ *d++ = hex[c >> 4];
+ *d++ = hex[c & 0x0f];
+ } else {
+ *d++ = *s;
+ }
+ }
+ *d = '\0';
+
+ return 1;
+}
+
+int
+hexdigit(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+
+ return 0;
+}
+
+/* decode until NUL separator or end of "key". */
+int
+decodeparam(char *buf, size_t bufsiz, const char *s)
+{
+ size_t i;
+
+ if (!bufsiz)
+ return -1;
+
+ for (i = 0; *s && *s != '&'; s++) {
+ switch (*s) {
+ case '%':
+ if (i + 3 >= bufsiz)
+ return -1;
+ if (!isxdigit((unsigned char)*(s+1)) ||
+ !isxdigit((unsigned char)*(s+2)))
+ return -1;
+ buf[i++] = hexdigit(*(s+1)) * 16 + hexdigit(*(s+2));
+ s += 2;
+ break;
+ case '+':
+ if (i + 1 >= bufsiz)
+ return -1;
+ buf[i++] = ' ';
+ break;
+ default:
+ if (i + 1 >= bufsiz)
+ return -1;
+ buf[i++] = *s;
+ break;
+ }
+ }
+ buf[i] = '\0';
+
+ return i;
+}
+
+char *
+getparam(const char *query, const char *s)
+{
+ const char *p, *last = NULL;
+ size_t len;
+
+ len = strlen(s);
+ for (p = query; (p = strstr(p, s)); p += len) {
+ if (p[len] == '=' && (p == query || p[-1] == '&' || p[-1] == '?'))
+ last = p + len + 1;
+ }
+
+ return (char *)last;
+}
+
+int
+friendlytime(time_t now, time_t t)
+{
+ long long d = now - t;
+
+ if (d < 60) {
+ printf("just now");
+ } else if (d < 3600) {
+ printf("%lld minutes ago", d / 60);
+ } else if (d <= 24*3600) {
+ printf("%lld hours ago", d / 3600);
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+/* Escape characters below as HTML 2.0 / XML 1.0. */
+void
+xmlencode(const char *s)
+{
+ for (; *s; s++) {
+ switch(*s) {
+ case '<': fputs("<", stdout); break;
+ case '>': fputs(">", stdout); break;
+ case '\'': fputs("'", stdout); break;
+ case '&': fputs("&", stdout); break;
+ case '"': fputs(""", stdout); break;
+ default: putchar(*s);
+ }
+ }
+}
+
+/* format `len' columns of characters. If string is shorter pad the rest
+ * with characters `pad`. */
+int
+utf8pad(char *buf, size_t bufsiz, const char *s, size_t len, int pad)
+{
+ wchar_t wc;
+ size_t col = 0, i, slen, siz = 0;
+ int rl, w;
+
+ if (!len)
+ return -1;
+
+ slen = strlen(s);
+ for (i = 0; i < slen; i += rl) {
+ if ((rl = mbtowc(&wc, &s[i], slen - i < 4 ? slen - i : 4)) <= 0)
+ break;
+ if ((w = wcwidth(wc)) == -1)
+ continue;
+ if (col + w > len || (col + w == len && s[i + rl])) {
+ if (siz + 4 >= bufsiz)
+ return -1;
+ memcpy(&buf[siz], "\xe2\x80\xa6", 3);
+ siz += 3;
+ if (col + w == len && w > 1)
+ buf[siz++] = pad;
+ buf[siz] = '\0';
+ return 0;
+ }
+ if (siz + rl + 1 >= bufsiz)
+ return -1;
+ memcpy(&buf[siz], &s[i], rl);
+ col += w;
+ siz += rl;
+ buf[siz] = '\0';
+ }
+
+ len -= col;
+ if (siz + len + 1 >= bufsiz)
+ return -1;
+ memset(&buf[siz], pad, len);
+ siz += len;
+ buf[siz] = '\0';
+
+ return 0;
+}
+
+/* Escape characters in gopher, CR and LF are ignored */
+void
+gophertext(FILE *fp, const char *s, size_t len)
+{
+ size_t i;
+
+ for (i = 0; *s && i < len; s++, i++) {
+ switch (*s) {
+ case '\r': /* ignore CR */
+ case '\n': /* ignore LF */
+ break;
+ case '\t':
+ fputs(" ", fp);
+ break;
+ default:
+ fputc(*s, fp);
+ break;
+ }
+ }
+} |
| t@@ -0,0 +1,18 @@
+#ifndef __OpenBSD__
+#define pledge(p1,p2) 0
+#define unveil(p1,p2) 0
+#endif
+
+#undef strlcat
+size_t strlcat(char *, const char *, size_t);
+#undef strlcpy
+size_t strlcpy(char *, const char *, size_t);
+
+int decodeparam(char *buf, size_t bufsiz, const char *s);
+int friendlytime(time_t now, time_t t);
+char *getparam(const char *query, const char *s);
+void gophertext(FILE *fp, const char *s, size_t len);
+int hexdigit(int c);
+int uriencode(const char *s, char *buf, size_t bufsiz);
+int utf8pad(char *buf, size_t bufsiz, const char *s, size_t len, int pad);
+void xmlencode(const char *s); |
| t@@ -5,20 +5,34 @@
#include
#include
#include
+#include "util.h"
#define OUT(s) (fputs((s), stdout))
#define POLLS_DIR "polls"
-static char poll[1024];
+static char rawpoll[1024], poll[1024];
void
-die_500() {
- OUT("Status: 500 Internal Server Error\r\n\r\n");
- exit(1);
+die(int statuscode)
+{
+ switch(statuscode) {
+ case 401:
+ OUT("Status: 401 Bad Request\r\n\r\n");
+ break;
+ case 500:
+ OUT("Status: 500 Internal Server Error\r\n\r\n");
+ break;
+ default:
+ fprintf(stderr, "unknown status code %d\n", statuscode);
+ OUT("Status: 500 Internal Server Error\r\n\r\n");
+ }
+
+ exit(statuscode);
}
void
-print_html_head() {
+print_html_head()
+{
OUT("Content-type: text/html; charset=utf-8\r\n\r\n");
OUT("\n"
"\n"
t@@ -26,39 +40,28 @@ print_html_head() {
}
void
-print_html_foot() {
+print_html_foot()
+{
OUT("\n"
" |