#include "internet_addressing.h"
#include "serv_imap.h"
#include "imap_tools.h"
+#include "imap_fetch.h"
+#include "imap_search.h"
long SYM_IMAP;
IMAP->msgids = NULL;
IMAP->num_msgs = 0;
}
+ if (IMAP->flags != NULL) {
+ phree(IMAP->flags);
+ IMAP->flags = NULL;
+ }
}
IMAP->msgids = reallok(IMAP->msgids,
IMAP->num_msgs * sizeof(long));
}
+ if (IMAP->flags == NULL) {
+ IMAP->flags = mallok(IMAP->num_msgs * sizeof(long));
+ }
+ else {
+ IMAP->flags = reallok(IMAP->flags,
+ IMAP->num_msgs * sizeof(long));
+ }
IMAP->msgids[IMAP->num_msgs - 1] = msgnum;
+ IMAP->flags[IMAP->num_msgs - 1] = 0;
}
void imap_greeting(void) {
strcpy(CC->cs_clientname, "IMAP session");
- CC->internal_pgm = 1;
CtdlAllocUserData(SYM_IMAP, sizeof(struct citimap));
+ IMAP->authstate = imap_as_normal;
cprintf("* OK %s Citadel/UX IMAP4rev1 server ready\r\n",
config.c_fqdn);
}
+/*
+ * Implements the AYTHENTICATE command
+ */
+void imap_authenticate(int num_parms, char *parms[]) {
+ char buf[SIZ];
+
+ if (num_parms != 3) {
+ cprintf("%s BAD incorrect number of parameters\r\n", parms[0]);
+ return;
+ }
+
+ if (!strcasecmp(parms[2], "LOGIN")) {
+ encode_base64(buf, "Username:");
+ cprintf("+ %s\r\n", buf);
+ IMAP->authstate = imap_as_expecting_username;
+ strcpy(IMAP->authseq, parms[0]);
+ return;
+ }
+
+ else {
+ cprintf("%s NO AUTHENTICATE %s failed\r\n",
+ parms[0], parms[1]);
+ }
+}
+
+void imap_auth_login_user(char *cmd) {
+ char buf[SIZ];
+
+ decode_base64(buf, cmd);
+ CtdlLoginExistingUser(buf);
+ encode_base64(buf, "Password:");
+ cprintf("+ %s\r\n", buf);
+ IMAP->authstate = imap_as_expecting_password;
+ return;
+}
+
+void imap_auth_login_pass(char *cmd) {
+ char buf[SIZ];
+
+ decode_base64(buf, cmd);
+ if (CtdlTryPassword(buf) == pass_ok) {
+ cprintf("%s OK authentication succeeded\r\n", IMAP->authseq);
+ }
+ else {
+ cprintf("%s NO authentication failed\r\n", IMAP->authseq);
+ }
+ IMAP->authstate = imap_as_normal;
+ return;
+}
+
+
+
/*
* implements the CAPABILITY command
*/
* implements the SELECT command
*/
void imap_select(int num_parms, char *parms[]) {
- char towhere[256];
- char augmented_roomname[256];
+ char towhere[SIZ];
+ char augmented_roomname[SIZ];
int c = 0;
int ok = 0;
int ra = 0;
strcpy(towhere, parms[2]);
/* IMAP uses the reserved name "INBOX" for the user's default incoming
- * mail folder. Convert this to Citadel's reserved name "_MAIL_".
+ * mail folder. Convert this to whatever Citadel is using for the
+ * default mail room name (usually "Mail>").
*/
- if (!strcasecmp(towhere, "INBOX"))
+ if (!strcasecmp(towhere, "INBOX")) {
strcpy(towhere, MAILROOM);
+ }
/* First try a regular match */
c = getroom(&QRscratch, towhere);
ra = CtdlRoomAccess(&QRscratch, &CC->usersupp);
/* normal clients have to pass through security */
- if (ra & UA_KNOWN)
+ if (ra & UA_KNOWN) {
ok = 1;
+ }
}
/* Fail here if no such room */
/*
* Back end for imap_lsub()
+ *
+ * IMAP "subscribed folder" is equivocated to Citadel "known rooms." This
+ * may or may not be the desired behavior in the future.
*/
void imap_lsub_listroom(struct quickroom *qrbuf, void *data) {
- char buf[256];
-
- imap_mailboxname(buf, sizeof buf, qrbuf);
- cprintf("* LSUB () \"|\" \"%s\"\r\n", buf);
+ char buf[SIZ];
+ int ra;
+
+ /* Only list rooms to which the user has access!! */
+ ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
+ if (ra & UA_KNOWN) {
+ imap_mailboxname(buf, sizeof buf, qrbuf);
+ cprintf("* LSUB () \"|\" \"%s\"\r\n", buf);
+ }
}
* Implements the LSUB command
*
* FIXME: Handle wildcards, please.
- * FIXME: Currently we show all rooms as subscribed folders. Need to handle
- * subscriptions properly.
*/
void imap_lsub(int num_parms, char *parms[]) {
ForEachRoom(imap_lsub_listroom, NULL);
* Back end for imap_list()
*/
void imap_list_listroom(struct quickroom *qrbuf, void *data) {
- char buf[256];
-
- imap_mailboxname(buf, sizeof buf, qrbuf);
- cprintf("* LIST () \"|\" \"%s\"\r\n", buf);
+ char buf[SIZ];
+ int ra;
+
+ /* Only list rooms to which the user has access!! */
+ ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
+ if ( (ra & UA_KNOWN)
+ || ((ra & UA_GOTOALLOWED) && (ra & UA_ZAPPED))) {
+ imap_mailboxname(buf, sizeof buf, qrbuf);
+ cprintf("* LIST () \"|\" \"%s\"\r\n", buf);
+ }
}
}
-/*
- * Do the actual work for imap_fetch(). By the time this function is called,
- * the "lo" and "hi" sequence numbers are already validated, and the data item
- * names are, um... something.
- */
-void imap_do_fetch(int lo, int hi, char *items) {
- cprintf("* lo=%d hi=%d items=<%s>\r\n", lo, hi, items);
-}
-
-
-/*
- * Mark Crispin is a fscking idiot.
- */
-void imap_fetch(int num_parms, char *parms[]) {
- int lo = 0;
- int hi = 0;
- char lostr[1024], histr[1024], items[1024];
- int i;
-
- if (num_parms < 4) {
- cprintf("%s BAD invalid parameters\r\n", parms[0]);
- return;
- }
-
- extract_token(lostr, parms[2], 0, ':');
- lo = atoi(lostr);
- extract_token(histr, parms[2], 1, ':');
- hi = atoi(histr);
-
- if ( (lo < 1) || (hi < 1) || (lo > hi) || (hi > IMAP->num_msgs) ) {
- cprintf("%s BAD invalid sequence numbers %d:%d\r\n",
- parms[0], lo, hi);
- return;
- }
-
- strcpy(items, "");
- for (i=3; i<num_parms; ++i) {
- strcat(items, parms[i]);
- if (i < (num_parms-1)) strcat(items, " ");
- }
- for (i=0; i<strlen(items); ++i) {
- if (isspace(items[i])) items[i] = ' ';
- }
-
- imap_do_fetch(lo, hi, items);
- cprintf("%s OK FETCH completed\r\n", parms[0]);
-}
-
-
-
/*
* Main command loop for IMAP sessions.
*/
void imap_command_loop(void) {
- char cmdbuf[256];
- char *parms[16];
+ char cmdbuf[SIZ];
+ char *parms[SIZ];
int num_parms;
- int i;
time(&CC->lastcmd);
memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
if (cmdbuf[strlen(cmdbuf)-1]=='\r') cmdbuf[strlen(cmdbuf)-1]=0;
striplt(cmdbuf);
+ /* If we're in the middle of a multi-line command, handle that */
+ if (IMAP->authstate == imap_as_expecting_username) {
+ imap_auth_login_user(cmdbuf);
+ return;
+ }
+ if (IMAP->authstate == imap_as_expecting_password) {
+ imap_auth_login_pass(cmdbuf);
+ return;
+ }
+
+
+ /* Ok, at this point we're in normal command mode */
+
/* grab the tag */
num_parms = imap_parameterize(parms, cmdbuf);
- for (i=0; i<num_parms; ++i) {
- lprintf(9, " parms[%d]='%s'\n", i, parms[i]);
- }
/* commands which may be executed in any state */
imap_login(num_parms, parms);
}
+ else if (!strcasecmp(parms[1], "AUTHENTICATE")) {
+ imap_authenticate(num_parms, parms);
+ }
+
else if (!strcasecmp(parms[1], "CAPABILITY")) {
imap_capability(num_parms, parms);
}
imap_fetch(num_parms, parms);
}
+ else if ( (!strcasecmp(parms[1], "UID"))
+ && (!strcasecmp(parms[2], "FETCH")) ) {
+ imap_uidfetch(num_parms, parms);
+ }
+
+ else if (!strcasecmp(parms[1], "SEARCH")) {
+ imap_search(num_parms, parms);
+ }
+
+ else if ( (!strcasecmp(parms[1], "UID"))
+ && (!strcasecmp(parms[2], "SEARCH")) ) {
+ imap_uidsearch(num_parms, parms);
+ }
+
else if (!strcasecmp(parms[1], "CLOSE")) {
imap_close(num_parms, parms);
}
char *Dynamic_Module_Init(void)
{
SYM_IMAP = CtdlGetDynamicSymbol();
- CtdlRegisterServiceHook(143, /* FIXME put in config setup */
+ CtdlRegisterServiceHook(config.c_imap_port,
NULL,
imap_greeting,
imap_command_loop);