* Convert room listings and some aide functions to new IPC code
authorMichael Hampton <io_error@uncensored.citadel.org>
Thu, 17 Oct 2002 11:13:27 +0000 (11:13 +0000)
committerMichael Hampton <io_error@uncensored.citadel.org>
Thu, 17 Oct 2002 11:13:27 +0000 (11:13 +0000)
citadel/ChangeLog
citadel/citadel.c
citadel/citadel.h
citadel/citadel_ipc.c
citadel/citadel_ipc.h
citadel/rooms.c

index c8856eae56641a0f3ca348c6198c8a5e23c25ca8..8fad209e24b0b893c2ef66083823c6fa2097a644 100644 (file)
@@ -1,4 +1,7 @@
  $Log$
+ Revision 601.32  2002/10/17 11:13:27  error
+ * Convert room listings and some aide functions to new IPC code
+
  Revision 601.31  2002/10/16 13:46:19  ajc
  * Remove some trace messages
 
@@ -4090,4 +4093,3 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
        * Initial CVS import
-
index 30de03c9eb5a0d4857b8bef9bec328e90f5442dd..8e68bd10a680841bca5afe22b01eb99a86e053d7 100644 (file)
@@ -335,7 +335,7 @@ char *pop_march(int desired_floor)
  */
 void dotgoto(CtdlIPC *ipc, char *towhere, int display_name, int fromungoto)
 {
-       char aaa[SIZ], bbb[SIZ], psearch[SIZ];
+       char aaa[SIZ], bbb[SIZ];
        static long ls = 0L;
        int newmailcount = 0;
        int partial_match, best_match;
@@ -381,25 +381,36 @@ void dotgoto(CtdlIPC *ipc, char *towhere, int display_name, int fromungoto)
         * has the highest-weighted match.
         */
        if (r / 100 != 2) {
+               struct march *march = NULL;
+               int r;  /* IPC result code; hides higher-level r */
+
                best_match = 0;
                strcpy(bbb, "");
-               CtdlIPC_putline(ipc, "LKRA");
-               CtdlIPC_getline(ipc, aaa);
-               if (aaa[0] == '1')
-                       while (CtdlIPC_getline(ipc, aaa), strcmp(aaa, "000")) {
-                               extract(psearch, aaa, 0);
+
+               r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, -1, &march, aaa);
+               if (r / 100 == 1) {
+                       /* Run the roomlist; free the data as we go */
+                       struct march *mp = march;       /* Current */
+
+                       while (mp) {
                                partial_match = 0;
-                               if (pattern(psearch, towhere) >= 0) {
+                               if (pattern(mp->march_name, towhere) >= 0) {
                                        partial_match = 1;
                                }
-                               if (!strncasecmp(towhere, psearch, strlen(towhere))) {
+                               if (!strncasecmp(mp->march_name, towhere, strlen(towhere))) {
                                        partial_match = 2;
                                }
                                if (partial_match > best_match) {
-                                       strcpy(bbb, psearch);
+                                       strcpy(bbb, mp->march_name);
                                        best_match = partial_match;
                                }
+                               /* Both pointers are NULL at end of list */
+                               march = mp->next;
+                               free(mp);
+                               mp = march;
                        }
+               }
+
                if (strlen(bbb) == 0) {
                        scr_printf("No room '%s'.\n", towhere);
                        return;
@@ -407,7 +418,7 @@ void dotgoto(CtdlIPC *ipc, char *towhere, int display_name, int fromungoto)
                roomrec = NULL;
                r = CtdlIPCGotoRoom(ipc, bbb, "", &roomrec, aaa);
        }
-       if (r / 100 != 2) {
+       if (r / 100 != 1 && r / 100 != 2) {
                scr_printf("%s\n", aaa);
                return;
        }
@@ -488,7 +499,7 @@ void gotonext(CtdlIPC *ipc)
         * If it is, pop the first room off the list and go there.
         */
        if (march == NULL) {
-               r = CtdlIPCKnownRooms(ipc, 1, -1, &march, buf);
+               r = CtdlIPCKnownRooms(ipc, SubscribedRoomsWithNewMessages, -1, &march, buf);
 /* add _BASEROOM_ to the end of the march list, so the user will end up
  * in the system base room (usually the Lobby>) at the end of the loop
  */
@@ -530,21 +541,12 @@ void forget_all_rooms_on(CtdlIPC *ipc, int ffloor)
 
        scr_printf("Forgetting all rooms on %s...\r", &floorlist[ffloor][0]);
        scr_flush();
-       snprintf(buf, sizeof buf, "LKRA %d", ffloor);
-       CtdlIPC_putline(ipc, buf);
-       CtdlIPC_getline(ipc, buf);
-       if (buf[0] != '1') {
-               scr_printf("%-72s\n", &buf[4]);
+       r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, ffloor, &flist, buf);
+       if (r / 100 != 1) {
+               scr_printf("%-72s\n", buf);
                return;
        }
-       flist = NULL;
-       while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) {
-               fptr = (struct march *) malloc(sizeof(struct march));
-               fptr->next = flist;
-               flist = fptr;
-               extract(fptr->march_name, buf, 0);
-       }
-       while (flist != NULL) {
+       while (flist) {
                r = CtdlIPCGotoRoom(ipc, flist->march_name, "", &roomrec, buf);
                if (r / 100 == 2) {
                        r = CtdlIPCForgetRoom(ipc, buf);
@@ -588,6 +590,7 @@ void gf_toroom(CtdlIPC *ipc, char *towhere, int mode)
 void gotofloor(CtdlIPC *ipc, char *towhere, int mode)
 {
        int a, tofloor;
+       int r;          /* IPC response code */
        struct march *mptr;
        char buf[SIZ], targ[SIZ];
 
@@ -621,14 +624,20 @@ void gotofloor(CtdlIPC *ipc, char *towhere, int mode)
        }
 
        strcpy(targ, "");
-       snprintf(buf, sizeof buf, "LKRA %d", tofloor);
-       CtdlIPC_putline(ipc, buf);
-       CtdlIPC_getline(ipc, buf);
-       if (buf[0] == '1')
-               while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) {
-                       if ((extract_int(buf, 2) == tofloor) && (strlen(targ) == 0))
-                               extract(targ, buf, 0);
+       mptr = NULL;
+       r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, tofloor, &mptr, buf);
+       if (r / 100 == 1) {
+               struct march *tmp = mptr;
+
+               /* TODO: room order is being ignored? */
+               if (mptr)
+                       strncpy(targ, mptr->march_name, ROOMNAMELEN);
+               while (mptr) {
+                       tmp = mptr->next;
+                       free(mptr);
+                       mptr = tmp;
                }
+       }
        if (strlen(targ) > 0) {
                gf_toroom(ipc, targ, mode);
        } else {
@@ -1086,26 +1095,20 @@ int main(int argc, char **argv)
        if (rc_remember_passwords) {
                get_stored_password(hostbuf, portbuf, fullname, password);
                if (strlen(fullname) > 0) {
-                       snprintf(aaa, sizeof(aaa)-1, "USER %s", fullname);
-                       CtdlIPC_putline(ipc, aaa);
-                       CtdlIPC_getline(ipc, aaa);
-                       if (nonce[0])
-                               {
-                                       snprintf(aaa, sizeof aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring, sizeof hexstring));
-                               }
-                       else    /* Else no APOP */
-                               {
-                                       snprintf(aaa, sizeof(aaa)-1, "PASS %s", password);
+                       r = CtdlIPCTryLogin(ipc, fullname, aaa);
+                       if (r / 100 == 3) {
+                               if (*nonce) {
+                                       r = CtdlIPCTryApopPassword(ipc, make_apop_string(password, nonce, hexstring, sizeof hexstring), aaa);
+                               } else {
+                                       r = CtdlIPCTryPassword(ipc, password, aaa);
                                }
-                       
-                       CtdlIPC_putline(ipc, aaa);
-                       CtdlIPC_getline(ipc, aaa);
-                       if (aaa[0] == '2') {
-                               load_user_info(&aaa[4]);
+                       }
+
+                       if (r / 100 == 2) {
+                               load_user_info(aaa);
                                stored_password = 1;
                                goto PWOK;
-                       }
-                       else {
+                       } else {
                                set_stored_password(hostbuf, portbuf, "", "");
                        }
                }
@@ -1145,19 +1148,14 @@ int main(int argc, char **argv)
        }
        strproc(password);
 
-       if (nonce[0])
-               {
-                       snprintf(aaa, sizeof aaa, "PAS2 %s", make_apop_string(password, nonce, hexstring, sizeof hexstring));
-               }
-       else    /* Else no APOP */
-               {
-                       snprintf(aaa, sizeof aaa, "PASS %s", password);
-               }
+       if (*nonce) {
+               r = CtdlIPCTryApopPassword(ipc, make_apop_string(password, nonce, hexstring, sizeof hexstring), aaa);
+       } else {
+               r = CtdlIPCTryPassword(ipc, password, aaa);
+       }
        
-       CtdlIPC_putline(ipc, aaa);
-       CtdlIPC_getline(ipc, aaa);
-       if (aaa[0] == '2') {
-               load_user_info(&aaa[4]);
+       if (r / 100 == 2) {
+               load_user_info(aaa);
                offer_to_remember_password(hostbuf, portbuf,
                                           fullname, password);
                goto PWOK;
@@ -1167,21 +1165,20 @@ int main(int argc, char **argv)
                logoff(ipc, 0);
        goto GSTA;
 
- NEWUSR:       if (strlen(rc_password) == 0) {
-        scr_printf("No record. Enter as new user? ");
-        if (yesno() == 0)
-                goto GSTA;
- }
-       snprintf(aaa, sizeof aaa, "NEWU %s", fullname);
-       CtdlIPC_putline(ipc, aaa);
-       CtdlIPC_getline(ipc, aaa);
-       if (aaa[0] != '2') {
+NEWUSR:        if (strlen(rc_password) == 0) {
+               scr_printf("No record. Enter as new user? ");
+               if (yesno() == 0)
+                       goto GSTA;
+       }
+
+       r = CtdlIPCCreateUser(ipc, fullname, 0, aaa);
+       if (r / 100 != 2) {
                scr_printf("%s\n", aaa);
                goto GSTA;
        }
-       load_user_info(&aaa[4]);
+       load_user_info(aaa);
 
-       while (set_password(ipc) != 0);;
+       while (set_password(ipc) != 0);
        newnow = 1;
 
        enter_config(ipc, 1);
@@ -1201,7 +1198,7 @@ int main(int argc, char **argv)
                   usernum, timescalled);
        if (lastcall > 0L) {
                scr_printf(" / Last login: %s\n",
-                          asctime(localtime(&lastcall)) );
+                          asctime(localtime(&lastcall)));
        }
        scr_printf("\n");
 
index b62239f78abece7a6d5ea326c22c787f9478c5cd..a9f09d724c3746a076ac1e4f8363b54cb92e4024 100644 (file)
@@ -131,6 +131,7 @@ struct config {
 struct march {
        struct march *next;
        char march_name[ROOMNAMELEN];
+       unsigned int march_flags;
        char march_floor;
        char march_order;
 };
index 3db0d89e361d3337854fcf9e074ef508e59abe8a..456a2a269a37646f0ecb73a8640728717993ba36 100644 (file)
@@ -193,6 +193,28 @@ int CtdlIPCTryPassword(CtdlIPC *ipc, const char *passwd, char *cret)
 }
 
 
+/*
+ * Second stage of authentication - provide password.  The server returns
+ * 200 and several arguments in cret relating to the user's account.
+ */
+int CtdlIPCTryApopPassword(CtdlIPC *ipc, const char *response, char *cret)
+{
+       register int ret;
+       char *aaa;
+
+       if (!response) return -2;
+       if (!cret) return -2;
+
+       aaa = (char *)malloc((size_t)(strlen(response) + 6));
+       if (!aaa) return -1;
+
+       sprintf(aaa, "PAS2 %s", response);
+       ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
+       free(aaa);
+       return ret;
+}
+
+
 /*
  * Create a new user.  This returns 200 plus the same arguments as TryPassword
  * if selfservice is nonzero, unless there was a problem creating the account.
@@ -241,13 +263,14 @@ int CtdlIPCChangePassword(CtdlIPC *ipc, const char *passwd, char *cret)
 
 /* LKRN */
 /* Caller must free the march list */
-/* which is 0 = LRMS, 1 = LKRN, 2 = LKRO, 3 = LKRA, 4 = LZRM */
+/* Room types are defined in enum RoomList; keep these in sync! */
 /* floor is -1 for all, or floornum */
-int CtdlIPCKnownRooms(CtdlIPC *ipc, int which, int floor, struct march **listing, char *cret)
+int CtdlIPCKnownRooms(CtdlIPC *ipc, enum RoomList which, int floor, struct march **listing, char *cret)
 {
        register int ret;
        struct march *march = NULL;
-       static char *proto[] = {"LRMS", "LKRN", "LKRO", "LKRA", "LZRM" };
+       static char *proto[] =
+               {"LKRA", "LKRN", "LKRO", "LZRM", "LRMS", "LPRM" };
        char aaa[SIZ];
        char *bbb = NULL;
        size_t bbbsize;
@@ -255,7 +278,7 @@ int CtdlIPCKnownRooms(CtdlIPC *ipc, int which, int floor, struct march **listing
        if (!listing) return -2;
        if (*listing) return -2;        /* Free the listing first */
        if (!cret) return -2;
-       if (which < 0 || which > 4) return -2;
+       /* if (which < 0 || which > 4) return -2; */
        if (floor < -1) return -2;      /* Can't validate upper bound, sorry */
 
        sprintf(aaa, "%s %d", proto[which], floor);
@@ -273,6 +296,7 @@ int CtdlIPCKnownRooms(CtdlIPC *ipc, int which, int floor, struct march **listing
                        if (mptr) {
                                mptr->next = NULL;
                                extract(mptr->march_name, aaa, 0);
+                               mptr->march_flags = (unsigned int) extract_int(aaa, 1);
                                mptr->march_floor = (char) extract_int(aaa, 2);
                                mptr->march_order = (char) extract_int(aaa, 3);
                                if (march == NULL)
@@ -710,6 +734,8 @@ int CtdlIPCGetRoomAttributes(CtdlIPC *ipc, struct quickroom **qret, char *cret)
                qret[0]->QRflags = extract_int(cret, 3);
                qret[0]->QRfloor = extract_int(cret, 4);
                qret[0]->QRorder = extract_int(cret, 5);
+               qret[0]->QRdefaultview = extract_int(cret, 6);
+               qret[0]->QRflags2 = extract_int(cret, 7);
        }
        return ret;
 }
@@ -1667,33 +1693,47 @@ int CtdlIPCAideSetUserParameters(CtdlIPC *ipc, const struct usersupp *uret, char
 
 /* GPEX */
 /* which is 0 = room, 1 = floor, 2 = site */
-int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which, char *cret)
+/* caller must free the struct ExpirePolicy */
+int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which,
+               struct ExpirePolicy **policy, char *cret)
 {
        static char *proto[] = {"room", "floor", "site"};
        char aaa[11];
+       register int ret;
 
        if (!cret) return -2;
+       if (!policy) return -2;
+       if (!*policy) *policy = (struct ExpirePolicy *)calloc(1, sizeof(struct ExpirePolicy));
+       if (!*policy) return -1;
        if (which < 0 || which > 2) return -2;
        
        sprintf(aaa, "GPEX %s", proto[which]);
-       return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
+       ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
+       if (ret / 100 == 2) {
+               policy[0]->expire_mode = extract_int(cret, 0);
+               policy[0]->expire_value = extract_int(cret, 1);
+       }
+       return ret;
+
 }
 
 
 /* SPEX */
 /* which is 0 = room, 1 = floor, 2 = site */
 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
-int CtdlIPCSetMessageExpirationPolicy(CtdlIPC *ipc, int which, int policy, int value,
-               char *cret)
+int CtdlIPCSetMessageExpirationPolicy(CtdlIPC *ipc, int which,
+               struct ExpirePolicy *policy, char *cret)
 {
        char aaa[38];
 
        if (!cret) return -2;
        if (which < 0 || which > 2) return -2;
-       if (policy < 0 || policy > 3) return -2;
-       if (policy >= 2 && value < 1) return -2;
+       if (!policy) return -2;
+       if (policy->expire_mode < 0 || policy->expire_mode > 3) return -2;
+       if (policy->expire_mode >= 2 && policy->expire_value < 1) return -2;
 
-       sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
+       sprintf(aaa, "SPEX %d|%d|%d", which,
+                       policy->expire_mode, policy->expire_value);
        return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
 }
 
index 2443ee1a281f8974748eaf9fd7e631e1ae2d82e4..98ea5a40da5b9e02debb824c66b0c475fbd7f7c7 100644 (file)
@@ -110,6 +110,15 @@ struct ctdlipcmisc {
        char needvalid;                 /* Nonzero if users need validation */
 };
 
+enum RoomList {
+       SubscribedRooms,
+       SubscribedRoomsWithNewMessages,
+       SubscribedRoomsWithNoNewMessages,
+       UnsubscribedRooms,
+       AllAccessibleRooms,
+       AllPublicRooms,
+};
+       
 /* Shared Diffie-Hellman parameters */
 #define DH_P           "1A74527AEE4EE2568E85D4FB2E65E18C9394B9C80C42507D7A6A0DBE9A9A54B05A9A96800C34C7AA5297095B69C88901EEFD127F969DCA26A54C0E0B5C5473EBAEB00957D2633ECAE3835775425DE66C0DE6D024DBB17445E06E6B0C78415E589B8814F08531D02FD43778451E7685541079CFFB79EF0D26EFEEBBB69D1E80383"
 #define DH_G           "2"
@@ -122,9 +131,10 @@ int CtdlIPCQuit(CtdlIPC *ipc);
 int CtdlIPCLogout(CtdlIPC *ipc);
 int CtdlIPCTryLogin(CtdlIPC *ipc, const char *username, char *cret);
 int CtdlIPCTryPassword(CtdlIPC *ipc, const char *passwd, char *cret);
+int CtdlIPCTryApopPassword(CtdlIPC *ipc, const char *response, char *cret);
 int CtdlIPCCreateUser(CtdlIPC *ipc, const char *username, int selfservice, char *cret);
 int CtdlIPCChangePassword(CtdlIPC *ipc, const char *passwd, char *cret);
-int CtdlIPCKnownRooms(CtdlIPC *ipc, int which, int floor, struct march **listing, char *cret);
+int CtdlIPCKnownRooms(CtdlIPC *ipc, enum RoomList which, int floor, struct march **listing, char *cret);
 int CtdlIPCGetConfig(CtdlIPC *ipc, struct usersupp **uret, char *cret);
 int CtdlIPCSetConfig(CtdlIPC *ipc, struct usersupp *uret, char *cret);
 int CtdlIPCGotoRoom(CtdlIPC *ipc, const char *room, const char *passwd,
@@ -203,9 +213,10 @@ time_t CtdlIPCServerTime(CtdlIPC *ipc, char *crert);
 int CtdlIPCAideGetUserParameters(CtdlIPC *ipc, const char *who,
                                 struct usersupp **uret, char *cret);
 int CtdlIPCAideSetUserParameters(CtdlIPC *ipc, const struct usersupp *uret, char *cret);
-int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which, char *cret);
-int CtdlIPCSetMessageExpirationPolicy(CtdlIPC *ipc, int which, int policy, int value,
-               char *cret);
+int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which,
+               struct ExpirePolicy **policy, char *cret);
+int CtdlIPCSetMessageExpirationPolicy(CtdlIPC *ipc, int which,
+               struct ExpirePolicy *policy, char *cret);
 int CtdlGetSystemConfig(CtdlIPC *ipc, char **listing, char *cret);
 int CtdlSetSystemConfig(CtdlIPC *ipc, const char *listing, char *cret);
 int CtdlGetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
index c843ea265f33596acdffd97bf1996516874ddfb9..51613ab378dc9928235272126e6b5dd84d5f6aad 100644 (file)
@@ -166,30 +166,34 @@ int rordercmp(struct roomlisting *r1, struct roomlisting *r2)
 /*
  * Common code for all room listings
  */
-void listrms(CtdlIPC *ipc, char *variety)
+static void listrms(CtdlIPC *ipc, enum RoomList variety, int floor)
 {
        char buf[SIZ];
-
+       struct march *listing = NULL;
+       struct march *tmp = NULL;
        struct roomlisting *rl = NULL;
        struct roomlisting *rp;
        struct roomlisting *rs;
-
+       int r;          /* IPC response code */
 
        /* Ask the server for a room list */
-       CtdlIPC_putline(ipc, variety);
-       CtdlIPC_getline(ipc, buf);
-       if (buf[0] != '1') {
+       r = CtdlIPCKnownRooms(ipc, variety, floor, &listing, buf);
+       if (r / 100 != 1) {
                return;
        }
-       while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) {
+       while (listing) {
                rp = malloc(sizeof(struct roomlisting));
-               extract(rp->rlname, buf, 0);
-               rp->rlflags = extract_int(buf, 1);
-               rp->rlfloor = extract_int(buf, 2);
-               rp->rlorder = extract_int(buf, 3);
+               strncpy(rp->rlname, listing->march_name, ROOMNAMELEN);
+               rp->rlflags = listing->march_flags;
+               rp->rlfloor = listing->march_floor;
+               rp->rlorder = listing->march_order;
                rp->lnext = NULL;
                rp->rnext = NULL;
 
+               tmp = listing->next;
+               free(listing);
+               listing = tmp;
+
                rs = rl;
                if (rl == NULL) {
                        rl = rp;
@@ -244,7 +248,6 @@ void list_other_floors(void)
  */
 void knrooms(CtdlIPC *ipc, int kn_floor_mode)
 {
-       char buf[SIZ];
        int a;
 
        load_floorlist(ipc);
@@ -252,10 +255,10 @@ void knrooms(CtdlIPC *ipc, int kn_floor_mode)
        if (kn_floor_mode == 0) {
                color(BRIGHT_CYAN);
                pprintf("\n   Rooms with unread messages:\n");
-               listrms(ipc, "LKRN");
+               listrms(ipc, SubscribedRoomsWithNewMessages, -1);
                color(BRIGHT_CYAN);
                pprintf("\n\n   No unseen messages in:\n");
-               listrms(ipc, "LKRO");
+               listrms(ipc, SubscribedRoomsWithNoNewMessages, -1);
                pprintf("\n");
        }
 
@@ -263,13 +266,11 @@ void knrooms(CtdlIPC *ipc, int kn_floor_mode)
                color(BRIGHT_CYAN);
                pprintf("\n   Rooms with unread messages on %s:\n",
                        floorlist[(int) curr_floor]);
-               snprintf(buf, sizeof buf, "LKRN %d", curr_floor);
-               listrms(ipc, buf);
+               listrms(ipc, SubscribedRoomsWithNewMessages, curr_floor);
                color(BRIGHT_CYAN);
                pprintf("\n\n   Rooms with no new messages on %s:\n",
                        floorlist[(int) curr_floor]);
-               snprintf(buf, sizeof buf, "LKRO %d", curr_floor);
-               listrms(ipc, buf);
+               listrms(ipc, SubscribedRoomsWithNoNewMessages, curr_floor);
                color(BRIGHT_CYAN);
                pprintf("\n\n   Other floors:\n");
                list_other_floors();
@@ -282,8 +283,7 @@ void knrooms(CtdlIPC *ipc, int kn_floor_mode)
                                color(BRIGHT_CYAN);
                                pprintf("\n   Rooms on %s:\n",
                                        floorlist[a]);
-                               snprintf(buf, sizeof buf, "LKRA %d", a);
-                               listrms(ipc, buf);
+                               listrms(ipc, AllAccessibleRooms, a);
                                pprintf("\n");
                        }
                }
@@ -298,7 +298,7 @@ void listzrooms(CtdlIPC *ipc)
 {                              /* list public forgotten rooms */
        color(BRIGHT_CYAN);
        pprintf("\n   Forgotten public rooms:\n");
-       listrms(ipc, "LZRM");
+       listrms(ipc, UnsubscribedRooms, -1);
        pprintf("\n");
        color(DIM_WHITE);
        IFNEXPERT hit_any_key();
@@ -376,46 +376,26 @@ int select_floor(CtdlIPC *ipc, int rfloor)
  */
 void editthisroom(CtdlIPC *ipc)
 {
-       char rname[ROOMNAMELEN];
-       char rpass[10];
-       char rdir[15];
-       unsigned rflags;
-       unsigned rflags2;
-       int rbump;
+       int rbump = 0;
        char raide[32];
        char buf[SIZ];
-       int rfloor;
-       int rorder;
-       int rview;
-       int expire_mode = 0;
-       int expire_value = 0;
+       struct quickroom *attr = NULL;
+       struct ExpirePolicy *eptr = NULL;
        int r;                          /* IPC response code */
 
        /* Fetch the existing room config */
-       CtdlIPC_putline(ipc, "GETR");
-       CtdlIPC_getline(ipc, buf);
-       if (buf[0] != '2') {
-               scr_printf("%s\n", &buf[4]);
+       r = CtdlIPCGetRoomAttributes(ipc, &attr, buf);
+       if (r / 100 != 2) {
+               scr_printf("%s\n", buf);
                return;
        }
-
-       extract(rname, &buf[4], 0);
-       extract(rpass, &buf[4], 1);
-       extract(rdir, &buf[4], 2);
-       rflags = extract_int(&buf[4], 3);
-       rfloor = extract_int(&buf[4], 4);
-       rorder = extract_int(&buf[4], 5);
-       rview = extract_int(&buf[4], 6);
-       rflags2 = extract_int(&buf[4], 7);
-       rbump = 0;
+       eptr = &(attr->QRep);
 
        /* Fetch the name of the current room aide */
-       CtdlIPC_putline(ipc, "GETA");
-       CtdlIPC_getline(ipc, buf);
-       if (buf[0] == '2') {
-               safestrncpy(raide, &buf[4], sizeof raide);
-       }
-       else {
+       r = CtdlIPCGetRoomAide(ipc, buf);
+       if (r / 100 == 2) {
+               safestrncpy(raide, buf, sizeof raide);
+       } else {
                strcpy(raide, "");
        }
        if (strlen(raide) == 0) {
@@ -425,78 +405,71 @@ void editthisroom(CtdlIPC *ipc)
        /* Fetch the expire policy (this will silently fail on old servers,
         * resulting in "default" policy)
         */
-       CtdlIPC_putline(ipc, "GPEX room");
-       CtdlIPC_getline(ipc, buf);
-       if (buf[0] == '2') {
-               expire_mode = extract_int(&buf[4], 0);
-               expire_value = extract_int(&buf[4], 1);
-       }
+       r = CtdlIPCGetMessageExpirationPolicy(ipc, 0, &eptr, buf);
 
        /* Now interact with the user. */
 
-       rfloor = select_floor(ipc, rfloor);
-       rflags = set_room_attr(ipc, rflags, "Private room", QR_PRIVATE);
-       if (rflags & QR_PRIVATE) {
-               rflags = set_room_attr(ipc, rflags,
+       attr->QRfloor = select_floor(ipc, attr->QRfloor);
+       attr->QRflags = set_room_attr(ipc, attr->QRflags, "Private room", QR_PRIVATE);
+       if (attr->QRflags & QR_PRIVATE) {
+               attr->QRflags = set_room_attr(ipc, attr->QRflags,
                                       "Accessible by guessing room name",
                                       QR_GUESSNAME);
        }
 
        /* if it's public, clear the privacy classes */
-       if ((rflags & QR_PRIVATE) == 0) {
-               if (rflags & QR_GUESSNAME) {
-                       rflags = rflags - QR_GUESSNAME;
+       if ((attr->QRflags & QR_PRIVATE) == 0) {
+               if (attr->QRflags & QR_GUESSNAME) {
+                       attr->QRflags = attr->QRflags - QR_GUESSNAME;
                }
-               if (rflags & QR_PASSWORDED) {
-                       rflags = rflags - QR_PASSWORDED;
+               if (attr->QRflags & QR_PASSWORDED) {
+                       attr->QRflags = attr->QRflags - QR_PASSWORDED;
                }
        }
 
        /* if it's private, choose the privacy classes */
-       if ((rflags & QR_PRIVATE)
-           && ((rflags & QR_GUESSNAME) == 0)) {
-               rflags = set_room_attr(ipc, rflags,
+       if ((attr->QRflags & QR_PRIVATE)
+           && ((attr->QRflags & QR_GUESSNAME) == 0)) {
+               attr->QRflags = set_room_attr(ipc, attr->QRflags,
                                       "Accessible by entering a password",
                                       QR_PASSWORDED);
        }
-       if ((rflags & QR_PRIVATE)
-           && ((rflags & QR_PASSWORDED) == QR_PASSWORDED)) {
-               strprompt("Room password", rpass, 9);
+       if ((attr->QRflags & QR_PRIVATE)
+           && ((attr->QRflags & QR_PASSWORDED) == QR_PASSWORDED)) {
+               strprompt("Room password", attr->QRpasswd, 9);
        }
 
-       if ((rflags & QR_PRIVATE) == QR_PRIVATE) {
-               rbump =
-                   boolprompt("Cause current users to forget room", 0);
+       if ((attr->QRflags & QR_PRIVATE) == QR_PRIVATE) {
+               rbump = boolprompt("Cause current users to forget room", 0);
        }
 
-       rflags =
-           set_room_attr(ipc, rflags, "Preferred users only", QR_PREFONLY);
-       rflags = set_room_attr(ipc, rflags, "Read-only room", QR_READONLY);
-       rflags = set_room_attr(ipc, rflags, "Directory room", QR_DIRECTORY);
-       rflags = set_room_attr(ipc, rflags, "Permanent room", QR_PERMANENT);
-       if (rflags & QR_DIRECTORY) {
-               strprompt("Directory name", rdir, 14);
-               rflags =
-                   set_room_attr(ipc, rflags, "Uploading allowed", QR_UPLOAD);
-               rflags =
-                   set_room_attr(ipc, rflags, "Downloading allowed",
+       attr->QRflags = set_room_attr(ipc, attr->QRflags, "Preferred users only", QR_PREFONLY);
+       attr->QRflags = set_room_attr(ipc, attr->QRflags, "Read-only room", QR_READONLY);
+       attr->QRflags = set_room_attr(ipc, attr->QRflags, "Directory room", QR_DIRECTORY);
+       attr->QRflags = set_room_attr(ipc, attr->QRflags, "Permanent room", QR_PERMANENT);
+       if (attr->QRflags & QR_DIRECTORY) {
+               strprompt("Directory name", attr->QRdirname, 14);
+               attr->QRflags =
+                   set_room_attr(ipc, attr->QRflags, "Uploading allowed", QR_UPLOAD);
+               attr->QRflags =
+                   set_room_attr(ipc, attr->QRflags, "Downloading allowed",
                                  QR_DOWNLOAD);
-               rflags =
-                   set_room_attr(ipc, rflags, "Visible directory", QR_VISDIR);
+               attr->QRflags =
+                   set_room_attr(ipc, attr->QRflags, "Visible directory", QR_VISDIR);
        }
-       rflags = set_room_attr(ipc, rflags, "Network shared room", QR_NETWORK);
-       rflags2 = set_room_attr(ipc, rflags2,
+       attr->QRflags = set_room_attr(ipc, attr->QRflags, "Network shared room", QR_NETWORK);
+       attr->QRflags2 = set_room_attr(ipc, attr->QRflags2,
                                "Self-service list subscribe/unsubscribe",
                                QR2_SELFLIST);
-       rflags = set_room_attr(ipc, rflags,
+       attr->QRflags = set_room_attr(ipc, attr->QRflags,
                               "Automatically make all messages anonymous",
                               QR_ANONONLY);
-       if ((rflags & QR_ANONONLY) == 0) {
-               rflags = set_room_attr(ipc, rflags,
+       if ((attr->QRflags & QR_ANONONLY) == 0) {
+               attr->QRflags = set_room_attr(ipc, attr->QRflags,
                                       "Ask users whether to make messages anonymous",
                                       QR_ANONOPT);
        }
-       rorder = intprompt("Listing order", rorder, 1, 127);
+       attr->QRorder = intprompt("Listing order", attr->QRorder, 1, 127);
 
        /* Ask about the room aide */
        do {
@@ -518,7 +491,7 @@ void editthisroom(CtdlIPC *ipc)
 
        /* Angels and demons dancing in my head... */
        do {
-               snprintf(buf, sizeof buf, "%d", expire_mode);
+               snprintf(buf, sizeof buf, "%d", attr->QRep.expire_mode);
                strprompt("Message expire policy (? for list)", buf, 1);
                if (buf[0] == '?') {
                        scr_printf("\n"
@@ -528,19 +501,19 @@ void editthisroom(CtdlIPC *ipc)
                                "3. Expire by message age\n");
                }
        } while ((buf[0] < 48) || (buf[0] > 51));
-       expire_mode = buf[0] - 48;
+       attr->QRep.expire_mode = buf[0] - 48;
 
        /* ...lunatics and monsters underneath my bed */
-       if (expire_mode == 2) {
-               snprintf(buf, sizeof buf, "%d", expire_value);
+       if (attr->QRep.expire_mode == 2) {
+               snprintf(buf, sizeof buf, "%d", attr->QRep.expire_value);
                strprompt("Keep how many messages online?", buf, 10);
-               expire_value = atol(buf);
+               attr->QRep.expire_value = atol(buf);
        }
 
-       if (expire_mode == 3) {
-               snprintf(buf, sizeof buf, "%d", expire_value);
+       if (attr->QRep.expire_mode == 3) {
+               snprintf(buf, sizeof buf, "%d", attr->QRep.expire_value);
                strprompt("Keep messages for how many days?", buf, 10);
-               expire_value = atol(buf);
+               attr->QRep.expire_value = atol(buf);
        }
 
        /* Give 'em a chance to change their minds */
@@ -548,22 +521,23 @@ void editthisroom(CtdlIPC *ipc)
 
        if (yesno() == 1) {
                r = CtdlIPCSetRoomAide(ipc, raide, buf);
-               if (r != 2) {
+               if (r / 100 != 2) {
                        scr_printf("%s\n", buf);
                }
 
-               r = CtdlIPCSetMessageExpirationPolicy(ipc, 0, expire_mode,
-                                                     expire_value, buf);
+               r = CtdlIPCSetMessageExpirationPolicy(ipc, 0, eptr, buf);
+               if (r / 100 != 2) {
+                       scr_printf("%s\n", buf);
+               }
 
-               snprintf(buf, sizeof buf, "SETR %s|%s|%s|%d|%d|%d|%d|%d|%d",
-                        rname, rpass, rdir, rflags, rbump, rfloor,
-                        rorder, rview, rflags2);
-               CtdlIPC_putline(ipc, buf);
-               CtdlIPC_getline(ipc, buf);
-               scr_printf("%s\n", &buf[4]);
-               if (buf[0] == '2')
-                       dotgoto(ipc, rname, 2, 0);
+               r = CtdlIPCSetRoomAttributes(ipc, rbump, attr, buf);
+               scr_printf("%s\n", buf);
+               strncpy(buf, attr->QRname, ROOMNAMELEN);
+               free(attr);
+               if (r / 100 == 2)
+                       dotgoto(ipc, buf, 2, 0);
        }
+       else free(attr);
 }
 
 
@@ -1117,8 +1091,7 @@ void create_floor(CtdlIPC *ipc)
 void edit_floor(CtdlIPC *ipc)
 {
        char buf[SIZ];
-       int expire_mode = 0;
-       int expire_value = 0;
+       struct ExpirePolicy *ep = NULL;
        int r;                          /* IPC response code */
 
        load_floorlist(ipc);
@@ -1126,11 +1099,7 @@ void edit_floor(CtdlIPC *ipc)
        /* Fetch the expire policy (this will silently fail on old servers,
         * resulting in "default" policy)
         */
-       r = CtdlIPCGetMessageExpirationPolicy(ipc, 1, buf);
-       if (r / 100 == 2) {
-               expire_mode = extract_int(buf, 0);
-               expire_value = extract_int(buf, 1);
-       }
+       r = CtdlIPCGetMessageExpirationPolicy(ipc, 1, &ep, buf);
 
        /* Interact with the user */
        scr_printf("You are editing the floor called \"%s\"\n", 
@@ -1139,7 +1108,7 @@ void edit_floor(CtdlIPC *ipc)
 
        /* Angels and demons dancing in my head... */
        do {
-               snprintf(buf, sizeof buf, "%d", expire_mode);
+               snprintf(buf, sizeof buf, "%d", ep->expire_mode);
                strprompt
                    ("Floor default message expire policy (? for list)",
                     buf, 1);
@@ -1151,24 +1120,23 @@ void edit_floor(CtdlIPC *ipc)
                                "3. Expire by message age\n");
                }
        } while ((buf[0] < '0') || (buf[0] > '3'));
-       expire_mode = buf[0] - '0';
+       ep->expire_mode = buf[0] - '0';
 
        /* ...lunatics and monsters underneath my bed */
-       if (expire_mode == 2) {
-               snprintf(buf, sizeof buf, "%d", expire_value);
+       if (ep->expire_mode == 2) {
+               snprintf(buf, sizeof buf, "%d", ep->expire_value);
                strprompt("Keep how many messages online?", buf, 10);
-               expire_value = atol(buf);
+               ep->expire_value = atol(buf);
        }
 
-       if (expire_mode == 3) {
-               snprintf(buf, sizeof buf, "%d", expire_value);
+       if (ep->expire_mode == 3) {
+               snprintf(buf, sizeof buf, "%d", ep->expire_value);
                strprompt("Keep messages for how many days?", buf, 10);
-               expire_value = atol(buf);
+               ep->expire_value = atol(buf);
        }
 
        /* Save it */
-       r = CtdlIPCSetMessageExpirationPolicy(ipc, 1, expire_mode,
-                                             expire_value, buf);
+       r = CtdlIPCSetMessageExpirationPolicy(ipc, 1, ep, buf);
        r = CtdlIPCEditFloor(ipc, curr_floor, &floorlist[(int)curr_floor][0], buf);
        scr_printf("%s\n", buf);
        load_floorlist(ipc);