home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / tcpip / amitcp-support / ncftp-1.5.6 / src / rcs / open.c,v < prev    next >
Encoding:
Text File  |  1994-06-29  |  16.5 KB  |  626 lines

  1. head    1.1;
  2. access;
  3. symbols
  4.     ORIGINAL:1.1;
  5. locks; strict;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.1
  10. date    93.07.09.11.27.07;    author alph;    state Exp;
  11. branches;
  12. next    ;
  13.  
  14.  
  15. desc
  16. @Original version
  17. @
  18.  
  19.  
  20. 1.1
  21. log
  22. @checked in with -k by alph at 1993/10/10 19:59:56
  23. @
  24. text
  25. @/* open.c */
  26.  
  27. /*  $RCSfile: open.c,v $
  28.  *  $Revision: 1.1 $
  29.  *  $Date: 93/07/09 11:27:07 $
  30.  */
  31.  
  32. #include "sys.h"
  33.  
  34. #include <sys/types.h>
  35. #include <sys/param.h>
  36. #include <sys/socket.h>
  37. #include <netdb.h>
  38. #include <netinet/in.h>
  39. #include <arpa/ftp.h>
  40.  
  41. #include <string.h>
  42. #include <errno.h>
  43.  
  44. #ifndef NO_UNISTDH
  45. #    include <unistd.h>
  46. #endif
  47.  
  48. #include "util.h"
  49. #include "open.h"
  50. #include "cmds.h"
  51. #include "ftp.h"
  52. #include "ftprc.h"
  53. #include "main.h"
  54. #include "defaults.h"
  55. #include "copyright.h"
  56.  
  57. /* open.c globals */
  58. int                    remote_is_unix;        /* TRUE if remote host is unix. */
  59. int                    auto_binary = dAUTOBINARY;
  60. int                    anon_open = dANONOPEN;
  61.                                         /* Anonymous logins by default? */
  62. int                    connected = 0;        /* TRUE if connected to server */
  63.                                         /* If TRUE, set binary each connection. */
  64. Hostname            hostname;            /* Name of current host */
  65. #ifdef GATEWAY
  66. string                gateway;            /* node name of firewall gateway */
  67. string                gate_login;            /* login at firewall gateway */
  68. #endif
  69.  
  70. /* open.c externs */
  71. extern char                    *reply_string, *line, *Optarg, *margv[];
  72. extern int                    Optind, margc, verbose, macnum;
  73. extern long                    eventnumber;
  74. extern struct servent        serv;
  75. extern FILE                    *cout;
  76. extern string                anon_password;
  77.  
  78. /* Given a pointer to an OpenOptions (structure containing all variables
  79.  * that can be set from the command line), this routine makes sure all
  80.  * the variables have valid values by setting them to their defaults.
  81.  */
  82.  
  83. void InitOpenOptions(OpenOptions *openopt)
  84. {
  85.     /* How do you want to open a site if neither -a or -u are given?
  86.      * anon_open is true (default to anonymous login), unless
  87.      * defaults.h was edited to set dANONOPEN to 0 instead.
  88.      */
  89.     openopt->openmode = anon_open ? openImplicitAnon : openImplicitUser;
  90.  
  91.     /* Normally you don't want to ignore the entry in your netrc. */
  92.     openopt->ignore_rc = 0;
  93.  
  94.     /* Set the default delay if the user specifies redial mode without
  95.      * specifying the redial delay.
  96.      */
  97.     openopt->redial_delay = dREDIALDELAY;
  98.  
  99.     /* Normally, you only want to try once. If you specify redial mode,
  100.      * this is changed.
  101.      */
  102.     openopt->max_dials = 1;
  103.     
  104.     /* You don't want to cat the file to stdout by default. */
  105.     openopt->ftpcat = NO_FTPCAT;
  106.  
  107.     /* Setup the port number to try. */
  108. #ifdef dFTP_PORT
  109.     /* If dFTP_PORT is defined, we use a different port number by default
  110.      * than the one supplied in the servent structure.
  111.      */
  112.     openopt->port = dFTP_PORT;
  113.     /* Make sure the correct byte order is supplied! */
  114.     openopt->port = htons(openopt->port);
  115. #else
  116.     /* Use the port number supplied by the operating system's servent
  117.      * structure.
  118.      */
  119.     openopt->port = serv.s_port;
  120. #endif
  121.  
  122.     /* We are not in colon-mode (yet). */
  123.     openopt->colonmodepath[0] = 0;
  124.  
  125.     /* Set the hostname to a null string, since there is no default host. */
  126.     openopt->hostname[0] = 0;
  127.     
  128.     /* Set the opening directory path to a null string. */
  129.     openopt->cdpath[0] = 0;
  130. }    /* InitOpenOptions */
  131.  
  132.  
  133.  
  134.  
  135. /* This is responsible for parsing the command line and setting variables
  136.  * in the OpenOptions structure according to the user's flags.
  137.  */
  138.  
  139. int GetOpenOptions(int argc, char **argv, OpenOptions *openopt)
  140. {
  141.     int                    opt;
  142.     char                *cp;
  143.  
  144.     /* First setup the openopt variables. */
  145.     InitOpenOptions(openopt);
  146.  
  147.     /* Tell Getopt() that we want to start over with a new command. */
  148.     Getopt_Reset();
  149.     while ((opt = Getopt(argc, argv, "aiup:rd:g:cm")) >= 0) {
  150.         switch (opt) {        
  151.             case 'a':
  152.                 /* User wants to open anonymously. */
  153.                 openopt->openmode = openExplicitAnon;
  154.                 break;
  155.                 
  156.             case 'u':
  157.                 /* User wants to open with a login and password. */
  158.                 openopt->openmode = openExplicitUser;
  159.                 break;
  160.                 
  161.             case 'i':
  162.                 /* User wants to ignore the entry in the netrc. */
  163.                 openopt->ignore_rc = 1;
  164.                 break;
  165.                 
  166.             case 'p':
  167.                 /* User supplied a port number different from the default
  168.                  * ftp port.
  169.                  */
  170.                 openopt->port = atoi(Optarg);
  171.                 if (openopt->port <= 0) {
  172.                     /* Probably never happen, but just in case. */
  173.                     (void) printf("%s: bad port number (%s).\n", argv[0], Optarg);
  174.                     goto usage;
  175.                 }
  176.                 /* Must ensure that the port is in the correct byte order! */
  177.                 openopt->port = htons(openopt->port);
  178.                 break;
  179.                 
  180.             case 'd':
  181.                 /* User supplied a delay (in seconds) that differs from
  182.                  * the default.
  183.                  */
  184.                 openopt->redial_delay = atoi(Optarg);
  185.                 break;
  186.                 
  187.             case 'g':
  188.                 /* User supplied an upper-bound on the number of redials
  189.                  * to try.
  190.                  */
  191.                 openopt->max_dials = atoi(Optarg);
  192.                 break;
  193.  
  194.             case 'r':
  195.                 openopt->max_dials = -1;
  196.                 break;
  197.  
  198.             case 'm':
  199.                 /* ftpcat mode is only available from your shell command-line,
  200.                  * not from the ncftp shell.  Do that yourself with 'more zz'.
  201.                  */
  202.                 if (eventnumber == 0L) {
  203.                     /* If eventnumber is zero, then we were called directly
  204.                      * from main(), and before the ftp shell has started.
  205.                      */
  206.                     openopt->ftpcat = FTPMORE;
  207.                     /* ftpcat mode is really ftpmore mode. */
  208.                     break;
  209.                 } else {
  210.                     fprintf(stderr,
  211. "You can only use this form of colon-mode (-m) from your shell command line.\n\
  212. Try 'ncftp -m wuarchive.wustl.edu:/README'\n");
  213.                     goto usage;
  214.                 }
  215.                 break;
  216.  
  217.             case 'c':
  218.                 /* ftpcat mode is only available from your shell command-line,
  219.                  * not from the ncftp shell.  Do that yourself with 'get zz -'.
  220.                  */
  221.                 if (eventnumber == 0L) {
  222.                     /* If eventnumber is zero, then we were called directly
  223.                      * from main(), and before the ftp shell has started.
  224.                      */
  225.                     openopt->ftpcat = FTPCAT;
  226.                     break;
  227.                 } else {
  228.                     fprintf(stderr,
  229. "You can only use ftpcat/colon-mode from your shell command line.\n\
  230. Try 'ncftp -c wuarchive.wustl.edu:/README > file.'\n");
  231.                     goto usage;
  232.                 }
  233.                 break;
  234.                 
  235.             default:
  236.             usage:
  237.                 return USAGE;
  238.         }
  239.     }
  240.  
  241.     if (argv[Optind] == NULL) {
  242.         /* No host was supplied.  Print out the list of sites we know
  243.          * about and ask the user for one.
  244.          */
  245.         PrintSiteList();
  246.         (void) Gets("(site to open) ", openopt->hostname, sizeof(openopt->hostname));
  247.         /* Make sure the user just didn't hit return, in which case we
  248.          * just give up and go home.
  249.          */
  250.         if (openopt->hostname[0] == 0)
  251.             goto usage;
  252.     } else {
  253.         /* The user gave us a host to open.
  254.          *
  255.          * First, check to see if they gave us a colon-mode path
  256.          * along with the hostname.
  257.          */
  258.         if ((cp = index(argv[Optind], ':')) != NULL) {
  259.             *cp++ = 0;
  260.             (void) Strncpy(openopt->colonmodepath, cp);
  261.         }    
  262.         (void) Strncpy(openopt->hostname, argv[Optind]);
  263.     }
  264.     return NOERR;
  265. }    /* GetOpenOptions */
  266.  
  267.  
  268.  
  269.  
  270. /* This examines the format of the string stored in the hostname
  271.  * field of the OpenOptions, and sees if has to strip out a colon-mode
  272.  * pathname (to store in the colonmodepath field).  Since colon-mode
  273.  * is run quietly (without any output being generated), we init the
  274.  * login_verbosity variable here to quiet if we are running colon-mode.
  275.  */
  276. int CheckForColonMode(OpenOptions *openopt, int *login_verbosity)
  277. {
  278.     /* Usually the user doesn't supply hostname in colon-mode format,
  279.      * and wants to interactively browse the remote host, so set the
  280.      * login_verbosity to whatever it is set to now.
  281.      */
  282.     *login_verbosity = verbose;
  283.  
  284.     if (openopt->colonmodepath[0] != 0) {
  285.         /* But if the user does use colon-mode, we want to do our business
  286.          * and leave, without all the login messages, etc., so set
  287.          * login_verbosity to quiet so we won't print anything until
  288.          * we finish.  Colon-mode can be specified from the shell command
  289.          * line, so we would like to be able to execute ncftp as a one
  290.          * line command from the shell without spewing gobs of output.
  291.          */
  292.         *login_verbosity = V_QUIET;
  293.     } else if (openopt->ftpcat != 0) {
  294.         /* User specified ftpcat mode, but didn't supply the host:file. */
  295.         (void) fprintf(stderr, "You didn't use colon mode correctly.\n\
  296. If you use -c or -m, you need to do something like this:\n\
  297.     ncftp -c wuarchive.wustl.edu:/pub/README (to cat this file to stdout).\n");
  298.         return USAGE;
  299.     }
  300.     return NOERR;
  301. }    /* CheckForColonMode */
  302.  
  303.  
  304.  
  305.  
  306. /* All this short routine does is to hookup a socket to either the
  307.  * remote host or the firewall gateway host.
  308.  */
  309. int HookupToRemote(OpenOptions *openopt)
  310. {
  311.     int hErr;
  312.  
  313. #ifdef GATEWAY
  314.     /* Try connecting to the gateway host. */
  315.     if (*gateway) {
  316.         hErr = hookup(gateway, openopt->port);
  317.         (void) Strncpy(hostname, openopt->hostname);
  318.     } else
  319. #endif
  320.         hErr = hookup(openopt->hostname, openopt->port);
  321.     
  322.     return hErr;
  323. }    /* HookupToRemote */
  324.  
  325.  
  326.  
  327.  
  328. void CheckRemoteSystemType(int force_binary)
  329. {
  330.     int tmpverbose;
  331.     char *cp, c;
  332.  
  333.     /* As of this writing, UNIX is pretty much standard. */
  334.     remote_is_unix = 1;
  335.  
  336.     /* Do a SYSTem command quietly. */
  337.     tmpverbose = verbose;
  338.     verbose = V_QUIET;
  339.     if (command("SYST") == COMPLETE) {
  340.         if (tmpverbose == V_VERBOSE) {        
  341.             /* Find the system type embedded in the reply_string,
  342.              * and separate it from the rest of the junk.
  343.              */
  344.             cp = index(reply_string+4, ' ');
  345.             if (cp == NULL)
  346.                 cp = index(reply_string+4, '\r');
  347.             if (cp) {
  348.                 if (cp[-1] == '.')
  349.                     cp--;
  350.                 c = *cp;
  351.                 *cp = '\0';
  352.             }
  353.  
  354.             (void) printf("Remote system type is %s.\n",
  355.                 reply_string+4);
  356.             if (cp)
  357.                 *cp = c;
  358.         }
  359.         remote_is_unix = !strncmp(reply_string + 4, "UNIX", (size_t) 4);
  360.     }
  361.  
  362.     /* Set to binary mode if any of the following are true:
  363.      * (a) The user has auto-binary set;
  364.      * (b) The user is using colon-mode (force_binary);
  365.      * (c) The reply-string from SYST said it was UNIX with 8-bit chars.
  366.      */
  367.     if (auto_binary || force_binary
  368.         || !strncmp(reply_string, "215 UNIX Type: L8", (size_t) 17)) {
  369.         (void) _settype("binary");
  370.         if (tmpverbose > V_TERSE)
  371.             (void) printf("Using binary mode to transfer files.\n");
  372.     }
  373.  
  374.     /* Print a warning for that (extremely) rare Tenex machine. */
  375.     if (tmpverbose >= V_ERRS && 
  376.         !strncmp(reply_string, "215 TOPS20", (size_t) 10)) {
  377.         (void) _settype("tenex");
  378.         (void) printf("Using tenex mode to transfer files.\n");
  379.     }
  380.     verbose = tmpverbose;
  381. }    /* CheckRemoteSystemType */
  382.  
  383.  
  384.  
  385. /* This is called if the user opened the host with a file appended to
  386.  * the host's name, like "wuarchive.wustl.edu:/pub/readme," or
  387.  * "wuarchive.wustl.edu:/pub."  In the former case, we open wuarchive,
  388.  * and fetch "readme."  In the latter case, we open wuarchive, then set
  389.  * the current remote directory to "/pub."  If we are fetching a file,
  390.  * we can do some other tricks if "ftpcat mode" is enabled.  This mode
  391.  * must be selected from your shell's command line, and this allows you
  392.  * to use the program as a one-liner to pipe a remote file into something,
  393.  * like "ncftp -c wu:/pub/README | wc."  If the user uses ftpcat mode,
  394.  * the program immediately quits instead of going into it's own command
  395.  * shell.
  396.  */
  397. void ColonMode(OpenOptions *openopt)
  398. {
  399.     int tmpverbose;
  400.  
  401.     /* How do we tell if colonmodepath is a file or a directory?
  402.      * We first try cd'ing to the path first.  If we can, then it
  403.      * was a directory.  If we could not, we'll assume it was a file.
  404.      */
  405.  
  406.     /* Shut up, so cd won't print 'foobar: Not a directory.' */
  407.     tmpverbose = verbose;
  408.     verbose = V_QUIET;
  409.  
  410.     /* If we are using ftpcat|more mode, or we couldn't cd to the
  411.      * colon-mode path (then it must be a file to fetch), then
  412.      * we need to fetch a file.
  413.      */
  414.     if (openopt->ftpcat || ! _cd(openopt->colonmodepath)) {
  415.         /* We call the appropriate fetching routine, so we have to
  416.          * have the argc and argv set up correctly.  To do this,
  417.          * we just make an entire command line, then let makeargv()
  418.          * convert it to argv/argc.
  419.          */
  420.         if (openopt->ftpcat == FTPCAT)
  421.             (void) sprintf(line, "get %s -", openopt->colonmodepath);
  422.         else if (openopt->ftpcat == FTPMORE)
  423.             (void) sprintf(line, "more %s", openopt->colonmodepath);
  424.         else {
  425.             /* Regular colon-mode, where we fetch the file, putting the
  426.              * copy in the current local directory.
  427.              */
  428.             (void) sprintf(line, "mget %s", openopt->colonmodepath);
  429.         }
  430.         makeargv();
  431.  
  432.         /* Turn on messaging if we aren't catting. */
  433.         if (openopt->ftpcat == 0)
  434.             verbose = tmpverbose;
  435.         
  436.         /* get() also handles 'more'. */
  437.         if (openopt->ftpcat)
  438.             (void) get(margc, margv);
  439.         else
  440.             (void) mget(margc, margv);
  441.  
  442.         /* If we were invoked from the command line, quit
  443.          * after we got this file.
  444.          */
  445.         if (eventnumber == 0L) {
  446.             (void) quit(0, NULL);
  447.         }
  448.     }
  449.     verbose = tmpverbose;
  450. }    /* ColonMode */
  451.  
  452.  
  453.  
  454.  
  455. /* Given a properly set up OpenOptions, we try connecting to the site,
  456.  * redialing if necessary, and do some initialization steps so the user
  457.  * can send commands.
  458.  */
  459. int Open(OpenOptions *openopt)
  460. {
  461.     int                    tmpverbose, hErr;
  462.     int                    dials;
  463.     char *ruser, *rpass, *racct;
  464.     int siteInRC;
  465.     char *user, *pass, *acct;    
  466.     int                    login_verbosity;
  467.  
  468.     macnum = 0;     /* Reset macros. */
  469.  
  470.     /* If the hostname supplied is in the form host.name.str:/path/file,
  471.      * then colon mode was used, and we need to fix the hostname to be
  472.      * just the hostname, copy the /path/file to colonmode path, and init
  473.      * the login_verbosity variable.
  474.      */
  475.     if (CheckForColonMode(openopt, &login_verbosity) == USAGE)
  476.         return USAGE;
  477.  
  478.     /* If the hostname supplied was an abbreviation, such as just
  479.      * "wu" (wuarchive.wustl.edu), look through the list of sites
  480.      * we know about and get the whole name.  We also would like
  481.      * the path we want to start out in, if it is available.
  482.      */
  483.     GetFullSiteName(openopt->hostname, openopt->cdpath);
  484.  
  485. #ifdef GATEWAY
  486.     /* Make sure the gateway host name is a full name and not an
  487.      * abbreviation.
  488.      */
  489.     if (*gateway)
  490.         GetFullSiteName(gateway, NULL);
  491. #endif
  492.  
  493.     ruser = rpass = racct = NULL;
  494.     /* This also loads the init macro. */
  495.     siteInRC = ruserpass2(openopt->hostname, &ruser, &rpass, &racct);
  496.     if (ISANONOPEN(openopt->openmode)) {
  497.         user = "anonymous";
  498.         pass = anon_password;
  499.     } else {
  500.         user = NULL;
  501.         pass = NULL;
  502.     }
  503.     acct = NULL;
  504.     
  505.     if (siteInRC && !openopt->ignore_rc) {
  506.         acct = racct;
  507.         if (ruser != NULL) {
  508.             /* We were given a username.  If we were given explicit
  509.              * instructions from the command line, follow those and
  510.              * ignore what the RC had.  Otherwise if no -a or -u
  511.              * was specified, we use whatever was in the RC.
  512.              */
  513.             if (ISIMPLICITOPEN(openopt->openmode)) {
  514.                 user = ruser;
  515.                 pass = rpass;
  516.             }
  517.         }        
  518.     }
  519.  
  520.     for (
  521.             dials = 0;
  522.             openopt->max_dials < 0 || dials < openopt->max_dials;
  523.             dials++)
  524.     {
  525.         if (dials > 0) {
  526.             /* If this is the second dial or higher, sleep a bit. */
  527.             (void) sleep(openopt->redial_delay);
  528.             (void) fprintf(stderr, "Retry Number: %d\n", dials + 1);
  529.         }
  530.  
  531.         if ((hErr = HookupToRemote(openopt)) == -2)    
  532.             /* Recoverable, so we can try re-dialing. */
  533.             continue;
  534.         else if (hErr == NOERR) {
  535.             /* We were hookup'd successfully. */
  536.             connected = 1;
  537.  
  538. #ifdef GATEWAY
  539.             if (*gateway) {
  540.                 if ((Login(
  541.                     user,
  542.                     pass,
  543.                     acct,
  544.                     (!openopt->ignore_rc && !openopt->colonmodepath[0])
  545.                 ) != NOERR) || cout == NULL)
  546.                     goto nextdial;        /* error! */
  547.             }
  548. #endif
  549.  
  550. #ifdef GATEWAY
  551.             if (!*gateway) {
  552. #endif
  553.                 /* We don't want to run the init macro for colon-mode. */
  554.                 if ((Login(
  555.                         user,
  556.                         pass,
  557.                         acct,
  558.                         (!openopt->ignore_rc && !openopt->colonmodepath[0])
  559.                     ) != NOERR) || cout == NULL)
  560.                 {
  561.                     goto nextdial;        /* error! */
  562.                 }
  563. #ifdef GATEWAY
  564.             }
  565. #endif
  566.  
  567.             /* We need to check for unix and see if we should set binary
  568.              * mode automatically.
  569.              */
  570.             CheckRemoteSystemType(openopt->colonmodepath[0] != (char)0);
  571.  
  572.             if (openopt->colonmodepath[0]) {
  573.                 ColonMode(openopt);
  574.             } else if (openopt->cdpath[0]) {
  575.                 /* If we didn't have a colon-mode path, we try setting
  576.                  * the current remote directory to cdpath.  cdpath is
  577.                  * usually the last directory we were in the previous
  578.                  * time we called this site.
  579.                  */
  580.                 (void) _cd(openopt->cdpath);
  581.             } else {
  582.                 /* Freshen 'cwd' variable for the prompt. 
  583.                  * We have to do atleast one 'cd' so our variable
  584.                  * cwd (which is saved by _cd()) is set to something
  585.                  * valid.
  586.                  */
  587.                 (void) _cd(NULL);
  588.             }
  589.             break;    /* we are connected, so break the redial loop. */
  590.             /* end if we are connected */
  591.         } else {
  592.             /* Irrecoverable error, so don't bother redialing. */
  593.             /* The error message should have already been printed
  594.              * from Hookup().
  595.              */
  596.             break;
  597.         }
  598. nextdial: continue;    /* Try re-dialing. */
  599.     }
  600.     return (NOERR);
  601. }    /* Open */
  602.  
  603.  
  604.  
  605. /* This stub is called by our command parser. */
  606. int cmdOpen(int argc, char **argv)
  607. {
  608.     OpenOptions            openopt;
  609.  
  610.     /* If there is already a site open, close that one so we can
  611.      * open a new one.
  612.      */
  613.     if (connected && NOT_VQUIET && hostname[0]) {
  614.         (void) printf("Closing %s...\n", hostname);
  615.         (void) disconnect(0, NULL);
  616.     }
  617.  
  618.     if ((GetOpenOptions(argc, argv, &openopt) == USAGE) ||
  619.         (Open(&openopt) == USAGE))
  620.         return USAGE;
  621.     return NOERR;
  622. }    /* cmdOpen */
  623.  
  624. /* eof open.c */
  625. @
  626.