[gmime: 12/14] Save (munged) From lines at the start of message/rfc822 parts



commit c763403773035b56bb1f32bfc5dc9bf56b0af580
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Fri Mar 31 08:53:24 2017 -0400

    Save (munged) From lines at the start of message/rfc822 parts

 gmime/gmime-message-part.c |   39 +++++++++++++++++++++++++++++++--
 gmime/gmime-message.c      |    1 +
 gmime/gmime-message.h      |    1 +
 gmime/gmime-parser.c       |   50 ++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 82 insertions(+), 9 deletions(-)
---
diff --git a/gmime/gmime-message-part.c b/gmime/gmime-message-part.c
index 53a5fa2..38ce5b7 100644
--- a/gmime/gmime-message-part.c
+++ b/gmime/gmime-message-part.c
@@ -113,7 +113,13 @@ static ssize_t
 message_part_write_to_stream (GMimeObject *object, GMimeFormatOptions *options, gboolean content_only, 
GMimeStream *stream)
 {
        GMimeMessagePart *part = (GMimeMessagePart *) object;
+       GMimeMessage *message = part->message;
        ssize_t nwritten, total = 0;
+       const char *newline, *eoln;
+       gboolean match;
+       size_t len;
+       
+       newline = g_mime_format_options_get_newline (options);
        
        if (!content_only) {
                /* write the content headers */
@@ -123,15 +129,42 @@ message_part_write_to_stream (GMimeObject *object, GMimeFormatOptions *options,
                total += nwritten;
                
                /* terminate the headers */
-               if ((nwritten = g_mime_stream_write (stream, "\n", 1)) == -1)
+               if ((nwritten = g_mime_stream_write_string (stream, newline)) == -1)
                        return -1;
                
                total += nwritten;
        }
        
        /* write the message */
-       if (part->message) {
-               if ((nwritten = g_mime_object_write_to_stream ((GMimeObject *) part->message, options, 
stream)) == -1)
+       if (message) {
+               if (message->marker && (len = strlen (message->marker)) > 0) {
+                       if (*(eoln = message->marker + (len - 1)) == '\n') {
+                               if (eoln > message->marker && eoln[-1] == '\r')
+                                       eoln--;
+                               
+                               /* check if newline sequences match... */
+                               if (!(match = !strcmp (eoln, newline))) {
+                                       /* they don't match... trim off the eoln sequence */
+                                       len = (size_t) (eoln - message->marker);
+                               }
+                       } else {
+                               match = FALSE;
+                       }
+                       
+                       if ((nwritten = g_mime_stream_write (stream, message->marker, len)) == -1)
+                               return -1;
+                       
+                       total += nwritten;
+                       
+                       if (!match) {
+                               if ((nwritten = g_mime_stream_write_string (stream, newline)) == -1)
+                                       return -1;
+                               
+                               total += nwritten;
+                       }
+               }
+               
+               if ((nwritten = g_mime_object_write_to_stream ((GMimeObject *) message, options, stream)) == 
-1)
                        return -1;
                
                total += nwritten;
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index 1e035d7..639f4fe 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -221,6 +221,7 @@ g_mime_message_finalize (GObject *object)
        g_free (message->addrlists);
        g_free (message->message_id);
        g_free (message->subject);
+       g_free (message->marker);
        
        if (message->date)
                g_date_time_unref (message->date);
diff --git a/gmime/gmime-message.h b/gmime/gmime-message.h
index f1ab970..5a2a918 100644
--- a/gmime/gmime-message.h
+++ b/gmime/gmime-message.h
@@ -87,6 +87,7 @@ struct _GMimeMessage {
        
        /* < private > */
        GMimeRfcComplianceMode compliance;
+       char *marker;
 };
 
 struct _GMimeMessageClass {
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index 66e5548..2313cc2 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -166,6 +166,8 @@ struct _GMimeParserPrivate {
        GByteArray *marker;
        gint64 marker_offset;
        
+       char *preheader;
+       
        /* current message headerblock offsets */
        gint64 message_headers_begin;
        gint64 message_headers_end;
@@ -282,6 +284,9 @@ parser_free_headers (struct _GMimeParserPrivate *priv)
        Header *header;
        guint i;
        
+       g_free (priv->preheader);
+       priv->preheader = NULL;
+       
        for (i = 0; i < priv->headers->len; i++) {
                header = priv->headers->pdata[i];
                
@@ -382,6 +387,8 @@ parser_init (GMimeParser *parser, GMimeStream *stream)
        priv->marker = g_byte_array_new ();
        priv->marker_offset = -1;
        
+       priv->preheader = NULL;
+       
        priv->headers = g_ptr_array_new ();
        
        priv->headerbuf = g_malloc (HEADER_INIT_SIZE);
@@ -751,6 +758,17 @@ g_mime_parser_eos (GMimeParser *parser)
        return g_mime_stream_eos (priv->stream) && priv->inptr == priv->inend;
 }
 
+static gboolean
+is_mbox_marker (const char *inptr, size_t len, gboolean allow_munged)
+{
+       if (allow_munged && *inptr == '>') {
+               inptr++;
+               len--;
+       }
+       
+       return len >= 5 && !strncmp ("From ", inptr, 5);
+}
+
 static int
 parser_step_marker (GMimeParser *parser, const char *marker, size_t marker_len)
 {
@@ -855,13 +873,27 @@ static void
 header_parse (GMimeParser *parser)
 {
        struct _GMimeParserPrivate *priv = parser->priv;
+       gboolean valid = TRUE, blank = FALSE;
        register char *inptr;
        Header *header;
        
        *priv->headerptr = ':';
        inptr = priv->headerbuf;
-       while (*inptr != ':')
+       
+       while (*inptr != ':') {
+               /* Note: blank spaces are allowed between the field name
+                * and the ':', but field names themselves are not allowed
+                * to contain spaces (or control characters). */
+               if (is_blank (*inptr)) {
+                       blank = TRUE;
+               } else if (blank || is_ctrl (*inptr)) {
+                       valid = FALSE;
+                       break;
+               }
+               
                inptr++;
+       }
+       
        *priv->headerptr = '\0';
        
        if (*inptr != ':') {
@@ -870,6 +902,9 @@ header_parse (GMimeParser *parser)
                             (long long) priv->header_offset,
                             priv->headerbuf));
                
+               if (priv->preheader == NULL)
+                       priv->preheader = g_strdup (priv->headerbuf);
+               
                priv->headerleft += priv->headerptr - priv->headerbuf;
                priv->headerptr = priv->headerbuf;
                return;
@@ -1000,7 +1035,7 @@ parser_step_headers (GMimeParser *parser)
                                        while (*inptr != ':') {
                                                /* Note: blank spaces are allowed between the field name
                                                 * and the ':', but field names themselves are not allowed
-                                                * to contain spaces. */
+                                                * to contain spaces (or control characters). */
                                                if (is_blank (*inptr)) {
                                                        blank = TRUE;
                                                } else if (blank || is_ctrl (*inptr)) {
@@ -1025,8 +1060,8 @@ parser_step_headers (GMimeParser *parser)
                                }
                                
                                if (!valid) {
-                                       if (priv->format == GMIME_FORMAT_MBOX && (inptr - start) >= 5
-                                           && !strncmp (start, "From ", 5))
+                                       if (priv->format == GMIME_FORMAT_MBOX &&
+                                           is_mbox_marker (start, (size_t) (inptr - start), FALSE))
                                                goto next_message;
                                        
                                        if (priv->headers->len > 0) {
@@ -1045,8 +1080,9 @@ parser_step_headers (GMimeParser *parser)
                                                }
                                        } else if (priv->state == GMIME_PARSER_STATE_MESSAGE_HEADERS) {
                                                /* Be a little more strict when scanning toplevel message
-                                                * headers, but remain lenient with From-lines. */
-                                               if ((inptr - start) < 5 || strncmp (start, "From ", 5) != 0) {
+                                                * headers, but remain lenient with lines starting with
+                                                * "From " or ">From ". */
+                                               if (!is_mbox_marker (start, (size_t) (inptr - start), TRUE)) {
                                                        priv->state = GMIME_PARSER_STATE_ERROR;
                                                        return -1;
                                                }
@@ -1628,6 +1664,8 @@ parser_scan_message_part (GMimeParser *parser, GMimeParserOptions *options, GMim
        
        message = g_mime_message_new (FALSE);
        message->compliance = GMIME_RFC_COMPLIANCE_LOOSE;
+       message->marker = priv->preheader;
+       priv->preheader = NULL;
        
        for (i = 0; i < priv->headers->len; i++) {
                header = priv->headers->pdata[i];


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]