Introduction
Introduction Statistics Contact Development Disclaimer Help
cgi.c - frontends - front-ends for some sites (experiment)
Log
Files
Refs
README
LICENSE
---
cgi.c (9039B)
---
1 #include <sys/socket.h>
2 #include <sys/types.h>
3
4 #include <ctype.h>
5 #include <errno.h>
6 #include <netdb.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 #include <unistd.h>
13
14 #include "reddit.h"
15
16 #define OUT(s) (fputs((s), stdout))
17
18 extern char **environ;
19
20 static struct list_response *response;
21 static time_t now;
22
23 /* CGI parameters */
24 static char rawsearch[4096], search[4096];
25 static char subreddit[1024], mode[16], slimit[32], order[16];
26 static long limit = 100;
27
28 void
29 parsecgi(void)
30 {
31 char *query, *p;
32 size_t len;
33
34 if (!(query = getenv("QUERY_STRING")))
35 query = "";
36
37 /* subreddit: select subreddit */
38 if ((p = getparam(query, "subreddit"))) {
39 if (decodeparam(subreddit, sizeof(subreddit), p) == -1)
40 subreddit[0] = '\0';
41 }
42
43 /* order */
44 if ((p = getparam(query, "o"))) {
45 if (decodeparam(order, sizeof(order), p) == -1 ||
46 (strcmp(order, "hot") &&
47 strcmp(order, "new") &&
48 strcmp(order, "rising") &&
49 strcmp(order, "controversial")))
50 order[0] = '\0';
51 }
52 if (!order[0])
53 snprintf(order, sizeof(order), "hot");
54
55 #if 0
56 /* TODO */
57 /* page */
58 if ((p = getparam(query, "page"))) {
59 if (decodeparam(page, sizeof(page), p) == -1)
60 page[0] = '\0';
61 /* check if it's a number >= 0 and < 100 */
62 errno = 0;
63 curpage = strtol(page, NULL, 10);
64 if (errno || curpage < 0 || curpage > 100) {
65 curpage = 1;
66 page[0] = '\0';
67 }
68 }
69 #endif
70
71 /* limit */
72 if ((p = getparam(query, "limit"))) {
73 if (decodeparam(slimit, sizeof(slimit), p) == -1)
74 slimit[0] = '\0';
75 /* check if it's a number > 0 and < 100 */
76 errno = 0;
77 limit = strtol(slimit, NULL, 10);
78 if (errno || limit <= 0 || limit > 100) {
79 limit = 100; /* default */
80 slimit[0] = '\0';
81 }
82 }
83
84 /* mode */
85 if ((p = getparam(query, "m"))) {
86 if (decodeparam(mode, sizeof(mode), p) != -1) {
87 /* fixup first character (label) for matching */
88 if (mode[0])
89 mode[0] = tolower((unsigned char)mode[0]…
90 /* allowed themes */
91 if (strcmp(mode, "light") &&
92 strcmp(mode, "dark") &&
93 strcmp(mode, "pink") &&
94 strcmp(mode, "templeos"))
95 mode[0] = '\0';
96 }
97 }
98 if (!mode[0])
99 snprintf(mode, sizeof(mode), "light");
100
101 /* search */
102 if ((p = getparam(query, "q"))) {
103 if ((len = strcspn(p, "&")) && len + 1 < sizeof(rawsearc…
104 memcpy(rawsearch, p, len);
105 rawsearch[len] = '\0';
106 }
107
108 if (decodeparam(search, sizeof(search), p) == -1) {
109 OUT("Status: 401 Bad Request\r\n\r\n");
110 exit(1);
111 }
112 }
113 }
114
115 int
116 render(struct list_response *r)
117 {
118 struct item *items = r->items, *item;
119 char tmp[64], timebuf[32], baseurl[256];
120 char *start, *end;
121 int i;
122
123 #if 0
124 if (pledge("stdio", NULL) == -1) {
125 OUT("Status: 500 Internal Server Error\r\n\r\n");
126 exit(1);
127 }
128 #endif
129
130 OUT(
131 "Content-Type: text/html; charset=utf-8\r\n\r\n"
132 "<!DOCTYPE html>\n<html>\n<head>\n"
133 "<meta name=\"referrer\" content=\"no-referrer\" />\n"
134 "<meta http-equiv=\"Content-Type\" content=\"text/html; …
135 "<title>");
136 if (r->nitems && subreddit[0]) {
137 OUT("r/");
138 xmlencode(subreddit);
139 OUT(" - Reddit");
140 } else {
141 OUT("Reddit");
142 }
143 OUT("</title>\n");
144 OUT(
145 "<link rel=\"stylesheet\" href=\"css/");
146 xmlencode(mode);
147 OUT(
148 ".css\" type=\"text/css\" media=\"screen\" />\n"
149 "<link rel=\"icon\" type=\"image/png\" href=\"/favicon.p…
150 "<meta content=\"width=device-width\" name=\"viewport\" …
151 "</head>\n"
152 "<body class=\"search\">\n"
153 "<form method=\"get\" action=\"\">\n");
154
155 OUT("<input type=\"hidden\" name=\"m\" value=\"");
156 xmlencode(mode);
157 OUT("\" />\n");
158 if (subreddit[0]) {
159 OUT("<input type=\"hidden\" name=\"subreddit\" value=\""…
160 xmlencode(subreddit);
161 OUT("\" />\n");
162 }
163 OUT("<input type=\"hidden\" name=\"limit\" value=\"");
164 xmlencode("100"); /* TODO maybe */
165 OUT("\" />\n");
166 OUT("<input type=\"hidden\" name=\"order\" value=\"");
167 xmlencode("hot"); /* TODO maybe */
168 OUT("\" />\n");
169
170 OUT(
171 "<table class=\"search\" width=\"100%\" border=\"0\" cel…
172 "<tr>\n"
173 "<td width=\"100%\" class=\"input\">\n"
174 " <input type=\"search\" name=\"q\" value=\"\" pl…
175 "</td>\n"
176 "<td nowrap class=\"nowrap\">\n"
177 " <input type=\"submit\" value=\"Search\" class=\…
178 " <select name=\"o\" title=\"Order by\" accesskey…
179 " <option value=\"hot\" selected=\"select…
180 " <option value=\"new\">New</option>\n"
181 " <option value=\"rising\">Rising</option…
182 " <option value=\"controversial\">Controv…
183 " </select>\n"
184 " <label for=\"m\">Style: </label>\n");
185
186 if (!strcmp(mode, "light"))
187 OUT("\t\t<input type=\"submit\" name=\"m\" value=\"Dark\…
188 else
189 OUT("\t\t<input type=\"submit\" name=\"m\" value=\"Light…
190
191 OUT(
192 " </td>\n"
193 "</tr>\n"
194 "</table>\n"
195 "</form>\n");
196
197 if (r->nitems) {
198 OUT(
199 "<hr/>\n"
200 "<table class=\"items\" width=\"100%\" border=\"…
201 "<tbody>\n");
202
203 for (i = 0; i < r->nitems; i++) {
204 item = r->items + i;
205
206 OUT(
207 "<tr>\n"
208 "<td valign=\"middle\" align=\"center\" class=\"…
209 " \n");
210 printf("%zu", item->ups); /* upvotes / score */
211 OUT(
212 "</td>\n"
213 "<td valign=\"middle\" align=\"center\" class=\"…
214
215 if (item->thumbnail[0] && !strncmp(item->thumbna…
216 OUT("<a href=\"");
217
218 /* link directly to dash url for video */
219 if (item->is_video)
220 xmlencode(item->dash_url);
221 else
222 xmlencode(item->url);
223
224 OUT("\"><img src=\"");
225 xmlencode(item->thumbnail);
226 OUT("\" width=\"140\" alt=\"\" /></a>");
227 }
228
229 OUT(
230 "</td>\n"
231 "<td valign=\"top\">\n"
232 " <h2><a href=\"");
233 /* link directly to dash url for video */
234 if (item->is_video)
235 xmlencode(item->dash_url);
236 else
237 xmlencode(item->url);
238 OUT("\">");
239
240 /* base url of url: somesite.org */
241 baseurl[0] = '\0';
242 if (!item->is_video && item->url[0]) {
243 if ((start = strstr(item->url, "://"))) {
244 start += strlen("://");
245 if ((end = strstr(start, "/"))) {
246 if (end - start + 1 < si…
247 memcpy(baseurl, …
248 baseurl[end - st…
249 }
250 }
251 }
252 }
253
254 if (item->is_video)
255 OUT("[video] ");
256 xmlencode(item->title);
257
258 strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:…
259
260 OUT("</a></h2>\n");
261 OUT(
262 " <time datetime=\"");
263 OUT(timebuf);
264 OUT("\">Submitted ");
265 if (!friendlytime(item->created_utc)) {
266 OUT("on ");
267 OUT(timebuf);
268 }
269 OUT(" by</time>\n"
270 " <a href=\"\">");
271 xmlencode(item->author);
272 OUT("</a>\n");
273
274 /* global view: show subreddit */
275 if (!subreddit[0]) {
276 /* TODO: link */
277 OUT(" in r/");
278 xmlencode(item->subreddit);
279 }
280
281 OUT(
282 " <br/>\n"
283 " <br/>\n"
284 " <a href=\"https://old.reddit.com/");
285 xmlencode(item->permalink);
286 OUT("\">");
287
288 printf("%zu", item->num_comments);
289
290 OUT(" comments</a>\n"
291 "</td>\n"
292 "<td valign=\"top\" align=\"right\" class=\"tags…
293 " <span class=\"base\">");
294 OUT(baseurl);
295 OUT(
296 "</span>\n"
297 " <br/>\n"
298 " <span class=\"tag\">");
299
300 /* TODO: + flair color */
301 xmlencode(item->link_flair_text);
302 OUT(" </span>\n"
303 "</td>\n"
304 "</tr>\n");
305
306 OUT("<tr><td colspan=\"4\"><hr/></td></tr>\n");
307 }
308 OUT("</tbody>\n");
309
310 /* pagination does not work for user/channel search */
311 if (r->before[0] || r->after[0]) {
312 OUT(
313 "<tfoot>\n"
314 "<tr>\n"
315 "\t<td align=\"left\" class=\"nowrap\" n…
316 if (r->before[0]) {
317 OUT("\t\t<a href=\"?q=");
318 xmlencode(""); // TODO: remove q param l…
319 OUT("&amp;before=");
320 xmlencode(r->before);
321 OUT("&amp;m=");
322 xmlencode(mode);
323 OUT("\" rel=\"prev\" accesskey=\"p\">&la…
324 }
325 if (r->after[0]) {
326 OUT(
327 "\t</td>\n\t<td colspan=\"2\"></…
328 "\t<td align=\"right\" class=\"a…
329 OUT("\t\t<a href=\"?q="); // TODO: remov…
330 xmlencode(""); //
331 OUT("&amp;after=");
332 xmlencode(r->after);
333 OUT("&amp;m=");
334 xmlencode(mode);
335 OUT("\" rel=\"next\" accesskey=\"n\">nex…
336 }
337
338 OUT(
339 "\t</td>\n"
340 "</tr>\n"
341 "</tfoot>\n");
342 }
343 OUT("</table>\n");
344 }
345
346 OUT("</body>\n</html>\n");
347
348 return 0;
349 }
350
351 int
352 main(void)
353 {
354 struct list_response *r;
355
356 #if 0
357 if (pledge("stdio dns inet rpath unveil", NULL) == -1 ||
358 unveil(TLS_CA_CERT_FILE, "r") == -1 ||
359 unveil(NULL, NULL) == -1) {
360 OUT("Status: 500 Internal Server Error\r\n\r\n");
361 exit(1);
362 }
363 #endif
364
365 parsecgi();
366
367 #if 0
368 if (!rawsearch[0] && !chan[0] && !user[0])
369 goto show;
370 #endif
371
372 r = reddit_list(subreddit, ""); // TODO: page
373 if (!r || r->nitems <= 0) {
374 OUT("Status: 500 Internal Server Error\r\n\r\n");
375 exit(1);
376 }
377
378 show:
379 now = time(NULL);
380 render(r);
381
382 return 0;
383 }
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.