main.c - www.codemadness.org - www.codemadness.org saait content files
(HTM) git clone git://git.codemadness.org/www.codemadness.org
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
main.c (3812B)
---
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6
7 #ifdef __OpenBSD__
8 #include <unistd.h>
9 #else
10 #define pledge(p1,p2) 0
11 #define unveil(p1,p2) 0
12 #endif
13
14 int
15 hexdigit(int c)
16 {
17 if (c >= '0' && c <= '9')
18 return c - '0';
19 else if (c >= 'A' && c <= 'F')
20 return c - 'A' + 10;
21 else if (c >= 'a' && c <= 'f')
22 return c - 'a' + 10;
23
24 return 0;
25 }
26
27 /* decode until NUL separator or end of "key". */
28 int
29 decodeparam(char *buf, size_t bufsiz, const char *s)
30 {
31 size_t i;
32
33 if (!bufsiz)
34 return -1;
35
36 for (i = 0; *s && *s != '&'; s++) {
37 switch (*s) {
38 case '%':
39 if (i + 3 >= bufsiz)
40 return -1;
41 if (!isxdigit((unsigned char)*(s+1)) ||
42 !isxdigit((unsigned char)*(s+2)))
43 return -1;
44 buf[i++] = hexdigit(*(s+1)) * 16 + hexdigit(*(s+2));
45 s += 2;
46 break;
47 case '+':
48 if (i + 1 >= bufsiz)
49 return -1;
50 buf[i++] = ' ';
51 break;
52 default:
53 if (i + 1 >= bufsiz)
54 return -1;
55 buf[i++] = *s;
56 break;
57 }
58 }
59 buf[i] = '\0';
60
61 return i;
62 }
63
64 char *
65 getparam(const char *query, const char *s)
66 {
67 const char *p, *last = NULL;
68 size_t len;
69
70 len = strlen(s);
71 for (p = query; (p = strstr(p, s)); p += len) {
72 if (p[len] == '=' && (p == query || p[-1] == '&' || p[-1] == '?'))
73 last = p + len + 1;
74 }
75
76 return (char *)last;
77 }
78
79 void
80 error(const char *s)
81 {
82 fputs("Status: 400 Bad Request\r\n", stdout);
83 fputs("Content-Type: text/plain\r\n", stdout);
84 fputs("\r\n", stdout);
85 fputs(s, stdout);
86 exit(0);
87 }
88
89 int
90 main(void)
91 {
92 time_t now;
93 FILE *fp;
94 char filename[256];
95 char _type[32], msg[4096], captcha[16], from[256];
96 char *p, *query;
97 int r, valid;
98
99 if (unveil("/donations", "rwc") == -1)
100 return 1;
101 if (pledge("stdio rpath cpath wpath", NULL) == -1)
102 return 1;
103
104 query = getenv("QUERY_STRING");
105 if (!query)
106 query = "";
107 if (query[0] == '?')
108 query++;
109
110 valid = 0;
111 if ((p = getparam(query, "captcha"))) {
112 r = decodeparam(captcha, sizeof(captcha), p);
113 if (r != -1 && !strcmp(captcha, "yes"))
114 valid = 1;
115 }
116 if (!valid)
117 error("Captcha must be: yes\n");
118
119 from[0] = '\0';
120 if ((p = getparam(query, "from"))) {
121 r = decodeparam(from, sizeof(from), p);
122 if (r == -1)
123 from[0] = '\0';
124 }
125
126 valid = 0;
127 if ((p = getparam(query, "type"))) {
128 r = decodeparam(_type, sizeof(_type), p);
129 if (r != -1 && (_type[0] == 'c' || _type[0] == 'h' || _type[0] == 'j' || _type[0] == 'm'))
130 valid = 1;
131 }
132 if (!valid)
133 error("Please select a type of donation\n");
134
135 valid = 0;
136 if ((p = getparam(query, "msg"))) {
137 r = decodeparam(msg, sizeof(msg), p);
138 if (msg[0])
139 valid = 1;
140 }
141 if (!valid)
142 error("Please type a message\n");
143
144 if (!(p = getparam(query, "pay")))
145 error("Please click the pay button\n");
146
147 /* future scaling improvement: multiple parallel donations at the same time won't work */
148 now = time(NULL);
149 r = snprintf(filename, sizeof(filename), "/donations/%c_%lld.txt", _type[0], (long long)now);
150 if (r < 0 || (size_t)r >= sizeof(filename))
151 error("shit happens\n");
152
153 fp = fopen(filename, "w+b");
154 if (!fp)
155 error("Cannot receive donation, thanks anyway.\n");
156
157 if (from[0])
158 fputs(from, fp);
159 else
160 fputs("Some person", fp);
161
162 switch (_type[0]) {
163 case 'c':
164 fputs(" sent a compliment:\n\n", fp);
165 break;
166 case 'h':
167 fputs(" sent pure hatred:\n\n", fp);
168 break;
169 case 'j':
170 fputs(" sent a joke:\n\n", fp);
171 break;
172 case 'm':
173 fputs(" sent ONE MILLION DOLLARS:\n\n", fp);
174 break;
175 }
176
177 fputs(msg, fp);
178 fputs("\n", fp);
179 fclose(fp);
180
181 if (_type[0] == 'm') {
182 fputs("Status: 302 Found\r\n", stdout);
183
184 fputs("Location: https://www.codemadness.org/downloads/1_million_dollars.webm\r\n", stdout);
185 } else {
186 fputs("Status: 200 OK\r\n", stdout);
187 }
188
189 fputs("Content-Type: text/plain\r\n", stdout);
190 fputs("\r\n", stdout);
191 fputs("Thank you for your donation!\n", stdout);
192 return 0;
193
194 return 0;
195 }