1 /*
2 ATP QWK MAIL READER FOR READING AND REPLYING TO QWK MAIL PACKETS.
3 Copyright (C) 1992, 1993, 1997 Thomas McWilliams
4 Copyright (C) 1990 Rene Cougnenc
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22 read.c
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include "reader.h"
32 #include "readlib.h"
33 #include "makemail.h"
34 #include "qlib.h"
35 #include "ansi.h"
36 #ifdef __LCLINT__
37 #endif
38
39 /*
40 * str2mem - copies a string without the trailing null character.
41 * used to correctly fill the Qmail header.
42 */
43 void
str2mem(char * mem,const char * str)44 str2mem(char *mem, const char *str)
45 {
46 while (*str != NUL_CHAR) {
47 *mem = *str;
48 str++;
49 mem++;
50 }
51 }
52
53
54 /*
55 * Numeric - returns TRUE if the string is a number or FALSE if not.
56 */
57 atp_BOOL_T
Numeric(const char * str)58 Numeric(const char *str)
59 {
60 atp_BOOL_T ret_code = FALSE;
61 if (*str != NUL_CHAR) {
62 while (*str != NUL_CHAR && '0' <= *str && *str <= '9')
63 str++;
64 if (*str == NUL_CHAR)
65 ret_code = TRUE;
66 }
67 return ret_code;
68 }
69
70
71 /*
72 * Date - displays the date and time.
73 */
74 void
Date(void)75 Date(void)
76 {
77 time_t t;
78 const size_t length_of_date_string = DATE_LEN ;
79 char date_string[DATE_LEN+1];
80
81 blue();
82 high();
83 /*@i1*/ time(&t);
84 tzset();
85 /* this macro is used only by msdos and its relatives */
86 ADJUST_DOS_TIME
87 (void) memcpy(date_string, ctime(&t), length_of_date_string);
88 date_string[ length_of_date_string ] = (char)0;
89 printf("%s", date_string);
90 green();
91 printf("\n");
92 }
93
94
95 /*
96 * show_again - re-displays the current message.
97 */
98 void
show_again(void)99 show_again(void)
100 {
101 if (get_FirstDone())
102 Display(NEXT, NULL, 0);
103 else
104 ReadNext(NEXT);
105 }
106
107
108 /*
109 * enter_msg - invokes Reply() routines to post a message.
110 */
111 void
enter_msg(char * tmp)112 enter_msg(char *tmp)
113 {
114 if (get_CurConf() == RCONF_IDX && tmp[1] == NUL_CHAR && get_FirstDone())
115 Reply(CHANGE, tmp);
116 else
117 Reply(ENTER, tmp);
118 }
119
120
121 /*
122 * reply_msg - post reply to current message.
123 */
124 void
reply_msg(const char * tmp)125 reply_msg(const char *tmp)
126 {
127 if (get_FirstDone() && get_CurConf() != RCONF_IDX)
128 Reply(REPLY, tmp);
129 }
130
131
132 /*
133 * xpost_msg - copy a perviously entered reply to another message area.
134 */
135 void
xpost_msg(const char * tmp)136 xpost_msg(const char *tmp)
137 {
138 if (get_CurConf() == RCONF_IDX && get_FirstDone())
139 Reply(XPOST, tmp);
140 }
141
142
143 /*
144 * change_msg - re-edit a message in the reply conference.
145 */
146 void
change_msg(const char * tmp)147 change_msg(const char *tmp)
148 {
149 if (get_CurConf() == RCONF_IDX && get_FirstDone())
150 Reply(CHANGE, tmp);
151 }
152
153
154 /*
155 * mark_private - marks the current message as private.
156 */
157 void
mark_private(void)158 mark_private(void)
159 {
160 if (get_CurConf() == RCONF_IDX)
161 ReadNext(PRIVATE);
162 }
163
164
165 /*
166 * FindActive, search conference array for next active conference.
167 * it will wrap around to start if need be.
168 */
169 static int
FindActive(const int curcon)170 FindActive(const int curcon)
171 {
172 int i;
173 for (i = curcon + 1; i <= LastConf; i++) {
174 if (ConfActive[i])
175 return (i);
176 }
177 for (i = 0; i <= curcon; i++) {
178 if (ConfActive[i])
179 return (i);
180 }
181 return FAILURE;
182 }
183
184
185 /*
186 * more - prompts "more ?" and wait for yes/oui/ja and returns TRUE for yes.
187 * returns FALSE for no, 'def ' manages the CR default answer.
188 */
189 atp_BOOL_T
more(atp_BOOL_T def)190 more(atp_BOOL_T def)
191 {
192 atp_BOOL_T ret_code = TRUE;
193 atp_BOOL_T loop_flag = TRUE;
194 char *response, tmp[80];
195
196 do {
197 high();
198 yellow();
199 luxptr = NULL;
200 sprintf(tmp, "\r %s ? %s : ", txt[60], def? txt[106] : txt[107]);
201 do {
202 response = readline(tmp, no_scroll);
203 } while (response == NULL);
204 strcpy(tmp, response);
205 free_string(response);
206 clear();
207 printf("\r %-75s \r", " "); /* erase prompt */
208 switch ((int) tmp[0]) {
209 case 'o':
210 case 'y':
211 case 'O':
212 case 'Y':
213 case 'j':
214 case 'J':
215 ret_code = TRUE;
216 loop_flag = FALSE;
217 break;
218 case 'N':
219 case 'n':
220 ret_code = FALSE;
221 loop_flag = FALSE;
222 break;
223 case '+':
224 case '-':
225 case 0: /* CR */
226 case 10:
227 if (def) {
228 ret_code = TRUE;
229 } else {
230 ret_code = FALSE;
231 }
232 loop_flag = FALSE;
233 }
234 } while (loop_flag);
235 return ret_code;
236 }
237
238
239 /*
240 * YesNo - prompts "Y/N : " and wait for yes/oui/ja then returns TRUE for yes.
241 */
242 atp_BOOL_T
YesNo(atp_BOOL_T def,const char * prmt)243 YesNo(atp_BOOL_T def, const char *prmt)
244 {
245 atp_BOOL_T ret_code = TRUE;
246 atp_BOOL_T loop_flag = TRUE;
247 char *response, tmp[80];
248
249 do {
250 luxptr = NULL;
251 sprintf(tmp, "\r%s %s : ", prmt, def? txt[106] : txt[107]);
252 do {
253 response = readline(tmp, no_scroll);
254 } while (response == NULL);
255 strcpy(tmp, response);
256 free_string(response);
257 clear();
258 printf("\r %-75s \r", " "); /* erase prompt */
259 switch ((int) tmp[0]) {
260 case 'o':
261 case 'y':
262 case 'O':
263 case 'Y':
264 case 'j':
265 case 'J':
266 ret_code = TRUE;
267 loop_flag = FALSE;
268 break;
269 case 'N':
270 case 'n':
271 ret_code = FALSE;
272 loop_flag = FALSE;
273 break;
274 case 0: /* CR */
275 case 10:
276 if (def)
277 ret_code = TRUE;
278 else
279 ret_code = FALSE;
280 loop_flag = FALSE;
281 }
282 } while (loop_flag);
283 return ret_code;
284 }
285
286
287 /*
288 * Chk4RepPkt - returns TRUE if bbsname.rep exists.
289 */
290 atp_BOOL_T
Chk4RepPkt(void)291 Chk4RepPkt(void)
292 {
293 atp_BOOL_T ret_code = FALSE;
294 char RepFile[MAXPATHS];
295
296 sprintf(RepFile, "%s%s.rep", ReplyPath, CurBoard);
297 if (access(RepFile, F_OK) == SUCCESS) {
298 char prmbuf[80];
299 red();
300 high();
301 /* "Warning ! file already exist " "delete it ?" */
302 printf("%s %s %s %s...!\n", txt[2], txt[62], RepFile, txt[63]);
303 sprintf(prmbuf, " %s ", txt[64]);
304 if (YesNo(YES, prmbuf))
305 do_unlink(RepFile);
306 else
307 ret_code = TRUE;
308 }
309 return ret_code;
310 }
311
312
313 /*
314 * chkerror - si un rigolo tape ce mot dans le shell.
315 */
316 void
chkerror(void)317 chkerror(void)
318 {
319 magenta();
320 high();
321 printf("\n");
322 switch (get_charset()) {
323 case ISOLAT1:
324 printf("Calice! Esp�ce");
325 break;
326 case CHRDOS:
327 printf("Calice! Esp�ce");
328 break;
329 default:
330 printf("Calice! Espece");
331 }
332 printf(" de petit connard, on t'a pas appris la politesse ???%c\n", BELL);
333 printf("Va te faire foutre !!!\n\n");
334 clear();
335 fflush(stdout);
336 }
337
338
339 /*
340 * LoadStat, called by DoLoad().
341 */
342 static atp_BOOL_T
LoadStat(char * OldDat,char * NewDat)343 LoadStat(char *OldDat, char *NewDat)
344 {
345 atp_BOOL_T ret_code = TRUE;
346 struct stat Oldst, Newst;
347 Newst.st_mtime = Oldst.st_mtime = 0L;
348 if (stat(OldDat, &Oldst) == FAILURE) {
349 printf("Load() Can't stat OldDat %s:%d\n",__FILE__,__LINE__);
350 (void) sleep(3);
351 }
352 if (stat(NewDat, &Newst) == FAILURE) {
353 printf("Load() Can't stat NewDat %s:%d\n",__FILE__,__LINE__);
354 (void) sleep(3);
355 }
356 if (Newst.st_mtime <= Oldst.st_mtime) {
357 char CONSPTR prmbuf = NewDat;
358 red();
359 high();
360 /* "New packet older..." */
361 printf("%s\n%s.\n", txt[2], txt[11]);
362 /* " Do you want to load it? " */
363 sprintf(prmbuf, "%s...", txt[12]);
364 if (!YesNo(NO, prmbuf))
365 ret_code = FALSE;
366 }
367 return ret_code;
368 }
369
370 /* used by DoLoad(), AutoJoin(), Read(), */
371 static atp_BOOL_T newmail = TRUE;
372
373 /* used by many routines in this file */
374 static atp_BOOL_T IsEmpty = TRUE; /* Flag false if a BBS is loaded */
375
376 /*
377 * get_isempty - allows global read access to IsEmpty variable.
378 */
379 atp_BOOL_T
get_isempty(void)380 get_isempty(void)
381 {
382 return IsEmpty;
383 }
384
385 /*
386 * UpdateConf - update last message read in index file.
387 */
388 void
UpdateConf(const update_command_t mode)389 UpdateConf(const update_command_t mode)
390 {
391 assert(/*@i2*/ mode == update_last_read_ptr || mode == reset_last_read_ptr);
392 if (get_ActvCnt() < 1 || !ConfActive[get_CurConf()]) {
393 deleol();
394 printf("No active conference to update.\n");
395 if (get_FilesOpen()) {
396 printf("ERROR: %s:%d UpdateConf() -- open files, inactive Conf\n", __FILE__, __LINE__);
397 printf("ActvCnt = %d CurAct = %d \n", get_ActvCnt(), (int) ConfActive[get_CurConf()]);
398 };
399 } else if (!get_FilesOpen()) {
400 printf("ERROR: module UpdateConf() -- bad file pointer for fseek()\n");
401 } else if (fseek(fidx, 0L, SEEK_SET) != SUCCESS) {
402 printf("UpdateConf() Seek error...\n");
403 } else {
404 struct MyIndex Idx;
405 fread((char *) &Idx, index_SIZE, one_record, fidx);
406 if (((Idx.LastRead < get_MsgNum()) || /*@i1*/ mode == reset_last_read_ptr) && get_FirstDone()) {
407 long here;
408 Idx.LastRead = get_MsgNum();
409 rewind(fidx);
410 fwrite((char *) &Idx, index_SIZE, one_record, fidx);
411 printf("%s.\n", txt[66]); /* "Last read pointer updated" */
412 here = Idx.LastRead * IDXSIZE;
413 fseek(fidx, here, SEEK_SET);
414 }
415 }
416 }
417
418
419 /*
420 * DoLoad, update BBS archive from files in working directory.
421 * called from Load(). OldDat points to buffers of size MAXPATHS.
422 * NewDat points to the new control.dat file in the work directory.
423 */
424
425 static int CurConf = 0;
426
427 /*
428 * get_CurConf - returns the number of the current conference.
429 */
430 int
get_CurConf(void)431 get_CurConf(void)
432 {
433 return CurConf;
434 }
435
436
437 /*
438 * set_CurConf - sets the number of the current conference.
439 */
440 void
set_CurConf(const int num,const scnf_access_t perm)441 set_CurConf(const int num, const scnf_access_t perm)
442 {
443 if (/*@i1*/ scnf_GetConf == perm)
444 CurConf = num;
445 #ifdef ATPDBG
446 else
447 assert(/*@i1*/ scnf_GetConf == perm);
448 #endif
449 }
450
451
452 /*
453 * DoLoad_MkIndex, after DoLoad() sets up, make index and clean up.
454 */
455 static void
DoLoad_MkIndex(const char * BbsDir,const char * BbsName)456 DoLoad_MkIndex(const char *BbsDir, const char *BbsName)
457 {
458 if (/*@i1*/ MkIndex(WorkPath, BbsDir) == ATP_OK) {
459 /* update array of active conferences */
460 set_CurBoard(BbsName, cb_DoLoad_MkIndex);
461 ActvConf();
462 (void) Chk4RepPkt();
463 Chk4RepCnf(BbsDir);
464 if (get_FilesOpen()) {
465 fclose_fmsg_fidx();
466 }
467 IsEmpty = FALSE;
468 newmail = TRUE;
469 set_caps(fido ? FALSE : TRUE);
470 if (get_pmail())
471 CurConf = findCindex(PERS_CONF);
472 else
473 CurConf = FindActive(LastConf);
474 if (CurConf < 0)
475 CurConf = 0;
476 }
477 }
478
479
480 /*
481 * DoLoad, called by LoadExtract(), does setup for DoLoad_MkIndex().
482 */
483 static void
DoLoad(char * BbsName,char * OldDat,char * NewDat)484 DoLoad(char *BbsName, char *OldDat, char *NewDat)
485 {
486 char BbsDir[MAXPATHS];
487 /* Access to a board subdir */
488 sprintf(BbsDir, "%s%s", HomePath, BbsName);
489 if (access(BbsDir, R_OK | W_OK) == FAILURE)
490 my_mkdir(BbsDir);
491 sprintf(OldDat, "%s%s%c%s", HomePath, BbsName, SEP, CNTRL_FILE);
492
493 /* If there exists an old control.dat */
494 if (access(OldDat, F_OK) == FAILURE || LoadStat(OldDat, NewDat)) {
495 if (!IsEmpty && ConfActive[CurConf])
496 UpdateConf(update_last_read_ptr);
497 /* Create Index Files */
498 DoLoad_MkIndex(BbsDir,BbsName);
499 GetConf(CurConf);
500 }
501 assert(!get_isempty() || (fmsg == NULL && fidx == NULL));
502 }
503
504 #ifdef NONUM
505 /*
506 * For problems with Searchlight BBS,
507 * don't use it unless you *really* need it.
508 */
509 static void
SearchlightCruft(char * BbsName,int i)510 SearchlightCruft(char *BbsName, int i)
511 {
512 char *tptr = BbsName;
513 if (!Numeric(tptr)) /* strip trailing packet sequence numbers */
514 while (isdigit(BbsName[--i]))
515 BbsName[i] = NUL_CHAR;
516 }
517 #endif
518
519 /*
520 * LoadExtract, called by Load().
521 */
522 static void
LoadExtract(char * BbsName,char * tmp1)523 LoadExtract(char *BbsName, char *tmp1)
524 {
525 if (access(tmp1, R_OK) == FAILURE) {
526 red();
527 /* No mail found */
528 printf("%s : %s\n", txt[6], tmp1);
529 printf("%s\n", txt[7]); /* Try the read command */
530 } else {
531 char tmp2[MAXPATHS];
532 /* Don't forget to clean work directory ! */
533 Clean();
534 yellow();
535 high();
536 /* " Extracting Messages..." */
537 printf("%s\n", txt[8]);
538 green();
539 fflush(stdout);
540 /*@-usedef */
541 /* save current directory */
542 GETCWD(tmp2, MAXPATHS);
543 /*@=usedef */
544 /* change to work directory */
545 if (CHPATH(WorkPath) != SUCCESS) {
546 yellow();
547 printf("Error: can't access workpath: %s\n", WorkPath);
548 } else {
549 char CONSPTR unarc = get_atprc_str(unarchvr);
550 assert(unarc != NULL);
551 fork_execvp(unarc, tmp1);
552 free_string(unarc);
553 CHPATH(tmp2); /* restore current directory */
554 yellow();
555 if(verify_new_file( tmp2, WorkPath, CNTRL_FILE) == ATP_ERROR)
556 printf("txt[49]: %s\n", tmp2);
557 else
558 DoLoad(BbsName, tmp1, tmp2);
559 }
560 }
561 }
562
563
564 /*
565 * Load - get a qwk packet; toss it then display it.
566 */
567 void
Load(const char * name)568 Load(const char *name)
569 {
570 char BbsName[50], tmp1[MAXPATHS];
571 /* reset global flag to indicate no personal mail yet */
572 set_pmail(FALSE, pmLoad); /* should this be moved ??? */
573 query_rep_exists();
574 BbsName[0] = NUL_CHAR;
575 sscanf(name, "%s %s", tmp1, BbsName);
576 if (BbsName[0] == NUL_CHAR) {
577 red();
578 printf("%s %s\n", txt[87], txt[88]); /* "usage" " load.." */
579 } else {
580 int i = -1;
581 printf("\n%s %s\n", txt[5], BbsName); /* "Loading" */
582 if (strstr(BbsName, ".qw") == NULL)
583 strcat(BbsName, ".qwk");
584 sprintf(tmp1, "%s%s", MailPath, BbsName);
585 /*
586 * Now that we've used BbsName to id the packet file,
587 * strip any trailing suffix.
588 */
589 while (BbsName[++i] != NUL_CHAR)/* empty loop */
590 ;
591 while (BbsName[--i] != '.') /* empty loop */
592 ;
593 BbsName[i] = NUL_CHAR;
594 #ifdef NONUM
595 /* do not use, this is a kludge only for Searchlight BBS problems */
596 SearchlightCruft(BbsName, i);
597 #endif
598 LoadExtract(BbsName, tmp1);
599 }
600 }
601
602
603 /*
604 * VerifyBBS, check for existing BBS and control.dat file.
605 *
606 */
607 static atp_BOOL_T
VerifyBBS(const char * BbsName,char * buf)608 VerifyBBS(const char *BbsName, char *buf)
609 {
610 atp_BOOL_T ret_code = FALSE;
611 sprintf(buf, "%s%s%c%s", HomePath, BbsName, SEP, CNTRL_FILE);
612 if (access(buf, F_OK) == FAILURE) {
613 printf("%s : %s\n", txt[13], buf); /* "No bbs found " */
614 } else {
615 sprintf(buf, "%s%s", HomePath, BbsName);
616 if (/*@i1*/ RdCn_ReadControl(buf) != ATP_OK) {
617 printf("%s: %s\n", buf, txt[14]); /* "Error in CONTROL.DAT." */
618 } else {
619 ret_code = TRUE;
620 }
621 }
622 return ret_code;
623 }
624
625
626 /*
627 * ReadExecute, after setup by Read() this changes to another BBS.
628 */
629 static void
ReadExecute(const char * BbsName,char * tmp_buffer)630 ReadExecute(const char *BbsName, char *tmp_buffer)
631 {
632 if (VerifyBBS(BbsName, tmp_buffer)) {
633 printf("%s %s\n", txt[5], BbsName); /* "Loading" */
634 set_CurBoard(BbsName, cb_Read);
635 (void) Chk4RepPkt();
636 Chk4RepCnf(tmp_buffer);
637 if (get_FilesOpen()) {
638 fclose_fmsg_fidx();
639 }
640 /* update boolean array of active/inactive flags */
641 ActvConf();
642 IsEmpty = FALSE; /* should this be set inside of GetConf()? !!! */
643 newmail = FALSE;
644 set_caps(fido ? FALSE : TRUE);
645 CurConf = FindActive(LastConf);
646 if (CurConf < 0)
647 CurConf = 0;
648 }
649 }
650
651
652 /*
653 * Read - join a BBS without extracting new mail.
654 */
655 void
Read(const char * cmd_line)656 Read(const char *cmd_line)
657 {
658 char BbsName[50];
659 char tmp_buffer[MAXPATHS];
660 query_rep_exists();
661 BbsName[0] = NUL_CHAR;
662 sscanf(cmd_line, "%s %s", tmp_buffer, BbsName);
663 if (BbsName[0] == NUL_CHAR) {
664 red();
665 printf("%s %s\n", txt[87], txt[89]); /* "usage " "rev..." */
666 } else {
667 if (!IsEmpty && ConfActive[CurConf])
668 UpdateConf(update_last_read_ptr);
669 ReadExecute(BbsName, tmp_buffer);
670 GetConf(CurConf);
671 }
672 #ifdef ATPDBG
673 assert(!get_isempty() || !get_FilesOpen());
674 assert(!get_FilesOpen() || ( fmsg != NULL && fidx != NULL ));
675 #endif
676 }
677
678 static const int not_found = -1 ;
679 /*
680 * chcon_string_parse, turn a conference string into a conference index.
681 */
682 static int
chcon_string_parse(char * Name,const char * buf,char * tmp)683 chcon_string_parse(char *Name, const char *buf, char *tmp)
684 {
685 int i = 0 ;
686 strcpy(tmp, strstr(buf, Name));
687 strcpy(Name, tmp);
688 for (i = 0; i <= LastConf; i++) {
689 if (stricmp(Name, ConfNames[i]) == SUCCESS)
690 break;
691 }
692 if (i > LastConf) {
693 const size_t m = strlen(Name);
694 for (i = 0; i <= LastConf; i++) {
695 if (strnicmp(Name, ConfNames[i], m) == SUCCESS)
696 break;
697 }
698 }
699 return ( i > LastConf ? not_found : i ) ;
700 }
701
702
703 /*
704 * chcon_scan, turn absolute conf number or name into a conference index.
705 */
706 static int
chcon_scan(char * Name,const char * buf,char * tmp)707 chcon_scan(char *Name, const char *buf, char *tmp)
708 {
709 int i;
710 if (Numeric(Name)) {
711 /* a number is given */
712 i = atoi(Name);
713 if ((i = findCindex(i)) > -1)
714 strcpy(Name, ConfNames[i]);
715 } else {
716 /* a string name is given */
717 i = chcon_string_parse(Name, buf, tmp);
718 }
719 return i;
720 }
721
722
723 /*
724 * chconf_join, actually invoke GetConf() to change current conference.
725 */
726 static void
chconf_join(int new_conference)727 chconf_join(int new_conference)
728 {
729 /* Save current conf pointer */
730 UpdateConf(update_last_read_ptr);
731 if (/*@i1*/ GetConf(new_conference) == ATP_OK) {
732 printf("\n ");
733 blue();
734 high();
735 printf("* %s %s %s. *", txt[29], ConfNames[CurConf], txt[30]);
736 green();
737 printf("\n\n");
738 /* "Conference " "joined" */
739 clear();
740 fflush(stdout);
741 }
742 }
743
744
745 /*
746 * chconf - change active conference.
747 */
748 void
chconf(const char * buf)749 chconf(const char *buf)
750 {
751 char Name[100];
752 char tmp[MAXPATHS];
753 if (IsEmpty) {
754 EmptyMsg();
755 } else {
756 Name[0] = NUL_CHAR;
757 sscanf(buf, "%s %s", tmp, Name);
758 if (Name[0] == NUL_CHAR) {
759 red();
760 printf("%s\n", txt[87]); /* "Usage" */
761 printf("\tj %s\n\t\t%s\n", txt[90], txt[91]); /* "Conf #" "or" */
762 printf("\tj %s\n", txt[92]); /* "conf name" */
763 printf("%s\n", txt[93]); /* "type conf to list..." */
764 } else {
765 int new_conference = chcon_scan(Name, buf, tmp);
766 if ( stricmp(Name, "MAIN") == SUCCESS)
767 new_conference = 0; /* Special case for "main board" */
768 if (new_conference > LastConf || new_conference < 0) {
769 /* "Unknown conference" */
770 printf("\n%s\n", txt[28]);
771 } else {
772 cnf_path(tmp, ConfNumbers[new_conference]);
773 if (access(tmp, F_OK) == FAILURE) {
774 red(); /* "No mail found" */
775 printf("%s : %s %s\n", txt[6], tmp, ConfNames[new_conference]);
776 } else
777 chconf_join(new_conference);
778 }
779 }
780 }
781 }
782
783
784 /*
785 * AutoJoin - loads next valid conferences.
786 */
787 #define ILR get_MsgLastRead()
788
789 void
AutoJoin(void)790 AutoJoin(void)
791 {
792 if (IsEmpty) {
793 EmptyMsg();
794 } else if (get_ActvCnt() == 0) {
795 chconf("j MAIN");
796 } else {
797 char tmp[MAXPATHS];
798 int i = CurConf;
799 int j = get_ActvCnt();
800
801 for (; j != 0; j--) {
802 i = FindActive(i);
803 sprintf(tmp, "j %d\n", ConfNumbers[i]);
804 chconf(tmp);
805 if (ILR < 0L || ILR != (get_TotMsg() - 1L) || !newmail) {
806 return;
807 } else
808 printf("\t%s.\n", txt[31]); /* "No new mail" */
809 }
810 newmail = FALSE;
811 printf("\n");
812 }
813 }
814
815