add gopher mode and twtxt output format - frontends - front-ends for some sites (experiment)
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit ee630780f97caacdc83bbbf29c60be757394f017
 (DIR) parent 5e29f7c0a3a955816bdc5e3b418726ec68d5e0b4
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sun, 14 May 2023 00:06:50 +0200
       
       add gopher mode and twtxt output format
       
       Diffstat:
         M youtube/feed.c                      |      73 ++++++++++++++++++++++++++-----
       
       1 file changed, 62 insertions(+), 11 deletions(-)
       ---
 (DIR) diff --git a/youtube/feed.c b/youtube/feed.c
       @@ -90,6 +90,7 @@ static void json_header(void);
        static void json_item(void);
        static void json_footer(void);
        static void sfeed_item(void); /* TSV / sfeed */
       +static void twtxt_item(void);
        
        static void string_append(String *, const char *, size_t);
        static void string_buffer_realloc(String *, size_t);
       @@ -151,7 +152,8 @@ static String attrrel, tmpstr;
        
        static struct search_response *search_res = NULL;
        static void (*printfields)(void) = sfeed_item;
       -static int cgimode = 0;
       +static int cgimode = 0, godmode = 0;
       +static const char *server_name = "127.0.0.1", *server_port = "70";
        
        static int
        tagcmp(const void *v1, const void *v2)
       @@ -631,6 +633,39 @@ sfeed_item(void)
                putchar('\n');
        }
        
       +static void
       +twtxt_item(void)
       +{
       +        struct item *v, *found = NULL;
       +        size_t i;
       +
       +        /* must have a video id */
       +        if (!ctx.fields[FeedFieldYoutubeId].str.len)
       +                return;
       +
       +        for (i = 0; i < search_res->nitems; i++) {
       +                v = &(search_res->items[i]);
       +                if (!strcmp(ctx.fields[FeedFieldYoutubeId].str.data, v->id))
       +                        found = v;
       +        }
       +        /* Only print the video if it was found in the feed aswell.
       +           This way it filters away shorts too. */
       +        if (!found)
       +                return;
       +
       +        string_print(&ctx.fields[FeedFieldTime].str);
       +        putchar(FieldSeparator);
       +        string_print(&ctx.fields[FeedFieldTitle].str);
       +        if (found->duration[0]) {
       +                fputs(" [", stdout);
       +                fputs(found->duration, stdout);
       +                fputs("]", stdout);
       +        }
       +        fputs(": ", stdout);
       +        string_print(&ctx.fields[FeedFieldLink].str);
       +        putchar('\n');
       +}
       +
        static int
        istag(const char *name, size_t len, const char *name2, size_t len2)
        {
       @@ -888,9 +923,13 @@ void
        usage(void)
        {
                if (cgimode) {
       -                fputs("Status: 400 Bad Request\r\n", stdout);
       -                fputs("Content-Type: text/plain; charset=utf-8\r\n\r\n", stdout);
       -                fputs("400 Bad Request\n", stdout);
       +                if (godmode) {
       +                        printf("3Bad Request\tErr\t%s\t%s\r\n", server_name, server_port);
       +                } else {
       +                        fputs("Status: 400 Bad Request\r\n", stdout);
       +                        fputs("Content-Type: text/plain; charset=utf-8\r\n\r\n", stdout);
       +                        fputs("400 Bad Request\n", stdout);
       +                }
                        exit(0);
                } else {
                        fputs("usage: feed <channelid> [atom|json|tsv]\n", stderr);
       @@ -903,19 +942,23 @@ main(int argc, char *argv[])
        {
                char buf[256];
                const char *channelid = NULL;
       -        char *data, *format = "tsv", *p, *requesturi, *tmp;
       +        char *data, *format = "tsv", *p, *path = NULL, *tmp;
                size_t i;
        
                if (pledge("stdio dns inet rpath unveil", NULL) == -1)
                        err(1, "pledge");
        
       -        if ((tmp = getenv("REQUEST_URI"))) {
       -                cgimode = 1;
       +        if ((tmp = getenv("REQUEST_URI")))
       +                path = tmp;
       +        else if ((tmp = getenv("REQUEST")))
       +                path = tmp;
        
       -                strlcpy(buf, tmp, sizeof(buf));
       -                requesturi = buf;
       +        if (path) {
       +                cgimode = 1;
       +                strlcpy(buf, path, sizeof(buf));
       +                path = buf;
        
       -                if (!(p = strrchr(requesturi, '/')))
       +                if (!(p = strrchr(path, '/')))
                                usage();
        
                        channelid = p + 1;
       @@ -923,6 +966,12 @@ main(int argc, char *argv[])
                                *p = '\0'; /* NULL terminate */
                                format = p + 1;
                        }
       +                if ((tmp = getenv("SERVER_NAME")))
       +                        server_name = tmp;
       +                if ((tmp = getenv("SERVER_PORT")))
       +                        server_port = tmp;
       +                if ((tmp = getenv("SERVER_PROTOCOL")) && strstr(tmp, "gopher"))
       +                        godmode = 1;
                } else {
                        if (argc <= 1)
                                usage();
       @@ -940,6 +989,8 @@ main(int argc, char *argv[])
                        printfields = json_item;
                else if (!strcmp(format, "tsv") || !strcmp(format, "sfeed"))
                        printfields = sfeed_item;
       +        else if (!strcmp(format, "txt") || !strcmp(format, "twtxt"))
       +                printfields = twtxt_item;
                else
                        usage();
        
       @@ -975,7 +1026,7 @@ main(int argc, char *argv[])
                        string_clear(&(ctx.fields[i].str));
                }
        
       -        if (cgimode) {
       +        if (cgimode && !godmode) {
                        fputs("Status: 200 OK\r\n", stdout);
                        if (!strcmp(format, "atom") || !strcmp(format, "xml"))
                                fputs("Content-Type: text/xml; charset=utf-8\r\n\r\n", stdout);