/*
 * this file is a part of yabbs - yet another bulletin board system.
 * Copyright (C) 1993, 1994 Alex Wetmore.  
 * email: aw2t@andrew.cmu.edu
 * address: 6 rech ave
 *          oreland pa 19075
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * msgbase.c - part of the yabbs bulletin board package by alex wetmore
 *             see bbs.c for information on the system and copying.
 */

#include "bbsdefs.h"

/*
 * add a message to the current base at the end.  This procedure fills in
 * the length field and the date field.
 */

void addmsg(mrec msg) {
    bbs_addmsg(b, msg.to, msg.title, msg.msg);
}

/*
 * read the message <mnum> in the current base and print it to the users
 * screen.  If we are in base 0 (email) check to see if the message is to
 * the user, from the user, or if the user is 0 before allowing them to read
 * the message.  Return M_PRIVATE if it was private and the user couldn't read 
 * it, M_OOB if the message doesn't exist, M_DELETED if the message was 
 * deleted, M_ERR for another error, or the number of the message read.
 */

int readmsg(int mnum) {
    size_t      len;
    mrec        msg;
    char        temp[255];

    msg = getmsg(mnum);

    switch (errorcode) {
         case M_PRIVATE: sputs("p"); break;
         case M_DELETED: sputs("Deleted message\n"); break;
    }

    if (errorcode != M_OK) return errorcode;
    len = strlen(msg.msg);

    if (strstr(msg.title, "re: ") == NULL) {
        strcpy(replytitle, "re: ");
        strcat(replytitle, msg.title);
    } else
        strcpy(replytitle, msg.title);
    strcpy(replyto, msg.from);

    bbs_clrscr();
    sprintf(temp, "num: [%i]  to: [%s]  from: [%s]  time: [%s]\n", 
        mnum + 1, msg.to, msg.from, msg.time);
    sputs(temp);
    sprintf(temp, "title: [%s]  length: [%d bytes]", msg.title, len);
    sputs(temp);
    if (msg.deleted == 'Y') sputs_mime("  <Bold>deleted</Bold>"); 
    sputs("\n----\n");
    if (msg.deleted == 'Y') 
        sputs("\n[This message is marked for deletion]\n\n");
    sputs_process = FALSE; sputs(msg.msg); sputs_process = TRUE;
    return 0;
}

/*
 * do all of the stuff needed to open a new message base.
 */

void changebase(int b) {
    static unsigned oldlast, oldb;

    if (oldb > 26) oldb = 0;
    strcpy(replyto, "all");
    strcpy(replytitle, "<no title>");

    oldb = b;
    msgnum = bbs_getmsgnum(b);
    userinfo.lastmsg[b] = bbs_getlastmsg(b);
    oldlast = m = userinfo.lastmsg[b];
    if (m > msgnum || m < 0) {
        m = 0;
        userinfo.lastmsg[b] = m;
        sputs("\n\nThis board was erased or newly created.  Resetting your last");
        sputs("\nmessage information.\n");
    }
}

/*
 * read the next message in the current message base.  If we are at the last
 * message prompt the user to see if he wants to go on to the next message
 * base.  If the next message is private recurse until we find one that isn't.
 */

