X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Frooms.c;h=87d46f8bb61a387614300496f5696671227f8378;hb=1e656d277fe91b7c4f5d73eab4a0dd0b7a173145;hp=c97533a840a80ad65ef9c47ed19ec9c55f9b2e03;hpb=38e42af66212266012408c367fd29e8c277690eb;p=citadel.git diff --git a/citadel/rooms.c b/citadel/rooms.c index c97533a84..87d46f8bb 100644 --- a/citadel/rooms.c +++ b/citadel/rooms.c @@ -19,25 +19,25 @@ #include #include #include +#include #include "citadel.h" #include "citadel_ipc.h" #include "citadel_decls.h" #include "rooms.h" #include "commands.h" -#include "tools.h" #include "messages.h" #ifndef HAVE_SNPRINTF #include "snprintf.h" #endif #include "screen.h" +#include "citadel_dirs.h" #define IFNEXPERT if ((userflags&US_EXPERT)==0) -void sttybbs(int cmd); -void hit_any_key(void); +void stty_ctdl(int cmd); void dotgoto(CtdlIPC *ipc, char *towhere, int display_name, int fromungoto); -void progress(long int curr, long int cmax); +void progress(CtdlIPC* ipc, unsigned long curr, unsigned long cmax); int pattern(char *search, char *patn); int file_checksum(char *filename); int nukedir(char *dirname); @@ -47,7 +47,6 @@ extern char room_name[]; extern char temp[]; extern char tempdir[]; extern int editor_pid; -extern char editor_path[]; extern int screenwidth; extern int screenheight; extern char fullname[]; @@ -80,16 +79,16 @@ void load_floorlist(CtdlIPC *ipc) strcpy(floorlist[0], "Main Floor"); return; } - while (*listing && strlen(listing)) { - extract_token(buf, listing, 0, '\n'); + while (*listing && !IsEmptyStr(listing)) { + extract_token(buf, listing, 0, '\n', sizeof buf); remove_token(listing, 0, '\n'); - extract(floorlist[extract_int(buf, 0)], buf, 1); + extract_token(floorlist[extract_int(buf, 0)], buf, 1, '|', SIZ); } free(listing); } -void room_tree_list(struct roomlisting *rp) +void room_tree_list(struct ctdlroomlisting *rp) { static int c = 0; char rmname[ROOMNAMELEN]; @@ -143,7 +142,7 @@ void room_tree_list(struct roomlisting *rp) /* * Room ordering stuff (compare first by floor, then by order) */ -int rordercmp(struct roomlisting *r1, struct roomlisting *r2) +int rordercmp(struct ctdlroomlisting *r1, struct ctdlroomlisting *r2) { if ((r1 == NULL) && (r2 == NULL)) return (0); @@ -166,48 +165,63 @@ int rordercmp(struct roomlisting *r1, struct roomlisting *r2) /* * Common code for all room listings */ -void listrms(CtdlIPC *ipc, char *variety) +static void listrms(struct march *listing, int new_only, int floor_only, unsigned int flags, char *match) { - char buf[SIZ]; - - struct roomlisting *rl = NULL; - struct roomlisting *rp; - struct roomlisting *rs; - - - /* Ask the server for a room list */ - CtdlIPC_putline(ipc, variety); - CtdlIPC_getline(ipc, buf); - if (buf[0] != '1') { - return; - } - while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) { - 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); - rp->lnext = NULL; - rp->rnext = NULL; - - rs = rl; - if (rl == NULL) { - rl = rp; - } else { - while (rp != NULL) { - if (rordercmp(rp, rs) < 0) { - if (rs->lnext == NULL) { - rs->lnext = rp; - rp = NULL; - } else { - rs = rs->lnext; - } - } else { - if (rs->rnext == NULL) { - rs->rnext = rp; - rp = NULL; + struct march *mptr; + struct ctdlroomlisting *rl = NULL; + struct ctdlroomlisting *rp; + struct ctdlroomlisting *rs; + int list_it; + + for (mptr = listing; mptr != NULL; mptr = mptr->next) { + list_it = 1; + + if ( (new_only == LISTRMS_NEW_ONLY) + && ((mptr->march_access & UA_HASNEWMSGS) == 0)) + list_it = 0; + + if ( (new_only == LISTRMS_OLD_ONLY) + && ((mptr->march_access & UA_HASNEWMSGS) != 0)) + list_it = 0; + + if ( (floor_only >= 0) + && (mptr->march_floor != floor_only)) + list_it = 0; + + if (flags && (mptr->march_flags & flags) == 0) + list_it = 0; + + if (match && (pattern(mptr->march_name, match) == -1)) + list_it = 0; + + if (list_it) { + rp = malloc(sizeof(struct ctdlroomlisting)); + strncpy(rp->rlname, mptr->march_name, ROOMNAMELEN); + rp->rlflags = mptr->march_flags; + rp->rlfloor = mptr->march_floor; + rp->rlorder = mptr->march_order; + rp->lnext = NULL; + rp->rnext = NULL; + + rs = rl; + if (rl == NULL) { + rl = rp; + } else { + while (rp != NULL) { + if (rordercmp(rp, rs) < 0) { + if (rs->lnext == NULL) { + rs->lnext = rp; + rp = NULL; + } else { + rs = rs->lnext; + } } else { - rs = rs->rnext; + if (rs->rnext == NULL) { + rs->rnext = rp; + rp = NULL; + } else { + rs = rs->rnext; + } } } } @@ -240,22 +254,33 @@ void list_other_floors(void) /* * List known rooms. kn_floor_mode should be set to 0 for a 'flat' listing, - * 1 to list rooms on the current floor, or 1 to list rooms on all floors. + * 1 to list rooms on the current floor, or 2 to list rooms on all floors. */ void knrooms(CtdlIPC *ipc, int kn_floor_mode) { - char buf[SIZ]; int a; + struct march *listing = NULL; + struct march *mptr; + int r; /* IPC response code */ + char buf[SIZ]; + + + /* Ask the server for a room list */ + r = CtdlIPCKnownRooms(ipc, SubscribedRooms, (-1), &listing, buf); + if (r / 100 != 1) { + listing = NULL; + } load_floorlist(ipc); + if (kn_floor_mode == 0) { color(BRIGHT_CYAN); pprintf("\n Rooms with unread messages:\n"); - listrms(ipc, "LKRN"); + listrms(listing, LISTRMS_NEW_ONLY, -1, 0, NULL); color(BRIGHT_CYAN); pprintf("\n\n No unseen messages in:\n"); - listrms(ipc, "LKRO"); + listrms(listing, LISTRMS_OLD_ONLY, -1, 0, NULL); pprintf("\n"); } @@ -263,13 +288,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(listing, LISTRMS_NEW_ONLY, curr_floor, 0, NULL); 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(listing, LISTRMS_OLD_ONLY, curr_floor, 0, NULL); color(BRIGHT_CYAN); pprintf("\n\n Other floors:\n"); list_other_floors(); @@ -282,30 +305,120 @@ 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(listing, LISTRMS_ALL, a, 0, NULL); pprintf("\n"); } } } + /* Free the room list */ + while (listing) { + mptr = listing->next; + free(listing); + listing = mptr; + }; + color(DIM_WHITE); - IFNEXPERT hit_any_key(); + IFNEXPERT hit_any_key(ipc); } void listzrooms(CtdlIPC *ipc) { /* list public forgotten rooms */ + struct march *listing = NULL; + struct march *mptr; + int r; /* IPC response code */ + char buf[SIZ]; + + + /* Ask the server for a room list */ + r = CtdlIPCKnownRooms(ipc, UnsubscribedRooms, (-1), &listing, buf); + if (r / 100 != 1) { + listing = NULL; + } + color(BRIGHT_CYAN); pprintf("\n Forgotten public rooms:\n"); - listrms(ipc, "LZRM"); + listrms(listing, LISTRMS_ALL, -1, 0, NULL); pprintf("\n"); + + /* Free the room list */ + while (listing) { + mptr = listing->next; + free(listing); + listing = mptr; + }; + color(DIM_WHITE); - IFNEXPERT hit_any_key(); + IFNEXPERT hit_any_key(ipc); } +void dotknown(CtdlIPC *ipc, int what, char *match) +{ /* list rooms according to attribute */ + struct march *listing = NULL; + struct march *mptr; + int r; /* IPC response code */ + char buf[SIZ]; + + /* Ask the server for a room list */ + r = CtdlIPCKnownRooms(ipc, AllAccessibleRooms, (-1), &listing, buf); + if (r / 100 != 1) { + listing = NULL; + } + + color(BRIGHT_CYAN); -int set_room_attr(CtdlIPC *ipc, int ibuf, char *prompt, unsigned int sbit) + switch (what) { + case 0: + pprintf("\n Anonymous rooms:\n"); + listrms(listing, LISTRMS_ALL, -1, QR_ANONONLY|QR_ANONOPT, NULL); + pprintf("\n"); + break; + case 1: + pprintf("\n Directory rooms:\n"); + listrms(listing, LISTRMS_ALL, -1, QR_DIRECTORY, NULL); + pprintf("\n"); + break; + case 2: + pprintf("\n Matching \"%s\" rooms:\n", match); + listrms(listing, LISTRMS_ALL, -1, 0, match); + pprintf("\n"); + break; + case 3: + pprintf("\n Preferred only rooms:\n"); + listrms(listing, LISTRMS_ALL, -1, QR_PREFONLY, NULL); + pprintf("\n"); + break; + case 4: + pprintf("\n Private rooms:\n"); + listrms(listing, LISTRMS_ALL, -1, QR_PRIVATE, NULL); + pprintf("\n"); + break; + case 5: + pprintf("\n Read only rooms:\n"); + listrms(listing, LISTRMS_ALL, -1, QR_READONLY, NULL); + pprintf("\n"); + break; + case 6: + pprintf("\n Shared rooms:\n"); + listrms(listing, LISTRMS_ALL, -1, QR_NETWORK, NULL); + pprintf("\n"); + break; + } + + /* Free the room list */ + while (listing) { + mptr = listing->next; + free(listing); + listing = mptr; + }; + + color(DIM_WHITE); + IFNEXPERT hit_any_key(ipc); +} + + +int set_room_attr(CtdlIPC *ipc, unsigned int ibuf, char *prompt, unsigned int sbit) { int a; @@ -338,6 +451,7 @@ int select_floor(CtdlIPC *ipc, int rfloor) newfloor = (-1); safestrncpy(floorstr, floorlist[rfloor], sizeof floorstr); + strprompt("Which floor", floorstr, 255); for (a = 0; a < 128; ++a) { if (!strcasecmp (floorstr, &floorlist[a][0])) @@ -365,6 +479,12 @@ int select_floor(CtdlIPC *ipc, int rfloor) } while (newfloor < 0); return (newfloor); } + + else { + scr_printf("Floor selection bypassed because you have " + "floor mode disabled.\n"); + } + return (rfloor); } @@ -376,127 +496,115 @@ 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; - char raide[32]; + int rbump = 0; + char raide[USERNAME_SIZE]; char buf[SIZ]; - int rfloor; - int rorder; - int rview; - int expire_mode = 0; - int expire_value = 0; + struct ctdlroom *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) { + if (IsEmptyStr(raide)) { strcpy(raide, "none"); } /* 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, + strprompt("Room name", attr->QRname, ROOMNAMELEN-1); + 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 ((rflags & 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", + if ((attr->QRflags & QR_PRIVATE) + && ((attr->QRflags & QR_PASSWORDED) == QR_PASSWORDED)) { + strprompt("Room password", attr->QRpasswd, 9); + } + + if ((attr->QRflags & QR_PRIVATE) == QR_PRIVATE) { + rbump = boolprompt("Cause current users to forget room", 0); + } + + 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->QRflags2 = set_room_attr(ipc, attr->QRflags2, + "Allow message deletion by anyone who can post", + QR2_COLLABDEL); + attr->QRflags = set_room_attr(ipc, attr->QRflags, + "Permanent room", QR_PERMANENT); + attr->QRflags2 = set_room_attr(ipc, attr->QRflags2, + "Subject Required (Force " + "users to specify a message " + "subject)", QR2_SUBJECTREQ); + attr->QRflags = set_room_attr(ipc, attr->QRflags, + "Directory room", QR_DIRECTORY); + 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, 0, 127); /* Ask about the room aide */ do { @@ -518,7 +626,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 +636,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,51 +656,109 @@ 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); } /* - * un-goto the previous room + * un-goto the previous room, or a specified room */ +void dotungoto(CtdlIPC *ipc, char *towhere) + { + /* Find this 'towhere' room in the list ungoto from this room to + that at the messagepointer position in that room in our ungoto list. + I suppose I could be a real dick and just ungoto that many places + in our list. */ + int found = -1; + int lp; + char buf[SIZ]; + struct ctdlipcroom *rret = NULL; /* ignored */ + int r; + + if (uglistsize == 0) + { + scr_printf("No rooms to ungoto.\n"); + return; + } + if (towhere == NULL) + { + scr_printf("Must specify a room to ungoto.\n"); + return; + } + if (IsEmptyStr(towhere)) + { + scr_printf("Must specify a room to ungoto.\n"); + return; + } + for (lp = uglistsize-1; lp >= 0; lp--) + { + if (strcasecmp(towhere, uglist[lp]) == 0) + { + found = lp; + break; + } + } + if (found == -1) + { + scr_printf("Room: %s not in ungoto list.\n", towhere); + return; + } + + r = CtdlIPCGotoRoom(ipc, uglist[found], "", &rret, buf); + if (rret) free(rret); /* ignored */ + if (r / 100 != 2) { + scr_printf("%s\n", buf); + return; + } + r = CtdlIPCSetLastRead(ipc, uglistlsn[found] ? uglistlsn[found] : 1, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); + } + safestrncpy(buf, uglist[found], sizeof(buf)); + /* we queue ungoto information here, because we're not really + ungotoing, we're really going to a random spot in some arbitrary + room list. */ + dotgoto(ipc, buf, 0, 0); + } + void ungoto(CtdlIPC *ipc) { char buf[SIZ]; + struct ctdlipcroom *rret = NULL; /* ignored */ + int r; if (uglistsize == 0) return; - snprintf(buf, sizeof buf, "GOTO %s", uglist[uglistsize-1]); - CtdlIPC_putline(ipc, buf); - CtdlIPC_getline(ipc, buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); + r = CtdlIPCGotoRoom(ipc, uglist[uglistsize-1], "", &rret, buf); + if (rret) free(rret); /* ignored */ + if (r / 100 != 2) { + scr_printf("%s\n", buf); return; } - snprintf(buf, sizeof buf, "SLRP %ld", uglistlsn[uglistsize-1]); - CtdlIPC_putline(ipc, buf); - CtdlIPC_getline(ipc, buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); + r = CtdlIPCSetLastRead(ipc, uglistlsn[uglistsize-1] ? uglistlsn[uglistsize-1] : 1, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); } - safestrncpy (buf, uglist[uglistsize-1], sizeof(buf)); - uglistsize--; - free(uglist[uglistsize]); + safestrncpy(buf, uglist[uglistsize-1], sizeof(buf)); + uglistsize--; + free(uglist[uglistsize]); /* Don't queue ungoto info or we end up in a loop */ dotgoto(ipc, buf, 0, 1); } @@ -613,7 +779,7 @@ int save_buffer(void *file, size_t filelen, const char *pathname) return 0; } do { - block = fwrite(file + bytes_written, 1, + block = fwrite((char *)file + bytes_written, 1, filelen - bytes_written, fp); bytes_written += block; } while (errno == EINTR && bytes_written < filelen); @@ -633,16 +799,34 @@ int save_buffer(void *file, size_t filelen, const char *pathname) */ void destination_directory(char *dest, const char *supplied_filename) { - scr_printf("Enter the name of the directory to save '%s'\n" - "to, or press return for the current directory.\n", - supplied_filename); - newprompt("Directory: ", dest, PATH_MAX); - if (strlen(dest) == 0) { - dest[0] = '.'; - dest[1] = 0; - } - strcat(dest, "/"); - strcat(dest, supplied_filename); + static char save_dir[SIZ] = { 0 }; + + if (IsEmptyStr(save_dir)) { + if (getenv("HOME") == NULL) { + strcpy(save_dir, "."); + } + else { + sprintf(save_dir, "%s/Desktop", getenv("HOME")); + if (access(save_dir, W_OK) != 0) { + sprintf(save_dir, "%s", getenv("HOME")); + if (access(save_dir, W_OK) != 0) { + sprintf(save_dir, "."); + } + } + } + } + + sprintf(dest, "%s/%s", save_dir, supplied_filename); + strprompt("Save as", dest, PATH_MAX); + + /* Remember the directory for next time */ + strcpy(save_dir, dest); + if (strrchr(save_dir, '/') != NULL) { + strcpy(strrchr(save_dir, '/'), ""); + } + else { + strcpy(save_dir, "."); + } } @@ -661,7 +845,7 @@ void download(CtdlIPC *ipc, int proto) int broken = 0; int r; void *file = NULL; /* The downloaded file */ - long filelen = 0L; /* The downloaded file length */ + size_t filelen = 0L; /* The downloaded file length */ if ((room_flags & QR_DOWNLOAD) == 0) { scr_printf("*** You cannot download from this room.\n"); @@ -673,22 +857,22 @@ void download(CtdlIPC *ipc, int proto) /* Save to local disk, for folks with their own copy of the client */ if (proto == 5) { destination_directory(tempname, filename); - r = CtdlIPCFileDownload(ipc, filename, &file, progress, buf); + r = CtdlIPCFileDownload(ipc, filename, &file, 0, progress, buf); if (r / 100 != 2) { scr_printf("%s\n", buf); return; } - save_buffer(file, extract_long(buf, 0), tempname); + save_buffer(file, (size_t)extract_long(buf, 0), tempname); free(file); return; } - r = CtdlIPCFileDownload(ipc, filename, &file, progress, buf); + r = CtdlIPCFileDownload(ipc, filename, &file, 0, progress, buf); if (r / 100 != 2) { scr_printf("%s\n", buf); return; } - filelen = extract_long(buf, 0); + filelen = extract_unsigned_long(buf, 0); /* Meta-download for public clients */ /* scr_printf("Fetching file from Citadel server...\n"); */ @@ -696,6 +880,7 @@ void download(CtdlIPC *ipc, int proto) snprintf(tempname, sizeof tempname, "%s/%s", tempdir, filename); tpipe = fopen(tempname, "wb"); if (fwrite(file, filelen, 1, tpipe) < filelen) { + /* FIXME: restart syscall on EINTR */ broken = 1; } fclose(tpipe); @@ -718,14 +903,14 @@ void download(CtdlIPC *ipc, int proto) snprintf(transmit_cmd, sizeof transmit_cmd, "exec cat %s", tempname); screen_reset(); - sttybbs(SB_RESTORE); + stty_ctdl(SB_RESTORE); system(transmit_cmd); - sttybbs(SB_NO_INTR); + stty_ctdl(SB_NO_INTR); screen_set(); /* clean up the temporary directory */ nukedir(tempdir); - scr_putc(7); /* Beep beep! */ + ctdl_beep(); /* Beep beep! */ } @@ -734,32 +919,37 @@ void download(CtdlIPC *ipc, int proto) */ void roomdir(CtdlIPC *ipc) { - char flnm[SIZ]; + char flnm[256]; char flsz[32]; - char comment[SIZ]; - char buf[SIZ]; + char comment[256]; + char buf[256]; + char *listing = NULL; /* Returned directory listing */ + int r; - CtdlIPC_putline(ipc, "RDIR"); - CtdlIPC_getline(ipc, buf); - if (buf[0] != '1') { - pprintf("%s\n", &buf[4]); + r = CtdlIPCReadDirectory(ipc, &listing, buf); + if (r / 100 != 1) { + pprintf("%s\n", buf); return; } - extract(comment, &buf[4], 0); - extract(flnm, &buf[4], 1); + extract_token(comment, buf, 0, '|', sizeof comment); + extract_token(flnm, buf, 1, '|', sizeof flnm); pprintf("\nDirectory of %s on %s\n", flnm, comment); pprintf("-----------------------\n"); - while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) { - extract(flnm, buf, 0); - extract(flsz, buf, 1); - extract(comment, buf, 2); + while (listing && *listing && !IsEmptyStr(listing)) { + extract_token(buf, listing, 0, '\n', sizeof buf); + remove_token(listing, 0, '\n'); + + extract_token(flnm, buf, 0, '|', sizeof flnm); + extract_token(flsz, buf, 1, '|', sizeof flsz); + extract_token(comment, buf, 2, '|', sizeof comment); if (strlen(flnm) <= 14) pprintf("%-14s %8s %s\n", flnm, flsz, comment); else pprintf("%s\n%14s %8s %s\n", flnm, "", flsz, comment); } + if (listing) free(listing); } @@ -832,6 +1022,7 @@ void forget(CtdlIPC *ipc) if (yesno() == 0) return; + remove_march(room_name, 0); if (CtdlIPCForgetRoom(ipc, buf) / 100 != 2) { scr_printf("%s\n", buf); return; @@ -863,10 +1054,10 @@ void entroom(CtdlIPC *ipc) } newprompt("Name for new room? ", new_room_name, ROOMNAMELEN - 1); - if (strlen(new_room_name) == 0) { + if (IsEmptyStr(new_room_name)) { return; } - for (a = 0; a < strlen(new_room_name); ++a) { + for (a = 0; !IsEmptyStr(&new_room_name[a]); ++a) { if (new_room_name[a] == '|') { new_room_name[a] = '_'; } @@ -893,7 +1084,7 @@ void entroom(CtdlIPC *ipc) new_room_type = b - 1; if (new_room_type == 2) { newprompt("Enter a room password: ", new_room_pass, 9); - for (a = 0; a < strlen(new_room_pass); ++a) + for (a = 0; !IsEmptyStr(&new_room_pass[a]); ++a) if (new_room_pass[a] == '|') new_room_pass[a] = '_'; } else { @@ -943,7 +1134,7 @@ void readinfo(CtdlIPC *ipc) else strcpy(raide, ""); - if (strlen(raide) > 0) + if (!IsEmptyStr(raide)) scr_printf("Room aide is %s.\n\n", raide); r = CtdlIPCRoomInfo(ipc, &text, buf); @@ -964,17 +1155,22 @@ void readinfo(CtdlIPC *ipc) */ void whoknows(CtdlIPC *ipc) { - char buf[SIZ]; - CtdlIPC_putline(ipc, "WHOK"); - CtdlIPC_getline(ipc, buf); - if (buf[0] != '1') { - pprintf("%s\n", &buf[4]); + char buf[256]; + char *listing = NULL; + int r; + + r = CtdlIPCWhoKnowsRoom(ipc, &listing, buf); + if (r / 100 != 1) { + pprintf("%s\n", buf); return; } - while (CtdlIPC_getline(ipc, buf), strncmp(buf, "000", 3)) { + while (!IsEmptyStr(listing)) { + extract_token(buf, listing, 0, '\n', sizeof buf); + remove_token(listing, 0, '\n'); if (sigcaught == 0) pprintf("%s\n", buf); } + free(listing); } @@ -985,8 +1181,7 @@ void do_edit(CtdlIPC *ipc, char cmd[SIZ]; int b, cksum, editor_exit; - - if (strlen(editor_path) == 0) { + if (IsEmptyStr(editor_paths[0])) { scr_printf("Do you wish to re-enter %s? ", desc); if (yesno() == 0) return; @@ -995,19 +1190,19 @@ void do_edit(CtdlIPC *ipc, fp = fopen(temp, "w"); fclose(fp); - CtdlIPC_putline(ipc, check_cmd); - CtdlIPC_getline(ipc, cmd); + CtdlIPC_chat_send(ipc, check_cmd); + CtdlIPC_chat_recv(ipc, cmd); if (cmd[0] != '2') { scr_printf("%s\n", &cmd[4]); return; } - if (strlen(editor_path) > 0) { - CtdlIPC_putline(ipc, read_cmd); - CtdlIPC_getline(ipc, cmd); + if (!IsEmptyStr(editor_paths[0])) { + CtdlIPC_chat_send(ipc, read_cmd); + CtdlIPC_chat_recv(ipc, cmd); if (cmd[0] == '1') { fp = fopen(temp, "w"); - while (CtdlIPC_getline(ipc, cmd), strcmp(cmd, "000")) { + while (CtdlIPC_chat_recv(ipc, cmd), strcmp(cmd, "000")) { fprintf(fp, "%s\n", cmd); } fclose(fp); @@ -1016,27 +1211,27 @@ void do_edit(CtdlIPC *ipc, cksum = file_checksum(temp); - if (strlen(editor_path) > 0) { + if (!IsEmptyStr(editor_paths[0])) { char tmp[SIZ]; snprintf(tmp, sizeof tmp, "WINDOW_TITLE=%s", desc); putenv(tmp); + screen_reset(); + stty_ctdl(SB_RESTORE); editor_pid = fork(); if (editor_pid == 0) { chmod(temp, 0600); - screen_reset(); - sttybbs(SB_RESTORE); - execlp(editor_path, editor_path, temp, NULL); + execlp(editor_paths[0], editor_paths[0], temp, NULL); exit(1); } if (editor_pid > 0) do { editor_exit = 0; - b = wait(&editor_exit); + b = ka_wait(&editor_exit); } while ((b != editor_pid) && (b >= 0)); editor_pid = (-1); - scr_printf("Executed %s\n", editor_path); - sttybbs(0); + scr_printf("Executed %s\n", editor_paths[0]); + stty_ctdl(0); screen_set(); } else { scr_printf("Entering %s. " @@ -1051,8 +1246,8 @@ void do_edit(CtdlIPC *ipc, } else { - CtdlIPC_putline(ipc, write_cmd); - CtdlIPC_getline(ipc, cmd); + CtdlIPC_chat_send(ipc, write_cmd); + CtdlIPC_chat_recv(ipc, cmd); if (cmd[0] != '4') { scr_printf("%s\n", &cmd[4]); return; @@ -1061,10 +1256,10 @@ void do_edit(CtdlIPC *ipc, fp = fopen(temp, "r"); while (fgets(cmd, SIZ - 1, fp) != NULL) { cmd[strlen(cmd) - 1] = 0; - CtdlIPC_putline(ipc, cmd); + CtdlIPC_chat_send(ipc, cmd); } fclose(fp); - CtdlIPC_putline(ipc, "000"); + CtdlIPC_chat_send(ipc, "000"); } unlink(temp); @@ -1095,12 +1290,13 @@ void create_floor(CtdlIPC *ipc) load_floorlist(ipc); r = CtdlIPCCreateFloor(ipc, 0, "", buf); - if (r / 100 != 2) { + if ( (r / 100 != 2) && (r != ERROR + ILLEGAL_VALUE) ) { scr_printf("%s\n", buf); return; } newprompt("Name for new floor: ", newfloorname, 255); + if (!*newfloorname) return; r = CtdlIPCCreateFloor(ipc, 1, newfloorname, buf); if (r / 100 == 2) { scr_printf("Floor has been created.\n"); @@ -1117,8 +1313,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 +1321,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 +1330,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 +1342,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); @@ -1190,7 +1380,7 @@ void kill_floor(CtdlIPC *ipc) floornum_to_delete = (-1); scr_printf("(Press return to abort)\n"); newprompt("Delete which floor? ", buf, 255); - if (strlen(buf) == 0) + if (IsEmptyStr(buf)) return; for (a = 0; a < 128; ++a) if (!strcasecmp(&floorlist[a][0], buf))