X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fimap%2Fserv_imap.c;h=55a80e8b0241f82f0aff512920a8c999e3855bba;hb=fa222fcfed9856832eb86a3cbaae7a044ff6142b;hp=29ab6536b579436f1115c485ac5545241a166aa4;hpb=3061bf4d898bdfb0e0dfe294676b2ac6274d0cb4;p=citadel.git diff --git a/citadel/modules/imap/serv_imap.c b/citadel/modules/imap/serv_imap.c index 29ab6536b..55a80e8b0 100644 --- a/citadel/modules/imap/serv_imap.c +++ b/citadel/modules/imap/serv_imap.c @@ -1,13 +1,14 @@ /* * IMAP server for the Citadel system - * Copyright (C) 2000-2009 by Art Cancro and others. + * + * Copyright (C) 2000-2011 by Art Cancro and others. * This code is released under the terms of the GNU General Public License. * * WARNING: the IMAP protocol is badly designed. No implementation of it * is perfect. Indeed, with so much gratuitous complexity, *all* IMAP * implementations have bugs. * - * This program is free software; you can redistribute it and/or modify + * This program is open source software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. @@ -68,7 +69,7 @@ #include "imap_misc.h" #include "ctdl_module.h" - +int IMAPDebugEnabled = 0; HashList *ImapCmds = NULL; void registerImapCMD(const char *First, long FLen, const char *Second, long SLen, @@ -101,8 +102,9 @@ void imap_cleanup(void) const imap_handler_hook *imap_lookup(int num_parms, ConstStr *Params) { + struct CitContext *CCC = CC; void *v; - citimap *Imap = IMAP; + citimap *Imap = CCCIMAP; if (num_parms < 1) return NULL; @@ -111,33 +113,33 @@ const imap_handler_hook *imap_lookup(int num_parms, ConstStr *Params) StrBufPlain(Imap->Reply, CKEY(Params[1])); StrBufUpCase(Imap->Reply); - syslog(LOG_DEBUG, "---- Looking up [%s] -----", + IMAP_syslog(LOG_DEBUG, "---- Looking up [%s] -----", ChrPtr(Imap->Reply)); if (GetHash(ImapCmds, SKEY(Imap->Reply), &v)) { - syslog(LOG_DEBUG, "Found. \n"); + IMAPM_syslog(LOG_DEBUG, "Found."); FlushStrBuf(Imap->Reply); return (imap_handler_hook *) v; } if (num_parms == 1) { - syslog(LOG_DEBUG, "NOT Found. \n"); + IMAPM_syslog(LOG_DEBUG, "NOT Found."); FlushStrBuf(Imap->Reply); return NULL; } - syslog(LOG_DEBUG, "---- Looking up [%s] -----", + IMAP_syslog(LOG_DEBUG, "---- Looking up [%s] -----", ChrPtr(Imap->Reply)); StrBufAppendBufPlain(Imap->Reply, CKEY(Params[2]), 0); StrBufUpCase(Imap->Reply); if (GetHash(ImapCmds, SKEY(Imap->Reply), &v)) { - syslog(LOG_DEBUG, "Found. \n"); + IMAPM_syslog(LOG_DEBUG, "Found."); FlushStrBuf(Imap->Reply); return (imap_handler_hook *) v; } - syslog(LOG_DEBUG, "NOT Found. \n"); + IMAPM_syslog(LOG_DEBUG, "NOT Found."); FlushStrBuf(Imap->Reply); return NULL; } @@ -151,11 +153,13 @@ struct irl { }; /* Data which is passed between imap_rename() and imap_rename_backend() */ -struct irlparms { - char *oldname; - char *newname; +typedef struct __irlparms { + const char *oldname; + long oldnamelen; + const char *newname; + long newnamelen; struct irl **irl; -}; +}irlparms; /* @@ -289,7 +293,7 @@ void imap_add_single_msgid(long msgnum, void *userdata) 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->flags = realloc(Imap->flags, (Imap->num_alloc * sizeof(unsigned int *)) ); } Imap->msgids[Imap->num_msgs - 1] = msgnum; Imap->flags[Imap->num_msgs - 1] = 0; @@ -302,12 +306,12 @@ void imap_add_single_msgid(long msgnum, void *userdata) */ void imap_load_msgids(void) { + struct CitContext *CCC = CC; struct cdbdata *cdbfr; - citimap *Imap = IMAP; + citimap *Imap = CCCIMAP; if (Imap->selected == 0) { - syslog(LOG_ERR, - "imap_load_msgids() can't run; no room selected\n"); + IMAPM_syslog(LOG_ERR, "imap_load_msgids() can't run; no room selected"); return; } @@ -324,7 +328,7 @@ void imap_load_msgids(void) } if (Imap->num_msgs) { - Imap->flags = malloc(Imap->num_alloc * sizeof(long)); + Imap->flags = malloc(Imap->num_alloc * sizeof(unsigned int *)); memset(Imap->flags, 0, (Imap->num_alloc * sizeof(long)) ); } @@ -337,7 +341,8 @@ void imap_load_msgids(void) */ void imap_rescan_msgids(void) { - citimap *Imap = IMAP; + struct CitContext *CCC = CC; + citimap *Imap = CCCIMAP; int original_num_msgs = 0; long original_highest = 0L; int i, j, jstart; @@ -348,7 +353,7 @@ void imap_rescan_msgids(void) int num_recent = 0; if (Imap->selected == 0) { - syslog(LOG_ERR, "imap_load_msgids() can't run; no room selected\n"); + IMAPM_syslog(LOG_ERR, "imap_load_msgids() can't run; no room selected"); return; } @@ -366,10 +371,11 @@ void imap_rescan_msgids(void) */ cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); if (cdbfr != NULL) { - msglist = malloc(cdbfr->len); + msglist = malloc(cdbfr->len + 1); if (msglist == NULL) { - syslog(LOG_CRIT, "malloc() failed\n"); - abort(); + IMAPM_syslog(LOG_CRIT, "malloc() failed"); + CC->kill_me = KILLME_MALLOC_FAILED; + return; } memcpy(msglist, cdbfr->ptr, (size_t)cdbfr->len); num_msgs = cdbfr->len / sizeof(long); @@ -405,14 +411,14 @@ void imap_rescan_msgids(void) * array. */ --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], - (sizeof(long) * - (Imap->num_msgs - i))); + memmove(&Imap->msgids[i], + &Imap->msgids[i + 1], + (sizeof(long) * + (Imap->num_msgs - i))); + memmove(&Imap->flags[i], + &Imap->flags[i + 1], + (sizeof(long) * + (Imap->num_msgs - i))); --i; } @@ -459,7 +465,7 @@ void imap_rescan_msgids(void) IAPrintf("* %d RECENT\r\n", num_recent); } - if (num_msgs != 0) { + if (msglist != NULL) { free(msglist); } Imap->last_mtime = CC->room.QRmtime; @@ -472,7 +478,8 @@ void imap_rescan_msgids(void) */ void imap_cleanup_function(void) { - citimap *Imap = IMAP; + struct CitContext *CCC = CC; + citimap *Imap = CCCIMAP; /* Don't do this stuff if this is not a Imap session! */ if (CC->h_command_function != imap_command_loop) @@ -483,7 +490,7 @@ void imap_cleanup_function(void) imap_do_expunge(); } - syslog(LOG_DEBUG, "Performing IMAP cleanup hook\n"); + IMAPM_syslog(LOG_DEBUG, "Performing IMAP cleanup hook"); imap_free_msgids(); imap_free_transmitted_message(); @@ -503,7 +510,7 @@ void imap_cleanup_function(void) FreeStrBuf(&Imap->Reply); if (Imap->Cmd.Params != NULL) free(Imap->Cmd.Params); free(Imap); - syslog(LOG_DEBUG, "Finished IMAP cleanup hook\n"); + IMAPM_syslog(LOG_DEBUG, "Finished IMAP cleanup hook"); } @@ -820,8 +827,6 @@ void imap_select(int num_parms, ConstStr *Params) int ra = 0; struct ctdlroom QRscratch; int msgs, new; - int floornum; - int roomflags; int i; /* Convert the supplied folder name to a roomname */ @@ -831,8 +836,6 @@ void imap_select(int num_parms, ConstStr *Params) Imap->selected = 0; return; } - floornum = (i & 0x00ff); - roomflags = (i & 0xff00); /* First try a regular match */ c = CtdlGetRoom(&QRscratch, towhere); @@ -912,13 +915,14 @@ void imap_select(int num_parms, ConstStr *Params) */ int imap_do_expunge(void) { - citimap *Imap = IMAP; + struct CitContext *CCC = CC; + citimap *Imap = CCCIMAP; int i; int num_expunged = 0; long *delmsgs = NULL; int num_delmsgs = 0; - syslog(LOG_DEBUG, "imap_do_expunge() called\n"); + IMAPM_syslog(LOG_DEBUG, "imap_do_expunge() called"); if (Imap->selected == 0) { return (0); } @@ -941,7 +945,7 @@ int imap_do_expunge(void) imap_rescan_msgids(); } - syslog(LOG_DEBUG, "Expunged %d messages from <%s>\n", num_expunged, CC->room.QRname); + IMAP_syslog(LOG_DEBUG, "Expunged %d messages from <%s>", num_expunged, CC->room.QRname); return (num_expunged); } @@ -1021,6 +1025,7 @@ void imap_namespace(int num_parms, ConstStr *Params) */ void imap_create(int num_parms, ConstStr *Params) { + struct CitContext *CCC = CC; int ret; char roomname[ROOMNAMELEN]; int floornum; @@ -1036,14 +1041,14 @@ void imap_create(int num_parms, ConstStr *Params) if (strchr(Params[2].Key, '\\') != NULL) { IReply("NO Invalid character in folder name"); - syslog(LOG_DEBUG, "invalid character in folder name\n"); + IMAPM_syslog(LOG_ERR, "invalid character in folder name"); return; } ret = imap_roomname(roomname, sizeof roomname, Params[2].Key); if (ret < 0) { IReply("NO Invalid mailbox name or location"); - syslog(LOG_DEBUG, "invalid mailbox name or location\n"); + IMAPM_syslog(LOG_ERR, "invalid mailbox name or location"); return; } floornum = (ret & 0x00ff); /* lower 8 bits = floor number */ @@ -1052,7 +1057,7 @@ void imap_create(int num_parms, ConstStr *Params) if (flags & IR_MAILBOX) { if (strncasecmp(Params[2].Key, "INBOX/", 6)) { IReply("NO Personal folders must be created under INBOX"); - syslog(LOG_DEBUG, "not subordinate to inbox\n"); + IMAPM_syslog(LOG_ERR, "not subordinate to inbox"); return; } } @@ -1065,8 +1070,8 @@ void imap_create(int num_parms, ConstStr *Params) newroomview = VIEW_BBS; } - syslog(LOG_INFO, "Create new room <%s> on floor <%d> with type <%d>\n", - roomname, floornum, newroomtype); + IMAP_syslog(LOG_INFO, "Create new room <%s> on floor <%d> with type <%d>", + roomname, floornum, newroomtype); ret = CtdlCreateRoom(roomname, newroomtype, "", floornum, 1, 0, newroomview); if (ret == 0) { @@ -1087,7 +1092,7 @@ void imap_create(int num_parms, ConstStr *Params) CtdlAideMessage(notification_message, "Room Creation Message"); free(notification_message); } - syslog(LOG_DEBUG, "imap_create() completed\n"); + IMAPM_syslog(LOG_DEBUG, "imap_create() completed"); } @@ -1347,19 +1352,19 @@ void imap_rename_backend(struct ctdlroom *qrbuf, void *data) char newroomname[ROOMNAMELEN]; int newfloor = 0; struct irl *irlp = NULL; /* scratch pointer */ - struct irlparms *irlparms; + irlparms *myirlparms; - irlparms = (struct irlparms *) data; + myirlparms = (irlparms *) data; imap_mailboxname(foldername, sizeof foldername, qrbuf); /* Rename subfolders */ - if ((!strncasecmp(foldername, irlparms->oldname, - strlen(irlparms->oldname)) - && (foldername[strlen(irlparms->oldname)] == '/'))) { + if ((!strncasecmp(foldername, myirlparms->oldname, + myirlparms->oldnamelen) + && (foldername[myirlparms->oldnamelen] == '/'))) { sprintf(newfoldername, "%s/%s", - irlparms->newname, - &foldername[strlen(irlparms->oldname) + 1] + myirlparms->newname, + &foldername[myirlparms->oldnamelen + 1] ); newfloor = imap_roomname(newroomname, @@ -1370,8 +1375,8 @@ void imap_rename_backend(struct ctdlroom *qrbuf, void *data) strcpy(irlp->irl_newroom, newroomname); strcpy(irlp->irl_oldroom, qrbuf->QRname); irlp->irl_newfloor = newfloor; - irlp->next = *(irlparms->irl); - *(irlparms->irl) = irlp; + irlp->next = *(myirlparms->irl); + *(myirlparms->irl) = irlp; } } @@ -1384,12 +1389,12 @@ void imap_rename(int num_parms, ConstStr *Params) { char old_room[ROOMNAMELEN]; char new_room[ROOMNAMELEN]; - int oldr, newr; + int newr; int new_floor; int r; struct irl *irl = NULL; /* the list */ struct irl *irlp = NULL; /* scratch pointer */ - struct irlparms irlparms; + irlparms irlparms; char aidemsg[1024]; if (strchr(Params[3].Key, '\\') != NULL) { @@ -1397,7 +1402,7 @@ void imap_rename(int num_parms, ConstStr *Params) return; } - oldr = imap_roomname(old_room, sizeof old_room, Params[2].Key); + imap_roomname(old_room, sizeof old_room, Params[2].Key); newr = imap_roomname(new_room, sizeof new_room, Params[3].Key); new_floor = (newr & 0xFF); @@ -1439,7 +1444,9 @@ void imap_rename(int num_parms, ConstStr *Params) /* Otherwise, do the subfolders. Build a list of rooms to rename... */ else { irlparms.oldname = Params[2].Key; + irlparms.oldnamelen = Params[2].len; irlparms.newname = Params[3].Key; + irlparms.newnamelen = Params[3].len; irlparms.irl = &irl; CtdlForEachRoom(imap_rename_backend, (void *) &irlparms); @@ -1449,8 +1456,9 @@ void imap_rename(int num_parms, ConstStr *Params) irl->irl_newroom, irl->irl_newfloor); if (r != crr_ok) { + struct CitContext *CCC = CC; /* FIXME handle error returns better */ - syslog(LOG_ERR, "CtdlRenameRoom() error %d\n", r); + IMAP_syslog(LOG_ERR, "CtdlRenameRoom() error %d", r); } irlp = irl; irl = irl->next; @@ -1474,16 +1482,16 @@ void imap_rename(int num_parms, ConstStr *Params) */ void imap_command_loop(void) { + struct CitContext *CCC = CC; struct timeval tv1, tv2; suseconds_t total_time = 0; - int untagged_ok = 1; citimap *Imap; const char *pchs, *pche; const imap_handler_hook *h; gettimeofday(&tv1, NULL); - CC->lastcmd = time(NULL); - Imap = IMAP; + CCC->lastcmd = time(NULL); + Imap = CCCIMAP; flush_output(); if (Imap->Cmd.CmdBuf == NULL) @@ -1492,23 +1500,23 @@ void imap_command_loop(void) FlushStrBuf(Imap->Cmd.CmdBuf); if (CtdlClientGetLine(Imap->Cmd.CmdBuf) < 1) { - syslog(LOG_ERR, "Client disconnected: ending session.\r\n"); + IMAPM_syslog(LOG_ERR, "client disconnected: ending session."); CC->kill_me = KILLME_CLIENT_DISCONNECTED; return; } if (Imap->authstate == imap_as_expecting_password) { - syslog(LOG_INFO, "IMAP: \n"); + IMAPM_syslog(LOG_INFO, ""); } else if (Imap->authstate == imap_as_expecting_plainauth) { - syslog(LOG_INFO, "IMAP: \n"); + IMAPM_syslog(LOG_INFO, ""); } else if ((Imap->authstate == imap_as_expecting_multilineusername) || cbmstrcasestr(ChrPtr(Imap->Cmd.CmdBuf), " LOGIN ")) { - syslog(LOG_INFO, "IMAP: LOGIN...\n"); + IMAPM_syslog(LOG_INFO, "LOGIN..."); } else { - syslog(LOG_INFO, "IMAP: %s\n", ChrPtr(Imap->Cmd.CmdBuf)); + IMAP_syslog(LOG_DEBUG, "%s", ChrPtr(Imap->Cmd.CmdBuf)); } pchs = ChrPtr(Imap->Cmd.CmdBuf); @@ -1553,10 +1561,6 @@ void imap_command_loop(void) * If the command just submitted does not contain a literal, we * might think about delivering some untagged stuff... */ - if (*(ChrPtr(Imap->Cmd.CmdBuf) + StrLength(Imap->Cmd.CmdBuf) - 1) - == '}') { - untagged_ok = 0; - } /* Grab the tag, command, and parameters. */ imap_parameterize(&Imap->Cmd); @@ -1564,19 +1568,18 @@ void imap_command_loop(void) /* debug output the parsed vector */ { int i; - syslog(LOG_DEBUG, "----- %ld params \n", - Imap->Cmd.num_parms); + IMAP_syslog(LOG_DEBUG, "----- %ld params", Imap->Cmd.num_parms); for (i=0; i < Imap->Cmd.num_parms; i++) { if (Imap->Cmd.Params[i].len != strlen(Imap->Cmd.Params[i].Key)) - syslog(LOG_DEBUG, "*********** %ld != %ld : %s\n", - Imap->Cmd.Params[i].len, - strlen(Imap->Cmd.Params[i].Key), + IMAP_syslog(LOG_DEBUG, "*********** %ld != %ld : %s", + Imap->Cmd.Params[i].len, + strlen(Imap->Cmd.Params[i].Key), Imap->Cmd.Params[i].Key); else - syslog(LOG_DEBUG, "%ld : %s\n", - Imap->Cmd.Params[i].len, - Imap->Cmd.Params[i].Key); + IMAP_syslog(LOG_DEBUG, "%ld : %s", + Imap->Cmd.Params[i].len, + Imap->Cmd.Params[i].Key); }} #endif @@ -1627,10 +1630,10 @@ BAIL: gettimeofday(&tv2, NULL); total_time = (tv2.tv_usec + (tv2.tv_sec * 1000000)) - (tv1.tv_usec + (tv1.tv_sec * 1000000)); - syslog(LOG_DEBUG, "IMAP command completed in %ld.%ld seconds\n", - (total_time / 1000000), - (total_time % 1000000) - ); + IMAP_syslog(LOG_DEBUG, "IMAP command completed in %ld.%ld seconds", + (total_time / 1000000), + (total_time % 1000000) + ); } void imap_noop (int num_parms, ConstStr *Params) @@ -1652,7 +1655,10 @@ void imap_logout(int num_parms, ConstStr *Params) const char *CitadelServiceIMAP="IMAP"; const char *CitadelServiceIMAPS="IMAPS"; - +void SetIMAPDebugEnabled(const int n) +{ + IMAPDebugEnabled = n; +} /* * This function is called to register the IMAP extension with Citadel. */ @@ -1708,16 +1714,17 @@ CTDL_MODULE_INIT(imap) if (!threading) { + CtdlRegisterDebugFlagHook(HKEY("imapsrv"), SetIMAPDebugEnabled, &IMAPDebugEnabled); CtdlRegisterServiceHook(config.c_imap_port, NULL, imap_greeting, imap_command_loop, NULL, CitadelServiceIMAP); #ifdef HAVE_OPENSSL CtdlRegisterServiceHook(config.c_imaps_port, NULL, imaps_greeting, imap_command_loop, NULL, CitadelServiceIMAPS); #endif - CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP); + CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP, PRIO_STOP + 30); CtdlRegisterCleanupHook(imap_cleanup); } - /* return our Subversion id for the Log */ + /* return our module name for the log */ return "imap"; }