From 2a1ca94403b93235af7ed9332cfdc7fb50379ce5 Mon Sep 17 00:00:00 2001 From: wessels <> Date: Tue, 21 Jul 1998 04:50:37 +0000 Subject: [PATCH] From: Henrik Nordstrom Changed mime.conf (and related C code) to include additional options to make it possible for the user to override mime.conf settings. Primary use is to view a text file that mime.conf says is binary, but it also allows the user do download a binary file that otherwise gets downloaded as ascii (and displayed in the browser). +download show a binary download icon in FTP listings +view show a ascii download icon in FTP listings +download should be set on every mimetype that may be binary files at some locations. +view should be set when it is known that some files may be ascii to make it easier for the users to view these files (like the default mime type). Had to rewrite most of the ftp listing formatting code, but now should it be much easier to maintain. Fixed a minor error in the slash hack. --- src/ftp.cc | 123 +++++++++++++++++++++++++++------------------------ src/mime.cc | 94 +++++++++++++++++++++++---------------- src/protos.h | 2 + 3 files changed, 124 insertions(+), 95 deletions(-) diff --git a/src/ftp.cc b/src/ftp.cc index be093a643a..a48b4c3c9d 100644 --- a/src/ftp.cc +++ b/src/ftp.cc @@ -1,6 +1,6 @@ /* - * $Id: ftp.cc,v 1.238 1998/07/20 22:16:35 wessels Exp $ + * $Id: ftp.cc,v 1.239 1998/07/20 22:50:37 wessels Exp $ * * DEBUG: section 9 File Transfer Protocol (FTP) * AUTHOR: Harvest Derived @@ -564,47 +564,53 @@ dots_fill(size_t len) static char * ftpHtmlifyListEntry(char *line, FtpStateData * ftpState) { - LOCAL_ARRAY(char, link, 2048 + 40); - LOCAL_ARRAY(char, link2, 2048 + 40); 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); size_t width = Config.Ftp.list_width; ftpListParts *parts; + *icon=*href=*text=*size=*chdir=*view=*download=*link=*html='\0'; if ((int) strlen(line) > 1024) { snprintf(html, 8192, "%s\n", line); return html; } /* Handle builtin */ if (!strcmp(line, "")) { + /* {icon} {text} {link} */ snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL("internal-dirup"), "[DIRUP]"); if (!ftpState->flags.no_dotdot && !ftpState->flags.root_dir) { /* Normal directory */ - snprintf(link, 2048, "%s", - "../", - "Parent Directory"); + strcpy(href, "../"); + strcpy(text, "Parent Directory"); } else if (!ftpState->flags.no_dotdot && ftpState->flags.root_dir) { /* "Top level" directory */ - snprintf(link, 2048, "%s (%s)", - "%2e%2e/", - "Parent Directory", + strcpy(href, "%2e%2e/"); + strcpy(text, "Parent Directory"); + snprintf(link, 2048, "(%s)", "%2f/", "Root Directory"); } else if (ftpState->flags.no_dotdot && !ftpState->flags.root_dir) { /* Normal directory where last component is / or .. */ - snprintf(link, 2048, "%s (%s)", - "%2e%2e/", - "Parent Directory", + strcpy(href, "%2e%2e/"); + strcpy(text, "Parent Directory"); + snprintf(link, 2048, "(%s)", "../", - "Up"); + "Back"); } else { /* NO_DOTDOT && ROOT_DIR */ /* "UNIX Root" directory */ - snprintf(link, 2048, "%s", - "../", - "Home Directory"); + strcpy(href, "../"); + strcpy(text, "Home Directory"); } - snprintf(html, 8192, "%s %s\n", icon, link); + snprintf(html, 8192, "%s %s %s\n", + href, icon, href, text, link); return html; } if ((parts = ftpListParseParts(line, ftpState->flags)) == NULL) { @@ -629,69 +635,68 @@ ftpHtmlifyListEntry(char *line, FtpStateData * ftpState) *(parts->showname + width - 0) = '\0'; } } + /* {icon} {text} . . . {date}{size}{chdir}{view}{download}{link}\n */ + xstrncpy(href,rfc1738_escape(parts->name),2048); + xstrncpy(text, parts->showname, 2048); switch (parts->type) { case 'd': - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL("internal-dir"), "[DIR]"); - snprintf(link, 2048, "%s%s", - rfc1738_escape(parts->name), - parts->showname, - dots_fill(strlen(parts->showname))); - snprintf(html, 8192, "%s %s [%s]\n", - icon, - link, - parts->date); + strncat(href, "/", 2048); break; case 'l': - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL("internal-link"), "[LINK]"); - snprintf(link, 2048, "%s%s", - rfc1738_escape(parts->name), - parts->showname, - dots_fill(strlen(parts->showname))); /* sometimes there is an 'l' flag, but no "->" link */ if (parts->link) - snprintf(link2, 2048, "%s", + snprintf(link, 2048, " -> %s", rfc1738_escape(parts->link), parts->link); - snprintf(html, 8192, "%s %s [%s] -> %s\n", - icon, - link, - parts->date, - link2); break; case '\0': - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL(parts->name), "[UNKNOWN]"); - snprintf(link, 2048, "%s", + snprintf(chdir, 2048, " ", rfc1738_escape(parts->name), - parts->name); - snprintf(link2, 2048, "(chdir)", - rfc1738_escape(parts->name)); - snprintf(html, 8192, "%s %s %s\n", - icon, - link, - link2); + mimeGetIconURL("internal-dir")); break; case '-': default: - snprintf(icon, 2048, "\"%-6s\"", + snprintf(icon, 2048, "\"%-6s\"", mimeGetIconURL(parts->name), "[FILE]"); - snprintf(link, 2048, "%s%s", - rfc1738_escape(parts->name), - parts->showname, - dots_fill(strlen(parts->showname))); - snprintf(html, 8192, "%s %s [%s] %6dk\n", - icon, - link, - parts->date, - parts->size); + snprintf(size, 2048, " %6dk", parts->size); break; } + if (parts->type != 'd') { + if (mimeGetViewOption(parts->name)) { + snprintf(view, 2048, " ", + href, mimeGetIconURL("internal-view")); + } + if (mimeGetDownloadOption(parts->name)) { + snprintf(download, 2048, " ", + 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", + href, icon, href, 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", + href, icon, href, text, dots_fill(strlen(text)), + chdir, view, download, link); + } ftpListPartsFree(&parts); return html; } @@ -2074,8 +2079,10 @@ ftpFail(FtpStateData * ftpState) ErrorState *err; debug(9, 3) ("ftpFail\n"); /* Try the / hack to support "Netscape" FTP URL's for retreiving files */ - if (!ftpState->flags.isdir && - !ftpState->flags.try_slash_hack) { + if (!ftpState->flags.isdir && /* Not a directory */ + !ftpState->flags.try_slash_hack && /* Not in slash hack */ + ftpState->mdtm <= 0 && ftpState->size < 0 && /* Not known as a file */ + !strNCaseCmp(ftpState->request->urlpath, "/%2f", 4)) { /* No slash encoded */ switch (ftpState->state) { case SENT_CWD: case SENT_RETR: diff --git a/src/mime.cc b/src/mime.cc index a72c3e030e..014b9e502b 100644 --- a/src/mime.cc +++ b/src/mime.cc @@ -1,6 +1,6 @@ /* - * $Id: mime.cc,v 1.70 1998/07/20 22:42:23 wessels Exp $ + * $Id: mime.cc,v 1.71 1998/07/20 22:50:38 wessels Exp $ * * DEBUG: section 25 MIME Parsing * AUTHOR: Harvest Derived @@ -115,6 +115,7 @@ typedef struct _mime_entry { char *content_type; char *content_encoding; char transfer_mode; + unsigned int view_option:1,download_option:1; struct _mime_entry *next; } mimeEntry; @@ -288,16 +289,34 @@ mime_get_auth(const char *hdr, const char *auth_scheme, const char **auth_field) return base64_decode(t); } -char * -mimeGetIcon(const char *fn) +static mimeEntry * +mimeGetEntry(const char *fn, int skip_encodings) { mimeEntry *m; + char *t; + char *name = xstrdup(fn); +try_again: for (m = MimeTable; m; m = m->next) { - if (m->icon == NULL) - continue; - if (regexec(&m->compiled_pattern, fn, 0, 0, 0) == 0) + if (regexec(&m->compiled_pattern, name, 0, 0, 0) == 0) break; } + if (skip_encodings && m != NULL && !strcmp(m->content_type, dash_str)) { + /* Assume we matched /\.\w$/ and cut off the last extension */ + if ((t = strrchr(name, '.'))) { + *t = '\0'; + goto try_again; + } + /* What? A encoding without a extension? */ + m=NULL; + } + xfree(name); + return m; +} + +char * +mimeGetIcon(const char *fn) +{ + mimeEntry *m = mimeGetEntry(fn, 1); if (m == NULL) return NULL; if (!strcmp(m->icon, dash_str)) @@ -317,25 +336,7 @@ mimeGetIconURL(const char *fn) char * mimeGetContentType(const char *fn) { - mimeEntry *m; - char *name = xstrdup(fn); - char *t; -try_again: - for (m = MimeTable; m; m = m->next) { - if (m->content_type == NULL) - continue; - if (regexec(&m->compiled_pattern, name, 0, 0, 0) == 0) - break; - } - if (!strcmp(m->content_type, dash_str)) { - /* Assume we matched /\.\w$/ and cut off the last extension */ - if ((t = strrchr(name, '.'))) { - *t = '\0'; - goto try_again; - } - /* What? A encoding without a extension? */ - } - xfree(name); + mimeEntry *m = mimeGetEntry(fn, 1); if (m == NULL) return NULL; if (!strcmp(m->content_type, dash_str)) @@ -346,13 +347,7 @@ try_again: char * mimeGetContentEncoding(const char *fn) { - mimeEntry *m; - for (m = MimeTable; m; m = m->next) { - if (m->content_encoding == NULL) - continue; - if (regexec(&m->compiled_pattern, fn, 0, 0, 0) == 0) - break; - } + mimeEntry *m = mimeGetEntry(fn, 0); if (m == NULL) return NULL; if (!strcmp(m->content_encoding, dash_str)) @@ -363,14 +358,24 @@ mimeGetContentEncoding(const char *fn) char mimeGetTransferMode(const char *fn) { - mimeEntry *m; - for (m = MimeTable; m; m = m->next) { - if (regexec(&m->compiled_pattern, fn, 0, 0, 0) == 0) - break; - } + mimeEntry *m = mimeGetEntry(fn, 0); return m ? m->transfer_mode : 'I'; } +int +mimeGetDownloadOption(const char *fn) +{ + mimeEntry *m = mimeGetEntry(fn, 1); + return m ? m->download_option : 0; +} + +int +mimeGetViewOption(const char *fn) +{ + mimeEntry *m = mimeGetEntry(fn, 0); + return m ? m->view_option : 0; +} + void mimeInit(char *filename) { @@ -383,6 +388,9 @@ mimeInit(char *filename) char *type; char *encoding; char *mode; + char *option; + int view_option; + int download_option; regex_t re; mimeEntry *m; int re_flags = REG_EXTENDED | REG_NOSUB | REG_ICASE; @@ -424,6 +432,16 @@ mimeInit(char *filename) debug(25, 1) ("mimeInit: parse error: '%s'\n", buf); continue; } + download_option=0; + view_option=0; + while ((option = strtok(NULL, w_space)) != NULL) { + if (!strcmp(option,"+download")) + download_option = 1; + else if (!strcmp(option,"+view")) + view_option = 1; + else + debug(25, 1) ("mimeInit: unknown option: '%s' (%s)\n", buf, option); + } if (regcomp(&re, pattern, re_flags) != 0) { debug(25, 1) ("mimeInit: regcomp error: '%s'\n", buf); continue; @@ -440,6 +458,8 @@ mimeInit(char *filename) m->transfer_mode = 'A'; else m->transfer_mode = 'I'; + m->view_option = view_option; + m->download_option = download_option; *MimeTableTail = m; MimeTableTail = &m->next; debug(25, 5) ("mimeInit: added '%s'\n", buf); diff --git a/src/protos.h b/src/protos.h index 3a863e584c..1499a09fa5 100644 --- a/src/protos.h +++ b/src/protos.h @@ -520,6 +520,8 @@ extern char *mimeGetContentType(const char *fn); extern char *mimeGetIcon(const char *fn); extern char *mimeGetIconURL(const char *fn); extern char mimeGetTransferMode(const char *fn); +extern int mimeGetDownloadOption(const char *fn); +extern int mimeGetViewOption(const char *fn); extern int mcastSetTtl(int, int); extern IPH mcastJoinGroups; -- 2.47.3