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