X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fimap%2Fimap_fetch.c;h=0ee327cb87ade858d3cbeb4d5d34b7f06659ce83;hb=0eea6dcc234e0f524bbf2a1d909455d41ed02314;hp=19d92dafd4422147f5ab0ca77250c9620e3b9971;hpb=8c47559cb5ae97ec0fa35660ee16fd61a9451c72;p=citadel.git diff --git a/citadel/modules/imap/imap_fetch.c b/citadel/modules/imap/imap_fetch.c index 19d92dafd..0ee327cb8 100644 --- a/citadel/modules/imap/imap_fetch.c +++ b/citadel/modules/imap/imap_fetch.c @@ -54,14 +54,12 @@ #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" @@ -102,8 +100,9 @@ void imap_fetch_flags(int seq) { cprintf(")"); } + void imap_fetch_internaldate(struct CtdlMessage *msg) { - char buf[SIZ]; + char datebuf[64]; time_t msgdate; if (!msg) return; @@ -114,8 +113,8 @@ void imap_fetch_internaldate(struct CtdlMessage *msg) { msgdate = time(NULL); } - datestring(buf, sizeof buf, msgdate, DATESTRING_IMAP); - cprintf("INTERNALDATE \"%s\"", buf); + datestring(datebuf, sizeof datebuf, msgdate, DATESTRING_IMAP); + cprintf("INTERNALDATE \"%s\"", datebuf); } @@ -128,14 +127,14 @@ void imap_fetch_internaldate(struct CtdlMessage *msg) { * "RFC822.SIZE" size of translated message * "RFC822.TEXT" body only (without leading blank line) */ -void imap_fetch_rfc822(long msgnum, char *whichfmt) { - char buf[SIZ]; - char *ptr = NULL; +void imap_fetch_rfc822(long msgnum, const char *whichfmt) { + const char *ptr = NULL; size_t headers_size, text_size, total_size; size_t bytes_to_send = 0; struct MetaData smi; int need_to_rewrite_metadata = 0; int need_body = 0; + CitContext *CCC = CC; /* Determine whether this particular fetch operation requires * us to fetch the message body from disk. If not, we can save @@ -165,43 +164,37 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) { * client requests something that involves reading the message * body, but we haven't fetched the body yet. */ - if ((IMAP->cached_rfc822_data != NULL) + if ((IMAP->cached_rfc822 != NULL) && (IMAP->cached_rfc822_msgnum == msgnum) && (IMAP->cached_rfc822_withbody || (!need_body)) ) { /* Good to go! */ } - else if (IMAP->cached_rfc822_data != NULL) { + else if (IMAP->cached_rfc822 != NULL) { /* Some other message is cached -- free it */ - free(IMAP->cached_rfc822_data); - IMAP->cached_rfc822_data = NULL; + FreeStrBuf(&IMAP->cached_rfc822); IMAP->cached_rfc822_msgnum = (-1); - IMAP->cached_rfc822_len = 0; } /* At this point, we now can fetch and convert the message iff it's not * the one we had cached. */ - if (IMAP->cached_rfc822_data == NULL) { + if (IMAP->cached_rfc822 == NULL) { /* * Load the message into memory for translation & measurement */ - CC->redirect_buffer = malloc(SIZ); - CC->redirect_len = 0; - CC->redirect_alloc = SIZ; + CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ); CtdlOutputMsg(msgnum, MT_RFC822, (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; + IMAP->cached_rfc822 = CCC->redirect_buffer; + CCC->redirect_buffer = NULL; IMAP->cached_rfc822_msgnum = msgnum; IMAP->cached_rfc822_withbody = need_body; - CC->redirect_buffer = NULL; - CC->redirect_len = 0; - CC->redirect_alloc = 0; - if ( (need_to_rewrite_metadata) && (IMAP->cached_rfc822_len > 0) ) { - smi.meta_rfc822_length = (long)IMAP->cached_rfc822_len; + if ( (need_to_rewrite_metadata) && + (StrLength(IMAP->cached_rfc822) > 0) ) { + smi.meta_rfc822_length = StrLength(IMAP->cached_rfc822); PutMetaData(&smi); } } @@ -215,23 +208,30 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) { total_size = 0; if (need_body) { - ptr = IMAP->cached_rfc822_data; + StrBuf *Line = NewStrBuf(); + ptr = NULL; do { - ptr = memreadline(ptr, buf, sizeof buf); - if (*ptr != 0) { - striplt(buf); - if (IsEmptyStr(buf)) { - headers_size = ptr - IMAP->cached_rfc822_data; + StrBufSipLine(Line, IMAP->cached_rfc822, &ptr); + + if ((StrLength(Line) != 0) && (ptr != StrBufNOTNULL)) + { + StrBufTrim(Line); + if ((StrLength(Line) != 0) && + (ptr != StrBufNOTNULL) ) + { + headers_size = ptr - ChrPtr(IMAP->cached_rfc822); } } - } while ( (headers_size == 0) && (*ptr != 0) ); + } while ( (headers_size == 0) && + (ptr != StrBufNOTNULL) ); - total_size = IMAP->cached_rfc822_len; + total_size = StrLength(IMAP->cached_rfc822); text_size = total_size - headers_size; + FreeStrBuf(&Line); } else { - headers_size = IMAP->cached_rfc822_len; - total_size = IMAP->cached_rfc822_len; + headers_size = + total_size = StrLength(IMAP->cached_rfc822); text_size = 0; } @@ -247,17 +247,17 @@ void imap_fetch_rfc822(long msgnum, char *whichfmt) { } else if (!strcasecmp(whichfmt, "RFC822")) { - ptr = IMAP->cached_rfc822_data; + ptr = ChrPtr(IMAP->cached_rfc822); bytes_to_send = total_size; } else if (!strcasecmp(whichfmt, "RFC822.HEADER")) { - ptr = IMAP->cached_rfc822_data; + ptr = ChrPtr(IMAP->cached_rfc822); bytes_to_send = headers_size; } else if (!strcasecmp(whichfmt, "RFC822.TEXT")) { - ptr = &IMAP->cached_rfc822_data[headers_size]; + ptr = &ChrPtr(IMAP->cached_rfc822)[headers_size]; bytes_to_send = text_size; } @@ -279,7 +279,7 @@ void imap_load_part(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, char *cbid, void *cbuserdata) { - char mbuf2[SIZ]; + char mimebuf2[SIZ]; char *desired_section; desired_section = (char *)cbuserdata; @@ -288,9 +288,9 @@ void imap_load_part(char *name, char *filename, char *partnum, char *disp, client_write(content, length); } - snprintf(mbuf2, sizeof mbuf2, "%s.MIME", partnum); + snprintf(mimebuf2, sizeof mimebuf2, "%s.MIME", partnum); - if (!strcasecmp(desired_section, mbuf2)) { + if (!strcasecmp(desired_section, mimebuf2)) { cprintf("Content-type: %s", cbtype); if (!IsEmptyStr(cbcharset)) cprintf("; charset=\"%s\"", cbcharset); @@ -336,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 */ @@ -397,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(" "); } @@ -441,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 */ @@ -492,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(")"); } @@ -507,107 +507,123 @@ void imap_fetch_envelope(struct CtdlMessage *msg) { * RFC822 headers with no body attached. Its job is to strip that set of * headers down to *only* the ones we're interested in. */ -void imap_strip_headers(char *section) { - char buf[SIZ]; - char *which_fields = NULL; +void imap_strip_headers(StrBuf *section) { + citimap_command Cmd; + StrBuf *which_fields = NULL; int doing_headers = 0; int headers_not = 0; - char *parms[SIZ]; - int num_parms = 0; + int num_parms = 0; int i; - char *boiled_headers = NULL; + StrBuf *boiled_headers = NULL; + StrBuf *Line; int ok = 0; int done_headers = 0; - char *ptr = NULL; + const char *Ptr = NULL; + CitContext *CCC = CC; - if (CC->redirect_buffer == NULL) return; + if (CCC->redirect_buffer == NULL) return; - which_fields = strdup(section); + which_fields = NewStrBufDup(section); - if (!strncasecmp(which_fields, "HEADER.FIELDS", 13)) + if (!strncasecmp(ChrPtr(which_fields), "HEADER.FIELDS", 13)) doing_headers = 1; - if (!strncasecmp(which_fields, "HEADER.FIELDS.NOT", 17)) + if (doing_headers && + !strncasecmp(ChrPtr(which_fields), "HEADER.FIELDS.NOT", 17)) headers_not = 1; - for (i=0; which_fields[i]; ++i) { - if (which_fields[i]=='(') - strcpy(which_fields, &which_fields[i+1]); + for (i=0; i < StrLength(which_fields); ++i) { + if (ChrPtr(which_fields)[i]=='(') + StrBufReplaceToken(which_fields, i, 1, HKEY("")); } - for (i=0; which_fields[i]; ++i) { - if (which_fields[i]==')') { - which_fields[i] = 0; + for (i=0; i < StrLength(which_fields); ++i) { + if (ChrPtr(which_fields)[i]==')') { + StrBufCutAt(which_fields, i, NULL); break; } } - num_parms = imap_parameterize(parms, which_fields); + memset(&Cmd, 0, sizeof(citimap_command)); + Cmd.CmdBuf = which_fields; + num_parms = imap_parameterize(&Cmd); - boiled_headers = malloc(CC->redirect_alloc); - strcpy(boiled_headers, ""); - - ptr = CC->redirect_buffer; + boiled_headers = NewStrBufPlain(NULL, StrLength(CCC->redirect_buffer)); + Line = NewStrBufPlain(NULL, SIZ); + Ptr = NULL; ok = 0; do { - ptr = memreadline(ptr, buf, sizeof buf); - if (!isspace(buf[0])) { + StrBufSipLine(Line, CCC->redirect_buffer, &Ptr); + + if (!isspace(ChrPtr(Line)[0])) { ok = 0; if (doing_headers == 0) ok = 1; else { - if (headers_not) ok = 1; - else ok = 0; - for (i=0; iredirect_buffer, boiled_headers); - CC->redirect_len = strlen(boiled_headers); + FreeStrBuf(&CCC->redirect_buffer); + CCC->redirect_buffer = boiled_headers; - free(which_fields); - free(boiled_headers); + free(Cmd.Params); + FreeStrBuf(&which_fields); + FreeStrBuf(&Line); } /* * Implements the BODY and BODY.PEEK fetch items */ -void imap_fetch_body(long msgnum, char *item, int is_peek) { +void imap_fetch_body(long msgnum, ConstStr item, int is_peek) { struct CtdlMessage *msg = NULL; - char section[SIZ]; - char partial[SIZ]; + StrBuf *section; + StrBuf *partial; int is_partial = 0; size_t pstart, pbytes; int loading_body_now = 0; int need_body = 1; int burn_the_cache = 0; + CitContext *CCC = CC; /* extract section */ - safestrncpy(section, item, sizeof section); - if (strchr(section, '[') != NULL) { - stripallbut(section, '[', ']'); + section = NewStrBufPlain(CKEY(item)); + + if (strchr(ChrPtr(section), '[') != NULL) { + StrBufStripAllBut(section, '[', ']'); } CtdlLogPrintf(CTDL_DEBUG, "Section is: %s%s\n", - section, - IsEmptyStr(section) ? "(empty)" : ""); + ChrPtr(section), + (StrLength(section) == 0) ? "(empty)" : "" + ); /* Burn the cache if we don't have the same section of the * same message again. @@ -619,7 +635,7 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) { else if ( (!IMAP->cached_body_withbody) && (need_body) ) { burn_the_cache = 1; } - else if (strcasecmp(IMAP->cached_bodypart, section)) { + else if (strcasecmp(IMAP->cached_bodypart, ChrPtr(section))) { burn_the_cache = 1; } if (burn_the_cache) { @@ -633,18 +649,19 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) { } /* extract partial */ - safestrncpy(partial, item, sizeof partial); - if (strchr(partial, '<') != NULL) { - stripallbut(partial, '<', '>'); + partial = NewStrBufPlain(CKEY(item)); + if (strchr(ChrPtr(partial), '<') != NULL) { + StrBufStripAllBut(partial, '<', '>'); is_partial = 1; } - if (is_partial == 0) strcpy(partial, ""); - /* if (!IsEmptyStr(partial)) CtdlLogPrintf(CTDL_DEBUG, "Partial is %s\n", partial); */ + if (is_partial == 0) + if (StrLength(partial) > 0) + CtdlLogPrintf(CTDL_DEBUG, + "Partial is %s\n", + ChrPtr(partial)); if (IMAP->cached_body == NULL) { - CC->redirect_buffer = malloc(SIZ); - CC->redirect_len = 0; - CC->redirect_alloc = SIZ; + CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ); loading_body_now = 1; msg = CtdlFetchMessage(msgnum, (need_body ? 1 : 0)); } @@ -655,11 +672,11 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) { /* What we want is already in memory */ } - else if ( (!strcmp(section, "1")) && (msg->cm_format_type != 4) ) { + else if ( (!strcmp(ChrPtr(section), "1")) && (msg->cm_format_type != 4) ) { CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1, SUPPRESS_ENV_TO); } - else if (!strcmp(section, "")) { + else if (StrLength(section) == 0) { CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, SUPPRESS_ENV_TO); } @@ -667,7 +684,7 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) { * If the client asked for just headers, or just particular header * fields, strip it down. */ - else if (!strncasecmp(section, "HEADER", 6)) { + else if (!strncasecmp(ChrPtr(section), "HEADER", 6)) { /* 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. @@ -679,7 +696,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)) { + else if (!strncasecmp(ChrPtr(section), "TEXT", 4)) { CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_NONE, 0, 1, SUPPRESS_ENV_TO); } @@ -695,29 +712,28 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) { } if (loading_body_now) { - IMAP->cached_body = CC->redirect_buffer; - IMAP->cached_body_len = CC->redirect_len; + IMAP->cached_body_len = StrLength(CCC->redirect_buffer); + IMAP->cached_body = SmashStrBuf(&CCC->redirect_buffer); IMAP->cached_bodymsgnum = msgnum; IMAP->cached_body_withbody = need_body; - strcpy(IMAP->cached_bodypart, section); - CC->redirect_buffer = NULL; - CC->redirect_len = 0; - CC->redirect_alloc = 0; + strcpy(IMAP->cached_bodypart, ChrPtr(section)); } if (is_partial == 0) { - cprintf("BODY[%s] {" SIZE_T_FMT "}\r\n", section, IMAP->cached_body_len); + cprintf("BODY[%s] {" SIZE_T_FMT "}\r\n", ChrPtr(section), IMAP->cached_body_len); pstart = 0; pbytes = IMAP->cached_body_len; } else { - sscanf(partial, SIZE_T_FMT "." SIZE_T_FMT, &pstart, &pbytes); + sscanf(ChrPtr(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]<" SIZE_T_FMT "> {" SIZE_T_FMT "}\r\n", section, pstart, pbytes); + cprintf("BODY[%s]<" SIZE_T_FMT "> {" SIZE_T_FMT "}\r\n", ChrPtr(section), pstart, pbytes); } + FreeStrBuf(&partial); + /* Here we go -- output it */ client_write(&IMAP->cached_body[pstart], pbytes); @@ -729,6 +745,7 @@ void imap_fetch_body(long msgnum, char *item, int is_peek) { if (is_peek == 0) { CtdlSetSeen(&msgnum, 1, 1, ctdlsetseen_seen, NULL, NULL); } + FreeStrBuf(§ion); } /* @@ -760,7 +777,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... */ @@ -798,9 +815,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 */ @@ -811,19 +828,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 */ @@ -832,10 +849,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(" "); @@ -874,10 +891,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(")"); @@ -893,14 +910,15 @@ void imap_fetch_bodystructure_part( * Spew the BODYSTRUCTURE data for a message. * */ -void imap_fetch_bodystructure (long msgnum, char *item, +void imap_fetch_bodystructure (long msgnum, const 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; @@ -921,15 +939,10 @@ void imap_fetch_bodystructure (long msgnum, char *item, * to measure it. FIXME use smi cached fields if possible */ - CC->redirect_buffer = malloc(SIZ); - CC->redirect_len = 0; - CC->redirect_alloc = SIZ; + CC->redirect_buffer = NewStrBufPlain(NULL, SIZ); CtdlOutputPreLoadedMsg(msg, MT_RFC822, 0, 0, 1, SUPPRESS_ENV_TO); - rfc822 = CC->redirect_buffer; - rfc822_len = CC->redirect_len; - CC->redirect_buffer = NULL; - CC->redirect_len = 0; - CC->redirect_alloc = 0; + rfc822_len = StrLength(CC->redirect_buffer); + rfc822 = pch = SmashStrBuf(&CC->redirect_buffer); ptr = rfc822; do { @@ -942,7 +955,7 @@ void imap_fetch_bodystructure (long msgnum, char *item, 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 " @@ -967,82 +980,83 @@ void imap_fetch_bodystructure (long msgnum, char *item, * imap_do_fetch() calls imap_do_fetch_msg() to output the data of an * individual message, once it has been selected for output. */ -void imap_do_fetch_msg(int seq, int num_items, char **itemlist) { +void imap_do_fetch_msg(int seq, citimap_command *Cmd) { int i; + citimap *Imap = IMAP; struct CtdlMessage *msg = NULL; int body_loaded = 0; /* Don't attempt to fetch bogus messages or UID's */ if (seq < 1) return; - if (IMAP->msgids[seq-1] < 1L) return; + if (Imap->msgids[seq-1] < 1L) return; buffer_output(); cprintf("* %d FETCH (", seq); - for (i=0; inum_parms; ++i) { /* Fetchable without going to the message store at all */ - if (!strcasecmp(itemlist[i], "UID")) { + if (!strcasecmp(Cmd->Params[i].Key, "UID")) { imap_fetch_uid(seq); } - else if (!strcasecmp(itemlist[i], "FLAGS")) { + else if (!strcasecmp(Cmd->Params[i].Key, "FLAGS")) { imap_fetch_flags(seq-1); } /* Potentially fetchable from cache, if the client requests * stuff from the same message several times in a row. */ - else if (!strcasecmp(itemlist[i], "RFC822")) { - imap_fetch_rfc822(IMAP->msgids[seq-1], itemlist[i]); + else if (!strcasecmp(Cmd->Params[i].Key, "RFC822")) { + imap_fetch_rfc822(Imap->msgids[seq-1], Cmd->Params[i].Key); } - else if (!strcasecmp(itemlist[i], "RFC822.HEADER")) { - imap_fetch_rfc822(IMAP->msgids[seq-1], itemlist[i]); + else if (!strcasecmp(Cmd->Params[i].Key, "RFC822.HEADER")) { + imap_fetch_rfc822(Imap->msgids[seq-1], Cmd->Params[i].Key); } - else if (!strcasecmp(itemlist[i], "RFC822.SIZE")) { - imap_fetch_rfc822(IMAP->msgids[seq-1], itemlist[i]); + else if (!strcasecmp(Cmd->Params[i].Key, "RFC822.SIZE")) { + imap_fetch_rfc822(Imap->msgids[seq-1], Cmd->Params[i].Key); } - else if (!strcasecmp(itemlist[i], "RFC822.TEXT")) { - imap_fetch_rfc822(IMAP->msgids[seq-1], itemlist[i]); + else if (!strcasecmp(Cmd->Params[i].Key, "RFC822.TEXT")) { + imap_fetch_rfc822(Imap->msgids[seq-1], Cmd->Params[i].Key); } /* BODY fetches do their own fetching and caching too. */ - else if (!strncasecmp(itemlist[i], "BODY[", 5)) { - imap_fetch_body(IMAP->msgids[seq-1], itemlist[i], 0); + else if (!strncasecmp(Cmd->Params[i].Key, "BODY[", 5)) { + imap_fetch_body(Imap->msgids[seq-1], Cmd->Params[i], 0); } - else if (!strncasecmp(itemlist[i], "BODY.PEEK[", 10)) { - imap_fetch_body(IMAP->msgids[seq-1], itemlist[i], 1); + else if (!strncasecmp(Cmd->Params[i].Key, "BODY.PEEK[", 10)) { + imap_fetch_body(Imap->msgids[seq-1], Cmd->Params[i], 1); } /* Otherwise, load the message into memory. */ - else if (!strcasecmp(itemlist[i], "BODYSTRUCTURE")) { + else if (!strcasecmp(Cmd->Params[i].Key, "BODYSTRUCTURE")) { if ((msg != NULL) && (!body_loaded)) { CtdlFreeMessage(msg); /* need the whole thing */ msg = NULL; } if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); body_loaded = 1; } - imap_fetch_bodystructure(IMAP->msgids[seq-1], - itemlist[i], msg); + imap_fetch_bodystructure(Imap->msgids[seq-1], + Cmd->Params[i].Key, msg); } - else if (!strcasecmp(itemlist[i], "ENVELOPE")) { + else if (!strcasecmp(Cmd->Params[i].Key, "ENVELOPE")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 0); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 0); body_loaded = 0; } imap_fetch_envelope(msg); } - else if (!strcasecmp(itemlist[i], "INTERNALDATE")) { + else if (!strcasecmp(Cmd->Params[i].Key, "INTERNALDATE")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 0); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 0); body_loaded = 0; } imap_fetch_internaldate(msg); } - if (i != num_items-1) cprintf(" "); + if (i != Cmd->num_parms-1) cprintf(" "); } cprintf(")\r\n"); @@ -1058,8 +1072,28 @@ void imap_do_fetch_msg(int seq, int num_items, char **itemlist) { * imap_fetch() calls imap_do_fetch() to do its actual work, once it's * validated and boiled down the request a bit. */ -void imap_do_fetch(int num_items, char **itemlist) { +void imap_do_fetch(citimap_command *Cmd) { int i; +#if 0 +/* debug output the parsed vector */ + { + int i; + CtdlLogPrintf(CTDL_DEBUG, "----- %ld params \n", + Cmd->num_parms); + + for (i=0; i < Cmd->num_parms; i++) { + if (Cmd->Params[i].len != strlen(Cmd->Params[i].Key)) + CtdlLogPrintf(CTDL_DEBUG, "*********** %ld != %ld : %s\n", + Cmd->Params[i].len, + strlen(Cmd->Params[i].Key), + Cmd->Params[i].Key); + else + CtdlLogPrintf(CTDL_DEBUG, "%ld : %s\n", + Cmd->Params[i].len, + Cmd->Params[i].Key); + }} + +#endif if (IMAP->num_msgs > 0) { for (i = 0; i < IMAP->num_msgs; ++i) { @@ -1073,7 +1107,7 @@ void imap_do_fetch(int num_items, char **itemlist) { /* Get any message marked for fetch. */ if (IMAP->flags[i] & IMAP_SELECTED) { - imap_do_fetch_msg(i+1, num_items, itemlist); + imap_do_fetch_msg(i+1, Cmd); } } } @@ -1086,22 +1120,25 @@ void imap_do_fetch(int num_items, char **itemlist) { * Note that this function *only* looks at the beginning of the string. It * is not a generic search-and-replace function. */ -void imap_macro_replace(char *str, char *find, char *replace) { - char holdbuf[SIZ]; - int findlen; - - findlen = strlen(find); - - if (!strncasecmp(str, find, findlen)) { - if (str[findlen]==' ') { - strcpy(holdbuf, &str[findlen+1]); - strcpy(str, replace); - strcat(str, " "); - strcat(str, holdbuf); +void imap_macro_replace(StrBuf *Buf, long where, + StrBuf *TmpBuf, + char *find, long findlen, + char *replace, long replacelen) +{ + + if (StrLength(Buf) - where > findlen) + return; + + if (!strncasecmp(ChrPtr(Buf) + where, find, findlen)) { + if (ChrPtr(Buf)[where + findlen] == ' ') { + StrBufPlain(TmpBuf, replace, replacelen); + StrBufAppendBufPlain(TmpBuf, HKEY(" "), 0); + StrBufReplaceToken(Buf, where, findlen, + SKEY(TmpBuf)); } - if (str[findlen]==0) { - strcpy(holdbuf, &str[findlen+1]); - strcpy(str, replace); + if (where + findlen == StrLength(Buf)) { + StrBufReplaceToken(Buf, where, findlen, + replace, replacelen); } } } @@ -1113,39 +1150,46 @@ void imap_macro_replace(char *str, char *find, char *replace) { * (What the heck are macros doing in a wire protocol? Are we trying to save * the computer at the other end the trouble of typing a lot of characters?) */ -void imap_handle_macros(char *str) { - int i; +void imap_handle_macros(citimap_command *Cmd) { + long i; int nest = 0; - - for (i=0; str[i]; ++i) { - if (str[i]=='(') ++nest; - if (str[i]=='[') ++nest; - if (str[i]=='<') ++nest; - if (str[i]=='{') ++nest; - if (str[i]==')') --nest; - if (str[i]==']') --nest; - if (str[i]=='>') --nest; - if (str[i]=='}') --nest; + StrBuf *Tmp = NewStrBuf(); + + for (i=0; i < StrLength(Cmd->CmdBuf); ++i) { + char ch = ChrPtr(Cmd->CmdBuf)[i]; + if ((ch=='(') || + (ch=='[') || + (ch=='<') || + (ch=='{')) ++nest; + else if ((ch==')') || + (ch==']') || + (ch=='>') || + (ch=='}')) --nest; if (nest <= 0) { - imap_macro_replace(&str[i], - "ALL", - "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE" + imap_macro_replace(Cmd->CmdBuf, i, + Tmp, + HKEY("ALL"), + HKEY("FLAGS INTERNALDATE RFC822.SIZE ENVELOPE") ); - imap_macro_replace(&str[i], - "BODY", - "BODYSTRUCTURE" + imap_macro_replace(Cmd->CmdBuf, i, + Tmp, + HKEY("BODY"), + HKEY("BODYSTRUCTURE") ); - imap_macro_replace(&str[i], - "FAST", - "FLAGS INTERNALDATE RFC822.SIZE" + imap_macro_replace(Cmd->CmdBuf, i, + Tmp, + HKEY("FAST"), + HKEY("FLAGS INTERNALDATE RFC822.SIZE") ); - imap_macro_replace(&str[i], - "FULL", - "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY" + imap_macro_replace(Cmd->CmdBuf, i, + Tmp, + HKEY("FULL"), + HKEY("FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY") ); } } + FreeStrBuf(&Tmp); } @@ -1155,56 +1199,85 @@ void imap_handle_macros(char *str) { * NOTE: this function alters the string it is fed, and uses it as a buffer * to hold the data for the pointers it returns. */ -int imap_extract_data_items(char **argv, char *items) { - int num_items = 0; +int imap_extract_data_items(citimap_command *Cmd) +{ + int nArgs; int nest = 0; - int i; - char *start; + const char *pch, *end; long initial_len; /* Convert all whitespace to ordinary space characters. */ - for (i=0; items[i]; ++i) { - if (isspace(items[i])) items[i]=' '; + pch = ChrPtr(Cmd->CmdBuf); + end = pch + StrLength(Cmd->CmdBuf); + + while (pch < end) + { + if (isspace(*pch)) + StrBufPeek(Cmd->CmdBuf, pch, 0, ' '); + pch++; } /* Strip leading and trailing whitespace, then strip leading and * trailing parentheses if it's a list */ - striplt(items); - if ( (items[0]=='(') && (items[strlen(items)-1]==')') ) { - items[strlen(items)-1] = 0; - strcpy(items, &items[1]); - striplt(items); + StrBufTrim(Cmd->CmdBuf); + pch = ChrPtr(Cmd->CmdBuf); + if ( (pch[0]=='(') && + (pch[StrLength(Cmd->CmdBuf)-1]==')') ) + { + StrBufCutRight(Cmd->CmdBuf, 1); + StrBufCutLeft(Cmd->CmdBuf, 1); + StrBufTrim(Cmd->CmdBuf); } /* Parse any macro data items */ - imap_handle_macros(items); + imap_handle_macros(Cmd); /* * Now break out the data items. We throw in one trailing space in * order to avoid having to break out the last one manually. */ - strcat(items, " "); - start = items; - initial_len = strlen(items); - for (i=0; i') --nest; - if (items[i]=='}') --nest; - - if (nest <= 0) if (items[i]==' ') { - items[i] = 0; - argv[num_items++] = start; - start = &items[i+1]; + nArgs = StrLength(Cmd->CmdBuf) / 10 + 10; + nArgs = CmdAdjust(Cmd, nArgs, 0); + initial_len = StrLength(Cmd->CmdBuf); + Cmd->num_parms = 0; + Cmd->Params[Cmd->num_parms].Key = pch = ChrPtr(Cmd->CmdBuf); + end = Cmd->Params[Cmd->num_parms].Key + StrLength(Cmd->CmdBuf); + + while (pch < end) + { + if ((*pch=='(') || + (*pch=='[') || + (*pch=='<') || + (*pch=='{')) + ++nest; + + else if ((*pch==')') || + (*pch==']') || + (*pch=='>') || + (*pch=='}')) + --nest; + + if ((nest <= 0) && (*pch==' ')) { + StrBufPeek(Cmd->CmdBuf, pch, 0, '\0'); + Cmd->Params[Cmd->num_parms].len = + pch - Cmd->Params[Cmd->num_parms].Key; + + if (Cmd->num_parms + 1 >= Cmd->avail_parms) { + nArgs = CmdAdjust(Cmd, nArgs * 2, 1); + } + Cmd->num_parms++; + Cmd->Params[Cmd->num_parms].Key = ++pch; } - } + else if (pch + 1 == end) { + Cmd->Params[Cmd->num_parms].len = + pch - Cmd->Params[Cmd->num_parms].Key + 1; - return(num_items); + Cmd->num_parms++; + } + pch ++; + } + return Cmd->num_parms; } @@ -1224,14 +1297,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 @@ -1284,7 +1357,6 @@ void imap_pick_range(char *supplied_range, int is_uid) { } } } - } @@ -1292,61 +1364,63 @@ 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[]) { - char items[SIZ]; - char *itemlist[512]; +void imap_fetch(int num_parms, ConstStr *Params) { + citimap_command Cmd; 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; iCmd.CmdBuf)); + MakeStringOf(Cmd.CmdBuf, 3); - num_items = imap_extract_data_items(itemlist, items); + num_items = imap_extract_data_items(&Cmd); 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); + FreeStrBuf(&Cmd.CmdBuf); + free(Cmd.Params); return; } - imap_do_fetch(num_items, itemlist); - cprintf("%s OK FETCH completed\r\n", parms[0]); + imap_do_fetch(&Cmd); + cprintf("%s OK FETCH completed\r\n", Params[0].Key); + FreeStrBuf(&Cmd.CmdBuf); + free(Cmd.Params); } /* * This function is called by the main command loop. */ -void imap_uidfetch(int num_parms, char *parms[]) { - char items[SIZ]; - char *itemlist[512]; +void imap_uidfetch(int num_parms, ConstStr *Params) { + citimap_command Cmd; int num_items; int i; 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; iCmd.CmdBuf)); - num_items = imap_extract_data_items(itemlist, items); + MakeStringOf(Cmd.CmdBuf, 4); +#if 0 + CtdlLogPrintf(CTDL_DEBUG, "-------%s--------\n", ChrPtr(Cmd.CmdBuf)); +#endif + num_items = imap_extract_data_items(&Cmd); 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); + FreeStrBuf(&Cmd.CmdBuf); + free(Cmd.Params); return; } @@ -1354,16 +1428,23 @@ void imap_uidfetch(int num_parms, char *parms[]) { * (at the beginning) because this is a UID FETCH command */ for (i=0; i= Cmd.avail_parms) + CmdAdjust(&Cmd, Cmd.avail_parms + 1, 1); + memmove(&Cmd.Params[1], + &Cmd.Params[0], + sizeof(ConstStr) * Cmd.num_parms); + + Cmd.num_parms++; + Cmd.Params[0] = (ConstStr){HKEY("UID")}; } - imap_do_fetch(num_items, itemlist); - cprintf("%s OK UID FETCH completed\r\n", parms[0]); + imap_do_fetch(&Cmd); + cprintf("%s OK UID FETCH completed\r\n", Params[0].Key); + FreeStrBuf(&Cmd.CmdBuf); + free(Cmd.Params); }