X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Frooms.c;h=eac37b0161c03d50f8b3e83dc34520b245dcfede;hb=27d35cf620da260472336afd096787cf5e5558d3;hp=5f4dcb6951df02ccc7bb30390c0713587970406a;hpb=07ba2ef8e2bc2fb34c90560566774f56ab9e9f90;p=citadel.git diff --git a/citadel/rooms.c b/citadel/rooms.c index 5f4dcb695..eac37b016 100644 --- a/citadel/rooms.c +++ b/citadel/rooms.c @@ -20,6 +20,8 @@ #include #include #include "citadel.h" +#include "citadel_ipc.h" +#include "citadel_decls.h" #include "rooms.h" #include "commands.h" #include "tools.h" @@ -34,14 +36,8 @@ void sttybbs(int cmd); void hit_any_key(void); -int yesno(void); -void strprompt(char *prompt, char *str, int len); -void newprompt(char *prompt, char *str, int len); -void dotgoto(char *towhere, int display_name, int fromungoto); -void serv_read(char *buf, int bytes); -void formout(char *name); -int inkey(void); -void progress(long int curr, long int cmax); +void dotgoto(CtdlIPC *ipc, char *towhere, int display_name, int fromungoto); +void progress(unsigned long curr, unsigned long cmax); int pattern(char *search, char *patn); int file_checksum(char *filename); int nukedir(char *dirname); @@ -51,11 +47,9 @@ 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[]; -extern int userflags; extern char sigcaught; extern char floor_mode; extern char curr_floor; @@ -70,27 +64,31 @@ extern int uglistsize; extern char floorlist[128][SIZ]; -void load_floorlist(void) +void load_floorlist(CtdlIPC *ipc) { int a; char buf[SIZ]; + char *listing = NULL; + int r; /* IPC response code */ for (a = 0; a < 128; ++a) floorlist[a][0] = 0; - serv_puts("LFLR"); - serv_gets(buf); - if (buf[0] != '1') { + r = CtdlIPCFloorListing(ipc, &listing, buf); + if (r / 100 != 1) { strcpy(floorlist[0], "Main Floor"); return; } - while (serv_gets(buf), strcmp(buf, "000")) { + while (*listing && strlen(listing)) { + extract_token(buf, listing, 0, '\n'); + remove_token(listing, 0, '\n'); extract(floorlist[extract_int(buf, 0)], buf, 1); } + free(listing); } -void room_tree_list(struct roomlisting *rp) +void room_tree_list(struct ctdlroomlisting *rp) { static int c = 0; char rmname[ROOMNAMELEN]; @@ -144,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); @@ -167,48 +165,57 @@ int rordercmp(struct roomlisting *r1, struct roomlisting *r2) /* * Common code for all room listings */ -void listrms(char *variety) +static void listrms(struct march *listing, int new_only, int floor_only) { - char buf[SIZ]; - - struct roomlisting *rl = NULL; - struct roomlisting *rp; - struct roomlisting *rs; - - - /* Ask the server for a room list */ - serv_puts(variety); - serv_gets(buf); - if (buf[0] != '1') { - return; - } - while (serv_gets(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 (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; + } } } } @@ -243,20 +250,31 @@ 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. */ -void knrooms(int kn_floor_mode) +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); - load_floorlist(); if (kn_floor_mode == 0) { color(BRIGHT_CYAN); pprintf("\n Rooms with unread messages:\n"); - listrms("LKRN"); + listrms(listing, LISTRMS_NEW_ONLY, -1); color(BRIGHT_CYAN); pprintf("\n\n No unseen messages in:\n"); - listrms("LKRO"); + listrms(listing, LISTRMS_OLD_ONLY, -1); pprintf("\n"); } @@ -264,13 +282,11 @@ void knrooms(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(buf); + listrms(listing, LISTRMS_NEW_ONLY, 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(buf); + listrms(listing, LISTRMS_OLD_ONLY, curr_floor); color(BRIGHT_CYAN); pprintf("\n\n Other floors:\n"); list_other_floors(); @@ -283,30 +299,56 @@ void knrooms(int kn_floor_mode) color(BRIGHT_CYAN); pprintf("\n Rooms on %s:\n", floorlist[a]); - snprintf(buf, sizeof buf, "LKRA %d", a); - listrms(buf); + listrms(listing, LISTRMS_ALL, a); pprintf("\n"); } } } + /* Free the room list */ + while (listing) { + mptr = listing->next; + free(listing); + listing = mptr; + }; + color(DIM_WHITE); IFNEXPERT hit_any_key(); } -void listzrooms(void) +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("LZRM"); + listrms(listing, LISTRMS_ALL, -1); pprintf("\n"); + + /* Free the room list */ + while (listing) { + mptr = listing->next; + free(listing); + listing = mptr; + }; + color(DIM_WHITE); IFNEXPERT hit_any_key(); } -int set_room_attr(int ibuf, char *prompt, unsigned int sbit) +int set_room_attr(CtdlIPC *ipc, unsigned int ibuf, char *prompt, unsigned int sbit) { int a; @@ -325,21 +367,21 @@ int set_room_attr(int ibuf, char *prompt, unsigned int sbit) * The supplied argument is the 'default' floor number. * This function returns the selected floor number. */ -int select_floor(int rfloor) +int select_floor(CtdlIPC *ipc, int rfloor) { int a, newfloor; char floorstr[SIZ]; if (floor_mode == 1) { if (floorlist[(int) curr_floor][0] == 0) { - load_floorlist(); + load_floorlist(ipc); } do { newfloor = (-1); safestrncpy(floorstr, floorlist[rfloor], sizeof floorstr); - strprompt("Which floor", floorstr, SIZ); + strprompt("Which floor", floorstr, 255); for (a = 0; a < 128; ++a) { if (!strcasecmp (floorstr, &floorlist[a][0])) @@ -367,6 +409,12 @@ int select_floor(int rfloor) } while (newfloor < 0); return (newfloor); } + + else { + scr_printf("Floor selection bypassed because you have " + "floor mode disabled.\n"); + } + return (rfloor); } @@ -376,43 +424,28 @@ int select_floor(int rfloor) /* * .ide dit room */ -void editthisroom(void) +void editthisroom(CtdlIPC *ipc) { - char rname[ROOMNAMELEN]; - char rpass[10]; - char rdir[15]; - unsigned rflags; - int rbump; - char raide[32]; + int rbump = 0; + char raide[USERNAME_SIZE]; char buf[SIZ]; - int rfloor; - int rorder; - 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 */ - serv_puts("GETR"); - serv_gets(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); - rbump = 0; + eptr = &(attr->QRep); /* Fetch the name of the current room aide */ - serv_puts("GETA"); - serv_gets(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) { @@ -422,100 +455,101 @@ void editthisroom(void) /* Fetch the expire policy (this will silently fail on old servers, * resulting in "default" policy) */ - serv_puts("GPEX room"); - serv_gets(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. */ - strprompt("Room name", rname, ROOMNAMELEN - 1); - rfloor = select_floor(rfloor); - rflags = set_room_attr(rflags, "Private room", QR_PRIVATE); - if (rflags & QR_PRIVATE) { - rflags = set_room_attr(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(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(rflags, "Preferred users only", QR_PREFONLY); - rflags = set_room_attr(rflags, "Read-only room", QR_READONLY); - rflags = set_room_attr(rflags, "Directory room", QR_DIRECTORY); - rflags = set_room_attr(rflags, "Permanent room", QR_PERMANENT); - if (rflags & QR_DIRECTORY) { - strprompt("Directory name", rdir, 14); - rflags = - set_room_attr(rflags, "Uploading allowed", QR_UPLOAD); - rflags = - set_room_attr(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->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(rflags, "Visible directory", QR_VISDIR); - } - rflags = set_room_attr(rflags, "Network shared room", QR_NETWORK); - rflags = set_room_attr(rflags, + attr->QRflags = + set_room_attr(ipc, attr->QRflags, + "Visible directory", QR_VISDIR); + } + 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); + attr->QRflags = set_room_attr(ipc, attr->QRflags, "Automatically make all messages anonymous", QR_ANONONLY); - if ((rflags & QR_ANONONLY) == 0) { - rflags = set_room_attr(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 { strprompt("Room aide (or 'none')", raide, 29); if (!strcasecmp(raide, "none")) { strcpy(raide, ""); - strcpy(buf, "200"); + break; } else { - snprintf(buf, sizeof buf, "QUSR %s", raide); - serv_puts(buf); - serv_gets(buf); - if (buf[0] != '2') - scr_printf("%s\n", &buf[4]); + r = CtdlIPCQueryUsername(ipc, raide, buf); + if (r / 100 != 2) + scr_printf("%s\n", buf); } - } while (buf[0] != '2'); + } while (r / 100 != 2); + /* FIXME: Duplicate code??? */ if (!strcasecmp(raide, "none")) { strcpy(raide, ""); } - /* 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" @@ -525,143 +559,179 @@ void editthisroom(void) "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 */ scr_printf("Save changes (y/n)? "); if (yesno() == 1) { - snprintf(buf, sizeof buf, "SETA %s", raide); - serv_puts(buf); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); + r = CtdlIPCSetRoomAide(ipc, raide, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); } - snprintf(buf, sizeof buf, "SPEX room|%d|%d", - expire_mode, expire_value); - serv_puts(buf); - serv_gets(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", - rname, rpass, rdir, rflags, rbump, rfloor, - rorder); - serv_puts(buf); - serv_gets(buf); - scr_printf("%s\n", &buf[4]); - if (buf[0] == '2') - dotgoto(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 ungoto(void) +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 (strlen(towhere) == 0) + { + 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], 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]; - if (uglistsize == 0) - return; - snprintf(buf, sizeof buf, "GOTO %s", uglist[uglistsize-1]); - serv_puts(buf); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); + struct ctdlipcroom *rret = NULL; /* ignored */ + int r; + + if (uglistsize == 0) + return; + + 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]); - serv_puts(buf); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); + r = CtdlIPCSetLastRead(ipc, uglistlsn[uglistsize-1], buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); } - safestrncpy (buf, uglist[uglistsize-1], sizeof(buf)); - uglistsize--; - free(uglist[uglistsize]); - dotgoto(buf, 0, 1); /* Don't queue ungoto info or we end up in a loop */ + 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); } -/* Here's the code for simply transferring the file to the client, - * for folks who have their own clientware. It's a lot simpler than - * the [XYZ]modem code below... - * (This function assumes that a download file is already open on the server) +/* + * saves filelen bytes from file at pathname */ -void download_to_local_disk(char *supplied_filename, long total_bytes) +int save_buffer(void *file, size_t filelen, const char *pathname) { - char buf[SIZ]; - char dbuf[4096]; - long transmitted_bytes = 0L; - long aa, bb; - FILE *savefp; - int broken = 0; - int packet; - char filename[SIZ]; + size_t block = 0; + size_t bytes_written = 0; + FILE *fp; - strcpy(filename, supplied_filename); - if (strlen(filename) == 0) { - newprompt("Filename: ", filename, 250); + fp = fopen(pathname, "w"); + if (!fp) { + err_printf("Cannot open '%s': %s\n", pathname, strerror(errno)); + return 0; } + do { + block = fwrite(file + bytes_written, 1, + filelen - bytes_written, fp); + bytes_written += block; + } while (errno == EINTR && bytes_written < filelen); + fclose(fp); - scr_printf("Enter the name of the directory to save '%s'\n" - "to, or press return for the current directory.\n", filename); - newprompt("Directory: ", dbuf, sizeof dbuf); - if (strlen(dbuf) == 0) - strcpy(dbuf, "."); - strcat(dbuf, "/"); - strcat(dbuf, filename); - - savefp = fopen(dbuf, "w"); - if (savefp == NULL) { - scr_printf("Cannot open '%s': %s\n", dbuf, strerror(errno)); - /* close the download file at the server */ - serv_puts("CLOS"); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); - } - return; + if (bytes_written < filelen) { + err_printf("Trouble saving '%s': %s\n", pathname, + strerror(errno)); + return 0; } - progress(0, total_bytes); - while ((transmitted_bytes < total_bytes) && (broken == 0)) { - bb = total_bytes - transmitted_bytes; - aa = ((bb < 4096) ? bb : 4096); - snprintf(buf, sizeof buf, "READ %ld|%ld", transmitted_bytes, aa); - serv_puts(buf); - serv_gets(buf); - if (buf[0] != '6') { - scr_printf("%s\n", &buf[4]); - return; - } - packet = extract_int(&buf[4], 0); - serv_read(dbuf, packet); - if (fwrite(dbuf, packet, 1, savefp) < 1) - broken = 1; - transmitted_bytes = transmitted_bytes + (long) packet; - progress(transmitted_bytes, total_bytes); - } - fclose(savefp); - /* close the download file at the server */ - serv_puts("CLOS"); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); - } - return; + return 1; +} + + +/* + * Save supplied_filename in dest directory; gets the name only + */ +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); } @@ -670,75 +740,59 @@ void download_to_local_disk(char *supplied_filename, long total_bytes) * function determines which protocol to use. * proto - 0 = paginate, 1 = xmodem, 2 = raw, 3 = ymodem, 4 = zmodem, 5 = save */ -void download(int proto) +void download(CtdlIPC *ipc, int proto) { char buf[SIZ]; - char filename[SIZ]; - char tempname[SIZ]; + char filename[PATH_MAX]; + char tempname[PATH_MAX]; char transmit_cmd[SIZ]; - long total_bytes = 0L; - char dbuf[4096]; - long transmitted_bytes = 0L; - long aa, bb; - int packet; FILE *tpipe = NULL; int broken = 0; + int r; + void *file = NULL; /* The downloaded file */ + size_t filelen = 0L; /* The downloaded file length */ if ((room_flags & QR_DOWNLOAD) == 0) { scr_printf("*** You cannot download from this room.\n"); return; } - newprompt("Enter filename: ", filename, 255); + newprompt("Enter filename: ", filename, PATH_MAX); - snprintf(buf, sizeof buf, "OPEN %s", filename); - serv_puts(buf); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); + /* 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, 0, progress, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); + return; + } + save_buffer(file, (size_t)extract_long(buf, 0), tempname); + free(file); return; } - total_bytes = extract_long(&buf[4], 0); - /* Save to local disk, for folks with their own copy of the client */ - if (proto == 5) { - download_to_local_disk(filename, total_bytes); + r = CtdlIPCFileDownload(ipc, filename, &file, 0, progress, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); return; } + filelen = extract_unsigned_long(buf, 0); /* Meta-download for public clients */ - scr_printf("Fetching file from Citadel server...\n"); + /* scr_printf("Fetching file from Citadel server...\n"); */ mkdir(tempdir, 0700); snprintf(tempname, sizeof tempname, "%s/%s", tempdir, filename); tpipe = fopen(tempname, "wb"); - while ((transmitted_bytes < total_bytes) && (broken == 0)) { - progress(transmitted_bytes, total_bytes); - bb = total_bytes - transmitted_bytes; - aa = ((bb < 4096) ? bb : 4096); - snprintf(buf, sizeof buf, "READ %ld|%ld", transmitted_bytes, aa); - serv_puts(buf); - serv_gets(buf); - if (buf[0] != '6') { - scr_printf("%s\n", &buf[4]); - } - packet = extract_int(&buf[4], 0); - serv_read(dbuf, packet); - if (fwrite(dbuf, packet, 1, tpipe) < 1) { - broken = 1; - } - transmitted_bytes = transmitted_bytes + (long) packet; + if (fwrite(file, filelen, 1, tpipe) < filelen) { + /* FIXME: restart syscall on EINTR */ + broken = 1; } fclose(tpipe); - progress(transmitted_bytes, total_bytes); - - /* close the download file at the server */ - serv_puts("CLOS"); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); - } + if (file) free(file); if (proto == 0) { + /* FIXME: display internally instead */ snprintf(transmit_cmd, sizeof transmit_cmd, "SHELL=/dev/null; export SHELL; TERM=dumb; export TERM; exec more -d <%s", tempname); @@ -750,6 +804,7 @@ void download(int proto) else if (proto == 4) snprintf(transmit_cmd, sizeof transmit_cmd, "exec sz %s", tempname); else + /* FIXME: display internally instead */ snprintf(transmit_cmd, sizeof transmit_cmd, "exec cat %s", tempname); screen_reset(); @@ -760,22 +815,22 @@ void download(int proto) /* clean up the temporary directory */ nukedir(tempdir); - scr_putc(7); + ctdl_beep(); /* Beep beep! */ } /* * read directory of this room */ -void roomdir(void) +void roomdir(CtdlIPC *ipc) { char flnm[SIZ]; char flsz[32]; char comment[SIZ]; char buf[SIZ]; - serv_puts("RDIR"); - serv_gets(buf); + CtdlIPC_putline(ipc, "RDIR"); + CtdlIPC_getline(ipc, buf); if (buf[0] != '1') { pprintf("%s\n", &buf[4]); return; @@ -785,7 +840,7 @@ void roomdir(void) extract(flnm, &buf[4], 1); pprintf("\nDirectory of %s on %s\n", flnm, comment); pprintf("-----------------------\n"); - while (serv_gets(buf), strcmp(buf, "000")) { + while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) { extract(flnm, buf, 0); extract(flsz, buf, 1); extract(comment, buf, 2); @@ -801,64 +856,50 @@ void roomdir(void) /* * add a user to a private room */ -void invite(void) +void invite(CtdlIPC *ipc) { - char aaa[31], bbb[SIZ]; - - /* Because kicking people out of public rooms now sets a LOCKOUT - * flag, we need to be able to invite people into public rooms - * in order to let them back in again. - * - cough - */ - - /* - * if ((room_flags & QR_PRIVATE)==0) { - * scr_printf("This is not a private room.\n"); - * return; - * } - */ + char username[USERNAME_SIZE]; + char buf[SIZ]; + int r; /* IPC response code */ - newprompt("Name of user? ", aaa, 30); - if (aaa[0] == 0) + newprompt("Name of user? ", username, USERNAME_SIZE); + if (username[0] == 0) return; - snprintf(bbb, sizeof bbb, "INVT %s", aaa); - serv_puts(bbb); - serv_gets(bbb); - scr_printf("%s\n", &bbb[4]); + r = CtdlIPCInviteUserToRoom(ipc, username, buf); + scr_printf("%s\n", buf); } /* * kick a user out of a room */ -void kickout(void) +void kickout(CtdlIPC *ipc) { - char username[31], cmd[SIZ]; + char username[USERNAME_SIZE]; + char buf[SIZ]; + int r; /* IPC response code */ - newprompt("Name of user? ", username, 30); - if (strlen(username) == 0) { + newprompt("Name of user? ", username, USERNAME_SIZE); + if (username[0] == 0) return; - } - snprintf(cmd, sizeof cmd, "KICK %s", username); - serv_puts(cmd); - serv_gets(cmd); - scr_printf("%s\n", &cmd[4]); + r = CtdlIPCKickoutUserFromRoom(ipc, username, buf); + scr_printf("%s\n", buf); } /* * aide command: kill the current room */ -void killroom(void) +void killroom(CtdlIPC *ipc) { char aaa[100]; + int r; - serv_puts("KILL 0"); - serv_gets(aaa); - if (aaa[0] != '2') { - scr_printf("%s\n", &aaa[4]); + r = CtdlIPCDeleteRoom(ipc, 0, aaa); + if (r / 100 != 2) { + scr_printf("%s\n", aaa); return; } @@ -866,51 +907,48 @@ void killroom(void) if (yesno() == 0) return; - serv_puts("KILL 1"); - serv_gets(aaa); - scr_printf("%s\n", &aaa[4]); - if (aaa[0] != '2') + r = CtdlIPCDeleteRoom(ipc, 1, aaa); + scr_printf("%s\n", aaa); + if (r / 100 != 2) return; - dotgoto("_BASEROOM_", 0, 0); + dotgoto(ipc, "_BASEROOM_", 0, 0); } -void forget(void) +void forget(CtdlIPC *ipc) { /* forget the current room */ - char cmd[SIZ]; + char buf[SIZ]; scr_printf("Are you sure you want to forget this room? "); if (yesno() == 0) return; - serv_puts("FORG"); - serv_gets(cmd); - if (cmd[0] != '2') { - scr_printf("%s\n", &cmd[4]); + if (CtdlIPCForgetRoom(ipc, buf) / 100 != 2) { + scr_printf("%s\n", buf); return; } /* now return to the lobby */ - dotgoto("_BASEROOM_", 0, 0); + dotgoto(ipc, "_BASEROOM_", 0, 0); } /* * create a new room */ -void entroom(void) +void entroom(CtdlIPC *ipc) { - char cmd[SIZ]; + char buf[SIZ]; char new_room_name[ROOMNAMELEN]; int new_room_type; char new_room_pass[10]; int new_room_floor; int a, b; + int r; /* IPC response code */ - serv_puts("CRE8 0"); - serv_gets(cmd); - - if (cmd[0] != '2') { - scr_printf("%s\n", &cmd[4]); + /* Check permission to create room */ + r = CtdlIPCCreateRoom(ipc, 0, "", 1, "", 0, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); return; } @@ -924,9 +962,9 @@ void entroom(void) } } - new_room_floor = select_floor((int) curr_floor); + new_room_floor = select_floor(ipc, (int) curr_floor); - IFNEXPERT formout("roomaccess"); + IFNEXPERT formout(ipc, "roomaccess"); do { scr_printf("Help\n<1>Public room\n<2>Guess-name room\n" "<3>Passworded room\n<4>Invitation-only room\n" @@ -937,10 +975,10 @@ void entroom(void) } while (((b < '1') || (b > '5')) && (b != '?')); if (b == '?') { scr_printf("?\n"); - formout("roomaccess"); + formout(ipc, "roomaccess"); } } while ((b < '1') || (b > '5')); - b = b - 48; + b -= '0'; /* Portable */ scr_printf("%d\n", b); new_room_type = b - 1; if (new_room_type == 2) { @@ -968,65 +1006,81 @@ void entroom(void) return; } - snprintf(cmd, sizeof cmd, "CRE8 1|%s|%d|%s|%d", new_room_name, - new_room_type, new_room_pass, new_room_floor); - serv_puts(cmd); - serv_gets(cmd); - if (cmd[0] != '2') { - scr_printf("%s\n", &cmd[4]); + r = CtdlIPCCreateRoom(ipc, 1, new_room_name, new_room_type, + new_room_pass, new_room_floor, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); return; } /* command succeeded... now GO to the new room! */ - dotgoto(new_room_name, 0, 0); + dotgoto(ipc, new_room_name, 0, 0); } -void readinfo(void) +void readinfo(CtdlIPC *ipc) { /* read info file for current room */ - char cmd[SIZ]; + char buf[SIZ]; + char raide[64]; + int r; /* IPC response code */ + char *text = NULL; + + /* Name of currernt room aide */ + r = CtdlIPCGetRoomAide(ipc, buf); + if (r / 100 == 2) + safestrncpy(raide, buf, sizeof raide); + else + strcpy(raide, ""); - snprintf(cmd, sizeof cmd, "RINF"); - serv_puts(cmd); - serv_gets(cmd); + if (strlen(raide) > 0) + scr_printf("Room aide is %s.\n\n", raide); - if (cmd[0] != '1') { + r = CtdlIPCRoomInfo(ipc, &text, buf); + if (r / 100 != 1) return; - } - fmout(screenwidth, NULL, NULL, - ((userflags & US_PAGINATOR) ? 1 : 0), screenheight, 0, 1); + if (text) { + fmout(screenwidth, NULL, text, NULL, + ((userflags & US_PAGINATOR) ? 1 : 0), screenheight, + (*raide) ? 2 : 0, 1); + free(text); + } } /* * ho knows room... */ -void whoknows(void) +void whoknows(CtdlIPC *ipc) { char buf[SIZ]; - serv_puts("WHOK"); - serv_gets(buf); - if (buf[0] != '1') { - pprintf("%s\n", &buf[5]); + char *listing = NULL; + int r; + + r = CtdlIPCWhoKnowsRoom(ipc, &listing, buf); + if (r / 100 != 1) { + pprintf("%s\n", buf); return; } - while (serv_gets(buf), strncmp(buf, "000", 3)) { + while (strlen(listing) > 0) { + extract_token(buf, listing, 0, '\n'); + remove_token(listing, 0, '\n'); if (sigcaught == 0) pprintf("%s\n", buf); } + free(listing); } -void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd) +void do_edit(CtdlIPC *ipc, + char *desc, char *read_cmd, char *check_cmd, char *write_cmd) { FILE *fp; char cmd[SIZ]; int b, cksum, editor_exit; - - if (strlen(editor_path) == 0) { + if (strlen(editor_paths[0]) == 0) { scr_printf("Do you wish to re-enter %s? ", desc); if (yesno() == 0) return; @@ -1035,19 +1089,19 @@ void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd) fp = fopen(temp, "w"); fclose(fp); - serv_puts(check_cmd); - serv_gets(cmd); + CtdlIPC_putline(ipc, check_cmd); + CtdlIPC_getline(ipc, cmd); if (cmd[0] != '2') { scr_printf("%s\n", &cmd[4]); return; } - if (strlen(editor_path) > 0) { - serv_puts(read_cmd); - serv_gets(cmd); + if (strlen(editor_paths[0]) > 0) { + CtdlIPC_putline(ipc, read_cmd); + CtdlIPC_getline(ipc, cmd); if (cmd[0] == '1') { fp = fopen(temp, "w"); - while (serv_gets(cmd), strcmp(cmd, "000")) { + while (CtdlIPC_getline(ipc, cmd), strcmp(cmd, "000")) { fprintf(fp, "%s\n", cmd); } fclose(fp); @@ -1056,33 +1110,33 @@ void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd) cksum = file_checksum(temp); - if (strlen(editor_path) > 0) { + if (strlen(editor_paths[0]) > 0) { char tmp[SIZ]; snprintf(tmp, sizeof tmp, "WINDOW_TITLE=%s", desc); putenv(tmp); + screen_reset(); + sttybbs(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); + scr_printf("Executed %s\n", editor_paths[0]); sttybbs(0); screen_set(); } else { scr_printf("Entering %s. " "Press return twice when finished.\n", desc); fp = fopen(temp, "r+"); - citedit(fp); + citedit(ipc, fp); fclose(fp); } @@ -1091,8 +1145,8 @@ void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd) } else { - serv_puts(write_cmd); - serv_gets(cmd); + CtdlIPC_putline(ipc, write_cmd); + CtdlIPC_getline(ipc, cmd); if (cmd[0] != '4') { scr_printf("%s\n", &cmd[4]); return; @@ -1101,87 +1155,83 @@ void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd) fp = fopen(temp, "r"); while (fgets(cmd, SIZ - 1, fp) != NULL) { cmd[strlen(cmd) - 1] = 0; - serv_puts(cmd); + CtdlIPC_putline(ipc, cmd); } fclose(fp); - serv_puts("000"); + CtdlIPC_putline(ipc, "000"); } unlink(temp); } -void enterinfo(void) +void enterinfo(CtdlIPC *ipc) { /* edit info file for current room */ - do_edit("the Info file for this room", "RINF", "EINF 0", "EINF 1"); + do_edit(ipc, "the Info file for this room", "RINF", "EINF 0", "EINF 1"); } -void enter_bio(void) +void enter_bio(CtdlIPC *ipc) { char cmd[SIZ]; snprintf(cmd, sizeof cmd, "RBIO %s", fullname); - do_edit("your Bio", cmd, "NOOP", "EBIO"); + do_edit(ipc, "your Bio", cmd, "NOOP", "EBIO"); } /* * create a new floor */ -void create_floor(void) +void create_floor(CtdlIPC *ipc) { char buf[SIZ]; char newfloorname[SIZ]; + int r; /* IPC response code */ - load_floorlist(); + load_floorlist(ipc); - serv_puts("CFLR xx|0"); - serv_gets(buf); - if (buf[0] != '2') { - scr_printf("%s\n", &buf[4]); + r = CtdlIPCCreateFloor(ipc, 0, "", buf); + if ( (r / 100 != 2) && (r != ERROR + ILLEGAL_VALUE) ) { + scr_printf("%s\n", buf); return; } newprompt("Name for new floor: ", newfloorname, 255); - snprintf(buf, sizeof buf, "CFLR %s|1", newfloorname); - serv_puts(buf); - serv_gets(buf); - if (buf[0] == '2') { + if (!*newprompt) return; + r = CtdlIPCCreateFloor(ipc, 1, newfloorname, buf); + if (r / 100 == 2) { scr_printf("Floor has been created.\n"); } else { - scr_printf("%s\n", &buf[4]); + scr_printf("%s\n", buf); } - load_floorlist(); + load_floorlist(ipc); } /* * edit the current floor */ -void edit_floor(void) +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(); + load_floorlist(ipc); /* Fetch the expire policy (this will silently fail on old servers, * resulting in "default" policy) */ - serv_puts("GPEX floor"); - serv_gets(buf); - if (buf[0] == '2') { - expire_mode = extract_int(&buf[4], 0); - expire_value = extract_int(&buf[4], 1); - } + r = CtdlIPCGetMessageExpirationPolicy(ipc, 1, &ep, buf); /* Interact with the user */ + scr_printf("You are editing the floor called \"%s\"\n", + &floorlist[(int) curr_floor][0] ); strprompt("Floor name", &floorlist[(int) curr_floor][0], 255); /* 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 essage expire policy (? for list)", + ("Floor default message expire policy (? for list)", buf, 1); if (buf[0] == '?') { scr_printf("\n" @@ -1190,34 +1240,27 @@ void edit_floor(void) "2. Expire by message count\n" "3. Expire by message age\n"); } - } while ((buf[0] < 48) || (buf[0] > 51)); - expire_mode = buf[0] - 48; + } while ((buf[0] < '0') || (buf[0] > '3')); + 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 */ - snprintf(buf, sizeof buf, "SPEX floor|%d|%d", - expire_mode, expire_value); - serv_puts(buf); - serv_gets(buf); - - snprintf(buf, sizeof buf, "EFLR %d|%s", curr_floor, - &floorlist[(int) curr_floor][0]); - serv_puts(buf); - serv_gets(buf); - scr_printf("%s\n", &buf[4]); - load_floorlist(); + 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); } @@ -1226,12 +1269,12 @@ void edit_floor(void) /* * kill the current floor */ -void kill_floor(void) +void kill_floor(CtdlIPC *ipc) { int floornum_to_delete, a; char buf[SIZ]; - load_floorlist(); + load_floorlist(ipc); do { floornum_to_delete = (-1); scr_printf("(Press return to abort)\n"); @@ -1248,9 +1291,7 @@ void kill_floor(void) scr_printf("%s\n", &floorlist[a][0]); } } while (floornum_to_delete < 0); - snprintf(buf, sizeof buf, "KFLR %d|1", floornum_to_delete); - serv_puts(buf); - serv_gets(buf); - scr_printf("%s\n", &buf[4]); - load_floorlist(); + CtdlIPCDeleteFloor(ipc, 1, floornum_to_delete, buf); + scr_printf("%s\n", buf); + load_floorlist(ipc); }