From: Amos Jeffries Date: Thu, 6 Nov 2008 13:26:08 +0000 (+1300) Subject: Bug 843: translation should cover FTP Directory Listings as well X-Git-Tag: SQUID_3_2_0_1~1255^2~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=47c9d60ea0f964792caa8356a4a37c1f3523958b;p=thirdparty%2Fsquid.git Bug 843: translation should cover FTP Directory Listings as well Converts the FTP directory listing to using error page templates. Which are translated, HTML strict standards compliant, and CSS styled. --- diff --git a/errors/errorpage.css b/errors/errorpage.css index 449a8ca34e..d7ba8bf0cc 100644 --- a/errors/errorpage.css +++ b/errors/errorpage.css @@ -66,6 +66,16 @@ pre { font-family:sans-serif; } +/* special event: FTP directory listing */ +#ftplisting tr.entry td.icon,td.filename,td.size,td.date { + border-bottom: groove; +} +#ftplisting td.size { + width: 50px; + text-align: right; + padding-right: 5px; +} + /* horizontal lines */ hr { margin: 0; diff --git a/src/MemBuf.h b/src/MemBuf.h index 4da921b3a8..2fff10579e 100644 --- a/src/MemBuf.h +++ b/src/MemBuf.h @@ -72,8 +72,8 @@ public: /** * Whether the buffer contains any data space available. - \retval true if data can be added to teh buffer - \retval false if teh buffer is full + \retval true if data can be added to the buffer + \retval false if the buffer is full */ bool hasSpace() const { return size+1 < capacity; } diff --git a/src/errorpage.cc b/src/errorpage.cc index 97b94105eb..9e333a7f2a 100644 --- a/src/errorpage.cc +++ b/src/errorpage.cc @@ -657,7 +657,10 @@ ErrorState::Convert(char token) case 'g': /* FTP SERVER MESSAGE */ - wordlistCat(ftp.server_msg, &mb); + if(ftp.server_msg) + wordlistCat(ftp.server_msg, &mb); + else if(ftp.listing) + mb.append(ftp.listing); break; @@ -808,6 +811,8 @@ ErrorState::Convert(char token) case 'z': if (dnsserver_msg) p = dnsserver_msg; + else if (ftp.cwd_msg) + p = ftp.cwd_msg; else p = "[unknown]"; diff --git a/src/errorpage.h b/src/errorpage.h index 35e556e6dd..02b15ad91c 100644 --- a/src/errorpage.h +++ b/src/errorpage.h @@ -138,6 +138,8 @@ public: wordlist *server_msg; char *request; char *reply; + char *cwd_msg; + MemBuf *listing; } ftp; char *request_hdrs; diff --git a/src/ftp.cc b/src/ftp.cc index e9463d734b..a452b881ee 100644 --- a/src/ftp.cc +++ b/src/ftp.cc @@ -176,6 +176,7 @@ public: char *old_reply; char *old_filepath; char typecode; + MemBuf listing; // \todo: optimize ctrl and data structs member order, to minimize size /// FTP control channel info; the channel is opened once per transaction @@ -214,8 +215,6 @@ public: void failed(err_type, int xerrno); void failedErrorMessage(err_type, int xerrno); void unhack(); - void listingStart(); - void listingFinish(); void scheduleReadControlReply(int); void handleControlReply(); void readStor(); @@ -567,95 +566,17 @@ FtpStateData::ftpTimeout(const CommTimeoutCbParams &io) void FtpStateData::listingStart() { - debugs(9,3, HERE); - wordlist *w; - char *dirup; - int i, j, k; - const char *title = title_url.buf(); - flags.listing_started = true; - printfReplyBody("\n"); - printfReplyBody("\n", - version_string); - printfReplyBody("\n", mkrfc1123(squid_curtime)); - printfReplyBody("\n"); - { - char *t = xstrdup(title); - rfc1738_unescape(t); - printfReplyBody("FTP Directory: %s\n", html_quote(t)); - xfree(t); - } - - printfReplyBody("\n"); - printfReplyBody("\n"); - - if (flags.need_base_href) - printfReplyBody("\n", - html_quote(base_href.buf())); - - printfReplyBody("\n"); - - if (cwd_message) { - printfReplyBody("
\n");
-
-        for (w = cwd_message; w; w = w->next)
-            printfReplyBody("%s\n", html_quote(w->key));
-
-        printfReplyBody("
\n"); - - printfReplyBody("
\n"); - - wordlistDestroy(&cwd_message); - } - - printfReplyBody("

\n"); - printfReplyBody("FTP Directory: "); - /* "ftp://" == 6 characters */ - assert(title_url.size() >= 6); - k = 6 + strcspn(&title[6], "/"); - - for (i = 6, j = 0; title[i]; j = i) { - printfReplyBody(" j) { - char *url = xstrdup(title); - url[i] = '\0'; - printfReplyBody("%s", html_quote(url + k)); - printfReplyBody("/"); - printfReplyBody("\">"); - rfc1738_unescape(url + j); - printfReplyBody("%s", html_quote(url + j)); - safe_free(url); - printfReplyBody(""); - } - - printfReplyBody("/"); - - if (title[i] == '/') - i++; - - if (i == j) { - /* Error guard, or "assert" */ - printfReplyBody("ERROR: Failed to parse URL: %s\n", - html_quote(title)); - debugs(9, DBG_CRITICAL, "Failed to parse URL: " << title); - break; - } - } - - printfReplyBody("

\n"); - printfReplyBody("
\n");
-    dirup = htmlifyListEntry("");
-    writeReplyBody(dirup, strlen(dirup));
-    flags.html_header_sent = 1;
 }
 
