diff --git a/src/common/rclconfig.cpp b/src/common/rclconfig.cpp index cc636eb5..5ecf6307 100644 --- a/src/common/rclconfig.cpp +++ b/src/common/rclconfig.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: rclconfig.cpp,v 1.61 2008-10-07 06:44:23 dockes Exp $ (C) 2004 J.F.Dockes"; +static char rcsid[] = "@(#$Id: rclconfig.cpp,v 1.62 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -42,6 +42,7 @@ static char rcsid[] = "@(#$Id: rclconfig.cpp,v 1.61 2008-10-07 06:44:23 dockes E #include "debuglog.h" #include "smallut.h" #include "textsplit.h" +#include "readfile.h" #ifndef NO_NAMESPACES using namespace std; @@ -454,6 +455,22 @@ string RclConfig::getMimeHandlerDef(const std::string &mtype, bool filtertypes) } return hs; } +string RclConfig::getMissingHelperDesc() +{ + string fmiss = path_cat(getConfDir(), "missing"); + string out; + file_to_string(fmiss, out); + return out; +} +void RclConfig::storeMissingHelperDesc(const string &s) +{ + string fmiss = path_cat(getConfDir(), "missing"); + FILE *fp = fopen(fmiss.c_str(), "w"); + if (fp) { + fwrite(s.c_str(), s.size(), 1, fp); + fclose(fp); + } +} // Read definitions for field prefixes, aliases, and hierarchy and arrange // things for speed (theses are used a lot during indexing) diff --git a/src/common/rclconfig.h b/src/common/rclconfig.h index fc002520..0aed8691 100644 --- a/src/common/rclconfig.h +++ b/src/common/rclconfig.h @@ -16,7 +16,7 @@ */ #ifndef _RCLCONFIG_H_INCLUDED_ #define _RCLCONFIG_H_INCLUDED_ -/* @(#$Id: rclconfig.h,v 1.41 2008-09-16 08:18:30 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: rclconfig.h,v 1.42 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include @@ -161,6 +161,9 @@ class RclConfig { bool getMimeViewerDefs(vector >&); bool setMimeViewerDef(const string& mimetype, const string& cmd); + /** Store/retrieve missing helpers description string */ + string getMissingHelperDesc(); + void storeMissingHelperDesc(const string &s); /** Find exec file for external filter. cmd is the command name from the * command string returned by getMimeHandlerDef */ diff --git a/src/filters/rcldvi b/src/filters/rcldvi index d696c4ad..2ad9fc4b 100755 --- a/src/filters/rcldvi +++ b/src/filters/rcldvi @@ -1,5 +1,5 @@ #!/bin/sh -# @(#$Id: rcldvi,v 1.6 2007-06-08 13:51:08 dockes Exp $ (C) 2006 J.F.Dockes +# @(#$Id: rcldvi,v 1.7 2008-10-08 16:15:22 dockes Exp $ (C) 2006 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 @@ -110,7 +110,7 @@ elif iscmd catdvi ; then fi if test X$decoder = X ; then - senderror NOTFOUND dvips catdvi + senderror HELPERNOTFOUND dvips or catdvi fi if test X$decoder = Xdvips ; then diff --git a/src/index/indexer.cpp b/src/index/indexer.cpp index e4d848b5..75d32904 100644 --- a/src/index/indexer.cpp +++ b/src/index/indexer.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: indexer.cpp,v 1.69 2008-10-04 14:26:59 dockes Exp $ (C) 2004 J.F.Dockes"; +static char rcsid[] = "@(#$Id: indexer.cpp,v 1.70 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -146,12 +146,13 @@ bool DbIndexer::indexDb(bool resetbefore, list *topdirs) m_dbdir.c_str())); return false; } - if (!m_missingExternal.empty()) { - string missing; - stringsToString(m_missingExternal, missing); - LOGINFO(("DbIndexer::index missing helper program(s): %s\n", + string missing; + FileInterner::getMissingDescription(missing); + if (!missing.empty()) { + LOGINFO(("DbIndexer::index missing helper program(s):\n%s\n", missing.c_str())); } + m_config->storeMissingHelperDesc(missing); return true; } @@ -443,9 +444,6 @@ DbIndexer::processone(const std::string &fn, const struct stat *stp, string ipath; fis = interner.internfile(doc, ipath); if (fis == FileInterner::FIError) { - list ext = interner.getMissingExternal(); - m_missingExternal.merge(ext); - m_missingExternal.unique(); // We used to return at this point. // // The nice side was that if a filter failed because of a diff --git a/src/index/indexer.h b/src/index/indexer.h index 34293258..66edac59 100644 --- a/src/index/indexer.h +++ b/src/index/indexer.h @@ -16,7 +16,7 @@ */ #ifndef _INDEXER_H_INCLUDED_ #define _INDEXER_H_INCLUDED_ -/* @(#$Id: indexer.h,v 1.25 2007-08-30 09:01:52 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: indexer.h,v 1.26 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include @@ -146,7 +146,6 @@ class DbIndexer : public FsTreeWalkerCB { Rcl::Db m_db; string m_tmpdir; DbIxStatusUpdater *m_updater; - list m_missingExternal; // Names of missing helper programs bool init(bool rst = false, bool rdonly = false); }; diff --git a/src/internfile/internfile.cpp b/src/internfile/internfile.cpp index b5f92ed6..34784496 100644 --- a/src/internfile/internfile.cpp +++ b/src/internfile/internfile.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: internfile.cpp,v 1.44 2008-10-04 14:26:59 dockes Exp $ (C) 2004 J.F.Dockes"; +static char rcsid[] = "@(#$Id: internfile.cpp,v 1.45 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -49,6 +49,9 @@ using namespace std; static const string isep(":"); static const string stxtplain("text/plain"); +set FileInterner::o_missingExternal; +map > FileInterner::o_typesForMissing; + // This is used when the user wants to retrieve a search result doc's parent // (ie message having a given attachment) bool FileInterner::getEnclosing(const string &url, const string &ipath, @@ -245,35 +248,52 @@ bool FileInterner::dataToTempFile(const string& dt, const string& mt, // See if the error string is formatted as a missing helper message, // accumulate helper name if it is -void FileInterner::checkExternalMissing(const string& msg) +void FileInterner::checkExternalMissing(const string& msg, const string& mt) { if (msg.find("RECFILTERROR") == 0) { list lerr; stringToStrings(msg, lerr); if (lerr.size() > 2) { list::iterator it = lerr.begin(); - it++; + lerr.erase(it++); if (*it == "HELPERNOTFOUND") { - it++; - m_missingExternal.push_back(it->c_str()); + lerr.erase(it++); + string s; + stringsToString(lerr, s); + o_missingExternal.insert(s); + o_typesForMissing[s].insert(mt); } } } } -// Return the list of missing external helper apps that we saw while -// working -const list& FileInterner::getMissingExternal() -{ - m_missingExternal.sort(); - m_missingExternal.unique(); - return m_missingExternal; -} void FileInterner::getMissingExternal(string& out) { - m_missingExternal.sort(); - m_missingExternal.unique(); - stringsToString(m_missingExternal, out); + stringsToString(o_missingExternal, out); +} + +void FileInterner::getMissingDescription(string& out) +{ + out.erase(); + + for (set::const_iterator it = o_missingExternal.begin(); + it != o_missingExternal.end(); it++) { + out += *it; + map >::const_iterator it2; + it2 = o_typesForMissing.find(*it); + if (it2 != o_typesForMissing.end()) { + out += " ("; + set::const_iterator it3; + for (it3 = it2->second.begin(); + it3 != it2->second.end(); it3++) { + out += *it3; + out += string(" "); + } + trimstring(out); + out += ")"; + } + out += "\n"; + } } // Helper for extracting a value from a map. @@ -475,10 +495,10 @@ void FileInterner::processNextDocError(Rcl::Doc &doc, string& ipath) { collectIpathAndMT(doc, ipath); m_reason = m_handlers.back()->get_error(); - checkExternalMissing(m_reason); + checkExternalMissing(m_reason, doc.mimetype); LOGERR(("FileInterner::internfile: next_document error " - "[%s%s%s] %s\n", m_fn.c_str(), ipath.empty() ? "" : "|", - ipath.c_str(), m_reason.c_str())); + "[%s%s%s] %s %s\n", m_fn.c_str(), ipath.empty() ? "" : "|", + ipath.c_str(), doc.mimetype.c_str(), m_reason.c_str())); } FileInterner::Status FileInterner::internfile(Rcl::Doc& doc, string& ipath) diff --git a/src/internfile/internfile.h b/src/internfile/internfile.h index 56836c8b..9753dab0 100644 --- a/src/internfile/internfile.h +++ b/src/internfile/internfile.h @@ -16,12 +16,16 @@ */ #ifndef _INTERNFILE_H_INCLUDED_ #define _INTERNFILE_H_INCLUDED_ -/* @(#$Id: internfile.h,v 1.20 2008-10-04 14:26:59 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: internfile.h,v 1.21 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include +#include +#include using std::string; using std::vector; +using std::map; +using std::set; #include "pathut.h" #include "Filter.h" @@ -95,6 +99,9 @@ class FileInterner { */ void setTargetMType(const string& tp) {m_targetMType = tp;} + /* In case we see an html version, it's set aside and can be recovered */ + const string& get_html() {return m_html;} + /** Utility function: extract internal document into temporary file. * This is used mainly for starting an external viewer for a * subdocument (ie: mail attachment). @@ -110,9 +117,8 @@ class FileInterner { const string& ipath, const string& mtype); const string& getReason() const {return m_reason;} - const list& getMissingExternal(); - void getMissingExternal(string& missing); - const string& get_html() {return m_html;} + static void getMissingExternal(string& missing); + static void getMissingDescription(string& desc); private: static const unsigned int MAXHANDLERS = 20; @@ -135,7 +141,8 @@ class FileInterner { // Error data if any string m_reason; // Missing external programs - list m_missingExternal; + static set o_missingExternal; + static map > o_typesForMissing; void tmpcleanup(); bool dijontorcl(Rcl::Doc&); @@ -143,7 +150,7 @@ class FileInterner { bool dataToTempFile(const string& data, const string& mt, string& fn); void popHandler(); int addHandler(); - void checkExternalMissing(const string& msg); + void checkExternalMissing(const string& msg, const string& mt); void processNextDocError(Rcl::Doc &doc, string& ipath); }; diff --git a/src/qtgui/rclmain.ui b/src/qtgui/rclmain.ui index 9a734c7f..60fef3e2 100644 --- a/src/qtgui/rclmain.ui +++ b/src/qtgui/rclmain.ui @@ -118,6 +118,7 @@ + @@ -137,6 +138,7 @@ + @@ -227,6 +229,14 @@ &Erase document history + + + showMissingHelpers_Action + + + &Show missing helpers + + helpAbout_RecollAction diff --git a/src/qtgui/rclmain_w.cpp b/src/qtgui/rclmain_w.cpp index ec80a691..5594855d 100644 --- a/src/qtgui/rclmain_w.cpp +++ b/src/qtgui/rclmain_w.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: rclmain_w.cpp,v 1.55 2008-09-30 12:38:29 dockes Exp $ (C) 2005 J.F.Dockes"; +static char rcsid[] = "@(#$Id: rclmain_w.cpp,v 1.56 2008-10-08 16:15:22 dockes Exp $ (C) 2005 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -209,6 +209,8 @@ void RclMain::init() this, SLOT(eraseDocHistory())); connect(helpAbout_RecollAction, SIGNAL(activated()), this, SLOT(showAboutDialog())); + connect(showMissingHelpers_Action, SIGNAL(activated()), + this, SLOT(showMissingHelpers())); connect(userManualAction, SIGNAL(activated()), this, SLOT(startManual())); connect(toolsDoc_HistoryAction, SIGNAL(activated()), this, SLOT(showDocHistory())); @@ -579,6 +581,18 @@ void RclMain::showAboutDialog() "
" + "http://www.recoll.org"; QMessageBox::information(this, tr("About Recoll"), vstring.c_str()); } +void RclMain::showMissingHelpers() +{ + string miss = rclconfig->getMissingHelperDesc(); + QString msg = tr("External applications/commands needed and not found " + "for indexing your file types:\n\n"); + if (!miss.empty()) { + msg += QString::fromUtf8(miss.c_str()); + } else { + msg += tr("No helpers found missing"); + } + QMessageBox::information(this, tr("Missing helper programs"), msg); +} // If a preview (toplevel) window gets closed by the user, we need to // clean up because there is no way to reopen it. And check the case diff --git a/src/qtgui/rclmain_w.h b/src/qtgui/rclmain_w.h index 1c7ec6a9..c16f9f19 100644 --- a/src/qtgui/rclmain_w.h +++ b/src/qtgui/rclmain_w.h @@ -82,6 +82,7 @@ public slots: virtual void showSortDialog(); virtual void showSpellDialog(); virtual void showAboutDialog(); + virtual void showMissingHelpers(); virtual void startManual(); virtual void showDocHistory(); virtual void showExtIdxDialog(); diff --git a/src/utils/smallut.cpp b/src/utils/smallut.cpp index f69f6cfd..a17197f9 100644 --- a/src/utils/smallut.cpp +++ b/src/utils/smallut.cpp @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "@(#$Id: smallut.cpp,v 1.33 2008-09-15 08:02:03 dockes Exp $ (C) 2004 J.F.Dockes"; +static char rcsid[] = "@(#$Id: smallut.cpp,v 1.34 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -304,6 +304,10 @@ void stringsToString(const vector &tokens, string &s) { stringsToString >(tokens, s); } +void stringsToString(const set &tokens, string &s) +{ + stringsToString >(tokens, s); +} void stringToTokens(const string& str, list& tokens, const string& delims, bool skipinit) diff --git a/src/utils/smallut.h b/src/utils/smallut.h index f9a2ec0c..2554e3cc 100644 --- a/src/utils/smallut.h +++ b/src/utils/smallut.h @@ -16,17 +16,19 @@ */ #ifndef _SMALLUT_H_INCLUDED_ #define _SMALLUT_H_INCLUDED_ -/* @(#$Id: smallut.h,v 1.30 2008-09-15 08:02:03 dockes Exp $ (C) 2004 J.F.Dockes */ +/* @(#$Id: smallut.h,v 1.31 2008-10-08 16:15:22 dockes Exp $ (C) 2004 J.F.Dockes */ #include #include #include #include +#include #ifndef NO_NAMESPACES using std::string; using std::list; using std::vector; using std::map; +using std::set; #endif /* NO_NAMESPACES */ // Note these are all ascii routines @@ -55,6 +57,7 @@ extern bool stringToStrings(const string &s, vector &tokens); */ extern void stringsToString(const list &tokens, string &s); extern void stringsToString(const vector &tokens, string &s); +extern void stringsToString(const set &tokens, string &s); /** * Split input string. No handling of quoting