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