]> code.citadel.org Git - citadel.git/blobdiff - citadel/mime_parser.c
* tell what we did to the debs
[citadel.git] / citadel / mime_parser.c
index cd98c538c06f553b4a7d26a5a3db09bf8bd70f6d..c6415f34bb7c2d658ad6befa7c626f11ff2c722d 100644 (file)
@@ -1,17 +1,13 @@
 /*
  * $Id$
  *
- * This is the MIME parser for Citadel.  Sometimes it actually works.
+ * This is the MIME parser for Citadel.
  *
- * Copyright (c) 1998-2005 by Art Cancro
- * This code is distributed under the terms of the GNU General Public License.
+ * Copyright (c) 1998-2006 by Art Cancro
+ * This code is distributed under the GNU General Public License v2.
  *
  */
 
-#ifdef DLL_EXPORT
-#define IN_LIBCIT
-#endif
-
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -66,68 +62,50 @@ char *fixed_partnum(char *supplied_partnum) {
 
 /*
  * Convert "quoted-printable" to binary.  Returns number of bytes decoded.
+ * according to RFC2045 section 6.7
  */
 int CtdlDecodeQuotedPrintable(char *decoded, char *encoded, int sourcelen) {
-       char buf[SIZ];
-       int buf_length = 0;
-       int soft_line_break = 0;
        unsigned int ch;
-       int decoded_length = 0;
-       int i;
+       int destpos = 1;
+       int sourcepos = 1;
+       int ignore_last = 0;
+       char *check;
 
        decoded[0] = 0;
-       decoded_length = 0;
-       buf[0] = 0;
-       buf_length = 0;
-
-       for (i = 0; i < sourcelen; ++i) {
-
-               buf[buf_length++] = encoded[i];
-
-               if ( (encoded[i] == '\n')
-                  || (encoded[i] == 0)
-                  || (i == (sourcelen-1)) ) {
-                       buf[buf_length++] = 0;
-
-                       /*** begin -- process one line ***/
-
-                       if (buf[strlen(buf)-1] == '\n') {
-                               buf[strlen(buf)-1] = 0;
-                       }
-                       if (buf[strlen(buf)-1] == '\r') {
-                               buf[strlen(buf)-1] = 0;
+       if (sourcelen >0)
+               decoded[0] = encoded[0];
+       while (sourcepos <= sourcelen){
+               check = &decoded[destpos];
+               decoded[destpos] = encoded[sourcepos];
+               if ((ignore_last == 0) && (decoded[destpos-1] == '='))
+               {
+                       if ((*check == '\0') || 
+                           (*check == '\n') ||  
+                           (*check == '\r'))
+                       {
+                               decoded[destpos - 1] = '\0';
+                               destpos-=2;
                        }
-                       while (isspace(buf[strlen(buf)-1])) {
-                               buf[strlen(buf)-1] = 0;
-                       }
-                       soft_line_break = 0;
-
-                       while (strlen(buf) > 0) {
-                               if (!strcmp(buf, "=")) {
-                                       soft_line_break = 1;
-                                       strcpy(buf, "");
-                               } else if ((strlen(buf)>=3) && (buf[0]=='=')) {
-                                       sscanf(&buf[1], "%02x", &ch);
-                                       decoded[decoded_length++] = ch;
-                                       strcpy(buf, &buf[3]);
-                               } else {
-                                       decoded[decoded_length++] = buf[0];
-                                       strcpy(buf, &buf[1]);
-                               }
+                       else if (sourcelen - sourcepos > 2)
+                       {
+                               sscanf(&encoded[sourcepos], "%02x", &ch);
+                               decoded[destpos - 1] = ch;
+                               sourcepos++;
+                               destpos --;
+                               ignore_last = 1;
                        }
-                       if (soft_line_break == 0) {
-                               decoded[decoded_length++] = '\r';
-                               decoded[decoded_length++] = '\n';
-                       }
-                       buf_length = 0;
-                       /*** end -- process one line ***/
                }
+               else 
+                       ignore_last = 0;
+               destpos ++;
+               sourcepos ++;
        }
 
-       decoded[decoded_length++] = 0;
-       return(decoded_length);
+       decoded[destpos] = 0;
+       return(destpos - 1);
 }
 
+
 /*
  * Given a message or message-part body and a length, handle any necessary
  * decoding and pass the request up the stack.
@@ -196,17 +174,19 @@ void mime_decode(char *partnum,
                return;
        }
        
+       /* Fail silently if we hit an unknown encoding. */
        if ((strcasecmp(encoding, "base64"))
            && (strcasecmp(encoding, "quoted-printable"))) {
                return;
        }
+
        /*
-        * Allocate a buffer for the decoded data.  The output buffer is the
-        * same size as the input buffer; this assumes that the decoded data
-        * will never be larger than the encoded data.  This is a safe
-        * assumption with base64, uuencode, and quoted-printable.
+        * Allocate a buffer for the decoded data.  The output buffer is slightly
+        * larger than the input buffer; this assumes that the decoded data
+        * will never be significantly larger than the encoded data.  This is a
+        * safe assumption with base64, uuencode, and quoted-printable.
         */
-       decoded = malloc(length+2048);
+       decoded = malloc(length + 32768);
        if (decoded == NULL) {
                return;
        }
@@ -215,8 +195,7 @@ void mime_decode(char *partnum,
                bytes_decoded = CtdlDecodeBase64(decoded, part_start, length);
        }
        else if (!strcasecmp(encoding, "quoted-printable")) {
-               bytes_decoded = CtdlDecodeQuotedPrintable(decoded,
-                                                       part_start, length);
+               bytes_decoded = CtdlDecodeQuotedPrintable(decoded, part_start, length);
        }
 
        if (bytes_decoded > 0) if (CallBack != NULL) {
@@ -275,11 +254,13 @@ void the_mime_parser(char *partnum,
 {
 
        char *ptr;
+       char *srch = NULL;
        char *part_start, *part_end = NULL;
        char buf[SIZ];
        char *header;
        char *boundary;
        char *startary;
+       size_t startary_len = 0;
        char *endary;
        char *next_boundary;
        char *content_type;
@@ -409,10 +390,18 @@ void the_mime_parser(char *partnum,
                /* Figure out where the boundaries are */
                snprintf(startary, SIZ, "--%s", boundary);
                snprintf(endary, SIZ, "--%s--", boundary);
+               startary_len = strlen(startary);
 
                part_start = NULL;
                do {
-                       next_boundary = bmstrstr(ptr, startary, strncmp);
+                       next_boundary = NULL;
+                       for (srch=ptr; srch<content_end; ++srch) {
+                               if (!memcmp(srch, startary, startary_len)) {
+                                       next_boundary = srch;
+                                       srch = content_end;
+                               }
+                       }
+
                        if ( (part_start != NULL) && (next_boundary != NULL) ) {
                                part_end = next_boundary;
                                --part_end;
@@ -438,8 +427,8 @@ void the_mime_parser(char *partnum,
                        }
 
                        if (next_boundary != NULL) {
-                               /* If we pass out of scope, don't attempt to read
-                                * past the end boundary. */
+                               /* If we pass out of scope, don't attempt to
+                                * read past the end boundary. */
                                if (!strcmp(next_boundary, endary)) {
                                        ptr = content_end;
                                }
@@ -472,9 +461,9 @@ void the_mime_parser(char *partnum,
                        ++length;
                }
                part_end = content_end;
-                /* fix an off-by-one error */
-                --part_end;
-                --length;
+               /* fix an off-by-one error */
+               --part_end;
+               --length;
                
                /* Truncate if the header told us to */
                if ( (content_length > 0) && (length > content_length) ) {
@@ -491,13 +480,59 @@ void the_mime_parser(char *partnum,
                else {
                        name = content_type_name;
                }
-               
+       
+               /* lprintf(CTDL_DEBUG, "mime_decode part=%s, len=%d, type=%s, charset=%s, encoding=%s\n",
+                       partnum, length, content_type, charset, encoding); */
+
+               /* Ok, we've got a non-multipart part here, so do something with it.
+                */
                mime_decode(partnum,
-                           part_start, length,
-                           content_type, charset, encoding, disposition,
-                           name, filename,
-                           CallBack, NULL, NULL,
-                           userdata, dont_decode);
+                       part_start, length,
+                       content_type, charset, encoding, disposition,
+                       name, filename,
+                       CallBack, NULL, NULL,
+                       userdata, dont_decode
+               );
+
+               /*
+                * Now if it's an encapsulated message/rfc822 then we have to recurse into it
+                */
+               if (!strcasecmp(content_type, "message/rfc822")) {
+
+                       if (PreMultiPartCallBack != NULL) {
+                               PreMultiPartCallBack("", "", partnum, "",
+                                       NULL, content_type, charset,
+                                       0, encoding, userdata);
+                       }
+                       if (CallBack != NULL) {
+                               if (strlen(partnum) > 0) {
+                                       snprintf(nested_partnum,
+                                                sizeof nested_partnum,
+                                                "%s.%d", partnum,
+                                                ++part_seq);
+                               }
+                               else {
+                                       snprintf(nested_partnum,
+                                                sizeof nested_partnum,
+                                                "%d", ++part_seq);
+                               }
+                               the_mime_parser(nested_partnum,
+                                       part_start, part_end,
+                                       CallBack,
+                                       PreMultiPartCallBack,
+                                       PostMultiPartCallBack,
+                                       userdata,
+                                       dont_decode
+                               );
+                       }
+                       if (PostMultiPartCallBack != NULL) {
+                               PostMultiPartCallBack("", "", partnum, "", NULL,
+                                       content_type, charset, 0, encoding, userdata);
+                       }
+
+
+               }
+
        }
 
 end_parser:    /* free the buffers!  end the oppression!! */