Add subscription feed fetching, clean up a bit
[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 "canned_responses.h"
13 #include "app.h"
14 #include "config.h"
15
16 yajl_gen_config yajl_c = { 0, 0 };
17
18 void respond_for_range(struct blerg *b, uint64_t from, uint64_t to) {
19         const unsigned char *ybuf;
20         unsigned int len;
21         uint64_t i;
22         yajl_gen g;
23         uint64_t record_count = blerg_get_record_count(b);
24
25         printf("Content-type: application/json\r\n\r\n");
26
27         if (from > to || from >= record_count || to >= record_count || to - from > 99) {
28                 respond_JSON_Failure();
29                 return;
30         }
31
32         g = yajl_gen_alloc(&yajl_c, NULL);
33         yajl_gen_array_open(g);
34
35         for (i = to; i != from - 1; i--) {
36                 json_generate_one_record(g, NULL, b, i, 0);
37                 yajl_gen_get_buf(g, &ybuf, &len);
38                 fwrite(ybuf, len, 1, stdout);
39                 yajl_gen_clear(g);
40         }
41
42         yajl_gen_array_close(g);
43         yajl_gen_get_buf(g, &ybuf, &len);
44         fwrite(ybuf, len, 1, stdout);
45         yajl_gen_free(g);
46 }
47
48 void respond_blergref_list(struct blergref * results, int i) {
49         const unsigned char *ybuf;
50         unsigned int len;
51         struct blerg *b;
52         yajl_gen g;
53
54         i--;
55
56         printf("Content-type: application/json\r\n\r\n");
57         g = yajl_gen_alloc(&yajl_c, NULL);
58
59         yajl_gen_array_open(g);
60
61         while (i >= 0) {
62                 b = blerg_open(results[i].author);
63                 if (b != NULL) {
64                         json_generate_one_record(g, results[i].author, b, results[i].record, 0);
65                         blerg_close(b);
66                 }
67                 yajl_gen_get_buf(g, &ybuf, &len);
68                 fwrite(ybuf, len, 1, stdout);
69                 yajl_gen_clear(g);
70
71                 i--;
72         }
73
74         yajl_gen_array_close(g);
75         yajl_gen_get_buf(g, &ybuf, &len);
76         fwrite(ybuf, len, 1, stdout);
77         yajl_gen_free(g);
78 }
79
80 int main(int argc, char *argv[]) {
81         char *path;
82         char *request_method;
83         int ret, len;
84         struct url_info info;
85         char *data;
86
87         if (cgi_init() != CGIERR_NONE)
88                 exit(0);
89
90         path = getenv("PATH_INFO");
91         if (path == NULL) {
92                 respond_404();
93                 exit(0);
94         }
95         request_method = getenv("REQUEST_METHOD");
96         if (request_method == NULL) {
97                 fprintf(stderr, "Request method is null!?\n");
98                 exit(0);
99         }
100
101         if (strncmp(path, "/get", 4) == 0 && strlen(path) > 4) {
102                 if (strncmp(request_method, "GET", 4) != 0) {
103                         respond_405();
104                         exit(0);
105                 }
106
107                 if (path[4] != '/') {
108                         respond_404();
109                         exit(0);
110                 }
111
112                 ret = parse_url_info(path + 5, &info);
113                 if ((ret & URL_INFO_NAME) == 0) {
114                         respond_404();
115                         exit(0);
116                 }
117
118                 if (!blerg_exists(info.name)) {
119                         respond_404();
120                         exit(0);
121                 }
122
123                 struct blerg *b = blerg_open(info.name);
124
125                 if ((ret & URL_INFO_RECORD) && (ret & URL_INFO_RECORD_TO)) {
126                         respond_for_range(b, info.record, info.record_to);
127                 } else if (ret & URL_INFO_RECORD) {
128                         ret = blerg_fetch(b, info.record, &data, &len);
129
130                         if (ret == 0) {
131                                 respond_404();
132                                 exit(0);
133                         }
134                         respond_simple_data(data, len);
135                 } else {
136                         uint64_t record_count, from, to;
137                         record_count = blerg_get_record_count(b);
138                         if (record_count == 0) {
139                                 respond_simple_data("[]", 2);
140                         } else {
141                                 to = record_count - 1;
142                                 from = (record_count > 50 ? to - 49 : 0);
143                                 respond_for_range(b, from, to);
144                         }
145                 }
146
147                 blerg_close(b);
148         } else if (strncmp(path, "/tag", 4) == 0 && strlen(path) > 4) {
149                 if (strcmp(request_method, "GET") != 0) {
150                         respond_405();
151                         exit(0);
152                 }
153
154                 if (path[4] != '/') {
155                         respond_404();
156                         exit(0);
157                 }
158
159                 ret = parse_url_info(path + 5, &info);
160                 if ((ret & URL_INFO_NAME) == 0) {
161                         respond_404();
162                         exit(0);
163                 }
164
165                 if (info.name[0] == 'H')
166                         info.name[0] = '#';
167                 if (!tag_exists(info.name)) {
168                         respond_404();
169                         exit(0);
170                 }
171
172                 int recs = 50;
173                 struct blergref *taglist = tag_list(info.name, 0, &recs, -1);
174
175                 if (recs == 0) {
176                         respond_simple_data("[]", 2);
177                 } else {
178                         respond_blergref_list(taglist, recs);
179                 }
180         } else if (strncmp(path, "/put", 4) == 0) {
181                 if (strcmp(request_method, "POST") != 0) {
182                         respond_405();
183                         exit(0);
184                 }
185
186                 if (path[4] == '/') {
187                         respond_404();
188                         exit(0);
189                 }
190
191                 const char *username = cgi_getentrystr("username");
192                 const char *data = cgi_getentrystr("data");
193                 if (username == NULL || username[0] == 0 ||
194                     data == NULL || data[0] == 0) {
195                         respond_JSON_Failure();
196                         exit(0);
197                 }
198
199                 const char *given_token = cgi_getcookie("auth");
200                 if (!auth_check_token(username, given_token)) {
201                         respond_JSON_Failure();
202                         exit(0);
203                 }
204
205                 struct blerg *b = blerg_open(username);
206                 if (b == NULL) {
207                         respond_JSON_Failure();
208                         exit(0);
209                 }
210                 ret = blerg_store(b, data, strlen(data));
211                 blerg_close(b);
212                 if (ret == -1) {
213                         respond_JSON_Failure();
214                         exit(0);
215                 }
216
217                 respond_JSON_Success();
218         } else if (strncmp(path, "/info", 5) == 0) {
219                 if (strcmp(request_method, "GET") != 0) {
220                         respond_405();
221                         exit(0);
222                 }
223
224                 if (path[5] != '/') {
225                         respond_404();
226                         exit(0);
227                 }
228
229                 ret = parse_url_info(path + 6, &info);
230                 if ((ret & URL_INFO_NAME) == 0) {
231                         respond_404();
232                         exit(0);
233                 }
234
235                 if (!blerg_exists(info.name)) {
236                         respond_404();
237                         exit(0);
238                 }
239
240                 struct blerg *b = blerg_open(info.name);
241                 uint64_t record_count = blerg_get_record_count(b);
242                 blerg_close(b);
243
244                 char number[21];
245                 yajl_gen g = yajl_gen_alloc(&yajl_c, NULL);
246                 yajl_gen_map_open(g);
247                 yajl_gen_string(g, "record_count", 12);
248                 snprintf(number, 21, "%llu", record_count);
249                 yajl_gen_string(g, number, strlen(number));
250                 yajl_gen_map_close(g);
251
252                 const unsigned char *ybuf;
253                 yajl_gen_get_buf(g, &ybuf, &len);
254
255                 printf("Content-type: application/json\r\n");
256                 printf("Content-length: %d\r\n\r\n", len);
257                 fwrite(ybuf, len, 1, stdout);
258
259                 yajl_gen_free(g);
260         } else if (strncmp(path, "/create", 8) == 0) {
261                 if (strcmp(request_method, "POST") != 0) {
262                         respond_405();
263                         exit(0);
264                 }
265
266                 const char *username = cgi_getentrystr("username");
267                 const char *password = cgi_getentrystr("password");
268                 if (username == NULL || username[0] == 0 ||
269                     password == NULL || password[0] == 0) {
270                         respond_JSON_Failure();
271                         exit(0);
272                 }
273
274                 if (blerg_exists(username)) {
275                         respond_JSON_Failure();
276                         exit(0);
277                 }
278
279                 struct blerg *b = blerg_open(username);
280                 blerg_close(b);
281                 auth_set_password(username, password);
282                 
283                 respond_JSON_Success();
284         } else if (strncmp(path, "/login", 7) == 0) {
285                 if (strcmp(request_method, "POST") != 0) {
286                         respond_405();
287                         exit(0);
288                 }
289
290                 const char *username = cgi_getentrystr("username");
291                 const char *password = cgi_getentrystr("password");
292                 if (username == NULL || username[0] == 0 ||
293                     password == NULL || password[0] == 0) {
294                         respond_JSON_Failure();
295                         exit(0);
296                 }
297
298                 if (!auth_login(username, password)) {
299                         respond_JSON_Failure();
300                         exit(0);
301                 }
302
303                 char *token = auth_get_token(username);
304                 printf("Set-Cookie: auth=%s\r\n", token);
305                 free(token);
306
307                 respond_JSON_Success();
308         } else if (strncmp(path, "/logout", 8) == 0) {
309                 if (strcmp(request_method, "POST") != 0) {
310                         respond_405();
311                         exit(0);
312                 }
313
314                 const char *username = cgi_getentrystr("username");
315                 if (username == NULL || username[0] == 0) {
316                         respond_JSON_Failure();
317                         exit(0);
318                 }
319
320
321                 const char *given_token = cgi_getcookie("auth");
322                 if (auth_check_token(username, given_token)) {
323                         auth_logout(username);
324                         respond_JSON_Success();
325                 } else {
326                         respond_JSON_Failure();
327                 }
328         } else {
329                 respond_404();
330                 exit(0);
331         }
332
333         cgi_quit();
334 }