]> code.citadel.org Git - citadel.git/blobdiff - citadel/messages.c
* Changed the comments at the beginning of each file to a consistent format
[citadel.git] / citadel / messages.c
index 22d2c49530eec481a104af9b3e5003433f6f32f6..27ff4968bc01a6c9963f857af969584c2dba8f65 100644 (file)
@@ -1,8 +1,11 @@
 /*
+ * $Id$
+ *
  * Citadel/UX message support routines
- * see copyright.doc for copyright information
+ * see copyright.txt for copyright information
  */
 
+#include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
-#include <time.h>
 #include <signal.h>
 #include <errno.h>
+#include <limits.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
+#include <sys/time.h>
+#include <stdarg.h>
 #include "citadel.h"
+#include "messages.h"
+#include "commands.h"
+#include "rooms.h"
+#include "tools.h"
+#ifndef HAVE_SNPRINTF
+#include "snprintf.h"
+#endif
 
 #define MAXWORDBUF 256
 #define MAXMSGS 512
@@ -25,20 +37,16 @@ struct cittext {
        char text[MAXWORDBUF];
        };
 
-long finduser();
-char inkey();
-void sttybbs();
-int struncmp();
-int fmout();
-int haschar();
-int checkpagin();
-void getline();
-void formout();
-int yesno();
-void newprompt();
-int file_checksum();
-void color();
-void do_edit();
+void sttybbs(int cmd);
+int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst);
+int haschar(char *st, int ch);
+int checkpagin(int lp, int pagin, int height);
+void getline(char *string, int lim);
+void formout(char *name);
+int yesno(void);
+void newprompt(char *prompt, char *str, int len);
+int file_checksum(char *filename);
+void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd);
 
 char reply_to[512];
 long msg_arr[MAXMSGS];
@@ -61,15 +69,16 @@ extern unsigned userflags;
 extern char sigcaught;
 extern char editor_path[];
 extern char printcmd[];
+extern int rc_allow_attachments;
+extern int rc_display_message_numbers;
+extern int rc_force_mail_prompts;
 
 extern int editor_pid;
 
-int lines_printed;
-
-void ka_sigcatch(void) {
+void ka_sigcatch(int signum) {
        char buf[256];
        alarm(S_KEEPALIVE);
-       signal(SIGALRM, (void *)ka_sigcatch);
+       signal(SIGALRM, ka_sigcatch);
        serv_puts("NOOP");
        serv_gets(buf);
        }
@@ -78,12 +87,12 @@ void ka_sigcatch(void) {
 /*
  * server keep-alive version of wait() (needed for external editor)
  */
-pid_t ka_wait(pid_t *kstatus)
+pid_t ka_wait(int *kstatus)
 {
        pid_t p;
 
        alarm(S_KEEPALIVE);
-       signal(SIGALRM, (void *)ka_sigcatch);
+       signal(SIGALRM, ka_sigcatch);
        do {
                errno = 0;
                p = wait(kstatus);
@@ -105,9 +114,9 @@ int ka_system(char *shc)
 
        childpid = fork();
        if (childpid < 0) {
-               color(1);
+               color(BRIGHT_RED);
                perror("Cannot fork");
-               color(7);
+               color(DIM_WHITE);
                return((pid_t)childpid);
                }
 
@@ -175,27 +184,18 @@ void add_word(struct cittext *textlist, char *wordbuf)
 
 
 /*
- * begin editing of an opened file pointed to by fp, beginning at position pos.
+ * begin editing of an opened file pointed to by fp
  */
-void citedit(FILE *fp, long int base_pos)
+void citedit(FILE *fp)
 {
        int a,prev,finished,b,last_space;
        int appending = 0;
        struct cittext *textlist = NULL;
        struct cittext *ptr;
        char wordbuf[MAXWORDBUF];
-       char buf[256];
-       long last_server_msg,now;
-
-       /*
-        * we're going to keep track of the last time we talked to
-        * the server, so we can periodically send keep-alive messages
-        * out so it doesn't time out.
-        */
-       time(&last_server_msg);
 
        /* first, load the text into the buffer */
-       fseek(fp,base_pos,0);
+       fseek(fp, 0L, 0);
        textlist = (struct cittext *)malloc(sizeof(struct cittext));
        textlist->next = NULL;
        strcpy(textlist->text,"");
@@ -211,40 +211,51 @@ void citedit(FILE *fp, long int base_pos)
                                add_word(textlist,"\n");
                                add_newline(textlist);
                                add_word(textlist,"");
-                               }
                        }
+               }
                else {
                        wordbuf[strlen(wordbuf)+1] = 0;
                        wordbuf[strlen(wordbuf)] = a;
-                       }
+               }
                if (strlen(wordbuf)+3 > screenwidth) {
                        add_word(textlist,wordbuf);
                        strcpy(wordbuf,"");
-                       }
-               prev = a;
                }
