2 * Parts were written/modified by:
3 * Andreas Krennmair <ak@synflood.at>
4 * Peter J. Holzer <hjp@hjp.net>
5 * Rocco Rutte <pdmef@cs.tu-berlin.de>
7 * This file is part of mutt-ng, see http://www.muttng.org/.
8 * It's licensed under the GNU General Public License,
9 * please see the file GPL in the top level source directory.
24 #include "mutt_curses.h"
33 #include "lib/debug.h"
37 static int get_quote_level (char *line)
41 for (quoted = 0; line[quoted] == '>'; quoted++);
45 static void print_flowed_line (char *line, STATE * s,
47 int* spaces, int space_len) {
50 int len = str_len (line);
53 if (MaxLineLength > 0) {
54 width = MaxLineLength - WrapMargin - ql - 1;
55 if (option (OPTSTUFFQUOTED))
58 width = MaxLineLength;
61 if (option (OPTMBOXPANE))
62 width = COLS - SidebarWidth - WrapMargin - ql - 1;
64 width = COLS - WrapMargin - ql - 1;
66 if (option (OPTSTUFFQUOTED))
72 if (str_len (line) == 0) {
73 if (option (OPTQUOTEEMPTY)) {
75 state_puts(s->prefix,s);
76 for (i=0;i<ql;++i) state_putc('>',s);
77 if (option(OPTSTUFFQUOTED))
87 for (; oldpos < line + len; pos += width) {
88 /* only search a new position when we're not over
89 * the end of the string w/ pos */
90 if (pos < line + len) {
92 debug_print (4, ("f=f: found space directly at width\n"));
98 debug_print (4, ("f=f: need to search for space\n"));
100 while (pos >= oldpos && *pos != ' ') {
104 debug_print (4, ("f=f: no space found while searching "
105 "to left; going right\n"));
107 while (pos < line + len && *pos && *pos != ' ') {
110 debug_print (4, ("f=f: found space at pos %d\n", pos-line));
112 debug_print (4, ("f=f: found space while searching to left\n"));
119 debug_print (4, ("f=f: line completely fits on screen\n"));
122 state_puts (s->prefix, s);
124 for (i = 0; i < ql; ++i)
126 if (option (OPTSTUFFQUOTED) && (ql > 0 || s->prefix))
129 if (delsp && spaces && space_len > 0) {
130 /* here, we need to character-wise step through the line
131 * to eliminate all spaces which were trailing due to DelSp */
132 for (i = 0; i < str_len (oldpos); i++) {
133 if (oldpos[i] == ' ' && spaces[&(oldpos[i])-line] != 0) {
134 debug_print (4, ("f=f: DelSp: spaces[%d] forces space removal\n",
138 /* print space at oldpos[i] if it was non-trailing */
139 state_putc (oldpos[i], s);
142 /* for no DelSp, just do whole line as per usual */
143 state_puts (oldpos, s);
144 /* fprintf(stderr,"print_flowed_line: `%s'\n",oldpos); */
145 if (pos < line + len)
147 state_putc ('\n', s);
152 int rfc3676_handler (BODY * a, STATE * s) {
153 int bytes = a->length;
154 char buf[LONG_STRING];
155 char *curline = str_dup ("");
157 unsigned int curline_len = 1, space_len = 1,
158 quotelevel = 0, newql = 0;
159 int buf_off, buf_len;
163 /* respect DelSP of RfC3676 only with f=f parts */
164 if ((t = (char*) mutt_get_parameter ("delsp", a->parameter))) {
165 delsp = str_len (t) == 3 && ascii_strncasecmp (t, "yes", 3) == 0;
169 debug_print (2, ("f=f: DelSp: %s\n", delsp ? "yes" : "no"));
171 while (bytes > 0 && fgets (buf, sizeof (buf), s->fpin)) {
172 buf_len = str_len (buf);
175 newql = get_quote_level (buf);
177 /* a change of quoting level in a paragraph - shouldn't happen,
178 * but has to be handled - see RFC 3676, sec. 4.5.
180 if (newql != quotelevel && curline && *curline) {
181 print_flowed_line (curline, s, quotelevel, delsp, spaces, space_len);
188 /* XXX - If a line is longer than buf (shouldn't happen), it is split.
189 * This will almost always cause an unintended line break, and
190 * possibly a change in quoting level. But that's better than not
191 * displaying it at all.
193 if ((t = strrchr (buf, '\n')) || (t = strrchr (buf, '\r'))) {
198 /* respect space-stuffing */
199 if (buf[buf_off] == ' ')
202 /* signature separator also flushes the previous paragraph */
203 if (strcmp(buf + buf_off, "-- ") == 0 && curline && *curline) {
204 print_flowed_line (curline, s, quotelevel, delsp, spaces, space_len);
210 mem_realloc (&curline, curline_len + buf_len - buf_off);
211 mem_realloc (&spaces, (curline_len + buf_len - buf_off)*sizeof (int));
212 strcpy (curline + curline_len - 1, buf + buf_off);
213 memset (&spaces[space_len], 0, (buf_len - buf_off)*sizeof (int));
214 curline_len += buf_len - buf_off;
215 space_len += buf_len - buf_off;
217 /* if this was a fixed line the paragraph is finished */
218 if (buf_len == 0 || buf[buf_len - 1] != ' ' || strcmp(buf + buf_off, "-- ") == 0) {
219 print_flowed_line (curline, s, quotelevel, delsp, spaces, space_len);
224 /* if last line we appended had a space and we have DelSp=yes,
225 * get a 1 into spaces array at proper position so that
226 * print_flowed_line() can handle it; don't kill the space
227 * right here 'cause we maybe need soft linebreaks to search for break
229 if (delsp && curline && *curline && curline_len-2 >= 0 &&
230 curline[curline_len-2] == ' ') {
231 debug_print (4, ("f=f: DelSp: marking spaces[%d] for later removal\n",
233 spaces[curline_len-2] = 1;
243 void rfc3676_quote_line (STATE* s, char* dst, size_t dstlen,
245 char quote[SHORT_STRING];
246 int offset = 0, i = 0, count = 0;
247 regmatch_t pmatch[1];
251 while (regexec ((regex_t *) QuoteRegexp.rx, &line[offset],
253 offset += pmatch->rm_eo;
256 /* first count number of real quoting characters;
258 * this maybe just plain wrong, but leaving spaces
259 * within quoting characters is what I consider
260 * more plain wrong...
262 for (i = 0; i < offset; i++)
265 /* just make sure we're inside quote althoug we
266 * likely won't have more than SHORT_STRING quote levels... */
267 i = (count > SHORT_STRING-1) ? SHORT_STRING-1 : count;
268 memset (quote, '>', i);
271 debug_print (4, ("f=f: quotelevel = %d, new prefix = '%s'\n",
273 /* if we changed prefix, make sure we respect $stuff_quoted */
274 snprintf (dst, dstlen, "%s%s%s%s", NONULL (s->prefix), NONULL (quote),
275 option (OPTSTUFFQUOTED) && line[offset] != ' ' ? " " : "",
279 void rfc3676_space_stuff (HEADER* hdr) {
283 unsigned char c = '\0';
285 FILE* in = NULL, *out = NULL;
286 char buf[LONG_STRING];
287 char tmpfile[_POSIX_PATH_MAX];
289 if (!hdr || !hdr->content || !hdr->content->filename)
292 debug_print (2, ("f=f: postprocess %s\n", hdr->content->filename));
293 if ((in = safe_fopen (hdr->content->filename, "r")) == NULL)
295 mutt_mktemp (tmpfile);
296 if ((out = safe_fopen (tmpfile, "w+")) == NULL) {
301 while (fgets (buf, sizeof (buf), in)) {
302 if (ascii_strncmp ("From ", buf, 4) == 0 || buf[0] == ' ') {
311 debug_print (4, ("f=f: line %d needs space-stuffing: '%s'\n",
320 unlink (hdr->content->filename);
322 str_replace (&hdr->content->filename, tmpfile);