void readnext(void) {
    int     i, read, nextbase, cmd;
    static int skipping;

    if (++m > msgnum) {
        if (skipping) nextbase = TRUE;
        else {
            sputs("\nEnd of message base.\n");
            sputs("Read the next one that you are subscribed to? [ynFe?] ");
            i = FALSE;
            while (!i) {
                cmd = waitfor("feyn? \n\r");
                switch (cmd) {
                    case ' ':
                    case '\n':
                    case '\r':
                    case 'f': sputs("fast\n\n"); i = nextbase = skipping = TRUE; break;
                    case 'y': sputs("yes\n\n"); i = nextbase = TRUE; break;
                    case 'n': sputs("no\n\n"); i = TRUE; nextbase = FALSE; break;
                    case 'e': sputs("enter\n\n"); entermsg(""); nextbase = FALSE; i = TRUE; break;
                    case '?': {
                        sputs("help\n\nWould you like to read the next message base that you are subscribed to?\n");
                        sputs("  y)es (go to next base I am subscribed to)\n");
                        sputs("  n)o (stay in this base)\n");
                        sputs("  f)ast (go to next base with new messages)\n");
                        sputs("  e)nter a message\n\n");
                        sputs("Read the next one that you are subscribed to? [Fyn?] ");
                    }
                }
            }
        }
        if (nextbase) {
            i = b;
            while (!subcheck(++i) && (i < MBASES));
            if (subcheck(i)) {
                bbs_setlastmsg(b, userinfo.lastmsg[b]);
                b = i;
                changebase(b);
                if (m == msgnum) {
                    sputs("\nNo new messages in ");
                    sputs(base[b].title);
                    sputs(" (why not post one?)\n");
                    readnext();
                } else {
                    skipping = FALSE;
                    readmsg(++m);
                }
            } else {
                hion();
                sputs("\nThis is the last board in your subscription list.\n");
                hioff();
                m = msgnum;
                skipping = FALSE;
            }
        } else {
            m = msgnum;
            skipping = FALSE;
        }
    } else {    
        skipping = FALSE;
        /* skip until we find a public message or reach the end of the base */
        while ((read = (((readmsg(m) == M_PRIVATE)) && (m < msgnum)))) 
            m = m + 1;
        /* at the last message we have to check to see if it is public or   */
        /* private, and recurse into readnext if it is public               */
        if (m == msgnum) {
            if (read == -2) readnext();
        }
    }
}

/*
 * read the previous message.  Similar to readnext();
 */

void readprev(void) {
    if (--m < 0) {
        sputs("beginning of base\n");
        m = 0;
    } else if (readmsg(m) == M_PRIVATE)
        readprev();
}

/*
 * allow the user to enter a new message.  I wouldn't call this thing an
 * editor, but that is what it attempts to do.
 */

