]> code.citadel.org Git - citadel.git/blobdiff - citadel/modules/imap/imap_fetch.c
* rework imap tokenizer, we no longer copy the stuff around, we keep a reference...
[citadel.git] / citadel / modules / imap / imap_fetch.c
index 75a05dbb41ab571672a005cd720dedbc43367d15..0f65985b5f0b564e99ee6e5cadd8e948690fe09a 100644 (file)
@@ -4,6 +4,21 @@
  * Implements the FETCH command in IMAP.
  * This is a good example of the protocol's gratuitous complexity.
  *
+ * Copyright (c) 2001-2009 by the citadel.org team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 
 #include "citserver.h"
 #include "support.h"
 #include "config.h"
-#include "room_ops.h"
 #include "user_ops.h"
 #include "policy.h"
 #include "database.h"
 #include "msgbase.h"
 #include "internet_addressing.h"
-#include "serv_imap.h"
 #include "imap_tools.h"
+#include "serv_imap.h"
 #include "imap_fetch.h"
 #include "genstamp.h"
 #include "ctdl_module.h"
@@ -87,6 +101,7 @@ void imap_fetch_flags(int seq) {
        cprintf(")");
 }
 
+
 void imap_fetch_internaldate(struct CtdlMessage *msg) {
        char buf[SIZ];
        time_t msgdate;
@@ -115,7 +130,7 @@ void imap_fetch_internaldate(struct CtdlMessage *msg) {
  */
 void imap_fetch_rfc822(long msgnum, char *whichfmt) {
        char buf[SIZ];
-       char *ptr = NULL;
+       const char *ptr = NULL;
        size_t headers_size, text_size, total_size;
        size_t bytes_to_send = 0;
        struct MetaData smi;
@@ -175,7 +190,8 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) {
                CC->redirect_alloc = SIZ;
                CtdlOutputMsg(msgnum, MT_RFC822,
                        (need_body ? HEADERS_ALL : HEADERS_FAST),
-                             0, 1, NULL, 0);
+                       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;
@@ -320,25 +336,25 @@ void imap_output_envelope_from(struct CtdlMessage *msg) {
 
        /* For everything else, we do stuff. */
        cprintf("((");                          /* open double-parens */
-       imap_strout(msg->cm_fields['A']);       /* personal name */
+       plain_imap_strout(msg->cm_fields['A']); /* personal name */
        cprintf(" NIL ");                       /* source route (not used) */
 
 
        if (msg->cm_fields['F'] != NULL) {
                process_rfc822_addr(msg->cm_fields['F'], user, node, name);
-               imap_strout(user);              /* mailbox name (user id) */
+               plain_imap_strout(user);                /* mailbox name (user id) */
                cprintf(" ");
                if (!strcasecmp(node, config.c_nodename)) {
-                       imap_strout(config.c_fqdn);
+                       plain_imap_strout(config.c_fqdn);
                }
                else {
-                       imap_strout(node);              /* host name */
+                       plain_imap_strout(node);                /* host name */
                }
        }
        else {
-               imap_strout(msg->cm_fields['A']); /* mailbox name (user id) */
+               plain_imap_strout(msg->cm_fields['A']); /* mailbox name (user id) */
                cprintf(" ");
-               imap_strout(msg->cm_fields['N']);       /* host name */
+               plain_imap_strout(msg->cm_fields['N']); /* host name */
        }
        
        cprintf(")) ");                         /* close double-parens */
@@ -348,7 +364,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.
  */
@@ -381,11 +397,11 @@ void imap_output_envelope_addr(char *addr) {
                striplt(individual_addr);
                process_rfc822_addr(individual_addr, user, node, name);
                cprintf("(");
-               imap_strout(name);
+               plain_imap_strout(name);
                cprintf(" NIL ");
-               imap_strout(user);
+               plain_imap_strout(user);
                cprintf(" ");
-               imap_strout(node);
+               plain_imap_strout(node);
                cprintf(")");
                if (i < (num_addrs-1)) cprintf(" ");
        }
@@ -425,11 +441,11 @@ void imap_fetch_envelope(struct CtdlMessage *msg) {
        cprintf("ENVELOPE (");
 
        /* Date */
-       imap_strout(datestringbuf);
+       plain_imap_strout(datestringbuf);
        cprintf(" ");
 
        /* Subject */
-       imap_strout(msg->cm_fields['U']);
+       plain_imap_strout(msg->cm_fields['U']);
        cprintf(" ");
 
        /* From */
@@ -476,12 +492,12 @@ void imap_fetch_envelope(struct CtdlMessage *msg) {
 
        /* In-reply-to */
        fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "In-reply-to");
-       imap_strout(fieldptr);
+       plain_imap_strout(fieldptr);
        cprintf(" ");
        if (fieldptr != NULL) free(fieldptr);
 
        /* message ID */
-       imap_strout(msg->cm_fields['I']);
+       plain_imap_strout(msg->cm_fields['I']);
 
        cprintf(")");
 }
@@ -502,7 +518,7 @@ void imap_strip_headers(char *section) {
        char *boiled_headers = NULL;
        int ok = 0;
        int done_headers = 0;
-       char *ptr = NULL;
+       const char *ptr = NULL;
 
        if (CC->redirect_buffer == NULL) return;
 
@@ -523,14 +539,15 @@ void imap_strip_headers(char *section) {
                        break;
                }
        }
-       num_parms = imap_parameterize(parms, which_fields);
+       num_parms = old_imap_parameterize(parms, which_fields);
 
        boiled_headers = malloc(CC->redirect_alloc);
        strcpy(boiled_headers, "");
 
        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;
@@ -556,7 +573,8 @@ void imap_strip_headers(char *section) {
                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");
 
@@ -589,20 +607,8 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) {
        }
        CtdlLogPrintf(CTDL_DEBUG, "Section is: %s%s\n", 
                section, 
-               IsEmptyStr(section) ? "(empty)" : "");
-
-       /*
-        * We used to have this great optimization in place that would avoid
-        * fetching the entire RFC822 message from disk if the client was only
-        * asking for the headers.  Unfortunately, fetching only the Citadel
-        * headers omits "Content-type:" and this behavior breaks the iPhone
-        * email client.  So we have to fetch the whole message from disk.  The
-        *
-        *      if (!strncasecmp(section, "HEADER", 6)) {
-        *              need_body = 0;
-        *      }
-        *
-        */
+               IsEmptyStr(section) ? "(empty)" : ""
+       );
 
        /* Burn the cache if we don't have the same section of the 
         * same message again.
@@ -651,11 +657,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, 0);
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1, SUPPRESS_ENV_TO);
        }
 
        else if (!strcmp(section, "")) {
-               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, 0);
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, SUPPRESS_ENV_TO);
        }
 
        /*
@@ -663,7 +669,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_FAST, 0, 1, 0);
+               /* 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);
        }
 
@@ -671,7 +681,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, 0);
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1, SUPPRESS_ENV_TO);
        }
 
        /*
@@ -751,7 +761,7 @@ void imap_fetch_bodystructure_post(
 
        /* disposition */
        extract_token(subtype, cbtype, 1, '/', sizeof subtype);
-       imap_strout(subtype);
+       plain_imap_strout(subtype);
 
        /* body language */
        /* cprintf(" NIL"); We thought we needed this at one point, but maybe we don't... */
@@ -789,9 +799,9 @@ void imap_fetch_bodystructure_part(
        }
 
        cprintf("(");
-       imap_strout(cbmaintype);                                        /* body type */
+       plain_imap_strout(cbmaintype);                                  /* body type */
        cprintf(" ");
-       imap_strout(cbsubtype);                                         /* body subtype */
+       plain_imap_strout(cbsubtype);                                           /* body subtype */
        cprintf(" ");
 
        cprintf("(");                                                   /* begin body parameter list */
@@ -802,19 +812,19 @@ void imap_fetch_bodystructure_part(
         */
        if (name != NULL) if (!IsEmptyStr(name)) {
                cprintf("\"NAME\" ");
-               imap_strout(name);
+               plain_imap_strout(name);
                cprintf(" ");
        }
 
        cprintf("\"CHARSET\" ");
        if (cbcharset == NULL) {
-               imap_strout("US-ASCII");
+               plain_imap_strout("US-ASCII");
        }
        else if (cbcharset[0] == 0) {
-               imap_strout("US-ASCII");
+               plain_imap_strout("US-ASCII");
        }
        else {
-               imap_strout(cbcharset);
+               plain_imap_strout(cbcharset);
        }
        cprintf(") ");                                                  /* end body parameter list */
 
@@ -823,10 +833,10 @@ void imap_fetch_bodystructure_part(
 
        if (encoding != NULL) if (encoding[0] != 0)  have_encoding = 1;
        if (have_encoding) {
-               imap_strout(encoding);
+               plain_imap_strout(encoding);
        }
        else {
-               imap_strout("7BIT");
+               plain_imap_strout("7BIT");
        }
        cprintf(" ");
 
@@ -846,12 +856,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 */
@@ -866,10 +875,10 @@ void imap_fetch_bodystructure_part(
        }
        else {
                cprintf("(");
-               imap_strout(disp);
+               plain_imap_strout(disp);
                if (filename != NULL) if (!IsEmptyStr(filename)) {
                        cprintf(" (\"FILENAME\" ");
-                       imap_strout(filename);
+                       plain_imap_strout(filename);
                        cprintf(")");
                }
                cprintf(")");
@@ -887,12 +896,13 @@ void imap_fetch_bodystructure_part(
  */
 void imap_fetch_bodystructure (long msgnum, char *item,
                struct CtdlMessage *msg) {
-       char *rfc822 = NULL;
-       char *rfc822_body = NULL;
+       const char *rfc822 = NULL;
+       const char *rfc822_body = NULL;
        size_t rfc822_len;
        size_t rfc822_headers_len;
        size_t rfc822_body_len;
-       char *ptr = NULL;
+       const char *ptr = NULL;
+       char *pch;
        char buf[SIZ];
        int lines = 0;
 
@@ -916,24 +926,25 @@ 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, 0);
-               rfc822 = CC->redirect_buffer;
+               CtdlOutputPreLoadedMsg(msg, MT_RFC822, 0, 0, 1, SUPPRESS_ENV_TO);
+               rfc822 = pch = CC->redirect_buffer;
                rfc822_len = CC->redirect_len;
                CC->redirect_buffer = NULL;
                CC->redirect_len = 0;
                CC->redirect_alloc = 0;
 
                ptr = rfc822;
-               while (ptr = memreadline(ptr, buf, sizeof buf), *ptr != 0) {
+               do {
+                       ptr = memreadline(ptr, buf, sizeof buf);
                        ++lines;
                        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;
-               free(rfc822);
+               free(pch);
 
                cprintf("BODYSTRUCTURE (\"TEXT\" \"PLAIN\" "
                        "(\"CHARSET\" \"US-ASCII\") NIL NIL "
@@ -1215,14 +1226,14 @@ int imap_extract_data_items(char **argv, char *items) {
  *
  * Set is_uid to 1 to fetch by UID instead of sequence number.
  */
-void imap_pick_range(char *supplied_range, int is_uid) {
+void imap_pick_range(const char *supplied_range, int is_uid) {
        int i;
        int num_sets;
        int s;
        char setstr[SIZ], lostr[SIZ], histr[SIZ];
        long lo, hi;
        char actual_range[SIZ];
-       struct citimap *Imap;
+       citimap *Imap;
 
        /* 
         * Handle the "ALL" macro
@@ -1275,7 +1286,6 @@ void imap_pick_range(char *supplied_range, int is_uid) {
                        }
                }
        }
-
 }
 
 
@@ -1283,39 +1293,39 @@ void imap_pick_range(char *supplied_range, int is_uid) {
 /*
  * This function is called by the main command loop.
  */
-void imap_fetch(int num_parms, char *parms[]) {
+void imap_fetch(int num_parms, ConstStr *Params) {
        char items[SIZ];
        char *itemlist[512];
        int num_items;
        int i;
 
        if (num_parms < 4) {
-               cprintf("%s BAD invalid parameters\r\n", parms[0]);
+               cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
                return;
        }
 
-       imap_pick_range(parms[2], 0);
+       imap_pick_range(Params[2].Key, 0);
 
        strcpy(items, "");
        for (i=3; i<num_parms; ++i) {
-               strcat(items, parms[i]);
+               strcat(items, Params[i].Key);
                if (i < (num_parms-1)) strcat(items, " ");
        }
 
        num_items = imap_extract_data_items(itemlist, items);
        if (num_items < 1) {
-               cprintf("%s BAD invalid data item list\r\n", parms[0]);
+               cprintf("%s BAD invalid data item list\r\n", Params[0].Key);
                return;
        }
 
        imap_do_fetch(num_items, itemlist);
-       cprintf("%s OK FETCH completed\r\n", parms[0]);
+       cprintf("%s OK FETCH completed\r\n", Params[0].Key);
 }
 
 /*
  * This function is called by the main command loop.
  */
-void imap_uidfetch(int num_parms, char *parms[]) {
+void imap_uidfetch(int num_parms, ConstStr *Params) {
        char items[SIZ];
        char *itemlist[512];
        int num_items;
@@ -1323,21 +1333,21 @@ void imap_uidfetch(int num_parms, char *parms[]) {
        int have_uid_item = 0;
 
        if (num_parms < 5) {
-               cprintf("%s BAD invalid parameters\r\n", parms[0]);
+               cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
                return;
        }
 
-       imap_pick_range(parms[3], 1);
+       imap_pick_range(Params[3].Key, 1);
 
        strcpy(items, "");
        for (i=4; i<num_parms; ++i) {
-               strcat(items, parms[i]);
+               strcat(items, Params[i].Key);
                if (i < (num_parms-1)) strcat(items, " ");
        }
 
        num_items = imap_extract_data_items(itemlist, items);
        if (num_items < 1) {
-               cprintf("%s BAD invalid data item list\r\n", parms[0]);
+               cprintf("%s BAD invalid data item list\r\n", Params[0].Key);
                return;
        }
 
@@ -1354,7 +1364,7 @@ void imap_uidfetch(int num_parms, char *parms[]) {
        }
 
        imap_do_fetch(num_items, itemlist);
-       cprintf("%s OK UID FETCH completed\r\n", parms[0]);
+       cprintf("%s OK UID FETCH completed\r\n", Params[0].Key);
 }