~ubuntu-branches/ubuntu/vivid/mutt/vivid-proposed

« back to all changes in this revision

Viewing changes to .pc/fix-search-performance-regression.patch/handler.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2015-10-01 15:27:35 UTC
  • Revision ID: package-import@ubuntu.com-20151001152735-yyjhtk4o0qchwd64
Tags: 1.5.23-3ubuntu1
import fix-search-performance-regression.patch from upstream (LP: #1483796)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1996-2000,2002,2010 Michael R. Elkins <me@mutt.org>
 
3
 * 
 
4
 *     This program is free software; you can redistribute it and/or modify
 
5
 *     it under the terms of the GNU General Public License as published by
 
6
 *     the Free Software Foundation; either version 2 of the License, or
 
7
 *     (at your option) any later version.
 
8
 * 
 
9
 *     This program is distributed in the hope that it will be useful,
 
10
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *     GNU General Public License for more details.
 
13
 * 
 
14
 *     You should have received a copy of the GNU General Public License
 
15
 *     along with this program; if not, write to the Free Software
 
16
 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
17
 */ 
 
18
 
 
19
#if HAVE_CONFIG_H
 
20
# include "config.h"
 
21
#endif
 
22
 
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <unistd.h>
 
26
#include <ctype.h>
 
27
#include <sys/wait.h>
 
28
#include <sys/stat.h>
 
29
 
 
30
#include "mutt.h"
 
31
#include "mutt_curses.h"
 
32
#include "rfc1524.h"
 
33
#include "keymap.h"
 
34
#include "mime.h"
 
35
#include "copy.h"
 
36
#include "charset.h"
 
37
#include "mutt_crypt.h"
 
38
#include "rfc3676.h"
 
39
 
 
40
#define BUFI_SIZE 1000
 
41
#define BUFO_SIZE 2000
 
42
 
 
43
 
 
44
typedef int (*handler_t) (BODY *, STATE *);
 
45
 
 
46
const int Index_hex[128] = {
 
47
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
48
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
49
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
50
     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,
 
51
    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
52
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
53
    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
54
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
 
55
};
 
56
 
 
57
const int Index_64[128] = {
 
58
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
59
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
 
60
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
 
61
    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
 
62
    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
 
63
    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
 
64
    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
 
65
    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
 
66
};
 
67
 
 
68
static void state_prefix_put (const char *d, size_t dlen, STATE *s)
 
69
{
 
70
  if (s->prefix)
 
71
    while (dlen--)
 
72
      state_prefix_putc (*d++, s);
 
73
  else
 
74
    fwrite (d, dlen, 1, s->fpout);
 
75
}
 
76
 
 
77
static void mutt_convert_to_state(iconv_t cd, char *bufi, size_t *l, STATE *s)
 
78
{
 
79
  char bufo[BUFO_SIZE];
 
80
  ICONV_CONST char *ib;
 
81
  char *ob;
 
82
  size_t ibl, obl;
 
83
 
 
84
  if (!bufi)
 
85
  {
 
86
    if (cd != (iconv_t)(-1))
 
87
    {
 
88
      ob = bufo, obl = sizeof (bufo);
 
89
      iconv (cd, 0, 0, &ob, &obl);
 
90
      if (ob != bufo)
 
91
        state_prefix_put (bufo, ob - bufo, s);
 
92
    }
 
93
    return;
 
94
  }
 
95
 
 
96
  if (cd == (iconv_t)(-1))
 
97
  {
 
98
    state_prefix_put (bufi, *l, s);
 
99
    *l = 0;
 
100
    return;
 
101
  }
 
102
 
 
103
  ib = bufi, ibl = *l;
 
104
  for (;;)
 
105
  {
 
106
    ob = bufo, obl = sizeof (bufo);
 
107
    mutt_iconv (cd, &ib, &ibl, &ob, &obl, 0, "?");
 
108
    if (ob == bufo)
 
109
      break;
 
110
    state_prefix_put (bufo, ob - bufo, s);
 
111
  }
 
112
  memmove (bufi, ib, ibl);
 
113
  *l = ibl;
 
114
}
 
115
 
 
116
static void mutt_decode_xbit (STATE *s, long len, int istext, iconv_t cd)
 
117
{
 
118
  int c, ch;
 
119
  char bufi[BUFI_SIZE];
 
120
  size_t l = 0;
 
121
 
 
122
  if (istext)
 
123
  {
 
124
    state_set_prefix(s);
 
125
 
 
126
    while ((c = fgetc(s->fpin)) != EOF && len--)
 
127
    {
 
128
      if(c == '\r' && len)
 
129
      {
 
130
        if((ch = fgetc(s->fpin)) == '\n')
 
131
        {
 
132
          c = ch;
 
133
          len--;
 
134
        }
 
135
        else 
 
136
          ungetc(ch, s->fpin);
 
137
      }
 
138
 
 
139
      bufi[l++] = c;
 
140
      if (l == sizeof (bufi))
 
141
        mutt_convert_to_state (cd, bufi, &l, s);
 
142
    }
 
143
 
 
144
    mutt_convert_to_state (cd, bufi, &l, s);
 
145
    mutt_convert_to_state (cd, 0, 0, s);
 
146
 
 
147
    state_reset_prefix (s);
 
148
  }
 
149
  else
 
150
    mutt_copy_bytes (s->fpin, s->fpout, len);
 
151
}
 
152
 
 
153
static int qp_decode_triple (char *s, char *d)
 
154
{
 
155
  /* soft line break */
 
156
  if (*s == '=' && !(*(s+1)))
 
157
    return 1;
 
158
  
 
159
  /* quoted-printable triple */
 
160
  if (*s == '=' &&
 
161
      isxdigit ((unsigned char) *(s+1)) &&
 
162
      isxdigit ((unsigned char) *(s+2)))
 
163
  {
 
164
    *d = (hexval (*(s+1)) << 4) | hexval (*(s+2));
 
165
    return 0;
 
166
  }
 
167
  
 
168
  /* something else */
 
169
  return -1;
 
170
}
 
171
 
 
172
static void qp_decode_line (char *dest, char *src, size_t *l,
 
173
                            int last)
 
174
{
 
175
  char *d, *s;
 
176
  char c = 0;
 
177
 
 
178
  int kind = -1;
 
179
  int soft = 0;
 
180
 
 
181
  /* decode the line */
 
182
  
 
183
  for (d = dest, s = src; *s;)
 
184
  {
 
185
    switch ((kind = qp_decode_triple (s, &c)))
 
186
    {
 
187
      case  0: *d++ = c; s += 3; break; /* qp triple */
 
188
      case -1: *d++ = *s++;      break; /* single character */
 
189
      case  1: soft = 1; s++;    break; /* soft line break */
 
190
    }
 
191
  }
 
192
 
 
193
  if (!soft && last == '\n')
 
194
  {
 
195
    /* neither \r nor \n as part of line-terminating CRLF
 
196
     * may be qp-encoded, so remove \r and \n-terminate;
 
197
     * see RfC2045, sect. 6.7, (1): General 8bit representation */
 
198
    if (kind == 0 && c == '\r')
 
199
      *(d-1) = '\n';
 
200
    else
 
201
      *d++ = '\n';
 
202
  }
 
203
  
 
204
  *d = '\0';
 
205
  *l = d - dest;
 
206
}
 
207
 
 
208
/* 
 
209
 * Decode an attachment encoded with quoted-printable.
 
210
 * 
 
211
 * Why doesn't this overflow any buffers?  First, it's guaranteed
 
212
 * that the length of a line grows when you _en_-code it to
 
213
 * quoted-printable.  That means that we always can store the
 
214
 * result in a buffer of at most the _same_ size.
 
215
 * 
 
216
 * Now, we don't special-case if the line we read with fgets()
 
217
 * isn't terminated.  We don't care about this, since STRING > 78,
 
218
 * so corrupted input will just be corrupted a bit more.  That
 
219
 * implies that STRING+1 bytes are always sufficient to store the
 
220
 * result of qp_decode_line.
 
221
 * 
 
222
 * Finally, at soft line breaks, some part of a multibyte character
 
223
 * may have been left over by mutt_convert_to_state().  This shouldn't
 
224
 * be more than 6 characters, so STRING + 7 should be sufficient
 
225
 * memory to store the decoded data.
 
226
 * 
 
227
 * Just to make sure that I didn't make some off-by-one error
 
228
 * above, we just use STRING*2 for the target buffer's size.
 
229
 * 
 
230
 */
 
231
 
 
232
static void mutt_decode_quoted (STATE *s, long len, int istext, iconv_t cd)
 
233
{
 
234
  char line[STRING];
 
235
  char decline[2*STRING];
 
236
  size_t l = 0;
 
237
  size_t linelen;      /* number of input bytes in `line' */
 
238
  size_t l3;
 
239
  
 
240
  int last;    /* store the last character in the input line */
 
241
  
 
242
  if (istext)
 
243
    state_set_prefix(s);
 
244
 
 
245
  while (len > 0)
 
246
  {
 
247
    last = 0;
 
248
    
 
249
    /*
 
250
     * It's ok to use a fixed size buffer for input, even if the line turns
 
251
     * out to be longer than this.  Just process the line in chunks.  This
 
252
     * really shouldn't happen according the MIME spec, since Q-P encoded
 
253
     * lines are at most 76 characters, but we should be liberal about what
 
254
     * we accept.
 
255
     */
 
256
    if (fgets (line, MIN ((ssize_t)sizeof (line), len + 1), s->fpin) == NULL)
 
257
      break;
 
258
 
 
259
    linelen = strlen(line);
 
260
    len -= linelen;
 
261
 
 
262
    /*
 
263
     * inspect the last character we read so we can tell if we got the
 
264
     * entire line.
 
265
     */
 
266
    last = linelen ? line[linelen - 1] : 0;
 
267
 
 
268
    /* chop trailing whitespace if we got the full line */
 
269
    if (last == '\n')
 
270
    {
 
271
      while (linelen > 0 && ISSPACE (line[linelen-1]))
 
272
       linelen--;
 
273
      line[linelen]=0;
 
274
    }
 
275
 
 
276
    /* decode and do character set conversion */
 
277
    qp_decode_line (decline + l, line, &l3, last);
 
278
    l += l3;
 
279
    mutt_convert_to_state (cd, decline, &l, s);
 
280
  }
 
281
 
 
282
  mutt_convert_to_state (cd, 0, 0, s);
 
283
  state_reset_prefix(s);
 
284
}
 
285
 
 
286
void mutt_decode_base64 (STATE *s, long len, int istext, iconv_t cd)
 
287
{
 
288
  char buf[5];
 
289
  int c1, c2, c3, c4, ch, cr = 0, i;
 
290
  char bufi[BUFI_SIZE];
 
291
  size_t l = 0;
 
292
 
 
293
  buf[4] = 0;
 
294
 
 
295
  if (istext) 
 
296
    state_set_prefix(s);
 
297
 
 
298
  while (len > 0)
 
299
  {
 
300
    for (i = 0 ; i < 4 && len > 0 ; len--)
 
301
    {
 
302
      if ((ch = fgetc (s->fpin)) == EOF)
 
303
        break;
 
304
      if (ch >= 0 && ch < 128 && (base64val(ch) != -1 || ch == '='))
 
305
        buf[i++] = ch;
 
306
    }
 
307
    if (i != 4)
 
308
    {
 
309
      /* "i" may be zero if there is trailing whitespace, which is not an error */
 
310
      if (i != 0)
 
311
        dprint (2, (debugfile, "%s:%d [mutt_decode_base64()]: "
 
312
              "didn't get a multiple of 4 chars.\n", __FILE__, __LINE__));
 
313
      break;
 
314
    }
 
315
 
 
316
    c1 = base64val (buf[0]);
 
317
    c2 = base64val (buf[1]);
 
318
    ch = (c1 << 2) | (c2 >> 4);
 
319
 
 
320
    if (cr && ch != '\n') 
 
321
      bufi[l++] = '\r';
 
322
 
 
323
    cr = 0;
 
324
      
 
325
    if (istext && ch == '\r')
 
326
      cr = 1;
 
327
    else
 
328
      bufi[l++] = ch;
 
329
 
 
330
    if (buf[2] == '=')
 
331
      break;
 
332
    c3 = base64val (buf[2]);
 
333
    ch = ((c2 & 0xf) << 4) | (c3 >> 2);
 
334
 
 
335
    if (cr && ch != '\n')
 
336
      bufi[l++] = '\r';
 
337
 
 
338
    cr = 0;
 
339
 
 
340
    if (istext && ch == '\r')
 
341
      cr = 1;
 
342
    else
 
343
      bufi[l++] = ch;
 
344
 
 
345
    if (buf[3] == '=') break;
 
346
    c4 = base64val (buf[3]);
 
347
    ch = ((c3 & 0x3) << 6) | c4;
 
348
 
 
349
    if (cr && ch != '\n')
 
350
      bufi[l++] = '\r';
 
351
    cr = 0;
 
352
 
 
353
    if (istext && ch == '\r')
 
354
      cr = 1;
 
355
    else
 
356
      bufi[l++] = ch;
 
357
    
 
358
    if (l + 8 >= sizeof (bufi))
 
359
      mutt_convert_to_state (cd, bufi, &l, s);
 
360
  }
 
361
 
 
362
  if (cr) bufi[l++] = '\r';
 
363
 
 
364
  mutt_convert_to_state (cd, bufi, &l, s);
 
365
  mutt_convert_to_state (cd, 0, 0, s);
 
366
 
 
367
  state_reset_prefix(s);
 
368
}
 
369
 
 
370
static unsigned char decode_byte (char ch)
 
371
{
 
372
  if (ch == 96)
 
373
    return 0;
 
374
  return ch - 32;
 
375
}
 
376
 
 
377
static void mutt_decode_uuencoded (STATE *s, long len, int istext, iconv_t cd)
 
378
{
 
379
  char tmps[SHORT_STRING];
 
380
  char linelen, c, l, out;
 
381
  char *pt;
 
382
  char bufi[BUFI_SIZE];
 
383
  size_t k = 0;
 
384
 
 
385
  if(istext)
 
386
    state_set_prefix(s);
 
387
  
 
388
  while(len > 0)
 
389
  {
 
390
    if ((fgets(tmps, sizeof(tmps), s->fpin)) == NULL)
 
391
      return;
 
392
    len -= mutt_strlen(tmps);
 
393
    if ((!mutt_strncmp (tmps, "begin", 5)) && ISSPACE (tmps[5]))
 
394
      break;
 
395
  }
 
396
  while(len > 0)
 
397
  {
 
398
    if ((fgets(tmps, sizeof(tmps), s->fpin)) == NULL)
 
399
      return;
 
400
    len -= mutt_strlen(tmps);
 
401
    if (!mutt_strncmp (tmps, "end", 3))
 
402
      break;
 
403
    pt = tmps;
 
404
    linelen = decode_byte (*pt);
 
405
    pt++;
 
406
    for (c = 0; c < linelen;)
 
407
    {
 
408
      for (l = 2; l <= 6; l += 2)
 
409
      {
 
410
        out = decode_byte (*pt) << l;
 
411
        pt++;
 
412
        out |= (decode_byte (*pt) >> (6 - l));
 
413
        bufi[k++] = out;
 
414
        c++;
 
415
        if (c == linelen)
 
416
          break;
 
417
      }
 
418
      mutt_convert_to_state (cd, bufi, &k, s);
 
419
      pt++;
 
420
    }
 
421
  }
 
422
 
 
423
  mutt_convert_to_state (cd, bufi, &k, s);
 
424
  mutt_convert_to_state (cd, 0, 0, s);
 
425
  
 
426
  state_reset_prefix(s);
 
427
}
 
428
 
 
429
/* ----------------------------------------------------------------------------
 
430
 * A (not so) minimal implementation of RFC1563.
 
431
 */
 
432
 
 
433
#define IndentSize (4)
 
434
    
 
435
enum { RICH_PARAM=0, RICH_BOLD, RICH_UNDERLINE, RICH_ITALIC, RICH_NOFILL, 
 
436
  RICH_INDENT, RICH_INDENT_RIGHT, RICH_EXCERPT, RICH_CENTER, RICH_FLUSHLEFT,
 
437
  RICH_FLUSHRIGHT, RICH_COLOR, RICH_LAST_TAG };
 
438
 
 
439
static const struct {
 
440
  const wchar_t *tag_name;
 
441
  int index;
 
442
} EnrichedTags[] = {
 
443
  { L"param",           RICH_PARAM },
 
444
  { L"bold",            RICH_BOLD },
 
445
  { L"italic",          RICH_ITALIC },
 
446
  { L"underline",       RICH_UNDERLINE },
 
447
  { L"nofill",          RICH_NOFILL },
 
448
  { L"excerpt",         RICH_EXCERPT },
 
449
  { L"indent",          RICH_INDENT },
 
450
  { L"indentright",     RICH_INDENT_RIGHT },
 
451
  { L"center",          RICH_CENTER },
 
452
  { L"flushleft",       RICH_FLUSHLEFT },
 
453
  { L"flushright",      RICH_FLUSHRIGHT },
 
454
  { L"flushboth",       RICH_FLUSHLEFT },
 
455
  { L"color",           RICH_COLOR },
 
456
  { L"x-color",         RICH_COLOR },
 
457
  { NULL,               -1 }
 
458
};
 
459
 
 
460
struct enriched_state
 
461
{
 
462
  wchar_t *buffer;
 
463
  wchar_t *line;
 
464
  wchar_t *param;
 
465
  size_t buff_len;
 
466
  size_t line_len;
 
467
  size_t line_used;
 
468
  size_t line_max;
 
469
  size_t indent_len;
 
470
  size_t word_len;
 
471
  size_t buff_used;
 
472
  size_t param_used;
 
473
  size_t param_len;
 
474
  int tag_level[RICH_LAST_TAG];
 
475
  int WrapMargin;
 
476
  STATE *s;
 
477
};
 
478
 
 
479
static void enriched_wrap (struct enriched_state *stte)
 
480
{
 
481
  int x;
 
482
  int extra;
 
483
 
 
484
  if (stte->line_len)
 
485
  {
 
486
    if (stte->tag_level[RICH_CENTER] || stte->tag_level[RICH_FLUSHRIGHT])
 
487
    {
 
488
      /* Strip trailing white space */
 
489
      size_t y = stte->line_used - 1;
 
490
 
 
491
      while (y && iswspace (stte->line[y]))
 
492
      {
 
493
        stte->line[y] = (wchar_t) '\0';
 
494
        y--;
 
495
        stte->line_used--;
 
496
        stte->line_len--;
 
497
      }
 
498
      if (stte->tag_level[RICH_CENTER])
 
499
      {
 
500
        /* Strip leading whitespace */
 
501
        y = 0;
 
502
 
 
503
        while (stte->line[y] && iswspace (stte->line[y]))
 
504
          y++;
 
505
        if (y)
 
506
        {
 
507
          size_t z;
 
508
 
 
509
          for (z = y ; z <= stte->line_used; z++)
 
510
          {
 
511
            stte->line[z - y] = stte->line[z];
 
512
          }
 
513
 
 
514
          stte->line_len -= y;
 
515
          stte->line_used -= y;
 
516
        }
 
517
      }
 
518
    }
 
519
 
 
520
    extra = stte->WrapMargin - stte->line_len - stte->indent_len -
 
521
      (stte->tag_level[RICH_INDENT_RIGHT] * IndentSize);
 
522
    if (extra > 0) 
 
523
    {
 
524
      if (stte->tag_level[RICH_CENTER]) 
 
525
      {
 
526
        x = extra / 2;
 
527
        while (x)
 
528
        {
 
529
          state_putc (' ', stte->s);
 
530
          x--;
 
531
        }
 
532
      } 
 
533
      else if (stte->tag_level[RICH_FLUSHRIGHT])
 
534
      {
 
535
        x = extra-1;
 
536
        while (x)
 
537
        {
 
538
          state_putc (' ', stte->s);
 
539
          x--;
 
540
        }
 
541
      }
 
542
    }
 
543
    state_putws ((const wchar_t*) stte->line, stte->s);
 
544
  }
 
545
 
 
546
  state_putc ('\n', stte->s);
 
547
  stte->line[0] = (wchar_t) '\0';
 
548
  stte->line_len = 0;
 
549
  stte->line_used = 0;
 
550
  stte->indent_len = 0;
 
551
  if (stte->s->prefix)
 
552
  {
 
553
    state_puts (stte->s->prefix, stte->s);
 
554
    stte->indent_len += mutt_strlen (stte->s->prefix);
 
555
  }
 
556
 
 
557
  if (stte->tag_level[RICH_EXCERPT])
 
558
  {
 
559
    x = stte->tag_level[RICH_EXCERPT];
 
560
    while (x) 
 
561
    {
 
562
      if (stte->s->prefix)
 
563
      {
 
564
        state_puts (stte->s->prefix, stte->s);
 
565
            stte->indent_len += mutt_strlen (stte->s->prefix);
 
566
      }
 
567
      else
 
568
      {
 
569
        state_puts ("> ", stte->s);
 
570
        stte->indent_len += mutt_strlen ("> ");
 
571
      }
 
572
      x--;
 
573
    }
 
574
  }
 
575
  else
 
576
    stte->indent_len = 0;
 
577
  if (stte->tag_level[RICH_INDENT])
 
578
  {
 
579
    x = stte->tag_level[RICH_INDENT] * IndentSize;
 
580
    stte->indent_len += x;
 
581
    while (x) 
 
582
    {
 
583
      state_putc (' ', stte->s);
 
584
      x--;
 
585
    }
 
586
  }
 
587
}
 
588
 
 
589
static void enriched_flush (struct enriched_state *stte, int wrap)
 
590
{
 
591
  if (!stte->tag_level[RICH_NOFILL] && (stte->line_len + stte->word_len > 
 
592
      (stte->WrapMargin - (stte->tag_level[RICH_INDENT_RIGHT] * IndentSize) - 
 
593
       stte->indent_len)))
 
594
    enriched_wrap (stte);
 
595
 
 
596
  if (stte->buff_used)
 
597
  {
 
598
    stte->buffer[stte->buff_used] = (wchar_t) '\0';
 
599
    stte->line_used += stte->buff_used;
 
600
    if (stte->line_used > stte->line_max)
 
601
    {
 
602
      stte->line_max = stte->line_used;
 
603
      safe_realloc (&stte->line, (stte->line_max + 1) * sizeof (wchar_t));
 
604
    }
 
605
    wcscat (stte->line, stte->buffer);
 
606
    stte->line_len += stte->word_len;
 
607
    stte->word_len = 0;
 
608
    stte->buff_used = 0;
 
609
  }
 
610
  if (wrap)
 
611
    enriched_wrap(stte);
 
612
  fflush (stte->s->fpout);
 
613
}
 
614
 
 
615
 
 
616
static void enriched_putwc (wchar_t c, struct enriched_state *stte)
 
617
{
 
618
  if (stte->tag_level[RICH_PARAM]) 
 
619
  {
 
620
    if (stte->tag_level[RICH_COLOR]) 
 
621
    {
 
622
      if (stte->param_used + 1 >= stte->param_len)
 
623
        safe_realloc (&stte->param, (stte->param_len += STRING) * sizeof (wchar_t));
 
624
 
 
625
      stte->param[stte->param_used++] = c;
 
626
    }
 
627
    return; /* nothing to do */
 
628
  }
 
629
 
 
630
  /* see if more space is needed (plus extra for possible rich characters) */
 
631
  if (stte->buff_len < stte->buff_used + 3)
 
632
  {
 
633
    stte->buff_len += LONG_STRING;
 
634
    safe_realloc (&stte->buffer, (stte->buff_len + 1) * sizeof (wchar_t));
 
635
  }
 
636
 
 
637
  if ((!stte->tag_level[RICH_NOFILL] && iswspace (c)) || c == (wchar_t) '\0')
 
638
  {
 
639
    if (c == (wchar_t) '\t')
 
640
      stte->word_len += 8 - (stte->line_len + stte->word_len) % 8;
 
641
    else
 
642
      stte->word_len++;
 
643
    
 
644
    stte->buffer[stte->buff_used++] = c;
 
645
    enriched_flush (stte, 0);
 
646
  }
 
647
  else
 
648
  {
 
649
    if (stte->s->flags & M_DISPLAY)
 
650
    {
 
651
      if (stte->tag_level[RICH_BOLD])
 
652
      {
 
653
        stte->buffer[stte->buff_used++] = c;
 
654
        stte->buffer[stte->buff_used++] = (wchar_t) '\010';
 
655
        stte->buffer[stte->buff_used++] = c;
 
656
      }
 
657
      else if (stte->tag_level[RICH_UNDERLINE])
 
658
      {
 
659
 
 
660
        stte->buffer[stte->buff_used++] = '_';
 
661
        stte->buffer[stte->buff_used++] = (wchar_t) '\010';
 
662
        stte->buffer[stte->buff_used++] = c;
 
663
      }
 
664
      else if (stte->tag_level[RICH_ITALIC])
 
665
      {
 
666
        stte->buffer[stte->buff_used++] = c;
 
667
        stte->buffer[stte->buff_used++] = (wchar_t) '\010';
 
668
        stte->buffer[stte->buff_used++] = '_';
 
669
      }
 
670
      else
 
671
      {
 
672
        stte->buffer[stte->buff_used++] = c;
 
673
      }
 
674
    }
 
675
    else
 
676
    {
 
677
      stte->buffer[stte->buff_used++] = c;
 
678
    }
 
679
    stte->word_len++;
 
680
  }
 
681
}
 
682
 
 
683
static void enriched_puts (const char *s, struct enriched_state *stte)
 
684
{
 
685
  const char *c;
 
686
 
 
687
  if (stte->buff_len < stte->buff_used + mutt_strlen (s))
 
688
  {
 
689
    stte->buff_len += LONG_STRING;
 
690
    safe_realloc (&stte->buffer, (stte->buff_len + 1) * sizeof (wchar_t));
 
691
  }
 
692
  c = s;
 
693
  while (*c)
 
694
  {
 
695
    stte->buffer[stte->buff_used++] = (wchar_t) *c;
 
696
    c++;
 
697
  }
 
698
}
 
699
 
 
700
static void enriched_set_flags (const wchar_t *tag, struct enriched_state *stte)
 
701
{
 
702
  const wchar_t *tagptr = tag;
 
703
  int i, j;
 
704
 
 
705
  if (*tagptr == (wchar_t) '/')
 
706
    tagptr++;
 
707
  
 
708
  for (i = 0, j = -1; EnrichedTags[i].tag_name; i++)
 
709
    if (wcscasecmp (EnrichedTags[i].tag_name, tagptr) == 0)
 
710
    {
 
711
      j = EnrichedTags[i].index;
 
712
      break;
 
713
    }
 
714
 
 
715
  if (j != -1)
 
716
  {
 
717
    if (j == RICH_CENTER || j == RICH_FLUSHLEFT || j == RICH_FLUSHRIGHT)
 
718
      enriched_flush (stte, 1);
 
719
 
 
720
    if (*tag == (wchar_t) '/')
 
721
    {
 
722
      if (stte->tag_level[j]) /* make sure not to go negative */
 
723
        stte->tag_level[j]--;
 
724
      if ((stte->s->flags & M_DISPLAY) && j == RICH_PARAM && stte->tag_level[RICH_COLOR])
 
725
      {
 
726
        stte->param[stte->param_used] = (wchar_t) '\0';
 
727
        if (!wcscasecmp(L"black", stte->param))
 
728
        {
 
729
          enriched_puts("\033[30m", stte);
 
730
        }
 
731
        else if (!wcscasecmp(L"red", stte->param))
 
732
        {
 
733
          enriched_puts("\033[31m", stte);
 
734
        }
 
735
        else if (!wcscasecmp(L"green", stte->param))
 
736
        {
 
737
          enriched_puts("\033[32m", stte);
 
738
        }
 
739
        else if (!wcscasecmp(L"yellow", stte->param))
 
740
        {
 
741
          enriched_puts("\033[33m", stte);
 
742
        }
 
743
        else if (!wcscasecmp(L"blue", stte->param))
 
744
        {
 
745
          enriched_puts("\033[34m", stte);
 
746
        }
 
747
        else if (!wcscasecmp(L"magenta", stte->param))
 
748
        {
 
749
          enriched_puts("\033[35m", stte);
 
750
        }
 
751
        else if (!wcscasecmp(L"cyan", stte->param))
 
752
        {
 
753
          enriched_puts("\033[36m", stte);
 
754
        }
 
755
        else if (!wcscasecmp(L"white", stte->param))
 
756
        {
 
757
          enriched_puts("\033[37m", stte);
 
758
        }
 
759
      }
 
760
      if ((stte->s->flags & M_DISPLAY) && j == RICH_COLOR)
 
761
      {
 
762
        enriched_puts("\033[0m", stte);
 
763
      }
 
764
 
 
765
      /* flush parameter buffer when closing the tag */
 
766
      if (j == RICH_PARAM)
 
767
      {
 
768
        stte->param_used = 0;
 
769
        stte->param[0] = (wchar_t) '\0';
 
770
      }
 
771
    }
 
772
    else
 
773
      stte->tag_level[j]++;
 
774
 
 
775
    if (j == RICH_EXCERPT)
 
776
      enriched_flush(stte, 1);
 
777
  }
 
778
}
 
779
 
 
780
static int text_enriched_handler (BODY *a, STATE *s)
 
781
{
 
782
  enum {
 
783
    TEXT, LANGLE, TAG, BOGUS_TAG, NEWLINE, ST_EOF, DONE
 
784
  } state = TEXT;
 
785
 
 
786
  long bytes = a->length;
 
787
  struct enriched_state stte;
 
788
  wchar_t wc = 0;
 
789
  int tag_len = 0;
 
790
  wchar_t tag[LONG_STRING + 1];
 
791
 
 
792
  memset (&stte, 0, sizeof (stte));
 
793
  stte.s = s;
 
794
  stte.WrapMargin = ((s->flags & M_DISPLAY) ? (COLS-4) : ((COLS-4)<72)?(COLS-4):72);
 
795
  stte.line_max = stte.WrapMargin * 4;
 
796
  stte.line = (wchar_t *) safe_calloc (1, (stte.line_max + 1) * sizeof (wchar_t));
 
797
  stte.param = (wchar_t *) safe_calloc (1, (STRING) * sizeof (wchar_t));
 
798
 
 
799
  stte.param_len = STRING;
 
800
  stte.param_used = 0;
 
801
 
 
802
  if (s->prefix)
 
803
  {
 
804
    state_puts (s->prefix, s);
 
805
    stte.indent_len += mutt_strlen (s->prefix);
 
806
  }
 
807
 
 
808
  while (state != DONE)
 
809
  {
 
810
    if (state != ST_EOF)
 
811
    {
 
812
      if (!bytes || (wc = fgetwc (s->fpin)) == WEOF)
 
813
        state = ST_EOF;
 
814
      else
 
815
        bytes--;
 
816
    }
 
817
 
 
818
    switch (state)
 
819
    {
 
820
      case TEXT :
 
821
        switch (wc)
 
822
        {
 
823
          case '<' :
 
824
            state = LANGLE;
 
825
            break;
 
826
 
 
827
          case '\n' :
 
828
            if (stte.tag_level[RICH_NOFILL])
 
829
            {
 
830
              enriched_flush (&stte, 1);
 
831
            }
 
832
            else 
 
833
            {
 
834
              enriched_putwc ((wchar_t) ' ', &stte);
 
835
              state = NEWLINE;
 
836
            }
 
837
            break;
 
838
 
 
839
          default:
 
840
            enriched_putwc (wc, &stte);
 
841
        }
 
842
        break;
 
843
 
 
844
      case LANGLE :
 
845
        if (wc == (wchar_t) '<')
 
846
        {
 
847
          enriched_putwc (wc, &stte);
 
848
          state = TEXT;
 
849
          break;
 
850
        }
 
851
        else
 
852
        {
 
853
          tag_len = 0;
 
854
          state = TAG;
 
855
        }
 
856
        /* Yes, fall through (it wasn't a <<, so this char is first in TAG) */
 
857
      case TAG :
 
858
        if (wc == (wchar_t) '>')
 
859
        {
 
860
          tag[tag_len] = (wchar_t) '\0';
 
861
          enriched_set_flags (tag, &stte);
 
862
          state = TEXT;
 
863
        }
 
864
        else if (tag_len < LONG_STRING)  /* ignore overly long tags */
 
865
          tag[tag_len++] = wc;
 
866
        else
 
867
          state = BOGUS_TAG;
 
868
        break;
 
869
 
 
870
      case BOGUS_TAG :
 
871
        if (wc == (wchar_t) '>')
 
872
          state = TEXT;
 
873
        break;
 
874
 
 
875
      case NEWLINE :
 
876
        if (wc == (wchar_t) '\n')
 
877
          enriched_flush (&stte, 1);
 
878
        else
 
879
        {
 
880
          ungetwc (wc, s->fpin);
 
881
          bytes++;
 
882
          state = TEXT;
 
883
        }
 
884
        break;
 
885
 
 
886
      case ST_EOF :
 
887
        enriched_putwc ((wchar_t) '\0', &stte);
 
888
        enriched_flush (&stte, 1);
 
889
        state = DONE;
 
890
        break;
 
891
 
 
892
      case DONE: /* not reached, but gcc complains if this is absent */
 
893
        break;
 
894
    }
 
895
  }
 
896
 
 
897
  state_putc ('\n', s); /* add a final newline */
 
898
 
 
899
  FREE (&(stte.buffer));
 
900
  FREE (&(stte.line));
 
901
  FREE (&(stte.param));
 
902
 
 
903
  return 0;
 
904
}                                                                              
 
905
 
 
906
/* for compatibility with metamail */
 
907
static int is_mmnoask (const char *buf)
 
908
{
 
909
  char tmp[LONG_STRING], *p, *q;
 
910
  int lng;
 
911
 
 
912
  if ((p = getenv ("MM_NOASK")) != NULL && *p)
 
913
  {
 
914
    if (mutt_strcmp (p, "1") == 0)
 
915
      return (1);
 
916
 
 
917
    strfcpy (tmp, p, sizeof (tmp));
 
918
    p = tmp;
 
919
 
 
920
    while ((p = strtok (p, ",")) != NULL)
 
921
    {
 
922
      if ((q = strrchr (p, '/')) != NULL)
 
923
      {
 
924
        if (*(q+1) == '*')
 
925
        {
 
926
          if (ascii_strncasecmp (buf, p, q-p) == 0)
 
927
            return (1);
 
928
        }
 
929
        else
 
930
        {
 
931
          if (ascii_strcasecmp (buf, p) == 0)
 
932
            return (1);
 
933
        }
 
934
      }
 
935
      else
 
936
      {
 
937
        lng = mutt_strlen (p);
 
938
        if (buf[lng] == '/' && mutt_strncasecmp (buf, p, lng) == 0)
 
939
          return (1);
 
940
      }
 
941
 
 
942
      p = NULL;
 
943
    }
 
944
  }
 
945
 
 
946
  return (0);
 
947
}
 
948
 
 
949
/*
 
950
 * Returns:
 
951
 * 1    if the body part should be filtered by a mailcap entry prior to viewing inline.
 
952
 *
 
953
 * 0    otherwise
 
954
 */
 
955
static int mutt_is_autoview (BODY *b)
 
956
{
 
957
  char type[SHORT_STRING];
 
958
 
 
959
  snprintf (type, sizeof (type), "%s/%s", TYPE (b), b->subtype);
 
960
 
 
961
  /* determine if there is a mailcap entry suitable for auto_view
 
962
   *
 
963
   * WARNING: _type is altered by this call as a result of `mime_lookup' support */
 
964
  if (rfc1524_mailcap_lookup(b, type, NULL, M_AUTOVIEW))
 
965
  {
 
966
    if (option(OPTIMPLICITAUTOVIEW))
 
967
    {
 
968
      /* $implicit_autoview is essentially the same as "auto_view *" */
 
969
      return 1;
 
970
    }
 
971
    else
 
972
    {
 
973
      /* determine if this type is on the user's auto_view list */
 
974
      LIST *t = AutoViewList;
 
975
 
 
976
      for (; t; t = t->next) {
 
977
        int i = mutt_strlen (t->data) - 1;
 
978
        if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && 
 
979
              ascii_strncasecmp (type, t->data, i) == 0) ||
 
980
            ascii_strcasecmp (type, t->data) == 0)
 
981
          return 1;
 
982
      }
 
983
 
 
984
      if (is_mmnoask (type))
 
985
        return 1;
 
986
    }
 
987
  }
 
