* Blank out the Envelope-to: header when reading messages via POP or IMAP. Resolves...
[citadel.git] / citadel / modules / imap / imap_fetch.c
index 66d5b44addce658164315f1c2e25e011b42760c0..1adac79a59f40ff814dd91efc416436cddee10f0 100644 (file)
@@ -32,6 +32,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <limits.h>
+#include <libcitadel.h>
 #include "citadel.h"
 #include "server.h"
 #include "sysdep_decls.h"
 #include "policy.h"
 #include "database.h"
 #include "msgbase.h"
-#include "tools.h"
 #include "internet_addressing.h"
-#include "mime_parser.h"
 #include "serv_imap.h"
 #include "imap_tools.h"
 #include "imap_fetch.h"
 #include "genstamp.h"
+#include "ctdl_module.h"
 
 
 
@@ -174,8 +174,9 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) {
                CC->redirect_len = 0;
                CC->redirect_alloc = SIZ;
                CtdlOutputMsg(msgnum, MT_RFC822,
-                       (need_body ? HEADERS_ALL : HEADERS_ONLY),
-                       0, 1, NULL);
+                       (need_body ? HEADERS_ALL : HEADERS_FAST),
+                       0, 1, NULL, SUPPRESS_ENV_TO
+               );
                if (!need_body) cprintf("\r\n");        /* extra trailing newline */
                IMAP->cached_rfc822_data = CC->redirect_buffer;
                IMAP->cached_rfc822_len = CC->redirect_len;
@@ -204,7 +205,7 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) {
                        ptr = memreadline(ptr, buf, sizeof buf);
                        if (*ptr != 0) {
                                striplt(buf);
-                               if (strlen(buf) == 0) {
+                               if (IsEmptyStr(buf)) {
                                        headers_size = ptr - IMAP->cached_rfc822_data;
                                }
                        }
@@ -219,11 +220,14 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) {
                text_size = 0;
        }
 
-       lprintf(CTDL_DEBUG, "RFC822: headers=%d, text=%d, total=%d\n",
+       CtdlLogPrintf(CTDL_DEBUG, 
+               "RFC822: headers=" SIZE_T_FMT 
+               ", text=" SIZE_T_FMT
+               ", total=" SIZE_T_FMT "\n",
                headers_size, text_size, total_size);
 
        if (!strcasecmp(whichfmt, "RFC822.SIZE")) {
-               cprintf("RFC822.SIZE %d", total_size);
+               cprintf("RFC822.SIZE " SIZE_T_FMT, total_size);
                return;
        }
 
@@ -242,7 +246,7 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) {
                bytes_to_send = text_size;
        }
 
-       cprintf("%s {%d}\r\n", whichfmt, bytes_to_send);
+       cprintf("%s {" SIZE_T_FMT "}\r\n", whichfmt, bytes_to_send);
        client_write(ptr, bytes_to_send);
 }
 
