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", LOGDEB(("RclConfig::getMimeViewerDef: mtype %s apptag %s\n",
mtype.c_str(), apptag.c_str())); mtype.c_str(), apptag.c_str()));
string hs; string hs;
if (mimeview == 0)
return hs;
if (apptag.empty() || !mimeview->get(mtype + string("|") + apptag, if (apptag.empty() || !mimeview->get(mtype + string("|") + apptag,
hs, "view")) hs, "view"))
mimeview->get(mtype, 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) bool RclConfig::setMimeViewerDef(const string& mt, const string& def)
{ {
if (mimeview == 0)
return false;
string pconfname = path_cat(m_confdir, "mimeview"); string pconfname = path_cat(m_confdir, "mimeview");
// Make sure this exists // Make sure this exists
close(open(pconfname.c_str(), O_CREAT|O_WRONLY, 0600)); 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; 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 * Return icon name and path
*/ */

View File

@ -209,6 +209,10 @@ class RclConfig {
string getMimeViewerDef(const string &mimetype, const string& apptag); string getMimeViewerDef(const string &mimetype, const string& apptag);
bool getMimeViewerDefs(vector<pair<string, string> >&); bool getMimeViewerDefs(vector<pair<string, string> >&);
bool setMimeViewerDef(const string& mimetype, const string& cmd); 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 */ /** Store/retrieve missing helpers description string */
string getMissingHelperDesc(); string getMissingHelperDesc();

View File

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

View File

@ -3605,7 +3605,7 @@ x-my-tag = mailmytag
which will override those from the central configuration which will override those from the central configuration
file.</para> file.</para>
<para>Please note that these entries must be placed under a <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 <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 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 all <filename>mimeview</filename> entries will be ignored
except the one labelled <literal>application/x-all</literal> except the one labelled <literal>application/x-all</literal>
(which is set to use <command>xdg-open</command> by default).</para> (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>
<sect2 id="rcl.install.config.examples"> <sect2 id="rcl.install.config.examples">

View File

@ -46,6 +46,7 @@ using namespace std;
#include "fileudi.h" #include "fileudi.h"
#include "beaglequeuecache.h" #include "beaglequeuecache.h"
#include "cancelcheck.h" #include "cancelcheck.h"
#include "copyfile.h"
#ifdef RCL_USE_XATTR #ifdef RCL_USE_XATTR
#include "pxattr.h" #include "pxattr.h"
@ -946,6 +947,110 @@ bool FileInterner::idocToFile(TempFile& otemp, const string& tofile,
return true; 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 #else

View File

@ -156,11 +156,25 @@ class FileInterner {
static bool idocToFile(TempFile& temp, const string& tofile, static bool idocToFile(TempFile& temp, const string& tofile,
RclConfig *cnf, const Rcl::Doc& doc); 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;} const string& getReason() const {return m_reason;}
static void getMissingExternal(string& missing); static void getMissingExternal(string& missing);
static void getMissingDescription(string& desc); static void getMissingDescription(string& desc);
bool ok() {return m_ok;} bool ok() {return m_ok;}
private: private:
static const unsigned int MAXHANDLERS = 20; static const unsigned int MAXHANDLERS = 20;
RclConfig *m_cfg; RclConfig *m_cfg;

View File

@ -1096,6 +1096,32 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
url = string("file://") + fn; 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 // Substitute %xx inside prototype command
string efftime; string efftime;
if (!doc.dmtime.empty() || !doc.fmtime.empty()) { if (!doc.dmtime.empty() || !doc.fmtime.empty()) {
@ -1134,6 +1160,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
if (!istempfile) if (!istempfile)
historyEnterDoc(g_dynconf, doc.meta[Rcl::Doc::keyudi]); historyEnterDoc(g_dynconf, doc.meta[Rcl::Doc::keyudi]);
// We should actually monitor these processes so that we can // We should actually monitor these processes so that we can
// delete the temp files when they exit // delete the temp files when they exit
LOGDEB(("Executing: [%s]\n", ncmd.c_str())); 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 # External viewers, launched by the recoll GUI when you click on a result
# 'edit' link # '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] [view]
# Pseudo entry used if the 'use desktop' preference is set in the GUI # Pseudo entry used if the 'use desktop' preference is set in the GUI
application/x-all = xdg-open %f application/x-all = xdg-open %f