Introduction
Introduction Statistics Contact Development Disclaimer Help
reddit.c - frontends - front-ends for some sites (experiment)
Log
Files
Refs
README
LICENSE
---
reddit.c (6587B)
---
1 #include <sys/socket.h>
2 #include <sys/types.h>
3
4 #include <ctype.h>
5 #include <errno.h>
6 #include <netdb.h>
7 #include <stdarg.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
14
15 #include "https.h"
16 #include "json.h"
17 #include "reddit.h"
18 #include "util.h"
19
20 static char *
21 reddit_request(const char *path)
22 {
23 return request("old.reddit.com", path, "");
24 }
25
26 /* unmarshal JSON response, skip HTTP headers */
27 int
28 json_unmarshal(const char *data,
29 void (*cb)(struct json_node *, size_t, const char *, size_t, voi…
30 void *pp)
31 {
32 const char *s;
33
34 /* strip/skip header part */
35 if (!(s = strstr(data, "\r\n\r\n"))) {
36 fprintf(stderr, "error parsing HTTP response header\n");
37 return -1; /* invalid response */
38 }
39 s += strlen("\r\n\r\n");
40
41 /* parse */
42 if (parsejson(s, strlen(s), cb, pp) < 0) {
43 fprintf(stderr, "error parsing JSON\n");
44 return -1;
45 }
46
47 return 0;
48 }
49
50 char *
51 reddit_list_data(const char *subreddit, int limit,
52 const char *before, const char *after)
53 {
54 char path[4096];
55 int r;
56
57 if (limit <= 0)
58 limit = 25;
59
60 if (subreddit[0])
61 r = snprintf(path, sizeof(path), "/r/%s/.json?raw_json=1…
62 subreddit, limit);
63 else
64 r = snprintf(path, sizeof(path), "/.json?raw_json=1&limi…
65 limit);
66
67 if (before[0]) {
68 strlcat(path, "&before=", sizeof(path));
69 strlcat(path, before, sizeof(path));
70 } else if (after[0]) {
71 strlcat(path, "&after=", sizeof(path));
72 strlcat(path, after, sizeof(path));
73 }
74
75 if (r < 0 || (size_t)r >= sizeof(path))
76 return NULL;
77
78 return reddit_request(path);
79 }
80
81 void
82 reddit_list_processnode(struct json_node *nodes, size_t depth, const cha…
83 void *pp)
84 {
85 struct list_response *r = (struct list_response *)pp;
86 struct item *item;
87 struct json_node *node;
88 struct tm *tm;
89
90 if (depth == 3 &&
91 nodes[0].type == JSON_TYPE_OBJECT &&
92 nodes[1].type == JSON_TYPE_OBJECT &&
93 nodes[2].type == JSON_TYPE_STRING &&
94 !strcmp(nodes[0].name, "") &&
95 !strcmp(nodes[1].name, "data")) {
96 if (!strcmp(nodes[2].name, "before")) {
97 strlcpy(r->before, value, sizeof(r->before));
98 } else if (!strcmp(nodes[2].name, "after")) {
99 strlcpy(r->after, value, sizeof(r->after));
100 }
101 }
102
103 if (r->nitems > MAX_ITEMS)
104 return;
105
106 /* new item */
107 if (depth == 5 &&
108 nodes[0].type == JSON_TYPE_OBJECT &&
109 nodes[1].type == JSON_TYPE_OBJECT &&
110 nodes[2].type == JSON_TYPE_ARRAY &&
111 nodes[3].type == JSON_TYPE_OBJECT &&
112 nodes[4].type == JSON_TYPE_OBJECT &&
113 !strcmp(nodes[0].name, "") &&
114 !strcmp(nodes[1].name, "data") &&
115 !strcmp(nodes[2].name, "children") &&
116 !strcmp(nodes[3].name, "") &&
117 !strcmp(nodes[4].name, "data")) {
118 r->nitems++;
119 return;
120 }
121
122 if (r->nitems == 0)
123 return;
124 item = &(r->items[r->nitems - 1]);
125
126 if (depth >= 5 &&
127 nodes[0].type == JSON_TYPE_OBJECT &&
128 nodes[1].type == JSON_TYPE_OBJECT &&
129 nodes[2].type == JSON_TYPE_ARRAY &&
130 nodes[3].type == JSON_TYPE_OBJECT &&
131 nodes[4].type == JSON_TYPE_OBJECT &&
132 !strcmp(nodes[0].name, "") &&
133 !strcmp(nodes[1].name, "data") &&
134 !strcmp(nodes[2].name, "children") &&
135 !strcmp(nodes[3].name, "") &&
136 !strcmp(nodes[4].name, "data")) {
137 if (depth == 6) {
138 node = &nodes[5];
139 switch (node->type) {
140 case JSON_TYPE_BOOL:
141 if (!strcmp(node->name, "is_video"))
142 item->is_video = value[0] == 't';
143 break;
144 case JSON_TYPE_NUMBER:
145 if (!strcmp(node->name, "ups"))
146 item->ups = strtol(value, NULL, …
147 else if (!strcmp(node->name, "downs"))
148 item->downs = strtol(value, NULL…
149 else if (!strcmp(node->name, "num_commen…
150 item->num_comments = strtol(valu…
151 else if (!strcmp(node->name, "created_ut…
152 item->created_utc = strtoll(valu…
153 /* convert to struct tm */
154 tm = gmtime(&(item->created_utc)…
155 memcpy(&(item->created_tm), tm, …
156 }
157 break;
158 case JSON_TYPE_STRING:
159 if (!strcmp(node->name, "name"))
160 strlcpy(item->name, value, sizeo…
161 else if (!strcmp(node->name, "title"))
162 strlcpy(item->title, value, size…
163 else if (!strcmp(node->name, "url"))
164 strlcpy(item->url, value, sizeof…
165 else if (!strcmp(node->name, "permalink"…
166 strlcpy(item->permalink, value, …
167 else if (!strcmp(node->name, "subreddit"…
168 strlcpy(item->subreddit, value, …
169 else if (!strcmp(node->name, "author"))
170 strlcpy(item->author, value, siz…
171 else if (!strcmp(node->name, "thumbnail"…
172 strlcpy(item->thumbnail, value, …
173 else if (!strcmp(node->name, "link_flair…
174 strlcpy(item->link_flair_text, v…
175 else if (!strcmp(node->name, "link_flair…
176 strlcpy(item->link_flair_backgro…
177 break;
178 default:
179 break;
180 }
181 } else if (depth == 8 &&
182 nodes[5].type == JSON_TYPE_OBJECT &&
183 nodes[6].type == JSON_TYPE_OBJECT &&
184 (!strcmp(nodes[5].name, "media") || !strcmp(nodes[5]…
185 !strcmp(nodes[6].name, "reddit_video")) {
186 node = &nodes[7];
187
188 switch (node->type) {
189 case JSON_TYPE_NUMBER:
190 /* prefer "insecure" */
191 if (nodes[5].name[0] == 's' && item->dur…
192 break;
193 if (!strcmp(node->name, "duration"))
194 item->duration = strtol(value, N…
195 break;
196 case JSON_TYPE_STRING:
197 /* prefer "insecure" */
198 if (nodes[5].name[0] == 's' && item->das…
199 break;
200 if (!strcmp(node->name, "dash_url"))
201 strlcpy(item->dash_url, value, s…
202 break;
203 default:
204 break;
205 }
206 }
207 }
208 }
209
210 struct list_response *
211 reddit_list(const char *subreddit, int limit,
212 const char *before, const char *after)
213 {
214 struct list_response *r;
215 char *data;
216
217 if (!(data = reddit_list_data(subreddit, limit, before, after)))…
218 fprintf(stderr, "%s\n", __func__);
219 return NULL;
220 }
221
222 if (!(r = calloc(1, sizeof(*r)))) {
223 fprintf(stderr, "calloc\n");
224 return NULL;
225 }
226
227 if (json_unmarshal(data, reddit_list_processnode, r) == -1) {
228 free(r);
229 r = NULL;
230 }
231 free(data);
232
233 return r;
234 }
235
236 int
237 reddit_isvalidlink(const char *s)
238 {
239 char *end = NULL;
240 unsigned long long l;
241
242 /* type prefix: reddit link is "t3_" */
243 if (strncmp(s, "t3_", 3))
244 return 0;
245 s += 3;
246
247 /* link is base36 */
248 errno = 0;
249 l = strtoull(s, &end, 36);
250 return (!errno && s != end && !*end && l > 0);
251 }
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.