988
 
 
989
  return 0;
 
990
}
 
991
 
 
992
#define TXTHTML     1
 
993
#define TXTPLAIN    2
 
994
#define TXTENRICHED 3
 
995
 
 
996
static int alternative_handler (BODY *a, STATE *s)
 
997
{
 
998
  BODY *choice = NULL;
 
999
  BODY *b;
 
1000
  LIST *t;
 
1001
  int type = 0;
 
1002
  int mustfree = 0;
 
1003
  int rc = 0;
 
1004
 
 
1005
  if (a->encoding == ENCBASE64 || a->encoding == ENCQUOTEDPRINTABLE ||
 
1006
      a->encoding == ENCUUENCODED)
 
1007
  {
 
1008
    struct stat st;
 
1009
    mustfree = 1;
 
1010
    fstat (fileno (s->fpin), &st);
 
1011
    b = mutt_new_body ();
 
1012
    b->length = (long) st.st_size;
 
1013
    b->parts = mutt_parse_multipart (s->fpin,
 
1014
                  mutt_get_parameter ("boundary", a->parameter),
 
1015
                  (long) st.st_size, ascii_strcasecmp ("digest", a->subtype) == 0);
 
1016
  }
 
1017
  else
 
1018
    b = a;
 
1019
 
 
1020
  a = b;
 
1021
 
 
1022
  /* First, search list of preferred types */
 
1023
  t = AlternativeOrderList;
 
1024
  while (t && !choice)
 
1025
  {
 
1026
    char *c;
 
1027
    int btlen;  /* length of basetype */
 
1028
    int wild;   /* do we have a wildcard to match all subtypes? */
 
1029
 
 
1030
    c = strchr (t->data, '/');
 
1031
    if (c)
 
1032
    {
 
1033
      wild = (c[1] == '*' && c[2] == 0);
 
1034
      btlen = c - t->data;
 
1035
    }
 
1036
    else
 
1037
    {
 
1038
      wild = 1;
 
1039
      btlen = mutt_strlen (t->data);
 
1040
    }
 
1041
 
 
1042
    if (a && a->parts) 
 
1043
      b = a->parts;
 
1044
    else
 
1045
      b = a;
 
1046
    while (b)
 
1047
    {
 
1048
      const char *bt = TYPE(b);
 
1049
      if (!ascii_strncasecmp (bt, t->data, btlen) && bt[btlen] == 0)
 
1050
      {
 
1051
        /* the basetype matches */
 
1052
        if (wild || !ascii_strcasecmp (t->data + btlen + 1, b->subtype))
 
1053
        {
 
1054
          choice = b;
 
1055
        }
 
1056
      }
 
1057
      b = b->next;
 
1058
    }
 
1059
    t = t->next;
 
1060
  }
 
1061
 
 
1062
  /* Next, look for an autoviewable type */
 
1063
  if (!choice)
 
1064
  {
 
1065
    if (a && a->parts) 
 
1066
      b = a->parts;
 
1067
    else
 
1068
      b = a;
 
1069
    while (b)
 
1070
    {
 
1071
      if (mutt_is_autoview (b))
 
1072
        choice = b;
 
1073
      b = b->next;
 
1074
    }
 
1075
  }
 
1076
 
 
1077
  /* Then, look for a text entry */
 
1078
  if (!choice)
 
1079
  {
 
1080
    if (a && a->parts) 
 
1081
      b = a->parts;
 
1082
    else
 
1083
      b = a;
 
1084
    while (b)
 
1085
    {
 
1086
      if (b->type == TYPETEXT)
 
1087
      {
 
1088
        if (! ascii_strcasecmp ("plain", b->subtype) && type <= TXTPLAIN)
 
1089
        {
 
1090
          choice = b;
 
1091
          type = TXTPLAIN;
 
1092
        }
 
1093
        else if (! ascii_strcasecmp ("enriched", b->subtype) && type <= TXTENRICHED)
 
1094
        {
 
1095
          choice = b;
 
1096
          type = TXTENRICHED;
 
1097
        }
 
1098
        else if (! ascii_strcasecmp ("html", b->subtype) && type <= TXTHTML)
 
1099
        {
 
1100
          choice = b;
 
1101
          type = TXTHTML;
 
1102
        }
 
1103
      }
 
1104
      b = b->next;
 
1105
    }
 
1106
  }
 
1107
 
 
1108
  /* Finally, look for other possibilities */
 
1109
  if (!choice)
 
1110
  {
 
1111
    if (a && a->parts) 
 
1112
      b = a->parts;
 
1113
    else
 
1114
      b = a;
 
1115
    while (b)
 
1116
    {
 
1117
      if (mutt_can_decode (b))
 
1118
        choice = b;
 
1119
      b = b->next;
 
1120
    }
 
1121
  }
 
1122
 
 
1123
  if (choice)
 
1124
  {
 
1125
    if (s->flags & M_DISPLAY && !option (OPTWEED))
 
1126
    {
 
1127
      fseeko (s->fpin, choice->hdr_offset, 0);
 
1128
      mutt_copy_bytes(s->fpin, s->fpout, choice->offset-choice->hdr_offset);
 
1129
    }
 
1130
    mutt_body_handler (choice, s);
 
1131
  }
 
1132
  else if (s->flags & M_DISPLAY)
 
1133
  {
 
1134
    /* didn't find anything that we could display! */
 
1135
    state_mark_attach (s);
 
1136
    state_puts(_("[-- Error:  Could not display any parts of Multipart/Alternative! --]\n"), s);
 
1137
    rc = -1;
 
1138
  }
 
1139
 
 
1140
  if (mustfree)
 
1141
    mutt_free_body(&a);
 
1142
 
 
1143
  return rc;
 
1144
}
 