@@ -258,7 +262,7 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) {
  */
 void imap_load_part(char *name, char *filename, char *partnum, char *disp,
                    void *content, char *cbtype, char *cbcharset, size_t length, char *encoding,
-                   void *cbuserdata)
+                   char *cbid, void *cbuserdata)
 {
        char mbuf2[SIZ];
        char *desired_section;
@@ -273,16 +277,16 @@ void imap_load_part(char *name, char *filename, char *partnum, char *disp,
 
        if (!strcasecmp(desired_section, mbuf2)) {
                cprintf("Content-type: %s", cbtype);
-               if (strlen(cbcharset) > 0)
+               if (!IsEmptyStr(cbcharset))
                        cprintf("; charset=\"%s\"", cbcharset);
-               if (strlen(name) > 0)
+               if (!IsEmptyStr(name))
                        cprintf("; name=\"%s\"", name);
                cprintf("\r\n");
-               if (strlen(encoding) > 0)
+               if (!IsEmptyStr(encoding))
                        cprintf("Content-Transfer-Encoding: %s\r\n", encoding);
-               if (strlen(encoding) > 0) {
+               if (!IsEmptyStr(encoding)) {
                        cprintf("Content-Disposition: %s", disp);
-                       if (strlen(filename) > 0) {
+                       if (!IsEmptyStr(filename)) {
                                cprintf("; filename=\"%s\"", filename);
                        }
                        cprintf("\r\n");
@@ -345,7 +349,7 @@ void imap_output_envelope_from(struct CtdlMessage *msg) {
 
 /*
  * Output an envelope address (or set of addresses) in the official,
- * convuluted, braindead format.  (Note that we can't use this for
+ * convoluted, braindead format.  (Note that we can't use this for
  * the "From" address because its data may come from a number of different
  * fields.  But we can use it for "To" and possibly others.
  */
@@ -362,7 +366,7 @@ void imap_output_envelope_addr(char *addr) {
                return;
        }
 
-       if (strlen(addr) == 0) {
+       if (IsEmptyStr(addr)) {
                cprintf("NIL ");
                return;
        }
@@ -510,13 +514,15 @@ void imap_strip_headers(char *section) {
        if (!strncasecmp(which_fields, "HEADER.FIELDS.NOT", 17))
                headers_not = 1;
 
-       for (i=0; i<strlen(which_fields); ++i) {
+       for (i=0; which_fields[i]; ++i) {
                if (which_fields[i]=='(')
                        strcpy(which_fields, &which_fields[i+1]);
        }
-       for (i=0; i<strlen(which_fields); ++i) {
-               if (which_fields[i]==')')
+       for (i=0; which_fields[i]; ++i) {
+               if (which_fields[i]==')') {
                        which_fields[i] = 0;
+                       break;
+               }
        }
        num_parms = imap_parameterize(parms, which_fields);
 
@@ -525,7 +531,8 @@ void imap_strip_headers(char *section) {
 
        ptr = CC->redirect_buffer;
        ok = 0;
-       while ( (done_headers == 0) && (ptr = memreadline(ptr, buf, sizeof buf), *ptr != 0) ) {
+       do {
+               ptr = memreadline(ptr, buf, sizeof buf);
                if (!isspace(buf[0])) {
                        ok = 0;
                        if (doing_headers == 0) ok = 1;
@@ -548,10 +555,11 @@ void imap_strip_headers(char *section) {
                        strcat(boiled_headers, "\r\n");
                }
 
-               if (strlen(buf) == 0) done_headers = 1;
+               if (IsEmptyStr(buf)) done_headers = 1;
                if (buf[0]=='\r') done_headers = 1;
                if (buf[0]=='\n') done_headers = 1;
-       }
+               if (*ptr == 0) done_headers = 1;
+       } while (!done_headers);
 
        strcat(boiled_headers, "\r\n");
 
@@ -582,10 +590,9 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
        if (strchr(section, '[') != NULL) {
                stripallbut(section, '[', ']');
        }
-       lprintf(CTDL_DEBUG, "Section is: %s%s\n", section, ((strlen(section)==0) ? "(empty)" : "") );
-       if (!strncasecmp(section, "HEADER", 6)) {
-               need_body = 0;
-       }
+       CtdlLogPrintf(CTDL_DEBUG, "Section is: %s%s\n", 
+               section, 
+               IsEmptyStr(section) ? "(empty)" : "");
 
        /* Burn the cache if we don't have the same section of the 
         * same message again.
@@ -617,7 +624,7 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
                is_partial = 1;
        }
        if (is_partial == 0) strcpy(partial, "");
-       /* if (strlen(partial) > 0) lprintf(CTDL_DEBUG, "Partial is %s\n", partial); */
+       /* if (!IsEmptyStr(partial)) CtdlLogPrintf(CTDL_DEBUG, "Partial is %s\n", partial); */
 
        if (IMAP->cached_body == NULL) {
                CC->redirect_buffer = malloc(SIZ);
@@ -634,11 +641,11 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
        }
 
        else if ( (!strcmp(section, "1")) && (msg->cm_format_type != 4) ) {
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1);
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1, SUPPRESS_ENV_TO);
        }
 
        else if (!strcmp(section, "")) {
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1);
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, SUPPRESS_ENV_TO);
        }
 
        /*
@@ -646,7 +653,11 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
         * fields, strip it down.
         */
        else if (!strncasecmp(section, "HEADER", 6)) {
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ONLY, 0, 1);
+               /* This used to work with HEADERS_FAST, but then Apple got stupid with their
+                * IMAP library and this broke Mail.App and iPhone Mail, so we had to change it
+                * to HEADERS_ONLY so the trendy hipsters with their iPhones can read mail.
+                */
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ONLY, 0, 1, SUPPRESS_ENV_TO);
                imap_strip_headers(section);
        }
 
@@ -654,7 +665,7 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
         * Strip it down if the client asked for everything _except_ headers.
         */
        else if (!strncasecmp(section, "TEXT", 4)) {
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1);
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1, SUPPRESS_ENV_TO);
        }
 
        /*
@@ -680,16 +691,16 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
        }
 
        if (is_partial == 0) {
-               cprintf("BODY[%s] {%d}\r\n", section, IMAP->cached_body_len);
+               cprintf("BODY[%s] {" SIZE_T_FMT "}\r\n", section, IMAP->cached_body_len);
                pstart = 0;
                pbytes = IMAP->cached_body_len;
        }
        else {
-               sscanf(partial, "%d.%d", &pstart, &pbytes);
+               sscanf(partial, SIZE_T_FMT "." SIZE_T_FMT, &pstart, &pbytes);
                if (pbytes > (IMAP->cached_body_len - pstart)) {
                        pbytes = IMAP->cached_body_len - pstart;
                }
-               cprintf("BODY[%s]<%d> {%d}\r\n", section, pstart, pbytes);
+               cprintf("BODY[%s]<" SIZE_T_FMT "> {" SIZE_T_FMT "}\r\n", section, pstart, pbytes);
        }
 
        /* Here we go -- output it */
@@ -711,7 +722,7 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
 void imap_fetch_bodystructure_pre(
                char *name, char *filename, char *partnum, char *disp,
                void *content, char *cbtype, char *cbcharset, size_t length, char *encoding,
-               void *cbuserdata
+               char *cbid, void *cbuserdata
                ) {
 
        cprintf("(");
@@ -725,7 +736,7 @@ void imap_fetch_bodystructure_pre(
 void imap_fetch_bodystructure_post(
                char *name, char *filename, char *partnum, char *disp,
                void *content, char *cbtype, char *cbcharset, size_t length, char *encoding,
-               void *cbuserdata
+               char *cbid, void *cbuserdata
                ) {
 
        char subtype[128];
@@ -737,7 +748,7 @@ void imap_fetch_bodystructure_post(
        imap_strout(subtype);
 
        /* body language */
-       cprintf(" NIL");
+       /* cprintf(" NIL"); We thought we needed this at one point, but maybe we don't... */
 
        cprintf(")");
 }
@@ -751,7 +762,7 @@ void imap_fetch_bodystructure_post(
 void imap_fetch_bodystructure_part(
                char *name, char *filename, char *partnum, char *disp,
                void *content, char *cbtype, char *cbcharset, size_t length, char *encoding,
-               void *cbuserdata
+               char *cbid, void *cbuserdata
                ) {
 
        int have_cbtype = 0;
@@ -761,7 +772,7 @@ void imap_fetch_bodystructure_part(
        char cbmaintype[128];
        char cbsubtype[128];
 
-       if (cbtype != NULL) if (strlen(cbtype)>0) have_cbtype = 1;
+       if (cbtype != NULL) if (!IsEmptyStr(cbtype)) have_cbtype = 1;
        if (have_cbtype) {
                extract_token(cbmaintype, cbtype, 0, '/', sizeof cbmaintype);
                extract_token(cbsubtype, cbtype, 1, '/', sizeof cbsubtype);
@@ -772,33 +783,39 @@ void imap_fetch_bodystructure_part(
        }
 
        cprintf("(");
-       imap_strout(cbmaintype);
+       imap_strout(cbmaintype);                                        /* body type */
        cprintf(" ");
-       imap_strout(cbsubtype);
+       imap_strout(cbsubtype);                                         /* body subtype */
        cprintf(" ");
 
+       cprintf("(");                                                   /* begin body parameter list */
+
+       /* "NAME" must appear as the first parameter.  This is not required by IMAP,
+        * but the Asterisk voicemail application blindly assumes that NAME will be in
+        * the first position.  If it isn't, it rejects the message.
+        */
+       if (name != NULL) if (!IsEmptyStr(name)) {
+               cprintf("\"NAME\" ");
+               imap_strout(name);
+               cprintf(" ");
+       }
+
+       cprintf("\"CHARSET\" ");
        if (cbcharset == NULL) {
-               cprintf("(\"CHARSET\" \"US-ASCII\"");
+               imap_strout("US-ASCII");
        }
-       else if (strlen(cbcharset) == 0) {
-               cprintf("(\"CHARSET\" \"US-ASCII\"");
+       else if (cbcharset[0] == 0) {
+               imap_strout("US-ASCII");
        }
        else {
-               cprintf("(\"CHARSET\" ");
                imap_strout(cbcharset);
        }
+       cprintf(") ");                                                  /* end body parameter list */
 
-       if (name != NULL) if (strlen(name)>0) {
-               cprintf(" \"NAME\" ");
-               imap_strout(name);
-       }
-
-       cprintf(") ");
+       cprintf("NIL ");                                                /* Body ID */
+       cprintf("NIL ");                                                /* Body description */
 
-       cprintf("NIL ");        /* Body ID */
-       cprintf("NIL ");        /* Body description */
-
-       if (encoding != NULL) if (strlen(encoding) > 0)  have_encoding = 1;
+       if (encoding != NULL) if (encoding[0] != 0)  have_encoding = 1;
        if (have_encoding) {
                imap_strout(encoding);
        }
@@ -823,12 +840,11 @@ void imap_fetch_bodystructure_part(
        /* More gratuitous complexity */
        if ((!strcasecmp(cbmaintype, "MESSAGE"))
           && (!strcasecmp(cbsubtype, "RFC822"))) {
-               /* FIXME
-                     A body type of type MESSAGE and subtype RFC822
-                     contains, immediately after the basic fields, the
-                     envelope structure, body structure, and size in
-                     text lines of the encapsulated message.
-               */
+               /* FIXME: message/rfc822 also needs to output the envelope structure,
+                * body structure, and line count of the encapsulated message.  Fortunately
+                * there are not yet any clients depending on this, so we can get away
+                * with not implementing it for now.
+                */
        }
 
        /* MD5 value of body part; we can get away with NIL'ing this */
@@ -838,13 +854,13 @@ void imap_fetch_bodystructure_part(
        if (disp == NULL) {
                cprintf("NIL");
        }
-       else if (strlen(disp) == 0) {
+       else if (IsEmptyStr(disp)) {
                cprintf("NIL");
        }
        else {
                cprintf("(");
                imap_strout(disp);
-               if (filename != NULL) if (strlen(filename)>0) {
+               if (filename != NULL) if (!IsEmptyStr(filename)) {
                        cprintf(" (\"FILENAME\" ");
                        imap_strout(filename);
                        cprintf(")");
@@ -893,7 +909,7 @@ void imap_fetch_bodystructure (long msgnum, char *item,
                CC->redirect_buffer = malloc(SIZ);
                CC->redirect_len = 0;
                CC->redirect_alloc = SIZ;
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, 0, 0, 1);
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, 0, 0, 1, SUPPRESS_ENV_TO);
                rfc822 = CC->redirect_buffer;
                rfc822_len = CC->redirect_len;
                CC->redirect_buffer = NULL;
@@ -901,12 +917,13 @@ void imap_fetch_bodystructure (long msgnum, char *item,
                CC->redirect_alloc = 0;
 
                ptr = rfc822;
-               while (ptr = memreadline(ptr, buf, sizeof buf), *ptr != 0) {
+               do {
+                       ptr = memreadline(ptr, buf, sizeof buf);
                        ++lines;
-                       if ((strlen(buf) == 0) && (rfc822_body == NULL)) {
+                       if ((IsEmptyStr(buf)) && (rfc822_body == NULL)) {
                                rfc822_body = ptr;
                        }
-               }
+               } while (*ptr != 0);
 
                rfc822_headers_len = rfc822_body - rfc822;
                rfc822_body_len = rfc822_len - rfc822_headers_len;
@@ -914,7 +931,7 @@ void imap_fetch_bodystructure (long msgnum, char *item,
 
                cprintf("BODYSTRUCTURE (\"TEXT\" \"PLAIN\" "
                        "(\"CHARSET\" \"US-ASCII\") NIL NIL "
-                       "\"7BIT\" %d %d)", rfc822_body_len, lines);
+                       "\"7BIT\" " SIZE_T_FMT " %d)", rfc822_body_len, lines);
 
                return;
        }
@@ -1056,16 +1073,19 @@ void imap_do_fetch(int num_items, char **itemlist) {
  */
 void imap_macro_replace(char *str, char *find, char *replace) {
        char holdbuf[SIZ];
+       int findlen;
 
-       if (!strncasecmp(str, find, strlen(find))) {
-               if (str[strlen(find)]==' ') {
-                       strcpy(holdbuf, &str[strlen(find)+1]);
+       findlen = strlen(find);
+
+       if (!strncasecmp(str, find, findlen)) {
+               if (str[findlen]==' ') {
+                       strcpy(holdbuf, &str[findlen+1]);
                        strcpy(str, replace);
                        strcat(str, " ");
                        strcat(str, holdbuf);
                }
-               if (str[strlen(find)]==0) {
-                       strcpy(holdbuf, &str[strlen(find)+1]);
+               if (str[findlen]==0) {
+                       strcpy(holdbuf, &str[findlen+1]);
                        strcpy(str, replace);
                }
        }
@@ -1082,7 +1102,7 @@ void imap_handle_macros(char *str) {
        int i;
        int nest = 0;
 
-       for (i=0; i<strlen(str); ++i) {
+       for (i=0; str[i]; ++i) {
                if (str[i]=='(') ++nest;
                if (str[i]=='[') ++nest;
                if (str[i]=='<') ++nest;
@@ -1123,11 +1143,12 @@ void imap_handle_macros(char *str) {
 int imap_extract_data_items(char **argv, char *items) {
        int num_items = 0;
        int nest = 0;
-       int i, initial_len;
+       int i;
        char *start;
+       long initial_len;
 
        /* Convert all whitespace to ordinary space characters. */
-       for (i=0; i<strlen(items); ++i) {
+       for (i=0; items[i]; ++i) {
                if (isspace(items[i])) items[i]=' ';
        }
 
@@ -1195,6 +1216,7 @@ void imap_pick_range(char *supplied_range, int is_uid) {
        char setstr[SIZ], lostr[SIZ], histr[SIZ];
        long lo, hi;
        char actual_range[SIZ];
+       struct citimap *Imap;
 
        /* 
         * Handle the "ALL" macro
@@ -1206,11 +1228,12 @@ void imap_pick_range(char *supplied_range, int is_uid) {
                safestrncpy(actual_range, supplied_range, sizeof actual_range);
        }
 
+       Imap = IMAP;
        /*
         * Clear out the IMAP_SELECTED flags for all messages.
         */
-       for (i = 0; i < IMAP->num_msgs; ++i) {
-               IMAP->flags[i] = IMAP->flags[i] & ~IMAP_SELECTED;
+       for (i = 0; i < Imap->num_msgs; ++i) {
+               Imap->flags[i] = Imap->flags[i] & ~IMAP_SELECTED;
        }
 
        /*
@@ -1232,16 +1255,16 @@ void imap_pick_range(char *supplied_range, int is_uid) {
                hi = atol(histr);
 
                /* Loop through the array, flipping bits where appropriate */
-               for (i = 1; i <= IMAP->num_msgs; ++i) {
+               for (i = 1; i <= Imap->num_msgs; ++i) {
                        if (is_uid) {   /* fetch by sequence number */
-                               if ( (IMAP->msgids[i-1]>=lo)
-                                  && (IMAP->msgids[i-1]<=hi)) {
-                                       IMAP->flags[i-1] |= IMAP_SELECTED;
+                               if ( (Imap->msgids[i-1]>=lo)
+                                  && (Imap->msgids[i-1]<=hi)) {
+                                       Imap->flags[i-1] |= IMAP_SELECTED;
                                }
                        }
                        else {          /* fetch by uid */
                                if ( (i>=lo) && (i<=hi)) {
-                                       IMAP->flags[i-1] |= IMAP_SELECTED;
+                                       Imap->flags[i-1] |= IMAP_SELECTED;
                                }
                        }
                }