1/*
2 * Another stupid program, this one parsing the headers of an
3 * email to figure out authorship and subject
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <ctype.h>
9
10static FILE *cmitmsg, *patchfile;
11
12static char line[1000];
13static char date[1000];
14static char name[1000];
15static char email[1000];
16static char subject[1000];
17
18static char *sanity_check(char *name, char *email)
19{
20 int len = strlen(name);
21 if (len < 3 || len > 60)
22 return email;
23 if (strchr(name, '@') || strchr(name, '<') || strchr(name, '>'))
24 return email;
25 return name;
26}
27
28static int handle_from(char *line)
29{
30 char *at = strchr(line, '@');
31 char *dst;
32
33 if (!at)
34 return 0;
35
36 /*
37 * If we already have one email, don't take any confusing lines
38 */
39 if (*email && strchr(at+1, '@'))
40 return 0;
41
42 while (at > line) {
43 char c = at[-1];
44 if (isspace(c) || c == '<')
45 break;
46 at--;
47 }
48 dst = email;
49 for (;;) {
50 unsigned char c = *at;
51 if (!c || c == '>' || isspace(c))
52 break;
53 *at++ = ' ';
54 *dst++ = c;
55 }
56 *dst++ = 0;
57
58 at = line + strlen(line);
59 while (at > line) {
60 unsigned char c = *--at;
61 if (isalnum(c))
62 break;
63 *at = 0;
64 }
65
66 at = line;
67 for (;;) {
68 unsigned char c = *at;
69 if (!c)
70 break;
71 if (isalnum(c))
72 break;
73 at++;
74 }
75
76 at = sanity_check(at, email);
77
78 strcpy(name, at);
79 return 1;
80}
81
82static void handle_date(char *line)
83{
84 strcpy(date, line);
85}
86
87static void handle_subject(char *line)
88{
89 strcpy(subject, line);
90}
91
92static void check_line(char *line, int len)
93{
94 if (!memcmp(line, "From:", 5) && isspace(line[5]))
95 handle_from(line+6);
96 else if (!memcmp(line, "Date:", 5) && isspace(line[5]))
97 handle_date(line+6);
98 else if (!memcmp(line, "Subject:", 8) && isspace(line[8]))
99 handle_subject(line+9);
100}
101
102static char * cleanup_subject(char *subject)
103{
104 for (;;) {
105 char *p;
106 int len, remove;
107 switch (*subject) {
108 case 'r': case 'R':
109 if (!memcmp("e:", subject+1, 2)) {
110 subject +=3;
111 continue;
112 }
113 break;
114 case ' ': case '\t': case ':':
115 subject++;
116 continue;
117
118 case '[':
119 p = strchr(subject, ']');
120 if (!p) {
121 subject++;
122 continue;
123 }
124 len = strlen(p);
125 remove = p - subject;
126 if (remove <= len *2) {
127 subject = p+1;
128 continue;
129 }
130 break;
131 }
132 return subject;
133 }
134}
135
136static void cleanup_space(char *buf)
137{
138 unsigned char c;
139 while ((c = *buf) != 0) {
140 buf++;
141 if (isspace(c)) {
142 buf[-1] = ' ';
143 c = *buf;
144 while (isspace(c)) {
145 int len = strlen(buf);
146 memmove(buf, buf+1, len);
147 c = *buf;
148 }
149 }
150 }
151}
152
153static void handle_rest(void)
154{
155 FILE *out = cmitmsg;
156 char *sub = cleanup_subject(subject);
157 cleanup_space(name);
158 cleanup_space(date);
159 cleanup_space(email);
160 cleanup_space(sub);
161 printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n", name, email, sub, date);
162
163 do {
164 if (!memcmp("diff -", line, 6) ||
165 !memcmp("---", line, 3) ||
166 !memcmp("Index: ", line, 7))
167 out = patchfile;
168
169 fputs(line, out);
170 } while (fgets(line, sizeof(line), stdin) != NULL);
171
172 if (out == cmitmsg) {
173 fprintf(stderr, "No patch found\n");
174 exit(1);
175 }
176
177 fclose(cmitmsg);
178 fclose(patchfile);
179}
180
181static int eatspace(char *line)
182{
183 int len = strlen(line);
184 while (len > 0 && isspace(line[len-1]))
185 line[--len] = 0;
186 return len;
187}
188
189static void handle_body(void)
190{
191 int has_from = 0;
192 int has_date = 0;
193
194 /* First lines of body can have From: and Date: */
195 while (fgets(line, sizeof(line), stdin) != NULL) {
196 int len = eatspace(line);
197 if (!len)
198 continue;
199 if (!memcmp("From:", line, 5) && isspace(line[5])) {
200 if (!has_from && handle_from(line+6)) {
201 has_from = 1;
202 continue;
203 }
204 }
205 if (!memcmp("Date:", line, 5) && isspace(line[5])) {
206 if (!has_date) {
207 handle_date(line+6);
208 has_date = 1;
209 continue;
210 }
211 }
212 line[len] = '\n';
213 handle_rest();
214 break;
215 }
216}
217
218static int read_one_header_line(char *line, int sz, FILE *in)
219{
220 int ofs = 0;
221 while (ofs < sz) {
222 int peek, len;
223 if (fgets(line + ofs, sz - ofs, in) == NULL)
224 return ofs;
225 len = eatspace(line + ofs);
226 if (len == 0)
227 return ofs;
228 peek = fgetc(in); ungetc(peek, in);
229 if (peek == ' ' || peek == '\t') {
230 /* Yuck, 2822 header "folding" */
231 ofs += len;
232 continue;
233 }
234 return ofs + len;
235 }
236 return ofs;
237}
238
239static void usage(void)
240{
241 fprintf(stderr, "mailinfo msg-file patch-file < email\n");
242 exit(1);
243}
244
245int main(int argc, char ** argv)
246{
247 if (argc != 3)
248 usage();
249 cmitmsg = fopen(argv[1], "w");
250 if (!cmitmsg) {
251 perror(argv[1]);
252 exit(1);
253 }
254 patchfile = fopen(argv[2], "w");
255 if (!patchfile) {
256 perror(argv[2]);
257 exit(1);
258 }
259 while (1) {
260 int len = read_one_header_line(line, sizeof(line), stdin);
261 if (!len) {
262 handle_body();
263 break;
264 }
265 check_line(line, len);
266 }
267 return 0;
268}