~ubuntu-branches/ubuntu/quantal/maildir-utils/quantal

« back to all changes in this revision

Viewing changes to src/mu-query-xapian.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2010-01-19 20:12:43 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100119201243-d8qmzgxgexhy1bs0
Tags: 0.6~beta1-1
* new upstream release 0.6-beta
  - that merges the several different programs under one binary mu
  - no sqlite storage is used anymore
* debian packaging changes:
  - debian/patches
    . remove all patches
  - remove debian/HOWTO (upstream document) it is completely outdated
  - debian/control:
    . adjust build-dep for gmime-2.4
    . remove build-dep on quilt and sqlite
    . adjust the description to new reality
  - debian/rules:
    . do not try to install doc files that are not present anymore
    . disable quilt adaptions
  - add debian/NEWS that explains that the separate programs are gone

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
** Copyright (C) 2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
 
3
**
 
4
** This program is free software; you can redistribute it and/or modify
 
5
** it under the terms of the GNU General Public License as published by
 
6
** the Free Software Foundation; either version 3 of the License, or
 
7
** (at your option) any later version.
 
8
**  
 
9
** This program is distributed in the hope that it will be useful,
 
10
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
** GNU General Public License for more details.
 
13
**  
 
14
** You should have received a copy of the GNU General Public License
 
15
** along with this program; if not, write to the Free Software Foundation,
 
16
** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  
 
17
**  
 
18
*/
 
19
 
 
20
#include <stdlib.h>
 
21
#include <xapian.h>
 
22
#include <glib/gstdio.h>
 
23
#include <string.h>
 
24
#include <string>
 
25
 
 
26
#include "mu-query-xapian.h"
 
27
 
 
28
#include "mu-msg-xapian.h"
 
29
#include "mu-msg-xapian-priv.hh"
 
30
 
 
31
#include "mu-util.h"
 
32
 
 
33
 
 
34
static void add_prefix (const MuMsgField* field, Xapian::QueryParser* qparser);
 
35
 
 
36
struct _MuQueryXapian {
 
37
        Xapian::Database*         _db;
 
38
        Xapian::QueryParser*      _qparser;
 
39
        Xapian::Sorter*           _sorters[MU_MSG_FIELD_TYPE_NUM];
 
40
};
 
41
 
 
42
gboolean
 
43
init_mu_query_xapian (MuQueryXapian *mqx, const char* dbpath)
 
44
{
 
45
        mqx->_db = 0;
 
46
        mqx->_qparser = 0;
 
47
        
 
48
        try {
 
49
                mqx->_db = new Xapian::Database(dbpath);
 
50
                mqx->_qparser = new Xapian::QueryParser;
 
51
                
 
52
                mqx->_qparser->set_database(*mqx->_db);
 
53
                mqx->_qparser->set_default_op(Xapian::Query::OP_OR);
 
54
                mqx->_qparser->set_stemming_strategy
 
55
                        (Xapian::QueryParser::STEM_SOME);
 
56
 
 
57
                memset (mqx->_sorters, 0, sizeof(mqx->_sorters));
 
58
                mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_prefix,
 
59
                                      (gpointer)mqx->_qparser);
 
60
                return TRUE;
 
61
 
 
62
        } MU_XAPIAN_CATCH_BLOCK;
 
63
 
 
64
        try {
 
65
                delete mqx->_db;
 
66
                delete mqx->_qparser;
 
67
 
 
68
        } MU_XAPIAN_CATCH_BLOCK;
 
69
        
 
70
        return FALSE;
 
71
}
 
72
 
 
73
        
 
74
static void
 
75
uninit_mu_query_xapian (MuQueryXapian *mqx)
 
76
{
 
77
        try {
 
78
                delete mqx->_db;
 
79
                delete mqx->_qparser;
 
80
 
 
81
                for (int i = 0; i != MU_MSG_FIELD_TYPE_NUM; ++i) 
 
82
                        delete mqx->_sorters[i];
 
83
                
 
84
        } MU_XAPIAN_CATCH_BLOCK;
 
85
}
 
86
 
 
87
static Xapian::Query
 
88
get_query  (MuQueryXapian * mqx, const char* searchexpr, int *err = 0)  {
 
89
        
 
90
        try {
 
91
                return mqx->_qparser->parse_query
 
92
                        (searchexpr,
 
93
                         Xapian::QueryParser::FLAG_BOOLEAN          | 
 
94
                         Xapian::QueryParser::FLAG_PHRASE           |
 
95
                         //      Xapian::QueryParser::FLAG_LOVEHATE         |
 
96
                         //      Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE |
 
97
                         Xapian::QueryParser::FLAG_WILDCARD         |
 
98
                         Xapian::QueryParser::FLAG_PURE_NOT         |
 
99
                         Xapian::QueryParser::FLAG_PARTIAL);
 
100
 
 
101
        } MU_XAPIAN_CATCH_BLOCK;
 
102
 
 
103
        if (err)
 
104
                *err  = 1;
 
105
        
 
106
        return Xapian::Query();
 
107
}
 
108
 
 
109
static void
 
110
add_prefix (const MuMsgField* field, Xapian::QueryParser* qparser)
 
