merged branch 1.25 fixes

This commit is contained in:
Jean-Francois Dockes 2019-08-09 11:54:39 +02:00
commit d4c099ab59
31 changed files with 1583 additions and 1145 deletions

View File

@ -112,10 +112,10 @@ overriden in the c++ code by ifdefs _WIN32 anyway */
#define PACKAGE_NAME "Recoll"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Recoll 1.25.19"
#define PACKAGE_STRING "Recoll 1.25.21"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.25.19"
#define PACKAGE_VERSION "1.25.21"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "recoll"

View File

@ -1559,6 +1559,9 @@ vector<string> RclConfig::getSkippedPaths() const
// don't do this.
skpl.push_back(getDbDir());
skpl.push_back(getConfDir());
#ifdef _WIN32
skpl.push_back(TempFile::rcltmpdir());
#endif
if (getCacheDir().compare(getConfDir())) {
skpl.push_back(getCacheDir());
}

View File

@ -92,11 +92,11 @@ alink="#0000FF">
"#RCL.INDEXING.INTRODUCTION.CONFIG">Configurations,
multiple indexes</a></span></dt>
<dt><span class="sect2">2.1.3. <a href=
"#idm218">Document types</a></span></dt>
"#idm233">Document types</a></span></dt>
<dt><span class="sect2">2.1.4. <a href=
"#idm259">Indexing failures</a></span></dt>
"#idm274">Indexing failures</a></span></dt>
<dt><span class="sect2">2.1.5. <a href=
"#idm271">Recovery</a></span></dt>
"#idm286">Recovery</a></span></dt>
</dl>
</dd>
<dt><span class="sect1">2.2. <a href=
@ -851,10 +851,10 @@ alink="#0000FF">
</div>
<p><span class="application">Recoll</span> supports
defining multiple indexes, each defined by its own
<a class="link" href="#RCL.INDEXING.CONFIG" title=
"2.3.&nbsp;Index configuration">configuration
directory</a>, in which several configuration files
describe what should be indexed and how.</p>
configuration directory. A configuration directory
contains <a class="link" href="#RCL.INDEXING.CONFIG"
title="2.3.&nbsp;Index configuration">several files</a>
which describe what should be indexed and how.</p>
<p>When <span class=
"command"><strong>recoll</strong></span> or <span class=
"command"><strong>recollindex</strong></span> is first
@ -864,14 +864,14 @@ alink="#0000FF">
is located in <code class=
"filename">$HOME/.recoll/</code> for <span class=
"application">Unix</span>-like systems and <code class=
"filename">%LOCALAPPDATA%</code> on <span class=
"filename">%LOCALAPPDATA%\Recoll</code> on <span class=
"application">Windows</span> (typically <code class=
"filename">C:\Users\[me]\Appdata\Local</code>).</p>
"filename">C:\Users\[me]\Appdata\Local\Recoll</code>).</p>
<p>All configuration parameters have defaults, defined in
system-wide files. Without further customisation, the
default configuration will process your complete home
directory, with a reasonable set of defaults. It can be
changed to process a different area of the file system,
adjusted to process a different area of the file system,
select files in different ways, and many other
things.</p>
<p>In some cases, it may be useful to create additional
@ -879,6 +879,35 @@ alink="#0000FF">
personal and shared indexes, or to take advantage of the
organization of your data to improve search
precision.</p>
<p>In order to do this, you would create an empty
directory in a location of your choice, and then instruct
<span class="command"><strong>recoll</strong></span> or
<span class="command"><strong>recollindex</strong></span>
to use it by setting either a command line option
(<code class="literal">-c</code> <em class=
"replaceable"><code>/some/directory</code></em>), or an
environment variable (<code class=
"envar">RECOLL_CONFDIR</code>=<em class=
"replaceable"><code>/some/directory</code></em>). Any
modification performed by the commands (e.g.
configuration customisation or searches by <span class=
"command"><strong>recoll</strong></span> or index
creation by <span class=
"command"><strong>recollindex</strong></span>) would then
apply to the new directory and not to the default
one.</p>
<p>Once multiple indexes are created, you can use each of
them separately by setting the <code class=
"literal">-c</code> option or the <code class=
"envar">RECOLL_CONFDIR</code> environment variable when
starting a command, to select the desired index.</p>
<p>It is also possible to instruct one configuration to
query one or several other indexes in addition to its
own, by using the <span class="guimenuitem">External
index</span> function in the <span class=
"command"><strong>recoll</strong></span> GUI, or some
other functions in the command line and programming
tools.</p>
<p>A plausible usage scenario for the multiple index
feature would be for a system administrator to set up a
central index for shared data, that you choose to search
@ -904,8 +933,8 @@ alink="#0000FF">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="idm218" id=
"idm218"></a>2.1.3.&nbsp;Document types</h3>
<h3 class="title"><a name="idm233" id=
"idm233"></a>2.1.3.&nbsp;Document types</h3>
</div>
</div>
</div>
@ -1002,8 +1031,8 @@ alink="#0000FF">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="idm259" id=
"idm259"></a>2.1.4.&nbsp;Indexing failures</h3>
<h3 class="title"><a name="idm274" id=
"idm274"></a>2.1.4.&nbsp;Indexing failures</h3>
</div>
</div>
</div>
@ -1038,8 +1067,8 @@ alink="#0000FF">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a name="idm271" id=
"idm271"></a>2.1.5.&nbsp;Recovery</h3>
<h3 class="title"><a name="idm286" id=
"idm286"></a>2.1.5.&nbsp;Recovery</h3>
</div>
</div>
</div>
@ -1390,8 +1419,8 @@ alink="#0000FF">
<div class="titlepage">
<div>
<div>
<h4 class="title"><a name="idm392" id=
"idm392"></a>In practise: creating and using an
<h4 class="title"><a name="idm407" id=
"idm407"></a>In practise: creating and using an
additional index</h4>
</div>
</div>

View File

