From 2e5843cef1b2da2b4b0569c1bfcd4a23bdffa052 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Sun, 4 Feb 2001 02:40:08 +0000 Subject: [PATCH] * more imap. imap sucks. die crispin die. --- citadel/ChangeLog | 4 ++- citadel/imap_fetch.c | 6 ++-- citadel/imap_tools.c | 66 +++++++++++++++++++++++++++++++++++++++++- citadel/imap_tools.h | 3 ++ citadel/policy.c | 50 ++++++++++++++++---------------- citadel/room_ops.c | 35 ++++++++++++++++++---- citadel/room_ops.h | 1 + citadel/serv_imap.c | 69 +++++++++++++++++++++++++++++++++----------- 8 files changed, 182 insertions(+), 52 deletions(-) diff --git a/citadel/ChangeLog b/citadel/ChangeLog index b281961be..c5ca8c01b 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -1,4 +1,7 @@ $Log$ + Revision 573.81 2001/02/04 02:40:07 ajc + * more imap. imap sucks. die crispin die. + Revision 573.80 2001/02/03 10:02:12 error * serv_ical.c: Verify that objects posted to My Calendar> are of type text/x-calendar or text/calendar; abort saving if not @@ -2365,4 +2368,3 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant Fri Jul 10 1998 Art Cancro * Initial CVS import - diff --git a/citadel/imap_fetch.c b/citadel/imap_fetch.c index 6f07f64ff..360fe09be 100644 --- a/citadel/imap_fetch.c +++ b/citadel/imap_fetch.c @@ -827,7 +827,7 @@ void imap_pick_range(char *range, int is_uid) { int i; int num_sets; int s; - char setstr[1024], lostr[1024], histr[1024]; + char setstr[SIZ], lostr[SIZ], histr[SIZ]; /* was 1024 */ int lo, hi; char *actual_range; @@ -884,7 +884,7 @@ void imap_pick_range(char *range, int is_uid) { * This function is called by the main command loop. */ void imap_fetch(int num_parms, char *parms[]) { - char items[1024]; + char items[SIZ]; /* was 1024 */ char *itemlist[SIZ]; int num_items; int i; @@ -916,7 +916,7 @@ void imap_fetch(int num_parms, char *parms[]) { * This function is called by the main command loop. */ void imap_uidfetch(int num_parms, char *parms[]) { - char items[1024]; + char items[SIZ]; /* was 1024 */ char *itemlist[SIZ]; int num_items; int i; diff --git a/citadel/imap_tools.c b/citadel/imap_tools.c index 8c9360545..0e7a058c3 100644 --- a/citadel/imap_tools.c +++ b/citadel/imap_tools.c @@ -13,6 +13,7 @@ #include "citadel.h" #include "sysdep_decls.h" #include "tools.h" +#include "room_ops.h" #include "internet_addressing.h" #include "imap_tools.h" @@ -92,15 +93,78 @@ int imap_parameterize(char **args, char *buf) { * Convert a struct quickroom to an IMAP-compatible mailbox name. */ void imap_mailboxname(char *buf, int bufsize, struct quickroom *qrbuf) { + struct floor *fl; - safestrncpy(buf, qrbuf->QRname, bufsize); + /* + * For mailboxes, just do it straight... + */ if (qrbuf->QRflags & QR_MAILBOX) { + safestrncpy(buf, qrbuf->QRname, bufsize); strcpy(buf, &buf[11]); if (!strcasecmp(buf, MAILROOM)) strcpy(buf, "INBOX"); } + + /* + * Otherwise, prefix the floor name as a "public folders" moniker + */ + else { + fl = cgetfloor(qrbuf->QRfloor); + snprintf(buf, bufsize, "%s|%s", + fl->f_name, + qrbuf->QRname); + } +} + + +/* + * Convert an inputted folder name to our best guess as to what an equivalent + * room name should be. It returns the floor number that the room is on (or + * will be on), or -1 if an error occurred. + */ +int imap_roomname(char *rbuf, int bufsize, char *foldername) { + int levels; + char buf[SIZ]; + int i; + struct floor *fl; + + if (foldername == NULL) return(0); + levels = num_parms(foldername); + + /* When we can support hierarchial mailboxes, take this out. */ + if (levels > 2) return(-1); + + /* + * Convert the crispy idiot's reserved names to our reserved names. + */ + if (!strcasecmp(foldername, "INBOX")) { + safestrncpy(rbuf, MAILROOM, bufsize); + return(0); + } + + if (levels > 1) { + extract(buf, foldername, 0); + for (i=0; if_flags & F_INUSE) { + if (!strcasecmp(buf, fl->f_name)) { + extract(rbuf, foldername, 1); + return(i); + } + } + } + + extract(rbuf, buf, 1); + return(0); + } + + safestrncpy(rbuf, foldername, bufsize); + return(0); } + + + /* * Output a struct internet_address_list in the form an IMAP client wants */ diff --git a/citadel/imap_tools.h b/citadel/imap_tools.h index 1505d2828..b47bcb95e 100644 --- a/citadel/imap_tools.h +++ b/citadel/imap_tools.h @@ -3,7 +3,10 @@ * */ + + void imap_strout(char *buf); int imap_parameterize(char **args, char *buf); void imap_mailboxname(char *buf, int bufsize, struct quickroom *qrbuf); void imap_ial_out(struct internet_address_list *ialist); +int imap_roomname(char *buf, int bufsize, char *foldername); diff --git a/citadel/policy.c b/citadel/policy.c index 1ae97f38b..7c51fd0b6 100644 --- a/citadel/policy.c +++ b/citadel/policy.c @@ -29,24 +29,24 @@ * Retrieve the applicable expire policy for a specific room */ void GetExpirePolicy(struct ExpirePolicy *epbuf, struct quickroom *qrbuf) { - struct floor flbuf; + struct floor *fl; /* If the room has its own policy, return it */ if (qrbuf->QRep.expire_mode != 0) { memcpy(epbuf, &qrbuf->QRep, sizeof(struct ExpirePolicy)); return; - } + } - /* Otherwise, if the floor has its own policy, return it */ - getfloor(&flbuf, qrbuf->QRfloor); - if (flbuf.f_ep.expire_mode != 0) { - memcpy(epbuf, &flbuf.f_ep, sizeof(struct ExpirePolicy)); + /* Otherwise, if the floor has its own policy, return it */ + fl = cgetfloor(qrbuf->QRfloor); + if (fl->f_ep.expire_mode != 0) { + memcpy(epbuf, &fl->f_ep, sizeof(struct ExpirePolicy)); return; - } + } /* Otherwise, fall back on the system default */ memcpy(epbuf, &config.c_ep, sizeof(struct ExpirePolicy)); - } +} /* @@ -54,27 +54,27 @@ void GetExpirePolicy(struct ExpirePolicy *epbuf, struct quickroom *qrbuf) { */ void cmd_gpex(char *argbuf) { struct ExpirePolicy exp; - struct floor flbuf; + struct floor *fl; char which[SIZ]; extract(which, argbuf, 0); if (!strcasecmp(which, "room")) { memcpy(&exp, &CC->quickroom.QRep, sizeof(struct ExpirePolicy)); - } + } else if (!strcasecmp(which, "floor")) { - getfloor(&flbuf, CC->quickroom.QRfloor); - memcpy(&exp, &flbuf.f_ep, sizeof(struct ExpirePolicy)); - } + fl = cgetfloor(CC->quickroom.QRfloor); + memcpy(&exp, &fl->f_ep, sizeof(struct ExpirePolicy)); + } else if (!strcasecmp(which, "site")) { memcpy(&exp, &config.c_ep, sizeof(struct ExpirePolicy)); - } + } else { cprintf("%d Invalid keyword.\n", ERROR); return; - } + } cprintf("%d %d|%d\n", OK, exp.expire_mode, exp.expire_value); - } +} /* @@ -93,26 +93,26 @@ void cmd_spex(char *argbuf) { if ((exp.expire_mode < 0) || (exp.expire_mode > 3)) { cprintf("%d Invalid policy.\n", ERROR); return; - } + } if (!strcasecmp(which, "room")) { if (!is_room_aide()) { cprintf("%d Higher access required.\n", ERROR+HIGHER_ACCESS_REQUIRED); return; - } + } lgetroom(&CC->quickroom, CC->quickroom.QRname); memcpy(&CC->quickroom.QRep, &exp, sizeof(struct ExpirePolicy)); lputroom(&CC->quickroom); cprintf("%d Room expire policy set.\n", OK); return; - } + } if (CC->usersupp.axlevel < 6) { cprintf("%d Higher access required.\n", ERROR+HIGHER_ACCESS_REQUIRED); return; - } + } if (!strcasecmp(which, "floor")) { lgetfloor(&flbuf, CC->quickroom.QRfloor); @@ -120,25 +120,25 @@ void cmd_spex(char *argbuf) { lputfloor(&flbuf, CC->quickroom.QRfloor); cprintf("%d Floor expire policy set.\n", OK); return; - } + } else if (!strcasecmp(which, "site")) { if (exp.expire_mode == EXPIRE_NEXTLEVEL) { cprintf("%d Invalid policy (no higher level)\n", ERROR); return; - } + } memcpy(&config.c_ep, &exp, sizeof(struct ExpirePolicy)); put_config(); cprintf("%d Site expire policy set.\n", OK); return; - } + } else { cprintf("%d Invalid keyword.\n", ERROR); return; - } - } +} + diff --git a/citadel/room_ops.c b/citadel/room_ops.c index 48c7d00d2..0367122f8 100644 --- a/citadel/room_ops.c +++ b/citadel/room_ops.c @@ -26,6 +26,8 @@ #include "control.h" #include "tools.h" +struct floor *floorcache[MAXFLOORS]; + /* * Generic routine for determining user access to rooms */ @@ -278,6 +280,23 @@ void lgetfloor(struct floor *flbuf, int floor_num) } +/* + * cgetfloor() - Get floor record from *cache* (loads from disk if needed) + * + * This is strictly a performance hack. + */ +struct floor *cgetfloor(int floor_num) { + + if (floorcache[floor_num] == NULL) { + floorcache[floor_num] = mallok(sizeof(struct floor)); + getfloor(floorcache[floor_num], floor_num); + } + + return(floorcache[floor_num]); +} + + + /* * putfloor() - store floor data on disk */ @@ -285,6 +304,11 @@ void putfloor(struct floor *flbuf, int floor_num) { cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int), flbuf, sizeof(struct floor)); + + /* If we've cached this, clear it out, 'cuz it's WRONG now! */ + if (floorcache[floor_num] != NULL) { + phree(floorcache[floor_num]); + } } @@ -912,6 +936,7 @@ void cmd_getr(void) void cmd_setr(char *args) { char buf[SIZ]; + struct floor *fl; struct floor flbuf; char old_name[ROOMNAMELEN]; int old_floor; @@ -932,8 +957,8 @@ void cmd_setr(char *args) if (num_parms(args) >= 6) { - getfloor(&flbuf, extract_int(args, 5)); - if ((flbuf.f_flags & F_INUSE) == 0) { + fl = cgetfloor(extract_int(args, 5)); + if ((fl->f_flags & F_INUSE) == 0) { cprintf("%d Invalid floor number.\n", ERROR + INVALID_FLOOR_OPERATION); return; @@ -1268,7 +1293,7 @@ void cmd_cre8(char *args) char aaa[SIZ]; unsigned newflags; struct quickroom qrbuf; - struct floor flbuf; + struct floor *fl; cre8_ok = extract_int(args, 0); extract(new_room_name, args, 1); @@ -1290,8 +1315,8 @@ void cmd_cre8(char *args) } if (num_parms(args) >= 5) { - getfloor(&flbuf, extract_int(args, 4)); - if ((flbuf.f_flags & F_INUSE) == 0) { + fl = cgetfloor(extract_int(args, 4)); + if ((fl->f_flags & F_INUSE) == 0) { cprintf("%d Invalid floor number.\n", ERROR + INVALID_FLOOR_OPERATION); return; diff --git a/citadel/room_ops.h b/citadel/room_ops.h index aee21030f..06a951b2f 100644 --- a/citadel/room_ops.h +++ b/citadel/room_ops.h @@ -12,6 +12,7 @@ void b_deleteroom(char *); int lgetroom(struct quickroom *qrbuf, char *room_name); void lputroom(struct quickroom *qrbuf); void getfloor (struct floor *flbuf, int floor_num); +struct floor *cgetfloor(int floor_num); void lgetfloor (struct floor *flbuf, int floor_num); void putfloor (struct floor *flbuf, int floor_num); void lputfloor (struct floor *flbuf, int floor_num); diff --git a/citadel/serv_imap.c b/citadel/serv_imap.c index adce7eddd..c3a70d0a8 100644 --- a/citadel/serv_imap.c +++ b/citadel/serv_imap.c @@ -2,10 +2,14 @@ * $Id$ * * IMAP server for the Citadel/UX system - * Copyright (C) 2000 by Art Cancro and others. + * Copyright (C) 2000-2001 by Art Cancro and others. * This code is released under the terms of the GNU General Public License. * - * *** THIS IS UNDER DEVELOPMENT. IT DOES NOT WORK. DO NOT USE IT. *** + * WARNING: this is an incomplete implementation, still in progress. Parts of + * it work, but it's not really usable yet from a user perspective. + * + * WARNING: Mark Crispin is an idiot. IMAP is the most brain-damaged protocol + * you will ever have the profound lack of pleasure to encounter. * */ @@ -159,7 +163,7 @@ void imap_login(int num_parms, char *parms[]) { /* - * Implements the AYTHENTICATE command + * Implements the AUTHENTICATE command */ void imap_authenticate(int num_parms, char *parms[]) { char buf[SIZ]; @@ -233,15 +237,14 @@ void imap_select(int num_parms, char *parms[]) { int ra = 0; struct quickroom QRscratch; int msgs, new; + int floornum; - strcpy(towhere, parms[2]); - - /* IMAP uses the reserved name "INBOX" for the user's default incoming - * mail folder. Convert this to whatever Citadel is using for the - * default mail room name (usually "Mail>"). - */ - if (!strcasecmp(towhere, "INBOX")) { - strcpy(towhere, MAILROOM); + /* Convert the supplied folder name to a roomname */ + floornum = imap_roomname(towhere, sizeof towhere, parms[2]); + if (floornum < 0) { + cprintf("%s NO Invalid mailbox name.\r\n", parms[0]); + IMAP->selected = 0; + return; } /* First try a regular match */ @@ -380,6 +383,25 @@ void imap_list(int num_parms, char *parms[]) { +/* + * Implements the CREATE command (FIXME not finished yet) + * + */ +void imap_create(int num_parms, char *parms[]) { + int floornum; + int levels; + + floornum = imap_roomname(parms[1]); + if (floornum < 0) { + cprintf("%s NO Invalid name\r\n", parms[0]); + return; + } + + cprintf("%s NO CREATE unimplemented\r\n", parms[0]); +} + + + /* * Main command loop for IMAP sessions. */ @@ -418,12 +440,15 @@ void imap_command_loop(void) { /* Ok, at this point we're in normal command mode */ - /* grab the tag */ + /* Grab the tag, command, and parameters. Check syntax. */ num_parms = imap_parameterize(parms, cmdbuf); + if (num_parms < 2) { + cprintf("BAD syntax error\r\n"); + } - /* commands which may be executed in any state */ + /* The commands below may be executed in any state */ - if ( (!strcasecmp(parms[1], "NOOP")) + else if ( (!strcasecmp(parms[1], "NOOP")) || (!strcasecmp(parms[1], "CHECK")) ) { cprintf("%s OK This command successfully did nothing.\r\n", parms[0]); @@ -452,7 +477,7 @@ void imap_command_loop(void) { cprintf("%s BAD Not logged in.\r\n", parms[0]); } - /* commands requiring the client to be logged in */ + /* The commans below require a logged-in state */ else if (!strcasecmp(parms[1], "SELECT")) { imap_select(num_parms, parms); @@ -470,11 +495,15 @@ void imap_command_loop(void) { imap_list(num_parms, parms); } + else if (!strcasecmp(parms[1], "CREATE")) { + imap_create(num_parms, parms); + } + else if (IMAP->selected == 0) { cprintf("%s BAD no folder selected\r\n", parms[0]); } - /* commands requiring the SELECT state */ + /* The commands below require the SELECT state on a mailbox */ else if (!strcasecmp(parms[1], "FETCH")) { imap_fetch(num_parms, parms); @@ -498,7 +527,9 @@ void imap_command_loop(void) { imap_close(num_parms, parms); } - /* end of commands */ + /* End of commands. If we get here, the command is either invalid + * or unimplemented. + */ else { cprintf("%s BAD command unrecognized\r\n", parms[0]); @@ -508,6 +539,10 @@ void imap_command_loop(void) { +/* + * This function is called by dynloader.c to register the IMAP module + * with the Citadel server. + */ char *Dynamic_Module_Init(void) { SYM_IMAP = CtdlGetDynamicSymbol(); -- 2.39.2