X-Git-Url: https://git.llucax.com/software/mutt-debian.git/blobdiff_plain/14c29200cb58d3c4a0830265f2433849781858d0..939639fcf1dad1b8f3a85d641f41d11c49281f3c:/rfc3676.c diff --git a/rfc3676.c b/rfc3676.c index 4de8ba7..aadda0f 100644 --- a/rfc3676.c +++ b/rfc3676.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2005 Andreas Krennmair * Copyright (C) 2005 Peter J. Holzer - * Copyright (C) 2005-7 Rocco Rutte + * Copyright (C) 2005-9 Rocco Rutte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,14 @@ #include "ascii.h" #include "lib.h" -#define FLOWED_MAX 77 +#define FLOWED_MAX 72 + +typedef struct flowed_state +{ + size_t width; + size_t spaces; + int delsp; +} flowed_state_t; static int get_quote_level (const char *line) { @@ -56,23 +63,37 @@ static int get_quote_level (const char *line) static size_t print_indent (int ql, STATE *s, int sp) { int i; + size_t wid = 0; if (s->prefix) - ql++; + { + /* use given prefix only for format=fixed replies to format=flowed, + * for format=flowed replies to format=flowed, use '>' indentation + */ + if (option (OPTTEXTFLOWED)) + ql++; + else + { + state_puts (s->prefix, s); + wid = mutt_strwidth (s->prefix); + sp = 0; + } + } for (i = 0; i < ql; i++) state_putc ('>', s); if (sp) state_putc (' ', s); - return ql + sp; + return ql + sp + wid; } -static void flush_par (STATE *s, size_t *sofar) +static void flush_par (STATE *s, flowed_state_t *fst) { - if (*sofar > 0) + if (fst->width > 0) { state_putc ('\n', s); - *sofar = 0; + fst->width = 0; } + fst->spaces = 0; } static int quote_width (STATE *s, int ql) @@ -85,120 +106,123 @@ static int quote_width (STATE *s, int ql) return width; } -static void print_flowed_line (char *line, STATE *s, int ql, size_t *sofar, int term) +static void print_flowed_line (char *line, STATE *s, int ql, + flowed_state_t *fst, int term) { - size_t width, w, words; + size_t width, w, words = 0; char *p; + char last; if (!line || !*line) { /* flush current paragraph (if any) first */ - flush_par (s, sofar); + flush_par (s, fst); print_indent (ql, s, 0); state_putc ('\n', s); return; } width = quote_width (s, ql); + last = line[mutt_strlen (line) - 1]; - dprint (4, (debugfile, "f-f: line [%s], width = %ld\n", NONULL(line), (long)width)); + dprint (4, (debugfile, "f=f: line [%s], width = %ld, spaces = %d\n", + NONULL(line), (long)width, fst->spaces)); for (p = (char *)line, words = 0; (p = strsep (&line, " ")) != NULL ; ) { - w = mutt_strwidth (NONULL(p)); - dprint (4, (debugfile, "f-f: word [%s], width = %ld, line = %ld\n", NONULL(p), (long)w, (long)*sofar)); - if (w + 1 + (*sofar) > width) + dprint(4,(debugfile,"f=f: word [%s], width: %d, remaining = [%s]\n", + p, fst->width, line)); + + /* remember number of spaces */ + if (!*p) { - /* line would be too long, flush */ - dprint (4, (debugfile, "f-f: width: %ld\n", (long)*sofar)); - state_puts (" \n", s); - *sofar = 0; + dprint(4,(debugfile,"f=f: additional space\n")); + fst->spaces++; + continue; } - if (*sofar == 0) + /* there's exactly one space prior to every but the first word */ + if (words) + fst->spaces++; + + w = mutt_strwidth (p); + /* see if we need to break the line but make sure the first + word is put on the line regardless; + if for DelSp=yes only one trailing space is used, we probably + have a long word that we should break within (we leave that + up to the pager or user) */ + if (!(!fst->spaces && fst->delsp && last != ' ') && + w < width && w + fst->width + fst->spaces > width) { - /* indent empty lines */ - *sofar = print_indent (ql, s, ql > 0 || s->prefix); + dprint(4,(debugfile,"f=f: break line at %d, %d spaces left\n", + fst->width, fst->spaces)); + /* only honor trailing spaces for format=flowed replies */ + if (option(OPTTEXTFLOWED)) + for ( ; fst->spaces; fst->spaces--) + state_putc (' ', s); + state_putc ('\n', s); + fst->width = 0; + fst->spaces = 0; words = 0; } - if (words > 0) - { - /* put space before current word if we have words already */ + + if (!words && !fst->width) + fst->width = print_indent (ql, s, !(s->flags & M_REPLYING) && + (ql > 0 || s->prefix)); + fst->width += w + fst->spaces; + for ( ; fst->spaces; fst->spaces--) state_putc (' ', s); - (*sofar)++; - } - state_puts (NONULL(p), s); - (*sofar) += w; + state_puts (p, s); words++; } if (term) - flush_par (s, sofar); + flush_par (s, fst); } -static void print_fixed_line (const char *line, STATE *s, int ql, size_t *sofar) +static void print_fixed_line (const char *line, STATE *s, int ql, + flowed_state_t *fst) { - int len = mutt_strlen (line); - - if (len == 0) - { - print_indent (ql, s, 0); - state_putc ('\n', s); - return; - } - - print_indent (ql, s, ql > 0 || s->prefix); - state_puts (line, s); + print_indent (ql, s, !(s->flags & M_REPLYING) && (ql > 0 || s->prefix)); + if (line && *line) + state_puts (line, s); state_putc ('\n', s); - *sofar = 0; + fst->width = 0; + fst->spaces = 0; } int rfc3676_handler (BODY * a, STATE * s) { - int bytes = a->length; - char buf[LONG_STRING]; - char *t = NULL; + char *buf = NULL, *t = NULL; unsigned int quotelevel = 0, newql = 0, sigsep = 0; - int buf_off = 0, buf_len; - int delsp = 0, fixed = 0; - size_t width = 0; + int buf_off = 0, delsp = 0, fixed = 0; + size_t buf_len = 0, sz = 0; + flowed_state_t fst; + + memset (&fst, 0, sizeof (fst)); /* respect DelSp of RfC3676 only with f=f parts */ if ((t = (char *) mutt_get_parameter ("delsp", a->parameter))) { delsp = mutt_strlen (t) == 3 && ascii_strncasecmp (t, "yes", 3) == 0; t = NULL; + fst.delsp = 1; } dprint (4, (debugfile, "f=f: DelSp: %s\n", delsp ? "yes" : "no")); - while (bytes > 0 && fgets (buf, sizeof (buf), s->fpin)) + while ((buf = mutt_read_line (buf, &sz, s->fpin, NULL, 0))) { - buf_len = mutt_strlen (buf); - bytes -= buf_len; - newql = get_quote_level (buf); /* end flowed paragraph (if we're within one) if quoting level * changes (should not but can happen, see RFC 3676, sec. 4.5.) */ if (newql != quotelevel) - flush_par (s, &width); + flush_par (s, &fst); quotelevel = newql; - - /* XXX - If a line is longer than buf (shouldn't happen), it is split. - * This will almost always cause an unintended line break, and - * possibly a change in quoting level. But that's better than not - * displaying it at all. - */ - if ((t = strrchr (buf, '\r')) || (t = strrchr (buf, '\n'))) - { - *t = '\0'; - buf_len = t - buf; - } - buf_off = newql; /* respect sender's space-stuffing by removing one leading space */ @@ -214,11 +238,11 @@ int rfc3676_handler (BODY * a, STATE * s) /* print fixed-and-standalone, fixed-and-empty and sigsep lines as * fixed lines */ - if ((fixed && (!width || !buf_len)) || sigsep) + if ((fixed && (!fst.width || !buf_len)) || sigsep) { /* if we're within a flowed paragraph, terminate it */ - flush_par (s, &width); - print_fixed_line (buf + buf_off, s, quotelevel, &width); + flush_par (s, &fst); + print_fixed_line (buf + buf_off, s, quotelevel, &fst); continue; } @@ -226,11 +250,12 @@ int rfc3676_handler (BODY * a, STATE * s) if (delsp && !fixed) buf[--buf_len] = '\0'; - print_flowed_line (buf + buf_off, s, quotelevel, &width, fixed); + print_flowed_line (buf + buf_off, s, quotelevel, &fst, fixed); } - flush_par (s, &width); + flush_par (s, &fst); + FREE (&buf); return (0); } @@ -267,10 +292,10 @@ void rfc3676_space_stuff (HEADER* hdr) if ((in = safe_fopen (hdr->content->filename, "r")) == NULL) return; - mutt_mktemp (tmpfile); + mutt_mktemp (tmpfile, sizeof (tmpfile)); if ((out = safe_fopen (tmpfile, "w+")) == NULL) { - fclose (in); + safe_fclose (&in); return; } @@ -294,8 +319,8 @@ void rfc3676_space_stuff (HEADER* hdr) } fputs (buf, out); } - fclose (in); - fclose (out); + safe_fclose (&in); + safe_fclose (&out); mutt_set_mtime (hdr->content->filename, tmpfile); unlink (hdr->content->filename); mutt_str_replace (&hdr->content->filename, tmpfile);