1145
 
 
1146
/* handles message/rfc822 body parts */
 
1147
static int message_handler (BODY *a, STATE *s)
 
1148
{
 
1149
  struct stat st;
 
1150
  BODY *b;
 
1151
  LOFF_T off_start;
 
1152
  int rc = 0;
 
1153
 
 
1154
  off_start = ftello (s->fpin);
 
1155
  if (a->encoding == ENCBASE64 || a->encoding == ENCQUOTEDPRINTABLE || 
 
1156
      a->encoding == ENCUUENCODED)
 
1157
  {
 
1158
    fstat (fileno (s->fpin), &st);
 
1159
    b = mutt_new_body ();
 
1160
    b->length = (LOFF_T) st.st_size;
 
1161
    b->parts = mutt_parse_messageRFC822 (s->fpin, b);
 
1162
  }
 
1163
  else
 
1164
    b = a;
 
1165
 
 
1166
  if (b->parts)
 
1167
  {
 
1168
    mutt_copy_hdr (s->fpin, s->fpout, off_start, b->parts->offset,
 
1169
        (((s->flags & M_WEED) || ((s->flags & (M_DISPLAY|M_PRINTING)) && option (OPTWEED))) ? (CH_WEED | CH_REORDER) : 0) |
 
1170
        (s->prefix ? CH_PREFIX : 0) | CH_DECODE | CH_FROM |
 
1171
        ((s->flags & M_DISPLAY) ? CH_DISPLAY : 0), s->prefix);
 
1172
 
 
1173
    if (s->prefix)
 
1174
      state_puts (s->prefix, s);
 
1175
    state_putc ('\n', s);
 
1176
 
 
1177
    rc = mutt_body_handler (b->parts, s);
 
1178
  }
 
1179
 
 
1180
  if (a->encoding == ENCBASE64 || a->encoding == ENCQUOTEDPRINTABLE ||
 
1181
      a->encoding == ENCUUENCODED)
 
1182
    mutt_free_body (&b);
 
1183
  
 
1184
  return rc;
 
1185
}
 
