Fix two encoding issues
[gpgol.git] / src / mimedataprovider.cpp
1 /* mimedataprover.cpp - GpgME dataprovider for mime data
2  * Copyright (C) 2016 by Bundesamt für Sicherheit in der Informationstechnik
3  * Software engineering by Intevation GmbH
4  *
5  * This file is part of GpgOL.
6  *
7  * GpgOL is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * GpgOL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20 #include "config.h"
21 #include "common_indep.h"
22 #include "xmalloc.h"
23 #include <string.h>
24 #include <vector>
25 #include <sstream>
26
27 #include "mimedataprovider.h"
28 #include "rfc822parse.h"
29 #include "rfc2047parse.h"
30 #include "attachment.h"
31 #include "cpphelp.h"
32
33 #ifndef HAVE_W32_SYSTEM
34 #define stricmp strcasecmp
35 #endif
36
37 /* The maximum length of a line we are able to process.  RFC822 allows
38    only for 1000 bytes; thus 2000 seems to be a reasonable value. */
39 #define LINEBUFSIZE 2000
40
41 /* How much data is read at once in collect */
42 #define BUFSIZE 8192
43
44 #include <gpgme++/error.h>
45
46 /* To keep track of the MIME message structures we use a linked list
47    with each item corresponding to one part. */
48 struct mimestruct_item_s;
49 typedef struct mimestruct_item_s *mimestruct_item_t;
50 struct mimestruct_item_s
51 {
52   mimestruct_item_t next;
53   unsigned int level;   /* Level in the hierarchy of that part.  0
54                            indicates the outer body.  */
55   char *filename;       /* Malloced filename or NULL.  */
56   char *cid;            /* Malloced content id or NULL. */
57   char *charset;        /* Malloced charset or NULL.  */
58   char content_type[1]; /* String with the content type. */
59 };
60
61 /* The context object we use to track information. */
62 struct mime_context
63 {
64   rfc822parse_t msg;  /* The handle of the RFC822 parser. */
65
66   int verify_mode;    /* True if we want to verify a signature. */
67
68   int nesting_level;  /* Current MIME nesting level. */
69   int in_data;        /* We are currently in data (body or attachment). */
70   int body_seen;      /* True if we have seen a part we consider the
71                          body of the message.  */
72
73   std::shared_ptr<Attachment> current_attachment; /* A pointer to the current
74                                                      attachment */
75   int collect_body;       /* True if we are collcting the body */
76   int collect_html_body;  /* True if we are collcting the html body */
77   int collect_crypto_data; /* True if we are collecting the signed data. */
78   int collect_signature;  /* True if we are collecting a signature.  */
79   int pgp_marker_checked; /* Checked if the first body line is pgp marker*/
80   int is_encrypted;       /* True if we are working on an encrypted mail. */
81   int start_hashing;      /* Flag used to start collecting signed data. */
82   int hashing_level;      /* MIME level where we started hashing. */
83   int is_qp_encoded;      /* Current part is QP encoded. */
84   int is_base64_encoded;  /* Current part is base 64 encoded. */
85   int is_body;            /* The current part belongs to the body.  */
86   protocol_t protocol;    /* The detected crypto protocol.  */
87
88   int part_counter;       /* Counts the number of processed parts. */
89   int any_boundary;       /* Indicates whether we have seen any
90                              boundary which means that we are actually
91                              working on a MIME message and not just on
92                              plain rfc822 message.  */
93
94   /* A linked list describing the structure of the mime message.  This
95      list gets build up while parsing the message.  */
96   mimestruct_item_t mimestruct;
97   mimestruct_item_t *mimestruct_tail;
98   mimestruct_item_t mimestruct_cur;
99
100   int any_attachments_created;  /* True if we created a new atatchment.  */
101
102   b64_state_t base64;     /* The state of the Base-64 decoder.  */
103
104   gpg_error_t parser_error;   /* Indicates that we encountered a error from
105                                  the parser. */
106 };
107 typedef struct mime_context *mime_context_t;
108
109 /* Print the message event EVENT. */
110 static void
111 debug_message_event (rfc822parse_event_t event)
112 {
113   const char *s;
114
115   switch (event)
116     {
117     case RFC822PARSE_OPEN: s= "Open"; break;
118     case RFC822PARSE_CLOSE: s= "Close"; break;
119     case RFC822PARSE_CANCEL: s= "Cancel"; break;
120     case RFC822PARSE_T2BODY: s= "T2Body"; break;
121     case RFC822PARSE_FINISH: s= "Finish"; break;
122     case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break;
123     case RFC822PARSE_LEVEL_DOWN: s= "Level_Down"; break;
124     case RFC822PARSE_LEVEL_UP: s= "Level_Up"; break;
125     case RFC822PARSE_BOUNDARY: s= "Boundary"; break;
126     case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break;
127     case RFC822PARSE_BEGIN_HEADER: s= "Begin_Header"; break;
128     case RFC822PARSE_PREAMBLE: s= "Preamble"; break;
129     case RFC822PARSE_EPILOGUE: s= "Epilogue"; break;
130     default: s= "[unknown event]"; break;
131     }
132   log_data ("%s: rfc822 event %s\n", SRCNAME, s);
133 }
134
135 /* returns true if the BER encoded data in BUFFER is CMS signed data.
136    LENGTH gives the length of the buffer, for correct detection LENGTH
137    should be at least about 24 bytes.  */
138 #if 0
139 static int
140 is_cms_signed_data (const char *buffer, size_t length)
141 {
142   TSTART;
143   const char *p = buffer;
144   size_t n = length;
145   tlvinfo_t ti;
146
147   if (parse_tlv (&p, &n, &ti))
148     {
149       TRETURN 0;
150     }
151   if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
152         && ti.is_cons) )
153     TRETURN 0;
154   if (parse_tlv (&p, &n, &ti))
155     {
156       TRETURN 0;
157     }
158   if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_OBJECT_ID
159         && !ti.is_cons && ti.length) || ti.length > n)
160     TRETURN 0;
161   if (ti.length == 9 && !memcmp (p, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02", 9))
162     {
163       TRETURN 1;
164     }
165   TRETURN 0;
166 }
167 #endif
168
169 /* Process the transition to body event.
170
171    This means we have received the empty line indicating the body and
172    should now check the headers to see what to do about this part.
173
174    This is mostly a C style function because it was based on the old
175    c mimeparser.
176 */
177 static int
178 t2body (MimeDataProvider *provider, rfc822parse_t msg)
179 {
180   TSTART;
181   rfc822parse_field_t field;
182   mime_context_t ctx = provider->mime_context ();
183   const char *ctmain, *ctsub;
184   const char *s;
185   size_t off;
186   char *p;
187   int is_text = 0;
188   int is_text_attachment = 0;
189   char *filename = NULL;
190   char *cid = NULL;
191   char *charset = NULL;
192   bool ignore_cid = false;
193
194   /* Figure out the encoding.  */
195   ctx->is_qp_encoded = 0;
196   ctx->is_base64_encoded = 0;
197   p = rfc822parse_get_field (msg, "Content-Transfer-Encoding", -1, &off);
198   if (p)
199     {
200       if (!stricmp (p+off, "quoted-printable"))
201         ctx->is_qp_encoded = 1;
202       else if (!stricmp (p+off, "base64"))
203         {
204           ctx->is_base64_encoded = 1;
205           b64_init (&ctx->base64);
206         }
207       xfree (p);
208     }
209
210   /* Get the filename from the header.  */
211   field = rfc822parse_parse_field (msg, "Content-Disposition", -1);
212   if (field)
213     {
214       s = rfc822parse_query_parameter (field, "filename", 0);
215       if (s)
216         filename = rfc2047_parse (s);
217       s = rfc822parse_query_parameter (field, NULL, 1);
218
219       if (s && strstr (s, "attachment"))
220         {
221           log_debug ("%s:%s: Found Content-Disposition attachment."
222                      " Ignoring content-id to avoid hiding.",
223                      SRCNAME, __func__);
224           ignore_cid = true;
225         }
226
227       /* This is a bit of a taste matter how to treat inline
228          attachments. Outlook does not show them inline so we
229          should not put it in the body either as we have
230          no way to show that it was actually an attachment.
231          For something like an inline patch it is better
232          to add it as an attachment instead of just putting
233          it in the body.
234
235          The handling in the old parser was:
236
237          if (s && strcmp (s, "inline"))
238            not_inline_text = 1;
239        */
240       if (ctx->body_seen)
241         {
242           /* Some MUA's like kontact e3.5 send the body as
243              an inline text attachment. So if we have not
244              seen the body yet we treat the first text/plain
245              element as the body and not as an inline attachment. */
246           is_text_attachment = 1;
247         }
248       rfc822parse_release_field (field);
249     }
250
251   /* Process the Content-type and all its parameters.  */
252   ctmain = ctsub = NULL;
253   field = rfc822parse_parse_field (msg, "Content-Type", -1);
254   if (field)
255     ctmain = rfc822parse_query_media_type (field, &ctsub);
256   if (!ctmain)
257     {
258       /* Either there is no content type field or it is faulty; in
259          both cases we fall back to text/plain.  */
260       ctmain = "text";
261       ctsub  = "plain";
262     }
263
264   log_data ("%s:%s: ctx=%p, ct=`%s/%s'\n",
265                    SRCNAME, __func__, ctx, ctmain, ctsub);
266
267   s = rfc822parse_query_parameter (field, "charset", 0);
268   if (s)
269     charset = xstrdup (s);
270
271   if (!filename)
272     {
273       /* Check for Content-Type name if Content-Disposition filename
274          was not found */
275       s = rfc822parse_query_parameter (field, "name", 0);
276       if (s)
277         filename = rfc2047_parse (s);
278     }
279
280   /* Parse a Content Id header */
281   if (!ignore_cid)
282     {
283       p = rfc822parse_get_field (msg, "Content-Id", -1, &off);
284       if (p)
285         {
286            cid = xstrdup (p+off);
287            xfree (p);
288         }
289     }
290   /* Update our idea of the entire MIME structure.  */
291   {
292     mimestruct_item_t ms;
293
294     ms = (mimestruct_item_t) xmalloc (sizeof *ms + strlen (ctmain) + 1 + strlen (ctsub));
295     ctx->mimestruct_cur = ms;
296     *ctx->mimestruct_tail = ms;
297     ctx->mimestruct_tail = &ms->next;
298     ms->next = NULL;
299     strcpy (stpcpy (stpcpy (ms->content_type, ctmain), "/"), ctsub);
300     ms->level = ctx->nesting_level;
301     ms->filename = filename;
302     ms->cid = cid;
303     filename = NULL;
304     ms->charset = charset;
305     charset = NULL;
306   }
307
308   if (!strcmp (ctmain, "multipart"))
309     {
310       /* We don't care about the top level multipart layer but wait
311          until it comes to the actual parts which then will get stored
312          as attachments.
313
314          For now encapsulated signed or encrypted containers are not
315          processed in a special way as they should.  Except for the
316          simple verify mode. */
317       if (!provider->signature()
318           && !strcmp (ctsub, "signed")
319           && (s = rfc822parse_query_parameter (field, "protocol", 0)))
320         {
321           if (!strcmp (s, "application/pgp-signature"))
322             ctx->protocol = PROTOCOL_OPENPGP;
323           else if (!strcmp (s, "application/pkcs7-signature")
324                    || !strcmp (s, "application/x-pkcs7-signature"))
325             ctx->protocol = PROTOCOL_SMIME;
326           else
327             ctx->protocol = PROTOCOL_UNKNOWN;
328
329           /* Need to start the hashing after the next boundary. */
330           ctx->start_hashing = 1;
331         }
332       else if (!strcmp (ctsub, "encrypted") &&
333                (s = rfc822parse_query_parameter (field, "protocol", 0)))
334         {
335            if (!strcmp (s, "application/pgp-encrypted"))
336              ctx->protocol = PROTOCOL_OPENPGP;
337            /* We expect an encrypted mime part. */
338            ctx->is_encrypted = 1;
339         }
340     }
341   else if (!strcmp (ctmain, "text"))
342     {
343       is_text = !strcmp (ctsub, "html")? 2:1;
344     }
345   else if (ctx->nesting_level == 1 && !provider->signature()
346            && !strcmp (ctmain, "application")
347            && ((ctx->protocol == PROTOCOL_OPENPGP
348                 && !strcmp (ctsub, "pgp-signature"))
349                || (ctx->protocol == PROTOCOL_SMIME
350                    && (!strcmp (ctsub, "pkcs7-signature")
351                        || !strcmp (ctsub, "x-pkcs7-signature")))))
352     {
353       /* This is the second part of a MOSS signature.  We only support
354          here full messages thus checking the nesting level is
355          sufficient.  We do this only for the first signature (i.e. if
356          sig_data has not been set yet).  We also do this only while
357          in verify mode because we don't want to write a full MUA.  */
358       ctx->collect_signature = 1;
359       log_data ("%s:%s: Collecting signature.",
360                        SRCNAME, __func__);
361     }
362   else if (ctx->nesting_level == 1 && ctx->is_encrypted
363            && !strcmp (ctmain, "application")
364            && (ctx->protocol == PROTOCOL_OPENPGP
365                && !strcmp (ctsub, "octet-stream")))
366     {
367       log_data ("%s:%s: Collecting encrypted PGP data.",
368                        SRCNAME, __func__);
369       ctx->collect_crypto_data = 1;
370     }
371   else /* Other type. */
372     {
373       /* Check whether this attachment is an opaque signed S/MIME
374          part.  We use a counter to later check that there is only one
375          such part. */
376       if (!strcmp (ctmain, "application")
377           && (!strcmp (ctsub, "pkcs7-mime")
378               || !strcmp (ctsub, "x-pkcs7-mime")))
379         {
380           log_data ("%s:%s: Collecting crypted S/MIME data.",
381                            SRCNAME, __func__);
382           ctx->collect_crypto_data = 1;
383         }
384     }
385   rfc822parse_release_field (field); /* (Content-type) */
386   ctx->in_data = 1;
387
388   log_data ("%s:%s: this body: nesting=%d partno=%d is_text=%d"
389                    " charset=\"%s\"\n body_seen=%d is_text_attachment=%d",
390                    SRCNAME, __func__,
391                    ctx->nesting_level, ctx->part_counter, is_text,
392                    ctx->mimestruct_cur->charset?ctx->mimestruct_cur->charset:"",
393                    ctx->body_seen, is_text_attachment);
394
395   /* If this is a text part, decide whether we treat it as one
396      of our bodies.
397      */
398   if ((is_text && !is_text_attachment))
399     {
400       if (is_text == 2)
401         {
402           ctx->body_seen = 2;
403           ctx->collect_html_body = 1;
404           ctx->collect_body = 0;
405           log_debug ("%s:%s: Collecting HTML body.",
406                      SRCNAME, __func__);
407           /* We need this crutch because of one liner html
408              mails which would not be collected by the line
409              collector if they dont have a linefeed at the
410              end. */
411           provider->set_has_html_body (true);
412         }
413       else
414         {
415           log_debug ("%s:%s: Collecting text body.",
416                      SRCNAME, __func__);
417           ctx->body_seen = 1;
418           ctx->collect_body = 1;
419           ctx->collect_html_body = 0;
420         }
421     }
422   else if (!ctx->collect_crypto_data && ctx->nesting_level >= 1)
423     {
424       /* Treat it as an attachment.  */
425       ctx->current_attachment = provider->create_attachment();
426       ctx->collect_body = 0;
427       ctx->collect_html_body = 0;
428       log_data ("%s:%s: Collecting attachment.",
429                        SRCNAME, __func__);
430     }
431
432   TRETURN 0;
433 }
434
435 static int
436 message_cb (void *opaque, rfc822parse_event_t event,
437             rfc822parse_t msg)
438 {
439   int retval = 0;
440
441   MimeDataProvider *provider = static_cast<MimeDataProvider*> (opaque);
442
443   mime_context_t ctx = provider->mime_context();
444
445   debug_message_event (event);
446
447   if (event == RFC822PARSE_BEGIN_HEADER || event == RFC822PARSE_T2BODY)
448     {
449       /* We need to check here whether to start collecting signed data
450          because attachments might come without header lines and thus
451          we won't see the BEGIN_HEADER event. */
452       if (ctx->start_hashing == 1)
453         {
454           ctx->start_hashing = 2;
455           ctx->hashing_level = ctx->nesting_level;
456           ctx->collect_crypto_data = 1;
457         }
458     }
459
460
461   switch (event)
462     {
463     case RFC822PARSE_T2BODY:
464       retval = t2body (provider, msg);
465       break;
466
467     case RFC822PARSE_LEVEL_DOWN:
468       ctx->nesting_level++;
469       break;
470
471     case RFC822PARSE_LEVEL_UP:
472       if (ctx->nesting_level)
473         ctx->nesting_level--;
474       else
475         {
476           log_error ("%s: ctx=%p, invalid structure: bad nesting level\n",
477                      SRCNAME, ctx);
478           ctx->parser_error = gpg_error (GPG_ERR_GENERAL);
479         }
480       break;
481
482     case RFC822PARSE_BOUNDARY:
483     case RFC822PARSE_LAST_BOUNDARY:
484       ctx->any_boundary = 1;
485       ctx->in_data = 0;
486       ctx->collect_body = 0;
487
488       if (ctx->start_hashing == 2 && ctx->hashing_level == ctx->nesting_level)
489         {
490           ctx->start_hashing = 3; /* Avoid triggering it again. */
491           ctx->collect_crypto_data = 0;
492         }
493       break;
494
495     case RFC822PARSE_BEGIN_HEADER:
496       ctx->part_counter++;
497       break;
498
499     default:  /* Ignore all other events. */
500       break;
501     }
502
503   return retval;
504 }
505
506 MimeDataProvider::MimeDataProvider(bool no_headers) :
507   m_signature(nullptr),
508   m_has_html_body(false),
509   m_collect_everything(no_headers)
510 {
511   TSTART;
512   memdbg_ctor ("MimeDataProvider");
513   m_mime_ctx = (mime_context_t) xcalloc (1, sizeof *m_mime_ctx);
514   m_mime_ctx->msg = rfc822parse_open (message_cb, this);
515   m_mime_ctx->mimestruct_tail = &m_mime_ctx->mimestruct;
516   TRETURN;
517 }
518
519 #ifdef HAVE_W32_SYSTEM
520 MimeDataProvider::MimeDataProvider(LPSTREAM stream, bool no_headers):
521   MimeDataProvider(no_headers)
522 {
523   TSTART;
524   if (stream)
525     {
526       stream->AddRef ();
527       memdbg_addRef (stream);
528     }
529   else
530     {
531       log_error ("%s:%s called without stream ", SRCNAME, __func__);
532       TRETURN;
533     }
534   log_data ("%s:%s Collecting data.", SRCNAME, __func__);
535   collect_data (stream);
536   log_data ("%s:%s Data collected.", SRCNAME, __func__);
537   gpgol_release (stream);
538   TRETURN;
539 }
540 #endif
541
542 MimeDataProvider::MimeDataProvider(FILE *stream, bool no_headers):
543   MimeDataProvider(no_headers)
544 {
545   TSTART;
546   log_data ("%s:%s Collecting data from file.", SRCNAME, __func__);
547   collect_data (stream);
548   log_data ("%s:%s Data collected.", SRCNAME, __func__);
549   TRETURN;
550 }
551
552 MimeDataProvider::~MimeDataProvider()
553 {
554   TSTART;
555   memdbg_dtor ("MimeDataProvider");
556   log_debug ("%s:%s", SRCNAME, __func__);
557   while (m_mime_ctx->mimestruct)
558     {
559       mimestruct_item_t tmp = m_mime_ctx->mimestruct->next;
560       xfree (m_mime_ctx->mimestruct->filename);
561       xfree (m_mime_ctx->mimestruct->charset);
562       xfree (m_mime_ctx->mimestruct->cid);
563       xfree (m_mime_ctx->mimestruct);
564       m_mime_ctx->mimestruct = tmp;
565     }
566   rfc822parse_close (m_mime_ctx->msg);
567   m_mime_ctx->current_attachment = NULL;
568   xfree (m_mime_ctx);
569   if (m_signature)
570     {
571       delete m_signature;
572     }
573   TRETURN;
574 }
575
576 bool
577 MimeDataProvider::isSupported(GpgME::DataProvider::Operation op) const
578 {
579   return op == GpgME::DataProvider::Read ||
580          op == GpgME::DataProvider::Seek ||
581          op == GpgME::DataProvider::Write ||
582          op == GpgME::DataProvider::Release;
583 }
584
585 ssize_t
586 MimeDataProvider::read(void *buffer, size_t size)
587 {
588   TSTART;
589   log_data ("%s:%s: Reading: " SIZE_T_FORMAT "Bytes",
590                  SRCNAME, __func__, size);
591   ssize_t bRead = m_crypto_data.read (buffer, size);
592   if ((opt.enable_debug & DBG_DATA) && bRead)
593     {
594       std::string buf ((char *)buffer, bRead);
595
596       if (!is_binary (buf))
597         {
598           log_data ("%s:%s: Data: \n------\n%s\n------",
599                            SRCNAME, __func__, buf.c_str());
600         }
601       else
602         {
603           log_data ("%s:%s: Hex Data: \n------\n%s\n------",
604                            SRCNAME, __func__,
605                            string_to_hex (buf).c_str ());
606         }
607     }
608   TRETURN bRead;
609 }
610
611 /* Split some raw data into lines and handle them accordingly.
612    Returns the amount of bytes not taken from the input buffer.
613 */
614 size_t
615 MimeDataProvider::collect_input_lines(const char *input, size_t insize)
616 {
617   TSTART;
618   char linebuf[LINEBUFSIZE];
619   const char *s = input;
620   size_t pos = 0;
621   size_t nleft = insize;
622   size_t not_taken = nleft;
623   size_t len = 0;
624
625   /* Split the raw data into lines */
626   for (; nleft; nleft--, s++)
627     {
628       if (pos >= LINEBUFSIZE)
629         {
630           log_error ("%s:%s: rfc822 parser failed: line too long\n",
631                      SRCNAME, __func__);
632           GpgME::Error::setSystemError (GPG_ERR_EIO);
633           TRETURN not_taken;
634         }
635       if (*s != '\n')
636         linebuf[pos++] = *s;
637       else
638         {
639           /* Got a complete line.  Remove the last CR.  */
640           not_taken -= pos + 1; /* Pos starts at 0 so + 1 for it */
641           if (pos && linebuf[pos-1] == '\r')
642             {
643               pos--;
644             }
645
646           log_data ("%s:%s: Parsing line=`%.*s'\n",
647                          SRCNAME, __func__, (int)pos, linebuf);
648           /* Check the next state */
649           if (rfc822parse_insert (m_mime_ctx->msg,
650                                   (unsigned char*) linebuf,
651                                   pos))
652             {
653               log_error ("%s:%s: rfc822 parser failed: %s\n",
654                          SRCNAME, __func__, strerror (errno));
655               TRETURN not_taken;
656             }
657
658           /* Check if the first line of the body is actually
659              a PGP Inline message. If so treat it as crypto data. */
660           if (!m_mime_ctx->pgp_marker_checked && m_mime_ctx->collect_body == 2)
661             {
662               m_mime_ctx->pgp_marker_checked = true;
663               if (pos >= 27 && !strncmp ("-----BEGIN PGP MESSAGE-----", linebuf, 27))
664                 {
665                   log_debug ("%s:%s: Found PGP Message in body.",
666                              SRCNAME, __func__);
667                   m_mime_ctx->collect_body = 0;
668                   m_mime_ctx->collect_crypto_data = 1;
669                   m_mime_ctx->start_hashing = 1;
670                   m_collect_everything = true;
671                 }
672             }
673
674           /* If we are currently in a collecting state actually
675              collect that line */
676           if (m_mime_ctx->collect_crypto_data && m_mime_ctx->start_hashing)
677             {
678               /* Save the signed data.  Note that we need to delay
679                  the CR/LF because the last line ending belongs to the
680                  next boundary. */
681               if (m_mime_ctx->collect_crypto_data == 2)
682                 {
683                   m_crypto_data.write ("\r\n", 2);
684                 }
685               log_data ("Writing raw crypto data: %.*s",
686                                (int)pos, linebuf);
687               m_crypto_data.write (linebuf, pos);
688               m_mime_ctx->collect_crypto_data = 2;
689             }
690           if (m_mime_ctx->in_data && !m_mime_ctx->collect_signature &&
691               !m_mime_ctx->collect_crypto_data)
692             {
693               /* We are inside of an attachment part.  Write it out. */
694               if (m_mime_ctx->in_data == 1)  /* Skip the first line. */
695                 m_mime_ctx->in_data = 2;
696
697               int slbrk = 0;
698               if (m_mime_ctx->is_qp_encoded)
699                 len = qp_decode (linebuf, pos, &slbrk);
700               else if (m_mime_ctx->is_base64_encoded)
701                 len = b64_decode (&m_mime_ctx->base64, linebuf, pos);
702               else
703                 len = pos;
704
705               if (m_mime_ctx->collect_body)
706                 {
707                   if (m_mime_ctx->collect_body == 2)
708                     {
709                       m_body += std::string(linebuf, len);
710                       if (!m_mime_ctx->is_base64_encoded && !slbrk)
711                         {
712                           m_body += "\r\n";
713                         }
714                     }
715                   if (m_body_charset.empty())
716                     {
717                       m_body_charset = m_mime_ctx->mimestruct_cur->charset ?
718                                        m_mime_ctx->mimestruct_cur->charset : "";
719                     }
720                   m_mime_ctx->collect_body = 2;
721                 }
722               else if (m_mime_ctx->collect_html_body)
723                 {
724                   if (m_mime_ctx->collect_html_body == 2)
725                     {
726                       m_html_body += std::string(linebuf, len);
727                       if (!m_mime_ctx->is_base64_encoded && !slbrk)
728                         {
729                           m_html_body += "\r\n";
730                         }
731                     }
732                   if (m_html_charset.empty())
733                     {
734                       m_html_charset = m_mime_ctx->mimestruct_cur->charset ?
735                                        m_mime_ctx->mimestruct_cur->charset : "";
736                     }
737                   m_mime_ctx->collect_html_body = 2;
738                 }
739               else if (m_mime_ctx->current_attachment && len)
740                 {
741                   m_mime_ctx->current_attachment->get_data().write(linebuf, len);
742                   if (!m_mime_ctx->is_base64_encoded && !slbrk)
743                     {
744                       m_mime_ctx->current_attachment->get_data().write("\r\n", 2);
745                     }
746                 }
747               else
748                 {
749                   log_data ("%s:%s Collecting ended / failed.",
750                                    SRCNAME, __func__);
751                 }
752             }
753           else if (m_mime_ctx->in_data && m_mime_ctx->collect_signature)
754             {
755               /* We are inside of a signature attachment part.  */
756               if (m_mime_ctx->collect_signature == 1)  /* Skip the first line. */
757                 m_mime_ctx->collect_signature = 2;
758               else
759                 {
760                   int slbrk = 0;
761
762                   if (m_mime_ctx->is_qp_encoded)
763                     len = qp_decode (linebuf, pos, &slbrk);
764                   else if (m_mime_ctx->is_base64_encoded)
765                     len = b64_decode (&m_mime_ctx->base64, linebuf, pos);
766                   else
767                     len = pos;
768                   if (!m_signature)
769                     {
770                       m_signature = new GpgME::Data();
771                     }
772                   if (len)
773                     m_signature->write(linebuf, len);
774                   if (!m_mime_ctx->is_base64_encoded && !slbrk)
775                     m_signature->write("\r\n", 2);
776                 }
777             }
778           else if (m_mime_ctx->in_data && !m_mime_ctx->start_hashing)
779             {
780               /* We are inside the data.  That should be the actual
781                  ciphertext in the given encoding. */
782               int slbrk = 0;
783
784               if (m_mime_ctx->is_qp_encoded)
785                 len = qp_decode (linebuf, pos, &slbrk);
786               else if (m_mime_ctx->is_base64_encoded)
787                 len = b64_decode (&m_mime_ctx->base64, linebuf, pos);
788               else
789                 len = pos;
790               log_debug ("Writing crypto data: %.*s",
791                          (int)pos, linebuf);
792               if (len)
793                 m_crypto_data.write(linebuf, len);
794               if (!m_mime_ctx->is_base64_encoded && !slbrk)
795                 m_crypto_data.write("\r\n", 2);
796             }
797           /* Continue with next line. */
798           pos = 0;
799         }
800     }
801   TRETURN not_taken;
802 }
803
804 #ifdef HAVE_W32_SYSTEM
805 void
806 MimeDataProvider::collect_data(LPSTREAM stream)
807 {
808   TSTART;
809   if (!stream)
810     {
811       TRETURN;
812     }
813   HRESULT hr;
814   char buf[BUFSIZE];
815   ULONG bRead;
816   bool first_read = true;
817   bool is_pgp_message = false;
818   size_t allRead = 0;
819   while ((hr = stream->Read (buf, BUFSIZE, &bRead)) == S_OK ||
820          hr == S_FALSE)
821     {
822       if (!bRead)
823         {
824           log_data ("%s:%s: Input stream at EOF.",
825                            SRCNAME, __func__);
826           break;
827         }
828       log_data ("%s:%s: Read %lu bytes.",
829                        SRCNAME, __func__, bRead);
830       allRead += bRead;
831       if (first_read)
832         {
833           if (bRead > 12 && strncmp ("MIME-Version", buf, 12) == 0)
834             {
835               /* Fun! In case we have exchange or sent messages created by us
836                  we get the mail attachment like it is before the MAPI to MIME
837                  conversion. So it has our MIME structure. In that case
838                  we have to expect MIME data even if the initial data check
839                  suggests that we don't.
840
841                  Checking if the content starts with MIME-Version appears
842                  to be a robust way to check if we try to parse MIME data. */
843               m_collect_everything = false;
844               log_debug ("%s:%s: Found MIME-Version marker."
845                          "Expecting headers even if type suggested not to.",
846                          SRCNAME, __func__);
847
848             }
849           else if (bRead > 12 && !strncmp ("Content-Type:", buf, 13))
850             {
851               /* Similar as above but we messed with the order of the headers
852                  for some s/mime mails. So also check for content type.
853
854                  Want some cheese with that hack?
855               */
856               m_collect_everything = false;
857               log_debug ("%s:%s: Found Content-Type header."
858                          "Expecting headers even if type suggested not to.",
859                          SRCNAME, __func__);
860
861             }
862           /* check for the PGP MESSAGE marker to see if we have it. */
863           if (bRead && m_collect_everything)
864             {
865               std::string tmp (buf, bRead);
866               std::size_t found = tmp.find ("-----BEGIN PGP MESSAGE-----");
867               if (found != std::string::npos)
868                 {
869                   log_debug ("%s:%s: found PGP Message marker,",
870                              SRCNAME, __func__);
871                   is_pgp_message = true;
872                 }
873             }
874         }
875       first_read = false;
876
877       if (m_collect_everything)
878         {
879           /* For S/MIME, Clearsigned, PGP MESSAGES we just pass everything
880              on. Only the Multipart classes need parsing. And the output
881              of course. */
882           log_data ("%s:%s: Just copying data.",
883                            SRCNAME, __func__);
884           m_crypto_data.write ((void*)buf, (size_t) bRead);
885           continue;
886         }
887       m_rawbuf += std::string (buf, bRead);
888       size_t not_taken = collect_input_lines (m_rawbuf.c_str(),
889                                               m_rawbuf.size());
890
891       if (not_taken == m_rawbuf.size())
892         {
893           log_error ("%s:%s: Collect failed to consume anything.\n"
894                      "Buffer too small?",
895                      SRCNAME, __func__);
896           break;
897         }
898       log_data ("%s:%s: Consumed: " SIZE_T_FORMAT " bytes",
899                        SRCNAME, __func__, m_rawbuf.size() - not_taken);
900       m_rawbuf.erase (0, m_rawbuf.size() - not_taken);
901     }
902
903
904   if (is_pgp_message && allRead < (1024 * 100))
905     {
906       /* Sometimes received PGP Messsages contain extra whitespace /
907          newlines. To also accept such messages we fix up pgp inline
908          messages here. We only do this for messages which are smaller
909          then a hundred KByte for performance. */
910       log_debug ("%s:%s: Fixing up a possible broken message.",
911                  SRCNAME, __func__);
912       /* Copy crypto data to string */
913       std::string data = m_crypto_data.toString();
914       m_crypto_data = GpgME::Data();
915       std::istringstream iss (data);
916       // Now parse it by line.
917       std::string line;
918       while (std::getline (iss, line))
919         {
920           trim (line);
921           if (line == "-----BEGIN PGP MESSAGE-----")
922             {
923               /* Finish an armor header */
924               line += "\n\n";
925               m_crypto_data.write (line.c_str (), line.size ());
926               continue;
927             }
928           /* Remove empty lines */
929           if (line.empty())
930             {
931               continue;
932             }
933           if (line.find (':') != std::string::npos)
934             {
935               log_data ("%s:%s: Removing comment '%s'.",
936                                SRCNAME, __func__, line.c_str ());
937               continue;
938             }
939           line += '\n';
940           m_crypto_data.write (line.c_str (), line.size ());
941         }
942     }
943   TRETURN;
944 }
945 #endif
946
947 void
948 MimeDataProvider::collect_data(FILE *stream)
949 {
950   TSTART;
951   if (!stream)
952     {
953       TRETURN;
954     }
955   char buf[BUFSIZE];
956   size_t bRead;
957   while ((bRead = fread (buf, 1, BUFSIZE, stream)) > 0)
958     {
959       log_data ("%s:%s: Read " SIZE_T_FORMAT " bytes.",
960                        SRCNAME, __func__, bRead);
961
962       if (m_collect_everything)
963         {
964           /* For S/MIME, Clearsigned, PGP MESSAGES we just pass everything
965              on. Only the Multipart classes need parsing. And the output
966              of course. */
967           log_data ("%s:%s: Making verbatim copy" SIZE_T_FORMAT " bytes.",
968                            SRCNAME, __func__, bRead);
969           m_crypto_data.write ((void*)buf, bRead);
970           continue;
971         }
972       m_rawbuf += std::string (buf, bRead);
973       size_t not_taken = collect_input_lines (m_rawbuf.c_str(),
974                                               m_rawbuf.size());
975
976       if (not_taken == m_rawbuf.size())
977         {
978           log_error ("%s:%s: Collect failed to consume anything.\n"
979                      "Buffer too small?",
980                      SRCNAME, __func__);
981           TRETURN;
982         }
983       log_data ("%s:%s: Consumed: " SIZE_T_FORMAT " bytes",
984                        SRCNAME, __func__, m_rawbuf.size() - not_taken);
985       m_rawbuf.erase (0, m_rawbuf.size() - not_taken);
986     }
987   TRETURN;
988 }
989
990 ssize_t MimeDataProvider::write(const void *buffer, size_t bufSize)
991 {
992   TSTART;
993   if (m_collect_everything)
994     {
995       /* Writing with collect everything one means that we are outputprovider.
996          In this case for inline messages we want to collect everything. */
997       log_data ("%s:%s: Using complete input as body " SIZE_T_FORMAT " bytes.",
998                        SRCNAME, __func__, bufSize);
999       m_body += std::string ((const char *) buffer, bufSize);
1000       TRETURN bufSize;
1001     }
1002   m_rawbuf += std::string ((const char*)buffer, bufSize);
1003   size_t not_taken = collect_input_lines (m_rawbuf.c_str(),
1004                                           m_rawbuf.size());
1005
1006   if (not_taken == m_rawbuf.size())
1007     {
1008       log_error ("%s:%s: Write failed to consume anything.\n"
1009                  "Buffer too small? or no newlines in text?",
1010                  SRCNAME, __func__);
1011       TRETURN bufSize;
1012     }
1013   log_data ("%s:%s: Write Consumed: " SIZE_T_FORMAT " bytes",
1014                    SRCNAME, __func__, m_rawbuf.size() - not_taken);
1015   m_rawbuf.erase (0, m_rawbuf.size() - not_taken);
1016   TRETURN bufSize;
1017 }
1018
1019 off_t
1020 MimeDataProvider::seek(off_t offset, int whence)
1021 {
1022   return m_crypto_data.seek (offset, whence);
1023 }
1024
1025 GpgME::Data *
1026 MimeDataProvider::signature() const
1027 {
1028   TSTART;
1029   TRETURN m_signature;
1030 }
1031
1032 std::shared_ptr<Attachment>
1033 MimeDataProvider::create_attachment()
1034 {
1035   TSTART;
1036   log_data ("%s:%s: Creating attachment.",
1037                    SRCNAME, __func__);
1038
1039   auto attach = std::shared_ptr<Attachment> (new Attachment());
1040   attach->set_attach_type (ATTACHTYPE_FROMMOSS);
1041   m_mime_ctx->any_attachments_created = 1;
1042
1043   /* And now for the real name.  We avoid storing the name "smime.p7m"
1044      because that one is used at several places in the mapi conversion
1045      functions.  */
1046   if (m_mime_ctx->mimestruct_cur && m_mime_ctx->mimestruct_cur->filename)
1047     {
1048       if (!strcmp (m_mime_ctx->mimestruct_cur->filename, "smime.p7m"))
1049         {
1050           attach->set_display_name ("x-smime.p7m");
1051         }
1052       else
1053         {
1054           log_data ("%s:%s: Attachment filename: %s",
1055                            SRCNAME, __func__, m_mime_ctx->mimestruct_cur->filename);
1056           attach->set_display_name (m_mime_ctx->mimestruct_cur->filename);
1057         }
1058     }
1059   if (m_mime_ctx->mimestruct_cur && m_mime_ctx->mimestruct_cur->cid)
1060     {
1061       attach->set_content_id (m_mime_ctx->mimestruct_cur->cid);
1062     }
1063   m_attachments.push_back (attach);
1064
1065   TRETURN attach;
1066   /* TODO handle encoding */
1067 }
1068
1069 void MimeDataProvider::finalize ()
1070 {
1071   TSTART;
1072   if (m_rawbuf.size ())
1073     {
1074       m_rawbuf += "\r\n";
1075       size_t not_taken = collect_input_lines (m_rawbuf.c_str(),
1076                                               m_rawbuf.size());
1077       m_rawbuf.erase (0, m_rawbuf.size() - not_taken);
1078       if (m_rawbuf.size ())
1079         {
1080           log_error ("%s:%s: Collect left data in buffer.\n",
1081                      SRCNAME, __func__);
1082         }
1083     }
1084   TRETURN;
1085 }
1086
1087 const std::string &MimeDataProvider::get_body ()
1088 {
1089   TSTART;
1090   TRETURN m_body;
1091 }
1092
1093 const std::string &MimeDataProvider::get_html_body ()
1094 {
1095   TSTART;
1096   TRETURN m_html_body;
1097 }
1098
1099 const std::string &MimeDataProvider::get_html_charset() const
1100 {
1101   TSTART;
1102   TRETURN m_html_charset;
1103 }
1104
1105 const std::string &MimeDataProvider::get_body_charset() const
1106 {
1107   TSTART;
1108   TRETURN m_body_charset;
1109 }