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