1186
 
 
1187
/* returns 1 if decoding the attachment will produce output */
 
1188
int mutt_can_decode (BODY *a)
 
1189
{
 
1190
  if (mutt_is_autoview (a))
 
1191
    return 1;
 
1192
  else if (a->type == TYPETEXT)
 
1193
    return (1);
 
1194
  else if (a->type == TYPEMESSAGE)
 
1195
    return (1);
 
1196
  else if (a->type == TYPEMULTIPART)
 
1197
  {
 
1198
    BODY *p;
 
1199
 
 
1200
    if (WithCrypto)
 
1201
    {
 
1202
      if (ascii_strcasecmp (a->subtype, "signed") == 0 ||
 
1203
          ascii_strcasecmp (a->subtype, "encrypted") == 0)
 
1204
        return (1);
 
1205
    }
 
1206
 
 
1207
    for (p = a->parts; p; p = p->next)
 
1208
    {
 
1209
      if (mutt_can_decode (p))
 
1210
        return (1);
 
1211
    }
 
1212
    
 
1213
  }
 
1214
  else if (WithCrypto && a->type == TYPEAPPLICATION)
 
1215
  {
 
1216
    if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp(a))
 
1217
      return (1);
 
1218
    if ((WithCrypto & APPLICATION_SMIME) && mutt_is_application_smime(a))
 
1219
      return (1);
 
1220
  }
 
