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 / DateSize.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  7KB  |  313 lines

  1. /* DateSize.c */
  2.  
  3. #include "Sys.h"
  4.  
  5. #include <ctype.h>
  6.  
  7. #include "Util.h"
  8. #include "RCmd.h"
  9. #include "Cmds.h"
  10. #include "Xfer.h"
  11. #include "List.h"
  12. #include "DateSize.h"
  13.  
  14.  
  15. /* Cheezy, but somewhat portable way to get GMT offset. */
  16. #ifdef HAVE_MKTIME
  17. static
  18. time_t GetUTCOffset(int mon, int mday)
  19. {
  20.     struct tm local_tm, utc_tm, *utc_tmptr;
  21.     time_t local_t, utc_t, utcOffset;
  22.  
  23.     ZERO(local_tm);
  24.     ZERO(utc_tm);
  25.     utcOffset = 0;
  26.     
  27.     local_tm.tm_year = 94;    /* Doesn't really matter. */
  28.     local_tm.tm_mon = mon;
  29.     local_tm.tm_mday = mday;
  30.     local_tm.tm_hour = 12;
  31.     local_tm.tm_isdst = -1;
  32.     local_t = mktime(&local_tm);
  33.     
  34.     if (local_t != (time_t) -1) {
  35.         utc_tmptr = gmtime(&local_t);
  36.         utc_tm.tm_year = utc_tmptr->tm_year;
  37.         utc_tm.tm_mon = utc_tmptr->tm_mon;
  38.         utc_tm.tm_mday = utc_tmptr->tm_mday;
  39.         utc_tm.tm_hour = utc_tmptr->tm_hour;
  40.         utc_tm.tm_isdst = -1;
  41.         utc_t = mktime(&utc_tm);
  42.  
  43.         if (utc_t != (time_t) -1)
  44.             utcOffset = (local_t - utc_t);
  45.     }
  46.     return (utcOffset);
  47. }    /* GetUTCOffset */
  48. #endif    /* HAVE_MKTIME */
  49.  
  50.  
  51.  
  52.  
  53. /* Converts an "ls" date, in either the "Feb  4  1992" or "Jan 16 13:42"
  54.  * format to a time_t.
  55.  */
  56. time_t UnLSDate(char *dstr)
  57. {
  58. #ifndef HAVE_MKTIME
  59.     return (kModTimeUnknown);
  60. #else
  61.     char *cp = dstr;
  62.     int mon, day, year, hr, min;
  63.     time_t now, mt;
  64.     time_t result = kModTimeUnknown;
  65.     struct tm ut, *t;
  66.  
  67.     switch (*cp++) {
  68.         case 'A':
  69.             mon = (*cp == 'u') ? 7 : 3;
  70.             break;
  71.         case 'D':
  72.             mon = 11;
  73.             break;
  74.         case 'F':
  75.             mon = 1;
  76.             break;
  77.         default:                       /* shut up un-init warning */
  78.         case 'J':
  79.             if (*cp++ == 'u')
  80.                 mon = (*cp == 'l') ? 6 : 5;
  81.             else
  82.                 mon = 0;
  83.             break;
  84.         case 'M':
  85.             mon = (*++cp == 'r') ? 2 : 4;
  86.             break;
  87.         case 'N':
  88.             mon = 10;
  89.             break;
  90.         case 'O':
  91.             mon = 9;
  92.             break;
  93.         case 'S':
  94.             mon = 8;
  95.     }
  96.     cp = dstr + 4;
  97.     day = 0;
  98.     if (*cp != ' ')
  99.         day = 10 * (*cp - '0');
  100.     cp++;
  101.     day += *cp++ - '0';
  102.     min = 0;
  103.     
  104.     (void) time(&now);
  105.     t = localtime(&now);
  106.  
  107.     if (*++cp != ' ') {
  108.         /* It's a time, XX:YY, not a year. */
  109.         cp[2] = ' ';
  110.         (void) sscanf(cp, "%d %d", &hr, &min);
  111.         cp[2] = ':';
  112.         year = t->tm_year;
  113.         if (mon > t->tm_mon)
  114.             --year;
  115.     } else {
  116.         hr = min = 0;
  117.         (void) sscanf(cp, "%d", &year);
  118.         year -= 1900;
  119.     }
  120.     /* Copy the whole structure of the 'tm' pointed to by t, so it will
  121.      * also set all fields we don't specify explicitly to be the same as
  122.      * they were in t.  That way we copy non-standard fields such as
  123.      * tm_gmtoff, if it exists or not.
  124.      */
  125.     ut = *t;
  126.     ut.tm_sec = 1;
  127.     ut.tm_min = min;
  128.     ut.tm_hour = hr;
  129.     ut.tm_mday = day;
  130.     ut.tm_mon = mon;
  131.     ut.tm_year = year;
  132.     ut.tm_wday = ut.tm_yday = 0;
  133.     ut.tm_isdst = -1;    /* Let mktime figure this out for us. */
  134.     mt = mktime(&ut);
  135.     if (mt != (time_t) -1)
  136.         result = (time_t) mt;
  137.     return (result);
  138. #endif    /* HAVE_MKTIME */
  139. }    /* UnLSDate */
  140.  
  141.  
  142.  
  143. /* Converts a MDTM date, like "19930602204445"
  144.  * format to a time_t.
  145.  */
  146. time_t UnMDTMDate(char *dstr)
  147. {
  148. #ifndef HAVE_MKTIME
  149.     return (kModTimeUnknown);
  150. #else
  151.     struct tm ut, *t;
  152.     time_t mt, now;
  153.     time_t result = kModTimeUnknown;
  154.  
  155.     (void) time(&now);
  156.     t = localtime(&now);
  157.  
  158.     /* Copy the whole structure of the 'tm' pointed to by t, so it will
  159.      * also set all fields we don't specify explicitly to be the same as
  160.      * they were in t.  That way we copy non-standard fields such as
  161.      * tm_gmtoff, if it exists or not.
  162.      */
  163.     ut = *t;
  164.  
  165.     /* The time we get back from the server is (should be) in UTC. */
  166.     if (sscanf(dstr, "%04d%02d%02d%02d%02d%02d",
  167.         &ut.tm_year,
  168.         &ut.tm_mon,
  169.         &ut.tm_mday,
  170.         &ut.tm_hour,
  171.         &ut.tm_min,
  172.         &ut.tm_sec) == 6)
  173.     {    
  174.         --ut.tm_mon;
  175.         ut.tm_year -= 1900;
  176.         mt = mktime(&ut);
  177.         if (mt != (time_t) -1) {
  178.             mt += GetUTCOffset(ut.tm_mon, ut.tm_mday);
  179.             result = (time_t) mt;
  180.         }
  181.     }
  182.     return result;
  183. #endif    /* HAVE_MKTIME */
  184. }    /* UnMDTMDate */
  185.  
  186.  
  187.  
  188.  
  189. /* Given a filename, do an "ls -ld" and from the output determine the
  190.  * size and date of that file.  Since this is UNIX dependent, we
  191.  * would rather use the SIZE and MDTM commands if we can.
  192.  */
  193. long GetDateSizeFromLSLine(char *fName, time_t *modifTime)
  194. {
  195.     char *cp, *np;
  196.     string lsline;
  197.     long size = kSizeUnknown;
  198.     int n;
  199.     static int depth = 0;
  200.     LineList fileList;
  201.  
  202.     depth++;    /* Try to prevent infinite recursion. */
  203.     *modifTime = kModTimeUnknown;
  204.     InitLineList(&fileList);
  205.     ListToMemory(&fileList, "LIST", kListDirNamesOnlyMode, fName);
  206.     if (fileList.first == NULL)
  207.         goto aa;
  208.  
  209.     (void) STRNCPY(lsline, fileList.first->line);
  210.     DisposeLineListContents(&fileList);
  211.  
  212.     /* See if this line looks like a unix-style ls line. 
  213.      * If so, we can grab the date and size from it.
  214.      */    
  215.     if (strpbrk(lsline, "-dlsbcp") == lsline) {
  216.         /* See if it looks like a typical '-rwxrwxrwx' line. */
  217.         cp = lsline + 1;
  218.         if (*cp != 'r' && *cp != '-')
  219.             goto aa;
  220.         ++cp;
  221.         if (*cp != 'w' && *cp != '-')
  222.             goto aa;
  223.         cp += 2;
  224.         if (*cp != 'r' && *cp != '-')
  225.             goto aa;
  226.  
  227.          /* skip mode, links, owner (and possibly group) */
  228.          for (n = 0; n < 4; n++) {
  229.              np = cp;
  230.              while (*cp != '\0' && !isspace(*cp))
  231.                  cp++;
  232.              while (*cp != '\0' &&  isspace(*cp))
  233.                  cp++;
  234.          }
  235.          if (!isdigit(*cp))
  236.              cp = np;    /* back up (no group) */
  237.          (void) sscanf(cp, "%ld%n", &size, &n);
  238.  
  239.          *modifTime = UnLSDate(cp + n + 1);
  240.  
  241.         if (size <= 512L) {
  242.             /* May be the size of a link to the file, instead of the file. */
  243.             if ((cp = strstr(lsline, " -> ")) != NULL) {
  244.                 /* Yes, it was a link. */
  245.                 size = (depth>4) ? kSizeUnknown :
  246.                     GetDateAndSize(cp + 4, modifTime);
  247.                 /* Try the file. */
  248.             }
  249.         }
  250.     }    
  251. aa:
  252.     --depth;
  253.     return (size);
  254. }    /* GetDateSizeFromLSLine */
  255.  
  256.  
  257.  
  258.  
  259. /* The caller wanted to know the modification date and size of the remote
  260.  * file given to us.  We try to get this information by using the SIZE
  261.  * and MDTM ftp commands, and if that didn't work we try sending the site
  262.  * a "ls -l <fName>" and try to get that information from the line it
  263.  * sends us back.  It is possible that we won't be able to determine
  264.  * either of these, though.
  265.  */
  266. long GetDateAndSize(char *fName, time_t *modifTime)
  267. {
  268.     time_t mdtm, ls_mdtm;
  269.     long size, ls_size;
  270.     int have_mdtm, have_size;
  271.  
  272.     size = ls_size = kSizeUnknown;
  273.     mdtm = ls_mdtm = kModTimeUnknown;
  274.     if (fName != NULL) {
  275.         have_mdtm = have_size = 0;
  276.         have_size = ((DoSize(fName, &size)) == 0);
  277.  
  278. #ifdef HAVE_MKTIME
  279.         /* This would use mktime() to un-mangle the reply. */
  280.         have_mdtm = ((DoMdtm(fName, (time_t *) &mdtm)) == 0);
  281. #endif /* HAVE_MKTIME */
  282.  
  283.         if (!have_mdtm || !have_size)
  284.             ls_size = GetDateSizeFromLSLine(fName, &ls_mdtm);
  285.  
  286.         /* Try to use the information from the real SIZE/MDTM commands if
  287.          * we could, since some maverick ftp server may be using a non-standard
  288.          * ls command, and we could parse it wrong.
  289.          */
  290.         
  291.         if (!have_mdtm)
  292.             mdtm = ls_mdtm;
  293.         if (!have_size)
  294.             size = ls_size;
  295.  
  296.         DebugMsg("Used SIZE: %s.  Used MDTM: %s.\n",
  297.             have_size ? "yes" : "no",
  298.             have_mdtm ? "yes" : "no"
  299.         );
  300.  
  301.         if (size != kSizeUnknown)
  302.             DebugMsg("Size: %ld\n", size);
  303.         else
  304.             DebugMsg("Size: ??\n");
  305.         if (mdtm != kModTimeUnknown)
  306.             DebugMsg("Mdtm: %s", ctime(&mdtm));
  307.         else
  308.             DebugMsg("Mdtm: ??\n");
  309.     }
  310.     *modifTime = mdtm;
  311.     return size;
  312. }    /* GetDateAndSize */
  313.