+#if DEAD_CODE // obsoleted by ERR_FTP_LISTING template.
 void
 FtpStateData::listingFinish()
 {
     debugs(9,3,HERE);
     entry->buffer();
-    printfReplyBody("
\n"); +/* + +// TODO: figure out what this means and how to show it ... if (flags.listformat_unknown && !flags.tried_nlst) { printfReplyBody("[As plain directory]\n", @@ -664,15 +585,9 @@ FtpStateData::listingFinish() const char *path = flags.dir_slash ? filepath : "."; printfReplyBody("[As extended directory]\n", rfc1738_escape_part(path)); } - - printfReplyBody("
\n"); - printfReplyBody("
\n"); - printfReplyBody("Generated %s by %s (%s)\n", - mkrfc1123(squid_curtime), - getMyHostname(), - visible_appname_string); - printfReplyBody("
\n"); +*/ } +#endif /* DEAD_CODE */ /// \ingroup ServerProtocolFTPInternal static const char *Month[] = @@ -964,25 +879,24 @@ dots_fill(size_t len) return buf; } -char * +MemBuf * FtpStateData::htmlifyListEntry(const char *line) { - LOCAL_ARRAY(char, icon, 2048); - LOCAL_ARRAY(char, href, 2048 + 40); - LOCAL_ARRAY(char, text, 2048); - LOCAL_ARRAY(char, size, 2048); - LOCAL_ARRAY(char, chdir, 2048 + 40); - LOCAL_ARRAY(char, view, 2048 + 40); - LOCAL_ARRAY(char, download, 2048 + 40); - LOCAL_ARRAY(char, link, 2048 + 40); - LOCAL_ARRAY(char, html, 8192); - LOCAL_ARRAY(char, prefix, 2048); - size_t width = Config.Ftp.list_width; + char icon[2048]; + char href[2048 + 40]; + char text[ 2048]; + char size[ 2048]; + char chdir[ 2048 + 40]; + char view[ 2048 + 40]; + char download[ 2048 + 40]; + char link[ 2048 + 40]; + MemBuf *html; + char prefix[2048]; ftpListParts *parts; *icon = *href = *text = *size = *chdir = *view = *download = *link = *html = '\0'; - if ((int) strlen(line) > 1024) { - snprintf(html, 8192, "%s\n", line); + if (strlen(line) > 1024) { + html->Printf("%s\n", line); return html; } @@ -991,64 +905,10 @@ FtpStateData::htmlifyListEntry(const char *line) else prefix[0] = '\0'; - /* Handle builtin */ - if (strcmp(line, "") == 0) { - /* {icon} {text} {link} */ - snprintf(icon, 2048, "\"%-6s\"", - mimeGetIconURL("internal-dirup"), - "[DIRUP]"); - - if (!flags.no_dotdot && !flags.root_dir) { - /* Normal directory */ - - if (!flags.dir_slash) - strcpy(href, "../"); - else - strcpy(href, "./"); - - strcpy(text, "Parent Directory"); - } else if (!flags.no_dotdot && flags.root_dir) { - /* "Top level" directory */ - strcpy(href, "%2e%2e/"); - strcpy(text, "Parent Directory"); - snprintf(link, 2048, "(%s)", - "%2f/", - "Root Directory"); - } else if (flags.no_dotdot && !flags.root_dir) { - char *url; - /* Normal directory where last component is / or .. */ - strcpy(href, "%2e%2e/"); - strcpy(text, "Parent Directory"); - - if (flags.dir_slash) { - url = xstrdup("./"); - } else { - const char *title = title_url.buf(); - int k = 6 + strcspn(&title[6], "/"); - char *t; - url = xstrdup(title + k); - t = url + strlen(url) - 2; - - while (t > url && *t != '/') - *t-- = '\0'; - } - - snprintf(link, 2048, "(%s)", url, "Back"); - safe_free(url); - } else { /* NO_DOTDOT && ROOT_DIR */ - /* "UNIX Root" directory */ - strcpy(href, "/"); - strcpy(text, "Home Directory"); - } - - snprintf(html, 8192, "%s %s %s\n", - href, icon, href, text, link); - return html; - } - if ((parts = ftpListParseParts(line, flags)) == NULL) { const char *p; - snprintf(html, 8192, "%s\n", line); + html = new MemBuf(); + html->Printf("%s\n", line); for (p = line; *p && xisspace(*p); p++); if (*p && !xisspace(*p)) @@ -1058,9 +918,8 @@ FtpStateData::htmlifyListEntry(const char *line) } if (!strcmp(parts->name, ".") || !strcmp(parts->name, "..")) { - *html = '\0'; ftpListPartsFree(&parts); - return html; + return NULL; } parts->size += 1023; @@ -1082,21 +941,21 @@ FtpStateData::htmlifyListEntry(const char *line) switch (parts->type) { case 'd': - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL("internal-dir"), "[DIR]"); strcat(href, "/"); /* margin is allocated above */ break; case 'l': - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL("internal-link"), "[LINK]"); /* sometimes there is an 'l' flag, but no "->" link */ if (parts->link) { char *link2 = xstrdup(html_quote(rfc1738_escape(parts->link))); - snprintf(link, 2048, " -> %s", + snprintf(link, 2048, " -> %s", *link2 != '/' ? prefix : "", link2, html_quote(parts->link)); safe_free(link2); @@ -1105,11 +964,11 @@ FtpStateData::htmlifyListEntry(const char *line) break; case '\0': - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL(parts->name), "[UNKNOWN]"); - snprintf(chdir, 2048, " ", + snprintf(chdir, 2048, "", rfc1738_escape_part(parts->name), mimeGetIconURL("internal-dir")); break; @@ -1117,7 +976,7 @@ FtpStateData::htmlifyListEntry(const char *line) case '-': default: - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL(parts->name), "[FILE]"); snprintf(size, 2048, " %6"PRId64"k", parts->size); @@ -1126,31 +985,32 @@ FtpStateData::htmlifyListEntry(const char *line) if (parts->type != 'd') { if (mimeGetViewOption(parts->name)) { - snprintf(view, 2048, " ", + snprintf(view, 2048, "", prefix, href, mimeGetIconURL("internal-view")); } if (mimeGetDownloadOption(parts->name)) { - snprintf(download, 2048, " ", + snprintf(download, 2048, "", prefix, href, mimeGetIconURL("internal-download")); } } - /* {icon} {text} . . . {date}{size}{chdir}{view}{download}{link}\n */ - if (parts->type != '\0') { - snprintf(html, 8192, "%s %s%s " - "%s%8s%s%s%s%s\n", - prefix, href, icon, prefix, href, html_quote(text), dots_fill(strlen(text)), - parts->date, size, chdir, view, download, link); - } else { - /* Plain listing. {icon} {text} ... {chdir}{view}{download} */ - snprintf(html, 8192, "%s %s%s " - "%s%s%s%s\n", - prefix, href, icon, prefix, href, html_quote(text), dots_fill(strlen(text)), - chdir, view, download, link); - } + /* construct the table row from parts. */ + html = new MemBuf(); + html->Printf("" + "%s" + "%s" + "%s" + "%s" + "%s%s%s%s" + "\n", + prefix, href, icon, + prefix, href, html_quote(text), + parts->date, + size, + chdir, view, download, link); ftpListPartsFree(&parts); return html; @@ -1222,9 +1082,9 @@ FtpStateData::parseListing() t = htmlifyListEntry(line); - assert(t != NULL); - - writeReplyBody(t, strlen(t)); + if( t != NULL) { + listing.append(t->content(), t->contentSize()); + } } data.readBuf->consume(usable); @@ -1416,11 +1276,28 @@ FtpStateData::processReplyBody() #endif - if (flags.isdir && !flags.listing_started) - listingStart(); - if (flags.isdir) { + +/* +// TODO: do we still need this in header? + if (flags.need_base_href) + printfReplyBody("\n", html_quote(base_href.buf())); +*/ + + if (cwd_message) { + String tmp; + for (wordlist *w = cwd_message; w; w = w->next) { + tmp.append(html_quote(w->key)); + tmp.append("\n"); + } + err_message = xstrdup(tmp.buf()); + } + + flags.html_header_sent = 1; + parseListing(); + return; + } else if (const int csize = data.readBuf->contentSize()) { writeReplyBody(data.readBuf->content(), csize); @@ -3325,8 +3202,7 @@ ftpReadTransferDone(FtpStateData * ftpState) /* Connection closed; retrieval done. */ if (ftpState->flags.html_header_sent) - ftpState->listingFinish(); - + ftpState->failed(ERR_FTP_LISTING, 0); ftpSendQuit(ftpState); } else { /* != 226 */ debugs(9, DBG_IMPORTANT, HERE << "Got code " << code << " after reading data"); @@ -3554,9 +3430,14 @@ FtpStateData::failedErrorMessage(err_type error, int xerrno) err->xerrno = xerrno; - err->ftp.server_msg = ctrl.message; + if(error == ERR_FTP_LISTING) { + err->ftp.listing = &listing; + } + else { + err->ftp.server_msg = ctrl.message; + ctrl.message = NULL; + } - ctrl.message = NULL; if (old_request) command = old_request;