sfeed_gopher.c (4404B)
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <time.h> 5 6#include "util.h" 7 8static char *prefixpath = "/", *host = "127.0.0.1", *port = "70"; /* default */ 9static char *line; 10static size_t linesize; 11static time_t comparetime; 12 13/* Escape characters in gopher, CR and LF are ignored */ 14static void 15gophertext(FILE *fp, const char *s) 16{ 17 for (; *s; s++) { 18 switch (*s) { 19 case '\r': /* ignore CR */ 20 case '\n': /* ignore LF */ 21 break; 22 case '\t': 23 fputs(" ", fp); 24 break; 25 default: 26 putc(*s, fp); 27 break; 28 } 29 } 30} 31 32static void 33printfeed(FILE *fpitems, FILE *fpin, struct feed *f) 34{ 35 struct uri u; 36 char *fields[FieldLast]; 37 char *itemhost, *itemport, *itempath, *itemquery, *itemfragment; 38 ssize_t linelen; 39 unsigned int isnew; 40 struct tm rtm, *tm; 41 time_t parsedtime; 42 int itemtype; 43 44 if (f->name[0]) { 45 fprintf(fpitems, "i%s\t\t%s\t%s\r\n", f->name, host, port); 46 fprintf(fpitems, "i\t\t%s\t%s\r\n", host, port); 47 } 48 49 while ((linelen = getline(&line, &linesize, fpin)) > 0 && 50 !ferror(fpitems)) { 51 if (line[linelen - 1] == '\n') 52 line[--linelen] = '\0'; 53 parseline(line, fields); 54 55 itemhost = host; 56 itemport = port; 57 itemtype = 'i'; 58 itempath = fields[FieldLink]; 59 itemquery = ""; 60 itemfragment = ""; 61 62 if (fields[FieldLink][0]) { 63 itemtype = 'h'; 64 /* if it is a gopher URL then change it into a DirEntity */ 65 if (!strncmp(fields[FieldLink], "gopher://", 9) && 66 uri_parse(fields[FieldLink], &u) != -1) { 67 itemhost = u.host; 68 itemport = u.port[0] ? u.port : "70"; 69 itemtype = '1'; 70 itempath = u.path; 71 itemquery = u.query; 72 itemfragment = u.fragment; 73 74 if (itempath[0] == '/') { 75 itempath++; 76 if (*itempath) { 77 itemtype = *itempath; 78 itempath++; 79 } 80 } 81 } 82 } 83 84 parsedtime = 0; 85 if (!strtotime(fields[FieldUnixTimestamp], &parsedtime) && 86 (tm = localtime_r(&parsedtime, &rtm))) { 87 isnew = (parsedtime >= comparetime) ? 1 : 0; 88 f->totalnew += isnew; 89 90 fprintf(fpitems, "%c%c %04d-%02d-%02d %02d:%02d ", 91 itemtype, 92 isnew ? 'N' : ' ', 93 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 94 tm->tm_hour, tm->tm_min); 95 } else { 96 fprintf(fpitems, "%c ", itemtype); 97 } 98 f->total++; 99 100 gophertext(fpitems, fields[FieldTitle]); 101 fputs("\t", fpitems); 102 if (itemtype == 'h' && fields[FieldLink] == itempath) 103 fputs("URL:", fpitems); 104 gophertext(fpitems, itempath); 105 if (itemquery[0]) { 106 fputs("?", fpitems); 107 gophertext(fpitems, itemquery); 108 } 109 if (itemfragment[0]) { 110 fputs("#", fpitems); 111 gophertext(fpitems, itemfragment); 112 } 113 fprintf(fpitems, "\t%s\t%s\r\n", itemhost, itemport); 114 } 115 fputs(".\r\n", fpitems); 116} 117 118int 119main(int argc, char *argv[]) 120{ 121 struct feed f = { 0 }; 122 FILE *fpitems, *fpindex, *fp; 123 char *name, *p; 124 int i; 125 126 if (argc == 1) { 127 if (pledge("stdio", NULL) == -1) 128 err(1, "pledge"); 129 } else { 130 if (unveil("/", "r") == -1) 131 err(1, "unveil: /"); 132 if (unveil(".", "rwc") == -1) 133 err(1, "unveil: ."); 134 if (pledge("stdio rpath wpath cpath", NULL) == -1) 135 err(1, "pledge"); 136 } 137 138 if ((comparetime = getcomparetime()) == (time_t)-1) 139 errx(1, "getcomparetime"); 140 141 if ((p = getenv("SFEED_GOPHER_HOST"))) 142 host = p; 143 if ((p = getenv("SFEED_GOPHER_PORT"))) 144 port = p; 145 146 if (argc == 1) { 147 f.name = ""; 148 printfeed(stdout, stdin, &f); 149 checkfileerror(stdin, "<stdin>", 'r'); 150 checkfileerror(stdout, "<stdout>", 'w'); 151 } else { 152 if ((p = getenv("SFEED_GOPHER_PATH"))) 153 prefixpath = p; 154 155 /* write main index page */ 156 if (!(fpindex = fopen("index", "wb"))) 157 err(1, "fopen: index"); 158 159 for (i = 1; i < argc; i++) { 160 memset(&f, 0, sizeof(f)); 161 name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i]; 162 f.name = name; 163 164 if (!(fp = fopen(argv[i], "r"))) 165 err(1, "fopen: %s", argv[i]); 166 if (!(fpitems = fopen(name, "wb"))) 167 err(1, "fopen"); 168 printfeed(fpitems, fp, &f); 169 checkfileerror(fp, argv[i], 'r'); 170 checkfileerror(fpitems, name, 'w'); 171 fclose(fp); 172 fclose(fpitems); 173 174 /* append directory item to index */ 175 fputs("1", fpindex); 176 gophertext(fpindex, name); 177 fprintf(fpindex, " (%lu/%lu)\t", f.totalnew, f.total); 178 gophertext(fpindex, prefixpath); 179 gophertext(fpindex, name); 180 fprintf(fpindex, "\t%s\t%s\r\n", host, port); 181 } 182 fputs(".\r\n", fpindex); 183 checkfileerror(fpindex, "index", 'w'); 184 fclose(fpindex); 185 } 186 187 return 0; 188}