@ -377,22 +377,23 @@
<title>Configurations, multiple indexes</title>
<para>&RCL; supports defining multiple indexes, each defined by its
own <link linkend="RCL.INDEXING.CONFIG">configuration directory</link>,
in which several configuration files describe
what should be indexed and how.</para>
own configuration directory. A configuration directory contains
<link linkend="RCL.INDEXING.CONFIG">several files</link> which
describe what should be indexed and how.</para>
<para>When <command>recoll</command> or
<command>recollindex</command> is first executed, it creates a
default configuration directory. This configuration is the one used
for indexing and querying when no specific configuration is
specified. It is located in <filename>$HOME/.recoll/</filename> for
&LIN; and <filename>%LOCALAPPDATA%</filename> on &WIN;
(typically <filename>C:\Users\[me]\Appdata\Local</filename>).</para>
&LIN; and <filename>%LOCALAPPDATA%\Recoll</filename> on &WIN;
(typically
<filename>C:\Users\[me]\Appdata\Local\Recoll</filename>).</para>
<para>All configuration parameters have defaults, defined in
system-wide files. Without further customisation, the default
configuration will process your complete home directory, with a
reasonable set of defaults. It can be changed to process a
reasonable set of defaults. It can be adjusted to process a
different area of the file system, select files in different ways,
and many other things.</para>
@ -401,6 +402,29 @@
shared indexes, or to take advantage of the organization of your
data to improve search precision.</para>
<para>In order to do this, you would create an empty directory in a
location of your choice, and then instruct
<command>recoll</command> or <command>recollindex</command> to use
it by setting either a command line option (<literal>-c</literal>
<replaceable>/some/directory</replaceable>), or an environment
variable
(<envar>RECOLL_CONFDIR</envar>=<replaceable>/some/directory</replaceable>).
Any modification performed by the commands (e.g. configuration
customisation or searches by <command>recoll</command> or index
creation by <command>recollindex</command>) would then apply to the
new directory and not to the default one.</para>
<para>Once multiple indexes are created, you can use each of them
separately by setting the <literal>-c</literal> option or the
<envar>RECOLL_CONFDIR</envar> environment variable when starting a
command, to select the desired index.</para>
<para>It is also possible to instruct one configuration to
query one or several other indexes in addition to its own, by using
the <guimenuitem>External index</guimenuitem> function in the
<command>recoll</command> GUI, or some other functions in the
command line and programming tools.</para>
<para>A plausible usage scenario for the multiple index feature
would be for a system administrator to set up a central index for
shared data, that you choose to search or not in addition to your

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2005 J.F.Dockes
/* Copyright (C) 2005-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
@ -14,302 +14,34 @@
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef TEST_MH_MBOX
#include "autoconfig.h"
#include <stdio.h>
#include "autoconfig.h"
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <sys/types.h>
#include "safesysstat.h"
#include <time.h>
#include <cstring>
#include <map>
#include <mutex>
#include <fstream>
#include "cstr.h"
#include "mimehandler.h"
#include "log.h"
#include "readfile.h"
#include "mh_mbox.h"
#include "smallut.h"
#include "rclconfig.h"
#include "md5ut.h"
#include "conftree.h"
#include "pathut.h"
using namespace std;
// Define maximum message size for safety. 100MB would seem reasonable
static const unsigned int max_mbox_member_size = 100 * 1024 * 1024;
class FpKeeper {
public:
FpKeeper(FILE **fpp) : m_fpp(fpp) {}
~FpKeeper()
{
if (m_fpp && *m_fpp) {
fclose(*m_fpp);
*m_fpp = 0;
}
}
private: FILE **m_fpp;
};
static std::mutex o_mcache_mutex;
/**
* Handles a cache for message numbers to offset translations. Permits direct
* accesses inside big folders instead of having to scan up to the right place
*
* Message offsets are saved to files stored under cfg(mboxcachedir), default
* confdir/mboxcache. Mbox files smaller than cfg(mboxcacheminmbs) are not
* cached.
* Cache files are named as the md5 of the file UDI, which is kept in
* the first block for possible collision detection. The 64 bits
* offsets for all message "From_" lines follow. The format is purely
* binary, values are not even byte-swapped to be proc-idependant.
*/
#ifdef _WIN32
// vc++ does not let define an array of size o_b1size because non-const??
#define M_o_b1size 1024
#else
#define M_o_b1size o_b1size
#endif
class MboxCache {
public:
typedef MimeHandlerMbox::mbhoff_type mbhoff_type;
MboxCache()
: m_ok(false), m_minfsize(0)
{
// Can't access rclconfig here, we're a static object, would
// have to make sure it's initialized.
}
~MboxCache() {}
mbhoff_type get_offset(RclConfig *config, const string& udi, int msgnum)
{
LOGDEB0("MboxCache::get_offsets: udi [" << (udi) << "] msgnum " << (msgnum) << "\n");
if (!ok(config)) {
LOGDEB0("MboxCache::get_offsets: init failed\n");
return -1;
}
std::unique_lock<std::mutex> locker(o_mcache_mutex);
string fn = makefilename(udi);
FILE *fp = 0;
if ((fp = fopen(fn.c_str(), "r")) == 0) {
LOGDEB("MboxCache::get_offsets: open failed, errno " << (errno) << "\n");
return -1;
}
FpKeeper keeper(&fp);
char blk1[M_o_b1size];
if (fread(blk1, 1, o_b1size, fp) != o_b1size) {
LOGDEB0("MboxCache::get_offsets: read blk1 errno " << (errno) << "\n");
return -1;
}
ConfSimple cf(string(blk1, o_b1size));
string fudi;
if (!cf.get("udi", fudi) || fudi.compare(udi)) {
LOGINFO("MboxCache::get_offset:badudi fn " << (fn) << " udi [" << (udi) << "], fudi [" << (fudi) << "]\n");
return -1;
}
if (fseeko(fp, cacheoffset(msgnum), SEEK_SET) != 0) {
LOGDEB0("MboxCache::get_offsets: seek " << (lltodecstr(cacheoffset(msgnum))) << " errno " << (errno) << "\n");
return -1;
}
mbhoff_type offset = -1;
size_t ret;
if ((ret = fread(&offset, 1, sizeof(mbhoff_type), fp))
!= sizeof(mbhoff_type)) {
LOGDEB0("MboxCache::get_offsets: read ret " << (ret) << " errno " << (errno) << "\n");
return -1;
}
LOGDEB0("MboxCache::get_offsets: ret " << (lltodecstr(offset)) << "\n");
return offset;
}
// Save array of offsets for a given file, designated by Udi
void put_offsets(RclConfig *config, const string& udi, mbhoff_type fsize,
vector<mbhoff_type>& offs)
{
LOGDEB0("MboxCache::put_offsets: " << (offs.size()) << " offsets\n");
if (!ok(config) || !maybemakedir())
return;
if (fsize < m_minfsize)
return;
std::unique_lock<std::mutex> locker(o_mcache_mutex);
string fn = makefilename(udi);
FILE *fp;
if ((fp = fopen(fn.c_str(), "w")) == 0) {
LOGDEB("MboxCache::put_offsets: fopen errno " << (errno) << "\n");
return;
}
FpKeeper keeper(&fp);
string blk1;
blk1.append("udi=");
blk1.append(udi);
blk1.append(cstr_newline);
blk1.resize(o_b1size, 0);
if (fwrite(blk1.c_str(), 1, o_b1size, fp) != o_b1size) {
LOGDEB("MboxCache::put_offsets: fwrite errno " << (errno) << "\n");
return;
}
for (vector<mbhoff_type>::const_iterator it = offs.begin();
it != offs.end(); it++) {
mbhoff_type off = *it;
if (fwrite((char*)&off, 1, sizeof(mbhoff_type), fp) !=
sizeof(mbhoff_type)) {
return;
}
}
}
// Check state, possibly initialize
bool ok(RclConfig *config) {
std::unique_lock<std::mutex> locker(o_mcache_mutex);
if (m_minfsize == -1)
return false;
if (!m_ok) {
int minmbs = 5;
config->getConfParam("mboxcacheminmbs", &minmbs);
if (minmbs < 0) {
// minmbs set to negative to disable cache
m_minfsize = -1;
return false;
}
m_minfsize = minmbs * 1000 * 1000;
m_dir = config->getMboxcacheDir();
m_ok = true;
}
return m_ok;
}
private:
bool m_ok;
// Place where we store things
string m_dir;
// Don't cache smaller files. If -1, don't do anything.
mbhoff_type m_minfsize;
static const size_t o_b1size;
// Create the cache directory if it does not exist
bool maybemakedir()
{
struct stat st;
if (stat(m_dir.c_str(), &st) != 0 && mkdir(m_dir.c_str(), 0700) != 0) {
return false;
}
return true;
}
// Compute file name from udi
string makefilename(const string& udi)
{
string digest, xdigest;
MD5String(udi, digest);
MD5HexPrint(digest, xdigest);
return path_cat(m_dir, xdigest);
}
// Compute offset in cache file for the mbox offset of msgnum
mbhoff_type cacheoffset(int msgnum)
{// Msgnums are from 1
return o_b1size + (msgnum-1) * sizeof(mbhoff_type);
}
};
const size_t MboxCache::o_b1size = 1024;
static class MboxCache o_mcache;
static const string cstr_keyquirks("mhmboxquirks");
MimeHandlerMbox::~MimeHandlerMbox()
{
clear();
}
void MimeHandlerMbox::clear_impl()
{
m_fn.erase();
if (m_vfp) {
fclose((FILE *)m_vfp);
m_vfp = 0;
}
m_msgnum = m_lineno = 0;
m_ipath.erase();
m_offsets.clear();
}
bool MimeHandlerMbox::set_document_file_impl(const string& mt, const string &fn)
{
LOGDEB("MimeHandlerMbox::set_document_file(" << fn << ")\n");
m_fn = fn;
if (m_vfp) {
fclose((FILE *)m_vfp);
m_vfp = 0;
}
m_vfp = fopen(fn.c_str(), "r");
if (m_vfp == 0) {
LOGERR("MimeHandlerMail::set_document_file: error opening " << fn <<
"\n");
return false;
}
#if defined O_NOATIME && O_NOATIME != 0
if (fcntl(fileno((FILE *)m_vfp), F_SETFL, O_NOATIME) < 0) {
// perror("fcntl");
}
#endif
// Used to use ftell() here: no good beyond 2GB
{struct stat st;
if (fstat(fileno((FILE*)m_vfp), &st) < 0) {
LOGERR("MimeHandlerMbox:setdocfile: fstat(" << fn <<
") failed errno " << errno << "\n");
return false;
}
m_fsize = st.st_size;
}
m_havedoc = true;
m_offsets.clear();
m_quirks = 0;
// Check for location-based quirks:
string quirks;
if (m_config && m_config->getConfParam(cstr_keyquirks, quirks)) {
if (quirks == "tbird") {
LOGDEB("MimeHandlerMbox: setting quirks TBIRD\n");
m_quirks |= MBOXQUIRK_TBIRD;
}
}
// And double check for thunderbird
string tbirdmsf = fn + ".msf";
if ((m_quirks&MBOXQUIRK_TBIRD) == 0 && path_exists(tbirdmsf)) {
LOGDEB("MimeHandlerMbox: detected unconfigured tbird mbox in " << (fn) << "\n");
m_quirks |= MBOXQUIRK_TBIRD;
}
return true;
}
#define LL 1024
typedef char line_type[LL+10];
static inline void stripendnl(line_type& line, int& ll)
{
ll = int(strlen(line));
while (ll > 0) {
if (line[ll-1] == '\n' || line[ll-1] == '\r') {
line[ll-1] = 0;
ll--;
} else
break;
}
}
// The mbox format uses lines beginning with 'From ' as separator.
// Mailers are supposed to quote any other lines beginning with
// 'From ', turning it into '>From '. This should make it easy to detect
@ -353,16 +85,16 @@ static inline void stripendnl(line_type& line, int& ll)
// emacs-vm, Recoll is not alone
// Update: 2009-11-27: word after From may be quoted string: From "john bull"
static const string frompat{
"^From[ ]+([^ ]+|\"[^\"]+\")[ ]+" // 'From (toto@tutu|"john bull") '
"[[:alpha:]]{3}[ ]+[[:alpha:]]{3}[ ]+[0-3 ][0-9][ ]+" // Fri Oct 26
"[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?[ ]+" // Time, seconds optional
"([^ ]+[ ]+)?" // Optional tz
"[12][0-9][0-9][0-9]" // Year, unanchored, more data may follow
"|" // Or standard mail Date: header format
"^From[ ]+[^ ]+[ ]+" // From toto@tutu
"[[:alpha:]]{3},[ ]+[0-3]?[0-9][ ]+[[:alpha:]]{3}[ ]+" // Mon, 8 May
"[12][0-9][0-9][0-9][ ]+" // Year
"[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?" // Time, secs optional
"^From[ ]+([^ ]+|\"[^\"]+\")[ ]+" // 'From (toto@tutu|"john bull") '
"[[:alpha:]]{3}[ ]+[[:alpha:]]{3}[ ]+[0-3 ][0-9][ ]+" // Fri Oct 26
"[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?[ ]+" // Time, seconds optional
"([^ ]+[ ]+)?" // Optional tz
"[12][0-9][0-9][0-9]" // Year, unanchored, more data may follow
"|" // Or standard mail Date: header format
"^From[ ]+[^ ]+[ ]+" // From toto@tutu
"[[:alpha:]]{3},[ ]+[0-3]?[0-9][ ]+[[:alpha:]]{3}[ ]+" // Mon, 8 May
"[12][0-9][0-9][0-9][ ]+" // Year
"[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?" // Time, secs optional
};
// Extreme thunderbird brokiness. Will sometimes use From lines
@ -373,84 +105,377 @@ static const string miniTbirdFrom{"^From $"};
static SimpleRegexp fromregex(frompat, SimpleRegexp::SRE_NOSUB);
static SimpleRegexp minifromregex(miniTbirdFrom, SimpleRegexp::SRE_NOSUB);
static std::mutex o_mcache_mutex;
/**
* Handles a cache for message numbers to offset translations. Permits direct
* accesses inside big folders instead of having to scan up to the right place
*
* Message offsets are saved to files stored under cfg(mboxcachedir), default
* confdir/mboxcache. Mbox files smaller than cfg(mboxcacheminmbs) are not
* cached.
* Cache files are named as the md5 of the file UDI, which is kept in
* the first block for possible collision detection. The 64 bits
* offsets for all message "From_" lines follow. The format is purely
* binary, values are not even byte-swapped to be proc-idependant.
*/
#define M_o_b1size 1024
class MboxCache {
public:
MboxCache() {
// Can't access rclconfig here, we're a static object, would
// have to make sure it's initialized.
}
~MboxCache() {}
int64_t get_offset(RclConfig *config, const string& udi, int msgnum) {
LOGDEB0("MboxCache::get_offsets: udi [" << udi << "] msgnum "
<< msgnum << "\n");
if (!ok(config)) {
LOGDEB("MboxCache::get_offsets: init failed\n");
return -1;
}
std::unique_lock<std::mutex> locker(o_mcache_mutex);
string fn = makefilename(udi);
ifstream instream(fn.c_str(), std::ifstream::binary);
if (!instream.good()) {
LOGSYSERR("MboxCache::get_offsets", "open", fn);
return false;
}
char blk1[M_o_b1size];
instream.read(blk1, M_o_b1size);
if (!instream.good()) {
LOGSYSERR("MboxCache::get_offsets", "read blk1", "");
return -1;
}
ConfSimple cf(string(blk1, M_o_b1size));
string fudi;
if (!cf.get("udi", fudi) || fudi.compare(udi)) {
LOGINFO("MboxCache::get_offset:badudi fn " << fn << " udi ["
<< udi << "], fudi [" << fudi << "]\n");
return -1;
}
LOGDEB1("MboxCache::get_offsets: reading offsets file at offs "
<< cacheoffset(msgnum) << "\n");
instream.seekg(cacheoffset(msgnum));
if (!instream.good()) {
LOGSYSERR("MboxCache::get_offsets", "seek",
lltodecstr(cacheoffset(msgnum)));
return -1;
}
int64_t offset = -1;
instream.read((char*)&offset, sizeof(int64_t));
if (!instream.good()) {
LOGSYSERR("MboxCache::get_offsets", "read", "");
return -1;
}
LOGDEB0("MboxCache::get_offsets: ret " << offset << "\n");
return offset;
}
// Save array of offsets for a given file, designated by Udi
void put_offsets(RclConfig *config, const string& udi, int64_t fsize,
vector<int64_t>& offs) {
LOGDEB0("MboxCache::put_offsets: " << offs.size() << " offsets\n");
if (!ok(config) || !maybemakedir())
return;
if (fsize < m_minfsize) {
LOGDEB0("MboxCache::put_offsets: fsize " << fsize << " < minsize "
<< m_minfsize << endl);
return;
}
std::unique_lock<std::mutex> locker(o_mcache_mutex);
string fn = makefilename(udi);
std::ofstream os(fn.c_str(), std::ios::out|std::ios::binary);
if (!os.good()) {
LOGSYSERR("MboxCache::put_offsets", "open", fn);
return;
}
string blk1("udi=");
blk1.append(udi);
blk1.append(cstr_newline);
blk1.resize(M_o_b1size, 0);
os.write(blk1.c_str(), M_o_b1size);
if (!os.good()) {
LOGSYSERR("MboxCache::put_offsets", "write blk1", "");
return;
}
for (const auto& off : offs) {
LOGDEB1("MboxCache::put_offsets: writing value " << off <<
" at offset " << ftello(fp) << endl);
os.write((char*)&off, sizeof(int64_t));
if (!os.good()) {
LOGSYSERR("MboxCache::put_offsets", "write", "");
return;
}
}
os.flush();
if (!os.good()) {
LOGSYSERR("MboxCache::put_offsets", "flush", "");
return;
}
}
// Check state, possibly initialize
bool ok(RclConfig *config) {
std::unique_lock<std::mutex> locker(o_mcache_mutex);
if (m_minfsize == -1)
return false;
if (!m_ok) {
int minmbs = 5;
config->getConfParam("mboxcacheminmbs", &minmbs);
if (minmbs < 0) {
// minmbs set to negative to disable cache
m_minfsize = -1;
return false;
}
m_minfsize = minmbs * 1000 * 1000;
m_dir = config->getMboxcacheDir();
m_ok = true;
}
return m_ok;
}
private:
bool m_ok{false};
// Place where we store things
string m_dir;
// Don't cache smaller files. If -1, don't do anything.
int64_t m_minfsize{0};
// Create the cache directory if it does not exist
bool maybemakedir() {
if (!path_makepath(m_dir, 0700)) {
LOGSYSERR("MboxCache::maybemakedir", "path_makepath", m_dir);
return false;
}
return true;
}
// Compute file name from udi
string makefilename(const string& udi) {
string digest, xdigest;
MD5String(udi, digest);
MD5HexPrint(digest, xdigest);
return path_cat(m_dir, xdigest);
}
// Compute offset in cache file for the mbox offset of msgnum
// Msgnums are from 1
int64_t cacheoffset(int msgnum) {
return M_o_b1size + (msgnum-1) * sizeof(int64_t);
}
};
static class MboxCache o_mcache;
static const string cstr_keyquirks("mhmboxquirks");
enum Quirks {MBOXQUIRK_TBIRD=1};
class MimeHandlerMbox::Internal {
public:
Internal(MimeHandlerMbox *p) : pthis(p) {}
std::string fn; // File name
std::string ipath;
ifstream instream;
int msgnum{0}; // Current message number in folder. Starts at 1
int64_t lineno{0}; // debug
int64_t fsize{0};
std::vector<int64_t> offsets;
int quirks;
MimeHandlerMbox *pthis;
bool tryUseCache(int mtarg);
};
MimeHandlerMbox::MimeHandlerMbox(RclConfig *cnf, const std::string& id)
: RecollFilter(cnf, id)
{
m = new Internal(this);
}
MimeHandlerMbox::~MimeHandlerMbox()
{
if (m) {
clear();
delete m;
}
}
void MimeHandlerMbox::clear_impl()
{
m->fn.erase();
m->ipath.erase();
m->instream = ifstream();
m->msgnum = m->lineno = m->fsize = 0;
m->offsets.clear();
m->quirks = 0;
}
bool MimeHandlerMbox::skip_to_document(const std::string& ipath) {
m->ipath = ipath;
return true;
}
bool MimeHandlerMbox::set_document_file_impl(const string& mt, const string &fn)
{
LOGDEB("MimeHandlerMbox::set_document_file(" << fn << ")\n");
clear_impl();
m->fn = fn;
m->instream = ifstream(fn.c_str(), std::ifstream::binary);
if (!m->instream.good()) {
LOGSYSERR("MimeHandlerMail::set_document_file", "ifstream", fn);
return false;
}
// TBD
#if 0 && defined O_NOATIME && O_NOATIME != 0
if (fcntl(fileno((FILE *)m->vfp), F_SETFL, O_NOATIME) < 0) {
// perror("fcntl");
}
#endif
m->fsize = path_filesize(fn);
m_havedoc = true;
// Check for location-based quirks:
string quirks;
if (m_config && m_config->getConfParam(cstr_keyquirks, quirks)) {
if (quirks == "tbird") {
LOGDEB("MimeHandlerMbox: setting quirks TBIRD\n");
m->quirks |= MBOXQUIRK_TBIRD;
}
}
// And double check for thunderbird
string tbirdmsf = fn + ".msf";
if (!(m->quirks & MBOXQUIRK_TBIRD) && path_exists(tbirdmsf)) {
LOGDEB("MimeHandlerMbox: detected unconf'd tbird mbox in "<< fn <<"\n");
m->quirks |= MBOXQUIRK_TBIRD;
}
return true;
}
bool MimeHandlerMbox::Internal::tryUseCache(int mtarg)
{
bool cachefound = false;
string line;
int64_t off;
LOGDEB0("MimeHandlerMbox::next_doc: mtarg " << mtarg << " m_udi[" <<
pthis->m_udi << "]\n");
if (pthis->m_udi.empty()) {
goto out;
}
if ((off = o_mcache.get_offset(pthis->m_config, pthis->m_udi, mtarg)) < 0) {
goto out;
}
instream.seekg(off);
if (!instream.good()) {
LOGSYSERR("tryUseCache", "seekg", "");
goto out;
}
getline(instream, line, '\n');
if (!instream.good()) {
LOGSYSERR("tryUseCache", "getline", "");
goto out;
}
LOGDEB1("MimeHandlerMbox::tryUseCache:getl ok. line:[" << line << "]\n");
if ((fromregex(line) ||
((quirks & MBOXQUIRK_TBIRD) && minifromregex(line))) ) {
LOGDEB0("MimeHandlerMbox: Cache: From_ Ok\n");
instream.seekg(off);
msgnum = mtarg -1;
cachefound = true;
} else {
LOGDEB0("MimeHandlerMbox: cache: regex failed for [" << line << "]\n");
}
out:
if (!cachefound) {
// No cached result: scan.
instream.seekg(0);
msgnum = 0;
}
return cachefound;
}
bool MimeHandlerMbox::next_document()
{
if (m_vfp == 0) {
if (!m->instream.good()) {
LOGERR("MimeHandlerMbox::next_document: not open\n");
return false;
}
if (!m_havedoc) {
return false;
}
FILE *fp = (FILE *)m_vfp;
int mtarg = 0;
if (!m_ipath.empty()) {
sscanf(m_ipath.c_str(), "%d", &mtarg);
if (!m->ipath.empty()) {
sscanf(m->ipath.c_str(), "%d", &mtarg);
} else if (m_forPreview) {
// Can't preview an mbox.
LOGDEB("MimeHandlerMbox::next_document: can't preview folders!\n");
return false;
}
LOGDEB0("MimeHandlerMbox::next_document: fn " << m_fn << ", msgnum " <<
m_msgnum << " mtarg " << mtarg << " \n");
LOGDEB0("MimeHandlerMbox::next_document: fn " << m->fn << ", msgnum " <<
m->msgnum << " mtarg " << mtarg << " \n");
if (mtarg == 0)
mtarg = -1;
// If we are called to retrieve a specific message, seek to bof
// (then scan up to the message). This is for the case where the
// same object is reused to fetch several messages (else the fp is
// just opened no need for a seek). We could also check if the
// current message number is lower than the requested one and
// avoid rereading the whole thing in this case. But I'm not sure
// we're ever used in this way (multiple retrieves on same
// object). So:
// If we are called to retrieve a specific message, try to use the
// offsets cache to try and position to the right header.
bool storeoffsets = true;
if (mtarg > 0) {
mbhoff_type off;
line_type line;
LOGDEB0("MimeHandlerMbox::next_doc: mtarg " << mtarg << " m_udi[" <<
m_udi << "]\n");
if (!m_udi.empty() &&
(off = o_mcache.get_offset(m_config, m_udi, mtarg)) >= 0 &&
fseeko(fp, (off_t)off, SEEK_SET) >= 0 &&
fgets(line, LL, fp) &&
(fromregex(line) || ((m_quirks & MBOXQUIRK_TBIRD) &&
minifromregex(line))) ) {
LOGDEB0("MimeHandlerMbox: Cache: From_ Ok\n");
fseeko(fp, (off_t)off, SEEK_SET);
m_msgnum = mtarg -1;
storeoffsets = false;
} else {
fseek(fp, 0, SEEK_SET);
m_msgnum = 0;
}
storeoffsets = !m->tryUseCache(mtarg);
}
off_t message_end = 0;
int64_t message_end = 0;
bool iseof = false;
bool hademptyline = true;
string& msgtxt = m_metaData[cstr_dj_keycontent];
msgtxt.erase();
line_type line;
string line;
for (;;) {
message_end = ftello(fp);
if (!fgets(line, LL, fp)) {
LOGDEB2("MimeHandlerMbox:next: eof\n");
message_end = m->instream.tellg();
getline(m->instream, line, '\n');
if (!m->instream.good()) {
ifstream::iostate st = m->instream.rdstate();
if (st & std::ifstream::eofbit) {
LOGDEB0("MimeHandlerMbox:next: eof\n");
}
if (st & std::ifstream::failbit) {
LOGDEB0("MimeHandlerMbox:next: fail\n");
LOGSYSERR("MimeHandlerMbox:next:", "", "");
}
if (st & std::ifstream::badbit) {
LOGDEB0("MimeHandlerMbox:next: bad\n");
LOGSYSERR("MimeHandlerMbox:next:", "", "");
}
if (st & std::ifstream::goodbit) {
LOGDEB0("MimeHandlerMbox:next: good\n");
}
LOGDEB0("MimeHandlerMbox:next: eof at " << message_end << endl);
iseof = true;
m_msgnum++;
m->msgnum++;
break;
}
m_lineno++;
int ll;
stripendnl(line, ll);
m->lineno++;
rtrimstring(line, "\r\n");
int ll = line.size();
LOGDEB2("mhmbox:next: hadempty " << hademptyline << " lineno " <<
m_lineno << " ll " << ll << " Line: [" << line << "]\n");
m->lineno << " ll " << ll << " Line: [" << line << "]\n");
if (hademptyline) {
if (ll > 0) {
// Non-empty line with empty line flag set, reset flag
// and check regex.
if (!(m_quirks & MBOXQUIRK_TBIRD)) {
if (!(m->quirks & MBOXQUIRK_TBIRD)) {
// Tbird sometimes ommits the empty line, so avoid
// resetting state (initially true) and hope for
// the best
@ -460,16 +485,18 @@ bool MimeHandlerMbox::next_document()
A LOT */
if (line[0] == 'F' && (
fromregex(line) ||
((m_quirks & MBOXQUIRK_TBIRD) && minifromregex(line)))
((m->quirks & MBOXQUIRK_TBIRD) && minifromregex(line)))
) {
LOGDEB0("MimeHandlerMbox: msgnum " << m_msgnum <<
", From_ at line " << m_lineno << ": [" << line
<< "]\n");
if (storeoffsets)
m_offsets.push_back(message_end);
m_msgnum++;
if ((mtarg <= 0 && m_msgnum > 1) ||
(mtarg > 0 && m_msgnum > mtarg)) {
LOGDEB1("MimeHandlerMbox: msgnum " << m->msgnum <<
", From_ at line " << m->lineno << " foffset " <<
message_end << " line: [" << line << "]\n");
if (storeoffsets) {
m->offsets.push_back(message_end);
}
m->msgnum++;
if ((mtarg <= 0 && m->msgnum > 1) ||
(mtarg > 0 && m->msgnum > mtarg)) {
// Got message, go do something with it
break;
}
@ -481,15 +508,14 @@ bool MimeHandlerMbox::next_document()
hademptyline = true;
}
if (mtarg <= 0 || m_msgnum == mtarg) {
if (mtarg <= 0 || m->msgnum == mtarg) {
// Accumulate message lines
line[ll] = '\n';
line[ll+1] = 0;
line += '\n';
msgtxt += line;
if (msgtxt.size() > max_mbox_member_size) {
LOGERR("mh_mbox: huge message (more than " <<
max_mbox_member_size/(1024*1024) << " MB) inside " <<
m_fn << ", giving up\n");
m->fn << ", giving up\n");
return false;
}
}
@ -497,135 +523,17 @@ bool MimeHandlerMbox::next_document()
LOGDEB2("Message text length " << msgtxt.size() << "\n");
LOGDEB2("Message text: [" << msgtxt << "]\n");
char buf[20];
// m_msgnum was incremented when hitting the next From_ or eof, so the data
// is for m_msgnum - 1
sprintf(buf, "%d", m_msgnum - 1);
// m->msgnum was incremented when hitting the next From_ or eof, so the data
// is for m->msgnum - 1
sprintf(buf, "%d", m->msgnum - 1);
m_metaData[cstr_dj_keyipath] = buf;
m_metaData[cstr_dj_keymt] = "message/rfc822";
if (iseof) {
LOGDEB2("MimeHandlerMbox::next: eof hit\n");
m_havedoc = false;
if (!m_udi.empty() && storeoffsets) {
o_mcache.put_offsets(m_config, m_udi, m_fsize, m_offsets);
o_mcache.put_offsets(m_config, m_udi, m->fsize, m->offsets);
}
}
return msgtxt.empty() ? false : true;
}
#else // Test driver ->
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
#include "rclconfig.h"
#include "rclinit.h"
#include "cstr.h"
#include "mh_mbox.h"
static char *thisprog;
static char usage [] =
"Test driver for mbox walking function\n"
"mh_mbox [-m num] mboxfile\n"
" \n\n"
;
static void
Usage(void)
{
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
exit(1);
}
static RclConfig *config;
static int op_flags;
#define OPT_MOINS 0x1
#define OPT_m 0x2
//#define OPT_t 0x4
int main(int argc, char **argv)
{
string msgnum;
thisprog = argv[0];
argc--; argv++;
while (argc > 0 && **argv == '-') {
(*argv)++;
if (!(**argv))
/* Cas du "adb - core" */
Usage();
while (**argv)
switch (*(*argv)++) {
case 'm': op_flags |= OPT_m; if (argc < 2) Usage();
msgnum = *(++argv);
argc--;
goto b1;
// case 't': op_flags |= OPT_t;break;
default: Usage(); break;
}
b1: argc--; argv++;
}
if (argc != 1)
Usage();
string filename = *argv++;argc--;
string reason;
config = recollinit(RclInitFlags(0), 0, 0, reason, 0);
if (config == 0) {
cerr << "init failed " << reason << endl;
exit(1);
}
config->setKeyDir(path_getfather(filename));
MimeHandlerMbox mh(config, "some_id");
if (!mh.set_document_file("text/x-mail", filename)) {
cerr << "set_document_file failed" << endl;
exit(1);
}
if (!msgnum.empty()) {
mh.skip_to_document(msgnum);
if (!mh.next_document()) {
cerr << "next_document failed after skipping to " << msgnum << endl;
exit(1);
}
map<string, string>::const_iterator it =
mh.get_meta_data().find(cstr_dj_keycontent);
int size;
if (it == mh.get_meta_data().end()) {
size = -1;
cerr << "No content!!" << endl;
exit(1);
}
cout << "Doc " << msgnum << ":" << endl;
cout << it->second << endl;
exit(0);
}
int docnt = 0;
while (mh.has_documents()) {
if (!mh.next_document()) {
cerr << "next_document failed" << endl;
exit(1);
}
docnt++;
map<string, string>::const_iterator it =
mh.get_meta_data().find(cstr_dj_keycontent);
int size;
if (it == mh.get_meta_data().end()) {
size = -1;
} else {
size = it->second.length();
}
cout << "Doc " << docnt << " size " << size << endl;
}
cout << docnt << " documents found in " << filename << endl;
exit(0);
}
#endif // TEST_MH_MBOX

View File

@ -19,6 +19,7 @@
#include <string>
#include <vector>
#include <inttypes.h>
#include "mimehandler.h"
@ -29,33 +30,19 @@
*/
class MimeHandlerMbox : public RecollFilter {
public:
MimeHandlerMbox(RclConfig *cnf, const std::string& id)
: RecollFilter(cnf, id), m_vfp(0), m_msgnum(0),
m_lineno(0), m_fsize(0) {
}
MimeHandlerMbox(RclConfig *cnf, const std::string& id);
virtual ~MimeHandlerMbox();
virtual bool next_document() override;
virtual bool skip_to_document(const std::string& ipath) override{
m_ipath = ipath;
return true;
}
virtual bool skip_to_document(const std::string& ipath) override;
virtual void clear_impl() override;
typedef long long mbhoff_type;
protected:
virtual bool set_document_file_impl(const std::string&,
const std::string&) override;
class Internal;
private:
std::string m_fn; // File name
void *m_vfp; // File pointer for folder
int m_msgnum; // Current message number in folder. Starts at 1
std::string m_ipath;
int m_lineno; // debug
mbhoff_type m_fsize;
std::vector<mbhoff_type> m_offsets;
enum Quirks {MBOXQUIRK_TBIRD=1};
int m_quirks;
Internal *m{nullptr};
};
#endif /* _MBOX_H_INCLUDED_ */

View File

@ -56,9 +56,12 @@ static const int margin = 2;
void ConfParamW::setValue(const QString& value)
{
#ifndef _WIN32
// On Windows all paths are unicode.
if (m_fsencoding)
m_cflink->set(string((const char *)value.toLocal8Bit()));
else
#endif
m_cflink->set(string((const char *)value.toUtf8()));
}
@ -158,9 +161,12 @@ void ConfParamStrW::loadValue()
{
string s;
m_cflink->get(s);
#ifndef _WIN32
// On Windows all paths are unicode.
if (m_fsencoding)
m_le->setText(QString::fromLocal8Bit(s.c_str()));
else
#endif
m_le->setText(QString::fromUtf8(s.c_str()));
}
@ -191,9 +197,12 @@ void ConfParamCStrW::loadValue()
string s;
m_cflink->get(s);
QString cs;
#ifndef _WIN32
// On Windows all paths are unicode.
if (m_fsencoding)
cs = QString::fromLocal8Bit(s.c_str());
else
#endif
cs = QString::fromUtf8(s.c_str());
for (int i = 0; i < m_cmb->count(); i++) {
@ -272,7 +281,12 @@ void ConfParamFNW::loadValue()
{
string s;
m_cflink->get(s);
#ifndef _WIN32
// On Windows all paths are unicode.
m_le->setText(QString::fromLocal8Bit(s.c_str()));
#else
m_le->setText(QString::fromUtf8(s.c_str()));
#endif
}
void ConfParamFNW::showBrowserDialog()
@ -346,9 +360,12 @@ void ConfParamSLW::loadValue()
stringToStrings(s, ls);
QStringList qls;
for (list<string>::const_iterator it = ls.begin(); it != ls.end(); it++) {
// On Windows all paths are unicode.
#ifndef _WIN32
if (m_fsencoding)
qls.push_back(QString::fromLocal8Bit(it->c_str()));
else
#endif
qls.push_back(QString::fromUtf8(it->c_str()));
}
m_lb->clear();
@ -379,7 +396,7 @@ void ConfParamSLW::showInputDialog()
void ConfParamSLW::listToConf()
{
list<string> ls;
LOGDEB2("ConfParamSLW::listToConf. m_fsencoding " << (int(m_fsencoding)) << "\n" );
LOGDEB2("ConfParamSLW::listToConf. m_fsencoding " << m_fsencoding << "\n");
for (int i = 0; i < m_lb->count(); i++) {
// General parameters are encoded as utf-8. File names as
// local8bit There is no hope for 8bit file names anyway
@ -390,8 +407,9 @@ void ConfParamSLW::listToConf()
// paths, and it will come back to haunt us one day.
QString text = m_lb->item(i)->text();
if (m_fsencoding) {
// On Windows all paths are unicode.
#ifdef _WIN32
string pth((const char *)(text.toLocal8Bit()));
string pth((const char *)(text.toUtf8()));
path_slashize(pth);
ls.push_back(pth);
#else
@ -426,7 +444,7 @@ void ConfParamSLW::deleteSelected()
}
for (vector<int>::reverse_iterator it = idxes.rbegin();
it != idxes.rend(); it++) {
LOGDEB0("deleteSelected: " << (*it) << " was selected\n" );
LOGDEB0("deleteSelected: " << *it << " was selected\n");
QListWidgetItem *item = m_lb->takeItem(*it);
emit entryDeleted(item->text());
delete item;
@ -479,4 +497,3 @@ void ConfParamCSLW::showInputDialog()
}
} // Namespace confgui

View File

@ -59,12 +59,10 @@ public:
ConfLinkRclRep(ConfNull *conf, const string& nm,
string *sk = 0)
: m_conf(conf), m_nm(nm), m_sk(sk) /* KEEP THE POINTER, shared data */
{
}
{ }
virtual ~ConfLinkRclRep() {}
virtual bool set(const string& val)
{
virtual bool set(const string& val) {
if (!m_conf)
return false;
LOGDEB1("Setting [" << m_nm << "] value to [" << val << "]\n");
@ -73,8 +71,7 @@ public:
LOGERR("Value set failed\n" );
return ret;
}
virtual bool get(string& val)
{
virtual bool get(string& val) {
if (!m_conf)
return false;
bool ret = m_conf->get(m_nm, val, getSk());
@ -731,4 +728,3 @@ void ConfSubPanelW::restoreEmpty()
}
} // Namespace confgui

View File

@ -1331,14 +1331,6 @@ Prověřte soubor pracovní plochy</translation>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1368,6 +1360,34 @@ Prověřte soubor pracovní plochy</translation>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2391,7 +2411,7 @@ Použijte odkaz &lt;b&gt;Ukázat hledání&lt;/b&gt;, když máte o výsledku po
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation>Začáteční adresář (jinak použít počáteční adresáře):</translation>
<translation type="vanished">Začáteční adresář (jinak použít počáteční adresáře):</translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
@ -2409,6 +2429,10 @@ Použijte odkaz &lt;b&gt;Ukázat hledání&lt;/b&gt;, když máte o výsledku po
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1239,14 +1239,6 @@ Tjek venligst desktopfilen</translation>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1276,6 +1268,34 @@ Tjek venligst desktopfilen</translation>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2056,7 +2076,7 @@ Brug &lt;b&gt;Vis Forespørgsel&lt;/b&gt; link når i tvivl om resultatet og se
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation>Startmappe (ellers brug de regulære øverste mapper):</translation>
<translation type="vanished">Startmappe (ellers brug de regulære øverste mapper):</translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
@ -2074,6 +2094,10 @@ Brug &lt;b&gt;Vis Forespørgsel&lt;/b&gt; link når i tvivl om resultatet og se
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1299,14 +1299,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1336,6 +1328,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2328,10 +2348,6 @@ Drücken Sie ESC+Leerzeichen für Vervollständigungen des aktuellen Begriffs.</
<source>Browse</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2348,6 +2364,10 @@ Drücken Sie ESC+Leerzeichen für Vervollständigungen des aktuellen Begriffs.</
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1283,14 +1283,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1320,6 +1312,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2239,10 +2259,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished">Περιήγηση</translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2259,6 +2275,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1289,14 +1289,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1326,6 +1318,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2282,10 +2302,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished">Buscar</translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2302,6 +2318,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

Binary file not shown.

View File

@ -1347,11 +1347,11 @@ Merci de vérifier le fichier desktop </translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation>(%d documents/%d fichiers/%d erreurs/%d fichiers en tout) </translation>
<translation type="vanished">(%d documents/%d fichiers/%d erreurs/%d fichiers en tout) </translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation>(%d documents/%d fichiers/%d erreurs) </translation>
<translation type="vanished">(%d documents/%d fichiers/%d erreurs) </translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
@ -1382,6 +1382,34 @@ Merci de vérifier le fichier desktop </translation>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation>Cliquer Annuler pour retourner à la liste.&lt;br&gt;Cliquer Ignorer pour afficher la prévisualisation (et enregister l&apos;option pour cette session). Il y a un risque d&apos;afficher le mauvais document.&lt;br/&gt;</translation>
</message>
<message>
<source>documents</source>
<translation>documents</translation>
</message>
<message>
<source>document</source>
<translation>document</translation>
</message>
<message>
<source>files</source>
<translation>fichiers</translation>
</message>
<message>
<source>file</source>
<translation>fichier</translation>
</message>
<message>
<source>errors</source>
<translation>erreurs</translation>
</message>
<message>
<source>error</source>
<translation>erreur</translation>
</message>
<message>
<source>total files)</source>
<translation>fichiers totaux)</translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2421,7 +2449,7 @@ Utiliser le lien &lt;b&gt;Afficher la requête en détail&lt;/b&gt; en cas de do
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation>Répertoire de départ (sinon utiliser la variable normale topdirs) :</translation>
<translation type="vanished">Répertoire de départ (sinon utiliser la variable normale topdirs) :</translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
@ -2443,6 +2471,14 @@ Utiliser le lien &lt;b&gt;Afficher la requête en détail&lt;/b&gt; en cas de do
<source>Retry previously failed files.</source>
<translation>Ne pas réessayer les fichiers en erreur.</translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. We use topdirs if empty.</source>
<translation type="vanished">Répertoire de départ. Doit faire partie de la zone indexée. topdirs est utilisé si non renseigné.</translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation>Répertoire de départ. Doit faire partie de la zone indexée. Traite toute la zone si non renseigné.</translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1203,14 +1203,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1240,6 +1232,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2077,10 +2097,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished">Esplora</translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2097,6 +2113,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1223,14 +1223,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1260,6 +1252,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2161,10 +2181,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished">Naršyti</translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2181,6 +2197,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -748,7 +748,7 @@ Click Cancel if you want to edit the configuration file before indexing starts,
<context>
<name>QObject</name>
<message>
<location filename="../confgui/confguiindex.cpp" line="+218"/>
<location filename="../confgui/confguiindex.cpp" line="+215"/>
<source>Global parameters</source>
<translation>Общие параметры</translation>
</message>
@ -1064,8 +1064,8 @@ p, li { white-space: pre-wrap; }
<translation>Невозможно извлечь сведения о документе из БД</translation>
</message>
<message>
<location filename="../rclm_idx.cpp" line="+261"/>
<location line="+271"/>
<location filename="../rclm_idx.cpp" line="+263"/>
<location line="+273"/>
<location line="+19"/>
<location filename="../rclm_preview.cpp" line="-138"/>
<location line="+44"/>
@ -1101,7 +1101,7 @@ p, li { white-space: pre-wrap; }
<translation>История</translation>
</message>
<message>
<location filename="../rclm_idx.cpp" line="-507"/>
<location filename="../rclm_idx.cpp" line="-511"/>
<source>Indexing in progress: </source>
<translation>Идёт индексирование: </translation>
</message>
@ -1162,7 +1162,7 @@ Please check the mimeconf file</source>
<translation>ошибка получения списка языков</translation>
</message>
<message>
<location filename="../rclm_idx.cpp" line="+121"/>
<location filename="../rclm_idx.cpp" line="+123"/>
<source>Update &amp;Index</source>
<translation>Обновить &amp;индекс</translation>
</message>
@ -1172,7 +1172,42 @@ Please check the mimeconf file</source>
<translation>Индексирование прервано</translation>
</message>
<message>
<location line="+34"/>
<location line="-66"/>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+94"/>
<location line="+27"/>
<source>Stop &amp;Indexing</source>
<translation>О&amp;становить индексирование</translation>
@ -1309,7 +1344,7 @@ Do you want to start the preferences dialog ?</source>
<translation>Поиск не дал результатов</translation>
</message>
<message>
<location filename="../rclm_idx.cpp" line="-136"/>
<location filename="../rclm_idx.cpp" line="-138"/>
<source>None</source>
<translation>Отсутствует</translation>
</message>
@ -1329,17 +1364,7 @@ Do you want to start the preferences dialog ?</source>
<translation>Монитор</translation>
</message>
<message>
<location line="+8"/>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+58"/>
<location line="+74"/>
<source>Indexing failed</source>
<translation>Не удалось выполнить индексирование</translation>
</message>
@ -1370,7 +1395,7 @@ Do you want to start the preferences dialog ?</source>
<translation>Сбросить индекс и начать заново?</translation>
</message>
<message>
<location line="+193"/>
<location line="+195"/>
<source>Can&apos;t update index: internal error</source>
<translation type="unfinished"></translation>
</message>
@ -1501,7 +1526,7 @@ Please check the desktop file</source>
<translation type="vanished">Для запуска текущего процесса индексирования был использован другой интерфейс. Прекратить выполнение процесса невозможно</translation>
</message>
<message>
<location filename="../rclm_idx.cpp" line="-303"/>
<location filename="../rclm_idx.cpp" line="-305"/>
<source>Bad paths</source>
<translation>Неверные пути</translation>
</message>
@ -1512,7 +1537,7 @@ Please check the desktop file</source>
</translation>
</message>
<message>
<location line="+279"/>
<location line="+281"/>
<source>Selection patterns need topdir</source>
<translation>Для шаблонов отбора требуется topdir</translation>
</message>
@ -1622,7 +1647,7 @@ Please check the desktop file</source>
<translation>Больше не показывать (для восстановления значений используйте окно настройки интерфейса).</translation>
</message>
<message>
<location filename="../rclm_idx.cpp" line="-342"/>
<location filename="../rclm_idx.cpp" line="-344"/>
<source>Index locked</source>
<translation>Индекс заблокирован</translation>
</message>
@ -2138,12 +2163,12 @@ Please check the desktop file</source>
<translation>Дата и время</translation>
</message>
<message>
<location line="+193"/>
<location line="+189"/>
<source>Can&apos;t sort by inverse relevance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-202"/>
<location line="-198"/>
<source>Ipath</source>
<translation>Ipath</translation>
</message>
@ -2293,7 +2318,7 @@ Please check the desktop file</source>
<context>
<name>ResTable</name>
<message>
<location filename="../restable.cpp" line="+787"/>
<location filename="../restable.cpp" line="+783"/>
<source>&amp;Reset sort</source>
<translation>&amp;Сбросить сортировку</translation>
</message>
@ -2311,7 +2336,7 @@ Please check the desktop file</source>
<translation type="obsolete">&quot;</translation>
</message>
<message>
<location line="-313"/>
<location line="-312"/>
<source>Save table to CSV file</source>
<translation>Сохранить таблицу в CSV-файл</translation>
</message>
@ -2353,7 +2378,7 @@ Please check the desktop file</source>
<translation type="obsolete">&amp;Открыть родительский документ/каталог</translation>
</message>
<message>
<location line="+301"/>
<location line="+300"/>
<source>&amp;Save as CSV</source>
<translation>&amp;Сохранить как CSV</translation>
</message>
@ -2843,8 +2868,12 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
</message>
<message>
<location line="+10"/>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation>Корневой каталог (или использовать стандартный topdirs):</translation>
<translation type="vanished">Корневой каталог (или использовать стандартный topdirs):</translation>
</message>
<message>
<location line="+14"/>
@ -3609,7 +3638,7 @@ This should give higher precedence to the results where the search terms appear
<translation type="obsolete">Просмотр</translation>
</message>
<message>
<location filename="../confgui/confgui.cpp" line="+258"/>
<location filename="../confgui/confgui.cpp" line="+267"/>
<source>Choose</source>
<translation>Выбрать</translation>
</message>
@ -3617,7 +3646,7 @@ This should give higher precedence to the results where the search terms appear
<context>
<name>confgui::ConfParamSLW</name>
<message>
<location line="+54"/>
<location line="+59"/>
<source>+</source>
<translation>+</translation>
</message>

View File

@ -1204,14 +1204,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1241,6 +1233,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2078,10 +2098,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished">Gözat</translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2098,6 +2114,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1221,14 +1221,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1258,6 +1250,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2107,10 +2127,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished">Перегляд</translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2127,6 +2143,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1144,14 +1144,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1181,6 +1173,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -1842,10 +1862,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -1862,6 +1878,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1317,14 +1317,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1354,6 +1346,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2250,10 +2270,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2270,6 +2286,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -1330,14 +1330,6 @@ Please check the desktop file</source>
<source>Content has been indexed for these MIME types:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors/%d total files) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(%d documents/%d files/%d errors) </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Empty or non-existant paths in configuration file. Click Ok to start indexing anyway (absent data will not be purged from the index):
</source>
@ -1367,6 +1359,34 @@ Please check the desktop file</source>
<source>Click Cancel to return to the list.&lt;br&gt;Click Ignore to show the preview anyway (and remember for this session). There is a risk of showing the wrong entry.&lt;br/&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>document</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>errors</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>total files)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RclMainBase</name>
@ -2283,10 +2303,6 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Browse</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory (else use regular topdirs):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Leave empty to select all files. You can use multiple space-separated shell-type patterns.&lt;br&gt;Patterns with embedded spaces should be quoted with double quotes.&lt;br&gt;Can only be used if the start target is set.</source>
<translation type="unfinished"></translation>
@ -2303,6 +2319,10 @@ Use &lt;b&gt;Show Query&lt;/b&gt; link when in doubt about result and see manual
<source>Retry previously failed files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SpellBase</name>

View File

@ -55,20 +55,22 @@ void RclMain::updateIdxStatus()
}
msg += phs + " ";
if (status.phase == DbIxStatus::DBIXS_FILES) {
char cnts[100];
QString sdocs = status.docsdone > 1 ?tr("documents") : tr("document");
QString sfiles = status.filesdone > 1 ? tr("files") : tr("file");
QString serrors = status.fileerrors > 1 ? tr("errors") : tr("error");
QString stats;
if (status.dbtotdocs > 0) {
string format =
qs2utf8s(tr("(%d documents/%d files/%d errors/%d total files) "));
sprintf(cnts, format.c_str(),
status.docsdone, status.filesdone, status.fileerrors,
status.totfiles);
stats = QString("(%1 ") + sdocs + "/%2 " + sfiles +
"/%3 " + serrors + "/%4 " + tr("total files)");
stats = stats.arg(status.docsdone).arg(status.filesdone).
arg(status.fileerrors).arg(status.totfiles);
} else {
string format =
qs2utf8s(tr("(%d documents/%d files/%d errors) "));
sprintf(cnts, format.c_str(),
status.docsdone, status.filesdone, status.fileerrors);
stats = QString("(%1 ") + sdocs + "/%2 " + sfiles +
"/%3 " + serrors + ") ";
stats = stats.arg(status.docsdone).arg(status.filesdone).
arg(status.fileerrors);
}
msg += QString::fromUtf8(cnts) + " ";
msg += stats + " ";
}
string mf;int ecnt = 0;
string fcharset = theconfig->getDefCharset(true);
@ -495,6 +497,8 @@ void RclMain::specialIndex()
args.push_back("-Z");
} else {
args.push_back("-e");
// -e also needs -i, else we don't reindex, just erase
args.push_back("-i");
}
}

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>413</width>
<height>191</height>
<width>610</width>
<height>192</height>
</rect>
</property>
<property name="windowTitle">
@ -70,7 +70,7 @@
<item row="0" column="0">
<widget class="QLabel" name="textLabel1">
<property name="text">
<string>Start directory (else use regular topdirs):</string>
<string>Start directory. Must be part of the indexed tree. Use full indexed area if empty.</string>
</property>
<property name="wordWrap">
<bool>false</bool>

View File

@ -90,9 +90,6 @@
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Enter search terms here.</string>
</property>
</widget>
</item>
<item>

130
src/testmains/trmbox.cpp Normal file
View File

@ -0,0 +1,130 @@
/* 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 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 <unistd.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
#include "rclconfig.h"
#include "rclinit.h"
#include "cstr.h"
#include "mh_mbox.h"
static char *thisprog;
static char usage [] =
"Test driver for mbox walking function\n"
"mh_mbox [-m num] mboxfile\n"
" \n\n"
;
static void
Usage(void)
{
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
exit(1);
}
static RclConfig *config;
static int op_flags;
#define OPT_MOINS 0x1
#define OPT_m 0x2
//#define OPT_t 0x4
int main(int argc, char **argv)
{
string msgnum;
thisprog = argv[0];
argc--; argv++;
while (argc > 0 && **argv == '-') {
(*argv)++;
if (!(**argv))
/* Cas du "adb - core" */
Usage();
while (**argv)
switch (*(*argv)++) {
case 'm': op_flags |= OPT_m; if (argc < 2) Usage();
msgnum = *(++argv);
argc--;
goto b1;
// case 't': op_flags |= OPT_t;break;
default: Usage(); break;
}
b1: argc--; argv++;
}
if (argc != 1)
Usage();
string filename = *argv++;argc--;
string reason;
config = recollinit(RclInitFlags(0), 0, 0, reason, 0);
if (config == 0) {
cerr << "init failed " << reason << endl;
exit(1);
}
config->setKeyDir(path_getfather(filename));
MimeHandlerMbox mh(config, "some_id");
if (!mh.set_document_file("text/x-mail", filename)) {
cerr << "set_document_file failed" << endl;
exit(1);
}
if (!msgnum.empty()) {
mh.skip_to_document(msgnum);
if (!mh.next_document()) {
cerr << "next_document failed after skipping to " << msgnum << endl;
exit(1);
}
map<string, string>::const_iterator it =
mh.get_meta_data().find(cstr_dj_keycontent);
int size;
if (it == mh.get_meta_data().end()) {
size = -1;
cerr << "No content!!" << endl;
exit(1);
}
cout << "Doc " << msgnum << ":" << endl;
cout << it->second << endl;
exit(0);
}
int docnt = 0;
while (mh.has_documents()) {
if (!mh.next_document()) {
cerr << "next_document failed" << endl;
exit(1);
}
docnt++;
map<string, string>::const_iterator it =
mh.get_meta_data().find(cstr_dj_keycontent);
int size;
if (it == mh.get_meta_data().end()) {
size = -1;
} else {
size = it->second.length();
}
cout << "Doc " << docnt << " size " << size << endl;
}
cout << docnt << " documents found in " << filename << endl;
exit(0);
}

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 Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
@ -57,9 +57,9 @@
#include "safesysstat.h"
#include "transcode.h"
#define STAT _wstat
#define LSTAT _wstat
#define STATBUF _stat
#define STAT _wstati64
#define LSTAT _wstati64
#define STATBUF _stati64
#define ACCESS _waccess
#else // Not windows ->
@ -654,18 +654,18 @@ bool path_makepath(const string& ipath, int mode)
vector<string> elems;
stringToTokens(path, elems, "/");
path = "/";
for (vector<string>::const_iterator it = elems.begin();
it != elems.end(); it++) {
for (const auto& elem : elems) {
#ifdef _WIN32
if (it == elems.begin() && path_strlookslikedrive(*it)) {
if (path == "/" && path_strlookslikedrive(elem)) {
path = "";
}
#endif
path += *it;
path += elem;
// Not using path_isdir() here, because this cant grok symlinks
// If we hit an existing file, no worry, mkdir will just fail.
if (access(path.c_str(), 0) != 0) {
if (mkdir(path.c_str(), mode) != 0) {
//cerr << "mkdir " << path << " failed, errno " << errno << endl;
return false;
}
}

View File

@ -83,7 +83,7 @@ static bool path_isdriveabs(const string& s)
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
string path_thisexecpath()
static string path_thisexecpath()
{
wchar_t text[MAX_PATH];
GetModuleFileNameW(NULL, text, MAX_PATH);
@ -100,13 +100,16 @@ string path_thisexecpath()
return path;
}
string path_wingettempfilename(wchar_t *pref)
// On Windows, we ese a subdirectory named "rcltmp" inside the windows
// temp location to create the temporary files in.
static const string& path_wingetrcltmpdir()
{
// Use a subdirectory named "rcltmp" inside the windows temp
// location.
// Constant: only need to compute once
static string tdir;
if (tdir.empty()) {
wchar_t dbuf[MAX_PATH + 1];
GetTempPathW(MAX_PATH + 1, dbuf);
string tdir;
wchartoutf8(dbuf, tdir);
tdir = path_cat(tdir, "rcltmp");;
if (!path_exists(tdir)) {
@ -114,11 +117,21 @@ string path_wingettempfilename(wchar_t *pref)
LOGSYSERR("path_wingettempfilename", "path_makepath", tdir);
}
}
}
return tdir;
}
static bool path_gettempfilename(string& filename, string& reason)
{
string tdir = path_wingetrcltmpdir();
wchar_t dbuf[MAX_PATH + 1];
utf8towchar(tdir, dbuf, MAX_PATH);
wchar_t buf[MAX_PATH + 1];
GetTempFileNameW(dbuf, pref, 0, buf);
string filename;
static wchar_t prefix[]{L"rcl"};
GetTempFileNameW(dbuf, prefix, 0, buf);
wchartoutf8(buf, filename);
// Windows will have created a temp file, we delete it.
if (!DeleteFileW(buf)) {
LOGSYSERR("path_wingettempfilename", "DeleteFileW", filename);
@ -126,10 +139,35 @@ string path_wingettempfilename(wchar_t *pref)
LOGDEB1("path_wingettempfilename: DeleteFile " << filename << " Ok\n");
}
path_slashize(filename);
return filename;
return true;
}
#endif // _WIN32
#else // _WIN32 above
static bool path_gettempfilename(string& filename, string& reason)
{
filename = path_cat(tmplocation(), "rcltmpfXXXXXX");
char *cp = strdup(filename.c_str());
if (!cp) {
reason = "Out of memory (for file name !)\n";
return false;
}
// Using mkstemp this way is awful (bot the suffix adding and
// using mkstemp() instead of mktemp just to avoid the warnings)
int fd;
if ((fd = mkstemp(cp)) < 0) {
free(cp);
reason = "TempFileInternal: mkstemp failed\n";
return false;
}
close(fd);
unlink(cp);
filename = cp;
free(cp);
return true;
}
#endif // posix
// Check if path is either non-existing or an empty directory.
bool path_empty(const string& path)
@ -259,7 +297,7 @@ bool maketmpdir(string& tdir, string& reason)
// There is a race condition between name computation and
// mkdir. try to make sure that we at least don't shoot ourselves
// in the foot
#if !defined(HAVE_MKDTEMP) || defined(_WIN32)
#if !defined(HAVE_MKDTEMP)
static std::mutex mmutex;
std::unique_lock<std::mutex> lock(mmutex);
#endif
@ -285,8 +323,9 @@ bool maketmpdir(string& tdir, string& reason)
// in the foot
static std::mutex mmutex;
std::unique_lock<std::mutex> lock(mmutex);
static wchar_t tmpbasename[]{L"rcltmp"};
tdir = path_wingettempfilename(tmpbasename);
if (!path_gettempfilename(tdir, reason)) {
return false;
}
#endif
// At this point the directory does not exist yet except if we used
@ -356,32 +395,10 @@ TempFile::Internal::Internal(const string& suffix)
static std::mutex mmutex;
std::unique_lock<std::mutex> lock(mmutex);
#ifndef _WIN32
string filename = path_cat(tmplocation(), "rcltmpfXXXXXX");
char *cp = strdup(filename.c_str());
if (!cp) {
m_reason = "Out of memory (for file name !)\n";
if (!path_gettempfilename(m_filename, m_reason)) {
return;
}
// Using mkstemp this way is awful (bot the suffix adding and
// using mkstemp() instead of mktemp just to avoid the warnings)
int fd;
if ((fd = mkstemp(cp)) < 0) {
free(cp);
m_reason = "TempFileInternal: mkstemp failed\n";
return;
}
close(fd);
unlink(cp);
filename = cp;
free(cp);
#else
static wchar_t tmpbasename[]{L"rcl"};
string filename = path_wingettempfilename(tmpbasename);
#endif
m_filename = filename + suffix;
m_filename += suffix;
LOGDEB1("TempFile: filename: " << m_filename << endl);
int fd1 = open(m_filename.c_str(), O_CREAT | O_EXCL, 0600);
if (fd1 < 0) {
@ -393,6 +410,15 @@ TempFile::Internal::Internal(const string& suffix)
}
}
const std::string& TempFile::rcltmpdir()
{
#ifdef _WIN32
return path_wingetrcltmpdir();
#else
return tmplocation();
#endif
}
#ifdef _WIN32
static list<string> remainingTempFileNames;
static std::mutex remTmpFNMutex;

View File

@ -63,6 +63,10 @@ public:
// process). Called after clearing the mimeHandler cache. Does
// nothing if not _WIN32
static void tryRemoveAgain();
// Also for Windows: for adding the temp files path to the default
// skippedPaths
static const std::string& rcltmpdir();
class Internal;
private:
std::shared_ptr<Internal> m;

View File

@ -1283,7 +1283,7 @@ bool SimpleRegexp::simpleMatch(const string& val) const
{
if (!ok())
return false;
return regex_match(val, m->res, m->expr);
return regex_search(val, m->res, m->expr);
}
string SimpleRegexp::getMatch(const string& val, int i) const