diff --git a/doc/README.mailcap b/doc/README.mailcap new file mode 100644 index 000000000..366c0d9a1 --- /dev/null +++ b/doc/README.mailcap @@ -0,0 +1,46 @@ +On mailcap support + + (11/07/2000) Okabe Katsuya + okabek@guitar.ocn.ne.jp + (translated from Japanese) + + * Starting with the 10/6/2000 version, w3m follows the mailcap fields + `nametemplate', `needsterminal', `copiousoutput', `edit' (see RFC-1524). + Also, starting with the 10/26/2000 version, the path of mailcap and + mime.types may be set from the option settings panel. + + * In mailcap, the %s is replaced with the path name passed to the external + command, and %t is replaced with the file's content type. + + * When a mailcap entry contains a test=command field, the file will only be + opened if the test command returns true. e.g. if you write + + image/gif; xv '%s'; test=test "$DISPLAY" + + then xv will only be launched if the DISPLAY environment variable is set. + + * When a mailcap entry contains the `copiousoutput' field, the external + command's output is read into a new buffer. + e.g. + + application/x-troff-man;/usr/bin/nroff -mandoc;copiousoutput + + For the most part, this functionality can substitute all uses of LESSOPEN. + Therefore, usage of LESSOPEN has been made optional. + + w3m has an extension called `x-htmloutput'. Just like `copiousoutput', + this reads the command's output into the buffer. The difference is that + `x-htmloutput' renders the output as HTML. For interoperability with other + browsers, it may be best to place entries not containing x-htmloutput before + entries that do contain the flag. + + * nametemplate= specifies the extension of files passed to the external + command. + Normally, when a temporary file is created, the file extension present + in the URL is used. This can be changed using the nametemplate= field. + e.g. + + application/x-dvi;xdvi '%s';test=test -n "$DISPLAY";nametemplate=%s.dvi + + * For the meaning of the `needsterminal' and `edit' fields, please consult + RFC 1524. diff --git a/file.c b/file.c index 9f8e97e30..e8183618c 100644 --- a/file.c +++ b/file.c @@ -1726,6 +1726,7 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, #endif HRequest hr; ParsedURL *volatile auth_pu; + int needs_halfclose = FALSE; tpath = path; prevtrap = NULL; @@ -2283,11 +2284,14 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, #endif frame_source = flag & RG_FRAME_SRC; if (proc == DO_EXTERNAL) { - b = doExternal(f, t, t_buf); + b = doExternal(f, t, t_buf, &needs_halfclose); } else { b = loadSomething(&f, proc, t_buf); } - UFclose(&f); + if (needs_halfclose) + UFhalfclose(&f); + else + UFclose(&f); frame_source = 0; if (b && b != NO_BUFFER) { b->real_scheme = f.scheme; @@ -7999,6 +8003,7 @@ openGeneralPagerBuffer(InputStream stream) char *t = "text/plain"; Buffer *t_buf = NULL; URLFile uf; + int needs_halfclose = FALSE; init_stream(&uf, SCM_UNKNOWN, stream); @@ -8043,8 +8048,11 @@ openGeneralPagerBuffer(InputStream stream) #endif else { if (searchExtViewer(t)) { - buf = doExternal(uf, t, t_buf); - UFclose(&uf); + buf = doExternal(uf, t, t_buf, &needs_halfclose); + if (needs_halfclose) + UFhalfclose(&uf); + else + UFclose(&uf); if (buf == NULL || buf == NO_BUFFER) return buf; } @@ -8185,21 +8193,15 @@ getNextPage(Buffer *buf, int plen) return last; } -int -save2tmp(URLFile uf, char *tmpf) +static int +save2file(URLFile uf, FILE *ff) { - FILE *ff; clen_t linelen = 0, trbyte = 0; MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; static JMP_BUF env_bak; volatile int retval = 0; char *volatile buf = NULL; - ff = fopen(tmpf, "wb"); - if (ff == NULL) { - /* fclose(f); */ - return -1; - } bcopy(AbortLoading, env_bak, sizeof(JMP_BUF)); if (SETJMP(AbortLoading) != 0) { goto _end; @@ -8248,19 +8250,35 @@ save2tmp(URLFile uf, char *tmpf) bcopy(env_bak, AbortLoading, sizeof(JMP_BUF)); TRAP_OFF; xfree(buf); - fclose(ff); current_content_length = 0; return retval; } +int +save2tmp(URLFile uf, char *tmpf) +{ + FILE *ff; + int r; + + ff = fopen(tmpf, "wb"); + if (ff == NULL) { + /* fclose(f); */ + return -1; + } + r = save2file(uf, ff); + fclose(ff); + return r; +} + Buffer * -doExternal(URLFile uf, char *type, Buffer *defaultbuf) +doExternal(URLFile uf, char *type, Buffer *defaultbuf, int *needs_halfclose) { Str tmpf, command; struct mailcap *mcap; - int mc_stat; + int mc_stat, err, background; Buffer *buf = NULL; char *header, *src = NULL, *ext = uf.ext; + FILE *ff; if (!(mcap = searchExtViewer(type))) return NULL; @@ -8279,7 +8297,8 @@ doExternal(URLFile uf, char *type, Buffer *defaultbuf) header = conv_to_system(header); command = unquote_mailcap(mcap->viewer, type, tmpf->ptr, header, &mc_stat); #ifndef __EMX__ - if (!(mc_stat & MCSTAT_REPNAME)) { + if (!(mc_stat & MCSTAT_REPNAME) && + (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT))) { Str tmp = Sprintf("(%s) < %s", command->ptr, shell_quote(tmpf->ptr)); command = tmp; } @@ -8291,18 +8310,35 @@ doExternal(URLFile uf, char *type, Buffer *defaultbuf) flush_tty(); if (!fork()) { setup_child(FALSE, 0, UFfileno(&uf)); - if (save2tmp(uf, tmpf->ptr) < 0) - exit(1); - UFclose(&uf); - myExec(command->ptr); + if (mc_stat & MCSTAT_REPNAME) { + if (save2tmp(uf, tmpf->ptr) < 0) + exit(1); + UFclose(&uf); + myExec(command->ptr); + } + else { + /* no file name needed; we can pipe directly */ + if (!(ff = popen(command->ptr, "w"))) + exit(1); + err = save2file(uf, ff); + pclose(ff); + /* we are in a child process, we can close uf. */ + UFclose(&uf); + exit(-err); /* exit child process */ + } } + if (needs_halfclose) + *needs_halfclose = TRUE; return NO_BUFFER; } else #endif { - if (save2tmp(uf, tmpf->ptr) < 0) { - return NULL; + if ((mc_stat & MCSTAT_REPNAME) || + (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT))) { + if (save2tmp(uf, tmpf->ptr) < 0) { + return NULL; + } } } if (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)) { @@ -8332,16 +8368,30 @@ doExternal(URLFile uf, char *type, Buffer *defaultbuf) } } else { - if (mcap->flags & MAILCAP_NEEDSTERMINAL || !BackgroundExtViewer) { + background = !(mcap->flags & MAILCAP_NEEDSTERMINAL) && + BackgroundExtViewer; + if (!background) fmTerm(); - mySystem(command->ptr, 0); + if (mc_stat & MCSTAT_REPNAME) { + /* saved already */ + mySystem(command->ptr, background); + } + else { + /* either: + * foreground, so we can save2file directly. + * OR background but no setpgrp, in which case we can't do better. + */ + if (!(ff = popen(command->ptr, "w"))) + return NULL; + err = save2file(uf, ff); + pclose(ff); + /* do *not* close uf, it will be closed later. */ + } + if (!background) { fmInit(); if (CurrentTab && Currentbuf) displayBuffer(Currentbuf, B_FORCE_REDRAW); } - else { - mySystem(command->ptr, 1); - } buf = NO_BUFFER; } if (buf && buf != NO_BUFFER) { @@ -8351,6 +8401,8 @@ doExternal(URLFile uf, char *type, Buffer *defaultbuf) buf->edit = mcap->edit; buf->mailcap = mcap; } + if (needs_halfclose) + *needs_halfclose = FALSE; return buf; } diff --git a/proto.h b/proto.h index c833e9f95..261c5355a 100644 --- a/proto.h +++ b/proto.h @@ -283,7 +283,8 @@ extern Buffer *openPagerBuffer(InputStream stream, Buffer *buf); extern Buffer *openGeneralPagerBuffer(InputStream stream); extern Line *getNextPage(Buffer *buf, int plen); extern int save2tmp(URLFile uf, char *tmpf); -extern Buffer *doExternal(URLFile uf, char *type, Buffer *defaultbuf); +extern Buffer *doExternal(URLFile uf, char *type, Buffer *defaultbuf, + int *needs_halfclose); extern int _doFileCopy(char *tmpf, char *defstr, int download); #define doFileCopy(tmpf, defstr) _doFileCopy(tmpf, defstr, FALSE); extern int doFileMove(char *tmpf, char *defstr);