void entermsg(char *outfile) {
    char    edit[MAXMSGLINES][80], temp[255], work[255], line[255], c;
    mrec    msg, quote;
    int     x, y, z, i = 0, done = FALSE, abort = FALSE;
    FILE    *f;
    char    edbin[255];

    if (!getfromenv("editor", edbin)) *edbin = 0;
    else if (strcmp(edbin, "internal") == 0) *edbin = 0;

    if (*outfile == 0) {
        do {
            x = FALSE;
            sputs("\nEnter \"list\" to list all users, \"all\" to send to all users, \"q\" to cancel.\n\n");
            sprintf(temp, "to: [%s] ", replyto); sputs(temp);
            sgets(msg.to, 8);
            if (strcmp(msg.to, "q") == 0) {
                sputs("\nPosting canceled\n");
                return;
            }
            if (strcmp(msg.to, "") == 0) strcpy(msg.to, replyto);
            if (strcmp(msg.to, "list") == 0) {
                sputs("\n---- User list ----\n");
                listusers();
                sputs("----\n");
                x = TRUE;
            } else if ((strcmp(msg.to, "all") != 0) && (!finduser(msg.to))) {
                sputs("\nThere are no users with that name.  Enter the name \"all\" to send a");
                sputs("\nmessage to everyone.  Don't forget that messages aren't private.");
                sputs("\nIf you are replying to the last message that you read, you don't have");
                sputs("\nto specify a name, the message will be sent the writer of the message.\n\n");
                x = TRUE;
            } else if ((strcmp(msg.to, "all") == 0) && 
                       (b == 0)) {
                sputs("\nSorry, the email base is for private messages only.  Please try posting");
                sputs("\nin one of the public message bases.  Select 'b' at the message menu");
                sputs("\nto select another message base\n");
                x = TRUE;
            }
        } while (x);
        strcpy(msg.from, userinfo.name);
        sprintf(temp, "title: [%s] ", replytitle); sputs(temp); sgets(msg.title, 27);
        if (strcmp(msg.title, "") == 0) strcpy(msg.title, replytitle);
    }

    /* if edbin is 0 length then use the internal editor                    */
    if (edbin[0] != 0) {
        strcpy(work, bbs_itoa(pid));
        if (*outfile == 0) {
            if (ynprompt("Quote the current message? [yN] ", FALSE)) {
                quote = getmsg(m);
                if (errorcode == M_OK) {
                    strcpy(temp, F_EDTMP);
                    strcat(temp, work);
                    if ((f = fopen(temp, "w")) != NULL) {
                        fprintf(f, "In message %s, %s said:\n", 
                            quote.title, quote.from);
                        y = strlen(quote.msg);
                        done = FALSE;
                        for (x = 0, z = 0; (x < y) && (!done); x++) {
                            if (quote.msg[x] == '\n') {
                                line[z] = 0;
                                sprintf(temp, "%s\nquote this line? [yNq] ", line);
                                sputs(temp);
                                if ((c = lower(readc())) == 'y') {
                                    fprintf(f, "> %s\n", line);
                                } else if (c == 'q') {
                                    done = TRUE;
                                }
                                sputs("\r                       \r");
                                z = 0;
                            } else line[z++] = quote.msg[x];
                        }
                        fclose(f);
                    } else {
                        sputs("\n\nerror opening text file: "); sputs(temp);
                    }
                } else {
                    sputs("\n\nerror reading message to quote from\n");
                }
            }
        }
        done = FALSE;
        while (!done) {
            strcpy(temp, edbin);
            strcat(temp, " ");
            strcat(temp, F_EDTMP);
            strcat(temp, work);
            system(temp);
    
            bbs_clrscr();
            strcpy(temp, F_EDTMP);
            strcat(temp, work);
            if ((f = fopen(temp, "r")) == NULL) {
                strcpy(msg.msg, "\n");
            } else {
                for (x = 0; (!feof(f) && (x < MAXMSGBYTES - 5));) {
                    msg.msg[x++] = getc(f);
                }
                if (msg.msg[x - 1] != '\n') msg.msg[x++] = '\n'; 
                msg.msg[x] = 0;
                sputs(msg.msg);
            }
            if (x == MAXMSGBYTES) {
                sputs("\nmessage to big, not posting, max 99 lines\n");
                done = ynprompt("Scrap it? [yN] ", FALSE);
            } else {
                if (ynprompt("Post your message? [Yn] ", TRUE)) {
                    if (*outfile == 0) {
                        addmsg(msg);
                        /* HACK: we should ask the server */
                        msgnum++; 
                        if (f != NULL) fclose(f);
                        remove(temp);
                    } else {
                        rename(temp, outfile);
                        if ((f = fopen(outfile, "a")) != NULL) {
                            fprintf(f, "\n");
                            fclose(f);
                        }
                    }
                } else {
                    sputs("\n\nmessage not posted\n");
                    remove(temp);
                }
                done = TRUE;
            }
        }
    } else {
        for (x = 0; x < 26 * 80; x++) msg.msg[x] = 0;
        sputs("----\n");
        if (*outfile == 0) {
            sputs("Enter your message now.  You have a maximum of 99 lines.");
        } else {
            sputs("You have a maximum of 99 lines for this file.");
        }
        sputs("\nOn a blank line, /s = save, /q = quit (no save), /? = help\n----\n");
        while (!done) {
            sprintf(temp, "%2i: ", i);
            sputs(temp);
            readlww(temp, 75, FALSE);
            if (temp[0] == '/') {
                switch (lower(temp[1])) {
                    case 's' :  done = TRUE; break;
                    case 'q' :  if (ynprompt("\nAre you sure? [Ny] ", FALSE)) {
                                    abort = done = TRUE;
                                } break;
                    case 'l' :  sputs("\n---- Your Message ----\n");
                                for (x = 0; x < i; x++) {
                                    sprintf(temp, "%2i) %s", x, &edit[x][0]);
                                    sputs(temp);
                                }
                                sputs("----\n\n");
                                break;
                    case 'd' :  strmid(work, temp, 2, strlen(temp) - 2);
                                y = atoi(work);
                                if ((y >= 0) && (y < i)) {
                                    sprintf(temp, "\n%2i: %s", y, &edit[y][0]);
                                    sputs(temp);
                                    if (ynprompt("Are you sure you want to delete this line? [Ny] ", FALSE)) {
                                        for (x = y; x < i; x++)
                                            strcpy(&edit[x][0], &edit[x + 1][0]);
                                        i--;
                                    } else {
                                        sputs("Canceled.\n\n");
                                    }
                                } else {
                                    sputs("That line doesn't exist!\n");
                                }
                                break;
                    case 'r' :  strmid(work, temp, 2, strlen(temp) - 2);
                                y = atoi(work);
                                if ((y >= 0) && (y < i)) {
                                    sprintf(temp, "\nChanging line [%i], <cr> to cancel\n", y); sputs(temp);
                                    sprintf(temp, "ol: %s", &edit[y][0]); sputs(temp);
                                    sputs("nw: "); sgets(temp, 74);
                                    if (temp[0] == '\0') {
                                        sputs("Canceled.\n\n");
                                    } else {
                                        strcat(temp, "\n");
                                        strcpy(&edit[y][0], temp);
                                        sprintf(temp, "%2i: %s", y, &edit[y][0]);
                                        sputs(temp);
                                    }
                                } else sputs("That line doesn't exist!\n");
                                break;
                    case 'c' :  if (ynprompt("\nAre you sure? [Ny] ", FALSE)) {
                                    i = 0;
                                    strcpy(&edit[0][0], "");
                                } break;
                    case '?' :  sputs_mime(H_MSG); break;
                    default  :  sputs("unknown command!");
                }
            } else {
                strcat(temp, "\n");
                strcpy(&edit[i][0], temp);
                i++;
                if (i > MAXMSGLINES) sputs("\nEnd of buffer\n");
                if (i > MAXMSGLINES) i = MAXMSGLINES;
            }
        }
        if (!abort) {
            if (*outfile == 0) {
                for (x = 0; x < i; x++)
                    strcat(msg.msg, &edit[x][0]);
                addmsg(msg);
                /* HACK: this should ask the server */
                msgnum++; 
            } else {
                if ((f = fopen(outfile, "w")) == NULL) {
                    sputs("error opening plan for write\n");
                    killconnection(K_FERR);
                }
                for (x = 0; x < i; x++) {
                    fprintf(f, "%s", &edit[x][0]);
                }
                fclose(f);
            }
        }
    }
}

