Switch to unified view

a/src/common/rclconfig.cpp b/src/common/rclconfig.cpp
...
...
204
      m_mdrstate(this, "metadatacmds")
204
      m_mdrstate(this, "metadatacmds")
205
{
205
{
206
    zeroMe();
206
    zeroMe();
207
207
208
    if (o_origcwd.empty()) {
208
    if (o_origcwd.empty()) {
209
  char buf[MAXPATHLEN];
209
        char buf[MAXPATHLEN];
210
  if (getcwd(buf, MAXPATHLEN)) {
210
        if (getcwd(buf, MAXPATHLEN)) {
211
      o_origcwd = string(buf);
211
            o_origcwd = string(buf);
212
  } else {
212
        } else {
213
      fprintf(stderr, "recollxx: can't retrieve current working "
213
            fprintf(stderr, "recollxx: can't retrieve current working "
214
                    "directory: relative path translations will fail\n");
214
                    "directory: relative path translations will fail\n");
215
  }
215
        }
216
    }
216
    }
217
217
218
    // Compute our data dir name, typically /usr/local/share/recoll
218
    // Compute our data dir name, typically /usr/local/share/recoll
219
    m_datadir = path_pkgdatadir();
219
    m_datadir = path_pkgdatadir();
220
    // We only do the automatic configuration creation thing for the default
220
    // We only do the automatic configuration creation thing for the default
221
    // config dir, not if it was specified through -c or RECOLL_CONFDIR
221
    // config dir, not if it was specified through -c or RECOLL_CONFDIR
222
    bool autoconfdir = false;
222
    bool autoconfdir = false;
223
223
224
    // Command line config name overrides environment
224
    // Command line config name overrides environment
225
    if (argcnf && !argcnf->empty()) {
225
    if (argcnf && !argcnf->empty()) {
226
  m_confdir = path_absolute(*argcnf);
226
        m_confdir = path_absolute(*argcnf);
227
  if (m_confdir.empty()) {
227
        if (m_confdir.empty()) {
228
      m_reason = 
228
            m_reason = 
229
      string("Cant turn [") + *argcnf + "] into absolute path";
229
                string("Cant turn [") + *argcnf + "] into absolute path";
230
      return;
230
            return;
231
  }
231
        }
232
    } else {
232
    } else {
233
  const char *cp = getenv("RECOLL_CONFDIR");
233
        const char *cp = getenv("RECOLL_CONFDIR");
234
  if (cp) {
234
        if (cp) {
235
      m_confdir = path_canon(cp);
235
            m_confdir = path_canon(cp);
236
  } else {
236
        } else {
237
      autoconfdir = true;
237
            autoconfdir = true;
238
      m_confdir=path_cat(path_homedata(), path_defaultrecollconfsubdir());
238
            m_confdir=path_cat(path_homedata(), path_defaultrecollconfsubdir());
239
  }
239
        }
240
    }
240
    }
241
241
242
    // Note: autoconfdir and isDefaultConfig() are normally the same. We just 
242
    // Note: autoconfdir and isDefaultConfig() are normally the same. We just 
243
    // want to avoid the imperfect test in isDefaultConfig() if we actually know
243
    // want to avoid the imperfect test in isDefaultConfig() if we actually know
244
    // this is the default conf
244
    // this is the default conf
245
    if (!autoconfdir && !isDefaultConfig()) {
245
    if (!autoconfdir && !isDefaultConfig()) {
246
  if (!path_exists(m_confdir)) {
246
        if (!path_exists(m_confdir)) {
247
      m_reason = "Explicitly specified configuration "
247
            m_reason = "Explicitly specified configuration "
248
      "directory must exist"
248
                "directory must exist"
249
      " (won't be automatically created). Use mkdir first";
249
                " (won't be automatically created). Use mkdir first";
250
      return;
250
            return;
251
  }
251
        }
252
    }
252
    }
253
253
254
    if (!path_exists(m_confdir)) {
254
    if (!path_exists(m_confdir)) {
255
  if (!initUserConfig()) 
255
        if (!initUserConfig()) 
256
      return;
256
            return;
257
    }
257
    }
258
258
259
    // This can't change once computed inside a process. It would be
259
    // This can't change once computed inside a process. It would be
260
    // nicer to move this to a static class initializer to avoid
260
    // nicer to move this to a static class initializer to avoid
261
    // possible threading issues but this doesn't work (tried) as
261
    // possible threading issues but this doesn't work (tried) as
262
    // things would not be ready. In practise we make sure that this
262
    // things would not be ready. In practise we make sure that this
263
    // is called from the main thread at once, by constructing a config
263
    // is called from the main thread at once, by constructing a config
264
    // from recollinit
264
    // from recollinit
265
    if (o_localecharset.empty()) {
265
    if (o_localecharset.empty()) {
266
#ifndef _WIN32
266
#ifndef _WIN32
267
  const char *cp;
267
        const char *cp;
268
  cp = nl_langinfo(CODESET);
268
        cp = nl_langinfo(CODESET);
269
  // We don't keep US-ASCII. It's better to use a superset
269
        // We don't keep US-ASCII. It's better to use a superset
270
  // Ie: me have a C locale and some french file names, and I
270
        // Ie: me have a C locale and some french file names, and I
271
  // can't imagine a version of iconv that couldn't translate
271
        // can't imagine a version of iconv that couldn't translate
272
  // from iso8859?
272
        // from iso8859?
273
  // The 646 thing is for solaris. 
273
        // The 646 thing is for solaris. 
274
  if (cp && *cp && strcmp(cp, "US-ASCII") 
274
        if (cp && *cp && strcmp(cp, "US-ASCII") 
275
#ifdef sun
275
#ifdef sun
276
      && strcmp(cp, "646")
276
            && strcmp(cp, "646")
277
#endif
277
#endif
278
      ) {
278
            ) {
279
      o_localecharset = string(cp);
279
            o_localecharset = string(cp);
280
  } else {
280
        } else {
281
      // Use cp1252 instead of iso-8859-1, it's a superset.
281
            // Use cp1252 instead of iso-8859-1, it's a superset.
282
      o_localecharset = string(cstr_cp1252);
282
            o_localecharset = string(cstr_cp1252);
283
  }
283
        }
284
#else
284
#else
285
        o_localecharset = winACPName();
285
        o_localecharset = winACPName();
286
#endif
286
#endif
287
  LOGDEB1("RclConfig::getDefCharset: localecharset ["  <<
287
        LOGDEB1("RclConfig::getDefCharset: localecharset ["  <<
288
                o_localecharset << "]\n");
288
                o_localecharset << "]\n");
289
    }
289
    }
290
290
291
    const char *cp;
291
    const char *cp;
292
292
293
    // Additional config directory, values override user ones
293
    // Additional config directory, values override user ones
294
    if ((cp = getenv("RECOLL_CONFTOP"))) {
294
    if ((cp = getenv("RECOLL_CONFTOP"))) {
295
  m_cdirs.push_back(cp);
295
        m_cdirs.push_back(cp);
296
    } 
296
    } 
297
297
298
    // User config
298
    // User config
299
    m_cdirs.push_back(m_confdir);
299
    m_cdirs.push_back(m_confdir);
300
300
301
    // Additional config directory, overrides system's, overridden by user's
301
    // Additional config directory, overrides system's, overridden by user's
302
    if ((cp = getenv("RECOLL_CONFMID"))) {
302
    if ((cp = getenv("RECOLL_CONFMID"))) {
303
  m_cdirs.push_back(cp);
303
        m_cdirs.push_back(cp);
304
    } 
304
    } 
305
305
306
    // Base/installation config
306
    // Base/installation config
307
    m_cdirs.push_back(path_cat(m_datadir, "examples"));
307
    m_cdirs.push_back(path_cat(m_datadir, "examples"));
308
308
309
    string cnferrloc;
309
    string cnferrloc;
310
    for (vector<string>::const_iterator it = m_cdirs.begin();
310
    for (vector<string>::const_iterator it = m_cdirs.begin();
311
   it != m_cdirs.end(); it++) {
311
         it != m_cdirs.end(); it++) {
312
  if (it != m_cdirs.begin())
312
        if (it != m_cdirs.begin())
313
      cnferrloc += string(" or ");
313
            cnferrloc += string(" or ");
314
  cnferrloc += *it;
314
        cnferrloc += *it;
315
    }
315
    }
316
316
317
    // Read and process "recoll.conf"
317
    // Read and process "recoll.conf"
318
    if (!updateMainConfig())
318
    if (!updateMainConfig())
319
  return;
319
        return;
320
    // Other files
320
    // Other files
321
    mimemap = new ConfStack<ConfTree>("mimemap", m_cdirs, true);
321
    mimemap = new ConfStack<ConfTree>("mimemap", m_cdirs, true);
322
    if (mimemap == 0 || !mimemap->ok()) {
322
    if (mimemap == 0 || !mimemap->ok()) {
323
  m_reason = string("No or bad mimemap file in: ") + cnferrloc;
323
        m_reason = string("No or bad mimemap file in: ") + cnferrloc;
324
  return;
324
        return;
325
    }
325
    }
326
326
327
    // Maybe create the MIME to suffix association reverse map. Do it
327
    // Maybe create the MIME to suffix association reverse map. Do it
328
    // in file order so that we can control what suffix is used when
328
    // in file order so that we can control what suffix is used when
329
    // there are several. This only uses the distributed file, not any
329
    // there are several. This only uses the distributed file, not any
...
...
344
        }
344
        }
345
    }
345
    }
346
346
347
    mimeconf = new ConfStack<ConfSimple>("mimeconf", m_cdirs, true);
347
    mimeconf = new ConfStack<ConfSimple>("mimeconf", m_cdirs, true);
348
    if (mimeconf == 0 || !mimeconf->ok()) {
348
    if (mimeconf == 0 || !mimeconf->ok()) {
349
  m_reason = string("No/bad mimeconf in: ") + cnferrloc;
349
        m_reason = string("No/bad mimeconf in: ") + cnferrloc;
350
  return;
350
        return;
351
    }
351
    }
352
    mimeview = new ConfStack<ConfSimple>("mimeview", m_cdirs, false);
352
    mimeview = new ConfStack<ConfSimple>("mimeview", m_cdirs, false);
353
    if (mimeview == 0)
353
    if (mimeview == 0)
354
  mimeview = new ConfStack<ConfSimple>("mimeview", m_cdirs, true);
354
        mimeview = new ConfStack<ConfSimple>("mimeview", m_cdirs, true);
355
    if (mimeview == 0 || !mimeview->ok()) {
355
    if (mimeview == 0 || !mimeview->ok()) {
356
  m_reason = string("No/bad mimeview in: ") + cnferrloc;
356
        m_reason = string("No/bad mimeview in: ") + cnferrloc;
357
  return;
357
        return;
358
    }
358
    }
359
    if (!readFieldsConfig(cnferrloc))
359
    if (!readFieldsConfig(cnferrloc))
360
  return;
360
        return;
361
361
362
    // Default is no threading
362
    // Default is no threading
363
    m_thrConf = {{-1, 0}, {-1, 0}, {-1, 0}};
363
    m_thrConf = {{-1, 0}, {-1, 0}, {-1, 0}};
364
364
365
    m_ptrans = new ConfSimple(path_cat(m_confdir, "ptrans").c_str());
365
    m_ptrans = new ConfSimple(path_cat(m_confdir, "ptrans").c_str());