1221
 
 
1222
  return (0);
 
1223
}
 
1224
 
 
1225
static int multipart_handler (BODY *a, STATE *s)
 
1226
{
 
1227
  BODY *b, *p;
 
1228
  char length[5];
 
1229
  struct stat st;
 
1230
  int count;
 
1231
  int rc = 0;
 
1232
 
 
1233
  if (a->encoding == ENCBASE64 || a->encoding == ENCQUOTEDPRINTABLE ||
 
1234
      a->encoding == ENCUUENCODED)
 
1235
  {
 
1236
    fstat (fileno (s->fpin), &st);
 
1237
    b = mutt_new_body ();
 
1238
    b->length = (long) st.st_size;
 
1239
    b->parts = mutt_parse_multipart (s->fpin,
 
1240
                  mutt_get_parameter ("boundary", a->parameter),
 
1241
                  (long) st.st_size, ascii_strcasecmp ("digest", a->subtype) == 0);
 
1242
  }
 
1243
  else
 
1244
    b = a;
 
1245
 
 
1246
  for (p = b->parts, count = 1; p; p = p->next, count++)
 
1247
  {
 
1248
    if (s->flags & M_DISPLAY)
 
1249
    {
 
1250
      state_mark_attach (s);
 
1251
      state_printf (s, _("[-- Attachment #%d"), count);
 
1252
      if (p->description || p->filename || p->form_name)
 
1253
      {
 
1254
        state_puts (": ", s);
 
1255
        state_puts (p->description ? p->description :
 
1256
                    p->filename ? p->filename : p->form_name, s);
 
1257
      }
 
1258
      state_puts (" --]\n", s);
 
1259
 
 
1260
      mutt_pretty_size (length, sizeof (length), p->length);
 
1261
      
 
1262
      state_mark_attach (s);
 
1263
      state_printf (s, _("[-- Type: %s/%s, Encoding: %s, Size: %s --]\n"),
 
1264
                    TYPE (p), p->subtype, ENCODING (p->encoding), length);
 
1265
      if (!option (OPTWEED))
 
1266
      {
 
1267
        fseeko (s->fpin, p->hdr_offset, 0);
 
1268
        mutt_copy_bytes(s->fpin, s->fpout, p->offset-p->hdr_offset);
 
1269
      }
 
1270
      else
 
1271
        state_putc ('\n', s);
 
1272
    }
 
1273
 
 
1274
    rc = mutt_body_handler (p, s);
 
1275
    state_putc ('\n', s);
 
1276
    
 
1277
    if (rc)
 
1278
    {
 
1279
      mutt_error (_("One or more parts of this message could not be displayed"));
 
1280
      dprint (1, (debugfile, "Failed on attachment #%d, type %s/%s.\n", count, TYPE(p), NONULL (p->subtype)));
 
1281
    }
 
1282
    
 
1283
    if ((s->flags & M_REPLYING)
 
1284
        && (option (OPTINCLUDEONLYFIRST)) && (s->flags & M_FIRSTDONE))
 
1285
      break;
 
1286
  }
 
1287
 
 
1288
  if (a->encoding == ENCBASE64 || a->encoding == ENCQUOTEDPRINTABLE ||
 
1289
      a->encoding == ENCUUENCODED)
 
1290
    mutt_free_body (&b);
 
1291
 
 
1292
  /* make failure of a single part non-fatal */
 
1293
  if (rc < 0)
 
1294
    rc = 1;
 
1295
  return rc;
 
1296
}
 
