home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / src / file_util.c < prev    next >
C/C++ Source or Header  |  1992-03-20  |  10KB  |  415 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: file_util.c,v 4.1 90/04/28 22:43:04 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    file_util.c,v $
  17.  * Revision 4.1  90/04/28  22:43:04  syd
  18.  * checkin of Elm 2.3 as of Release PL0
  19.  *
  20.  *
  21.  ******************************************************************************/
  22.  
  23. /** File oriented utility routines for ELM
  24.  
  25. **/
  26.  
  27. #include "headers.h"
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <ctype.h>
  31. #include <errno.h>
  32.  
  33. #ifdef BSD
  34. # undef tolower
  35. #endif
  36.  
  37. #include <signal.h>
  38.  
  39. #ifdef BSD
  40. # include <sys/wait.h>
  41. #endif
  42.  
  43. #ifndef OS2
  44. extern int errno;        /* system error number */
  45. #endif
  46.  
  47. char *error_name(), *error_description(), *strcpy(), *getlogin();
  48. long  fsize();
  49.  
  50. long
  51. bytes(name)
  52. char *name;
  53. {
  54.     /** return the number of bytes in the specified file.  This
  55.         is to check to see if new mail has arrived....  (also
  56.         see "fsize()" to see how we can get the same information
  57.         on an opened file descriptor slightly more quickly)
  58.     **/
  59.  
  60.     int ok = 1;
  61.     struct stat buffer;
  62.  
  63.     if (stat(name, &buffer) != 0)
  64.       if (errno != 2) {
  65.         dprint(1,(debugfile,
  66.              "Error: errno %s on fstat of file %s (bytes)\n",
  67.              error_name(errno), name));
  68.         Write_to_screen("\n\rError attempting fstat on file %s!\n\r",
  69.              1, name);
  70.         Write_to_screen("** %s - %s. **\n\r", 2, error_name(errno),
  71.           error_description(errno));
  72.         emergency_exit();
  73.       }
  74.       else
  75.         ok = 0;
  76.  
  77.     return(ok ? (long) buffer.st_size : 0L);
  78. }
  79.  
  80. int
  81. can_access(file, mode)
  82. char *file;
  83. int   mode;
  84. {
  85.     /** returns ZERO iff user can access file or "errno" otherwise **/
  86.  
  87.     int the_stat = 0, pid, w;
  88.     struct stat stat_buf;
  89.  
  90. #ifdef OS2
  91.         the_stat = (access(file, mode) == 0) ? 0 : (errno == 0) ? 1 : errno;
  92. #else
  93.     void _exit(), exit();
  94. #if defined(BSD) && !defined(WEXITSTATUS)
  95.     union wait status;
  96. #else
  97.     int status;
  98. #endif
  99. #ifdef VOIDSIG
  100.     register void (*istat)(), (*qstat)();
  101. #else
  102.     register int (*istat)(), (*qstat)();
  103. #endif
  104.  
  105. #ifdef VFORK
  106.     if ((pid = vfork()) == 0) {
  107. #else
  108.     if ((pid = fork()) == 0) {
  109. #endif
  110.       setgid(groupid);
  111.       setuid(userid);        /** back to normal userid **/
  112.  
  113.       errno = 0;
  114.  
  115.       if (access(file, mode) == 0)
  116.         _exit(0);
  117.       else
  118.         _exit(errno != 0? errno : 1);    /* never return zero! */
  119.       _exit(127);
  120.     }
  121.  
  122.     istat = signal(SIGINT, SIG_IGN);
  123.     qstat = signal(SIGQUIT, SIG_IGN);
  124.  
  125.     while ((w = wait(&status)) != pid && w != -1)
  126.         ;
  127.  
  128. #if    defined(WEXITSTATUS)
  129.     /* Use POSIX macro if defined */
  130.     the_stat = WEXITSTATUS(status);
  131. #else
  132. #ifdef BSD
  133.     the_stat = status.w_retcode;
  134. #else
  135.     the_stat = status >> 8;
  136. #endif
  137. #endif    /*WEXITSTATUS*/
  138.  
  139.     signal(SIGINT, istat);
  140.     signal(SIGQUIT, qstat);
  141. #endif
  142.  
  143.     if (the_stat == 0) {
  144.       if (stat(file, &stat_buf) == 0) {
  145.         w = stat_buf.st_mode & S_IFMT;
  146. #ifdef S_IFLNK
  147.         if (w != S_IFREG && w != S_IFLNK)
  148. #else
  149.         if (w != S_IFREG)
  150. #endif
  151.           the_stat = 1;
  152.       }
  153.     }
  154.  
  155.     return(the_stat);
  156. }
  157.  
  158. int
  159. can_open(file, mode)
  160. char *file, *mode;
  161. {
  162.     /** Returns 0 iff user can open the file.  This is not
  163.         the same as can_access - it's used for when the file might
  164.         not exist... **/
  165.  
  166.     FILE *fd;
  167.     int the_stat = 0, pid, w, preexisted = 0;
  168. #ifdef OS2
  169.     errno = 0;
  170.     if (access(file, ACCESS_EXISTS) == 0)
  171.       preexisted = 1;
  172.     if ((fd = fopen(file, mode)) == NULL)
  173.       the_stat = errno;
  174.     else {
  175.       fclose(fd);        /* don't just leave it open! */
  176.       if(!preexisted)    /* don't leave it if this test created it! */
  177.         unlink(file);
  178.       the_stat = 0;
  179.     }
  180. #else
  181.     void _exit(), exit();
  182. #if defined(BSD) && !defined(WEXITSTATUS)
  183.     union wait status;
  184. #else
  185.     int status;
  186. #endif
  187. #ifdef VOIDSIG
  188.     register void (*istat)(), (*qstat)();
  189. #else
  190.     register int (*istat)(), (*qstat)();
  191. #endif
  192.  
  193. #ifdef VFORK
  194.     if ((pid = vfork()) == 0) {
  195. #else
  196.     if ((pid = fork()) == 0) {
  197. #endif
  198.       setgid(groupid);
  199.       setuid(userid);        /** back to normal userid **/
  200.       errno = 0;
  201.       if (access(file, ACCESS_EXISTS) == 0)
  202.         preexisted = 1;
  203.       if ((fd = fopen(file, mode)) == NULL)
  204.         _exit(errno);
  205.       else {
  206.         fclose(fd);        /* don't just leave it open! */
  207.         if(!preexisted)    /* don't leave it if this test created it! */
  208.           unlink(file);
  209.         _exit(0);
  210.       }
  211.       _exit(127);
  212.     }
  213.  
  214.     istat = signal(SIGINT, SIG_IGN);
  215.     qstat = signal(SIGQUIT, SIG_IGN);
  216.  
  217.     while ((w = wait(&status)) != pid && w != -1)
  218.         ;
  219.  
  220. #ifdef WEXITSTATUS
  221.     the_stat = WEXITSTATUS(status);
  222. #else
  223. #ifdef BSD
  224.     the_stat = status.w_retcode;
  225. #else
  226.     the_stat = status >> 8;
  227. #endif
  228. #endif /*WEXITSTATUS*/
  229.  
  230.     signal(SIGINT, istat);
  231.     signal(SIGQUIT, qstat);
  232. #endif
  233.  
  234.     return(the_stat);
  235. }
  236.  
  237. int
  238. copy(from, to)
  239. char *from, *to;
  240. {
  241.     /** this routine copies a specified file to the destination
  242.         specified.  Non-zero return code indicates that something
  243.         dreadful happened! **/
  244.  
  245.     FILE *from_file, *to_file;
  246.     char buffer[VERY_LONG_STRING];
  247.  
  248.     if ((from_file = fopen(from, "r")) == NULL) {
  249.       dprint(1, (debugfile, "Error: could not open %s for reading (copy)\n",
  250.          from));
  251.       error1("Could not open file %s.", from);
  252.       return(1);
  253.     }
  254.  
  255.     if ((to_file = fopen(to, "w")) == NULL) {
  256.       dprint(1, (debugfile, "Error: could not open %s for writing (copy)\n",
  257.          to));
  258.       error1("Could not open file %s.", to);
  259.       return(1);
  260.     }
  261.  
  262.     while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
  263.       if (fputs(buffer, to_file) == EOF) {
  264.           Write_to_screen("\n\rWrite failed to tempfile in copy\n\r", 0);
  265.           perror(to);
  266.           fclose(to_file);
  267.           fclose(from_file);
  268.           return(1);
  269.       }
  270.     fclose(from_file);
  271.         if (fclose(to_file) == EOF) {
  272.       Write_to_screen("\n\rClose failed on tempfile in copy\n\r", 0);
  273.       perror(to);
  274.       return(1);
  275.     }
  276.     chown( to, userid, groupid);
  277.  
  278.     return(0);
  279. }
  280.  
  281. int
  282. append(fd, filename)
  283. FILE *fd;
  284. char *filename;
  285. {
  286.     /** This routine appends the specified file to the already
  287.         open file descriptor.. Returns non-zero if fails.  **/
  288.  
  289.     FILE *my_fd;
  290.     char buffer[VERY_LONG_STRING];
  291.  
  292.     if ((my_fd = fopen(filename, "r")) == NULL) {
  293.       dprint(1, (debugfile,
  294.         "Error: could not open %s for reading (append)\n", filename));
  295.       return(1);
  296.     }
  297.  
  298.     while (fgets(buffer, VERY_LONG_STRING, my_fd) != NULL)
  299.       if (fputs(buffer, fd) == EOF) {
  300.           Write_to_screen("\n\rWrite failed to tempfile in append\n\r", 0);
  301.           perror(filename);
  302.           rm_temps_exit();
  303.       }
  304.  
  305.     if (fclose(my_fd) == EOF) {
  306.       Write_to_screen("\n\rClose failed on tempfile in append\n\r", 0);
  307.       perror(filename);
  308.       rm_temps_exit();
  309.     }
  310.  
  311.     return(0);
  312. }
  313.  
  314. #define FORWARDSIGN    "Forward to "
  315. int
  316. check_mailfile_size(mfile)
  317. char *mfile;
  318. {
  319.     /** Check to ensure we have mail.  Only used with the '-z'
  320.         starting option. So we output a diagnostic if there is
  321.         no mail to read (including  forwarding).
  322.         Return 0 if there is mail,
  323.            <0 if no permission to check,
  324.            1 if no mail,
  325.            2 if no mail because mail is being forwarded.
  326.      **/
  327.  
  328.     char firstline[SLEN];
  329.     int retcode;
  330.     struct stat statbuf;
  331.     FILE *fp;
  332.  
  333.     /* see if file exists first */
  334.     if (access(mfile, ACCESS_EXISTS) != 0)
  335.       retcode = 1;                    /* no file */
  336.  
  337.     /* exists - now see if user has read access */
  338.     else if (can_access(mfile, READ_ACCESS) != 0)
  339.       retcode = -1;                    /* no perm */
  340.  
  341.     /* read access - now see if file has a reasonable size */
  342.     else if ((fp = fopen(mfile, "r")) == NULL)
  343.       retcode = -1;        /* no perm? should have detected this above! */
  344.     else if (fstat(fileno(fp), &statbuf) == -1)
  345.       retcode = -1;                    /* arg error! */
  346.     else if (statbuf.st_size < 2)
  347.       retcode = 1;    /* empty or virtually empty, e.g. just a newline */
  348.  
  349.     /* file has reasonable size - see if forwarding */
  350.     else if (fgets (firstline, SLEN, fp) == NULL)
  351.       retcode = 1;         /* empty? should have detected this above! */
  352.     else if (first_word(firstline, FORWARDSIGN))
  353.       retcode = 2;                    /* forwarding */
  354.  
  355.     /* not forwarding - so file must have some mail in it */
  356.     else
  357.       retcode = 0;
  358.  
  359.     /* now display the appropriate message if there isn't mail in it */
  360.     switch(retcode) {
  361.  
  362.     case -1:    printf("\r\nYou have no permission to read %s!\r\n", mfile);
  363.             break;
  364.     case 1:        printf("\r\nYou have no mail.\r\n");
  365.             break;
  366.     case 2:        no_ret(firstline) /* remove newline before using */
  367.             printf("Your mail is being forwarded to %s.\n\r",
  368.               firstline + strlen(FORWARDSIGN));
  369.             break;
  370.     }
  371.     return(retcode);
  372. }
  373.  
  374. create_readmsg_file()
  375. {
  376.     /** Creates the file ".current" in the users home directory
  377.         for use with the "readmsg" program.
  378.     **/
  379.  
  380.     FILE *fd;
  381.     char buffer[SLEN];
  382.  
  383.     sprintf(buffer,"%s/%s", home, readmsg_file);
  384.  
  385.     if ((fd = fopen (buffer, "w")) == NULL) {
  386.       dprint(1, (debugfile,
  387.          "Error: couldn't create file %s - error %s (%s)\n",
  388.          buffer, error_name(errno), "create_readmsg_file"));
  389.       return;    /* no error to user */
  390.     }
  391.  
  392.     if (current)
  393.       fprintf(fd, "%d\n", headers[current-1]->index_number);
  394.     else
  395.       fprintf(fd, "\n");
  396.  
  397.     fclose(fd);
  398.     chown( buffer, userid, groupid);
  399. }
  400.  
  401. long fsize(fd)
  402. FILE *fd;
  403. {
  404.     /** return the size of the current file pointed to by the given
  405.         file descriptor - see "bytes()" for the same function with
  406.         filenames instead of open files...
  407.     **/
  408.  
  409.     struct stat buffer;
  410.  
  411.     (void) fstat(fileno(fd), &buffer);
  412.  
  413.     return( (long) buffer.st_size );
  414. }
  415.