Deploy contact page, too.
[blerg.git] / cgi / cgi_blerg.c
1 /* Blerg is (C) 2011 The Dominion of Awesome, and is distributed under a
2  * BSD-style license.  Please see the COPYING file for details.
3  */
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <cgi-util.h>
8 #include <yajl/yajl_gen.h>
9 #include "database.h"
10 #include "tags.h"
11 #include "auth.h"
12 #include "subscription.h"
13 #include "json.h"
14 #include "canned_responses.h"
15 #include "app.h"
16 #include "config.h"
17
18 yajl_gen_config yajl_c = { 0, 0 };
19
20 int check_auth(const char *username) {
21         if (username == NULL || username[0] == 0) {
22                 respond_403();
23                 return 0;
24         }
25
26         const char *given_token = cgi_getcookie("auth");
27         if (!auth_check_token(username, given_token)) {
28                 respond_403();
29                 return 0;
30         }
31         return 1;
32 }
33
34
35 void respond_for_range(struct blerg *b, uint64_t from, uint64_t to) {
36         const unsigned char *ybuf;
37         unsigned int len;
38         uint64_t i;
39         yajl_gen g;
40         uint64_t record_count = blerg_get_record_count(b);
41
42         printf("Content-type: application/json\r\n\r\n");
43
44         if (from > to || from >= record_count || to >= record_count || to - from > 99) {
45                 respond_JSON_Failure();
46                 return;
47         }
48
49         g = yajl_gen_alloc(&yajl_c, NULL);
50         yajl_gen_array_open(g);
51
52         for (i = to; i != from - 1; i--) {
53                 json_generate_one_record(g, NULL, b, i, 0);
54                 yajl_gen_get_buf(g, &ybuf, &len);
55                 fwrite(ybuf, len, 1, stdout);
56                 yajl_gen_clear(g);
57         }
58
59         yajl_gen_array_close(g);
60         yajl_gen_get_buf(g, &ybuf, &len);
61         fwrite(ybuf, len, 1, stdout);
62         yajl_gen_free(g);
63 }
64
65 void respond_blergref_list(struct blergref * results, int i) {
66         const unsigned char *ybuf;
67         unsigned int len;
68         struct blerg *b;
69         yajl_gen g;
70
71         i--;
72
73         printf("Content-type: application/json\r\n\r\n");
74         g = yajl_gen_alloc(&yajl_c, NULL);
75
76         yajl_gen_array_open(g);
77
78         while (i >= 0) {
79                 b = blerg_open(results[i].author);
80                 if (b != NULL) {
81                         json_generate_one_record(g, results[i].author, b, results[i].record, 0);
82                         blerg_close(b);
83                 }
84                 yajl_gen_get_buf(g, &ybuf, &len);
85                 fwrite(ybuf, len, 1, stdout);
86                 yajl_gen_clear(g);
87
88                 i--;
89         }
90
91         yajl_gen_array_close(g);
92         yajl_gen_get_buf(g, &ybuf, &len);
93         fwrite(ybuf, len, 1, stdout);
94         yajl_gen_free(g);
95 }
96
97 int main(int argc, char *argv[]) {
98         char *path;
99         char *request_method;
100         int ret, len;
101         struct url_info info;
102         char *data;
103
104         if (!blerg_init())
105                 exit(1);
106
107         if (cgi_init() != CGIERR_NONE)
108                 exit(0);
109
110         path = getenv("PATH_INFO");
111         if (path == NULL) {
112                 respond_404();
113                 exit(0);
114         }
115         request_method = getenv("REQUEST_METHOD");
116         if (request_method == NULL) {
117                 fprintf(stderr, "Request method is null!?\n");
118                 exit(0);
119         }
120
121         if (strncmp(path, "/get", 4) == 0 && strlen(path) > 4) {
122                 if (strncmp(request_method, "GET", 4) != 0) {
123                         respond_405();
124                         exit(0);
125                 }
126
127                 if (path[4] != '/') {
128                         respond_404();
129                         exit(0);
130                 }
131
132                 ret = parse_url_info(path + 5, &info);
133                 if ((ret & URL_INFO_NAME) == 0) {
134                         respond_404();
135                         exit(0);
136                 }
137
138                 if (!blerg_exists(info.name)) {
139                         respond_404();
140                         exit(0);
141                 }
142
143                 struct blerg *b = blerg_open(info.name);
144
145                 if ((ret & URL_INFO_RECORD) && (ret & URL_INFO_RECORD_TO)) {
146                         respond_for_range(b, info.record, info.record_to);
147                 } else if (ret & URL_INFO_RECORD) {
148                         ret = blerg_fetch(b, info.record, &data, &len);
149
150                         if (ret == 0) {
151                                 respond_404();
152                                 exit(0);
153                         }
154                         respond_simple_data(data, len);
155                 } else {
156                         uint64_t record_count, from, to;
157                         record_count = blerg_get_record_count(b);
158                         if (record_count == 0) {
159                                 respond_simple_data("[]", 2);
160                         } else {
161                                 to = record_count - 1;
162                                 from = (record_count > 50 ? to - 49 : 0);
163                                 respond_for_range(b, from, to);
164                         }
165                 }
166
167                 blerg_close(b);
168         } else if (strncmp(path, "/tag", 4) == 0 && strlen(path) > 4) {
169                 if (strcmp(request_method, "GET") != 0) {
170                         respond_405();
171                         exit(0);
172                 }
173
174                 if (path[4] != '/') {
175                         respond_404();
176                         exit(0);
177                 }
178
179                 ret = parse_url_info(path + 5, &info);
180                 if ((ret & URL_INFO_NAME) == 0) {
181                         respond_404();
182                         exit(0);
183                 }
184
185                 if (info.name[0] == 'H')
186                         info.name[0] = '#';
187                 if (!tag_exists(info.name)) {
188                         respond_404();
189                         exit(0);
190                 }
191
192                 int recs = 50;
193                 struct blergref *taglist = tag_list(info.name, 0, &recs, -1);
194
195                 if (recs == 0) {
196                         respond_simple_data("[]", 2);
197                 } else {
198                         respond_blergref_list(taglist, recs);
199                 }
200         } else if (strncmp(path, "/put", 4) == 0) {
201                 if (strcmp(request_method, "POST") != 0) {
202                         respond_405();
203                         exit(0);
204                 }
205
206                 const char *username = cgi_getentrystr("username");
207                 if (!check_auth(username))
208                         exit(0);
209
210                 if (path[4] == '/') {
211                         respond_404();
212                         exit(0);
213                 }
214
215                 const char *data = cgi_getentrystr("data");
216                 if (data == NULL || data[0] == 0) {
217                         respond_JSON_Failure();
218                         exit(0);
219                 }
220
221                 struct blerg *b = blerg_open(username);
222                 if (b == NULL) {
223                         respond_JSON_Failure();
224                         exit(0);
225                 }
226                 ret = blerg_store(b, data, strlen(data));
227                 blerg_close(b);
228                 if (ret == -1) {
229                         respond_JSON_Failure();
230                         exit(0);
231                 }
232
233                 respond_JSON_Success();
234         } else if (strncmp(path, "/info", 5) == 0) {
235                 if (strcmp(request_method, "GET") != 0) {
236                         respond_405();
237                         exit(0);
238                 }
239
240                 if (path[5] != '/') {
241                         respond_404();
242                         exit(0);
243                 }
244
245                 ret = parse_url_info(path + 6, &info);
246                 if ((ret & URL_INFO_NAME) == 0) {
247                         respond_404();
248                         exit(0);
249                 }
250
251                 if (!blerg_exists(info.name)) {
252                         respond_404();
253                         exit(0);
254                 }
255
256                 struct blerg *b = blerg_open(info.name);
257                 uint64_t record_count = blerg_get_record_count(b);
258                 blerg_close(b);
259
260                 char number[21];
261                 yajl_gen g = yajl_gen_alloc(&yajl_c, NULL);
262                 yajl_gen_map_open(g);
263                 yajl_gen_string(g, (unsigned char *)"record_count", 12);
264                 snprintf(number, 21, "%llu", record_count);
265                 yajl_gen_string(g, (unsigned char *)number, strlen(number));
266                 yajl_gen_map_close(g);
267
268                 const unsigned char *ybuf;
269                 unsigned int content_len;
270                 yajl_gen_get_buf(g, &ybuf, &content_len);
271
272                 printf("Content-type: application/json\r\n");
273                 printf("Content-length: %d\r\n\r\n", content_len);
274                 fwrite(ybuf, content_len, 1, stdout);
275
276                 yajl_gen_free(g);
277         } else if (strncmp(path, "/create", 8) == 0) {
278                 if (strcmp(request_method, "POST") != 0) {
279                         respond_405();
280                         exit(0);
281                 }
282
283                 const char *username = cgi_getentrystr("username");
284                 const char *password = cgi_getentrystr("password");
285                 if (username == NULL || username[0] == 0 ||
286                     password == NULL || password[0] == 0) {
287                         respond_JSON_Failure();
288                         exit(0);
289                 }
290
291                 if (blerg_exists(username)) {
292                         respond_JSON_Failure();
293                         exit(0);
294                 }
295
296                 struct blerg *b = blerg_open(username);
297                 if (b != NULL) {
298                         blerg_close(b);
299                         auth_set_password(username, password);
300                         
301                         respond_JSON_Success();
302                 } else {
303                         respond_JSON_Failure();
304                 }
305         } else if (strncmp(path, "/login", 7) == 0) {
306                 if (strcmp(request_method, "POST") != 0) {
307                         respond_405();
308                         exit(0);
309                 }
310
311                 const char *username = cgi_getentrystr("username");
312                 const char *password = cgi_getentrystr("password");
313                 if (username == NULL || username[0] == 0 ||
314                     password == NULL || password[0] == 0) {
315                         respond_JSON_Failure();
316                         exit(0);
317                 }
318
319                 char *token = auth_login(username, password);
320                 if (token == NULL) {
321                         respond_JSON_Failure();
322                         exit(0);
323                 }
324
325                 printf("Set-Cookie: auth=%s\r\n", token);
326                 free(token);
327
328                 respond_JSON_Success();
329         } else if (strncmp(path, "/logout", 8) == 0) {
330                 if (strcmp(request_method, "POST") != 0) {
331                         respond_405();
332                         exit(0);
333                 }
334
335                 const char *username = cgi_getentrystr("username");
336                 if (!check_auth(username))
337                         exit(0);
338
339                 const char *given_token = cgi_getcookie("auth");
340                 auth_logout(username, given_token);
341                 respond_JSON_Success();
342         } else if (strncmp(path, "/subscribe", 10) == 0 || strncmp(path, "/unsubscribe", 12) == 0) {
343                 const char *username = cgi_getentrystr("username");
344                 if (!check_auth(username))
345                         exit(0);
346
347                 if (path[1] == 'u') {
348                         if (path[12] != '/') {
349                                 respond_404();
350                                 exit(0);
351                         }
352
353                         ret = parse_url_info(path + 13, &info);
354                         if ((ret & URL_INFO_NAME) == 0) {
355                                 respond_404();
356                                 exit(0);
357                         }
358
359                         subscription_remove(username, info.name);
360                 } else {
361                         if (path[10] != '/') {
362                                 respond_404();
363                                 exit(0);
364                         }
365
366                         ret = parse_url_info(path + 11, &info);
367                         if ((ret & URL_INFO_NAME) == 0) {
368                                 respond_404();
369                                 exit(0);
370                         }
371
372                         subscription_add(username, info.name);
373                 }
374                 respond_JSON_Success();
375         } else if (strncmp(path, "/feed", 6) == 0) {
376                 const char *username = cgi_getentrystr("username");
377                 if (!check_auth(username))
378                         exit(0);
379
380                 int recs = 50;
381                 struct blergref *feedlist = subscription_list(username, 0, &recs, -1);
382
383                 if (recs == 0) {
384                         respond_simple_data("[]", 2);
385                 } else {
386                         respond_blergref_list(feedlist, recs);
387                 }
388
389                 struct blerg *b = blerg_open(username);
390                 blerg_set_subscription_mark(b);
391                 blerg_close(b);
392         } else if (strncmp(path, "/feedinfo", 9) == 0) {
393                 const char *username = cgi_getentrystr("username");
394                 if (!check_auth(username))
395                         exit(0);
396
397                 yajl_gen g = yajl_gen_alloc(&yajl_c, NULL);
398                 yajl_gen_map_open(g);
399                 if (path[9] == 0) {
400                         struct blerg *b = blerg_open(username);
401                         uint64_t subscription_mark = blerg_get_subscription_mark(b);
402                         blerg_close(b);
403
404                         yajl_gen_string(g, (unsigned char *)"new", 3);
405                         yajl_gen_integer(g, subscription_count_items(username) - subscription_mark);
406                 } else {
407                         yajl_gen_string(g, (unsigned char *)"subscribed", 10);
408                         ret = parse_url_info(path + 10, &info);
409                         if ((ret & URL_INFO_NAME) == 1) {
410                                 yajl_gen_bool(g, is_subscribed(username, info.name));
411                         } else {
412                                 yajl_gen_bool(g, 0);
413                         }
414                 }
415                 yajl_gen_map_close(g);
416
417                 const unsigned char *ybuf;
418                 unsigned int content_len;
419                 yajl_gen_get_buf(g, &ybuf, &content_len);
420
421                 printf("Content-type: application/json\r\n");
422                 printf("Content-length: %d\r\n\r\n", content_len);
423                 fwrite(ybuf, content_len, 1, stdout);
424
425                 yajl_gen_free(g);
426         } else if (strncmp(path, "/passwd", 7) == 0) {
427                 const char *username = cgi_getentrystr("username");
428                 if (!check_auth(username))
429                         exit(0);
430
431                 const char *password = cgi_getentrystr("password");
432                 const char *new_password = cgi_getentrystr("new_password");
433                 if (password == NULL || new_password == NULL) {
434                         respond_JSON_Failure();
435                 } else {
436                         if (auth_check_password(username, password)) {
437                                 auth_set_password(username, new_password);
438                                 respond_JSON_Success();
439                         } else {
440                                 respond_JSON_Failure();
441                         }
442                 }
443         } else {
444                 respond_404();
445                 exit(0);
446         }
447
448         cgi_quit();
449 }