1 /*
2 *  RAL -- Rubrica Addressbook Library
3 *  file: abook.c
4 *
5 *  Copyright (C) Nicola Fragale <nicolafragale@libero.it>
6 *
7 *  This program is free software; you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation; either version 3 of the License
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program; if not, write to the Free Software
18 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20 
21 #include <time.h>
22 #include <string.h>
23 #include <glib.h>
24 #include <glib-object.h>
25 #include <glib/gstdio.h>
26 #include <glib/gi18n-lib.h>
27 
28 #include "rlib.h"
29 #include "manager.h"
30 #include "plugin.h"
31 #include "abook.h"
32 #include "card.h"
33 #include "personal.h"
34 #include "company.h"
35 #include "group_box.h"
36 #include "utils.h"
37 #include "error.h"
38 
39 
40 /*  property enumeration
41  */
42 enum {
43   ABOOK_NAME = 1,
44   ABOOK_PATH,
45   DELETED_CARDS,
46   SELECTED_ID,
47   MARKED_CARDS,
48   PRINTABLE_CARDS,
49   MODIFYED,
50   FILE_FILTER,
51 };
52 
53 
54 struct _RAbookPrivate {
55   gchar*     name;          /* the addressbook (the file) name       */
56   gchar*     path;          /* the addressbook (the file) path       */
57   gchar*     filter;        /* filter/plugin setted from filechooser */
58 
59   gboolean   modifyed;      /* was addressbook modifyed?             */
60   gulong     selected_id;   /* selected card id                      */
61   gint       deleted;       /* cards marked deleted in addressbook   */
62   gint       marked;        /* how many marked cards                 */
63   gint       printable;     /* how many printable cards              */
64 
65   RGroupBox* box;
66 
67   GList*     cards;
68   GList*     trash;
69   GList*     iter;
70 
71   RPluginManager* manager;
72   RPlugin*        plugin;    /* RPlugin */
73   gpointer        engine;    /* ptr to the real plugin (a gobject) */
74 
75   gboolean dispose_has_run;
76 };
77 
78 
79 #define R_ABOOK_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE((o),   \
80 			            R_ABOOK_TYPE, RAbookPrivate))
81 
82 
83 /*    signals enumeration
84  */
85 enum {
86   OPEN_FAIL,            /* file not opened     */
87   SAVE_FAIL,            /* file not saved      */
88 
89   ADDRESSBOOK_CHANGED,  /* addressbook changed */
90   ADDRESSBOOK_READ,     /* file read           */
91   ADDRESSBOOK_SAVED,    /* file saved          */
92   ADDRESSBOOK_CLOSED,
93 
94   CARD_READ,            /* card read                                        */
95   CARD_ADDED,           /* card added to addressbook                        */
96   CARD_DELETED,         /* card deleted from addressbook and moved to trash */
97   CARD_DESTROYED,       /* card destroyed                                   */
98   CARD_RECOVERED,       /* card recoverd from trash                         */
99   CARD_REPLACED,        /* card replaced in addressbook                     */
100 
101   CARD_CUTTED,
102   CARD_PASTED,
103   NEED_NAME,
104 
105   LAST_SIGNAL
106 };
107 
108 static guint r_abook_signals[LAST_SIGNAL] = {0};
109 
110 
111 static void   r_abook_class_init    (RAbookClass* klass);
112 static void   r_abook_init          (RAbook* obj);
113 
114 static void   r_abook_dispose       (RAbook* obj);
115 static void   r_abook_finalize      (RAbook* obj);
116 
117 static void   r_abook_set_property  (GObject* obj, guint property_id,
118 				     GValue* value, GParamSpec* spec);
119 static void   r_abook_get_property  (GObject* obj, guint property_id,
120 				     GValue* value, GParamSpec* spec);
121 
122 
123 
124 static gchar*   _r_get_file_extension   (gchar* string);
125 static gchar*   _r_get_plugin_extension (RPlugin* plugin);
126 static gboolean _r_try_all_plugins      (RAbook *abook, gchar* fname);
127 static void     _r_abook_add_card       (RAbook* abook, RCard* card,
128 					 gboolean emit_signals);
129 
130 static void     on_group_removed        (RGroupBox *box, gint grp_id,
131 					 gpointer data);
132 static void     on_group_modifyed       (RGroupBox *box, gpointer grp,
133 					 gpointer data);
134 
135 
136 
137 
138 
139 GType
r_abook_get_type()140 r_abook_get_type()
141 {
142   static GType r_abook_type = 0;
143 
144   if (!r_abook_type)
145     {
146       static const GTypeInfo r_abook_info =
147 	{
148 	  sizeof(RAbookClass),
149 	  NULL,
150 	  NULL,
151 	  (GClassInitFunc) r_abook_class_init,
152 	  NULL,
153 	  NULL,
154 	  sizeof(RAbook),
155 	  0,
156 	  (GInstanceInitFunc) r_abook_init
157 	};
158 
159       r_abook_type = g_type_register_static (G_TYPE_OBJECT, "RAbook",
160 					     &r_abook_info, 0);
161     }
162 
163   return r_abook_type;
164 }
165 
166 
167 static void
r_abook_class_init(RAbookClass * klass)168 r_abook_class_init(RAbookClass* klass)
169 {
170   GObjectClass *class;
171   GParamSpec* pspec;
172 
173   class  = G_OBJECT_CLASS (klass);
174 
175   class->dispose         = (GObjectFinalizeFunc) r_abook_dispose;
176   class->finalize        = (GObjectFinalizeFunc) r_abook_finalize;
177   class->set_property    = (gpointer) r_abook_set_property;
178   class->get_property    = (gpointer) r_abook_get_property;
179 
180   klass->abook_open_file = NULL;
181   klass->abook_save_file = NULL;
182   klass->abook_overwrite = NULL;
183 
184   g_type_class_add_private (klass, sizeof(RAbookPrivate));
185 
186   /* class signals
187    */
188   /**
189    * RAbook::open-fail:
190    * @abook: the #RAbook object that receives the signal
191    * @err: an #RError
192    *
193    * the "open-fail" signal is emitted if the given file can't be read
194    */
195   r_abook_signals[OPEN_FAIL] =
196     g_signal_new("open_fail",
197 		 R_ABOOK_TYPE,
198 		 G_SIGNAL_RUN_LAST,
199 		 G_STRUCT_OFFSET(RAbookClass, open_fail),
200 		 NULL,
201 		 NULL,
202 		 g_cclosure_marshal_VOID__INT,
203 		 G_TYPE_NONE,            /* return type */
204 		 1,                      /* params      */
205 		 G_TYPE_INT);            /* params type: error code */
206 
207   /**
208    * RAbook::save-fail:
209    * @abook: the #RAbook object that receives the signal
210    * @err: an #RError
211    *
212    * the "save-fail" signal is emitted if the given file can't be read
213    */
214   r_abook_signals[SAVE_FAIL] =
215     g_signal_new("save_fail",
216 		 R_ABOOK_TYPE,
217 		 G_SIGNAL_RUN_LAST,
218 		 G_STRUCT_OFFSET(RAbookClass, save_fail),
219 		 NULL,
220 		 NULL,
221 		 g_cclosure_marshal_VOID__INT,
222 		 G_TYPE_NONE,            /* return type */
223 		 1,                      /* params      */
224 		 G_TYPE_INT);            /* params type: error code */
225 
226   /**
227    * RAbook::card-read:
228    * @abook: the #RAbook object that receives the signal
229    * @data: a pointer to the readed card
230    *
231    * The "card-read" signal is emitted after the addressbook has been readed
232    */
233   r_abook_signals[CARD_READ] =
234     g_signal_new("card_read",
235 		 R_ABOOK_TYPE,
236 		 G_SIGNAL_RUN_LAST,
237 		 G_STRUCT_OFFSET(RAbookClass, card_read),
238 		 NULL,
239 		 NULL,
240 		 g_cclosure_marshal_VOID__POINTER,
241 		 G_TYPE_NONE,
242 		 1,
243 		 G_TYPE_POINTER);
244 
245   /**
246    * RAbook::card-added:
247    * @abook: the #RAbook object that receives the signal
248    * @data: a pointer to the readed card
249    *
250    * The "card-added" signal is emitted after a card is added to addressbook.
251    * A pointer to the card is passed to the callback function
252    */
253   r_abook_signals[CARD_ADDED] =
254     g_signal_new("card_added",
255 		 R_ABOOK_TYPE,
256 		 G_SIGNAL_RUN_LAST,
257 		 G_STRUCT_OFFSET(RAbookClass, card_added),
258 		 NULL,
259 		 NULL,
260 		 g_cclosure_marshal_VOID__POINTER,
261 		 G_TYPE_NONE,
262 		 1,
263 		 G_TYPE_POINTER);
264 
265   /**
266    * RAbook::card-deleted:
267    * @abook: the #RAbook object that receives the signal
268    *
269    * The "card-removed" signal is emitted when a card is
270    * (deleted) removed from addressbook. The removed cards are
271    * marked as deleted, to really delete (remove) the card
272    * you must destroy it. You can recover (deleted) removed cards.
273    * Destroyed cards are unrecoverable
274    */
275   r_abook_signals[CARD_DELETED] =
276     g_signal_new("card_deleted",
277 		 R_ABOOK_TYPE,
278 		 G_SIGNAL_RUN_LAST,
279 		 G_STRUCT_OFFSET(RAbookClass, card_deleted),
280 		 NULL,
281 		 NULL,
282 		 g_cclosure_marshal_VOID__POINTER,
283 		 G_TYPE_NONE,
284 		 1,
285 		 G_TYPE_POINTER);
286 
287   /**
288    * RAbook::card-destroyed:
289    * @abook: the #RAbook object that receives the signal
290    *
291    * The "card-destroyed" signal is emitted when a card is
292    * deleted from addressbook. Destroyed cards are unrecoverable.
293    */
294   r_abook_signals[CARD_DESTROYED] =
295     g_signal_new("card_destroyed",
296 		 R_ABOOK_TYPE,
297 		 G_SIGNAL_RUN_LAST,
298 		 G_STRUCT_OFFSET(RAbookClass, card_destroyed),
299 		 NULL,
300 		 NULL,
301 		 g_cclosure_marshal_VOID__STRING,
302 		 G_TYPE_NONE,
303 		 1,
304 		 G_TYPE_STRING);
305 
306   /**
307    * RAbook::card-recovered:
308    * @abook: the #RAbook object that receives the signal
309    *
310    * The "card-recovered" signal is emitted when a previously deleted
311    * marked card is unmarked.
312    */
313   r_abook_signals[CARD_RECOVERED] =
314     g_signal_new("card_recovered",
315 		 R_ABOOK_TYPE,
316 		 G_SIGNAL_RUN_LAST,
317 		 G_STRUCT_OFFSET(RAbookClass, card_recovered),
318 		 NULL,
319 		 NULL,
320 		 g_cclosure_marshal_VOID__POINTER,
321 		 G_TYPE_NONE,
322 		 1,
323 		 G_TYPE_POINTER);
324 
325   /**
326    * RAbook::card-replaced:
327    * @abook: the #RAbook object that receives the signal
328    * @data: a pointer to the readed card
329    *
330    * The "card-replaced" signal is emitted on a card replacement.
331    * A pointer to the new card is passed to the callback function
332    */
333   r_abook_signals[CARD_REPLACED] =
334     g_signal_new("card_replaced",
335 		 R_ABOOK_TYPE,
336 		 G_SIGNAL_RUN_LAST,
337 		 G_STRUCT_OFFSET(RAbookClass, card_replaced),
338 		 NULL,
339 		 NULL,
340 		 g_cclosure_marshal_VOID__POINTER,
341 		 G_TYPE_NONE,
342 		 1,
343 		 G_TYPE_POINTER);
344 
345   /**
346    * RAbook::card-cutted
347    * @abook: the #RAbook object that receives the signal
348    * @data: a pointer to the cutted card
349    *
350    * The "card-cutted" signal is emitted when a card in the
351    * addressbook is cutted.
352    * A pointer to the cutted card is passed to the callback function
353    */
354   r_abook_signals[CARD_CUTTED] =
355     g_signal_new("card_cutted",
356 		 R_ABOOK_TYPE,
357 		 G_SIGNAL_RUN_LAST,
358 		 G_STRUCT_OFFSET(RAbookClass, card_cutted),
359 		 NULL,
360 		 NULL,
361 		 g_cclosure_marshal_VOID__POINTER,
362 		 G_TYPE_NONE,
363 		 1,
364 		 G_TYPE_POINTER);
365 
366 
367   /**
368    * RAbook::need-name:
369    * @abook: the #RAbook object that receives the signal
370    *
371    * The "need-name" signal is emitted if user
372    * tries to save an addressbook without giving a filename to it
373    */
374   r_abook_signals[NEED_NAME] =
375     g_signal_new("need_name",
376 		 R_ABOOK_TYPE,
377 		 G_SIGNAL_RUN_LAST,
378 		 G_STRUCT_OFFSET(RAbookClass, need_name),
379 		 NULL,
380 		 NULL,
381 		 g_cclosure_marshal_VOID__VOID,
382 		 G_TYPE_NONE,
383 		 0,
384 		 G_TYPE_NONE);
385 
386   /**
387    * RAbook::addressbook-read:
388    * @abook: the #RAbook object that receives the signal
389    *
390    * The "addressbook-read" signal is emitted when the
391    * addressbook is read
392    */
393   r_abook_signals[ADDRESSBOOK_READ] =
394     g_signal_new("addressbook_read",
395 		 R_ABOOK_TYPE,
396 		 G_SIGNAL_RUN_LAST,
397 		 G_STRUCT_OFFSET(RAbookClass, addressbook_read),
398 		 NULL,
399 		 NULL,
400 		 g_cclosure_marshal_VOID__VOID,
401 		 G_TYPE_NONE,
402 		 0,
403 		 G_TYPE_NONE);
404 
405   /**
406    * RAbook::addressbook-saved:
407    * @abook: the #RAbook object that receives the signal
408    *
409    * The "addressbook_saved" signal
410    */
411   r_abook_signals[ADDRESSBOOK_SAVED] =
412     g_signal_new("addressbook_saved",
413 		 R_ABOOK_TYPE,
414 		 G_SIGNAL_RUN_LAST,
415 		 G_STRUCT_OFFSET(RAbookClass, addressbook_saved),
416 		 NULL,
417 		 NULL,
418 		 g_cclosure_marshal_VOID__VOID,
419 		 G_TYPE_NONE,
420 		 0,
421 		 G_TYPE_NONE);
422 
423   /**
424    * RAbook::addressbook-changed:
425    * @abook: the #RAbook object that receives the signal
426    *
427    * The "addressbook_changed" signal
428    */
429   r_abook_signals[ADDRESSBOOK_CHANGED] =
430     g_signal_new("addressbook_changed",
431 		 R_ABOOK_TYPE,
432 		 G_SIGNAL_RUN_LAST,
433 		 G_STRUCT_OFFSET(RAbookClass, addressbook_changed),
434 		 NULL,
435 		 NULL,
436 		 g_cclosure_marshal_VOID__VOID,
437 		 G_TYPE_NONE,
438 		 0,
439 		 G_TYPE_NONE);
440 
441 
442   /**
443    * RAbook::addressbook-closed:
444    * @abook: the #RAbook object that receives the signal
445    *
446    * The "addressbook_closed" signal
447    */
448   r_abook_signals[ADDRESSBOOK_CLOSED] =
449     g_signal_new("addressbook_closed",
450 		 R_ABOOK_TYPE,
451 		 G_SIGNAL_RUN_LAST,
452 		 G_STRUCT_OFFSET(RAbookClass, addressbook_closed),
453 		 NULL,
454 		 NULL,
455 		 g_cclosure_marshal_VOID__VOID,
456 		 G_TYPE_NONE,
457 		 0,
458 		 G_TYPE_NONE);
459 
460 
461   /**
462    * ABook:addressbook-name
463    *
464    * address book's name
465    */
466   pspec = g_param_spec_string("addressbook-name",
467 			      "addressbook's name",
468 			      "the name (filename) of the addressbook",
469 			      NULL,
470 			      G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
471   g_object_class_install_property(class, ABOOK_NAME, pspec);
472 
473   /**
474    * ABook:addressbook-path
475    *
476    * address book's path
477    */
478   pspec = g_param_spec_string("addressbook-path",
479 			      "addressbook's path",
480 			      "the path of the addressbook",
481 			      NULL,
482 			      G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
483   g_object_class_install_property(class, ABOOK_PATH, pspec);
484 
485 
486   /**
487    * ABook:deleted-cards
488    *
489    * the number of cards marked as deleted in the addressbook
490    */
491   pspec = g_param_spec_int("deleted-cards",
492 			   "deleted cards",
493 			   "number of cards marked as deleted "
494 			   "in the addressbook",
495 			   G_MININT,
496 			   G_MAXINT,
497 			   0,
498 			   G_PARAM_READABLE);
499   g_object_class_install_property(class, DELETED_CARDS, pspec);
500 
501 
502   /**
503    * ABook:selected-id
504    *
505    * the id of the selected card
506    */
507   pspec = g_param_spec_long("selected-id",
508 			    "selected card's id",
509 			    "The id of the selected card",
510 			    G_MINLONG,
511 			    G_MAXLONG,
512 			    0,
513 			    G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
514   g_object_class_install_property(class, SELECTED_ID, pspec);
515 
516   /**
517    * ABook:addressbook-modifyed
518    *
519    * Check if the addressbook was modifyed
520    */
521   pspec = g_param_spec_boolean("addressbook-modifyed",
522 			       "addressbook modifyed",
523 			       "check if addressbook was modifyed",
524 			       FALSE,
525 			       G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
526   g_object_class_install_property(class, MODIFYED, pspec);
527 
528   /**
529    * ABook:cards-marked
530    *
531    * Check if the all addressbook's cards are marked
532    */
533   pspec = g_param_spec_int("marked-cards",
534 			   "marked cards",
535 			   "check how many addressbooks's cards are marked",
536 			   0,
537 			   G_MAXINT,
538 			   0,
539 			   G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
540   g_object_class_install_property(class, MARKED_CARDS, pspec);
541 
542   /**
543    * ABook:printable-cards
544    *
545    * how many cards are marked as printable
546    */
547   pspec = g_param_spec_int("printable-cards",
548 			   "printable cards",
549 			   "how many cards are marked printable",
550 			   0,
551 			   G_MAXINT,
552 			   0,
553 			   G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
554   g_object_class_install_property(class, MARKED_CARDS, pspec);
555 
556   /**
557    * ABook:file-filter
558    *
559    * File filter. It indentifies the addressbook's fileformat and
560    * the plugin that will be loaded to manage this fileformat.
561    */
562   pspec = g_param_spec_string("file-filter",
563 			      "file filter",
564 			      "filter used to identify the file's type",
565 			      NULL,
566 			      G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
567   g_object_class_install_property(class, FILE_FILTER, pspec);
568 }
569 
570 
571 
572 static void
r_abook_set_property(GObject * obj,guint property_id,GValue * value,GParamSpec * spec)573 r_abook_set_property (GObject* obj, guint property_id,
574 		      GValue* value, GParamSpec* spec)
575 {
576   RAbook *self = (RAbook*) obj;
577 
578   switch(property_id)
579     {
580     case ABOOK_NAME:
581       if (self->priv->name)
582 	g_free(self->priv->name);
583       self->priv->name = g_value_dup_string(value);
584       break;
585 
586     case ABOOK_PATH:
587       g_free(self->priv->path);
588       self->priv->path = g_value_dup_string(value);
589       break;
590 
591     case DELETED_CARDS:
592       break;
593 
594     case SELECTED_ID:
595       self->priv->selected_id = g_value_get_long(value);
596       break;
597 
598     case MODIFYED:
599       self->priv->modifyed = g_value_get_boolean(value);
600       break;
601 
602     case MARKED_CARDS:
603       self->priv->marked = g_value_get_int(value);
604       break;
605 
606     case PRINTABLE_CARDS:
607       self->priv->printable = g_value_get_int(value);
608       break;
609 
610     case FILE_FILTER:
611       self->priv->filter = g_value_dup_string(value);
612       break;
613 
614     default:
615       break;
616     }
617 }
618 
619 
620 static void
r_abook_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * spec)621 r_abook_get_property (GObject* obj, guint property_id,
622 		      GValue* value, GParamSpec* spec)
623 {
624   RAbook *self = (RAbook*) obj;
625 
626   switch(property_id)
627     {
628     case ABOOK_NAME:
629       g_value_set_string(value, self->priv->name);
630       break;
631 
632     case ABOOK_PATH:
633       g_value_set_string(value, self->priv->path);
634       break;
635 
636     case DELETED_CARDS:
637       g_value_set_int(value, self->priv->deleted);
638       break;
639 
640     case MODIFYED:
641       g_value_set_boolean(value, self->priv->modifyed);
642       break;
643 
644     case MARKED_CARDS:
645       g_value_set_int(value, self->priv->marked);
646       break;
647 
648     case PRINTABLE_CARDS:
649       g_value_set_int(value, self->priv->printable);
650       break;
651 
652     case SELECTED_ID:
653       g_value_set_long(value, self->priv->selected_id);
654       break;
655 
656     default:
657       break;
658     }
659 }
660 
661 
662 static void
r_abook_init(RAbook * self)663 r_abook_init(RAbook* self)
664 {
665   self->priv = R_ABOOK_GET_PRIVATE(self);
666 
667   self->priv->name        = NULL;
668   self->priv->path        = NULL;
669   self->priv->filter      = NULL;
670 
671   self->priv->modifyed    = FALSE;
672   self->priv->selected_id = 0L;
673   self->priv->deleted     = 0;
674   self->priv->marked      = 0;
675   self->priv->printable   = 0;
676 
677   self->priv->box         = r_lib_get_group_box();
678 
679   self->priv->cards       = NULL;
680   self->priv->trash       = NULL;
681   self->priv->iter        = NULL;
682 
683   self->priv->manager     = r_lib_get_manager();
684   self->priv->plugin      = r_plugin_manager_get_plugin(self->priv->manager,
685 							"rubrica");
686   self->priv->engine      = r_plugin_get_engine(self->priv->plugin);
687 
688   r_lib_admit (self);
689 
690   self->priv->dispose_has_run = FALSE;
691 
692   g_signal_connect(G_OBJECT (self->priv->box), "group_removed",
693 		   G_CALLBACK (on_group_removed), self);
694 
695   g_signal_connect(G_OBJECT (self->priv->box), "group_modifyed",
696 		   G_CALLBACK (on_group_modifyed), self);
697 }
698 
699 
700 
701 static void
r_abook_dispose(RAbook * self)702 r_abook_dispose (RAbook* self)
703 {
704   RAbookPrivate* priv;
705 
706   g_return_if_fail(IS_R_ABOOK(self));
707 
708   priv = R_ABOOK_GET_PRIVATE(self);
709 
710   /* free the list's items (PersonalCard or CompanyCard)
711    */
712   priv->iter = priv->cards;
713   for (; priv->iter; priv->iter = priv->iter->next)
714     {
715       RCard* card = priv->iter->data;
716 
717       if (IS_R_CARD(card))
718 	r_card_free(R_CARD(card));
719     }
720 
721   g_list_free(priv->cards);
722   g_list_free(priv->trash);
723   priv->cards = NULL;
724   priv->trash = NULL;
725   priv->iter  = NULL;
726 
727   r_plugin_free(priv->plugin);
728 
729   if (priv->dispose_has_run)
730     return;
731 
732   priv->dispose_has_run = TRUE;
733 }
734 
735 
736 static void
r_abook_finalize(RAbook * self)737 r_abook_finalize (RAbook* self)
738 {
739   RAbookPrivate* priv;
740 
741   g_return_if_fail(IS_R_ABOOK(self));
742 
743   priv = R_ABOOK_GET_PRIVATE(self);
744 
745   r_utils_free_string(priv->name);
746   r_utils_free_string(priv->path);
747   r_utils_free_string(priv->filter);
748 }
749 
750 
751 static gchar*
_r_get_file_extension(gchar * string)752 _r_get_file_extension (gchar* string)
753 {
754   gint len;
755 
756   if (!string)
757     return NULL;
758 
759   len = strlen(string);
760   for(; len; len --)
761     {
762       if (string[len] == '.')
763 	{
764 	  char* tmp;
765 
766 	  tmp = g_strdup(&string[len+1]);
767 
768 	  return tmp;
769 	}
770     }
771 
772   return NULL;
773 }
774 
775 static gchar*
_r_get_plugin_extension(RPlugin * plugin)776 _r_get_plugin_extension(RPlugin* plugin)
777 {
778   GList *filters = NULL;
779   RFilter* filter;
780   gchar* ext = NULL;
781 
782   g_return_val_if_fail(IS_R_PLUGIN(plugin), NULL);
783 
784   filters = r_plugin_get_filters(plugin);
785 
786   if (filters && filters->data)
787     {
788       filter = (RFilter*) filters->data;
789       g_object_get(filter, "filter-extension", &ext, NULL);
790     }
791 
792   return ext;
793 }
794 
795 
796 static gboolean
_r_try_all_plugins(RAbook * abook,gchar * fname)797 _r_try_all_plugins(RAbook *abook, gchar* fname)
798 {
799   RAbookClass* class;
800   gint n, i = 0;
801 
802   g_return_val_if_fail(IS_R_ABOOK(abook), FALSE);
803 
804   class = R_ABOOK_GET_CLASS(abook);
805 
806   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, " ");
807 
808   n = r_plugin_manager_how_many(abook->priv->manager);
809   for (; i < n; i++)
810     {
811       RPlugin* plugin;
812       gchar *name, *label;
813 
814       plugin = r_plugin_manager_get_nth_plugin(abook->priv->manager, i);
815       g_object_get(plugin, "plugin-name", &name, "plugin-label", &label, NULL);
816 
817       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Trying plugin: %s (%s)",
818 	    name, label);
819 
820       if (r_abook_load_plugin(abook, name))
821 	{
822 	  if(class->abook_open_file(abook, fname))
823 	    {
824 	      g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Used %s plugin", name);
825 	      g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, " ");
826 
827 	      return TRUE;
828 	    }
829 	}
830       else
831 	g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Can't load %s plugin", name);
832     }
833 
834   return FALSE;
835 }
836 
837 
838 static void
_r_abook_add_card(RAbook * abook,RCard * card,gboolean emit_signals)839 _r_abook_add_card(RAbook* abook, RCard* card, gboolean emit_signals)
840 {
841   GList* user_groups = NULL;
842   RAbookPrivate* priv;
843   gboolean deleted = FALSE;
844   glong id;
845 
846   g_return_if_fail(IS_R_ABOOK(abook));
847 
848   priv = R_ABOOK_GET_PRIVATE(abook);
849 
850   user_groups = r_card_get_groups_owned_by(R_CARD(card), "user");
851   for (; user_groups; user_groups = user_groups->next)
852     r_group_box_add_group(abook->priv->box, R_GROUP(user_groups->data));
853 
854   /* check if the card is marked deleted */
855   g_object_get(card, "card-id", &id, "card-deleted", &deleted, NULL);
856   if (deleted)
857     {
858       priv->deleted++;
859       priv->trash = g_list_append(priv->trash, (gpointer) id);
860     }
861 
862   priv->cards = g_list_append(priv->cards, card);
863   priv->iter  = priv->cards;
864 
865   if (emit_signals)
866     {
867       g_signal_emit_by_name(abook, "card_added", card, G_TYPE_POINTER);
868       g_signal_emit_by_name(abook, "addressbook_changed", NULL, G_TYPE_NONE);
869     }
870 }
871 
872 
873 
874 static void
on_group_removed(RGroupBox * box,gint grp_id,gpointer data)875 on_group_removed  (RGroupBox *box, gint grp_id, gpointer data)
876 {
877   RAbook *book = R_ABOOK(data);
878   RAbookPrivate* priv = R_ABOOK_GET_PRIVATE(book);
879 
880   priv->modifyed = TRUE;
881   g_signal_emit_by_name(book, "addressbook_changed", NULL, G_TYPE_NONE);
882 }
883 
884 
885 static void
on_group_modifyed(RGroupBox * box,gpointer grp,gpointer data)886 on_group_modifyed (RGroupBox *box, gpointer grp, gpointer data)
887 {
888   RAbook *book = R_ABOOK(data);
889   RAbookPrivate* priv = R_ABOOK_GET_PRIVATE(book);;
890 
891   priv->modifyed = TRUE;
892   g_signal_emit_by_name(book, "addressbook_changed", NULL, G_TYPE_NONE);
893 }
894 
895 
896 
897 /*   ***************************** Public *****************************
898 */
899 
900 
901 /**
902  * r_abook_new
903  *
904  * create a #RAbook
905  *
906  * Returns: a new #RAbook
907  */
908 RAbook*
r_abook_new(void)909 r_abook_new(void)
910 {
911   RAbook* abook;
912 
913   if (!r_lib_is_running())
914     g_error("\nLibral is not running");
915 
916   abook = g_object_new(r_abook_get_type(), NULL);
917 
918   return abook;
919 }
920 
921 
922 /**
923  * r_abook_free
924  * @abook: a #RAbook
925  *
926  * free the #RAbook
927  * The "addressbook_closed" signal is emitted
928  */
929 void
r_abook_free(RAbook * abook)930 r_abook_free(RAbook* abook)
931 {
932   g_return_if_fail(IS_R_ABOOK(abook));
933 
934   g_signal_emit_by_name(abook, "addressbook_closed", NULL, G_TYPE_NONE);
935 
936   g_object_unref(abook);
937 }
938 
939 
940 
941 /**
942  * r_abook_open_file
943  * @abook: a #RAbook
944  * @fname: the name of the addressbook
945  *
946  * open the addressbook with given name
947  *
948  * Returns: %TRUE if file is opened successfully, %FALSE otherwise
949  */
950 gboolean
r_abook_open_file(RAbook * abook,gchar * fname)951 r_abook_open_file (RAbook* abook, gchar* fname)
952 {
953   RAbookClass* class;
954   RAbookPrivate* priv;
955   gboolean result = FALSE;
956 
957   g_return_val_if_fail(IS_R_ABOOK(abook), FALSE);
958 
959   priv  = R_ABOOK_GET_PRIVATE(abook);
960   class = R_ABOOK_GET_CLASS(abook);
961 
962   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, " ");
963   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Opening %s ...", fname);
964 
965   if (g_ascii_strcasecmp(priv->filter, "autodetect") == 0)
966     {
967       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_INFO, "Try to determine the file's type");
968 
969       result = _r_try_all_plugins(abook, fname);
970     }
971   else
972     {
973       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Opening file with %s plugin",
974 	    priv->filter);
975 
976       if (r_abook_load_plugin(abook, priv->filter))
977 	result = class->abook_open_file(abook, fname);
978     }
979 
980   if (result)
981     {
982       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "addressbook: %s",
983 	    abook->priv->name);
984       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "path: %s", abook->priv->path);
985 
986       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s opened successfully", fname);
987       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Cards in this addressbook: %d",
988 	    r_abook_get_items(R_ABOOK(abook)));
989       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Cards marked as deleted: %d",
990 	    abook->priv->deleted);
991       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, " ");
992 
993       return TRUE;
994     }
995 
996   // error occurred during file loading
997   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "%s open failed", fname);
998   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, " ");
999 
1000   return FALSE;
1001 }
1002 
1003 
1004 
1005 /**
1006  * r_abook_save_file
1007  * @abook: a #RAbook
1008  * @fname: the name of file
1009  *
1010  * save the addressbook with given filename
1011  *
1012  * Returns: %TRUE if file is saved successfully, %FALSE otherwise
1013  */
1014 gboolean
r_abook_save_file(RAbook * abook,gchar * fname,gint compression_rate)1015 r_abook_save_file (RAbook* abook, gchar* fname, gint compression_rate)
1016 {
1017   RAbookClass* class;
1018   RAbookPrivate* priv;
1019   gchar* ext = NULL, *tmp;
1020   gboolean result = FALSE;
1021 
1022   g_return_val_if_fail(IS_R_ABOOK(abook), FALSE);
1023 
1024   if (!fname)
1025     {
1026       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "addressbook needs a filename");
1027 
1028       g_signal_emit_by_name(abook, "need_name", NULL, G_TYPE_NONE);
1029 
1030       return FALSE;
1031     }
1032 
1033   class = R_ABOOK_GET_CLASS(abook);
1034   priv  = R_ABOOK_GET_PRIVATE(abook);
1035   ext   = _r_get_file_extension(g_path_get_basename(fname));
1036 
1037   if (!ext)
1038     ext = _r_get_plugin_extension(abook->priv->plugin);
1039 
1040   tmp = g_strdup_printf("%s.%s", fname, ext);
1041   g_free(fname);
1042   fname = tmp;
1043 
1044   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO,
1045 	"Trying plugin %s to save the file", r_abook_get_plugin_name(abook));
1046 
1047   result = class->abook_save_file(abook, fname, compression_rate);
1048 
1049   if (result)
1050     {
1051       g_signal_emit_by_name(abook, "addressbook_saved", NULL, G_TYPE_NONE);
1052 
1053       g_free(fname);
1054       return TRUE;
1055     }
1056   else
1057     g_signal_emit_by_name(abook, "save_fail", WRITING_FILE, G_TYPE_INT);
1058 
1059   g_free(fname);
1060   return FALSE;
1061 }
1062 
1063 
1064 /**
1065  * r_abook_overwrite_file
1066  * @abook: a #RAbook
1067  * @backup: boolean
1068  *
1069  * overwrite an existing addressbook with a new one.
1070  * If backup is %TRUE the old addressbook is backuped.
1071  *
1072  * Returns: a %TRUE if old addressbook was successfully overwited,
1073  * %FALSE otherwise
1074  **/
1075 gboolean
r_abook_overwrite_file(RAbook * abook,gboolean backup,gint compression_rate)1076 r_abook_overwrite_file(RAbook* abook, gboolean backup, gint compression_rate)
1077 {
1078   gchar *old, *new;
1079   RAbookClass* class;
1080 
1081   g_return_val_if_fail(IS_R_ABOOK(abook), FALSE);
1082 
1083   class = R_ABOOK_GET_CLASS(abook);
1084 
1085   if (backup)
1086     {
1087       old = g_strdup_printf("%s%s%s", abook->priv->path,
1088 			    G_DIR_SEPARATOR_S, abook->priv->name);
1089 
1090       if (!old || (g_ascii_strcasecmp(old, _("no name")) == 0))
1091 	{
1092 	  g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
1093 		"addressbook needs a filename");
1094 
1095 	  g_signal_emit_by_name(abook, "need_name", NULL, G_TYPE_NONE);
1096 
1097 	  return FALSE;
1098 	}
1099 
1100       new = g_strdup_printf("%s~", old);
1101       g_rename(old, new);
1102       g_free(new);
1103       g_free(old);
1104     }
1105 
1106   /* write the file */
1107   if (class->abook_overwrite)
1108     return class->abook_overwrite(abook, compression_rate);
1109 
1110   return FALSE;
1111 }
1112 
1113 
1114 /**
1115  * r_abook_copy
1116  * @abook: a #RAbook
1117  *
1118  * copy the addressbook pointed by abook
1119  *
1120  * Returns: a new #RAbook
1121  */
1122 RAbook*
r_abook_copy(RAbook * abook)1123 r_abook_copy (RAbook* abook)
1124 {
1125   RAbook* new;
1126   gpointer engine;
1127   RPlugin* plugin;
1128   RAbookClass* class = NULL;
1129   gpointer card;
1130 
1131   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1132 
1133   new = r_abook_new();
1134 
1135   engine = r_abook_get_engine(abook);
1136   plugin = r_abook_get_plugin(abook);
1137 
1138   new->priv->engine = engine;
1139   new->priv->plugin = plugin;
1140   g_object_ref(engine);
1141   g_object_ref(plugin);
1142 
1143   class = R_ABOOK_GET_CLASS(new);
1144   if (class)
1145     {
1146       class->abook_open_file = r_plugin_get_handle(plugin, "read");
1147       class->abook_save_file = r_plugin_get_handle(plugin, "write");
1148       class->abook_overwrite = r_plugin_get_handle(plugin, "overwrite");
1149     }
1150 
1151   card = r_abook_get_card(abook);
1152   for (; card; card = r_abook_get_next_card(abook))
1153     {
1154       gpointer new_card;
1155 
1156       new_card = r_card_copy(R_CARD(card));
1157 
1158       if (new_card)
1159 	r_abook_add_card(new, new_card);
1160     }
1161   r_abook_reset_book(abook);
1162 
1163   return new;
1164 }
1165 
1166 
1167 /**
1168  * r_abook_plugin_from_file
1169  * @abook: a #RAbook
1170  * @filename: gchar*
1171  *
1172  * Try to load the plugin using the file extension. If the file has a
1173  * known extension the rigth plugin is loaded.
1174  *
1175  * Returns: %TRUE if plugin is loaded, %FALSE otherwise
1176  **/
1177 gboolean
r_abook_plugin_from_file(RAbook * abook,gchar * filename)1178 r_abook_plugin_from_file (RAbook* abook, gchar* filename)
1179 {
1180   GList* filters = NULL;
1181 
1182   filters = r_plugin_manager_get_all_filters(abook->priv->manager);
1183   for (; filters; filters = filters->next)
1184     {
1185       gchar *name, *pattern;
1186       RFilter* filter = (RFilter*) filters->data;
1187 
1188       g_object_get(filter, "filter-name", &name, NULL);
1189 
1190       r_filter_reset(filter);
1191       pattern = r_filter_get_pattern(filter);
1192       for (; pattern; pattern = r_filter_get_next_pattern(filter))
1193 	if (g_str_has_suffix(filename, pattern))
1194 	  {
1195 	    gchar* name;
1196 
1197 	    g_object_get(filter, "filter-name", &name, NULL);
1198 	    return r_abook_load_plugin (abook, name);
1199 	  }
1200     }
1201 
1202   return FALSE;
1203 }
1204 
1205 
1206 
1207 /**
1208  * r_abook_load_plugin
1209  * @abook: a #RAbook
1210  * @plugin_name: const gchar*
1211  *
1212  * Load the "plugin_name" plugin.
1213  *
1214  * Returns: %TRUE if plugin is loaded, %FALSE otherwise
1215  **/
1216 gboolean
r_abook_load_plugin(RAbook * abook,const gchar * plugin_name)1217 r_abook_load_plugin (RAbook* abook, const gchar* plugin_name)
1218 {
1219   RPlugin* plugin;
1220   RAbookClass* class = NULL;
1221 
1222   g_return_val_if_fail(IS_R_ABOOK(abook), FALSE);
1223   g_return_val_if_fail(plugin_name != NULL, FALSE);
1224 
1225   class = R_ABOOK_GET_CLASS(abook);
1226   if (!class)
1227     {
1228       g_warning("\nR_ABOOK_GET_CLASS");
1229 
1230       return FALSE;
1231     }
1232 
1233   plugin = r_plugin_manager_get_plugin(abook->priv->manager, plugin_name);
1234   if (plugin)
1235     {
1236       abook->priv->plugin = plugin;
1237       abook->priv->engine = r_plugin_get_engine(plugin);
1238 
1239       class->abook_open_file = r_plugin_get_handle(plugin, "read");
1240       class->abook_save_file = r_plugin_get_handle(plugin, "write");
1241       class->abook_overwrite = r_plugin_get_handle(plugin, "overwrite");
1242 
1243       return TRUE;
1244     }
1245 
1246   return FALSE;
1247 }
1248 
1249 
1250 
1251 /**
1252  * r_abook_get_plugin_extension
1253  * @abook: a #RAbook
1254  *
1255  * Get the extension that is associate to the current active plugin
1256  *
1257  * Returns: a gchar* or NULL if an error occured
1258  **/
1259 gchar*
r_abook_get_plugin_extension(RAbook * abook)1260 r_abook_get_plugin_extension (RAbook* abook)
1261 {
1262   GList* filters = NULL;
1263   RFilter* filter;
1264 
1265   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1266 
1267   filters = r_plugin_get_filters (abook->priv->plugin);
1268   filter  = (RFilter*) filters->data;
1269   r_filter_reset(filter);
1270 
1271   return r_filter_get_pattern(filter);
1272 }
1273 
1274 
1275 /**
1276  * r_abook_get_plugin_name
1277  * @abook: a #RAbook
1278  *
1279  * get the name of the active plugin
1280  *
1281  * Returns: a gchar*
1282  */
1283 gchar*
r_abook_get_plugin_name(RAbook * abook)1284 r_abook_get_plugin_name (RAbook* abook)
1285 {
1286   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1287 
1288   return r_plugin_get_name(R_PLUGIN(abook->priv->plugin));
1289 }
1290 
1291 
1292 /**
1293  * r_abook_get_engine
1294  * @abook: a #RAbook
1295  *
1296  * Get the active engine (the real plugin)
1297  *
1298  * Currently are available those engines (plugins) with rubrica:
1299  * Rubrica        (manages the rubrica's file format)
1300  * VCard          (manages the vcard's file format)
1301  * CsvGmail       (manages the gmail's csv file format)
1302  * CsvThunderbird (managed the thunderbird's csv file format)
1303  *
1304  * working on CsvOutlook and generic csv
1305  *
1306  * Returns: a %gpointer to the engine
1307  **/
1308 gpointer
r_abook_get_engine(RAbook * abook)1309 r_abook_get_engine (RAbook* abook)
1310 {
1311   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1312 
1313   return abook->priv->engine;
1314 }
1315 
1316 
1317 
1318 /**
1319  * r_abook_get_r_plugin
1320  * @abook: a #RAbook
1321  *
1322  * Get the currently active plugin (ptr to an #RPlugin struct)
1323  *
1324  * Returns: a %gpointer to the plugin
1325  **/
1326 gpointer
r_abook_get_plugin(RAbook * abook)1327 r_abook_get_plugin (RAbook* abook)
1328 {
1329   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1330 
1331   return abook->priv->plugin;
1332 }
1333 
1334 
1335 /**
1336  * r_abook_get_items
1337  * @abook: a #RAbook
1338  *
1339  * get the number of cards into addressbok
1340  *
1341  * Returns: an integer
1342  */
1343 gint
r_abook_get_items(RAbook * abook)1344 r_abook_get_items (RAbook* abook)
1345 {
1346   g_return_val_if_fail(IS_R_ABOOK(abook), -1);
1347 
1348   return g_list_length(abook->priv->cards);
1349 }
1350 
1351 /**
1352  * r_abook_get_deleted
1353  * @abook: a #RAbook
1354  *
1355  * get the number of cards marked as deleted into addressbok
1356  *
1357  * Returns: an integer. If an error occurred -1 is returne
1358  */
1359 gint
r_abook_get_deleted(RAbook * abook)1360 r_abook_get_deleted (RAbook* abook)
1361 {
1362   g_return_val_if_fail(IS_R_ABOOK(abook), -1);
1363 
1364   return abook->priv->deleted;
1365 }
1366 
1367 
1368 
1369 /**
1370  * r_abook_is_empty
1371  * @abook: a #RAbook
1372  *
1373  * is the addressbook empty?
1374  *
1375  * Returns: a boolean. %TRUE if addressbook is empty, %FALSE otherwise
1376  */
1377 gboolean
r_abook_is_empty(RAbook * abook)1378 r_abook_is_empty (RAbook* abook)
1379 {
1380   g_return_val_if_fail(IS_R_ABOOK(abook), TRUE);
1381 
1382   return (r_abook_get_items(abook) == 0);
1383 }
1384 
1385 
1386 
1387 /**
1388  * r_abook_add_card
1389  * @abook: a #RAbook
1390  * @card: an #RCard object
1391  *
1392  * append the given card into the addressbook
1393  * The "card_added" and "addressbook_changed" signals are emitted
1394  */
1395 void
r_abook_add_card(RAbook * abook,RCard * card)1396 r_abook_add_card (RAbook* abook, RCard* card)
1397 {
1398   _r_abook_add_card(abook, card, TRUE);
1399 }
1400 
1401 
1402 
1403 /**
1404  * r_abook_add_loaded_card
1405  * @abook: a #RAbook
1406  * @card: an #RCard object
1407  *
1408  * append a card read from disk into the addressbook
1409  */
1410 void
r_abook_add_loaded_card(RAbook * abook,RCard * card)1411 r_abook_add_loaded_card (RAbook* abook, RCard* card)
1412 {
1413   _r_abook_add_card(abook, card, FALSE);
1414 }
1415 
1416 
1417 
1418 /**
1419  * r_abook_paste_card
1420  * @abook: a #RAbook
1421  * @card: an #RCard object
1422  *
1423  * peste the given card into the addressbook (append the card)
1424  */
1425 void
r_abook_paste_card(RAbook * abook,RCard * card)1426 r_abook_paste_card (RAbook* abook, RCard* card)
1427 {
1428   _r_abook_add_card(abook, card, TRUE);
1429 }
1430 
1431 
1432 
1433 /**
1434  * r_abook_empty_trash
1435  * @abook: a #RAbook
1436  *
1437  * Destroy all cards in the trash. The destroyed cards are unrecoverable
1438  * the "addressbook_changed" signal is emitted
1439  */
1440 void
r_abook_empty_trash(RAbook * abook)1441 r_abook_empty_trash(RAbook* abook)
1442 {
1443   GList* iter;
1444 
1445   g_return_if_fail(IS_R_ABOOK(abook));
1446 
1447   for (iter = abook->priv->trash; iter; iter = iter->next)
1448     {
1449       RCard* card = NULL;
1450 
1451       card = r_abook_get_card_by_id(abook, (glong) iter->data);
1452       g_object_set(card, "card-destroyed", TRUE, NULL);
1453 
1454       abook->priv->deleted--;
1455     }
1456 
1457   g_list_free(abook->priv->trash);
1458   abook->priv->trash = NULL;
1459 
1460   g_signal_emit_by_name(abook, "addressbook_changed", NULL, G_TYPE_NONE);
1461 }
1462 
1463 
1464 /**
1465  * r_abook_destroy_card
1466  * @abook: a #RAbook
1467  * @card: an #RCard object
1468  *
1469  * Destroy the given card. The destroyed cards are unrecoverable
1470  * The "card_destroyed" and "addressbook_changed" signals are emitted
1471  */
1472 void
r_abook_destroy_card(RAbook * abook,RCard * card)1473 r_abook_destroy_card(RAbook* abook, RCard* card)
1474 {
1475   gchar* name;
1476 
1477   g_return_if_fail(IS_R_ABOOK(abook));
1478   g_return_if_fail(IS_R_CARD(card));
1479 
1480   g_object_get(card, "card-name", &name, NULL);
1481   g_object_set(card, "card-destroyed", TRUE, NULL);
1482 
1483   abook->priv->cards = g_list_remove(abook->priv->cards, card);
1484   abook->priv->deleted--;
1485 
1486   g_signal_emit_by_name(abook, "card_destroyed", name, G_TYPE_STRING);
1487   g_signal_emit_by_name(abook, "addressbook_changed", NULL, G_TYPE_NONE);
1488 }
1489 
1490 
1491 /**
1492  * r_abook_delete_card
1493  * @abook: a #RAbook
1494  * @card: an #RCard object
1495  *
1496  * mark the given card as delete.
1497  * The id of the card is appended to the addressbook's trash
1498  * The "card_removed" and "addressbook_changed" signals are emitted
1499  */
1500 void
r_abook_delete_card(RAbook * abook,RCard * card)1501 r_abook_delete_card (RAbook* abook, RCard* card)
1502 {
1503   gint id;
1504 
1505   g_return_if_fail(IS_R_ABOOK(abook));
1506   g_return_if_fail(IS_R_CARD(card));
1507 
1508   g_object_set(card, "card-deleted", TRUE, NULL);
1509   g_object_get(card, "card-id", &id, NULL);
1510 
1511   abook->priv->deleted++;
1512   abook->priv->trash = g_list_append(abook->priv->trash, GINT_TO_POINTER(id));
1513 
1514   g_signal_emit_by_name(abook, "card_deleted", card, G_TYPE_POINTER);
1515   g_signal_emit_by_name(abook, "addressbook_changed", NULL, G_TYPE_NONE);
1516 }
1517 
1518 
1519 /**
1520  * r_abook_recovery_card
1521  * @abook: a #RAbook
1522  * @card: an #RCard object
1523  *
1524  * unmark the card previously marked as deleted.
1525  * The "card_recovered" and "addressbook_changed" signals are emitted
1526  *
1527  * Returns: %TRUE if card is successfully recovered, %FALSE otherwise
1528  */
1529 gboolean
r_abook_recovery_card(RAbook * abook,RCard * card)1530 r_abook_recovery_card (RAbook* abook, RCard* card)
1531 {
1532   g_return_val_if_fail(IS_R_ABOOK(abook), FALSE);
1533   g_return_val_if_fail(IS_R_CARD(card), FALSE);
1534 
1535 
1536   g_object_set(card, "card-deleted", FALSE, NULL);
1537   abook->priv->deleted--;
1538 
1539   g_signal_emit_by_name(abook, "card_recovered", card, G_TYPE_POINTER);
1540   g_signal_emit_by_name(abook, "addressbook_changed", NULL, G_TYPE_NONE);
1541 
1542   return TRUE;
1543 }
1544 
1545 
1546 
1547 /**
1548  * r_abook_replace_card
1549  * @abook: a #RAbook
1550  * @old: an #RCard object
1551  * @new: an #RCard object
1552  *
1553  * replace the old card with the new one
1554  * The "card_replaced" and "addressbook_changed" signals are emitted
1555  */
1556 void
r_abook_replace_card(RAbook * abook,RCard * old,RCard * new)1557 r_abook_replace_card (RAbook* abook, RCard* old, RCard* new)
1558 {
1559   gint pos;
1560   GList* node = NULL;
1561   gpointer card = NULL;
1562 
1563   g_return_if_fail(IS_R_ABOOK(abook));
1564 
1565   pos  = g_list_index(abook->priv->cards, old);
1566   node = g_list_nth(abook->priv->cards, pos);
1567   if (node)
1568     {
1569       abook->priv->cards = g_list_remove_link(abook->priv->cards, node);
1570 
1571       card = node->data;
1572       r_card_free(R_CARD(card));
1573 
1574       g_list_free_1(node);
1575 
1576       abook->priv->cards = g_list_insert(abook->priv->cards, new, pos);
1577 
1578       g_signal_emit_by_name(abook, "addressbook_changed", NULL, G_TYPE_NONE);
1579       g_signal_emit_by_name(abook, "card_replaced", new, G_TYPE_POINTER);
1580     }
1581 }
1582 
1583 
1584 
1585 /**
1586  * r_abook_get_card
1587  * @abook: a #RAbook
1588  *
1589  * Get the first card in addressbook.
1590  *
1591  * Returns: a pointer to the card or NULL if addressbook is empty
1592  */
1593 gpointer
r_abook_get_card(RAbook * abook)1594 r_abook_get_card (RAbook* abook)
1595 {
1596   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1597 
1598   if (abook->priv->iter)
1599     return abook->priv->iter->data;
1600 
1601   return NULL;
1602 }
1603 
1604 
1605 
1606 /**
1607  * r_abook_get_selected_card
1608  * @abook: a #RAbook
1609  *
1610  * Get the selected card in the addressbook
1611  *
1612  * Returns:
1613  */
1614 gpointer
r_abook_get_selected_card(RAbook * abook)1615 r_abook_get_selected_card (RAbook* abook)
1616 {
1617   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1618 
1619   return r_abook_get_card_by_id(abook, abook->priv->selected_id);
1620 }
1621 
1622 
1623 /**
1624  * r_abook_unselect_cards
1625  * @abook: a #RAbook
1626  *
1627  * unselect card. Clear previpus selections
1628  */
1629 void
r_abook_unselect_cards(RAbook * abook)1630 r_abook_unselect_cards (RAbook* abook)
1631 {
1632   g_return_if_fail(IS_R_ABOOK(abook));
1633 
1634   abook->priv->selected_id = 0L;
1635 }
1636 
1637 
1638 /**
1639  * r_abook_get_card_by_id
1640  * @abook: a #RAbook
1641  * @id: the card id
1642  *
1643  * get the card with "id" id
1644  *
1645  * Returns: a pointer to the card or NULL if addressbook doesn't own that card
1646  */
1647 gpointer
r_abook_get_card_by_id(RAbook * abook,glong id)1648 r_abook_get_card_by_id (RAbook* abook, glong id)
1649 {
1650   gpointer card = NULL;
1651 
1652   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1653   g_return_val_if_fail(id > 0L, NULL);
1654 
1655   r_abook_reset_book(abook);
1656   for (card = r_abook_get_card(abook); card;
1657        card = r_abook_get_next_card(abook))
1658     {
1659       glong card_id;
1660 
1661       g_object_get(R_CARD(card), "card-id", &card_id, NULL);
1662       if (id == card_id)
1663 	{
1664 	  abook->priv->selected_id = id;
1665 
1666 	  return card;
1667 	}
1668     }
1669 
1670   return NULL;
1671 }
1672 
1673 /**
1674  * r_abook_get_group_box(RAbook* abook)
1675  * @abook: a #RAbook
1676  *
1677  * get the default groups set
1678  *
1679  * returns: a #gpointer (caller must cast to #RGroupSet*) or NULL
1680  */
1681 gpointer
r_abook_get_groups_box(RAbook * abook)1682 r_abook_get_groups_box(RAbook* abook)
1683 {
1684   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1685 
1686   return (gpointer) abook->priv->box;
1687 }
1688 
1689 
1690 
1691 
1692 /**
1693  * r_abook_reset_book
1694  * @abook: a #RAbook
1695  *
1696  * reset the private addressbook iterator. The iterator
1697  * will point the head of cards's list.
1698  */
1699 void
r_abook_reset_book(RAbook * abook)1700 r_abook_reset_book (RAbook* abook)
1701 {
1702   g_return_if_fail(IS_R_ABOOK(abook));
1703 
1704   abook->priv->iter = abook->priv->cards;
1705 }
1706 
1707 
1708 /**
1709  * r_abook_get_next_card
1710  * @abook: a #RAbook
1711  *
1712  * get the next card in addressbook
1713  *
1714  * Returns: a pointer to the card or NULL if the cards's end list is reached.
1715  */
1716 gpointer
r_abook_get_next_card(RAbook * abook)1717 r_abook_get_next_card (RAbook* abook)
1718 {
1719   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1720 
1721   abook->priv->iter = g_list_next(abook->priv->iter);
1722   if (abook->priv->iter)
1723     return abook->priv->iter->data;
1724   else
1725     abook->priv->iter = g_list_last(abook->priv->cards);
1726 
1727   return NULL;
1728 }
1729 
1730 
1731 /**
1732  * r_abook_get_prev_card
1733  * @abook: a #RAbook
1734  *
1735  * get the previous card in addressbook
1736  *
1737  * Returns: a pointer to the card or NULL if the cards's head list is reached.
1738  */
1739 gpointer
r_abook_get_prev_card(RAbook * abook)1740 r_abook_get_prev_card (RAbook* abook)
1741 {
1742   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1743 
1744   abook->priv->iter = g_list_previous(abook->priv->iter);
1745   if (abook->priv->iter)
1746     return abook->priv->iter->data;
1747   else
1748     abook->priv->iter = abook->priv->cards;
1749 
1750   return NULL;
1751 }
1752 
1753 
1754 /**
1755  * r_abook_foreach_card
1756  * @abook: a #RAbook
1757  * @func: the #RFunc that will be called for each card in addressbook
1758  * @data: user's data to pass to func
1759  *
1760  * Call the function func() for each card in the #RAbook.
1761  */
1762 void
r_abook_foreach_card(RAbook * abook,RFunc func,gpointer data)1763 r_abook_foreach_card (RAbook* abook, RFunc func, gpointer data)
1764 {
1765   gpointer card;
1766 
1767   r_abook_reset_book(abook);
1768   card = r_abook_get_card(abook);
1769   for (; card; card = r_abook_get_next_card(abook))
1770     func(card, data);
1771 }
1772 
1773 
1774 /**
1775  * r_abook_find_cards_by_group
1776  * @abook: a #RAbook
1777  * @group_name: the name of the group
1778  *
1779  * Find all cards that belongs to the given group.
1780  * Found cards's ID has inserted in a GList. Caller must free returned GList
1781  *
1782  * returns: a GList* or %NULL if no cards belong to group
1783  */
1784 GList*
r_abook_find_cards_by_group(RAbook * abook,const gchar * group_name)1785 r_abook_find_cards_by_group  (RAbook* abook, const gchar* group_name)
1786 {
1787   gpointer data;
1788   GList* found = NULL;
1789 
1790   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1791   g_return_val_if_fail(group_name != NULL, NULL);
1792 
1793   r_abook_reset_book(abook);
1794   data = r_abook_get_card(abook);
1795   for (; data; data = r_abook_get_next_card(abook))
1796     {
1797       glong id;
1798 
1799       if (!r_card_is_deleted(R_CARD(data)) &&
1800 	  (r_card_belong_to_group(R_CARD(data), group_name) ||
1801 	   (g_ascii_strcasecmp(group_name, "all groups") == 0)))
1802 	{
1803 	  g_object_get(R_CARD(data), "card-id", &id, NULL);
1804 
1805 	  found = g_list_append(found, GINT_TO_POINTER(id));
1806 	}
1807     }
1808 
1809   return found;
1810 }
1811 
1812 
1813 /**
1814  * r_abook_find_cards_by_type
1815  * @abook: a #RAbook
1816  * @type: the type
1817  *
1818  * Find all cards that belongs to the given type.
1819  * Found cards's ID has inserted in a GList. Caller must free returned GList
1820  *
1821  * returns: a GList* or %NULL if no cards belong to the given type
1822  */
1823 GList*
r_abook_find_cards_by_type(RAbook * abook,const gchar * type)1824 r_abook_find_cards_by_type (RAbook* abook, const gchar* type)
1825 {
1826   gpointer data;
1827   GList* found = NULL;
1828 
1829   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1830   g_return_val_if_fail(type != NULL, NULL);
1831 
1832   r_abook_reset_book(abook);
1833   data = r_abook_get_card(abook);
1834   for (; data; data = r_abook_get_next_card(abook))
1835     {
1836       gchar* card_type = NULL;
1837       gboolean deleted;
1838       glong id;
1839 
1840       g_object_get(R_CARD(data), "card-id", &id,
1841 		   "card-deleted", &deleted,
1842 		   "card-type", &card_type, NULL);
1843 
1844       if (!card_type)
1845 	{
1846 	  gchar* name;
1847 
1848 	  g_object_get(R_CARD(data), "card-name", &name, NULL);
1849 
1850 	  g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
1851 		"This card (%s) has a wrong type.", name);
1852 
1853 	  continue;
1854 	}
1855 
1856       if (!deleted)
1857 	{
1858 	  if (g_ascii_strcasecmp(type, "all") == 0)
1859 	    found = g_list_append(found, GINT_TO_POINTER(id));
1860 	  else
1861 	    if (g_ascii_strcasecmp(type, card_type) == 0)
1862 	      found = g_list_append(found, GINT_TO_POINTER(id));
1863 	}
1864     }
1865 
1866   return found;
1867 }
1868 
1869 
1870 
1871 /**
1872  * r_abook_find_cards_by_rate
1873  * @abook: a #RAbook
1874  * @rate: an #RRate
1875  *
1876  * Find all cards that have the given rate
1877  * Found cards's ID has inserted in a GList. Caller must free returned GList
1878  *
1879  * returns: a GList* or %NULL if no cards have the requested rate
1880  */
1881 GList*
r_abook_find_cards_by_rate(RAbook * abook,RRate rate)1882 r_abook_find_cards_by_rate (RAbook* abook, RRate rate)
1883 {
1884   gpointer data;
1885   GList* found = NULL;
1886 
1887   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1888 
1889   r_abook_reset_book(abook);
1890   data = r_abook_get_card(abook);
1891   for (; data; data = r_abook_get_next_card(abook))
1892     {
1893       glong id, card_rate;
1894       gboolean deleted;
1895 
1896       g_object_get(R_CARD(data), "card-id", &id,
1897 		   "card-deleted", &deleted,
1898 		   "card-rate", &card_rate, NULL);
1899 
1900       if (!deleted && (card_rate == rate))
1901 	found = g_list_append(found, GINT_TO_POINTER(id));
1902     }
1903 
1904   return found;
1905 }
1906 
1907 
1908 /**
1909  * r_abook_find_cards_by_genre
1910  * @abook: a #RAbook
1911  * @genre: a string
1912  *
1913  * Find all cards with the given genre ("male" or "female")
1914  * Found cards's ID has inserted in a GList. Caller must free returned GList
1915  *
1916  * returns: a GList* or %NULL if no cards have the requested genre
1917  */
1918 GList*
r_abook_find_cards_by_genre(RAbook * abook,const gchar * genre)1919 r_abook_find_cards_by_genre (RAbook* abook, const gchar* genre)
1920 {
1921   gpointer data;
1922   GList* found = NULL;
1923 
1924   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1925   g_return_val_if_fail(genre != NULL, NULL);
1926 
1927   r_abook_reset_book(abook);
1928   data = r_abook_get_card(abook);
1929   for (; data; data = r_abook_get_next_card(abook))
1930     {
1931        gchar* type = NULL;
1932        gboolean deleted;
1933        glong id;
1934 
1935        g_object_get(R_CARD(data), "card-id", &id, "card-deleted", &deleted,
1936 		    "card-type", &type, NULL);
1937 
1938        if (!deleted && (g_ascii_strcasecmp(type, "personal") == 0))
1939 	 {
1940 	   if (r_personal_card_belongs_to_genre(R_PERSONAL_CARD(data), genre))
1941 	     found = g_list_append(found, GINT_TO_POINTER(id));
1942 	 }
1943     }
1944 
1945   return found;
1946 }
1947 
1948 
1949 /**
1950  * r_abook_search
1951  * @abook: a #RAbook
1952  * @str: an string
1953  *
1954  * Search the given string in all cards's fields
1955  *
1956  * returns: a GList* of cards's id or %NULL if no cards
1957  * have the requested string
1958  */
1959 GList*
r_abook_search(RAbook * abook,const gchar * str)1960 r_abook_search (RAbook* abook, const gchar* str)
1961 {
1962   gpointer data;
1963   GList* found = NULL;
1964 
1965   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
1966   g_return_val_if_fail(str != NULL, NULL);
1967 
1968   r_abook_reset_book(abook);
1969   data = r_abook_get_card(abook);
1970   for (; data; data = r_abook_get_next_card(abook))
1971     {
1972       glong id;
1973 
1974       g_object_get(R_CARD(data), "card-id", &id, NULL);
1975 
1976       if (r_card_search(R_CARD(data), str))
1977 	found = g_list_append(found, GINT_TO_POINTER(id));
1978     }
1979 
1980   return found;
1981 }
1982 
1983 
1984 /**
1985  * r_abook_search_date
1986  * @abook: a #RAbook
1987  * @search_date: a time_t date
1988  * type: a #SearchType
1989  *
1990  * Search the given date
1991  *
1992  * returns: a GList* of cards's id or %NULL if no cards have the date
1993  */
1994 GList*
r_abook_search_date(RAbook * abook,gint search_date,SearchType type)1995 r_abook_search_date (RAbook* abook, gint search_date, SearchType type)
1996 {
1997   gpointer data;
1998   GList* found = NULL;
1999 
2000   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
2001   g_return_val_if_fail(search_date > 0, NULL);
2002 
2003   r_abook_reset_book(abook);
2004   data = r_abook_get_card(abook);
2005   for (; data; data = r_abook_get_next_card(abook))
2006     {
2007       glong id;
2008       gint creation, changed;
2009       GDate *date1, *date2;
2010       gboolean find = FALSE;
2011 
2012       g_object_get(R_CARD(data), "card-id", &id,
2013 		   "card-created", &creation, "card-changed", &changed, NULL);
2014 
2015       switch(type)
2016 	{
2017 	case SEARCH_ON_CREATION:
2018 	  date1 = g_date_new();
2019 	  date2 = g_date_new();
2020 
2021 	  g_date_set_time_t(date1, creation);
2022 	  g_date_set_time_t(date2, search_date);
2023 
2024 	  find = ((g_date_get_day(date1)   == g_date_get_day(date2))   &&
2025 		  (g_date_get_month(date1) == g_date_get_month(date2)) &&
2026 		  (g_date_get_year(date1)  == g_date_get_year(date2)));
2027 
2028 	  g_date_free (date1);
2029 	  g_date_free (date2);
2030 	  break;
2031 
2032 	case SEARCH_ON_CHANGE:
2033 	  date1 = g_date_new();
2034 	  date2 = g_date_new();
2035 
2036 	  g_date_set_time_t(date1, changed);
2037 	  g_date_set_time_t(date2, search_date);
2038 
2039 	  find = ((g_date_get_day(date1)   == g_date_get_day(date2))   &&
2040 		  (g_date_get_month(date1) == g_date_get_month(date2)) &&
2041 		  (g_date_get_year(date1)  == g_date_get_year(date2)));
2042 
2043 	  g_date_free (date1);
2044 	  g_date_free (date2);
2045 	  break;
2046 
2047 	case SEARCH_CREATION_BEFORE:
2048 	  find = (creation < search_date);
2049 	  break;
2050 
2051 	case SEARCH_CREATION_AFTER:
2052 	  find = (creation > search_date);
2053 	  break;
2054 
2055 	case SEARCH_CHANGE_BEFORE:
2056 	  find = (changed < search_date);
2057 	  break;
2058 
2059 	case SEARCH_CHANGE_AFTER:
2060 	  find = (changed > search_date);
2061 	  break;
2062 
2063 	default:
2064 	  break;
2065 	}
2066 
2067       if (find)
2068 	found = g_list_append(found, GINT_TO_POINTER(id));
2069     }
2070 
2071   return found;
2072 }
2073 
2074 
2075 /**
2076  * r_abook_search_between
2077  * @abook: a #RAbook
2078  * @first: a time_t date
2079  * @second: a time_t date
2080  * type: a #SearchType
2081  *
2082  * Search the for a date between the first and the second date
2083  *
2084  * returns: a GList* of cards's id or %NULL if no cards have the date
2085  */
2086 GList*
r_abook_search_between(RAbook * abook,gint first,gint second,SearchType type)2087 r_abook_search_between (RAbook* abook, gint first, gint second,
2088 			SearchType type)
2089 {
2090   gpointer data;
2091   GList* found = NULL;
2092 
2093   g_return_val_if_fail(IS_R_ABOOK(abook), NULL);
2094   g_return_val_if_fail(first > 0, NULL);
2095   g_return_val_if_fail(second > 0, NULL);
2096 
2097   r_abook_reset_book(abook);
2098   data = r_abook_get_card(abook);
2099   for (; data; data = r_abook_get_next_card(abook))
2100     {
2101       glong id;
2102       gint creation, changed;
2103       gboolean find = FALSE;
2104 
2105       g_object_get(R_CARD(data), "card-id", &id,
2106 		   "card-created", &creation, "card-changed", &changed, NULL);
2107 
2108       switch(type)
2109 	{
2110 	case SEARCH_CREATION_BETWEEN:
2111 	  find = ((creation >= first) && (creation <= second));
2112 	  break;
2113 
2114 	case SEARCH_CHANGE_BETWEEN:
2115 	  find = ((changed >= first) && (changed <= second));
2116 	  break;
2117 
2118 	default:
2119 	  break;
2120 	}
2121 
2122       if (find)
2123 	found = g_list_append(found, GINT_TO_POINTER(id));
2124     }
2125 
2126   return found;
2127 }
2128 
2129