sfeed_mbox.c - sfeed - RSS and Atom parser | |
git clone git://git.codemadness.org/sfeed | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
sfeed_mbox.c (4890B) | |
--- | |
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 #include <time.h> | |
5 #include <unistd.h> | |
6 | |
7 #include "util.h" | |
8 | |
9 static char *line; | |
10 static size_t linesize; | |
11 static char host[256], *user, dtimebuf[32], mtimebuf[32]; | |
12 static int usecontent = 0; /* env variable: $SFEED_MBOX_CONTENT */ | |
13 | |
14 static unsigned long long | |
15 djb2(unsigned char *s, unsigned long long hash) | |
16 { | |
17 int c; | |
18 | |
19 while ((c = *s++)) | |
20 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ | |
21 return hash; | |
22 } | |
23 | |
24 /* Unescape / decode fields printed by string_print_encoded() | |
25 * "\\" to "\", "\t", to TAB, "\n" to newline. Other escape sequences are | |
26 * ignored: "\z" etc. Mangle "From " in mboxrd style (always prefix >). … | |
27 static void | |
28 printcontent(const char *s, FILE *fp) | |
29 { | |
30 escapefrom: | |
31 for (; *s == '>'; s++) | |
32 putc('>', fp); | |
33 /* escape "From ", mboxrd-style. */ | |
34 if (!strncmp(s, "From ", 5)) | |
35 putc('>', fp); | |
36 | |
37 for (; *s; s++) { | |
38 switch (*s) { | |
39 case '\\': | |
40 if (*(s + 1) == '\0') | |
41 break; | |
42 s++; | |
43 switch (*s) { | |
44 case 'n': | |
45 putc('\n', fp); | |
46 s++; | |
47 goto escapefrom; | |
48 case '\\': putc('\\', fp); break; | |
49 case 't': putc('\t', fp); break; | |
50 } | |
51 break; | |
52 default: | |
53 putc(*s, fp); break; | |
54 } | |
55 } | |
56 } | |
57 | |
58 static void | |
59 printfeed(FILE *fp, const char *feedname) | |
60 { | |
61 char *fields[FieldLast], timebuf[32]; | |
62 struct tm parsedtm, *tm; | |
63 time_t parsedtime; | |
64 unsigned long long hash; | |
65 ssize_t linelen; | |
66 int ishtml; | |
67 | |
68 while ((linelen = getline(&line, &linesize, fp)) > 0 && | |
69 !ferror(stdout)) { | |
70 if (line[linelen - 1] == '\n') | |
71 line[--linelen] = '\0'; | |
72 hash = djb2((unsigned char *)line, 5381ULL); | |
73 parseline(line, fields); | |
74 | |
75 /* mbox + mail header */ | |
76 printf("From MAILER-DAEMON %s\n", mtimebuf); | |
77 | |
78 parsedtime = 0; | |
79 if (!strtotime(fields[FieldUnixTimestamp], &parsedtime) … | |
80 (tm = gmtime_r(&parsedtime, &parsedtm)) && | |
81 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:… | |
82 printf("Date: %s\n", timebuf); | |
83 } else { | |
84 printf("Date: %s\n", dtimebuf); /* invalid/missi… | |
85 } | |
86 | |
87 printf("From: %s <anonymous@>\n", fields[FieldAuthor][0]… | |
88 printf("To: %s <%s@%s>\n", user, user, host); | |
89 printf("Subject: %s\n", fields[FieldTitle]); | |
90 printf("Message-ID: <%s%s%llu@%s>\n", | |
91 fields[FieldUnixTimestamp], | |
92 fields[FieldUnixTimestamp][0] ? "." : "", | |
93 hash, feedname); | |
94 | |
95 ishtml = usecontent && !strcmp(fields[FieldContentType],… | |
96 if (ishtml) | |
97 fputs("Content-Type: text/html; charset=\"utf-8\… | |
98 else | |
99 fputs("Content-Type: text/plain; charset=\"utf-8… | |
100 fputs("Content-Transfer-Encoding: binary\n", stdout); | |
101 printf("X-Feedname: %s\n", feedname); | |
102 fputs("\n", stdout); | |
103 | |
104 if (ishtml) { | |
105 fputs("<p>\n", stdout); | |
106 if (fields[FieldLink][0]) { | |
107 fputs("Link: <a href=\"", stdout); | |
108 xmlencode(fields[FieldLink], stdout); | |
109 fputs("\">", stdout); | |
110 xmlencode(fields[FieldLink], stdout); | |
111 fputs("</a><br/>\n", stdout); | |
112 } | |
113 if (fields[FieldEnclosure][0]) { | |
114 fputs("Enclosure: <a href=\"", stdout); | |
115 xmlencode(fields[FieldEnclosure], stdout… | |
116 fputs("\">", stdout); | |
117 xmlencode(fields[FieldEnclosure], stdout… | |
118 fputs("</a><br/>\n", stdout); | |
119 } | |
120 fputs("</p>\n", stdout); | |
121 } else { | |
122 if (fields[FieldLink][0]) | |
123 printf("Link: %s\n", fields[FieldLi… | |
124 if (fields[FieldEnclosure][0]) | |
125 printf("Enclosure: %s\n", fields[FieldEn… | |
126 } | |
127 if (usecontent) { | |
128 fputs("\n", stdout); | |
129 if (ishtml && fields[FieldLink][0]) { | |
130 fputs("<base href=\"", stdout); | |
131 xmlencode(fields[FieldLink], stdout); | |
132 fputs("\"/>\n", stdout); | |
133 } | |
134 printcontent(fields[FieldContent], stdout); | |
135 } | |
136 fputs("\n\n", stdout); | |
137 } | |
138 } | |
139 | |
140 int | |
141 main(int argc, char *argv[]) | |
142 { | |
143 struct tm tmnow; | |
144 time_t now; | |
145 FILE *fp; | |
146 char *name, *tmp; | |
147 int i; | |
148 | |
149 if (pledge(argc == 1 ? "stdio" : "stdio rpath", NULL) == -1) | |
150 err(1, "pledge"); | |
151 | |
152 if ((tmp = getenv("SFEED_MBOX_CONTENT"))) | |
153 usecontent = !strcmp(tmp, "1"); | |
154 if (!(user = getenv("USER"))) | |
155 user = "you"; | |
156 if (gethostname(host, sizeof(host)) == -1) | |
157 err(1, "gethostname"); | |
158 if ((now = time(NULL)) == (time_t)-1) | |
159 errx(1, "time"); | |
160 if (!gmtime_r(&now, &tmnow)) | |
161 err(1, "gmtime_r: can't get current time"); | |
162 if (!strftime(mtimebuf, sizeof(mtimebuf), "%a %b %d %H:%M:%S %Y"… | |
163 errx(1, "strftime: can't format current time"); | |
164 if (!strftime(dtimebuf, sizeof(dtimebuf), "%a, %d %b %Y %H:%M:%S… | |
165 errx(1, "strftime: can't format current time"); | |
166 | |
167 if (argc == 1) { | |
168 printfeed(stdin, ""); | |
169 checkfileerror(stdin, "<stdin>", 'r'); | |
170 } else { | |
171 for (i = 1; i < argc; i++) { | |
172 if (!(fp = fopen(argv[i], "r"))) | |
173 err(1, "fopen: %s", argv[i]); | |
174 name = ((name = strrchr(argv[i], '/'))) ? name +… | |
175 printfeed(fp, name); | |
176 checkfileerror(fp, argv[i], 'r'); | |
177 checkfileerror(stdout, "<stdout>", 'w'); | |
178 fclose(fp); | |
179 } | |
180 } | |
181 | |
182 checkfileerror(stdout, "<stdout>", 'w'); | |
183 | |
184 return 0; | |
185 } |