uncompress file before starting external viewer except if in the nouncompforviewmts list

This commit is contained in:
Jean-Francois Dockes 2010-09-20 10:35:26 +02:00
parent 8b1797b4a5
commit ad4f24923f
8 changed files with 180 additions and 2 deletions

View File

@ -721,6 +721,8 @@ string RclConfig::getMimeViewerDef(const string &mtype, const string& apptag)
LOGDEB(("RclConfig::getMimeViewerDef: mtype %s apptag %s\n",
mtype.c_str(), apptag.c_str()));
string hs;
if (mimeview == 0)
return hs;
if (apptag.empty() || !mimeview->get(mtype + string("|") + apptag,
hs, "view"))
mimeview->get(mtype, hs, "view");
@ -740,6 +742,8 @@ bool RclConfig::getMimeViewerDefs(vector<pair<string, string> >& defs)
bool RclConfig::setMimeViewerDef(const string& mt, const string& def)
{
if (mimeview == 0)
return false;
string pconfname = path_cat(m_confdir, "mimeview");
// Make sure this exists
close(open(pconfname.c_str(), O_CREAT|O_WRONLY, 0600));
@ -763,6 +767,17 @@ bool RclConfig::setMimeViewerDef(const string& mt, const string& def)
return true;
}
bool RclConfig::mimeViewerNeedsUncomp(const string &mimetype)
{
string s;
vector<string> v;
if (mimeview != 0 && mimeview->get("nouncompforviewmts", s, "") &&
stringToStrings(s, v) &&
find_if(v.begin(), v.end(), StringIcmpPred(mimetype)) != v.end())
return false;
return true;
}
/**
* Return icon name and path
*/

View File

