Actually implement /tag in cgi_blerg. Also /create
[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 "app.h"
10 #include "config.h"
11
12 yajl_gen_config yajl_c = { 0, 0 };
13
14 void respond_simple_data(unsigned const char *data, int len) {
15         printf("Content-length: %d\r\n\r\n", len);
16         write(0, data, len);
17 }
18
19 void respond_404() {
20         printf("Status: 404 Not Found\r\n");
21         printf("Content-type: text/html\r\n");
22         printf("Content-length: %d\r\n\r\n", strlen(CONTENT_404));
23
24         printf(CONTENT_404);
25 }
26
27 void respond_405() {
28         printf("Status: 405 Method Not Allowed\r\n");
29         printf("Content-type: text/html\r\n");
30         printf("Content-length: %d\r\n\r\n", strlen(CONTENT_405));
31
32         printf(CONTENT_405);
33 }
34
35 void respond_JSON_Failure() {
36         respond_simple_data(JSON_FAILURE, strlen(JSON_FAILURE));
37 }
38
39 void respond_JSON_Success() {
40         respond_simple_data(JSON_SUCCESS, strlen(JSON_SUCCESS));
41 }
42
43 void respond_for_range(struct blerg *b, uint64_t from, uint64_t to) {
44         const unsigned char *ybuf;
45         unsigned int len;
46         uint64_t i;
47         yajl_gen g;
48         uint64_t record_count = blerg_get_record_count(b);
49
50         printf("Content-type: application/json\r\n\r\n");
51
52         if (from > to || from >= record_count || to >= record_count || to - from > 99) {
53                 respond_JSON_Failure();
54                 return;
55         }
56
57         g = yajl_gen_alloc(&yajl_c, NULL);
58         yajl_gen_array_open(g);
59
60         for (i = to; i != from - 1; i--) {
61                 json_generate_one_record(g, NULL, b, i);
62                 yajl_gen_get_buf(g, &ybuf, &len);
63                 write(0, ybuf, len);
64                 yajl_gen_clear(g);
65         }
66
67         yajl_gen_array_close(g);
68         yajl_gen_get_buf(g, &ybuf, &len);
69         write(0, ybuf, len);
70         yajl_gen_free(g);
71 }
72
73 void respond_taglist(struct tag *results, int i) {
74         const unsigned char *ybuf;
75         unsigned int len;
76         struct blerg *b;
77         yajl_gen g;
78
79         i--;
80
81         printf("Content-type: application/json\r\n\r\n");
82         g = yajl_gen_alloc(&yajl_c, NULL);
83
84         yajl_gen_array_open(g);
85
86         while (i >= 0) {
87                 b = blerg_open(results[i].author);
88                 if (b != NULL) {
89                         json_generate_one_record(g, results[i].author, b, results[i].record);
90                         blerg_close(b);
91                 }
92                 yajl_gen_get_buf(g, &ybuf, &len);
93                 write(0, ybuf, len);
94                 yajl_gen_clear(g);
95
96                 i--;
97         }
98
99         yajl_gen_array_close(g);
100         yajl_gen_get_buf(g, &ybuf, &len);
101         write(0, ybuf, len);
102         yajl_gen_free(g);
103 }
104
105 int main(int argc, char *argv[]) {
106         char *path;
107         char *request_method;
108         int ret, len;
109         struct url_info info;
110         char *data;
111
112         if (cgi_init() != CGIERR_NONE)
113                 exit(0);
114
115         path = getenv("PATH_INFO");
116         if (path == NULL) {
117                 respond_404();
118                 exit(0);
119         }
120         request_method = getenv("REQUEST_METHOD");
121
122         if (strncmp(path, "/get", 4) == 0 && strlen(path) > 4) {
123                 if (strncmp(request_method, "GET", 4) != 0) {
124                         respond_405();
125                         exit(0);
126                 }
127
128                 if (path[4] != '/') {
129                         respond_404();
130                         exit(0);
131                 }
132
133                 ret = parse_url_info(path + 5, &info);
134                 if ((ret & URL_INFO_AUTHOR) == 0) {
135                         respond_404();
136                         exit(0);
137                 }
138
139                 if (!blerg_exists(info.author)) {
140                         respond_404();
141                         exit(0);
142                 }
143
144                 struct blerg *b = blerg_open(info.author);
145
146                 if ((ret & URL_INFO_RECORD) && (ret & URL_INFO_RECORD_TO)) {
147                         respond_for_range(b, info.record, info.record_to);
148                 } else if (ret & URL_INFO_RECORD) {
149                         ret = blerg_fetch(b, info.record, &data, &len);
150
151                         if (ret == 0) {
152                                 respond_404();
153                                 exit(0);
154                         }
155                         respond_simple_data(data, len);
156                 } else {
157                         uint64_t record_count, from, to;
158                         record_count = blerg_get_record_count(b);
159                         if (record_count == 0) {
160                                 respond_simple_data("[]", 2);
161                         } else {
162                                 to = record_count - 1;
163                                 from = (record_count > 50 ? to - 49 : 0);
164                                 respond_for_range(b, from, to);
165                         }
166                 }
167
168                 blerg_close(b);
169         } else if (strncmp(path, "/tag", 4) == 0 && strlen(path) > 4) {
170                 if (strcmp(request_method, "GET") != 0) {
171                         respond_405();
172                         exit(0);
173                 }
174
175                 if (path[4] != '/') {
176                         respond_404();
177                         exit(0);
178                 }
179
180                 ret = parse_url_info(path + 5, &info);
181                 if ((ret & URL_INFO_AUTHOR) == 0) {
182                         respond_404();
183                         exit(0);
184                 }
185
186                 if (!tag_exists(info.author)) {
187                         respond_404();
188                         exit(0);
189                 }
190
191                 int recs = 50;
192                 struct tag *taglist = tag_list(info.author, 0, &recs, -1);
193
194                 if (recs == 0) {
195                         respond_simple_data("[]", 2);
196                 } else {
197                         respond_taglist(taglist, recs);
198                 }
199         } else if (strncmp(path, "/put", 4) == 0) {
200         } else if (strncmp(path, "/info", 5) == 0) {
201                 if (strcmp(request_method, "GET") != 0) {
202                         respond_405();
203                         exit(0);
204                 }
205
206                 if (path[5] != '/') {
207                         respond_404();
208                         exit(0);
209                 }
210
211                 ret = parse_url_info(path + 6, &info);
212                 if ((ret & URL_INFO_AUTHOR) == 0) {
213                         respond_404();
214                         exit(0);
215                 }
216
217                 if (!blerg_exists(info.author)) {
218                         respond_404();
219                         exit(0);
220                 }
221
222                 struct blerg *b = blerg_open(info.author);
223                 uint64_t record_count = blerg_get_record_count(b);
224                 blerg_close(b);
225
226                 char number[21];
227                 yajl_gen g = yajl_gen_alloc(&yajl_c, NULL);
228                 yajl_gen_map_open(g);
229                 yajl_gen_string(g, "record_count", 12);
230                 snprintf(number, 21, "%llu", record_count);
231                 yajl_gen_string(g, number, strlen(number));
232                 yajl_gen_map_close(g);
233
234                 const unsigned char *ybuf;
235                 yajl_gen_get_buf(g, &ybuf, &len);
236
237                 printf("Content-type: application/json\r\n");
238                 printf("Content-length: %d\r\n\r\n", len);
239                 write(0, ybuf, len);
240
241                 yajl_gen_free(g);
242         } else if (strncmp(path, "/create", 8) == 0) {
243                 if (strcmp(request_method, "POST") != 0) {
244                         respond_405();
245                         exit(0);
246                 }
247
248                 const char *username = cgi_getentrystr("username");
249                 const char *password = cgi_getentrystr("password");
250                 if (username == NULL || username[0] == 0 ||
251                     password == NULL || password[0] == 0) {
252                         respond_JSON_Failure();
253                         exit(0);
254                 }
255
256                 if (blerg_exists(username)) {
257                         respond_JSON_Failure();
258                         exit(0);
259                 }
260
261                 struct blerg *b = blerg_open(username);
262                 blerg_close(b);
263                 auth_set_password(username, password);
264                 
265                 respond_JSON_Success();
266         } else {
267                 respond_404();
268                 exit(0);
269         }
270
271         cgi_quit();
272 }