~ubuntu-branches/ubuntu/lucid/mutt/lucid-updates

1.1.5 by Christoph Berg
Import upstream version 1.5.15+20070412
1
/*
2
 * Copyright (C) 2005 Andreas Krennmair <ak@synflood.at>
3
 * Copyright (C) 2005 Peter J. Holzer <hjp@hjp.net>
4
 * Copyright (C) 2005-7 Rocco Rutte <pdmef@gmx.net>
5
 * 
6
 *     This program is free software; you can redistribute it and/or modify
7
 *     it under the terms of the GNU General Public License as published by
8
 *     the Free Software Foundation; either version 2 of the License, or
9
 *     (at your option) any later version.
10
 * 
11
 *     This program is distributed in the hope that it will be useful,
12
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *     GNU General Public License for more details.
15
 * 
16
 *     You should have received a copy of the GNU General Public License
17
 *     along with this program; if not, write to the Free Software
18
 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
 *
20
 */ 
21
22
/* This file was originally part of mutt-ng */
23
24
#if HAVE_CONFIG_H
25
# include "config.h"
26
#endif
27
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
#include <ctype.h>
32
#include <sys/wait.h>
33
#include <sys/stat.h>
34
35
#include "mutt.h"
36
#include "mutt_curses.h"
37
#include "ascii.h"
38
#include "lib.h"
39
40
#define FLOWED_MAX 77
41
42
static int get_quote_level (const char *line)
43
{
44
  int quoted = 0;
45
  char *p = (char *) line;
46
47
  while (p && *p == '>')
48
  {
49
    quoted++;
50
    p++;
51
  }
52
53
  return quoted;
54
}
55
56
static void print_indent (int ql, STATE *s)
57
{
58
  int i;
59
60
  if (s->prefix)
61
    ql++;
62
  for (i = 0; i < ql; i++)
63
    state_putc ('>', s);
64
}
65
66
static void print_flowed_line (const char *line, STATE *s, int ql)
67
{
68
  int width;
69
  char *pos, *oldpos;
70
  int len = mutt_strlen (line);
71
72
  width = (Wrap ? mutt_term_width (Wrap) : FLOWED_MAX) - 1;
73
  if (s->flags & M_REPLYING && width > FLOWED_MAX)
74
    width = FLOWED_MAX;
75
  /* probably want a quote_width function */
76
  if (ql + 1 < width)
77
    width -= ql + 1;
78
    
79
  if (len == 0)
80
  {
81
    print_indent (ql, s);
82
    state_putc ('\n', s);
83
    return;
84
  }
85
86
  pos = (char *) line + width;
87
  oldpos = (char *) line;
88
89
  for (; oldpos < line + len; pos += width)
90
  {
91
    /* only search for a new position when we're not over the end */
92
    if (pos < line + len)
93
    {
94
      if (*pos == ' ')
95
      {
96
        dprint (4, (debugfile, "f=f: found space directly at width\n"));
97
        *pos = '\0';
98
        ++pos;
99
      }
100
      else
101
      {
102
        char *save = pos;
103
        dprint (4, (debugfile, "f=f: need to search for space\n"));
104
105
        while (pos >= oldpos && *pos != ' ')
106
          --pos;
107
108
        if (pos < oldpos)
109
        {
110
          dprint (4, (debugfile, "f=f: no space found while searching "
111
                           "to left; going right\n"));
112
          pos = save;
113
          while (pos < line + len && *pos && *pos != ' ')
114
            ++pos;
115
          dprint (4, (debugfile, "f=f: found space at pos %d\n", pos-line));
116
        }
117
        else
118
        {
119
          dprint (4, (debugfile, "f=f: found space while searching to left\n"));
120
        }
121
122
        *pos = '\0';
123
        ++pos;
124
      }
125
    }
126
    else
127
    {
128
      dprint (4, (debugfile, "f=f: line completely fits on screen\n"));
129
    }
130
131
    print_indent (ql, s);
132
    if (ql > 0 || s->prefix)
133
      state_putc (' ', s);
134
    state_puts (oldpos, s);
135
136
    if (pos < line + len)
137
      state_putc (' ', s);
138
    state_putc ('\n', s);
139
    oldpos = pos;
140
  }
141
}
142
143
int rfc3676_handler (BODY * a, STATE * s)
144
{
145
  int bytes = a->length;
146
  char buf[LONG_STRING];
147
  char *curline = safe_malloc (STRING);
148
  char *t = NULL;
149
  unsigned int curline_len = 1, quotelevel = 0, newql = 0, sigsep = 0;
150
  int buf_off, buf_len;
151
  int delsp = 0, fixed = 0;
152
153
  *curline = '\0';
154
155
  /* respect DelSp of RfC3676 only with f=f parts */
156
  if ((t = (char *) mutt_get_parameter ("delsp", a->parameter)))
157
  {
158
    delsp = mutt_strlen (t) == 3 && ascii_strncasecmp (t, "yes", 3) == 0;
159
    t = NULL;
160
  }
161
162
  dprint (2, (debugfile, "f=f: DelSp: %s\n", delsp ? "yes" : "no"));
163
164
  while (bytes > 0 && fgets (buf, sizeof (buf), s->fpin))
165
  {
166
167
    buf_len = mutt_strlen (buf);
168
    bytes -= buf_len;
169
170
    newql = get_quote_level (buf);
171
172
    /* a change of quoting level in a paragraph - shouldn't happen, 
173
     * but has to be handled - see RFC 3676, sec. 4.5.
174
     */
175
    if (newql != quotelevel && curline && *curline)
176
    {
177
      print_flowed_line (curline, s, quotelevel);
178
      *curline = '\0';
179
      curline_len = 1;
180
    }
181
    quotelevel = newql;
182
183
    /* XXX - If a line is longer than buf (shouldn't happen), it is split.
184
     * This will almost always cause an unintended line break, and 
185
     * possibly a change in quoting level. But that's better than not
186
     * displaying it at all.
187
     */
188
    if ((t = strrchr (buf, '\r')) || (t = strrchr (buf, '\n')))
189
    {
190
      *t = '\0';
191
      buf_len = t - buf;
192
    }
193
194
    buf_off = newql;
195
196
    /* respect sender's space-stuffing by removing one leading space */
197
    if (buf[buf_off] == ' ')
198
      buf_off++;
199
200
    /* test for signature separator */
201
    sigsep = ascii_strcmp (buf + buf_off, "-- ") == 0;
202
203
    /* a fixed line either has no trailing space or is the
204
     * signature separator */
205
    fixed = buf_len == 0 || buf[buf_len - 1] != ' ' || sigsep;
206
207
    /* for DelSp=yes, we need to strip one SP prior to CRLF;
208
     * in case of the signature separator, leave the space */
209
    if (delsp && !sigsep && buf_len >= 1 && buf[buf_len-1] == ' ')
210
      buf[--buf_len] = '\0';
211
212
    /* we're here when last space removed because of DelSp was
213
     * the last space and there isn't more -> done */
214
    if ((buf_len - buf_off) < 0)
215
    {
216
      print_flowed_line (curline, s, quotelevel);
217
      *curline = '\0';
218
      curline_len = 1;
219
      continue;
220
    }
221
222
    /* signature separator also flushes the previous paragraph */
223
    if (sigsep && curline && *curline)
224
    {
225
      print_flowed_line (curline, s, quotelevel);
226
      *curline = '\0';
227
      curline_len = 1;
228
    }
229
230
    /* append remaining contents without quotes, space-stuffed
231
     * spaces and with 1 trailing space (0 or 1 for DelSp=yes) */
232
    safe_realloc (&curline, curline_len + buf_len - buf_off);
233
    strcpy (curline + curline_len - 1, buf + buf_off);		/* __STRCPY_CHECKED__ */
234
    curline_len += buf_len - buf_off;
235
236
    /* if this was a fixed line, the paragraph is finished */
237
    if (fixed)
238
    {
239
      print_flowed_line (curline, s, quotelevel);
240
      *curline = '\0';
241
      curline_len = 1;
242
    }
243
244
  }
1.1.6 by Adeodato Simó
Import upstream version 1.5.16
245
246
  if (*curline)
247
  {
248
    dprint (2, (debugfile, "f=f: still content buffered af EOF, flushing at ql=%d\n", quotelevel));
249
    print_flowed_line (curline, s, quotelevel);
250
  }
251
1.1.5 by Christoph Berg
Import upstream version 1.5.15+20070412
252
  FREE(&curline);
253
  return (0);
254
}
255
256
/*
257
 * This routine does RfC3676 space stuffing since it's a MUST.
258
 * Space stuffing means that we have to add leading spaces to
259
 * certain lines:
260
 *   - lines starting with a space
261
 *   - lines starting with 'From '
262
 * This routine is only called once right after editing the
263
 * initial message so it's up to the user to take care of stuffing
264
 * when editing the message several times before actually sending it
265
 *
266
 * This is more or less a hack as it replaces the message's content with
267
 * a freshly created copy in a tempfile and modifies the file's mtime
268
 * so we don't trigger code paths watching for mtime changes
269
 */
