X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fimap%2Fserv_imap.c;h=eca6f3c7fdc80df87df4b6602d50be9b9426bbec;hb=63262a64633e72e4096aaeedda6950c02fb4d990;hp=9dd687500654da182d420c3994458c3c404da9c5;hpb=7d0ec733619b5919c5ee0bc4f72d221740f53f6e;p=citadel.git diff --git a/citadel/modules/imap/serv_imap.c b/citadel/modules/imap/serv_imap.c index 9dd687500..eca6f3c7f 100644 --- a/citadel/modules/imap/serv_imap.c +++ b/citadel/modules/imap/serv_imap.c @@ -2,12 +2,26 @@ * $Id$ * * IMAP server for the Citadel system - * Copyright (C) 2000-2007 by Art Cancro and others. + * Copyright (C) 2000-2009 by Art Cancro and others. * This code is released under the terms of the GNU General Public License. * * WARNING: the IMAP protocol is badly designed. No implementation of it * is perfect. Indeed, with so much gratuitous complexity, *all* IMAP * implementations have bugs. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdep.h" @@ -41,14 +55,12 @@ #include "citserver.h" #include "support.h" #include "config.h" -#include "room_ops.h" #include "user_ops.h" -#include "policy.h" #include "database.h" #include "msgbase.h" #include "internet_addressing.h" -#include "serv_imap.h" #include "imap_tools.h" +#include "serv_imap.h" #include "imap_list.h" #include "imap_fetch.h" #include "imap_search.h" @@ -57,7 +69,6 @@ #include "imap_metadata.h" #include "imap_misc.h" - #include "ctdl_module.h" @@ -101,11 +112,7 @@ void imap_free_msgids(void) */ void imap_free_transmitted_message(void) { - if (IMAP->transmitted_message != NULL) { - free(IMAP->transmitted_message); - IMAP->transmitted_message = NULL; - IMAP->transmitted_length = 0; - } + FreeStrBuf(&IMAP->TransmittedMessage); } @@ -121,7 +128,7 @@ void imap_free_transmitted_message(void) */ void imap_set_seen_flags(int first_msg) { - struct visit vbuf; + visit vbuf; int i; int num_sets; int s; @@ -208,10 +215,8 @@ void imap_add_single_msgid(long msgnum, void *userdata) ++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 = 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; @@ -269,8 +274,7 @@ void imap_rescan_msgids(void) int num_recent = 0; if (IMAP->selected == 0) { - CtdlLogPrintf(CTDL_ERR, - "imap_load_msgids() can't run; no room selected\n"); + CtdlLogPrintf(CTDL_ERR, "imap_load_msgids() can't run; no room selected\n"); return; } @@ -278,7 +282,7 @@ void imap_rescan_msgids(void) * Check to see if the room's contents have changed. * If not, we can avoid this rescan. */ - getroom(&CC->room, CC->room.QRname); + CtdlGetRoom(&CC->room, CC->room.QRname); if (IMAP->last_mtime == CC->room.QRmtime) { /* No changes! */ return; } @@ -354,6 +358,8 @@ void imap_rescan_msgids(void) /* * Now peruse the room for *new* messages only. + * This logic is probably the cause of Bug # 368 + * [ http://bugzilla.citadel.org/show_bug.cgi?id=368 ] */ if (num_msgs > 0) { for (j = 0; j < num_msgs; ++j) { @@ -386,11 +392,6 @@ void imap_rescan_msgids(void) } - - - - - /* * This cleanup function blows away the temporary memory and files used by * the IMAP server. @@ -411,9 +412,8 @@ void imap_cleanup_function(void) imap_free_msgids(); imap_free_transmitted_message(); - if (IMAP->cached_rfc822_data != NULL) { - free(IMAP->cached_rfc822_data); - IMAP->cached_rfc822_data = NULL; + if (IMAP->cached_rfc822 != NULL) { + FreeStrBuf(&IMAP->cached_rfc822); IMAP->cached_rfc822_msgnum = (-1); IMAP->cached_rfc822_withbody = 0; } @@ -424,7 +424,8 @@ void imap_cleanup_function(void) IMAP->cached_body_len = 0; IMAP->cached_bodymsgnum = (-1); } - + FreeStrBuf(&IMAP->Cmd.CmdBuf); + if (IMAP->Cmd.Params != NULL) free(IMAP->Cmd.Params); free(IMAP); CtdlLogPrintf(CTDL_DEBUG, "Finished IMAP cleanup hook\n"); } @@ -463,19 +464,19 @@ void imap_output_capability_string(void) { */ } + /* * implements the CAPABILITY command */ -void imap_capability(int num_parms, char *parms[]) +void imap_capability(int num_parms, ConstStr *Params) { cprintf("* "); imap_output_capability_string(); cprintf("\r\n"); - cprintf("%s OK CAPABILITY completed\r\n", parms[0]); + cprintf("%s OK CAPABILITY completed\r\n", Params[0].Key); } - /* * Implements the ID command (specified by RFC2971) * @@ -485,14 +486,13 @@ void imap_capability(int num_parms, char *parms[]) * making use of this extension. * */ -void imap_id(int num_parms, char *parms[]) +void imap_id(int num_parms, ConstStr *Params) { cprintf("* ID NIL\r\n"); - cprintf("%s OK ID completed\r\n", parms[0]); + cprintf("%s OK ID completed\r\n", Params[0].Key); } - /* * Here's where our IMAP session begins its happy day. */ @@ -500,10 +500,9 @@ void imap_greeting(void) { strcpy(CC->cs_clientname, "IMAP session"); - CC->session_specific_data = malloc(sizeof(struct citimap)); - memset(IMAP, 0, sizeof(struct citimap)); + CC->session_specific_data = malloc(sizeof(citimap)); + memset(IMAP, 0, sizeof(citimap)); IMAP->authstate = imap_as_normal; - IMAP->cached_rfc822_data = NULL; IMAP->cached_rfc822_msgnum = (-1); IMAP->cached_rfc822_withbody = 0; @@ -518,6 +517,7 @@ void imap_greeting(void) cprintf("] %s IMAP4rev1 %s ready\r\n", config.c_fqdn, CITADEL); } + /* * IMAPS is just like IMAP, except it goes crypto right away. */ @@ -533,79 +533,105 @@ void imaps_greeting(void) { /* * implements the LOGIN command (ordinary username/password login) */ -void imap_login(int num_parms, char *parms[]) +void imap_login(int num_parms, ConstStr *Params) { - if (num_parms != 4) { - cprintf("%s BAD incorrect number of parameters\r\n", parms[0]); - return; - } - if (CtdlLoginExistingUser(NULL, parms[2]) == login_ok) { - if (CtdlTryPassword(parms[3]) == pass_ok) { - cprintf("%s OK [", parms[0]); - imap_output_capability_string(); - cprintf("] Hello, %s\r\n", CC->user.fullname); + switch (num_parms) { + case 3: + if (Params[2].Key[0] == '{') { + cprintf("+ 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); 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); + imap_output_capability_string(); + cprintf("] Hello, %s\r\n", CC->user.fullname); + return; + } + else + { + cprintf("%s NO AUTHENTICATE %s failed\r\n", + Params[0].Key, Params[3].Key); + } + } + + cprintf("%s BAD Login incorrect\r\n", Params[0].Key); + default: + cprintf("%s BAD incorrect number of parameters\r\n", Params[0].Key); + return; } - cprintf("%s BAD Login incorrect\r\n", parms[0]); } /* * Implements the AUTHENTICATE command */ -void imap_authenticate(int num_parms, char *parms[]) +void imap_authenticate(int num_parms, ConstStr *Params) { - char buf[SIZ]; + char UsrBuf[SIZ]; if (num_parms != 3) { cprintf("%s BAD incorrect number of parameters\r\n", - parms[0]); + Params[0].Key); return; } if (CC->logged_in) { - cprintf("%s BAD Already logged in.\r\n", parms[0]); + cprintf("%s BAD Already logged in.\r\n", Params[0].Key); return; } - if (!strcasecmp(parms[2], "LOGIN")) { - CtdlEncodeBase64(buf, "Username:", 9, 0); - cprintf("+ %s\r\n", buf); + if (!strcasecmp(Params[2].Key, "LOGIN")) { + CtdlEncodeBase64(UsrBuf, "Username:", 9, 0); + cprintf("+ %s\r\n", UsrBuf); IMAP->authstate = imap_as_expecting_username; - strcpy(IMAP->authseq, parms[0]); + strcpy(IMAP->authseq, Params[0].Key); return; } - if (!strcasecmp(parms[2], "PLAIN")) { - // CtdlEncodeBase64(buf, "Username:", 9, 0); - // cprintf("+ %s\r\n", buf); + if (!strcasecmp(Params[2].Key, "PLAIN")) { + // CtdlEncodeBase64(UsrBuf, "Username:", 9, 0); + // cprintf("+ %s\r\n", UsrBuf); cprintf("+ \r\n"); IMAP->authstate = imap_as_expecting_plainauth; - strcpy(IMAP->authseq, parms[0]); + strcpy(IMAP->authseq, Params[0].Key); return; } else { cprintf("%s NO AUTHENTICATE %s failed\r\n", - parms[0], parms[1]); + Params[0].Key, Params[1].Key); } } -void imap_auth_plain(char *cmd) + +void imap_auth_plain(void) { - char decoded_authstring[1024]; + const char *decoded_authstring; char ident[256]; char user[256]; char pass[256]; int result; + long len; + + memset(pass, 0, sizeof(pass)); + StrBufDecodeBase64(IMAP->Cmd.CmdBuf); - CtdlDecodeBase64(decoded_authstring, cmd, strlen(cmd)); + decoded_authstring = ChrPtr(IMAP->Cmd.CmdBuf); safestrncpy(ident, decoded_authstring, sizeof ident); safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user); - safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass); + len = safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass); + if (len < 0) + len = sizeof(pass) - 1; IMAP->authstate = imap_as_normal; @@ -617,7 +643,7 @@ void imap_auth_plain(char *cmd) } if (result == login_ok) { - if (CtdlTryPassword(pass) == pass_ok) { + if (CtdlTryPassword(pass, len) == pass_ok) { cprintf("%s OK authentication succeeded\r\n", IMAP->authseq); return; } @@ -625,24 +651,53 @@ void imap_auth_plain(char *cmd) cprintf("%s NO authentication failed\r\n", IMAP->authseq); } -void imap_auth_login_user(char *cmd) -{ - char buf[SIZ]; - CtdlDecodeBase64(buf, cmd, SIZ); - CtdlLoginExistingUser(NULL, buf); - CtdlEncodeBase64(buf, "Password:", 9, 0); - cprintf("+ %s\r\n", buf); - IMAP->authstate = imap_as_expecting_password; - return; +void imap_auth_login_user(long state) +{ + char PWBuf[SIZ]; + citimap *Imap = IMAP; + + switch (state){ + case imap_as_expecting_username: + StrBufDecodeBase64(Imap->Cmd.CmdBuf); + CtdlLoginExistingUser(NULL, ChrPtr(Imap->Cmd.CmdBuf)); + CtdlEncodeBase64(PWBuf, "Password:", 9, 0); + cprintf("+ %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; + return; + } } -void imap_auth_login_pass(char *cmd) -{ - char buf[SIZ]; - CtdlDecodeBase64(buf, cmd, SIZ); - if (CtdlTryPassword(buf) == pass_ok) { +void imap_auth_login_pass(long state) +{ + citimap *Imap = IMAP; + const char *pass = NULL; + long len = 0; + + switch (state) { + default: + case imap_as_expecting_password: + StrBufDecodeBase64(Imap->Cmd.CmdBuf); + pass = ChrPtr(Imap->Cmd.CmdBuf); + len = StrLength(Imap->Cmd.CmdBuf); + break; + case imap_as_expecting_multilinepassword: + pass = ChrPtr(Imap->Cmd.CmdBuf); + len = StrLength(Imap->Cmd.CmdBuf); + break; + } + if (len > USERNAME_SIZE) + StrBufCutAt(Imap->Cmd.CmdBuf, USERNAME_SIZE, NULL); + + if (CtdlTryPassword(pass, len) == pass_ok) { cprintf("%s OK authentication succeeded\r\n", IMAP->authseq); } else { cprintf("%s NO authentication failed\r\n", IMAP->authseq); @@ -655,21 +710,15 @@ void imap_auth_login_pass(char *cmd) /* * implements the STARTTLS command (Citadel API version) */ -void imap_starttls(int num_parms, char *parms[]) +void imap_starttls(int num_parms, ConstStr *Params) { char ok_response[SIZ]; char nosup_response[SIZ]; char error_response[SIZ]; - sprintf(ok_response, - "%s OK begin TLS negotiation now\r\n", - parms[0]); - sprintf(nosup_response, - "%s NO TLS not supported here\r\n", - parms[0]); - sprintf(error_response, - "%s BAD Internal error\r\n", - parms[0]); + snprintf(ok_response, SIZ, "%s OK begin TLS negotiation now\r\n", Params[0].Key); + snprintf(nosup_response, SIZ, "%s NO TLS not supported here\r\n", Params[0].Key); + snprintf(error_response, SIZ, "%s BAD Internal error\r\n", Params[0].Key); CtdlModuleStartCryptoMsgs(ok_response, nosup_response, error_response); } @@ -677,9 +726,9 @@ void imap_starttls(int num_parms, char *parms[]) /* * implements the SELECT command */ -void imap_select(int num_parms, char *parms[]) +void imap_select(int num_parms, ConstStr *Params) { - char towhere[SIZ]; + char towhere[ROOMNAMELEN]; char augmented_roomname[ROOMNAMELEN]; int c = 0; int ok = 0; @@ -691,9 +740,9 @@ void imap_select(int num_parms, char *parms[]) int i; /* Convert the supplied folder name to a roomname */ - i = imap_roomname(towhere, sizeof towhere, parms[2]); + i = imap_roomname(towhere, sizeof towhere, Params[2].Key); if (i < 0) { - cprintf("%s NO Invalid mailbox name.\r\n", parms[0]); + cprintf("%s NO Invalid mailbox name.\r\n", Params[0].Key); IMAP->selected = 0; return; } @@ -701,15 +750,15 @@ void imap_select(int num_parms, char *parms[]) roomflags = (i & 0xff00); /* First try a regular match */ - c = getroom(&QRscratch, towhere); + c = CtdlGetRoom(&QRscratch, towhere); /* Then try a mailbox name match */ if (c != 0) { - MailboxName(augmented_roomname, sizeof augmented_roomname, - &CC->user, towhere); - c = getroom(&QRscratch, augmented_roomname); - if (c == 0) - strcpy(towhere, augmented_roomname); + CtdlMailboxName(augmented_roomname, sizeof augmented_roomname, &CC->user, towhere); + c = CtdlGetRoom(&QRscratch, augmented_roomname); + if (c == 0) { + safestrncpy(towhere, augmented_roomname, sizeof(towhere)); + } } /* If the room exists, check security/access */ @@ -725,8 +774,7 @@ void imap_select(int num_parms, char *parms[]) /* Fail here if no such room */ if (!ok) { - cprintf("%s NO ... no such room, or access denied\r\n", - parms[0]); + cprintf("%s NO ... no such room, or access denied\r\n", Params[0].Key); return; } @@ -734,14 +782,14 @@ void imap_select(int num_parms, char *parms[]) imap_do_expunge(); /* - * usergoto() formally takes us to the desired room, happily returning + * CtdlUserGoto() formally takes us to the desired room, happily returning * the number of messages and number of new messages. */ memcpy(&CC->room, &QRscratch, sizeof(struct ctdlroom)); - usergoto(NULL, 0, 0, &msgs, &new); + CtdlUserGoto(NULL, 0, 0, &msgs, &new); IMAP->selected = 1; - if (!strcasecmp(parms[1], "EXAMINE")) { + if (!strcasecmp(Params[1].Key, "EXAMINE")) { IMAP->readonly = 1; } else { IMAP->readonly = 0; @@ -762,19 +810,19 @@ void imap_select(int num_parms, char *parms[]) * * Unfortunately, omitting \Deleted as a PERMANENTFLAGS flag causes * some clients (particularly Thunderbird) to misbehave -- they simply - * electing not to transmit the flag at all. So we have to advertise + * 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"); cprintf("%s OK [%s] %s completed\r\n", - parms[0], - (IMAP->readonly ? "READ-ONLY" : "READ-WRITE"), parms[1]); + Params[0].Key, + (IMAP->readonly ? "READ-ONLY" : "READ-WRITE"), Params[1].Key + ); } - /* * Does the real work for expunge. */ @@ -808,8 +856,7 @@ int imap_do_expunge(void) imap_rescan_msgids(); } - CtdlLogPrintf(CTDL_DEBUG, "Expunged %d messages from <%s>\n", - num_expunged, CC->room.QRname); + CtdlLogPrintf(CTDL_DEBUG, "Expunged %d messages from <%s>\n", num_expunged, CC->room.QRname); return (num_expunged); } @@ -817,19 +864,19 @@ int imap_do_expunge(void) /* * implements the EXPUNGE command syntax */ -void imap_expunge(int num_parms, char *parms[]) +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", parms[0], num_expunged); + cprintf("%s OK expunged %d messages.\r\n", Params[0].Key, num_expunged); } /* * implements the CLOSE command */ -void imap_close(int num_parms, char *parms[]) +void imap_close(int num_parms, ConstStr *Params) { /* Yes, we always expunge on close. */ @@ -840,19 +887,19 @@ void imap_close(int num_parms, char *parms[]) IMAP->selected = 0; IMAP->readonly = 0; imap_free_msgids(); - cprintf("%s OK CLOSE completed\r\n", parms[0]); + cprintf("%s OK CLOSE completed\r\n", Params[0].Key); } /* * Implements the NAMESPACE command. */ -void imap_namespace(int num_parms, char *parms[]) +void imap_namespace(int num_parms, ConstStr *Params) { int i; struct floor *fl; int floors = 0; - char buf[SIZ]; + char Namespace[SIZ]; cprintf("* NAMESPACE "); @@ -865,12 +912,12 @@ void imap_namespace(int num_parms, char *parms[]) /* Show all floors as shared namespaces. Neato! */ cprintf("("); for (i = 0; i < MAXFLOORS; ++i) { - fl = cgetfloor(i); + fl = CtdlGetCachedFloor(i); if (fl->f_flags & F_INUSE) { if (floors > 0) cprintf(" "); cprintf("("); - sprintf(buf, "%s/", fl->f_name); - imap_strout(buf); + snprintf(Namespace, sizeof(Namespace), "%s/", fl->f_name); + plain_imap_strout(Namespace); cprintf(" \"/\")"); ++floors; } @@ -879,16 +926,15 @@ void imap_namespace(int num_parms, char *parms[]) /* Wind it up with a newline and a completion message. */ cprintf("\r\n"); - cprintf("%s OK NAMESPACE completed\r\n", parms[0]); + cprintf("%s OK NAMESPACE completed\r\n", Params[0].Key); } - /* * Implements the CREATE command * */ -void imap_create(int num_parms, char *parms[]) +void imap_create(int num_parms, ConstStr *Params) { int ret; char roomname[ROOMNAMELEN]; @@ -898,17 +944,21 @@ void imap_create(int num_parms, char *parms[]) int newroomview = 0; char *notification_message = NULL; - if (strchr(parms[2], '\\') != NULL) { - cprintf("%s NO Invalid character in folder name\r\n", - parms[0]); + if (num_parms < 3) { + cprintf("%s NO A foder name must be specified\r\n", Params[0].Key); + return; + } + + if (strchr(Params[2].Key, '\\') != NULL) { + cprintf("%s NO Invalid character in folder name\r\n", Params[0].Key); CtdlLogPrintf(CTDL_DEBUG, "invalid character in folder name\n"); return; } - ret = imap_roomname(roomname, sizeof roomname, parms[2]); + ret = imap_roomname(roomname, sizeof roomname, Params[2].Key); if (ret < 0) { cprintf("%s NO Invalid mailbox name or location\r\n", - parms[0]); + Params[0].Key); CtdlLogPrintf(CTDL_DEBUG, "invalid mailbox name or location\n"); return; } @@ -916,8 +966,8 @@ void imap_create(int num_parms, char *parms[]) flags = (ret & 0xff00); /* upper 8 bits = flags */ if (flags & IR_MAILBOX) { - if (strncasecmp(parms[2], "INBOX/", 6)) { - cprintf("%s NO Personal folders must be created under INBOX\r\n", parms[0]); + if (strncasecmp(Params[2].Key, "INBOX/", 6)) { + cprintf("%s NO Personal folders must be created under INBOX\r\n", Params[0].Key); CtdlLogPrintf(CTDL_DEBUG, "not subordinate to inbox\n"); return; } @@ -934,12 +984,12 @@ void imap_create(int num_parms, char *parms[]) CtdlLogPrintf(CTDL_INFO, "Create new room <%s> on floor <%d> with type <%d>\n", roomname, floornum, newroomtype); - ret = create_room(roomname, newroomtype, "", floornum, 1, 0, newroomview); + 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", parms[0]); + cprintf("%s NO Mailbox already exists, or create failed\r\n", Params[0].Key); } else { - cprintf("%s OK CREATE completed\r\n", parms[0]); + cprintf("%s OK CREATE completed\r\n", Params[0].Key); /* post a message in Aide> describing the new room */ notification_message = malloc(1024); snprintf(notification_message, 1024, @@ -950,7 +1000,7 @@ void imap_create(int num_parms, char *parms[]) ((ret & QR_PRIVATE) ? " [private]" : ""), ((ret & QR_GUESSNAME) ? " [hidden]" : "") ); - aide_message(notification_message, "Room Creation Message"); + CtdlAideMessage(notification_message, "Room Creation Message"); free(notification_message); } CtdlLogPrintf(CTDL_DEBUG, "imap_create() completed\n"); @@ -961,7 +1011,7 @@ void imap_create(int num_parms, char *parms[]) * Locate a room by its IMAP folder name, and check access to it. * If zapped_ok is nonzero, we can also look for the room in the zapped list. */ -int imap_grabroom(char *returned_roomname, char *foldername, int zapped_ok) +int imap_grabroom(char *returned_roomname, const char *foldername, int zapped_ok) { int ret; char augmented_roomname[ROOMNAMELEN]; @@ -977,15 +1027,15 @@ int imap_grabroom(char *returned_roomname, char *foldername, int zapped_ok) } /* First try a regular match */ - c = getroom(&QRscratch, roomname); + c = CtdlGetRoom(&QRscratch, roomname); /* Then try a mailbox name match */ if (c != 0) { - MailboxName(augmented_roomname, sizeof augmented_roomname, + CtdlMailboxName(augmented_roomname, sizeof augmented_roomname, &CC->user, roomname); - c = getroom(&QRscratch, augmented_roomname); + c = CtdlGetRoom(&QRscratch, augmented_roomname); if (c == 0) - strcpy(roomname, augmented_roomname); + safestrncpy(roomname, augmented_roomname, sizeof(roomname)); } /* If the room exists, check security/access */ @@ -1007,7 +1057,7 @@ int imap_grabroom(char *returned_roomname, char *foldername, int zapped_ok) strcpy(returned_roomname, ""); return (2); } else { - strcpy(returned_roomname, QRscratch.QRname); + safestrncpy(returned_roomname, QRscratch.QRname, ROOMNAMELEN); return (0); } } @@ -1017,31 +1067,31 @@ int imap_grabroom(char *returned_roomname, char *foldername, int zapped_ok) * Implements the STATUS command (sort of) * */ -void imap_status(int num_parms, char *parms[]) +void imap_status(int num_parms, ConstStr *Params) { int ret; char roomname[ROOMNAMELEN]; - char buf[SIZ]; + char imaproomname[SIZ]; char savedroom[ROOMNAMELEN]; int msgs, new; - ret = imap_grabroom(roomname, parms[2], 0); + ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { cprintf ("%s NO Invalid mailbox name or location, or access denied\r\n", - parms[0]); + Params[0].Key); return; } /* - * usergoto() formally takes us to the desired room, happily returning + * CtdlUserGoto() formally takes us to the desired room, happily returning * the number of messages and number of new messages. (If another * folder is selected, save its name so we can return there!!!!!) */ if (IMAP->selected) { strcpy(savedroom, CC->room.QRname); } - usergoto(roomname, 0, 0, &msgs, &new); + CtdlUserGoto(roomname, 0, 0, &msgs, &new); /* * Tell the client what it wants to know. In fact, tell it *more* than @@ -1049,9 +1099,9 @@ void imap_status(int num_parms, char *parms[]) * names and simply spew all possible data items. It's far easier to * code and probably saves us some processing time too. */ - imap_mailboxname(buf, sizeof buf, &CC->room); + imap_mailboxname(imaproomname, sizeof imaproomname, &CC->room); cprintf("* STATUS "); - imap_strout(buf); + plain_imap_strout(imaproomname); cprintf(" (MESSAGES %d ", msgs); cprintf("RECENT %d ", new); /* Initially, new==recent */ cprintf("UIDNEXT %ld ", CitControl.MMhighest + 1); @@ -1062,57 +1112,56 @@ void imap_status(int num_parms, char *parms[]) * our happy day without violent explosions. */ if (IMAP->selected) { - usergoto(savedroom, 0, 0, &msgs, &new); + CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } /* * Oooh, look, we're done! */ - cprintf("%s OK STATUS completed\r\n", parms[0]); + cprintf("%s OK STATUS completed\r\n", Params[0].Key); } - /* * Implements the SUBSCRIBE command * */ -void imap_subscribe(int num_parms, char *parms[]) +void imap_subscribe(int num_parms, ConstStr *Params) { int ret; char roomname[ROOMNAMELEN]; char savedroom[ROOMNAMELEN]; int msgs, new; - ret = imap_grabroom(roomname, parms[2], 1); + 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", - parms[0], + Params[0].Key, ret ); return; } /* - * usergoto() formally takes us to the desired room, which has the side + * CtdlUserGoto() formally takes us to the desired room, which has the side * effect of marking the room as not-zapped ... exactly the effect * we're looking for. */ if (IMAP->selected) { strcpy(savedroom, CC->room.QRname); } - usergoto(roomname, 0, 0, &msgs, &new); + CtdlUserGoto(roomname, 0, 0, &msgs, &new); /* * If another folder is selected, go back to that room so we can resume * our happy day without violent explosions. */ if (IMAP->selected) { - usergoto(savedroom, 0, 0, &msgs, &new); + CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } - cprintf("%s OK SUBSCRIBE completed\r\n", parms[0]); + cprintf("%s OK SUBSCRIBE completed\r\n", Params[0].Key); } @@ -1120,38 +1169,38 @@ void imap_subscribe(int num_parms, char *parms[]) * Implements the UNSUBSCRIBE command * */ -void imap_unsubscribe(int num_parms, char *parms[]) +void imap_unsubscribe(int num_parms, ConstStr *Params) { int ret; char roomname[ROOMNAMELEN]; char savedroom[ROOMNAMELEN]; int msgs, new; - ret = imap_grabroom(roomname, parms[2], 0); + ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { cprintf ("%s NO Invalid mailbox name or location, or access denied\r\n", - parms[0]); + Params[0].Key); return; } /* - * usergoto() formally takes us to the desired room. + * CtdlUserGoto() formally takes us to the desired room. */ if (IMAP->selected) { strcpy(savedroom, CC->room.QRname); } - usergoto(roomname, 0, 0, &msgs, &new); + CtdlUserGoto(roomname, 0, 0, &msgs, &new); /* * Now make the API call to zap the room */ if (CtdlForgetThisRoom() == 0) { - cprintf("%s OK UNSUBSCRIBE completed\r\n", parms[0]); + cprintf("%s OK UNSUBSCRIBE completed\r\n", Params[0].Key); } else { cprintf ("%s NO You may not unsubscribe from this folder.\r\n", - parms[0]); + Params[0].Key); } /* @@ -1159,48 +1208,47 @@ void imap_unsubscribe(int num_parms, char *parms[]) * our happy day without violent explosions. */ if (IMAP->selected) { - usergoto(savedroom, 0, 0, &msgs, &new); + CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } } - /* * Implements the DELETE command * */ -void imap_delete(int num_parms, char *parms[]) +void imap_delete(int num_parms, ConstStr *Params) { int ret; char roomname[ROOMNAMELEN]; char savedroom[ROOMNAMELEN]; int msgs, new; - ret = imap_grabroom(roomname, parms[2], 1); + ret = imap_grabroom(roomname, Params[2].Key, 1); if (ret != 0) { cprintf("%s NO Invalid mailbox name, or access denied\r\n", - parms[0]); + Params[0].Key); return; } /* - * usergoto() formally takes us to the desired room, happily returning + * CtdlUserGoto() formally takes us to the desired room, happily returning * the number of messages and number of new messages. (If another * folder is selected, save its name so we can return there!!!!!) */ if (IMAP->selected) { strcpy(savedroom, CC->room.QRname); } - usergoto(roomname, 0, 0, &msgs, &new); + CtdlUserGoto(roomname, 0, 0, &msgs, &new); /* * Now delete the room. */ if (CtdlDoIHavePermissionToDeleteThisRoom(&CC->room)) { - schedule_room_for_deletion(&CC->room); - cprintf("%s OK DELETE completed\r\n", parms[0]); + CtdlScheduleRoomForDeletion(&CC->room); + cprintf("%s OK DELETE completed\r\n", Params[0].Key); } else { - cprintf("%s NO Can't delete this folder.\r\n", parms[0]); + cprintf("%s NO Can't delete this folder.\r\n", Params[0].Key); } /* @@ -1208,7 +1256,7 @@ void imap_delete(int num_parms, char *parms[]) * our happy day without violent explosions. */ if (IMAP->selected) { - usergoto(savedroom, 0, 0, &msgs, &new); + CtdlUserGoto(savedroom, 0, 0, &msgs, &new); } } @@ -1256,7 +1304,7 @@ void imap_rename_backend(struct ctdlroom *qrbuf, void *data) * Implements the RENAME command * */ -void imap_rename(int num_parms, char *parms[]) +void imap_rename(int num_parms, ConstStr *Params) { char old_room[ROOMNAMELEN]; char new_room[ROOMNAMELEN]; @@ -1266,45 +1314,45 @@ void imap_rename(int num_parms, char *parms[]) struct irl *irl = NULL; /* the list */ struct irl *irlp = NULL; /* scratch pointer */ struct irlparms irlparms; - char buf[1024]; + char aidemsg[1024]; - if (strchr(parms[3], '\\') != NULL) { + if (strchr(Params[3].Key, '\\') != NULL) { cprintf("%s NO Invalid character in folder name\r\n", - parms[0]); + Params[0].Key); return; } - oldr = imap_roomname(old_room, sizeof old_room, parms[2]); - newr = imap_roomname(new_room, sizeof new_room, parms[3]); + oldr = imap_roomname(old_room, sizeof old_room, Params[2].Key); + newr = imap_roomname(new_room, sizeof new_room, Params[3].Key); new_floor = (newr & 0xFF); r = CtdlRenameRoom(old_room, new_room, new_floor); if (r == crr_room_not_found) { cprintf("%s NO Could not locate this folder\r\n", - parms[0]); + Params[0].Key); return; } if (r == crr_already_exists) { - cprintf("%s NO '%s' already exists.\r\n", parms[0], parms[2]); + cprintf("%s NO '%s' already exists.\r\n", Params[0].Key, Params[2].Key); return; } if (r == crr_noneditable) { - cprintf("%s NO This folder is not editable.\r\n", parms[0]); + cprintf("%s NO This folder is not editable.\r\n", Params[0].Key); return; } if (r == crr_invalid_floor) { - cprintf("%s NO Folder root does not exist.\r\n", parms[0]); + cprintf("%s NO Folder root does not exist.\r\n", Params[0].Key); return; } if (r == crr_access_denied) { cprintf("%s NO You do not have permission to edit this folder.\r\n", - parms[0]); + Params[0].Key); return; } if (r != crr_ok) { cprintf("%s NO Rename failed - undefined error %d\r\n", - parms[0], r); + Params[0].Key, r); return; } @@ -1312,16 +1360,16 @@ void imap_rename(int num_parms, char *parms[]) * contents. In a Citadel environment it's easier to rename the room * (already did that) and create a new inbox. */ - if (!strcasecmp(parms[2], "INBOX")) { - create_room(MAILROOM, 4, "", 0, 1, 0, VIEW_MAILBOX); + if (!strcasecmp(Params[2].Key, "INBOX")) { + CtdlCreateRoom(MAILROOM, 4, "", 0, 1, 0, VIEW_MAILBOX); } /* Otherwise, do the subfolders. Build a list of rooms to rename... */ else { - irlparms.oldname = parms[2]; - irlparms.newname = parms[3]; + irlparms.oldname = Params[2].Key; + irlparms.newname = Params[3].Key; irlparms.irl = &irl; - ForEachRoom(imap_rename_backend, (void *) &irlparms); + CtdlForEachRoom(imap_rename_backend, (void *) &irlparms); /* ... and now rename them. */ while (irl != NULL) { @@ -1338,76 +1386,89 @@ void imap_rename(int num_parms, char *parms[]) } } - snprintf(buf, sizeof buf, "IMAP folder \"%s\" renamed to \"%s\" by %s\n", - parms[2], - parms[3], + snprintf(aidemsg, sizeof aidemsg, "IMAP folder \"%s\" renamed to \"%s\" by %s\n", + Params[2].Key, + Params[3].Key, CC->curr_user ); - aide_message(buf, "IMAP folder rename"); + CtdlAideMessage(aidemsg, "IMAP folder rename"); - cprintf("%s OK RENAME completed\r\n", parms[0]); + cprintf("%s OK RENAME completed\r\n", Params[0].Key); } - - /* * Main command loop for IMAP sessions. */ void imap_command_loop(void) { - char cmdbuf[SIZ]; - char *parms[SIZ]; - int num_parms; struct timeval tv1, tv2; suseconds_t total_time = 0; int untagged_ok = 1; + citimap *Imap; + const char *pchs, *pche; gettimeofday(&tv1, NULL); CC->lastcmd = time(NULL); - memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */ + Imap = IMAP; + flush_output(); - if (client_getln(cmdbuf, sizeof cmdbuf) < 1) { + if (Imap->Cmd.CmdBuf == NULL) + Imap->Cmd.CmdBuf = NewStrBufPlain(NULL, SIZ); + else + FlushStrBuf(Imap->Cmd.CmdBuf); + + if (CtdlClientGetLine(Imap->Cmd.CmdBuf) < 1) { CtdlLogPrintf(CTDL_ERR, "Client disconnected: ending session.\r\n"); CC->kill_me = 1; return; } - if (IMAP->authstate == imap_as_expecting_password) { + if (Imap->authstate == imap_as_expecting_password) { CtdlLogPrintf(CTDL_INFO, "IMAP: \n"); } - else if (IMAP->authstate == imap_as_expecting_plainauth) { + else if (Imap->authstate == imap_as_expecting_plainauth) { CtdlLogPrintf(CTDL_INFO, "IMAP: \n"); } - else if (bmstrcasestr(cmdbuf, " LOGIN ")) { + else if ((Imap->authstate == imap_as_expecting_multilineusername) || + cbmstrcasestr(ChrPtr(Imap->Cmd.CmdBuf), " LOGIN ")) { CtdlLogPrintf(CTDL_INFO, "IMAP: LOGIN...\n"); } else { - CtdlLogPrintf(CTDL_INFO, "IMAP: %s\n", cmdbuf); + CtdlLogPrintf(CTDL_INFO, "IMAP: %s\n", ChrPtr(Imap->Cmd.CmdBuf)); } - while (strlen(cmdbuf) < 5) - strcat(cmdbuf, " "); + pchs = ChrPtr(Imap->Cmd.CmdBuf); + pche = pchs + StrLength(Imap->Cmd.CmdBuf); - /* strip off l/t whitespace and CRLF */ - if (cmdbuf[strlen(cmdbuf) - 1] == '\n') - cmdbuf[strlen(cmdbuf) - 1] = 0; - if (cmdbuf[strlen(cmdbuf) - 1] == '\r') - cmdbuf[strlen(cmdbuf) - 1] = 0; - striplt(cmdbuf); + while ((pche > pchs) && + ((*pche == '\n') || + (*pche == '\r'))) + { + pche --; + StrBufCutRight(Imap->Cmd.CmdBuf, 1); + } + StrBufTrim(Imap->Cmd.CmdBuf); /* If we're in the middle of a multi-line command, handle that */ - if (IMAP->authstate == imap_as_expecting_username) { - imap_auth_login_user(cmdbuf); + switch (Imap->authstate){ + case imap_as_expecting_username: + imap_auth_login_user(imap_as_expecting_username); return; - } - if (IMAP->authstate == imap_as_expecting_plainauth) { - imap_auth_plain(cmdbuf); + case imap_as_expecting_multilineusername: + imap_auth_login_user(imap_as_expecting_multilineusername); return; - } - if (IMAP->authstate == imap_as_expecting_password) { - imap_auth_login_pass(cmdbuf); + case imap_as_expecting_plainauth: + imap_auth_plain(); + return; + case imap_as_expecting_password: + imap_auth_login_pass(imap_as_expecting_password); return; + case imap_as_expecting_multilinepassword: + imap_auth_login_pass(imap_as_expecting_multilinepassword); + return; + default: + break; } @@ -1415,18 +1476,38 @@ void imap_command_loop(void) * If the command just submitted does not contain a literal, we * might think about delivering some untagged stuff... */ - if (cmdbuf[strlen(cmdbuf)-1] == '}') { + if (*(ChrPtr(Imap->Cmd.CmdBuf) + StrLength(Imap->Cmd.CmdBuf) - 1) + == '}') { untagged_ok = 0; } /* Grab the tag, command, and parameters. */ - num_parms = imap_parameterize(parms, cmdbuf); + imap_parameterize(&Imap->Cmd); +#if 0 +/* debug output the parsed vector */ + { + int i; + CtdlLogPrintf(CTDL_DEBUG, "----- %ld params \n", + Imap->Cmd.num_parms); + + for (i=0; i < Imap->Cmd.num_parms; i++) { + if (Imap->Cmd.Params[i].len != strlen(Imap->Cmd.Params[i].Key)) + CtdlLogPrintf(CTDL_DEBUG, "*********** %ld != %ld : %s\n", + Imap->Cmd.Params[i].len, + strlen(Imap->Cmd.Params[i].Key), + Imap->Cmd.Params[i].Key); + else + CtdlLogPrintf(CTDL_DEBUG, "%ld : %s\n", + Imap->Cmd.Params[i].len, + Imap->Cmd.Params[i].Key); + }} +#endif /* RFC3501 says that we cannot output untagged data during these commands */ - if (num_parms >= 2) { - if ( (!strcasecmp(parms[1], "FETCH")) - || (!strcasecmp(parms[1], "STORE")) - || (!strcasecmp(parms[1], "SEARCH")) + 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; } @@ -1442,190 +1523,190 @@ void imap_command_loop(void) * messages, and for deletions/changes of existing messages. This * could probably be optimized better with some deep thought... */ - if (IMAP->selected) { + if (Imap->selected) { imap_rescan_msgids(); } } /* Now for the command set. */ - if (num_parms < 2) { + if (Imap->Cmd.num_parms < 2) { cprintf("BAD syntax error\r\n"); } /* The commands below may be executed in any state */ - else if ((!strcasecmp(parms[1], "NOOP")) - || (!strcasecmp(parms[1], "CHECK"))) { + else if ((!strcasecmp(Imap->Cmd.Params[1].Key, "NOOP")) + || (!strcasecmp(Imap->Cmd.Params[1].Key, "CHECK"))) { cprintf("%s OK No operation\r\n", - parms[0]); + Imap->Cmd.Params[0].Key); } - else if (!strcasecmp(parms[1], "ID")) { - imap_id(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "ID")) { + imap_id(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "LOGOUT")) { - if (IMAP->selected) { + 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", - parms[0]); + Imap->Cmd.Params[0].Key); CC->kill_me = 1; return; } - else if (!strcasecmp(parms[1], "LOGIN")) { - imap_login(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LOGIN")) { + imap_login(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "AUTHENTICATE")) { - imap_authenticate(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "AUTHENTICATE")) { + imap_authenticate(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "CAPABILITY")) { - imap_capability(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "CAPABILITY")) { + imap_capability(Imap->Cmd.num_parms, Imap->Cmd.Params); } #ifdef HAVE_OPENSSL - else if (!strcasecmp(parms[1], "STARTTLS")) { - imap_starttls(num_parms, parms); + 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", parms[0]); + cprintf("%s BAD Not logged in.\r\n", Imap->Cmd.Params[0].Key); } /* The commans below require a logged-in state */ - else if (!strcasecmp(parms[1], "SELECT")) { - imap_select(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SELECT")) { + imap_select(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "EXAMINE")) { - imap_select(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "EXAMINE")) { + imap_select(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "LSUB")) { - imap_list(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LSUB")) { + imap_list(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "LIST")) { - imap_list(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LIST")) { + imap_list(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "CREATE")) { - imap_create(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "CREATE")) { + imap_create(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "DELETE")) { - imap_delete(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "DELETE")) { + imap_delete(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "RENAME")) { - imap_rename(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "RENAME")) { + imap_rename(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "STATUS")) { - imap_status(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "STATUS")) { + imap_status(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "SUBSCRIBE")) { - imap_subscribe(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SUBSCRIBE")) { + imap_subscribe(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "UNSUBSCRIBE")) { - imap_unsubscribe(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "UNSUBSCRIBE")) { + imap_unsubscribe(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "APPEND")) { - imap_append(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "APPEND")) { + imap_append(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "NAMESPACE")) { - imap_namespace(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "NAMESPACE")) { + imap_namespace(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "SETACL")) { - imap_setacl(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SETACL")) { + imap_setacl(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "DELETEACL")) { - imap_deleteacl(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "DELETEACL")) { + imap_deleteacl(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "GETACL")) { - imap_getacl(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "GETACL")) { + imap_getacl(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "LISTRIGHTS")) { - imap_listrights(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "LISTRIGHTS")) { + imap_listrights(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "MYRIGHTS")) { - imap_myrights(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "MYRIGHTS")) { + imap_myrights(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "GETMETADATA")) { - imap_getmetadata(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "GETMETADATA")) { + imap_getmetadata(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if (!strcasecmp(parms[1], "SETMETADATA")) { - imap_setmetadata(num_parms, parms); + 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", parms[0]); + 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(parms[1], "FETCH")) { - imap_fetch(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "FETCH")) { + imap_fetch(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if ((!strcasecmp(parms[1], "UID")) - && (!strcasecmp(parms[2], "FETCH"))) { - imap_uidfetch(num_parms, parms); + 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(parms[1], "SEARCH")) { - imap_search(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "SEARCH")) { + imap_search(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if ((!strcasecmp(parms[1], "UID")) - && (!strcasecmp(parms[2], "SEARCH"))) { - imap_uidsearch(num_parms, parms); + 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(parms[1], "STORE")) { - imap_store(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "STORE")) { + imap_store(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if ((!strcasecmp(parms[1], "UID")) - && (!strcasecmp(parms[2], "STORE"))) { - imap_uidstore(num_parms, parms); + 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(parms[1], "COPY")) { - imap_copy(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "COPY")) { + imap_copy(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if ((!strcasecmp(parms[1], "UID")) && (!strcasecmp(parms[2], "COPY"))) { - imap_uidcopy(num_parms, parms); + 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(parms[1], "EXPUNGE")) { - imap_expunge(num_parms, parms); + else if (!strcasecmp(Imap->Cmd.Params[1].Key, "EXPUNGE")) { + imap_expunge(Imap->Cmd.num_parms, Imap->Cmd.Params); } - else if ((!strcasecmp(parms[1], "UID")) && (!strcasecmp(parms[2], "EXPUNGE"))) { - imap_expunge(num_parms, parms); + 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(parms[1], "CLOSE")) { - imap_close(num_parms, parms); + 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 @@ -1633,7 +1714,7 @@ void imap_command_loop(void) */ else { - cprintf("%s BAD command unrecognized\r\n", parms[0]); + cprintf("%s BAD command unrecognized\r\n", Imap->Cmd.Params[0].Key); } /* If the client transmitted a message we can free it now */ @@ -1641,7 +1722,6 @@ void imap_command_loop(void) gettimeofday(&tv2, NULL); total_time = (tv2.tv_usec + (tv2.tv_sec * 1000000)) - (tv1.tv_usec + (tv1.tv_sec * 1000000)); - CtdlLogPrintf(CTDL_INFO, "IMAP: %s\n", cmdbuf); // FIXME FIXME FIXME REMOVE THIS NOW CtdlLogPrintf(CTDL_DEBUG, "IMAP command completed in %ld.%ld seconds\n", (total_time / 1000000), (total_time % 1000000)