mailinfo.con commit Add "applypatch" and "dotest" scripts to tie it all together. (853916f)
   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, *filelist;
  11
  12static char line[1000];
  13static char name[1000];
  14static char email[1000];
  15static char subject[1000];
  16
  17static char *sanity_check(char *name, char *email)
  18{
  19        int len = strlen(name);
  20        if (len < 3 || len > 60)
  21                return email;
  22        if (strchr(name, '@') || strchr(name, '<') || strchr(name, '>'))
  23                return email;
  24        return name;
  25}
  26
  27static int handle_from(char *line)
  28{
  29        char *at = strchr(line, '@');
  30        char *dst;
  31
  32        if (!at)
  33                return 0;
  34
  35        /*
  36         * If we already have one email, don't take any confusing lines
  37         */
  38        if (*email && strchr(at+1, '@'))
  39                return 0;
  40
  41        while (at > line) {
  42                char c = at[-1];
  43                if (isspace(c) || c == '<')
  44                        break;
  45                at--;
  46        }
  47        dst = email;
  48        for (;;) {
  49                unsigned char c = *at;
  50                if (!c || c == '>' || isspace(c))
  51                        break;
  52                *at++ = ' ';
  53                *dst++ = c;
  54        }
  55        *dst++ = 0;
  56
  57        at = line + strlen(line);
  58        while (at > line) {
  59                unsigned char c = *--at;
  60                if (isalnum(c))
  61                        break;
  62                *at = 0;
  63        }
  64
  65        at = line;
  66        for (;;) {
  67                unsigned char c = *at;
  68                if (!c)
  69                        break;
  70                if (isalnum(c))
  71                        break;
  72                at++;
  73        }
  74
  75        at = sanity_check(at, email);
  76        
  77        strcpy(name, at);
  78        return 1;
  79}
  80
  81static void handle_subject(char *line)
  82{
  83        strcpy(subject, line);
  84}
  85
  86static void add_subject_line(char *line)
  87{
  88        while (isspace(*line))
  89                line++;
  90        *--line = ' ';
  91        strcat(subject, line);
  92}
  93
  94static void check_line(char *line, int len)
  95{
  96        static int cont = -1;
  97        if (!memcmp(line, "From:", 5) && isspace(line[5])) {
  98                handle_from(line+6);
  99                cont = 0;
 100                return;
 101        }
 102        if (!memcmp(line, "Subject:", 8) && isspace(line[8])) {
 103                handle_subject(line+9);
 104                cont = 1;
 105                return;
 106        }
 107        if (isspace(*line)) {
 108                switch (cont) {
 109                case 0:
 110                        fprintf(stderr, "I don't do 'From:' line continuations\n");
 111                        break;
 112                case 1:
 113                        add_subject_line(line);
 114                        return;
 115                default:
 116                        break;
 117                }
 118        }
 119        cont = -1;
 120}
 121
 122static char * cleanup_subject(char *subject)
 123{
 124        for (;;) {
 125                char *p;
 126                int len, remove;
 127                switch (*subject) {
 128                case 'r': case 'R':
 129                        if (!memcmp("e:", subject+1, 2)) {
 130                                subject +=3;
 131                                continue;
 132                        }
 133                        break;
 134                case ' ': case '\t': case ':':
 135                        subject++;
 136                        continue;
 137
 138                case '[':
 139                        p = strchr(subject, ']');
 140                        if (!p) {
 141                                subject++;
 142                                continue;
 143                        }
 144                        len = strlen(p);
 145                        remove = p - subject;
 146                        if (remove <= len *2) {
 147                                subject = p+1;
 148                                continue;
 149                        }       
 150                        break;
 151                }
 152                return subject;
 153        }
 154}                       
 155
 156static void cleanup_space(char *buf)
 157{
 158        unsigned char c;
 159        while ((c = *buf) != 0) {
 160                buf++;
 161                if (isspace(c)) {
 162                        buf[-1] = ' ';
 163                        c = *buf;
 164                        while (isspace(c)) {
 165                                int len = strlen(buf);
 166                                memmove(buf, buf+1, len);
 167                                c = *buf;
 168                        }
 169                }
 170        }
 171}
 172
 173/*
 174 * Hacky hacky. This depends not only on -p1, but on
 175 * filenames not having some special characters in them,
 176 * like tilde.
 177 */
 178static void show_filename(char *line)
 179{
 180        int len;
 181        char *name = strchr(line, '/');
 182
 183        if (!name || !isspace(*line))
 184                return;
 185        name++;
 186        len = 0;
 187        for (;;) {
 188                unsigned char c = name[len];
 189                switch (c) {
 190                default:
 191                        len++;
 192                        continue;
 193
 194                case 0: case ' ':
 195                case '\t': case '\n':
 196                        break;
 197
 198                /* patch tends to special-case these things.. */
 199                case '~':
 200                        break;
 201                }
 202                break;
 203        }
 204        /* remove ".orig" from the end - common patch behaviour */
 205        if (len > 5 && !memcmp(name+len-5, ".orig", 5))
 206                len -=5;
 207        if (!len)
 208                return;
 209        fprintf(filelist, "%.*s\n", len, name);
 210}
 211
 212static void handle_rest(void)
 213{
 214        char *sub = cleanup_subject(subject);
 215        cleanup_space(name);
 216        cleanup_space(email);
 217        cleanup_space(sub);
 218        printf("Author: %s\nEmail: %s\nSubject: %s\n\n", name, email, sub);
 219        FILE *out = cmitmsg;
 220
 221        do {
 222                /* Track filename information from the patch.. */
 223                if (!memcmp("---", line, 3)) {
 224                        out = patchfile;
 225                        show_filename(line+3);
 226                }
 227
 228                if (!memcmp("+++", line, 3))
 229                        show_filename(line+3);
 230
 231                fputs(line, out);
 232        } while (fgets(line, sizeof(line), stdin) != NULL);
 233
 234        if (out == cmitmsg) {
 235                fprintf(stderr, "No patch found\n");
 236                exit(1);
 237        }
 238
 239        fclose(cmitmsg);
 240        fclose(patchfile);
 241}
 242
 243static int eatspace(char *line)
 244{
 245        int len = strlen(line);
 246        while (len > 0 && isspace(line[len-1]))
 247                line[--len] = 0;
 248        return len;
 249}
 250
 251static void handle_body(void)
 252{
 253        int has_from = 0;
 254
 255        /* First line of body can be a From: */
 256        while (fgets(line, sizeof(line), stdin) != NULL) {
 257                int len = eatspace(line);
 258                if (!len)
 259                        continue;
 260                if (!memcmp("From:", line, 5) && isspace(line[5])) {
 261                        if (!has_from && handle_from(line+6)) {
 262                                has_from = 1;
 263                                continue;
 264                        }
 265                }
 266                line[len] = '\n';
 267                handle_rest();
 268                break;
 269        }
 270}
 271
 272static void usage(void)
 273{
 274        fprintf(stderr, "mailinfo msg-file path-file filelist-file < email\n");
 275        exit(1);
 276}
 277
 278int main(int argc, char ** argv)
 279{
 280        if (argc != 4)
 281                usage();
 282        cmitmsg = fopen(argv[1], "w");
 283        if (!cmitmsg) {
 284                perror(argv[1]);
 285                exit(1);
 286        }
 287        patchfile = fopen(argv[2], "w");
 288        if (!patchfile) {
 289                perror(argv[2]);
 290                exit(1);
 291        }
 292        filelist = fopen(argv[3], "w");
 293        if (!filelist) {
 294                perror(argv[3]);
 295                exit(1);
 296        }
 297        while (fgets(line, sizeof(line), stdin) != NULL) {
 298                int len = eatspace(line);
 299                if (!len) {
 300                        handle_body();
 301                        break;
 302                }
 303                check_line(line, len);
 304        }
 305        return 0;
 306}