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