]> code.citadel.org Git - citadel.git/blob - citadel/messages.c
* <R>eplace string is now case sensitive
[citadel.git] / citadel / messages.c
1 /*
2  * $Id$
3  *
4  * Citadel/UX message support routines
5  * see copyright.txt for copyright information
6  */
7
8 #include "sysdep.h"
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <errno.h>
18 #include <limits.h>
19 #include <sys/wait.h>
20 #include <sys/stat.h>
21
22 #if TIME_WITH_SYS_TIME
23 # include <sys/time.h>
24 # include <time.h>
25 #else
26 # if HAVE_SYS_TIME_H
27 #  include <sys/time.h>
28 # else
29 #  include <time.h>
30 # endif
31 #endif
32
33 #include <stdarg.h>
34 #include "citadel.h"
35 #include "messages.h"
36 #include "commands.h"
37 #include "rooms.h"
38 #include "tools.h"
39 #include "citadel_ipc.h"
40 #ifndef HAVE_SNPRINTF
41 #include "snprintf.h"
42 #endif
43 #include "screen.h"
44
45 #define MAXWORDBUF SIZ
46
47 struct cittext {
48         struct cittext *next;
49         char text[MAXWORDBUF];
50 };
51
52 void sttybbs(int cmd);
53 int haschar(const char *st, int ch);
54 int checkpagin(int lp, int pagin, int height);
55 void getline(char *string, int lim);
56 void formout(char *name);
57 int yesno(void);
58 void newprompt(char *prompt, char *str, int len);
59 int file_checksum(char *filename);
60 void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd);
61
62 long *msg_arr = NULL;
63 int msg_arr_size = 0;
64 int num_msgs;
65 char rc_alt_semantics;
66 extern char room_name[];
67 extern unsigned room_flags;
68 extern long highest_msg_read;
69 extern struct CtdlServInfo serv_info;
70 extern char temp[];
71 extern char temp2[];
72 extern int screenwidth;
73 extern int screenheight;
74 extern long maxmsgnum;
75 extern char is_mail;
76 extern char is_aide;
77 extern char is_room_aide;
78 extern char fullname[];
79 extern char axlevel;
80 extern unsigned userflags;
81 extern char sigcaught;
82 extern char editor_path[];
83 extern char printcmd[];
84 extern int rc_allow_attachments;
85 extern int rc_display_message_numbers;
86 extern int rc_force_mail_prompts;
87
88 extern int editor_pid;
89
90 void ka_sigcatch(int signum)
91 {
92         alarm(S_KEEPALIVE);
93         signal(SIGALRM, ka_sigcatch);
94         CtdlIPCNoop();
95 }
96
97
98 /*
99  * server keep-alive version of wait() (needed for external editor)
100  */
101 pid_t ka_wait(int *kstatus)
102 {
103         pid_t p;
104
105         alarm(S_KEEPALIVE);
106         signal(SIGALRM, ka_sigcatch);
107         do {
108                 errno = 0;
109                 p = wait(kstatus);
110         } while (errno == EINTR);
111         signal(SIGALRM, SIG_IGN);
112         alarm(0);
113         return (p);
114 }
115
116
117 /*
118  * version of system() that uses ka_wait()
119  */
120 int ka_system(char *shc)
121 {
122         pid_t childpid;
123         pid_t waitpid;
124         int retcode;
125
126         childpid = fork();
127         if (childpid < 0) {
128                 color(BRIGHT_RED);
129                 perror("Cannot fork");
130                 color(DIM_WHITE);
131                 return ((pid_t) childpid);
132         }
133
134         if (childpid == 0) {
135                 execlp("/bin/sh", "sh", "-c", shc, NULL);
136                 exit(127);
137         }
138
139         if (childpid > 0) {
140                 do {
141                         waitpid = ka_wait(&retcode);
142                 } while (waitpid != childpid);
143                 return (retcode);
144         }
145
146         return (-1);
147 }
148
149
150
151 /*
152  * add a newline to the buffer...
153  */
154 void add_newline(struct cittext *textlist)
155 {
156         struct cittext *ptr;
157
158         ptr = textlist;
159         while (ptr->next != NULL)
160                 ptr = ptr->next;
161
162         while (ptr->text[strlen(ptr->text) - 1] == 32)
163                 ptr->text[strlen(ptr->text) - 1] = 0;
164         /* strcat(ptr->text,"\n"); */
165
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
174 /*
175  * add a word to the buffer...
176  */
177 void add_word(struct cittext *textlist, char *wordbuf)
178 {
179         struct cittext *ptr;
180
181         ptr = textlist;
182         while (ptr->next != NULL)
183                 ptr = ptr->next;
184
185         if (3 + strlen(ptr->text) + strlen(wordbuf) > screenwidth) {
186                 ptr->next = (struct cittext *)
187                     malloc(sizeof(struct cittext));
188                 ptr = ptr->next;
189                 ptr->next = NULL;
190                 strcpy(ptr->text, "");
191         }
192
193         strcat(ptr->text, wordbuf);
194         strcat(ptr->text, " ");
195 }
196
197
198 /*
199  * begin editing of an opened file pointed to by fp
200  */
201 void citedit(FILE * fp)
202 {
203         int a, prev, finished, b, last_space;
204         int appending = 0;
205         struct cittext *textlist = NULL;
206         struct cittext *ptr;
207         char wordbuf[MAXWORDBUF];
208
209         /* first, load the text into the buffer */
210         fseek(fp, 0L, 0);
211         textlist = (struct cittext *) malloc(sizeof(struct cittext));
212         textlist->next = NULL;
213         strcpy(textlist->text, "");
214
215         strcpy(wordbuf, "");
216         prev = (-1);
217         while (a = getc(fp), a >= 0) {
218                 appending = 1;
219                 if ((a == 32) || (a == 9) || (a == 13) || (a == 10)) {
220                         add_word(textlist, wordbuf);
221                         strcpy(wordbuf, "");
222                         if ((prev == 13) || (prev == 10)) {
223                                 add_word(textlist, "\n");
224                                 add_newline(textlist);
225                                 add_word(textlist, "");
226                         }
227                 } else {
228                         wordbuf[strlen(wordbuf) + 1] = 0;
229                         wordbuf[strlen(wordbuf)] = a;
230                 }
231                 if (strlen(wordbuf) + 3 > screenwidth) {
232                         add_word(textlist, wordbuf);
233                         strcpy(wordbuf, "");
234                 }
235                 prev = a;
236         }
237
238         /* get text */
239         finished = 0;
240         prev = (appending ? 13 : (-1));
241         strcpy(wordbuf, "");
242         async_ka_start();
243         do {
244                 a = inkey();
245                 if (a == 10)
246                         a = 13;
247                 if (a == 9)
248                         a = 32;
249                 if (a == 127)
250                         a = 8;
251
252         /******* new ***********/
253                 if ((a > 32) && (a < 127) && (prev == 13)) {
254                         add_word(textlist, "\n");
255                         scr_printf(" ");
256                 }
257         /***********************/
258
259                 if ((a == 32) && (prev == 13)) {
260                         add_word(textlist, "\n");
261                         add_newline(textlist);
262                 }
263
264                 if (a == 8) {
265                         if (strlen(wordbuf) > 0) {
266                                 wordbuf[strlen(wordbuf) - 1] = 0;
267                                 scr_putc(8);
268                                 scr_putc(32);
269                                 scr_putc(8);
270                         }
271                 } else if (a == 23) {
272                         do {
273                                 wordbuf[strlen(wordbuf) - 1] = 0;
274                                 scr_putc(8);
275                                 scr_putc(32);
276                                 scr_putc(8);
277                         } while (strlen(wordbuf) && wordbuf[strlen(wordbuf) - 1] != ' ');
278                 } else if (a == 13) {
279                         scr_printf("\n");
280                         if (strlen(wordbuf) == 0)
281                                 finished = 1;
282                         else {
283                                 for (b = 0; b < strlen(wordbuf); ++b)
284                                         if (wordbuf[b] == 32) {
285                                                 wordbuf[b] = 0;
286                                                 add_word(textlist,
287                                                          wordbuf);
288                                                 strcpy(wordbuf,
289                                                        &wordbuf[b + 1]);
290                                                 b = 0;
291                                         }
292                                 add_word(textlist, wordbuf);
293                                 strcpy(wordbuf, "");
294                         }
295                 } else {
296                         scr_putc(a);
297                         wordbuf[strlen(wordbuf) + 1] = 0;
298                         wordbuf[strlen(wordbuf)] = a;
299                 }
300                 if ((strlen(wordbuf) + 3) > screenwidth) {
301                         last_space = (-1);
302                         for (b = 0; b < strlen(wordbuf); ++b)
303                                 if (wordbuf[b] == 32)
304                                         last_space = b;
305                         if (last_space >= 0) {
306                                 for (b = 0; b < strlen(wordbuf); ++b)
307                                         if (wordbuf[b] == 32) {
308                                                 wordbuf[b] = 0;
309                                                 add_word(textlist,
310                                                          wordbuf);
311                                                 strcpy(wordbuf,
312                                                        &wordbuf[b + 1]);
313                                                 b = 0;
314                                         }
315                                 for (b = 0; b < strlen(wordbuf); ++b) {
316                                         scr_putc(8);
317                                         scr_putc(32);
318                                         scr_putc(8);
319                                 }
320                                 scr_printf("\n%s", wordbuf);
321                         } else {
322                                 add_word(textlist, wordbuf);
323                                 strcpy(wordbuf, "");
324                                 scr_printf("\n");
325                         }
326                 }
327                 prev = a;
328         } while (finished == 0);
329         async_ka_end();
330
331         /* write the buffer back to disk */
332         fseek(fp, 0L, 0);
333         for (ptr = textlist; ptr != NULL; ptr = ptr->next) {
334                 fprintf(fp, "%s", ptr->text);
335         }
336         putc(10, fp);
337         fflush(fp);
338         ftruncate(fileno(fp), ftell(fp));
339
340         /* and deallocate the memory we used */
341         while (textlist != NULL) {
342                 ptr = textlist->next;
343                 free(textlist);
344                 textlist = ptr;
345         }
346 }
347
348 /* Read a message from the server
349  */
350 int read_message(
351         long num,   /* message number */
352         char pagin, /* 0 = normal read, 1 = read with pagination, 2 = header */
353         FILE *dest) /* Destination file, NULL for screen */
354 {
355         char buf[SIZ];
356         char now[SIZ];
357         int format_type = 0;
358         int fr = 0;
359         int nhdr = 0;
360         struct ctdlipcmessage *message = NULL;
361         char reply_to[SIZ];
362         char reply_subject[SIZ];
363         int r;                          /* IPC response code */
364
365         sigcaught = 0;
366         sttybbs(1);
367
368         r = CtdlIPCGetSingleMessage(num, (pagin == READ_HEADER ? 1 : 0), 0,
369                                     &message, buf);
370         if (r / 100 != 1) {
371                 err_printf("*** msg #%ld: %d %s\n", num, r, buf);
372                 ++lines_printed;
373                 lines_printed =
374                     checkpagin(lines_printed, pagin, screenheight);
375                 sttybbs(0);
376                 return (0);
377         }
378
379         strcpy(reply_to, "nobody ... xxxxx");
380
381         if (dest) {
382                 fprintf(dest, "\n ");
383         } else {
384                 scr_printf("\n");
385                 ++lines_printed;
386                 lines_printed = checkpagin(lines_printed, pagin, screenheight);
387                 scr_printf(" ");
388         }
389         if (pagin == 1 && !dest) {
390                 color(BRIGHT_CYAN);
391         }
392
393         /* View headers only */
394         if (pagin == 2) {
395                 sprintf(buf, "nhdr=%s\nfrom=%s\ntype=%d\nmsgn=%s\n",
396                                 message->nhdr ? "yes" : "no",
397                                 message->author, message->type,
398                                 message->msgid);
399                 /* FIXME output buf */
400                 if (strlen(message->subject)) {
401                         sprintf(buf, "subj=%s\n", message->subject);
402                         /* FIXME: output buf */
403                 }
404                 if (strlen(message->email)) {
405                         sprintf(buf, "rfca=%s\n", message->email);
406                         /* FIXME: output buf */
407                 }
408                 sprintf(buf, "hnod=%s\nroom=%s\nnode=%s\ntime=%s",
409                                 message->hnod, message->room,
410                                 message->node, 
411                                 asctime(localtime(&message->time)));
412                 if (strlen(message->recipient)) {
413                         sprintf(buf, "rcpt=%s\n", message->recipient);
414                         /* FIXME: output buf */
415                 }
416                 if (message->attachments) {
417                         struct parts *ptr;
418
419                         for (ptr = message->attachments; ptr; ptr = ptr->next) {
420                                 sprintf(buf, "part=%s|%s|%s|%s|%s|%ld\n",
421                                         ptr->name, ptr->filename, ptr->number,
422                                         ptr->disposition, ptr->mimetype,
423                                         ptr->length);
424                                 /* FIXME: output buf */
425                         }
426                 }
427                 sttybbs(0);
428                 return (0);
429         }
430
431         if (rc_display_message_numbers) {
432                 if (dest) {
433                         fprintf(dest, "[#%s] ", message->msgid);
434                 } else {
435                         color(DIM_WHITE);
436                         scr_printf("[");
437                         color(BRIGHT_WHITE);
438                         scr_printf("#%s", message->msgid);
439                         color(DIM_WHITE);
440                         scr_printf("] ");
441                 }
442         }
443         if (nhdr == 1 && !is_room_aide) {
444                 if (dest) {
445                         fprintf(dest, " ****");
446                 } else {
447                         scr_printf(" ****");
448                 }
449         } else {
450                 fmt_date(now, sizeof now, message->time, 0);
451                 if (dest) {
452                         fprintf(dest, "%s from %s ", now, message->author);
453                         if (strlen(message->email)) {
454                                 fprintf(dest, "<%s> ", message->email);
455                         }
456                 } else {
457                         color(BRIGHT_CYAN);
458                         scr_printf("%s ", now);
459                         color(DIM_WHITE);
460                         scr_printf("from ");
461                         color(BRIGHT_CYAN);
462                         scr_printf("%s ", message->author);
463                         if (strlen(message->email)) {
464                                 color(DIM_WHITE);
465                                 scr_printf("<");
466                                 color(BRIGHT_BLUE);
467                                 scr_printf("%s", message->email);
468                                         color(DIM_WHITE);
469                                 scr_printf("> ");
470                         }
471                 }
472                 if (strlen(message->node)) {
473                         if ((room_flags & QR_NETWORK)
474                             || ((strcasecmp(message->node, serv_info.serv_nodename)
475                              && (strcasecmp(message->node, serv_info.serv_fqdn))))) {
476                                 if (strlen(message->email) == 0) {
477                                         if (dest) {
478                                                 fprintf(dest, "@%s ", message->node);
479                                         } else {
480                                                 color(DIM_WHITE);
481                                                 scr_printf("@");
482                                                 color(BRIGHT_YELLOW);
483                                                 scr_printf("%s ", message->node);
484                                         }
485                                 }
486                         }
487                 }
488                 if (strcasecmp(message->hnod, serv_info.serv_humannode)
489                     && (strlen(message->hnod)) && (!strlen(message->email))) {
490                         if (dest) {
491                                 fprintf(dest, "(%s) ", message->hnod);
492                         } else {
493                                 color(DIM_WHITE);
494                                 scr_printf("(");
495                                 color(BRIGHT_WHITE);
496                                 scr_printf("%s", message->hnod);
497                                 color(DIM_WHITE);
498                                 scr_printf(") ");
499                         }
500                 }
501                 if (strcasecmp(message->room, room_name) && (strlen(message->email) == 0)) {
502                         if (dest) {
503                                 fprintf(dest, "in %s> ", message->room);
504                         } else {
505                                 color(DIM_WHITE);
506                                 scr_printf("in ");
507                                 color(BRIGHT_MAGENTA);
508                                 scr_printf("%s> ", message->room);
509                         }
510                 }
511                 if (strlen(message->recipient)) {
512                         if (dest) {
513                                 fprintf(dest, "to %s ", message->recipient);
514                         } else {
515                                 color(DIM_WHITE);
516                                 scr_printf("to ");
517                                 color(BRIGHT_CYAN);
518                                 scr_printf("%s ", message->recipient);
519                         }
520                 }
521         }
522         
523         if (dest) {
524                 fprintf(dest, "\n");
525         } else {
526                 scr_printf("\n");
527         }
528
529         if (strlen(message->email) > 0) {
530                 strcpy(reply_to, message->email);
531         } else {
532                 snprintf(reply_to, sizeof(reply_to), "%s @ %s",
533                          message->author, message->node);
534         }
535
536         if (pagin == 1 && !dest)
537                 color(BRIGHT_WHITE);
538         if (!dest) {
539                 ++lines_printed;
540                 lines_printed = checkpagin(lines_printed, pagin, screenheight);
541         }
542
543         strcpy(reply_subject, message->subject);
544         if (strlen(message->subject) > 0) {
545                 if (dest) {
546                         fprintf(dest, "Subject: %s\n", message->subject);
547                 } else {
548                         scr_printf("Subject: %s\n", message->subject);
549                         ++lines_printed;
550                         lines_printed = checkpagin(lines_printed,
551                                         pagin, screenheight);
552                 }
553         }
554
555         /******* end of header output, start of message text output *******/
556
557         /* scr_printf("message->mime_chosen is <%s>\n", message->mime_chosen); FIXME */
558
559         if (format_type == 0) {
560                 fr = fmout(screenwidth, NULL, message->text, dest,
561                            ((pagin == 1) ? 1 : 0), screenheight, (-1), 1);
562         } else {
563                 int i;
564
565                 for (i = 0; i < num_tokens(message->text, '\n'); i++) {
566                         if (sigcaught == 0) {
567                                 extract_token(buf, message->text, i, '\n');
568                                 if (dest) {
569                                         fprintf(dest, "%s\n", buf);
570                                 } else {
571                                         scr_printf("%s\n", buf);
572                                         lines_printed = lines_printed + 1 +
573                                             (strlen(buf) / screenwidth);
574                                         lines_printed =
575                                             checkpagin(lines_printed, pagin,
576                                                        screenheight);
577                                 }
578                         }
579                 }
580                 fr = sigcaught;
581         }
582         if (dest) {
583                 fprintf(dest, "\n");
584         } else {
585                 scr_printf("\n");
586                 /* scr_flush(); */
587                 ++lines_printed;
588                 lines_printed = checkpagin(lines_printed, pagin, screenheight);
589         }
590         free(message->text);
591         free(message);
592
593         if (pagin == 1 && !dest)
594                 color(DIM_WHITE);
595         sttybbs(0);
596         return (fr);
597 }
598
599 /*
600  * replace string function for the built-in editor
601  */
602 void replace_string(char *filename, long int startpos)
603 {
604         char buf[512];
605         char srch_str[128];
606         char rplc_str[128];
607         FILE *fp;
608         int a;
609         long rpos, wpos;
610         char *ptr;
611         int substitutions = 0;
612         long msglen = 0L;
613
614         scr_printf("Enter text to be replaced:\n: ");
615         getline(srch_str, (sizeof(srch_str)-1) );
616         if (strlen(srch_str) == 0)
617                 return;
618
619         scr_printf("Enter text to replace it with:\n: ");
620         getline(rplc_str, (sizeof(rplc_str)-1) );
621
622         fp = fopen(filename, "r+");
623         if (fp == NULL)
624                 return;
625
626         wpos = startpos;
627         fseek(fp, startpos, 0);
628         strcpy(buf, "");
629         while (a = getc(fp), a > 0) {
630                 ++msglen;
631                 buf[strlen(buf) + 1] = 0;
632                 buf[strlen(buf)] = a;
633                 if (strlen(buf) >= strlen(srch_str)) {
634                         ptr = (&buf[strlen(buf) - strlen(srch_str)]);
635                         if (!strncmp(ptr, srch_str, strlen(srch_str))) {
636                                 strcpy(ptr, rplc_str);
637                                 ++substitutions;
638                         }
639                 }
640                 if (strlen(buf) > 384) {
641                         rpos = ftell(fp);
642                         fseek(fp, wpos, 0);
643                         fwrite((char *) buf, 128, 1, fp);
644                         strcpy(buf, &buf[128]);
645                         wpos = ftell(fp);
646                         fseek(fp, rpos, 0);
647                 }
648         }
649         fseek(fp, wpos, 0);
650         if (strlen(buf) > 0)
651                 fwrite((char *) buf, strlen(buf), 1, fp);
652         wpos = ftell(fp);
653         fclose(fp);
654         truncate(filename, wpos);
655         scr_printf("<R>eplace made %d substitution(s).\n\n", substitutions);
656 }
657
658 /*
659  * Function to begin composing a new message
660  */
661 int client_make_message(char *filename, /* temporary file name */
662                 char *recipient,        /* NULL if it's not mail */
663                 int anon_type,          /* see MES_ types in header file */
664                 int format_type,
665                 int mode,
666                 char *subject)          /* buffer to store subject line */
667 {
668         FILE *fp;
669         int a, b, e_ex_code;
670         long beg;
671         char datestr[SIZ];
672         char header[SIZ];
673         int cksum = 0;
674
675         if (mode == 2)
676                 if (strlen(editor_path) == 0) {
677                         err_printf
678                             ("*** No editor available, using built-in editor\n");
679                         mode = 0;
680                 }
681
682         fmt_date(datestr, sizeof datestr, time(NULL), 0);
683         header[0] = 0;
684
685         if (room_flags & QR_ANONONLY && !recipient) {
686                 snprintf(header, sizeof header, " ****");
687         }
688         else {
689                 snprintf(header, sizeof header,
690                         " %s from %s", datestr, fullname);
691                 if (strlen(recipient) > 0) {
692                         size_t tmp = strlen(header);
693                         snprintf(&header[tmp], sizeof header - tmp,
694                                 " to %s", recipient);
695                 }
696         }
697         scr_printf("%s\n", header);
698         if (subject != NULL) if (strlen(subject) > 0) {
699                 scr_printf("Subject: %s\n", subject);
700         }
701
702         beg = 0L;
703
704         if (mode == 1) {
705                 scr_printf("(Press ctrl-d when finished)\n");
706         }
707
708         if (mode == 0) {
709                 fp = fopen(filename, "r");
710                 if (fp != NULL) {
711                         fmout(screenwidth, fp, NULL, NULL, 0, screenheight, 0, 0);
712                         beg = ftell(fp);
713                         fclose(fp);
714                 } else {
715                         fp = fopen(filename, "w");
716                         if (fp == NULL) {
717                                 err_printf("*** Error opening temp file!\n"
718                                         "    %s: %s\n",
719                                         filename, strerror(errno));
720                         return(1);
721                         }
722                         fclose(fp);
723                 }
724         }
725
726 ME1:    switch (mode) {
727
728         case 0:
729                 fp = fopen(filename, "r+");
730                 if (fp == NULL) {
731                         err_printf("*** Error opening temp file!\n"
732                                 "    %s: %s\n",
733                                 filename, strerror(errno));
734                         return(1);
735                 }
736                 citedit(fp);
737                 fclose(fp);
738                 goto MECR;
739
740         case 1:
741                 fp = fopen(filename, "a");
742                 if (fp == NULL) {
743                         err_printf("*** Error opening temp file!\n"
744                                 "    %s: %s\n",
745                                 filename, strerror(errno));
746                         return(1);
747                 }
748                 do {
749                         a = inkey();
750                         if (a == 255)
751                                 a = 32;
752                         if (a == 13)
753                                 a = 10;
754                         if (a != 4) {
755                                 putc(a, fp);
756                                 scr_putc(a);
757                         }
758                         if (a == 10)
759                                 scr_putc(10);
760                 } while (a != 4);
761                 fclose(fp);
762                 break;
763
764         case 2:
765                 e_ex_code = 1;  /* start with a failed exit code */
766                 editor_pid = fork();
767                 cksum = file_checksum(filename);
768                 if (editor_pid == 0) {
769                         char tmp[SIZ];
770
771                         chmod(filename, 0600);
772                         screen_reset();
773                         sttybbs(SB_RESTORE);
774                         snprintf(tmp, sizeof tmp, "WINDOW_TITLE=%s", header);
775                         putenv(tmp);
776                         execlp(editor_path, editor_path, filename, NULL);
777                         exit(1);
778                 }
779                 if (editor_pid > 0)
780                         do {
781                                 e_ex_code = 0;
782                                 b = ka_wait(&e_ex_code);
783                         } while ((b != editor_pid) && (b >= 0));
784                 editor_pid = (-1);
785                 sttybbs(0);
786                 screen_set();
787                 break;
788         }
789
790 MECR:   if (mode == 2) {
791                 if (file_checksum(filename) == cksum) {
792                         err_printf("*** Aborted message.\n");
793                         e_ex_code = 1;
794                 }
795                 if (e_ex_code == 0)
796                         goto MEFIN;
797                 goto MEABT2;
798         }
799
800         b = keymenu("Entry command (? for options)",
801                     "<A>bort|<C>ontinue|<S>ave message|<P>rint formatted|"
802                     "add s<U>bject|"
803                     "<R>eplace string|<H>old message");
804
805         if (b == 'a')
806                 goto MEABT;
807         if (b == 'c')
808                 goto ME1;
809         if (b == 's')
810                 goto MEFIN;
811         if (b == 'p') {
812                 scr_printf(" %s from %s", datestr, fullname);
813                 if (strlen(recipient) > 0)
814                         scr_printf(" to %s", recipient);
815                 scr_printf("\n");
816                 if (subject != NULL) if (strlen(subject) > 0) {
817                         scr_printf("Subject: %s\n", subject);
818                 }
819                 fp = fopen(filename, "r");
820                 if (fp != NULL) {
821                         fmout(screenwidth, fp, NULL, NULL,
822                               ((userflags & US_PAGINATOR) ? 1 : 0),
823                               screenheight, 0, 0);
824                         beg = ftell(fp);
825                         fclose(fp);
826                 }
827                 goto MECR;
828         }
829         if (b == 'r') {
830                 replace_string(filename, 0L);
831                 goto MECR;
832         }
833         if (b == 'h') {
834                 return (2);
835         }
836         if (b == 'u') {
837                 if (subject != NULL) {
838                         newprompt("Subject: ", subject, 70);
839                 }
840                 goto MECR;
841         }
842
843 MEFIN:  return (0);
844
845 MEABT:  scr_printf("Are you sure? ");
846         if (yesno() == 0) {
847                 goto ME1;
848         }
849 MEABT2: unlink(filename);
850         return (2);
851 }
852
853 /*
854  * Transmit message text to the server.
855  * 
856  * This loop also implements a "tick" counter that displays the progress, if
857  * we're sending something that will take a long time to transmit.
858  */
859 void transmit_message(FILE *fp)
860 {
861         char buf[SIZ];
862         int ch, a;
863         long msglen;
864         time_t lasttick;
865
866         fseek(fp, 0L, SEEK_END);
867         msglen = ftell(fp);
868         rewind(fp);
869         lasttick = time(NULL);
870         strcpy(buf, "");
871         while (ch = getc(fp), (ch >= 0)) {
872                 if (ch == 10) {
873                         if (!strcmp(buf, "000"))
874                                 strcpy(buf, ">000");
875                         serv_puts(buf);
876                         strcpy(buf, "");
877                 } else {
878                         a = strlen(buf);
879                         buf[a + 1] = 0;
880                         buf[a] = ch;
881                         if ((ch == 32) && (strlen(buf) > 200)) {
882                                 buf[a] = 0;
883                                 if (!strcmp(buf, "000"))
884                                         strcpy(buf, ">000");
885                                 serv_puts(buf);
886                                 strcpy(buf, "");
887                         }
888                         if (strlen(buf) > 250) {
889                                 if (!strcmp(buf, "000"))
890                                         strcpy(buf, ">000");
891                                 serv_puts(buf);
892                                 strcpy(buf, "");
893                         }
894                 }
895
896                 if ((time(NULL) - lasttick) > 2L) {
897                         scr_printf(" %3ld%% completed\r",
898                                ((ftell(fp) * 100L) / msglen));
899                         scr_flush();
900                         lasttick = time(NULL);
901                 }
902
903         }
904         serv_puts(buf);
905         scr_printf("                \r");
906         scr_flush();
907 }
908
909
910
911 /*
912  * entmsg()  -  edit and create a message
913  *              returns 0 if message was saved
914  */
915 int entmsg(int is_reply,        /* nonzero if this was a <R>eply command */
916                 int c)          /* */
917 {
918         char buf[300];
919         char cmd[SIZ];
920         int a, b;
921         int need_recp = 0;
922         int mode;
923         long highmsg;
924         FILE *fp;
925         char reply_to[SIZ];
926         char reply_subject[SIZ];
927         char subject[SIZ];
928
929         if (c > 0)
930                 mode = 1;
931         else
932                 mode = 0;
933
934         strcpy(subject, "");
935
936         /*
937          * First, check to see if we have permission to enter a message in
938          * this room.  The server will return an error code if we can't.
939          */
940         snprintf(cmd, sizeof cmd, "ENT0 0||0|%d", mode);
941         serv_puts(cmd);
942         serv_gets(cmd);
943
944         if ((strncmp(cmd, "570", 3)) && (strncmp(cmd, "200", 3))) {
945                 scr_printf("%s\n", &cmd[4]);
946                 return (1);
947         }
948
949         /* Error code 570 is special.  It means that we CAN enter a message
950          * in this room, but a recipient needs to be specified.
951          */
952         need_recp = 0;
953         if (!strncmp(cmd, "570", 3))
954                 need_recp = 1;
955
956         /* If the user is a dumbass, tell them how to type. */
957         if ((userflags & US_EXPERT) == 0) {
958                 formout("entermsg");
959         }
960
961         /* Handle the selection of a recipient, if necessary. */
962         strcpy(buf, "");
963         if (need_recp == 1) {
964                 if (axlevel >= 2) {
965                         if (is_reply) {
966                                 strcpy(buf, reply_to);
967                         } else {
968                                 scr_printf("Enter recipient: ");
969                                 getline(buf, (SIZ-100) );
970                                 if (strlen(buf) == 0)
971                                         return (1);
972                         }
973                 } else
974                         strcpy(buf, "sysop");
975         }
976
977         if (is_reply) {
978                 if (strlen(reply_subject) > 0) {
979                         if (!strncasecmp(reply_subject,
980                            "Re: ", 3)) {
981                                 strcpy(subject, reply_subject);
982                         }
983                         else {
984                                 snprintf(subject,
985                                         sizeof subject,
986                                         "Re: %s",
987                                         reply_subject);
988                         }
989                 }
990         }
991
992         b = 0;
993         if (room_flags & QR_ANONOPT) {
994                 scr_printf("Anonymous (Y/N)? ");
995                 if (yesno() == 1)
996                         b = 1;
997         }
998
999         /* If it's mail, we've got to check the validity of the recipient... */
1000         if (strlen(buf) > 0) {
1001                 snprintf(cmd, sizeof cmd, "ENT0 0|%s|%d|%d|%s", buf, b, mode, subject);
1002                 serv_puts(cmd);
1003                 serv_gets(cmd);
1004                 if (cmd[0] != '2') {
1005                         scr_printf("%s\n", &cmd[4]);
1006                         return (1);
1007                 }
1008         }
1009
1010         /* Learn the number of the newest message in in the room, so we can
1011          * tell upon saving whether someone else has posted too.
1012          */
1013         num_msgs = 0;
1014         serv_puts("MSGS LAST|1");
1015         serv_gets(cmd);
1016         if (cmd[0] != '1') {
1017                 scr_printf("%s\n", &cmd[5]);
1018         } else {
1019                 while (serv_gets(cmd), strcmp(cmd, "000")) {
1020
1021                         if ((num_msgs + 1) > msg_arr_size) {
1022                                 msg_arr_size += 512;
1023                                 msg_arr = realloc(msg_arr,
1024                                         ((sizeof(long)) * msg_arr_size) );
1025                         }
1026
1027                         msg_arr[num_msgs++] = atol(cmd);
1028                 }
1029         }
1030
1031         /* Now compose the message... */
1032         if (client_make_message(temp, buf, b, 0, c, subject) != 0) {
1033                 return (2);
1034         }
1035
1036         /* Reopen the temp file that was created, so we can send it */
1037         fp = fopen(temp, "r");
1038
1039         /* Yes, unlink it now, so it doesn't stick around if we crash */
1040         unlink(temp);
1041
1042         if (fp == NULL) {
1043                 err_printf("*** Internal error while trying to save message!\n"
1044                         "    %s: %s\n",
1045                         temp, strerror(errno));
1046                 return(errno);
1047         }
1048
1049         /* Transmit message to the server */
1050         snprintf(cmd, sizeof cmd, "ENT0 1|%s|%d|%d|%s|", buf, b, mode, subject);
1051         serv_puts(cmd);
1052         serv_gets(cmd);
1053         if (cmd[0] != '4') {
1054                 scr_printf("%s\n", &cmd[4]);
1055                 return (1);
1056         }
1057
1058         transmit_message(fp);
1059         serv_puts("000");
1060
1061         fclose(fp);
1062
1063         highmsg = msg_arr[num_msgs - 1];
1064         num_msgs = 0;
1065         serv_puts("MSGS NEW");
1066         serv_gets(cmd);
1067         if (cmd[0] != '1') {
1068                 scr_printf("%s\n", &cmd[5]);
1069         } else {
1070                 while (serv_gets(cmd), strcmp(cmd, "000")) {
1071                         msg_arr[num_msgs++] = atol(cmd);
1072                 }
1073         }
1074
1075         /* get new highest message number in room to set lrp for goto... */
1076         maxmsgnum = msg_arr[num_msgs - 1];
1077
1078         /* now see if anyone else has posted in here */
1079         b = (-1);
1080         for (a = 0; a < num_msgs; ++a) {
1081                 if (msg_arr[a] > highmsg) {
1082                         ++b;
1083                 }
1084         }
1085
1086         /* In the Mail> room, this algorithm always counts one message
1087          * higher than in public rooms, so we decrement it by one.
1088          */
1089         if (need_recp) {
1090                 --b;
1091         }
1092
1093         if (b == 1) {
1094                 scr_printf("*** 1 additional message has been entered "
1095                         "in this room by another user.\n");
1096         }
1097         else if (b > 1) {
1098                 scr_printf("*** %d additional messages have been entered "
1099                         "in this room by other users.\n", b);
1100         }
1101
1102         return(0);
1103 }
1104
1105 /*
1106  * Do editing on a quoted file
1107  */
1108 void process_quote(void)
1109 {
1110         FILE *qfile, *tfile;
1111         char buf[128];
1112         int line, qstart, qend;
1113
1114         /* Unlink the second temp file as soon as it's opened, so it'll get
1115          * deleted even if the program dies
1116          */
1117         qfile = fopen(temp2, "r");
1118         unlink(temp2);
1119
1120         /* Display the quotable text with line numbers added */
1121         line = 0;
1122         fgets(buf, 128, qfile);
1123         while (fgets(buf, 128, qfile) != NULL) {
1124                 scr_printf("%2d %s", ++line, buf);
1125         }
1126         scr_printf("Begin quoting at [ 1] : ");
1127         getline(buf, 3);
1128         qstart = (buf[0] == 0) ? (1) : atoi(buf);
1129         scr_printf("  End quoting at [%d] : ", line);
1130         getline(buf, 3);
1131         qend = (buf[0] == 0) ? (line) : atoi(buf);
1132         rewind(qfile);
1133         line = 0;
1134         fgets(buf, 128, qfile);
1135         tfile = fopen(temp, "w");
1136         while (fgets(buf, 128, qfile) != NULL) {
1137                 if ((++line >= qstart) && (line <= qend))
1138                         fprintf(tfile, " >%s", buf);
1139         }
1140         fprintf(tfile, " \n");
1141         fclose(qfile);
1142         fclose(tfile);
1143         chmod(temp, 0666);
1144 }
1145
1146
1147
1148 /*
1149  * List the URL's which were embedded in the previous message
1150  */
1151 void list_urls()
1152 {
1153         int i;
1154         char cmd[SIZ];
1155
1156         if (num_urls == 0) {
1157                 scr_printf("There were no URL's in the previous message.\n\n");
1158                 return;
1159         }
1160
1161         for (i = 0; i < num_urls; ++i) {
1162                 scr_printf("%3d %s\n", i + 1, urls[i]);
1163         }
1164
1165         if ((i = num_urls) != 1)
1166                 i = intprompt("Display which one", 1, 1, num_urls);
1167
1168         snprintf(cmd, sizeof cmd, rc_url_cmd, urls[i - 1]);
1169         system(cmd);
1170         scr_printf("\n");
1171 }
1172
1173 /*
1174  * Read the messages in the current room
1175  */
1176 void readmsgs(
1177         int c,          /* 0=Read all  1=Read new  2=Read old 3=Read last q */
1178         int rdir,       /* 1=Forward (-1)=Reverse */
1179         int q           /* Number of msgs to read (if c==3) */
1180 ) {
1181         int a, b, e, f, g, start;
1182         int savedpos;
1183         int hold_sw = 0;
1184         char arcflag = 0;
1185         char quotflag = 0;
1186         int hold_color = 0;
1187         char prtfile[PATH_MAX];
1188         char pagin;
1189         char cmd[SIZ];
1190         char targ[ROOMNAMELEN];
1191         char filename[SIZ];
1192         FILE *dest = NULL;      /* Alternate destination other than screen */
1193         int r;                          /* IPC response code */
1194
1195         if (c < 0)
1196                 b = (num_msgs - 1);
1197         else
1198                 b = 0;
1199
1200         strcpy(prtfile, tmpnam(NULL));
1201
1202         num_msgs = 0;
1203         strcpy(cmd, "MSGS ");
1204         switch (c) {
1205         case 0:
1206                 strcat(cmd, "ALL");
1207                 break;
1208         case 1:
1209                 strcat(cmd, "NEW");
1210                 break;
1211         case 2:
1212                 strcat(cmd, "OLD");
1213                 break;
1214         case 3:
1215                 snprintf(&cmd[5], sizeof cmd - 5, "LAST|%d", q);
1216                 break;
1217         }
1218         serv_puts(cmd);
1219         serv_gets(cmd);
1220         if (cmd[0] != '1') {
1221                 scr_printf("%s\n", &cmd[5]);
1222         } else {
1223                 while (serv_gets(cmd), strcmp(cmd, "000")) {
1224
1225                         if ((num_msgs + 1) > msg_arr_size) {
1226                                 msg_arr_size += 512;
1227                                 msg_arr = realloc(msg_arr,
1228                                         ((sizeof(long)) * msg_arr_size) );
1229                         }
1230
1231                         msg_arr[num_msgs++] = atol(cmd);
1232                 }
1233         }
1234
1235         if (num_msgs == 0) {
1236                 if (c == 3) return;
1237                 scr_printf("*** There are no ");
1238                 if (c == 1) scr_printf("new ");
1239                 if (c == 2) scr_printf("old ");
1240                 scr_printf("messages in this room.\n");
1241                 return;
1242         }
1243
1244         lines_printed = 0;
1245
1246         /* this loop cycles through each message... */
1247         start = ((rdir == 1) ? 0 : (num_msgs - 1));
1248         for (a = start; ((a < num_msgs) && (a >= 0)); a = a + rdir) {
1249                 while (msg_arr[a] == 0L) {
1250                         a = a + rdir;
1251                         if ((a == num_msgs) || (a == (-1)))
1252                                 return;
1253                 }
1254
1255 RAGAIN:         pagin = ((arcflag == 0)
1256                          && (quotflag == 0)
1257                          && (userflags & US_PAGINATOR)) ? 1 : 0;
1258
1259                 /* If we're doing a quote, set the screenwidth to 72 */
1260                 if (quotflag) {
1261                         hold_sw = screenwidth;
1262                         screenwidth = 72;
1263                 }
1264
1265                 /* If printing or archiving, set the screenwidth to 80 */
1266                 if (arcflag) {
1267                         hold_sw = screenwidth;
1268                         screenwidth = 80;
1269                 }
1270
1271                 /* now read the message... */
1272                 e = read_message(msg_arr[a], pagin, dest);
1273
1274                 /* ...and set the screenwidth back if we have to */
1275                 if ((quotflag) || (arcflag)) {
1276                         screenwidth = hold_sw;
1277                 }
1278 RMSGREAD:       scr_flush();
1279                 highest_msg_read = msg_arr[a];
1280                 if (quotflag) {
1281                         fclose(dest);
1282                         dest = NULL;
1283                         quotflag = 0;
1284                         enable_color = hold_color;
1285                         process_quote();
1286                 }
1287                 if (arcflag) {
1288                         fclose(dest);
1289                         dest = NULL;
1290                         arcflag = 0;
1291                         enable_color = hold_color;
1292                         f = fork();
1293                         if (f == 0) {
1294                                 freopen(prtfile, "r", stdin);
1295                                 screen_reset();
1296                                 sttybbs(SB_RESTORE);
1297                                 ka_system(printcmd);
1298                                 sttybbs(SB_NO_INTR);
1299                                 screen_set();
1300                                 unlink(prtfile);
1301                                 exit(0);
1302                         }
1303                         if (f > 0)
1304                                 do {
1305                                         g = wait(NULL);
1306                                 } while ((g != f) && (g >= 0));
1307                         scr_printf("Message printed.\n");
1308                 }
1309                 if (rc_alt_semantics && c == 1) {
1310                         char buf[SIZ];
1311
1312                         r = CtdlIPCSetMessageSeen(msg_arr[a], 1, buf);
1313                 }
1314                 if (e == 3)
1315                         return;
1316                 if (((userflags & US_NOPROMPT) || (e == 2))
1317                     && (((room_flags & QR_MAILBOX) == 0)
1318                         || (rc_force_mail_prompts == 0))) {
1319                         e = 'n';
1320                 } else {
1321                         color(DIM_WHITE);
1322                         scr_printf("(");
1323                         color(BRIGHT_WHITE);
1324                         scr_printf("%d", num_msgs - a - 1);
1325                         color(DIM_WHITE);
1326                         scr_printf(") ");
1327
1328                         keyopt("<B>ack <A>gain <Q>uote <R>eply <N>ext <S>top m<Y> next ");
1329                         if (rc_url_cmd[0] && num_urls)
1330                                 keyopt("<U>RLview ");
1331                         keyopt("<?>help -> ");
1332
1333                         do {
1334                                 lines_printed = 2;
1335                                 e = (inkey() & 127);
1336                                 e = tolower(e);
1337 /* return key same as <N> */ if (e == 10)
1338                                         e = 'n';
1339 /* space key same as <N> */ if (e == 32)
1340                                         e = 'n';
1341 /* del/move for aides only */
1342                                     if ((!is_room_aide)
1343                                         && ((room_flags & QR_MAILBOX) ==
1344                                             0)) {
1345                                         if ((e == 'd') || (e == 'm'))
1346                                                 e = 0;
1347                                 }
1348 /* print only if available */
1349                                 if ((e == 'p') && (strlen(printcmd) == 0))
1350                                         e = 0;
1351 /* can't file if not allowed */
1352                                     if ((e == 'f')
1353                                         && (rc_allow_attachments == 0))
1354                                         e = 0;
1355 /* link only if browser avail*/
1356                                     if ((e == 'u')
1357                                         && (strlen(rc_url_cmd) == 0))
1358                                         e = 0;
1359                         } while ((e != 'a') && (e != 'n') && (e != 's')
1360                                  && (e != 'd') && (e != 'm') && (e != 'p')
1361                                  && (e != 'q') && (e != 'b') && (e != 'h')
1362                                  && (e != 'r') && (e != 'f') && (e != '?')
1363                                  && (e != 'u') && (e != 'c') && (e != 'y'));
1364                         switch (e) {
1365                         case 's':
1366                                 scr_printf("Stop");
1367                                 break;
1368                         case 'a':
1369                                 scr_printf("Again");
1370                                 break;
1371                         case 'd':
1372                                 scr_printf("Delete");
1373                                 break;
1374                         case 'm':
1375                                 scr_printf("Move");
1376                                 break;
1377                         case 'c':
1378                                 scr_printf("Copy");
1379                                 break;
1380                         case 'n':
1381                                 scr_printf("Next");
1382                                 break;
1383                         case 'p':
1384                                 scr_printf("Print");
1385                                 break;
1386                         case 'q':
1387                                 scr_printf("Quote");
1388                                 break;
1389                         case 'b':
1390                                 scr_printf("Back");
1391                                 break;
1392                         case 'h':
1393                                 scr_printf("Header");
1394                                 break;
1395                         case 'r':
1396                                 scr_printf("Reply");
1397                                 break;
1398                         case 'f':
1399                                 scr_printf("File");
1400                                 break;
1401                         case 'u':
1402                                 scr_printf("URL's");
1403                                 break;
1404                         case 'y':
1405                                 scr_printf("mY next");
1406                                 break;
1407                         case '?':
1408                                 scr_printf("? <help>");
1409                                 break;
1410                         }
1411                         if (userflags & US_DISAPPEAR)
1412                                 scr_printf("\r%79s\r", "");
1413                         else
1414                                 scr_printf("\n");
1415                         scr_flush();
1416                 }
1417                 switch (e) {
1418                 case '?':
1419                         scr_printf("Options available here:\n"
1420                                 " ?  Help (prints this message)\n"
1421                                 " S  Stop reading immediately\n"
1422                                 " A  Again (repeats last message)\n"
1423                                 " N  Next (continue with next message)\n"
1424                                 " Y  My Next (continue with next message you authored)\n"
1425                                 " B  Back (go back to previous message)\n");
1426                         if ((is_room_aide)
1427                             || (room_flags & QR_MAILBOX)) {
1428                                 scr_printf(" D  Delete this message\n"
1429                                         " M  Move message to another room\n");
1430                         }
1431                         scr_printf(" C  Copy message to another room\n");
1432                         if (strlen(printcmd) > 0)
1433                                 scr_printf(" P  Print this message\n");
1434                         scr_printf(
1435                                 " Q  Quote portions of this message for your next post\n"
1436                                 " H  Headers (display message headers only)\n");
1437                         if (is_mail)
1438                                 scr_printf(" R  Reply to this message\n");
1439                         if (rc_allow_attachments)
1440                                 scr_printf
1441                                     (" F  (save attachments to a file)\n");
1442                         if (strlen(rc_url_cmd) > 0)
1443                                 scr_printf(" U  (list URL's for display)\n");
1444                         scr_printf("\n");
1445                         goto RMSGREAD;
1446                 case 'p':
1447                         scr_flush();
1448                         dest = fopen(prtfile, "w");
1449                         arcflag = 1;
1450                         hold_color = enable_color;
1451                         enable_color = 0;
1452                         goto RAGAIN;
1453                 case 'q':
1454                         scr_flush();
1455                         dest = fopen(temp2, "w");
1456                         quotflag = 1;
1457                         hold_color = enable_color;
1458                         enable_color = 0;
1459                         goto RAGAIN;
1460                 case 's':
1461                         return;
1462                 case 'a':
1463                         goto RAGAIN;
1464                 case 'b':
1465                         a = a - (rdir * 2);
1466                         break;
1467                 case 'm':
1468                 case 'c':
1469                         newprompt("Enter target room: ",
1470                                   targ, ROOMNAMELEN - 1);
1471                         if (strlen(targ) > 0) {
1472                                 r = CtdlIPCMoveMessage((e == 'c' ? 1 : 0),
1473                                                        msg_arr[a], targ, cmd);
1474                                 scr_printf("%s\n", cmd);
1475                                 if (r / 100 == 2)
1476                                         msg_arr[a] = 0L;
1477                         } else {
1478                                 goto RMSGREAD;
1479                         }
1480                         if (r / 100 != 2)       /* r will be init'ed, FIXME */
1481                                 goto RMSGREAD;  /* the logic here sucks */
1482                         break;
1483                 case 'f':
1484                         newprompt("Which section? ", filename,
1485                                   ((sizeof filename) - 1));
1486                         snprintf(cmd, sizeof cmd,
1487                                  "OPNA %ld|%s", msg_arr[a], filename);
1488                         serv_puts(cmd);
1489                         serv_gets(cmd);
1490                         if (cmd[0] == '2') {
1491                                 extract(filename, &cmd[4], 2);
1492                                 download_to_local_disk(filename,
1493                                                        extract_int(&cmd[4],
1494                                                                    0));
1495                         } else {
1496                                 scr_printf("%s\n", &cmd[4]);
1497                         }
1498                         goto RMSGREAD;
1499                 case 'd':
1500                         scr_printf("*** Delete this message? ");
1501                         if (yesno() == 1) {
1502                                 r = CtdlIPCDeleteMessage(msg_arr[a], cmd);
1503                                 scr_printf("%s\n", cmd);
1504                                 if (r / 100 == 2)
1505                                         msg_arr[a] = 0L;
1506                         } else {
1507                                 goto RMSGREAD;
1508                         }
1509                         break;
1510                 case 'h':
1511                         read_message(msg_arr[a], READ_HEADER, NULL);
1512                         goto RMSGREAD;
1513                 case 'r':
1514                         savedpos = num_msgs;
1515                         entmsg(1, (DEFAULT_ENTRY == 46 ? 2 : 0));
1516                         num_msgs = savedpos;
1517                         goto RMSGREAD;
1518                 case 'u':
1519                         list_urls();
1520                         goto RMSGREAD;
1521             case 'y':
1522           { /* hack hack hack */
1523             /* find the next message by me, stay here if we find nothing */
1524             int finda;
1525             int lasta = a;
1526             for (finda = a; ((finda < num_msgs) && (finda >= 0)); finda += rdir)
1527               {
1528                 /* This is repetitively dumb, but that's what computers are for.
1529                    We have to load up messages until we find one by us */
1530                 char buf[SIZ];
1531                 int founda = 0;
1532                 
1533                 snprintf(buf, sizeof buf, "MSG0 %ld|1", msg_arr[finda]); /* read the header so we can get 'from=' */
1534                 serv_puts(buf);
1535                 serv_gets(buf);
1536                 while (serv_gets(buf), strcmp(buf, "000")) 
1537                   {
1538                         if ((!strncasecmp(buf, "from=", 5)) && (finda != a)) /* Skip current message. */
1539                       { 
1540                         if (strcasecmp(buf+5, fullname) == 0)
1541                           {
1542                             a = lasta; /* meesa current */
1543                             founda = 1;
1544                           }
1545                           }
1546                   }
1547                     // we are now in synch with the server
1548                 if (founda)
1549                   break; /* for */
1550                 lasta = finda; /* keep one behind or we skip on the reentrance to the for */
1551               } /* for */
1552           } /* case 'y' */
1553       } /* switch */
1554         }                       /* end for loop */
1555 }                               /* end read routine */
1556
1557
1558
1559
1560 /*
1561  * View and edit a system message
1562  */
1563 void edit_system_message(char *which_message)
1564 {
1565         char desc[64];
1566         char read_cmd[64];
1567         char write_cmd[64];
1568
1569         snprintf(desc, sizeof desc, "system message '%s'", which_message);
1570         snprintf(read_cmd, sizeof read_cmd, "MESG %s", which_message);
1571         snprintf(write_cmd, sizeof write_cmd, "EMSG %s", which_message);
1572         do_edit(desc, read_cmd, "NOOP", write_cmd);
1573 }
1574
1575
1576
1577
1578 /*
1579  * Verify the message base
1580  */
1581 void check_message_base(void)
1582 {
1583         char buf[SIZ];
1584
1585         scr_printf
1586             ("Please read the documentation before running this command.\n"
1587             "Having done so, do you still want to check the message base? ");
1588         if (yesno() == 0)
1589                 return;
1590
1591         serv_puts("FSCK");
1592         serv_gets(buf);
1593         if (buf[0] != '1') {
1594                 scr_printf("%s\n", &buf[4]);
1595                 return;
1596         }
1597
1598         while (serv_gets(buf), strcmp(buf, "000")) {
1599                 scr_printf("%s\n", buf);
1600         }
1601 }