#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"
*/
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;
}
*/
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;
}
* 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)
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 */
/* 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) */
* theoretically prevent compliant clients from attempting to
* perform them.
*
- * strcat(rights, "a");
+ * StrBufAppendBufPlain(rights, HKEY("a"), 0);
*/
}
}
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;
}
*/
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;
}
}
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);
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
CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
}
- cprintf("%s OK GETACL completed\r\n", Params[0].Key);
+ IReply("OK GETACL completed");
}
struct ctdluser temp;
if (num_parms != 4) {
- 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;
}
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;
}
/*
* 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
CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
}
- cprintf("%s OK LISTRIGHTS completed\r\n", Params[0].Key);
+ IReply("OK LISTRIGHTS completed");
return;
}
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;
}
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.
CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
}
- cprintf("%s OK MYRIGHTS completed\r\n", Params[0].Key);
+ IReply("OK MYRIGHTS completed");
return;
}
#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"
*/
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(")");
}
}
datestring(datebuf, sizeof datebuf, msgdate, DATESTRING_IMAP);
- cprintf("INTERNALDATE \"%s\"", datebuf);
+ IAPrintf( "INTERNALDATE \"%s\"", datebuf);
}
* "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;
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;
* 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
*/
(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);
}
}
StrBuf *Line = NewStrBuf();
ptr = NULL;
do {
- StrBufSipLine(Line, IMAP->cached_rfc822, &ptr);
+ StrBufSipLine(Line, Imap->cached_rfc822, &ptr);
if ((StrLength(Line) != 0) && (ptr != StrBufNOTNULL))
{
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;
}
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);
}
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);
}
-
-
}
/* 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);
}
}
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 */
}
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, ',');
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(") ");
}
char datestringbuf[SIZ];
time_t msgdate;
char *fieldptr = NULL;
+ long len;
if (!msg) return;
* 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);
/* 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(")");
}
/*
int need_body = 1;
int burn_the_cache = 0;
CitContext *CCC = CC;
+ citimap *Imap = IMAP;
/* extract section */
section = NewStrBufPlain(CKEY(item));
/* 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, "");
}
}
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));
}
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);
char *cbid, void *cbuserdata
) {
- cprintf("(");
+ IAPuts("(");
}
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(")");
}
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");
}
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) {
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.
if (length) for (i=0; i<length; ++i) {
if (((char *)content)[i] == '\n') ++lines;
}
- cprintf("%d ", lines);
+ IAPrintf("%d ", lines);
}
/* More gratuitous complexity */
}
/* MD5 value of body part; we can get away with NIL'ing this */
- cprintf("NIL ");
+ IAPuts("NIL ");
/* Disposition */
if (disp == NULL) {
- cprintf("NIL");
+ IAPuts("NIL");
}
else if (IsEmptyStr(disp)) {
- cprintf("NIL");
+ IAPuts("NIL");
}
else {
- cprintf("(");
+ IAPuts("(");
plain_imap_strout(disp);
if (filename != NULL) if (!IsEmptyStr(filename)) {
- cprintf(" (\"FILENAME\" ");
+ IAPuts(" (\"FILENAME\" ");
plain_imap_strout(filename);
- cprintf(")");
+ IAPuts(")");
}
- cprintf(")");
+ IAPuts(")");
}
/* Body language (not defined yet) */
- cprintf(" NIL)");
+ IAPuts(" NIL)");
}
/* Handle NULL message gracefully */
if (msg == NULL) {
- cprintf("BODYSTRUCTURE (\"TEXT\" \"PLAIN\" "
+ IAPuts("BODYSTRUCTURE (\"TEXT\" \"PLAIN\" "
"(\"CHARSET\" \"US-ASCII\") NIL NIL "
"\"7BIT\" 0 0)");
return;
rfc822_body_len = rfc822_len - rfc822_headers_len;
free(pch);
- cprintf("BODYSTRUCTURE (\"TEXT\" \"PLAIN\" "
- "(\"CHARSET\" \"US-ASCII\") NIL NIL "
- "\"7BIT\" " SIZE_T_FMT " %d)", rfc822_body_len, lines);
+ IAPuts("BODYSTRUCTURE (\"TEXT\" \"PLAIN\" "
+ "(\"CHARSET\" \"US-ASCII\") NIL NIL "
+ "\"7BIT\" ");
+ IAPrintf(SIZE_T_FMT " %d)", rfc822_body_len, lines);
return;
}
/* For messages already stored in RFC822 format, we have to parse. */
- cprintf("BODYSTRUCTURE ");
+ IAPuts("BODYSTRUCTURE ");
mime_parser(msg->cm_fields['M'],
NULL,
*imap_fetch_bodystructure_part, /* part */
if (Imap->msgids[seq-1] < 1L) return;
buffer_output();
- cprintf("* %d FETCH (", seq);
+ IAPrintf("* %d FETCH (", seq);
for (i=0; i<Cmd->num_parms; ++i) {
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);
* 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 */
#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
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);
}
}
* 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
safestrncpy(actual_range, supplied_range, sizeof actual_range);
}
- Imap = IMAP;
/*
* Clear out the IMAP_SELECTED flags for all messages.
*/
int num_items;
if (num_parms < 4) {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
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);
}
int have_uid_item = 0;
if (num_parms < 5) {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
#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;
}
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);
}
#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"
}
}
if (match) {
- cprintf("* %s (\\NoSelect \\HasChildren) \"/\" ", verb);
+ IAPrintf("* %s (\\NoSelect \\HasChildren) \"/\" ", verb);
plain_imap_strout(fl->f_name);
- cprintf("\r\n");
+ IAPuts("\r\n");
}
}
}
}
}
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");
}
}
}
*/
void imap_list(int num_parms, ConstStr *Params)
{
+ citimap *Imap = IMAP;
int i, j, paren_nest;
ImapRoomListFilter ImapFilter;
int selection_left = (-1);
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;
}
/* 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);
}
/* 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);
* 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,
}
- cprintf("%s OK %s completed\r\n", Params[0].Key, ImapFilter.verb);
+ IReplyPrintf("OK %s completed", ImapFilter.verb);
}
#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"
visit vbuf;
if (num_parms != 6) {
- cprintf("%s BAD usage error\r\n", Params[0].Key);
+ IReply("BAD usage error");
return;
}
* 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;
}
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;
}
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 (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
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");
}
/*
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;
}
}
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.
* 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.
CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
}
- cprintf("%s OK GETMETADATA complete\r\n", Params[0].Key);
+ IReply("OK GETMETADATA complete");
return;
}
#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"
* 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);
}
/*
* 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];
}
}
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];
}
}
}
* 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("] ");
}
}
int ret;
if (num_parms != 4) {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
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);
}
}
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;
}
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");
}
}
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;
}
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;
}
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;
}
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 (ret) {
/* Nope ... print an error message */
- cprintf("%s NO %s\r\n", Params[0].Key, errbuf);
+ IReplyPrintf("NO %s", errbuf);
}
else {
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);
}
}
#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"
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;
}
else if (!strcasecmp(itemlist[pos].Key, "ANSWERED")) {
- if (IMAP->flags[seq-1] & IMAP_ANSWERED) {
+ if (Imap->flags[seq-1] & IMAP_ANSWERED) {
match = 1;
}
++pos;
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) {
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) {
/* 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) {
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) {
}
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;
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) {
* 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;
}
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) {
}
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;
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) {
}
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;
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
/* 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;
*/
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;
}
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;
* 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;
for (i=0; i<num_items; ++i) {
if (itemlist[i].Key[0] == '(') {
- TokenCutLeft(&IMAP->Cmd,
+ TokenCutLeft(&Imap->Cmd,
&itemlist[i],
1);
}
if (itemlist[i].Key[itemlist[i].len-1] == ')') {
- TokenCutRight(&IMAP->Cmd,
+ TokenCutRight(&Imap->Cmd,
&itemlist[i],
1);
}
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; k<fts_num_msgs; ++k) {
- if (IMAP->msgids[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) {
/* 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();
}
int i;
if (num_parms < 3) {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
}
imap_do_search(num_parms-2, &Params[2], 0);
- cprintf("%s OK SEARCH completed\r\n", Params[0].Key);
+ IReply("OK SEARCH completed");
}
/*
int i;
if (num_parms < 4) {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
}
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");
}
#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"
* 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);
}
}
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");
}
}
imap_do_expunge();
imap_rescan_msgids();
}
-
}
int num_items;
if (num_parms < 3) {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
imap_pick_range(Params[2].Key, 0);
}
else {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
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);
}
int num_items;
if (num_parms < 4) {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
imap_pick_range(Params[3].Key, 1);
}
else {
- cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
+ IReply("BAD invalid parameters");
return;
}
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);
}
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define SHOW_ME_VAPPEND_PRINTF
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
+#include <stdarg.h>
#include <libcitadel.h>
#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
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);
- }
-}
-
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(")");
}
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);
+}
-/*
- * 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,
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);
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)
+*/
+
+
#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);
+ }
+}
+
+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 {
*/
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)
{
+ citimap *Imap = IMAP;
visit vbuf;
int i;
int num_sets;
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) {
+ if (Imap->selected == 0) {
CtdlLogPrintf(CTDL_ERR,
"imap_load_msgids() can't run; no room selected\n");
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) {
+ if (Imap->selected == 0) {
CtdlLogPrintf(CTDL_ERR, "imap_load_msgids() can't run; no room selected\n");
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;
}
/*
* 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();
}
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");
}
* 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_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();
}
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;
}
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;
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];
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);
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);
}
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;
}
}
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;
}
*/
void imap_select(int num_parms, ConstStr *Params)
{
+ citimap *Imap = IMAP;
char towhere[ROOMNAMELEN];
char augmented_roomname[ROOMNAMELEN];
int c = 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);
/* 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) {
+ 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) {
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 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");
}
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;
}
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;
}
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,
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;
}
* 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.
/*
* 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.");
}
/*
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;
}
);
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);
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...
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);
- }
-
- 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);
);
}
+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,
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 */
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 */
#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)