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