tools / mailinfo.con commit Merge with gitk. (3f81fc8)
   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}