home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / older_versions / ncftp-3.2.2-src.tar.bz2 / ncftp-3.2.2-src.tar / ncftp-3.2.2 / libncftp / unls.c < prev    next >
C/C++ Source or Header  |  2008-07-13  |  23KB  |  1,010 lines

  1. /* unls.c
  2.  *
  3.  * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
  4.  * All rights reserved.
  5.  *
  6.  */
  7.  
  8. #include "syshdrs.h"
  9. #ifdef PRAGMA_HDRSTOP
  10. #    pragma hdrstop
  11. #endif
  12.  
  13. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  14. #    define _CRT_SECURE_NO_WARNINGS 1
  15. #    pragma warning(disable : 4706)    // warning C4706: assignment within conditional expression
  16. #endif
  17.  
  18. static const char *rwx[9] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx", NULL };
  19.  
  20. #if 0
  21. /* May need this later. */
  22. static void
  23. CheckForLS_d(FTPCIPtr cip)
  24. {
  25.     FTPLineList lines;
  26.     char *cp;
  27.  
  28.     if (cip->hasNLST_d == kCommandAvailabilityUnknown) {
  29.         if (FTPListToMemory2(cip, ".", &lines, "-d ", 0, (int *) 0) == kNoErr) {
  30.             if ((lines.first != NULL) && (lines.first == lines.last)) {
  31.                 /* If we have only one item in the list, see if it really was
  32.                  * an error message we would recognize.
  33.                  */
  34.                 cp = strchr(lines.first->line, ':');
  35.                 if ((cp != NULL) && STREQ(cp, ": No such file or directory")) {
  36.                     cip->hasNLST_d = kCommandNotAvailable;
  37.                 } else {
  38.                     cip->hasNLST_d = kCommandAvailable;
  39.                 }
  40.             } else {
  41.                 cip->hasNLST_d = kCommandNotAvailable;
  42.             }
  43.         } else {
  44.             cip->hasNLST_d = kCommandNotAvailable;
  45.         }
  46.         DisposeLineListContents(&lines);
  47.     }
  48. }    /* CheckForLS_d */
  49. #endif
  50.  
  51.  
  52.  
  53.  
  54. static int
  55. LsMonthNameToNum(char *cp)
  56. {
  57.     int mon;    /* 0..11 */
  58.  
  59.     switch (*cp++) {
  60.         case 'A':
  61.             mon = (*cp == 'u') ? 7 : 3;
  62.             break;
  63.         case 'D':
  64.             mon = 11;
  65.             break;
  66.         case 'F':
  67.             mon = 1;
  68.             break;
  69.         default:
  70.         case 'J':
  71.             if (*cp++ == 'u')
  72.                 mon = (*cp == 'l') ? 6 : 5;
  73.             else
  74.                 mon = 0;
  75.             break;
  76.         case 'M':
  77.             mon = (*++cp == 'r') ? 2 : 4;
  78.             break;
  79.         case 'N':
  80.             mon = 10;
  81.             break;
  82.         case 'O':
  83.             mon = 9;
  84.             break;
  85.         case 'S':
  86.             mon = 8;
  87.     }
  88.     return (mon);
  89. }    /* LsMonthNameToNum */
  90.  
  91.  
  92.  
  93.  
  94. static int
  95. UnDosLine(    char *const line,
  96.         const char *const curdir,
  97.         size_t curdirlen,
  98.         char *fname,
  99.         size_t fnamesize,
  100.         int *ftype,
  101.         longest_int *fsize,
  102.         time_t *ftime)
  103. {
  104.     char *cp;
  105.     int hour, year;
  106.     char *filestart;
  107.     char *sizestart;
  108.     struct tm ftm;
  109.  
  110.     /*
  111.      *
  112. 0123456789012345678901234567890123456789012345678901234567890123456789
  113. 04-27-99  10:32PM               270158 Game booklet.pdf
  114. 03-11-99  10:03PM       <DIR>          Get A3d Banner
  115.  
  116. We also try to parse the format from CMD.EXE, which is similar:
  117.  
  118. 03/22/2001  06:23p              62,325 cls.pdf
  119.  
  120.      *
  121.      */
  122.     cp = line;
  123.     if (
  124.         isdigit((int) cp[0])
  125.         && isdigit((int) cp[1])
  126.         && ispunct((int) cp[2])
  127.         && isdigit((int) cp[3])
  128.         && isdigit((int) cp[4])
  129.         && ispunct((int) cp[5])
  130.         && isdigit((int) cp[6])
  131.         && isdigit((int) cp[7])
  132.     ) {
  133.         (void) memset(&ftm, 0, sizeof(struct tm));
  134.         ftm.tm_isdst = -1;
  135.         cp[2] = '\0';
  136.         ftm.tm_mon = atoi(cp + 0);
  137.         if (ftm.tm_mon > 0)
  138.             ftm.tm_mon -= 1;
  139.         cp[5] = '\0';
  140.         ftm.tm_mday = atoi(cp + 3);
  141.         if ((isdigit((int) cp[8])) && (isdigit((int) cp[9]))) {
  142.             /* Four-digit year */
  143.             cp[10] = '\0';
  144.             year = atoi(cp + 6);
  145.             if (year > 1900)
  146.                 year -= 1900;
  147.             ftm.tm_year = year;    /* years since 1900 */
  148.             cp += 11;
  149.         } else {
  150.             /* Two-digit year */
  151.             cp[8] = '\0';
  152.             year = atoi(cp + 6);
  153.             if (year < 98)
  154.                 year += 100;
  155.             ftm.tm_year = year;    /* years since 1900 */
  156.             cp += 9;
  157.         }
  158.  
  159.         for (;;) {
  160.             if (*cp == '\0')
  161.                 return (-1);
  162.             if (isdigit((int) *cp))
  163.                 break;
  164.             cp++;
  165.         }
  166.  
  167.         cp[2] = '\0';
  168.         hour = atoi(cp);
  169.         if (((cp[5] == 'P') || (cp[5] == 'p')) && (hour < 12))
  170.             hour += 12;
  171.         else if (((cp[5] == 'A') || (cp[5] == 'a')) && (hour == 12))
  172.             hour -= 12;
  173.         ftm.tm_hour = hour;
  174.         cp[5] = '\0';
  175.         ftm.tm_min = atoi(cp + 3);
  176.         *ftime = mktime(&ftm);
  177.         if (*ftype == (time_t) -1)
  178.             return (-1);
  179.  
  180.         cp += 6;
  181.         *ftype = '-';
  182.         for (;;) {
  183.             if (*cp == '\0')
  184.                 return (-1);
  185.             if ((*cp == '<') && (cp[1] == 'D')) {
  186.                 /* found <DIR> */
  187.                 *ftype = 'd';
  188.                 cp += 5;
  189.                 break;    /* size field will end up being empty string */
  190.             } else if ((*cp == '<') && (cp[1] == 'J')) {
  191.                 /* found <JUNCTION>
  192.                  *
  193.                  * Will we ever really see this?
  194.                  * IIS from Win2000sp1 sends <DIR>
  195.                  * for FTP, but CMD.EXE prints
  196.                  * <JUNCTION>.
  197.                  */
  198.                 *ftype = 'd';
  199.                 cp += 10;
  200.                 break;
  201.             } else if (isdigit((int) *cp)) {
  202.                 break;
  203.             } else {
  204.                 cp++;
  205.             }
  206.         }
  207.  
  208.         sizestart = cp;
  209.         for (;;) {
  210.             if (*cp == '\0')
  211.                 return (-1);
  212. #ifdef HAVE_MEMMOVE
  213.             if (*cp == ',') {
  214.                 /* Yuck -- US Locale dependency */
  215.                 memmove(cp, cp + 1, strlen(cp + 1) + 1);
  216.             }
  217. #endif
  218.             if (!isdigit((int) *cp)) {
  219.                 *cp++ = '\0';
  220.                 break;
  221.             }
  222.             cp++;
  223.         }
  224.  
  225.         if (fsize != NULL) {
  226. #if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
  227.             if (*ftype == 'd')
  228.                 *fsize = 0;
  229.             else
  230.                 (void) sscanf(sizestart, SCANF_LONG_LONG, fsize);
  231. #elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
  232.             if (*ftype == 'd')
  233.                 *fsize = 0;
  234.             else
  235.                 *fsize = (longest_int) strtoq(sizestart, NULL, 0);
  236. #else
  237.             *fsize = (longest_int) 0;
  238.             if (*ftype != 'd') {
  239.                 long fsize2 = 0L;
  240.  
  241.                 (void) sscanf(sizestart, "%ld", &fsize2);
  242.                 *fsize = (longest_int) fsize2;
  243.             }
  244. #endif
  245.         }
  246.  
  247.         for (;;) {
  248.             if (*cp == '\0')
  249.                 return (-1);
  250.             if (!isspace((int) *cp)) {
  251.                 break;
  252.             }
  253.             cp++;
  254.         }
  255.  
  256.         filestart = cp;
  257.         if (curdirlen == 0) {
  258.             (void) Strncpy(fname, filestart, fnamesize);
  259.         } else {
  260.             (void) Strncpy(fname, curdir, fnamesize);
  261.             (void) Strncat(fname, filestart, fnamesize);
  262.         }
  263.  
  264.         return (0);
  265.     }
  266.     return (-1);
  267. }    /* UnDosLine */
  268.  
  269.  
  270.  
  271.  
  272. static int
  273. UnLslRLine(    char *const line,
  274.         const char *const curdir,
  275.         size_t curdirlen,
  276.         char *fname,
  277.         size_t fnamesize,
  278.         char *linkto,
  279.         size_t linktosize,
  280.         int *ftype,
  281.         longest_int *fsize,
  282.         time_t *ftime,
  283.         time_t now,
  284.         int thisyear,
  285.         int *plugend)
  286. {
  287.     char *cp;
  288.     int mon = 0, day = 0, hr = 0, min = 0, year = 0, sec = 0;
  289.     int haveIsoHHMMSS = -1;
  290.     char *monstart, *daystart, *hrstart, *minstart, *yearstart, *secstart = NULL;
  291.     char *linktostart, *filestart = NULL;
  292.     char *sizestart;
  293.     char *pe;
  294.     struct tm ftm;
  295.  
  296.     *plugend = 0;
  297.     *ftype = 0;
  298.     if (ftime != NULL)
  299.         *ftime = (time_t) -1;
  300.     if (fsize != NULL)
  301.         *fsize = (longest_int) -1;
  302.  
  303.     /*
  304.      * Look for the digit just before the space
  305.      * before the month name.
  306.      *
  307. -rw-rw----   1 gleason  sysdev      33404 Mar 24 01:29 RCmd.o
  308. -rw-rw-r--   1 gleason  sysdevzz     1829 Jul  7  1996 README
  309. -rw-rw-r--   1 gleason  sysdevzz     1829 Jul 7   1996 README
  310. -rw-rw-r--   1 gleason  sysdevzz     1829 Jul  7 1996  README
  311. -rw-rw-r--   1 gleason  sysdevzz     1829 Jul 7  1996  README
  312.          *
  313.      *------------------------------^
  314.      *                              0123456789012345
  315.      *------plugend--------^
  316.      *                     9876543210
  317.      *
  318.      */
  319.     for (cp = line; *cp != '\0'; cp++) {
  320.         if (    (isdigit((int) *cp))
  321.             && (isspace((int) cp[1]))
  322.             && (isupper((int) cp[2]))
  323.             && (islower((int) cp[3]))
  324.         /*    && (islower((int) cp[4])) */
  325.             && (isspace((int) cp[5]))
  326.             && (
  327. ((isdigit((int) cp[6])) && (isdigit((int) cp[7])))
  328. || ((isdigit((int) cp[6])) && (isspace((int) cp[7])))
  329. || ((isspace((int) cp[6])) && (isdigit((int) cp[7])))
  330.             )
  331.             && (isspace((int) cp[8]))
  332.         ) {
  333.             monstart = cp + 2;
  334.             daystart = cp + 6;
  335.             if (    ((isspace((int) cp[9])) || (isdigit((int) cp[9])))
  336.                 && (isdigit((int) cp[10]))
  337.                 && (isdigit((int) cp[11]))
  338.                 && (isdigit((int) cp[12]))
  339.                 && ((isdigit((int) cp[13])) || (isspace((int) cp[13])))
  340.             ) {
  341.                 /* "Mon DD  YYYY" form */
  342.                 yearstart = cp + 9;
  343.                 if (isspace((int) *yearstart))
  344.                     yearstart++;
  345.                 hrstart = NULL;
  346.                 minstart = NULL;
  347.                 filestart = cp + 15;
  348.                 cp[1] = '\0';    /* end size */
  349.                 cp[5] = '\0';    /* end mon */
  350.                 cp[8] = '\0';    /* end day */
  351.                 cp[14] = '\0';    /* end year */
  352.                 mon = LsMonthNameToNum(monstart);
  353.                 day = atoi(daystart);
  354.                 hr = 23;
  355.                 min = 59;
  356.                 sec = 59;
  357.                 year = atoi(yearstart);
  358.  
  359.                 pe = cp;
  360.                 while (isdigit((int) *pe))
  361.                     pe--;
  362.                 while (isspace((int) *pe))
  363.                     pe--;
  364.                 *plugend = (int) (pe - line) + 1;
  365.                 break;
  366.             } else if (    /*
  367.                      * Windows NT does not 0 pad.
  368.                     (isdigit((int) cp[9])) &&
  369.                      */
  370.                 (isdigit((int) cp[10]))
  371.                 && (cp[11] == ':')
  372.                 && (isdigit((int) cp[12]))
  373.                 && (isdigit((int) cp[13]))
  374.             ) {
  375.                 /* "Mon DD HH:MM" form */
  376.                 yearstart = NULL;
  377.                 hrstart = cp + 9;
  378.                 minstart = cp + 12;
  379.                 filestart = cp + 15;
  380.                 cp[1] = '\0';    /* end size */
  381.                 cp[5] = '\0';    /* end mon */
  382.                 cp[8] = '\0';    /* end day */
  383.                 cp[11] = '\0';    /* end hr */
  384.                 cp[14] = '\0';    /* end min */
  385.                 mon = LsMonthNameToNum(monstart);
  386.                 day = atoi(daystart);
  387.                 hr = atoi(hrstart);
  388.                 min = atoi(minstart);
  389.                 sec = 0;
  390.                 year = 0;
  391.  
  392.                 pe = cp;
  393.                 while (isdigit((int) *pe))
  394.                     pe--;
  395.                 while (isspace((int) *pe))
  396.                     pe--;
  397.                 *plugend = (int) (pe - line) + 1;
  398.                 break;
  399.             }
  400.         } else if (    (isdigit((int) *cp))
  401.             && (isspace((int) cp[1]))
  402.  
  403.             && (isdigit((int) cp[2]))
  404.             && (isdigit((int) cp[3]))
  405.             && (isdigit((int) cp[4]))
  406.             && (isdigit((int) cp[5]))
  407.             && (cp[6] == '-')
  408.             && (isdigit((int) cp[7]))
  409.             && (isdigit((int) cp[8]))
  410.             && (cp[9] == '-')
  411.             && (isdigit((int) cp[10]))
  412.             && (isdigit((int) cp[11]))
  413.  
  414.             && (isspace((int) cp[12]))
  415.  
  416.             && (isdigit((int) cp[13]))
  417.             && (isdigit((int) cp[14]))
  418.             && (cp[15] == ':')
  419.             && (isdigit((int) cp[16]))
  420.             && (isdigit((int) cp[17]))
  421.  
  422.             && (
  423.                 ((haveIsoHHMMSS = isspace((int) cp[18]))) ||
  424.                 (
  425.                        (isdigit((int) cp[19]))
  426.                     && (isdigit((int) cp[20]))
  427.                     && (isspace((int) cp[21]))
  428.                     && ((haveIsoHHMMSS = (int) cp[18]) == ':')
  429.                 )
  430.  
  431.             )
  432.         ) {
  433.             /* "YYYY-mm-dd HH:MM" or "YYYY-mm-dd HH:MM:SS" form */
  434. /* drwxr-xr-x   4 ftpuser  ftpusers  136 2008-03-12 23:38 beta
  435.                                        0123456789012345678901234567890123456789
  436. */
  437.             yearstart = cp + 2;
  438.             cp[6] = '\0';    /* end year */
  439.  
  440.             monstart = cp + 7;
  441.             cp[9] = '\0';    /* end month */
  442.  
  443.             daystart = cp + 10;
  444.             cp[12] = '\0';    /* end day */
  445.  
  446.             hrstart = cp + 13;
  447.             cp[15] = '\0';    /* end hr */
  448.  
  449.             minstart = cp + 16;
  450.             cp[18] = '\0';    /* end min */
  451.  
  452.             if (haveIsoHHMMSS == ':') {
  453.                 secstart = cp + 19;
  454.                 cp[21] = '\0';    /* end sec */
  455.                 sec = atoi(secstart);
  456.                 filestart = cp + 22;
  457.             } else {
  458.                 filestart = cp + 19;
  459.                 sec = 0;
  460.             }
  461.  
  462.             mon = atoi(monstart) - 1;
  463.             day = atoi(daystart);
  464.             hr = atoi(hrstart);
  465.             min = atoi(minstart);
  466.             year = atoi(yearstart);
  467.  
  468.             pe = cp;
  469.             while (isdigit((int) *pe))
  470.                 pe--;
  471.             while (isspace((int) *pe))
  472.                 pe--;
  473.             *plugend = (int) (pe - line) + 1;
  474.             break;
  475.         }
  476.     }
  477.  
  478.     if (*cp == '\0')
  479.         return (-1);
  480.  
  481.     linktostart = strstr(filestart, " -> ");
  482.     if (linktostart != NULL) {
  483.         *linktostart = '\0';
  484.         linktostart += 4;
  485.         (void) Strncpy(linkto, linktostart, linktosize);
  486.     } else {
  487.         *linkto = '\0';
  488.     }
  489.  
  490.     if (curdirlen == 0) {
  491.         (void) Strncpy(fname, filestart, fnamesize);
  492.     } else {
  493.         (void) Strncpy(fname, curdir, fnamesize);
  494.         (void) Strncat(fname, filestart, fnamesize);
  495.     }
  496.  
  497.     if (ftime != NULL) {
  498.         (void) memset(&ftm, 0, sizeof(struct tm));
  499.         ftm.tm_mon = mon;
  500.         ftm.tm_mday = day;
  501.         ftm.tm_hour = hr;
  502.         ftm.tm_min = min;
  503.         ftm.tm_sec = sec;
  504.         ftm.tm_isdst = -1;
  505.         if (year == 0) {
  506.             /* We guess the year, based on what the
  507.              * current year is.  We know the file
  508.              * on the remote server is either less
  509.              * than six months old or less than
  510.              * one hour into the future.
  511.              */
  512.             ftm.tm_year = thisyear - 1900;
  513.             *ftime = mktime(&ftm);
  514.             if (*ftime == (time_t) -1) {
  515.                 /* panic */
  516.             } else if (*ftime > (now + (15552000L + 86400L))) {
  517.                 --ftm.tm_year;
  518.                 *ftime = mktime(&ftm);
  519.             } else if (*ftime < (now - (15552000L + 86400L))) {
  520.                 ++ftm.tm_year;
  521.                 *ftime = mktime(&ftm);
  522.             }
  523.         } else {
  524.             ftm.tm_year = year - 1900;
  525.             *ftime = mktime(&ftm);
  526.         }
  527.     }
  528.  
  529.     if (fsize != NULL) {
  530.         while ((cp > line) && (isdigit((int) *cp)))
  531.             --cp;
  532.         sizestart = cp + 1;
  533. #if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
  534.         (void) sscanf(sizestart, SCANF_LONG_LONG, fsize);
  535. #elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
  536.         *fsize = (longest_int) strtoq(sizestart, NULL, 0);
  537. #else
  538.         {
  539.             long fsize2 = 0L;
  540.             
  541.             (void) sscanf(sizestart, "%ld", &fsize2);
  542.             *fsize = (longest_int) fsize2;
  543.         }
  544. #endif
  545.     }
  546.  
  547.     switch (line[0]) {
  548.         case 'd':
  549.         case 'l':
  550.             *ftype = (int) line[0];
  551.             break;
  552.         case 'b':
  553.         case 'c':
  554.         case 's':
  555.             *ftype = (int) line[0];
  556.             return (-1);
  557.         default:
  558.             *ftype = '-';
  559.     }
  560.  
  561.     return (0);
  562. }    /* UnLslRLine */
  563.  
  564.  
  565.  
  566. int
  567. UnLslR(const FTPCIPtr cip, FTPFileInfoListPtr filp, FTPLineListPtr llp, int serverType)
  568. {
  569.     char curdir[512];
  570.     char line[512];
  571.     int len;
  572.     size_t curdirlen = 0;
  573.     char fname[256];
  574.     char linkto[256];
  575.     char *cp;
  576.     longest_int fsize;
  577.     int ftype;
  578.     time_t ftime, now;
  579.     int thisyear;
  580.     struct tm nowtm;
  581.     int rc;
  582.     FTPLinePtr lp;
  583.     FTPFileInfo fi;
  584.     int linesread = 0;
  585.     int linesconverted = 0;
  586.     size_t maxFileLen = 0;
  587.     size_t maxPlugLen = 0;
  588.     size_t fileLen;
  589.     int plugend;
  590.     int skipdir = 0;
  591.     size_t cwdlen;
  592.  
  593.     if (Localtime(time(&now), &nowtm) == NULL)
  594.         thisyear = 1970;    /* should never happen */
  595.     else
  596.         thisyear = nowtm.tm_year + 1900;
  597.  
  598.     curdir[0] = '\0';
  599.     cip->buf[0] = '\0';
  600.     cwdlen = 0;
  601.  
  602.     InitFileInfoList(filp);
  603.     for (lp = llp->first; lp != NULL; lp = lp->next) {
  604.         len = (int) strlen(STRNCPY(line, lp->line));
  605.         for (cp = line; ; cp++) {
  606.             if ((*cp == '\0') || (!isspace((int) *cp)))
  607.                 break;
  608.         }
  609.         if (*cp == '\0') {
  610.             /* Entire line was blank. */
  611.             /* separator line between dirs */
  612.             continue;
  613.         }
  614.  
  615.         if (serverType == kServerTypeMicrosoftFTP) {
  616.             /* IIS runs on WinNT only, and NT
  617.              * can use / as a separator rather
  618.              * that \.  We will convert them
  619.              * here.
  620.              */
  621.             for (cp = line; *cp != '\0'; cp++) {
  622.                 if (*cp == '\\')
  623.                     *cp = '/';
  624.             }
  625.         }
  626.  
  627.         linesread++;
  628.         rc = UnLslRLine(line, curdir, curdirlen, fname, sizeof(fname), linkto, sizeof(linkto), &ftype, &fsize, &ftime, now, thisyear, &plugend);
  629.         if ((rc < 0) && (serverType == kServerTypeMicrosoftFTP)) {
  630.             rc = UnDosLine(line, curdir, curdirlen, fname, sizeof(fname), &ftype, &fsize, &ftime);
  631.             if (rc == 0) {
  632.                 *linkto = '\0';
  633.                 plugend = 0;
  634.             }
  635.         }
  636.  
  637.         if (rc == 0) {
  638.             if (skipdir != 0)
  639.                 continue;
  640.             cp = fname + curdirlen;
  641.             if ((cp[0] == '.') && ((cp[1] == '\0') || ((cp[1] == '.') && (cp[2] == '\0'))))
  642.                 continue;    /* ignore . and .. */
  643.             linesconverted++;
  644.             cp = fname;
  645.             if ((cp[0] == '.') && ((cp[1] == '/') || (cp[1] == '\\')))
  646.                 cp += 2;
  647.             if ((*cp == '/') || (*cp == '\\')) {
  648.                 /* Absolute pathnames not allowed unless
  649.                  * they are in the cwd.
  650.                  */
  651.                 if (cip->buf[0] == '\0') {
  652.                     (void) FTPGetCWD(cip, cip->buf, cip->bufSize);
  653.                     cwdlen = strlen(cip->buf);
  654.                 }
  655.                 /* In root directory (cwdlen == 1), paths
  656.                  * from root are OK.
  657.                  */
  658.                 if (cwdlen > 1) {
  659.                     if (memcmp(cp, cip->buf, cwdlen) == 0) {
  660.                         /* Abs path prefixed with cwd */
  661.                         cp += cwdlen;
  662.                         if ((*cp == '/') || (*cp == '\\'))
  663.                             cp++;
  664.                     } else {
  665.                         /* Abs path not prefixed with cwd */
  666.                         continue;
  667.                     }
  668.                 }
  669.             }
  670.             if (PathContainsIntermediateDotDotSubDir(cp))
  671.                 continue;
  672.             fileLen = strlen(cp);
  673.             if (fileLen > maxFileLen)
  674.                 maxFileLen = fileLen;
  675.             fi.relnameLen = fileLen;
  676.             fi.relname = StrDup(cp);
  677.             fi.rname = NULL;
  678.             fi.lname = NULL;
  679.             fi.rlinkto = (linkto[0] == '\0') ? NULL : StrDup(linkto);
  680.             fi.mdtm = ftime;
  681.             fi.size = (longest_int) fsize;
  682.             fi.type = ftype;
  683.             fi.mode = -1;
  684.             if (plugend > 0) {
  685.                 fi.plug = (char *) malloc((size_t) plugend + 1);
  686.                 if (fi.plug != NULL) {
  687.                     (void) memcpy(fi.plug, line, (size_t) plugend);
  688.                     fi.plug[plugend] = '\0';
  689.                     if ((size_t) plugend > maxPlugLen)
  690.                         maxPlugLen = (size_t) plugend;
  691.                 }
  692.             } else {
  693.                 fi.plug = (char *) malloc(32 + 1);
  694.                 if (fi.plug != NULL) {
  695.                     (void) strcpy(fi.plug, "----------   1 ftpuser  ftpusers");
  696.                     fi.plug[0] = (char) ftype;
  697.                     if (32 > maxPlugLen)
  698.                         maxPlugLen = (size_t) 32;
  699.                 }
  700.             }
  701.             (void) AddFileInfo(filp, &fi);
  702.         } else if ((rc < 0) && (line[len - 1] == ':')) {
  703.             if ((line[0] == '.') && (line[1] == '/')) {
  704.                 line[len - 1] = '/';
  705.                 (void) memcpy(curdir, line + 2, (size_t) len + 1 - 2);
  706.                 curdirlen = (size_t) (len - 2);
  707.             } else if ((line[0] == '.') && (line[1] == '\\')) {
  708.                 line[len - 1] = '\\';
  709.                 (void) memcpy(curdir, line + 2, (size_t) len + 1 - 2);
  710.                 curdirlen = (size_t) (len - 2);
  711.             } else {
  712.                 line[len - 1] = '/';
  713.                 (void) memcpy(curdir, line, (size_t) len + 1);
  714.                 curdirlen = (size_t) len;
  715.             }
  716.             skipdir = 0;
  717.             cp = curdir;
  718.             if ((*cp == '/') || (*cp == '\\')) {
  719.                 skipdir = 1;    /* absolute pathnames not allowed */
  720.                 if (cip->buf[0] == '\0') {
  721.                     (void) FTPGetCWD(cip, cip->buf, cip->bufSize);
  722.                     cwdlen = strlen(cip->buf);
  723.                 }
  724.                 if (cwdlen == 1) {
  725.                     /* In root directory, so paths
  726.                      * from root are OK.
  727.                      */
  728.                     skipdir = 0;
  729.                 } else {
  730.                     if (memcmp(cp, cip->buf, cwdlen) == 0) {
  731.                         cp += cwdlen;
  732.                         if ((*cp == '/') || (*cp == '\\'))
  733.                             cp++;
  734.                         memmove(curdir, cp, strlen(cp) + 1);
  735.                         skipdir = 0;
  736.                         cp = curdir;
  737.                     }
  738.                 }
  739.             }
  740.             if (PathContainsIntermediateDotDotSubDir(cp)) {
  741.                 skipdir = 1;
  742.             }
  743.         }
  744.     }
  745.  
  746.     filp->maxFileLen = maxFileLen;
  747.     filp->maxPlugLen = maxPlugLen;
  748.     if (linesread == 0)
  749.         return (0);
  750.     return ((linesconverted > 0) ? linesconverted : (-1));
  751. }    /* UnLslR */
  752.  
  753.  
  754.  
  755.  
  756. int
  757. UnMlsT(const FTPCIPtr UNUSED(cip), const char *const line0, const MLstItemPtr mlip)
  758. {
  759.     char *cp, *val, *fact;
  760.     int ec;
  761.     size_t len;
  762.     char line[1024];
  763.  
  764.     LIBNCFTP_USE_VAR(cip);
  765.     memset(mlip, 0, sizeof(MLstItem));
  766.     mlip->mode = -1;
  767.     mlip->fsize = kSizeUnknown;
  768.     mlip->ftype = '-';
  769.     mlip->ftime = kModTimeUnknown;
  770.  
  771.     len = strlen(line0);
  772.     if (len > (sizeof(line) - 1))
  773.         return (-1);    /* Line too long, sorry. */
  774.     /* This should be re-coded so does not need to make a
  775.      * copy of the buffer; it could be done in place.
  776.      */
  777.     memcpy(line, line0, len + 1);
  778.  
  779.     /* Skip leading whitespace. */
  780.     for (cp = line; *cp != '\0'; cp++) {
  781.         if (! isspace((int) *cp))
  782.             break;
  783.     }
  784.  
  785.     while (*cp != '\0') {
  786.         for (fact = cp; ; cp++) {
  787.             if ((*cp == '\0') || (*cp == ' ')) {
  788.                 /* protocol violation */
  789.                 return (-1);
  790.             }
  791.             if (*cp == '=') {
  792.                 /* End of fact name. */
  793.                 *cp++ = '\0';
  794.                 break;
  795.             }
  796.         }
  797.         for (val = cp; ; cp++) {
  798.             if (*cp == '\0') {
  799.                 /* protocol violation */
  800.                 return (-1);
  801.             }
  802.             if (*cp == ' ') {
  803.                 ec = ' ';
  804.                 *cp++ = '\0';
  805.                 break;
  806.             } else if (*cp == ';') {
  807.                 if (cp[1] == ' ') {
  808.                     ec = ' ';
  809.                     *cp++ = '\0';
  810.                     *cp++ = '\0';
  811.                 } else {
  812.                     ec = ';';
  813.                     *cp++ = '\0';
  814.                 }
  815.                 break;
  816.             }
  817.         }
  818.         if (ISTRNEQ(fact, "OS.", 3))
  819.             fact += 3;
  820.         if (ISTREQ(fact, "type")) {
  821.             if (ISTREQ(val, "file")) {
  822.                 mlip->ftype = '-';
  823.             } else if (ISTREQ(val, "dir")) {
  824.                 mlip->ftype = 'd';
  825.             } else if (ISTREQ(val, "cdir")) {
  826.                 /* not supported: current directory */
  827.                 return (-2);
  828.             } else if (ISTREQ(val, "pdir")) {
  829.                 /* not supported: parent directory */
  830.                 return (-2);
  831.             } else {
  832.                 /* ? */
  833.                 return (-1);
  834.             }
  835.         } else if (ISTREQ(fact, "UNIX.mode")) {
  836.             if (val[0] == '0')
  837.                 sscanf(val, "%o", &mlip->mode);
  838.             else    
  839.                 sscanf(val, "%i", &mlip->mode);
  840.             if (mlip->mode != (-1))
  841.                 mlip->mode &= 00777;
  842.         } else if (ISTREQ(fact, "perm")) {
  843.             STRNCPY(mlip->perm, val);
  844.         } else if (ISTREQ(fact, "size")) {
  845. #if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
  846.             (void) sscanf(val, SCANF_LONG_LONG, &mlip->fsize);
  847. #elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
  848.             mlip->fsize = (longest_int) strtoq(val, NULL, 0);
  849. #else
  850.             {
  851.                 long fsize2 = 0L;
  852.  
  853.                 (void) sscanf(val, "%ld", &fsize2);
  854.                 mlip->fsize = (longest_int) fsize2;
  855.             }
  856. #endif
  857.         } else if (ISTREQ(fact, "modify")) {
  858.             mlip->ftime = UnMDTMDate(val);
  859.         } else if (ISTREQ(fact, "UNIX.owner")) {
  860.             STRNCPY(mlip->owner, val);
  861.         } else if (ISTREQ(fact, "UNIX.group")) {
  862.             STRNCPY(mlip->group, val);
  863.         } else if (ISTREQ(fact, "UNIX.uid")) {
  864.             mlip->uid = atoi(val);
  865.         } else if (ISTREQ(fact, "UNIX.gid")) {
  866.             mlip->gid = atoi(val);
  867.         } else if (ISTREQ(fact, "perm")) {
  868.             STRNCPY(mlip->perm, val);
  869.         }
  870.  
  871.         /* End of facts? */
  872.         if (ec == ' ')
  873.             break;
  874.     }
  875.  
  876.     len = strlen(cp);
  877.     if (len > (sizeof(mlip->fname) - 1)) {
  878.         /* Filename too long */
  879.         return (-1);
  880.     }
  881.     memcpy(mlip->fname, cp, len);
  882.  
  883.     /* also set linkto here if used */
  884.  
  885.     return (0);
  886. }    /* UnMlsT */
  887.  
  888.  
  889.  
  890.  
  891. int
  892. UnMlsD(const FTPCIPtr cip, FTPFileInfoListPtr filp, FTPLineListPtr llp)
  893. {
  894.     MLstItem mli;
  895.     char plug[64];
  896.     char og[32];
  897.     int rc;
  898.     FTPLinePtr lp;
  899.     FTPFileInfo fi;
  900.     int linesread = 0;
  901.     int linesconverted = 0;
  902.     int linesignored = 0;
  903.     size_t maxFileLen = 0;
  904.     size_t maxPlugLen = 0;
  905.     size_t fileLen, plugLen;
  906.     int m1, m2, m3;
  907.     const char *cm1, *cm2, *cm3;
  908.  
  909.     InitFileInfoList(filp);
  910.     for (lp = llp->first; lp != NULL; lp = lp->next) {
  911.         linesread++;
  912.         rc = UnMlsT(cip, lp->line, &mli);
  913.         if (rc == 0) {
  914.             if (PathContainsIntermediateDotDotSubDir(mli.fname)) {
  915.                 linesignored++;
  916.                 continue;
  917.             }
  918.             fileLen = strlen(mli.fname);
  919.             linesconverted++;
  920.             if (fileLen > maxFileLen)
  921.                 maxFileLen = fileLen;
  922.             fi.relnameLen = fileLen;
  923.             fi.relname = StrDup(mli.fname);
  924.             fi.rname = NULL;
  925.             fi.lname = NULL;
  926.             fi.rlinkto = (mli.linkto[0] == '\0') ? NULL : StrDup(mli.linkto);
  927.             fi.mdtm = mli.ftime;
  928.             fi.size = (longest_int) mli.fsize;
  929.             fi.type = mli.ftype;
  930.             fi.mode = -1;
  931.             plug[0] = (char) mli.ftype;
  932.             plug[1] = '\0';
  933.             m1 = 0;
  934.             m2 = 0;
  935.             m3 = -1;
  936.             if (mli.mode != (-1)) {
  937.                 fi.mode = mli.mode;
  938.                 m1 = (mli.mode & 00700) >> 6;
  939.                 m2 = (mli.mode & 00070) >> 3;
  940.                 m3 = (mli.mode & 00007);
  941.             }
  942.             if (mli.perm[0] != '\0') {
  943.                 m3 = 0;
  944.                 if (fi.type == 'd') {
  945.                     if (strchr(mli.perm, 'e') != NULL) {
  946.                         /* execute -> execute */
  947.                         m3 |= 00001;
  948.                     }
  949.                     if (strchr(mli.perm, 'c') != NULL) {
  950.                         /* create -> write */
  951.                         m3 |= 00002;
  952.                     }
  953.                     if (strchr(mli.perm, 'l') != NULL) {
  954.                         /* list -> read */
  955.                         m3 |= 00004;
  956.                     }
  957.                 } else {
  958.                     if (strchr(mli.perm, 'w') != NULL) {
  959.                         /* write -> write */
  960.                         m3 |= 00002;
  961.                     }
  962.                     if (strchr(mli.perm, 'r') != NULL) {
  963.                         /* read -> read */
  964.                         m3 |= 00004;
  965.                     }
  966.                 }
  967.             }
  968.             if (m3 != (-1)) {
  969.                 cm1 = rwx[m1];
  970.                 cm2 = rwx[m2];
  971.                 cm3 = rwx[m3];
  972.                 sprintf(plug + 1, "%s%s%s", cm1, cm2, cm3);
  973.             }
  974.             if (mli.owner[0] != '\0') {
  975.                 if (mli.group[0] != '\0') {
  976. #ifdef HAVE_SNPRINTF
  977.                     snprintf(og, sizeof(og) - 1,
  978. #else
  979.                     sprintf(og,
  980. #endif    /* HAVE_SNPRINTF */
  981.                         "   %-8.8s %s",
  982.                         mli.owner, mli.group
  983.                     );
  984.                     STRNCAT(plug, og);
  985.                 } else {
  986.                     STRNCAT(plug, "   ");
  987.                     STRNCAT(plug, mli.owner);
  988.                 }
  989.             }
  990.             fi.plug = StrDup(plug);
  991.             if (fi.plug != NULL) {
  992.                 plugLen = strlen(plug);
  993.                 if (plugLen > maxPlugLen)
  994.                     maxPlugLen = plugLen;
  995.             }
  996.             (void) AddFileInfo(filp, &fi);
  997.         } else if (rc == (-2)) {
  998.             linesignored++;
  999.         }
  1000.     }
  1001.  
  1002.     filp->maxFileLen = maxFileLen;
  1003.     filp->maxPlugLen = maxPlugLen;
  1004.     if ((linesread == 0) || ((linesconverted == 0) && (linesignored > 0)))
  1005.         return (0);
  1006.     return ((linesconverted > 0) ? linesconverted : (-1));
  1007. }    /* UnMlsD */
  1008.  
  1009.  
  1010.