gopher.c - frontends - front-ends for some sites (experiment)
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       gopher.c (4954B)
       ---
            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 <time.h>
           12 #include <unistd.h>
           13 
           14 #include "https.h"
           15 #include "reddit.h"
           16 #include "util.h"
           17 
           18 #define OUT(s) (fputs((s), stdout))
           19 #define OUTLINK(s) gophertext(stdout, s, strlen(s))
           20 #define OUTTEXT(s) gophertext(stdout, s, strlen(s))
           21 
           22 static const char *baserel = "/reddit.cgi";
           23 static const char *host = "127.0.0.1", *port = "70";
           24 
           25 static char before[16], after[16], subreddit[1024];
           26 
           27 void
           28 line(int _type, const char *username, const char *selector)
           29 {
           30         putchar(_type);
           31         OUTTEXT(username);
           32         putchar('\t');
           33         OUTLINK(selector);
           34         printf("\t%s\t%s\r\n", host, port);
           35 }
           36 
           37 void
           38 error(const char *s)
           39 {
           40         line('3', s, "");
           41 }
           42 
           43 void
           44 info(const char *s)
           45 {
           46         line('i', s, "");
           47 }
           48 
           49 void
           50 dir(const char *username, const char *selector)
           51 {
           52         line('1', username, selector);
           53 }
           54 
           55 void
           56 html(const char *username, const char *selector)
           57 {
           58         line('h', username, selector);
           59 }
           60 
           61 void
           62 page(int _type, const char *username, const char *page)
           63 {
           64         putchar(_type);
           65         OUTTEXT(username);
           66         putchar('\t');
           67         printf("%s?p=%s", baserel, page);
           68         printf("\t%s\t%s\r\n", host, port);
           69 }
           70 
           71 void
           72 header(void)
           73 {
           74 }
           75 
           76 void footer(void)
           77 {
           78         printf(".\r\n");
           79 }
           80 
           81 void
           82 printitem(struct item *item)
           83 {
           84         if (!item || !item->title[0])
           85                 return;
           86 
           87         struct tm *tm = gmtime(&(item->created_utc));
           88 
           89         putchar('h');
           90         OUTTEXT(item->title);
           91         OUT(" by ");
           92         OUTTEXT(item->author);
           93         OUT(" at ");
           94         printf("%04d-%02d-%02d %02d:%02d",
           95                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           96                 tm->tm_hour, tm->tm_min);
           97         OUT("\tURL:");
           98         OUTLINK(item->url);
           99         printf("\t%s\t%s\r\n", host, port);
          100 
          101         /* if global (no subreddit), show where it was posted */
          102         if (!subreddit[0]) {
          103                 printf("1Posted in r/");
          104                 OUTTEXT(item->subreddit);
          105                 OUT("\t");
          106                 OUTTEXT(baserel);
          107                 OUT("?subreddit=");
          108                 OUTTEXT(item->subreddit);
          109                 printf("\t%s\t%s\r\n", host, port);
          110         }
          111 
          112         printf("hUpvotes: %ld, downvotes %ld, comments: %ld",
          113                item->ups, item->downs, item->num_comments);
          114         OUT("\tURL:https://old.reddit.com/r/");
          115         OUTTEXT(item->subreddit);
          116         OUTTEXT("/comments/");
          117         if (reddit_isvalidlink(item->name) && !strncmp(item->name, "t3_", 3))
          118                 OUTTEXT(item->name + 3);
          119         printf("/\t%s\t%s\r\n", host, port);
          120 
          121         /* TODO: also noticed "spoiler" as value, ignore? */
          122         if (item->thumbnail[0] &&
          123             strcmp(item->thumbnail, "self") &&
          124             strcmp(item->thumbnail, "default")) {
          125                 putchar('h');
          126                 OUT("Thumbnail");
          127                 OUT("\tURL:");
          128                 OUTTEXT(item->thumbnail);
          129                 printf("\t%s\t%s\r\n", host, port);
          130         }
          131 
          132         if (item->is_video) {
          133                 putchar('h');
          134                 OUT("Video, duration: ");
          135                 printf("%ld, url: ", item->duration);
          136                 OUTTEXT(item->dash_url);
          137                 OUT("\tURL:");
          138                 OUTTEXT(item->dash_url);
          139                 printf("\t%s\t%s\r\n", host, port);
          140         }
          141 
          142         info("");
          143 }
          144 
          145 int
          146 render_pagination(struct list_response *r)
          147 {
          148         int i = 0;
          149 
          150         if (r->before[0]) {
          151                 printf("1Previous page");
          152                 OUT("\t");
          153                 OUTTEXT(baserel);
          154                 OUT("?subreddit=");
          155                 OUTTEXT(subreddit);
          156                 OUT("&before=");
          157                 OUTTEXT(r->before);
          158                 printf("\t%s\t%s\r\n", host, port);
          159                 i++;
          160         }
          161         if (r->after[0]) {
          162                 printf("1Next page");
          163                 OUT("\t");
          164                 OUTTEXT(baserel);
          165                 OUT("?subreddit=");
          166                 OUTTEXT(subreddit);
          167                 OUT("&after=");
          168                 OUTTEXT(r->after);
          169                 printf("\t%s\t%s\r\n", host, port);
          170                 i++;
          171         }
          172         return i;
          173 }
          174 
          175 int
          176 render(struct list_response *r)
          177 {
          178         size_t i;
          179 
          180         header();
          181 
          182         if (pledge("stdio", NULL) == -1)
          183                 exit(1);
          184 
          185         if (render_pagination(r))
          186                 info("");
          187 
          188         for (i = 0; i < r->nitems; i++)
          189                 printitem(&(r->items[i]));
          190 
          191         render_pagination(r);
          192 
          193         footer();
          194 
          195         return 0;
          196 }
          197 
          198 static void
          199 usage(void)
          200 {
          201         printf("3Specify a subreddit\t\t%s\t%s\r\n", host, port);
          202         printf(".\r\n");
          203         exit(1);
          204 }
          205 
          206 int
          207 main(int argc, char *argv[])
          208 {
          209         struct list_response *r;
          210         char *querystring, *p, *search;
          211 
          212         if (pledge("stdio dns inet rpath unveil", NULL) == -1)
          213                 exit(1);
          214         if (unveil(TLS_CA_CERT_FILE, "r") == -1 ||
          215             unveil(NULL, NULL) == -1)
          216                 exit(1);
          217 
          218         if ((p = getenv("SERVER_NAME")))
          219                 host = p;
          220         if ((p = getenv("SERVER_PORT")))
          221                 port = p;
          222 
          223         if (!(querystring = getenv("QUERY_STRING")))
          224                 querystring = "";
          225 
          226         if ((p = getparam(querystring, "subreddit"))) {
          227                 if (decodeparam(subreddit, sizeof(subreddit), p) == -1)
          228                         subreddit[0] = '\0';
          229         } else {
          230                 if (!(search = getenv("X_GOPHER_SEARCH"))) /* geomyidae */
          231                         search = getenv("SEARCHREQUEST"); /* gophernicus */
          232 
          233                 if (search && !uriencode(search, subreddit, sizeof(subreddit)))
          234                         usage();
          235         }
          236 
          237         if ((p = getparam(querystring, "before"))) {
          238                 if (decodeparam(before, sizeof(before), p) == -1)
          239                         before[0] = '\0';
          240                 if (!reddit_isvalidlink(before))
          241                         before[0] = '\0';
          242         }
          243 
          244         if ((p = getparam(querystring, "after"))) {
          245                 if (decodeparam(after, sizeof(after), p) == -1)
          246                         after[0] = '\0';
          247                 if (!reddit_isvalidlink(after))
          248                         after[0] = '\0';
          249         }
          250 
          251         r = reddit_list(subreddit, 100, before, after);
          252         if (!r || r->nitems == 0) {
          253                 error("No items found");
          254                 printf(".\r\n");
          255                 exit(1);
          256         }
          257 
          258         render(r);
          259 
          260         return 0;
          261 }