...
...
373
}
373
}
374
374
375
bool RclConfig::updateMainConfig()
375
bool RclConfig::updateMainConfig()
376
{
376
{
377
    ConfStack<ConfTree> *newconf = 
377
    ConfStack<ConfTree> *newconf = 
378
  new ConfStack<ConfTree>("recoll.conf", m_cdirs, true);
378
        new ConfStack<ConfTree>("recoll.conf", m_cdirs, true);
379
    if (newconf == 0 || !newconf->ok()) {
379
    if (newconf == 0 || !newconf->ok()) {
380
  if (m_conf)
380
        if (m_conf)
381
      return false;
381
            return false;
382
  string where;
382
        string where;
383
  stringsToString(m_cdirs, where);
383
        stringsToString(m_cdirs, where);
384
  m_reason = string("No/bad main configuration file in: ") + where;
384
        m_reason = string("No/bad main configuration file in: ") + where;
385
  m_ok = false;
385
        m_ok = false;
386
        initParamStale(0, 0);
386
        initParamStale(0, 0);
387
  return false;
387
        return false;
388
    }
388
    }
389
389
390
    delete m_conf;
390
    delete m_conf;
391
    m_conf = newconf;
391
    m_conf = newconf;
392
392
...
...
394
394
395
    setKeyDir(cstr_null);
395
    setKeyDir(cstr_null);
396
396
397
    bool bvalue = false;
397
    bool bvalue = false;
398
    if (getConfParam("nocjk", &bvalue) && bvalue == true) {
398
    if (getConfParam("nocjk", &bvalue) && bvalue == true) {
399
  TextSplit::cjkProcessing(false);
399
        TextSplit::cjkProcessing(false);
400
    } else {
400
    } else {
401
  int ngramlen;
401
        int ngramlen;
402
  if (getConfParam("cjkngramlen", &ngramlen)) {
402
        if (getConfParam("cjkngramlen", &ngramlen)) {
403
      TextSplit::cjkProcessing(true, (unsigned int)ngramlen);
403
            TextSplit::cjkProcessing(true, (unsigned int)ngramlen);
404
  } else {
404
        } else {
405
      TextSplit::cjkProcessing(true);
405
            TextSplit::cjkProcessing(true);
406
  }
406
        }
407
    }
407
    }
408
408
409
    bvalue = false;
409
    bvalue = false;
410
    if (getConfParam("nonumbers", &bvalue) && bvalue == true) {
410
    if (getConfParam("nonumbers", &bvalue) && bvalue == true) {
411
  TextSplit::noNumbers();
411
        TextSplit::noNumbers();
412
    }
412
    }
413
413
414
    bvalue = false;
414
    bvalue = false;
415
    if (getConfParam("dehyphenate", &bvalue)) {
415
    if (getConfParam("dehyphenate", &bvalue)) {
416
  TextSplit::deHyphenate(bvalue);
416
        TextSplit::deHyphenate(bvalue);
417
    }
417
    }
418
418
419
    bvalue = true;
419
    bvalue = true;
420
    if (getConfParam("skippedPathsFnmPathname", &bvalue) && bvalue == false) {
420
    if (getConfParam("skippedPathsFnmPathname", &bvalue) && bvalue == false) {
421
  FsTreeWalker::setNoFnmPathname();
421
        FsTreeWalker::setNoFnmPathname();
422
    }
422
    }
423
423
424
    static int m_index_stripchars_init = 0;
424
    static int m_index_stripchars_init = 0;
425
    if (!m_index_stripchars_init) {
425
    if (!m_index_stripchars_init) {
426
  getConfParam("indexStripChars", &o_index_stripchars);
426
        getConfParam("indexStripChars", &o_index_stripchars);
427
        getConfParam("indexStoreDocText", &o_index_storedoctext);
427
        getConfParam("indexStoreDocText", &o_index_storedoctext);
428
        getConfParam("testmodifusemtime", &o_uptodate_test_use_mtime);
428
        getConfParam("testmodifusemtime", &o_uptodate_test_use_mtime);
429
  m_index_stripchars_init = 1;
429
        m_index_stripchars_init = 1;
430
    }
430
    }
431
431
432
    if (getConfParam("cachedir", m_cachedir)) {
432
    if (getConfParam("cachedir", m_cachedir)) {
433
        m_cachedir = path_canon(path_tildexpand(m_cachedir));
433
        m_cachedir = path_canon(path_tildexpand(m_cachedir));
434
    }
434
    }
...
...
437
437
438
ConfNull *RclConfig::cloneMainConfig()
438
ConfNull *RclConfig::cloneMainConfig()
439
{
439
{
440
    ConfNull *conf = new ConfStack<ConfTree>("recoll.conf", m_cdirs, false);
440
    ConfNull *conf = new ConfStack<ConfTree>("recoll.conf", m_cdirs, false);
441
    if (conf == 0 || !conf->ok()) {
441
    if (conf == 0 || !conf->ok()) {
442
  m_reason = string("Can't read config");
442
        m_reason = string("Can't read config");
443
  return 0;
443
        return 0;
444
    }
444
    }
445
    return conf;
445
    return conf;
446
}
446
}
447
447
448
// Remember what directory we're under (for further conf->get()s), and 
448
// Remember what directory we're under (for further conf->get()s), and 
...
...
453
        return;
453
        return;
454
454
455
    m_keydirgen++;
455
    m_keydirgen++;
456
    m_keydir = dir;
456
    m_keydir = dir;
457
    if (m_conf == 0)
457
    if (m_conf == 0)
458
  return;
458
        return;
459
459
460
    if (!m_conf->get("defaultcharset", m_defcharset, m_keydir))
460
    if (!m_conf->get("defaultcharset", m_defcharset, m_keydir))
461
  m_defcharset.erase();
461
        m_defcharset.erase();
462
}
462
}
463
463
464
bool RclConfig::getConfParam(const string &name, int *ivp, bool shallow) const
464
bool RclConfig::getConfParam(const string &name, int *ivp, bool shallow) const
465
{
465
{
466
    string value;
466
    string value;
467
    if (!getConfParam(name, value, shallow))
467
    if (!getConfParam(name, value, shallow))
468
  return false;
468
        return false;
469
    errno = 0;
469
    errno = 0;
470
    long lval = strtol(value.c_str(), 0, 0);
470
    long lval = strtol(value.c_str(), 0, 0);
471
    if (lval == 0 && errno)
471
    if (lval == 0 && errno)
472
  return 0;
472
        return 0;
473
    if (ivp)
473
    if (ivp)
474
  *ivp = int(lval);
474
        *ivp = int(lval);
475
    return true;
475
    return true;
476
}
476
}
477
477
478
bool RclConfig::getConfParam(const string &name, bool *bvp, bool shallow) const
478
bool RclConfig::getConfParam(const string &name, bool *bvp, bool shallow) const
479
{
479
{
480
    if (!bvp) 
480
    if (!bvp) 
481
  return false;
481
        return false;
482
482
483
    *bvp = false;
483
    *bvp = false;
484
    string s;
484
    string s;
485
    if (!getConfParam(name, s, shallow))
485
    if (!getConfParam(name, s, shallow))
486
  return false;
486
        return false;
487
    *bvp = stringToBool(s);
487
    *bvp = stringToBool(s);
488
    return true;
488
    return true;
489
}
489
}
490
490
491
bool RclConfig::getConfParam(const string &name, vector<string> *svvp,
491
bool RclConfig::getConfParam(const string &name, vector<string> *svvp,
492
                             bool shallow) const
492
                             bool shallow) const
493
{
493
{
494
    if (!svvp) 
494
    if (!svvp) 
495
  return false;
495
        return false;
496
    svvp->clear();
496
    svvp->clear();
497
    string s;
497
    string s;
498
    if (!getConfParam(name, s, shallow))
498
    if (!getConfParam(name, s, shallow))
499
  return false;
499
        return false;
500
    return stringToStrings(s, *svvp);
500
    return stringToStrings(s, *svvp);
501
}
501
}
502
502
503
bool RclConfig::getConfParam(const string &name, unordered_set<string> *out,
503
bool RclConfig::getConfParam(const string &name, unordered_set<string> *out,
504
                             bool shallow) const
504
                             bool shallow) const
505
{
505
{
506
    vector<string> v;
506
    vector<string> v;
507
    if (!out || !getConfParam(name, &v, shallow)) {
507
    if (!out || !getConfParam(name, &v, shallow)) {
508
  return false;
508
        return false;
509
    }
509
    }
510
    out->clear();
510
    out->clear();
511
    out->insert(v.begin(), v.end());
511
    out->insert(v.begin(), v.end());
512
    return true;
512
    return true;
513
}
513
}
514
514
515
bool RclConfig::getConfParam(const string &name, vector<int> *vip,
515
bool RclConfig::getConfParam(const string &name, vector<int> *vip,
516
                             bool shallow) const
516
                             bool shallow) const
517
{
517
{
518
    if (!vip) 
518
    if (!vip) 
519
  return false;
519
        return false;
520
    vip->clear();
520
    vip->clear();
521
    vector<string> vs;
521
    vector<string> vs;
522
    if (!getConfParam(name, &vs, shallow))
522
    if (!getConfParam(name, &vs, shallow))
523
  return false;
523
        return false;
524
    vip->reserve(vs.size());
524
    vip->reserve(vs.size());
525
    for (unsigned int i = 0; i < vs.size(); i++) {
525
    for (unsigned int i = 0; i < vs.size(); i++) {
526
  char *ep;
526
        char *ep;
527
  vip->push_back(strtol(vs[i].c_str(), &ep, 0));
527
        vip->push_back(strtol(vs[i].c_str(), &ep, 0));
528
  if (ep == vs[i].c_str()) {
528
        if (ep == vs[i].c_str()) {
529
      LOGDEB("RclConfig::getConfParam: bad int value in [" << name <<
529
            LOGDEB("RclConfig::getConfParam: bad int value in [" << name <<
530
                   "]\n");
530
                   "]\n");
531
      return false;
531
            return false;
532
  }
532
        }
533
    }
533
    }
534
    return true;
534
    return true;
535
}
535
}
536
536
537
void RclConfig::initThrConf()
537
void RclConfig::initThrConf()
...
...
540
    m_thrConf = {{-1, 0}, {-1, 0}, {-1, 0}};
540
    m_thrConf = {{-1, 0}, {-1, 0}, {-1, 0}};
541
541
542
    vector<int> vq;
542
    vector<int> vq;
543
    vector<int> vt;
543
    vector<int> vt;
544
    if (!getConfParam("thrQSizes", &vq)) {
544
    if (!getConfParam("thrQSizes", &vq)) {
545
  LOGINFO("RclConfig::initThrConf: no thread info (queues)\n");
545
        LOGINFO("RclConfig::initThrConf: no thread info (queues)\n");
546
  goto out;
546
        goto out;
547
    }
547
    }
548
548
549
    // If the first queue size is 0, autoconf is requested.
549
    // If the first queue size is 0, autoconf is requested.
550
    if (vq.size() > 0 && vq[0] == 0) {
550
    if (vq.size() > 0 && vq[0] == 0) {
551
  CpuConf cpus;
551
        CpuConf cpus;
552
  if (!getCpuConf(cpus) || cpus.ncpus < 1) {
552
        if (!getCpuConf(cpus) || cpus.ncpus < 1) {
553
      LOGERR("RclConfig::initThrConf: could not retrieve cpu conf\n");
553
            LOGERR("RclConfig::initThrConf: could not retrieve cpu conf\n");
554
      cpus.ncpus = 1;
554
            cpus.ncpus = 1;
555
  }
555
        }
556
        if (cpus.ncpus != 1) {
556
        if (cpus.ncpus != 1) {
557
            LOGDEB("RclConfig::initThrConf: autoconf requested. " <<
557
            LOGDEB("RclConfig::initThrConf: autoconf requested. " <<
558
                   cpus.ncpus << " concurrent threads available.\n");
558
                   cpus.ncpus << " concurrent threads available.\n");
559
        }
559
        }
560
560
561
  // Arbitrarily set threads config based on number of CPUS. This also
561
        // Arbitrarily set threads config based on number of CPUS. This also
562
  // depends on the IO setup actually, so we're bound to be wrong...
562
        // depends on the IO setup actually, so we're bound to be wrong...
563
  if (cpus.ncpus == 1) {
563
        if (cpus.ncpus == 1) {
564
      // Somewhat counter-intuitively (because of possible IO//)
564
            // Somewhat counter-intuitively (because of possible IO//)
565
      // it seems that the best config here is no threading
565
            // it seems that the best config here is no threading
566
  } else if (cpus.ncpus < 4) {
566
        } else if (cpus.ncpus < 4) {
567
      // Untested so let's guess...
567
            // Untested so let's guess...
568
            m_thrConf = {{2, 2}, {2, 2}, {2, 1}};
568
            m_thrConf = {{2, 2}, {2, 2}, {2, 1}};
569
  } else if (cpus.ncpus < 6) {
569
        } else if (cpus.ncpus < 6) {
570
      m_thrConf = {{2, 4}, {2, 2}, {2, 1}};
570
            m_thrConf = {{2, 4}, {2, 2}, {2, 1}};
571
  } else {
571
        } else {
572
      m_thrConf = {{2, 5}, {2, 3}, {2, 1}};
572
            m_thrConf = {{2, 5}, {2, 3}, {2, 1}};
573
  }
573
        }
574
  goto out;
574
        goto out;
575
    } else if (vq.size() > 0 && vq[0] < 0) {
575
    } else if (vq.size() > 0 && vq[0] < 0) {
576
  // threads disabled by config
576
        // threads disabled by config
577
  goto out;
577
        goto out;
578
    }
578
    }
579
579
580
    if (!getConfParam("thrTCounts", &vt) ) {
580
    if (!getConfParam("thrTCounts", &vt) ) {
581
  LOGINFO("RclConfig::initThrConf: no thread info (threads)\n");
581
        LOGINFO("RclConfig::initThrConf: no thread info (threads)\n");
582
  goto out;
582
        goto out;
583
    }
583
    }
584
584
585
    if (vq.size() != 3 || vt.size() != 3) {
585
    if (vq.size() != 3 || vt.size() != 3) {
586
  LOGINFO("RclConfig::initThrConf: bad thread info vector sizes\n");
586
        LOGINFO("RclConfig::initThrConf: bad thread info vector sizes\n");
587
  goto out;
587
        goto out;
588
    }
588
    }
589
589
590
    // Normal case: record info from config
590
    // Normal case: record info from config
591
    m_thrConf.clear();
591
    m_thrConf.clear();
592
    for (unsigned int i = 0; i < 3; i++) {
592
    for (unsigned int i = 0; i < 3; i++) {
593
  m_thrConf.push_back({vq[i], vt[i]});
593
        m_thrConf.push_back({vq[i], vt[i]});
594
    }
594
    }
595
595
596
out:
596
out:
597
    ostringstream sconf;
597
    ostringstream sconf;