+               prev = a;
+       }
 
        /* get text */
        finished = 0;
        prev = (appending ? 13 : (-1));
        strcpy(wordbuf,"");
+       async_ka_start();
        do {
                a=inkey();
                if (a==10) a=13;
                if (a==9) a=32;
                if (a==127) a=8;
+
+
+       /******* new ***********/
+               if ((a>32)&&(a<127)&&(prev==13)) {
+                       add_word(textlist,"\n");
+                       printf(" ");
+               }
+       /***********************/
+
                if ((a==32)&&(prev==13)) {
                        add_word(textlist,"\n");
                        add_newline(textlist);
-                       }
+               }
+
                if (a==8) {
                        if (strlen(wordbuf)>0) {
                                wordbuf[strlen(wordbuf)-1] = 0;
                                putc(8,stdout);
                                putc(32,stdout);
                                putc(8,stdout);
-                               }
                        }
+               }
                else if (a==13) {
                        printf("\n");
                        if (strlen(wordbuf)==0) finished = 1;
@@ -255,16 +266,16 @@ void citedit(FILE *fp, long int base_pos)
                                        add_word(textlist,wordbuf);
                                        strcpy(wordbuf,&wordbuf[b+1]);
                                        b=0;
-                                       }
+                               }
                                add_word(textlist,wordbuf);
                                strcpy(wordbuf,"");
-                               }
                        }
+               }
                else {
                        putc(a,stdout);
                        wordbuf[strlen(wordbuf)+1] = 0;
                        wordbuf[strlen(wordbuf)] = a;
-                       }
+               }
                if ((strlen(wordbuf)+3) > screenwidth) {
                        last_space = (-1);
                        for (b=0; b<strlen(wordbuf); ++b)
@@ -276,58 +287,50 @@ void citedit(FILE *fp, long int base_pos)
                                        add_word(textlist,wordbuf);
                                        strcpy(wordbuf,&wordbuf[b+1]);
                                        b=0;
-                                       }
+                               }
                                for (b=0; b<strlen(wordbuf); ++b) {
                                        putc(8,stdout);
                                        putc(32,stdout);
                                        putc(8,stdout);
-                                       }
-                               printf("\n%s",wordbuf);
                                }
+                               printf("\n%s",wordbuf);
+                       }
                        else {
                                add_word(textlist,wordbuf);
                                strcpy(wordbuf,"");
                                printf("\n");
-                               }
                        }
+               }
                prev = a;
-
-               /* this check implements the server keep-alive */
-               time(&now);
-               if ( (now - last_server_msg) > S_KEEPALIVE ) {
-                       serv_puts("NOOP");
-                       serv_gets(buf);
-                       last_server_msg = now;
-                       }
-
-               } while (finished==0);
+       } while (finished==0);
+       async_ka_end();
 
        /* write the buffer back to disk */
-       fseek(fp,base_pos,0);
+       fseek(fp, 0L, 0);
        for (ptr=textlist; ptr!=NULL; ptr=ptr->next) {
                fprintf(fp,"%s",ptr->text);
                }
        putc(10,fp);
-       putc(0,fp);
+       fflush(fp);
+       ftruncate(fileno(fp), ftell(fp));
 
        /* and deallocate the memory we used */
        while (textlist!=NULL) {
                ptr=textlist->next;
                free(textlist);
                textlist=ptr;
-               }
        }
+}
 
 
-int read_message(long int num, char pagin)     /* Read a message from the server */
-                               /* message number */
+int read_message(long int num, char pagin) /* Read a message from the server */
+                                          /* message number */
                /* 0 = normal read, 1 = read with pagination, 2 = header */
 {
        char buf[256];
        char m_subject[256];
-       char from[256];
-       long now;
-       struct tm *tm;
+       char from[256], node[256], rfca[256];
+       char now[256];
        int format_type = 0;
        int fr = 0;
        int nhdr = 0;
@@ -347,11 +350,16 @@ int read_message(long int num, char pagin)        /* Read a message from the server */
                }
 
        strcpy(m_subject,"");