1297
 
 
1298
static int autoview_handler (BODY *a, STATE *s)
 
1299
{
 
1300
  rfc1524_entry *entry = rfc1524_new_entry ();
 
1301
  char buffer[LONG_STRING];
 
1302
  char type[STRING];
 
1303
  char command[LONG_STRING];
 
1304
  char tempfile[_POSIX_PATH_MAX] = "";
 
1305
  char *fname;
 
1306
  FILE *fpin = NULL;
 
1307
  FILE *fpout = NULL;
 
1308
  FILE *fperr = NULL;
 
1309
  int piped = FALSE;
 
1310
  pid_t thepid;
 
1311
  int rc = 0;
 
1312
 
 
1313
  snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
 
1314
  rfc1524_mailcap_lookup (a, type, entry, M_AUTOVIEW);
 
1315
 
 
1316
  fname = safe_strdup (a->filename);
 
1317
  mutt_sanitize_filename (fname, 1);
 
1318
  rfc1524_expand_filename (entry->nametemplate, fname, tempfile, sizeof (tempfile));
 
1319
  FREE (&fname);
 
1320
 
 
1321
  if (entry->command)
 
1322
  {
 
1323
    strfcpy (command, entry->command, sizeof (command));
 
1324
 
 
1325
    /* rfc1524_expand_command returns 0 if the file is required */
 
1326
    piped = rfc1524_expand_command (a, tempfile, type, command, sizeof (command));
 
1327
 
 
1328
    if (s->flags & M_DISPLAY)
 
1329
    {
 
1330
      state_mark_attach (s);
 
1331
      state_printf (s, _("[-- Autoview using %s --]\n"), command);
 
1332
      mutt_message(_("Invoking autoview command: %s"),command);
 
1333
    }
 
1334
 
 
1335
    if ((fpin = safe_fopen (tempfile, "w+")) == NULL)
 
1336
    {
 
1337
      mutt_perror ("fopen");
 
1338
      rfc1524_free_entry (&entry);
 
1339
      return -1;
 
1340
    }
 
1341
    
 
1342
    mutt_copy_bytes (s->fpin, fpin, a->length);
 
1343
 
 
1344
    if(!piped)
 
1345
    {
 
1346
      safe_fclose (&fpin);
 
1347
      thepid = mutt_create_filter (command, NULL, &fpout, &fperr);
 
1348
    }
 
1349
    else
 
1350
    {
 
1351
      unlink (tempfile);
 
1352
      fflush (fpin);
 
1353
      rewind (fpin);
 
1354
      thepid = mutt_create_filter_fd (command, NULL, &fpout, &fperr,
 
1355
                                      fileno(fpin), -1, -1);
 
1356
    }
 
1357
 
 
1358
    if (thepid < 0)
 
1359
    {
 
1360
      mutt_perror _("Can't create filter");
 
1361
      if (s->flags & M_DISPLAY)
 
1362
      {
 
1363
        state_mark_attach (s);
 
1364
        state_printf (s, _("[-- Can't run %s. --]\n"), command);
 
1365
      }
 
1366
      rc = -1;
 
1367
      goto bail;
 
1368
    }
 
1369
    
 
1370
    if (s->prefix)
 
1371
    {
 
1372
      while (fgets (buffer, sizeof(buffer), fpout) != NULL)
 
1373
      {
 
1374
        state_puts (s->prefix, s);
 
1375
        state_puts (buffer, s);
 
1376
      }
 
1377
      /* check for data on stderr */
 
1378
      if (fgets (buffer, sizeof(buffer), fperr)) 
 
1379
      {
 
1380
        if (s->flags & M_DISPLAY)
 
1381
        {
 
1382
          state_mark_attach (s);
 
1383
          state_printf (s, _("[-- Autoview stderr of %s --]\n"), command);
 
1384
        }
 
1385
 
 
1386
        state_puts (s->prefix, s);
 
1387
        state_puts (buffer, s);
 
1388
        while (fgets (buffer, sizeof(buffer), fperr) != NULL)
 
1389
        {
 
1390
          state_puts (s->prefix, s);
 
1391
          state_puts (buffer, s);
 
1392
        }
 
1393
      }
 
1394
    }
 
1395
    else
 
1396
    {
 
1397
      mutt_copy_stream (fpout, s->fpout);
 
1398
      /* Check for stderr messages */
 
1399
      if (fgets (buffer, sizeof(buffer), fperr))
 
1400
      {
 
1401
        if (s->flags & M_DISPLAY)
 
1402
        {
 
1403
          state_mark_attach (s);
 
1404
          state_printf (s, _("[-- Autoview stderr of %s --]\n"), 
 
1405
                        command);
 
1406
        }
 
1407
        
 
1408
        state_puts (buffer, s);
 
1409
        mutt_copy_stream (fperr, s->fpout);
 
1410
      }
 
1411
    }
 
1412
 
 
1413
  bail:
 
1414
    safe_fclose (&fpout);
 
1415
    safe_fclose (&fperr);
 
1416
 
 
1417
    mutt_wait_filter (thepid);
 
1418
    if (piped)
 
1419
      safe_fclose (&fpin);
 
1420
    else
 
1421
      mutt_unlink (tempfile);
 
1422
 
 
1423
    if (s->flags & M_DISPLAY) 
 
1424
      mutt_clear_error ();
 
1425
  }
 
1426
  rfc1524_free_entry (&entry);
 
1427
 
 
1428
  return rc;
 
1429
}
 
