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 system.c
23 */
24
25 /*
26 * Operating System system-dependant functions for ATP
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "reader.h"
33 #include "readlib.h"
34 #include "ansi.h"
35 #include "qlib.h"
36
37 #ifdef DJGPP
38 #include <pc.h>
39 #include <dos.h>
40 #endif
41
42 #if defined(__MSDOS__)
43 #ifdef _MSC_
44 #include <direct.h>
45 #else
46 #include <dir.h>
47 #endif
48 #include <io.h>
49 #include <dos.h>
50 #endif
51
52 #ifdef WIN32
53 #include <direct.h>
54 #include <io.h>
55 #endif
56
57 /*
58 * Erase - deletes ALL files in a directory pointed to by PathName.
59 * This is system-dependant.
60 */
61 void
Erase(const char * PathName)62 Erase(const char *PathName)
63 {
64 char Pattern[MAXPATHS];
65
66 #if defined(DIRENTRY)
67 DIR *dirp;
68 struct DIRENTRY *firp;
69
70 dirp = opendir(PathName);
71 if (dirp != NULL) {
72 while ((firp = readdir(dirp)) != NULL) /*@-strictops */
73 if (firp->d_name[0] != '.') { /*@=strictops */
74 sprintf(Pattern, "%s%c%s", PathName, SEP, firp->d_name);
75 do_unlink(Pattern);
76 }
77 (void)closedir(dirp);
78 } else {
79 printf("Can't seem to open %s\n", PathName);
80 }
81
82 #elif defined(UNIXCMDS)
83 sprintf(Pattern, "rm -f %s/*", PathName);
84 system(Pattern);
85
86 #elif !defined(WIN32) /* for dos, this method saves you from an annoying prompt */
87 /* see below for WIN32 variation */
88 int ok;
89 char tmp[130];
90 char cwd[130];
91 struct ffblk FileDoc;
92
93 GETCWD(cwd, 128);
94 sprintf((char *) Pattern, "%s\\*.*", PathName);
95
96 if ((ok = findfirst((char *) Pattern, &FileDoc, 0)) == ATP_OK) {
97 while (ok == ATP_OK) {
98 sprintf(tmp, "%s\\%s", PathName, FileDoc.ff_name);
99 do_unlink(tmp);
100 ok = findnext(&FileDoc);
101 }
102 CHPATH(cwd);
103 }
104 /* WIN32 below */
105 #else
106
107 int ok;
108 long filegrouphandle;
109 char tmp[MAXPATHS];
110 char cwd[MAXPATHS];
111
112 struct _finddata_t FileDoc;
113
114 GETCWD(cwd, MAXPATHS - 2);
115 sprintf((char *) Pattern, "%s\\*.*", PathName);
116
117 if ((ok = _findfirst((char *) Pattern, &FileDoc)) == ATP_OK) {
118 filegrouphandle = ok;
119 while (ok == ATP_OK) {
120 sprintf(tmp, "%s\\%s", PathName, FileDoc.name);
121 do_unlink(tmp);
122 ok = _findnext(filegrouphandle, &FileDoc);
123 }
124 _findclose(filegrouphandle);
125 CHPATH(cwd);
126 }
127 #endif
128 } /* end of Erase() */
129
130
131 #if !defined(HAVE_STRNICMP)
132
133 /*
134 * strnicmp - case insensitive counted string comparison.
135 */
136 int
strnicmp(const char * s1,const char * s2,size_t n)137 strnicmp(const char *s1, const char *s2, size_t n)
138 {
139 while (n && *s1 && *s2) {
140 if (tolower(*s1) != tolower(*s2))
141 return (tolower(*s1) > tolower(*s2) ? 1 : -1);
142 s1++;
143 s2++;
144 n--;
145 }
146 if (n) {
147 if (*s1)
148 return (1);
149 if (*s2)
150 return (-1);
151 }
152 return (0);
153 }
154
155
156 /*
157 * strnicmp - case insensitive string comparison.
158 */
159 int
stricmp(const char * s1,const char * s2)160 stricmp(const char *s1, const char *s2)
161 {
162 while (*s1 != NUL_CHAR && *s2 != NUL_CHAR) {
163 if (tolower(*s1) != tolower(*s2))
164 return (tolower(*s1) > tolower(*s2) ? 1 : -1);
165 s1++;
166 s2++;
167 }
168 if (*s1)
169 return (1);
170 if (*s2)
171 return (-1);
172 return (0);
173 }
174
175 #endif
176
177 #if !defined(HAVE_STRUPR)
178 /*@-strictops */
179 /*
180 * strlwr - converts string to lower case.
181 */
182 char *
strlwr(char * s)183 strlwr(char *s)
184 {
185 char *s1;
186
187 s1 = s;
188 while (*s1 != NUL_CHAR ) {
189 *s1 = tolower(*s1);
190 s1++;
191 }
192 return (s);
193 }
194
195 /*
196 * strupr - converts string to upper case.
197 */
198 char *
strupr(char * s)199 strupr(char *s)
200 {
201 char *s1;
202
203 s1 = s;
204 while (*s1 != NUL_CHAR) {
205 *s1 = toupper(*s1);
206 s1++;
207 }
208 return (s);
209 }
210 /*@=strictops */
211 #endif
212
213 #if !defined(HAVE_STRSTR) || defined(NEED_STRSTR)
214 /*
215 * Copyright (C) 1991, 1992 Free Software Foundation, Inc.
216 * This function is part of the GNU C Library.
217 */
218
219 /*
220 * strstr - find a substring in another string (from GNU C library).
221 *
222 * Return the first ocurrence of NEEDLE in HAYSTACK.
223 */
224 char *
strstr(const char * haystack,const char * needle)225 strstr(const char *haystack, const char *needle)
226 {
227 const char CONSPTR needle_end = strchr(needle, NUL_CHAR);
228 const char CONSPTR haystack_end = strchr(haystack, NUL_CHAR);
229 const size_t needle_len = needle_end - needle;
230 const size_t needle_last = needle_len - 1;
231 const char *begin;
232
233 if (needle_len == 0)
234 return (char *) haystack; /* ANSI 4.11.5.7, line 25. */
235 if ((size_t) (haystack_end - haystack) < needle_len)
236 return NULL;
237
238 for (begin = &haystack[needle_last]; begin < haystack_end; ++begin) {
239 const char *n = &needle[needle_last];
240 const char *h = begin;
241
242 do {
243 if (*h != *n)
244 goto loop; /* continue for loop */
245 } while (--n >= needle && --h >= haystack);
246
247 return (char *) h;
248
249 loop:;
250 }
251 return NULL;
252 }
253 #endif
254
255 #if !defined(HAVE_TMPNAM) || defined(NEEDTMPNAM)
256
257 #undef L_tmpnam
258 #define L_tmpnam 30
259
260 /*
261 * mytmprnam - provides the posix tmpnam() function.
262 * assumes the existence of the non-posix mktemp() function.
263 */
264 char *
mytmprnam(char * buf)265 mytmprnam(char *buf)
266 {
267 static char tbf[(L_tmpnam + 1)];
268 char *tbptr;
269
270 tbf[0] = NUL_CHAR;
271 #if defined(SYS_UNIX)
272 strcpy(tbf, "/usr/tmp/");
273 #endif
274 strcat(tbf, "tmXXXXXX");
275 tbptr = mktemp(tbf);
276 if (tbptr == NULL) { /* try to return something anyway */
277 tbptr = tbf;
278 }
279 if (buf != NULL) {
280 strcpy(buf, tbptr);
281 tbptr = buf;
282 }
283 return tbptr;
284 }
285
286 #endif
287
288 /* unix terminal functions, see system.h for more info */
289 #if defined(SYS_UNIX)
290 /*
291 * restore_terminal - reset terminal from previously saved attributes.
292 */
293 static struct ATPSRTERM savedterm;
294 void
restore_terminal(void)295 restore_terminal(void)
296 {
297 (void)ATPSETERM;
298 }
299
300 /*
301 * save_terminal - store terminal attributes for later retrieval.
302 */
303 void
save_terminal(void)304 save_terminal(void)
305 {
306 (void)ATPGETERM;
307 }
308
309 #endif
310
311
312 /*
313 * BEGIN PROCESS CREATION ROUTINES
314 *
315 */
316
317 #if defined(USE_FORK)
318 static char *eargv[101], tbf[MAXPATHS];
319
320 /*@-strictops */
321 /*
322 * build_eargv, build array of arguments for execvp.
323 */
324 static atp_ERROR_T
build_eargv(const char * prg,const char * prgfile)325 build_eargv(const char *prg, const char *prgfile)
326 {
327 atp_ERROR_T ret_code = ATP_ERROR;
328 char *tp = tbf;
329
330 /* create command line */
331 sprintf(tbf, "%s %s", prg, prgfile);
332 StripLSpace(tbf);
333
334 /* decompose command line into arguments */
335 if (tbf[0] != NUL_CHAR) {
336 int i = 1;
337 for (; i < 100; i++) {
338 eargv[i] = 0;
339 while (*tp != SPC_CHAR && *tp != TAB_CHAR && *tp != NUL_CHAR)
340 tp++;
341 if (*tp != NUL_CHAR)
342 *tp = NUL_CHAR;
343 else
344 break;
345 tp++;
346 while (*tp == SPC_CHAR || *tp == TAB_CHAR) {
347 *tp = NUL_CHAR;
348 tp++;
349 }
350 if (*tp != NUL_CHAR)
351 eargv[i] = tp;
352 else
353 break;
354 tp++;
355 }
356 eargv[0] = tbf;
357 eargv[100] = 0;
358 ret_code = ATP_OK;
359 }
360 return ret_code;
361 }
362 /*@=strictops */
363 #endif
364
365
366 #ifdef USE_FORK
367 static pid_t Proc_ID = NO_CHILD;
368 static atp_BOOL_T reperror = FALSE ;
369
370 /*
371 * get_reperror - returns value of reperror reply error flag.
372 */
373 atp_BOOL_T
get_reperror(void)374 get_reperror(void)
375 {
376 return reperror;
377 }
378
379 /*
380 * reset_reperror - resets value of reperror reply error flag to FALSE.
381 */
382 void
reset_reperror(void)383 reset_reperror(void)
384 {
385 reperror = FALSE;
386 }
387 /*@-paramuse */
388
389 /*
390 * kill_child - signal handler for SIGINT to catch a signal in Reply().
391 */
392 RETSIGTYPE
kill_child(int dummy_arg)393 kill_child(int dummy_arg)
394 {
395 #ifndef HAVE_SIGACTION
396 signal(SIGINT, SIG_IGN);
397 #endif
398 if (Proc_ID > 0) {
399 (void)kill(Proc_ID, SIGTERM);
400 (void)sleep(2);
401 (void)kill(Proc_ID, SIGKILL);
402 #ifndef HAVE_SIGACTION
403 signal(SIGINT, kill_child);
404 #endif
405 }
406 restore_terminal(); /* restore terminal parameters */
407 reperror = TRUE;
408 }
409 /*@=paramuse */
410 #endif /* USE_FORK */
411
412
413 /*
414 * fork_execvp - spawn process via fork()/execvp() or system().
415 */
416 void
fork_execvp(const char * prg,const char * prgfile)417 fork_execvp(const char *prg, const char *prgfile)
418 {
419 #ifdef USE_FORK
420 Proc_ID = NO_CHILD; /*@-strictops */
421 if (build_eargv(prg, prgfile) == ATP_OK) { /*@=strictops */
422 if ((Proc_ID = fork()) == 0) {
423 /* child */
424 (void)execvp(tbf, eargv);
425 /* this should never be reached */
426 exit(EXIT_FAILURE);
427 }
428 if (Proc_ID < 0) {
429 reperror = TRUE;
430 } else {
431 /* parent */
432 /* set new handler for SIGINT */
433 pid_t npid;
434 sig_chint();
435 do {
436 int childstatus;
437 npid = wait(&childstatus);
438 } while (npid != Proc_ID);
439 sig_ignore(SIGINT);
440 }
441 /* reset Proc_ID to indicate no active child */
442 Proc_ID = NO_CHILD;
443 }
444 #else
445 char forkbuf[MAXPATHS];
446 /* build command for call system() */
447 sprintf(forkbuf, "%s %s", prg, prgfile);
448 /* execute command */
449 system(forkbuf);
450 #endif
451 }
452 /* END OF PROCESS CREATION ROUTINES */
453
454
455
456 /*
457 * replacement for missing getcwd() function
458 */
459
460 #if !defined(HAVE_GETCWD) || defined(NEEDGETCWD)
461
462 #ifdef no_proto
463 char *getwd();
464 #else
465 EXTERNC char *getwd(char *p);
466 #endif
467
468 /*
469 * mygetcwd - provides posix getcwd() assuming getwd() is available.
470 */
471 char *
mygetcwd(char * buf,size_t siz)472 mygetcwd(char *buf, size_t siz)
473 {
474 char tmp[MAXPATHS];
475
476 memset(tmp, 0, (size_t) (siz - 1));
477 getwd(tmp);
478 #ifdef DJGPP
479 addrive(tmp);
480 #endif
481 if (siz <= MAXPATHS)
482 tmp[siz - 1] = 0;
483 strcpy(buf, tmp);
484 return (buf);
485 }
486 #endif
487
488 /* ************************************************************************ */
489 /* THE FOLLOWING SECTION IS DEVOTED TO MS-DOS, OS/2, AND WINDOWS STUFF ONLY */
490 /* ************************************************************************ */
491
492 #ifdef __MSDOS__
493
494 /*
495 * DosChPath - (msdos) changes active path to new drive and directory.
496 */
497 atp_ERROR_T
DosChPath(const char * path)498 DosChPath(const char *path)
499 {
500 int driv;
501 atp_ERROR_T ret_code = ATP_ERROR;
502
503 /* get drive letter from path */
504 driv = toupper(path[0]);
505
506 /* test for valid drive designator at start of path */
507 if ((path[2] == SEP || path[2] == '/') && path[1] == ':' && driv > '@' && driv < 'Q') {
508 /* convert to numeric */
509 const int drive_mask = 15;
510 driv &= drive_mask;
511 #ifndef _MSC_
512 driv--;
513 #endif
514 if (setdisk(driv) < driv) {
515 /* can't set drive */
516 printf("ERROR: can't set drive to '%c:'\n", driv);
517 sleep(4);
518 } else if (chdir(path) == ATP_OK) {
519 ret_code = ATP_OK;
520 } else {
521 /* can't change to new path */
522 printf("ERROR: can't change path to '%s:'\n", path);
523 sleep(4);
524 }
525 }
526 return ret_code;
527 }
528 #endif
529
530 #if defined(_OS2) || defined(__MSDOS__)
531
532 /*
533 * addrive - (msdos) prepends a drive designator to a path name.
534 */
535 void
addrive(char * path)536 addrive(char *path)
537 {
538 if ((path[2] != SEP && path[2] != SEPDOS) || path[1] != ':') {
539 char tmp[MAXPATHS];
540 int driv;
541 #ifdef __EMX__
542 driv = _getdrive();
543 #else
544 driv = getdisk();
545 driv = driv + 'A';
546 #endif
547 if (path[0] != SEP && path[0] != SEPDOS)
548 #ifdef DJGPP
549 sprintf(tmp, "%c:%c%s", driv, '/', path);
550 #else
551 sprintf(tmp, "%c:%c%s", driv, SEP, path);
552 #endif
553 else
554 sprintf(tmp, "%c:%s", (char) driv, path);
555 strcpy(path, tmp);
556 }
557 }
558
559 #endif
560
561 #ifdef NEEDISKS
562
563 #ifdef __MSDOS__
564
565 /*
566 * getdisk - (msdos) get and return current active drive.
567 */
568 int
getdisk(void)569 getdisk(void)
570 {
571 const int drive_mask = 15;
572 int temp;
573 #ifdef _MSC_
574 _dos_getdrive(&temp);
575 return temp;
576 #else
577 union REGS regs;
578
579 regs.h.ah = 0x19;
580 regs.x.dx = 0;
581 regs.h.al = 0;
582
583 temp = intdos(®s, ®s);
584 return (temp & drive_mask);
585 #endif
586 }
587
588 /*
589 * setdisk - (msdos) set the current active disk drive.
590 */
591 int
setdisk(int driv)592 setdisk(int driv)
593 {
594 int temp;
595 const int mask = 0x7F;
596 #ifdef _MSC_
597 _dos_setdrive(driv, &temp);
598 #else
599 union REGS regs;
600
601 regs.h.ah = 0x0e;
602 regs.h.dl = (char) (driv & mask);
603 regs.h.al = 0;
604
605 temp = intdos(®s, ®s);
606 #endif
607 return (temp);
608 }
609
610 #endif
611 #endif
612
613 #ifdef NEED_SLEEP
614 /* Microsoft QuickC 2.0 doesnt' seem to have sleep() in its library */
615
616 #ifdef __MSDOS__
617
618 #define DOS_TICK_CNTR 0x046c
619
620 #define time_t long
621
622 /*
623 * sleep - (msdos) provides sleep routine for Microsoft C.
624 */
625 void
sleep(unsigned sec)626 sleep(unsigned sec)
627 {
628 time_t *ticker = (time_t *) DOS_TICK_CNTR;
629 time_t tick, tock;
630
631 tock = (time_t) ((181 * sec) + 5) / 10; /* fixed point math with round up */
632 tick = *ticker;
633 tock += tick;
634
635 do {
636 A_DVPAUZ; /* if we are desqview aware this is defined to dv_pause(); */
637 tick = *ticker;
638 } while (tick < tock);
639 }
640
641 #else
642 void
sleep(int sec)643 sleep(int sec)
644 {
645 time_t tick1, tick2, tock;
646
647 tick1 = time(&tock);
648 do {
649 tick2 = time(&tock);
650 } while ((tick2 - tick1) < sec);
651
652 }
653 #endif
654 #endif /* need sleep */
655
656
657 #ifdef DOSTIME
658 /*
659 * msdos_time_init - (msdos) pseudo-posix time zone routine for MSDOS.
660 */
661 void
msdos_time_init(void)662 msdos_time_init(void)
663 {
664 char *tp;
665 if (!((tp = getenv("TZ")) != NULL && *tp
666 && strlen(tp) > 3 && atoi(tp + 3) != 0)) {
667 putenv("TZ=TML0CAL");
668 }
669 tzset();
670 }
671 #endif
672
673
674 #if 0
675
676 /******************************************************************/
677 /******* THE FUNCTIONS BELOW ARE CURRENTLY UNUSED BY ATP! *********/
678 /******************************************************************/
679 /******* THE FUNCTIONS BELOW ARE CURRENTLY UNUSED BY ATP! *********/
680 /******************************************************************/
681 /******* THE FUNCTIONS BELOW ARE CURRENTLY UNUSED BY ATP! *********/
682 /******************************************************************/
683
684 #if defined(NEEDREADLINE)
685
686 #ifndef UNIXCMDS
687 #define STOPIT (int)'\r'
688 #else
689 #define STOPIT (int)'\n'
690 #endif
691 /*
692 **readline - display prompt and retrieve user's response.
693 */
694 char *
695 readline(char *prmt, int scrollflag)
696 {
697
698 static char rdlnbuf[128];
699 extern char *luxptr;
700 char *buf, *tempr;
701 int cin = 0, idx = 0, i, firsthere = TRUE;
702
703 buf = (char *) malloc(128); /* inialize buffers */
704 rdlnbuf[0] = buf[0] = 0;
705
706 printf("%s", prmt); /* display prompt */
707 if (luxptr != NULL) {
708 strcpy(rdlnbuf, luxptr);
709 printf("%s\n", luxptr);
710 up(1);
711 right(14);
712 buf[0] = 1;
713 }
714 fflush(stdout);
715 while ((cin = getch()) != STOPIT) {
716 if (firsthere) {
717 for (i = idx; i < field_len; i++)
718 printf(" "); /* clear line */
719 for (i = idx; i < field_len; i++)
720 printf("\b");
721 buf[0] = 1;
722 firsthere = FALSE;
723 }
724 if (cin > 31) {
725 printf("%c", cin);
726 buf[idx] = (char) cin;
727 idx++;
728 buf[idx] = 0;
729 if (idx > 24) {
730 idx--;
731 printf("\b");
732 };
733 } else if (cin == '\b' && idx > 0) { /* do backspace */
734 printf("\b \b");
735 buf[--idx] = 0;
736 } else if (cin == 0) {
737 buf[idx] = 0;
738 #ifdef __TURBOC__ /* check for special keys */
739 tempr = NULL;
740 if (luxptr == NULL) {
741 switch (cin = getch()) {
742 case 0x3b:
743 tempr = "help";
744 break;
745 case 0x3c:
746 tempr = "tag help";
747 break;
748 case 0x3d:
749 tempr = "tag list";
750 break;
751 case 0x3e:
752 tempr = "qlist";
753 break;
754 case 0x49:
755 tempr = "-";
756 break;
757 case 0x51:
758 tempr = "+";
759 break;
760 case 0x4f:
761 tempr = "last";
762 break;
763 case 0x47:
764 tempr = "1";
765 break;
766 case 0x3f:
767 tempr = "show terms";
768 break;
769 case 0x4c:
770 tempr = "N";
771 break;
772 default:
773 break;
774 }
775 if (tempr != NULL) {
776 strcpy(buf, tempr);
777 printf("\n");
778 return buf;
779 }
780 }
781 #endif
782 } else {
783 buf[idx] = 0;
784 }
785 fflush(stdout);
786 }
787 printf("\n");
788 if (buf[0] == 1)
789 strcpy(buf, rdlnbuf);
790 return buf;
791
792 };
793
794 void /* dummy function for compatibility */
795 rl_initialize(void)
796 {
797 }
798
799 #endif
800
801 #ifdef NEEDFIXPATH
802 void
803 fixpath(char *path)
804 {
805
806 char *tptr;
807
808 tptr = path;
809 while (*tptr) {
810 if (*tptr == '/')
811 *tptr = '\\';
812 tptr++;
813 }
814 }
815 #endif
816
817 #if defined(NEEDTEMPNAM)
818 char *
819 mytempnam(const char *workpath, const char *rep)
820 {
821
822 char *tp1, *tp2;
823 static char tbuf[MAXPATHS];
824 char buffy[15];
825
826 strcpy(buffy, "atpXXXXXX");
827 tp2 = tbuf;
828 tp1 = mktemp(buffy);
829 if (tp1 != NULL) {
830 strcpy(tbuf, workpath);
831 while (*tp2)
832 tp2++;
833 tp2--;
834 if (*tp2 != SEP) {
835 tp2++;
836 *tp2 = SEP;
837 tp2++;
838 *tp2 = NUL_CHAR;
839 }
840 strcat(tbuf, rep);
841 strcat(tbuf, tp1);
842 tp1 = tbuf;
843 }
844 return tp1;
845 }
846 #endif
847
848 #if defined(NEEDSYSTEM)
849 #ifdef UNIXCMDS
850 #define ATPSWC "-c"
851 #else
852 #define ATPSWC "/C"
853 #endif
854
855 int
856 mysystem(char *command)
857 {
858 pid_t mpid, npid;
859 int statloc;
860 char *shelbuf;
861
862 if ((shelbuf = malloc(MAXPATHS)) == NULL)
863 return (0);
864 shelbuf = getenv(SHELL);
865
866 mpid = fork();
867
868 if (mpid == 0) { /* child */
869 execl(shelbuf, shelbuf, ATPSWC, command, NULL);
870 free(shelbuf);
871 abort();
872 } else if (mpid < 0) {
873 printf("Unable to fork %s\n", command);
874 free(shelbuf);
875 return (0);
876 } else { /* parent */
877 wmore:
878 npid = wait(&statloc);
879 if (npid != mpid)
880 goto wmore;
881 }
882 free(shelbuf);
883 return (1);
884 }
885
886 #endif
887 #endif /* UNUSED BY ATP */
888