home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ncftp-2.3.0-base.tgz / ncftp-2.3.0-base.tar / contrib / ncftp / Open.c < prev    next >
C/C++ Source or Header  |  1995-11-26  |  23KB  |  872 lines

  1. /* Open.c */
  2.  
  3. #include "Sys.h"
  4.  
  5. #ifdef SYSLOG
  6. #    include <syslog.h>
  7. #endif
  8.  
  9. #include "Open.h"
  10. #include "Util.h"
  11. #include "GetPass.h"
  12. #include "Cmds.h"
  13. #include "RCmd.h"
  14. #include "Bookmark.h"
  15. #include "FTP.h"
  16. #include "Get.h"
  17. #include "Getopt.h"
  18. #include "Macro.h"
  19. #include "Hostwin.h"
  20. #include "Main.h"
  21. #include "Complete.h"
  22.  
  23. /* This is a preference setting specifying whether we use anonymous logins
  24.  * by default (as opposed to user/passwd logins).
  25.  */
  26. int gAnonOpen = (UOPEN == 0);
  27.  
  28. /* A structure containing some extra information we've learned about
  29.  * the remote host, so we don't need to find out the hard way each
  30.  * time we do something.
  31.  */
  32. extern Bookmark gRmtInfo;
  33.  
  34. /* Name of the host we're connected to. */
  35. string gHost;
  36.  
  37. /* We keep track if we've logged in to the host yet.  It's possible to
  38.  * be connected but not authorized (authenticated, whatever) to do anything.
  39.  */
  40. int gLoggedIn = 0;
  41.  
  42. /* Need to know if we are trying to connect and login, so if we get
  43.  * hangup during that, we will come back to the open without longjmp'ing
  44.  * out.
  45.  */
  46. int gAttemptingConnection = 0;
  47.  
  48. /* Need to know if they did a 'open -r' so we don't use the built-in pager
  49.  * for long site-connect messages.  Otherwise the program would stop to
  50.  * wait for the user to hit <space> each time we connected to that site
  51.  * which would sort of defeat the purpose of redialing.
  52.  */
  53. int gRedialModeEnabled = 0;
  54.  
  55. /* If we connect successfully, we'll want to save this port number
  56.  * when we add a host file entry.
  57.  */
  58. int gPortNumberUsed;
  59.  
  60. int gSavePasswords = 0;
  61.  
  62. /* Open.c externs */
  63. extern char *gOptArg;
  64. extern int gOptInd, gIsToTTY;
  65. extern unsigned int gFTPPort;
  66. extern long gEventNumber;
  67. extern char gRemoteCWD[256];
  68. extern char gIPStr[32];
  69. extern int gTransferType, gCurType;
  70. extern int gRmtInfoIsNew, gWantRmtInfoSaved;
  71. extern int gConnected, gHasPASV, gVerbosity;
  72. extern int gDoneApplication, gWinInit;
  73. extern string gEmailAddress, gAnonPassword, gPager;
  74. extern UserInfo gUserInfo;
  75. extern FILE *gLogFile;
  76. extern LineList gRedir;
  77.  
  78.  
  79. /* This is used primarily for non-anonymous logins.  We'll have to ask
  80.  * the user some questions, like their username, password, etc.
  81.  */
  82. int LoginQuestion(
  83.     char *prompt,
  84.     char *answer,
  85.     size_t siz,
  86.     char *defanswer,
  87.     int noEcho)
  88. {
  89.     string prompt2;
  90.     
  91.     /* Only do this if we have an empty string as the answer. */
  92.     if (*answer == '\0') {
  93.         if (defanswer != NULL)
  94.             sprintf(prompt2, "%s [%s]: ", prompt, defanswer);
  95.         else
  96.             sprintf(prompt2, "%s: ", prompt);
  97.         GetAnswer(prompt2, answer, siz, noEcho);
  98.         if ((*answer == '\0') && (defanswer != NULL))
  99.             Strncpy(answer, defanswer, siz);
  100.     }
  101.     return (*answer == '\0' ? (-1) : 0);
  102. }    /* LoginQuestion */
  103.  
  104.  
  105.  
  106.  
  107. int Login(char *u, char *p, char *a)
  108. {
  109.     string u2, p2, a2;
  110.     ResponsePtr rp;
  111.     int result = -1;
  112.     int isAnonLogin = 1;
  113.  
  114.     STRNCPY(u2, u);
  115.     STRNCPY(p2, p);
  116.     STRNCPY(a2, a);
  117.         
  118.     rp = InitResponse();
  119.     if (LoginQuestion("User", u2, sizeof(u2), "anonymous", 0) < 0)
  120.         goto done;
  121.     RCmd(rp, "USER %s", u2);
  122.  
  123.     for (;;) {
  124.         /* Here's a mini finite-automaton for the login process.
  125.          *
  126.          * Originally, the FTP protocol was designed to be entirely
  127.          * implementable from a FA.  It could be done, but I don't think
  128.          * it's something an interactive process could be the most
  129.          * effective with.
  130.          */
  131.         switch (rp->code) {
  132.             case 230:    /* 230 User logged in, proceed. */
  133.             case 202:    /* Command not implemented, superfluous at this site. */
  134.                 goto okay;
  135.  
  136.             case 421:    /* 421 Service not available, closing control connection. */
  137.                 goto done;
  138.                 
  139.             case 331:    /* 331 User name okay, need password. */
  140.                 isAnonLogin =    STREQ("anonymous", u2) ||
  141.                                 STREQ("ftp", u2);
  142.                 if (isAnonLogin)
  143.                     rp->printMode = kDontPrint;
  144.  
  145.                 ReInitResponse(rp);
  146.                 (void) LoginQuestion(
  147.                     "Password",
  148.                     p2,
  149.                     sizeof(p2),
  150.                     isAnonLogin ? gAnonPassword : NULL,
  151.                     1
  152.                 );
  153.                 RCmd(rp, "PASS %s", p2);
  154.                 break;
  155.  
  156.              case 332:    /* 332 Need account for login. */
  157.              case 532:     /* 532 Need account for storing files. */
  158.                 ReInitResponse(rp);
  159.                 (void) LoginQuestion("Account", a2, sizeof(a2), NULL, 1);
  160.                 RCmd(rp, "ACCT %s", a2);
  161.                 break;
  162.  
  163.             case 501:    /* Syntax error in parameters or arguments. */
  164.             case 503:    /* Bad sequence of commands. */
  165.             case 530:    /* Not logged in. */
  166.             case 550:    /* Can't set guest privileges. */
  167.                 goto done;
  168.                 
  169.             default:
  170.                 if (rp->msg.first == NULL) {
  171.                     Error(kDontPerror, "Lost connection during login.\n");
  172.                 } else {
  173.                     Error(kDontPerror, "Unexpected response: %s\n",
  174.                         rp->msg.first->line
  175.                     );
  176.                 }
  177.                 goto done;
  178.         }
  179.     }
  180. okay:
  181.     if (isAnonLogin) {
  182.         gRmtInfo.user[0] = '\0';
  183.         gRmtInfo.pass[0] = '\0';
  184.         STRNCPY(gRmtInfo.acct, a2);
  185.     } else {
  186.         STRNCPY(gRmtInfo.user, u2);
  187.         if (gSavePasswords) {
  188.             STRNCPY(gRmtInfo.pass, p2);
  189.             STRNCPY(gRmtInfo.acct, a2);
  190.         }
  191.     }
  192.  
  193.     result = 0;
  194. done:
  195.     DoneWithResponse(rp);
  196.     return result;
  197. }    /* Login */
  198.  
  199.  
  200.  
  201.  
  202. /* After closing a site, set or restore some things to their original
  203.  * states.
  204.  */
  205. void PostCloseStuff(void)
  206. {
  207. #ifdef SYSLOG
  208.     syslog (LOG_INFO, "%s disconnected from %s.", gUserInfo.userName, gHost);
  209. #endif
  210.     if (gLoggedIn) {
  211.         gRmtInfo.hasPASV = gHasPASV;
  212.         gRmtInfo.port = gPortNumberUsed;
  213.         gRmtInfo.nCalls++;
  214.         time((time_t *) &gRmtInfo.lastCall);
  215.         STRNCPY(gRmtInfo.lastIP, gIPStr);
  216.         if (gEventNumber > 0L) {
  217.             /* Only do these if we were not in batch mode (colon-mode). */
  218.             if (gRmtInfo.noSaveDir == 0)
  219.                     STRNCPY(gRmtInfo.dir, gRemoteCWD);
  220.             (void) RunPrefixedMacro("close.", gRmtInfo.bookmarkName);
  221.             (void) RunPrefixedMacro("close.", "any");
  222.         } else {
  223.             /* Only do these if we are running colon mode. */
  224.             (void) RunPrefixedMacro("colon.close.", gRmtInfo.bookmarkName);
  225.             (void) RunPrefixedMacro("colon.close.", "any");
  226.         }
  227.         SaveCurHostBookmark(NULL);
  228.     }
  229.     gLoggedIn = 0;
  230.     gRemoteCWD[0] = gHost[0] = '\0';
  231. }    /* PostCloseStuff */
  232.  
  233.  
  234.  
  235.  
  236. /* Close the connection to the remote host and cleanup. */
  237. void DoClose(int tryQUIT)
  238. {
  239.     ResponsePtr rp;
  240.     
  241.     if (tryQUIT != 0) {
  242.         rp = InitResponse();
  243.         rp->eofOkay = 1;    /* We are expecting EOF after this cmd. */
  244.         RCmd(rp, "QUIT");
  245.         DoneWithResponse(rp);
  246.     }
  247.     
  248.     CloseControlConnection();
  249.     PostCloseStuff();
  250. }    /* DoClose */
  251.  
  252.  
  253.  
  254.  
  255. int CloseCmd(int argc, char **argv)
  256. {
  257.     DoClose(gConnected);
  258.     if (gWinInit == 0)
  259.             SetScreenInfo();    /* Need for line mode. */
  260.     return kNoErr;
  261. }    /* CloseCmd */
  262.  
  263.  
  264.  
  265.  
  266. /* Given a pointer to an OpenOptions (structure containing all variables
  267.  * that can be set from the command line), this routine makes sure all
  268.  * the variables have valid values by setting them to their defaults.
  269.  */
  270.  
  271. void InitOpenOptions(OpenOptions *openopt)
  272. {
  273.     /* How do you want to open a site if neither -a or -u are given?
  274.      * gAnonOpen is true (default to anonymous login), unless
  275.      * Config.h was edited to set UOPEN to 0 instead.
  276.      */
  277.     openopt->openmode = gAnonOpen ? kOpenImplicitAnon : kOpenImplicitUser;
  278.  
  279.     /* Normally you don't want to ignore the entry in your netrc. */
  280.     openopt->ignoreRC = 0;
  281.  
  282.     /* Set the default delay if the user specifies redial mode without
  283.      * specifying the redial delay.
  284.      */
  285.     openopt->redialDelay = kRedialDelay;
  286.  
  287.     /* Normally, you only want to try once. If you specify redial mode,
  288.      * this is changed.
  289.      */
  290.     openopt->maxDials = 1;
  291.     
  292.     /* You don't want to dump the file to stdout by default. */
  293.     openopt->ftpcat = kNoFTPCat;
  294.  
  295.     /* We'll set this later, but we'll use 0 to mean that the port
  296.      * is explicitly not set by the user.
  297.      */
  298.     openopt->port = kPortUnset;
  299.  
  300.     /* We are not in colon-mode (yet). */
  301.     openopt->colonModePath[0] = 0;
  302.  
  303.     /* Set the hostname to a null string, since there is no default host. */
  304.     openopt->hostname[0] = 0;
  305.     
  306.     /* Set the opening directory path to a null string. */
  307.     openopt->cdpath[0] = 0;
  308.  
  309.     openopt->interactiveColonMode = 0;
  310.  
  311.     /* Since we're opening with a possible colon-mode item, we have to
  312.      * track options for the GetCmd too.
  313.      */
  314.     InitGetOptions(&openopt->gopt);
  315. }    /* InitOpenOptions */
  316.  
  317.  
  318.  
  319.  
  320.  
  321. /* This is responsible for parsing the command line and setting variables
  322.  * in the OpenOptions structure according to the user's flags.
  323.  */
  324.  
  325. int GetOpenOptions(int argc, char **argv, OpenOptions *openopt, int fromMain)
  326. {
  327.     int                    opt, www;
  328.     char                *cp, *hostp, *cpath;
  329.  
  330.     /* First setup the openopt variables. */
  331.     InitOpenOptions(openopt);
  332.  
  333.     /* Tell Getopt() that we want to start over with a new command. */
  334.     GetoptReset();
  335.     while ((opt = Getopt(argc, argv, "aiup:rd:g:cmCfGRn:")) >= 0) {
  336.         switch (opt) {        
  337.             case 'a':
  338.                 /* User wants to open anonymously. */
  339.                 openopt->openmode = kOpenExplicitAnon;
  340.                 break;
  341.                 
  342.             case 'u':
  343.                 /* User wants to open with a login and password. */
  344.                 openopt->openmode = kOpenExplicitUser;
  345.                 break;
  346.  
  347.             case 'i':
  348.                 /* User wants to ignore the entry in the netrc. */
  349.                 openopt->ignoreRC = 1;
  350.                 break;
  351.  
  352.             case 'p':
  353.                 /* User supplied a port number different from the default
  354.                  * ftp port.
  355.                  */
  356.                 openopt->port = atoi(gOptArg);
  357.                 if (openopt->port <= 0) {
  358.                     /* Probably never happen, but just in case. */
  359.                     (void) PrintF("%s: bad port number (%s).\n", argv[0],
  360.                         gOptArg);
  361.                     goto usage;
  362.                 }
  363.                 break;
  364.                 
  365.             case 'd':
  366.                 /* User supplied a delay (in seconds) that differs from
  367.                  * the default.
  368.                  */
  369.                 openopt->redialDelay = atoi(gOptArg);
  370.                 break;
  371.                 
  372.             case 'g':
  373.                 /* User supplied an upper-bound on the number of redials
  374.                  * to try.
  375.                  */
  376.                 openopt->maxDials = atoi(gOptArg);
  377.                 break;
  378.  
  379.             case 'r':
  380.                 openopt->maxDials = -1;
  381.                 break;
  382.  
  383.             case 'm':
  384.                 /* ftpcat mode is only available from your shell command-line,
  385.                  * not from the ncftp shell.  Do that yourself with 'more zz'.
  386.                  */
  387.                 if (gEventNumber == 0L) {
  388.                     /* If gEventNumber is zero, then we were called directly
  389.                      * from main(), and before the ftp shell has started.
  390.                      */
  391.                     openopt->ftpcat = kFTPMore;
  392.                     /* ftpcat mode is really ftpmore mode. */
  393.                     break;
  394.                 } else {
  395.                     PrintF(
  396. "You can only use this form of colon-mode (-m) from your shell command line.\n\
  397. Try 'ncftp -m wuarchive.wustl.edu:/README'\n");
  398.                 }
  399.                 goto usage;
  400.  
  401.             case 'c':
  402.                 /* ftpcat mode is only available from your shell command-line,
  403.                  * not from the ncftp shell.  Do that yourself with 'get zz -'.
  404.                  */
  405.                 if (gEventNumber == 0L) {
  406.                     /* If gEventNumber is zero, then we were called directly
  407.                      * from main(), and before the ftp shell has started.
  408.                      */
  409.                     openopt->ftpcat = kFTPCat;
  410.                     break;
  411.                 } else {
  412.                     PrintF(
  413. "You can only use ftpcat/colon-mode from your shell command line.\n\
  414. Try 'ncftp -c wuarchive.wustl.edu:/README > file.'\n");
  415.                 }
  416.                 goto usage;
  417.  
  418.             /* These are options that can be passed to get. */
  419.             case 'C':
  420.             case 'f':
  421.             case 'G':
  422.             case 'R':
  423.             /* case 'z':  Note that we can't handle the rename here. */
  424.             case 'n':
  425.                 if (fromMain) {
  426.                     (void) SetGetOption(&openopt->gopt, opt, gOptArg);
  427.                     break;
  428.                 }
  429.                 goto usage;
  430.  
  431.             default:
  432.                 if (fromMain)
  433.                     break;
  434.                     
  435.             usage:
  436.                 return kUsageErr;
  437.         }
  438.     }
  439.  
  440.     if (argv[gOptInd] == NULL) {
  441.         if (!fromMain) {
  442.             if (openopt->hostname[0] == 0)
  443.                 goto usage;
  444.         }
  445.     } else {
  446.         /* The user gave us a host to open.
  447.          *
  448.          * First, check to see if they gave us a colon-mode path
  449.          * along with the hostname.  We also understand a WWW path,
  450.          * like "ftp://bang.nta.no/pub/fm2html.v.0.8.4.tar.Z".
  451.          */
  452.         hostp = argv[gOptInd];
  453.         cpath = NULL;
  454.         if ((cp = strchr(hostp, ':')) != NULL) {
  455.             if (fromMain) {
  456.                 *cp++ = '\0';
  457.                 cpath = cp;
  458.                 www = 0;    /* Is 0 or 1, depending on the type of path. */
  459.                 if ((*cp == '/') && (cp[1] == '/')) {
  460.                     /* First make sure the path was intended to be used
  461.                      * with ftp and not one of the other URLs.
  462.                      */
  463.                     if (!ISTREQ(argv[gOptInd], "ftp")) {
  464.                         PrintF(
  465.                             "Bad URL '%s' -- WWW paths must be prefixed by 'ftp://'.\n",
  466.                             argv[gOptInd]
  467.                         );
  468.                         goto usage;
  469.                     }
  470.     
  471.                     cp += 2;
  472.                     hostp = cp;
  473.                     cpath = NULL;    /* It could have been ftp://hostname only. */
  474.     
  475.                     if ((cp = strchr(hostp, '/')) != NULL) {
  476.                         *cp++ = '\0';
  477.                         cpath = cp;
  478.                     }
  479.                     www = 1;
  480.                 }
  481.                 if (cpath != NULL) {
  482.                     (void) STRNCPY(openopt->colonModePath, www ? "/" : "");
  483.                     (void) STRNCAT(openopt->colonModePath, cpath);
  484.                     cp = openopt->colonModePath +
  485.                         strlen(openopt->colonModePath) - 1;
  486.                     if (*cp == '/') {
  487.                         /* Colon-mode path ended in a slash, so you said it
  488.                          * was a directory.  That means we should start from
  489.                          * this directory when we open this site.
  490.                          */
  491.                         *cp = '\0';
  492.                         openopt->interactiveColonMode = 1;
  493.                     }
  494.                     DebugMsg("Colon-Mode Path = '%s'\n", openopt->colonModePath);
  495.                 }
  496.  
  497.             } else {
  498.                 /* I may lift this restriction later. */
  499.                 EPrintF("You can't use colon mode in the command shell.\n");
  500.                 return kUsageErr;
  501.             }
  502.         }
  503.         (void) STRNCPY(openopt->hostname, hostp);
  504.  
  505.         if ((openopt->colonModePath[0] == '\0') &&
  506.             (openopt->ftpcat != kNoFTPCat))
  507.         {
  508.             /* User specified ftpcat mode, but didn't supply
  509.              * the host:file.
  510.              */
  511.             EPrintF("You didn't use colon mode correctly.\n\
  512. If you use -c or -m, you need to do something like this:\n\
  513. ncftp -c wuarchive.wustl.edu:/pub/README (to cat this file to stdout).\n");
  514.             return kUsageErr;
  515.         }
  516.  
  517.         GetBookmark(openopt->hostname, sizeof(openopt->hostname));
  518.         if (openopt->port == kPortUnset) {
  519.             /* No port specified, so use same port as last time. */
  520.             if (gRmtInfo.port == kPortUnset)
  521.                 openopt->port = gFTPPort;
  522.             else
  523.                 openopt->port = gRmtInfo.port;
  524.         }
  525.     }
  526.     return kNoErr;
  527. }    /* GetOpenOptions */
  528.  
  529.  
  530.  
  531.  
  532. void CheckRemoteSystemType(int force_binary)
  533. {
  534.     string remoteSys;
  535.  
  536.     if (gRmtInfoIsNew) {
  537.         /* If first time here, check somethings while we can. */
  538.         if (DoSystem(remoteSys, sizeof(remoteSys)) == 0)
  539.             gRmtInfo.isUnix = !strncmp(remoteSys, "UNIX", (size_t) 4);
  540.     
  541.         /* Set to binary mode if any of the following are true:
  542.          * (a) The user is using colon-mode (force_binary; below);
  543.          * (b) The reply-string from SYST said it was UNIX with 8-bit chars.
  544.          */
  545.         if (!strncmp(remoteSys, "UNIX Type: L8", (size_t) 13))
  546.         {
  547.             gRmtInfo.xferType = 'I';
  548.         }
  549.     
  550.         /* Print a warning for that (extremely) rare Tenex machine. */
  551.         if (!strncmp(remoteSys, "TOPS20", (size_t) 6)) {
  552.             gRmtInfo.xferType = 'T';
  553.             (void) PrintF("Using tenex mode to transfer files.\n");
  554.         }
  555.     }
  556.     gTransferType = gRmtInfo.xferType;
  557.     
  558.     /* Use binary mode if this site was last set using ascii mode,
  559.      * and we are using colon-mode.
  560.      */
  561.     if ((force_binary) && (gTransferType == 'A'))
  562.         gTransferType = 'I';
  563. }    /* CheckRemoteSystemType */
  564.  
  565.  
  566.  
  567. /* This is called if the user opened the host with a file appended to
  568.  * the host's name, like "wuarchive.wustl.edu:/pub/readme," or
  569.  * "wuarchive.wustl.edu:/pub."  In the former case, we open wuarchive,
  570.  * and fetch "readme."  In the latter case, we open wuarchive, then set
  571.  * the current remote directory to "/pub."  If we are fetching a file,
  572.  * we can do some other tricks if "ftpcat mode" is enabled.  This mode
  573.  * must be selected from your shell's command line, and this allows you
  574.  * to use the program as a one-liner to pipe a remote file into something,
  575.  * like "ncftp -c wu:/pub/README | wc."  If the user uses ftpcat mode,
  576.  * the program immediately quits instead of going into its own command
  577.  * shell.
  578.  */
  579. void ColonMode(OpenOptions *openopt)
  580. {
  581.     int result;
  582.  
  583.     /* Check for FTP-cat mode, so we call the appropriate
  584.      * fetching routine.
  585.      */
  586.     if (openopt->ftpcat == kFTPCat) {
  587.         InitGetOutputMode(&openopt->gopt, kDumpToStdout);
  588.         openopt->gopt.rName = openopt->colonModePath;
  589.         openopt->gopt.doReports = 0;
  590.         result = DoGet(&openopt->gopt);
  591.     } else if (openopt->ftpcat == kFTPMore) {
  592.         result = DoPage(openopt->colonModePath);
  593.     } else {
  594.         /* Regular colon-mode, where we fetch the file, putting the
  595.          * copy in the current local directory.
  596.          */
  597.         InitGetOutputMode(&openopt->gopt, kSaveToDisk);
  598.         openopt->gopt.doReports = 0;
  599.         openopt->gopt.rName = openopt->colonModePath;
  600.         result = DoGetWithGlobbingAndRecursion(&openopt->gopt);
  601.     }
  602.     DoQuit(result == 0 ? result : kExitColonModeFail);
  603.     /*NOTREACHED*/
  604. }    /* ColonMode */
  605.  
  606.  
  607.  
  608.  
  609. /* Now that we're logged in, do some other stuff prior to letting the
  610.  * user type away at the shell.
  611.  */
  612. void PostLoginStuff(OpenOptions *openopt)
  613. {
  614.     time_t now;
  615.     int wasColonMode;
  616.     
  617.     gLoggedIn = 1;
  618.  
  619.     /* Clear out the old redir buffer, since we are on a new site. */
  620.     DisposeLineListContents(&gRedir);
  621.  
  622.     /* Since we're logged in okay, we know what we've collected so far
  623.      * should be saved for next time.
  624.      */
  625.     gWantRmtInfoSaved = 1;
  626.     
  627.     /* The FTP module keeps its own note of whether the site has PASV
  628.      * or not, and has already initialized it to true.  If the gRmtInfo
  629.      * was fetched from our host file, we can tell FTP.c for sure if
  630.      * PASV should even be attempted.  If this was a new gRmtInfo, we
  631.      * will just be a little redundant, since new entries also assume
  632.      * PASV is supported.
  633.      */
  634.     gHasPASV = gRmtInfo.hasPASV;
  635.     
  636.     /* Since we connected okay, save this port number for later. */
  637.     gPortNumberUsed = openopt->port;
  638.  
  639.     /* When a new site is opened, ASCII mode is assumed (by protocol). */
  640.     gCurType = 'A';
  641.     
  642.     STRNCPY(gHost, openopt->hostname);
  643. #ifdef SYSLOG
  644.     syslog (LOG_INFO, "%s logged into %s.", gUserInfo.userName, gHost);
  645. #endif
  646.     if (gLogFile != NULL) {
  647.         (void) time(&now);
  648.         fprintf(gLogFile, "%s at %s", gHost, ctime(&now));
  649.     }
  650.  
  651.     wasColonMode = openopt->colonModePath[0] != (char)0;
  652.  
  653.     /* We need to check for unix and see if we should set binary
  654.      * mode automatically.
  655.      */
  656.     CheckRemoteSystemType(wasColonMode);
  657.  
  658.     if (wasColonMode) {
  659.         if (openopt->interactiveColonMode) {
  660.             /* Interactive colon mode simply means that the thing they
  661.              * gave us was a directory, and we should just cd to that
  662.              * directory when we start up.
  663.              */
  664.             (void) DoChdir(openopt->colonModePath);
  665.         } else {
  666.             /* Regular colon-mode is fetching a file by specifying the
  667.              * pathname of the file on the shell command line.
  668.              */
  669.             (void) GetRemoteCWD(kDidNotChdir);
  670.             ColonMode(openopt);        /* Does not return... */
  671.         }
  672.     } else if (gRmtInfo.dir[0]) {
  673.         /* If we didn't have a colon-mode path, we try setting
  674.          * the current remote directory to cdpath.  The .dir field is
  675.          * (usually) the last directory we were in the previous
  676.          * time we called this site.
  677.          */
  678.         (void) DoChdir(gRmtInfo.dir);
  679.     } else {
  680.         /* Freshen 'cwd' variable for the prompt. */
  681.         (void) GetRemoteCWD(kDidNotChdir);
  682.     }
  683.  
  684.     if (wasColonMode) {
  685.         /* Run separate sets of macros for colon-mode opens and regular,
  686.          * interactive opens.
  687.          */
  688.         (void) RunPrefixedMacro("colon.open.", "any");
  689.         (void) RunPrefixedMacro("colon.open.", gRmtInfo.bookmarkName);
  690.     } else {
  691.         (void) RunPrefixedMacro("open.", "any");
  692.         (void) RunPrefixedMacro("open.", gRmtInfo.bookmarkName);
  693.         if (gWinInit == 0)
  694.                 SetScreenInfo();    /* Need for line mode. */
  695.         ClearDirCache();
  696.     }
  697. }    /* PostLoginStuff */
  698.  
  699.  
  700.  
  701.  
  702.  
  703. /* Given a properly set up OpenOptions, we try connecting to the site,
  704.  * redialing if necessary, and do some initialization steps so the user
  705.  * can send commands.
  706.  */
  707. int Open(OpenOptions *openopt)
  708. {
  709.     int                    hErr;
  710.     int                    dials;
  711.     char                *user, *pass, *r_acct;    
  712.     int                    loginResult;
  713.     int                    openMode;
  714.  
  715.     /* This should be reset for each site, because a slow site may have
  716.      * bumped the value rather high.
  717.      */
  718.     ResetBlockTimeout();
  719.  
  720.     gRedialModeEnabled = (openopt->maxDials != 1);
  721.  
  722.     if (ISEXPLICITOPEN(openopt->openmode)) {
  723.         /* User specified an open mode explictly, like open -u,
  724.          * so do what the user said in spite of what we may have had
  725.          * in the gRmtInfo.
  726.          */
  727.         openMode = (ISANONOPEN(openopt->openmode)) ? 'a' : 'u';
  728.     } else {
  729.         if (gRmtInfoIsNew == 1) {
  730.             /* First time opening this site.  Open it anonymously
  731.              * unless you said not to with a -option.
  732.              */
  733.             openMode = (ISANONOPEN(openopt->openmode)) ? 'a' : 'u';
  734.         } else {
  735.             /* We've been here before, so use what we had last time. */
  736.             openMode = 'r';
  737.         }
  738.     }
  739.  
  740.     if ((openMode == 'r') && (gRmtInfo.user[0] == '\0'))
  741.         openMode = 'a';
  742.     if (openMode == 'a') {
  743.         user = "anonymous";
  744.         pass = strchr(gRmtInfo.pass, '@') ? gRmtInfo.pass : gAnonPassword;
  745.         r_acct = "";
  746.     } else if (openMode == 'u') {
  747.         user = "";
  748.         pass = "";
  749.         r_acct = "";
  750.     } else {
  751.         user = gRmtInfo.user;
  752.         pass = gRmtInfo.pass;
  753.         r_acct = gRmtInfo.acct;
  754.     }
  755.  
  756.     if ((openopt->colonModePath[0]) && (!openopt->interactiveColonMode)) {
  757.         /* If we're running from a shell script (or whatever)
  758.          * don't dump any output.  If the user is doing this from
  759.          * the shell, we will at least print the error messages.
  760.          * We also don't want to "pollute" ftpcat mode, but since
  761.          * error messages are printed to stderr, and we weren't
  762.          * going to print anything but error messages anyway,
  763.          * we're okay by using kErrorsOnly.
  764.          */
  765.         if (gIsToTTY != 0)
  766.             (void) SetVerbose(kErrorsOnly);
  767.         else
  768.             (void) SetVerbose(kQuiet);
  769.     } else {
  770.         /* If we haven't already setup our interactive shell, which
  771.          * would happen if you gave a host on the command line, then
  772.          * we need to do that now because we want the remote host's
  773.          * startup information to be displayed.
  774.          */
  775.         Startup();
  776.     }
  777.  
  778.     
  779.     PrintF("Trying to connect to %s...\n", openopt->hostname);
  780.     for (
  781.             dials = 0;
  782.             openopt->maxDials < 0 || dials < openopt->maxDials;
  783.             dials++)
  784.     {
  785.         if (dials > 0) {
  786.             /* If this is the second dial or higher, sleep a bit. */
  787.             PrintF("Sleeping %u seconds...  ",
  788.                 (unsigned) openopt->redialDelay);
  789.             FlushListWindow();
  790.             (void) sleep((unsigned) openopt->redialDelay);
  791.             PrintF("Retry Number: %d\n", dials + 1);
  792.         }
  793.         FlushListWindow();
  794.  
  795.         SetBar(NULL, "CONNECTING", NULL, 1, 1);
  796.         gAttemptingConnection = 1;
  797.         hErr = OpenControlConnection(openopt->hostname, openopt->port);
  798.         if (hErr == kConnectErrFatal) {
  799.             /* Irrecoverable error, so don't bother redialing.
  800.              * The error message should have already been printed
  801.              * from OpenControlConnection().
  802.              */
  803.             DebugMsg("Cannot recover from open error %d.\n", hErr);
  804.             break;
  805.         } else if (hErr == kConnectNoErr) {
  806.             /* We were hooked up successfully. */
  807.             
  808.             gRemoteCWD[0] = '\0';
  809.     
  810.             /* This updates the status bar (for visual mode). */
  811.             SetBar(NULL, "LOGGING IN", NULL, 1, 1);
  812.             SetPostHangupOnServerProc(PostCloseStuff);
  813.             loginResult = Login(user, pass, r_acct);
  814.             
  815.             if (loginResult == 0) {
  816.                 PostLoginStuff(openopt);
  817.                 if (openopt->maxDials != 1) {
  818.                     /* If they selected redial mode, beep at the user
  819.                      * to get their attention.
  820.                      */
  821.                     Beep(1);
  822.                 }
  823.                 gAttemptingConnection = 0;    /* We are connected. */
  824.                 gRedialModeEnabled = 0;        /* Not dialing any more. */
  825.                 return(kNoErr);    /* Login okay, so done. */
  826.             }
  827.             /* Otherwise, an error during login occurred, so try again. */
  828.         } else /* (hErr == kConnectErrReTryable), so redial. */ {
  829.             /* Display error now. */
  830.             FlushListWindow();
  831.         }
  832.         
  833.         DoClose(gConnected);
  834.         gAttemptingConnection = 0;
  835.     }
  836.  
  837.     /* Display error now. */
  838.     FlushListWindow();
  839.  
  840.     if ((openopt->colonModePath[0]) && (!openopt->interactiveColonMode)) {
  841.         /* If we get here, we we're colon-moding and got a non-redialable
  842.          * error or we ran out of attempts.
  843.          */
  844.         DoQuit(kExitColonModeFail);
  845.     }
  846.     return (kCmdErr);
  847. }    /* Open */
  848.  
  849.  
  850.  
  851.  
  852. int OpenCmd(int argc, char **argv)
  853. {
  854.     OpenOptions            openopt;
  855.     int result;
  856.  
  857.     /* If there is already a site open, close that one so we can
  858.      * open a new one.
  859.      */
  860.     DoClose(gConnected);
  861.  
  862.     if (argc < 2) {
  863.         result = HostWindow();
  864.     } else {
  865.         if ((result = GetOpenOptions(argc, argv, &openopt, 0)) == kNoErr)
  866.             result = Open(&openopt);
  867.     }
  868.     return result;
  869. }    /* OpenCmd */
  870.  
  871. /* Open.c */
  872.