598
    for (unsigned int i = 0; i < 3; i++) {
598
    for (unsigned int i = 0; i < 3; i++) {
599
  sconf << "(" << m_thrConf[i].first << ", " << m_thrConf[i].second <<
599
        sconf << "(" << m_thrConf[i].first << ", " << m_thrConf[i].second <<
600
      ") ";
600
            ") ";
601
    }
601
    }
602
602
603
    LOGDEB("RclConfig::initThrConf: chosen config (ql,nt): " << sconf.str() <<
603
    LOGDEB("RclConfig::initThrConf: chosen config (ql,nt): " << sconf.str() <<
604
           "\n");
604
           "\n");
605
}
605
}
606
606
607
pair<int,int> RclConfig::getThrConf(ThrStage who) const
607
pair<int,int> RclConfig::getThrConf(ThrStage who) const
608
{
608
{
609
    if (m_thrConf.size() != 3) {
609
    if (m_thrConf.size() != 3) {
610
  LOGERR("RclConfig::getThrConf: bad data in rclconfig\n");
610
        LOGERR("RclConfig::getThrConf: bad data in rclconfig\n");
611
  return pair<int,int>(-1,-1);
611
        return pair<int,int>(-1,-1);
612
    }
612
    }
613
    return m_thrConf[who];
613
    return m_thrConf[who];
614
}
614
}
615
615
616
vector<string> RclConfig::getTopdirs(bool formonitor) const
616
vector<string> RclConfig::getTopdirs(bool formonitor) const
...
...
622
        }
622
        }
623
    } else {
623
    } else {
624
        getConfParam("topdirs", &tdl);
624
        getConfParam("topdirs", &tdl);
625
    }
625
    }
626
    if (tdl.empty()) {
626
    if (tdl.empty()) {
627
  LOGERR("RclConfig::getTopdirs: nothing to index:  topdirs/monitordirs "
627
        LOGERR("RclConfig::getTopdirs: nothing to index:  topdirs/monitordirs "
628
               " are not set or have a bad list format\n");
628
               " are not set or have a bad list format\n");
629
  return tdl;
629
        return tdl;
630
    }
630
    }
631
631
632
    for (auto& dir : tdl) {
632
    for (auto& dir : tdl) {
633
  dir = path_canon(path_tildexpand(dir));
633
        dir = path_canon(path_tildexpand(dir));
634
    }
634
    }
635
    return tdl;
635
    return tdl;
636
}
636
}
637
637
638
const string& RclConfig::getLocaleCharset()
638
const string& RclConfig::getLocaleCharset()
...
...
650
// For filenames, same thing except that we do not use the config file value
650
// For filenames, same thing except that we do not use the config file value
651
// (only the locale).
651
// (only the locale).
652
const string& RclConfig::getDefCharset(bool filename) const
652
const string& RclConfig::getDefCharset(bool filename) const
653
{
653
{
654
    if (filename) {
654
    if (filename) {
655
  return o_localecharset;
655
        return o_localecharset;
656
    } else {
656
    } else {
657
  return m_defcharset.empty() ? o_localecharset : m_defcharset;
657
        return m_defcharset.empty() ? o_localecharset : m_defcharset;
658
    }
658
    }
659
}
659
}
660
660
661
// Get all known document mime values. We get them from the mimeconf
661
// Get all known document mime values. We get them from the mimeconf
662
// 'index' submap.
662
// 'index' submap.
...
...
676
// comparison with suffix-only sensitivity
676
// comparison with suffix-only sensitivity
677
class SfString {
677
class SfString {
678
public:
678
public:
679
    SfString(const string& s) : m_str(s) {}
679
    SfString(const string& s) : m_str(s) {}
680
    bool operator==(const SfString& s2) {
680
    bool operator==(const SfString& s2) {
681
  string::const_reverse_iterator r1 = m_str.rbegin(), re1 = m_str.rend(),
681
        string::const_reverse_iterator r1 = m_str.rbegin(), re1 = m_str.rend(),
682
      r2 = s2.m_str.rbegin(), re2 = s2.m_str.rend();
682
            r2 = s2.m_str.rbegin(), re2 = s2.m_str.rend();
683
  while (r1 != re1 && r2 != re2) {
683
        while (r1 != re1 && r2 != re2) {
684
      if (*r1 != *r2) {
684
            if (*r1 != *r2) {
685
      return 0;
685
                return 0;
686
      }
686
            }
687
      ++r1; ++r2;
687
            ++r1; ++r2;
688
  }
688
        }
689
  return 1;
689
        return 1;
690
    }
690
    }
691
    string m_str;
691
    string m_str;
692
};
692
};
693
693
694
class SuffCmp {
694
class SuffCmp {
695
public:
695
public:
696
    int operator()(const SfString& s1, const SfString& s2) {
696
    int operator()(const SfString& s1, const SfString& s2) {
697
  //cout << "Comparing " << s1.m_str << " and " << s2.m_str << endl;
697
        //cout << "Comparing " << s1.m_str << " and " << s2.m_str << endl;
698
  string::const_reverse_iterator 
698
        string::const_reverse_iterator 
699
      r1 = s1.m_str.rbegin(), re1 = s1.m_str.rend(),
699
            r1 = s1.m_str.rbegin(), re1 = s1.m_str.rend(),
700
      r2 = s2.m_str.rbegin(), re2 = s2.m_str.rend();
700
            r2 = s2.m_str.rbegin(), re2 = s2.m_str.rend();
701
  while (r1 != re1 && r2 != re2) {
701
        while (r1 != re1 && r2 != re2) {
702
      if (*r1 != *r2) {
702
            if (*r1 != *r2) {
703
      return *r1 < *r2 ? 1 : 0;
703
                return *r1 < *r2 ? 1 : 0;
704
      }
704
            }
705
      ++r1; ++r2;
705
            ++r1; ++r2;
706
  }
706
        }
707
  return 0;
707
        return 0;
708
    }
708
    }
709
};
709
};
710
710
711
typedef multiset<SfString, SuffCmp> SuffixStore;
711
typedef multiset<SfString, SuffCmp> SuffixStore;
712
#define STOPSUFFIXES ((SuffixStore *)m_stopsuffixes)
712
#define STOPSUFFIXES ((SuffixStore *)m_stopsuffixes)
...
...
761
    string fn(fni, pos);
761
    string fn(fni, pos);
762
762
763
    stringtolower(fn);
763
    stringtolower(fn);
764
    SuffixStore::const_iterator it = STOPSUFFIXES->find(fn);
764
    SuffixStore::const_iterator it = STOPSUFFIXES->find(fn);
765
    if (it != STOPSUFFIXES->end()) {
765
    if (it != STOPSUFFIXES->end()) {
766
  LOGDEB2("RclConfig::inStopSuffixes: Found (" << fni << ") ["  <<
766
        LOGDEB2("RclConfig::inStopSuffixes: Found (" << fni << ") ["  <<
767
                ((*it).m_str) << "]\n");
767
                ((*it).m_str) << "]\n");
768
  return true;
768
        return true;
769
    } else {
769
    } else {
770
  LOGDEB2("RclConfig::inStopSuffixes: not found [" << fni << "]\n");
770
        LOGDEB2("RclConfig::inStopSuffixes: not found [" << fni << "]\n");
771
  return false;
771
        return false;
772
    }
772
    }
773
}
773
}
774
774
775
string RclConfig::getMimeTypeFromSuffix(const string& suff) const
775
string RclConfig::getMimeTypeFromSuffix(const string& suff) const
776
{
776
{
...
...
790
    // Try again from local data. The map is in the wrong direction,
790
    // Try again from local data. The map is in the wrong direction,
791
    // have to walk it.
791
    // have to walk it.
792
    vector<string> sfs = mimemap->getNames(cstr_null);
792
    vector<string> sfs = mimemap->getNames(cstr_null);
793
    for (const auto& suff : sfs) {
793
    for (const auto& suff : sfs) {
794
        string mt1;
794
        string mt1;
795
  if (mimemap->get(suff, mt1, cstr_null) && !stringicmp(mt, mt1)) {
795
        if (mimemap->get(suff, mt1, cstr_null) && !stringicmp(mt, mt1)) {
796
            return suff;
796
            return suff;
797
        }
797
        }
798
    }
798
    }
799
    return cstr_null;
799
    return cstr_null;
800
}
800
}
801
801
802
/** Get list of file categories from mimeconf */
802
/** Get list of file categories from mimeconf */
803
bool RclConfig::getMimeCategories(vector<string>& cats) const
803
bool RclConfig::getMimeCategories(vector<string>& cats) const
804
{
804
{
805
    if (!mimeconf)
805
    if (!mimeconf)
806
  return false;
806
        return false;
807
    cats = mimeconf->getNames("categories");
807
    cats = mimeconf->getNames("categories");
808
    return true;
808
    return true;
809
}
809
}
810
810
811
bool RclConfig::isMimeCategory(string& cat) const
811
bool RclConfig::isMimeCategory(string& cat) const
812
{
812
{
813
    vector<string>cats;
813
    vector<string>cats;
814
    getMimeCategories(cats);
814
    getMimeCategories(cats);
815
    for (vector<string>::iterator it = cats.begin(); it != cats.end(); it++) {
815
    for (vector<string>::iterator it = cats.begin(); it != cats.end(); it++) {
816
  if (!stringicmp(*it,cat))
816
        if (!stringicmp(*it,cat))
817
      return true;
817
            return true;
818
    }
818
    }
819
    return false;
819
    return false;
820
}
820
}
821
821
822
/** Get list of mime types for category from mimeconf */
822
/** Get list of mime types for category from mimeconf */
823
bool RclConfig::getMimeCatTypes(const string& cat, vector<string>& tps) const
823
bool RclConfig::getMimeCatTypes(const string& cat, vector<string>& tps) const
824
{
824
{
825
    tps.clear();
825
    tps.clear();
826
    if (!mimeconf)
826
    if (!mimeconf)
827
  return false;
827
        return false;
828
    string slist;
828
    string slist;
829
    if (!mimeconf->get(cat, slist, "categories"))
829
    if (!mimeconf->get(cat, slist, "categories"))
830
  return false;
830
        return false;
831
831
832
    stringToStrings(slist, tps);
832
    stringToStrings(slist, tps);
833
    return true;
833
    return true;
834
}
834
}
835
835
...
...
859
            return hs;
859
            return hs;
860
        }
860
        }
861
    }
861
    }
862
862
863
    if (!mimeconf->get(mtype, hs, "index")) {
863
    if (!mimeconf->get(mtype, hs, "index")) {
864
  LOGDEB1("getMimeHandlerDef: no handler for '" << mtype << "'\n");
864
        LOGDEB1("getMimeHandlerDef: no handler for '" << mtype << "'\n");
865
    }
865
    }
866
    return hs;
866
    return hs;
867
}
867
}
868
868
869
const vector<MDReaper>& RclConfig::getMDReapers()
869
const vector<MDReaper>& RclConfig::getMDReapers()
870
{
870
{
871
    string hs;
871
    string hs;
872
    if (m_mdrstate.needrecompute()) {
872
    if (m_mdrstate.needrecompute()) {
873
        m_mdreapers.clear();
873
        m_mdreapers.clear();
874
  // New value now stored in m_mdrstate.getvalue(0)
874
        // New value now stored in m_mdrstate.getvalue(0)
875
  const string& sreapers = m_mdrstate.getvalue(0);
875
        const string& sreapers = m_mdrstate.getvalue(0);
876
  if (sreapers.empty())
876
        if (sreapers.empty())
877
    return m_mdreapers;
877
            return m_mdreapers;
878
  string value;
878
        string value;
879
  ConfSimple attrs;
879
        ConfSimple attrs;
880
  valueSplitAttributes(sreapers, value, attrs);
880
        valueSplitAttributes(sreapers, value, attrs);
881
  vector<string> nmlst = attrs.getNames(cstr_null);
881
        vector<string> nmlst = attrs.getNames(cstr_null);
882
  for (vector<string>::const_iterator it = nmlst.begin();
882
        for (vector<string>::const_iterator it = nmlst.begin();
883
       it != nmlst.end(); it++) {
883
             it != nmlst.end(); it++) {
884
    MDReaper reaper;
884
            MDReaper reaper;
885
    reaper.fieldname = fieldCanon(*it);
885
            reaper.fieldname = fieldCanon(*it);
886
    string s;
886
            string s;
887
    attrs.get(*it, s);
887
            attrs.get(*it, s);
888
    stringToStrings(s, reaper.cmdv);
888
            stringToStrings(s, reaper.cmdv);
889
    m_mdreapers.push_back(reaper);
889
            m_mdreapers.push_back(reaper);
890
  }
890
        }
891
    }
891
    }
892
    return m_mdreapers;
892
    return m_mdreapers;
893
}
893
}
894
894
895
bool RclConfig::getGuiFilterNames(vector<string>& cats) const
895
bool RclConfig::getGuiFilterNames(vector<string>& cats) const
896
{
896
{
897
    if (!mimeconf)
897
    if (!mimeconf)
898
  return false;
898
        return false;
899
    cats = mimeconf->getNamesShallow("guifilters");
899
    cats = mimeconf->getNamesShallow("guifilters");
900
    return true;
900
    return true;
901
}
901
}
902
902
903
bool RclConfig::getGuiFilter(const string& catfiltername, string& frag) const
903
bool RclConfig::getGuiFilter(const string& catfiltername, string& frag) const
904
{
904
{
905
    frag.clear();
905
    frag.clear();
906
    if (!mimeconf)
906
    if (!mimeconf)
907
  return false;
907
        return false;
908
    if (!mimeconf->get(catfiltername, frag, "guifilters"))
908
    if (!mimeconf->get(catfiltername, frag, "guifilters"))
909
  return false;
909
        return false;
910
    return true;
910
    return true;
911
}
911
}
912
912
913
bool RclConfig::valueSplitAttributes(const string& whole, string& value, 
913
bool RclConfig::valueSplitAttributes(const string& whole, string& value, 
914
                   ConfSimple& attrs)
914
                                     ConfSimple& attrs)
