home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / ncftp-1.9.5.tar.gz / ncftp-1.9.5.tar / ncftp-1.9.5 / open.c < prev    next >
C/C++ Source or Header  |  1995-10-01  |  18KB  |  645 lines

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