1430
 
 
1431
static int external_body_handler (BODY *b, STATE *s)
 
1432
{
 
1433
  const char *access_type;
 
1434
  const char *expiration;
 
1435
  time_t expire;
 
1436
 
 
1437
  access_type = mutt_get_parameter ("access-type", b->parameter);
 
1438
  if (!access_type)
 
1439
  {
 
1440
    if (s->flags & M_DISPLAY)
 
1441
    {
 
1442
      state_mark_attach (s);
 
1443
      state_puts (_("[-- Error: message/external-body has no access-type parameter --]\n"), s);
 
1444
      return 0;
 
1445
    }
 
1446
    else
 
1447
      return -1;
 
1448
  }
 
1449
 
 
1450
  expiration = mutt_get_parameter ("expiration", b->parameter);
 
1451
  if (expiration)
 
1452
    expire = mutt_parse_date (expiration, NULL);
 
1453
  else
 
1454
    expire = -1;
 
1455
 
 
1456
  if (!ascii_strcasecmp (access_type, "x-mutt-deleted"))
 
1457
  {
 
1458
    if (s->flags & (M_DISPLAY|M_PRINTING))
 
1459
    {
 
1460
      char *length;
 
1461
      char pretty_size[10];
 
1462
      
 
1463
      state_mark_attach (s);
 
1464
      state_printf (s, _("[-- This %s/%s attachment "),
 
1465
               TYPE(b->parts), b->parts->subtype);
 
1466
      length = mutt_get_parameter ("length", b->parameter);
 
1467
      if (length)
 
1468
      {
 
1469
        mutt_pretty_size (pretty_size, sizeof (pretty_size),
 
1470
                          strtol (length, NULL, 10));
 
1471
        state_printf (s, _("(size %s bytes) "), pretty_size);
 
1472
      }
 
1473
      state_puts (_("has been deleted --]\n"), s);
 
1474
 
 
1475
      if (expire != -1)
 
1476
      {
 
1477
        state_mark_attach (s);
 
1478
        state_printf (s, _("[-- on %s --]\n"), expiration);
 
1479
      }
 
1480
      if (b->parts->filename)
 
1481
      {
 
1482
        state_mark_attach (s);
 
1483
        state_printf (s, _("[-- name: %s --]\n"), b->parts->filename);
 
1484
      }
 
1485
 
 
1486
      mutt_copy_hdr (s->fpin, s->fpout, ftello (s->fpin), b->parts->offset,
 
1487
                     (option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) |
 
1488
                     CH_DECODE , NULL);
 
1489
    }
 
1490
  }
 
1491
  else if(expiration && expire < time(NULL))
 
1492
  {
 
1493
    if (s->flags & M_DISPLAY)
 
1494
    {
 
1495
      state_mark_attach (s);
 
1496
      state_printf (s, _("[-- This %s/%s attachment is not included, --]\n"),
 
1497
                    TYPE(b->parts), b->parts->subtype);
 
1498
      state_attach_puts (_("[-- and the indicated external source has --]\n"
 
1499
                           "[-- expired. --]\n"), s);
 
1500
 
 
1501
      mutt_copy_hdr(s->fpin, s->fpout, ftello (s->fpin), b->parts->offset,
 
1502
                    (option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) |
 
1503
                    CH_DECODE | CH_DISPLAY, NULL);
 
1504
    }
 
1505
  }
 
1506
  else
 
1507
  {
 
1508
    if (s->flags & M_DISPLAY)
 
1509
    {
 
1510
      state_mark_attach (s);
 
1511
      state_printf (s,
 
1512
                    _("[-- This %s/%s attachment is not included, --]\n"),
 
1513
                    TYPE (b->parts), b->parts->subtype);
 
1514
      state_mark_attach (s);
 
1515
      state_printf (s, 
 
1516
                    _("[-- and the indicated access-type %s is unsupported --]\n"),
 
1517
                    access_type);
 
1518
      mutt_copy_hdr (s->fpin, s->fpout, ftello (s->fpin), b->parts->offset,
 
1519
                     (option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) |
 
1520
                     CH_DECODE | CH_DISPLAY, NULL);
 
1521
    }
 
1522
  }
 
1523
  
 
1524
  return 0;
 
1525
}
 
1526
 
 
1527
void mutt_decode_attachment (BODY *b, STATE *s)
 
1528
{
 
1529
  int istext = mutt_is_text_part (b);
 
1530
  iconv_t cd = (iconv_t)(-1);
 
1531
 
 
1532
  if (istext && s->flags & M_CHARCONV)
 
1533
  {
 
1534
    char *charset = mutt_get_parameter ("charset", b->parameter);
 
1535
    if (!charset && AssumedCharset && *AssumedCharset)
 
1536
      charset = mutt_get_default_charset ();
 
1537
    if (charset && Charset)
 
1538
      cd = mutt_iconv_open (Charset, charset, M_ICONV_HOOK_FROM);
 
1539
  }
 
1540
  else if (istext && b->charset)
 
1541
    cd = mutt_iconv_open (Charset, b->charset, M_ICONV_HOOK_FROM);
 
1542
 
 
1543
  fseeko (s->fpin, b->offset, 0);
 
1544
  switch (b->encoding)
 
1545
  {
 
1546
    case ENCQUOTEDPRINTABLE:
 
1547
      mutt_decode_quoted (s, b->length, istext || ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b)), cd);
 
1548
      break;
 
1549
    case ENCBASE64:
 
1550
      mutt_decode_base64 (s, b->length, istext || ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b)), cd);
 
1551
      break;
 
1552
    case ENCUUENCODED:
 
1553
      mutt_decode_uuencoded (s, b->length, istext || ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b)), cd);
 
1554
      break;
 
1555
    default:
 
1556
      mutt_decode_xbit (s, b->length, istext || ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b)), cd);
 
1557
      break;
 
1558
  }
 
1559
 
 
1560
  if (cd != (iconv_t)(-1))
 
1561
    iconv_close (cd);
 
1562
}
 
1563
 
 
1564
/* when generating format=flowed ($text_flowed is set) from format=fixed,
 
1565
 * strip all trailing spaces to improve interoperability;
 
1566
 * if $text_flowed is unset, simply verbatim copy input
 
1567
 */
 
1568
static int text_plain_handler (BODY *b, STATE *s)
 
1569
{
 
1570
  char *buf = NULL;
 
1571
  size_t l = 0, sz = 0;
 
1572
 
 
1573
  while ((buf = mutt_read_line (buf, &sz, s->fpin, NULL, 0)))
 
1574
  {
 
1575
    if (mutt_strcmp (buf, "-- ") != 0 && option (OPTTEXTFLOWED))
 
1576
    {
 
1577
      l = mutt_strlen (buf);
 
1578
      while (l > 0 && buf[l-1] == ' ')
 
1579
        buf[--l] = 0;
 
1580
    }
 
1581
    if (s->prefix)
 
1582
      state_puts (s->prefix, s);
 
1583
    state_puts (buf, s);
 
1584
    state_putc ('\n', s);
 
1585
  }
 
1586
 
 
1587
  FREE (&buf);
 
1588
  return 0;
 
1589
}
 
1590
 
 
1591
int mutt_body_handler (BODY *b, STATE *s)
 
1592
{
 
1593
  int decode = 0;
 
1594
  int plaintext = 0;
 
1595
  FILE *fp = NULL;
 
1596
  char tempfile[_POSIX_PATH_MAX];
 
1597
  handler_t handler = NULL;
 
1598
  LOFF_T tmpoffset = 0;
 
1599
  size_t tmplength = 0;
 
1600
  int rc = 0;
 
1601
 
 
1602
  int oflags = s->flags;
 
1603
  
 
1604
  /* first determine which handler to use to process this part */
 
1605
 
 
1606
  if (mutt_is_autoview (b))
 
1607
  {
 
1608
    handler = autoview_handler;
 
1609
    s->flags &= ~M_CHARCONV;
 
1610
  }
 
1611
  else if (b->type == TYPETEXT)
 
1612
  {
 
1613
    if (ascii_strcasecmp ("plain", b->subtype) == 0)
 
1614
    {
 
1615
      /* avoid copying this part twice since removing the transfer-encoding is
 
1616
       * the only operation needed.
 
1617
       */
 
1618
      if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b))
 
1619
        handler = crypt_pgp_application_pgp_handler;
 
1620
      else if (option(OPTREFLOWTEXT) && ascii_strcasecmp ("flowed", mutt_get_parameter ("format", b->parameter)) == 0)
 
1621
        handler = rfc3676_handler;
 
1622
      else
 
1623
        handler = text_plain_handler;
 
1624
    }
 