/*
 * show a list of message bases that the user has access to and allow them
 * to jump to a new one.
 */

void selectbase(void) {
    int     i, j;
    char    temp[80], keylist[80], ch;

    bbs_setlastmsg(b, userinfo.lastmsg[b]);
    for (j = 0; j <= MBASES; j++) keylist[j] = 0;
    j = 0;
    for (i = 0; i < MBASES; i++) {
        if (accesscheck(i)) {
            sprintf(temp, "%c) %s\n", (i + BASEOF), base[i].title);
            sputs(temp);
            keylist[j++] = lower((i + BASEOF));
        }
    }
    sputs("\nJust hit enter or space to cancel\n");
    sprintf(temp, "Which message base would you like to read? [%s] ", keylist);
    sputs(temp);
    keylist[j] = '\r'; keylist[j + 1] = '\n'; keylist[j + 2] = ' ';
    ch = upper(waitfor(keylist));
    if (ch <= ' ') return; else b = ch - BASEOF;
    writec(b + BASEOF); writec(')'); sputs(base[b].title);
    changebase(b);
}

/*
 * jump to a message with a specific message number.  If the message is
 * private leave them where they are.
 */

void jump2msg(void) {
    int     nm;
    char    temp[80];

    sputs("Just hit <enter> to cancel.\n");
    sprintf(temp, "Which message? [1-%i] ", msgnum + 1);
    sputs(temp); sgets(temp, 6); sputs("\n");
    if (strcmp(temp, "") != 0) {
        nm = atoi(temp) - 1;
        if (nm < 0) nm = 0;
        if (nm > msgnum) nm = msgnum;

        if (readmsg(nm) != M_PRIVATE) {
            m = nm;
        } else {
            sputs("That is a private message that you can't read.\n");
        }
    }
}

void cli_msgline(char *line, int type, void *null) {
    sputs(".");
    switch (type) {
        case ML_TO: strcpy(gmsg.to, line); break;
        case ML_FROM: strcpy(gmsg.from, line); break;
        case ML_TITLE: strcpy(gmsg.title, line); break;
        case ML_TIME: strcpy(gmsg.time, line); break;
        case ML_DELETED: gmsg.deleted = line[0]; break;
        case ML_LINE: strcat(gmsg.msg, line); strcat(gmsg.msg, "\n"); break;
    }
}

/*
 * get message number <mnum> and return it.
 */

mrec getmsg(int mnum) {
    strcpy(gmsg.msg, "");
    errorcode = bbs_getmsg(b, mnum, NULL);
    if (errorcode != M_PRIVATE) sputs("\n");
    return gmsg;
}

