From 826932b012c26b5ef97a5bbf45acf10fca6acc60 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Sun, 7 Nov 2010 21:29:18 +0100 Subject: [PATCH] Rewrite IMAP-Module to buffer its output - move defines from imap_tools.h into serv_imap.h - switch includes in sequence - we now have IMAP->Reply, which we write into, until IUnbuffer sends it to the client - IReply & IReplyPrintf do now send 'Params[0].Key BAD xxxxxx\r\n' to the client; this makes the code more compact. - IA* append stuff to the outbuffer that we want to send. - replace rumpelstilskin handler lookup by hashlist and central register calls. - replace if's in the sequence separating the handlers by their required pre-conditions by flags on the register call. this should - (hopefully) fix some troubles with evolutions imap, which wouldn't like to read enough chunks until the line ends - speed up stuff like header fetching in huge lists, since we reduce the number of context switches here. --- citadel/modules/imap/imap_acl.c | 95 ++-- citadel/modules/imap/imap_fetch.c | 344 +++++++----- citadel/modules/imap/imap_list.c | 25 +- citadel/modules/imap/imap_metadata.c | 121 +++-- citadel/modules/imap/imap_misc.c | 94 ++-- citadel/modules/imap/imap_search.c | 104 ++-- citadel/modules/imap/imap_store.c | 33 +- citadel/modules/imap/imap_tools.c | 205 ++++--- citadel/modules/imap/imap_tools.h | 53 +- citadel/modules/imap/serv_imap.c | 762 +++++++++++++-------------- citadel/modules/imap/serv_imap.h | 51 ++ 11 files changed, 1036 insertions(+), 851 deletions(-) diff --git a/citadel/modules/imap/imap_acl.c b/citadel/modules/imap/imap_acl.c index 76fc7e4f7..48aae83c0 100644 --- a/citadel/modules/imap/imap_acl.c +++ b/citadel/modules/imap/imap_acl.c @@ -55,8 +55,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_fetch.h" #include "imap_misc.h" #include "genstamp.h" @@ -68,7 +68,7 @@ */ void imap_setacl(int num_parms, ConstStr *Params) { - cprintf("%s BAD not yet implemented FIXME\r\n", Params[0].Key); + IReply("BAD not yet implemented FIXME"); return; } @@ -78,7 +78,7 @@ void imap_setacl(int num_parms, ConstStr *Params) { */ void imap_deleteacl(int num_parms, ConstStr *Params) { - cprintf("%s BAD not yet implemented FIXME\r\n", Params[0].Key); + IReply("BAD not yet implemented FIXME"); return; } @@ -87,9 +87,9 @@ void imap_deleteacl(int num_parms, ConstStr *Params) { * Given the bits returned by CtdlRoomAccess(), populate a string buffer * with IMAP ACL format flags. This code is common to GETACL and MYRIGHTS. */ -void imap_acl_flags(char *rights, int ra) +void imap_acl_flags(StrBuf *rights, int ra) { - strcpy(rights, ""); + FlushStrBuf(rights); /* l - lookup (mailbox is visible to LIST/LSUB commands) * r - read (SELECT the mailbox, perform STATUS et al) @@ -98,9 +98,9 @@ void imap_acl_flags(char *rights, int ra) if ( (ra & UA_KNOWN) /* known rooms */ || ((ra & UA_GOTOALLOWED) && (ra & UA_ZAPPED)) /* zapped rooms */ ) { - strcat(rights, "l"); - strcat(rights, "r"); - strcat(rights, "s"); + StrBufAppendBufPlain(rights, HKEY("l"), 0); + StrBufAppendBufPlain(rights, HKEY("r"), 0); + StrBufAppendBufPlain(rights, HKEY("s"), 0); /* Only output the remaining flags if the room is known */ @@ -110,14 +110,14 @@ void imap_acl_flags(char *rights, int ra) /* p - post (send mail to submission address for mailbox - not enforced) */ /* c - create (CREATE new sub-mailboxes) */ if (ra & UA_POSTALLOWED) { - strcat(rights, "i"); - strcat(rights, "p"); - strcat(rights, "c"); + StrBufAppendBufPlain(rights, HKEY("i"), 0); + StrBufAppendBufPlain(rights, HKEY("p"), 0); + StrBufAppendBufPlain(rights, HKEY("c"), 0); } /* d - delete messages (STORE DELETED flag, perform EXPUNGE) */ if (ra & UA_DELETEALLOWED) { - strcat(rights, "d"); + StrBufAppendBufPlain(rights, HKEY("d"), 0); } /* a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS) */ @@ -130,7 +130,7 @@ void imap_acl_flags(char *rights, int ra) * theoretically prevent compliant clients from attempting to * perform them. * - * strcat(rights, "a"); + * StrBufAppendBufPlain(rights, HKEY("a"), 0); */ } } @@ -148,10 +148,10 @@ void imap_getacl(int num_parms, ConstStr *Params) { struct ctdluser temp; struct cdbdata *cdbus; int ra; - char rights[32]; + StrBuf *rights; if (num_parms != 3) { - cprintf("%s BAD usage error\r\n", Params[0].Key); + IReply("BAD usage error"); return; } @@ -160,7 +160,7 @@ void imap_getacl(int num_parms, ConstStr *Params) { */ ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf("%s NO Invalid mailbox name or access denied\r\n", Params[0].Key); + IReply("NO Invalid mailbox name or access denied"); return; } @@ -173,15 +173,16 @@ void imap_getacl(int num_parms, ConstStr *Params) { } CtdlUserGoto(roomname, 0, 0, &msgs, &new); - cprintf("* ACL"); - cprintf(" "); - imap_strout(&Params[2]); + IAPuts("* ACL "); + IPutCParamStr(2); /* * Traverse the userlist */ + rights = NewStrBuf(); cdb_rewind(CDB_USERS); - while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) { + while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) + { memset(&temp, 0, sizeof temp); memcpy(&temp, cdbus->ptr, sizeof temp); cdb_free(cdbus); @@ -189,15 +190,16 @@ void imap_getacl(int num_parms, ConstStr *Params) { CtdlRoomAccess(&CC->room, &temp, &ra, NULL); if (!IsEmptyStr(temp.fullname)) { imap_acl_flags(rights, ra); - if (!IsEmptyStr(rights)) { - cprintf(" "); + if (StrLength(rights) > 0) { + IAPuts(" "); plain_imap_strout(temp.fullname); - cprintf(" %s", rights); + IAPuts(" "); + iaputs(SKEY( rights)); } } } - - cprintf("\r\n"); + FreeStrBuf(&rights); + IAPuts("\r\n"); /* * If another folder is selected, go back to that room so we can resume @@ -207,7 +209,7 @@ void imap_getacl(int num_parms, ConstStr *Params) { CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } - cprintf("%s OK GETACL completed\r\n", Params[0].Key); + IReply("OK GETACL completed"); } @@ -223,7 +225,7 @@ void imap_listrights(int num_parms, ConstStr *Params) { struct ctdluser temp; if (num_parms != 4) { - cprintf("%s BAD usage error\r\n", Params[0].Key); + IReply("BAD usage error"); return; } @@ -232,7 +234,7 @@ void imap_listrights(int num_parms, ConstStr *Params) { */ ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf("%s NO Invalid mailbox name or access denied\r\n", Params[0].Key); + IReply("NO Invalid mailbox name or access denied"); return; } @@ -248,7 +250,7 @@ void imap_listrights(int num_parms, ConstStr *Params) { free_recipients(valid); } if (ret != 0) { - cprintf("%s NO Invalid user name or access denied\r\n", Params[0].Key); + IReply("NO Invalid user name or access denied"); return; } @@ -264,13 +266,13 @@ void imap_listrights(int num_parms, ConstStr *Params) { /* * Now output the list of rights */ - cprintf("* LISTRIGHTS "); - imap_strout(&Params[2]); - cprintf(" "); - imap_strout(&Params[3]); - cprintf(" "); - plain_imap_strout(""); /* FIXME ... do something here */ - cprintf("\r\n"); + IAPuts("* LISTRIGHTS "); + IPutCParamStr(2); + IAPuts(" "); + IPutCParamStr(3); + IAPuts(" "); + IPutStr(HKEY("")); /* FIXME ... do something here */ + IAPuts("\r\n"); /* * If another folder is selected, go back to that room so we can resume @@ -280,7 +282,7 @@ void imap_listrights(int num_parms, ConstStr *Params) { CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } - cprintf("%s OK LISTRIGHTS completed\r\n", Params[0].Key); + IReply("OK LISTRIGHTS completed"); return; } @@ -294,16 +296,16 @@ void imap_myrights(int num_parms, ConstStr *Params) { int msgs, new; int ret; int ra; - char rights[32]; + StrBuf *rights; if (num_parms != 3) { - cprintf("%s BAD usage error\r\n", Params[0].Key); + IReply("BAD usage error"); return; } ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf("%s NO Invalid mailbox name or access denied\r\n", Params[0].Key); + IReply("NO Invalid mailbox name or access denied"); return; } @@ -317,11 +319,16 @@ void imap_myrights(int num_parms, ConstStr *Params) { CtdlUserGoto(roomname, 0, 0, &msgs, &new); CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL); + rights = NewStrBuf(); imap_acl_flags(rights, ra); - cprintf("* MYRIGHTS "); - imap_strout(&Params[2]); - cprintf(" %s\r\n", rights); + IAPuts("* MYRIGHTS "); + IPutCParamStr(2); + IAPuts(" "); + IPutStr(SKEY(rights)); + IAPuts("\r\n"); + + FreeStrBuf(&rights); /* * If a different folder was previously selected, return there now. @@ -330,6 +337,6 @@ void imap_myrights(int num_parms, ConstStr *Params) { CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } - cprintf("%s OK MYRIGHTS completed\r\n", Params[0].Key); + IReply("OK MYRIGHTS completed"); return; } diff --git a/citadel/modules/imap/imap_fetch.c b/citadel/modules/imap/imap_fetch.c index 29e64ed37..7667ab68a 100644 --- a/citadel/modules/imap/imap_fetch.c +++ b/citadel/modules/imap/imap_fetch.c @@ -56,8 +56,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_fetch.h" #include "genstamp.h" #include "ctdl_module.h" @@ -69,33 +69,39 @@ */ void imap_fetch_uid(int seq) { - cprintf("UID %ld", IMAP->msgids[seq-1]); + IAPrintf("UID %ld", IMAP->msgids[seq-1]); } -void imap_fetch_flags(int seq) { +void imap_fetch_flags(int seq) +{ + citimap *Imap = IMAP; int num_flags_printed = 0; - cprintf("FLAGS ("); - if (IMAP->flags[seq] & IMAP_DELETED) { - if (num_flags_printed > 0) cprintf(" "); - cprintf("\\Deleted"); + IAPuts("FLAGS ("); + if (Imap->flags[seq] & IMAP_DELETED) { + if (num_flags_printed > 0) + IAPuts(" "); + IAPuts("\\Deleted"); ++num_flags_printed; } - if (IMAP->flags[seq] & IMAP_SEEN) { - if (num_flags_printed > 0) cprintf(" "); - cprintf("\\Seen"); + if (Imap->flags[seq] & IMAP_SEEN) { + if (num_flags_printed > 0) + IAPuts(" "); + IAPuts("\\Seen"); ++num_flags_printed; } - if (IMAP->flags[seq] & IMAP_ANSWERED) { - if (num_flags_printed > 0) cprintf(" "); - cprintf("\\Answered"); + if (Imap->flags[seq] & IMAP_ANSWERED) { + if (num_flags_printed > 0) + IAPuts(" "); + IAPuts("\\Answered"); ++num_flags_printed; } - if (IMAP->flags[seq] & IMAP_RECENT) { - if (num_flags_printed > 0) cprintf(" "); - cprintf("\\Recent"); + if (Imap->flags[seq] & IMAP_RECENT) { + if (num_flags_printed > 0) + IAPuts(" "); + IAPuts("\\Recent"); ++num_flags_printed; } - cprintf(")"); + IAPuts(")"); } @@ -112,7 +118,7 @@ void imap_fetch_internaldate(struct CtdlMessage *msg) { } datestring(datebuf, sizeof datebuf, msgdate, DATESTRING_IMAP); - cprintf("INTERNALDATE \"%s\"", datebuf); + IAPrintf( "INTERNALDATE \"%s\"", datebuf); } @@ -126,6 +132,7 @@ void imap_fetch_internaldate(struct CtdlMessage *msg) { * "RFC822.TEXT" body only (without leading blank line) */ void imap_fetch_rfc822(long msgnum, const char *whichfmt) { + citimap *Imap = IMAP; const char *ptr = NULL; size_t headers_size, text_size, total_size; size_t bytes_to_send = 0; @@ -149,7 +156,7 @@ void imap_fetch_rfc822(long msgnum, const char *whichfmt) { if (!strcasecmp(whichfmt, "RFC822.SIZE")) { GetMetaData(&smi, msgnum); if (smi.meta_rfc822_length > 0L) { - cprintf("RFC822.SIZE %ld", smi.meta_rfc822_length); + IAPrintf("RFC822.SIZE %ld", smi.meta_rfc822_length); return; } need_to_rewrite_metadata = 1; @@ -162,21 +169,21 @@ void imap_fetch_rfc822(long msgnum, const char *whichfmt) { * client requests something that involves reading the message * body, but we haven't fetched the body yet. */ - if ((IMAP->cached_rfc822 != NULL) - && (IMAP->cached_rfc822_msgnum == msgnum) - && (IMAP->cached_rfc822_withbody || (!need_body)) ) { + if ((Imap->cached_rfc822 != NULL) + && (Imap->cached_rfc822_msgnum == msgnum) + && (Imap->cached_rfc822_withbody || (!need_body)) ) { /* Good to go! */ } - else if (IMAP->cached_rfc822 != NULL) { + else if (Imap->cached_rfc822 != NULL) { /* Some other message is cached -- free it */ - FreeStrBuf(&IMAP->cached_rfc822); - IMAP->cached_rfc822_msgnum = (-1); + FreeStrBuf(&Imap->cached_rfc822); + Imap->cached_rfc822_msgnum = (-1); } /* At this point, we now can fetch and convert the message iff it's not * the one we had cached. */ - if (IMAP->cached_rfc822 == NULL) { + if (Imap->cached_rfc822 == NULL) { /* * Load the message into memory for translation & measurement */ @@ -185,14 +192,14 @@ void imap_fetch_rfc822(long msgnum, const char *whichfmt) { (need_body ? HEADERS_ALL : HEADERS_FAST), 0, 1, NULL, SUPPRESS_ENV_TO ); - if (!need_body) cprintf("\r\n"); /* extra trailing newline */ - IMAP->cached_rfc822 = CCC->redirect_buffer; + if (!need_body) IAPuts("\r\n"); /* extra trailing newline */ + Imap->cached_rfc822 = CCC->redirect_buffer; CCC->redirect_buffer = NULL; - IMAP->cached_rfc822_msgnum = msgnum; - IMAP->cached_rfc822_withbody = need_body; + Imap->cached_rfc822_msgnum = msgnum; + Imap->cached_rfc822_withbody = need_body; if ( (need_to_rewrite_metadata) && - (StrLength(IMAP->cached_rfc822) > 0) ) { - smi.meta_rfc822_length = StrLength(IMAP->cached_rfc822); + (StrLength(Imap->cached_rfc822) > 0) ) { + smi.meta_rfc822_length = StrLength(Imap->cached_rfc822); PutMetaData(&smi); } } @@ -209,7 +216,7 @@ void imap_fetch_rfc822(long msgnum, const char *whichfmt) { StrBuf *Line = NewStrBuf(); ptr = NULL; do { - StrBufSipLine(Line, IMAP->cached_rfc822, &ptr); + StrBufSipLine(Line, Imap->cached_rfc822, &ptr); if ((StrLength(Line) != 0) && (ptr != StrBufNOTNULL)) { @@ -217,19 +224,19 @@ void imap_fetch_rfc822(long msgnum, const char *whichfmt) { if ((StrLength(Line) != 0) && (ptr != StrBufNOTNULL) ) { - headers_size = ptr - ChrPtr(IMAP->cached_rfc822); + headers_size = ptr - ChrPtr(Imap->cached_rfc822); } } } while ( (headers_size == 0) && (ptr != StrBufNOTNULL) ); - total_size = StrLength(IMAP->cached_rfc822); + total_size = StrLength(Imap->cached_rfc822); text_size = total_size - headers_size; FreeStrBuf(&Line); } else { headers_size = - total_size = StrLength(IMAP->cached_rfc822); + total_size = StrLength(Imap->cached_rfc822); text_size = 0; } @@ -240,27 +247,27 @@ void imap_fetch_rfc822(long msgnum, const char *whichfmt) { headers_size, text_size, total_size); if (!strcasecmp(whichfmt, "RFC822.SIZE")) { - cprintf("RFC822.SIZE " SIZE_T_FMT, total_size); + IAPrintf("RFC822.SIZE " SIZE_T_FMT, total_size); return; } else if (!strcasecmp(whichfmt, "RFC822")) { - ptr = ChrPtr(IMAP->cached_rfc822); + ptr = ChrPtr(Imap->cached_rfc822); bytes_to_send = total_size; } else if (!strcasecmp(whichfmt, "RFC822.HEADER")) { - ptr = ChrPtr(IMAP->cached_rfc822); + ptr = ChrPtr(Imap->cached_rfc822); bytes_to_send = headers_size; } else if (!strcasecmp(whichfmt, "RFC822.TEXT")) { - ptr = &ChrPtr(IMAP->cached_rfc822)[headers_size]; + ptr = &ChrPtr(Imap->cached_rfc822)[headers_size]; bytes_to_send = text_size; } - cprintf("%s {" SIZE_T_FMT "}\r\n", whichfmt, bytes_to_send); - client_write(ptr, bytes_to_send); + IAPrintf("%s {" SIZE_T_FMT "}\r\n", whichfmt, bytes_to_send); + iaputs(ptr, bytes_to_send); } @@ -293,26 +300,37 @@ void imap_load_part(char *name, char *filename, char *partnum, char *disp, snprintf(mimebuf2, sizeof mimebuf2, "%s.MIME", partnum); if (!strcasecmp(desired_section, mimebuf2)) { - cprintf("Content-type: %s", cbtype); - if (!IsEmptyStr(cbcharset)) - cprintf("; charset=\"%s\"", cbcharset); - if (!IsEmptyStr(name)) - cprintf("; name=\"%s\"", name); - cprintf("\r\n"); - if (!IsEmptyStr(encoding)) - cprintf("Content-Transfer-Encoding: %s\r\n", encoding); + IAPuts("Content-type: "); + _iaputs(cbtype); + if (!IsEmptyStr(cbcharset)) { + IAPuts("; charset=\""); + _iaputs(cbcharset); + IAPuts("\""); + } + if (!IsEmptyStr(name)) { + IAPuts("; name=\""); + _iaputs(name); + IAPuts("\""); + } + IAPuts("\r\n"); + if (!IsEmptyStr(encoding)) { + IAPuts("Content-Transfer-Encoding: "); + _iaputs(encoding); + IAPuts("\r\n"); + } if (!IsEmptyStr(encoding)) { - cprintf("Content-Disposition: %s", disp); + IAPuts("Content-Disposition: "); + _iaputs(disp); + if (!IsEmptyStr(filename)) { - cprintf("; filename=\"%s\"", filename); + IAPuts("; filename=\""); + _iaputs(filename); + IAPuts("\""); } - cprintf("\r\n"); + IAPuts("\r\n"); } - cprintf("Content-Length: %ld\r\n", (long)length); - cprintf("\r\n"); + IAPrintf("Content-Length: %ld\r\n\r\n", (long)length); } - - } @@ -328,24 +346,24 @@ void imap_output_envelope_from(struct CtdlMessage *msg) { /* For anonymous messages, it's so easy! */ if (!is_room_aide() && (msg->cm_anon_type == MES_ANONONLY)) { - cprintf("((\"----\" NIL \"x\" \"x.org\")) "); + IAPuts("((\"----\" NIL \"x\" \"x.org\")) "); return; } if (!is_room_aide() && (msg->cm_anon_type == MES_ANONOPT)) { - cprintf("((\"anonymous\" NIL \"x\" \"x.org\")) "); + IAPuts("((\"anonymous\" NIL \"x\" \"x.org\")) "); return; } /* For everything else, we do stuff. */ - cprintf("(("); /* open double-parens */ + IAPuts("(("); /* open double-parens */ plain_imap_strout(msg->cm_fields['A']); /* personal name */ - cprintf(" NIL "); /* source route (not used) */ + IAPuts(" NIL "); /* source route (not used) */ if (msg->cm_fields['F'] != NULL) { process_rfc822_addr(msg->cm_fields['F'], user, node, name); plain_imap_strout(user); /* mailbox name (user id) */ - cprintf(" "); + IAPuts(" "); if (!strcasecmp(node, config.c_nodename)) { plain_imap_strout(config.c_fqdn); } @@ -355,11 +373,11 @@ void imap_output_envelope_from(struct CtdlMessage *msg) { } else { plain_imap_strout(msg->cm_fields['A']); /* mailbox name (user id) */ - cprintf(" "); + IAPuts(" "); plain_imap_strout(msg->cm_fields['N']); /* host name */ } - cprintf(")) "); /* close double-parens */ + IAPuts(")) "); /* close double-parens */ } @@ -379,16 +397,16 @@ void imap_output_envelope_addr(char *addr) { char name[256]; if (addr == NULL) { - cprintf("NIL "); + IAPuts("NIL "); return; } if (IsEmptyStr(addr)) { - cprintf("NIL "); + IAPuts("NIL "); return; } - cprintf("("); + IAPuts("("); /* How many addresses are listed here? */ num_addrs = num_tokens(addr, ','); @@ -398,17 +416,18 @@ void imap_output_envelope_addr(char *addr) { extract_token(individual_addr, addr, i, ',', sizeof individual_addr); striplt(individual_addr); process_rfc822_addr(individual_addr, user, node, name); - cprintf("("); + IAPuts("("); plain_imap_strout(name); - cprintf(" NIL "); + IAPuts(" NIL "); plain_imap_strout(user); - cprintf(" "); + IAPuts(" "); plain_imap_strout(node); - cprintf(")"); - if (i < (num_addrs-1)) cprintf(" "); + IAPuts(")"); + if (i < (num_addrs-1)) + IAPuts(" "); } - cprintf(") "); + IAPuts(") "); } @@ -422,6 +441,7 @@ void imap_fetch_envelope(struct CtdlMessage *msg) { char datestringbuf[SIZ]; time_t msgdate; char *fieldptr = NULL; + long len; if (!msg) return; @@ -440,15 +460,15 @@ void imap_fetch_envelope(struct CtdlMessage *msg) { * be output as NIL, existent fields must be quoted or literalled. * The imap_strout() function conveniently does all this for us. */ - cprintf("ENVELOPE ("); + IAPuts("ENVELOPE ("); /* Date */ plain_imap_strout(datestringbuf); - cprintf(" "); + IAPuts(" "); /* Subject */ plain_imap_strout(msg->cm_fields['U']); - cprintf(" "); + IAPuts(" "); /* From */ imap_output_envelope_from(msg); @@ -495,13 +515,41 @@ void imap_fetch_envelope(struct CtdlMessage *msg) { /* In-reply-to */ fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "In-reply-to"); plain_imap_strout(fieldptr); - cprintf(" "); + IAPuts(" "); if (fieldptr != NULL) free(fieldptr); /* message ID */ - plain_imap_strout(msg->cm_fields['I']); - - cprintf(")"); + len = strlen(msg->cm_fields['I']); + + if ((len == 0) || ( + (msg->cm_fields['I'][0] == '<') && + (msg->cm_fields['I'][len - 1] == '>')) + ) + { + plain_imap_strout(msg->cm_fields['I']); + } + else + { + char *Buf = malloc(len + 3); + long pos = 0; + + if (msg->cm_fields['I'][0] != '<') + { + Buf[pos] = '<'; + pos ++; + } + memcpy(&Buf[pos], msg->cm_fields['I'], len); + pos += len; + if (msg->cm_fields['I'][len] != '>') + { + Buf[pos] = '>'; + pos++; + } + Buf[pos] = '\0'; + IPutStr(Buf, pos); + free(Buf); + } + IAPuts(")"); } /* @@ -615,6 +663,7 @@ void imap_fetch_body(long msgnum, ConstStr item, int is_peek) { int need_body = 1; int burn_the_cache = 0; CitContext *CCC = CC; + citimap *Imap = IMAP; /* extract section */ section = NewStrBufPlain(CKEY(item)); @@ -629,23 +678,23 @@ void imap_fetch_body(long msgnum, ConstStr item, int is_peek) { /* Burn the cache if we don't have the same section of the * same message again. */ - if (IMAP->cached_body != NULL) { - if (IMAP->cached_bodymsgnum != msgnum) { + if (Imap->cached_body != NULL) { + if (Imap->cached_bodymsgnum != msgnum) { burn_the_cache = 1; } - else if ( (!IMAP->cached_body_withbody) && (need_body) ) { + else if ( (!Imap->cached_body_withbody) && (need_body) ) { burn_the_cache = 1; } - else if (strcasecmp(IMAP->cached_bodypart, ChrPtr(section))) { + else if (strcasecmp(Imap->cached_bodypart, ChrPtr(section))) { burn_the_cache = 1; } if (burn_the_cache) { /* Yup, go ahead and burn the cache. */ - free(IMAP->cached_body); - IMAP->cached_body_len = 0; - IMAP->cached_body = NULL; - IMAP->cached_bodymsgnum = (-1); - strcpy(IMAP->cached_bodypart, ""); + free(Imap->cached_body); + Imap->cached_body_len = 0; + Imap->cached_body = NULL; + Imap->cached_bodymsgnum = (-1); + strcpy(Imap->cached_bodypart, ""); } } @@ -659,7 +708,7 @@ void imap_fetch_body(long msgnum, ConstStr item, int is_peek) { CtdlLogPrintf(CTDL_DEBUG, "Partial is <%s>\n", ChrPtr(partial)); } - if (IMAP->cached_body == NULL) { + if (Imap->cached_body == NULL) { CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ); loading_body_now = 1; msg = CtdlFetchMessage(msgnum, (need_body ? 1 : 0)); @@ -712,30 +761,34 @@ void imap_fetch_body(long msgnum, ConstStr item, int is_peek) { } if (loading_body_now) { - 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, ChrPtr(section)); + 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, ChrPtr(section)); } if (is_partial == 0) { - cprintf("BODY[%s] {" SIZE_T_FMT "}\r\n", ChrPtr(section), IMAP->cached_body_len); + IAPuts("BODY["); + iaputs(SKEY(section)); + IAPrintf("] {" SIZE_T_FMT "}\r\n", Imap->cached_body_len); pstart = 0; - pbytes = IMAP->cached_body_len; + pbytes = Imap->cached_body_len; } else { sscanf(ChrPtr(partial), SIZE_T_FMT "." SIZE_T_FMT, &pstart, &pbytes); - if (pbytes > (IMAP->cached_body_len - pstart)) { - pbytes = IMAP->cached_body_len - pstart; + if (pbytes > (Imap->cached_body_len - pstart)) { + pbytes = Imap->cached_body_len - pstart; } - cprintf("BODY[%s]<" SIZE_T_FMT "> {" SIZE_T_FMT "}\r\n", ChrPtr(section), pstart, pbytes); + IAPuts("BODY["); + iaputs(SKEY(section)); + IAPrintf("]<" SIZE_T_FMT "> {" SIZE_T_FMT "}\r\n", pstart, pbytes); } FreeStrBuf(&partial); /* Here we go -- output it */ - client_write(&IMAP->cached_body[pstart], pbytes); + iaputs(&Imap->cached_body[pstart], pbytes); if (msg != NULL) { CtdlFreeMessage(msg); @@ -757,7 +810,7 @@ void imap_fetch_bodystructure_pre( char *cbid, void *cbuserdata ) { - cprintf("("); + IAPuts("("); } @@ -773,16 +826,16 @@ void imap_fetch_bodystructure_post( char subtype[128]; - cprintf(" "); + IAPuts(" "); /* disposition */ extract_token(subtype, cbtype, 1, '/', sizeof subtype); plain_imap_strout(subtype); /* body language */ - /* cprintf(" NIL"); We thought we needed this at one point, but maybe we don't... */ + /* IAPuts(" NIL"); We thought we needed this at one point, but maybe we don't... */ - cprintf(")"); + IAPuts(")"); } @@ -814,25 +867,25 @@ void imap_fetch_bodystructure_part( strcpy(cbsubtype, "PLAIN"); } - cprintf("("); + IAPuts("("); plain_imap_strout(cbmaintype); /* body type */ - cprintf(" "); + IAPuts(" "); plain_imap_strout(cbsubtype); /* body subtype */ - cprintf(" "); + IAPuts(" "); - cprintf("("); /* begin body parameter list */ + IAPuts("("); /* 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\" "); + IAPuts("\"NAME\" "); plain_imap_strout(name); - cprintf(" "); + IAPuts(" "); } - cprintf("\"CHARSET\" "); + IAPuts("\"CHARSET\" "); if (cbcharset == NULL) { plain_imap_strout("US-ASCII"); } @@ -842,10 +895,10 @@ void imap_fetch_bodystructure_part( else { plain_imap_strout(cbcharset); } - cprintf(") "); /* end body parameter list */ + IAPuts(") "); /* end body parameter list */ - cprintf("NIL "); /* Body ID */ - cprintf("NIL "); /* Body description */ + IAPuts("NIL "); /* Body ID */ + IAPuts("NIL "); /* Body description */ if (encoding != NULL) if (encoding[0] != 0) have_encoding = 1; if (have_encoding) { @@ -854,10 +907,10 @@ void imap_fetch_bodystructure_part( else { plain_imap_strout("7BIT"); } - cprintf(" "); + IAPuts(" "); /* The next field is the size of the part in bytes. */ - cprintf("%ld ", (long)length); /* bytes */ + IAPrintf("%ld ", (long)length); /* bytes */ /* The next field is the number of lines in the part, if and only * if the part is TEXT. More gratuitous complexity. @@ -866,7 +919,7 @@ void imap_fetch_bodystructure_part( if (length) for (i=0; icm_fields['M'], NULL, *imap_fetch_bodystructure_part, /* part */ @@ -991,7 +1045,7 @@ void imap_do_fetch_msg(int seq, citimap_command *Cmd) { if (Imap->msgids[seq-1] < 1L) return; buffer_output(); - cprintf("* %d FETCH (", seq); + IAPrintf("* %d FETCH (", seq); for (i=0; inum_parms; ++i) { @@ -1056,10 +1110,10 @@ void imap_do_fetch_msg(int seq, citimap_command *Cmd) { imap_fetch_internaldate(msg); } - if (i != Cmd->num_parms-1) cprintf(" "); + if (i != Cmd->num_parms-1) IAPuts(" "); } - cprintf(")\r\n"); + IAPuts(")\r\n"); unbuffer_output(); if (msg != NULL) { CtdlFreeMessage(msg); @@ -1073,6 +1127,7 @@ void imap_do_fetch_msg(int seq, citimap_command *Cmd) { * validated and boiled down the request a bit. */ void imap_do_fetch(citimap_command *Cmd) { + citimap *Imap = IMAP; int i; #if 0 /* debug output the parsed vector */ @@ -1095,8 +1150,8 @@ void imap_do_fetch(citimap_command *Cmd) { #endif - if (IMAP->num_msgs > 0) { - for (i = 0; i < IMAP->num_msgs; ++i) { + if (Imap->num_msgs > 0) { + for (i = 0; i < Imap->num_msgs; ++i) { /* Abort the fetch loop if the session breaks. * This is important for users who keep mailboxes @@ -1106,7 +1161,7 @@ void imap_do_fetch(citimap_command *Cmd) { if (CC->kill_me) return; /* Get any message marked for fetch. */ - if (IMAP->flags[i] & IMAP_SELECTED) { + if (Imap->flags[i] & IMAP_SELECTED) { imap_do_fetch_msg(i+1, Cmd); } } @@ -1298,13 +1353,13 @@ int imap_extract_data_items(citimap_command *Cmd) * Set is_uid to 1 to fetch by UID instead of sequence number. */ void imap_pick_range(const char *supplied_range, int is_uid) { + citimap *Imap = IMAP; int i; int num_sets; int s; char setstr[SIZ], lostr[SIZ], histr[SIZ]; long lo, hi; char actual_range[SIZ]; - citimap *Imap; /* * Handle the "ALL" macro @@ -1316,7 +1371,6 @@ void imap_pick_range(const 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. */ @@ -1369,7 +1423,7 @@ void imap_fetch(int num_parms, ConstStr *Params) { int num_items; if (num_parms < 4) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -1381,14 +1435,14 @@ void imap_fetch(int num_parms, ConstStr *Params) { num_items = imap_extract_data_items(&Cmd); if (num_items < 1) { - cprintf("%s BAD invalid data item list\r\n", Params[0].Key); + IReply("BAD invalid data item list"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); return; } imap_do_fetch(&Cmd); - cprintf("%s OK FETCH completed\r\n", Params[0].Key); + IReply("OK FETCH completed"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); } @@ -1403,7 +1457,7 @@ void imap_uidfetch(int num_parms, ConstStr *Params) { int have_uid_item = 0; if (num_parms < 5) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -1418,7 +1472,7 @@ void imap_uidfetch(int num_parms, ConstStr *Params) { #endif num_items = imap_extract_data_items(&Cmd); if (num_items < 1) { - cprintf("%s BAD invalid data item list\r\n", Params[0].Key); + IReply("BAD invalid data item list"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); return; @@ -1442,7 +1496,7 @@ void imap_uidfetch(int num_parms, ConstStr *Params) { } imap_do_fetch(&Cmd); - cprintf("%s OK UID FETCH completed\r\n", Params[0].Key); + IReply("OK UID FETCH completed"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); } diff --git a/citadel/modules/imap/imap_list.c b/citadel/modules/imap/imap_list.c index 005f8c88d..015ee1cd3 100644 --- a/citadel/modules/imap/imap_list.c +++ b/citadel/modules/imap/imap_list.c @@ -54,8 +54,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_fetch.h" #include "imap_search.h" #include "imap_store.h" @@ -96,9 +96,9 @@ void imap_list_floors(char *verb, int num_patterns, StrBuf **patterns) } } if (match) { - cprintf("* %s (\\NoSelect \\HasChildren) \"/\" ", verb); + IAPrintf("* %s (\\NoSelect \\HasChildren) \"/\" ", verb); plain_imap_strout(fl->f_name); - cprintf("\r\n"); + IAPuts("\r\n"); } } } @@ -176,9 +176,9 @@ void imap_listroom(struct ctdlroom *qrbuf, void *data) } } if (match) { - cprintf("* %s (%s) \"/\" ", ImapFilter->verb, return_options); + IAPrintf("* %s (%s) \"/\" ", ImapFilter->verb, return_options); plain_imap_strout(MailboxName); - cprintf("\r\n"); + IAPuts("\r\n"); } } } @@ -189,6 +189,7 @@ void imap_listroom(struct ctdlroom *qrbuf, void *data) */ void imap_list(int num_parms, ConstStr *Params) { + citimap *Imap = IMAP; int i, j, paren_nest; ImapRoomListFilter ImapFilter; int selection_left = (-1); @@ -201,7 +202,7 @@ void imap_list(int num_parms, ConstStr *Params) int extended_list_in_use = 0; if (num_parms < 4) { - cprintf("%s BAD arguments invalid\r\n", Params[0].Key); + IReply("BAD arguments invalid"); return; } @@ -268,12 +269,12 @@ void imap_list(int num_parms, ConstStr *Params) /* Strip off the outer parentheses */ if (Params[selection_left].Key[0] == '(') { - TokenCutLeft(&IMAP->Cmd, + TokenCutLeft(&Imap->Cmd, &Params[selection_left], 1); } if (Params[selection_right].Key[Params[selection_right].len-1] == ')') { - TokenCutRight(&IMAP->Cmd, + TokenCutRight(&Imap->Cmd, &Params[selection_right], 1); } @@ -368,11 +369,11 @@ void imap_list(int num_parms, ConstStr *Params) /* Might as well look for these while we're in here... */ if (Params[i].Key[0] == '(') - TokenCutLeft(&IMAP->Cmd, + TokenCutLeft(&Imap->Cmd, &Params[i], 1); if (Params[i].Key[Params[i].len-1] == ')') - TokenCutRight(&IMAP->Cmd, + TokenCutRight(&Imap->Cmd, &Params[i], 1); @@ -402,7 +403,7 @@ void imap_list(int num_parms, ConstStr *Params) * reference parameter. */ if ( (StrLength(ImapFilter.patterns[0]) == 0) && (extended_list_in_use == 0) ) { - cprintf("* %s (\\Noselect) \"/\" \"\"\r\n", ImapFilter.verb); + IAPrintf("* %s (\\Noselect) \"/\" \"\"\r\n", ImapFilter.verb); } /* Non-empty mailbox names, and any form of the extended LIST command, @@ -424,5 +425,5 @@ void imap_list(int num_parms, ConstStr *Params) } - cprintf("%s OK %s completed\r\n", Params[0].Key, ImapFilter.verb); + IReplyPrintf("OK %s completed", ImapFilter.verb); } diff --git a/citadel/modules/imap/imap_metadata.c b/citadel/modules/imap/imap_metadata.c index 5ffa1f5b0..73a2f71a3 100644 --- a/citadel/modules/imap/imap_metadata.c +++ b/citadel/modules/imap/imap_metadata.c @@ -57,8 +57,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_fetch.h" #include "imap_misc.h" #include "genstamp.h" @@ -84,7 +84,7 @@ void imap_setmetadata(int num_parms, ConstStr *Params) { visit vbuf; if (num_parms != 6) { - cprintf("%s BAD usage error\r\n", Params[0].Key); + IReply("BAD usage error"); return; } @@ -92,7 +92,7 @@ void imap_setmetadata(int num_parms, ConstStr *Params) { * Don't allow other types of metadata to be set */ if (strcasecmp(Params[3].Key, "/vendor/kolab/folder-type")) { - cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", Params[0].Key); + IReply("NO [METADATA TOOMANY] SETMETADATA failed"); return; } @@ -103,7 +103,7 @@ void imap_setmetadata(int num_parms, ConstStr *Params) { setting_user_value = 1; /* per-user view */ } else { - cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", Params[0].Key); + IReply("NO [METADATA TOOMANY] SETMETADATA failed"); return; } @@ -136,8 +136,7 @@ void imap_setmetadata(int num_parms, ConstStr *Params) { ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf("%s NO Invalid mailbox name or access denied\r\n", - Params[0].Key); + IReply("NO Invalid mailbox name or access denied"); return; } @@ -161,7 +160,7 @@ void imap_setmetadata(int num_parms, ConstStr *Params) { if (setting_user_value) { - cprintf("%s OK SETANNOTATION complete\r\n", Params[0].Key); + IReply("OK SETANNOTATION complete"); } /* If this is a "value.shared" set operation, we are allowed to perform it @@ -176,12 +175,12 @@ void imap_setmetadata(int num_parms, ConstStr *Params) { CtdlGetRoomLock(&CC->room, CC->room.QRname); CC->room.QRdefaultview = set_view; CtdlPutRoomLock(&CC->room); - cprintf("%s OK SETANNOTATION complete\r\n", Params[0].Key); + IReply("OK SETANNOTATION complete"); } /* If we got to this point, we don't have permission to set the default view. */ else { - cprintf("%s NO [METADATA TOOMANY] SETMETADATA failed\r\n", Params[0].Key); + IReply("NO [METADATA TOOMANY] SETMETADATA failed"); } /* @@ -205,16 +204,16 @@ void imap_getmetadata(int num_parms, ConstStr *Params) { char savedroom[ROOMNAMELEN]; int msgs, new; int ret; + int found = 0; if (num_parms > 5) { - cprintf("%s BAD usage error\r\n", Params[0].Key); + IReply("BAD usage error"); return; } ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf("%s NO Invalid mailbox name or access denied\r\n", - Params[0].Key); + IReply("NO Invalid mailbox name or access denied"); return; } @@ -227,32 +226,42 @@ void imap_getmetadata(int num_parms, ConstStr *Params) { } CtdlUserGoto(roomname, 0, 0, &msgs, &new); - cprintf("* METADATA "); - imap_strout(&Params[2]); - cprintf(" \"/vendor/kolab/folder-type\" (\"value.shared\" \""); + IAPuts("* METADATA "); + IPutCParamStr(2); + IAPuts(" \"/vendor/kolab/folder-type\" (\"value.shared\" \""); /* If it's one of our hard-coded default rooms, we know what to do... */ - if (!strcasecmp(&CC->room.QRname[11], MAILROOM)) { - cprintf("mail.inbox"); - } - else if (!strcasecmp(&CC->room.QRname[11], SENTITEMS)) { - cprintf("mail.sentitems"); - } - else if (!strcasecmp(&CC->room.QRname[11], USERDRAFTROOM)) { - cprintf("mail.drafts"); - } - else if (!strcasecmp(&CC->room.QRname[11], USERCALENDARROOM)) { - cprintf("event.default"); - } - else if (!strcasecmp(&CC->room.QRname[11], USERCONTACTSROOM)) { - cprintf("contact.default"); - } - else if (!strcasecmp(&CC->room.QRname[11], USERNOTESROOM)) { - cprintf("note.default"); - } - else if (!strcasecmp(&CC->room.QRname[11], USERTASKSROOM)) { - cprintf("task.default"); + if (CC->room.QRname[10] == '.') + { + if (!strcasecmp(&CC->room.QRname[11], MAILROOM)) { + found = 1; + IAPuts("mail.inbox"); + } + else if (!strcasecmp(&CC->room.QRname[11], SENTITEMS)) { + found = 1; + IAPuts("mail.sentitems"); + } + else if (!strcasecmp(&CC->room.QRname[11], USERDRAFTROOM)) { + found = 1; + IAPuts("mail.drafts"); + } + else if (!strcasecmp(&CC->room.QRname[11], USERCALENDARROOM)) { + found = 1; + IAPuts("event.default"); + } + else if (!strcasecmp(&CC->room.QRname[11], USERCONTACTSROOM)) { + found = 1; + IAPuts("contact.default"); + } + else if (!strcasecmp(&CC->room.QRname[11], USERNOTESROOM)) { + found = 1; + IAPuts("note.default"); + } + else if (!strcasecmp(&CC->room.QRname[11], USERTASKSROOM)) { + found = 1; + IAPuts("task.default"); + } } /* Otherwise, use the view for this room to determine the type of data. @@ -261,31 +270,33 @@ void imap_getmetadata(int num_parms, ConstStr *Params) { * user's view might only make changes to presentation. It also saves us * an extra database access because we don't need to load the visit record. */ - - else if (CC->room.QRdefaultview == VIEW_CALENDAR) { - cprintf("event"); - } - else if (CC->room.QRdefaultview == VIEW_ADDRESSBOOK) { - cprintf("contact"); - } - else if (CC->room.QRdefaultview == VIEW_TASKS) { - cprintf("task"); - } - else if (CC->room.QRdefaultview == VIEW_NOTES) { - cprintf("note"); - } - else if (CC->room.QRdefaultview == VIEW_JOURNAL) { - cprintf("journal"); + if (!found) + { + if (CC->room.QRdefaultview == VIEW_CALENDAR) { + IAPuts("event"); + } + else if (CC->room.QRdefaultview == VIEW_ADDRESSBOOK) { + IAPuts("contact"); + } + else if (CC->room.QRdefaultview == VIEW_TASKS) { + IAPuts("task"); + } + else if (CC->room.QRdefaultview == VIEW_NOTES) { + IAPuts("note"); + } + else if (CC->room.QRdefaultview == VIEW_JOURNAL) { + IAPuts("journal"); + } } - /* If none of the above conditions were met, consider it an ordinary mailbox. */ - else { - cprintf("mail"); + + if (!found) { + IAPuts("mail"); } /* "mail.outbox" and "junkemail" are not implemented. */ - cprintf("\")\r\n"); + IAPuts("\")\r\n"); /* * If a different folder was previously selected, return there now. @@ -294,7 +305,7 @@ void imap_getmetadata(int num_parms, ConstStr *Params) { CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } - cprintf("%s OK GETMETADATA complete\r\n", Params[0].Key); + IReply("OK GETMETADATA complete"); return; } diff --git a/citadel/modules/imap/imap_misc.c b/citadel/modules/imap/imap_misc.c index fba0c767e..500c2dc6a 100644 --- a/citadel/modules/imap/imap_misc.c +++ b/citadel/modules/imap/imap_misc.c @@ -53,8 +53,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_fetch.h" #include "imap_misc.h" #include "genstamp.h" @@ -69,13 +69,14 @@ * validated and boiled down the request a bit. (returns 0 on success) */ int imap_do_copy(const char *destination_folder) { + citimap *Imap = IMAP; int i; char roomname[ROOMNAMELEN]; struct ctdlroom qrbuf; long *selected_msgs = NULL; int num_selected = 0; - if (IMAP->num_msgs < 1) { + if (Imap->num_msgs < 1) { return(0); } @@ -85,12 +86,12 @@ int imap_do_copy(const char *destination_folder) { /* * Copy all the message pointers in one shot. */ - selected_msgs = malloc(sizeof(long) * IMAP->num_msgs); + selected_msgs = malloc(sizeof(long) * Imap->num_msgs); if (selected_msgs == NULL) return(-1); - for (i = 0; i < IMAP->num_msgs; ++i) { - if (IMAP->flags[i] & IMAP_SELECTED) { - selected_msgs[num_selected++] = IMAP->msgids[i]; + for (i = 0; i < Imap->num_msgs; ++i) { + if (Imap->flags[i] & IMAP_SELECTED) { + selected_msgs[num_selected++] = Imap->msgids[i]; } } @@ -119,19 +120,19 @@ int imap_do_copy(const char *destination_folder) { answ_yes = malloc(num_selected * sizeof(long)); answ_no = malloc(num_selected * sizeof(long)); - for (i = 0; i < IMAP->num_msgs; ++i) { - if (IMAP->flags[i] & IMAP_SELECTED) { - if (IMAP->flags[i] & IMAP_SEEN) { - seen_yes[num_seen_yes++] = IMAP->msgids[i]; + for (i = 0; i < Imap->num_msgs; ++i) { + if (Imap->flags[i] & IMAP_SELECTED) { + if (Imap->flags[i] & IMAP_SEEN) { + seen_yes[num_seen_yes++] = Imap->msgids[i]; } - if ((IMAP->flags[i] & IMAP_SEEN) == 0) { - seen_no[num_seen_no++] = IMAP->msgids[i]; + if ((Imap->flags[i] & IMAP_SEEN) == 0) { + seen_no[num_seen_no++] = Imap->msgids[i]; } - if (IMAP->flags[i] & IMAP_ANSWERED) { - answ_yes[num_answ_yes++] = IMAP->msgids[i]; + if (Imap->flags[i] & IMAP_ANSWERED) { + answ_yes[num_answ_yes++] = Imap->msgids[i]; } - if ((IMAP->flags[i] & IMAP_ANSWERED) == 0) { - answ_no[num_answ_no++] = IMAP->msgids[i]; + if ((Imap->flags[i] & IMAP_ANSWERED) == 0) { + answ_no[num_answ_no++] = Imap->msgids[i]; } } } @@ -163,23 +164,24 @@ int imap_do_copy(const char *destination_folder) { * can get this done quite easily. */ void imap_output_copyuid_response(void) { + citimap *Imap = IMAP; int i; int num_output = 0; - for (i = 0; i < IMAP->num_msgs; ++i) { - if (IMAP->flags[i] & IMAP_SELECTED) { + for (i = 0; i < Imap->num_msgs; ++i) { + if (Imap->flags[i] & IMAP_SELECTED) { ++num_output; if (num_output == 1) { - cprintf("[COPYUID "); + IAPuts("[COPYUID "); } else if (num_output > 1) { - cprintf(","); + IAPuts(","); } - cprintf("%ld", IMAP->msgids[i]); + IAPrintf("%ld", Imap->msgids[i]); } } if (num_output > 0) { - cprintf("] "); + IAPuts("] "); } } @@ -191,7 +193,7 @@ void imap_copy(int num_parms, ConstStr *Params) { int ret; if (num_parms != 4) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -199,18 +201,18 @@ void imap_copy(int num_parms, ConstStr *Params) { imap_pick_range(Params[2].Key, 0); } else { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } ret = imap_do_copy(Params[3].Key); if (!ret) { - cprintf("%s OK ", Params[0].Key); + IAPrintf("%s OK ", Params[0].Key); imap_output_copyuid_response(); - cprintf("COPY completed\r\n"); + IAPuts("COPY completed\r\n"); } else { - cprintf("%s NO COPY failed (error %d)\r\n", Params[0].Key, ret); + IReplyPrintf("NO COPY failed (error %d)\r\n", ret); } } @@ -220,7 +222,7 @@ void imap_copy(int num_parms, ConstStr *Params) { void imap_uidcopy(int num_parms, ConstStr *Params) { if (num_parms != 5) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -228,17 +230,17 @@ void imap_uidcopy(int num_parms, ConstStr *Params) { imap_pick_range(Params[3].Key, 1); } else { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } if (imap_do_copy(Params[4].Key) == 0) { - cprintf("%s OK ", Params[0].Key); + IAPrintf("%s OK ", Params[0].Key); imap_output_copyuid_response(); - cprintf("UID COPY completed\r\n"); + IAPuts("UID COPY completed\r\n"); } else { - cprintf("%s NO UID COPY failed\r\n", Params[0].Key); + IReply("NO UID COPY failed"); } } @@ -293,13 +295,13 @@ void imap_append(int num_parms, ConstStr *Params) { citimap *Imap; if (num_parms < 4) { - cprintf("%s BAD usage error\r\n", Params[0].Key); + IReply("BAD usage error"); return; } if ( (Params[num_parms-1].Key[0] != '{') || (Params[num_parms-1].Key[Params[num_parms-1].len-1] != '}') ) { - cprintf("%s BAD no message literal supplied\r\n", Params[0].Key); + IReply("BAD no message literal supplied"); return; } @@ -320,8 +322,7 @@ void imap_append(int num_parms, ConstStr *Params) { literal_length = atol(&Params[num_parms-1].Key[1]); if (literal_length < 1) { - cprintf("%s BAD Message length must be at least 1.\r\n", - Params[0].Key); + IReply("BAD Message length must be at least 1."); return; } @@ -331,17 +332,19 @@ void imap_append(int num_parms, ConstStr *Params) { Imap->TransmittedMessage = NewStrBufPlain(NULL, literal_length); if (Imap->TransmittedMessage == NULL) { - cprintf("%s NO Cannot allocate memory.\r\n", Params[0].Key); + IReply("NO Cannot allocate memory."); return; } - cprintf("+ Transmit message now.\r\n"); + IAPrintf("+ Transmit message now.\r\n"); + + IUnbuffer (); bytes_transferred = 0; client_read_blob(Imap->TransmittedMessage, literal_length, config.c_sleeping); if ((ret < 0) || (StrLength(Imap->TransmittedMessage) < literal_length)) { - cprintf("%s NO Read failed.\r\n", Params[0].Key); + IReply("NO Read failed."); return; } @@ -360,8 +363,7 @@ void imap_append(int num_parms, ConstStr *Params) { ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf("%s NO Invalid mailbox name or access denied\r\n", - Params[0].Key); + IReply("NO Invalid mailbox name or access denied"); return; } @@ -399,7 +401,7 @@ void imap_append(int num_parms, ConstStr *Params) { if (ret) { /* Nope ... print an error message */ - cprintf("%s NO %s\r\n", Params[0].Key, errbuf); + IReplyPrintf("NO %s", errbuf); } else { @@ -408,12 +410,12 @@ void imap_append(int num_parms, ConstStr *Params) { new_msgnum = CtdlSubmitMsg(msg, NULL, "", 0); } if (new_msgnum >= 0L) { - cprintf("%s OK [APPENDUID %ld %ld] APPEND completed\r\n", - Params[0].Key, GLOBAL_UIDVALIDITY_VALUE, new_msgnum); + IReplyPrintf("OK [APPENDUID %ld %ld] APPEND completed", + GLOBAL_UIDVALIDITY_VALUE, new_msgnum); } else { - cprintf("%s BAD Error %ld saving message to disk.\r\n", - Params[0].Key, new_msgnum); + IReplyPrintf("BAD Error %ld saving message to disk.\r\n", + new_msgnum); } } diff --git a/citadel/modules/imap/imap_search.c b/citadel/modules/imap/imap_search.c index 001a96ce8..8a8673e6a 100644 --- a/citadel/modules/imap/imap_search.c +++ b/citadel/modules/imap/imap_search.c @@ -58,8 +58,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_fetch.h" #include "imap_search.h" #include "genstamp.h" @@ -77,6 +77,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, int num_items, ConstStr *itemlist, int is_uid) { + citimap *Imap = IMAP; int match = 0; int is_not = 0; int is_or = 0; @@ -113,7 +114,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, } else if (!strcasecmp(itemlist[pos].Key, "ANSWERED")) { - if (IMAP->flags[seq-1] & IMAP_ANSWERED) { + if (Imap->flags[seq-1] & IMAP_ANSWERED) { match = 1; } ++pos; @@ -121,7 +122,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "BCC")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -138,7 +139,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "BEFORE")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -164,7 +165,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, /* Otherwise, we have to do a slow search. */ else { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -179,7 +180,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "CC")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -203,21 +204,21 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, } else if (!strcasecmp(itemlist[pos].Key, "DELETED")) { - if (IMAP->flags[seq-1] & IMAP_DELETED) { + if (Imap->flags[seq-1] & IMAP_DELETED) { match = 1; } ++pos; } else if (!strcasecmp(itemlist[pos].Key, "DRAFT")) { - if (IMAP->flags[seq-1] & IMAP_DRAFT) { + if (Imap->flags[seq-1] & IMAP_DRAFT) { match = 1; } ++pos; } else if (!strcasecmp(itemlist[pos].Key, "FLAGGED")) { - if (IMAP->flags[seq-1] & IMAP_FLAGGED) { + if (Imap->flags[seq-1] & IMAP_FLAGGED) { match = 1; } ++pos; @@ -225,7 +226,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "FROM")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -247,7 +248,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, * examining the message body. */ if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } @@ -277,7 +278,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "LARGER")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -289,14 +290,14 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, } else if (!strcasecmp(itemlist[pos].Key, "NEW")) { - if ( (IMAP->flags[seq-1] & IMAP_RECENT) && (!(IMAP->flags[seq-1] & IMAP_SEEN))) { + if ( (Imap->flags[seq-1] & IMAP_RECENT) && (!(Imap->flags[seq-1] & IMAP_SEEN))) { match = 1; } ++pos; } else if (!strcasecmp(itemlist[pos].Key, "OLD")) { - if (!(IMAP->flags[seq-1] & IMAP_RECENT)) { + if (!(Imap->flags[seq-1] & IMAP_RECENT)) { match = 1; } ++pos; @@ -304,7 +305,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "ON")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -319,14 +320,14 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, } else if (!strcasecmp(itemlist[pos].Key, "RECENT")) { - if (IMAP->flags[seq-1] & IMAP_RECENT) { + if (Imap->flags[seq-1] & IMAP_RECENT) { match = 1; } ++pos; } else if (!strcasecmp(itemlist[pos].Key, "SEEN")) { - if (IMAP->flags[seq-1] & IMAP_SEEN) { + if (Imap->flags[seq-1] & IMAP_SEEN) { match = 1; } ++pos; @@ -334,7 +335,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "SENTBEFORE")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -350,7 +351,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "SENTON")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -366,7 +367,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "SENTSINCE")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -382,7 +383,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "SINCE")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -398,7 +399,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "SMALLER")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -411,7 +412,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "SUBJECT")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -424,7 +425,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "TEXT")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -439,7 +440,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, else if (!strcasecmp(itemlist[pos].Key, "TO")) { if (msg == NULL) { - msg = CtdlFetchMessage(IMAP->msgids[seq-1], 1); + msg = CtdlFetchMessage(Imap->msgids[seq-1], 1); need_to_free_msg = 1; } if (msg != NULL) { @@ -460,7 +461,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, /* FIXME this is b0rken. fix it. */ else if (!strcasecmp(itemlist[pos].Key, "UID")) { - if (is_msg_in_sequence_set(itemlist[pos+1].Key, IMAP->msgids[seq-1])) { + if (is_msg_in_sequence_set(itemlist[pos+1].Key, Imap->msgids[seq-1])) { match = 1; } pos += 2; @@ -472,28 +473,28 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, */ else if (!strcasecmp(itemlist[pos].Key, "UNANSWERED")) { - if ((IMAP->flags[seq-1] & IMAP_ANSWERED) == 0) { + if ((Imap->flags[seq-1] & IMAP_ANSWERED) == 0) { match = 1; } ++pos; } else if (!strcasecmp(itemlist[pos].Key, "UNDELETED")) { - if ((IMAP->flags[seq-1] & IMAP_DELETED) == 0) { + if ((Imap->flags[seq-1] & IMAP_DELETED) == 0) { match = 1; } ++pos; } else if (!strcasecmp(itemlist[pos].Key, "UNDRAFT")) { - if ((IMAP->flags[seq-1] & IMAP_DRAFT) == 0) { + if ((Imap->flags[seq-1] & IMAP_DRAFT) == 0) { match = 1; } ++pos; } else if (!strcasecmp(itemlist[pos].Key, "UNFLAGGED")) { - if ((IMAP->flags[seq-1] & IMAP_FLAGGED) == 0) { + if ((Imap->flags[seq-1] & IMAP_FLAGGED) == 0) { match = 1; } ++pos; @@ -505,7 +506,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, } else if (!strcasecmp(itemlist[pos].Key, "UNSEEN")) { - if ((IMAP->flags[seq-1] & IMAP_SEEN) == 0) { + if ((Imap->flags[seq-1] & IMAP_SEEN) == 0) { match = 1; } ++pos; @@ -542,6 +543,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg, * validated and boiled down the request a bit. */ void imap_do_search(int num_items, ConstStr *itemlist, int is_uid) { + citimap *Imap = IMAP; int i, j, k; int fts_num_msgs = 0; long *fts_msgs = NULL; @@ -555,12 +557,12 @@ void imap_do_search(int num_items, ConstStr *itemlist, int is_uid) { for (i=0; iCmd, + TokenCutLeft(&Imap->Cmd, &itemlist[i], 1); } if (itemlist[i].Key[itemlist[i].len-1] == ')') { - TokenCutRight(&IMAP->Cmd, + TokenCutRight(&Imap->Cmd, &itemlist[i], 1); } @@ -574,23 +576,23 @@ void imap_do_search(int num_items, ConstStr *itemlist, int is_uid) { if (!strcasecmp(itemlist[i].Key, "BODY")) { CtdlModuleDoSearch(&fts_num_msgs, &fts_msgs, itemlist[i+1].Key, "fulltext"); if (fts_num_msgs > 0) { - for (j=0; j < IMAP->num_msgs; ++j) { - if (IMAP->flags[j] & IMAP_SELECTED) { + for (j=0; j < Imap->num_msgs; ++j) { + if (Imap->flags[j] & IMAP_SELECTED) { is_in_list = 0; for (k=0; kmsgids[j] == fts_msgs[k]) { + if (Imap->msgids[j] == fts_msgs[k]) { ++is_in_list; } } } if (!is_in_list) { - IMAP->flags[j] = IMAP->flags[j] & ~IMAP_SELECTED; + Imap->flags[j] = Imap->flags[j] & ~IMAP_SELECTED; } } } else { /* no hits on the index; disqualify every message */ - for (j=0; j < IMAP->num_msgs; ++j) { - IMAP->flags[j] = IMAP->flags[j] & ~IMAP_SELECTED; + for (j=0; j < Imap->num_msgs; ++j) { + Imap->flags[j] = Imap->flags[j] & ~IMAP_SELECTED; } } if (fts_msgs) { @@ -601,24 +603,24 @@ void imap_do_search(int num_items, ConstStr *itemlist, int is_uid) { /* Now go through the messages and apply all search criteria. */ buffer_output(); - cprintf("* SEARCH "); - if (IMAP->num_msgs > 0) - for (i = 0; i < IMAP->num_msgs; ++i) - if (IMAP->flags[i] & IMAP_SELECTED) { + IAPuts("* SEARCH "); + if (Imap->num_msgs > 0) + for (i = 0; i < Imap->num_msgs; ++i) + if (Imap->flags[i] & IMAP_SELECTED) { if (imap_do_search_msg(i+1, NULL, num_items, itemlist, is_uid)) { if (num_results != 0) { - cprintf(" "); + IAPuts(" "); } if (is_uid) { - cprintf("%ld", IMAP->msgids[i]); + IAPrintf("%ld", Imap->msgids[i]); } else { - cprintf("%d", i+1); + IAPrintf("%d", i+1); } ++num_results; } } - cprintf("\r\n"); + IAPuts("\r\n"); unbuffer_output(); } @@ -630,7 +632,7 @@ void imap_search(int num_parms, ConstStr *Params) { int i; if (num_parms < 3) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -639,7 +641,7 @@ void imap_search(int num_parms, ConstStr *Params) { } imap_do_search(num_parms-2, &Params[2], 0); - cprintf("%s OK SEARCH completed\r\n", Params[0].Key); + IReply("OK SEARCH completed"); } /* @@ -649,7 +651,7 @@ void imap_uidsearch(int num_parms, ConstStr *Params) { int i; if (num_parms < 4) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -658,7 +660,7 @@ void imap_uidsearch(int num_parms, ConstStr *Params) { } imap_do_search(num_parms-3, &Params[3], 1); - cprintf("%s OK UID SEARCH completed\r\n", Params[0].Key); + IReply("OK UID SEARCH completed"); } diff --git a/citadel/modules/imap/imap_store.c b/citadel/modules/imap/imap_store.c index a25908708..dceefbbbe 100644 --- a/citadel/modules/imap/imap_store.c +++ b/citadel/modules/imap/imap_store.c @@ -55,8 +55,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_fetch.h" #include "imap_store.h" #include "genstamp.h" @@ -69,17 +69,17 @@ * We also implement the ".SILENT" protocol option here. :( */ void imap_do_store_msg(int seq, const char *oper, unsigned int bits_to_twiddle) { - + citimap *Imap = IMAP; if (!strncasecmp(oper, "FLAGS", 5)) { - IMAP->flags[seq] &= IMAP_MASK_SYSTEM; - IMAP->flags[seq] |= bits_to_twiddle; + Imap->flags[seq] &= IMAP_MASK_SYSTEM; + Imap->flags[seq] |= bits_to_twiddle; } else if (!strncasecmp(oper, "+FLAGS", 6)) { - IMAP->flags[seq] |= bits_to_twiddle; + Imap->flags[seq] |= bits_to_twiddle; } else if (!strncasecmp(oper, "-FLAGS", 6)) { - IMAP->flags[seq] &= (~bits_to_twiddle); + Imap->flags[seq] &= (~bits_to_twiddle); } } @@ -162,9 +162,9 @@ void imap_do_store(citimap_command *Cmd) { imap_do_store_msg(i, oper, bits_to_twiddle); if (!silent) { - cprintf("* %d FETCH (", i+1); + IAPrintf("* %d FETCH (", i+1); imap_fetch_flags(i); - cprintf(")\r\n"); + IAPuts(")\r\n"); } } @@ -203,7 +203,6 @@ void imap_do_store(citimap_command *Cmd) { imap_do_expunge(); imap_rescan_msgids(); } - } @@ -215,7 +214,7 @@ void imap_store(int num_parms, ConstStr *Params) { int num_items; if (num_parms < 3) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -223,7 +222,7 @@ void imap_store(int num_parms, ConstStr *Params) { imap_pick_range(Params[2].Key, 0); } else { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -233,14 +232,14 @@ void imap_store(int num_parms, ConstStr *Params) { num_items = imap_extract_data_items(&Cmd); if (num_items < 1) { - cprintf("%s BAD invalid data item list\r\n", Params[0].Key); + IReply("BAD invalid data item list"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); return; } imap_do_store(&Cmd); - cprintf("%s OK STORE completed\r\n", Params[0].Key); + IReply("OK STORE completed"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); } @@ -253,7 +252,7 @@ void imap_uidstore(int num_parms, ConstStr *Params) { int num_items; if (num_parms < 4) { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -261,7 +260,7 @@ void imap_uidstore(int num_parms, ConstStr *Params) { imap_pick_range(Params[3].Key, 1); } else { - cprintf("%s BAD invalid parameters\r\n", Params[0].Key); + IReply("BAD invalid parameters"); return; } @@ -271,14 +270,14 @@ void imap_uidstore(int num_parms, ConstStr *Params) { num_items = imap_extract_data_items(&Cmd); if (num_items < 1) { - cprintf("%s BAD invalid data item list\r\n", Params[0].Key); + IReply("BAD invalid data item list"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); return; } imap_do_store(&Cmd); - cprintf("%s OK UID STORE completed\r\n", Params[0].Key); + IReply("OK UID STORE completed"); FreeStrBuf(&Cmd.CmdBuf); free(Cmd.Params); } diff --git a/citadel/modules/imap/imap_tools.c b/citadel/modules/imap/imap_tools.c index d0f4c2cac..0af9406d4 100644 --- a/citadel/modules/imap/imap_tools.c +++ b/citadel/modules/imap/imap_tools.c @@ -19,17 +19,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define SHOW_ME_VAPPEND_PRINTF #include #include #include #include #include +#include #include #include "citadel.h" #include "sysdep_decls.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "ctdl_module.h" #ifndef HAVE_SNPRINTF @@ -381,59 +383,6 @@ static int cfrommap(int c) return c; } -/* Output a string to the IMAP client, either as a literal or quoted. - * (We do a literal if it has any double-quotes or backslashes.) */ - -void plain_imap_strout(char *buf) -{ - int i; - int is_literal = 0; - long len; - - if (buf == NULL) { /* yeah, we handle this */ - cprintf("NIL"); - return; - } - - len = strlen(buf); - for (i = 0; i < len; ++i) { - if ((buf[i] == '\"') || (buf[i] == '\\')) - is_literal = 1; - } - - if (is_literal) { - cprintf("{%ld}\r\n%s", len, buf); - } else { - cprintf("\"%s\"", buf); - } -} - -/* Output a string to the IMAP client, either as a literal or quoted. - * (We do a literal if it has any double-quotes or backslashes.) */ - -void imap_strout(ConstStr *args) -{ - int i; - int is_literal = 0; - - if ((args == NULL) || (args->len == 0)) - { /* yeah, we handle this */ - cprintf("NIL"); - return; - } - - for (i = 0; i < args->len; ++i) { - if ((args->Key[i] == '\"') || (args->Key[i] == '\\')) - is_literal = 1; - } - - if (is_literal) { - cprintf("{%ld}\r\n%s", args->len, args->Key); - } else { - cprintf("\"%s\"", args->Key); - } -} - @@ -743,22 +692,22 @@ void imap_ial_out(struct internet_address_list *ialist) struct internet_address_list *iptr; if (ialist == NULL) { - cprintf("NIL"); + IAPuts("NIL"); return; } - cprintf("("); + IAPuts("("); for (iptr = ialist; iptr != NULL; iptr = iptr->next) { - cprintf("("); + IAPuts("("); plain_imap_strout(iptr->ial_name); - cprintf(" NIL "); + IAPuts(" NIL "); plain_imap_strout(iptr->ial_user); - cprintf(" "); + IAPuts(" "); plain_imap_strout(iptr->ial_node); - cprintf(")"); + IAPuts(")"); } - cprintf(")"); + IAPuts(")"); } @@ -974,3 +923,137 @@ int imap_datecmp(const char *datestr, time_t msgtime) { return(0); } + + + + +void IAPrintf(const char *Format, ...) +{ + va_list arg_ptr; + + va_start(arg_ptr, Format); + StrBufVAppendPrintf(IMAP->Reply, Format, arg_ptr); + va_end(arg_ptr); +} + +void iaputs(const char *Str, long Len) +{ + StrBufAppendBufPlain(IMAP->Reply, Str, Len, 0); +} + +void ireply(const char *Msg, long len) +{ + citimap *Imap = IMAP; + + StrBufAppendBufPlain(Imap->Reply, + CKEY(Imap->Cmd.Params[0]), 0); + StrBufAppendBufPlain(Imap->Reply, + HKEY(" "), 0); + StrBufAppendBufPlain(Imap->Reply, + Msg, len, 0); + + StrBufAppendBufPlain(Imap->Reply, + HKEY("\r\n"), 0); + +} + +void IReplyPrintf(const char *Format, ...) +{ + citimap *Imap = IMAP; + va_list arg_ptr; + + + StrBufAppendBufPlain(Imap->Reply, + CKEY(Imap->Cmd.Params[0]), 0); + + StrBufAppendBufPlain(Imap->Reply, + HKEY(" "), 0); + + va_start(arg_ptr, Format); + StrBufVAppendPrintf(IMAP->Reply, Format, arg_ptr); + va_end(arg_ptr); + + StrBufAppendBufPlain(Imap->Reply, + HKEY("\r\n"), 0); + +} + + + +/* Output a string to the IMAP client, either as a literal or quoted. + * (We do a literal if it has any double-quotes or backslashes.) */ + +void plain_imap_strout(char *buf) +{ + int i; + int is_literal = 0; + long Len; + citimap *Imap = IMAP; + + if (buf == NULL) { /* yeah, we handle this */ + IAPuts("NIL"); + return; + } + + Len = strlen(buf); + for (i = 0; i < Len; ++i) { + if ((buf[i] == '\"') || (buf[i] == '\\')) + is_literal = 1; + } + + if (is_literal) { + StrBufAppendPrintf(Imap->Reply, "{%ld}\r\n", Len); + StrBufAppendBufPlain(Imap->Reply, buf, Len, 0); + } else { + StrBufAppendBufPlain(Imap->Reply, + HKEY("\""), 0); + StrBufAppendBufPlain(Imap->Reply, + buf, Len, 0); + StrBufAppendBufPlain(Imap->Reply, + HKEY("\""), 0); + } +} + + +/* Output a string to the IMAP client, either as a literal or quoted. + * (We do a literal if it has any double-quotes or backslashes.) */ + + +void IPutStr(const char *Msg, long Len) +{ + int i; + int is_literal = 0; + citimap *Imap = IMAP; + + + if ((Msg == NULL) || (Len == 0)) + { /* yeah, we handle this */ + StrBufAppendBufPlain(Imap->Reply, HKEY("NIL"), 0); + return; + } + + for (i = 0; i < Len; ++i) { + if ((Msg[i] == '\"') || (Msg[i] == '\\')) + is_literal = 1; + } + + if (is_literal) { + StrBufAppendPrintf(Imap->Reply, "{%ld}\r\n", Len); + StrBufAppendBufPlain(Imap->Reply, Msg, Len, 0); + } else { + StrBufAppendBufPlain(Imap->Reply, + HKEY("\""), 0); + StrBufAppendBufPlain(Imap->Reply, + Msg, Len, 0); + StrBufAppendBufPlain(Imap->Reply, + HKEY("\""), 0); + } +} + +void IUnbuffer (void) +{ + citimap *Imap = IMAP; + + cputbuf(Imap->Reply); + FlushStrBuf(Imap->Reply); +} diff --git a/citadel/modules/imap/imap_tools.h b/citadel/modules/imap/imap_tools.h index d9b72cc51..52afbacbc 100644 --- a/citadel/modules/imap/imap_tools.h +++ b/citadel/modules/imap/imap_tools.h @@ -1,19 +1,3 @@ -/* - * FDELIM defines which character we want to use as a folder delimiter - * in room names. Originally we used a forward slash, but that caused - * rooms with names like "Sent/Received Pages" to get delimited, so we - * changed it to a backslash. This is completely irrelevant to how Citadel - * speaks to IMAP clients -- the delimiter used in the IMAP protocol is - * a vertical bar, which is illegal in Citadel room names anyway. - */ -#define FDELIM '\\' - -typedef struct __citimap_command { - StrBuf *CmdBuf; /* our current commandline; gets chopped into: */ - ConstStr *Params; /* Commandline tokens */ - int num_parms; /* Number of Commandline tokens available */ - int avail_parms; /* Number of ConstStr args is big */ -} citimap_command; /* * since we work with shifted pointers to ConstStrs in some places, @@ -38,6 +22,8 @@ int CmdAdjust(citimap_command *Cmd, void imap_strout(ConstStr *args); +void imap_strbuffer(StrBuf *Reply, ConstStr *args); +void plain_imap_strbuffer(StrBuf *Reply, char *buf); void plain_imap_strout(char *buf); int imap_parameterize(citimap_command *Cmd); void imap_mailboxname(char *buf, int bufsize, struct ctdlroom *qrbuf); @@ -47,10 +33,33 @@ int imap_is_message_set(const char *); int imap_mailbox_matches_pattern(const char *pattern, char *mailboxname); int imap_datecmp(const char *datestr, time_t msgtime); + + + + +/* Imap Append Printf, send to the outbuffer */ +void IAPrintf(const char *Format, ...); + +void iaputs(const char *Str, long Len); +#define IAPuts(Msg) iaputs(HKEY(Msg)) +/* give it a naughty name since its ugly. */ +#define _iaputs(Msg) iaputs(Msg, strlen(Msg)) + +/* outputs a static message prepended by the sequence no */ +void ireply(const char *Msg, long len); +#define IReply(msg) ireply(HKEY(msg)) +/* outputs a dynamic message prepended by the sequence no */ +void IReplyPrintf(const char *Format, ...); + + +/* output a string like that {%ld}%s */ +void IPutStr(const char *Msg, long Len); +#define IPutCStr(_ConstStr) IPutStr(CKEY(_ConstStr)) +#define IPutCParamStr(n) IPutStr(CKEY(Params[n])) + /* - * Flags that may be returned by imap_roomname() - * (the lower eight bits will be the floor number) - */ -#define IR_MAILBOX 0x0100 /* Mailbox */ -#define IR_EXISTS 0x0200 /* Room exists (not implemented) */ -#define IR_BABOON 0x0000 /* Just had to put this here :) */ +void plain_imap_strout(char *buf) +void imap_strout(ConstStr *args) +*/ + + diff --git a/citadel/modules/imap/serv_imap.c b/citadel/modules/imap/serv_imap.c index cd0de575d..753396213 100644 --- a/citadel/modules/imap/serv_imap.c +++ b/citadel/modules/imap/serv_imap.c @@ -57,8 +57,8 @@ #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "imap_tools.h" #include "serv_imap.h" +#include "imap_tools.h" #include "imap_list.h" #include "imap_fetch.h" #include "imap_search.h" @@ -69,6 +69,73 @@ #include "ctdl_module.h" +HashList *ImapCmds = NULL; +void registerImapCMD(const char *First, long FLen, + const char *Second, long SLen, + imap_handler H, + int Flags) +{ + imap_handler_hook *h; + + h = (imap_handler_hook*) malloc(sizeof(imap_handler_hook)); + memset(h, 0, sizeof(imap_handler_hook)); + + h->Flags = Flags; + h->h = H; + if (SLen == 0) { + Put(ImapCmds, First, FLen, h, NULL); + } + else { + char CMD[SIZ]; + memcpy(CMD, First, FLen); + memcpy(CMD+FLen, Second, SLen); + CMD[FLen+SLen] = '\0'; + Put(ImapCmds, CMD, FLen + SLen, h, NULL); + } +} + +const imap_handler_hook *imap_lookup(int num_parms, ConstStr *Params) +{ + void *v; + citimap *Imap = IMAP; + + if (num_parms < 1) + return NULL; + + /* we abuse the Reply-buffer for uppercasing... */ + StrBufPlain(Imap->Reply, CKEY(Params[1])); + StrBufUpCase(Imap->Reply); + + CtdlLogPrintf(CTDL_DEBUG, "---- Looking up [%s] -----", + ChrPtr(Imap->Reply)); + if (GetHash(ImapCmds, SKEY(Imap->Reply), &v)) + { + CtdlLogPrintf(CTDL_DEBUG, "Found. \n"); + FlushStrBuf(Imap->Reply); + return (imap_handler_hook *) v; + } + + if (num_parms == 1) + { + CtdlLogPrintf(CTDL_DEBUG, "NOT Found. \n"); + FlushStrBuf(Imap->Reply); + return NULL; + } + + CtdlLogPrintf(CTDL_DEBUG, "---- Looking up [%s] -----", + ChrPtr(Imap->Reply)); + StrBufAppendBufPlain(Imap->Reply, CKEY(Params[2]), 0); + StrBufUpCase(Imap->Reply); + if (GetHash(ImapCmds, SKEY(Imap->Reply), &v)) + { + CtdlLogPrintf(CTDL_DEBUG, "Found. \n"); + FlushStrBuf(Imap->Reply); + return (imap_handler_hook *) v; + } + CtdlLogPrintf(CTDL_DEBUG, "NOT Found. \n"); + FlushStrBuf(Imap->Reply); + return NULL; +} /* imap_rename() uses this struct containing list of rooms to rename */ struct irl { @@ -91,17 +158,18 @@ struct irlparms { */ void imap_free_msgids(void) { - if (IMAP->msgids != NULL) { - free(IMAP->msgids); - IMAP->msgids = NULL; - IMAP->num_msgs = 0; - IMAP->num_alloc = 0; + citimap *Imap = IMAP; + if (Imap->msgids != NULL) { + free(Imap->msgids); + Imap->msgids = NULL; + Imap->num_msgs = 0; + Imap->num_alloc = 0; } - if (IMAP->flags != NULL) { - free(IMAP->flags); - IMAP->flags = NULL; + if (Imap->flags != NULL) { + free(Imap->flags); + Imap->flags = NULL; } - IMAP->last_mtime = (-1); + Imap->last_mtime = (-1); } @@ -126,6 +194,7 @@ void imap_free_transmitted_message(void) */ void imap_set_seen_flags(int first_msg) { + citimap *Imap = IMAP; visit vbuf; int i; int num_sets; @@ -133,13 +202,13 @@ void imap_set_seen_flags(int first_msg) char setstr[64], lostr[64], histr[64]; long lo, hi; - if (IMAP->num_msgs < 1) return; + if (Imap->num_msgs < 1) return; CtdlGetRelationship(&vbuf, &CC->user, &CC->room); - for (i = first_msg; i < IMAP->num_msgs; ++i) { - IMAP->flags[i] = IMAP->flags[i] & ~IMAP_SEEN; - IMAP->flags[i] |= IMAP_RECENT; - IMAP->flags[i] = IMAP->flags[i] & ~IMAP_ANSWERED; + for (i = first_msg; i < Imap->num_msgs; ++i) { + Imap->flags[i] = Imap->flags[i] & ~IMAP_SEEN; + Imap->flags[i] |= IMAP_RECENT; + Imap->flags[i] = Imap->flags[i] & ~IMAP_ANSWERED; } /* @@ -163,10 +232,10 @@ void imap_set_seen_flags(int first_msg) lo = atol(lostr); hi = atol(histr); - for (i = first_msg; i < IMAP->num_msgs; ++i) { - if ((IMAP->msgids[i] >= lo) && (IMAP->msgids[i] <= hi)){ - IMAP->flags[i] |= IMAP_SEEN; - IMAP->flags[i] = IMAP->flags[i] & ~IMAP_RECENT; + for (i = first_msg; i < Imap->num_msgs; ++i) { + if ((Imap->msgids[i] >= lo) && (Imap->msgids[i] <= hi)){ + Imap->flags[i] |= IMAP_SEEN; + Imap->flags[i] = Imap->flags[i] & ~IMAP_RECENT; } } } @@ -189,9 +258,9 @@ void imap_set_seen_flags(int first_msg) lo = atol(lostr); hi = atol(histr); - for (i = first_msg; i < IMAP->num_msgs; ++i) { - if ((IMAP->msgids[i] >= lo) && (IMAP->msgids[i] <= hi)){ - IMAP->flags[i] |= IMAP_ANSWERED; + for (i = first_msg; i < Imap->num_msgs; ++i) { + if ((Imap->msgids[i] >= lo) && (Imap->msgids[i] <= hi)){ + Imap->flags[i] |= IMAP_ANSWERED; } } } @@ -209,15 +278,16 @@ void imap_set_seen_flags(int first_msg) */ void imap_add_single_msgid(long msgnum, void *userdata) { + citimap *Imap = IMAP; - ++IMAP->num_msgs; - if (IMAP->num_msgs > IMAP->num_alloc) { - IMAP->num_alloc += REALLOC_INCREMENT; - IMAP->msgids = realloc(IMAP->msgids, (IMAP->num_alloc * sizeof(long)) ); - IMAP->flags = realloc(IMAP->flags, (IMAP->num_alloc * sizeof(long)) ); + ++Imap->num_msgs; + if (Imap->num_msgs > Imap->num_alloc) { + Imap->num_alloc += REALLOC_INCREMENT; + Imap->msgids = realloc(Imap->msgids, (Imap->num_alloc * sizeof(long)) ); + Imap->flags = realloc(Imap->flags, (Imap->num_alloc * sizeof(long)) ); } - IMAP->msgids[IMAP->num_msgs - 1] = msgnum; - IMAP->flags[IMAP->num_msgs - 1] = 0; + Imap->msgids[Imap->num_msgs - 1] = msgnum; + Imap->flags[Imap->num_msgs - 1] = 0; } @@ -228,8 +298,9 @@ void imap_add_single_msgid(long msgnum, void *userdata) void imap_load_msgids(void) { struct cdbdata *cdbfr; + citimap *Imap = IMAP; - if (IMAP->selected == 0) { + if (Imap->selected == 0) { CtdlLogPrintf(CTDL_ERR, "imap_load_msgids() can't run; no room selected\n"); return; @@ -240,16 +311,16 @@ void imap_load_msgids(void) /* Load the message list */ cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); if (cdbfr != NULL) { - IMAP->msgids = malloc(cdbfr->len); - memcpy(IMAP->msgids, cdbfr->ptr, cdbfr->len); - IMAP->num_msgs = cdbfr->len / sizeof(long); - IMAP->num_alloc = cdbfr->len / sizeof(long); + Imap->msgids = malloc(cdbfr->len); + memcpy(Imap->msgids, cdbfr->ptr, cdbfr->len); + Imap->num_msgs = cdbfr->len / sizeof(long); + Imap->num_alloc = cdbfr->len / sizeof(long); cdb_free(cdbfr); } - if (IMAP->num_msgs) { - IMAP->flags = malloc(IMAP->num_alloc * sizeof(long)); - memset(IMAP->flags, 0, (IMAP->num_alloc * sizeof(long)) ); + if (Imap->num_msgs) { + Imap->flags = malloc(Imap->num_alloc * sizeof(long)); + memset(Imap->flags, 0, (Imap->num_alloc * sizeof(long)) ); } imap_set_seen_flags(0); @@ -261,7 +332,7 @@ void imap_load_msgids(void) */ void imap_rescan_msgids(void) { - + citimap *Imap = IMAP; int original_num_msgs = 0; long original_highest = 0L; int i, j, jstart; @@ -271,7 +342,7 @@ void imap_rescan_msgids(void) int num_msgs = 0; int num_recent = 0; - if (IMAP->selected == 0) { + if (Imap->selected == 0) { CtdlLogPrintf(CTDL_ERR, "imap_load_msgids() can't run; no room selected\n"); return; } @@ -281,7 +352,7 @@ void imap_rescan_msgids(void) * If not, we can avoid this rescan. */ CtdlGetRoom(&CC->room, CC->room.QRname); - if (IMAP->last_mtime == CC->room.QRmtime) { /* No changes! */ + if (Imap->last_mtime == CC->room.QRmtime) { /* No changes! */ return; } @@ -305,14 +376,14 @@ void imap_rescan_msgids(void) /* * Check to see if any of the messages we know about have been expunged */ - if (IMAP->num_msgs > 0) { + if (Imap->num_msgs > 0) { jstart = 0; - for (i = 0; i < IMAP->num_msgs; ++i) { + for (i = 0; i < Imap->num_msgs; ++i) { message_still_exists = 0; if (num_msgs > 0) { for (j = jstart; j < num_msgs; ++j) { - if (msglist[j] == IMAP->msgids[i]) { + if (msglist[j] == Imap->msgids[i]) { message_still_exists = 1; jstart = j; break; @@ -321,22 +392,22 @@ void imap_rescan_msgids(void) } if (message_still_exists == 0) { - cprintf("* %d EXPUNGE\r\n", i + 1); + IAPrintf("* %d EXPUNGE\r\n", i + 1); /* Here's some nice stupid nonsense. When a * message is expunged, we have to slide all * the existing messages up in the message * array. */ - --IMAP->num_msgs; - memcpy(&IMAP->msgids[i], - &IMAP->msgids[i + 1], + --Imap->num_msgs; + memcpy(&Imap->msgids[i], + &Imap->msgids[i + 1], (sizeof(long) * - (IMAP->num_msgs - i))); - memcpy(&IMAP->flags[i], - &IMAP->flags[i + 1], + (Imap->num_msgs - i))); + memcpy(&Imap->flags[i], + &Imap->flags[i + 1], (sizeof(long) * - (IMAP->num_msgs - i))); + (Imap->num_msgs - i))); --i; } @@ -347,9 +418,9 @@ void imap_rescan_msgids(void) /* * Remember how many messages were here before we re-scanned. */ - original_num_msgs = IMAP->num_msgs; - if (IMAP->num_msgs > 0) { - original_highest = IMAP->msgids[IMAP->num_msgs - 1]; + original_num_msgs = Imap->num_msgs; + if (Imap->num_msgs > 0) { + original_highest = Imap->msgids[Imap->num_msgs - 1]; } else { original_highest = 0L; } @@ -371,22 +442,22 @@ void imap_rescan_msgids(void) /* * If new messages have arrived, tell the client about them. */ - if (IMAP->num_msgs > original_num_msgs) { + if (Imap->num_msgs > original_num_msgs) { for (j = 0; j < num_msgs; ++j) { - if (IMAP->flags[j] & IMAP_RECENT) { + if (Imap->flags[j] & IMAP_RECENT) { ++num_recent; } } - cprintf("* %d EXISTS\r\n", IMAP->num_msgs); - cprintf("* %d RECENT\r\n", num_recent); + IAPrintf("* %d EXISTS\r\n", Imap->num_msgs); + IAPrintf("* %d RECENT\r\n", num_recent); } if (num_msgs != 0) { free(msglist); } - IMAP->last_mtime = CC->room.QRmtime; + Imap->last_mtime = CC->room.QRmtime; } @@ -396,13 +467,14 @@ void imap_rescan_msgids(void) */ void imap_cleanup_function(void) { + citimap *Imap = IMAP; - /* Don't do this stuff if this is not a IMAP session! */ + /* Don't do this stuff if this is not a Imap session! */ if (CC->h_command_function != imap_command_loop) return; /* If there is a mailbox selected, auto-expunge it. */ - if (IMAP->selected) { + if (Imap->selected) { imap_do_expunge(); } @@ -410,21 +482,22 @@ void imap_cleanup_function(void) imap_free_msgids(); imap_free_transmitted_message(); - if (IMAP->cached_rfc822 != NULL) { - FreeStrBuf(&IMAP->cached_rfc822); - IMAP->cached_rfc822_msgnum = (-1); - IMAP->cached_rfc822_withbody = 0; + if (Imap->cached_rfc822 != NULL) { + FreeStrBuf(&Imap->cached_rfc822); + Imap->cached_rfc822_msgnum = (-1); + Imap->cached_rfc822_withbody = 0; } - if (IMAP->cached_body != NULL) { - free(IMAP->cached_body); - IMAP->cached_body = NULL; - IMAP->cached_body_len = 0; - IMAP->cached_bodymsgnum = (-1); + if (Imap->cached_body != NULL) { + free(Imap->cached_body); + Imap->cached_body = NULL; + Imap->cached_body_len = 0; + Imap->cached_bodymsgnum = (-1); } - FreeStrBuf(&IMAP->Cmd.CmdBuf); - if (IMAP->Cmd.Params != NULL) free(IMAP->Cmd.Params); - free(IMAP); + FreeStrBuf(&Imap->Cmd.CmdBuf); + FreeStrBuf(&Imap->Reply); + if (Imap->Cmd.Params != NULL) free(Imap->Cmd.Params); + free(Imap); CtdlLogPrintf(CTDL_DEBUG, "Finished IMAP cleanup hook\n"); } @@ -434,14 +507,14 @@ void imap_cleanup_function(void) * output this stuff in other places as well) */ void imap_output_capability_string(void) { - cprintf("CAPABILITY IMAP4REV1 NAMESPACE ID AUTH=PLAIN AUTH=LOGIN UIDPLUS"); + IAPuts("CAPABILITY IMAP4REV1 NAMESPACE ID AUTH=PLAIN AUTH=LOGIN UIDPLUS"); #ifdef HAVE_OPENSSL - if (!CC->redirect_ssl) cprintf(" STARTTLS"); + if (!CC->redirect_ssl) IAPuts(" STARTTLS"); #endif #ifndef DISABLE_IMAP_ACL - cprintf(" ACL"); + IAPuts(" ACL"); #endif /* We are building a partial implementation of METADATA for the sole purpose @@ -449,7 +522,7 @@ void imap_output_capability_string(void) { * It is not a full RFC5464 implementation, but it should refuse non-Bynari * metadata in a compatible and graceful way. */ - cprintf(" METADATA"); + IAPuts(" METADATA"); /* * LIST-EXTENDED was originally going to be required by the METADATA extension. @@ -458,7 +531,7 @@ void imap_output_capability_string(void) { * If you uncomment this declaration you are responsible for writing a lot of new * code. * - * cprintf(" LIST-EXTENDED") + * IAPuts(" LIST-EXTENDED") */ } @@ -468,10 +541,10 @@ void imap_output_capability_string(void) { */ void imap_capability(int num_parms, ConstStr *Params) { - cprintf("* "); + IAPuts("* "); imap_output_capability_string(); - cprintf("\r\n"); - cprintf("%s OK CAPABILITY completed\r\n", Params[0].Key); + IAPuts("\r\n"); + IReply("OK CAPABILITY completed"); } @@ -486,8 +559,8 @@ void imap_capability(int num_parms, ConstStr *Params) */ void imap_id(int num_parms, ConstStr *Params) { - cprintf("* ID NIL\r\n"); - cprintf("%s OK ID completed\r\n", Params[0].Key); + IAPuts("* ID NIL\r\n"); + IReply("OK ID completed"); } @@ -496,23 +569,30 @@ void imap_id(int num_parms, ConstStr *Params) */ void imap_greeting(void) { - - strcpy(CC->cs_clientname, "IMAP session"); - CC->session_specific_data = malloc(sizeof(citimap)); - memset(IMAP, 0, sizeof(citimap)); - IMAP->authstate = imap_as_normal; - IMAP->cached_rfc822_msgnum = (-1); - IMAP->cached_rfc822_withbody = 0; - - if (CC->nologin) + citimap *Imap; + CitContext *CCC = CC; + + strcpy(CCC->cs_clientname, "IMAP session"); + CCC->session_specific_data = malloc(sizeof(citimap)); + Imap = (citimap *)CCC->session_specific_data; + memset(Imap, 0, sizeof(citimap)); + Imap->authstate = imap_as_normal; + Imap->cached_rfc822_msgnum = (-1); + Imap->cached_rfc822_withbody = 0; + Imap->Reply = NewStrBufPlain(NULL, SIZ * 10); /* 40k */ + + if (CCC->nologin) { - cprintf("* BYE; Server busy, try later\r\n"); - CC->kill_me = 1; + IAPuts("* BYE; Server busy, try later\r\n"); + CCC->kill_me = 1; + IUnbuffer(); return; } - cprintf("* OK ["); + + IAPuts("* OK ["); imap_output_capability_string(); - cprintf("] %s IMAP4rev1 %s ready\r\n", config.c_fqdn, CITADEL); + IAPrintf("] %s IMAP4rev1 %s ready\r\n", config.c_fqdn, CITADEL); + IUnbuffer(); } @@ -537,33 +617,34 @@ void imap_login(int num_parms, ConstStr *Params) switch (num_parms) { case 3: if (Params[2].Key[0] == '{') { - cprintf("+ go ahead\r\n"); + IAPuts("+ go ahead\r\n"); IMAP->authstate = imap_as_expecting_multilineusername; strcpy(IMAP->authseq, Params[0].Key); return; } else { - cprintf("%s BAD incorrect number of parameters\r\n", Params[0].Key); + IReply("BAD incorrect number of parameters"); return; } case 4: if (CtdlLoginExistingUser(NULL, Params[2].Key) == login_ok) { if (CtdlTryPassword(Params[3].Key, Params[3].len) == pass_ok) { - cprintf("%s OK [", Params[0].Key); + /* hm, thats not doable by IReply :-( */ + IAPrintf("%s OK [", Params[0].Key); imap_output_capability_string(); - cprintf("] Hello, %s\r\n", CC->user.fullname); + IAPrintf("] Hello, %s\r\n", CC->user.fullname); return; } else { - cprintf("%s NO AUTHENTICATE %s failed\r\n", - Params[0].Key, Params[3].Key); + IReplyPrintf("NO AUTHENTICATE %s failed\r\n", + Params[3].Key); } } - cprintf("%s BAD Login incorrect\r\n", Params[0].Key); + IReply("BAD Login incorrect"); default: - cprintf("%s BAD incorrect number of parameters\r\n", Params[0].Key); + IReply("BAD incorrect number of parameters"); return; } @@ -578,19 +659,18 @@ void imap_authenticate(int num_parms, ConstStr *Params) char UsrBuf[SIZ]; if (num_parms != 3) { - cprintf("%s BAD incorrect number of parameters\r\n", - Params[0].Key); + IReply("BAD incorrect number of parameters"); return; } if (CC->logged_in) { - cprintf("%s BAD Already logged in.\r\n", Params[0].Key); + IReply("BAD Already logged in."); return; } if (!strcasecmp(Params[2].Key, "LOGIN")) { CtdlEncodeBase64(UsrBuf, "Username:", 9, 0); - cprintf("+ %s\r\n", UsrBuf); + IAPrintf("+ %s\r\n", UsrBuf); IMAP->authstate = imap_as_expecting_username; strcpy(IMAP->authseq, Params[0].Key); return; @@ -598,22 +678,23 @@ void imap_authenticate(int num_parms, ConstStr *Params) if (!strcasecmp(Params[2].Key, "PLAIN")) { // CtdlEncodeBase64(UsrBuf, "Username:", 9, 0); - // cprintf("+ %s\r\n", UsrBuf); - cprintf("+ \r\n"); + // IAPuts("+ %s\r\n", UsrBuf); + IAPuts("+ \r\n"); IMAP->authstate = imap_as_expecting_plainauth; strcpy(IMAP->authseq, Params[0].Key); return; } else { - cprintf("%s NO AUTHENTICATE %s failed\r\n", - Params[0].Key, Params[1].Key); + IReplyPrintf("NO AUTHENTICATE %s failed", + Params[1].Key); } } void imap_auth_plain(void) { + citimap *Imap = IMAP; const char *decoded_authstring; char ident[256]; char user[256]; @@ -622,16 +703,16 @@ void imap_auth_plain(void) long len; memset(pass, 0, sizeof(pass)); - StrBufDecodeBase64(IMAP->Cmd.CmdBuf); + StrBufDecodeBase64(Imap->Cmd.CmdBuf); - decoded_authstring = ChrPtr(IMAP->Cmd.CmdBuf); + decoded_authstring = ChrPtr(Imap->Cmd.CmdBuf); safestrncpy(ident, decoded_authstring, sizeof ident); safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user); len = safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass); if (len < 0) len = sizeof(pass) - 1; - IMAP->authstate = imap_as_normal; + Imap->authstate = imap_as_normal; if (!IsEmptyStr(ident)) { result = CtdlLoginExistingUser(user, ident); @@ -642,11 +723,11 @@ void imap_auth_plain(void) if (result == login_ok) { if (CtdlTryPassword(pass, len) == pass_ok) { - cprintf("%s OK authentication succeeded\r\n", IMAP->authseq); + IAPrintf("%s OK authentication succeeded\r\n", Imap->authseq); return; } } - cprintf("%s NO authentication failed\r\n", IMAP->authseq); + IAPrintf("%s NO authentication failed\r\n", Imap->authseq); } @@ -660,15 +741,15 @@ void imap_auth_login_user(long state) StrBufDecodeBase64(Imap->Cmd.CmdBuf); CtdlLoginExistingUser(NULL, ChrPtr(Imap->Cmd.CmdBuf)); CtdlEncodeBase64(PWBuf, "Password:", 9, 0); - cprintf("+ %s\r\n", PWBuf); + IAPrintf("+ %s\r\n", PWBuf); Imap->authstate = imap_as_expecting_password; return; case imap_as_expecting_multilineusername: extract_token(PWBuf, ChrPtr(Imap->Cmd.CmdBuf), 1, ' ', sizeof(PWBuf)); CtdlLoginExistingUser(NULL, ChrPtr(Imap->Cmd.CmdBuf)); - cprintf("+ go ahead\r\n"); - IMAP->authstate = imap_as_expecting_multilinepassword; + IAPuts("+ go ahead\r\n"); + Imap->authstate = imap_as_expecting_multilinepassword; return; } } @@ -696,11 +777,11 @@ void imap_auth_login_pass(long state) StrBufCutAt(Imap->Cmd.CmdBuf, USERNAME_SIZE, NULL); if (CtdlTryPassword(pass, len) == pass_ok) { - cprintf("%s OK authentication succeeded\r\n", IMAP->authseq); + IAPrintf("%s OK authentication succeeded\r\n", Imap->authseq); } else { - cprintf("%s NO authentication failed\r\n", IMAP->authseq); + IAPrintf("%s NO authentication failed\r\n", Imap->authseq); } - IMAP->authstate = imap_as_normal; + Imap->authstate = imap_as_normal; return; } @@ -726,6 +807,7 @@ void imap_starttls(int num_parms, ConstStr *Params) */ void imap_select(int num_parms, ConstStr *Params) { + citimap *Imap = IMAP; char towhere[ROOMNAMELEN]; char augmented_roomname[ROOMNAMELEN]; int c = 0; @@ -740,8 +822,8 @@ void imap_select(int num_parms, ConstStr *Params) /* Convert the supplied folder name to a roomname */ i = imap_roomname(towhere, sizeof towhere, Params[2].Key); if (i < 0) { - cprintf("%s NO Invalid mailbox name.\r\n", Params[0].Key); - IMAP->selected = 0; + IReply("NO Invalid mailbox name."); + Imap->selected = 0; return; } floornum = (i & 0x00ff); @@ -772,7 +854,7 @@ void imap_select(int num_parms, ConstStr *Params) /* Fail here if no such room */ if (!ok) { - cprintf("%s NO ... no such room, or access denied\r\n", Params[0].Key); + IReply("NO ... no such room, or access denied"); return; } @@ -785,22 +867,22 @@ void imap_select(int num_parms, ConstStr *Params) */ memcpy(&CC->room, &QRscratch, sizeof(struct ctdlroom)); CtdlUserGoto(NULL, 0, 0, &msgs, &new); - IMAP->selected = 1; + Imap->selected = 1; if (!strcasecmp(Params[1].Key, "EXAMINE")) { - IMAP->readonly = 1; + Imap->readonly = 1; } else { - IMAP->readonly = 0; + Imap->readonly = 0; } imap_load_msgids(); - IMAP->last_mtime = CC->room.QRmtime; + Imap->last_mtime = CC->room.QRmtime; - cprintf("* %d EXISTS\r\n", msgs); - cprintf("* %d RECENT\r\n", new); + IAPrintf("* %d EXISTS\r\n", msgs); + IAPrintf("* %d RECENT\r\n", new); - cprintf("* OK [UIDVALIDITY %ld] UID validity status\r\n", GLOBAL_UIDVALIDITY_VALUE); - cprintf("* OK [UIDNEXT %ld] Predicted next UID\r\n", CitControl.MMhighest + 1); + IAPrintf("* OK [UIDVALIDITY %ld] UID validity status\r\n", GLOBAL_UIDVALIDITY_VALUE); + IAPrintf("* OK [UIDNEXT %ld] Predicted next UID\r\n", CitControl.MMhighest + 1); /* Technically, \Deleted is a valid flag, but not a permanent flag, * because we don't maintain its state across sessions. Citadel @@ -811,12 +893,11 @@ void imap_select(int num_parms, ConstStr *Params) * elect not to transmit the flag at all. So we have to advertise * \Deleted as a PERMANENTFLAGS flag, even though it technically isn't. */ - cprintf("* FLAGS (\\Deleted \\Seen \\Answered)\r\n"); - cprintf("* OK [PERMANENTFLAGS (\\Deleted \\Seen \\Answered)] permanent flags\r\n"); + IAPuts("* FLAGS (\\Deleted \\Seen \\Answered)\r\n"); + IAPuts("* OK [PERMANENTFLAGS (\\Deleted \\Seen \\Answered)] permanent flags\r\n"); - cprintf("%s OK [%s] %s completed\r\n", - Params[0].Key, - (IMAP->readonly ? "READ-ONLY" : "READ-WRITE"), Params[1].Key + IReplyPrintf("OK [%s] %s completed", + (Imap->readonly ? "READ-ONLY" : "READ-WRITE"), Params[1].Key ); } @@ -826,21 +907,22 @@ void imap_select(int num_parms, ConstStr *Params) */ int imap_do_expunge(void) { + citimap *Imap = IMAP; int i; int num_expunged = 0; long *delmsgs = NULL; int num_delmsgs = 0; CtdlLogPrintf(CTDL_DEBUG, "imap_do_expunge() called\n"); - if (IMAP->selected == 0) { + if (Imap->selected == 0) { return (0); } - if (IMAP->num_msgs > 0) { - delmsgs = malloc(IMAP->num_msgs * sizeof(long)); - for (i = 0; i < IMAP->num_msgs; ++i) { - if (IMAP->flags[i] & IMAP_DELETED) { - delmsgs[num_delmsgs++] = IMAP->msgids[i]; + if (Imap->num_msgs > 0) { + delmsgs = malloc(Imap->num_msgs * sizeof(long)); + for (i = 0; i < Imap->num_msgs; ++i) { + if (Imap->flags[i] & IMAP_DELETED) { + delmsgs[num_delmsgs++] = Imap->msgids[i]; } } if (num_delmsgs > 0) { @@ -867,7 +949,7 @@ void imap_expunge(int num_parms, ConstStr *Params) int num_expunged = 0; num_expunged = imap_do_expunge(); - cprintf("%s OK expunged %d messages.\r\n", Params[0].Key, num_expunged); + IReplyPrintf("OK expunged %d messages.", num_expunged); } @@ -885,7 +967,7 @@ void imap_close(int num_parms, ConstStr *Params) IMAP->selected = 0; IMAP->readonly = 0; imap_free_msgids(); - cprintf("%s OK CLOSE completed\r\n", Params[0].Key); + IReply("OK CLOSE completed"); } @@ -899,32 +981,32 @@ void imap_namespace(int num_parms, ConstStr *Params) int floors = 0; char Namespace[SIZ]; - cprintf("* NAMESPACE "); + IAPuts("* NAMESPACE "); /* All personal folders are subordinate to INBOX. */ - cprintf("((\"INBOX/\" \"/\")) "); + IAPuts("((\"INBOX/\" \"/\")) "); /* Other users' folders ... coming soon! FIXME */ - cprintf("NIL "); + IAPuts("NIL "); /* Show all floors as shared namespaces. Neato! */ - cprintf("("); + IAPuts("("); for (i = 0; i < MAXFLOORS; ++i) { fl = CtdlGetCachedFloor(i); if (fl->f_flags & F_INUSE) { - /* if (floors > 0) cprintf(" "); samjam says this confuses javamail */ - cprintf("("); + /* if (floors > 0) IAPuts(" "); samjam says this confuses javamail */ + IAPuts("("); snprintf(Namespace, sizeof(Namespace), "%s/", fl->f_name); plain_imap_strout(Namespace); - cprintf(" \"/\")"); + IAPuts(" \"/\")"); ++floors; } } - cprintf(")"); + IAPuts(")"); /* Wind it up with a newline and a completion message. */ - cprintf("\r\n"); - cprintf("%s OK NAMESPACE completed\r\n", Params[0].Key); + IAPuts("\r\n"); + IReply("OK NAMESPACE completed"); } @@ -943,20 +1025,19 @@ void imap_create(int num_parms, ConstStr *Params) char *notification_message = NULL; if (num_parms < 3) { - cprintf("%s NO A foder name must be specified\r\n", Params[0].Key); + IReply("NO A foder name must be specified"); return; } if (strchr(Params[2].Key, '\\') != NULL) { - cprintf("%s NO Invalid character in folder name\r\n", Params[0].Key); + IReply("NO Invalid character in folder name"); CtdlLogPrintf(CTDL_DEBUG, "invalid character in folder name\n"); return; } ret = imap_roomname(roomname, sizeof roomname, Params[2].Key); if (ret < 0) { - cprintf("%s NO Invalid mailbox name or location\r\n", - Params[0].Key); + IReply("NO Invalid mailbox name or location"); CtdlLogPrintf(CTDL_DEBUG, "invalid mailbox name or location\n"); return; } @@ -965,7 +1046,7 @@ void imap_create(int num_parms, ConstStr *Params) if (flags & IR_MAILBOX) { if (strncasecmp(Params[2].Key, "INBOX/", 6)) { - cprintf("%s NO Personal folders must be created under INBOX\r\n", Params[0].Key); + IReply("%s NO Personal folders must be created under INBOX"); CtdlLogPrintf(CTDL_DEBUG, "not subordinate to inbox\n"); return; } @@ -985,9 +1066,9 @@ void imap_create(int num_parms, ConstStr *Params) ret = CtdlCreateRoom(roomname, newroomtype, "", floornum, 1, 0, newroomview); if (ret == 0) { /*** DO NOT CHANGE THIS ERROR MESSAGE IN ANY WAY! BYNARI CONNECTOR DEPENDS ON IT! ***/ - cprintf("%s NO Mailbox already exists, or create failed\r\n", Params[0].Key); + IReply("NO Mailbox already exists, or create failed"); } else { - cprintf("%s OK CREATE completed\r\n", Params[0].Key); + IReply("%s OK CREATE completed"); /* post a message in Aide> describing the new room */ notification_message = malloc(1024); snprintf(notification_message, 1024, @@ -1075,9 +1156,7 @@ void imap_status(int num_parms, ConstStr *Params) ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf - ("%s NO Invalid mailbox name or location, or access denied\r\n", - Params[0].Key); + IReply("NO Invalid mailbox name or location, or access denied"); return; } @@ -1098,13 +1177,13 @@ void imap_status(int num_parms, ConstStr *Params) * code and probably saves us some processing time too. */ imap_mailboxname(imaproomname, sizeof imaproomname, &CC->room); - cprintf("* STATUS "); - plain_imap_strout(imaproomname); - cprintf(" (MESSAGES %d ", msgs); - cprintf("RECENT %d ", new); /* Initially, new==recent */ - cprintf("UIDNEXT %ld ", CitControl.MMhighest + 1); - cprintf("UNSEEN %d)\r\n", new); - + IAPuts("* STATUS "); + plain_imap_strout(imaproomname); + IAPrintf(" (MESSAGES %d ", msgs); + IAPrintf("RECENT %d ", new); /* Initially, new==recent */ + IAPrintf("UIDNEXT %ld ", CitControl.MMhighest + 1); + IAPrintf("UNSEEN %d)\r\n", new); + /* * If another folder is selected, go back to that room so we can resume * our happy day without violent explosions. @@ -1116,7 +1195,7 @@ void imap_status(int num_parms, ConstStr *Params) /* * Oooh, look, we're done! */ - cprintf("%s OK STATUS completed\r\n", Params[0].Key); + IReply("OK STATUS completed"); } @@ -1133,9 +1212,8 @@ void imap_subscribe(int num_parms, ConstStr *Params) ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf( - "%s NO Error %d: invalid mailbox name or location, or access denied\r\n", - Params[0].Key, + IReplyPrintf( + "NO Error %d: invalid mailbox name or location, or access denied", ret ); return; @@ -1159,7 +1237,7 @@ void imap_subscribe(int num_parms, ConstStr *Params) CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } - cprintf("%s OK SUBSCRIBE completed\r\n", Params[0].Key); + IReply("OK SUBSCRIBE completed"); } @@ -1176,9 +1254,7 @@ void imap_unsubscribe(int num_parms, ConstStr *Params) ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf - ("%s NO Invalid mailbox name or location, or access denied\r\n", - Params[0].Key); + IReply("NO Invalid mailbox name or location, or access denied"); return; } @@ -1194,11 +1270,9 @@ void imap_unsubscribe(int num_parms, ConstStr *Params) * Now make the API call to zap the room */ if (CtdlForgetThisRoom() == 0) { - cprintf("%s OK UNSUBSCRIBE completed\r\n", Params[0].Key); + IReply("OK UNSUBSCRIBE completed"); } else { - cprintf - ("%s NO You may not unsubscribe from this folder.\r\n", - Params[0].Key); + IReply("NO You may not unsubscribe from this folder."); } /* @@ -1224,8 +1298,7 @@ void imap_delete(int num_parms, ConstStr *Params) ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { - cprintf("%s NO Invalid mailbox name, or access denied\r\n", - Params[0].Key); + IReply("NO Invalid mailbox name, or access denied"); return; } @@ -1244,9 +1317,9 @@ void imap_delete(int num_parms, ConstStr *Params) */ if (CtdlDoIHavePermissionToDeleteThisRoom(&CC->room)) { CtdlScheduleRoomForDeletion(&CC->room); - cprintf("%s OK DELETE completed\r\n", Params[0].Key); + IReply("OK DELETE completed"); } else { - cprintf("%s NO Can't delete this folder.\r\n", Params[0].Key); + IReply("NO Can't delete this folder."); } /* @@ -1315,8 +1388,7 @@ void imap_rename(int num_parms, ConstStr *Params) char aidemsg[1024]; if (strchr(Params[3].Key, '\\') != NULL) { - cprintf("%s NO Invalid character in folder name\r\n", - Params[0].Key); + IReply("NO Invalid character in folder name"); return; } @@ -1327,30 +1399,27 @@ void imap_rename(int num_parms, ConstStr *Params) r = CtdlRenameRoom(old_room, new_room, new_floor); if (r == crr_room_not_found) { - cprintf("%s NO Could not locate this folder\r\n", - Params[0].Key); + IReply("NO Could not locate this folder"); return; } if (r == crr_already_exists) { - cprintf("%s NO '%s' already exists.\r\n", Params[0].Key, Params[2].Key); + IReplyPrintf("NO '%s' already exists."); return; } if (r == crr_noneditable) { - cprintf("%s NO This folder is not editable.\r\n", Params[0].Key); + IReply("NO This folder is not editable."); return; } if (r == crr_invalid_floor) { - cprintf("%s NO Folder root does not exist.\r\n", Params[0].Key); + IReply("NO Folder root does not exist."); return; } if (r == crr_access_denied) { - cprintf("%s NO You do not have permission to edit this folder.\r\n", - Params[0].Key); + IReply("NO You do not have permission to edit this folder."); return; } if (r != crr_ok) { - cprintf("%s NO Rename failed - undefined error %d\r\n", - Params[0].Key, r); + IReplyPrintf("NO Rename failed - undefined error %d", r); return; } @@ -1391,7 +1460,7 @@ void imap_rename(int num_parms, ConstStr *Params) ); CtdlAideMessage(aidemsg, "IMAP folder rename"); - cprintf("%s OK RENAME completed\r\n", Params[0].Key); + IReply("OK RENAME completed"); } @@ -1405,6 +1474,7 @@ void imap_command_loop(void) int untagged_ok = 1; citimap *Imap; const char *pchs, *pche; + const imap_handler_hook *h; gettimeofday(&tv1, NULL); CC->lastcmd = time(NULL); @@ -1452,24 +1522,28 @@ void imap_command_loop(void) switch (Imap->authstate){ case imap_as_expecting_username: imap_auth_login_user(imap_as_expecting_username); + IUnbuffer(); return; case imap_as_expecting_multilineusername: imap_auth_login_user(imap_as_expecting_multilineusername); + IUnbuffer(); return; case imap_as_expecting_plainauth: imap_auth_plain(); + IUnbuffer(); return; case imap_as_expecting_password: imap_auth_login_pass(imap_as_expecting_password); + IUnbuffer(); return; case imap_as_expecting_multilinepassword: imap_auth_login_pass(imap_as_expecting_multilinepassword); + IUnbuffer(); return; default: break; } - /* Ok, at this point we're in normal command mode. * If the command just submitted does not contain a literal, we * might think about delivering some untagged stuff... @@ -1499,19 +1573,19 @@ void imap_command_loop(void) Imap->Cmd.Params[i].len, Imap->Cmd.Params[i].Key); }} - #endif - /* RFC3501 says that we cannot output untagged data during these commands */ - if (Imap->Cmd.num_parms >= 2) { - if ( (!strcasecmp(Imap->Cmd.Params[1].Key, "FETCH")) - || (!strcasecmp(Imap->Cmd.Params[1].Key, "STORE")) - || (!strcasecmp(Imap->Cmd.Params[1].Key, "SEARCH")) - ) { - untagged_ok = 0; - } + + /* Now for the command set. */ + h = imap_lookup(Imap->Cmd.num_parms, Imap->Cmd.Params); + + if (h == NULL) + { + IReply("BAD command unrecognized"); + goto BAIL; } - - if (untagged_ok) { + + /* RFC3501 says that we cannot output untagged data during these commands */ + if ((h->Flags & I_FLAG_UNTAGGED) == 0) { /* we can put any additional untagged stuff right here in the future */ @@ -1526,196 +1600,24 @@ void imap_command_loop(void) } } - /* Now for the command set. */ - - if (Imap->Cmd.num_parms < 2) { - cprintf("BAD syntax error\r\n"); - } - - /* The commands below may be executed in any state */ - - else if ((!strcasecmp(Imap->Cmd.Params[1].Key, "NOOP")) - || (!strcasecmp(Imap->Cmd.Params[1].Key, "CHECK"))) { - cprintf("%s OK No operation\r\n", - Imap->Cmd.Params[0].Key); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "ID")) { - imap_id(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LOGOUT")) { - if (Imap->selected) { - imap_do_expunge(); /* yes, we auto-expunge at logout */ - } - cprintf("* BYE %s logging out\r\n", config.c_fqdn); - cprintf("%s OK Citadel IMAP session ended.\r\n", - Imap->Cmd.Params[0].Key); - CC->kill_me = 1; - return; - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LOGIN")) { - imap_login(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "AUTHENTICATE")) { - imap_authenticate(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "CAPABILITY")) { - imap_capability(Imap->Cmd.num_parms, Imap->Cmd.Params); - } -#ifdef HAVE_OPENSSL - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "STARTTLS")) { - imap_starttls(Imap->Cmd.num_parms, Imap->Cmd.Params); - } -#endif - else if (!CC->logged_in) { - cprintf("%s BAD Not logged in.\r\n", Imap->Cmd.Params[0].Key); - } - - /* The commans below require a logged-in state */ - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SELECT")) { - imap_select(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "EXAMINE")) { - imap_select(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LSUB")) { - imap_list(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LIST")) { - imap_list(Imap->Cmd.num_parms, Imap->Cmd.Params); + /* does our command require a logged-in state */ + if ((!CC->logged_in) && ((h->Flags & I_FLAG_LOGGED_IN) != 0)) { + IReply("BAD Not logged in."); + goto BAIL; } - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "CREATE")) { - imap_create(Imap->Cmd.num_parms, Imap->Cmd.Params); + /* does our command require the SELECT state on a mailbox */ + if ((Imap->selected == 0) && ((h->Flags & I_FLAG_SELECT) != 0)){ + IReply("BAD no folder selected"); + goto BAIL; } + h->h(Imap->Cmd.num_parms, Imap->Cmd.Params); - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "DELETE")) { - imap_delete(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "RENAME")) { - imap_rename(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "STATUS")) { - imap_status(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SUBSCRIBE")) { - imap_subscribe(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "UNSUBSCRIBE")) { - imap_unsubscribe(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "APPEND")) { - imap_append(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "NAMESPACE")) { - imap_namespace(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SETACL")) { - imap_setacl(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "DELETEACL")) { - imap_deleteacl(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "GETACL")) { - imap_getacl(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LISTRIGHTS")) { - imap_listrights(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "MYRIGHTS")) { - imap_myrights(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "GETMETADATA")) { - imap_getmetadata(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SETMETADATA")) { - imap_setmetadata(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (Imap->selected == 0) { - cprintf("%s BAD no folder selected\r\n", Imap->Cmd.Params[0].Key); - } - - /* The commands below require the SELECT state on a mailbox */ - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "FETCH")) { - imap_fetch(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if ((!strcasecmp(Imap->Cmd.Params[1].Key, "UID")) - && (!strcasecmp(Imap->Cmd.Params[2].Key, "FETCH"))) { - imap_uidfetch(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SEARCH")) { - imap_search(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if ((!strcasecmp(Imap->Cmd.Params[1].Key, "UID")) - && (!strcasecmp(Imap->Cmd.Params[2].Key, "SEARCH"))) { - imap_uidsearch(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "STORE")) { - imap_store(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if ((!strcasecmp(Imap->Cmd.Params[1].Key, "UID")) - && (!strcasecmp(Imap->Cmd.Params[2].Key, "STORE"))) { - imap_uidstore(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "COPY")) { - imap_copy(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if ((!strcasecmp(Imap->Cmd.Params[1].Key, "UID")) && (!strcasecmp(Imap->Cmd.Params[2].Key, "COPY"))) { - imap_uidcopy(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "EXPUNGE")) { - imap_expunge(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if ((!strcasecmp(Imap->Cmd.Params[1].Key, "UID")) && (!strcasecmp(Imap->Cmd.Params[2].Key, "EXPUNGE"))) { - imap_expunge(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - else if (!strcasecmp(Imap->Cmd.Params[1].Key, "CLOSE")) { - imap_close(Imap->Cmd.num_parms, Imap->Cmd.Params); - } - - /* End of commands. If we get here, the command is either invalid - * or unimplemented. - */ + /* If the client transmitted a message we can free it now */ - else { - cprintf("%s BAD command unrecognized\r\n", Imap->Cmd.Params[0].Key); - } +BAIL: + IUnbuffer(); - /* If the client transmitted a message we can free it now */ imap_free_transmitted_message(); gettimeofday(&tv2, NULL); @@ -1726,15 +1628,79 @@ void imap_command_loop(void) ); } +void imap_noop (int num_parms, ConstStr *Params) +{ + IReply("OK No operation"); +} + +void imap_logout(int num_parms, ConstStr *Params) +{ + if (IMAP->selected) { + imap_do_expunge(); /* yes, we auto-expunge at logout */ + } + IAPrintf("* BYE %s logging out\r\n", config.c_fqdn); + IReply("OK Citadel IMAP session ended."); + CC->kill_me = 1; + return; +} const char *CitadelServiceIMAP="IMAP"; const char *CitadelServiceIMAPS="IMAPS"; + /* * This function is called to register the IMAP extension with Citadel. */ CTDL_MODULE_INIT(imap) { + if (ImapCmds == NULL) + ImapCmds = NewHash(1, NULL); + + RegisterImapCMD("NOOP", "", imap_noop, I_FLAG_NONE); + RegisterImapCMD("CHECK", "", imap_noop, I_FLAG_NONE); + RegisterImapCMD("ID", "", imap_id, I_FLAG_NONE); + RegisterImapCMD("LOGOUT", "", imap_logout, I_FLAG_NONE); + RegisterImapCMD("LOGIN", "", imap_login, I_FLAG_NONE); + RegisterImapCMD("AUTHENTICATE", "", imap_authenticate, I_FLAG_NONE); + RegisterImapCMD("CAPABILITY", "", imap_capability, I_FLAG_NONE); +#ifdef HAVE_OPENSSL + RegisterImapCMD("STARTTLS", "", imap_starttls, I_FLAG_NONE); +#endif + + /* The commans below require a logged-in state */ + RegisterImapCMD("SELECT", "", imap_select, I_FLAG_LOGGED_IN); + RegisterImapCMD("EXAMINE", "", imap_select, I_FLAG_LOGGED_IN); + RegisterImapCMD("LSUB", "", imap_list, I_FLAG_LOGGED_IN); + RegisterImapCMD("LIST", "", imap_list, I_FLAG_LOGGED_IN); + RegisterImapCMD("CREATE", "", imap_create, I_FLAG_LOGGED_IN); + RegisterImapCMD("DELETE", "", imap_delete, I_FLAG_LOGGED_IN); + RegisterImapCMD("RENAME", "", imap_rename, I_FLAG_LOGGED_IN); + RegisterImapCMD("STATUS", "", imap_status, I_FLAG_LOGGED_IN); + RegisterImapCMD("SUBSCRIBE", "", imap_subscribe, I_FLAG_LOGGED_IN); + RegisterImapCMD("UNSUBSCRIBE", "", imap_unsubscribe, I_FLAG_LOGGED_IN); + RegisterImapCMD("APPEND", "", imap_append, I_FLAG_LOGGED_IN); + RegisterImapCMD("NAMESPACE", "", imap_namespace, I_FLAG_LOGGED_IN); + RegisterImapCMD("SETACL", "", imap_setacl, I_FLAG_LOGGED_IN); + RegisterImapCMD("DELETEACL", "", imap_deleteacl, I_FLAG_LOGGED_IN); + RegisterImapCMD("GETACL", "", imap_getacl, I_FLAG_LOGGED_IN); + RegisterImapCMD("LISTRIGHTS", "", imap_listrights, I_FLAG_LOGGED_IN); + RegisterImapCMD("MYRIGHTS", "", imap_myrights, I_FLAG_LOGGED_IN); + RegisterImapCMD("GETMETADATA", "", imap_getmetadata, I_FLAG_LOGGED_IN); + RegisterImapCMD("SETMETADATA", "", imap_setmetadata, I_FLAG_LOGGED_IN); + + /* The commands below require the SELECT state on a mailbox */ + RegisterImapCMD("FETCH", "", imap_fetch, I_FLAG_LOGGED_IN | I_FLAG_SELECT | I_FLAG_UNTAGGED); + RegisterImapCMD("UID", "FETCH", imap_uidfetch, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + RegisterImapCMD("SEARCH", "", imap_search, I_FLAG_LOGGED_IN | I_FLAG_SELECT | I_FLAG_UNTAGGED); + RegisterImapCMD("UID", "SEARCH", imap_uidsearch, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + RegisterImapCMD("STORE", "", imap_store, I_FLAG_LOGGED_IN | I_FLAG_SELECT | I_FLAG_UNTAGGED); + RegisterImapCMD("UID", "STORE", imap_uidstore, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + RegisterImapCMD("COPY", "", imap_copy, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + RegisterImapCMD("UID", "COPY", imap_uidcopy, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + RegisterImapCMD("EXPUNGE", "", imap_expunge, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + RegisterImapCMD("UID", "EXPUNGE", imap_expunge, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + RegisterImapCMD("CLOSE", "", imap_close, I_FLAG_LOGGED_IN | I_FLAG_SELECT); + if (!threading) { CtdlRegisterServiceHook(config.c_imap_port, diff --git a/citadel/modules/imap/serv_imap.h b/citadel/modules/imap/serv_imap.h index 354c13d69..8113f675b 100644 --- a/citadel/modules/imap/serv_imap.h +++ b/citadel/modules/imap/serv_imap.h @@ -9,9 +9,33 @@ void imap_free_transmitted_message(void); int imap_do_expunge(void); void imap_rescan_msgids(void); +/* + * FDELIM defines which character we want to use as a folder delimiter + * in room names. Originally we used a forward slash, but that caused + * rooms with names like "Sent/Received Pages" to get delimited, so we + * changed it to a backslash. This is completely irrelevant to how Citadel + * speaks to IMAP clients -- the delimiter used in the IMAP protocol is + * a vertical bar, which is illegal in Citadel room names anyway. + */ + +typedef void (*imap_handler)(int num_parms, ConstStr *Params); + +typedef struct _imap_handler_hook { + imap_handler h; + int Flags; +} imap_handler_hook; + +typedef struct __citimap_command { + StrBuf *CmdBuf; /* our current commandline; gets chopped into: */ + ConstStr *Params; /* Commandline tokens */ + int num_parms; /* Number of Commandline tokens available */ + int avail_parms; /* Number of ConstStr args is big */ + const imap_handler_hook *hh; +} citimap_command; typedef struct __citimap { + StrBuf *Reply; int authstate; char authseq[SIZ]; int selected; /* set to 1 if in the SELECTED state */ @@ -21,6 +45,7 @@ typedef struct __citimap { time_t last_mtime; /* For checking whether the room was modified... */ long *msgids; unsigned int *flags; + StrBuf *TransmittedMessage; /* for APPEND command... */ citimap_command Cmd; /* our current commandline */ @@ -66,10 +91,36 @@ enum { #define IMAP_RECENT 64 /* reportable but not setable */ +/* + * Flags that may be returned by imap_roomname() + * (the lower eight bits will be the floor number) + */ +#define IR_MAILBOX 0x0100 /* Mailbox */ +#define IR_EXISTS 0x0200 /* Room exists (not implemented) */ +#define IR_BABOON 0x0000 /* Just had to put this here :) */ + +#define FDELIM '\\' + + #define IMAP ((citimap *)CC->session_specific_data) +#define I_FLAG_NONE (0) +#define I_FLAG_LOGGED_IN (1<<0) +#define I_FLAG_SELECT (1<<1) +/* RFC3501 says that we cannot output untagged data during these commands */ +#define I_FLAG_UNTAGGED (1<<2) + /* * When loading arrays of message ID's into memory, increase the buffer to * hold this many additional messages instead of calling realloc() each time. */ #define REALLOC_INCREMENT 100 + + +void registerImapCMD(const char *First, long FLen, + const char *Second, long SLen, + imap_handler H, + int Flags); + +#define RegisterImapCMD(First, Second, H, Flags) \ + registerImapCMD(HKEY(First), HKEY(Second), H, Flags) -- 2.30.2