More changes to get attachments working.
[citadel.git] / citadel / messages.c
1 /*
2  * Citadel/UX message support routines
3  * see copyright.txt 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 char inkey(void);
30 void sttybbs(int cmd);
31 int struncmp(char *lstr, char *rstr, int len);
32 int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst);
33 int haschar(char *st, int ch);
34 int checkpagin(int lp, int pagin, int height);
35 void getline(char *string, int lim);
36 void formout(char *name);
37 int yesno(void);
38 void newprompt(char *prompt, char *str, int len);
39 int file_checksum(char *filename);
40 void color(int colornum);
41 void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd);
42
43 char reply_to[512];
44 long msg_arr[MAXMSGS];
45 int num_msgs;
46 extern char room_name[];
47 extern unsigned room_flags;
48 extern long highest_msg_read;
49 extern struct CtdlServInfo serv_info;
50 extern char temp[];
51 extern char temp2[];
52 extern int screenwidth;
53 extern int screenheight;
54 extern long maxmsgnum;
55 extern char is_mail;
56 extern char is_aide;
57 extern char is_room_aide;
58 extern char fullname[];
59 extern char axlevel;
60 extern unsigned userflags;
61 extern char sigcaught;
62 extern char editor_path[];
63 extern char printcmd[];
64 extern int rc_allow_attachments;
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, char *boundary)
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         if ((b=='f')&&(rc_allow_attachments==1)) {
656                 printf("attach File\n");
657                 if (strlen(boundary)==0) {
658                         sprintf(boundary, "Citadel-Attachment-%ld.%d",
659                                 time(NULL), getpid() );
660                         }
661                 /* FIX FIX now you have to attach the file, stupid */
662                 }
663         goto MECR2;
664
665 MEFIN:  return(0);
666
667 MEABT:  printf("Are you sure? ");
668         if (yesno()==0) goto ME1;
669 MEABT2: unlink(filename);
670         return(2);
671         }
672
673 /*
674  * transmit message text to the server
675  */
676 void transmit_message(FILE *fp)
677 {
678         char buf[256];
679         int ch,a;
680         
681         strcpy(buf,"");
682         while (ch=getc(fp), (ch>=0)) {
683                 if (ch==10) {
684                         if (!strcmp(buf,"000")) strcpy(buf,">000");
685                         serv_puts(buf);
686                         strcpy(buf,"");
687                         }
688                 else {
689                         a = strlen(buf);
690                         buf[a+1] = 0;
691                         buf[a] = ch;
692                         if ((ch==32)&&(strlen(buf)>200)) {
693                                 buf[a]=0;
694                                 if (!strcmp(buf,"000")) strcpy(buf,">000");
695                                 serv_puts(buf);
696                                 strcpy(buf,"");
697                                 }
698                         if (strlen(buf)>250) {
699                                 if (!strcmp(buf,"000")) strcpy(buf,">000");
700                                 serv_puts(buf);
701                                 strcpy(buf,"");
702                                 }
703                         }
704                 }
705         serv_puts(buf);
706         }
707
708
709
710 /*
711  * entmsg()  -  edit and create a message
712  *              returns 0 if message was saved
713  */
714 int entmsg(int is_reply, int c)
715                         /* nonzero if this was a <R>eply command */
716        {                /* */
717         char buf[300];
718         char cmd[256];
719         char boundary[256];
720         int a,b;
721         int need_recp = 0;
722         int mode;
723         long highmsg;
724         FILE *fp;
725
726         if (c>0) mode=1;
727         else mode=0;
728
729         sprintf(cmd,"ENT0 0||0|%d",mode);
730         serv_puts(cmd);
731         serv_gets(cmd);
732
733         if ((strncmp(cmd,"570",3)) && (strncmp(cmd,"200",3))) {
734                 printf("%s\n",&cmd[4]);
735                 return(1);
736                 }
737         need_recp = 0;
738         if (!strncmp(cmd,"570",3)) need_recp = 1;
739
740         if ((userflags & US_EXPERT) == 0) formout("entermsg");
741                 
742         strcpy(buf,"");
743         if (need_recp==1) {
744                 if (axlevel>=2) {
745                         if (is_reply) {
746                                 strcpy(buf,reply_to);
747                                 }
748                         else {
749                                 printf("Enter recipient: ");
750                                 getline(buf,299);
751                                 if (strlen(buf)==0) return(1);
752                                 }
753                         }
754                 else strcpy(buf,"sysop");
755                 }
756
757         b=0;
758         if (room_flags&QR_ANON2) {
759                 printf("Anonymous (Y/N)? ");
760                 if (yesno()==1) b=1;
761                 }
762
763 /* if it's mail, we've got to check the validity of the recipient... */
764         if (strlen(buf)>0) {
765                 sprintf(cmd,"ENT0 0|%s|%d|%d",buf,b,mode);
766                 serv_puts(cmd);
767                 serv_gets(cmd);
768                 if (cmd[0]!='2') {
769                         printf("%s\n",&cmd[4]);
770                         return(1);
771                         }
772                 }
773
774 /* learn the number of the newest message in in the room, so we can tell
775  * upon saving whether someone else has posted too
776  */
777         num_msgs = 0;
778         serv_puts("MSGS LAST|1");
779         serv_gets(cmd);
780         if (cmd[0]!='1') {
781                 printf("%s\n",&cmd[5]);
782                 }
783         else {
784                 while (serv_gets(cmd), strcmp(cmd,"000")) {
785                         msg_arr[num_msgs++] = atol(cmd);
786                         }
787                 }
788
789 /* now put together the message */
790         strcpy(boundary, "");
791         if ( make_message(temp,buf,b,0,c,boundary) != 0 ) return(2);
792
793 /* and send it to the server */
794         sprintf(cmd,"ENT0 1|%s|%d|%d||%s|",buf,b,mode,boundary);
795         serv_puts(cmd);
796         serv_gets(cmd);
797         if (cmd[0]!='4') {
798                 printf("%s\n",&cmd[4]);
799                 return(1);
800                 }
801         fp=fopen(temp,"r");
802         if (fp!=NULL) {
803                 transmit_message(fp);
804                 fclose(fp);
805                 }
806         serv_puts("000");
807         unlink(temp);
808         
809         highmsg = msg_arr[num_msgs - 1];
810         num_msgs = 0;
811         serv_puts("MSGS NEW");
812         serv_gets(cmd);
813         if (cmd[0]!='1') {
814                 printf("%s\n",&cmd[5]);
815                 }
816         else {
817                 while (serv_gets(cmd), strcmp(cmd,"000")) {
818                         msg_arr[num_msgs++] = atol(cmd);
819                         }
820                 }
821
822         /* get new highest message number in room to set lrp for goto... */
823         maxmsgnum = msg_arr[num_msgs - 1];
824
825         /* now see if anyone else has posted in here */
826         b=(-1);
827         for (a=0; a<num_msgs; ++a) if (msg_arr[a]>highmsg) ++b;
828
829         /* in the Mail> room, this algorithm always counts one message
830          * higher than in public rooms, so we decrement it by one */
831         if (need_recp) --b;
832
833         if (b==1) printf(
834 "*** 1 additional message has been entered in this room by another user.\n");
835         if (b>1) printf(
836 "*** %d additional messages have been entered in this room by other users.\n",b);
837
838         return(0);
839         }
840
841 void process_quote(void) {      /* do editing on quoted file */
842 FILE *qfile,*tfile;
843 char buf[128];
844 int line,qstart,qend;
845
846         /* Unlink the second temp file as soon as it's opened, so it'll get
847          * deleted even if the program dies
848          */
849         qfile = fopen(temp2,"r");
850         unlink(temp2);
851
852         /* Display the quotable text with line numbers added */
853         line = 0;
854         fgets(buf,128,qfile);
855         while (fgets(buf,128,qfile)!=NULL) {
856                 printf("%2d %s",++line,buf);
857                 }
858         printf("Begin quoting at [ 1] : ");
859         getline(buf,3);
860         qstart = (buf[0]==0) ? (1) : atoi(buf);
861         printf("  End quoting at [%d] : ",line);
862         getline(buf,3);
863         qend = (buf[0]==0) ? (line) : atoi(buf);
864         rewind(qfile);
865         line=0;
866         fgets(buf,128,qfile);
867         tfile=fopen(temp,"w");
868         while(fgets(buf,128,qfile)!=NULL) {
869                 if ((++line>=qstart)&&(line<=qend)) fprintf(tfile," >%s",buf);
870                 }
871         fprintf(tfile," \n");
872         fclose(qfile);
873         fclose(tfile);
874         chmod(temp,0666);
875         }
876
877
878 void readmsgs(int c, int rdir, int q)   /* read contents of a room */
879                 /* 0=Read all  1=Read new  2=Read old 3=Read last q */
880                 /* 1=Forward (-1)=Reverse */
881                 /* Number of msgs to read (if c==3) */
882         {
883         int a,b,e,f,g,start;
884         int hold_sw = 0;
885         char arcflag = 0;
886         char quotflag = 0;
887         char prtfile[16];
888         char pagin;
889         char cmd[256];
890         char targ[20];
891
892         signal(SIGINT,SIG_IGN);
893         signal(SIGQUIT,SIG_IGN);
894
895         if (c<0) b=(MAXMSGS-1);
896         else b=0;
897
898         sprintf(prtfile,"/tmp/CPrt%d",getpid());
899
900         num_msgs = 0;
901         strcpy(cmd,"MSGS ");
902         switch(c) {
903                 case 0: strcat(cmd,"ALL");
904                         break;
905                 case 1: strcat(cmd,"NEW");
906                         break;
907                 case 2: strcat(cmd,"OLD");
908                         break;
909                 case 3: sprintf(&cmd[strlen(cmd)], "LAST|%d", q);
910                         break;
911                 }
912         serv_puts(cmd);
913         serv_gets(cmd);
914         if (cmd[0]!='1') {
915                 printf("%s\n",&cmd[5]);
916                 }
917         else {
918                 while (serv_gets(cmd), strcmp(cmd,"000")) {
919                         msg_arr[num_msgs++] = atol(cmd);
920                         }
921                 }
922
923         lines_printed = 0;
924
925         /* this loop cycles through each message... */
926         start = ( (rdir==1) ? 0 : (num_msgs-1) );
927         for (a=start; ((a<num_msgs)&&(a>=0)); a=a+rdir) {
928                 while (msg_arr[a]==0L) {
929                         a=a+rdir; if ((a==MAXMSGS)||(a==(-1))) return;
930                         }
931
932 RAGAIN:         pagin=((arcflag==0)&&(quotflag==0)&&
933                         (userflags & US_PAGINATOR)) ? 1 : 0;
934
935         /* if we're doing a quote, set the screenwidth to 72 temporarily */
936                 if (quotflag) {
937                         hold_sw = screenwidth;
938                         screenwidth = 72;
939                         }
940
941         /* now read the message... */
942                 e=read_message(msg_arr[a],pagin);
943
944         /* ...and set the screenwidth back if we have to */
945                 if (quotflag) {
946                         screenwidth = hold_sw;
947                         }
948 RMSGREAD:       fflush(stdout);
949                 highest_msg_read = msg_arr[a];
950                 if (quotflag) {
951                         freopen("/dev/tty","r+",stdout);
952                         quotflag=0;
953                         process_quote();
954                         }
955                 if (arcflag) {
956                         freopen("/dev/tty","r+",stdout);
957                         arcflag=0;
958                         f=fork();
959                         if (f==0) {
960                                 freopen(prtfile,"r",stdin);
961                                 sttybbs(SB_RESTORE);
962                                 ka_system(printcmd);
963                                 sttybbs(SB_NO_INTR);
964                                 unlink(prtfile);
965                                 exit(0);
966                                 }
967                         if (f>0) do {
968                                 g=wait(NULL);
969                                 } while((g!=f)&&(g>=0));
970                         printf("Message printed.\n");
971                         }
972                 if (e==3) return;
973                 if ((userflags&US_NOPROMPT)||(e==2)) e='n';
974                 else {
975                         printf("(%d) ",num_msgs-a-1);
976                         if (is_mail==1) printf("<R>eply ");
977                         if (strlen(printcmd)>0) printf("<P>rint ");
978                 printf("<B>ack <A>gain <Q>uote <H>eader <N>ext <S>top -> ");
979                         do {
980                                 lines_printed = 2;
981                                 e=(inkey()&127); e=tolower(e);
982 /* return key same as <N> */    if (e==13) e='n';
983 /* del/move for aides only */   if (!is_room_aide) if ((e=='d')||(e=='m')) e=0;
984 /* print only if available */   if ((e=='p')&&(strlen(printcmd)==0)) e=0;
985 /* can't move from Mail> */     if ((e=='m')&&(is_mail==1)) e=0;
986 /* can't reply in public rms */ if ((e=='r')&&(is_mail!=1)) e=0;
987                                 } while((e!='a')&&(e!='n')&&(e!='s')
988                                         &&(e!='d')&&(e!='m')&&(e!='p')
989                                         &&(e!='q')&&(e!='b')&&(e!='h')
990                                         &&(e!='r'));
991                         switch(e) {
992                                 case 's':       printf("Stop\r");       break;
993                                 case 'a':       printf("Again\r");      break;
994                                 case 'd':       printf("Delete\r");     break;
995                                 case 'm':       printf("Move\r");       break;
996                                 case 'n':       printf("Next\r");       break;
997                                 case 'p':       printf("Print\r");      break;
998                                 case 'q':       printf("Quote\r");      break;
999                                 case 'b':       printf("Back\r");       break;
1000                                 case 'h':       printf("Header\r");     break;
1001                                 case 'r':       printf("Reply\r");      break;
1002                                 }
1003                         if (userflags & US_DISAPPEAR)
1004                                 printf("%75s\r","");
1005                         else
1006                                 printf("\n");
1007                         fflush(stdout);
1008                         }
1009                 switch(e) {
1010                    case 'p':    fflush(stdout);
1011                                 freopen(prtfile,"w",stdout);
1012                                 arcflag = 1;
1013                                 goto RAGAIN;
1014                    case 'q':    fflush(stdout);
1015                                 freopen(temp2,"w",stdout);
1016                                 quotflag = 1;
1017                                 goto RAGAIN;
1018                    case 's':    return;
1019                    case 'a':    goto RAGAIN;
1020                    case 'b':    a=a-(rdir*2);
1021                                 break;
1022                    case 'm':    newprompt("Enter target room: ",targ,19);
1023                                 if (strlen(targ)>0) {
1024                                         sprintf(cmd,"MOVE %ld|%s",
1025                                                 msg_arr[a],targ);
1026                                         serv_puts(cmd);
1027                                         serv_gets(cmd);
1028                                         printf("%s\n",&cmd[4]);
1029                                         if (cmd[0]=='2') msg_arr[a]=0L;
1030                                         }
1031                                 else {
1032                                         goto RMSGREAD;
1033                                         }
1034                                 if (cmd[0]!='2') goto RMSGREAD;
1035                                 break;
1036                    case 'd':    printf("*** Delete this message? ");
1037                                 if (yesno()==1) {
1038                                         sprintf(cmd,"DELE %ld",msg_arr[a]);
1039                                         serv_puts(cmd);
1040                                         serv_gets(cmd);
1041                                         printf("%s\n",&cmd[4]);
1042                                         if (cmd[0]=='2') msg_arr[a]=0L;
1043                                         }
1044                                 else {
1045                                         goto RMSGREAD;
1046                                         }
1047                                 break;
1048                    case 'h':    read_message(msg_arr[a],READ_HEADER);
1049                                 goto RMSGREAD;
1050                    case 'r':    entmsg(1,(DEFAULT_ENTRY==46 ? 2 : 0));
1051                                 goto RMSGREAD;
1052                         }
1053                 } /* end for loop */
1054         } /* end read routine */
1055
1056
1057
1058
1059 /*
1060  * View and edit a system message
1061  */
1062 void edit_system_message(char *which_message)
1063 {
1064         char desc[64];
1065         char read_cmd[64];
1066         char write_cmd[64];
1067
1068         sprintf(desc, "system message '%s'", which_message);
1069         sprintf(read_cmd, "MESG %s", which_message);
1070         sprintf(write_cmd, "EMSG %s", which_message);
1071         do_edit(desc, read_cmd, "NOOP", write_cmd);
1072         }