Try to give possible explanations when opening a preview fails

This commit is contained in:
Jean-Francois Dockes 2019-06-15 19:21:52 +02:00
parent e7ba872404
commit dca18bc585
12 changed files with 574 additions and 479 deletions

View File

@ -77,7 +77,8 @@ bool EXEDocFetcher::makesig(RclConfig* cnf, const Rcl::Doc& idoc, string& sig)
}
// Lookup bckid in the config and create an appropriate fetcher.
EXEDocFetcher *exeDocFetcherMake(RclConfig *config, const string& bckid)
std::unique_ptr<EXEDocFetcher> exeDocFetcherMake(RclConfig *config,
const string& bckid)
{
// The config we only read once, not gonna change.
static ConfSimple *bconf;
@ -122,5 +123,5 @@ EXEDocFetcher *exeDocFetcherMake(RclConfig *config, const string& bckid)
" not found in exec path or filters dir\n");
return 0;
}
return new EXEDocFetcher(m);
return std::unique_ptr<EXEDocFetcher>(new EXEDocFetcher(m));
}

View File

@ -17,6 +17,7 @@
#ifndef _EXEFETCHER_H_INCLUDED_
#define _EXEFETCHER_H_INCLUDED_
#include <memory>
#include "fetcher.h"
class RclConfig;
@ -35,6 +36,7 @@ class RclConfig;
* query time for previewing and opening the document.
*/
class EXEDocFetcher : public DocFetcher {
public:
class Internal;
EXEDocFetcher(const Internal&);
virtual ~EXEDocFetcher() {}
@ -42,12 +44,14 @@ class EXEDocFetcher : public DocFetcher {
virtual bool fetch(RclConfig* cnf, const Rcl::Doc& idoc, RawDoc& out);
/** Calls stat to retrieve file signature data */
virtual bool makesig(RclConfig* cnf, const Rcl::Doc& idoc,std::string& sig);
friend EXEDocFetcher *exeDocFetcherMake(RclConfig *, const std::string&);
friend std::unique_ptr<EXEDocFetcher>
exeDocFetcherMake(RclConfig *, const std::string&);
private:
Internal *m;
};
// Lookup bckid in the config and create an appropriate fetcher.
EXEDocFetcher *exeDocFetcherMake(RclConfig *config, const std::string& bckid);
std::unique_ptr<EXEDocFetcher> exeDocFetcherMake(RclConfig *config,
const std::string& bckid);
#endif /* _EXEFETCHER_H_INCLUDED_ */

View File

@ -16,6 +16,8 @@
*/
#include "autoconfig.h"
#include <memory>
#include "log.h"
#include "rclconfig.h"
#include "fetcher.h"
@ -23,22 +25,23 @@
#include "webqueuefetcher.h"
#include "exefetcher.h"
DocFetcher *docFetcherMake(RclConfig *config, const Rcl::Doc& idoc)
std::unique_ptr<DocFetcher> docFetcherMake(RclConfig *config,
const Rcl::Doc& idoc)
{
if (idoc.url.empty()) {
LOGERR("docFetcherMakeg:: no url in doc!\n" );
return 0;
return std::unique_ptr<DocFetcher>();
}
string backend;
idoc.getmeta(Rcl::Doc::keybcknd, &backend);
if (backend.empty() || !backend.compare("FS")) {
return new FSDocFetcher;
return std::unique_ptr<DocFetcher>(new FSDocFetcher);
#ifndef DISABLE_WEB_INDEXER
} else if (!backend.compare("BGL")) {
return new WQDocFetcher;
return std::unique_ptr<DocFetcher>(new WQDocFetcher);
#endif
} else {
DocFetcher *f = exeDocFetcherMake(config, backend);
std::unique_ptr<DocFetcher> f(exeDocFetcherMake(config, backend));
if (!f) {
LOGERR("DocFetcherFactory: unknown backend [" << backend << "]\n");
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2012 J.F.Dockes
/* Copyright (C) 2012-2019 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@ -19,6 +19,7 @@
#include "safesysstat.h"
#include <string>
#include <memory>
#include "rcldoc.h"
@ -45,12 +46,12 @@ class RclConfig;
class DocFetcher {
public:
/** A RawDoc is the data for a document-holding entity either as a
memory block, or pointed to by a file name */
memory block, or pointed to by a file name */
struct RawDoc {
enum RawDocKind {RDK_FILENAME, RDK_DATA, RDK_DATADIRECT};
RawDocKind kind;
std::string data; // Doc data or file name
struct stat st; // Only used if RDK_FILENAME
enum RawDocKind {RDK_FILENAME, RDK_DATA, RDK_DATADIRECT};
RawDocKind kind;
std::string data; // Doc data or file name
struct stat st; // Only used if RDK_FILENAME
};
/**
@ -73,11 +74,16 @@ public:
*/
virtual bool makesig(RclConfig* cnf, const Rcl::Doc& idoc,
std::string& sig) = 0;
enum Reason{FetchOk, FetchNotExist, FetchNoPerm, FetchOther};
virtual Reason testAccess(RclConfig* cnf, const Rcl::Doc& idoc) {
return FetchOther;
}
virtual ~DocFetcher() {}
};
/** Return an appropriate fetcher object given the backend string
* identifier inside idoc*/
DocFetcher *docFetcherMake(RclConfig *config, const Rcl::Doc& idoc);
std::unique_ptr<DocFetcher> docFetcherMake(RclConfig *config,
const Rcl::Doc& idoc);
#endif /* _FETCHER_H_INCLUDED_ */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2012 J.F.Dockes
/* Copyright (C) 2012-2019 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@ -28,31 +28,32 @@
using std::string;
static bool urltopath(RclConfig* cnf,
const Rcl::Doc& idoc, string& fn, struct stat& st)
static DocFetcher::Reason urltopath(RclConfig* cnf, const Rcl::Doc& idoc,
string& fn, struct stat& st)
{
// The url has to be like file://
fn = fileurltolocalpath(idoc.url);
if (fn.empty()) {
LOGERR("FSDocFetcher::fetch/sig: non fs url: [" << (idoc.url) << "]\n" );
return false;
LOGERR("FSDocFetcher::fetch/sig: non fs url: [" << idoc.url << "]\n");
return DocFetcher::FetchOther;
}
cnf->setKeyDir(path_getfather(fn));
bool follow = false;
cnf->getConfParam("followLinks", &follow);
if (path_fileprops(fn, &st, follow) < 0) {
LOGERR("FSDocFetcher::fetch: stat errno " << (errno) << " for [" << (fn) << "]\n" );
return false;
LOGERR("FSDocFetcher::fetch: stat errno " << errno << " for [" << fn
<< "]\n");
return DocFetcher::FetchNotExist;
}
return true;
return DocFetcher::FetchOk;
}
bool FSDocFetcher::fetch(RclConfig* cnf, const Rcl::Doc& idoc, RawDoc& out)
{
string fn;
if (!urltopath(cnf, idoc, fn, out.st))
return false;
if (urltopath(cnf, idoc, fn, out.st) != DocFetcher::FetchOk)
return false;
out.kind = RawDoc::RDK_FILENAME;
out.data = fn;
return true;
@ -62,10 +63,24 @@ bool FSDocFetcher::makesig(RclConfig* cnf, const Rcl::Doc& idoc, string& sig)
{
string fn;
struct stat st;
if (!urltopath(cnf, idoc, fn, st))
return false;
if (urltopath(cnf, idoc, fn, st) != DocFetcher::FetchOk)
return false;
FsIndexer::makesig(&st, sig);
return true;
}
DocFetcher::Reason FSDocFetcher::testAccess(RclConfig* cnf, const Rcl::Doc& idoc)
{
string fn;
struct stat st;
DocFetcher::Reason reason = urltopath(cnf, idoc, fn, st);
if (reason != DocFetcher::FetchOk) {
return reason;
}
if (!path_readable(fn)) {
return DocFetcher::FetchNoPerm;
}
// We have no way to know if the file is fully readable without
// trying (local Windows locks), which would take too much time.
return DocFetcher::FetchOther;
}

View File

@ -28,6 +28,7 @@ class FSDocFetcher : public DocFetcher{
/** Calls stat to retrieve file signature data */
virtual bool makesig(RclConfig* cnf,const Rcl::Doc& idoc, std::string& sig);
virtual DocFetcher::Reason testAccess(RclConfig* cnf, const Rcl::Doc& idoc);
virtual ~FSDocFetcher() {}
};

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2004 J.F.Dockes
/* Copyright (C) 2004-2019 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@ -33,7 +33,7 @@ using std::set;
class RclConfig;
namespace Rcl {
class Doc;
class Doc;
}
class Uncomp;
@ -51,9 +51,9 @@ public:
FIMissingStore(const string& in);
virtual ~FIMissingStore() {}
virtual void addMissing(const string& prog, const string& mt)
{
m_typesForMissing[prog].insert(mt);
}
{
m_typesForMissing[prog].insert(mt);
}
// Get simple progs list string
virtual void getMissingExternal(string& out);
// Get progs + assoc mtypes description string
@ -87,7 +87,7 @@ public:
*
*/
class FileInterner {
public:
public:
/** Operation modifier flags */
enum Flags {FIF_none, FIF_forPreview, FIF_doUseInputMimetype};
/** Return values for internfile() */
@ -115,7 +115,7 @@ class FileInterner {
* mime type for the uncompressed version.
*/
FileInterner(const string &fn, const struct stat *stp,
RclConfig *cnf, int flags, const string *mtype = 0);
RclConfig *cnf, int flags, const string *mtype = 0);
/**
* Alternate constructor for the case where the data is in memory.
@ -138,9 +138,8 @@ class FileInterner {
~FileInterner();
void setMissingStore(FIMissingStore *st)
{
m_missingdatap = st;
void setMissingStore(FIMissingStore *st) {
m_missingdatap = st;
}
/**
@ -160,9 +159,9 @@ class FileInterner {
Status internfile(Rcl::Doc& doc, const string &ipath = "");
/** Extract subdoc defined by ipath in idoc to file. See params for
idocToFile() */
idocToFile() */
bool interntofile(TempFile& otemp, const string& tofile,
const string& ipath, const string& mimetype);
const string& ipath, const string& mimetype);
/** Return the file's (top level object) mimetype (useful for
* creating the pseudo-doc for container files)
@ -181,17 +180,17 @@ class FileInterner {
const string& get_html() {return m_html;}
/** If we happen to be processing an image file and need a temp file,
we keep it around to save work for our caller, which can get it here */
we keep it around to save work for our caller, which can get it here */
TempFile get_imgtmp() {return m_imgtmp;}
const string& getReason() const
{
return m_reason;
}
{
return m_reason;
}
bool ok() const
{
return m_ok;
}
{
return m_ok;
}
/**
* Get UDI for immediate parent for document.
@ -234,7 +233,7 @@ class FileInterner {
* anything for a top level document.
*/
static bool idocToFile(TempFile& temp, const string& tofile,
RclConfig *cnf, const Rcl::Doc& doc,
RclConfig *cnf, const Rcl::Doc& doc,
bool uncompress = true);
/** Does file appear to be the compressed version of a document? */
@ -248,7 +247,14 @@ class FileInterner {
static bool maybeUncompressToTemp(TempFile& temp, const string& fn,
RclConfig *cnf, const Rcl::Doc& doc);
private:
/** Try to get a top level reason after an operation failed. This
* is just for "simple" issues, like file missing, permissions,
* etc. */
enum ErrorPossibleCause{FetchMissing, FetchPerm, FetchNoBackend,
InternfileOther};
static ErrorPossibleCause tryGetReason(RclConfig *, const Rcl::Doc&);
private:
static const unsigned int MAXHANDLERS = 20;
RclConfig *m_cfg;
string m_fn;
@ -287,7 +293,7 @@ class FileInterner {
void init(const string &fn, const struct stat *stp,
RclConfig *cnf, int flags, const string *mtype = 0);
void init(const string &data, RclConfig *cnf, int flags,
const string& mtype);
const string& mtype);
void initcommon(RclConfig *cnf, int flags);
bool dijontorcl(Rcl::Doc&);
@ -298,7 +304,7 @@ class FileInterner {
void checkExternalMissing(const string& msg, const string& mt);
void processNextDocError(Rcl::Doc &doc);
static bool tempFileForMT(TempFile& otemp, RclConfig *cnf,
const std::string& mimetype);
const std::string& mimetype);
static bool topdocToFile(TempFile& otemp, const std::string& tofile,
RclConfig *cnf, const Rcl::Doc& idoc,
bool uncompress);

View File

@ -62,6 +62,7 @@ void LoadThread::run()
} else {
fdoc.mimetype = interner.getMimetype();
mst.getMissingExternal(missing);
explain = FileInterner::tryGetReason(&m_config, m_idoc);
status = -1;
}
} catch (CancelExcept) {

View File

@ -25,6 +25,7 @@
#include "pathut.h"
#include "rclutil.h"
#include "rclconfig.h"
#include "internfile.h"
/*
* A thread to perform the file reading / format conversion work for preview
@ -48,7 +49,8 @@ public:
Rcl::Doc fdoc;
TempFile tmpimg;
std::string missing;
FileInterner::ErrorPossibleCause explain{FileInterner::InternfileOther};
private:
Rcl::Doc m_idoc;
bool m_previewHtml;

View File

@ -643,7 +643,6 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
if (CancelCheck::instance().cancelState())
return false;
if (lthr.status != 0) {
progress.close();
QString explain;
if (!lthr.missing.empty()) {
explain = QString::fromUtf8("<br>") +
@ -655,13 +654,40 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
lthr.fdoc.mimetype.c_str() + explain);
} else {
if (progress.wasCanceled()) {
//QMessageBox::warning(0, "Recoll", tr("Canceled"));
QMessageBox::warning(0, "Recoll", tr("Canceled"));
} else {
QMessageBox::warning(0, "Recoll",
tr("Error while loading file"));
progress.close();
// Note that we can't easily check for a readable file
// because it's possible that only a region is locked
// (e.g. on Windows for an ost file the first block is
// readable even if Outlook is running).
QString msg;
switch (lthr.explain) {
case FileInterner::FetchMissing:
msg = tr("Error loading the document: file missing");
break;
case FileInterner::FetchPerm:
msg = tr("Error loading the document: no permission");
break;
case FileInterner::FetchNoBackend:
msg =
tr("Error loading the document: backend not configured");
break;
case FileInterner::InternfileOther:
#ifdef _WIN32
msg = tr("Error loading the document: other handler error");
#else
msg = tr("Error loading the document: "
"other handler error<br>"
"Maybe the application is locking the file ?");
#endif
break;
}
QMessageBox::warning(0, "Recoll", msg);
}
}
progress.close();
return false;
}
// Reset config just in case.
@ -894,7 +920,7 @@ PreviewTextEdit::PreviewTextEdit(QWidget* parent, const char* nm, Preview *pv)
void PreviewTextEdit::onAnchorClicked(const QUrl& url)
{
LOGDEB("PreviewTextEdit::onAnchorClicked: " << qs2utf8s(url.toString())
<< std::endl);
<< std::endl);
if (prefs.previewActiveLinks && m_preview->m_rclmain) {
Rcl::Doc doc;
doc.url = qs2utf8s(url.toString()).c_str();
@ -1016,4 +1042,3 @@ void PreviewTextEdit::print()
QTextEdit::print(&printer);
#endif
}

View File

@ -0,0 +1,129 @@
/* Copyright (C) 2017-2019 J.F.Dockes
*
* License: GPL 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include "safesysstat.h"
using namespace std;
#include "log.h"
#include "rclinit.h"
#include "internfile.h"
#include "rclconfig.h"
#include "rcldoc.h"
static string thisprog;
static string usage =
" internfile <filename> [ipath]\n"
" \n\n"
;
static void
Usage(void)
{
cerr << thisprog << ": usage:\n" << usage;
exit(1);
}
static int op_flags;
#define OPT_q 0x1
RclConfig *config;
int main(int argc, char **argv)
{
thisprog = argv[0];
argc--; argv++;
while (argc > 0 && **argv == '-') {
(*argv)++;
if (!(**argv))
/* Cas du "adb - core" */
Usage();
while (**argv)
switch (*(*argv)++) {
default: Usage(); break;
}
argc--; argv++;
}
DebugLog::getdbl()->setloglevel(DEBDEB1);
DebugLog::setfilename("stderr");
if (argc < 1)
Usage();
string fn(*argv++);
argc--;
string ipath;
if (argc >= 1) {
ipath.append(*argv++);
argc--;
}
string reason;
config = recollinit(0, 0, 0, reason);
if (config == 0 || !config->ok()) {
string str = "Configuration problem: ";
str += reason;
fprintf(stderr, "%s\n", str.c_str());
exit(1);
}
struct stat st;
if (stat(fn.c_str(), &st)) {
perror("stat");
exit(1);
}
FileInterner interner(fn, &st, config, 0);
Rcl::Doc doc;
FileInterner::Status status = interner.internfile(doc, ipath);
switch (status) {
case FileInterner::FIDone:
case FileInterner::FIAgain:
break;
case FileInterner::FIError:
default:
fprintf(stderr, "internfile failed\n");
exit(1);
}
cout << "doc.url [[[[" << doc.url <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.ipath [[[[" << doc.ipath <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.mimetype [[[[" << doc.mimetype <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.fmtime [[[[" << doc.fmtime <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.dmtime [[[[" << doc.dmtime <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.origcharset [[[[" << doc.origcharset <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.meta[title] [[[[" << doc.meta["title"] <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.meta[keywords] [[[[" << doc.meta["keywords"] <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.meta[abstract] [[[[" << doc.meta["abstract"] <<
"]]]]\n-----------------------------------------------------\n" <<
"doc.text [[[[" << doc.text << "]]]]\n";
}