Code

[PATCH] mailinfo: handle folded header.
[git.git] / tools / mailinfo.c
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>
10 static FILE *cmitmsg, *patchfile;
12 static char line[1000];
13 static char date[1000];
14 static char name[1000];
15 static char email[1000];
16 static char subject[1000];
18 static 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 }
28 static int handle_from(char *line)
29 {
30         char *at = strchr(line, '@');
31         char *dst;
33         if (!at)
34                 return 0;
36         /*
37          * If we already have one email, don't take any confusing lines
38          */
39         if (*email && strchr(at+1, '@'))
40                 return 0;
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;
58         at = line + strlen(line);
59         while (at > line) {
60                 unsigned char c = *--at;
61                 if (isalnum(c))
62                         break;
63                 *at = 0;
64         }
66         at = line;
67         for (;;) {
68                 unsigned char c = *at;
69                 if (!c)
70                         break;
71                 if (isalnum(c))
72                         break;
73                 at++;
74         }
76         at = sanity_check(at, email);
77         
78         strcpy(name, at);
79         return 1;
80 }
82 static void handle_date(char *line)
83 {
84         strcpy(date, line);
85 }
87 static void handle_subject(char *line)
88 {
89         strcpy(subject, line);
90 }
92 static 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);
102 static char * cleanup_subject(char *subject)
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;
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 }                       
136 static void cleanup_space(char *buf)
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         }
153 static void handle_rest(void)
155         char *sub = cleanup_subject(subject);
156         cleanup_space(name);
157         cleanup_space(date);
158         cleanup_space(email);
159         cleanup_space(sub);
160         printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n", name, email, sub, date);
161         FILE *out = cmitmsg;
163         do {
164                 if (!memcmp("diff -", line, 6) ||
165                     !memcmp("---", line, 3) ||
166                     !memcmp("Index: ", line, 7))
167                         out = patchfile;
169                 fputs(line, out);
170         } while (fgets(line, sizeof(line), stdin) != NULL);
172         if (out == cmitmsg) {
173                 fprintf(stderr, "No patch found\n");
174                 exit(1);
175         }
177         fclose(cmitmsg);
178         fclose(patchfile);
181 static int eatspace(char *line)
183         int len = strlen(line);
184         while (len > 0 && isspace(line[len-1]))
185                 line[--len] = 0;
186         return len;
189 static void handle_body(void)
191         int has_from = 0;
192         int has_date = 0;
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         }
218 static int read_one_header_line(char *line, int sz, FILE *in)
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;
239 static void usage(void)
241         fprintf(stderr, "mailinfo msg-file patch-file < email\n");
242         exit(1);
245 int main(int argc, char ** argv)
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;