270
void rfc3676_space_stuff (HEADER* hdr)
271
{
272
#if DEBUG
273
  int lc = 0;
274
  size_t len = 0;
275
  unsigned char c = '\0';
276
#endif
277
  FILE *in = NULL, *out = NULL;
278
  char buf[LONG_STRING];
279
  char tmpfile[_POSIX_PATH_MAX];
280
281
  if (!hdr || !hdr->content || !hdr->content->filename)
282
    return;
283
284
  dprint (2, (debugfile, "f=f: postprocess %s\n", hdr->content->filename));
285
286
  if ((in = safe_fopen (hdr->content->filename, "r")) == NULL)
287
    return;
288
289
  mutt_mktemp (tmpfile);
290
  if ((out = safe_fopen (tmpfile, "w+")) == NULL)
291
  {
292
    fclose (in);
293
    return;
294
  }
295
296
  while (fgets (buf, sizeof (buf), in))
297
  {
298
    if (ascii_strncmp ("From ", buf, 5) == 0 || buf[0] == ' ') {
299
      fputc (' ', out);
300
#if DEBUG
301
      lc++;
302
      len = mutt_strlen (buf);
303
      if (len > 0)
304
      {
305
        c = buf[len-1];
306
        buf[len-1] = '\0';
307
      }
308
      dprint (4, (debugfile, "f=f: line %d needs space-stuffing: '%s'\n",
309
                  lc, buf));
310
      if (len > 0)
311
        buf[len-1] = c;
312
#endif
313
    }
314
    fputs (buf, out);
315
  }
316
  fclose (in);
317
  fclose (out);
318
  mutt_set_mtime (hdr->content->filename, tmpfile);
319
  unlink (hdr->content->filename);
320
  mutt_str_replace (&hdr->content->filename, tmpfile);
321
}