X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=builtin-mailinfo.c;h=cf5ef29c0fa524799675734a3b4355ab326c76aa;hb=41b200179dfac7bf4c3b98270951937b537e2b24;hp=b8d7dbc0b71929a95aaebd79d5912897d5eb70e7;hpb=b0ed9eafb35b2330d5a96be79307f0e65547febb;p=thirdparty%2Fgit.git diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index b8d7dbc0b7..cf5ef29c0f 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -2,17 +2,9 @@ * Another stupid program, this one parsing the headers of an * email to figure out authorship and subject */ -#define _GNU_SOURCE -#include -#include -#include -#include -#ifndef NO_ICONV -#include -#endif -#include "git-compat-util.h" #include "cache.h" #include "builtin.h" +#include "utf8.h" static FILE *cmitmsg, *patchfile, *fin, *fout; @@ -414,6 +406,11 @@ static int is_rfc2822_header(char *line) */ int ch; char *cp = line; + + /* Count mbox From headers as headers */ + if (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6)) + return 1; + while ((ch = *cp++)) { if (ch == ':') return cp != line; @@ -425,30 +422,61 @@ static int is_rfc2822_header(char *line) return 0; } +/* + * sz is size of 'line' buffer in bytes. Must be reasonably + * long enough to hold one physical real-world e-mail line. + */ static int read_one_header_line(char *line, int sz, FILE *in) { - int ofs = 0; - while (ofs < sz) { - int peek, len; - if (fgets(line + ofs, sz - ofs, in) == NULL) - break; - len = eatspace(line + ofs); - if ((len == 0) || !is_rfc2822_header(line)) { - /* Re-add the newline */ - line[ofs + len] = '\n'; - line[ofs + len + 1] = '\0'; - break; - } - ofs += len; - /* Yuck, 2822 header "folding" */ + int len; + + /* + * We will read at most (sz-1) bytes and then potentially + * re-add NUL after it. Accessing line[sz] after this is safe + * and we can allow len to grow up to and including sz. + */ + sz--; + + /* Get the first part of the line. */ + if (!fgets(line, sz, in)) + return 0; + + /* + * Is it an empty line or not a valid rfc2822 header? + * If so, stop here, and return false ("not a header") + */ + len = eatspace(line); + if (!len || !is_rfc2822_header(line)) { + /* Re-add the newline */ + line[len] = '\n'; + line[len + 1] = '\0'; + return 0; + } + + /* + * Now we need to eat all the continuation lines.. + * Yuck, 2822 header "folding" + */ + for (;;) { + int peek, addlen; + static char continuation[1000]; + peek = fgetc(in); ungetc(peek, in); if (peek != ' ' && peek != '\t') break; + if (!fgets(continuation, sizeof(continuation), in)) + break; + addlen = eatspace(continuation); + if (len < sz - 1) { + if (addlen >= sz - len) + addlen = sz - len - 1; + memcpy(line + len, continuation, addlen); + len += addlen; + } } - /* Count mbox From headers as headers */ - if (!ofs && (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6))) - ofs = 1; - return ofs; + line[len] = 0; + + return 1; } static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047) @@ -519,40 +547,15 @@ static int decode_b_segment(char *in, char *ot, char *ep) static void convert_to_utf8(char *line, char *charset) { -#ifndef NO_ICONV - char *in, *out; - size_t insize, outsize, nrc; - char outbuf[4096]; /* cheat */ static char latin_one[] = "latin1"; char *input_charset = *charset ? charset : latin_one; - iconv_t conv = iconv_open(metainfo_charset, input_charset); - - if (conv == (iconv_t) -1) { - static int warned_latin1_once = 0; - if (input_charset != latin_one) { - fprintf(stderr, "cannot convert from %s to %s\n", - input_charset, metainfo_charset); - *charset = 0; - } - else if (!warned_latin1_once) { - warned_latin1_once = 1; - fprintf(stderr, "tried to convert from %s to %s, " - "but your iconv does not work with it.\n", - input_charset, metainfo_charset); - } - return; - } - in = line; - insize = strlen(in); - out = outbuf; - outsize = sizeof(outbuf); - nrc = iconv(conv, &in, &insize, &out, &outsize); - iconv_close(conv); - if (nrc == (size_t) -1) - return; - *out = 0; - strcpy(line, outbuf); -#endif + char *out = reencode_string(line, metainfo_charset, input_charset); + + if (!out) + die("cannot convert from %s to %s\n", + input_charset, metainfo_charset); + strcpy(line, out); + free(out); } static int decode_header_bq(char *it) @@ -827,16 +830,23 @@ static const char mailinfo_usage[] = int cmd_mailinfo(int argc, const char **argv, const char *prefix) { + const char *def_charset; + /* NEEDSWORK: might want to do the optional .git/ directory * discovery */ git_config(git_default_config); + def_charset = (git_commit_encoding ? git_commit_encoding : "utf-8"); + metainfo_charset = def_charset; + while (1 < argc && argv[1][0] == '-') { if (!strcmp(argv[1], "-k")) keep_subject = 1; else if (!strcmp(argv[1], "-u")) - metainfo_charset = git_commit_encoding; + metainfo_charset = def_charset; + else if (!strcmp(argv[1], "-n")) + metainfo_charset = NULL; else if (!strncmp(argv[1], "--encoding=", 11)) metainfo_charset = argv[1] + 11; else