sfeed_gopher.c 4.3 KB

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