home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ncftp-2.3.0-src.tgz / tar.out / contrib / ncftp / Cmds.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  28KB  |  1,233 lines

  1. /* Cmds.c */
  2.  
  3. #include "Sys.h"
  4.  
  5. #include <ctype.h>
  6. #include <netinet/in.h>
  7. #include <netdb.h>
  8. #include <signal.h>
  9. #include <setjmp.h>
  10.  
  11. #include "Util.h"
  12. #include "RCmd.h"
  13. #include "Cmds.h"
  14. #include "Cmdline.h"
  15. #include "List.h"
  16. #include "MakeArgv.h"
  17. #include "Macro.h"
  18. #include "Main.h"
  19. #include "DateSize.h"
  20. #include "Open.h"
  21. #include "Glob.h"
  22. #include "Getopt.h"
  23. #include "FTP.h"
  24. #include "Bookmark.h"
  25. #include "Cpp.h"
  26. #include "Prefs.h"
  27. #include "Tips.h"
  28. #include "Version.h"
  29.  
  30. /* Full path of the remote current working directory. */
  31. longstring gRemoteCWD = "";
  32.  
  33. /* The full path of the previous remote working directory. */
  34. longstring gPrevRemoteCWD = "";
  35.  
  36. /* Full path of the local current working directory. */
  37. longstring gLocalCWD = "";
  38.  
  39. /* Full path of the previous local working directory. */
  40. longstring gPrevLocalCWD = "";
  41.  
  42. /* This is the type we use for file transfers.  Note that we always use
  43.  * type ascii for directory listings.
  44.  */
  45. int gTransferType = 'I';
  46.  
  47. /* This what type is in use at the moment. */
  48. int gCurType;
  49.  
  50. /* Upon receipt of a signal during paging a local file, we jump here. */
  51. jmp_buf gShellJmp;
  52.  
  53. /* Flag for debugging mode. */
  54. #if (kAlpha > 0) || (kBeta > 0)
  55. int gDebug = kDebuggingOff;
  56. int gTrace = kTracingOn;
  57. #else
  58. int gDebug = kDebuggingOff;
  59. int gTrace = kTracingOff;
  60. #endif
  61.  
  62. extern int gNumCommands;
  63. extern Command gCommands[];
  64. extern int gVerbosity;
  65. extern Bookmark gRmtInfo;
  66. extern UserInfo gUserInfo;
  67. extern CppSymbol gCppSymbols[];
  68. extern int gNumCppSymbols;
  69. extern string gVersion;
  70. extern longstring gPager;
  71. extern int gDoneApplication, gConnected;
  72. extern FILE *gTraceLogFile;
  73. extern int gStdout;
  74. extern MacroNodePtr gFirstMacro;
  75. extern int gNumGlobalMacros, gOtherSessionRunning;
  76. extern char *gOptArg;
  77. extern int gOptInd;
  78. extern struct hostent *GetHostEntry(char *host, struct in_addr *ip_address);
  79.  
  80. /* Runs the "SYST" command, and if the remote host supports it, will return
  81.  * the system type we're connected to, otherwise an empty string.  This is
  82.  * handy to see if we're connected to a UNIX box, or something icky, like
  83.  * MS/DOS, or even more icky, VMS.
  84.  */
  85. int DoSystem(char *systType, size_t siz)
  86. {
  87.     ResponsePtr rp;
  88.     int result;
  89.  
  90.     rp = InitResponse();
  91.     result = RCmd(rp, "SYST");
  92.     rp->printMode = kDontPrint;
  93.     Strncpy(systType, rp->msg.first->line, siz);
  94.     DoneWithResponse(rp);
  95.     if (result != 2) {
  96.         systType[0] = '\0';
  97.         return (-1);
  98.     }
  99.     return (0);
  100. }    /* DoSystem */
  101.  
  102.  
  103.  
  104.  
  105. /*ARGSUSED*/
  106. static void SigLocalPage(int sigNum)
  107. {
  108.     alarm(0);
  109.     longjmp(gShellJmp, 1);
  110. }    /* SigLocalPage */
  111.  
  112.  
  113.  
  114.  
  115. int LocalPageCmd(int argc, char **argv)
  116. {
  117.     volatile FILE *fp, *pager;
  118.     int i, errs, opt;
  119.     longstring pageCmd;
  120.     volatile LineList globFiles;
  121.     LinePtr globFile;
  122.     volatile int useBuiltIn;
  123.     volatile Sig_t si, sp;
  124.     string str;
  125.  
  126.     GetoptReset();
  127.     useBuiltIn = 0;
  128.     while ((opt = Getopt(argc, argv, "bp")) >= 0) {
  129.         switch (opt) {
  130.             case 'b':
  131.                 useBuiltIn = 1;
  132.                 break;
  133.             case 'p':
  134.                 useBuiltIn = 0;
  135.                 break;
  136.             default:
  137.                 return (kUsageErr);
  138.         }
  139.     }
  140.     argv += gOptInd;
  141.     argc -= gOptInd;
  142.  
  143.     si = SIGNAL(SIGINT, SigLocalPage);
  144.     sp = SIGNAL(SIGPIPE, SigLocalPage);
  145.     errs = 0;
  146.     
  147.     if (useBuiltIn == 0) {
  148.         if (gPager[0] == '\0') {
  149.             EPrintF("You haven't specified a program to use as a pager.\n");
  150.             EPrintF("You can set this from the preferences screen (prefs command).\n");
  151.             errs = -1;
  152.             goto done;
  153.         }
  154.         SaveScreen();
  155.     }
  156.     
  157.     for (i=0; i<argc; i++) {
  158.         InitLineList((LineList *) &globFiles);
  159.         LocalGlob((LineList *) &globFiles, argv[i]);
  160.         for (globFile = globFiles.first; globFile != NULL;
  161.             globFile = globFile->next)
  162.         {
  163.             fp = fopen(globFile->line, "r");
  164.             if (fp == NULL) {
  165.                 Error(kDoPerror, "Can't open %s.\n", globFile->line);
  166.                 --errs;
  167.             } else if (useBuiltIn == 1) {
  168.                 MultiLineInit();
  169.                 MultiLinePrintF("*** %s ***\n", globFile->line);
  170.                 if (setjmp(gShellJmp) != 0) {
  171.                     /* Command was interrupted. */
  172.                     (void) SIGNAL(SIGINT, SIG_IGN);
  173.                     fclose((FILE *) fp);
  174.                     DisposeLineListContents((LineList *) &globFiles);
  175.                     --errs;
  176.                     goto done;
  177.                 } else {
  178.                     while (fgets(str, ((int) sizeof(str)) - 1, (FILE *)fp) != NULL)
  179.                         MultiLinePrintF("%s", str);
  180.                 }
  181.                 (void) SIGNAL(SIGINT, SIG_IGN);
  182.                 fclose((FILE *) fp);
  183.             } else {
  184.                 STRNCPY(pageCmd, gPager);
  185.                 STRNCAT(pageCmd, " ");
  186.                 STRNCAT(pageCmd, globFile->line);
  187.                 pager = (volatile FILE *) 0;
  188.                 if (setjmp(gShellJmp) != 0) {
  189.                     /* Command was interrupted. */
  190.                     (void) SIGNAL(SIGINT, SIG_IGN);
  191.                     (void) SIGNAL(SIGPIPE, SIG_IGN);
  192.                     if (pager != ((volatile FILE *) 0))
  193.                         PClose((FILE *) pager);
  194.                     fclose((FILE *) fp);
  195.                     DisposeLineListContents((LineList *) &globFiles);
  196.                     --errs;
  197.                     goto done;
  198.                 } else {
  199.                     pager = POpen(pageCmd, "w", 1);
  200.                     while (fgets(str, ((int) sizeof(str)) - 1, (FILE *)fp) != NULL)
  201.                         fputs(str, (FILE *) pager);
  202.                     PClose((FILE *) pager);
  203.                     fclose((FILE *) fp);
  204.                 }
  205.             }
  206.         }
  207.         DisposeLineListContents((LineList *) &globFiles);
  208.     }
  209.  
  210. done:
  211.     if (useBuiltIn == 0)
  212.         RestoreScreen(1);
  213.     (void) SIGNAL(SIGINT, si);
  214.     (void) SIGNAL(SIGPIPE, sp);
  215.     Beep(0);    /* User should be aware that it took a while, so no beep. */
  216.     return (errs);
  217. }    /* LocalPageCmd */
  218.  
  219.  
  220.  
  221.  
  222. /* Returns the full path of the remote working directory. */
  223. void GetRemoteCWD(char *cdstub)
  224. {
  225.     ResponsePtr rp;
  226.     char *l, *r;
  227.     char *cp1;
  228.     
  229.     rp = InitResponse();
  230.     if (RCmd(rp, "PWD") == 2) {
  231.         if ((r = strrchr(rp->msg.first->line, '"')) != NULL) {
  232.             /* "xxxx" is current directory.
  233.              * Strip out just the xxxx to copy into the remote cwd.
  234.              */
  235.             l = strchr(rp->msg.first->line, '"');
  236.             if ((l != NULL) && (l != r)) {
  237.                 *r = '\0';
  238.                 ++l;
  239.                 STRNCPY(gRemoteCWD, l);
  240.                 *r = '"';    /* Restore, so response prints correctly. */
  241.             }
  242.         } else {
  243.             /* xxxx is current directory.
  244.              * Mostly for VMS.
  245.              */
  246.             if ((r = strchr(rp->msg.first->line, ' ')) != NULL) {
  247.                 *r = '\0';
  248.                 STRNCPY(gRemoteCWD, (rp->msg.first->line));
  249.                 *r = ' ';    /* Restore, so response prints correctly. */
  250.             }
  251.         }
  252.         SetScreenInfo();
  253.     } else {
  254.         /* Error. */
  255.         if (cdstub != kDidNotChdir) {
  256.             /* We couldn't PWD.  This could happen if we chdir'd to a
  257.              * directory that looked like d--x--x--x.  We could cd there,
  258.              * but not read the contents.
  259.              *
  260.              * What we can do, since we know we just tried cd'ing here from
  261.              * a previous directory is fake it and just append the path
  262.              * we tried to cd at after the previous CWD.
  263.              */
  264.             if (*cdstub == '/') {
  265.                 /* Just cd'd using an absolute path. */
  266.                 STRNCPY(gRemoteCWD, cdstub);
  267.             } else {
  268.                 /* If "cd .." , remove the lowest directory.
  269.                  * If "cd ." , do nothing.
  270.                  * Don't append the slash if previous directory was
  271.                  * the root.
  272.                  */
  273.                 cp1 = strrchr(gRemoteCWD, '/');
  274.                 if (STREQ(cdstub, "..") && !STREQ(gRemoteCWD, "/")
  275.                     && (cp1 != NULL))
  276.                     *cp1 = '\0';
  277.                 else if (STREQ(cdstub, ".")); /* do nothing */
  278.                 else {
  279.                     if (! STREQ(gRemoteCWD, "/"))
  280.                         STRNCAT(gRemoteCWD, "/");
  281.                     STRNCAT(gRemoteCWD, cdstub);
  282.                 }
  283.             }
  284.             SetScreenInfo();
  285.         }
  286.     }
  287.     DoneWithResponse(rp);
  288. }    /* GetRemoteCWD */
  289.  
  290.  
  291.  
  292.  
  293. int LocalPwdCmd(int argc, char **argv)
  294. {
  295.     (void) GetCWD(gLocalCWD, sizeof(gLocalCWD));
  296.     PrintF("Current local directory is %s.\n", gLocalCWD);
  297.     return 0;
  298. }    /* LocalPwdCmd */
  299.  
  300.  
  301.  
  302.  
  303. int PwdCmd(int argc, char **argv)
  304. {
  305.     GetRemoteCWD(kDidNotChdir);
  306.     PrintF("Current remote directory: %s\n", gRemoteCWD);
  307.     return 0;
  308. }    /* PwdCmd */
  309.  
  310.  
  311.  
  312.  
  313. /* If the remote host supports the MDTM command, we can find out the exact
  314.  * modification date of a remote file.
  315.  */
  316. int DoMdtm(char *fName, time_t *mdtm)
  317. {
  318.     ResponsePtr rp;
  319.     int result;
  320.  
  321.     *mdtm = kModTimeUnknown;
  322.     result = -1;
  323.     /* Don't bother if we know the current host doesn't support it.
  324.      * We must make sure that the gRmtInfo is properly set each
  325.      * time a host is opened.
  326.      */
  327.     if (gRmtInfo.hasMDTM) {
  328.         rp = InitResponse();
  329.         rp->printMode = kDontPrint;
  330.         if (RCmd(rp, "MDTM %s", fName) == 2) {
  331.             /* Reply should look like "213 19930602204445\n" so we will have
  332.              * "19930602204445" in the first line of the reply string list.
  333.              */
  334.             *mdtm = UnMDTMDate(rp->msg.first->line);
  335.             result = 0;
  336.         } else if (UNIMPLEMENTED_CMD(rp->code))
  337.             gRmtInfo.hasMDTM = 0;    /* Command not supported. */
  338.         DoneWithResponse(rp);
  339.     }
  340.     return (result);
  341. }    /* DoMdtm */
  342.  
  343.  
  344.  
  345.  
  346. /* If the remote host supports the SIZE command, we can find out the exact
  347.  * size of a remote file, depending on the transfer type in use.  SIZE
  348.  * returns different values for ascii and binary modes!
  349.  */
  350. int DoSize(char *fName, long *size)
  351. {
  352.     ResponsePtr rp;
  353.     int result;
  354.     
  355.     *size = kSizeUnknown;
  356.     result = -1;
  357.     /* Don't bother if we know the current host doesn't support it.
  358.      * We must make sure that the gRmtInfo is properly set each
  359.      * time a host is opened.
  360.      */
  361.     if (gRmtInfo.hasSIZE) {
  362.         rp = InitResponse();
  363.         rp->printMode = kDontPrint;
  364.         if (RCmd(rp, "SIZE %s", fName) == 2) {
  365.             sscanf(rp->msg.first->line, "%ld", size);
  366.             result = 0;
  367.         } else if (UNIMPLEMENTED_CMD(rp->code))
  368.             gRmtInfo.hasSIZE = 0;    /* Command not supported. */
  369.         DoneWithResponse(rp);
  370.     }
  371.     return (result);
  372. }    /* DoSize */
  373.  
  374.  
  375.  
  376.  
  377. /* See if we can cd to the dir requested, and if not, that's okay. */
  378. int TryQuietChdir(char *dir)
  379. {
  380.     int result;
  381.  
  382.     if (STREQ(dir, ".."))
  383.         result = RCmd(kIgnoreResponse, "CDUP");
  384.     else {
  385.         if (*dir == '\0')
  386.             dir = "/";
  387.         result = RCmd(kIgnoreResponse, "CWD %s", dir);
  388.     }
  389.     if (result == 2) {
  390.         GetRemoteCWD(dir);
  391.         return (0);
  392.     }
  393.     return (-1);
  394. }    /* TryQuietChdir */
  395.  
  396.  
  397.  
  398.  
  399. /* Attempt to cd to the directory specifed, reporting an error if we
  400.  * failed (or maybe not, depending on the verbosity level in use).
  401.  */
  402. int DoChdir(char *dir)
  403. {
  404.     int result;
  405.  
  406.     if (STREQ(dir, ".."))
  407.         result = RCmd(kDefaultResponse, "CDUP");
  408.     else {
  409.         if (*dir == '\0')
  410.             dir = "/";
  411.         result = RCmd(kDefaultResponse, "CWD %s", dir);
  412.     }
  413.     GetRemoteCWD(dir);
  414.     return (result != 2 ? -1 : 0);
  415. }    /* DoChdir */
  416.  
  417.  
  418.  
  419.  
  420. int ChdirCmd(int argc, char **argv)
  421. {
  422.     LineList globFiles;
  423.     longstring str;
  424.     char *cddir;
  425.     int rglobbed;
  426.     int result;
  427.  
  428. #if 0
  429.     /* Can't glob a directory name without a major hassle.
  430.      * We could do a "NLST -d dir*pattern" but most servers have that
  431.      * damned NLST/-flags/glob-pattern conflict which prevents that.
  432.      *
  433.      * We could just do a "NLST dir*pattern" but then that gives us back
  434.      * entire directory listings, like "dir/file1 dir/file2..." which 
  435.      * could get large and too wasteful of net bandwidth just because
  436.      * the user is too lazy to type a directory name.
  437.      *
  438.      * We could try a "LIST -d dir*pattern" but then we'd have to parse
  439.      * a big line of junk.  This may be done sometime later.
  440.      *
  441.      * For now, I just don't support globbing wth cd.
  442.      */
  443.     cddir = argv[1];
  444.     rglobbed = 0;
  445. #else
  446.     InitLineList(&globFiles);
  447.     if (gRmtInfo.isUnix == 0) {
  448.         /* Don't try to glob the directory name unless server is UNIX.
  449.          * This won't work on VMS, for example.
  450.          */
  451.         cddir = argv[1];
  452.         rglobbed = 0;
  453.     } else {
  454.         RemoteGlob(&globFiles, argv[1], kListNoFlags);
  455.         if (globFiles.first == NULL) {
  456.             EPrintF("%s: no match.\n", argv[1]);
  457.             DisposeLineListContents(&globFiles);
  458.             return (kCmdErr);
  459.         } else if (globFiles.first->next != NULL) {
  460.             EPrintF("%s: wildcard matches more than one remote item.\n", argv[1]);
  461.             DisposeLineListContents(&globFiles);
  462.             return (kCmdErr);
  463.         } else {
  464.             rglobbed = 1;
  465.             cddir = globFiles.first->line;
  466.         }
  467.     }
  468. #endif
  469.  
  470.     /* Steal the Korn shell's "cd -" trick, which cd's you to the
  471.      * directory you were in before.
  472.      */
  473.     STRNCPY(str, gRemoteCWD);
  474.     if (STREQ(cddir, "-") && (gPrevRemoteCWD[0] != '\0')) {
  475.         result = DoChdir(gPrevRemoteCWD);    /* Sets gRemoteCWD. */
  476.     } else
  477.         result = DoChdir(cddir);
  478.     if (result == 0)
  479.         STRNCPY(gPrevRemoteCWD, str);
  480.  
  481.     if (rglobbed != 0)
  482.         DisposeLineListContents(&globFiles);
  483.     return (result);
  484. }    /* ChdirCmd */
  485.  
  486.  
  487.  
  488.  
  489. /* cd to 'dir' on the local host.  The dir specified may have glob
  490.  * characters, or ~stuff in it also.
  491.  */
  492. int DoLocalChdir(char *dir, int quiet)
  493. {
  494.     int result;
  495.     LineList globFiles;
  496.  
  497.     InitLineList(&globFiles);
  498.     LocalGlob(&globFiles, dir);
  499.     dir = globFiles.first->line;
  500.     if (globFiles.first->next != NULL) {
  501.         Error(kDontPerror, "Ambiguous directory name %s.\n", dir);
  502.         result = kCmdErr;
  503.     } else if ((result = chdir(dir)) < 0) {
  504.         Error(kDoPerror, "Could not change local directory to %s.\n", dir);
  505.     } else {
  506.         (void) GetCWD(gLocalCWD, sizeof(gLocalCWD));
  507.         if (!quiet)
  508.             PrintF("Current local directory is %s.\n", gLocalCWD);
  509.     }
  510.     DisposeLineListContents(&globFiles);
  511.     return (result);
  512. }    /* DoLocalChdir */
  513.  
  514.  
  515.  
  516. /* Stub command that lcd's to the appropriate directory, or if none
  517.  * was supplied, carry on the tradition and make that the same as
  518.  * lcd'ing to the home directory.
  519.  */
  520. int LocalChdirCmd(int argc, char **argv)
  521. {
  522.     int result;
  523.     char *cp;
  524.     longstring str;
  525.  
  526.     if (argc < 2)
  527.         cp = gUserInfo.home;
  528.     else if (STREQ(argv[1], "-") && (gPrevLocalCWD[0] != '\0'))
  529.         cp = gPrevLocalCWD;
  530.     else
  531.         cp = argv[1];
  532.     STRNCPY(str, gLocalCWD);
  533.     result = DoLocalChdir(cp, 0);    /* Sets gRemoteCWD. */
  534.     if (result == 0)
  535.         STRNCPY(gPrevLocalCWD, str);
  536.     return (result);
  537. }    /* LocalChdirCmd */
  538.  
  539.  
  540.  
  541.  
  542. /* Changes the debugging status, or prints some extra debugging
  543.  * info depending on the parameter given.
  544.  */
  545. int DebugCmd(int argc, char **argv)
  546. {
  547.     char *cp;
  548.     int i;
  549.  
  550.     if (argc == 1) {
  551.         PrintF("Debug Mode = %d.  Trace Mode = %d.\n", gDebug, gTrace);
  552.     } else {
  553. #if (LIBMALLOC == FAST_MALLOC)
  554.         if (STREQ(argv[1], "memchk")) {
  555.             struct mallinfo mi;
  556.         
  557.             mi = mallinfo();
  558.             PrintF("\
  559. total space in arena:               %d\n\
  560. number of ordinary blocks:          %d\n\
  561. number of small blocks:             %d\n\
  562. number of holding blocks:           %d\n\
  563. space in holding block headers:     %d\n\
  564. space in small blocks in use:       %d\n\
  565. space in free small blocks:         %d\n\
  566. space in ordinary blocks in use:    %d\n\
  567. space in free ordinary blocks:      %d\n\
  568. cost of enabling keep option:       %d\n",
  569.                 mi.arena,
  570.                 mi.ordblks,
  571.                 mi.smblks,
  572.                 mi.hblks,
  573.                 mi.hblkhd,
  574.                 mi.usmblks,
  575.                 mi.fsmblks,
  576.                 mi.uordblks,
  577.                 mi.fordblks,
  578.                 mi.keepcost
  579.             );
  580.             return 0;
  581.         }
  582. #endif
  583. #if (LIBMALLOC == DEBUG_MALLOC)
  584.         if (STREQ(argv[1], "memchk")) {
  585.             PrintF("malloc_chain_check: %d\n\n", malloc_chain_check(0));
  586.             PrintF("malloc_inuse: %lu\n", malloc_inuse(NULL));
  587.             return 0;
  588.         }
  589.         if (STREQ(argv[1], "memdump")) {
  590.             malloc_dump(1);
  591.             return 0;
  592.         }
  593. #endif
  594.         for (cp = argv[1]; (*cp != '\0') && isdigit(*cp); )
  595.             ++cp;
  596.         if (*cp == '\0') {
  597.             gDebug = atoi(argv[1]);
  598.             return 0;
  599.         } else if (ISTREQ(argv[1], "macro")) {
  600.             /* Dump specified macro, or if NULL, all of them. */
  601.             DumpMacro(argv[2]);
  602.         } else if (ISTREQ(argv[1], "segv")) {
  603.             /* Intentionally bomb the program... */
  604.             *((int *) 0) = 99;
  605.         } else if (ISTREQ(argv[1], "multi")) {
  606.             MultiLineInit();
  607.             for (i=1; i<=60; i++)
  608.                 MultiLinePrintF("This is line %d.\n", i);
  609.         } else if (ISTREQ(argv[1], "trace")) {
  610.             if (argc > 2)
  611.                 gTrace = atoi(argv[2]);
  612.             else
  613.                 gTrace = !gTrace;
  614.             if (gTrace) {
  615.                 if (gTraceLogFile == NULL)
  616.                     OpenTraceLog();
  617.             } else {
  618.                 if (gTraceLogFile != NULL)
  619.                     CloseTraceLog();
  620.             }
  621.         } else if (ISTREQ(argv[1], "tips")) {
  622.             /* Dump all the tips. */
  623.             PrintAllTips();
  624.         }
  625.     }
  626.     return 0;
  627. }    /* DebugCmd */
  628.  
  629.  
  630.  
  631.  
  632. /* Sets the verbosity level of our informational messages. */
  633. int VerboseCmd(int argc, char **argv)
  634. {
  635.     int newVerbose;
  636.  
  637.     if (argc == 1)
  638.         PrintF("Verbosity = %d.\n", gVerbosity);
  639.     else {
  640.         newVerbose = atoi(argv[1]);
  641.         if (newVerbose < kQuiet)
  642.             newVerbose = kQuiet;
  643.         else if (newVerbose > kVerbose)
  644.             newVerbose = kVerbose;
  645.         (void) SetVerbose(newVerbose);
  646.     }
  647.     return 0;
  648. }    /* VerboseCmd */
  649.  
  650.  
  651.  
  652. /* Sets the data transfer type to the one specified, if needed, and returns
  653.  * the type it used or -1 upon failure.  The 'type' parameter must be
  654.  * an uppercase letter.
  655.  */
  656. int SetType(int type)
  657. {
  658.     ResponsePtr rp;
  659.     
  660.     int result = -1;
  661.  
  662.     if (type == 'B')
  663.         type = 'I';
  664.  
  665.     if (type == gCurType) {
  666.         /* Already on this type, so don't waste network bandwidth. */
  667.         result = type;
  668.     } else if ((type == 'A') || (type == 'I') || (type == 'T')) {
  669.         rp = InitResponse();
  670.         RCmd(rp, "TYPE %c", type);
  671.         if (rp->codeType == 2) {
  672.             result = 0;
  673.             gCurType = type;
  674.         }
  675.         DoneWithResponse(rp);
  676.     }
  677.     return (result);
  678. }    /* SetType */
  679.  
  680.  
  681.  
  682.  
  683. void DoType(char *typestr)
  684. {
  685.     int type;
  686.  
  687.     type = *typestr;
  688.     if (islower(type))
  689.         type = toupper(type);
  690.     
  691.     if (SetType(type) < 0)
  692.         PrintF("Unknown type '%s'\n", typestr);
  693.     else {
  694.         gTransferType = gCurType;
  695.         /* We only "remember" this type for next time, if the user
  696.          * explicitly issued a type command.
  697.          */
  698.         gRmtInfo.xferType = gTransferType;
  699.     }
  700. }    /* DoType */
  701.  
  702.  
  703.  
  704.  
  705. int TypeCmd(int argc, char **argv)
  706. {
  707.     if ((argc == 1) && (argv[0][0] != 't')) {
  708.         /* Check for aliased commands binary and ascii, which come here. */
  709.         DoType(argv[0]);
  710.     } if (argc > 1) {
  711.         DoType(argv[1]);
  712.     } else {
  713.         PrintF("Is %c.\n", gTransferType);
  714.     }
  715.     return 0;
  716. }    /* ChdirCmd */
  717.  
  718.  
  719.  
  720. void DoQuit(int exitStatus)
  721. {
  722.     /* Only do this once, in case we get caught with infinite recursion. */
  723.     if (++gDoneApplication <= 1) {
  724.         if (gConnected)
  725.             DoClose(1);
  726.         (void) RunPrefixedMacro("quit.", "ncftp");
  727.         (void) RunPrefixedMacro("end.", "ncftp");
  728.         if (gOtherSessionRunning == 0) {
  729.             WriteBookmarkFile();
  730.             CloseLogs();
  731.             WritePrefs();
  732.             SaveHistory();
  733.         }
  734.     }
  735.     Exit(exitStatus);
  736. }    /* DoQuit */
  737.  
  738.  
  739.  
  740. int QuitCmd(int argc, char **argv)
  741. {
  742.     DoQuit(kExitNoErr);
  743.     /*NOTREACHED*/
  744.     return 0;
  745. }    /* QuitCmd */
  746.  
  747.  
  748.  
  749.  
  750. /* Prints the command list, or gives a little more detail about a
  751.  * specified command.
  752.  */
  753. int HelpCmd(int argc, char **argv)
  754. {
  755.     CommandPtr c;
  756.     MacroNodePtr macp;
  757.     int showall = 0, helpall = 0;
  758.     char *arg;
  759.     int i, j, k, n;
  760.     int nRows, nCols;
  761.     int nCmds2Print;
  762.     int screenColumns;
  763.     int len, widestName;
  764.     char *cp, **cmdnames, spec[16];
  765.     CMNamePtr cm;
  766.  
  767.     MultiLineInit();
  768.     if (argc == 2) {
  769.         showall = (STREQ(argv[1], "showall"));
  770.         helpall = (STREQ(argv[1], "helpall"));
  771.     }
  772.     if (argc == 1 || showall) {
  773.         MultiLinePrintF("\
  774. Commands may be abbreviated.  'help showall' shows aliases, invisible and\n\
  775. unsupported commands.  'help <command>' gives a brief description of <command>.\n\n");
  776.  
  777.         /* First, see how many commands we will be printing to the screen.
  778.          * Unless 'showall' was given, we won't be printing the hidden
  779.          * (i.e. not very useful to the end-user) commands.
  780.          */
  781.         c = gCommands;
  782.         nCmds2Print = 0;
  783.         for (n = 0; n < gNumCommands; c++, n++)
  784.             if ((!iscntrl(c->name[0])) && (!(c->flags & kCmdHidden) || showall))
  785.                 nCmds2Print++;
  786.  
  787.         if ((cmdnames = (char **) malloc(sizeof(char *) * nCmds2Print)) == NULL)
  788.             OutOfMemory();
  789.  
  790.         /* Now form the list we'll be printing, and noting what the maximum
  791.          * length of a command name was, so we can use that when determining
  792.          * how to print in columns.
  793.          */
  794.         c = gCommands;
  795.         i = 0;
  796.         widestName = 0;
  797.         for (n = 0; n < gNumCommands; c++, n++) {
  798.             if ((!iscntrl(c->name[0])) && (!(c->flags & kCmdHidden) || showall)) {
  799.                 cmdnames[i++] = c->name;
  800.                 len = (int) strlen(c->name);
  801.                 if (len > widestName)
  802.                     widestName = len;
  803.             }
  804.         }
  805.  
  806.         if ((cp = (char *) getenv("COLUMNS")) == NULL)
  807.             screenColumns = 80;
  808.         else
  809.             screenColumns = atoi(cp);
  810.  
  811.         /* Leave an extra bit of whitespace for the margins between columns. */
  812.         widestName += 2;
  813.         
  814.         nCols = (screenColumns + 0) / widestName;
  815.         nRows = nCmds2Print / nCols;
  816.         if ((nCmds2Print % nCols) > 0)
  817.             nRows++;
  818.  
  819.         for (i = 0; i < nRows; i++) {
  820.             for (j = 0; j < nCols; j++) {
  821.                 k = nRows * j + i;
  822.                 if (k < nCmds2Print) {
  823.                     (void) sprintf(spec, "%%-%ds",
  824.                         (j < nCols - 1) ? widestName : widestName - 2
  825.                     );
  826.                     MultiLinePrintF(spec, cmdnames[k]);
  827.                 }
  828.             }
  829.             MultiLinePrintF("\n");
  830.         }
  831.         free(cmdnames);
  832.         
  833.         if (gNumGlobalMacros > 0) {
  834.             MultiLinePrintF("\nMacros:\n\n");
  835.             /* Now do the same for the macros. */
  836.             if ((cmdnames = (char **) malloc(sizeof(char *) * gNumGlobalMacros)) == NULL)
  837.                 OutOfMemory();
  838.     
  839.             /* Form the list we'll be printing, and noting what the maximum
  840.              * length of a command name was, so we can use that when determining
  841.              * how to print in columns.
  842.              */
  843.             macp = gFirstMacro;
  844.             widestName = 0;
  845.             for (i = 0; macp != NULL; macp = macp->next) {
  846.                     cmdnames[i++] = macp->name;
  847.                     len = (int) strlen(macp->name);
  848.                     if (len > widestName)
  849.                         widestName = len;
  850.             }
  851.             nCmds2Print = i;
  852.     
  853.             /* Leave an extra bit of whitespace for the margins between columns. */
  854.             widestName += 2;
  855.             
  856.             nCols = (screenColumns + 0) / widestName;
  857.             nRows = nCmds2Print / nCols;
  858.             if ((nCmds2Print % nCols) > 0)
  859.                 nRows++;
  860.     
  861.             for (i = 0; i < nRows; i++) {
  862.                 for (j = 0; j < nCols; j++) {
  863.                     k = nRows * j + i;
  864.                     if (k < nCmds2Print) {
  865.                         (void) sprintf(spec, "%%-%ds",
  866.                             (j < nCols - 1) ? widestName : widestName - 2
  867.                         );
  868.                         MultiLinePrintF(spec, cmdnames[k]);
  869.                     }
  870.                 }
  871.                 MultiLinePrintF("\n");
  872.             }
  873.             free(cmdnames);
  874.         }
  875.     } else if (helpall) {
  876.         /* Really intended for me, so I can debug the help strings. */
  877.         for (c = gCommands, n = 0; n < gNumCommands; c++, n++) {
  878.             PrintCmdHelp(c);
  879.             PrintCmdUsage(c);
  880.         }
  881.     } else {
  882.         /* For each command name specified, print its help stuff. */
  883.         while (--argc > 0) {
  884.             arg = *++argv;
  885.             cm = GetCommandOrMacro(arg, kAbbreviatedMatchAllowed);
  886.             if (cm == kAmbiguousName)
  887.                 MultiLinePrintF("\"%s:\" Ambiguous command or macro name.\n", arg);
  888.             else if (cm == kNoName)
  889.                 MultiLinePrintF("\"%s:\" Invalid command or macro name.\n", arg);
  890.             else if (cm->isCmd) {
  891.                 c = cm->u.cmd;
  892.                 PrintCmdHelp(c);
  893.                 PrintCmdUsage(c);
  894.             } else {
  895.                 MultiLinePrintF("\"%s\" is a macro, so no help is available.\n", arg);
  896.             }
  897.         }
  898.     }
  899.     return 0;
  900. }                                       /* HelpCmd */
  901.  
  902.  
  903.  
  904. int VersionCmd(int argc, char **argv)
  905. {
  906.     int i;
  907.     longstring line;
  908.     longstring sym;
  909.     char num[32];
  910.     int symsOnLine;
  911.     int symLen;
  912.     int lineLen;
  913.     
  914.     MultiLineInit();
  915.     MultiLinePrintF("Version:       %s\n", gVersion);
  916.     MultiLinePrintF("Author:        Mike Gleason, NCEMRSoft (mgleason@cse.unl.edu)\n");
  917. #if (kBeta == 0) && (kAlpha == 0)
  918.     MultiLinePrintF("Archived at:   ftp://ftp.probe.net/pub/ncftp/ncftp.tgz\n");
  919. #else
  920.     MultiLinePrintF("Archived in:   ftp://ftp.probe.net/pub/ncftp/BETA/\n");
  921. #endif
  922.  
  923. #ifdef __DATE__
  924.     MultiLinePrintF("Compile Date:  %s\n", __DATE__);
  925. #endif
  926. #ifdef MK
  927.     MultiLinePrintF("MK: %s\n", MK);
  928. #endif
  929.  
  930.     MultiLinePrintF("\nCompile options:\n\n");
  931.     line[0] = '\0';
  932.     symsOnLine = 0;
  933.     lineLen = 0;
  934.     for (i=0; i<gNumCppSymbols; i++) {
  935.         STRNCPY(sym, gCppSymbols[i].name);
  936.         if (gCppSymbols[i].symType == 0) {
  937.             if (gCppSymbols[i].l != 1L) {
  938.                 sprintf(num, "=%ld", gCppSymbols[i].l);
  939.                 STRNCAT(sym, num);
  940.             }
  941.             STRNCAT(sym, "  ");
  942.         } else {
  943.             STRNCAT(sym, "=\"");
  944.             STRNCAT(sym, gCppSymbols[i].s);
  945.             STRNCAT(sym, "\"  ");
  946.         }
  947.         symLen = (int) strlen(sym);
  948.         if (lineLen + symLen > 79) {
  949.             MultiLinePrintF("%s\n", line);
  950.             line[0] = '\0';
  951.             symsOnLine = 0;
  952.             lineLen = 0;
  953.         }
  954.         STRNCAT(line, sym);
  955.         ++symsOnLine;
  956.         lineLen += symLen;
  957.     }
  958.     if (symsOnLine) {
  959.         MultiLinePrintF("%s\n", line);
  960.     }
  961.     return 0;
  962. }    /* VersionCmd */
  963.  
  964.  
  965.  
  966.  
  967. int GenericGlobCmd(int argc, char **argv, char *cmd, int printMode)
  968. {
  969.     ResponsePtr rp;
  970.     int i;
  971.     int result, errs;
  972.     LineList globFiles;
  973.     LinePtr globFile;
  974.  
  975.     rp = InitResponse();
  976.     for (i=1, errs=0; i<argc; i++) {
  977.         InitLineList(&globFiles);
  978.         RemoteGlob(&globFiles, argv[i], kListNoFlags);
  979.         for (globFile = globFiles.first; globFile != NULL;
  980.             globFile = globFile->next)
  981.         {
  982.             rp->printMode = printMode;
  983.             result = RCmd(rp, "%s %s", cmd, globFile->line);
  984.             if (result != 2) {
  985.                 --errs;
  986.                 if (UNIMPLEMENTED_CMD(rp->code)) {
  987.                     DoneWithResponse(rp);
  988.                     DisposeLineListContents(&globFiles);
  989.                     return (errs);
  990.                 }
  991.             }
  992.             ReInitResponse(rp);
  993.         }
  994.         DisposeLineListContents(&globFiles);
  995.     }
  996.  
  997.     DoneWithResponse(rp);
  998.     return (errs);
  999. }    /* GenericGlobCmd */
  1000.  
  1001.  
  1002.  
  1003.  
  1004. int GenericCmd(int argc, char **argv, char *cmd, int printMode)
  1005. {
  1006.     ResponsePtr rp;
  1007.     int i;
  1008.     int result, errs;
  1009.  
  1010.     rp = InitResponse();
  1011.     for (i=1, errs=0; i<argc; i++) {
  1012.         rp->printMode = printMode;
  1013.         result = RCmd(rp, "%s %s", cmd, argv[i]);
  1014.         if (result != 2) {
  1015.             --errs;
  1016.             if (UNIMPLEMENTED_CMD(rp->code))
  1017.                 goto done;
  1018.         }
  1019.         ReInitResponse(rp);
  1020.     }
  1021.  
  1022. done:
  1023.     DoneWithResponse(rp);
  1024.     return (errs);
  1025. }    /* GenericCmd */
  1026.  
  1027.  
  1028.  
  1029.  
  1030. int DeleteCmd(int argc, char **argv)
  1031. {
  1032.     return GenericGlobCmd(argc, argv, "DELE", kDefaultPrint);
  1033. }    /* DeleteCmd */
  1034.  
  1035.  
  1036.  
  1037.  
  1038. int RmdirCmd(int argc, char **argv)
  1039. {
  1040.     return GenericGlobCmd(argc, argv, "RMD", kDefaultPrint);
  1041. }    /* RmdirCmd */
  1042.  
  1043.  
  1044.  
  1045.  
  1046. int MkdirCmd(int argc, char **argv)
  1047. {
  1048.     return GenericCmd(argc, argv, "MKD", kDefaultPrint);
  1049. }    /* MkdirCmd */
  1050.  
  1051.  
  1052.  
  1053.  
  1054. int RenameCmd(int argc, char **argv)
  1055. {
  1056.     if (RCmd(kDefaultResponse, "RNFR %s", argv[1]) == 3) {
  1057.         RCmd(kDefaultResponse, "RNTO %s", argv[2]);
  1058.     }
  1059.     return 0;
  1060. }    /* MkdirCmd */
  1061.  
  1062.  
  1063.  
  1064.  
  1065. int QuoteCmd(int argc, char **argv)
  1066. {
  1067.     longstring str;
  1068.     ResponsePtr rp;
  1069.     int i;
  1070.  
  1071.     str[0] = '\0';
  1072.     for (i=1; i<argc; i++) {
  1073.         if (i > 1)
  1074.             STRNCAT(str, " ");
  1075.         STRNCAT(str, argv[i]);
  1076.     }
  1077.  
  1078.     rp = InitResponse();
  1079.     rp->printMode = kDoPrint;
  1080.     (void) RCmd(rp, "%s%s",
  1081.         argv[0][0] == 's' ? "SITE " : "",
  1082.         str
  1083.     );
  1084.     DoneWithResponse(rp);
  1085.     return 0;
  1086. }    /* QuoteCmd */
  1087.  
  1088.  
  1089.  
  1090.  
  1091. int ClearCmd(int argc, char **argv)
  1092. {
  1093.     UpdateScreen(1);
  1094.     return 0;
  1095. }    /* ClearCmd */
  1096.  
  1097.  
  1098.  
  1099.  
  1100. int RmtHelpCmd(int argc, char **argv)
  1101. {
  1102.     ResponsePtr rp;
  1103.  
  1104.     if (argc > 1)
  1105.         GenericCmd(argc, argv, "HELP", kDoPrint);
  1106.     else {
  1107.         rp = InitResponse();
  1108.         rp->printMode = kDoPrint;
  1109.         (void) RCmd(rp, "HELP");
  1110.         DoneWithResponse(rp);
  1111.     }
  1112.     return 0;
  1113. }    /* RmtHelpCmd */
  1114.  
  1115.  
  1116.  
  1117.  
  1118. int ShellCmd(int argc, char **argv)
  1119. {
  1120.     int result;
  1121.     char *theShell;
  1122.     char *cmdLine;
  1123.     VSig_t si;
  1124.  
  1125.     si = (VSig_t) 0;
  1126.     if ((theShell = (char *) getenv("SHELL")) == NULL)
  1127.         theShell = gUserInfo.shell;
  1128.     if (theShell == NULL)
  1129.         theShell = "/bin/sh";
  1130.  
  1131.     SaveScreen();
  1132.     if (setjmp(gShellJmp) != 0) {
  1133.         /* Command was interrupted. */
  1134.         (void) SIGNAL(SIGINT, SIG_IGN);
  1135.         result = 1;
  1136.     } else {
  1137.         si = SIGNAL(SIGINT, SigLocalPage);
  1138.         if (argc < 2)
  1139.             result = system(theShell);
  1140.         else {
  1141.             /* We have a hack where we keep a copy of the original
  1142.              * command line before parsing at position argc + 2.
  1143.              */
  1144.             cmdLine = CMDLINEFROMARGS(argc, argv);
  1145.             
  1146.             /* Skip the ! and whitespace after it. */
  1147.             while ((*cmdLine == '!') || isspace(*cmdLine))
  1148.                 cmdLine++;
  1149.             result = system(cmdLine);
  1150.         }
  1151.     }
  1152.     RestoreScreen(1);
  1153.     if (si != (VSig_t) 0)
  1154.         (void) SIGNAL(SIGINT, si);
  1155.     return result;
  1156. }    /* ShellCmd */
  1157.  
  1158.  
  1159.  
  1160.  
  1161. int EchoCmd(int argc, char **argv)
  1162. {
  1163.     longstring str;
  1164.     int i;
  1165.     int noNewLine = 0;
  1166.  
  1167.     for (i=1; i<argc; i++) {
  1168.         (void) FlagStrCopy(str, sizeof(str), argv[i]);
  1169.         /* The above writes an @ sign after the nul if we were supposed
  1170.          * to not issue a final newline.
  1171.          */
  1172.         noNewLine = (str[strlen(str) + 1] == '@');
  1173.         PrintF("%s%s", (i > 1 ? " " : ""), str);
  1174.     }
  1175.     if (!noNewLine)
  1176.         PrintF("\n");
  1177.     return 0;
  1178. }    /* EchoCmd */
  1179.  
  1180.  
  1181.  
  1182.  
  1183. int LookupCmd(int argc, char **argv)
  1184. {
  1185.     int i, j;
  1186.     struct hostent *hp;
  1187.     char *host, **cpp;
  1188.     struct in_addr ip_address;
  1189.     int shortMode, opt;
  1190.     char ipStr[16];
  1191.  
  1192.     shortMode = 1;
  1193.     
  1194.     GetoptReset();
  1195.     while ((opt = Getopt(argc, argv, "v")) >= 0) {
  1196.         if (opt == 'v')
  1197.             shortMode = 0;
  1198.         else
  1199.             return kUsageErr;
  1200.     }
  1201.  
  1202.     for (i=gOptInd; i<argc; i++) {
  1203.         hp = GetHostEntry((host = argv[i]), &ip_address);
  1204.         if ((i > gOptInd) && (shortMode == 0))
  1205.             PrintF("\n");
  1206.         if (hp == NULL) {
  1207.             PrintF("Unable to get information about site %s.\n", host);
  1208.         } else if (shortMode) {
  1209.             MyInetAddr(ipStr, sizeof(ipStr), hp->h_addr_list, 0);
  1210.             PrintF("%-40s %s\n", hp->h_name, ipStr);
  1211.         } else {
  1212.             PrintF("%s:\n", host);
  1213.             PrintF("    Name:     %s\n", hp->h_name);
  1214.             for (cpp = hp->h_aliases; *cpp != NULL; cpp++)
  1215.                 PrintF("    Alias:    %s\n", *cpp);
  1216.             for (j = 0, cpp = hp->h_addr_list; *cpp != NULL; cpp++, ++j) {
  1217.                 MyInetAddr(ipStr, sizeof(ipStr), hp->h_addr_list, j);
  1218.                 PrintF("    Address:  %s\n", ipStr);    
  1219.             }
  1220.         }
  1221.     }
  1222.     return 0;
  1223. }    /* LookupCmd */
  1224.  
  1225.  
  1226.  
  1227.  
  1228. int BookmarkCmd(int argc, char **argv)
  1229. {
  1230.     SaveBookmark(argv[1]);
  1231.     return 0;
  1232. }    /* BookmarkCmd */
  1233.