Tue Aug 18 00:42:33 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
[citadel.git] / citadel / messages.c
1 /*
2  * Citadel/UX message support routines
3  * see copyright.doc for copyright information
4  */
5
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 #include <string.h>
13 #include <time.h>
14 #include <signal.h>
15 #include <errno.h>
16 #include <sys/wait.h>
17 #include <sys/stat.h>
18 #include "citadel.h"
19 #include "messages.h"
20
21 #define MAXWORDBUF 256
22 #define MAXMSGS 512
23
24 struct cittext {
25         struct cittext *next;
26         char text[MAXWORDBUF];
27         };
28
29 long finduser(int file, char *name);
30 char inkey(void);
31 void sttybbs(int cmd);
32 int struncmp(char *lstr, char *rstr, int len);
33 int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst);
34 int haschar(char *st, int ch);
35 int checkpagin(int lp, int pagin, int height);
36 void getline(char *string, int lim);
37 void formout(char *name);
38 int yesno(void);
39 void newprompt(char *prompt, char *str, int len);
40 int file_checksum(char *filename);
41 void color(int colornum);
42 void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd);
43
44 char reply_to[512];
45 long msg_arr[MAXMSGS];
46 int num_msgs;
47 extern char room_name[];
48 extern unsigned room_flags;
49 extern long highest_msg_read;
50 extern struct CtdlServInfo serv_info;
51 extern char temp[];
52 extern char temp2[];
53 extern int screenwidth;
54 extern int screenheight;
55 extern long maxmsgnum;
56 extern char is_mail;
57 extern char is_aide;
58 extern char is_room_aide;
59 extern char fullname[];
60 extern char axlevel;
61 extern unsigned userflags;
62 extern char sigcaught;
63 extern char editor_path[];
64 extern char printcmd[];
65
66 extern int editor_pid;
67
68 int lines_printed;
69
70 void ka_sigcatch(void) {
71         char buf[256];
72         alarm(S_KEEPALIVE);
73         signal(SIGALRM, (void *)ka_sigcatch);
74         serv_puts("NOOP");
75         serv_gets(buf);
76         }
77
78
79 /*
80  * server keep-alive version of wait() (needed for external editor)
81  */
82 pid_t ka_wait(pid_t *kstatus)
83 {
84         pid_t p;
85
86         alarm(S_KEEPALIVE);
87         signal(SIGALRM, (void *)ka_sigcatch);
88         do {
89                 errno = 0;
90                 p = wait(kstatus);
91                 } while (errno==EINTR);
92         signal(SIGALRM,SIG_IGN);
93         alarm(0);
94         return(p);
95         }
96
97
98 /*
99  * version of system() that uses ka_wait()
100  */
101 int ka_system(char *shc)
102 {
103         pid_t childpid;
104         pid_t waitpid;
105         int retcode;
106
107         childpid = fork();
108         if (childpid < 0) {
109                 color(1);
110                 perror("Cannot fork");
111                 color(7);
112                 return((pid_t)childpid);
113                 }
114
115         if (childpid == 0) {
116                 execlp("/bin/sh","sh","-c",shc,NULL);
117                 exit(127);
118                 }
119
120         if (childpid > 0) {
121                 do {
122                         waitpid = ka_wait(&retcode);
123                         } while (waitpid != childpid);
124                 return(retcode);
125                 }
126
127         return(-1);
128         }
129
130
131
132 /*
133  * add a newline to the buffer...
134  */
135 void add_newline(struct cittext *textlist)
136 {
137         struct cittext *ptr;
138
139         ptr=textlist;
140         while (ptr->next != NULL) ptr = ptr->next;
141
142         while (ptr->text[strlen(ptr->text)-1]==32)
143                 ptr->text[strlen(ptr->text)-1] = 0;
144         /* strcat(ptr->text,"\n"); */
145
146         ptr->next = (struct cittext *)
147                 malloc(sizeof(struct cittext));
148         ptr = ptr->next;
149         ptr->next = NULL;
150         strcpy(ptr->text,"");
151         }
152
153
154 /*
155  * add a word to the buffer...
156  */
157 void add_word(struct cittext *textlist, char *wordbuf)
158 {
159         struct cittext *ptr;
160
161
162         ptr=textlist;
163         while (ptr->next != NULL) ptr = ptr->next;
164         
165         if (3+strlen(ptr->text)+strlen(wordbuf) > screenwidth) {
166                 ptr->next = (struct cittext *)
167                         malloc(sizeof(struct cittext));
168                 ptr = ptr->next;
169                 ptr->next = NULL;
170                 strcpy(ptr->text,"");
171                 }
172         
173         strcat(ptr->text,wordbuf);
174         strcat(ptr->text," ");
175         }
176
177
178 /*
179  * begin editing of an opened file pointed to by fp, beginning at position pos.
180  */
181 void citedit(FILE *fp, long int base_pos)
182 {
183         int a,prev,finished,b,last_space;
184         int appending = 0;
185         struct cittext *textlist = NULL;
186         struct cittext *ptr;
187         char wordbuf[MAXWORDBUF];
188         char buf[256];
189         long last_server_msg,now;
190
191         /*
192          * we're going to keep track of the last time we talked to
193          * the server, so we can periodically send keep-alive messages
194          * out so it doesn't time out.
195          */
196         time(&last_server_msg);
197
198         /* first, load the text into the buffer */
199         fseek(fp,base_pos,0);
200         textlist = (struct cittext *)malloc(sizeof(struct cittext));
201         textlist->next = NULL;
202         strcpy(textlist->text,"");
203
204         strcpy(wordbuf,"");
205         prev = (-1);
206         while (a=getc(fp), a>=0) {
207                 appending = 1;
208                 if ((a==32)||(a==9)||(a==13)||(a==10)) {
209                         add_word(textlist,wordbuf);
210                         strcpy(wordbuf,"");
211                         if ((prev==13)||(prev==10)) {
212                                 add_word(textlist,"\n");
213                                 add_newline(textlist);
214                                 add_word(textlist,"");
215                                 }
216                         }
217                 else {
218                         wordbuf[strlen(wordbuf)+1] = 0;
219                         wordbuf[strlen(wordbuf)] = a;
220                         }
221                 if (strlen(wordbuf)+3 > screenwidth) {
222                         add_word(textlist,wordbuf);
223                         strcpy(wordbuf,"");
224                         }
225                 prev = a;
226                 }
227
228         /* get text */
229         finished = 0;
230         prev = (appending ? 13 : (-1));
231         strcpy(wordbuf,"");
232         do {
233                 a=inkey();
234                 if (a==10) a=13;
235                 if (a==9) a=32;
236                 if (a==127) a=8;
237                 if ((a==32)&&(prev==13)) {
238                         add_word(textlist,"\n");
239                         add_newline(textlist);
240                         }
241                 if (a==8) {
242                         if (strlen(wordbuf)>0) {
243                                 wordbuf[strlen(wordbuf)-1] = 0;
244                                 putc(8,stdout);
245                                 putc(32,stdout);
246                                 putc(8,stdout);
247                                 }
248                         }
249                 else if (a==13) {
250                         printf("\n");
251                         if (strlen(wordbuf)==0) finished = 1;
252                         else {
253                                 for (b=0; b<strlen(wordbuf); ++b)
254                                    if (wordbuf[b]==32) {
255                                         wordbuf[b]=0;
256                                         add_word(textlist,wordbuf);
257                                         strcpy(wordbuf,&wordbuf[b+1]);
258                                         b=0;
259                                         }
260                                 add_word(textlist,wordbuf);
261                                 strcpy(wordbuf,"");
262                                 }
263                         }
264                 else {
265                         putc(a,stdout);
266                         wordbuf[strlen(wordbuf)+1] = 0;
267                         wordbuf[strlen(wordbuf)] = a;
268                         }
269                 if ((strlen(wordbuf)+3) > screenwidth) {
270                         last_space = (-1);
271                         for (b=0; b<strlen(wordbuf); ++b)
272                                 if (wordbuf[b]==32) last_space = b;
273                         if (last_space>=0) {
274                                 for (b=0; b<strlen(wordbuf); ++b)
275                                    if (wordbuf[b]==32) {
276                                         wordbuf[b]=0;
277                                         add_word(textlist,wordbuf);
278                                         strcpy(wordbuf,&wordbuf[b+1]);
279                                         b=0;
280                                         }
281                                 for (b=0; b<strlen(wordbuf); ++b) {
282                                         putc(8,stdout);
283                                         putc(32,stdout);
284                                         putc(8,stdout);
285                                         }
286                                 printf("\n%s",wordbuf);
287                                 }
288                         else {
289                                 add_word(textlist,wordbuf);
290                                 strcpy(wordbuf,"");
291                                 printf("\n");
292                                 }
293                         }
294                 prev = a;
295
296                 /* this check implements the server keep-alive */
297                 time(&now);
298                 if ( (now - last_server_msg) > S_KEEPALIVE ) {
299                         serv_puts("NOOP");
300                         serv_gets(buf);
301                         last_server_msg = now;
302                         }
303
304                 } while (finished==0);
305
306         /* write the buffer back to disk */
307         fseek(fp,base_pos,0);
308         for (ptr=textlist; ptr!=NULL; ptr=ptr->next) {
309                 fprintf(fp,"%s",ptr->text);
310                 }
311         putc(10,fp);
312         putc(0,fp);
313
314         /* and deallocate the memory we used */
315         while (textlist!=NULL) {
316                 ptr=textlist->next;
317                 free(textlist);
318                 textlist=ptr;
319                 }
320         }
321
322
323 int read_message(long int num, char pagin)      /* Read a message from the server */
324                                 /* message number */
325                 /* 0 = normal read, 1 = read with pagination, 2 = header */
326 {
327         char buf[256];
328         char m_subject[256];
329         char from[256];
330         long now;
331         struct tm *tm;
332         int format_type = 0;
333         int fr = 0;
334         int nhdr = 0;
335
336         sigcaught = 0;
337         sttybbs(1);
338
339         sprintf(buf,"MSG0 %ld|%d",num,(pagin==READ_HEADER ? 1 : 0));
340         serv_puts(buf);
341         serv_gets(buf);
342         if (buf[0]!='1') {
343                 printf("*** msg #%ld: %s\n",num,buf);
344                 ++lines_printed;
345                 lines_printed = checkpagin(lines_printed,pagin,screenheight);
346                 sttybbs(0);
347                 return(0);
348                 }
349
350         strcpy(m_subject,"");
351         printf("\n");
352         ++lines_printed;
353         lines_printed = checkpagin(lines_printed,pagin,screenheight);
354         printf(" ");
355         if (pagin == 1) color(3);
356
357         if (pagin==2) {
358                 while(serv_gets(buf), strcmp(buf,"000")) {
359                         if (buf[4]=='=') {
360                                 printf("%s\n",buf);
361                                 ++lines_printed;
362                                 lines_printed = 
363                                         checkpagin(lines_printed,
364                                                 pagin,screenheight);
365                                 }
366                         }
367                 sttybbs(0);
368                 return(0);
369                 }
370
371         strcpy(reply_to,"nobody...xxxxx");
372         while(serv_gets(buf), struncmp(buf,"text",4)) {
373                 if (!struncmp(buf,"nhdr=yes",8)) nhdr=1;
374                 if (!struncmp(buf,"from=",5)) {
375                         strcpy(from,&buf[5]);
376                         }
377                 if (nhdr==1) buf[0]='_';
378                 if (!struncmp(buf,"type=",5))
379                         format_type=atoi(&buf[5]);
380                 if (!struncmp(buf,"from=",5)) {
381                         printf("from %s ",&buf[5]);
382                         }
383                 if (!struncmp(buf,"subj=",5))
384                         strcpy(m_subject,&buf[5]);
385                 if ((!struncmp(buf,"hnod=",5)) 
386                    && (strucmp(&buf[5],serv_info.serv_humannode)))
387                         printf("(%s) ",&buf[5]);
388                 if ((!struncmp(buf,"room=",5))
389                    && (strucmp(&buf[5],room_name)))
390                         printf("in %s> ",&buf[5]);
391
392                 if (!struncmp(buf,"node=",5)) {
393                         if ( (room_flags&QR_NETWORK)
394                            || ((strucmp(&buf[5],serv_info.serv_nodename)
395                            &&(strucmp(&buf[5],serv_info.serv_fqdn)))))
396                                 {
397                                 printf("@%s ",&buf[5]);
398                                 }
399                         if ((!strucmp(&buf[5],serv_info.serv_nodename))
400                            ||(!strucmp(&buf[5],serv_info.serv_fqdn)))
401                                 {
402                                 strcpy(reply_to,from);
403                                 }
404                         else {
405                                 sprintf(reply_to,"%s @ %s",from,&buf[5]);
406                                 }
407                         }
408
409                 if (!struncmp(buf,"rcpt=",5))
410                         printf("to %s ",&buf[5]);
411                 if (!struncmp(buf,"time=",5)) {
412                         now=atol(&buf[5]);
413                         tm=(struct tm *)localtime(&now);
414                         strcpy(buf,asctime(tm)); buf[strlen(buf)-1]=0;
415                         strcpy(&buf[16],&buf[19]);
416                         printf("%s ",&buf[4]);
417                         }
418                 }
419
420         if (nhdr==1) {
421                 if (!is_room_aide) {
422                         printf(" ****");
423                         }
424                 else {
425                         printf(" %s",from);
426                         }
427                 }
428         printf("\n");
429         if (pagin == 1 ) color(2);
430         ++lines_printed;
431         lines_printed = checkpagin(lines_printed,pagin,screenheight);
432
433         if (strlen(m_subject)>0) {
434                 printf("Subject: %s\n",m_subject);
435                 ++lines_printed;
436                 lines_printed = checkpagin(lines_printed,pagin,screenheight);
437                 }
438
439         if (format_type == 0) {
440                 fr=fmout(screenwidth,NULL,
441                         ((pagin==1) ? 1 : 0),
442                         screenheight,(-1),1);
443                 }
444         else {
445                 while(serv_gets(buf), strcmp(buf,"000")) {
446                         if (sigcaught==0) {
447                                 printf("%s\n",buf);
448                                 lines_printed = lines_printed + 1 +
449                                         (strlen(buf)/screenwidth);
450                                 lines_printed =
451                                         checkpagin(lines_printed,pagin,screenheight);
452                                 }
453                         }
454                 fr = sigcaught;
455                 }
456         printf("\n");
457         ++lines_printed;
458         lines_printed = checkpagin(lines_printed,pagin,screenheight);
459
460         if (pagin == 1) color(7);
461         sttybbs(0);
462         return(fr);
463         }
464
465 /*
466  * replace string function for the built-in editor
467  */
468 void replace_string(char *filename, long int startpos)
469 {
470         char buf[512];
471         char srch_str[128];
472         char rplc_str[128];
473         FILE *fp;
474         int a;
475         long rpos,wpos;
476         char *ptr;
477         int substitutions = 0;
478         long msglen = 0L;
479
480         printf("Enter text to be replaced:\n: ");
481         getline(srch_str,128);
482         if (strlen(srch_str)==0) return;
483         
484         printf("Enter text to replace it with:\n: ");
485         getline(rplc_str,128);
486
487         fp=fopen(filename,"r+");
488         if (fp==NULL) return;
489
490         wpos=startpos;
491         fseek(fp,startpos,0);
492         strcpy(buf,"");
493         while (a=getc(fp), a>0) {
494                 ++msglen;
495                 buf[strlen(buf)+1] = 0;
496                 buf[strlen(buf)] = a;
497                 if ( strlen(buf) >= strlen(srch_str) ) {
498                         ptr=&buf[strlen(buf)-strlen(srch_str)];
499                         if (!struncmp(ptr,srch_str,strlen(srch_str))) {
500                                 strcpy(ptr,rplc_str);
501                                 ++substitutions;
502                                 }
503                         }
504                 if (strlen(buf)>384) {
505                         rpos=ftell(fp);
506                         fseek(fp,wpos,0);
507                         fwrite((char *)buf,128,1,fp);
508                         strcpy(buf,&buf[128]);
509                         wpos = ftell(fp);
510                         fseek(fp,rpos,0);
511                         }
512                 }
513         fseek(fp,wpos,0);
514         if (strlen(buf)>0) fwrite((char *)buf,strlen(buf),1,fp);
515         putc(0,fp);
516         fclose(fp);
517         printf("<R>eplace made %d substitution(s).\n\n",substitutions);
518         }
519
520
521 int make_message(char *filename, char *recipient, int anon_type, int format_type, int mode)
522                         /* temporary file name */
523                         /* NULL if it's not mail */
524                         /* see MES_ types in header file */
525                 
526          
527
528         FILE *fp;
529         int a,b,e_ex_code;
530         long now,beg;
531         char datestr[64];
532         int cksum = 0;
533
534         if (mode==2) if (strlen(editor_path)==0) {
535                 printf("*** No editor available, using built-in editor\n");
536                 mode=0;
537                 }
538
539         time(&now);
540         strcpy(datestr,asctime(localtime(&now)));
541         datestr[strlen(datestr)-1] = 0;
542
543         if (room_flags & QR_ANONONLY) {
544                 printf(" ****");
545                 }
546         else {
547                 printf(" %s from %s",datestr,fullname);
548                 if (strlen(recipient)>0) printf(" to %s",recipient);
549                 }
550         printf("\n");
551
552         beg = 0L;
553
554         if (mode==1) printf("(Press ctrl-d when finished)\n");
555         if (mode==0) {
556                 fp=fopen(filename,"r");
557                 if (fp!=NULL) {
558                         fmout(screenwidth,fp,0,screenheight,0,0);
559                         beg = ftell(fp);
560                         fclose(fp);
561                         }
562                 else {
563                         fp=fopen(filename,"w");
564                         fclose(fp);
565                         }
566                 }
567
568 ME1:    switch(mode) {
569
570            case 0:
571                 fp=fopen(filename,"r+");
572                 citedit(fp,beg);
573                 fclose(fp);
574                 goto MECR;
575                 break;
576
577            case 1:
578                 fp=fopen(filename,"w");
579                 do {
580                         a=inkey(); if (a==255) a=32;
581                         if (a==13) a=10;
582                         if (a!=4) {
583                                 putc(a,fp);
584                                 putc(a,stdout);
585                                 }
586                         if (a==10) putc(13,stdout);
587                         } while(a!=4);
588                 fclose(fp);
589                 break;
590
591            case 2:
592                 e_ex_code = 1;  /* start with a failed exit code */
593                 editor_pid=fork();
594                 cksum = file_checksum(filename);
595                 if (editor_pid==0) {
596                         chmod(filename,0600);
597                         sttybbs(SB_RESTORE);
598                         execlp(editor_path,editor_path,filename,NULL);
599                         exit(1);
600                         }
601                 if (editor_pid>0) do {
602                         e_ex_code = 0;
603                         b=ka_wait(&e_ex_code);
604                         } while((b!=editor_pid)&&(b>=0));
605                 editor_pid = (-1);
606                 sttybbs(0);
607                 break;
608                 }
609
610 MECR:   if (mode==2) {
611                 if (file_checksum(filename) == cksum) {
612                         printf("*** Aborted message.\n");
613                         e_ex_code = 1;
614                         }
615                 if (e_ex_code==0) goto MEFIN;
616                 goto MEABT2;
617                 }
618 MECR1:  printf("Entry cmd (? for options) -> ");
619 MECR2:  b=inkey();
620         if (b==NEXT_KEY) b='n';
621         if (b==STOP_KEY) b='s';
622         b=(b&127); b=tolower(b);
623         if (b=='?') {
624                 printf("Help\n");
625                 formout("saveopt");
626                 goto MECR1;
627                 }
628         if (b=='a') { printf("Abort\n");        goto MEABT;     }
629         if (b=='c') { printf("Continue\n");     goto ME1;       }
630         if (b=='s') { printf("Save message\n"); goto MEFIN;     } 
631         if (b=='p') {
632                 printf("Print formatted\n");
633                 printf(" %s from %s",datestr,fullname);
634                 if (strlen(recipient)>0) printf(" to %s",recipient);
635                 printf("\n");
636                 fp=fopen(filename,"r");
637                 if (fp!=NULL) {
638                         fmout(screenwidth,fp,
639                                 ((userflags & US_PAGINATOR) ? 1 : 0),
640                                 screenheight,0,0);
641                         beg = ftell(fp);
642                         fclose(fp);
643                         }
644                 goto MECR;
645                 }
646         if (b=='r') {
647                 printf("Replace string\n");
648                 replace_string(filename,0L);
649                 goto MECR;
650                 }
651         if (b=='h') {
652                 printf("Hold message\n");
653                 return(2);
654                 }
655         goto MECR2;
656
657 MEFIN:  return(0);
658
659 MEABT:  printf("Are you sure? ");
660         if (yesno()==0) goto ME1;
661 MEABT2: unlink(filename);
662         return(2);
663         }
664
665 /*
666  * transmit message text to the server
667  */
668 void transmit_message(FILE *fp)
669 {
670         char buf[256];
671         int ch,a;
672         
673         strcpy(buf,"");
674         while (ch=getc(fp), (ch>=0)) {
675                 if (ch==10) {
676                         if (!strcmp(buf,"000")) strcpy(buf,">000");
677                         serv_puts(buf);
678                         strcpy(buf,"");
679                         }
680                 else {
681                         a = strlen(buf);
682                         buf[a+1] = 0;
683                         buf[a] = ch;
684                         if ((ch==32)&&(strlen(buf)>200)) {
685                                 buf[a]=0;
686                                 if (!strcmp(buf,"000")) strcpy(buf,">000");
687                                 serv_puts(buf);
688                                 strcpy(buf,"");
689                                 }
690                         if (strlen(buf)>250) {
691                                 if (!strcmp(buf,"000")) strcpy(buf,">000");
692                                 serv_puts(buf);
693                                 strcpy(buf,"");
694                                 }
695                         }
696                 }
697         serv_puts(buf);
698         }
699
700
701
702 /*
703  * entmsg()  -  edit and create a message
704  *              returns 0 if message was saved
705  */
706 int entmsg(int is_reply, int c)
707                         /* nonzero if this was a <R>eply command */
708        {                /* */
709         char buf[300];
710         char cmd[256];
711         int a,b;
712         int need_recp = 0;
713         int mode;
714         long highmsg;
715         FILE *fp;
716
717         if (c>0) mode=1;
718         else mode=0;
719
720         sprintf(cmd,"ENT0 0||0|%d",mode);
721         serv_puts(cmd);
722         serv_gets(cmd);
723
724         if ((strncmp(cmd,"570",3)) && (strncmp(cmd,"200",3))) {
725                 printf("%s\n",&cmd[4]);
726                 return(1);
727                 }
728         need_recp = 0;
729         if (!strncmp(cmd,"570",3)) need_recp = 1;
730
731         if ((userflags & US_EXPERT) == 0) formout("entermsg");
732                 
733         strcpy(buf,"");
734         if (need_recp==1) {
735                 if (axlevel>=2) {
736                         if (is_reply) {
737                                 strcpy(buf,reply_to);
738                                 }
739                         else {
740                                 printf("Enter recipient: ");
741                                 getline(buf,299);
742                                 if (strlen(buf)==0) return(1);
743                                 }
744                         }
745                 else strcpy(buf,"sysop");
746                 }
747
748         b=0;
749         if (room_flags&QR_ANON2) {
750                 printf("Anonymous (Y/N)? ");
751                 if (yesno()==1) b=1;
752                 }
753
754 /* if it's mail, we've got to check the validity of the recipient... */
755         if (strlen(buf)>0) {
756                 sprintf(cmd,"ENT0 0|%s|%d|%d",buf,b,mode);
757                 serv_puts(cmd);
758                 serv_gets(cmd);
759                 if (cmd[0]!='2') {
760                         printf("%s\n",&cmd[4]);
761                         return(1);
762                         }
763                 }
764
765 /* learn the number of the newest message in in the room, so we can tell
766  * upon saving whether someone else has posted too
767  */
768         num_msgs = 0;
769         serv_puts("MSGS LAST|1");
770         serv_gets(cmd);
771         if (cmd[0]!='1') {
772                 printf("%s\n",&cmd[5]);
773                 }
774         else {
775                 while (serv_gets(cmd), strcmp(cmd,"000")) {
776                         msg_arr[num_msgs++] = atol(cmd);
777                         }
778                 }
779
780 /* now put together the message */
781         a=make_message(temp,buf,b,0,c);
782         if (a!=0)
783         {
784            return(2);
785         }
786
787 /* and send it to the server */
788         sprintf(cmd,"ENT0 1|%s|%d|%d",buf,b,mode);
789         serv_puts(cmd);
790         serv_gets(cmd);
791         if (cmd[0]!='4') {
792                 printf("%s\n",&cmd[4]);
793                 return(1);
794                 }
795         fp=fopen(temp,"r");
796         if (fp!=NULL) {
797                 transmit_message(fp);
798                 fclose(fp);
799                 }
800         serv_puts("000");
801         unlink(temp);
802         
803         highmsg = msg_arr[num_msgs - 1];
804         num_msgs = 0;
805         serv_puts("MSGS NEW");
806         serv_gets(cmd);
807         if (cmd[0]!='1') {
808                 printf("%s\n",&cmd[5]);
809                 }
810         else {
811                 while (serv_gets(cmd), strcmp(cmd,"000")) {
812                         msg_arr[num_msgs++] = atol(cmd);
813                         }
814                 }
815
816         /* get new highest message number in room to set lrp for goto... */
817         maxmsgnum = msg_arr[num_msgs - 1];
818
819         /* now see if anyone else has posted in here */
820         b=(-1);
821         for (a=0; a<num_msgs; ++a) if (msg_arr[a]>highmsg) ++b;
822
823         /* in the Mail> room, this algorithm always counts one message
824          * higher than in public rooms, so we decrement it by one */
825         if (need_recp) --b;
826
827         if (b==1) printf(
828 "*** 1 additional message has been entered in this room by another user.\n");
829         if (b>1) printf(
830 "*** %d additional messages have been entered in this room by other users.\n",b);
831
832         return(0);
833         }
834
835 void process_quote(void) {      /* do editing on quoted file */
836 FILE *qfile,*tfile;
837 char buf[128];
838 int line,qstart,qend;
839
840         qfile = fopen(temp2,"r");
841         line = 0;
842         fgets(buf,128,qfile);
843         while (fgets(buf,128,qfile)!=NULL) {
844                 printf("%2d %s",++line,buf);
845                 }
846         printf("Begin quoting at [ 1] : ");
847         getline(buf,3);
848         qstart = (buf[0]==0) ? (1) : atoi(buf);
849         printf("  End quoting at [%d] : ",line);
850         getline(buf,3);
851         qend = (buf[0]==0) ? (line) : atoi(buf);
852         rewind(qfile);
853         line=0;
854         fgets(buf,128,qfile);
855         tfile=fopen(temp,"w");
856         while(fgets(buf,128,qfile)!=NULL) {
857                 if ((++line>=qstart)&&(line<=qend)) fprintf(tfile," >%s",buf);
858                 }
859         fprintf(tfile," \n");
860         fclose(qfile);
861         fclose(tfile);
862         unlink(temp2);
863         chmod(temp,0666);
864         }
865
866
867 void readmsgs(int c, int rdir, int q)   /* read contents of a room */
868                 /* 0=Read all  1=Read new  2=Read old 3=Read last q */
869                 /* 1=Forward (-1)=Reverse */
870                 /* Number of msgs to read (if c==3) */
871         {
872         int a,b,e,f,g,start;
873         int hold_sw = 0;
874         char arcflag = 0;
875         char quotflag = 0;
876         char prtfile[16];
877         char pagin;
878         char cmd[256];
879         char targ[20];
880
881         signal(SIGINT,SIG_IGN);
882         signal(SIGQUIT,SIG_IGN);
883
884         if (c<0) b=(MAXMSGS-1);
885         else b=0;
886
887         sprintf(prtfile,"/tmp/CPrt%d",getpid());
888
889         num_msgs = 0;
890         strcpy(cmd,"MSGS ");
891         switch(c) {
892                 case 0: strcat(cmd,"ALL");
893                         break;
894                 case 1: strcat(cmd,"NEW");
895                         break;
896                 case 2: strcat(cmd,"OLD");
897                         break;
898                 case 3: sprintf(&cmd[strlen(cmd)], "LAST|%d", q);
899                         break;
900                 }
901         serv_puts(cmd);
902         serv_gets(cmd);
903         if (cmd[0]!='1') {
904                 printf("%s\n",&cmd[5]);
905                 }
906         else {
907                 while (serv_gets(cmd), strcmp(cmd,"000")) {
908                         msg_arr[num_msgs++] = atol(cmd);
909                         }
910                 }
911
912         lines_printed = 0;
913
914         /* this loop cycles through each message... */
915         start = ( (rdir==1) ? 0 : (num_msgs-1) );
916         for (a=start; ((a<num_msgs)&&(a>=0)); a=a+rdir) {
917                 while (msg_arr[a]==0L) {
918                         a=a+rdir; if ((a==MAXMSGS)||(a==(-1))) return;
919                         }
920
921 RAGAIN:         pagin=((arcflag==0)&&(quotflag==0)&&
922                         (userflags & US_PAGINATOR)) ? 1 : 0;
923
924         /* if we're doing a quote, set the screenwidth to 72 temporarily */
925                 if (quotflag) {
926                         hold_sw = screenwidth;
927                         screenwidth = 72;
928                         }
929
930         /* now read the message... */
931                 e=read_message(msg_arr[a],pagin);
932
933         /* ...and set the screenwidth back if we have to */
934                 if (quotflag) {
935                         screenwidth = hold_sw;
936                         }
937 RMSGREAD:       fflush(stdout);
938                 highest_msg_read = msg_arr[a];
939                 if (quotflag) {
940                         freopen("/dev/tty","r+",stdout);
941                         quotflag=0;
942                         process_quote();
943                         }
944                 if (arcflag) {
945                         freopen("/dev/tty","r+",stdout);
946                         arcflag=0;
947                         f=fork();
948                         if (f==0) {
949                                 freopen(prtfile,"r",stdin);
950                                 sttybbs(SB_RESTORE);
951                                 ka_system(printcmd);
952                                 sttybbs(SB_NO_INTR);
953                                 unlink(prtfile);
954                                 exit(0);
955                                 }
956                         if (f>0) do {
957                                 g=wait(NULL);
958                                 } while((g!=f)&&(g>=0));
959                         printf("Message printed.\n");
960                         }
961                 if (e==3) return;
962                 if ((userflags&US_NOPROMPT)||(e==2)) e='n';
963                 else {
964                         printf("(%d) ",num_msgs-a-1);
965                         if (is_mail==1) printf("<R>eply ");
966                         if (strlen(printcmd)>0) printf("<P>rint ");
967                 printf("<B>ack <A>gain <Q>uote <H>eader <N>ext <S>top -> ");
968                         do {
969                                 lines_printed = 2;
970                                 e=(inkey()&127); e=tolower(e);
971 /* return key same as <N> */    if (e==13) e='n';
972 /* del/move for aides only */   if (!is_room_aide) if ((e=='d')||(e=='m')) e=0;
973 /* print only if available */   if ((e=='p')&&(strlen(printcmd)==0)) e=0;
974 /* can't move from Mail> */     if ((e=='m')&&(is_mail==1)) e=0;
975 /* can't reply in public rms */ if ((e=='r')&&(is_mail!=1)) e=0;
976                                 } while((e!='a')&&(e!='n')&&(e!='s')
977                                         &&(e!='d')&&(e!='m')&&(e!='p')
978                                         &&(e!='q')&&(e!='b')&&(e!='h')
979                                         &&(e!='r'));
980                         switch(e) {
981                                 case 's':       printf("Stop\r");       break;
982                                 case 'a':       printf("Again\r");      break;
983                                 case 'd':       printf("Delete\r");     break;
984                                 case 'm':       printf("Move\r");       break;
985                                 case 'n':       printf("Next\r");       break;
986                                 case 'p':       printf("Print\r");      break;
987                                 case 'q':       printf("Quote\r");      break;
988                                 case 'b':       printf("Back\r");       break;
989                                 case 'h':       printf("Header\r");     break;
990                                 case 'r':       printf("Reply\r");      break;
991                                 }
992                         if (userflags & US_DISAPPEAR)
993                                 printf("%75s\r","");
994                         else
995                                 printf("\n");
996                         fflush(stdout);
997                         }
998                 switch(e) {
999                    case 'p':    fflush(stdout);
1000                                 freopen(prtfile,"w",stdout);
1001                                 arcflag = 1;
1002                                 goto RAGAIN;
1003                    case 'q':    fflush(stdout);
1004                                 freopen(temp2,"w",stdout);
1005                                 quotflag = 1;
1006                                 goto RAGAIN;
1007                    case 's':    return;
1008                    case 'a':    goto RAGAIN;
1009                    case 'b':    a=a-(rdir*2);
1010                                 break;
1011                    case 'm':    newprompt("Enter target room: ",targ,19);
1012                                 if (strlen(targ)>0) {
1013                                         sprintf(cmd,"MOVE %ld|%s",
1014                                                 msg_arr[a],targ);
1015                                         serv_puts(cmd);
1016                                         serv_gets(cmd);
1017                                         printf("%s\n",&cmd[4]);
1018                                         if (cmd[0]=='2') msg_arr[a]=0L;
1019                                         }
1020                                 else {
1021                                         goto RMSGREAD;
1022                                         }
1023                                 if (cmd[0]!='2') goto RMSGREAD;
1024                                 break;
1025                    case 'd':    printf("*** Delete this message? ");
1026                                 if (yesno()==1) {
1027                                         sprintf(cmd,"DELE %ld",msg_arr[a]);
1028                                         serv_puts(cmd);
1029                                         serv_gets(cmd);
1030                                         printf("%s\n",&cmd[4]);
1031                                         if (cmd[0]=='2') msg_arr[a]=0L;
1032                                         }
1033                                 else {
1034                                         goto RMSGREAD;
1035                                         }
1036                                 break;
1037                    case 'h':    read_message(msg_arr[a],READ_HEADER);
1038                                 goto RMSGREAD;
1039                    case 'r':    entmsg(1,(DEFAULT_ENTRY==46 ? 2 : 0));
1040                                 goto RMSGREAD;
1041                         }
1042                 } /* end for loop */
1043         } /* end read routine */
1044
1045
1046
1047
1048 /*
1049  * View and edit a system message
1050  */
1051 void edit_system_message(char *which_message)
1052 {
1053         char desc[64];
1054         char read_cmd[64];
1055         char write_cmd[64];
1056
1057         sprintf(desc, "system message '%s'", which_message);
1058         sprintf(read_cmd, "MESG %s", which_message);
1059         sprintf(write_cmd, "EMSG %s", which_message);
1060         do_edit(desc, read_cmd, "NOOP", write_cmd);
1061         }