home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / ImageMagick-4.0.6.tar.gz / ImageMagick-4.0.6.tar / ImageMagick-4.0.6 / xtp / xtp.c < prev    next >
C/C++ Source or Header  |  1998-04-05  |  54KB  |  1,721 lines

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. %                                                                             %
  4. %                                                                             %
  5. %                                                                             %
  6. %                            X   X  TTTTT PPPP                                %
  7. %                             X X     T   P   P                               %
  8. %                              X      T   PPPP                                %
  9. %                             X X     T   P                                   %
  10. %                            X   X    T   P                                   %
  11. %                                                                             %
  12. %                                                                             %
  13. %                         File transfer program.                              %
  14. %                                                                             %
  15. %                                                                             %
  16. %                                                                             %
  17. %                            Software Design                                  %
  18. %                              John Cristy                                    %
  19. %                             October 1992                                    %
  20. %                                                                             %
  21. %                                                                             %
  22. %  Copyright 1998 E. I. du Pont de Nemours and Company                        %
  23. %                                                                             %
  24. %  Permission is hereby granted, free of charge, to any person obtaining a    %
  25. %  copy of this software and associated documentation files ("ImageMagick"),  %
  26. %  to deal in ImageMagick without restriction, including without limitation   %
  27. %  the rights to use, copy, modify, merge, publish, distribute, sublicense,   %
  28. %  and/or sell copies of ImageMagick, and to permit persons to whom the       %
  29. %  ImageMagick is furnished to do so, subject to the following conditions:    %
  30. %                                                                             %
  31. %  The above copyright notice and this permission notice shall be included in %
  32. %  all copies or substantial portions of ImageMagick.                         %
  33. %                                                                             %
  34. %  The software is provided "as is", without warranty of any kind, express or %
  35. %  implied, including but not limited to the warranties of merchantability,   %
  36. %  fitness for a particular purpose and noninfringement.  In no event shall   %
  37. %  E. I. du Pont de Nemours and Company be liable for any claim, damages or   %
  38. %  other liability, whether in an action of contract, tort or otherwise,      %
  39. %  arising from, out of or in connection with ImageMagick or the use or other %
  40. %  dealings in ImageMagick.                                                   %
  41. %                                                                             %
  42. %  Except as contained in this notice, the name of the E. I. du Pont de       %
  43. %  Nemours and Company shall not be used in advertising or otherwise to       %
  44. %  promote the sale, use or other dealings in ImageMagick without prior       %
  45. %  written authorization from the E. I. du Pont de Nemours and Company.       %
  46. %                                                                             %
  47. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  48. %
  49. %  Xtp is a utility for retrieving, listing, or printing files from a
  50. %  remote network site.  Xtp performs most of the same functions as the
  51. %  FTP program, but does not require any interactive commands.  You simply
  52. %  specify the file transfer task on the command line and xtp performs the
  53. %  transfer automatically.
  54. %
  55. %  This program was adapted from a similiar program written by Steve Singles,
  56. %  University of Delaware.
  57. %
  58. %  Command syntax:
  59. %
  60. %  Usage: xtp [-options ...] < uniform resource locator >
  61. %
  62. %  Where options include:
  63. %    -account password    supplemental password
  64. %    -binary              retrieve files as binary
  65. %    -exclude expression  exclude files that match the expression
  66. %    -directory           list file names that match the expression
  67. %    -file name           store the file with this name
  68. %    -get                 get files that match the expression
  69. %    -port number         port number of FTP server
  70. %    -print               print files that match the expression
  71. %    -proxy hostname      access remote host via this proxy host
  72. %    -prune               do not recursively search for files
  73. %    -put                 put files that match the expression
  74. %    -retrieve            retrieve files that match the expression
  75. %    -timeout seconds     specifies maximum seconds of XTP session
  76. %
  77. %
  78. */
  79.  
  80. /*
  81.   Include declarations.
  82. */
  83. #define __EXTENSIONS__  1
  84. #include "xtp.h"
  85. #include "regular.h"
  86. #include <termios.h>
  87. #include <fcntl.h>
  88. #if defined(SVR4) && !defined(linux)
  89. #include <stropts.h>
  90. #include <sys/socket.h>
  91. #endif
  92. #include <sys/stat.h>
  93. #include <sys/wait.h>
  94. /*
  95.   Variable declarations.
  96. */
  97. static char
  98.   *client_name,
  99.   slave_tty[16];
  100.  
  101. static int
  102.   child,
  103.   master,
  104.   status;
  105.  
  106. static RegularExpression
  107.   *directory_expression,
  108.   *exclude_expression,
  109.   *print_expression,
  110.   *retrieve_expression;
  111.  
  112. /*
  113.   External declarations.
  114. */
  115. extern char
  116.   *GetHostInfo(char *);
  117.  
  118. /*
  119.   Forward declarations.
  120. */
  121. static char
  122.   *Wait(void);
  123.  
  124. static int
  125.   MakeDirectory(char *);
  126.  
  127. static void
  128.   DirectoryRequest(char *, char *),
  129.   Error(char *,char *),
  130.   ExecuteFtp(char *,char *),
  131.   GetPseudoTerminal(void),
  132.   PrintRequest(char *,unsigned int),
  133.   ProcessRequest(char *,unsigned int,unsigned int),
  134.   RetrieveRequest(char *,unsigned int),
  135.   Usage(void);
  136.  
  137. /*
  138. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  139. %                                                                             %
  140. %                                                                             %
  141. %                                                                             %
  142. %   D i r e c t o r y R e q u e s t                                           %
  143. %                                                                             %
  144. %                                                                             %
  145. %                                                                             %
  146. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  147. %
  148. %  Function DirectoryRequest lists a file name and its attributes.
  149. %
  150. %  The format of the DirectoryRequest routine is:
  151. %
  152. %    DirectoryRequest(fileinfo,filename)
  153. %
  154. %  A description of each parameter follows:
  155. %
  156. %    o fileinfo:  Specifies a pointer to a character array that contains
  157. %      information about the file.
  158. %
  159. %    o filename:  Specifies a pointer to a character array that contains
  160. %      the name of the file.
  161. %
  162. */
  163. static void DirectoryRequest(char *fileinfo,char *filename)
  164. {
  165.   register char
  166.     *p;
  167.  
  168.   status=0;
  169.   for (p=filename; *p != '\0'; p++)
  170.     if (!isprint(*p))
  171.       *p=' ';
  172.   if (*fileinfo == '\0')
  173.     (void) fprintf(stdout,"%s\n",filename);
  174.   else
  175.     (void) fprintf(stdout,"%s %s\n",fileinfo,filename);
  176. }
  177.  
  178. /*
  179. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  180. %                                                                             %
  181. %                                                                             %
  182. %                                                                             %
  183. %   E r r o r                                                                 %
  184. %                                                                             %
  185. %                                                                             %
  186. %                                                                             %
  187. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  188. %
  189. %  Function Error displays an error message and then terminates the program.
  190. %
  191. %  The format of the Error routine is:
  192. %
  193. %      Error(message,qualifier)
  194. %
  195. %  A description of each parameter follows:
  196. %
  197. %    o message: Specifies the message to display before terminating the
  198. %      program.
  199. %
  200. %    o qualifier: Specifies any qualifier to the message.
  201. %
  202. %
  203. */
  204. static void Error(char *message,char *qualifier)
  205. {
  206.   (void) fprintf(stderr,"%s: %s",client_name,message);
  207.   if (qualifier != (char *) NULL)
  208.     (void) fprintf(stderr," (%s)",qualifier);
  209.   (void) fprintf(stderr,".\n");
  210.   if (child > 0)
  211.     if (master != -1)
  212.       {
  213.         (void) fcntl(master,F_SETFL,fcntl(master,F_GETFL) | O_NONBLOCK);
  214.         write(master,"quit\n",5);
  215.         while (Wait());
  216.       }
  217.   exit(1);
  218. }
  219.  
  220. /*
  221. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  222. %                                                                             %
  223. %                                                                             %
  224. %                                                                             %
  225. %   E x p a n d F i l e n a m e                                               %
  226. %                                                                             %
  227. %                                                                             %
  228. %                                                                             %
  229. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  230. %
  231. %  Function ExpandFilename expands '~' in a filename.
  232. %
  233. %  The format of the ExpandFilename function is:
  234. %
  235. %      ExpandFilename(filename)
  236. %
  237. %  A description of each parameter follows:
  238. %
  239. %    o filename: Specifies a pointer to an character array that contains the
  240. %      filename.
  241. %
  242. %
  243. */
  244. void ExpandFilename(char *filename)
  245. {
  246. #if !defined(vms) && !defined(macintosh) && !defined(WIN32)
  247.   char
  248.     expanded_filename[MaxTextLength];
  249.  
  250.   register char
  251.     *p;
  252.  
  253.   if (filename == (char *) NULL)
  254.     return;
  255.   if (*filename != '~')
  256.     return;
  257.   if (*(filename+1) == '/')
  258.     {
  259.       /*
  260.         Substitute ~ with $HOME.
  261.       */
  262.       p=(char *) getenv("HOME");
  263.       if (p == (char *) NULL)
  264.         p=".";
  265.       (void) strcpy(expanded_filename,p);
  266.       (void) strcat(expanded_filename,filename+1);
  267.     }
  268.   else
  269.     {
  270.       char
  271.         username[MaxTextLength];
  272.  
  273.       struct passwd
  274.         *entry;
  275.  
  276.       /*
  277.         Substitute ~ with home directory from password file.
  278.       */
  279.       (void) strcpy(username,filename+1);
  280.       p=strchr(username,'/');
  281.       if (p != (char *) NULL)
  282.         *p='\0';
  283.       entry=getpwnam(username);
  284.       if (entry == (struct passwd *) NULL)
  285.         return;
  286.       (void) strcpy(expanded_filename,entry->pw_dir);
  287.       if (p != (char *) NULL)
  288.         {
  289.           (void) strcat(expanded_filename,"/");
  290.           (void) strcat(expanded_filename,p+1);
  291.         }
  292.     }
  293.   (void) strcpy(filename,expanded_filename);
  294. #endif
  295. }
  296.  
  297. /*
  298. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  299. %                                                                             %
  300. %                                                                             %
  301. %                                                                             %
  302. %   E x e c u t e F t p                                                       %
  303. %                                                                             %
  304. %                                                                             %
  305. %                                                                             %
  306. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  307. %
  308. %  Function ExecuteFtp executes the FTP program as a child process.
  309. %
  310. %  The format of the ExecuteFtp routine is:
  311. %
  312. %    ExecuteFtp(hostname,port)
  313. %
  314. %  A description of each parameter follows:
  315. %
  316. %    o hostname:  Specifies a pointer to a character array that contains the
  317. %      name of the host to establish a connection to a FTP server.
  318. %
  319. %    o port:  Specifies a port number.  If the port number is NULL, xtp
  320. %      attempts to contact a FTP server at the default port.
  321. %
  322. %
  323. %
  324. */
  325. static void ExecuteFtp(char *hostname,char *port)
  326. {
  327.   int
  328.     slave;
  329.  
  330.   struct sigaction
  331.     action;
  332.  
  333.   struct termios
  334.     attributes;
  335.  
  336.   /*
  337.     Get slave tty line.
  338.   */
  339.   action.sa_handler=SIG_IGN;
  340.   (void) sigemptyset(&action.sa_mask);
  341.   action.sa_flags=0;
  342.   (void) sigaction(SIGTSTP,&action,(struct sigaction *) NULL);
  343.   slave=open(slave_tty,O_RDWR | O_NOCTTY);
  344.   if (slave < 0)
  345.     Error("Unable to open slave pseudo-terminal",slave_tty);
  346.   /*
  347.     Condition slave tty line.
  348.   */
  349. #if defined(SVR4) && !defined(linux)
  350.   (void) ioctl(slave,I_PUSH,"ptem");
  351.   (void) ioctl(slave,I_PUSH,"ldterm");
  352.   (void) ioctl(slave,I_PUSH,"ttcompat");
  353. #endif
  354.   (void) tcgetattr(slave,&attributes);
  355.   attributes.c_iflag&=(~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR |
  356.     IGNCR | ICRNL | IXON));
  357.   attributes.c_iflag|=IGNBRK | IXOFF;
  358.   attributes.c_oflag&=(~OPOST);
  359.   attributes.c_lflag&=
  360.     (~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | ISIG | NOFLSH | TOSTOP));
  361.   attributes.c_cflag&=(~(CSIZE | CSTOPB | HUPCL | PARENB));
  362.   attributes.c_cflag|=CLOCAL | CREAD | CS8;
  363.   (void) tcflush(slave,TCIFLUSH);
  364.   (void) tcsetattr(slave,TCSANOW,&attributes);
  365.   /*
  366.     Execute FTP program as a child process.
  367.   */
  368.   (void) close(master);
  369.   (void) dup2(slave,STDIN_FILENO);
  370.   (void) dup2(slave,STDOUT_FILENO);
  371.   (void) dup2(slave,STDERR_FILENO);
  372.   (void) close(slave);
  373.   (void) execlp(XTP_FTP,"ftp","-n","-i","-g","-v",hostname,port,(char *) 0);
  374.   perror("ftp");
  375.   (void) kill(0,SIGTERM);
  376. }
  377.  
  378. /*
  379. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  380. %                                                                             %
  381. %                                                                             %
  382. %                                                                             %
  383. %   G e t L o g i n I n f o                                                   %
  384. %                                                                             %
  385. %                                                                             %
  386. %                                                                             %
  387. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  388. %
  389. %  Function GetLoginInfo searches the .netrc file for a machine token that
  390. %  matches the remote machine specified with parameter hostname.  Once a
  391. %  match is made, the subsequent .netrc tokens are processed, stopping when
  392. %  the EOF is reached or another machine token is encountered.
  393. %
  394. %  The format of the GetLoginInfo routine is:
  395. %
  396. %      GetLoginInfo(hostname,user,ident,account)
  397. %
  398. %
  399. */
  400. static void GetLoginInfo(const char *hostname,char *user,char *ident,
  401.   char *account)
  402. {
  403.   char
  404.     filename[MaxTextLength],
  405.     keyword[MaxTextLength],
  406.     value[MaxTextLength];
  407.  
  408.   FILE
  409.     *file;
  410.  
  411.   int
  412.     match;
  413.  
  414.   register int
  415.     c;
  416.  
  417.   /*
  418.     Open netrc file.
  419.   */
  420.   (void) strcpy(filename,"~/.netrc");
  421.   ExpandFilename(filename);
  422.   file=fopen(filename,"r");
  423.   if (file == (FILE *) NULL)
  424.     return;
  425.   /*
  426.     Search netrc file for a machine name match.
  427.   */
  428.   match=False;
  429.   c=fgetc(file);
  430.   if (c == EOF)
  431.     return;
  432.   while (isgraph(c) && (c != EOF))
  433.   {
  434.     register char
  435.       *p;
  436.  
  437.     if (!isalnum(c))
  438.       c=fgetc(file);
  439.     else
  440.       {
  441.         /*
  442.           Determine a keyword and its value.
  443.         */
  444.         p=keyword;
  445.         do
  446.         {
  447.           if ((p-keyword) < (MaxTextLength-1))
  448.             *p++=(char) c;
  449.           c=fgetc(file);
  450.         } while (isalnum(c));
  451.         *p='\0';
  452.         while (isspace(c) || (c == '='))
  453.           c=fgetc(file);
  454.         p=value;
  455.         if (c != '"')
  456.           while (!isspace(c) && (c != EOF))
  457.           {
  458.             if ((p-value) < (MaxTextLength-1))
  459.               *p++=(char) c;
  460.             c=fgetc(file);
  461.           }
  462.         else
  463.           {
  464.             c=fgetc(file);
  465.             while ((c != '"') && (c != EOF))
  466.             {
  467.               if ((p-value) < (MaxTextLength-1))
  468.                 *p++=(char) c;
  469.               c=fgetc(file);
  470.             }
  471.           }
  472.         *p='\0';
  473.         /*
  474.           Assign a value to the specified keyword.
  475.         */
  476.         if (strcmp(keyword,"machine") == 0)
  477.           {
  478.             if (match)
  479.               break;
  480.             match=strcmp(hostname,value) == 0;
  481.             *user='\0';
  482.             *ident='\0';
  483.             *account='\0';
  484.           }
  485.         if (match)
  486.           {
  487.             if (strcmp(keyword,"login") == 0)
  488.               (void) strcpy(user,value);
  489.             if (strcmp(keyword,"password") == 0)
  490.               (void) strcpy(ident,value);
  491.             if (strcmp(keyword,"account") == 0)
  492.               (void) strcpy(account,value);
  493.           }
  494.       }
  495.     while (isspace(c))
  496.       c=fgetc(file);
  497.   }
  498.   (void) fclose(file);
  499. }
  500.  
  501. /*
  502. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  503. %                                                                             %
  504. %                                                                             %
  505. %                                                                             %
  506. %   G e t P s e u d o T e r m i n a l                                         %
  507. %                                                                             %
  508. %                                                                             %
  509. %                                                                             %
  510. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  511. %
  512. %  Function GetPseudoTerminal returns a master/slave pair of pseudo-terminals.
  513. %
  514. %  The format of the GetPseudoTerminal routine is:
  515. %
  516. %    GetPseudoTerminal()
  517. %
  518. %
  519. */
  520. static void GetPseudoTerminal(void)
  521. {
  522.   register char
  523.     *cp;
  524.  
  525.   struct termios
  526.     attributes;
  527.  
  528. #if defined(SVR4) && !defined(linux)
  529.   *slave_tty='\0';
  530.   master=open("/dev/ptmx",O_RDWR);
  531.   if (master > 0)
  532.     if ((grantpt(master) != -1) && (unlockpt(master) != -1))
  533.       {
  534.         cp=(char *) ptsname(master);
  535.         if (cp != (char *) NULL)
  536.           (void) strcpy(slave_tty,cp);
  537.       }
  538.   if (*slave_tty == '\0')
  539.     {
  540.       close(master);
  541.       master=(-1);
  542.     }
  543. #else
  544.   char
  545.     master_tty[16];
  546.  
  547.   register char
  548.     *bank;
  549.  
  550.   struct stat
  551.     info;
  552.  
  553.   master=(-1);
  554.   for (bank="pqrs"; *bank; bank++)
  555.   {
  556.     (void) sprintf(master_tty,"/dev/pty%c0",*bank);
  557.     (void) sprintf(slave_tty,"/dev/tty%c0",*bank);
  558.     if (stat(master_tty,&info) < 0)
  559.       break;
  560.     for (cp="0123456789abcdef"; *cp; cp++)
  561.     {
  562.       (void) sprintf((char *) master_tty,"/dev/pty%c%c",*bank,*cp);
  563.       master=open(master_tty,O_RDWR);
  564.       if (master < 0)
  565.         continue;
  566.       /*
  567.         Verify slave side is usable.
  568.       */
  569.       (void) sprintf(slave_tty,"/dev/tty%c%c",*bank,*cp);
  570.       if (access(slave_tty,R_OK | W_OK) == 0)
  571.         break;
  572.       (void) close(master);
  573.     }
  574.     if (access(slave_tty,R_OK | W_OK) == 0)
  575.       break;
  576.   }
  577. #endif
  578.   if (master < 0)
  579.     Error("All network ports in use",(char *) NULL);
  580.   /*
  581.     Condition master tty line.
  582.   */
  583.   (void) tcgetattr(master,&attributes);
  584.   attributes.c_lflag&=(~(ICANON | ECHO));
  585.   (void) tcflush(master,TCIFLUSH);
  586.   (void) tcsetattr(master,TCSANOW,&attributes);
  587. }
  588.  
  589. /*
  590. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  591. %                                                                             %
  592. %                                                                             %
  593. %                                                                             %
  594. %   M a k e D i r e c t o r y                                                 %
  595. %                                                                             %
  596. %                                                                             %
  597. %                                                                             %
  598. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  599. %
  600. %  Function MakeDirectory checks each component of a directory path and if it
  601. %  does not exist, creates it.
  602. %
  603. %  The format of the MakeDirectory routine is:
  604. %
  605. %    MakeDirectory(directory)
  606. %
  607. %  A description of each parameter follows:
  608. %
  609. %    o directory:  Specifies a pointer to a character array that contains
  610. %      the name of the directory to create.
  611. %
  612. %
  613. */
  614. static int MakeDirectory(char *directory)
  615. {
  616.   register char
  617.     *p;
  618.  
  619.   struct stat
  620.     info;
  621.  
  622.   /*
  623.     Determine first component of the directory.
  624.   */
  625.   p=strrchr(directory,'/');
  626.   if ((p == (char *) NULL) || (p == directory))
  627.     return(False);
  628.   *p='\0';
  629.   if (lstat(directory,&info) < 0)
  630.     {
  631.       /*
  632.         Path component does not exist;  create it.
  633.       */
  634.       if (MakeDirectory(directory) == 0)
  635.         if (mkdir(directory,(mode_t) 0777) >= 0)
  636.           {
  637.             *p='/';
  638.             return(False);
  639.           }
  640.     }
  641.   else
  642.     if (S_ISDIR(info.st_mode))
  643.       {
  644.         /*
  645.           Path component already exists.
  646.         */
  647.         *p='/';
  648.         return(False);
  649.       }
  650.   /*
  651.     Path component is a file not a directory.
  652.   */
  653.   *p='/';
  654.   return(True);
  655. }
  656.  
  657. /*
  658. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  659. %                                                                             %
  660. %                                                                             %
  661. %                                                                             %
  662. %   P r i n t R e q u e s t                                                   %
  663. %                                                                             %
  664. %                                                                             %
  665. %                                                                             %
  666. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  667. %
  668. %  Function PrintRequest prints a file on the remote FTP server.
  669. %
  670. %  The format of the PrintRequest routine is:
  671. %
  672. %    PrintRequest(filename,verbose)
  673. %
  674. %  A description of each parameter follows:
  675. %
  676. %    o filename:  Specifies a pointer to a character array that contains
  677. %      the name of the file to print.
  678. %
  679. %    o verbose: An unsigned integer.  A value other than zero dhows all
  680. %      responses from the remote server.
  681. %
  682. %
  683. */
  684. static void PrintRequest(char *filename,unsigned int verbose)
  685. {
  686.   char
  687.     command[MaxTextLength],
  688.     *response;
  689.  
  690.   /*
  691.     get remote-file [ - | < |zcat > ].
  692.   */
  693.   (void) sprintf(command,"get %s",filename);
  694.   if (strcmp(filename+strlen(filename)-2,".Z") == 0)
  695.     (void) strcat(command," |zcat\n");
  696.   else
  697.     if (strcmp(filename+strlen(filename)-3,".gz") == 0)
  698.       (void) strcat(command," |gunzip -c\n");
  699.     else
  700.       (void) strcat(command," -\n");
  701.   (void) write(master,command,strlen(command));
  702.   (void) fprintf(stdout,"%s:\n",filename);
  703.   while (response=Wait())
  704.     if (status == 0)
  705.       (void) fprintf(stdout,"%s\n",response);
  706.     else
  707.       if ((status == 5) || verbose)
  708.         (void) fprintf(stderr,"%s\n",response);
  709. }
  710.  
  711. /*
  712. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  713. %                                                                             %
  714. %                                                                             %
  715. %                                                                             %
  716. %   P r o c e s s R e q u e s t                                               %
  717. %                                                                             %
  718. %                                                                             %
  719. %                                                                             %
  720. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  721. %
  722. %  Function ProcessRequest first gets a recursive listing of the remote
  723. %  directory.  Next each filename in the list is either accepted or rejected
  724. %  based on a user specified regular expresssion.  If any files match the
  725. %  regular expression, its filename is listed, printed, or retrieved as
  726. %  specified by the command line arguments.
  727. %
  728. %  The format of the ProcessRequest routine is:
  729. %
  730. %    ProcessRequest(system_type,prune,verbose)
  731. %
  732. %  A description of each parameter follows:
  733. %
  734. %    o system_type:  Specifies what type of system the remote host is:
  735. %      UNIX, VMS, or other.
  736. %
  737. %    o prune:  Specifies whether to recusively search for files.
  738. %
  739. %    o verbose: An unsigned integer.  A value other than zero dhows all
  740. %      responses from the remote server.
  741. %
  742. %
  743. */
  744. static void ProcessRequest(char *system_type,unsigned int prune,
  745.   unsigned int verbose)
  746. {
  747. #define AccessExpression  "[Pp]ermission denied|not found|cannot access"
  748. #define DateExpression  " (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) "
  749. #define ListExpression  "ls-l([Rt])+([Rt])*([^ ])*"
  750.  
  751.   char
  752.     command[MaxTextLength],
  753.     directory[MaxTextLength],
  754.     **filelist,
  755.     filename[MaxTextLength << 1],
  756.     *info,
  757.     *response;
  758.  
  759.   register char
  760.     *p;
  761.  
  762.   register int
  763.     i;
  764.  
  765.   RegularExpression
  766.     *access_expression,
  767.     *date_expression;
  768.  
  769.   unsigned int
  770.     match,
  771.     maximum_files,
  772.     number_files;
  773.  
  774.   if (*system_type == '\0')
  775.     {
  776.       /*
  777.         Determine system type.
  778.       */
  779.       (void) strcpy(system_type,"UNIX");
  780.       (void) strcpy(command,"quote syst\n");
  781.       (void) write(master,command,strlen(command));
  782.       while (response=Wait())
  783.         if (status == 2)
  784.           (void) strcpy(system_type,response+4);
  785.     }
  786.   /*
  787.     Ask remote server for a file listing.
  788.   */
  789.   (void) strcpy(command,"dir\n");
  790.   if (!prune)
  791.     if (strncmp("VMS",system_type,3) == 0)
  792.       (void) strcpy(command,"ls [...]\n");
  793.     else
  794.       if ((strncmp("UNIX",system_type,4) == 0) ||
  795.           (strncmp("Windows_NT",system_type,10) == 0))
  796.         {
  797.           RegularExpression
  798.             *list_expression;
  799.  
  800.           /*
  801.             Get a recursive file listing.
  802.           */
  803.           (void) write(master,command,strlen(command));
  804.           (void) strcpy(command,"ls -ltR\n");
  805.           list_expression=CompileRegularExpression(ListExpression);
  806.           while (response=Wait())
  807.             if ((status == 0) && (*response != '\0'))
  808.               if (ExecuteRegularExpression(list_expression,response))
  809.                 {
  810.                   /*
  811.                     Remote site has a directory listing file.
  812.                   */
  813.                   (void) strncpy(filename,list_expression->subpattern[0],
  814.                     list_expression->pattern_length);
  815.                   (void) fprintf(stderr,"Using remote file listing %s...\n",
  816.                     filename);
  817.                   (void) sprintf(command,"get %s",filename);
  818.                   if (strcmp(filename+strlen(filename)-2,".Z") == 0)
  819.                     (void) strcat(command," |zcat\n");
  820.                   else
  821.                     if (strcmp(filename+strlen(filename)-3,".gz") == 0)
  822.                       (void) strcat(command," |gunzip -c\n");
  823.                     else
  824.                       (void) strcat(command," -\n");
  825.                   while (Wait());
  826.                   break;
  827.                 }
  828.           free((char *) list_expression);
  829.         }
  830.   (void) write(master,command,strlen(command));
  831.   while (response=Wait())
  832.     if ((status == 0) || (status == 5))
  833.       break;
  834.   if (status == 5)
  835.     {
  836.       /*
  837.         Directory command has limited functionality.
  838.       */
  839.       while (Wait());
  840.       (void) strcpy(command,"dir\n");
  841.       (void) write(master,command,strlen(command));
  842.       while (response=Wait())
  843.         if ((status == 0) || (status == 5))
  844.           break;
  845.     }
  846.   status=(-1);
  847.   if (response == (char *) NULL)
  848.     return;
  849.   /*
  850.     Search the recursive directory listing and act on expression matches.
  851.   */
  852.   access_expression=CompileRegularExpression(AccessExpression);
  853.   date_expression=CompileRegularExpression(DateExpression);
  854.   *directory='\0';
  855.   if (print_expression || retrieve_expression)
  856.     {
  857.       maximum_files=2048;
  858.       filelist=(char **) malloc(maximum_files*sizeof(char *));
  859.       if (filelist == (char **) NULL)
  860.         Error("Unable to allocate memory",(char *) NULL);
  861.       number_files=0;
  862.     }
  863.   do
  864.   {
  865.     if ((status > 0) || (*response == '\0'))
  866.       continue;
  867.     /*
  868.       Construct file name and info.
  869.     */
  870.     while (*response == ' ')
  871.       response++;
  872.     info=response;
  873.     p=response+strlen(response)-1;
  874.     if (*p == '\r')
  875.       p--;
  876.     if ((strncmp("UNIX",system_type,4) != 0) &&
  877.         (strncmp("Windows_NT",system_type,10) != 0))
  878.       {
  879.         if (strncmp("VMS",system_type,3) == 0)
  880.           if (*p == ']')
  881.             {
  882.               /*
  883.                 File is a directory.
  884.               */
  885.               do { p--; } while (*p == ' ');
  886.               *(++p)='\0';
  887.               (void) strcpy(directory,response);
  888.               (void) strcat(directory,"]");
  889.               continue;
  890.             }
  891.         while ((*info != ' ') && *info)
  892.           info++;
  893.         *info='\0';
  894.         p=response;
  895.       }
  896.     else
  897.       {
  898.         if ((*response != '-') && (*response != 'F'))
  899.           {
  900.             if (*p == ':')
  901.               {
  902.                 /*
  903.                   File is a directory.
  904.                 */
  905.                 do { p--; } while (*p == ' ');
  906.                 *(++p)='\0';
  907.                 (void) strcpy(directory,response);
  908.                 (void) strcat(directory,"/");
  909.               }
  910.             continue;
  911.           }
  912.         if (ExecuteRegularExpression(access_expression,response))
  913.           continue;
  914.         if (ExecuteRegularExpression(date_expression,response))
  915.           p=date_expression->subpattern[0]+13;
  916.         *p++='\0';
  917.         while (*p == ' ')
  918.           p++;
  919.       }
  920.     (void) strcpy(filename,directory);
  921.     (void) strcat(filename,p);
  922.     if (exclude_expression)
  923.       if (ExecuteRegularExpression(exclude_expression,filename))
  924.         continue;
  925.     if (directory_expression)
  926.       if (ExecuteRegularExpression(directory_expression,filename))
  927.         DirectoryRequest(info,filename);
  928.     match=False;
  929.     if (print_expression)
  930.       match|=ExecuteRegularExpression(print_expression,filename);
  931.     if (retrieve_expression)
  932.       match|=ExecuteRegularExpression(retrieve_expression,filename);
  933.     if (!match)
  934.       continue;
  935.     if (number_files >= maximum_files)
  936.       {
  937.         maximum_files<<=1;
  938.         filelist=(char **) realloc(filelist,maximum_files*sizeof(char *));
  939.         if (filelist == (char **) NULL)
  940.           Error("Unable to allocate memory",(char *) NULL);
  941.       }
  942.     filelist[number_files]=(char *) malloc((strlen(filename)+1)*sizeof(char));
  943.     if (filelist[number_files] == (char *) NULL)
  944.       Error("Unable to allocate memory",(char *) NULL);
  945.     (void) strcpy(filelist[number_files],filename);
  946.     number_files++;
  947.   } while (response=Wait());
  948.   free((char *) date_expression);
  949.   free((char *) access_expression);
  950.   if (!print_expression && !retrieve_expression)
  951.     return;
  952.   if (number_files == 0)
  953.     {
  954.       Warning("no files matched your expression",(char *) NULL);
  955.       return;
  956.     }
  957.   /*
  958.     Print, or retrieve a file.
  959.   */
  960.   for (i=0; i < number_files; i++)
  961.   {
  962.     if (print_expression)
  963.       if (ExecuteRegularExpression(print_expression,filelist[i]))
  964.         PrintRequest(filelist[i],verbose);
  965.     if (retrieve_expression)
  966.       if (ExecuteRegularExpression(retrieve_expression,filelist[i]))
  967.         RetrieveRequest(filelist[i],verbose);
  968.     free((char *) filelist[i]);
  969.   }
  970.   free((char *) filelist);
  971. }
  972.  
  973. /*
  974. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  975. %                                                                             %
  976. %                                                                             %
  977. %                                                                             %
  978. %   R e t r i e v e R e q u e s t                                             %
  979. %                                                                             %
  980. %                                                                             %
  981. %                                                                             %
  982. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  983. %
  984. %  Function RetrieveRequest retrieves a file from the remote FTP server.
  985. %
  986. %  The format of the RetrieveRequest routine is:
  987. %
  988. %    RetrieveRequest(filename,verbose)
  989. %
  990. %  A description of each parameter follows:
  991. %
  992. %    o filename:  Specifies a pointer to a character array that contains
  993. %      the name of the file to retrieve.
  994. %
  995. %    o verbose: An unsigned integer.  A value other than zero dhows all
  996. %      responses from the remote server.
  997. %
  998. %
  999. */
  1000. static void RetrieveRequest(char *filename,unsigned int verbose)
  1001. {
  1002.   char
  1003.     command[MaxTextLength],
  1004.     *response;
  1005.  
  1006.   /*
  1007.     get remote-file
  1008.   */
  1009.   (void) MakeDirectory(filename);
  1010.   (void) sprintf(command,"get %s\n",filename);
  1011.   (void) write(master,command,strlen(command));
  1012.   while (response=Wait())
  1013.     if (verbose)
  1014.       (void) fprintf(stderr,"%s\n",response);
  1015. }
  1016.  
  1017. /*
  1018. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1019. %                                                                             %
  1020. %                                                                             %
  1021. %                                                                             %
  1022. %   S i g n a l A l a r m                                                     %
  1023. %                                                                             %
  1024. %                                                                             %
  1025. %                                                                             %
  1026. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1027. %
  1028. %  Function SignalAlarm is called if the timer expires.
  1029. %
  1030. %  The format of the SignalAlarm routine is:
  1031. %
  1032. %    SignalAlarm(status)
  1033. %
  1034. %
  1035. */
  1036. static void SignalAlarm(int status)
  1037. {
  1038.   char
  1039.     message[MaxTextLength];
  1040.  
  1041.   int
  1042.     process_status;
  1043.  
  1044.   while (waitpid((pid_t) NULL,&process_status,WNOHANG) > 0);
  1045.   (void) sprintf(message,"timeout expired, status %x",process_status);
  1046.   Error(message,(char *) NULL);
  1047. }
  1048.  
  1049. /*
  1050. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1051. %                                                                             %
  1052. %                                                                             %
  1053. %                                                                             %
  1054. %   S i g n a l C h i l d                                                     %
  1055. %                                                                             %
  1056. %                                                                             %
  1057. %                                                                             %
  1058. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1059. %
  1060. %  Function SignalChild is called if the status of the child process changes.
  1061. %
  1062. %  The format of the SignalChild routine is:
  1063. %
  1064. %    SignalChild(status)
  1065. %
  1066. %
  1067. */
  1068. static void SignalChild(int status)
  1069. {
  1070.   char
  1071.     message[MaxTextLength];
  1072.  
  1073.   int
  1074.     process_status;
  1075.  
  1076.   while (waitpid((pid_t) NULL,&process_status,WNOHANG) > 0);
  1077.   (void) sprintf(message,"child died, status %x",process_status);
  1078.   Error(message,(char *) NULL);
  1079. }
  1080.  
  1081. /*
  1082. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1083. %                                                                             %
  1084. %                                                                             %
  1085. %                                                                             %
  1086. %   U s a g e                                                                 %
  1087. %                                                                             %
  1088. %                                                                             %
  1089. %                                                                             %
  1090. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1091. %
  1092. %  Procedure Usage displays the program usage;
  1093. %
  1094. %  The format of the Usage routine is:
  1095. %
  1096. %      Usage()
  1097. %
  1098. %
  1099. */
  1100. static void Usage(void)
  1101. {
  1102.   char
  1103.     **p;
  1104.  
  1105.   static char
  1106.     *options[]=
  1107.     {
  1108.       "  -account password    supplemental password",
  1109.       "  -binary              retrieve files as binary",
  1110.       "  -exclude expression  exclude files that match the expression",
  1111.       "  -directory           list file names that match the expression",
  1112.       "  -file name           store the file with this name",
  1113.       "  -get                 get files that match the expression",
  1114.       "  -port number         port number of FTP server",
  1115.       "  -print               print files that match the expression",
  1116.       "  -prune               do not recursively search for files",
  1117.       "  -proxy hostname      access remote host via this proxy host",
  1118.       "  -put                 put files that match the expression",
  1119.       "  -retrieve            retrieve files that match the expression",
  1120.       "  -timeout seconds     specifies maximum seconds of XTP session",
  1121.       "  -verbose             show all responses from the remote server",
  1122.       "",
  1123.       "<uniform resource locator> has the format:",
  1124.       "",
  1125.       "    protocol://host/[directory/[filename]]",
  1126.       "",
  1127.       "where protocol is `ftp' and host is `[user[:password]]@hostname'.",
  1128.       "User defaults to `anonymous' and password defaults to `host.domain'.",
  1129.       "Note that `directory/[filename]' is interpreted relative to the home",
  1130.       "directory for `user', thus an absolute pathname must be specified",
  1131.       "with the leading '/':",
  1132.       "",
  1133.       "    ftp://host//tmp/anyfile",
  1134.       "",
  1135.       "As an extension, the filename part of the locator is expanded",
  1136.       "by the shell for options -get or -put, otherwise it is processed",
  1137.       "as a regular expression.  For convenience, the protocol component",
  1138.       "of the uniform resource locator (ftp://) may be omitted.",
  1139.       NULL
  1140.     };
  1141.   (void) fprintf(stderr,
  1142.     "Usage: %s [-options ...] <uniform resource locator>\n",client_name);
  1143.   (void) fprintf(stderr,"\nWhere options include:\n");
  1144.   for (p=options; *p; p++)
  1145.     (void) fprintf(stderr,"%s\n",*p);
  1146.   exit(1);
  1147. }
  1148.  
  1149. /*
  1150. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1151. %                                                                             %
  1152. %                                                                             %
  1153. %                                                                             %
  1154. %   W a i t                                                                   %
  1155. %                                                                             %
  1156. %                                                                             %
  1157. %                                                                             %
  1158. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1159. %
  1160. %  Function Wait reads a line of output from the remote FTP server.
  1161. %
  1162. %  The format of the Wait() routine is:
  1163. %
  1164. %    response=Wait()
  1165. %
  1166. %  A description of each parameter follows:
  1167. %
  1168. %    o response:  Function Wait returns this pointer to the output obtained
  1169. %      from the remote FTP server.
  1170. %
  1171. %
  1172. */
  1173. static char *Wait(void)
  1174. {
  1175.   register char
  1176.     *p;
  1177.  
  1178.   static char
  1179.     buffer[1024],
  1180.     *q;
  1181.  
  1182.   static char
  1183.     line[1024];
  1184.  
  1185.   static int
  1186.     count=0;
  1187.  
  1188.   status=0;
  1189.   p=line;
  1190.   do
  1191.   {
  1192.     if (count <= 0)
  1193.       {
  1194.         /*
  1195.           The buffer is empty;  read output from the remote FTP server.
  1196.         */
  1197.         count=read(master,buffer,sizeof(buffer));
  1198.         q=buffer;
  1199.         if (count <= 0)
  1200.           {
  1201.             if (p == line)
  1202.               return((char *) NULL);
  1203.             break;
  1204.           }
  1205.       }
  1206.     count--;
  1207.     *p=(*q++);
  1208.     if (*p == '\n')
  1209.       break;
  1210.     p++;
  1211.     if ((p-line) >= 5)
  1212.       if (!strncmp(p-5,"ftp> ",5))
  1213.         if (count == 0)
  1214.           return((char *) NULL);
  1215.   } while (p < (line+sizeof(line)));
  1216.   *p='\0';
  1217.   if (isdigit(*line))
  1218.     status=atoi(line)/100;
  1219.   return(line);
  1220. }
  1221.  
  1222. /*
  1223. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1224. %                                                                             %
  1225. %                                                                             %
  1226. %                                                                             %
  1227. %   m a i n                                                                   %
  1228. %                                                                             %
  1229. %                                                                             %
  1230. %                                                                             %
  1231. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1232. %
  1233. %
  1234. */
  1235. int main(int argc,char **argv)
  1236. {
  1237. #define AccountExpression "[Aa]ccount"
  1238. #define ConnectExpression  "[Nn]ot connected"
  1239. #define IdentExpression  "[Pp]assword"
  1240. #define TypeExpression  "system type is "
  1241.  
  1242.   char
  1243.     account[MaxTextLength],
  1244.     command[MaxTextLength],
  1245.     directory[MaxTextLength],
  1246.     filename[MaxTextLength],
  1247.     *get_expression,
  1248.     *host_info,
  1249.     hostname[MaxTextLength],
  1250.     ident[MaxTextLength],
  1251.     *localname,
  1252.     *port,
  1253.     protocol[MaxTextLength],
  1254.     *proxy,
  1255.     *put_expression,
  1256.     *remotename,
  1257.     system_type[MaxTextLength],
  1258.     *url,
  1259.     user[MaxTextLength];
  1260.  
  1261.   int
  1262.     binary,
  1263.     field,
  1264.     process_status;
  1265.  
  1266.   register char
  1267.     *p,
  1268.     *q,
  1269.     *response;
  1270.  
  1271.   RegularExpression
  1272.     *account_expression,
  1273.     *connect_expression,
  1274.     *ident_expression,
  1275.     *type_expression;
  1276.  
  1277.   struct sigaction
  1278.     action;
  1279.  
  1280.   unsigned int
  1281.     count,
  1282.     prune,
  1283.     timeout,
  1284.     verbose;
  1285.  
  1286.   client_name=argv[0];
  1287.   if (argc < 2)
  1288.     Usage();
  1289. #if defined(SOCKS)
  1290.   SOCKSinit(argv[0]);
  1291. #endif
  1292.   /*
  1293.     Initialize program variables.
  1294.   */
  1295.   *account='\0';
  1296.   binary=True;
  1297.   child=(-1);
  1298.   *directory='\0';
  1299.   directory_expression=(RegularExpression *) NULL;
  1300.   exclude_expression=(RegularExpression *) NULL;
  1301.   *filename='\0';
  1302.   *ident='\0';
  1303.   get_expression=(char *) NULL;
  1304.   *hostname='\0';
  1305.   localname=(char *) NULL;
  1306.   master=(-1);
  1307.   port=(char *) NULL;
  1308.   print_expression=(RegularExpression *) NULL;
  1309.   *protocol='\0';
  1310.   proxy=(char *) getenv("xtp_proxy");
  1311.   prune=False;
  1312.   put_expression=(char *) NULL;
  1313.   remotename=(char *) NULL;
  1314.   retrieve_expression=(RegularExpression *) NULL;
  1315.   *system_type='\0';
  1316.   timeout=0;
  1317.   *user='\0';
  1318.   verbose=False;
  1319.   /*
  1320.     Parse uniform resource locator.
  1321.   */
  1322.   field=0;
  1323.   url=argv[argc-1];
  1324.   p=url;
  1325.   for (q=url; *q != '\0'; q++)
  1326.   {
  1327.     if (*q != '/')
  1328.       continue;
  1329.     switch (field)
  1330.     {
  1331.       case 0:
  1332.       {
  1333.         if ((q > url) && (*(q-1) == ':'))
  1334.           (void) strncat(protocol,p,q-p);
  1335.         else
  1336.           {
  1337.             (void) strncat(hostname,p,q-p);
  1338.             field+=2;
  1339.           }
  1340.         break;
  1341.       }
  1342.       case 1:
  1343.         break;
  1344.       case 2:
  1345.       {
  1346.         (void) strncat(hostname,p,q-p);
  1347.         break;
  1348.       }
  1349.       default:
  1350.       {
  1351.         (void) strncat(directory,p,q-p+1);
  1352.         break;
  1353.       }
  1354.     }
  1355.     field++;
  1356.     p=q+1;
  1357.   }
  1358.   if (*directory != '\0')
  1359.     directory[strlen(directory)-1]='\0';
  1360.   (void) strncat(filename,p,q-p);
  1361.   if (*hostname == '\0')
  1362.     (void) gethostname(hostname,64);
  1363.   GetLoginInfo(hostname,user,ident,account);
  1364.   p=strrchr(hostname,'@');
  1365.   if (p != (char *) NULL)
  1366.     {
  1367.       /*
  1368.         Parse login-name:password@site.
  1369.       */
  1370.       GetLoginInfo(p+1,user,ident,account);
  1371.       strncpy(user,hostname,p-hostname);
  1372.       user[p-hostname]='\0';
  1373.       strcpy(hostname,p+1);
  1374.       p=strchr(user,':');
  1375.       if (p != (char *) NULL)
  1376.         {
  1377.           strcpy(ident,p+1);
  1378.           user[p-user]='\0';
  1379.         }
  1380.     }
  1381.   /*
  1382.     Parse command line arguments.
  1383.   */
  1384.   for (*argv++; *argv && ((**argv == '-') || (**argv == '+')); argv++)
  1385.     switch (argv[0][1])
  1386.     {
  1387.       case 'a':
  1388.       {
  1389.         (void) strcpy(account,*++argv);
  1390.         break;
  1391.       }
  1392.       case 'b':
  1393.       {
  1394.         binary=(**argv == '-');
  1395.         break;
  1396.       }
  1397.       case 'd':
  1398.       {
  1399.         directory_expression=CompileRegularExpression(filename);
  1400.         if (!directory_expression)
  1401.           exit(1);
  1402.         break;
  1403.       }
  1404.       case 'e':
  1405.       {
  1406.         exclude_expression=CompileRegularExpression(*++argv);
  1407.         if (!exclude_expression)
  1408.           exit(1);
  1409.         break;
  1410.       }
  1411.       case 'f':
  1412.       {
  1413.         localname=(*++argv);
  1414.         remotename=(*++argv);
  1415.         break;
  1416.       }
  1417.       case '?':
  1418.       case 'h':
  1419.       {
  1420.         Usage();
  1421.         break;
  1422.       }
  1423.       case 'g':
  1424.       {
  1425.         get_expression=filename;
  1426.         break;
  1427.       }
  1428.       case 'p':
  1429.       {
  1430.         if (strncmp("port",*argv+1,2) == 0)
  1431.           {
  1432.             port=(*++argv);
  1433.             break;
  1434.           }
  1435.         if (strncmp("proxy",*argv+1,3) == 0)
  1436.           {
  1437.             proxy=(char *) NULL;
  1438.             if (**argv == '-')
  1439.               {
  1440.                 argv++;
  1441.                 if (*argv == (char *) NULL)
  1442.                   Error("Missing host on -proxy",(char *) NULL);
  1443.                 proxy=(*argv);
  1444.               }
  1445.             break;
  1446.           }
  1447.         if (strncmp("prune",*argv+1,3) == 0)
  1448.           {
  1449.             prune=(**argv == '-');
  1450.             break;
  1451.           }
  1452.         if (strncmp("print",*argv+1,3) == 0)
  1453.           {
  1454.             print_expression=CompileRegularExpression(filename);
  1455.             if (!print_expression)
  1456.               exit(1);
  1457.             break;
  1458.           }
  1459.         if (strncmp("put",*argv+1,2) == 0)
  1460.           {
  1461.             put_expression=filename;
  1462.             break;
  1463.           }
  1464.         Error("Unrecognized option",*argv);
  1465.         break;
  1466.       }
  1467.       case 'r':
  1468.       {
  1469.         retrieve_expression=CompileRegularExpression(filename);
  1470.         if (!retrieve_expression)
  1471.           exit(1);
  1472.         break;
  1473.       }
  1474.       case 't':
  1475.       {
  1476.         timeout=atoi(*++argv);
  1477.         break;
  1478.       }
  1479.       case 'v':
  1480.       {
  1481.         verbose=True;
  1482.         break;
  1483.       }
  1484.       default:
  1485.       {
  1486.         Error("Unrecognized option",(char *) NULL);
  1487.         break;
  1488.       }
  1489.     }
  1490.   if ((directory_expression == (RegularExpression *) NULL) &&
  1491.       (print_expression == (RegularExpression *) NULL) &&
  1492.       (retrieve_expression == (RegularExpression *) NULL) &&
  1493.       (put_expression == (char *) NULL))
  1494.     get_expression=filename;
  1495.   if (*protocol != '\0')
  1496.     if (strcmp(protocol,"ftp:") != 0)
  1497.       if ((get_expression == (char *) NULL) || (strlen(get_expression) == 0))
  1498.         Error("Unsupported protocol",protocol);
  1499.       else
  1500.         {
  1501.           /*
  1502.             Use GET to handle non-ftp protocol but only for *get*.
  1503.           */
  1504.           (void) sprintf(command,"GET %s > %s",url,filename);
  1505.           status=system(command);
  1506.           return(status < 0);
  1507.         }
  1508.   if ((*ident == '\0') && (*user == '\0'))
  1509.     {
  1510.       struct passwd
  1511.         *user_info;
  1512.  
  1513.       /*
  1514.         Identify user as user@host.domain.
  1515.       */
  1516.       (void) strcpy(user,"anonymous");
  1517.       (void) strcpy(ident,"anonymous");
  1518.       user_info=getpwuid(geteuid());
  1519.       if (user_info != (struct passwd *) NULL)
  1520.         (void) strcpy(ident,user_info->pw_name);
  1521.       if (proxy != (char *) NULL)
  1522.         {
  1523.           (void) strcat(ident,"@");
  1524.           (void) strcat(ident,proxy);
  1525.         }
  1526.       else
  1527.         {
  1528.           p=ident+strlen(ident);
  1529.           *p++='@';
  1530.           (void) gethostname(p,64);
  1531.           p=ident+strlen(ident);
  1532.           *p++='.';
  1533.           (void) getdomainname(p,64);
  1534.         }
  1535.     }
  1536.   if (proxy != (char *) NULL)
  1537.     {
  1538.       /*
  1539.         Access the remote host via a proxy ftpd client.
  1540.       */
  1541.       (void) strcat(user,"@");
  1542.       (void) strcat(user,hostname);
  1543.       (void) strcpy(hostname,proxy);
  1544.     }
  1545.   host_info=GetHostInfo(hostname);
  1546.   if (host_info == (char *) NULL)
  1547.     Error("Unknown host",hostname);
  1548.   if (verbose)
  1549.     if (*directory == '\0')
  1550.       (void) fprintf(stderr,"%s\n",host_info);
  1551.     else
  1552.       (void) fprintf(stderr,"%s %s\n",host_info,directory);
  1553.   GetPseudoTerminal();
  1554.   /*
  1555.     Set signal handlers.
  1556.   */
  1557.   action.sa_handler=SignalAlarm;
  1558.   (void) sigemptyset(&action.sa_mask);
  1559.   action.sa_flags=0;
  1560.   (void) sigaction(SIGALRM,&action,(struct sigaction *) NULL);
  1561.   if (timeout != 0)
  1562.     (void) alarm(Max(timeout >> 4,120));  /* enable login timer. */
  1563.   action.sa_handler=SignalChild;
  1564.   (void) sigaction(SIGCHLD,&action,(struct sigaction *) NULL);
  1565.   /*
  1566.     Connect and logon to host.
  1567.   */
  1568.   child=fork();
  1569.   if (child < 0)
  1570.     Error("Unable to fork",(char *) NULL);
  1571.   if (child == 0)
  1572.     ExecuteFtp(hostname,port);
  1573.   type_expression=CompileRegularExpression(TypeExpression);
  1574.   while (response=Wait())
  1575.   {
  1576.     if (verbose)
  1577.       (void) fprintf(stderr,"%s\n",response);
  1578.     if (ExecuteRegularExpression(type_expression,response))
  1579.       (void) strcpy(system_type,type_expression->subpattern_end[0]);
  1580.   }
  1581.   free((char *) type_expression);
  1582.   if (*user == '\0')
  1583.     (void) strcpy(user,"anonymous");
  1584.   (void) sprintf(command,"user %s\n",user);
  1585.   if (*ident != '\0')
  1586.     (void) sprintf(command,"user %s %s\n",user,ident);
  1587.   (void) write(master,command,strlen(command));
  1588.   /*
  1589.     Logon dialog may require a password or account information.
  1590.   */
  1591.   account_expression=CompileRegularExpression(AccountExpression);
  1592.   connect_expression=CompileRegularExpression(ConnectExpression);
  1593.   ident_expression=CompileRegularExpression(IdentExpression);
  1594.   while (response=Wait())
  1595.   {
  1596.     if (verbose)
  1597.       (void) fprintf(stderr,"%s\n",response);
  1598.     if (status == 3)
  1599.       if (*ident == '\0')
  1600.         if (ExecuteRegularExpression(ident_expression,response))
  1601.           {
  1602.             if (!verbose)
  1603.               (void) fprintf(stderr,"%s\n",response);
  1604.             count=read(master,command,sizeof(command));
  1605.             command[count]='\0';
  1606.             (void) fprintf(stderr,"%s",command);
  1607.           }
  1608.     if (status == 3)
  1609.       if (*account == '\0')
  1610.         if (ExecuteRegularExpression(account_expression,response))
  1611.           {
  1612.             if (!verbose)
  1613.               (void) fprintf(stderr,"%s\n",response);
  1614.             count=read(master,command,sizeof(command));
  1615.             command[count]='\0';
  1616.             (void) fprintf(stderr,"%s",command);
  1617.           }
  1618.     if (status == 5)
  1619.       Error(response,user);
  1620.     if (ExecuteRegularExpression(connect_expression,response))
  1621.       Error("Unable to connect to remote host",hostname);
  1622.   }
  1623.   free((char *) ident_expression);
  1624.   free((char *) connect_expression);
  1625.   free((char *) account_expression);
  1626.   if (timeout != 0)
  1627.     (void) alarm(timeout);  /* enable session timer. */
  1628.   if (*directory != '\0')
  1629.     {
  1630.       /*
  1631.         Change remote working directory.
  1632.       */
  1633.       (void) sprintf(command,"cd %s\n",directory);
  1634.       (void) write(master,command,strlen(command));
  1635.       while (response=Wait())
  1636.       {
  1637.         if (verbose)
  1638.           (void) fprintf(stderr,"%s\n",response);
  1639.         if (status == 5)
  1640.           Error("No such directory",directory);
  1641.       }
  1642.       (void) strcpy(command,"pwd\n");
  1643.       (void) write(master,command,strlen(command));
  1644.       while (response=Wait())
  1645.         if (verbose)
  1646.           (void) fprintf(stderr,"%s\n",response);
  1647.     }
  1648.   if (binary)
  1649.     {
  1650.       /*
  1651.         Set file transfer type.
  1652.       */
  1653.       (void) strcpy(command,"binary\n");
  1654.       (void) write(master,command,strlen(command));
  1655.       while (response=Wait())
  1656.         if (verbose)
  1657.           (void) fprintf(stderr,"%s\n",response);
  1658.       (void) strcpy(command,"type\n");
  1659.       (void) write(master,command,strlen(command));
  1660.       while (response=Wait())
  1661.         if (verbose)
  1662.           (void) fprintf(stderr,"%s\n",response);
  1663.     }
  1664.   if (get_expression != (char *) NULL)
  1665.     {
  1666.       /*
  1667.         Process get request.
  1668.       */
  1669.       (void) sprintf(command,"mget %s\n",get_expression);
  1670.       if (!IsGlob(get_expression) && (localname != (char *) NULL))
  1671.         (void) sprintf(command,"get %s %s\n",get_expression,localname);
  1672.       (void) write(master,command,strlen(command));
  1673.       while (response=Wait())
  1674.         if ((status == 5) || verbose)
  1675.           (void) fprintf(stderr,"%s\n",response);
  1676.     }
  1677.   else
  1678.     if (put_expression != (char *) NULL)
  1679.       {
  1680.         /*
  1681.           Process put request.
  1682.         */
  1683.         (void) strcpy(command,"glob on\n");
  1684.         (void) write(master,command,strlen(command));
  1685.         while (response=Wait())
  1686.           if (verbose)
  1687.             (void) fprintf(stderr,"%s\n",response);
  1688.         (void) sprintf(command,"mput %s\n",put_expression);
  1689.         if (!IsGlob(put_expression) && (remotename != (char *) NULL))
  1690.           (void) sprintf(command,"put %s %s\n",put_expression,remotename);
  1691.         (void) write(master,command,strlen(command));
  1692.         while (response=Wait())
  1693.           if ((status == 5) || verbose)
  1694.             (void) fprintf(stderr,"%s\n",response);
  1695.       }
  1696.     else
  1697.       ProcessRequest(system_type,prune,verbose);
  1698.   (void) strcpy(command,"quit\n");
  1699.   (void) write(master,command,strlen(command));
  1700.   /*
  1701.     Wait for child to finish.
  1702.   */
  1703.   action.sa_handler=SIG_DFL;
  1704.   (void) sigemptyset(&action.sa_mask);
  1705.   action.sa_flags=0;
  1706.   (void) sigaction(SIGCHLD,&action,(struct sigaction *) NULL);
  1707.   (void) fcntl(master,F_SETFL,fcntl(master,F_GETFL) | O_NONBLOCK);
  1708.   while (Wait());
  1709.   (void) waitpid(child,&process_status,WNOHANG);
  1710.   (void) close(master);
  1711.   if (directory_expression != (RegularExpression *) NULL)
  1712.     free((char *) directory_expression);
  1713.   if (exclude_expression != (RegularExpression *) NULL)
  1714.     free((char *) exclude_expression);
  1715.   if (print_expression != (RegularExpression *) NULL)
  1716.     free((char *) print_expression);
  1717.   if (retrieve_expression != (RegularExpression *) NULL)
  1718.     free((char *) retrieve_expression);
  1719.   return(status < 0);
  1720. }
  1721.