sfeed_atom.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include <sys/types.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include "util.h"
  6. static struct tm tmnow;
  7. static time_t now;
  8. static char *line;
  9. static size_t linesize;
  10. static void
  11. printcontent(const char *s)
  12. {
  13. for (; *s; ++s) {
  14. switch (*s) {
  15. case '<': fputs("&lt;", stdout); break;
  16. case '>': fputs("&gt;", stdout); break;
  17. case '\'': fputs("&#39;", stdout); break;
  18. case '&': fputs("&amp;", stdout); break;
  19. case '"': fputs("&quot;", stdout); break;
  20. case '\\':
  21. s++;
  22. switch (*s) {
  23. case 'n': putchar('\n'); break;
  24. case '\\': putchar('\\'); break;
  25. case 't': putchar('\t'); break;
  26. }
  27. break;
  28. default: putchar(*s);
  29. }
  30. }
  31. }
  32. static void
  33. printfeed(FILE *fp, const char *feedname)
  34. {
  35. char *fields[FieldLast], *p, *tmp;
  36. struct tm parsedtm, *tm;
  37. time_t parsedtime;
  38. ssize_t linelen;
  39. int c;
  40. while ((linelen = getline(&line, &linesize, fp)) > 0 &&
  41. !ferror(stdout)) {
  42. if (line[linelen - 1] == '\n')
  43. line[--linelen] = '\0';
  44. parseline(line, fields);
  45. fputs("<entry>\n\t<title>", stdout);
  46. if (feedname[0]) {
  47. fputs("[", stdout);
  48. xmlencode(feedname, stdout);
  49. fputs("] ", stdout);
  50. }
  51. xmlencode(fields[FieldTitle], stdout);
  52. fputs("</title>\n", stdout);
  53. if (fields[FieldLink][0]) {
  54. fputs("\t<link rel=\"alternate\" href=\"", stdout);
  55. xmlencode(fields[FieldLink], stdout);
  56. fputs("\" />\n", stdout);
  57. }
  58. /* prefer link over id for Atom <id>. */
  59. fputs("\t<id>", stdout);
  60. if (fields[FieldLink][0])
  61. xmlencode(fields[FieldLink], stdout);
  62. else if (fields[FieldId][0])
  63. xmlencode(fields[FieldId], stdout);
  64. fputs("</id>\n", stdout);
  65. if (fields[FieldEnclosure][0]) {
  66. fputs("\t<link rel=\"enclosure\" href=\"", stdout);
  67. xmlencode(fields[FieldEnclosure], stdout);
  68. fputs("\" />\n", stdout);
  69. }
  70. parsedtime = 0;
  71. if (strtotime(fields[FieldUnixTimestamp], &parsedtime) ||
  72. !(tm = gmtime_r(&parsedtime, &parsedtm)))
  73. tm = &tmnow;
  74. fprintf(stdout, "\t<updated>%04d-%02d-%02dT%02d:%02d:%02dZ</updated>\n",
  75. tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
  76. tm->tm_hour, tm->tm_min, tm->tm_sec);
  77. if (fields[FieldAuthor][0]) {
  78. fputs("\t<author><name>", stdout);
  79. xmlencode(fields[FieldAuthor], stdout);
  80. fputs("</name></author>\n", stdout);
  81. }
  82. if (fields[FieldContent][0]) {
  83. if (!strcmp(fields[FieldContentType], "html")) {
  84. fputs("\t<content type=\"html\">", stdout);
  85. } else {
  86. /* NOTE: an RSS/Atom viewer may or may not format
  87. whitespace such as newlines.
  88. Workaround: type="html" and <![CDATA[<pre></pre>]]> */
  89. fputs("\t<content type=\"text\">", stdout);
  90. }
  91. printcontent(fields[FieldContent]);
  92. fputs("</content>\n", stdout);
  93. }
  94. for (p = fields[FieldCategory]; (tmp = strchr(p, '|')); p = tmp + 1) {
  95. c = *tmp;
  96. *tmp = '\0'; /* temporary NUL-terminate */
  97. if (*p) {
  98. fputs("\t<category term=\"", stdout);
  99. xmlencode(p, stdout);
  100. fputs("\" />\n", stdout);
  101. }
  102. *tmp = c; /* restore */
  103. }
  104. fputs("</entry>\n", stdout);
  105. }
  106. }
  107. int
  108. main(int argc, char *argv[])
  109. {
  110. struct tm *tm;
  111. FILE *fp;
  112. char *name;
  113. int i;
  114. if (pledge(argc == 1 ? "stdio" : "stdio rpath", NULL) == -1)
  115. err(1, "pledge");
  116. if ((now = time(NULL)) == (time_t)-1)
  117. errx(1, "time");
  118. if (!(tm = gmtime_r(&now, &tmnow)))
  119. err(1, "gmtime_r");
  120. fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  121. "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n"
  122. "\t<title type=\"text\">Newsfeed</title>\n"
  123. "\t<author><name>sfeed</name></author>\n", stdout);
  124. printf("\t<id>urn:newsfeed:%lld</id>\n"
  125. "\t<updated>%04d-%02d-%02dT%02d:%02d:%02dZ</updated>\n",
  126. (long long)now,
  127. tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
  128. tm->tm_hour, tm->tm_min, tm->tm_sec);
  129. if (argc == 1) {
  130. printfeed(stdin, "");
  131. checkfileerror(stdin, "<stdin>", 'r');
  132. } else {
  133. for (i = 1; i < argc; i++) {
  134. if (!(fp = fopen(argv[i], "r")))
  135. err(1, "fopen: %s", argv[i]);
  136. name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
  137. printfeed(fp, name);
  138. checkfileerror(fp, argv[i], 'r');
  139. checkfileerror(stdout, "<stdout>", 'w');
  140. fclose(fp);
  141. }
  142. }
  143. fputs("</feed>\n", stdout);
  144. checkfileerror(stdout, "<stdout>", 'w');
  145. return 0;
  146. }