diff --git a/src/ChangeLog b/src/ChangeLog index 324f0b75..d5acdc16 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2000-12-05 Hrvoje Niksic + + * url.c (init_unsafe_char_table): Reinstate space as an unsafe + char. + 2000-11-29 John Summerfield * netrc.c (parse_netrc): Get rid of line ending. diff --git a/src/ftp-basic.c b/src/ftp-basic.c index 1b2680ff..8f6f25e1 100644 --- a/src/ftp-basic.c +++ b/src/ftp-basic.c @@ -541,7 +541,7 @@ ftp_list (struct rbuf *rbuf, const char *file) /* Sends the SYST command to the server. */ uerr_t -ftp_syst (struct rbuf *rbuf, enum stype *host_type) +ftp_syst (struct rbuf *rbuf, enum stype *server_type) { char *request, *respline; int nwritten; @@ -577,12 +577,15 @@ ftp_syst (struct rbuf *rbuf, enum stype *host_type) request = strtok (NULL, " "); if (!strcasecmp (request, "VMS")) - *host_type = ST_VMS; + *server_type = ST_VMS; else if (!strcasecmp (request, "UNIX")) - *host_type = ST_UNIX; + *server_type = ST_UNIX; else - *host_type = ST_OTHER; + if (!strcasecmp (request, "WINDOWS_NT")) + *server_type = ST_WINNT; + else + *server_type = ST_OTHER; xfree (respline); /* All OK. */ diff --git a/src/ftp-ls.c b/src/ftp-ls.c index 61fdfa2a..4f0878f2 100644 --- a/src/ftp-ls.c +++ b/src/ftp-ls.c @@ -76,7 +76,7 @@ symperms (const char *s) The time stamps are stored in a separate variable, time_t compatible (I hope). The timezones are ignored. */ static struct fileinfo * -ftp_parse_unix_ls (const char *file) +ftp_parse_unix_ls (const char *file, int ignore_perms) { FILE *fp; static const char *months[] = { @@ -149,10 +149,28 @@ ftp_parse_unix_ls (const char *file) break; } - cur.perms = symperms (tok + 1); - DEBUGP (("perms %0o; ", cur.perms)); + if (ignore_perms) + { + switch (cur.type) + { + case FT_PLAINFILE: + cur.perms = 420; + break; + case FT_DIRECTORY: + cur.perms = 493; + break; + default: + cur.perms = 1023; + } + DEBUGP (("implicite perms %0o; ", cur.perms)); + } + else + { + cur.perms = symperms (tok + 1); + DEBUGP (("perms %0o; ", cur.perms)); + } - error = ignore = 0; /* Errnoeous and ignoring entries are + error = ignore = 0; /* Erroneous and ignoring entries are treated equally for now. */ year = hour = min = sec = 0; /* Silence the compiler. */ month = day = 0; @@ -385,6 +403,133 @@ ftp_parse_unix_ls (const char *file) return dir; } +static struct fileinfo * +ftp_parse_winnt_ls (const char *file) +{ + FILE *fp; + int len; + int year, month, day; /* for time analysis */ + int hour, min, sec; + struct tm timestruct; + + char *line, *tok; /* tokenizer */ + struct fileinfo *dir, *l, cur; /* list creation */ + + fp = fopen (file, "rb"); + if (!fp) + { + logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); + return NULL; + } + dir = l = NULL; + + /* Line loop to end of file: */ + while ((line = read_whole_line (fp))) + { + DEBUGP (("%s\n", line)); + len = strlen (line); + /* Destroy if present. */ + if (len && line[len - 1] == '\n') + line[--len] = '\0'; + if (len && line[len - 1] == '\r') + line[--len] = '\0'; + + /* Extracting name is a bit of black magic and we have to do it + before `strtok' inserted extra \0 characters in the line + string. For the moment let us just suppose that the name starts at + column 39 of the listing. This way we could also recognize + filenames that begin with a series of space characters (but who + really wants to use such filenames anyway?). */ + if (len < 40) continue; + tok = line + 39; + cur.name = xstrdup(tok); + DEBUGP(("Name: '%s'\n", cur.name)); + + /* First column: mm-dd-yy */ + tok = strtok(line, "-"); + month = atoi(tok); + tok = strtok(NULL, "-"); + day = atoi(tok); + tok = strtok(NULL, " "); + year = atoi(tok); + /* Assuming the epoch starting at 1.1.1970 */ + if (year <= 70) year += 100; + + /* Second column: hh:mm[AP]M */ + tok = strtok(NULL, ":"); + hour = atoi(tok); + tok = strtok(NULL, "M"); + min = atoi(tok); + /* Adjust hour from AM/PM */ + tok+=2; + if (*tok == 'P') hour += 12; + /* Listing does not contain value for seconds */ + sec = 0; + + DEBUGP(("YYYY/MM/DD HH:MM - %d/%02d/%02d %02d:%02d\n", + year+1900, month, day, hour, min)); + + /* Build the time-stamp (copy & paste from above) */ + timestruct.tm_sec = sec; + timestruct.tm_min = min; + timestruct.tm_hour = hour; + timestruct.tm_mday = day; + timestruct.tm_mon = month; + timestruct.tm_year = year; + timestruct.tm_wday = 0; + timestruct.tm_yday = 0; + timestruct.tm_isdst = -1; + cur.tstamp = mktime (×truct); /* store the time-stamp */ + + DEBUGP(("Timestamp: %ld\n", cur.tstamp)); + + /* Third column: Either file length, or . We also set the + permissions (guessed as 0644 for plain files and 0755 for + directories as the listing does not give us a clue) and filetype + here. */ + tok = strtok(NULL, " "); + while (*tok == '\0') tok = strtok(NULL, " "); + if (*tok == '<') + { + cur.type = FT_DIRECTORY; + cur.size = 0; + cur.perms = 493; /* my gcc does not like 0755 ?? */ + DEBUGP(("Directory\n")); + } + else + { + cur.type = FT_PLAINFILE; + cur.size = atoi(tok); + cur.perms = 420; /* 0664 octal */ + DEBUGP(("File, size %ld bytes\n", cur.size)); + } + + cur.linkto = NULL; + + /* And put everything into the linked list */ + if (!dir) + { + l = dir = (struct fileinfo *)xmalloc (sizeof (struct fileinfo)); + memcpy (l, &cur, sizeof (cur)); + l->prev = l->next = NULL; + } + else + { + cur.prev = l; + l->next = (struct fileinfo *)xmalloc (sizeof (struct fileinfo)); + l = l->next; + memcpy (l, &cur, sizeof (cur)); + l->next = NULL; + } + + xfree(line); + } + + fclose(fp); + return dir; +} + + #ifdef HAVE_FTPPARSE /* This is a "glue function" that connects the ftpparse interface to @@ -477,12 +622,31 @@ ftp_parse_nonunix_ls (const char *file) struct fileinfo * ftp_parse_ls (const char *file, const enum stype system_type) { - if (system_type == ST_UNIX) + switch (system_type) { - return ftp_parse_unix_ls (file); + case ST_UNIX: + return ftp_parse_unix_ls (file, FALSE); + case ST_WINNT: + { + /* Detect whether the listing is simulating the UNIX format */ + FILE *fp; + int c; + fp = fopen (file, "rb"); + if (!fp) + { + logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno)); + return NULL; } + c = fgetc(fp); + fclose(fp); + /* If the first character of the file is '0'-'9', it's WINNT + format. */ + if (c >= '0' && c <='9') + return ftp_parse_winnt_ls (file); else - { + return ftp_parse_unix_ls (file, TRUE); + } + default: #ifdef HAVE_FTPPARSE return ftp_parse_nonunix_ls (file); #else diff --git a/src/ftp.c b/src/ftp.c index 46677d6b..8ce71fd6 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -353,6 +353,7 @@ Error in server response, closing control connection.\n")); /* Change working directory. If the FTP host runs VMS and the path specified is absolute, we will have to convert it to VMS style as VMS does not like leading slashes */ + DEBUGP (("changing working directory\n")); if (*(u->dir) == '/') { int pwd_len = strlen (pwd); @@ -375,6 +376,7 @@ Error in server response, closing control connection.\n")); } break; case ST_UNIX: + case ST_WINNT: /* pwd_len == 1 means pwd = "/", but u->dir begins with '/' already */ if (pwd_len > 1) diff --git a/src/ftp.h b/src/ftp.h index 61c72400..0fa0a164 100644 --- a/src/ftp.h +++ b/src/ftp.h @@ -26,6 +26,7 @@ enum stype { ST_UNIX, ST_VMS, + ST_WINNT, ST_OTHER }; diff --git a/src/url.c b/src/url.c index dbd19a82..eea36a10 100644 --- a/src/url.c +++ b/src/url.c @@ -176,6 +176,7 @@ init_unsafe_char_table (void) int i; for (i = 0; i < 256; i++) if (i < 32 || i >= 127 + || i == ' ' || i == '<' || i == '>' || i == '\"'