return 0;
}
-static void add_rfc2047(struct strbuf *sb, const char *line, int len,
+static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,
const char *encoding, enum rfc2047_type type)
{
static const int max_encoded_length = 76; /* per rfc2047 */
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
strbuf_addf(sb, "=?%s?q?", encoding);
line_len += strlen(encoding) + 5; /* 5 for =??q? */
- for (i = 0; i < len; i++) {
- unsigned ch = line[i] & 0xFF;
- int is_special = is_rfc2047_special(ch, type);
+
+ while (len) {
+ /*
+ * RFC 2047, section 5 (3):
+ *
+ * Each 'encoded-word' MUST represent an integral number of
+ * characters. A multi-octet character may not be split across
+ * adjacent 'encoded- word's.
+ */
+ const unsigned char *p = (const unsigned char *)line;
+ int chrlen = mbs_chrlen(&line, &len, encoding);
+ int is_special = (chrlen > 1) || is_rfc2047_special(*p, type);
+
+ /* "=%02X" * chrlen, or the byte itself */
+ const char *encoded_fmt = is_special ? "=%02X" : "%c";
+ int encoded_len = is_special ? 3 * chrlen : 1;
/*
* According to RFC 2047, we could encode the special character
* causes ' ' to be encoded as '=20', avoiding this problem.
*/
- if (line_len + 2 + (is_special ? 3 : 1) > max_encoded_length) {
+ if (line_len + encoded_len + 2 > max_encoded_length) {
+ /* It won't fit with trailing "?=" --- break the line */
strbuf_addf(sb, "?=\n =?%s?q?", encoding);
line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
}
- if (is_special) {
- strbuf_addf(sb, "=%02X", ch);
- line_len += 3;
- } else {
- strbuf_addch(sb, ch);
- line_len++;
- }
+ for (i = 0; i < chrlen; i++)
+ strbuf_addf(sb, encoded_fmt, p[i]);
+ line_len += encoded_len;
}
strbuf_addstr(sb, "?=");
}
+static const char *show_ident_date(const struct ident_split *ident,
+ enum date_mode mode)
+{
+ unsigned long date = 0;
+ int tz = 0;
+
+ if (ident->date_begin && ident->date_end)
+ date = strtoul(ident->date_begin, NULL, 10);
+ if (ident->tz_begin && ident->tz_end)
+ tz = strtol(ident->tz_begin, NULL, 10);
+ return show_date(date, tz, mode);
+}
+
void pp_user_info(const struct pretty_print_context *pp,
const char *what, struct strbuf *sb,
const char *line, const char *encoding)
struct strbuf mail;
struct ident_split ident;
int linelen;
- char *line_end, *date;
+ char *line_end;
const char *mailbuf, *namebuf;
size_t namelen, maillen;
int max_length = 78; /* per rfc2822 */
- unsigned long time;
- int tz;
if (pp->fmt == CMIT_FMT_ONELINE)
return;
strbuf_add(&name, namebuf, namelen);
namelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */
- time = strtoul(ident.date_begin, &date, 10);
- tz = strtol(date, NULL, 10);
if (pp->fmt == CMIT_FMT_EMAIL) {
strbuf_addstr(sb, "From: ");
switch (pp->fmt) {
case CMIT_FMT_MEDIUM:
- strbuf_addf(sb, "Date: %s\n", show_date(time, tz, pp->date_mode));
+ strbuf_addf(sb, "Date: %s\n",
+ show_ident_date(&ident, pp->date_mode));
break;
case CMIT_FMT_EMAIL:
- strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
+ strbuf_addf(sb, "Date: %s\n",
+ show_ident_date(&ident, DATE_RFC2822));
break;
case CMIT_FMT_FULLER:
- strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, pp->date_mode));
+ strbuf_addf(sb, "%sDate: %s\n", what,
+ show_ident_date(&ident, pp->date_mode));
break;
default:
/* notin' */
{
/* currently all placeholders have same length */
const int placeholder_len = 2;
- int tz;
- unsigned long date = 0;
struct ident_split s;
const char *name, *mail;
size_t maillen, namelen;
if (!s.date_begin)
goto skip;
- date = strtoul(s.date_begin, NULL, 10);
-
if (part == 't') { /* date, UNIX timestamp */
strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
return placeholder_len;
}
- /* parse tz */
- tz = strtoul(s.tz_begin + 1, NULL, 10);
- if (*s.tz_begin == '-')
- tz = -tz;
-
switch (part) {
case 'd': /* date */
- strbuf_addstr(sb, show_date(date, tz, dmode));
+ strbuf_addstr(sb, show_ident_date(&s, dmode));
return placeholder_len;
case 'D': /* date, RFC2822 style */
- strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
+ strbuf_addstr(sb, show_ident_date(&s, DATE_RFC2822));
return placeholder_len;
case 'r': /* date, relative */
- strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
+ strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));
return placeholder_len;
case 'i': /* date, ISO 8601 */
- strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
+ strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));
return placeholder_len;
}
unsigned commit_signature_parsed:1;
struct {
char *gpg_output;
+ char *gpg_status;
char good_bad;
char *signer;
+ char *key;
} signature;
char *message;
size_t width, indent1, indent2;
char result;
const char *check;
} signature_check[] = {
- { 'G', ": Good signature from " },
- { 'B', ": BAD signature from " },
+ { 'G', "\n[GNUPG:] GOODSIG " },
+ { 'B', "\n[GNUPG:] BADSIG " },
};
static void parse_signature_lines(struct format_commit_context *ctx)
{
- const char *buf = ctx->signature.gpg_output;
+ const char *buf = ctx->signature.gpg_status;
int i;
for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
continue;
ctx->signature.good_bad = signature_check[i].result;
found += strlen(signature_check[i].check);
+ ctx->signature.key = xmemdupz(found, 16);
+ found += 17;
next = strchrnul(found, '\n');
ctx->signature.signer = xmemdupz(found, next - found);
break;
struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT;
struct strbuf gpg_output = STRBUF_INIT;
+ struct strbuf gpg_status = STRBUF_INIT;
int status;
ctx->commit_signature_parsed = 1;
goto out;
status = verify_signed_buffer(payload.buf, payload.len,
signature.buf, signature.len,
- &gpg_output);
+ &gpg_output, &gpg_status);
if (status && !gpg_output.len)
goto out;
ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
+ ctx->signature.gpg_status = strbuf_detach(&gpg_status, NULL);
parse_signature_lines(ctx);
out:
+ strbuf_release(&gpg_status);
strbuf_release(&gpg_output);
strbuf_release(&payload);
strbuf_release(&signature);
if (c->signature.signer)
strbuf_addstr(sb, c->signature.signer);
break;
+ case 'K':
+ if (c->signature.key)
+ strbuf_addstr(sb, c->signature.key);
+ break;
}
return 2;
}