home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / POPCLIEN.000 / POPCLIEN / pop / popclient.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  15.0 KB  |  593 lines

  1. /* Copyright 1993,1994 by Carl Harris, Jr.
  2.  * All rights reserved
  3.  *
  4.  * Distribute freely, except: don't remove my name from the source or
  5.  * documentation (don't take credit for my work), mark your changes (don't
  6.  * get me blamed for your possible bugs), don't alter or remove this
  7.  * notice.  May be sold if buildable source is provided to buyer.  No
  8.  * warrantee of any kind, express or implied, is included with this
  9.  * software; use at your own risk, responsibility for damages (if any) to
  10.  * anyone resulting from the use of this software rests entirely with the
  11.  * user.
  12.  *
  13.  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  14.  * I'll try to keep a version up to date.  I can be reached as follows:
  15.  * Carl Harris <ceharris@vt.edu>
  16.  */
  17.  
  18.  
  19. /***********************************************************************
  20.   module:       popclient.c
  21.   program:      popclient
  22.   SCCS ID:      @(#)popclient.c    2.5  4/1/94
  23.   programmer:   Carl Harris, ceharris@vt.edu
  24.   date:         29 December 1993
  25.   compiler:     DEC RISC C compiler (Ultrix 4.1)
  26.   environment:  DEC Ultrix 4.3 
  27.   description:  main driver module for the popclient package.  contains
  28.                 code for command-line parsing and invocation of the
  29.                 appropriate POP driver routine.
  30.  ***********************************************************************/
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <unistd.h>
  36. #include <signal.h>
  37. #include <pwd.h>
  38. #include <errno.h>
  39. #include <sys/types.h>
  40. #include <sys/file.h>
  41. #include <sys/wait.h>
  42. #include <sys/stat.h>
  43.  
  44. #include "config.h"
  45. #include "popclient.h"
  46.  
  47. /* release info */
  48. #define         COMPILE_SCCS    "2.21 [2.5] (4/1/94)"
  49.  
  50. /* requisite, venerable SCCS ID string */
  51. static char sccs_id [] = "@(#)popclient.c    2.5\t4/1/94";
  52.  
  53. #ifndef NO_PROTO
  54. /* prototypes for internal functions */
  55. int showoptions (struct optrec *options);
  56. int parseMDAargs (struct optrec *options);
  57. int parsecmdline (int argc, char **argv, struct optrec *options);
  58. int setdefaults (struct optrec *options);
  59. int showversioninfo (void);
  60. int clearbiffbit (void);
  61. int restorebiffbit (void);
  62. #endif
  63.  
  64. /* Controls the detail of status/progress messages written to stderr */
  65. int outlevel;      /* see the O_.* constants in popclient.h */
  66. int biffwas = -1;  /* previous chmod bits on the controlling tty */
  67.  
  68. /* args for the MDA, parsed out in the usual fashion by parseMDAargs() */
  69. #ifdef MDA_ARGS
  70. char *mda_argv [MDA_ARGCOUNT + 2];
  71. #else
  72. char *mda_argv [2];
  73. #endif
  74.  
  75.  
  76. /*********************************************************************
  77.   function:      main
  78.   description:   main driver routine 
  79.   arguments:     
  80.     argc         argument count as passed by runtime startup code.
  81.     argv         argument strings as passed by runtime startup code.
  82.  
  83.   return value:  an exit status code for the shell -- see the 
  84.                  PS_.* constants defined above.
  85.   calls:         parsecmdline, setdefaults, openuserfolder, doPOP2.
  86.   globals:       none.
  87.  *********************************************************************/
  88.  
  89. main (argc,argv)
  90. int argc;
  91. char **argv;
  92.   int mboxfd;
  93.   struct optrec options;
  94.   int popstatus;
  95.   int cleanup();
  96.  
  97.   signal(SIGINT,cleanup);
  98.   clearbiffbit();
  99.  
  100.   if (parsecmdline(argc,argv,&options) == 0)
  101.     if (!options.versioninfo)
  102.       if (setdefaults(&options) == 0) {
  103.         parseMDAargs(&options);
  104.         if (options.whichpop == 3) 
  105.           popstatus = doPOP3(&options);
  106.         else
  107.           popstatus = doPOP2(&options);
  108.       } 
  109.       else
  110.         popstatus = PS_UNDEFINED;
  111.     else
  112.       showversioninfo();
  113.   else
  114.     popstatus = PS_SYNTAX;
  115.  
  116.   restorebiffbit();
  117.   exit(popstatus);
  118. }
  119.     
  120.  
  121.  
  122. /*********************************************************************
  123.   function:      parsecmdline
  124.   description:   parse/validate the command line options.
  125.   arguments:
  126.     argc         argument count.
  127.     argv         argument strings.
  128.     options      pointer to a struct optrec to receive the parsed 
  129.                  options.
  130.  
  131.   return value:  zero if the command line was syntactically correct,
  132.                  else non-zero (an error message has been written to stderr).  
  133.   calls:         none.  
  134.   globals:       none.  
  135.  *********************************************************************/
  136.  
  137. int parsecmdline (argc,argv,options)
  138. int argc;
  139. char **argv;
  140. struct optrec *options;
  141. {
  142.   int c,i;
  143.   int fflag = 0;     /* TRUE when -o or -c has been specified */
  144.   int errflag = 0;   /* TRUE when a syntax error is detected */
  145.   extern int optind,opterr;     /* defined in getopt(2) */
  146.   extern char *optarg;          /* defined in getopt(2) */
  147.  
  148.   bzero(options,sizeof(struct optrec));    /* start clean */
  149.   while (!errflag && (c = getopt(argc,argv,"23Vkvscu:p:f:o:")) != EOF) {
  150.     switch (c) {
  151.       case '2':
  152.         options->whichpop = 2;
  153.         break;
  154.       case '3':
  155.         options->whichpop = 3;
  156.         break;
  157.       case 'V':
  158.         options->versioninfo = !0;
  159.         break;
  160.       case 'k':
  161.         options->keep = !0;
  162.         break;
  163.       case 'v':
  164.         options->verbose = !0;
  165.         break;
  166.       case 's':
  167.         options->silent = !0;
  168.         break;
  169.       case 'c':
  170.         if (fflag)
  171.           errflag++;
  172.         else {
  173.           fflag++;
  174.           options->foldertype = OF_STDOUT;
  175.         }
  176.         break;
  177.       case 'u':
  178.         strcpy(options->userid,optarg);
  179.         break;
  180.       case 'p':
  181.         strcpy(options->password,optarg);
  182.         break;
  183.       case 'o':
  184.         if (fflag) 
  185.           errflag++;
  186.         else {
  187.           fflag++;
  188.           options->foldertype = OF_USERMBOX;
  189.           strcpy(options->userfolder,optarg);
  190.         }
  191.         break;
  192.       case 'f':
  193.         strcpy(options->remotefolder,optarg);
  194.         break;
  195.       default:
  196.         errflag++;
  197.     }
  198.   }
  199.  
  200.   if (!options->versioninfo) {
  201.     /* get host argument -- error if not present */
  202.     if (optind < argc)
  203.       strcpy(options->host,argv[optind++]);
  204.     else
  205.       errflag++;
  206.  
  207.     /* error if more unparsed arguments are present */
  208.     if (optind < argc)
  209.       errflag++;
  210.     else
  211.       ;
  212.   }
  213.   else 
  214.     ;
  215.  
  216.  
  217.   /* squawk if syntax errors were detected */
  218.   if (errflag) {
  219.     fputs("usage:  popclient [-2|-3] [-Vksv] [-u server-userid] [-p server-password]\n",
  220.           stderr);
  221.     fputs("                  [-f remote-folder] [-c | -o local-folder]  host\n",
  222.           stderr);
  223.   }
  224.   else
  225.     ;
  226.  
  227.   /* clean up the command line in case -p was used */
  228.   for (i = 1; i < argc; i++)
  229.     argv[i] = (char *) 0;
  230.  
  231.   return(errflag);
  232. }
  233.          
  234.  
  235. /*********************************************************************
  236.   function:      setdefaults
  237.   description:   set reasonable default values for unspecified options.
  238.   arguments:     
  239.     options      option values parsed from the command-line; unspeci-
  240.                  fied options must be filled with zero.
  241.  
  242.   return value:  zero if defaults were successfully set, else non-zero
  243.                  (indicates a problem reading /etc/passwd).
  244.   calls:         none.
  245.   globals:       writes outlevel.
  246.  *********************************************************************/
  247.  
  248. int setdefaults (options)
  249. struct optrec *options;
  250. {
  251.   int uid;
  252.   struct passwd *pw;
  253.   char *mailvar;
  254.  
  255.   if ((pw = getpwuid(uid = getuid())) == NULL) {
  256.     fprintf(stderr,"No passwd entry for uid %d\n",uid);
  257.     return(-1);
  258.   }
  259.   /* save the login name for delivery use */
  260.   strcpy(options->loginid,pw->pw_name);
  261.  
  262.   if (options->whichpop == 0)
  263.     options->whichpop = DEF_PROTOCOL;
  264.   else
  265.     ; /* -2 or -3 was specified */
  266.  
  267.   if (*(options->userid) == '\0') 
  268.     strcpy(options->userid,pw->pw_name);
  269.   else
  270.     ;  /* -u was specified */
  271.  
  272.   if (options->foldertype == 0) 
  273.     options->foldertype = OF_SYSMBOX;
  274.   else
  275.     ;  /* -o or -c was specified */
  276.     
  277.   if (*(options->password) == '\0')  
  278.     strcpy(options->password,(char *) getpass("Enter mailserver password: "));
  279.   else
  280.     ;  /* -p was specified */
  281.  
  282.   if (options->verbose)
  283.     outlevel = O_VERBOSE;
  284.   else if (options->silent)
  285.     outlevel = O_SILENT;
  286.   else
  287.     outlevel = O_NORMAL;
  288.  
  289.   return(0);
  290. }
  291.  
  292.  
  293.  
  294. /*********************************************************************
  295.   function:      showversioninfo
  296.   description:   display program release and compiler info
  297.   arguments:     none.
  298.   return value:  none.
  299.   calls:         none.
  300.   globals:       none.
  301.  *********************************************************************/
  302.  
  303. int showversioninfo()
  304. {
  305.   printf("popclient release %s\n",COMPILE_SCCS);
  306. }
  307.  
  308.  
  309.  
  310. /*********************************************************************
  311.   function:      openuserfolder
  312.   description:   open the file to which the retrieved messages will
  313.                  be appended.  Do NOT call when options->foldertype
  314.                  is OF_SYSMBOX.
  315.  
  316.   arguments:     
  317.     options      fully-determined options (i.e. parsed, defaults invoked,
  318.                  etc).
  319.  
  320.   return value:  file descriptor for the open file, else -1.
  321.   calls:         none.
  322.   globals:       none.
  323.  *********************************************************************/
  324.  
  325. int openuserfolder (options)
  326. struct optrec *options;
  327. {
  328.   int fd;
  329.  
  330.   if (options->foldertype == OF_STDOUT)
  331.     return(1);
  332.   else    /* options->foldertype == OF_USERMBOX */
  333.     if ((fd = open(options->userfolder,O_CREAT|O_WRONLY|O_APPEND,0600)) >= 0) {
  334.       return(fd);
  335.     }
  336.     else {
  337.       perror("popclient: openuserfolder: open()");
  338.       return(-1);
  339.     }
  340.   
  341. }
  342.  
  343.  
  344.  
  345. /*********************************************************************
  346.   function:      openmailpipe
  347.   description:   open a one-way pipe to the mail delivery agent.
  348.   arguments:     
  349.     options      fully-determined options (i.e. parsed, defaults invoked,
  350.                  etc).
  351.  
  352.   return value:  open file descriptor for the pipe or -1.
  353.   calls:         none.
  354.   globals:       reads mda_argv.
  355.  *********************************************************************/
  356.  
  357. int openmailpipe (options)
  358. struct optrec *options;
  359. {
  360.   int pipefd [2];
  361.   int childpid;
  362.   char binmailargs [80];
  363.  
  364.   if (pipe(pipefd) < 0) {
  365.     perror("popclient: openmailpipe: pipe");
  366.     return(-1);
  367.   }
  368.   if ((childpid = fork()) < 0) {
  369.     perror("popclient: openmailpipe: fork");
  370.     return(-1);
  371.   }
  372.   else if (childpid == 0) {
  373.  
  374.     /* in child process space */
  375.     close(pipefd[1]);  /* close the 'write' end of the pipe */
  376.     close(0);          /* get rid of inherited stdin */
  377.     if (dup(pipefd[0]) != 0) {
  378.       fputs("popclient: openmailpipe: dup() failed\n",stderr);
  379.       exit(1);
  380.     }
  381.  
  382.     execv(MDA_PATH,mda_argv);
  383.  
  384.     /* if we got here, an error occurred */
  385.     perror("popclient: openmailpipe: exec");
  386.     return(-1);
  387.  
  388.   }
  389.  
  390.   /* in the parent process space */
  391.   close(pipefd[0]);  /* close the 'read' end of the pipe */
  392.   return(pipefd[1]);
  393. }
  394.  
  395.  
  396.  
  397. /*********************************************************************
  398.   function:      closeuserfolder
  399.   description:   close the user-specified mail folder.
  400.   arguments:     
  401.     fd           mail folder descriptor.
  402.  
  403.   return value:  zero if success else -1.
  404.   calls:         none.
  405.   globals:       none.
  406.  *********************************************************************/
  407.  
  408. int closeuserfolder(fd)
  409. int fd;
  410. {
  411.   int err;
  412.  
  413.   if (fd != 1) {   /* not stdout */
  414.     err = close(fd);
  415.   }   
  416.   else
  417.     err = 0;
  418.   
  419.   if (err)
  420.     perror("popclient: closeuserfolder: close");
  421.  
  422.   return(err);
  423. }
  424.  
  425.  
  426.  
  427. /*********************************************************************
  428.   function:      closemailpipe
  429.   description:   close pipe to the mail delivery agent.
  430.   arguments:     
  431.     options      fully-determined options record
  432.     fd           pipe descriptor.
  433.  
  434.   return value:  0 if success, else -1.
  435.   calls:         none.
  436.   globals:       none.
  437.  *********************************************************************/
  438.  
  439. int closemailpipe (fd)
  440. int fd;
  441. {
  442.   int err;
  443.   int childpid;
  444.  
  445.   err = close(fd);
  446.   childpid = wait((union wait *) 0);
  447.   if (err)
  448.     perror("popclient: closemailpipe: close");
  449.  
  450.   return(err);
  451. }
  452.  
  453.  
  454.  
  455. /*********************************************************************
  456.   function:      parseMDAargs
  457.   description:   parse the argument string given in MDA_ARGS into
  458.                  a regular *argv[] array.
  459.   arguments:
  460.     options      fully-determined options record pointer.
  461.  
  462.   return value:  none.
  463.   calls:         none.
  464.   globals:       writes mda_argv.
  465.  *********************************************************************/
  466.  
  467. int parseMDAargs (options)
  468. struct optrec *options;
  469. {
  470.   int argi;
  471.   char *argp;
  472.  
  473.   /* first put the MDA alias in as argv[0] */
  474.   mda_argv[0] = MDA_ALIAS;
  475.   
  476. #ifdef MDA_ARGS
  477.  
  478.   /* make a writeable copy of MDA_ARGS */
  479.   argp = strcpy((char *) malloc(strlen(MDA_ARGS)+1), MDA_ARGS);
  480.   
  481.   while (*argp != '\0' && isspace(*argp))    /* skip null first arg */
  482.     argp++;                    
  483.  
  484.   /* now punch nulls into the delimiting whitespace in the args */
  485.   for (argi = 1;  
  486.        *argp != '\0';
  487.        argi++) {
  488.  
  489.     mda_argv[argi] = argp;     /* store pointer to this argument */
  490.  
  491.     /* find end of this argument */
  492.     while (!(*argp == '\0' || isspace(*argp)))
  493.       argp++;
  494.  
  495.     /* punch in a null terminator */
  496.     if (*argp != '\0')
  497.       *(argp++) = '\0';  
  498.  
  499.     /* check for macros */
  500.     if (strcmp(mda_argv[argi],"$u") == 0)
  501.       mda_argv[argi] = 
  502.         strcpy((char *) malloc(strlen(options->loginid)+1),options->loginid);
  503.     else
  504.       ;  /* no macros to expand */
  505.  
  506.   }
  507.   mda_argv[argi] = (char *) 0;
  508.  
  509. #else 
  510.  
  511.   mda_argv[1] = (char *) 0;
  512.  
  513. #endif
  514.  
  515. }
  516.  
  517.  
  518.  
  519. /*********************************************************************
  520.   function:      clearbiffbit
  521.   description:   clear the owner execute bit on the controlling tty, so
  522.                  that biff messages do not appear on the terminal with
  523.                  the program output.
  524.  
  525.   arguments:     none.
  526.   return value:  none.
  527.   calls:         none.
  528.   globals:       writes biffwas
  529.  *********************************************************************/
  530.  
  531. int clearbiffbit ()
  532. {
  533.   struct stat buf;
  534.  
  535.   if (fstat(0,&buf) < 0) {
  536.     perror("popclient: clearbiffbit: fstat");  /* fuss but don't quit */
  537.     return;
  538.   }
  539.  
  540.   if (buf.st_mode & S_IFCHR) {
  541.     buf.st_mode &= 0777;        /* isolate the device permissions */
  542.     biffwas = buf.st_mode;    /* save for restore */
  543.     buf.st_mode &= ~S_IEXEC;    /* clear the execute bit */
  544.     if (fchmod(0,buf.st_mode) < 0) {
  545.       perror("popclient: clearbiffbit: fchmod");  /* fuss but don't quit */
  546.       return;
  547.     }
  548.   }
  549. }
  550.  
  551.  
  552.  
  553.  
  554. /*********************************************************************
  555.   function:      restorebiffbit
  556.   description:   restore the previous state of the owner execute bit
  557.                  on the controlling tty.
  558.   arguments:     none.
  559.   return value:  none.
  560.   calls:         none.
  561.   globals:       reads biffwas
  562.  *********************************************************************/
  563.  
  564. int restorebiffbit ()
  565. {
  566.   if (biffwas == -1)
  567.     return;    /* not a tty */
  568.   else {
  569.     if (fchmod(0,biffwas) < 0) 
  570.       perror("popclient: restorebiffbit: fchmod");   /* fuss but don't quit */
  571.   }
  572. }
  573.  
  574.  
  575.  
  576. /*********************************************************************
  577.   function:      cleanup
  578.   description:   signal catcher.
  579.   arguments:     none.
  580.   return value:  none.
  581.   calls:         restorebiff
  582.   globals:       reads biffwas.
  583.  *********************************************************************/
  584.     
  585. int cleanup ()
  586. {
  587.   if (biffwas != -1) 
  588.     restorebiffbit();
  589. }
  590.  
  591.  
  592.