/*
* Copyright (C) 2005 Andreas Krennmair <ak@synflood.at>
* Copyright (C) 2005 Peter J. Holzer <hjp@hjp.net>
- * Copyright (C) 2005-7 Rocco Rutte <pdmef@gmx.net>
+ * Copyright (C) 2005-9 Rocco Rutte <pdmef@gmx.net>
*
* 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
#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)
{
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)
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 */
/* 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;
}
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);
}
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;
}
}
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);