@ -209,6 +209,10 @@ class RclConfig {
string getMimeViewerDef(const string &mimetype, const string& apptag);
bool getMimeViewerDefs(vector<pair<string, string> >&);
bool setMimeViewerDef(const string& mimetype, const string& cmd);
/** Check if mime type is designated as needing no uncompress before view
* (if a file of this type is found compressed). Default is true,
* exceptions are found in the nouncompforviewmts mimeview list */
bool mimeViewerNeedsUncomp(const string &mimetype);
/** Store/retrieve missing helpers description string */
string getMissingHelperDesc();

View File

@ -1,7 +1,7 @@
#!/bin/sh
while true;do
make FORMATS=html
make FORMATS="html html-split"
cp *.html /usr/local/www/lesbonscomptes/recoll/usermanual/
sleep 1
done

View File

@ -3605,7 +3605,7 @@ x-my-tag = mailmytag
which will override those from the central configuration
file.</para>
<para>Please note that these entries must be placed under a
<literal>[view]</literal> section.</para>
<literal>[view]</literal> section.</para>
<para>The keys in the file are normally mime types. You can add an
application tag to specialize the choice for an area of the
@ -3618,6 +3618,14 @@ x-my-tag = mailmytag
all <filename>mimeview</filename> entries will be ignored
except the one labelled <literal>application/x-all</literal>
(which is set to use <command>xdg-open</command> by default).</para>
<para>The <literal>nouncompforviewmts</literal> entry, (placed at
the top level, outside of the <literal>[view]</literal> section),
holds a list of mime types that should not be uncompressed before
starting the viewer (if they are found compressed, ie:
<replaceable>mydoc.doc.gz</replaceable>).</para>
</sect2>
<sect2 id="rcl.install.config.examples">

View File

@ -46,6 +46,7 @@ using namespace std;
#include "fileudi.h"
#include "beaglequeuecache.h"
#include "cancelcheck.h"
#include "copyfile.h"
#ifdef RCL_USE_XATTR
#include "pxattr.h"
@ -946,6 +947,110 @@ bool FileInterner::idocToFile(TempFile& otemp, const string& tofile,
return true;
}
bool FileInterner::isCompressed(const string& fn, RclConfig *cnf)
{
LOGDEB(("FileInterner::isCompressed: [%s]\n", fn.c_str()));
struct stat st;
if (stat(fn.c_str(), &st) < 0) {
LOGERR(("FileInterner::isCompressed: can't stat [%s]\n", fn.c_str()));
return false;
}
string l_mime = mimetype(fn, &st, cnf, true);
if (l_mime.empty()) {
LOGERR(("FileInterner::isUncompressed: can't get mime for [%s]\n",
fn.c_str()));
return false;
}
list<string>ucmd;
if (cnf->getUncompressor(l_mime, ucmd)) {
return true;
}
return false;
}
bool FileInterner::maybeUncompressToTemp(TempFile& temp, const string& fn,
RclConfig *cnf, const Rcl::Doc& doc)
{
LOGDEB(("FileInterner::maybeUncompressToTemp: [%s]\n", fn.c_str()));
struct stat st;
if (stat(fn.c_str(), &st) < 0) {
LOGERR(("FileInterner::maybeUncompressToTemp: can't stat [%s]\n",
fn.c_str()));
return false;
}
string l_mime = mimetype(fn, &st, cnf, true);
if (l_mime.empty()) {
LOGERR(("FileInterner::maybeUncompress.: can't id. mime for [%s]\n",
fn.c_str()));
return false;
}
list<string>ucmd;
if (!cnf->getUncompressor(l_mime, ucmd)) {
return true;
}
// Check for compressed size limit
int maxkbs = -1;
if (cnf->getConfParam("compressedfilemaxkbs", &maxkbs) &&
maxkbs >= 0 && int(st.st_size / 1024) > maxkbs) {
LOGINFO(("FileInterner:: %s over size limit %d kbs\n",
fn.c_str(), maxkbs));
return false;
}
TempDir tmpdir;
temp =
TempFile(new TempFileInternal(cnf->getSuffixFromMimeType(doc.mimetype)));
if (!tmpdir.ok() || !temp->ok()) {
LOGERR(("FileInterner: cant create temporary file/dir"));
return false;
}
// uncompressfile choses the output file name, there is good
// reason for this, but it's not nice here. Have to copy or rename
// the uncompressed file
string uncomped;
if (!uncompressfile(cnf, fn, ucmd, tmpdir, uncomped)) {
return false;
}
// uncompressfile choses the output file name, there is good
// reason for this, but it's not nice here. Have to copy or rename
// the uncompressed file.
// Hopefully the cross-dev case won't happen as we're
// probably choosing the temp names in the same dir. However...
// Unix really should have a rename-else-copy call...
if (stat(temp->filename(), &st) < 0) {
LOGERR(("FileInterner::maybeUncompressToTemp: can't stat [%s]\n",
temp->filename()));
return false;
}
struct stat st1;
if (stat(uncomped.c_str(), &st1) < 0) {
LOGERR(("FileInterner::maybeUncompressToTemp: can't stat [%s]\n",
uncomped.c_str()));
return false;
}
if (st.st_dev == st1.st_dev) {
if (rename(uncomped.c_str(), temp->filename()) < 0) {
LOGERR(("FileInterner::maybeUncompress: rename [%s] -> [%s]"
"failed, errno %d\n",
uncomped.c_str(), temp->filename(), errno));
return false;
}
} else {
string reason;
bool ret = copyfile(uncomped.c_str(), temp->filename(), reason);
if (ret == false) {
LOGERR(("FileInterner::maybeUncompress: copy [%s] -> [%s]"
"failed: %s\n",
uncomped.c_str(), temp->filename(), reason.c_str()));
return false;
}
// We let the tempdir cleanup get rid of uncomped
}
return true;
}
#else

View File

@ -156,11 +156,25 @@ class FileInterner {
static bool idocToFile(TempFile& temp, const string& tofile,
RclConfig *cnf, const Rcl::Doc& doc);
/**
* Does file appear to be the compressed version of a document?
*/
static bool isCompressed(const string& fn, RclConfig *cnf);
/**
* Check input compressed, allocate temp file and uncompress if it is.
* @return true if ok, false for error. Actual decompression is indicated
* by the TempFile status (!isNull())
*/
static bool maybeUncompressToTemp(TempFile& temp, const string& fn,
RclConfig *cnf, const Rcl::Doc& doc);
const string& getReason() const {return m_reason;}
static void getMissingExternal(string& missing);
static void getMissingDescription(string& desc);
bool ok() {return m_ok;}
private:
static const unsigned int MAXHANDLERS = 20;
RclConfig *m_cfg;

View File

@ -1096,6 +1096,32 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
url = string("file://") + fn;
}
// If using an actual file, check that it exists, and if it is
// compressed, we may need an uncompressed version
if (!fn.empty() && rclconfig->mimeViewerNeedsUncomp(doc.mimetype)) {
if (access(fn.c_str(), R_OK) != 0) {
QMessageBox::warning(0, "Recoll",
tr("Can't access file: ") +
QString::fromLocal8Bit(fn.c_str()));
return;
}
TempFile temp;
if (FileInterner::isCompressed(fn, rclconfig)) {
if (!FileInterner::maybeUncompressToTemp(temp, fn, rclconfig,
doc)) {
QMessageBox::warning(0, "Recoll",
tr("Can't uncompress file: ") +
QString::fromLocal8Bit(fn.c_str()));
return;
}
}
if (!temp.isNull()) {
m_tempfiles.push_back(temp);
fn = temp->filename();
url = string("file://") + fn;
}
}
// Substitute %xx inside prototype command
string efftime;
if (!doc.dmtime.empty() || !doc.fmtime.empty()) {
@ -1134,6 +1160,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
if (!istempfile)
historyEnterDoc(g_dynconf, doc.meta[Rcl::Doc::keyudi]);
// We should actually monitor these processes so that we can
// delete the temp files when they exit
LOGDEB(("Executing: [%s]\n", ncmd.c_str()));

View File

@ -4,6 +4,11 @@
# External viewers, launched by the recoll GUI when you click on a result
# 'edit' link
# Mime types which we should not uncompress if they are found gzipped or
# bzipped because the native viewer knows how to handle. These would be
# exceptions and the list is normally empty
#nouncompforviewmts =
[view]
# Pseudo entry used if the 'use desktop' preference is set in the GUI
application/x-all = xdg-open %f