915
{
915
{
916
    /* There is currently no way to escape a semi-colon */
916
    /* There is currently no way to escape a semi-colon */
917
    string::size_type semicol0 = whole.find_first_of(";");
917
    string::size_type semicol0 = whole.find_first_of(";");
918
    value = whole.substr(0, semicol0);
918
    value = whole.substr(0, semicol0);
919
    trimstring(value);
919
    trimstring(value);
...
...
926
    // with newlines and use a ConfSimple
926
    // with newlines and use a ConfSimple
927
    if (!attrstr.empty()) {
927
    if (!attrstr.empty()) {
928
        for (string::size_type i = 0; i < attrstr.size(); i++) {
928
        for (string::size_type i = 0; i < attrstr.size(); i++) {
929
            if (attrstr[i] == ';')
929
            if (attrstr[i] == ';')
930
                attrstr[i] = '\n';
930
                attrstr[i] = '\n';
931
  }
931
        }
932
        attrs.reparse(attrstr);
932
        attrs.reparse(attrstr);
933
    } else {
933
    } else {
934
  attrs.clear();
934
        attrs.clear();
935
    }
935
    }
936
    
936
    
937
    return true;
937
    return true;
938
}
938
}
939
939
940
bool RclConfig::getMissingHelperDesc(string& out) const
940
bool RclConfig::getMissingHelperDesc(string& out) const
941
{
941
{
942
    string fmiss = path_cat(getConfDir(), "missing");
942
    string fmiss = path_cat(getConfDir(), "missing");
943
    out.clear();
943
    out.clear();
944
    if (!file_to_string(fmiss, out))
944
    if (!file_to_string(fmiss, out))
945
  return false;
945
        return false;
946
    return true;
946
    return true;
947
}
947
}
948
948
949
void RclConfig::storeMissingHelperDesc(const string &s)
949
void RclConfig::storeMissingHelperDesc(const string &s)
950
{
950
{
951
    string fmiss = path_cat(getCacheDir(), "missing");
951
    string fmiss = path_cat(getCacheDir(), "missing");
952
    FILE *fp = fopen(fmiss.c_str(), "w");
952
    FILE *fp = fopen(fmiss.c_str(), "w");
953
    if (fp) {
953
    if (fp) {
954
  if (s.size() > 0 && fwrite(s.c_str(), s.size(), 1, fp) != 1) {
954
        if (s.size() > 0 && fwrite(s.c_str(), s.size(), 1, fp) != 1) {
955
            LOGERR("storeMissingHelperDesc: fwrite failed\n");
955
            LOGERR("storeMissingHelperDesc: fwrite failed\n");
956
        }
956
        }
957
  fclose(fp);
957
        fclose(fp);
958
    }
958
    }
959
}
959
}
960
960
961
// Read definitions for field prefixes, aliases, and hierarchy and arrange 
961
// Read definitions for field prefixes, aliases, and hierarchy and arrange 
962
// things for speed (theses are used a lot during indexing)
962
// things for speed (theses are used a lot during indexing)
963
bool RclConfig::readFieldsConfig(const string& cnferrloc)
963
bool RclConfig::readFieldsConfig(const string& cnferrloc)
964
{
964
{
965
    LOGDEB2("RclConfig::readFieldsConfig\n");
965
    LOGDEB2("RclConfig::readFieldsConfig\n");
966
    m_fields = new ConfStack<ConfSimple>("fields", m_cdirs, true);
966
    m_fields = new ConfStack<ConfSimple>("fields", m_cdirs, true);
967
    if (m_fields == 0 || !m_fields->ok()) {
967
    if (m_fields == 0 || !m_fields->ok()) {
968
  m_reason = string("No/bad fields file in: ") + cnferrloc;
968
        m_reason = string("No/bad fields file in: ") + cnferrloc;
969
  return false;
969
        return false;
970
    }
970
    }
971
971
972
    // Build a direct map avoiding all indirections for field to
972
    // Build a direct map avoiding all indirections for field to
973
    // prefix translation
973
    // prefix translation
974
    // Add direct prefixes from the [prefixes] section
974
    // Add direct prefixes from the [prefixes] section
975
    vector<string> tps = m_fields->getNames("prefixes");
975
    vector<string> tps = m_fields->getNames("prefixes");
976
    for (const auto& fieldname : tps) {
976
    for (const auto& fieldname : tps) {
977
  string val;
977
        string val;
978
  m_fields->get(fieldname, val, "prefixes");
978
        m_fields->get(fieldname, val, "prefixes");
979
  ConfSimple attrs;
979
        ConfSimple attrs;
980
  FieldTraits ft;
980
        FieldTraits ft;
981
        // fieldname = prefix ; attr1=val;attr2=val...
981
        // fieldname = prefix ; attr1=val;attr2=val...
982
  if (!valueSplitAttributes(val, ft.pfx, attrs)) {
982
        if (!valueSplitAttributes(val, ft.pfx, attrs)) {
983
      LOGERR("readFieldsConfig: bad config line for ["  << fieldname <<
983
            LOGERR("readFieldsConfig: bad config line for ["  << fieldname <<
984
                   "]: [" << val << "]\n");
984
                   "]: [" << val << "]\n");
985
      return 0;
985
            return 0;
986
  }
986
        }
987
  string tval;
987
        string tval;
988
  if (attrs.get("wdfinc", tval))
988
        if (attrs.get("wdfinc", tval))
989
      ft.wdfinc = atoi(tval.c_str());
989
            ft.wdfinc = atoi(tval.c_str());
990
  if (attrs.get("boost", tval))
990
        if (attrs.get("boost", tval))
991
      ft.boost = atof(tval.c_str());
991
            ft.boost = atof(tval.c_str());
992
  if (attrs.get("pfxonly", tval))
992
        if (attrs.get("pfxonly", tval))
993
      ft.pfxonly = stringToBool(tval);
993
            ft.pfxonly = stringToBool(tval);
994
  if (attrs.get("noterms", tval))
994
        if (attrs.get("noterms", tval))
995
      ft.noterms = stringToBool(tval);
995
            ft.noterms = stringToBool(tval);
996
  m_fldtotraits[stringtolower(fieldname)] = ft;
996
        m_fldtotraits[stringtolower(fieldname)] = ft;
997
  LOGDEB2("readFieldsConfig: ["  << fieldname << "] -> ["  << ft.pfx <<
997
        LOGDEB2("readFieldsConfig: ["  << fieldname << "] -> ["  << ft.pfx <<
998
                "] " << ft.wdfinc << " " << ft.boost << "\n");
998
                "] " << ft.wdfinc << " " << ft.boost << "\n");
999
    }
999
    }
1000
1000
1001
    // Values section
1001
    // Values section
1002
    tps = m_fields->getNames("values");
1002
    tps = m_fields->getNames("values");
1003
    for (const auto& fieldname : tps) {
1003
    for (const auto& fieldname : tps) {
1004
  string canonic = stringtolower(fieldname); // canonic name
1004
        string canonic = stringtolower(fieldname); // canonic name
1005
  string val;
1005
        string val;
1006
  m_fields->get(fieldname, val, "values");
1006
        m_fields->get(fieldname, val, "values");
1007
  ConfSimple attrs;
1007
        ConfSimple attrs;
1008
        string svslot;
1008
        string svslot;
1009
        // fieldname = valueslot ; attr1=val;attr2=val...
1009
        // fieldname = valueslot ; attr1=val;attr2=val...
1010
  if (!valueSplitAttributes(val, svslot, attrs)) {
1010
        if (!valueSplitAttributes(val, svslot, attrs)) {
1011
      LOGERR("readFieldsConfig: bad value line for ["  << fieldname <<
1011
            LOGERR("readFieldsConfig: bad value line for ["  << fieldname <<
1012
                   "]: [" << val << "]\n");
1012
                   "]: [" << val << "]\n");
1013
      return 0;
1013
            return 0;
1014
  }
1014
        }
1015
        uint32_t valueslot = uint32_t(atoi(svslot.c_str()));
1015
        uint32_t valueslot = uint32_t(atoi(svslot.c_str()));
1016
        if (valueslot == 0) {
1016
        if (valueslot == 0) {
1017
            LOGERR("readFieldsConfig: found 0 value slot for [" << fieldname <<
1017
            LOGERR("readFieldsConfig: found 0 value slot for [" << fieldname <<
1018
                   "]: [" << val << "]\n");
1018
                   "]: [" << val << "]\n");
1019
            continue;
1019
            continue;
...
...
1036
        if (attrs.get("len", tval)) {
1036
        if (attrs.get("len", tval)) {
1037
            valuelen = atoi(tval.c_str());
1037
            valuelen = atoi(tval.c_str());
1038
        }
1038
        }
1039
        
1039
        
1040
        // Find or insert traits entry
1040
        // Find or insert traits entry
1041
  const auto pit =
1041
        const auto pit =
1042
      m_fldtotraits.insert(
1042
            m_fldtotraits.insert(
1043
                pair<string, FieldTraits>(canonic, FieldTraits())).first;
1043
                pair<string, FieldTraits>(canonic, FieldTraits())).first;
1044
        pit->second.valueslot = valueslot;
1044
        pit->second.valueslot = valueslot;
1045
        pit->second.valuetype = valuetype;
1045
        pit->second.valuetype = valuetype;
1046
        pit->second.valuelen = valuelen;
1046
        pit->second.valuelen = valuelen;
1047
    }
1047
    }
...
...
1049
    // Add prefixes for aliases and build alias-to-canonic map while
1049
    // Add prefixes for aliases and build alias-to-canonic map while
1050
    // we're at it. Having the aliases in the prefix map avoids an
1050
    // we're at it. Having the aliases in the prefix map avoids an
1051
    // additional indirection at index time.
1051
    // additional indirection at index time.
1052
    tps = m_fields->getNames("aliases");
1052
    tps = m_fields->getNames("aliases");
1053
    for (const auto& fieldname : tps) {
1053
    for (const auto& fieldname : tps) {
1054
  string canonic = stringtolower(fieldname); // canonic name
1054
        string canonic = stringtolower(fieldname); // canonic name
1055
  FieldTraits ft;
1055
        FieldTraits ft;
1056
  const auto pit = m_fldtotraits.find(canonic);
1056
        const auto pit = m_fldtotraits.find(canonic);
1057
  if (pit != m_fldtotraits.end()) {
1058
      ft = pit->second;
1059
  }
1060
  string aliases;
1061
  m_fields->get(canonic, aliases, "aliases");
1062
  vector<string> l;
1063
  stringToStrings(aliases, l);
1064
  for (const auto& alias : l) {
1065
      if (pit != m_fldtotraits.end())
1057
        if (pit != m_fldtotraits.end()) {
1058
            ft = pit->second;
1059
        }
1060
        string aliases;
1061
        m_fields->get(canonic, aliases, "aliases");
1062
        vector<string> l;
1063
        stringToStrings(aliases, l);
1064
        for (const auto& alias : l) {
1065
            if (pit != m_fldtotraits.end())
1066
      m_fldtotraits[stringtolower(alias)] = ft;
1066
                m_fldtotraits[stringtolower(alias)] = ft;
1067
      m_aliastocanon[stringtolower(alias)] = canonic;
1067
            m_aliastocanon[stringtolower(alias)] = canonic;
1068
  }
1068
        }
1069
    }
1069
    }
1070
1070
1071
    // Query aliases map
1071
    // Query aliases map
1072
    tps = m_fields->getNames("queryaliases");
1072
    tps = m_fields->getNames("queryaliases");
1073
    for (const auto& entry: tps) {
1073
    for (const auto& entry: tps) {
1074
  string canonic = stringtolower(entry); // canonic name
1074
        string canonic = stringtolower(entry); // canonic name
1075
  string aliases;
1075
        string aliases;
1076
  m_fields->get(canonic, aliases, "queryaliases");
1076
        m_fields->get(canonic, aliases, "queryaliases");
1077
  vector<string> l;
1077
        vector<string> l;
1078
  stringToStrings(aliases, l);
1078
        stringToStrings(aliases, l);
1079
  for (const auto& alias : l) {
1079
        for (const auto& alias : l) {
1080
      m_aliastoqcanon[stringtolower(alias)] = canonic;
1080
            m_aliastoqcanon[stringtolower(alias)] = canonic;
1081
  }
1081
        }
1082
    }
1082
    }
1083
1083
1084
#if 0
1084
#if 0
1085
    for (map<string, FieldTraits>::const_iterator it = m_fldtotraits.begin();
1085
    for (map<string, FieldTraits>::const_iterator it = m_fldtotraits.begin();
1086
   it != m_fldtotraits.end(); it++) {
1086
         it != m_fldtotraits.end(); it++) {
1087
  LOGDEB("readFieldsConfig: ["  << entry << "] -> ["  << it->second.pfx <<
1087
        LOGDEB("readFieldsConfig: ["  << entry << "] -> ["  << it->second.pfx <<
1088
               "] " << it->second.wdfinc << " " << it->second.boost << "\n");
1088
               "] " << it->second.wdfinc << " " << it->second.boost << "\n");
1089
    }
1089
    }
1090
#endif
1090
#endif
1091
1091
1092
    vector<string> sl = m_fields->getNames("stored");
1092
    vector<string> sl = m_fields->getNames("stored");
...
...
1095
    }
1095
    }
1096
1096
1097
    // Extended file attribute to field translations
1097
    // Extended file attribute to field translations
1098
    vector<string>xattrs = m_fields->getNames("xattrtofields");
1098
    vector<string>xattrs = m_fields->getNames("xattrtofields");
1099
    for (const auto& xattr : xattrs) {
1099
    for (const auto& xattr : xattrs) {
1100
  string val;
1100
        string val;
1101
  m_fields->get(xattr, val, "xattrtofields");
1101
        m_fields->get(xattr, val, "xattrtofields");
1102
  m_xattrtofld[xattr] = val;
1102
        m_xattrtofld[xattr] = val;
1103
    }
1103
    }
1104
1104
1105
    return true;
1105
    return true;
1106
}
1106
}
1107
1107
1108
// Return specifics for field name:
1108
// Return specifics for field name:
1109
bool RclConfig::getFieldTraits(const string& _fld, const FieldTraits **ftpp,
1109
bool RclConfig::getFieldTraits(const string& _fld, const FieldTraits **ftpp,
1110
    bool isquery) const
1110
                               bool isquery) const
