Introduction
Introduction Statistics Contact Development Disclaimer Help
gopher.c - frontends - front-ends for some sites (experiment)
Log
Files
Refs
README
LICENSE
---
gopher.c (7294B)
---
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 <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #include "https.h"
14 #include "util.h"
15 #include "youtube.h"
16
17 #define OUT(s) (fputs((s), stdout))
18 #define OUTTEXT(s) gophertext(stdout, s, strlen(s));
19 #define OUTLINK(s) gophertext(stdout, s, strlen(s));
20
21 static const char *host = "127.0.0.1", *port = "70", *requestpath = "/";
22
23 void
24 line(int _type, const char *username, const char *selector)
25 {
26 putchar(_type);
27 OUTTEXT(username);
28 putchar('\t');
29 OUTLINK(selector);
30 printf("\t%s\t%s\r\n", host, port);
31 }
32
33 void
34 error(const char *s)
35 {
36 line('3', s, "");
37 }
38
39 void
40 info(const char *s)
41 {
42 line('i', s, "");
43 }
44
45 void
46 header(void)
47 {
48 }
49
50 void
51 footer(void)
52 {
53 fputs(".\r\n", stdout);
54 }
55
56 int
57 render_search(struct search_response *r)
58 {
59 struct item *v;
60 size_t i;
61
62 if (pledge("stdio", NULL) == -1)
63 exit(1);
64
65 header();
66
67 for (i = 0; i < r->nitems; i++) {
68 v = &(r->items[i]);
69
70 if (i > 0) {
71 info("");
72 info("");
73 }
74 if (v->id[0])
75 putchar('h');
76 else
77 putchar('i');
78
79 switch (v->linktype) {
80 case Channel:
81 OUT("[Channel] ");
82 OUTTEXT(v->channeltitle);
83 break;
84 case Movie:
85 OUT("[Movie] ");
86 OUTTEXT(v->title);
87 break;
88 case Playlist:
89 OUT("[Playlist] ");
90 OUTTEXT(v->title);
91 break;
92 default:
93 OUTTEXT(v->title);
94 break;
95 }
96
97 OUT("\t");
98 if (v->id[0]) {
99 OUT("URL:https://www.youtube.com/embed/");
100 OUTLINK(v->id);
101 }
102 printf("\t%s\t%s\r\n", host, port);
103
104 if (v->id[0]) {
105 printf("1Details\t%s?v=", requestpath);
106 OUTLINK(v->id);
107 printf("\t%s\t%s\r\n", host, port);
108 }
109
110 if (v->channelid[0]) {
111 OUT("1");
112 OUTTEXT(v->channeltitle);
113 printf("\t%s?c=", requestpath);
114 OUTLINK(v->channelid);
115 printf("\t%s\t%s\r\n", host, port);
116 } else if (v->userid[0]) {
117 OUT("1");
118 OUTTEXT(v->channeltitle);
119 printf("\t%s?u=", requestpath);
120 OUTLINK(v->userid);
121 printf("\t%s\t%s\r\n", host, port);
122 } else if (v->channeltitle[0]) {
123 OUT("i");
124 OUTTEXT(v->channeltitle);
125 printf("\t%s\t%s\t%s\r\n", "", host, port);
126 }
127
128 if (v->channelid[0] || v->userid[0]) {
129 OUT("hAtom feed of ");
130 OUTTEXT(v->channeltitle);
131 OUT("\t");
132 OUTLINK("URL:https://www.youtube.com/feeds/video…
133 if (v->channelid[0]) {
134 OUT("channel_id=");
135 OUTLINK(v->channelid);
136 } else if (v->userid[0]) {
137 OUT("user=");
138 OUTLINK(v->userid);
139 }
140 printf("\t%s\t%s\r\n", host, port);
141 }
142 if (v->duration[0]) {
143 OUT("iDuration: " );
144 OUTTEXT(v->duration);
145 printf("\t%s\t%s\t%s\r\n", "", host, port);
146 }
147 if (v->publishedat[0]) {
148 OUT("iPublished: ");
149 OUTTEXT(v->publishedat);
150 printf("\t%s\t%s\t%s\r\n", "", host, port);
151 }
152 if (v->viewcount[0]) {
153 OUT("iViews: ");
154 if (!printnumsep(v->viewcount))
155 OUT("0");
156 printf("\t%s\t%s\t%s\r\n", "", host, port);
157 }
158 }
159 footer();
160
161 return 0;
162 }
163
164 int
165 render_video(struct video_response *r)
166 {
167 char buf[256];
168 const char *s, *e;
169 /* softwrap: try to wrap on word boundary, otherwise hardwrap */
170 int i, sw = 72, hw = 9999;
171
172 if (pledge("stdio", NULL) == -1)
173 exit(1);
174
175 header();
176
177 info("");
178
179 OUT("hTitle: ");
180 OUTTEXT(r->title);
181 OUT("\tURL:https://www.youtube.com/embed/");
182 OUTTEXT(r->id);
183 printf("\t%s\t%s\r\n", host, port);
184
185 OUT("hURL: ");
186 OUT("https://www.youtube.com/embed/");
187 OUTTEXT(r->id);
188 OUT("\tURL:");
189 OUT("https://www.youtube.com/embed/");
190 OUTTEXT(r->id);
191 printf("\t%s\t%s\r\n", host, port);
192
193 if (r->lengthseconds > 0) {
194 OUT("iLength: ");
195 if (durationstr(r->lengthseconds, buf, sizeof(buf)) < si…
196 OUTTEXT(buf);
197 printf("\t%s\t%s\t%s\r\n", "", host, port);
198 }
199
200 OUT("hThumbnail: https://i.ytimg.com/vi/");
201 OUTTEXT(r->id);
202 OUT("/hqdefault.jpg\tURL:https://i.ytimg.com/vi/");
203 OUTLINK(r->id);
204 printf("/hqdefault.jpg\t%s\t%s\r\n", host, port);
205
206 if (r->author[0]) {
207 OUT("1Channel: ");
208 OUTTEXT(r->author);
209 printf("\t%s?c=%s\t%s\t%s\r\n", requestpath, r->channeli…
210
211 if (r->channelid[0]) {
212 OUT("hAtom feed\tURL:https://www.youtube.com/fee…
213 OUTTEXT(r->channelid);
214 printf("\t%s\t%s\r\n", host, port);
215 }
216 }
217
218 OUT("iViews: ");
219 snprintf(buf, sizeof(buf), "%ld", r->viewcount);
220 if (!printnumsep(buf))
221 OUT("0");
222 printf("\t%s\t%s\t%s\r\n", "", host, port);
223
224 if (r->publishdate[0]) {
225 OUT("iPublished: ");
226 OUTTEXT(r->publishdate);
227 printf("\t%s\t%s\t%s\r\n", "", host, port);
228 }
229
230 if (r->uploaddate[0]) {
231 OUT("iUploaded: ");
232 OUTTEXT(r->uploaddate);
233 printf("\t%s\t%s\t%s\r\n", "", host, port);
234 }
235
236 if (r->shortdescription[0]) {
237 info("");
238 info("");
239
240 /* multi-line text */
241 i = 0;
242 for (s = e = r->shortdescription; ; e++) {
243 if (!i)
244 putchar('i');
245 if (*e == '\n' || *e == '\0' ||
246 i > hw || (i > sw && (*e == ' ' || *e == '\t'…
247 i = 0;
248 gophertext(stdout, s, e - s);
249 printf("\t%s\t%s\t%s\r\n", "", host, por…
250 if (*e == '\0')
251 break;
252 s = e + 1;
253 } else {
254 /* start of rune, wrongly assume 1 rune …
255 if (!((unsigned char)*e & 0x80))
256 i++;
257 }
258 }
259 }
260
261 footer();
262
263 return 0;
264 }
265
266 int
267 main(void)
268 {
269 struct search_response *r = NULL;
270 struct video_response *vr = NULL;
271 const char *channelid = "", *userid = "", *videoid = "";
272 const char *querystring = "", *rawsearch = "", *p;
273 char search[1024] = "";
274
275 if (pledge("stdio dns inet rpath unveil", NULL) == -1)
276 exit(1);
277 if (unveil(TLS_CA_CERT_FILE, "r") == -1 ||
278 unveil(NULL, NULL) == -1)
279 exit(1);
280
281 if ((p = getenv("SERVER_NAME")))
282 host = p;
283 if ((p = getenv("SERVER_PORT")))
284 port = p;
285 if ((p = getenv("PATH_TRANSLATED")))
286 requestpath = p;
287 else if ((p = getenv("PATH_INFO"))) /* fallback to PATH_INFO */
288 requestpath = p;
289 if ((p = getenv("QUERY_STRING")))
290 querystring = p;
291
292 p = NULL;
293 if (querystring[0] == '?')
294 querystring++;
295 if (querystring[0] == 'c' && querystring[1] == '=') {
296 channelid = querystring + 2;
297 p = querystring = "";
298 } else if (querystring[0] == 'u' && querystring[1] == '=') {
299 userid = querystring + 2;
300 p = querystring = "";
301 } else if (querystring[0] == 'v' && querystring[1] == '=') {
302 videoid = querystring + 2;
303 p = querystring = "";
304 }
305
306 if (querystring[0])
307 p = querystring;
308 if (!p)
309 p = getenv("X_GOPHER_SEARCH"); /* geomyidae */
310 if (!p)
311 p = getenv("SEARCHREQUEST"); /* gophernicus */
312 if (p)
313 rawsearch = p;
314 if (p && !uriencode(p, search, sizeof(search))) {
315 error("Invalid search");
316 footer();
317 return 0;
318 }
319
320 OUT("7Search");
321 if (rawsearch[0]) {
322 OUT(": ");
323 OUT(rawsearch);
324 }
325 printf("\t%s\t%s\t%s\r\n", requestpath, host, port);
326
327 info("");
328 line('1', "<- back to main directory", requestpath);
329
330 if (search[0]) {
331 r = youtube_search(search, "", "relevance");
332 } else if (channelid[0]) {
333 r = youtube_channel_videos(channelid);
334 } else if (userid[0]) {
335 r = youtube_user_videos(userid);
336 } else if (videoid[0]) {
337 vr = youtube_video(videoid);
338 if (!vr || vr->isfound == 0) {
339 error("No video found");
340 footer();
341 return 0;
342 }
343 render_video(vr);
344 return 0;
345 } else {
346 footer();
347 return 0;
348 }
349 info("");
350
351 if (!r || r->nitems == 0) {
352 error("No videos found");
353 footer();
354 return 0;
355 }
356
357 render_search(r);
358
359 return 0;
360 }
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.