111
{
 
112
        if (!mu_msg_field_is_xapian_enabled(field)) 
 
113
                return;
 
114
 
 
115
        const std::string prefix (mu_msg_field_xapian_prefix(field));
 
116
        
 
117
        qparser->add_boolean_prefix(std::string(mu_msg_field_name(field)),
 
118
                                   prefix);
 
119
        qparser->add_boolean_prefix(std::string(mu_msg_field_shortcut(field)),
 
120
                                    prefix);
 
121
 
 
122
        /* make the empty string match this field too*/
 
123
        qparser->add_prefix ("", prefix);
 
124
}
 
125
 
 
126
MuQueryXapian*
 
127
mu_query_xapian_new (const char* xpath)
 
128
{
 
129
        MuQueryXapian *mqx;
 
130
        
 
131
        g_return_val_if_fail (xpath, NULL);
 
132
 
 
133
        if (!mu_util_check_dir (xpath, TRUE, FALSE)) {
 
134
                g_warning ("'%s' is not a readable xapian dir",
 
135
                           xpath);
 
136
                return NULL;
 
137
        }
 
138
 
 
139
        mqx = g_new (MuQueryXapian, 1);
 
140
 
 
141
        if (!init_mu_query_xapian (mqx, xpath)) {
 
142
                g_warning ("failed to initalize xapian query");
 
143
                g_free (mqx);
 
144
                return NULL;
 
145
        }
 
146
        
 
147
        return mqx;
 
148
}
 
149
 
 
150
 
 
151
void
 
152
mu_query_xapian_destroy (MuQueryXapian *self)
 
153
{
 
154
        if (!self)
 
155
                return;
 
156
 
 
157
        uninit_mu_query_xapian (self);
 
158
        g_free (self);
 
159
}
 
160
 
 
161
 
 
162
MuMsgXapian*
 
163
mu_query_xapian_run (MuQueryXapian *self, const char* searchexpr,
 
164
                     const MuMsgField* sortfield, gboolean ascending)  
 
165
{
 
166
        g_return_val_if_fail (self, NULL);
 
167
        g_return_val_if_fail (searchexpr, NULL);
 
168
                
 
169
        try {
 
170
                Xapian::Query q(get_query(self, searchexpr));
 
171
                Xapian::Enquire enq (*self->_db);
 
172
                
 
173
                if (sortfield) 
 
174
                        enq.set_sort_by_value (
 
175
                                (Xapian::valueno)mu_msg_field_id(sortfield),
 
176
                                ascending);
 
177
 
 
178
                enq.set_query  (q);
 
179
                enq.set_cutoff (0,0);
 
180
 
 
181
                return mu_msg_xapian_new (enq, 10000);
 
182
                
 
183
        } MU_XAPIAN_CATCH_BLOCK_RETURN(NULL);
 
184
}
 
185
 
 
186
char*
 
187
mu_query_xapian_as_string  (MuQueryXapian *self, const char* searchexpr) 
 
188
{
 
189
        g_return_val_if_fail (self, NULL);
 
190
        g_return_val_if_fail (searchexpr, NULL);
 
191
                
 
192
        try {
 
193
                Xapian::Query q(get_query(self, searchexpr));
 
194
                return g_strdup(q.get_description().c_str());
 
195
                
 
196
        } MU_XAPIAN_CATCH_BLOCK_RETURN(NULL);
 
197
}
 
198
 
 
199
 
 
200
static gboolean
 
201
needs_quotes (const char* str)
 
202
{
 
203
        int i;
 
204
        const char *keywords[] = {
 
205
                "ANO", "OR", "NOT", "NEAR", "ADJ"
 
206
        };
 
207
 
 
208
        for (i = 0; i != G_N_ELEMENTS(keywords); ++i)
 
209
                if (g_strcasecmp (str, keywords[i]) == 0)
 
210
                        return TRUE;
 
211
 
 
212
        return FALSE;
 
213
}
 
214
 
 
215
 
 
216
char*
 
217
mu_query_xapian_combine (const gchar **params, gboolean connect_or)
 
218
{
 
219
        GString *str;
 
220
        int i;
 
221
        
 
222
        g_return_val_if_fail (params && params[0], NULL);
 
223
        
 
224
        str = g_string_sized_new (64); /* just a guess */
 
225
        
 
226
        for (i = 0; params && params[i]; ++i) { 
 
227
 
 
228
                const char* elm;
 
229
                const char* cnx = "";
 
230
                gboolean do_quote;
 
231
 
 
232
                elm = (const gchar*)params[i];
 
233
                if (!elm) /* shouldn't happen */
 
234
                        break;  
 
235
                
 
236
                if (params[i + 1])
 
237
                        cnx = connect_or ? " OR " : " AND ";
 
238
                
 
239
                do_quote = needs_quotes (elm);
 
240
                g_string_append_printf (str, "%s%s%s%s",
 
241
                                        do_quote ? "\"" : "",
 
242
                                        elm,
 
243
                                        do_quote ? "\"" : "",
 
244
                                        cnx);   
 
245
        }
 
246
 
 
247
        return g_string_free (str, FALSE);
 
248
}
 
249
 
 
250