1625
    else if (ascii_strcasecmp ("enriched", b->subtype) == 0)
 
1626
      handler = text_enriched_handler;
 
1627
    else /* text body type without a handler */
 
1628
      plaintext = 1;
 
1629
  }
 
1630
  else if (b->type == TYPEMESSAGE)
 
1631
  {
 
1632
    if(mutt_is_message_type(b->type, b->subtype))
 
1633
      handler = message_handler;
 
1634
    else if (!ascii_strcasecmp ("delivery-status", b->subtype))
 
1635
      plaintext = 1;
 
1636
    else if (!ascii_strcasecmp ("external-body", b->subtype))
 
1637
      handler = external_body_handler;
 
1638
  }
 
1639
  else if (b->type == TYPEMULTIPART)
 
1640
  {
 
1641
    char *p;
 
1642
 
 
1643
    if (ascii_strcasecmp ("alternative", b->subtype) == 0)
 
1644
      handler = alternative_handler;
 
1645
    else if (WithCrypto && ascii_strcasecmp ("signed", b->subtype) == 0)
 
1646
    {
 
1647
      p = mutt_get_parameter ("protocol", b->parameter);
 
1648
 
 
1649
      if (!p)
 
1650
        mutt_error _("Error: multipart/signed has no protocol.");
 
1651
      else if (s->flags & M_VERIFY)
 
1652
        handler = mutt_signed_handler;
 
1653
    }
 
1654
    else if ((WithCrypto & APPLICATION_PGP)
 
1655
             && ascii_strcasecmp ("encrypted", b->subtype) == 0)
 
1656
    {
 
1657
      p = mutt_get_parameter ("protocol", b->parameter);
 
1658
 
 
1659
      if (!p)
 
1660
        mutt_error _("Error: multipart/encrypted has no protocol parameter!");
 
1661
      else if (ascii_strcasecmp ("application/pgp-encrypted", p) == 0)
 
1662
        handler = crypt_pgp_encrypted_handler;
 
1663
    }
 
1664
 
 
1665
    if (!handler)
 
1666
      handler = multipart_handler;
 
1667
    
 
1668
    if (b->encoding != ENC7BIT && b->encoding != ENC8BIT
 
1669
        && b->encoding != ENCBINARY)
 
1670
    {
 
1671
      dprint (1, (debugfile, "Bad encoding type %d for multipart entity, "
 
1672
                  "assuming 7 bit\n", b->encoding));
 
1673
      b->encoding = ENC7BIT;
 
1674
    }
 
1675
  }
 
1676
  else if (WithCrypto && b->type == TYPEAPPLICATION)
 
1677
  {
 
1678
    if (option (OPTDONTHANDLEPGPKEYS)
 
1679
        && !ascii_strcasecmp("pgp-keys", b->subtype))
 
1680
    {
 
1681
      /* pass raw part through for key extraction */
 
1682
      plaintext = 1;
 
1683
    }
 
1684
    else if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b))
 
1685
      handler = crypt_pgp_application_pgp_handler;
 
1686
    else if ((WithCrypto & APPLICATION_SMIME) && mutt_is_application_smime(b))
 
1687
      handler = crypt_smime_application_smime_handler;
 
1688
  }
 
1689
 
 
1690
  /* only respect disposition == attachment if we're not
 
1691
     displaying from the attachment menu (i.e. pager) */
 
1692
  if ((!option (OPTHONORDISP) || (b->disposition != DISPATTACH ||
 
1693
                                  option(OPTVIEWATTACH))) &&
 
1694
       (plaintext || handler))
 
1695
  {
 
1696
    fseeko (s->fpin, b->offset, 0);
 
1697
 
 
1698
    /* see if we need to decode this part before processing it */
 
1699
    if (b->encoding == ENCBASE64 || b->encoding == ENCQUOTEDPRINTABLE ||
 
1700
        b->encoding == ENCUUENCODED || plaintext || 
 
1701
        mutt_is_text_part (b))                          /* text subtypes may
 
1702
                                                         * require character
 
1703
                                                         * set conversion even
 
1704
                                                         * with 8bit encoding.
 
1705
                                                         */
 
1706
    {
 
1707
      int origType = b->type;
 
1708
      char *savePrefix = NULL;
 
1709
 
 
1710
      if (!plaintext)
 
1711
      {
 
1712
        /* decode to a tempfile, saving the original destination */
 
1713
        fp = s->fpout;
 
1714
        mutt_mktemp (tempfile, sizeof (tempfile));
 
1715
        if ((s->fpout = safe_fopen (tempfile, "w")) == NULL)
 
1716
        {
 
1717
          mutt_error _("Unable to open temporary file!");
 
1718
          dprint (1, (debugfile, "Can't open %s.\n", tempfile));
 
1719
          goto bail;
 
1720
        }
 
1721
        /* decoding the attachment changes the size and offset, so save a copy
 
1722
         * of the "real" values now, and restore them after processing
 
1723
         */
 
1724
        tmplength = b->length;
 
1725
        tmpoffset = b->offset;
 
1726
 
 
1727
        /* if we are decoding binary bodies, we don't want to prefix each
 
1728
         * line with the prefix or else the data will get corrupted.
 
1729
         */
 
1730
        savePrefix = s->prefix;
 
1731
        s->prefix = NULL;
 
1732
 
 
1733
        decode = 1;
 
1734
      }
 
1735
      else
 
1736
        b->type = TYPETEXT;
 
1737
 
 
1738
      mutt_decode_attachment (b, s);
 
1739
 
 
1740
      if (decode)
 
1741
      {
 
1742
        b->length = ftello (s->fpout);
 
1743
        b->offset = 0;
 
1744
        safe_fclose (&s->fpout);
 
1745
 
 
1746
        /* restore final destination and substitute the tempfile for input */
 
1747
        s->fpout = fp;
 
1748
        fp = s->fpin;
 
1749
        s->fpin = fopen (tempfile, "r");
 
1750
        unlink (tempfile);
 
1751
 
 
1752
        /* restore the prefix */
 
1753
        s->prefix = savePrefix;
 
1754
      }
 
1755
 
 
1756
      b->type = origType;
 
1757
    }
 
1758
 
 
1759
    /* process the (decoded) body part */
 
1760
    if (handler)
 
1761
    {
 
1762
      rc = handler (b, s);
 
1763
 
 
1764
      if (rc)
 
1765
      {
 
1766
        dprint (1, (debugfile, "Failed on attachment of type %s/%s.\n", TYPE(b), NONULL (b->subtype)));
 
1767
      }
 
1768
      
 
1769
      if (decode)
 
1770
      {
 
1771
        b->length = tmplength;
 
1772
        b->offset = tmpoffset;
 
1773
 
 
1774
        /* restore the original source stream */
 
1775
        safe_fclose (&s->fpin);
 
1776
        s->fpin = fp;
 
1777
      }
 
1778
    }
 
1779
    s->flags |= M_FIRSTDONE;
 
1780
  }
 
1781
  /* print hint to use attachment menu for disposition == attachment
 
1782
     if we're not already being called from there */
 
1783
  else if ((s->flags & M_DISPLAY) || (b->disposition == DISPATTACH &&
 
1784
                                      !option (OPTVIEWATTACH) &&
 
1785
                                      option (OPTHONORDISP) &&
 
1786
                                      (plaintext || handler)))
 
1787
  {
 
1788
    state_mark_attach (s);
 
1789
    if (option (OPTHONORDISP) && b->disposition == DISPATTACH)
 
1790
      fputs (_("[-- This is an attachment "), s->fpout);
 
1791
    else
 
1792
      state_printf (s, _("[-- %s/%s is unsupported "), TYPE (b), b->subtype);
 
1793
    if (!option (OPTVIEWATTACH))
 
1794
    {
 
1795
      char keystroke[SHORT_STRING];
 
1796
 
 
1797
      if (km_expand_key (keystroke, sizeof(keystroke),
 
1798
                        km_find_func (MENU_PAGER, OP_VIEW_ATTACHMENTS)))
 
1799
        fprintf (s->fpout, _("(use '%s' to view this part)"), keystroke);
 
1800
      else
 
1801
        fputs (_("(need 'view-attachments' bound to key!)"), s->fpout);
 
1802
    }
 
1803
    fputs (" --]\n", s->fpout);
 
1804
  }
 
1805
 
 
1806
  bail:
 
1807
  s->flags = oflags | (s->flags & M_FIRSTDONE);
 
1808
  if (rc)
 
1809
  {
 
1810
    dprint (1, (debugfile, "Bailing on attachment of type %s/%s.\n", TYPE(b), NONULL (b->subtype)));
 
1811
  }
 
1812
 
 
1813
  return rc;
 
1814
}