Imported Upstream version 0.48
[platform/upstream/libical.git] / src / libicalss / icalset.c
1 /* -*- Mode: C -*- */
2 /*======================================================================
3  FILE: icalset.c
4  CREATOR: eric 17 Jul 2000
5
6
7  Icalset is the "base class" for representations of a collection of
8  iCal components. Derived classes (actually delegates) include:
9  
10     icalfileset   Store components in a single file
11     icaldirset    Store components in multiple files in a directory
12     icalheapset   Store components on the heap
13     icalmysqlset  Store components in a mysql database. 
14
15  $Id: icalset.c,v 1.18 2008-01-02 20:07:41 dothebart Exp $
16  $Locker:  $
17
18  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
19
20  This program is free software; you can redistribute it and/or modify
21  it under the terms of either: 
22
23     The LGPL as published by the Free Software Foundation, version
24     2.1, available at: http://www.fsf.org/copyleft/lesser.html
25
26   Or:
27
28     The Mozilla Public License Version 1.0. You may obtain a copy of
29     the License at http://www.mozilla.org/MPL/
30
31  The Original Code is eric. The Initial Developer of the Original
32  Code is Eric Busboom
33
34
35 ======================================================================*/
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include <libical/ical.h>
42 #include "icalset.h"
43 #include "icalfileset.h"
44 #include "icalfilesetimpl.h"
45 #include "icaldirset.h"
46 #include "icaldirsetimpl.h"
47 #include <stdlib.h>
48 #include <string.h>
49 #include <errno.h>
50
51 #ifdef WITH_BDB4
52 #include "icalbdbset.h"
53 #include "icalbdbsetimpl.h"
54 #endif
55
56 /* #define _DLOPEN_TEST */
57 #ifdef _DLOPEN_TEST
58 #include <sys/types.h>
59 #include <dlfcn.h>
60 #include <dirent.h>
61 #endif
62
63 static icalset icalset_dirset_init = {
64     ICAL_DIR_SET,
65     sizeof(icaldirset),
66     NULL,
67     icaldirset_init,
68     icaldirset_free,
69     icaldirset_path,
70     icaldirset_mark,
71     icaldirset_commit,
72     icaldirset_add_component,
73     icaldirset_remove_component,
74     icaldirset_count_components,
75     icaldirset_select,
76     icaldirset_clear,
77     icaldirset_fetch,
78     icaldirset_fetch_match,
79     icaldirset_has_uid,
80     icaldirset_modify,
81     icaldirset_get_current_component,
82     icaldirset_get_first_component,
83     icaldirset_get_next_component,
84     icaldirset_begin_component,
85     icaldirsetiter_to_next,
86     icaldirsetiter_to_prior
87 };
88
89
90 static icalset icalset_fileset_init = {
91     ICAL_FILE_SET,
92     sizeof(icalfileset),
93     NULL,
94     icalfileset_init,
95     icalfileset_free,
96     icalfileset_path,
97     icalfileset_mark,
98     icalfileset_commit,
99     icalfileset_add_component,
100     icalfileset_remove_component,
101     icalfileset_count_components,
102     icalfileset_select,
103     icalfileset_clear,
104     icalfileset_fetch,
105     icalfileset_fetch_match,
106     icalfileset_has_uid,
107     icalfileset_modify,
108     icalfileset_get_current_component,
109     icalfileset_get_first_component,
110     icalfileset_get_next_component,
111     icalfileset_begin_component,
112     icalfilesetiter_to_next,
113     NULL
114 };
115
116 #ifdef WITH_BDB4
117 static icalset icalset_bdbset_init = {
118     ICAL_BDB_SET,
119     sizeof(icalbdbset),
120     NULL,
121     icalbdbset_init,
122     icalbdbset_free,
123     icalbdbset_path,
124     icalbdbset_mark,
125     icalbdbset_commit,
126     icalbdbset_add_component,
127     icalbdbset_remove_component,
128     icalbdbset_count_components,
129     icalbdbset_select,
130     icalbdbset_clear,
131     icalbdbset_fetch,
132     icalbdbset_fetch_match,
133     icalbdbset_has_uid,
134     icalbdbset_modify,
135     icalbdbset_get_current_component,
136     icalbdbset_get_first_component,
137     icalbdbset_get_next_component,
138     icalbdbset_begin_component,
139     icalbdbsetiter_to_next,
140     NULL 
141 };
142 #endif
143
144 #ifdef _DLOPEN_TEST
145 static int      icalset_init_done = 0;
146 static pvl_list icalset_kinds = 0;
147
148 typedef icalset *(*fptr)(void);
149
150 /**
151  * Try to load the file and register any icalset found within.
152  */
153 static int load(const char *file) {
154
155         void           *modh;
156         fptr            inith;
157         icalset        *icalset_init_ptr;
158
159         if ((modh = dlopen(file, RTLD_NOW)) == 0) {
160                 perror("dlopen");
161                 return 0;
162         }
163
164         if ((inith = (fptr)dlsym(modh, "InitModule")) == 0) {
165                 perror("dlsym");
166                 return 0;
167         }
168
169         while ((icalset_init_ptr = ((inith)())) != 0) {
170                 pvl_push(icalset_kinds, &icalset_init_ptr);
171         }
172
173         return 1;
174 }
175
176 /**
177  * Look in the given directory for files called mod_*.o and try to
178  * load them.
179  */
180 int icalset_loaddir(const char *path) {
181         DIR             *d;
182         struct dirent   *dp;
183         char            buf[PATH_MAX],
184                        *bufptr;
185         int             tot = 0;
186
187         strcpy(buf, path);
188         bufptr = buf + strlen(buf);
189
190         if (*(bufptr-1) != '/')
191                 *bufptr++ = '/';
192
193         if ((d = opendir(path)) == 0) {
194                 perror("opendir");
195                 return 0;
196         }
197
198         while ((dp = readdir(d)) != 0) {
199                 if (strncmp(dp->d_name, "mod_", 4)) continue;
200
201                 strcpy(bufptr, dp->d_name);
202
203                 load(buf);
204                 tot++;
205         }
206         (void)closedir(d);
207
208         return 1;
209 }
210
211 int icalset_register_class(icalset *set);
212
213 static void icalset_init(void) {
214     assert(icalset_kinds == 0);
215     icalset_kinds = pvl_newlist();
216
217     pvl_push(icalset_kinds, &icalset_fileset_init);
218     pvl_push(icalset_kinds, &icalset_dirset_init);
219 #ifdef WITH_BDB4
220     pvl_push(icalset_kinds, &icalset_bdb4set_init);
221 #endif
222
223 #ifdef EXT_PATH
224     icalset_loaddir(EXT_PATH);
225 #endif
226
227     icalset_init_done++;
228 }
229
230 int icalset_register_class(icalset *set) {
231
232     if (!icalset_init_done)
233         icalset_init();
234
235     pvl_push(icalset_kinds, set);
236     return 1;
237 }
238
239 #endif
240
241 icalset* icalset_new(icalset_kind kind, const char* dsn, void* options) {
242   icalset *data = NULL;
243   icalset *ret = NULL;
244
245 #ifdef _DLOPEN_TEST
246     pvl_elem    e;
247     icalset    *impl;
248
249     if (!icalset_init_done)
250         icalset_init();
251
252     for(e = pvl_head(icalset_kinds); e!=0; e = pvl_next(e)) {
253         impl = (icalset*)pvl_data(e);
254         if (impl->kind == kind)
255             break;
256     }
257     if (e == 0) {
258         icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
259         return(NULL);
260     }
261
262     data = (icalset*)malloc(impl->size);
263     if (data == 0) {
264         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
265         errno = ENOMEM;
266         return 0;
267     }
268
269     /* The first member of the derived class must be an icalset. */
270     memset(data,0,impl->size);
271     /* *data = *impl; */
272     memcpy(data, impl, sizeof(icalset));
273
274     data->dsn     = strdup(dsn);
275 #else
276   switch(kind) {
277   case ICAL_FILE_SET:
278     data = (icalset*) malloc(sizeof(icalfileset));
279     if (data == 0) {
280         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
281         errno = ENOMEM;
282         return 0;
283     }
284     memset(data,0,sizeof(icalfileset));
285     *data = icalset_fileset_init;
286     break;
287   case ICAL_DIR_SET:
288     data = (icalset*) malloc(sizeof(icaldirset));
289     if (data == 0) {
290         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
291         errno = ENOMEM;
292         return 0;
293     }
294     memset(data,0,sizeof(icaldirset));
295     *data = icalset_dirset_init;
296     break;
297 #ifdef WITH_BDB4
298   case ICAL_BDB_SET:
299     data = (icalset*) malloc(sizeof(icalbdbset));
300     if (data == 0) {
301         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
302         errno = ENOMEM;
303         return 0;
304     }
305     memset(data,0,sizeof(icalbdbset));
306     *data = icalset_bdbset_init;
307     break;
308 #endif
309     
310   default:
311     icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
312     /** unimplemented **/
313     return(NULL);
314   }
315
316   data->kind    = kind;
317   data->dsn     = strdup(dsn);
318 #endif
319
320   /** call the implementation specific initializer **/
321   if ((ret = data->init(data, dsn, options)) == NULL)
322     icalset_free(data);
323
324   return ret;
325 }
326
327 icalset* icalset_new_file(const char* path)
328 {
329   return icalset_new(ICAL_FILE_SET, path, NULL);
330 }
331
332 icalset* icalset_new_file_writer(const char* path)
333 {
334   return icalfileset_new_writer(path);
335 }
336
337 icalset* icalset_new_file_reader(const char* path)
338 {
339   return icalfileset_new_reader(path);
340 }
341
342
343 icalset* icalset_new_dir(const char* path)
344 {
345   return icalset_new(ICAL_DIR_SET, path, NULL);
346 }
347
348 icalset* icalset_new_dir_writer(const char* path)
349 {
350   return icaldirset_new_writer(path);
351 }
352
353 icalset* icalset_new_dir_reader(const char* path)
354 {
355   return icaldirset_new_reader(path);
356 }
357
358
359
360 /* Functions for built-in methods */
361
362 /**
363  *  free memory associated with this icalset
364  *  automatically calls the implementation specific free routine
365  */
366
367 void icalset_free(icalset* set)
368 {
369   if (set->free)
370     set->free(set);
371
372   if (set->dsn)
373     free(set->dsn);
374
375   free(set);
376 }
377
378
379 const char* icalset_path(icalset* set) {
380     return set->path(set);
381 }
382
383 void icalset_mark(icalset* set) {
384     set->mark(set);
385 }
386
387 icalerrorenum icalset_commit(icalset* set) {
388     return set->commit(set);
389 }
390
391 icalerrorenum icalset_add_component(icalset* set, icalcomponent* comp) {
392     return set->add_component(set,comp);
393 }
394
395 icalerrorenum icalset_remove_component(icalset* set, icalcomponent* comp) {
396     return set->remove_component(set,comp);
397 }
398
399 int icalset_count_components(icalset* set,icalcomponent_kind kind) {
400     return set->count_components(set,kind);
401 }
402
403 icalerrorenum icalset_select(icalset* set, icalgauge* gauge) {
404     return set->select(set, gauge);
405 }
406
407 void icalset_clear(icalset* set) {
408     set->clear(set);
409 }
410
411 icalcomponent* icalset_fetch(icalset* set, const char* uid) {
412     return set->fetch(set, uid);
413 }
414
415 icalcomponent* icalset_fetch_match(icalset* set, icalcomponent *comp) {
416     return set->fetch_match(set, comp);
417 }
418
419 int icalset_has_uid(icalset* set, const char* uid) {
420     return set->has_uid(set, uid);
421 }
422
423 icalerrorenum icalset_modify(icalset* set, icalcomponent *old,
424                                icalcomponent *new) {
425     return set->modify(set, old, new);
426 }
427
428 icalcomponent* icalset_get_current_component(icalset* set) {
429     return set->get_current_component(set);
430 }
431
432 icalcomponent* icalset_get_first_component(icalset* set) {
433     return set->get_first_component(set);
434 }
435
436 icalcomponent* icalset_get_next_component(icalset* set) {
437     return set->get_next_component(set);
438 }
439
440 icalsetiter icalsetiter_null = {{ICAL_NO_COMPONENT, 0}, 0};
441
442 icalsetiter icalset_begin_component(icalset* set,
443                                  icalcomponent_kind kind, icalgauge* gauge) {
444     return set->icalset_begin_component(set, kind, gauge);
445 }
446
447 icalcomponent* icalsetiter_next(icalsetiter* itr) {
448
449     icalcomponent* c = 0;
450     icalerror_check_arg_rz( (itr != NULL), "i");
451
452     do  {
453         c = icalcompiter_next(&(itr->iter));
454         if(c != 0 && (itr->gauge == 0 ||
455                         icalgauge_compare(itr->gauge, c) == 1)){
456             return c;
457         }
458     } while (c != 0);
459
460     return 0;
461 }
462
463 icalcomponent* icalsetiter_prior(icalsetiter* i) {
464
465     icalcomponent* c = 0;
466     icalerror_check_arg_rz( (i != NULL), "i" );
467
468     do  {
469         c = icalcompiter_prior(&(i->iter));
470         if(c != 0 && (i->gauge == 0 ||
471                         icalgauge_compare(i->gauge, c) == 1)){
472             return c;
473         }
474     } while (c != 0);
475
476     return 0;
477 }
478
479 icalcomponent* icalsetiter_deref(icalsetiter* i) {
480     icalerror_check_arg_rz( (i != NULL), "i" );
481     return (icalcompiter_deref(&(i->iter)));
482 }
483
484 /* for subclasses that use multiple clusters that require specialized cluster traversal */
485 icalcomponent* icalsetiter_to_next(icalset* set, icalsetiter* i)
486 {
487     return set->icalsetiter_to_next(set, i);
488 }
489
490 icalcomponent* icalsetiter_to_prior(icalset* set, icalsetiter* i)
491 {
492     return set->icalsetiter_to_prior(set, i);
493 }