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