SF.net SVN: mahogany:[7541] trunk/M

[email protected] Thu, 07 Aug 2008 23:57:46 +0000
Newsgroups gmane.mail.mahogany.cvs
Message-ID <[email protected]>
Revision: 7541
          http://mahogany.svn.sourceforge.net/mahogany/?rev=7541&view=rev
Author:   vadz
Date:     2008-08-07 23:57:45 +0000 (Thu, 07 Aug 2008)

Log Message:
-----------
encode 7 bit data with LF EOLs using CR LF when sending it

Modified Paths:
--------------
    trunk/M/include/strutil.h
    trunk/M/src/mail/SendMessageCC.cpp
    trunk/M/src/util/strutil.cpp

Modified: trunk/M/include/strutil.h
===================================================================
--- trunk/M/include/strutil.h	2008-08-07 23:50:51 UTC (rev 7540)
+++ trunk/M/include/strutil.h	2008-08-07 23:57:45 UTC (rev 7541)
@@ -212,6 +212,16 @@
 
 /** Enforces DOS/RFC822 CR/LF newline convention.
 
+    @param out the output buffer which will contain the text with CR/LF EOLs.
+    @param outLen the length of the output buffer.
+    @param in original string, with any EOLs, it must be NUL-terminated.
+    @return true if ok, false if the output buffer is too small.
+ */
+bool
+strutil_enforceCRLF(unsigned char *out, size_t outLen, const unsigned char *in);
+
+/** Enforces DOS/RFC822 CR/LF newline convention.
+
     @param in string to copy
     @return the DOSified string
 */

Modified: trunk/M/src/mail/SendMessageCC.cpp
===================================================================
--- trunk/M/src/mail/SendMessageCC.cpp	2008-08-07 23:50:51 UTC (rev 7540)
+++ trunk/M/src/mail/SendMessageCC.cpp	2008-08-07 23:57:45 UTC (rev 7541)
@@ -683,34 +683,77 @@
 
 // Check if the given data can be sent without encoding it (using QP or
 // Base64): for this it must not contain 8bit chars nor embedded NUL chars and
-// must not have too long lines
-static bool Is7BitText(const unsigned char *text, size_t len)
+// must not have too long lines.
+//
+// If it can be sent as 7 bit also enforce the CR LF as line end terminators as
+// c-client doesn't apply any transformation to 7 bit data and sending CR (or
+// LF) delimited data violates RFC 2822.
+static bool CanSendAs7BitText(const unsigned char *& text, size_t& len)
 {
    if ( !text )
       return true;
 
-   size_t lenLine = 0;
+   // check if we have 7 bit text and also find out whether we need to correct
+   // EOLs
+   bool isCRLF = true;
+   size_t lenLine = 0,
+          numLines = 0; // actually number of EOLs
    for ( size_t n = 0; n < len; n++ )
    {
-      if ( *text == '\0' )
-         return false;
+      const unsigned char ch = text[n];
 
-      if ( *text == '\n' )
+      switch ( ch )
       {
-         lenLine = 0;
-         text++;
-         continue;
+         case '\0':
+            // text can't have embedded NULs
+            return false;
+
+         case '\r':
+            if ( n < len - 1 && text[n + 1] == '\n' )
+            {
+               lenLine = 0;
+               numLines++;
+               continue;
+            }
+            // fall through
+
+         case '\n':
+            // we get here for '\n's not preceded by '\r's and '\r's not
+            // followed by '\n's
+            lenLine = 0;
+            numLines++;
+            isCRLF = false;
+            continue;
+
+         default:
+            if ( !isascii(ch) )
+               return false;
       }
 
-      if ( !isascii(*text++) )
-         return false;
-
       // the real limit is bigger (~990) but chances are that anything with
       // lines of such length is not plain text
       if ( ++lenLine > 800 )
          return false;
    }
 
+   // it is a 7 bit text but we may need to correct its line endings
+   if ( !isCRLF )
+   {
+      const unsigned char * const textOld = text;
+
+      // we're going to add at most numLines characters for the EOLs and
+      // another one for the trailing NUL
+      len += numLines + sizeof(char);
+      text = (unsigned char *) fs_get(len);
+
+      if ( !strutil_enforceCRLF(text, len, textOld) )
+      {
+         FAIL_MSG( "buffer should have been big enough" );
+      }
+
+      fs_give((void **)&textOld);
+   }
+
    return true;
 }
 
@@ -1320,7 +1363,7 @@
    //            buf is already allocated with malloc() and is NUL-terminated
    //            (this is important of encoding it wouldn't work correctly) we
    //            would be able to avoid it
-   unsigned char * const data = (unsigned char *) fs_get(len + sizeof(char));
+   unsigned char *data = (unsigned char *) fs_get(len + sizeof(char));
    data[len] = '\0';
    memcpy(data, buf, len);
 
@@ -1383,9 +1426,6 @@
    bdy->type = type;
    bdy->subtype = cpystr(subtype.c_str());
 
-   bdy->contents.text.data = data;
-   bdy->contents.text.size = len;
-
    // set the transfer encoding
    switch ( type )
    {
@@ -1400,7 +1440,7 @@
       case TYPETEXT:
          // if the actual message text is in 7 bit, avoid encoding it even if
          // some charset which we would have normally encoded was used
-         if ( Is7BitText(data, len) )
+         if ( CanSendAs7BitText(data, len) )
          {
             bdy->encoding = ENC7BIT;
          }
@@ -1443,9 +1483,13 @@
          break;
 
       default:
-         bdy->encoding = Is7BitText(data, len) ? ENC7BIT : ENCBINARY;
+         bdy->encoding = CanSendAs7BitText(data, len) ? ENC7BIT : ENCBINARY;
    }
 
+   bdy->contents.text.data = data;
+   bdy->contents.text.size = len;
+
+
    PARAMETER *lastpar = NULL,
              *par;
 

Modified: trunk/M/src/util/strutil.cpp
===================================================================
--- trunk/M/src/util/strutil.cpp	2008-08-07 23:50:51 UTC (rev 7540)
+++ trunk/M/src/util/strutil.cpp	2008-08-07 23:57:45 UTC (rev 7541)
@@ -493,6 +493,40 @@
 
 
 
+bool
+strutil_enforceCRLF(char *out, size_t outLen, const char *in)
+{
+   for ( char * const outEnd = out + outLen; out != outEnd; )
+   {
+      switch ( char ch = *in++ )
+      {
+         case '\0':
+            *out = '\0';
+            return true;
+
+         case '\r':
+            if ( *in == '\n' )
+            {
+               // this line already has CR LF
+               in++;
+            }
+            // fall through
+
+         case '\n':
+            *out++ = '\r';
+            if ( out != outEnd )
+               *out++ = '\n';
+            break;
+
+         default:
+            *out++ = ch;
+      }
+   }
+
+   // if we get here out must have reached outEnd
+   return false;
+}
+
 /** Enforces CR/LF newline convention.
 
     @param in string to copy


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/