$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
Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
* Initial CVS import
-
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;
* 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;
* 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;
#include "citadel.h"
#include "sysdep_decls.h"
#include "tools.h"
+#include "room_ops.h"
#include "internet_addressing.h"
#include "imap_tools.h"
* 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; i<MAXFLOORS; ++i) {
+ fl = cgetfloor(i);
+ if (fl->f_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
*/
*
*/
+
+
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);
* 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));
- }
+}
/*
*/
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);
- }
+}
/*
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);
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;
- }
-
}
+}
+
#include "control.h"
#include "tools.h"
+struct floor *floorcache[MAXFLOORS];
+
/*
* Generic routine for determining user access to rooms
*/
}
+/*
+ * 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
*/
{
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]);
+ }
}
void cmd_setr(char *args)
{
char buf[SIZ];
+ struct floor *fl;
struct floor flbuf;
char old_name[ROOMNAMELEN];
int old_floor;
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;
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);
}
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;
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);
* $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.
*
*/
/*
- * Implements the AYTHENTICATE command
+ * Implements the AUTHENTICATE command
*/
void imap_authenticate(int num_parms, char *parms[]) {
char buf[SIZ];
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 */
+/*
+ * 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.
*/
/* 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]);
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);
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);
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]);
+/*
+ * This function is called by dynloader.c to register the IMAP module
+ * with the Citadel server.
+ */
char *Dynamic_Module_Init(void)
{
SYM_IMAP = CtdlGetDynamicSymbol();