1111
{
1111
{
1112
    string fld = isquery ? fieldQCanon(_fld) : fieldCanon(_fld);
1112
    string fld = isquery ? fieldQCanon(_fld) : fieldCanon(_fld);
1113
    map<string, FieldTraits>::const_iterator pit = m_fldtotraits.find(fld);
1113
    map<string, FieldTraits>::const_iterator pit = m_fldtotraits.find(fld);
1114
    if (pit != m_fldtotraits.end()) {
1114
    if (pit != m_fldtotraits.end()) {
1115
  *ftpp = &pit->second;
1115
        *ftpp = &pit->second;
1116
  LOGDEB1("RclConfig::getFieldTraits: [" << _fld << "]->["  <<
1116
        LOGDEB1("RclConfig::getFieldTraits: [" << _fld << "]->["  <<
1117
                pit->second.pfx << "]\n");
1117
                pit->second.pfx << "]\n");
1118
  return true;
1118
        return true;
1119
    } else {
1119
    } else {
1120
  LOGDEB1("RclConfig::getFieldTraits: no prefix for field [" << fld <<
1120
        LOGDEB1("RclConfig::getFieldTraits: no prefix for field [" << fld <<
1121
                "]\n");
1121
                "]\n");
1122
  *ftpp = 0;
1122
        *ftpp = 0;
1123
  return false;
1123
        return false;
1124
    }
1124
    }
1125
}
1125
}
1126
1126
1127
set<string> RclConfig::getIndexedFields() const
1127
set<string> RclConfig::getIndexedFields() const
1128
{
1128
{
1129
    set<string> flds;
1129
    set<string> flds;
1130
    if (m_fields == 0)
1130
    if (m_fields == 0)
1131
  return flds;
1131
        return flds;
1132
1132
1133
    vector<string> sl = m_fields->getNames("prefixes");
1133
    vector<string> sl = m_fields->getNames("prefixes");
1134
    flds.insert(sl.begin(), sl.end());
1134
    flds.insert(sl.begin(), sl.end());
1135
    return flds;
1135
    return flds;
1136
}
1136
}
...
...
1138
string RclConfig::fieldCanon(const string& f) const
1138
string RclConfig::fieldCanon(const string& f) const
1139
{
1139
{
1140
    string fld = stringtolower(f);
1140
    string fld = stringtolower(f);
1141
    map<string, string>::const_iterator it = m_aliastocanon.find(fld);
1141
    map<string, string>::const_iterator it = m_aliastocanon.find(fld);
1142
    if (it != m_aliastocanon.end()) {
1142
    if (it != m_aliastocanon.end()) {
1143
  LOGDEB1("RclConfig::fieldCanon: [" << f << "] -> [" << it->second <<
1143
        LOGDEB1("RclConfig::fieldCanon: [" << f << "] -> [" << it->second <<
1144
                "]\n");
1144
                "]\n");
1145
  return it->second;
1145
        return it->second;
1146
    }
1146
    }
1147
    LOGDEB1("RclConfig::fieldCanon: ["  << (f) << "] -> ["  << (fld) << "]\n");
1147
    LOGDEB1("RclConfig::fieldCanon: ["  << (f) << "] -> ["  << (fld) << "]\n");
1148
    return fld;
1148
    return fld;
1149
}
1149
}
1150
1150
1151
string RclConfig::fieldQCanon(const string& f) const
1151
string RclConfig::fieldQCanon(const string& f) const
1152
{
1152
{
1153
    string fld = stringtolower(f);
1153
    string fld = stringtolower(f);
1154
    map<string, string>::const_iterator it = m_aliastoqcanon.find(fld);
1154
    map<string, string>::const_iterator it = m_aliastoqcanon.find(fld);
1155
    if (it != m_aliastoqcanon.end()) {
1155
    if (it != m_aliastoqcanon.end()) {
1156
  LOGDEB1("RclConfig::fieldQCanon: [" << f << "] -> ["  << it->second <<
1156
        LOGDEB1("RclConfig::fieldQCanon: [" << f << "] -> ["  << it->second <<
1157
                "]\n");
1157
                "]\n");
1158
  return it->second;
1158
        return it->second;
1159
    }
1159
    }
1160
    return fieldCanon(f);
1160
    return fieldCanon(f);
1161
}
1161
}
1162
1162
1163
vector<string> RclConfig::getFieldSectNames(const string &sk, const char* patrn)
1163
vector<string> RclConfig::getFieldSectNames(const string &sk, const char* patrn)
...
...
1178
1178
1179
set<string> RclConfig::getMimeViewerAllEx() const
1179
set<string> RclConfig::getMimeViewerAllEx() const
1180
{
1180
{
1181
    set<string> res;
1181
    set<string> res;
1182
    if (mimeview == 0)
1182
    if (mimeview == 0)
1183
  return res;
1183
        return res;
1184
1184
1185
    string base, plus, minus;
1185
    string base, plus, minus;
1186
    mimeview->get("xallexcepts", base, "");
1186
    mimeview->get("xallexcepts", base, "");
1187
    LOGDEB1("RclConfig::getMimeViewerAllEx(): base: " << s << endl);
1187
    LOGDEB1("RclConfig::getMimeViewerAllEx(): base: " << s << endl);
1188
    mimeview->get("xallexcepts+", plus, "");
1188
    mimeview->get("xallexcepts+", plus, "");
...
...
1190
    mimeview->get("xallexcepts-", minus, "");
1190
    mimeview->get("xallexcepts-", minus, "");
1191
    LOGDEB1("RclConfig::getMimeViewerAllEx(): minus: " << minus << endl);
1191
    LOGDEB1("RclConfig::getMimeViewerAllEx(): minus: " << minus << endl);
1192
1192
1193
    computeBasePlusMinus(res, base, plus, minus);
1193
    computeBasePlusMinus(res, base, plus, minus);
1194
    LOGDEB1("RclConfig::getMimeViewerAllEx(): res: " << stringsToString(res)
1194
    LOGDEB1("RclConfig::getMimeViewerAllEx(): res: " << stringsToString(res)
1195
           << endl);
1195
            << endl);
1196
    return res;
1196
    return res;
1197
}
1197
}
1198
1198
1199
bool RclConfig::setMimeViewerAllEx(const set<string>& allex)
1199
bool RclConfig::setMimeViewerAllEx(const set<string>& allex)
1200
{
1200
{
...
...
1206
1206
1207
    string splus, sminus;
1207
    string splus, sminus;
1208
    setPlusMinus(sbase, allex, splus, sminus);
1208
    setPlusMinus(sbase, allex, splus, sminus);
1209
1209
1210
    if (!mimeview->set("xallexcepts-", sminus, "")) {
1210
    if (!mimeview->set("xallexcepts-", sminus, "")) {
1211
  m_reason = string("RclConfig:: cant set value. Readonly?");
1211
        m_reason = string("RclConfig:: cant set value. Readonly?");
1212
  return false;
1212
        return false;
1213
    }
1213
    }
1214
    if (!mimeview->set("xallexcepts+", splus, "")) {
1214
    if (!mimeview->set("xallexcepts+", splus, "")) {
1215
  m_reason = string("RclConfig:: cant set value. Readonly?");
1215
        m_reason = string("RclConfig:: cant set value. Readonly?");
1216
  return false;
1216
        return false;
1217
    }
1217
    }
1218
1218
1219
    return true;
1219
    return true;
1220
}
1220
}
1221
1221
1222
string RclConfig::getMimeViewerDef(const string &mtype, const string& apptag,
1222
string RclConfig::getMimeViewerDef(const string &mtype, const string& apptag,
1223
                 bool useall) const
1223
                                   bool useall) const
1224
{
1224
{
1225
    LOGDEB2("RclConfig::getMimeViewerDef: mtype [" << mtype << "] apptag ["
1225
    LOGDEB2("RclConfig::getMimeViewerDef: mtype [" << mtype << "] apptag ["
1226
            << apptag << "]\n");
1226
            << apptag << "]\n");
1227
    string hs;
1227
    string hs;
1228
    if (mimeview == 0)
1228
    if (mimeview == 0)
1229
  return hs;
1229
        return hs;
1230
1230
1231
    if (useall) {
1231
    if (useall) {
1232
  // Check for exception
1232
        // Check for exception
1233
  set<string> allex = getMimeViewerAllEx();
1233
        set<string> allex = getMimeViewerAllEx();
1234
  bool isexcept = false;
1234
        bool isexcept = false;
1235
  for (auto& it : allex) {
1235
        for (auto& it : allex) {
1236
      vector<string> mita;
1236
            vector<string> mita;
1237
      stringToTokens(it, mita, "|");
1237
            stringToTokens(it, mita, "|");
1238
      if ((mita.size() == 1 && apptag.empty() && mita[0] == mtype) ||
1238
            if ((mita.size() == 1 && apptag.empty() && mita[0] == mtype) ||
1239
      (mita.size() == 2 && mita[1] == apptag && mita[0] == mtype)) {
1239
                (mita.size() == 2 && mita[1] == apptag && mita[0] == mtype)) {
1240
      // Exception to x-all
1240
                // Exception to x-all
1241
      isexcept = true;
1241
                isexcept = true;
1242
      break;
1242
                break;
1243
      }
1243
            }
1244
  }
1244
        }
1245
1245
1246
  if (isexcept == false) {
1246
        if (isexcept == false) {
1247
      mimeview->get("application/x-all", hs, "view");
1247
            mimeview->get("application/x-all", hs, "view");
1248
      return hs;
1248
            return hs;
1249
  }
1249
        }
1250
  // Fallthrough to normal case.
1250
        // Fallthrough to normal case.
1251
    }
1251
    }
1252
1252
1253
    if (apptag.empty() || !mimeview->get(mtype + string("|") + apptag,
1253
    if (apptag.empty() || !mimeview->get(mtype + string("|") + apptag,
1254
                                         hs, "view"))
1254
                                         hs, "view"))
1255
        mimeview->get(mtype, hs, "view");
1255
        mimeview->get(mtype, hs, "view");
...
...
1257
}
1257
}
1258
1258
1259
bool RclConfig::getMimeViewerDefs(vector<pair<string, string> >& defs) const
1259
bool RclConfig::getMimeViewerDefs(vector<pair<string, string> >& defs) const
1260
{
1260
{
1261
    if (mimeview == 0)
1261
    if (mimeview == 0)
1262
  return false;
1262
        return false;
1263
    vector<string>tps = mimeview->getNames("view");
1263
    vector<string>tps = mimeview->getNames("view");
1264
    for (vector<string>::const_iterator it = tps.begin(); 
1264
    for (vector<string>::const_iterator it = tps.begin(); 
1265
   it != tps.end();it++) {
1265
         it != tps.end();it++) {
1266
  defs.push_back(pair<string, string>(*it, getMimeViewerDef(*it, "", 0)));
1266
        defs.push_back(pair<string, string>(*it, getMimeViewerDef(*it, "", 0)));
1267
    }
1267
    }
1268
    return true;
1268
    return true;
1269
}
1269
}
1270
1270
1271
bool RclConfig::setMimeViewerDef(const string& mt, const string& def)
1271
bool RclConfig::setMimeViewerDef(const string& mt, const string& def)
1272
{
1272
{
1273
    if (mimeview == 0)
1273
    if (mimeview == 0)
1274
        return false;
1274
        return false;
1275
    bool status;
1275
    bool status;
1276
    if (!def.empty()) 
1276
    if (!def.empty()) 
1277
  status = mimeview->set(mt, def, "view");
1277
        status = mimeview->set(mt, def, "view");
1278
    else 
1278
    else 
1279
  status = mimeview->erase(mt, "view");
1279
        status = mimeview->erase(mt, "view");
1280
1280
1281
    if (!status) {
1281
    if (!status) {
1282
  m_reason = string("RclConfig:: cant set value. Readonly?");
1282
        m_reason = string("RclConfig:: cant set value. Readonly?");
1283
  return false;
1283
        return false;
1284
    }
1284
    }
1285
    return true;
1285
    return true;
1286
}
1286
}
1287
1287
1288
bool RclConfig::mimeViewerNeedsUncomp(const string &mimetype) const
1288
bool RclConfig::mimeViewerNeedsUncomp(const string &mimetype) const
...
...
1299
string RclConfig::getMimeIconPath(const string &mtype, const string &apptag)
1299
string RclConfig::getMimeIconPath(const string &mtype, const string &apptag)
1300
    const
