1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
2 /*
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 *
5 * This library is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Michael Zucchi <notzed@ximian.com>
18 */
19
20 #include "evolution-data-server-config.h"
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28
29 #include "camel-index.h"
30 #include "camel-object.h"
31
32 #define w(x)
33 #define io(x)
34 #define d(x) /*(printf ("%s (%d): ", __FILE__, __LINE__),(x))*/
35
36 #define CAMEL_INDEX_VERSION (0x01)
37
38 struct _CamelIndexPrivate {
39 gpointer dummy;
40 };
41
42 /* ********************************************************************** */
43 /* CamelIndex */
44 /* ********************************************************************** */
45
G_DEFINE_TYPE_WITH_PRIVATE(CamelIndex,camel_index,G_TYPE_OBJECT)46 G_DEFINE_TYPE_WITH_PRIVATE (CamelIndex, camel_index, G_TYPE_OBJECT)
47
48 static void
49 index_finalize (GObject *object)
50 {
51 CamelIndex *index = CAMEL_INDEX (object);
52
53 g_free (index->path);
54
55 /* Chain up to parent's finalize () method. */
56 G_OBJECT_CLASS (camel_index_parent_class)->finalize (object);
57 }
58
59 static void
camel_index_class_init(CamelIndexClass * class)60 camel_index_class_init (CamelIndexClass *class)
61 {
62 GObjectClass *object_class;
63
64 object_class = G_OBJECT_CLASS (class);
65 object_class->finalize = index_finalize;
66 }
67
68 static void
camel_index_init(CamelIndex * index)69 camel_index_init (CamelIndex *index)
70 {
71 index->priv = camel_index_get_instance_private (index);
72 index->version = CAMEL_INDEX_VERSION;
73 }
74
75 void
camel_index_construct(CamelIndex * idx,const gchar * path,gint flags)76 camel_index_construct (CamelIndex *idx,
77 const gchar *path,
78 gint flags)
79 {
80 g_free (idx->path);
81 idx->path = g_strdup_printf ("%s.index", path);
82 idx->flags = flags;
83 }
84
85 gint
camel_index_rename(CamelIndex * idx,const gchar * path)86 camel_index_rename (CamelIndex *idx,
87 const gchar *path)
88 {
89 CamelIndexClass *class;
90
91 g_return_val_if_fail (CAMEL_IS_INDEX (idx), -1);
92
93 class = CAMEL_INDEX_GET_CLASS (idx);
94 g_return_val_if_fail (class != NULL, -1);
95 g_return_val_if_fail (class->rename != NULL, -1);
96
97 if ((idx->state & CAMEL_INDEX_DELETED) == 0)
98 return class->rename (idx, path);
99 else {
100 errno = ENOENT;
101 return -1;
102 }
103 }
104
105 /**
106 * camel_index_set_normalize:
107 * @index: a #CamelIndex
108 * @func: (scope call): normalization function
109 * @user_data: user data for @func
110 *
111 * Since: 2.32
112 **/
113 void
camel_index_set_normalize(CamelIndex * index,CamelIndexNorm func,gpointer user_data)114 camel_index_set_normalize (CamelIndex *index,
115 CamelIndexNorm func,
116 gpointer user_data)
117 {
118 g_return_if_fail (CAMEL_IS_INDEX (index));
119
120 index->normalize = func;
121 index->normalize_data = user_data;
122 }
123
124 gint
camel_index_sync(CamelIndex * idx)125 camel_index_sync (CamelIndex *idx)
126 {
127 CamelIndexClass *class;
128
129 g_return_val_if_fail (CAMEL_IS_INDEX (idx), -1);
130
131 class = CAMEL_INDEX_GET_CLASS (idx);
132 g_return_val_if_fail (class != NULL, -1);
133 g_return_val_if_fail (class->sync != NULL, -1);
134
135 if ((idx->state & CAMEL_INDEX_DELETED) == 0)
136 return class->sync (idx);
137 else {
138 errno = ENOENT;
139 return -1;
140 }
141 }
142
143 gint
camel_index_compress(CamelIndex * idx)144 camel_index_compress (CamelIndex *idx)
145 {
146 CamelIndexClass *class;
147
148 g_return_val_if_fail (CAMEL_IS_INDEX (idx), -1);
149
150 class = CAMEL_INDEX_GET_CLASS (idx);
151 g_return_val_if_fail (class != NULL, -1);
152 g_return_val_if_fail (class->compress != NULL, -1);
153
154 if ((idx->state & CAMEL_INDEX_DELETED) == 0)
155 return class->compress (idx);
156 else {
157 errno = ENOENT;
158 return -1;
159 }
160 }
161
162 gint
camel_index_delete(CamelIndex * idx)163 camel_index_delete (CamelIndex *idx)
164 {
165 CamelIndexClass *class;
166 gint ret;
167
168 g_return_val_if_fail (CAMEL_IS_INDEX (idx), -1);
169
170 class = CAMEL_INDEX_GET_CLASS (idx);
171 g_return_val_if_fail (class != NULL, -1);
172 g_return_val_if_fail (class->delete_ != NULL, -1);
173
174 if ((idx->state & CAMEL_INDEX_DELETED) == 0) {
175 ret = class->delete_ (idx);
176 idx->state |= CAMEL_INDEX_DELETED;
177 } else {
178 errno = ENOENT;
179 ret = -1;
180 }
181
182 return ret;
183 }
184
185 gint
camel_index_has_name(CamelIndex * idx,const gchar * name)186 camel_index_has_name (CamelIndex *idx,
187 const gchar *name)
188 {
189 CamelIndexClass *class;
190
191 g_return_val_if_fail (CAMEL_IS_INDEX (idx), FALSE);
192
193 class = CAMEL_INDEX_GET_CLASS (idx);
194 g_return_val_if_fail (class != NULL, FALSE);
195 g_return_val_if_fail (class->has_name != NULL, FALSE);
196
197 if ((idx->state & CAMEL_INDEX_DELETED) == 0)
198 return class->has_name (idx, name);
199 else
200 return FALSE;
201 }
202
203 /**
204 * camel_index_add_name:
205 * @index: a #CamelIndex
206 * @name: a name to add
207 *
208 * Returns: (transfer none) (nullable): a #CamelIndexName with
209 * added given @name, or %NULL, when the @name could not be
210 * added.
211 **/
212 CamelIndexName *
camel_index_add_name(CamelIndex * index,const gchar * name)213 camel_index_add_name (CamelIndex *index,
214 const gchar *name)
215 {
216 CamelIndexClass *class;
217
218 g_return_val_if_fail (CAMEL_IS_INDEX (index), NULL);
219
220 class = CAMEL_INDEX_GET_CLASS (index);
221 g_return_val_if_fail (class != NULL, NULL);
222 g_return_val_if_fail (class->add_name != NULL, NULL);
223
224 if ((index->state & CAMEL_INDEX_DELETED) == 0)
225 return class->add_name (index, name);
226 else
227 return NULL;
228 }
229
230 gint
camel_index_write_name(CamelIndex * idx,CamelIndexName * idn)231 camel_index_write_name (CamelIndex *idx,
232 CamelIndexName *idn)
233 {
234 CamelIndexClass *class;
235
236 g_return_val_if_fail (CAMEL_IS_INDEX (idx), -1);
237
238 class = CAMEL_INDEX_GET_CLASS (idx);
239 g_return_val_if_fail (class != NULL, -1);
240 g_return_val_if_fail (class->write_name != NULL, -1);
241
242 if ((idx->state & CAMEL_INDEX_DELETED) == 0)
243 return class->write_name (idx, idn);
244 else {
245 errno = ENOENT;
246 return -1;
247 }
248 }
249
250 /**
251 * camel_index_find_name:
252 * @index: a #CamelIndex
253 * @name: a name to find
254 *
255 * Returns: (transfer none) (nullable): a #CamelIndexCursor with
256 * the given @name, or %NULL< when not found.
257 **/
258 CamelIndexCursor *
camel_index_find_name(CamelIndex * index,const gchar * name)259 camel_index_find_name (CamelIndex *index,
260 const gchar *name)
261 {
262 CamelIndexClass *class;
263
264 g_return_val_if_fail (CAMEL_IS_INDEX (index), NULL);
265
266 class = CAMEL_INDEX_GET_CLASS (index);
267 g_return_val_if_fail (class != NULL, NULL);
268 g_return_val_if_fail (class->find_name != NULL, NULL);
269
270 if ((index->state & CAMEL_INDEX_DELETED) == 0)
271 return class->find_name (index, name);
272 else
273 return NULL;
274 }
275
276 /**
277 * camel_index_delete_name:
278 * @index: a #CamelIndex
279 * @name: a name to delete
280 *
281 * Deletes the given @name from @index.
282 **/
283 void
camel_index_delete_name(CamelIndex * index,const gchar * name)284 camel_index_delete_name (CamelIndex *index,
285 const gchar *name)
286 {
287 CamelIndexClass *class;
288
289 g_return_if_fail (CAMEL_IS_INDEX (index));
290
291 class = CAMEL_INDEX_GET_CLASS (index);
292 g_return_if_fail (class != NULL);
293 g_return_if_fail (class->delete_name != NULL);
294
295 if ((index->state & CAMEL_INDEX_DELETED) == 0)
296 class->delete_name (index, name);
297 }
298
299 /**
300 * camel_index_find:
301 * @index: a #CamelIndex
302 * @word: a word to find
303 *
304 * Returns: (transfer none) (nullable): a #CamelIndexCursor object with
305 * the given @word, or %NULL, when not found
306 **/
307 CamelIndexCursor *
camel_index_find(CamelIndex * index,const gchar * word)308 camel_index_find (CamelIndex *index,
309 const gchar *word)
310 {
311 CamelIndexClass *class;
312 CamelIndexCursor *ret;
313 gchar *b = (gchar *) word;
314
315 g_return_val_if_fail (CAMEL_IS_INDEX (index), NULL);
316
317 class = CAMEL_INDEX_GET_CLASS (index);
318 g_return_val_if_fail (class != NULL, NULL);
319 g_return_val_if_fail (class->find != NULL, NULL);
320
321 if ((index->state & CAMEL_INDEX_DELETED) != 0)
322 return NULL;
323
324 if (index->normalize)
325 b = index->normalize (index, word, index->normalize_data);
326
327 ret = class->find (index, b);
328
329 if (b != word)
330 g_free (b);
331
332 return ret;
333 }
334
335 /**
336 * camel_index_words:
337 * @index: a #CamelIndex
338 *
339 * Returns: (transfer none) (nullable): a #CamelIndexCursor containing
340 * all words of the @index, or %NULL, when there are none
341 **/
342 CamelIndexCursor *
camel_index_words(CamelIndex * index)343 camel_index_words (CamelIndex *index)
344 {
345 CamelIndexClass *class;
346
347 g_return_val_if_fail (CAMEL_IS_INDEX (index), NULL);
348
349 class = CAMEL_INDEX_GET_CLASS (index);
350 g_return_val_if_fail (class != NULL, NULL);
351 g_return_val_if_fail (class->words != NULL, NULL);
352
353 if ((index->state & CAMEL_INDEX_DELETED) == 0)
354 return class->words (index);
355 else
356 return NULL;
357 }
358
359 /* ********************************************************************** */
360 /* CamelIndexName */
361 /* ********************************************************************** */
362
G_DEFINE_TYPE(CamelIndexName,camel_index_name,G_TYPE_OBJECT)363 G_DEFINE_TYPE (CamelIndexName, camel_index_name, G_TYPE_OBJECT)
364
365 static void
366 index_name_dispose (GObject *object)
367 {
368 CamelIndexName *index_name = CAMEL_INDEX_NAME (object);
369
370 g_clear_object (&index_name->index);
371
372 /* Chain up to parent's dispose () method. */
373 G_OBJECT_CLASS (camel_index_name_parent_class)->dispose (object);
374 }
375
376 static void
camel_index_name_class_init(CamelIndexNameClass * class)377 camel_index_name_class_init (CamelIndexNameClass *class)
378 {
379 GObjectClass *object_class;
380
381 object_class = G_OBJECT_CLASS (class);
382 object_class->dispose = index_name_dispose;
383 }
384
385 static void
camel_index_name_init(CamelIndexName * index_name)386 camel_index_name_init (CamelIndexName *index_name)
387 {
388 }
389
390 void
camel_index_name_add_word(CamelIndexName * idn,const gchar * word)391 camel_index_name_add_word (CamelIndexName *idn,
392 const gchar *word)
393 {
394 CamelIndexNameClass *class;
395 gchar *b = (gchar *) word;
396
397 g_return_if_fail (CAMEL_IS_INDEX_NAME (idn));
398
399 class = CAMEL_INDEX_NAME_GET_CLASS (idn);
400 g_return_if_fail (class != NULL);
401 g_return_if_fail (class->add_word != NULL);
402
403 if (idn->index->normalize)
404 b = idn->index->normalize (idn->index, word, idn->index->normalize_data);
405
406 class->add_word (idn, b);
407
408 if (b != word)
409 g_free (b);
410 }
411
412 gsize
camel_index_name_add_buffer(CamelIndexName * idn,const gchar * buffer,gsize len)413 camel_index_name_add_buffer (CamelIndexName *idn,
414 const gchar *buffer,
415 gsize len)
416 {
417 CamelIndexNameClass *class;
418
419 g_return_val_if_fail (CAMEL_IS_INDEX_NAME (idn), 0);
420
421 class = CAMEL_INDEX_NAME_GET_CLASS (idn);
422 g_return_val_if_fail (class != NULL, 0);
423 g_return_val_if_fail (class->add_buffer != NULL, 0);
424
425 return class->add_buffer (idn, buffer, len);
426 }
427
428 /* ********************************************************************** */
429 /* CamelIndexCursor */
430 /* ********************************************************************** */
431
G_DEFINE_TYPE(CamelIndexCursor,camel_index_cursor,G_TYPE_OBJECT)432 G_DEFINE_TYPE (CamelIndexCursor, camel_index_cursor, G_TYPE_OBJECT)
433
434 static void
435 index_cursor_dispose (GObject *object)
436 {
437 CamelIndexCursor *index_cursor = CAMEL_INDEX_CURSOR (object);
438
439 g_clear_object (&index_cursor->index);
440
441 /* Chain up to parent's dispose () method. */
442 G_OBJECT_CLASS (camel_index_cursor_parent_class)->dispose (object);
443 }
444
445 static void
camel_index_cursor_class_init(CamelIndexCursorClass * class)446 camel_index_cursor_class_init (CamelIndexCursorClass *class)
447 {
448 GObjectClass *object_class;
449
450 object_class = G_OBJECT_CLASS (class);
451 object_class->dispose = index_cursor_dispose;
452 }
453
454 static void
camel_index_cursor_init(CamelIndexCursor * index_cursor)455 camel_index_cursor_init (CamelIndexCursor *index_cursor)
456 {
457 }
458
459 const gchar *
camel_index_cursor_next(CamelIndexCursor * idc)460 camel_index_cursor_next (CamelIndexCursor *idc)
461 {
462 CamelIndexCursorClass *class;
463
464 g_return_val_if_fail (CAMEL_IS_INDEX_CURSOR (idc), NULL);
465
466 class = CAMEL_INDEX_CURSOR_GET_CLASS (idc);
467 g_return_val_if_fail (class != NULL, NULL);
468 g_return_val_if_fail (class->next != NULL, NULL);
469
470 return class->next (idc);
471 }
472
473