Workaround for apache mangling our /tag/#blah urls
[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         fwrite(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 (info.author[0] == 'H')
163                         info.author[0] = '#';
164                 if (!tag_exists(info.author)) {
165                         respond_404();
166                         exit(0);
167                 }
168
169                 int recs = 50;
170                 struct tag *taglist = tag_list(info.author, 0, &recs, -1);
171
172                 if (recs == 0) {
173                         respond_simple_data("[]", 2);
174                 } else {
175                         respond_taglist(taglist, recs);
176                 }
177         } else if (strncmp(path, "/put", 4) == 0) {
178                 if (strcmp(request_method, "POST") != 0) {
179                         respond_405();
180                         exit(0);
181                 }
182
183                 if (path[4] == '/') {
184                         respond_404();
185                         exit(0);
186                 }
187
188                 const char *username = cgi_getentrystr("username");
189                 const char *data = cgi_getentrystr("data");
190                 if (username == NULL || username[0] == 0 ||
191                     data == NULL || data[0] == 0) {
192                         respond_JSON_Failure();
193                         exit(0);
194                 }
195
196                 const char *given_token = cgi_getcookie("auth");
197                 if (!auth_check_token(username, given_token)) {
198                         respond_JSON_Failure();
199                         exit(0);
200                 }
201
202                 struct blerg *b = blerg_open(username);
203                 if (b == NULL) {
204                         respond_JSON_Failure();
205                         exit(0);
206                 }
207                 ret = blerg_store(b, data, strlen(data));
208                 blerg_close(b);
209                 if (ret == -1) {
210                         respond_JSON_Failure();
211                         exit(0);
212                 }
213
214                 respond_JSON_Success();
215         } else if (strncmp(path, "/info", 5) == 0) {
216                 if (strcmp(request_method, "GET") != 0) {
217                         respond_405();
218                         exit(0);
219                 }
220
221                 if (path[5] != '/') {
222                         respond_404();
223                         exit(0);
224                 }
225
226                 ret = parse_url_info(path + 6, &info);
227                 if ((ret & URL_INFO_AUTHOR) == 0) {
228                         respond_404();
229                         exit(0);
230                 }
231
232                 if (!blerg_exists(info.author)) {
233                         respond_404();
234                         exit(0);
235                 }
236
237                 struct blerg *b = blerg_open(info.author);
238                 uint64_t record_count = blerg_get_record_count(b);
239                 blerg_close(b);
240
241                 char number[21];
242                 yajl_gen g = yajl_gen_alloc(&yajl_c, NULL);
243                 yajl_gen_map_open(g);
244                 yajl_gen_string(g, "record_count", 12);
245                 snprintf(number, 21, "%llu", record_count);
246                 yajl_gen_string(g, number, strlen(number));
247                 yajl_gen_map_close(g);
248
249                 const unsigned char *ybuf;
250                 yajl_gen_get_buf(g, &ybuf, &len);
251
252                 printf("Content-type: application/json\r\n");
253                 printf("Content-length: %d\r\n\r\n", len);
254                 fwrite(ybuf, len, 1, stdout);
255
256                 yajl_gen_free(g);
257         } else if (strncmp(path, "/create", 8) == 0) {
258                 if (strcmp(request_method, "POST") != 0) {
259                         respond_405();
260                         exit(0);
261                 }
262
263                 const char *username = cgi_getentrystr("username");
264                 const char *password = cgi_getentrystr("password");
265                 if (username == NULL || username[0] == 0 ||
266                     password == NULL || password[0] == 0) {
267                         respond_JSON_Failure();
268                         exit(0);
269                 }
270
271                 if (blerg_exists(username)) {
272                         respond_JSON_Failure();
273                         exit(0);
274                 }
275
276                 struct blerg *b = blerg_open(username);
277                 blerg_close(b);
278                 auth_set_password(username, password);
279                 
280                 respond_JSON_Success();
281         } else if (strncmp(path, "/login", 7) == 0) {
282                 if (strcmp(request_method, "POST") != 0) {
283                         respond_405();
284                         exit(0);
285                 }
286
287                 const char *username = cgi_getentrystr("username");
288                 const char *password = cgi_getentrystr("password");
289                 if (username == NULL || username[0] == 0 ||
290                     password == NULL || password[0] == 0) {
291                         respond_JSON_Failure();
292                         exit(0);
293                 }
294
295                 if (!auth_login(username, password)) {
296                         respond_JSON_Failure();
297                         exit(0);
298                 }
299
300                 char *token = auth_get_token(username);
301                 printf("Set-Cookie: auth=%s\r\n", token);
302                 free(token);
303
304                 respond_JSON_Success();
305         } else if (strncmp(path, "/logout", 8) == 0) {
306                 if (strcmp(request_method, "POST") != 0) {
307                         respond_405();
308                         exit(0);
309                 }
310
311                 const char *username = cgi_getentrystr("username");
312                 if (username == NULL || username[0] == 0) {
313                         respond_JSON_Failure();
314                         exit(0);
315                 }
316
317
318                 const char *given_token = cgi_getcookie("auth");
319                 if (auth_check_token(username, given_token)) {
320                         auth_logout(username);
321                         respond_JSON_Success();
322                 } else {
323                         respond_JSON_Failure();
324                 }
325         } else {
326                 respond_404();
327                 exit(0);
328         }
329
330         cgi_quit();
331 }