/*
- * $Id$
- *
* IMAP server for the Citadel system
- * Copyright (C) 2000-2009 by Art Cancro and others.
+ *
+ * Copyright (C) 2000-2011 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
+ * This program is open source 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.
#include "support.h"
#include "config.h"
#include "user_ops.h"
-#include "policy.h"
#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"
#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);
+ }
+}
+
+void imap_cleanup(void)
+{
+ DeleteHash(&ImapCmds);
+}
+
+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);
+
+ syslog(LOG_DEBUG, "---- Looking up [%s] -----",
+ ChrPtr(Imap->Reply));
+ if (GetHash(ImapCmds, SKEY(Imap->Reply), &v))
+ {
+ syslog(LOG_DEBUG, "Found.");
+ FlushStrBuf(Imap->Reply);
+ return (imap_handler_hook *) v;
+ }
+
+ if (num_parms == 1)
+ {
+ syslog(LOG_DEBUG, "NOT Found.");
+ FlushStrBuf(Imap->Reply);
+ return NULL;
+ }
+
+ syslog(LOG_DEBUG, "---- Looking up [%s] -----",
+ ChrPtr(Imap->Reply));
+ StrBufAppendBufPlain(Imap->Reply, CKEY(Params[2]), 0);
+ StrBufUpCase(Imap->Reply);
+ if (GetHash(ImapCmds, SKEY(Imap->Reply), &v))
+ {
+ syslog(LOG_DEBUG, "Found.");
+ FlushStrBuf(Imap->Reply);
+ return (imap_handler_hook *) v;
+ }
+ syslog(LOG_DEBUG, "NOT Found.");
+ FlushStrBuf(Imap->Reply);
+ return NULL;
+}
/* imap_rename() uses this struct containing list of rooms to rename */
struct irl {
*/
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);
}
*/
void imap_set_seen_flags(int first_msg)
{
- struct visit vbuf;
+ citimap *Imap = IMAP;
+ visit vbuf;
int i;
int num_sets;
int s;
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;
}
/*
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;
}
}
}
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;
}
}
}
*/
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;
}
void imap_load_msgids(void)
{
struct cdbdata *cdbfr;
+ citimap *Imap = IMAP;
- if (IMAP->selected == 0) {
- CtdlLogPrintf(CTDL_ERR,
- "imap_load_msgids() can't run; no room selected\n");
+ if (Imap->selected == 0) {
+ syslog(LOG_ERR, "imap_load_msgids() can't run; no room selected");
return;
}
/* 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);
*/
void imap_rescan_msgids(void)
{
-
+ citimap *Imap = IMAP;
int original_num_msgs = 0;
long original_highest = 0L;
int i, j, jstart;
int num_msgs = 0;
int num_recent = 0;
- if (IMAP->selected == 0) {
- CtdlLogPrintf(CTDL_ERR, "imap_load_msgids() can't run; no room selected\n");
+ if (Imap->selected == 0) {
+ syslog(LOG_ERR, "imap_load_msgids() can't run; no room selected");
return;
}
* 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;
}
if (cdbfr != NULL) {
msglist = malloc(cdbfr->len);
if (msglist == NULL) {
- CtdlLogPrintf(CTDL_CRIT, "malloc() failed\n");
- abort();
+ syslog(LOG_CRIT, "IMAP: malloc() failed");
+ CC->kill_me = KILLME_MALLOC_FAILED;
+ return;
}
memcpy(msglist, cdbfr->ptr, (size_t)cdbfr->len);
num_msgs = cdbfr->len / sizeof(long);
/*
* 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;
}
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;
}
/*
* 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;
}
/*
* 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;
}
*/
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();
}
- CtdlLogPrintf(CTDL_DEBUG, "Performing IMAP cleanup hook\n");
+ syslog(LOG_DEBUG, "Performing IMAP cleanup hook");
imap_free_msgids();
imap_free_transmitted_message();
- if (IMAP->cached_rfc822_data != NULL) {
- free(IMAP->cached_rfc822_data);
- IMAP->cached_rfc822_data = NULL;
- 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);
- CtdlLogPrintf(CTDL_DEBUG, "Finished IMAP cleanup hook\n");
+ FreeStrBuf(&Imap->Cmd.CmdBuf);
+ FreeStrBuf(&Imap->Reply);
+ if (Imap->Cmd.Params != NULL) free(Imap->Cmd.Params);
+ free(Imap);
+ syslog(LOG_DEBUG, "Finished IMAP cleanup hook");
}
* 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
* 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.
* If you uncomment this declaration you are responsible for writing a lot of new
* code.
*
- * cprintf(" LIST-EXTENDED")
+ * IAPuts(" LIST-EXTENDED")
*/
}
*/
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");
}
*/
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");
}
*/
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_data = NULL;
- 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 = KILLME_NOLOGIN;
+ 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();
}
void imaps_greeting(void) {
CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
#ifdef HAVE_OPENSSL
- if (!CC->redirect_ssl) CC->kill_me = 1; /* kill session if no crypto */
+ if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO; /* kill session if no crypto */
#endif
imap_greeting();
}
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) == pass_ok) {
- cprintf("%s OK [", Params[0].Key);
+ if (CtdlTryPassword(Params[3].Key, Params[3].len) == pass_ok) {
+ /* 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
+ {
+ IReplyPrintf("NO AUTHENTICATE %s failed",
+ 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;
}
*/
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",
- 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(buf, "Username:", 9, 0);
- cprintf("+ %s\r\n", buf);
+ CtdlEncodeBase64(UsrBuf, "Username:", 9, 0);
+ IAPrintf("+ %s\r\n", UsrBuf);
IMAP->authstate = imap_as_expecting_username;
strcpy(IMAP->authseq, Params[0].Key);
return;
}
if (!strcasecmp(Params[2].Key, "PLAIN")) {
- // CtdlEncodeBase64(buf, "Username:", 9, 0);
- // cprintf("+ %s\r\n", buf);
- cprintf("+ \r\n");
+ // CtdlEncodeBase64(UsrBuf, "Username:", 9, 0);
+ // 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];
char pass[256];
int result;
+ 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);
- 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;
+ Imap->authstate = imap_as_normal;
if (!IsEmptyStr(ident)) {
result = CtdlLoginExistingUser(user, ident);
}
if (result == login_ok) {
- if (CtdlTryPassword(pass) == pass_ok) {
- cprintf("%s OK authentication succeeded\r\n", IMAP->authseq);
+ if (CtdlTryPassword(pass, len) == pass_ok) {
+ 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);
}
void imap_auth_login_user(long state)
{
- char buf[SIZ];
+ char PWBuf[SIZ];
citimap *Imap = IMAP;
switch (state){
case imap_as_expecting_username:
StrBufDecodeBase64(Imap->Cmd.CmdBuf);
CtdlLoginExistingUser(NULL, ChrPtr(Imap->Cmd.CmdBuf));
- CtdlEncodeBase64(buf, "Password:", 9, 0);
- cprintf("+ %s\r\n", buf);
+ CtdlEncodeBase64(PWBuf, "Password:", 9, 0);
+ IAPrintf("+ %s\r\n", PWBuf);
Imap->authstate = imap_as_expecting_password;
return;
case imap_as_expecting_multilineusername:
- extract_token(buf, ChrPtr(Imap->Cmd.CmdBuf), 1, ' ', sizeof(buf));
+ 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;
}
}
{
citimap *Imap = IMAP;
const char *pass = NULL;
- char buf[SIZ];
+ long len = 0;
switch (state) {
default:
case imap_as_expecting_password:
StrBufDecodeBase64(Imap->Cmd.CmdBuf);
- pass = buf;
+ 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 (CtdlTryPassword(pass) == pass_ok) {
- cprintf("%s OK authentication succeeded\r\n", IMAP->authseq);
+ if (len > USERNAME_SIZE)
+ StrBufCutAt(Imap->Cmd.CmdBuf, USERNAME_SIZE, NULL);
+
+ if (CtdlTryPassword(pass, len) == pass_ok) {
+ 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;
}
char nosup_response[SIZ];
char error_response[SIZ];
- sprintf(ok_response, "%s OK begin TLS negotiation now\r\n", Params[0].Key);
- sprintf(nosup_response, "%s NO TLS not supported here\r\n", Params[0].Key);
- sprintf(error_response, "%s BAD Internal error\r\n", Params[0].Key);
+ 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);
}
*/
void imap_select(int num_parms, ConstStr *Params)
{
- char towhere[SIZ];
+ citimap *Imap = IMAP;
+ char towhere[ROOMNAMELEN];
char augmented_roomname[ROOMNAMELEN];
int c = 0;
int ok = 0;
/* 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);
CtdlMailboxName(augmented_roomname, sizeof augmented_roomname, &CC->user, towhere);
c = CtdlGetRoom(&QRscratch, augmented_roomname);
if (c == 0) {
- strcpy(towhere, augmented_roomname);
+ safestrncpy(towhere, augmented_roomname, sizeof(towhere));
}
}
/* 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;
}
*/
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
* 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
);
}
*/
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) {
+ syslog(LOG_DEBUG, "imap_do_expunge() called");
+ 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) {
imap_rescan_msgids();
}
- CtdlLogPrintf(CTDL_DEBUG, "Expunged %d messages from <%s>\n", num_expunged, CC->room.QRname);
+ syslog(LOG_DEBUG, "Expunged %d messages from <%s>", num_expunged, CC->room.QRname);
return (num_expunged);
}
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);
}
IMAP->selected = 0;
IMAP->readonly = 0;
imap_free_msgids();
- cprintf("%s OK CLOSE completed\r\n", Params[0].Key);
+ IReply("OK CLOSE completed");
}
int i;
struct floor *fl;
int floors = 0;
- char buf[SIZ];
+ 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(" ");
- cprintf("(");
- sprintf(buf, "%s/", fl->f_name);
- plain_imap_strout(buf);
- cprintf(" \"/\")");
+ /* if (floors > 0) IAPuts(" "); samjam says this confuses javamail */
+ IAPuts("(");
+ snprintf(Namespace, sizeof(Namespace), "%s/", fl->f_name);
+ plain_imap_strout(Namespace);
+ 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");
}
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);
- CtdlLogPrintf(CTDL_DEBUG, "invalid character in folder name\n");
+ IReply("NO Invalid character in folder name");
+ syslog(LOG_DEBUG, "invalid character in folder name");
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);
- CtdlLogPrintf(CTDL_DEBUG, "invalid mailbox name or location\n");
+ IReply("NO Invalid mailbox name or location");
+ syslog(LOG_DEBUG, "invalid mailbox name or location");
return;
}
floornum = (ret & 0x00ff); /* lower 8 bits = floor number */
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);
- CtdlLogPrintf(CTDL_DEBUG, "not subordinate to inbox\n");
+ IReply("NO Personal folders must be created under INBOX");
+ syslog(LOG_DEBUG, "not subordinate to inbox");
return;
}
}
newroomview = VIEW_BBS;
}
- CtdlLogPrintf(CTDL_INFO, "Create new room <%s> on floor <%d> with type <%d>\n",
+ syslog(LOG_INFO, "IMAP: Create new room <%s> on floor <%d> with type <%d>",
roomname, floornum, newroomtype);
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("OK CREATE completed");
/* post a message in Aide> describing the new room */
notification_message = malloc(1024);
snprintf(notification_message, 1024,
CtdlAideMessage(notification_message, "Room Creation Message");
free(notification_message);
}
- CtdlLogPrintf(CTDL_DEBUG, "imap_create() completed\n");
+ syslog(LOG_DEBUG, "imap_create() completed");
}
&CC->user, 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 */
strcpy(returned_roomname, "");
return (2);
} else {
- strcpy(returned_roomname, QRscratch.QRname);
+ safestrncpy(returned_roomname, QRscratch.QRname, ROOMNAMELEN);
return (0);
}
}
{
int ret;
char roomname[ROOMNAMELEN];
- char buf[SIZ];
+ char imaproomname[SIZ];
char savedroom[ROOMNAMELEN];
int msgs, new;
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;
}
* 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);
- cprintf("* STATUS ");
- plain_imap_strout(buf);
- cprintf(" (MESSAGES %d ", msgs);
- cprintf("RECENT %d ", new); /* Initially, new==recent */
- cprintf("UIDNEXT %ld ", CitControl.MMhighest + 1);
- cprintf("UNSEEN %d)\r\n", new);
-
+ imap_mailboxname(imaproomname, sizeof imaproomname, &CC->room);
+ 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.
/*
* Oooh, look, we're done!
*/
- cprintf("%s OK STATUS completed\r\n", Params[0].Key);
+ IReply("OK STATUS completed");
}
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;
CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
}
- cprintf("%s OK SUBSCRIBE completed\r\n", Params[0].Key);
+ IReply("OK SUBSCRIBE completed");
}
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;
}
* 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.");
}
/*
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;
}
*/
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.");
}
/*
struct irl *irl = NULL; /* the list */
struct irl *irlp = NULL; /* scratch pointer */
struct irlparms irlparms;
- char buf[1024];
+ 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;
}
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;
}
irl->irl_newfloor);
if (r != crr_ok) {
/* FIXME handle error returns better */
- CtdlLogPrintf(CTDL_ERR, "CtdlRenameRoom() error %d\n", r);
+ syslog(LOG_ERR, "IMAP: CtdlRenameRoom() error %d", r);
}
irlp = irl;
irl = irl->next;
}
}
- snprintf(buf, sizeof buf, "IMAP folder \"%s\" renamed to \"%s\" by %s\n",
+ snprintf(aidemsg, sizeof aidemsg, "IMAP folder \"%s\" renamed to \"%s\" by %s\n",
Params[2].Key,
Params[3].Key,
CC->curr_user
);
- CtdlAideMessage(buf, "IMAP folder rename");
+ CtdlAideMessage(aidemsg, "IMAP folder rename");
- cprintf("%s OK RENAME completed\r\n", Params[0].Key);
+ IReply("OK RENAME completed");
}
int untagged_ok = 1;
citimap *Imap;
const char *pchs, *pche;
+ const imap_handler_hook *h;
gettimeofday(&tv1, NULL);
CC->lastcmd = time(NULL);
FlushStrBuf(Imap->Cmd.CmdBuf);
if (CtdlClientGetLine(Imap->Cmd.CmdBuf) < 1) {
- CtdlLogPrintf(CTDL_ERR, "Client disconnected: ending session.\r\n");
- CC->kill_me = 1;
+ syslog(LOG_ERR, "IMAP: client disconnected: ending session.");
+ CC->kill_me = KILLME_CLIENT_DISCONNECTED;
return;
}
if (Imap->authstate == imap_as_expecting_password) {
- CtdlLogPrintf(CTDL_INFO, "IMAP: <password>\n");
+ syslog(LOG_INFO, "IMAP: <password>");
}
else if (Imap->authstate == imap_as_expecting_plainauth) {
- CtdlLogPrintf(CTDL_INFO, "IMAP: <plain_auth>\n");
+ syslog(LOG_INFO, "IMAP: <plain_auth>");
}
else if ((Imap->authstate == imap_as_expecting_multilineusername) ||
- bmstrcasestr(ChrPtr(Imap->Cmd.CmdBuf), " LOGIN ")) {
- CtdlLogPrintf(CTDL_INFO, "IMAP: LOGIN...\n");
+ cbmstrcasestr(ChrPtr(Imap->Cmd.CmdBuf), " LOGIN ")) {
+ syslog(LOG_INFO, "IMAP: LOGIN...");
}
else {
- CtdlLogPrintf(CTDL_INFO, "IMAP: %s\n", ChrPtr(Imap->Cmd.CmdBuf));
+ syslog(LOG_INFO, "IMAP: %s", ChrPtr(Imap->Cmd.CmdBuf));
}
pchs = ChrPtr(Imap->Cmd.CmdBuf);
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...
/* debug output the parsed vector */
{
int i;
- CtdlLogPrintf(CTDL_DEBUG, "----- %ld params \n",
- Imap->Cmd.num_parms);
+ syslog(LOG_DEBUG, "----- %ld params", 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",
+ syslog(LOG_DEBUG, "*********** %ld != %ld : %s",
Imap->Cmd.Params[i].len,
strlen(Imap->Cmd.Params[i].Key),
Imap->Cmd.Params[i].Key);
else
- CtdlLogPrintf(CTDL_DEBUG, "%ld : %s\n",
+ syslog(LOG_DEBUG, "%ld : %s",
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 */
}
}
- /* 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);
+ /* 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, "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);
+ /* 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);
- /* 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);
- }
-
- else if (!strcasecmp(Imap->Cmd.Params[1].Key, "CREATE")) {
- imap_create(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);
total_time = (tv2.tv_usec + (tv2.tv_sec * 1000000)) - (tv1.tv_usec + (tv1.tv_sec * 1000000));
- CtdlLogPrintf(CTDL_DEBUG, "IMAP command completed in %ld.%ld seconds\n",
+ syslog(LOG_DEBUG, "IMAP command completed in %ld.%ld seconds",
(total_time / 1000000),
(total_time % 1000000)
);
}
+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 = KILLME_CLIENT_LOGGED_OUT;
+ 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,
NULL, imaps_greeting, imap_command_loop, NULL, CitadelServiceIMAPS);
#endif
CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP);
+ CtdlRegisterCleanupHook(imap_cleanup);
}
- /* return our Subversion id for the Log */
- return "$Id$";
+ /* return our module name for the log */
+ return "imap";
}