1300
    const
1301
{
1301
{
1302
    string iconname;
1302
    string iconname;
1303
    if (!apptag.empty())
1303
    if (!apptag.empty())
1304
  mimeconf->get(mtype + string("|") + apptag, iconname, "icons");
1304
        mimeconf->get(mtype + string("|") + apptag, iconname, "icons");
1305
    if (iconname.empty())
1305
    if (iconname.empty())
1306
        mimeconf->get(mtype, iconname, "icons");
1306
        mimeconf->get(mtype, iconname, "icons");
1307
    if (iconname.empty())
1307
    if (iconname.empty())
1308
  iconname = "document";
1308
        iconname = "document";
1309
1309
1310
    string iconpath;
1310
    string iconpath;
1311
#if defined (__FreeBSD__) && __FreeBSD_version < 500000
1311
#if defined (__FreeBSD__) && __FreeBSD_version < 500000
1312
    // gcc 2.95 dies if we call getConfParam here ??
1312
    // gcc 2.95 dies if we call getConfParam here ??
1313
    if (m_conf) m_conf->get(string("iconsdir"), iconpath, m_keydir);
1313
    if (m_conf) m_conf->get(string("iconsdir"), iconpath, m_keydir);
1314
#else
1314
#else
1315
    getConfParam("iconsdir", iconpath);
1315
    getConfParam("iconsdir", iconpath);
1316
#endif
1316
#endif
1317
1317
1318
    if (iconpath.empty()) {
1318
    if (iconpath.empty()) {
1319
  iconpath = path_cat(m_datadir, "images");
1319
        iconpath = path_cat(m_datadir, "images");
1320
    } else {
1320
    } else {
1321
  iconpath = path_tildexpand(iconpath);
1321
        iconpath = path_tildexpand(iconpath);
1322
    }
1322
    }
1323
    return path_cat(iconpath, iconname) + ".png";
1323
    return path_cat(iconpath, iconname) + ".png";
1324
}
1324
}
1325
1325
1326
// Return path defined by varname. May be absolute or relative to
1326
// Return path defined by varname. May be absolute or relative to
1327
// confdir, with default in confdir
1327
// confdir, with default in confdir
1328
string RclConfig::getConfdirPath(const char *varname, const char *dflt) const
1328
string RclConfig::getConfdirPath(const char *varname, const char *dflt) const
1329
{
1329
{
1330
    string result;
1330
    string result;
1331
    if (!getConfParam(varname, result)) {
1331
    if (!getConfParam(varname, result)) {
1332
  result = path_cat(getConfDir(), dflt);
1332
        result = path_cat(getConfDir(), dflt);
1333
    } else {
1333
    } else {
1334
  result = path_tildexpand(result);
1334
        result = path_tildexpand(result);
1335
  // If not an absolute path, compute relative to config dir
1335
        // If not an absolute path, compute relative to config dir
1336
  if (!path_isabsolute(result)) {
1336
        if (!path_isabsolute(result)) {
1337
      result = path_cat(getConfDir(), result);
1337
            result = path_cat(getConfDir(), result);
1338
  }
1338
        }
1339
    }
1339
    }
1340
    return path_canon(result);
1340
    return path_canon(result);
1341
}
1341
}
1342
1342
1343
string RclConfig::getCacheDir() const
1343
string RclConfig::getCacheDir() const
...
...
1349
// confdir, with default in confdir
1349
// confdir, with default in confdir
1350
string RclConfig::getCachedirPath(const char *varname, const char *dflt) const
1350
string RclConfig::getCachedirPath(const char *varname, const char *dflt) const
1351
{
1351
{
1352
    string result;
1352
    string result;
1353
    if (!getConfParam(varname, result)) {
1353
    if (!getConfParam(varname, result)) {
1354
  result = path_cat(getCacheDir(), dflt);
1354
        result = path_cat(getCacheDir(), dflt);
1355
    } else {
1355
    } else {
1356
  result = path_tildexpand(result);
1356
        result = path_tildexpand(result);
1357
  // If not an absolute path, compute relative to cache dir
1357
        // If not an absolute path, compute relative to cache dir
1358
  if (!path_isabsolute(result)) {
1358
        if (!path_isabsolute(result)) {
1359
      result = path_cat(getCacheDir(), result);
1359
            result = path_cat(getCacheDir(), result);
1360
  }
1360
        }
1361
    }
1361
    }
1362
    return path_canon(result);
1362
    return path_canon(result);
1363
}
1363
}
1364
1364
1365
string RclConfig::getDbDir() const
1365
string RclConfig::getDbDir() const
...
...
1405
 * /mnt1/common/part /mnt2/common/part -> /mnt1 /mnt2. This is used
1405
 * /mnt1/common/part /mnt2/common/part -> /mnt1 /mnt2. This is used
1406
 * for computing translations for paths when the dataset has been
1406
 * for computing translations for paths when the dataset has been
1407
 * moved. Of course this could be done more efficiently than by splitting 
1407
 * moved. Of course this could be done more efficiently than by splitting 
1408
 * into vectors, but we don't care.*/
1408
 * into vectors, but we don't care.*/
1409
static string path_diffstems(const string& p1, const string& p2,
1409
static string path_diffstems(const string& p1, const string& p2,
1410
                            string& r1, string& r2)
1410
                             string& r1, string& r2)