/*
 * get the header information for msg <mnum> and return it.
 * if <display> is set to true then the header info is displayed, otherwise
 * it is returned in a gmsg structure;
 */

mrec getmsghdr(int mnum) {
    hnum = -1;
    bbs_getmsghdr(b, mnum, NULL);
    return gmsg;
}

void printmsghdrs(int mnum1, int mnum2) {
    hnum = 0;
    if (b == 0) sputs("\rscanning . . .");
    bbs_getmsghdrs(b, mnum1, mnum2, NULL);
    if (b == 0) sputs("\r              \r");
}

void cli_msghdrline(int num, char *to, char *from, char *del, char *subject, 
    void *null) {
    char buf[255];

    if (hnum == -1) {
        strcpy(gmsg.to, to);
        strcpy(gmsg.from, from);
        strcpy(gmsg.title, subject);
        gmsg.deleted = del[0];
    } else {
        if (b == 0) sputs("\r              \r");
        sprintf(buf, "%c %4i: [%8s] to [%8s] - [%s]\n", 
            (m == num) ? '*' : ' ', num + 1, from, to, subject);
        sputs(buf);
        if (b == 0) sputs("\rscanning . . .");
    }       
}

/*
 * delete the message <mnum> from the data base.  Only allow deletion
 * if the user is sysop or owner.
 */

void deletemsg(int mnum, int sysoponly) {
    if (bbs_deletemsg(b, mnum) != M_OK) 
        sputs("\nYou don't have access to delete that message\n");
}

/*
 * find a message that is to the current user, from them, or just has text
 * that the user is looking for.
 */

void findmsg(void) {
    char    type, text[33], temp[80];
    mrec    msg;
    int     i, done;

    sputs("T)o you, F)rom you, P)hrase or C)ontinue? [tfpC] ");
    type = waitfor("tfpc\r \n");
    if ((type == 'c') || (type == '\r') || (type == ' ') || (type == '\n')) {
        sputs("con't ");
        type = lstype;
        strcpy(text, lstext);
        if (++m > msgnum) {
            sputs("\nThis is the last message.\n");
            m--;
            return;
        }
    } else {
        strcpy(text, "");
        m = 0;
    }
    lstype = type;
    switch (type) {
        case 't' :  done = FALSE;
                    sputs("to me\n\nSearching for messages to you . . . ");
                    for (i = m; ((i <= msgnum) && (!done)); i++) {
                        msg = getmsghdr(i);
                        if (errorcode == M_OK) {
                            if (strcmp(
                                 (char *) strlwr(msg.to), 
                                 (char *) strlwr(userinfo.name)) == 0) {
                                m = i;
                                sputs("found one!\n\n");
                                readmsg(m);
                                done = TRUE;
                            }
                        }
                    } break;
        case 'f' :  done = FALSE;
                    sputs("from me\n\nSearching for messages from you . . . ");
                    for (i = m; ((i <= msgnum) && (!done)); i++) {
                        msg = getmsghdr(i);
                        if (errorcode == M_OK) {
                            if (strcmp(
                                 (char *) strlwr(msg.from), 
                                 (char *) strlwr(userinfo.name)) == 0) {
                                m = i;
                                sputs("found one!\n\n");
                                readmsg(m);
                                done = TRUE;
                            }
                        }
                    } break;
        case 'p' :  done = FALSE;
                    if (strcmp(text, "") == 0) {
                        sputs("phrase\n\nWhat would you like to search for? ");
                        sgets(text, 32);
                    } else sputs("phrase\n");
                    sprintf(temp, "\nSearching for messages with [%s] in them . . . ", text);
                    sputs(temp);
                    for (i = m; ((i <= msgnum) && (!done)); i++) {
                        msg = getmsg(i);
                        if (errorcode == M_OK) {
                            if (strstr(
                                 (char *) strlwr(msg.msg), 
                                 (char *) strlwr(text)) != NULL) {
                                m = i;
                                sputs("found one!\n\n");
                                readmsg(m);
                                done = TRUE;
                            }
                        }
                    } break;
        case 0   :  
            sputs("\n\nhow can you continue something you haven't started?\n"); 
            done = TRUE;
            break;
        default  :  sputs("what?\n"); done = TRUE;
    }
    if (!done) {
        sputs("none found.\n");
    }
    strcpy(lstext, text);
}