+       strcpy(reply_to, "nobody ... xxxxx");
+       strcpy(from, "");
+       strcpy(node, "");
+       strcpy(rfca, "");
+
        printf("\n");
        ++lines_printed;
        lines_printed = checkpagin(lines_printed,pagin,screenheight);
        printf(" ");
-       if (pagin == 1) color(3);
+       if (pagin == 1) color(BRIGHT_CYAN);
 
        if (pagin==2) {
                while(serv_gets(buf), strcmp(buf,"000")) {
@@ -367,52 +375,83 @@ int read_message(long int num, char pagin)        /* Read a message from the server */
                return(0);
                }
 
-       strcpy(reply_to,"nobody...xxxxx");
-       while(serv_gets(buf), struncmp(buf,"text",4)) {
-               if (!struncmp(buf,"nhdr=yes",8)) nhdr=1;
-               if (!struncmp(buf,"from=",5)) {
+       while(serv_gets(buf), strncasecmp(buf,"text",4)) {
+               if (!strncasecmp(buf,"nhdr=yes",8)) nhdr=1;
+               if (!strncasecmp(buf,"from=",5)) {
                        strcpy(from,&buf[5]);
                        }
                if (nhdr==1) buf[0]='_';
-               if (!struncmp(buf,"type=",5))
+               if (!strncasecmp(buf,"type=",5))
                        format_type=atoi(&buf[5]);
-               if (!struncmp(buf,"from=",5)) {
-                       printf("from %s ",&buf[5]);
+               if ((!strncasecmp(buf,"msgn=",5))&&(rc_display_message_numbers)) {
+                       color(DIM_WHITE);
+                       printf("[");
+                       color(BRIGHT_WHITE);
+                       printf("#%s",&buf[5]);
+                       color(DIM_WHITE);
+                       printf("] ");
+                       }
+               if (!strncasecmp(buf,"from=",5)) {
+                       color(DIM_WHITE);
+                       printf("from ");
+                       color(BRIGHT_CYAN);
+                       printf("%s ",&buf[5]);
                        }
-               if (!struncmp(buf,"subj=",5))
+               if (!strncasecmp(buf,"subj=",5))
                        strcpy(m_subject,&buf[5]);
-               if ((!struncmp(buf,"hnod=",5)) 
-                  && (strucmp(&buf[5],serv_info.serv_humannode)))
-                       printf("(%s) ",&buf[5]);
-               if ((!struncmp(buf,"room=",5))
-                  && (strucmp(&buf[5],room_name)))
-                       printf("in %s> ",&buf[5]);
-
-               if (!struncmp(buf,"node=",5)) {
+
+               if (!strncasecmp(buf,"rfca=",5)) {
+                       safestrncpy(rfca, &buf[5], sizeof(rfca) - 5);
+                       color(DIM_WHITE);
+                       printf("<");
+                       color(BRIGHT_BLUE);
+                       printf("%s",&buf[5]);
+                       color(DIM_WHITE);
+                       printf("> ");
+                       }
+               if ((!strncasecmp(buf,"hnod=",5)) 
+                  && (strcasecmp(&buf[5],serv_info.serv_humannode))
+                  && (strlen(rfca) == 0) ) {
+                       color(DIM_WHITE);
+                       printf("(");
+                       color(BRIGHT_WHITE);
+                       printf("%s",&buf[5]);
+                       color(DIM_WHITE);
+                       printf(") ");
+                       }
+               if ((!strncasecmp(buf,"room=",5))
+                  && (strcasecmp(&buf[5],room_name)) 
+                  && (strlen(rfca) == 0)) {
+                       color(DIM_WHITE);
+                       printf("in ");
+                       color(BRIGHT_MAGENTA);
+                       printf("%s> ",&buf[5]);
+                       }
+
+               if (!strncasecmp(buf,"node=",5)) {
+                       safestrncpy(node, &buf[5], sizeof(buf) - 5);
                        if ( (room_flags&QR_NETWORK)
-                          || ((strucmp(&buf[5],serv_info.serv_nodename)
-                          &&(strucmp(&buf[5],serv_info.serv_fqdn)))))
-                               {
-                               printf("@%s ",&buf[5]);
-                               }
-                       if ((!strucmp(&buf[5],serv_info.serv_nodename))
-                          ||(!strucmp(&buf[5],serv_info.serv_fqdn)))
+                          || ((strcasecmp(&buf[5],serv_info.serv_nodename)
+                          &&(strcasecmp(&buf[5],serv_info.serv_fqdn)))) ) 
                                {
-                               strcpy(reply_to,from);
-                               }
-                       else {
-                               sprintf(reply_to,"%s @ %s",from,&buf[5]);
+                               if (strlen(rfca) == 0) {
+                                       color(DIM_WHITE);
+                                       printf("@");
+                                       color(BRIGHT_YELLOW);
+                                       printf("%s ",&buf[5]);
                                }
                        }
+               }
 
-               if (!struncmp(buf,"rcpt=",5))
-                       printf("to %s ",&buf[5]);
-               if (!struncmp(buf,"time=",5)) {
-                       now=atol(&buf[5]);
-                       tm=(struct tm *)localtime(&now);
-                       strcpy(buf,asctime(tm)); buf[strlen(buf)-1]=0;
-                       strcpy(&buf[16],&buf[19]);
-                       printf("%s ",&buf[4]);
+               if (!strncasecmp(buf,"rcpt=",5)) {
+                       color(DIM_WHITE);
+                       printf("to ");
+                       color(BRIGHT_CYAN);
+                       printf("%s ",&buf[5]);
+                       }
+               if (!strncasecmp(buf,"time=",5)) {
+                       fmt_date(now, atol(&buf[5]));
+                       printf("%s ", now);
                        }
                }
 
@@ -425,7 +464,15 @@ int read_message(long int num, char pagin) /* Read a message from the server */
                        }
                }
        printf("\n");
-       if (pagin == 1 ) color(2);
+
+       if (strlen(rfca) > 0) {
+               strcpy(reply_to, rfca);
+       }
+       else {
+               snprintf(reply_to, sizeof(reply_to), "%s @ %s", from, node);
+       }
+
+       if (pagin == 1) color(BRIGHT_WHITE);
        ++lines_printed;
        lines_printed = checkpagin(lines_printed,pagin,screenheight);
 
@@ -456,7 +503,7 @@ int read_message(long int num, char pagin)  /* Read a message from the server */
        ++lines_printed;
        lines_printed = checkpagin(lines_printed,pagin,screenheight);
 
-       if (pagin == 1) color(7);
+       if (pagin == 1) color(DIM_WHITE);
        sttybbs(0);
        return(fr);
        }
@@ -495,7 +542,7 @@ void replace_string(char *filename, long int startpos)
                buf[strlen(buf)] = a;
                if ( strlen(buf) >= strlen(srch_str) ) {
                        ptr=&buf[strlen(buf)-strlen(srch_str)];
-                       if (!struncmp(ptr,srch_str,strlen(srch_str))) {
+                       if (!strncasecmp(ptr,srch_str,strlen(srch_str))) {
                                strcpy(ptr,rplc_str);
                                ++substitutions;
                                }
@@ -511,22 +558,22 @@ void replace_string(char *filename, long int startpos)
                }
        fseek(fp,wpos,0);
        if (strlen(buf)>0) fwrite((char *)buf,strlen(buf),1,fp);
-       putc(0,fp);
+       wpos = ftell(fp);
        fclose(fp);
+       truncate(filename, wpos);
        printf("<R>eplace made %d substitution(s).\n\n",substitutions);
        }
 
 
-int make_message(char *filename, char *recipient, int anon_type, int format_type, int mode)
-                       /* temporary file name */
-                       /* NULL if it's not mail */
-                       /* see MES_ types in header file */
-                
-         
+int make_message(char *filename,       /* temporary file name */
+               char *recipient,        /* NULL if it's not mail */
+               int anon_type,          /* see MES_ types in header file */
+               int format_type,
+               int mode)
 { 
        FILE *fp;
        int a,b,e_ex_code;
-       long now,beg;
+       long beg;
        char datestr[64];
        int cksum = 0;
 
@@ -535,9 +582,7 @@ int make_message(char *filename, char *recipient, int anon_type, int format_type
                mode=0;
                }
 
-       time(&now);
-       strcpy(datestr,asctime(localtime(&now)));
-       datestr[strlen(datestr)-1] = 0;
+       fmt_date(datestr, time(NULL));
 
        if (room_flags & QR_ANONONLY) {
                printf(" ****");
@@ -568,10 +613,9 @@ ME1:       switch(mode) {
 
           case 0:
                fp=fopen(filename,"r+");
-               citedit(fp,beg);
+               citedit(fp);
                fclose(fp);
                goto MECR;
-               break;
 
           case 1:
                fp=fopen(filename,"w");
@@ -614,21 +658,15 @@ MECR:     if (mode==2) {
                if (e_ex_code==0) goto MEFIN;
                goto MEABT2;
                }
-MECR1: printf("Entry cmd (? for options) -> ");
-MECR2: b=inkey();
-       if (b==NEXT_KEY) b='n';
-       if (b==STOP_KEY) b='s';
-       b=(b&127); b=tolower(b);
-       if (b=='?') {
-               printf("Help\n");
-               formout("saveopt");
-               goto MECR1;
-               }
-       if (b=='a') { printf("Abort\n");        goto MEABT;     }
-       if (b=='c') { printf("Continue\n");     goto ME1;       }
-       if (b=='s') { printf("Save message\n"); goto MEFIN;     } 
+
+       b = keymenu("Entry command (? for options)",
+               "<A>bort|<C>ontinue|<S>ave message|<P>rint formatted|"
+               "<R>eplace string|<H>old message");
+
+       if (b=='a') goto MEABT;
+       if (b=='c') goto ME1;
+       if (b=='s') goto MEFIN;
        if (b=='p') {
-               printf("Print formatted\n");
                printf(" %s from %s",datestr,fullname);
                if (strlen(recipient)>0) printf(" to %s",recipient);
                printf("\n");
@@ -643,15 +681,12 @@ MECR2:    b=inkey();
                goto MECR;
                }
        if (b=='r') {
-               printf("Replace string\n");
                replace_string(filename,0L);
                goto MECR;
                }
        if (b=='h') {
-               printf("Hold message\n");
                return(2);
                }
-       goto MECR2;
 
 MEFIN: return(0);
 
@@ -668,7 +703,13 @@ void transmit_message(FILE *fp)
 {
        char buf[256];
        int ch,a;
-       
+       long msglen;
+       time_t lasttick;
+
+       fseek(fp, 0L, SEEK_END);
+       msglen = ftell(fp);
+       rewind(fp);
+       lasttick = time(NULL);
        strcpy(buf,"");
        while (ch=getc(fp), (ch>=0)) {
                if (ch==10) {
@@ -692,8 +733,18 @@ void transmit_message(FILE *fp)
                                strcpy(buf,"");
                                }
                        }
+
+               if ( (time(NULL) - lasttick) > 2L ) {
+                       printf(" %3ld%% completed\r",
+                               ((ftell(fp) * 100L) / msglen) );
+                       fflush(stdout);
+                       lasttick = time(NULL);
+                       }
+
                }
        serv_puts(buf);
+       printf("                \r");
+       fflush(stdout);
        }
 
 
@@ -737,7 +788,7 @@ int entmsg(int is_reply, int c)
                                }
                        else {
                                printf("Enter recipient: ");
-                               getline(buf,299);
+                               getline(buf, 60);
                                if (strlen(buf)==0) return(1);
                                }
                        }
@@ -745,7 +796,7 @@ int entmsg(int is_reply, int c)
                }
 
        b=0;
-       if (room_flags&QR_ANON2) {
+       if (room_flags&QR_ANONOPT) {
                printf("Anonymous (Y/N)? ");
                if (yesno()==1) b=1;
                }
@@ -777,14 +828,10 @@ int entmsg(int is_reply, int c)
                }
 
 /* now put together the message */
-       a=make_message(temp,buf,b,0,c);
-       if (a!=0)
-       {
-          return(2);
-       }
+       if ( make_message(temp,buf,b,0,c) != 0 ) return(2);
 
 /* and send it to the server */
-       sprintf(cmd,"ENT0 1|%s|%d|%d",buf,b,mode);
+       sprintf(cmd,"ENT0 1|%s|%d|%d||",buf,b,mode);
        serv_puts(cmd);
        serv_gets(cmd);
        if (cmd[0]!='4') {
@@ -836,7 +883,13 @@ FILE *qfile,*tfile;
 char buf[128];
 int line,qstart,qend;
 
+       /* Unlink the second temp file as soon as it's opened, so it'll get
+        * deleted even if the program dies
+        */
        qfile = fopen(temp2,"r");
+       unlink(temp2);
+
+       /* Display the quotable text with line numbers added */
        line = 0;
        fgets(buf,128,qfile);
        while (fgets(buf,128,qfile)!=NULL) {
@@ -858,11 +911,36 @@ int line,qstart,qend;
        fprintf(tfile," \n");
        fclose(qfile);
        fclose(tfile);
-       unlink(temp2);
        chmod(temp,0666);
        }
 
 
+
+/*
+ * List the URL's which were embedded in the previous message
+ */
+void list_urls() {
+       int i;
+       char cmd[256];
+
+       if (num_urls == 0) {
+               printf("There were no URL's in the previous message.\n\n");
+               return;
+       }
+
+       for (i=0; i<num_urls; ++i) {
+               printf("%3d %s\n", i+1, urls[i]);
+       }
+
+       if((i = num_urls) != 1)
+               i = intprompt("Display which one", 1, 1, num_urls);
+
+       sprintf(cmd, rc_url_cmd, urls[i-1]);
+       system(cmd);
+       printf("\n");
+}
+
+
 void readmsgs(int c, int rdir, int q)  /* read contents of a room */
                /* 0=Read all  1=Read new  2=Read old 3=Read last q */
                /* 1=Forward (-1)=Reverse */
@@ -872,10 +950,12 @@ void readmsgs(int c, int rdir, int q)     /* read contents of a room */
        int hold_sw = 0;
        char arcflag = 0;
        char quotflag = 0;
-       char prtfile[16];
+       int hold_color = 0;
+       char prtfile[PATH_MAX];
        char pagin;
        char cmd[256];
-       char targ[20];
+       char targ[ROOMNAMELEN];
+       char filename[256];
 
        signal(SIGINT,SIG_IGN);
        signal(SIGQUIT,SIG_IGN);
@@ -883,7 +963,7 @@ void readmsgs(int c, int rdir, int q)       /* read contents of a room */
        if (c<0) b=(MAXMSGS-1);
        else b=0;
 
-       sprintf(prtfile,"/tmp/CPrt%d",getpid());
+       sprintf(prtfile, tmpnam(NULL));
 
        num_msgs = 0;
        strcpy(cmd,"MSGS ");
@@ -904,6 +984,11 @@ void readmsgs(int c, int rdir, int q)      /* read contents of a room */
                }
        else {
                while (serv_gets(cmd), strcmp(cmd,"000")) {
+                       if (num_msgs == MAXMSGS) {
+                               memcpy(&msg_arr[0], &msg_arr[1],
+                                       (sizeof(long) * (MAXMSGS - 1)) );
+                               --num_msgs;
+                               }
                        msg_arr[num_msgs++] = atol(cmd);
                        }
                }
@@ -920,17 +1005,23 @@ void readmsgs(int c, int rdir, int q)    /* read contents of a room */
 RAGAIN:                pagin=((arcflag==0)&&(quotflag==0)&&
                        (userflags & US_PAGINATOR)) ? 1 : 0;
 
-       /* if we're doing a quote, set the screenwidth to 72 temporarily */
+       /* If we're doing a quote, set the screenwidth to 72 temporarily */
                if (quotflag) {
                        hold_sw = screenwidth;
                        screenwidth = 72;
                        }
 
+       /* If printing or archiving, set the screenwidth to 80 temporarily */
+               if (arcflag) {
+                       hold_sw = screenwidth;
+                       screenwidth = 80;
+                       }
+
        /* now read the message... */
                e=read_message(msg_arr[a],pagin);
 
        /* ...and set the screenwidth back if we have to */
-               if (quotflag) {
+               if ((quotflag)||(arcflag)) {
                        screenwidth = hold_sw;
                        }
 RMSGREAD:      fflush(stdout);
@@ -938,14 +1029,16 @@ RMSGREAD:        fflush(stdout);
                if (quotflag) {
                        freopen("/dev/tty","r+",stdout);
                        quotflag=0;
+                       enable_color = hold_color;
                        process_quote();
                        }
                if (arcflag) {
                        freopen("/dev/tty","r+",stdout);
                        arcflag=0;
+                       enable_color = hold_color;
                        f=fork();
                        if (f==0) {
-                               freopen(prtfile,"r",stdin);
+                               freopen(prtfile, "r", stdin);
                                sttybbs(SB_RESTORE);
                                ka_system(printcmd);
                                sttybbs(SB_NO_INTR);
@@ -958,59 +1051,111 @@ RMSGREAD:       fflush(stdout);
                        printf("Message printed.\n");
                        }
                if (e==3) return;
-               if ((userflags&US_NOPROMPT)||(e==2)) e='n';
+               if ( ((userflags&US_NOPROMPT)||(e==2)) 
+                  && (((room_flags&QR_MAILBOX)==0)
+                    ||(rc_force_mail_prompts==0))  ) {
+                       e='n';
+                       }
                else {
-                       printf("(%d) ",num_msgs-a-1);
-                       if (is_mail==1) printf("<R>eply ");
-                       if (strlen(printcmd)>0) printf("<P>rint ");
-               printf("<B>ack <A>gain <Q>uote <H>eader <N>ext <S>top -> ");
+                       color(DIM_WHITE);
+                       printf("(");
+                       color(BRIGHT_WHITE);
+                       printf("%d",num_msgs-a-1);
+                       color(DIM_WHITE);
+                       printf(") ");
+
+                       keyopt("<B>ack <A>gain <Q>uote <R>eply <N>ext <S>top ");
+                       if (rc_url_cmd[0] && num_urls) keyopt("<U>RL View ");
+                       keyopt("<?>Help/others -> ");
+                       
                        do {
                                lines_printed = 2;
                                e=(inkey()&127); e=tolower(e);
 /* return key same as <N> */   if (e==13) e='n';
-/* del/move for aides only */  if (!is_room_aide) if ((e=='d')||(e=='m')) e=0;
+/* space key same as <N> */    if (e==32) e='n';
+/* del/move for aides only */  if ((!is_room_aide)
+                                   &&((room_flags&QR_MAILBOX)==0)) {
+                                       if ((e=='d')||(e=='m')||(e=='c')) e=0;
+                                       }
 /* print only if available */  if ((e=='p')&&(strlen(printcmd)==0)) e=0;
-/* can't move from Mail> */    if ((e=='m')&&(is_mail==1)) e=0;
-/* can't reply in public rms */        if ((e=='r')&&(is_mail!=1)) e=0;
+/* can't file if not allowed */        if ((e=='f')&&(rc_allow_attachments==0)) e=0;
+/* link only if browser avail*/        if ((e=='u')&&(strlen(rc_url_cmd)==0)) e=0;
                                } while((e!='a')&&(e!='n')&&(e!='s')
                                        &&(e!='d')&&(e!='m')&&(e!='p')
                                        &&(e!='q')&&(e!='b')&&(e!='h')
-                                       &&(e!='r'));
+                                       &&(e!='r')&&(e!='f')&&(e!='?')
+                                       &&(e!='u')&&(e!='c'));
                        switch(e) {
                                case 's':       printf("Stop\r");       break;
                                case 'a':       printf("Again\r");      break;
                                case 'd':       printf("Delete\r");     break;
                                case 'm':       printf("Move\r");       break;
+                               case 'c':       printf("Copy\r");       break;
                                case 'n':       printf("Next\r");       break;
                                case 'p':       printf("Print\r");      break;
                                case 'q':       printf("Quote\r");      break;
                                case 'b':       printf("Back\r");       break;
                                case 'h':       printf("Header\r");     break;
                                case 'r':       printf("Reply\r");      break;
+                               case 'f':       printf("File\r");       break;
+                               case 'u':       printf("URL's\r");      break;
+                               case '?':       printf("? <help>\r");   break;
                                }
                        if (userflags & US_DISAPPEAR)
-                               printf("%75s\r","");
+                               printf("\r%79s\r","");
                        else
                                printf("\n");
                        fflush(stdout);
                        }
                switch(e) {
+                  case '?':    printf("Options available here:\n");
+                               printf(" ?  Help (prints this message)\n");
+                               printf(" S  Stop reading immediately\n");
+                               printf(" A  Again (repeats last message)\n");
+                               printf(" N  Next (continue with next message)\n");
+                               printf(" B  Back (go back to previous message)\n");
+                               if ((is_room_aide)
+                                   ||(room_flags&QR_MAILBOX)) {
+                                       printf(" D  Delete this message\n");
+                                       printf(" M  Move message to another room\n");
+                                       printf(" C  Copy message to another room\n");
+                                       }
+                               if (strlen(printcmd)>0)
+                                       printf(" P  Print this message\n");
+                               printf(" Q  Quote portions of this message for your next post\n");
+                               printf(" H  Headers (display message headers only)\n");
+                               if (is_mail)
+                                       printf(" R  Reply to this message\n");
+                               if (rc_allow_attachments)
+                                       printf(" F  (save attachments to a file)\n");
+                               if (strlen(rc_url_cmd)>0)
+                                       printf(" U  (list URL's for display)\n");
+                               printf("\n");
+                               goto RMSGREAD;
                   case 'p':    fflush(stdout);
                                freopen(prtfile,"w",stdout);
                                arcflag = 1;
+                               hold_color = enable_color;
+                               enable_color = 0;
                                goto RAGAIN;
                   case 'q':    fflush(stdout);
                                freopen(temp2,"w",stdout);
                                quotflag = 1;
+                               hold_color = enable_color;
+                               enable_color = 0;
                                goto RAGAIN;
                   case 's':    return;
                   case 'a':    goto RAGAIN;
                   case 'b':    a=a-(rdir*2);
                                break;
-                  case 'm':    newprompt("Enter target room: ",targ,19);
+                  case 'm':
+                  case 'c':
+                               newprompt("Enter target room: ",
+                                       targ,ROOMNAMELEN-1);
                                if (strlen(targ)>0) {
-                                       sprintf(cmd,"MOVE %ld|%s",
-                                               msg_arr[a],targ);
+                                       sprintf(cmd,"MOVE %ld|%s|%d",
+                                               msg_arr[a],targ,
+                                               (e=='c' ? 1 : 0) );
                                        serv_puts(cmd);
                                        serv_gets(cmd);
                                        printf("%s\n",&cmd[4]);
@@ -1021,6 +1166,21 @@ RMSGREAD:        fflush(stdout);
                                        }
                                if (cmd[0]!='2') goto RMSGREAD;
                                break;
+                  case 'f':    newprompt("Which section? ", filename,
+                                       ((sizeof filename) -1));
+                               snprintf(cmd, sizeof cmd,
+                                       "OPNA %ld|%s", msg_arr[a], filename);
+                               serv_puts(cmd);
+                               serv_gets(cmd);
+                               if (cmd[0]=='2') {
+                                       extract(filename, &cmd[4], 2);
+                                       download_to_local_disk(filename,
+                                               extract_int(&cmd[4], 0));
+                                       }
+                               else {
+                                       printf("%s\n",&cmd[4]);
+                                       }
+                               goto RMSGREAD;
                   case 'd':    printf("*** Delete this message? ");
                                if (yesno()==1) {
                                        sprintf(cmd,"DELE %ld",msg_arr[a]);
@@ -1037,6 +1197,8 @@ RMSGREAD: fflush(stdout);
                                goto RMSGREAD;
                   case 'r':    entmsg(1,(DEFAULT_ENTRY==46 ? 2 : 0));
                                goto RMSGREAD;
+                  case 'u':    list_urls();
+                               goto RMSGREAD;
                        }
                } /* end for loop */
        } /* end read routine */
@@ -1058,3 +1220,28 @@ void edit_system_message(char *which_message)
        sprintf(write_cmd, "EMSG %s", which_message);
        do_edit(desc, read_cmd, "NOOP", write_cmd);
        }
+
+
+
+
+/*
+ * Verify the message base
+ */
+void check_message_base(void) {
+       char buf[256];
+
+       printf("Please read the documentation before running this command.\n");
+       printf("Having done so, do you still want to check the message base? ");
+       if (yesno()==0) return;
+
+       serv_puts("FSCK");
+       serv_gets(buf);
+       if (buf[0] != '1') {
+               printf("%s\n", &buf[4]);
+               return;
+       }
+
+       while (serv_gets(buf), strcmp(buf, "000")) {
+               printf("%s\n", buf);
+       }
+}