1411
{
1411
{
1412
    string reason;
1412
    string reason;
1413
    r1.clear();
1413
    r1.clear();
1414
    r2.clear();
1414
    r2.clear();
1415
    vector<string> v1, v2;
1415
    vector<string> v1, v2;
...
...
1455
    if (m_conf->get("orgidxconfdir", orig_confdir, "")) {
1455
    if (m_conf->get("orgidxconfdir", orig_confdir, "")) {
1456
        if (!m_conf->get("curidxconfdir", cur_confdir, "")) {
1456
        if (!m_conf->get("curidxconfdir", cur_confdir, "")) {
1457
            cur_confdir = m_confdir;
1457
            cur_confdir = m_confdir;
1458
        }
1458
        }
1459
        LOGDEB1("RclConfig::urlrewrite: orgidxconfdir: " << orig_confdir <<
1459
        LOGDEB1("RclConfig::urlrewrite: orgidxconfdir: " << orig_confdir <<
1460
               " cur_confdir " << cur_confdir << endl);
1460
                " cur_confdir " << cur_confdir << endl);
1461
        string reason = path_diffstems(orig_confdir, cur_confdir,
1461
        string reason = path_diffstems(orig_confdir, cur_confdir,
1462
                                       confstemorg, confstemrep);
1462
                                       confstemorg, confstemrep);
1463
        if (!reason.empty()) {
1463
        if (!reason.empty()) {
1464
            LOGERR("urlrewrite: path_diffstems failed: " << reason <<
1464
            LOGERR("urlrewrite: path_diffstems failed: " << reason <<
1465
                   " : orig_confdir [" << orig_confdir <<
1465
                   " : orig_confdir [" << orig_confdir <<
...
...
1469
    }
1469
    }
1470
    
1470
    
1471
    // Do path translations exist for this index ?
1471
    // Do path translations exist for this index ?
1472
    bool needptrans = true;
1472
    bool needptrans = true;
1473
    if (m_ptrans == 0 || !m_ptrans->hasSubKey(dbdir)) {
1473
    if (m_ptrans == 0 || !m_ptrans->hasSubKey(dbdir)) {
1474
  LOGDEB2("RclConfig::urlrewrite: no paths translations (m_ptrans " <<
1474
        LOGDEB2("RclConfig::urlrewrite: no paths translations (m_ptrans " <<
1475
                m_ptrans << ")\n");
1475
                m_ptrans << ")\n");
1476
        needptrans = false;
1476
        needptrans = false;
1477
    }
1477
    }
1478
1478
1479
    if (!needptrans && confstemorg.empty()) {
1479
    if (!needptrans && confstemorg.empty()) {
...
...
1481
    }
1481
    }
1482
    bool computeurl = false;
1482
    bool computeurl = false;
1483
    
1483
    
1484
    string path = fileurltolocalpath(url);
1484
    string path = fileurltolocalpath(url);
1485
    if (path.empty()) {
1485
    if (path.empty()) {
1486
  LOGDEB2("RclConfig::urlrewrite: not file url\n");
1486
        LOGDEB2("RclConfig::urlrewrite: not file url\n");
1487
  return;
1487
        return;
1488
    }
1488
    }
1489
    
1489
    
1490
    // Do the movable volume thing.
1490
    // Do the movable volume thing.
1491
    if (!confstemorg.empty() && confstemorg.size() <= path.size() &&
1491
    if (!confstemorg.empty() && confstemorg.size() <= path.size() &&
1492
        !path.compare(0, confstemorg.size(), confstemorg)) {
1492
        !path.compare(0, confstemorg.size(), confstemorg)) {
...
...
1517
}
1517
}
1518
1518
1519
bool RclConfig::sourceChanged() const
1519
bool RclConfig::sourceChanged() const
1520
{
1520
{
1521
    if (m_conf && m_conf->sourceChanged())
1521
    if (m_conf && m_conf->sourceChanged())
1522
  return true;
1522
        return true;
1523
    if (mimemap && mimemap->sourceChanged())
1523
    if (mimemap && mimemap->sourceChanged())
1524
  return true;
1524
        return true;
1525
    if (mimeconf && mimeconf->sourceChanged())
1525
    if (mimeconf && mimeconf->sourceChanged())
1526
  return true;
1526
        return true;
1527
    if (mimeview && mimeview->sourceChanged())
1527
    if (mimeview && mimeview->sourceChanged())
1528
  return true;
1528
        return true;
1529
    if (m_fields && m_fields->sourceChanged())
1529
    if (m_fields && m_fields->sourceChanged())
1530
  return true;
1530
        return true;
1531
    if (m_ptrans && m_ptrans->sourceChanged())
1531
    if (m_ptrans && m_ptrans->sourceChanged())
1532
  return true;
1532
        return true;
1533
    return false;
1533
    return false;
1534
}
1534
}
1535
1535
1536
string RclConfig::getWebQueueDir() const
1536
string RclConfig::getWebQueueDir() const
1537
{
1537
{
1538
    string webqueuedir;
1538
    string webqueuedir;
1539
    if (!getConfParam("webqueuedir", webqueuedir))
1539
    if (!getConfParam("webqueuedir", webqueuedir))
1540
  webqueuedir = "~/.recollweb/ToIndex/";
1540
        webqueuedir = "~/.recollweb/ToIndex/";
1541
    webqueuedir = path_tildexpand(webqueuedir);
1541
    webqueuedir = path_tildexpand(webqueuedir);
1542
    return webqueuedir;
1542
    return webqueuedir;
1543
}
1543
}
1544
1544
1545
vector<string>& RclConfig::getSkippedNames()
1545
vector<string>& RclConfig::getSkippedNames()
...
...
1567
        skpl.push_back(getCacheDir());
1567
        skpl.push_back(getCacheDir());
1568
    }
1568
    }
1569
    // And the web queue dir
1569
    // And the web queue dir
1570
    skpl.push_back(getWebQueueDir());
1570
    skpl.push_back(getWebQueueDir());
1571
    for (vector<string>::iterator it = skpl.begin(); it != skpl.end(); it++) {
1571
    for (vector<string>::iterator it = skpl.begin(); it != skpl.end(); it++) {
1572
  *it = path_tildexpand(*it);
1572
        *it = path_tildexpand(*it);
1573
  *it = path_canon(*it);
1573
        *it = path_canon(*it);
1574
    }
1574
    }
1575
    sort(skpl.begin(), skpl.end());
1575
    sort(skpl.begin(), skpl.end());
1576
    vector<string>::iterator uit = unique(skpl.begin(), skpl.end());
1576
    vector<string>::iterator uit = unique(skpl.begin(), skpl.end());
1577
    skpl.resize(uit - skpl.begin());
1577
    skpl.resize(uit - skpl.begin());
1578
    return skpl;
1578
    return skpl;
...
...
1582
{
1582
{
1583
    vector<string> dskpl;
1583
    vector<string> dskpl;
1584
    getConfParam("daemSkippedPaths", &dskpl);
1584
    getConfParam("daemSkippedPaths", &dskpl);
1585
1585
1586
    for (vector<string>::iterator it = dskpl.begin(); it != dskpl.end(); it++) {
1586
    for (vector<string>::iterator it = dskpl.begin(); it != dskpl.end(); it++) {
1587
  *it = path_tildexpand(*it);
1587
        *it = path_tildexpand(*it);
1588
  *it = path_canon(*it);
1588
        *it = path_canon(*it);
1589
    }
1589
    }
1590
1590
1591
    vector<string> skpl1 = getSkippedPaths();
1591
    vector<string> skpl1 = getSkippedPaths();
1592
    vector<string> skpl;
1592
    vector<string> skpl;
1593
    if (dskpl.empty()) {
1593
    if (dskpl.empty()) {
1594
  skpl = skpl1;
1594
        skpl = skpl1;
1595
    } else {
1595
    } else {
1596
  sort(dskpl.begin(), dskpl.end());
1596
        sort(dskpl.begin(), dskpl.end());
1597
  merge(dskpl.begin(), dskpl.end(), skpl1.begin(), skpl1.end(), 
1597
        merge(dskpl.begin(), dskpl.end(), skpl1.begin(), skpl1.end(), 
1598
        skpl.begin());
1598
              skpl.begin());
1599
  vector<string>::iterator uit = unique(skpl.begin(), skpl.end());
1599
        vector<string>::iterator uit = unique(skpl.begin(), skpl.end());
1600
  skpl.resize(uit - skpl.begin());
1600
        skpl.resize(uit - skpl.begin());
1601
    }
1601
    }
1602
    return skpl;
1602
    return skpl;
1603
}
1603
}
1604
1604
1605
1605
...
...
1607
// and filtersdir from the config file to the PATH, then use execmd::which()
1607
// and filtersdir from the config file to the PATH, then use execmd::which()
1608
string RclConfig::findFilter(const string &icmd) const
1608
string RclConfig::findFilter(const string &icmd) const
1609
{
1609
{
1610
    // If the path is absolute, this is it
1610
    // If the path is absolute, this is it
1611
    if (path_isabsolute(icmd))
1611
    if (path_isabsolute(icmd))
1612
  return icmd;
1612
        return icmd;
1613
1613
1614
    const char *cp = getenv("PATH");
1614
    const char *cp = getenv("PATH");
1615
    if (!cp) //??
1615
    if (!cp) //??
1616
        cp = "";
1616
        cp = "";
1617
    string PATH(cp);
1617
    string PATH(cp);
...
...
1651
{
1651
{
1652
    string hs;
1652
    string hs;
1653
1653
1654
    mimeconf->get(mtype, hs, cstr_null);
1654
    mimeconf->get(mtype, hs, cstr_null);
1655
    if (hs.empty())
1655
    if (hs.empty())
1656
  return false;
1656
        return false;
1657
    vector<string> tokens;
1657
    vector<string> tokens;
1658
    stringToStrings(hs, tokens);
1658
    stringToStrings(hs, tokens);
1659
    if (tokens.empty()) {
1659
    if (tokens.empty()) {
1660
  LOGERR("getUncompressor: empty spec for mtype " << mtype << "\n");
1660
        LOGERR("getUncompressor: empty spec for mtype " << mtype << "\n");
1661
  return false;
1661
        return false;
1662
    }
1662
    }
1663
    vector<string>::iterator it = tokens.begin();
1663
    vector<string>::iterator it = tokens.begin();
1664
    if (tokens.size() < 2)
1664
    if (tokens.size() < 2)
1665
  return false;
1665
        return false;
1666
    if (stringlowercmp("uncompress", *it++)) 
1666
    if (stringlowercmp("uncompress", *it++)) 
1667
  return false;
1667
        return false;
1668
    cmd.clear();
1668
    cmd.clear();
1669
    cmd.push_back(findFilter(*it));
1669
    cmd.push_back(findFilter(*it));
1670
1670
1671
    // Special-case python and perl on windows: we need to also locate the
1671
    // Special-case python and perl on windows: we need to also locate the
1672
    // first argument which is the script name "python somescript.py". 
1672
    // first argument which is the script name "python somescript.py". 
...
...
1695
"# at them for an explanation of what can be set (you could also take a look\n"
1695
"# at them for an explanation of what can be set (you could also take a look\n"
1696
"# at the manual instead).\n"
1696
"# at the manual instead).\n"
1697
"# Values set in this file will override the system-wide values for the file\n"
1697
"# Values set in this file will override the system-wide values for the file\n"
1698
"# with the same name in the central directory. The syntax for setting\n"
1698
"# with the same name in the central directory. The syntax for setting\n"
1699
"# values is identical.\n"
1699
"# values is identical.\n"
1700
    ;
1700
;
1701
// We just use path_max to print the path to /usr/share/recoll/examples 
1702
// inside the config file. At worse, the text is truncated (using
1703
// snprintf). But 4096 should be enough :)
1704
#ifndef PATH_MAX
1705
#define MYPATHALLOC 4096
1706
#else
1707
#define MYPATHALLOC PATH_MAX
1708
#endif
1701
1709
1702
// Use uni2ascii -a K to generate these from the utf-8 strings
1710
// Use uni2ascii -a K to generate these from the utf-8 strings
1703
// Swedish and Danish. 
1711
// Swedish and Danish. 
1704
static const char swedish_ex[] = "unac_except_trans = \303\244\303\244 \303\204\303\244 \303\266\303\266 \303\226\303\266 \303\274\303\274 \303\234\303\274 \303\237ss \305\223oe \305\222oe \303\246ae \303\206ae \357\254\201fi \357\254\202fl \303\245\303\245 \303\205\303\245";
1712
static const char swedish_ex[] = "unac_except_trans = \303\244\303\244 \303\204\303\244 \303\266\303\266 \303\226\303\266 \303\274\303\274 \303\234\303\274 \303\237ss \305\223oe \305\222oe \303\246ae \303\206ae \357\254\201fi \357\254\202fl \303\245\303\245 \303\205\303\245";
1705
// German:
1713
// German:
1706
static const char german_ex[] = "unac_except_trans = \303\244\303\244 \303\204\303\244 \303\266\303\266 \303\226\303\266 \303\274\303\274 \303\234\303\274 \303\237ss \305\223oe \305\222oe \303\246ae \303\206ae \357\254\201fi \357\254\202fl";
1714
static const char german_ex[] = "unac_except_trans = \303\244\303\244 \303\204\303\244 \303\266\303\266 \303\226\303\266 \303\274\303\274 \303\234\303\274 \303\237ss \305\223oe \305\222oe \303\246ae \303\206ae \357\254\201fi \357\254\202fl";
1707
1715
1708
// Create initial user config by creating commented empty files
1716
// Create initial user config by creating commented empty files
1709
static const char *configfiles[] = {"recoll.conf", "mimemap", "mimeconf", 
1717
static const char *configfiles[] = {"recoll.conf", "mimemap", "mimeconf", 
1710
                  "mimeview"};
1718
                                    "mimeview"};
1711
static int ncffiles = sizeof(configfiles) / sizeof(char *);
1719
static int ncffiles = sizeof(configfiles) / sizeof(char *);
1712
bool RclConfig::initUserConfig()
1720
bool RclConfig::initUserConfig()
1713
{
1721
{
1714
    // Explanatory text
1722
    // Explanatory text
1715
    const int bs = sizeof(blurb0)+PATH_MAX+1;
1723
    const int bs = sizeof(blurb0)+MYPATHALLOC+1;
1716
    char blurb[bs];
1724
    char blurb[bs];
1717
    string exdir = path_cat(m_datadir, "examples");
1725
    string exdir = path_cat(m_datadir, "examples");
1718
    snprintf(blurb, bs, blurb0, exdir.c_str());
1726
    snprintf(blurb, bs, blurb0, exdir.c_str());
1719
1727
1720
    // Use protective 700 mode to create the top configuration
1728
    // Use protective 700 mode to create the top configuration
1721
    // directory: documents can be reconstructed from index data.
1729
    // directory: documents can be reconstructed from index data.
1722
    if (!path_exists(m_confdir) && 
1730
    if (!path_exists(m_confdir) && 
1723
  mkdir(m_confdir.c_str(), 0700) < 0) {
1731
        mkdir(m_confdir.c_str(), 0700) < 0) {
1724
  m_reason += string("mkdir(") + m_confdir + ") failed: " + 
1732
        m_reason += string("mkdir(") + m_confdir + ") failed: " + 
1725
      strerror(errno);
1733
            strerror(errno);
1726
  return false;
1734
        return false;
1727
    }
1735
    }
1728
    string lang = localelang();
1736
    string lang = localelang();
1729
    for (int i = 0; i < ncffiles; i++) {
1737
    for (int i = 0; i < ncffiles; i++) {
1730
  string dst = path_cat(m_confdir, string(configfiles[i])); 
1738
        string dst = path_cat(m_confdir, string(configfiles[i])); 
1731
  if (!path_exists(dst)) {
1739
        if (!path_exists(dst)) {
1732
      FILE *fp = fopen(dst.c_str(), "w");
1740
            FILE *fp = fopen(dst.c_str(), "w");
1733
      if (fp) {
1741
            if (fp) {
1734
      fprintf(fp, "%s\n", blurb);
1742
                fprintf(fp, "%s\n", blurb);
1735
      if (!strcmp(configfiles[i], "recoll.conf")) {
1743
                if (!strcmp(configfiles[i], "recoll.conf")) {
1736
          // Add improved unac_except_trans for some languages
1744
                    // Add improved unac_except_trans for some languages
1737
          if (lang == "se" || lang == "dk" || lang == "no" || 
1745
                    if (lang == "se" || lang == "dk" || lang == "no" || 
1738
          lang == "fi") {
1746
                        lang == "fi") {
1739
          fprintf(fp, "%s\n", swedish_ex);
1747
                        fprintf(fp, "%s\n", swedish_ex);
1740
          } else if (lang == "de") {
1748
                    } else if (lang == "de") {
1741
          fprintf(fp, "%s\n", german_ex);
1749
                        fprintf(fp, "%s\n", german_ex);
1742
          }
1750
                    }
1743
      }
1751
                }
1744
      fclose(fp);
1752
                fclose(fp);
1745
      } else {
1753
            } else {
1746
      m_reason += string("fopen ") + dst + ": " + strerror(errno);
1754
                m_reason += string("fopen ") + dst + ": " + strerror(errno);
1747
      return false;
1755
                return false;
1748
      }
1756
            }
1749
  }
1757
        }
1750
    }
1758
    }
1751
    return true;
1759
    return true;
1752
}
1760
}
1753
1761
1754
void RclConfig::zeroMe() {
1762
void RclConfig::zeroMe() {
...
...
1780
1788
1781
void RclConfig::initFrom(const RclConfig& r)
1789
void RclConfig::initFrom(const RclConfig& r)
1782
{
1790
{
1783
    zeroMe();
1791
    zeroMe();
1784
    if (!(m_ok = r.m_ok))
1792
    if (!(m_ok = r.m_ok))
1785
  return;
1793
        return;
1786
1794
1787
    // Copyable fields
1795
    // Copyable fields
1788
    m_ok = r.m_ok;
1796
    m_ok = r.m_ok;
1789
    m_reason = r.m_reason;
1797
    m_reason = r.m_reason;
1790
    m_confdir = r.m_confdir;
1798
    m_confdir = r.m_confdir;
...
...
1807
    m_thrConf = r.m_thrConf;
1815
    m_thrConf = r.m_thrConf;
1808
    m_mdreapers = r.m_mdreapers;
1816
    m_mdreapers = r.m_mdreapers;
1809
1817
1810
    // Special treatment
1818
    // Special treatment
1811
    if (r.m_conf)
1819
    if (r.m_conf)
1812
  m_conf = new ConfStack<ConfTree>(*(r.m_conf));
1820
        m_conf = new ConfStack<ConfTree>(*(r.m_conf));
1813
    if (r.mimemap)
1821
    if (r.mimemap)
1814
  mimemap = new ConfStack<ConfTree>(*(r.mimemap));
1822
        mimemap = new ConfStack<ConfTree>(*(r.mimemap));
1815
    if (r.mimeconf)
1823
    if (r.mimeconf)
1816
  mimeconf = new ConfStack<ConfSimple>(*(r.mimeconf));
1824
        mimeconf = new ConfStack<ConfSimple>(*(r.mimeconf));
1817
    if (r.mimeview)
1825
    if (r.mimeview)
1818
  mimeview = new ConfStack<ConfSimple>(*(r.mimeview));
1826
        mimeview = new ConfStack<ConfSimple>(*(r.mimeview));
1819
    if (r.m_fields)
1827
    if (r.m_fields)
1820
  m_fields = new ConfStack<ConfSimple>(*(r.m_fields));
1828
        m_fields = new ConfStack<ConfSimple>(*(r.m_fields));
1821
    if (r.m_ptrans)
1829
    if (r.m_ptrans)
1822
  m_ptrans = new ConfSimple(*(r.m_ptrans));
1830
        m_ptrans = new ConfSimple(*(r.m_ptrans));
1823
    if (r.m_stopsuffixes)
1831
    if (r.m_stopsuffixes)
1824
  m_stopsuffixes = new SuffixStore(*((SuffixStore*)r.m_stopsuffixes));
1832
        m_stopsuffixes = new SuffixStore(*((SuffixStore*)r.m_stopsuffixes));
1825
    initParamStale(m_conf, mimemap);
1833
    initParamStale(m_conf, mimemap);
1826
}
1834
}
1827
1835
1828
void RclConfig::initParamStale(ConfNull *cnf, ConfNull *mimemap)
1836
void RclConfig::initParamStale(ConfNull *cnf, ConfNull *mimemap)
1829
{
1837
{
...
...
1853
#include "cstr.h"
1861
#include "cstr.h"
1854
1862
1855
static char *thisprog;
1863
static char *thisprog;
1856
1864
1857
static char usage [] = "\n"
1865
static char usage [] = "\n"
1858
"-c: check a few things in the configuration files\n"
1866
    "-c: check a few things in the configuration files\n"
1859
"[-s subkey] -q param : query parameter value\n"
1867
    "[-s subkey] -q param : query parameter value\n"
1860
"-f : print some field data\n"
1868
    "-f : print some field data\n"
1861
"  : default: print parameters\n"
1869
    "  : default: print parameters\n"
1862
1870
1863
;
1871
    ;
1864
static void
1872
static void
1865
Usage(void)
1873
Usage(void)
1866
{
1874
{
1867
    fprintf(stderr, "%s: usage: %s\n", thisprog, usage);
1875
    fprintf(stderr, "%s: usage: %s\n", thisprog, usage);
1868
    exit(1);
1876
    exit(1);
1869
}
1877
}
1870
1878
1871
static int     op_flags;
1879
static int     op_flags;
1872
#define OPT_MOINS 0x1
1880
#define OPT_MOINS 0x1
1873
#define OPT_s   0x2 
1881
#define OPT_s     0x2 
1874
#define OPT_q   0x4 
1882
#define OPT_q     0x4 
1875
#define OPT_c     0x8
1883
#define OPT_c     0x8
1876
#define OPT_f     0x10
1884
#define OPT_f     0x10
1877
1885
1878
int main(int argc, char **argv)
1886
int main(int argc, char **argv)
1879
{
1887
{
...
...
1881
    
1889
    
1882
    thisprog = argv[0];
1890
    thisprog = argv[0];
1883
    argc--; argv++;
1891
    argc--; argv++;
1884
1892
1885
    while (argc > 0 && **argv == '-') {
1893
    while (argc > 0 && **argv == '-') {
1886
  (*argv)++;
1894
        (*argv)++;
1887
  if (!(**argv))
1895
        if (!(**argv))
1888
      /* Cas du "adb - core" */
1896
            /* Cas du "adb - core" */
1889
      Usage();
1897
            Usage();
1890
  while (**argv)
1898
        while (**argv)
1891
      switch (*(*argv)++) {
1899
            switch (*(*argv)++) {
1892
      case 'c':    op_flags |= OPT_c; break;
1900
            case 'c':   op_flags |= OPT_c; break;
1893
      case 'f':    op_flags |= OPT_f; break;
1901
            case 'f':   op_flags |= OPT_f; break;
1894
      case 's':    op_flags |= OPT_s; if (argc < 2)  Usage();
1902
            case 's':   op_flags |= OPT_s; if (argc < 2)  Usage();
1895
      skey = *(++argv);
1903
                skey = *(++argv);
1896
      argc--; 
1904
                argc--; 
1897
      goto b1;
1905
                goto b1;
1898
      case 'q':    op_flags |= OPT_q; if (argc < 2)  Usage();
1906
            case 'q':   op_flags |= OPT_q; if (argc < 2)  Usage();
1899
      pname = *(++argv);
1907
                pname = *(++argv);
1900
      argc--; 
1908
                argc--; 
1901
      goto b1;
1909
                goto b1;
1902
      default: Usage();    break;
1910
            default: Usage();   break;
1903
      }
1911
            }
1904
    b1: argc--; argv++;
1912
    b1: argc--; argv++;
1905
    }
1913
    }
1906
1914
1907
    if (argc != 0)
1915
    if (argc != 0)
1908
  Usage();
1916
        Usage();
1909
1917
1910
    string reason;
1918
    string reason;
1911
    RclConfig *config = recollinit(0, 0, reason);
1919
    RclConfig *config = recollinit(0, 0, reason);
1912
    if (config == 0 || !config->ok()) {
1920
    if (config == 0 || !config->ok()) {
1913
  cerr << "Configuration problem: " << reason << endl;
1921
        cerr << "Configuration problem: " << reason << endl;
1914
  exit(1);
1922
        exit(1);
1915
    }
1923
    }
1916
    if (op_flags & OPT_s)
1924
    if (op_flags & OPT_s)
1917
  config->setKeyDir(skey);
1925
        config->setKeyDir(skey);
1918
    if (op_flags & OPT_q) {
1926
    if (op_flags & OPT_q) {
1919
  string value;
1927
        string value;
1920
  if (!config->getConfParam(pname, value)) {
1928
        if (!config->getConfParam(pname, value)) {
1921
      fprintf(stderr, "getConfParam failed for [%s]\n", pname.c_str());
1929
            fprintf(stderr, "getConfParam failed for [%s]\n", pname.c_str());
1922
      exit(1);
1930
            exit(1);
1923
  }
1931
        }
1924
  printf("[%s] -> [%s]\n", pname.c_str(), value.c_str());
1932
        printf("[%s] -> [%s]\n", pname.c_str(), value.c_str());
1925
    } else if (op_flags & OPT_f) {
1933
    } else if (op_flags & OPT_f) {
1926
  set<string> stored = config->getStoredFields();
1934
        set<string> stored = config->getStoredFields();
1927
  set<string> indexed = config->getIndexedFields();
1935
        set<string> indexed = config->getIndexedFields();
1928
  cout << "Stored fields: ";
1936
        cout << "Stored fields: ";
1929
        for (set<string>::const_iterator it = stored.begin(); 
1937
        for (set<string>::const_iterator it = stored.begin(); 
1930
             it != stored.end(); it++) {
1938
             it != stored.end(); it++) {
1931
            cout << "[" << *it << "] ";
1939
            cout << "[" << *it << "] ";
1932
        }
1940
        }
1933
  cout << endl;   
1941
        cout << endl;   
1934
  cout << "Indexed fields: ";
1942
        cout << "Indexed fields: ";
1935
        for (set<string>::const_iterator it = indexed.begin(); 
1943
        for (set<string>::const_iterator it = indexed.begin(); 
1936
             it != indexed.end(); it++) {
1944
             it != indexed.end(); it++) {
1937
      const FieldTraits *ftp;
1945
            const FieldTraits *ftp;
1938
      config->getFieldTraits(*it, &ftp);
1946
            config->getFieldTraits(*it, &ftp);
1939
      if (ftp)
1947
            if (ftp)
1940
      cout << "[" << *it << "]" << " -> [" << ftp->pfx << "] ";
1948
                cout << "[" << *it << "]" << " -> [" << ftp->pfx << "] ";
1941
      else 
1949
            else 
1942
      cout << "[" << *it << "]" << " -> [" << "(none)" << "] ";
1950
                cout << "[" << *it << "]" << " -> [" << "(none)" << "] ";
1943
1951
1944
        }
1952
        }
1945
  cout << endl;   
1953
        cout << endl;   
1946
    } else if (op_flags & OPT_c) {
1954
    } else if (op_flags & OPT_c) {
1947
  // Checking the configuration consistency
1955
        // Checking the configuration consistency
1948
  
1956
    
1949
  // Find and display category names
1957
        // Find and display category names
1950
        vector<string> catnames;
1958
        vector<string> catnames;
1951
        config->getMimeCategories(catnames);
1959
        config->getMimeCategories(catnames);
1952
        cout << "Categories: ";
1960
        cout << "Categories: ";
1953
        for (vector<string>::const_iterator it = catnames.begin(); 
1961
        for (vector<string>::const_iterator it = catnames.begin(); 
1954
             it != catnames.end(); it++) {
1962
             it != catnames.end(); it++) {
1955
            cout << *it << " ";
1963
            cout << *it << " ";
1956
        }
1964
        }
1957
        cout << endl;
1965
        cout << endl;
1958
1966
1959
  // Compute union of all types from each category. Check that there
1967
        // Compute union of all types from each category. Check that there
1960
  // are no duplicates while we are at it.
1968
        // are no duplicates while we are at it.
1961
        set<string> allmtsfromcats;
1969
        set<string> allmtsfromcats;
1962
        for (vector<string>::const_iterator it = catnames.begin(); 
1970
        for (vector<string>::const_iterator it = catnames.begin(); 
1963
             it != catnames.end(); it++) {
1971
             it != catnames.end(); it++) {
1964
            vector<string> cts;
1972
            vector<string> cts;
1965
            config->getMimeCatTypes(*it, cts);
1973
            config->getMimeCatTypes(*it, cts);
...
...
1971
                }
1979
                }
1972
                allmtsfromcats.insert(*it1);
1980
                allmtsfromcats.insert(*it1);
1973
            }
1981
            }
1974
        }
1982
        }
1975
1983
1976
  // Retrieve complete list of mime types 
1984
        // Retrieve complete list of mime types 
1977
        vector<string> mtypes = config->getAllMimeTypes();
1985
        vector<string> mtypes = config->getAllMimeTypes();
1978
1986
1979
  // And check that each mime type is found in exactly one category
1987
        // And check that each mime type is found in exactly one category
1980
        for (vector<string>::const_iterator it = mtypes.begin();
1988
        for (vector<string>::const_iterator it = mtypes.begin();
1981
             it != mtypes.end(); it++) {
1989
             it != mtypes.end(); it++) {
1982
            if (allmtsfromcats.find(*it) == allmtsfromcats.end()) {
1990
            if (allmtsfromcats.find(*it) == allmtsfromcats.end()) {
1983
                cout << "Not found in catgs: [" << *it << "]" << endl;
1991
                cout << "Not found in catgs: [" << *it << "]" << endl;
1984
            }
1992
            }
1985
        }
1993
        }
1986
1994
1987
  // List mime types not in mimeview
1995
        // List mime types not in mimeview
1988
        for (vector<string>::const_iterator it = mtypes.begin();
1996
        for (vector<string>::const_iterator it = mtypes.begin();
1989
             it != mtypes.end(); it++) {
1997
             it != mtypes.end(); it++) {
1990
      if (config->getMimeViewerDef(*it, "", false).empty()) {
1998
            if (config->getMimeViewerDef(*it, "", false).empty()) {
1991
      cout << "No viewer: [" << *it << "]" << endl;
1999
                cout << "No viewer: [" << *it << "]" << endl;
1992
      }
1993
        }
2000
            }
2001
        }
1994
2002
1995
  // Check that each mime type has an indexer
2003
        // Check that each mime type has an indexer
1996
        for (vector<string>::const_iterator it = mtypes.begin();
2004
        for (vector<string>::const_iterator it = mtypes.begin();
1997
             it != mtypes.end(); it++) {
2005
             it != mtypes.end(); it++) {
1998
      if (config->getMimeHandlerDef(*it, false).empty()) {
2006
            if (config->getMimeHandlerDef(*it, false).empty()) {
1999
      cout << "No filter: [" << *it << "]" << endl;
2007
                cout << "No filter: [" << *it << "]" << endl;
2000
      }
2001
        }
2008
            }
2009
        }
2002
2010
2003
  // Check that each mime type has a defined icon
2011
        // Check that each mime type has a defined icon
2004
        for (vector<string>::const_iterator it = mtypes.begin();
2012
        for (vector<string>::const_iterator it = mtypes.begin();
2005
             it != mtypes.end(); it++) {
2013
             it != mtypes.end(); it++) {
2006
      if (config->getMimeIconPath(*it, "") == "document") {
2014
            if (config->getMimeIconPath(*it, "") == "document") {
2007
      cout << "No or generic icon: [" << *it << "]" << endl;
2015
                cout << "No or generic icon: [" << *it << "]" << endl;
2008
      }
2016
            }
2009
        }
2017
        }
2010
2018
2011
    } else {
2019
    } else {
2012
        config->setKeyDir(cstr_null);
2020
        config->setKeyDir(cstr_null);
2013
  vector<string> names = config->getConfNames();
2021
        vector<string> names = config->getConfNames();
2014
  for (vector<string>::iterator it = names.begin(); 
2022
        for (vector<string>::iterator it = names.begin(); 
2015
       it != names.end();it++) {
2023
             it != names.end();it++) {
2016
      string value;
2024
            string value;
2017
      config->getConfParam(*it, value);
2025
            config->getConfParam(*it, value);
2018
      cout << *it << " -> [" << value << "]" << endl;
2026
            cout << *it << " -> [" << value << "]" << endl;
2019
  }
2027
        }
2020
    }
2028
    }
2021
    exit(0);
2029
    exit(0);
2022
}
2030
}
2023
2031
2024
#endif // TEST_RCLCONFIG
2032
#endif // TEST_RCLCONFIG