1 /* Copyright (C) 2005-2021 J.F.Dockes
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the
14  *   Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 #include "autoconfig.h"
18 
19 #include "log.h"
20 #include "filtseq.h"
21 #include "rclconfig.h"
22 
23 using std::string;
24 
filter(const DocSeqFiltSpec & fs,const Rcl::Doc * x)25 static bool filter(const DocSeqFiltSpec& fs, const Rcl::Doc *x)
26 {
27     LOGDEB2("  Filter: ncrits " << fs.crits.size() << "\n");
28     // Compare using each criterion in term. We're doing an or: 1st ok ends
29     for (unsigned int i = 0; i < fs.crits.size(); i++) {
30         switch (fs.crits[i]) {
31         case DocSeqFiltSpec::DSFS_MIMETYPE:
32             LOGDEB2(" filter: MIMETYPE: me [" << fs.values[i] << "] doc [" << x->mimetype << "]\n");
33             if (x->mimetype == fs.values[i])
34                 return true;
35             break;
36         case DocSeqFiltSpec::DSFS_QLANG: {
37             LOGDEB(" filter: QLANG [" << fs.values[i] << "]!!\n");
38         }
39             break;
40         case DocSeqFiltSpec::DSFS_PASSALL:
41             return true;
42         }
43     }
44     // Did all comparisons
45     return false;
46 }
47 
DocSeqFiltered(RclConfig * conf,std::shared_ptr<DocSequence> iseq,DocSeqFiltSpec & filtspec)48 DocSeqFiltered::DocSeqFiltered(
49     RclConfig *conf, std::shared_ptr<DocSequence> iseq, DocSeqFiltSpec &filtspec)
50     : DocSeqModifier(iseq), m_config(conf)
51 {
52     setFiltSpec(filtspec);
53 }
54 
setFiltSpec(const DocSeqFiltSpec & filtspec)55 bool DocSeqFiltered::setFiltSpec(const DocSeqFiltSpec &filtspec)
56 {
57     LOGDEB0("DocSeqFiltered::setFiltSpec\n");
58     for (unsigned int i = 0; i < filtspec.crits.size(); i++) {
59         switch (filtspec.crits[i]) {
60         case DocSeqFiltSpec::DSFS_MIMETYPE:
61             m_spec.orCrit(filtspec.crits[i], filtspec.values[i]);
62             break;
63         case DocSeqFiltSpec::DSFS_QLANG: {
64             // There are very few lang constructs that we can interpret. The
65             // default config uses rclcat:value only. That will be all for now...
66             string val = filtspec.values[i];
67             if (val.find("rclcat:") == 0) {
68                 string catg = val.substr(7);
69                 vector<string> tps;
70                 m_config->getMimeCatTypes(catg, tps);
71                 for (const auto& mime : tps) {
72                     LOGDEB2("Adding mime: [" << mime << "]\n");
73                     m_spec.orCrit(DocSeqFiltSpec::DSFS_MIMETYPE, mime);
74                 }
75             }
76         }
77             break;
78         default:
79             break;
80         }
81     }
82     // If m_spec ends up empty, pass everything, better than filtering all.
83     if (m_spec.crits.empty()) {
84         m_spec.orCrit(DocSeqFiltSpec::DSFS_PASSALL, "");
85     }
86     m_dbindices.clear();
87     return true;
88 }
89 
getDoc(int idx,Rcl::Doc & doc,string *)90 bool DocSeqFiltered::getDoc(int idx, Rcl::Doc &doc, string *)
91 {
92     LOGDEB2("DocSeqFiltered::getDoc() fetching " << idx << "\n");
93 
94     if (idx >= (int)m_dbindices.size()) {
95         // Have to fetch docs and filter until we get enough or
96         // fail
97         m_dbindices.reserve(idx+1);
98 
99         // First backend seq doc we fetch is the one after last stored
100         int backend_idx = m_dbindices.size() > 0 ? m_dbindices.back() + 1 : 0;
101 
102         // Loop until we get enough docs
103         Rcl::Doc tdoc;
104         while (idx >= (int)m_dbindices.size()) {
105             if (!m_seq->getDoc(backend_idx, tdoc))
106                 return false;
107             if (filter(m_spec, &tdoc)) {
108                 m_dbindices.push_back(backend_idx);
109             }
110             backend_idx++;
111         }
112         doc = tdoc;
113     } else {
114         // The corresponding backend indice is already known
115         if (!m_seq->getDoc(m_dbindices[idx], doc))
116             return false;
117     }
118     return true;
119 }
120 
121