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 / List.c < prev    next >
C/C++ Source or Header  |  1995-11-26  |  11KB  |  489 lines

  1. /* List.c */
  2.  
  3. #include "Sys.h"
  4.  
  5. #include <signal.h>
  6. #include <setjmp.h>
  7.  
  8. #include "Util.h"
  9. #include "RCmd.h"
  10. #include "Xfer.h"
  11. #include "Cmds.h"
  12. #include "List.h"
  13. #include "Glob.h"
  14. #include "Bookmark.h"
  15. #include "Complete.h"
  16.  
  17. jmp_buf gPDirJmp;
  18. jmp_buf gLocalListJmp;
  19. LineList gRedir;
  20. extern int gStdout;
  21. extern longstring gPager;
  22. extern Bookmark gRmtInfo;
  23.  
  24. long ListGetProc(char *buf, size_t bufsize, XferSpecPtr xp)
  25. {
  26.     long len;
  27.  
  28.     len = (long) BufferGets(buf, bufsize, xp);
  29.     return (len);
  30. }    /* ListGetProc */
  31.  
  32.  
  33.  
  34.  
  35. long ListPutProc(char *buf, size_t bufsize, XferSpecPtr xp)
  36. {
  37.     long result;
  38.     char *cp;
  39.     int len;
  40.     longstring buf2;
  41.  
  42.     if (isatty(xp->outStream)) {
  43.         MakeStringPrintable(buf2, (unsigned char *) buf, sizeof(buf2));
  44.         MultiLinePrintF("%s", buf2);
  45.         result = (long) bufsize;
  46.     } else {
  47.         result = (long) write(xp->outStream, buf, bufsize);
  48.         if (result != bufsize) {
  49.             return (-1L);
  50.         }
  51.     }
  52.  
  53.     /* Save this output line for "redir". */
  54.     len = (int) strlen(buf);
  55.     cp = buf + len - 1;
  56.     if (*cp == '\n')
  57.         *cp = 0;
  58.     AddLine(&gRedir, buf);
  59.     CompleteParse(buf);
  60.  
  61.     return (result);
  62. }    /* ListPutProc */
  63.  
  64.  
  65.  
  66.  
  67. long ListToMemoryPutProc(char *buf, size_t bufsize, XferSpecPtr xp)
  68. {
  69.     char *cp;
  70.     long len;
  71.  
  72.     len = (long) strlen(buf);
  73.     cp = buf + len - 1;
  74.     if (*cp == '\n')
  75.         *cp = 0;
  76.     AddLine((LineListPtr) xp->miscPtr, buf);
  77.     return (len);
  78. }    /* ListToMemoryPutProc */
  79.  
  80.  
  81.  
  82.  
  83. void ListToMemory(LineListPtr fileList, char *cmd, char *flags, char *what)
  84. {
  85.     XferSpecPtr xp;
  86.  
  87.     fileList->first = fileList->last = NULL;
  88.  
  89.     /* Setup the parameter block for RDataCmd.  Note that we purposely
  90.      * leave the other fields unset, since we don't use them, and
  91.      * being zeroed-out is okay.
  92.      */
  93.     xp = InitXferSpec();
  94.     xp->netMode = kNetReading;
  95.     xp->getBlock = ListGetProc;
  96.     xp->putBlock = ListToMemoryPutProc;
  97.     xp->outStream = -1;            /* Not used... */
  98.     xp->miscPtr = fileList;
  99.     
  100.     SETASCII;    /* Directory listings should be in ascii mode. */
  101.     if ((flags == NULL) || (gRmtInfo.isUnix == 0))
  102.         (void) RDataCmd(xp, "%s %s", cmd, what);
  103.     else
  104.         (void) RDataCmd(xp, "%s %s %s", cmd, flags, what);
  105.         
  106.     DoneWithXferSpec(xp);            /* Doesn't dispose miscPtr. */
  107. }    /* ListToMemory */
  108.  
  109.  
  110.  
  111.  
  112. long FileListGetProc(char *buf, size_t bufsize, XferSpecPtr xp)
  113. {
  114.     char *cp;
  115.     int len;
  116.     int c;
  117.     longstring str;
  118.     
  119.     len = BufferGets(buf, bufsize, xp);
  120.     if (len < 1)
  121.         return (0L);
  122.  
  123.     cp = buf;
  124.  
  125.     /* Unix dependency: ls message */
  126.     if (strncmp(buf, "can not access", SZ(14)) == 0) {
  127.         EPrintF("%s", buf);
  128.         return (0L);
  129.     }
  130.  
  131.     cp += len - 2;    /* Want last char of name, but also have \n. */
  132.     if (gRmtInfo.isUnix) {
  133.         c = *cp;
  134.         switch(c) {
  135.             /* Unix dependency:  ls -F format. */
  136.             case '/': c = 'd'; goto subt;
  137.             case '@': c = 'l'; goto subt;
  138.             case '*': c = '-'; goto subt;
  139.             /* No (supported) suffix, so treat it like a plain file. */
  140.             default:  c = '-'; cp[1] = '\0'; break;
  141.             subt: *cp = '\0';    /* Remove suffix. */
  142.         }
  143.     } else {
  144.         /* For non unix, just have to assume file. */
  145.         c = '-';
  146.         cp[1] = '\0';
  147.     }
  148.  
  149.     /* Just want the item names, no path prefixes. */
  150.     cp = strrchr(buf, '/');
  151.     if (cp != NULL) {
  152.         cp = Strncpy(str, cp + 1, sizeof(str));
  153.     } else {
  154.         cp = Strncpy(str, buf, sizeof(str));
  155.     }
  156.  
  157.     /* We write the one-char file type, followed by the item name. */
  158.     *buf = c;
  159.     (void) Strncpy(buf + 1, str, bufsize - 1);
  160.     
  161.     return ((long) len);
  162. }    /* FileListGetProc */
  163.  
  164.  
  165.  
  166.  
  167. long FileListPutProc(char *buf, size_t bufsize, XferSpecPtr xp)
  168. {
  169.     long len;
  170.  
  171.     len = (long) strlen(buf);
  172.     AddLine((LineListPtr) xp->miscPtr, buf);
  173.     return (len);
  174. }    /* FileListPutProc */
  175.  
  176.  
  177.  
  178.  
  179. void GetFileList(LineListPtr fileList, char *what)
  180. {
  181.     XferSpecPtr xp;
  182.  
  183.     fileList->first = fileList->last = NULL;
  184.  
  185.     /* Setup the parameter block for RDataCmd.  Note that we purposely
  186.      * leave the other fields unset, since we don't use them, and
  187.      * being zeroed-out is okay.
  188.      */
  189.     xp = InitXferSpec();
  190.     xp->netMode = kNetReading;
  191.     xp->getBlock = FileListGetProc;
  192.     xp->putBlock = FileListPutProc;
  193.     xp->outStream = -1;            /* Not used... */
  194.     xp->miscPtr = fileList;
  195.     
  196.     SETASCII;    /* Directory listings should be in ascii mode. */
  197.     if (gRmtInfo.isUnix)
  198.         (void) RDataCmd(xp, "NLST -F %s", what);
  199.     else
  200.         (void) RDataCmd(xp, "NLST %s", what);
  201.     DoneWithXferSpec(xp);            /* Doesn't dispose miscPtr. */
  202. }    /* GetFileList */
  203.  
  204.  
  205.  
  206.  
  207. int DoList(int argc, char **argv, char *lsMode)
  208. {
  209.     char flags[64];
  210.     char flags2[64];
  211.     char *cmd;
  212.     char thingsToList[256];
  213.     int i, wildcards;
  214.     XferSpecPtr xp;
  215.  
  216.     SETASCII;    /* Directory listings should be in ascii mode. */
  217.     thingsToList[0] = '\0';
  218.     flags2[0] = '\0';
  219.     wildcards = 0;
  220.  
  221.     if (STREQ(lsMode, kListLongMode)) {
  222.         cmd = "LIST";
  223.         CompleteSetFlags("-l");
  224.         flags[0] = '\0';
  225.     } else {
  226.         cmd = "NLST";
  227.         STRNCPY(flags, lsMode + 1);
  228.         CompleteSetFlags(lsMode);
  229.     }
  230.  
  231.     /* Go through and find all the things that look like dash-flags,
  232.      * and combine them into one string.  We do the same thing
  233.      * for the items to list, so we'll have to groups of things
  234.      * to hand to RDataCmd.
  235.      */
  236.     for (i=1; i<argc; i++) {
  237.         CompleteSetFlags(argv[i]);
  238.         if (argv[i][0] == '-')
  239.             STRNCAT(flags2, argv[i] + 1);
  240.         else {
  241.             STRNCAT(thingsToList, " ");
  242.             STRNCAT(thingsToList, argv[i]);            
  243.             if (GLOBCHARSINSTR(argv[i]))
  244.                 wildcards = 1;
  245.         }
  246.     }
  247.  
  248.     /* For some unknown reason, traditional servers can do "LIST -t *.tar"
  249.      * but not "NLST -t *.tar."  This kludges around that limitation.
  250.      */
  251.     if ((wildcards) && STREQ(cmd, "NLST")) {
  252.         if (flags2[0] == '\0') {
  253.             /* They didn't give any other flags, so use NLST, but without
  254.              * our usual -CF, but with the wildcard expression.
  255.              */
  256.             flags[0] = '\0';
  257.         } else {
  258.             /* They gave some other flags, but print them a warning, and
  259.              * switch them over to LIST, and retain their flags.
  260.              */
  261.             cmd = "LIST";
  262.             STRNCPY(flags, flags2);
  263.             BoldPrintF("Warning: cannot use both flags and wildcards with ls, using dir instead.\n");
  264.         }
  265.     } else {
  266.         /* Append their flags to the default flags. */
  267.         STRNCAT(flags, flags2);
  268.     }
  269.  
  270.     /* Setup the parameter block for RDataCmd.  Note that we purposely
  271.      * leave the other fields unset, since we don't use them, and
  272.      * being zeroed-out is okay.
  273.      */
  274.     xp = InitXferSpec();
  275.     xp->netMode = kNetReading;
  276.     xp->getBlock = ListGetProc;
  277.     xp->putBlock = ListPutProc;
  278.     /* xp->inStream = gDataSocket;  RDataCmd fills this in when it gets it. */
  279.     xp->outStream = gStdout;
  280.     /* The rest of the xp parameters can be left zeroed, since we won't
  281.      * be using them, and progress reports will not be activated, so
  282.      * they won't use them either.
  283.      */
  284.      
  285.     MultiLineInit();
  286.  
  287.     /* Dispose previous buffer, and also be set up for a new one. */
  288.     DisposeLineListContents(&gRedir);
  289.  
  290.     if ((flags[0]) && (gRmtInfo.isUnix != 0))
  291.         (void) RDataCmd(xp, "%s -%s%s", cmd, flags, thingsToList);
  292.     else
  293.         (void) RDataCmd(xp, "%s%s", cmd, thingsToList);
  294.  
  295.     DoneWithXferSpec(xp);
  296.  
  297.     return 0;
  298. }    /* DoList */
  299.  
  300.  
  301.  
  302.  
  303. static
  304. void PDirHandler(int ignored)
  305. {
  306.     alarm(0);
  307.     longjmp(gPDirJmp, 1);
  308. }    /* PDirHandler */
  309.  
  310.  
  311.  
  312.  
  313. /* Do a remote directory listing, to the screen (or file), or
  314.  * through your pager.
  315.  */
  316. int ListCmd(int argc, char **argv)
  317. {
  318.     char *cp, *lsMode;
  319.     int result;
  320.     volatile int pageMode;
  321.     volatile FILE *pager;
  322.     volatile int saved;
  323.     volatile Sig_t si, sp;
  324.  
  325.     result = kNoErr;
  326.     cp = argv[0];
  327.     pageMode = kNoPaging;
  328.     pager = NULL;
  329.     saved = -1;
  330.     lsMode = kListShortMode;
  331.     if (*cp == 'p') {
  332.         /* If the command started with 'p' we should be paging this. */
  333.         if (gPager[0] == '\0') {
  334.             EPrintF("You haven't specified a program to use as a pager.\n");
  335.             EPrintF("You can set this from the preferences screen (prefs command).\n");
  336.             return (-1);
  337.         }
  338.         ++cp;
  339.         pageMode = kPageMode;
  340.         pager = (volatile FILE *) POpen(gPager, "w", 1);
  341.         if (pager == NULL) {
  342.             RestoreScreen(1);
  343.             Error(kDoPerror, "Could not open: %s\n", gPager);
  344.             return (-1);
  345.         }
  346.         
  347.         /* Now replace our own stdout stream with the pager stream,
  348.          * so that writes go to the pager instead.
  349.          */
  350.         saved = (volatile int) gStdout;
  351.         gStdout = fileno((FILE *) pager);
  352.     }
  353.     if (*cp == 'd')
  354.         lsMode = kListLongMode;        /* i.e. "dir" or "pdir" */
  355.  
  356.     CompleteStart(".");
  357.     if (setjmp(gPDirJmp) == 0) {
  358.         sp = SIGNAL(SIGPIPE, PDirHandler);
  359.         si = SIGNAL(SIGINT, PDirHandler);
  360.         result = DoList(argc, argv, lsMode);
  361.     }
  362.     CompleteFinish();
  363.  
  364.     if (pageMode == kPageMode) {
  365.         /* Cleanup the mess we made. */
  366.         (void) SIGNAL(SIGPIPE, SIG_IGN);
  367.         (void) SIGNAL(SIGINT, SIG_IGN);
  368.         if (pager != NULL)
  369.             PClose((FILE *) pager);
  370.         gStdout = saved;
  371.         RestoreScreen(1);
  372.     }
  373.     (void) SIGNAL(SIGPIPE, sp);
  374.     (void) SIGNAL(SIGINT, si);
  375.     return (result);
  376. }    /* ListCmd */
  377.  
  378.  
  379.  
  380.  
  381. /*ARGSUSED*/
  382. static void SigLocalList(int sigNum)
  383. {
  384.     alarm(0);
  385.     longjmp(gLocalListJmp, 1);
  386. }    /* SigLocalList */
  387.  
  388.  
  389.  
  390. /* Run ls on the local host.  This is mostly useful for visual mode, where
  391.  * it is troublesome to spawn commands.
  392.  */
  393. int LocalListCmd(int argc, char **argv)
  394. {
  395.     volatile FILE *fp;
  396.     VSig_t si, sp;
  397.     longstring str;
  398.     int i, cf;
  399.  
  400.     si = (VSig_t) kNoSignalHandler;
  401.     sp = (VSig_t) kNoSignalHandler;
  402.  
  403.     str[0] = '\0';
  404.     STRNCPY(str, LS);
  405.     cf = 1;
  406.     if (argc > 1) {
  407.         /* Look for "-l", and turn of -CF if we find it. */
  408.         for (i=1; (i < argc) && (argv[i][0] == '-'); i++) {
  409.             if (strchr(argv[i], 'l') != NULL) {
  410.                 cf = 0;
  411.                 break;
  412.             }
  413.         }
  414.     }
  415.     if (cf)
  416.         STRNCAT(str, " -CF");
  417.     for (i=1; i<argc; i++) {
  418.         STRNCAT(str, " ");
  419.         STRNCAT(str, argv[i]);
  420.     }
  421.  
  422.     DebugMsg("%s\n", str);
  423.     fp = (volatile FILE *) POpen(str, "r", 0);
  424.     if (fp != NULL) {
  425.         if (setjmp(gLocalListJmp) == 0) {
  426.             /* Command was not interrupted. */
  427.             si = SIGNAL(SIGINT, SigLocalList);
  428.             sp = SIGNAL(SIGPIPE, SigLocalList);
  429.             MultiLineInit();
  430.             while (fgets(str, ((int) sizeof(str)) - 1, (FILE *)fp) != NULL)
  431.                 MultiLinePrintF("%s", str);
  432.         }
  433.         (void) SIGNAL(SIGINT, SIG_IGN);
  434.         (void) SIGNAL(SIGPIPE, SIG_IGN);
  435.         PClose((FILE *) fp);
  436.     }
  437.  
  438.     if (si != (VSig_t) kNoSignalHandler)
  439.         (void) SIGNAL(SIGINT, si);
  440.     if (sp != (VSig_t) kNoSignalHandler)
  441.         (void) SIGNAL(SIGPIPE, sp);
  442.     return (kNoErr);
  443. }    /* LocalListCmd */
  444.  
  445.  
  446.  
  447.  
  448. int RedirCmd(int argc, char **argv)
  449. {
  450.     LinePtr lp;
  451.     volatile FILE *pager;
  452.     VSig_t si, sp;
  453.  
  454.     si = (VSig_t) kNoSignalHandler;
  455.     sp = (VSig_t) kNoSignalHandler;
  456.  
  457.     if (argv[0][0] == 'p') {
  458.         /* If the command started with 'p' we should be paging this. */
  459.         if (gPager[0] == '\0') {
  460.             EPrintF("You haven't specified a program to use as a pager.\n");
  461.             EPrintF("You can set this from the preferences screen (prefs command).\n");
  462.             return (-1);
  463.         }
  464.         pager = (volatile FILE *) POpen(gPager, "w", 1);
  465.         if (pager == NULL) {
  466.             Error(kDoPerror, "Could not open: %s\n", gPager);
  467.             return (-1);
  468.         }
  469.         if (setjmp(gPDirJmp) == 0) {
  470.             /* Command was not interrupted. */
  471.             sp = SIGNAL(SIGPIPE, PDirHandler);
  472.             si = SIGNAL(SIGINT, PDirHandler);
  473.             for (lp = gRedir.first; lp != NULL; lp = lp->next)
  474.                 fprintf((FILE *) pager, "%s\n", lp->line);
  475.             PClose((FILE *) pager);
  476.             RestoreScreen(1);
  477.         }
  478.     } else {
  479.         MultiLineInit();
  480.         for (lp = gRedir.first; lp != NULL; lp = lp->next)
  481.             MultiLinePrintF("%s\n", lp->line);
  482.     }
  483.     if (si != (VSig_t) kNoSignalHandler)
  484.         (void) SIGNAL(SIGINT, si);
  485.     if (sp != (VSig_t) kNoSignalHandler)
  486.         (void) SIGNAL(SIGPIPE, sp);
  487.     return (kNoErr);
  488. }    /* RedirCmd */
  489.