/*
 * list all of the messages in the current base.  When done call jump2msg
 * to allow the user to jump to a new message.
 */

void listmsgs(void) {
    char    buf[80];
    int     i;

    sprintf(buf, "\n---- Message Listing for Base [%s] ----\n",
        base[b].title);
    sputs(buf);
    i = m - ((userinfo.scrlen == 0) ? 10 : (userinfo.scrlen / 2));
    if (i < 0) i = 0;
    printmsghdrs(i, msgnum);
    sputs("----\n");
    jump2msg();
}

void countnew(void) {
    char buf[255];
    int i, newmsgs;
    
    sputs("\n");
    /* private bases                                                */
    newmsgs = bbs_getmsgnum(0) - bbs_getlastmsg(0);
    if (newmsgs > 0) {
        sprintf(buf, "*** you have %i unread email message%c\n", newmsgs,
            (newmsgs == 1) ? ' ' : 's');
        sputs(buf);
    }

    /* public bases                                                 */
    newmsgs = 0;
    for (i = 0; i < MBASES; i++) {
        while (!subcheck(++i) && (i < MBASES));
        if (i == MBASES) break;

        newmsgs += bbs_getmsgnum(i) - bbs_getlastmsg(i);
    }
    if (newmsgs > 0) {
        sprintf(buf, "*** you have %i unread public message%c\n", newmsgs,
            (newmsgs == 1) ? ' ' : 's');
        sputs(buf);
    }
}

/*
 * the actual message menu.  Just put the thing on the screen and allow
 * people to pick and option, then call the appropriate procedure.  Really
 * simple.
 */

int domessages(void) {
    int     done = FALSE, bye = FALSE;
    char    cmd, prompt[255];

    b = 0;
    changebase(b);
    strcpy(replyto, "all");
    strcpy(replytitle, "<no title>");
    while (!done) {
        sputs("\n");
        if (!(userinfo.options & O_XPERT)) sputs_mime(MNU_MSG);
        if (m > userinfo.lastmsg[b]) userinfo.lastmsg[b] = m;
        sprintf(prompt, "base: [<Bold>%c) %s</Bold>]  last: [<Bold>%i</Bold>]  message: [<Bold>%i</Bold> of <Bold>%i</Bold>]<nl>messages: <Bold>[Npcebjsdufligq?]</Bold> ",
            (b + BASEOF), base[b].title, userinfo.lastmsg[b] + 1, m + 1, 
            msgnum + 1);
        sputs_mime(prompt);
        cmd = waitfor("n+\r\n p-cerjbsdufligq?");
        switch (cmd) {
            case '?'  : sputs("help\n\n"); sputs_mime(MNU_MSG); break;
            case 'n'  :
            case '+'  : 
            case '\n' :
            case '\r' :
            case ' '  : sputs("next\n\n"); readnext(); 
                        done = bye = FALSE; break;
            case 'p'  :
            case '-'  : sputs("previous\n\n"); readprev(); break;
            case 'c'  : sputs("current\n\n"); readmsg(m); break;
            case 'r'  : 
            case 'e'  : sputs("enter\n\n"); entermsg(""); break;
            case 'j'  : sputs("jump\n\n"); jump2msg(); break;
            case 'b'  : sputs("base\n\n"); selectbase(); break;
            case 's'  : sputs("subscriptions\n\n"); changesubs(); break;
            case 'd'  : sputs("delete\n\n"); deletemsg(m, TRUE); break;
            case 'f'  : sputs("find\n\n"); findmsg(); break;
            case 'u'  : sputs("users\n\n"); listusers(); break;
            case 'l'  : sputs("list\n\n"); listmsgs(); break;
            case 'i'  : sputs("info on user\n\n"); readplan(replyto);
                        break;
            case 'g'  : sputs("goodbye\n\n"); 
                        done = bye = ynprompt("Are you sure? [Yn] ", TRUE); 
                        break;
            case 'q'  : sputs("quit\n\n"); done = TRUE; bye = FALSE; break;
            default   : sputs("what?\n\n");
        }
    }
    bbs_setlastmsg(b, userinfo.lastmsg[b]);
    return bye;
}
