X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fimap%2Fimap_fetch.c;h=19d92dafd4422147f5ab0ca77250c9620e3b9971;hb=8c47559cb5ae97ec0fa35660ee16fd61a9451c72;hp=1e026ba939a2765345836dda20d82b7d52f98bab;hpb=e4e72be8bd8c1ea356357a50fc04b765d97c0dfb;p=citadel.git diff --git a/citadel/modules/imap/imap_fetch.c b/citadel/modules/imap/imap_fetch.c index 1e026ba93..19d92dafd 100644 --- a/citadel/modules/imap/imap_fetch.c +++ b/citadel/modules/imap/imap_fetch.c @@ -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 */ @@ -32,6 +47,7 @@ #include #include #include +#include #include "citadel.h" #include "server.h" #include "sysdep_decls.h" @@ -43,13 +59,12 @@ #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 +189,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; @@ -219,11 +235,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 +261,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 +277,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; @@ -345,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. */ @@ -527,7 +546,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; @@ -553,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"); @@ -584,23 +605,10 @@ 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", + 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; - * } - * - */ - /* Burn the cache if we don't have the same section of the * same message again. */ @@ -631,7 +639,7 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) { is_partial = 1; } if (is_partial == 0) strcpy(partial, ""); - /* if (!IsEmptyStr(partial)) 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); @@ -648,11 +656,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); } /* @@ -660,7 +668,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); } @@ -668,7 +680,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); } /* @@ -694,16 +706,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 */ @@ -725,7 +737,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("("); @@ -739,7 +751,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]; @@ -751,7 +763,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(")"); } @@ -765,7 +777,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; @@ -774,7 +786,6 @@ void imap_fetch_bodystructure_part( size_t i; char cbmaintype[128]; char cbsubtype[128]; - char iteration[128]; if (cbtype != NULL) if (!IsEmptyStr(cbtype)) have_cbtype = 1; if (have_cbtype) { @@ -786,51 +797,40 @@ void imap_fetch_bodystructure_part( strcpy(cbsubtype, "PLAIN"); } - /* If this is the second or subsequent part of a multipart sequence, - * we need to output another space here. We do this by obtaining the - * last subpart token of the partnum and converting it to a number. - */ - if (strrchr(partnum, '.')) { - safestrncpy(iteration, (strrchr(partnum, '.')+1), sizeof iteration); - } - else { - safestrncpy(iteration, partnum, sizeof iteration); - } - if (atoi(iteration) > 1) { - cprintf(" "); - } - - - /* output loop */ - 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 (IsEmptyStr(cbcharset)) { - 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 (!IsEmptyStr(name)) { - cprintf(" \"NAME\" "); - imap_strout(name); - } + cprintf("NIL "); /* Body ID */ + cprintf("NIL "); /* Body description */ - cprintf(") "); - - cprintf("NIL "); /* Body ID */ - cprintf("NIL "); /* Body description */ - - if (encoding != NULL) if (!IsEmptyStr(encoding)) have_encoding = 1; + if (encoding != NULL) if (encoding[0] != 0) have_encoding = 1; if (have_encoding) { imap_strout(encoding); } @@ -855,12 +855,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 */ @@ -925,7 +924,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; @@ -933,12 +932,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 ((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; @@ -946,7 +946,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; } @@ -1088,16 +1088,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; + + findlen = strlen(find); - if (!strncasecmp(str, find, strlen(find))) { - if (str[strlen(find)]==' ') { - strcpy(holdbuf, &str[strlen(find)+1]); + 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); } } @@ -1228,6 +1231,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 @@ -1239,11 +1243,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; } /* @@ -1265,16 +1270,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; } } }