Assamese translation updated
[platform/upstream/evolution-data-server.git] / libedataserverui / e-destination-store.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* e-destination-store.c - EDestination store with GtkTreeModel interface.
4  *
5  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
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 Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Authors: Hans Petter Jansson <hpj@novell.com>
21  */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <glib/gi18n-lib.h>
29
30 #include "e-destination-store.h"
31
32 #define ITER_IS_VALID(destination_store, iter) \
33         ((iter)->stamp == (destination_store)->priv->stamp)
34 #define ITER_GET(iter) \
35         GPOINTER_TO_INT (iter->user_data)
36 #define ITER_SET(destination_store, iter, index) \
37         G_STMT_START { \
38         (iter)->stamp = (destination_store)->priv->stamp; \
39         (iter)->user_data = GINT_TO_POINTER (index); \
40         } G_STMT_END
41
42 #define E_DESTINATION_STORE_GET_PRIVATE(obj) \
43         (G_TYPE_INSTANCE_GET_PRIVATE \
44         ((obj), E_TYPE_DESTINATION_STORE, EDestinationStorePrivate))
45
46 struct _EDestinationStorePrivate {
47         GPtrArray *destinations;
48         gint stamp;
49 };
50
51 static GType column_types[E_DESTINATION_STORE_NUM_COLUMNS];
52
53 static void e_destination_store_tree_model_init (GtkTreeModelIface *iface);
54
55 G_DEFINE_TYPE_EXTENDED (
56         EDestinationStore, e_destination_store, G_TYPE_OBJECT, 0,
57         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, e_destination_store_tree_model_init);
58         column_types[E_DESTINATION_STORE_COLUMN_NAME]    = G_TYPE_STRING;
59         column_types[E_DESTINATION_STORE_COLUMN_EMAIL]   = G_TYPE_STRING;
60         column_types[E_DESTINATION_STORE_COLUMN_ADDRESS] = G_TYPE_STRING;
61 )
62
63 static GtkTreeModelFlags e_destination_store_get_flags       (GtkTreeModel       *tree_model);
64 static gint         e_destination_store_get_n_columns   (GtkTreeModel       *tree_model);
65 static GType        e_destination_store_get_column_type (GtkTreeModel       *tree_model,
66                                                          gint                index);
67 static gboolean     e_destination_store_get_iter        (GtkTreeModel       *tree_model,
68                                                          GtkTreeIter        *iter,
69                                                          GtkTreePath        *path);
70 static void         e_destination_store_get_value       (GtkTreeModel       *tree_model,
71                                                          GtkTreeIter        *iter,
72                                                          gint                column,
73                                                          GValue             *value);
74 static gboolean     e_destination_store_iter_next       (GtkTreeModel       *tree_model,
75                                                          GtkTreeIter        *iter);
76 static gboolean     e_destination_store_iter_children   (GtkTreeModel       *tree_model,
77                                                          GtkTreeIter        *iter,
78                                                          GtkTreeIter        *parent);
79 static gboolean     e_destination_store_iter_has_child  (GtkTreeModel       *tree_model,
80                                                          GtkTreeIter        *iter);
81 static gint         e_destination_store_iter_n_children (GtkTreeModel       *tree_model,
82                                                          GtkTreeIter        *iter);
83 static gboolean     e_destination_store_iter_nth_child  (GtkTreeModel       *tree_model,
84                                                          GtkTreeIter        *iter,
85                                                          GtkTreeIter        *parent,
86                                                          gint                n);
87 static gboolean     e_destination_store_iter_parent     (GtkTreeModel       *tree_model,
88                                                          GtkTreeIter        *iter,
89                                                          GtkTreeIter        *child);
90
91 static void destination_changed (EDestinationStore *destination_store, EDestination *destination);
92 static void stop_destination    (EDestinationStore *destination_store, EDestination *destination);
93
94 static void
95 destination_store_dispose (GObject *object)
96 {
97         EDestinationStorePrivate *priv;
98         gint ii;
99
100         priv = E_DESTINATION_STORE_GET_PRIVATE (object);
101
102         for (ii = 0; ii < priv->destinations->len; ii++) {
103                 EDestination *destination;
104
105                 destination = g_ptr_array_index (priv->destinations, ii);
106                 stop_destination (E_DESTINATION_STORE (object), destination);
107                 g_object_unref (destination);
108         }
109         g_ptr_array_set_size (priv->destinations, 0);
110
111         /* Chain up to parent's dispose() method. */
112         G_OBJECT_CLASS (e_destination_store_parent_class)->dispose (object);
113 }
114
115 static void
116 destination_store_finalize (GObject *object)
117 {
118         EDestinationStorePrivate *priv;
119
120         priv = E_DESTINATION_STORE_GET_PRIVATE (object);
121
122         g_ptr_array_free (priv->destinations, TRUE);
123
124         /* Chain up to parent's finalize() method. */
125         G_OBJECT_CLASS (e_destination_store_parent_class)->finalize (object);
126 }
127
128 static void
129 e_destination_store_class_init (EDestinationStoreClass *class)
130 {
131         GObjectClass *object_class;
132
133         g_type_class_add_private (class, sizeof (EDestinationStorePrivate));
134
135         object_class = G_OBJECT_CLASS (class);
136         object_class->dispose = destination_store_dispose;
137         object_class->finalize = destination_store_finalize;
138 }
139
140 static void
141 e_destination_store_tree_model_init (GtkTreeModelIface *iface)
142 {
143         iface->get_flags       = e_destination_store_get_flags;
144         iface->get_n_columns   = e_destination_store_get_n_columns;
145         iface->get_column_type = e_destination_store_get_column_type;
146         iface->get_iter        = e_destination_store_get_iter;
147         iface->get_path        = e_destination_store_get_path;
148         iface->get_value       = e_destination_store_get_value;
149         iface->iter_next       = e_destination_store_iter_next;
150         iface->iter_children   = e_destination_store_iter_children;
151         iface->iter_has_child  = e_destination_store_iter_has_child;
152         iface->iter_n_children = e_destination_store_iter_n_children;
153         iface->iter_nth_child  = e_destination_store_iter_nth_child;
154         iface->iter_parent     = e_destination_store_iter_parent;
155 }
156
157 static void
158 e_destination_store_init (EDestinationStore *destination_store)
159 {
160         destination_store->priv =
161                 E_DESTINATION_STORE_GET_PRIVATE (destination_store);
162
163         destination_store->priv->destinations = g_ptr_array_new ();
164         destination_store->priv->stamp = g_random_int ();
165 }
166
167 /**
168  * e_destination_store_new:
169  *
170  * Creates a new #EDestinationStore.
171  *
172  * Returns: A new #EDestinationStore.
173  **/
174 EDestinationStore *
175 e_destination_store_new (void)
176 {
177         return g_object_new (E_TYPE_DESTINATION_STORE, NULL);
178 }
179
180 /* ------------------ *
181  * Row update helpers *
182  * ------------------ */
183
184 static void
185 row_deleted (EDestinationStore *destination_store,
186              gint n)
187 {
188         GtkTreePath *path;
189
190         path = gtk_tree_path_new ();
191         gtk_tree_path_append_index (path, n);
192         gtk_tree_model_row_deleted (GTK_TREE_MODEL (destination_store), path);
193         gtk_tree_path_free (path);
194 }
195
196 static void
197 row_inserted (EDestinationStore *destination_store,
198               gint n)
199 {
200         GtkTreePath *path;
201         GtkTreeIter  iter;
202
203         path = gtk_tree_path_new ();
204         gtk_tree_path_append_index (path, n);
205
206         if (gtk_tree_model_get_iter (GTK_TREE_MODEL (destination_store), &iter, path))
207                 gtk_tree_model_row_inserted (GTK_TREE_MODEL (destination_store), path, &iter);
208
209         gtk_tree_path_free (path);
210 }
211
212 static void
213 row_changed (EDestinationStore *destination_store,
214              gint n)
215 {
216         GtkTreePath *path;
217         GtkTreeIter  iter;
218
219         path = gtk_tree_path_new ();
220         gtk_tree_path_append_index (path, n);
221
222         if (gtk_tree_model_get_iter (GTK_TREE_MODEL (destination_store), &iter, path))
223                 gtk_tree_model_row_changed (GTK_TREE_MODEL (destination_store), path, &iter);
224
225         gtk_tree_path_free (path);
226 }
227
228 /* ------------------- *
229  * Destination helpers *
230  * ------------------- */
231
232 static gint
233 find_destination_by_pointer (EDestinationStore *destination_store,
234                              EDestination *destination)
235 {
236         GPtrArray *array;
237         gint i;
238
239         array = destination_store->priv->destinations;
240
241         for (i = 0; i < array->len; i++) {
242                 EDestination *destination_here;
243
244                 destination_here = g_ptr_array_index (array, i);
245
246                 if (destination_here == destination)
247                         return i;
248         }
249
250         return -1;
251 }
252
253 static gint
254 find_destination_by_email (EDestinationStore *destination_store,
255                            EDestination *destination)
256 {
257         GPtrArray *array;
258         gint i;
259         const gchar *e_mail = e_destination_get_email (destination);
260
261         array = destination_store->priv->destinations;
262
263         for (i = 0; i < array->len; i++) {
264                 EDestination *destination_here;
265                 const gchar *mail;
266
267                 destination_here = g_ptr_array_index (array, i);
268                 mail = e_destination_get_email (destination_here);
269
270                 if (g_str_equal (e_mail, mail))
271                         return i;
272         }
273
274         return -1;
275 }
276
277 static void
278 start_destination (EDestinationStore *destination_store,
279                    EDestination *destination)
280 {
281         g_signal_connect_swapped (
282                 destination, "changed",
283                 G_CALLBACK (destination_changed), destination_store);
284 }
285
286 static void
287 stop_destination (EDestinationStore *destination_store,
288                   EDestination *destination)
289 {
290         g_signal_handlers_disconnect_matched (
291                 destination, G_SIGNAL_MATCH_DATA,
292                 0, 0, NULL, NULL, destination_store);
293 }
294
295 /* --------------- *
296  * Signal handlers *
297  * --------------- */
298
299 static void
300 destination_changed (EDestinationStore *destination_store,
301                      EDestination *destination)
302 {
303         gint n;
304
305         n = find_destination_by_pointer (destination_store, destination);
306         if (n < 0) {
307                 g_warning ("EDestinationStore got change from unknown EDestination!");
308                 return;
309         }
310
311         row_changed (destination_store, n);
312 }
313
314 /* --------------------- *
315  * EDestinationStore API *
316  * --------------------- */
317
318 /**
319  * e_destination_store_get_destination:
320  * @destination_store: an #EDestinationStore
321  * @iter: a #GtkTreeIter
322  *
323  * Gets the #EDestination from @destination_store at @iter.
324  *
325  * Returns: An #EDestination.
326  **/
327 EDestination *
328 e_destination_store_get_destination (EDestinationStore *destination_store,
329                                      GtkTreeIter *iter)
330 {
331         GPtrArray *array;
332         gint index;
333
334         g_return_val_if_fail (E_IS_DESTINATION_STORE (destination_store), NULL);
335         g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), NULL);
336
337         array = destination_store->priv->destinations;
338         index = ITER_GET (iter);
339
340         return g_ptr_array_index (array, index);
341 }
342
343 /**
344  * e_destination_store_list_destinations:
345  * @destination_store: an #EDestinationStore
346  *
347  * Gets a list of all the #EDestinations in @destination_store.
348  *
349  * Returns: A #GList of pointers to #EDestination. The list is owned
350  * by the caller, but the #EDestination elements aren't.
351  **/
352 GList *
353 e_destination_store_list_destinations (EDestinationStore *destination_store)
354 {
355         GList *destination_list = NULL;
356         GPtrArray *array;
357         gint   i;
358
359         g_return_val_if_fail (E_IS_DESTINATION_STORE (destination_store), NULL);
360
361         array = destination_store->priv->destinations;
362
363         for (i = 0; i < array->len; i++) {
364                 EDestination *destination;
365
366                 destination = g_ptr_array_index (array, i);
367                 destination_list = g_list_prepend (destination_list, destination);
368         }
369
370         destination_list = g_list_reverse (destination_list);
371
372         return destination_list;
373 }
374
375 /**
376  * e_destination_store_insert_destination:
377  * @destination_store: an #EDestinationStore
378  * @index: the index at which to insert
379  * @destination: an #EDestination to insert
380  *
381  * Inserts @destination into @destination_store at the position
382  * indicated by @index. @destination_store will ref @destination.
383  **/
384 void
385 e_destination_store_insert_destination (EDestinationStore *destination_store,
386                                         gint index,
387                                         EDestination *destination)
388 {
389         GPtrArray *array;
390
391         g_return_if_fail (E_IS_DESTINATION_STORE (destination_store));
392         g_return_if_fail (index >= 0);
393
394         if (find_destination_by_pointer (destination_store, destination) >= 0) {
395                 g_warning ("Same destination added more than once to EDestinationStore!");
396                 return;
397         }
398
399         g_object_ref (destination);
400
401         array = destination_store->priv->destinations;
402         index = MIN (index, array->len);
403
404         g_ptr_array_set_size (array, array->len + 1);
405
406         if (array->len - 1 - index > 0) {
407                 memmove (
408                         array->pdata + index + 1,
409                         array->pdata + index,
410                         (array->len - 1 - index) * sizeof (gpointer));
411         }
412
413         array->pdata[index] = destination;
414         start_destination (destination_store, destination);
415         row_inserted (destination_store, index);
416 }
417
418 /**
419  * e_destination_store_append_destination:
420  * @destination_store: an #EDestinationStore
421  * @destination: an #EDestination
422  *
423  * Appends @destination to the list of destinations in @destination_store.
424  * @destination_store will ref @destination.
425  **/
426 void
427 e_destination_store_append_destination (EDestinationStore *destination_store,
428                                         EDestination *destination)
429 {
430         GPtrArray *array;
431
432         g_return_if_fail (E_IS_DESTINATION_STORE (destination_store));
433
434         if (find_destination_by_email (destination_store, destination) >= 0 && !e_destination_is_evolution_list (destination)) {
435                 g_warning ("Same destination added more than once to EDestinationStore!");
436                 return;
437         }
438
439         array = destination_store->priv->destinations;
440         g_object_ref (destination);
441
442         g_ptr_array_add (array, destination);
443         start_destination (destination_store, destination);
444         row_inserted (destination_store, array->len - 1);
445 }
446
447 /**
448  * e_destination_store_remove_destination:
449  * @destination_store: an #EDestinationStore
450  * @destination: an #EDestination to remove
451  *
452  * Removes @destination from @destination_store. @destination_store will
453  * unref @destination.
454  **/
455 void
456 e_destination_store_remove_destination (EDestinationStore *destination_store,
457                                         EDestination *destination)
458 {
459         GPtrArray *array;
460         gint n;
461
462         g_return_if_fail (E_IS_DESTINATION_STORE (destination_store));
463
464         n = find_destination_by_pointer (destination_store, destination);
465         if (n < 0) {
466                 g_warning ("Tried to remove unknown destination from EDestinationStore!");
467                 return;
468         }
469
470         stop_destination (destination_store, destination);
471         g_object_unref (destination);
472
473         array = destination_store->priv->destinations;
474         g_ptr_array_remove_index (array, n);
475         row_deleted (destination_store, n);
476 }
477
478 void
479 e_destination_store_remove_destination_nth (EDestinationStore *destination_store,
480                                             gint n)
481 {
482         EDestination *destination;
483         GPtrArray *array;
484
485         g_return_if_fail (n >= 0);
486
487         array = destination_store->priv->destinations;
488         destination = g_ptr_array_index (array, n);
489         stop_destination (destination_store, destination);
490         g_object_unref (destination);
491
492         g_ptr_array_remove_index (array, n);
493         row_deleted (destination_store, n);
494 }
495
496 guint
497 e_destination_store_get_destination_count (EDestinationStore *destination_store)
498 {
499         return destination_store->priv->destinations->len;
500 }
501
502 /* ---------------- *
503  * GtkTreeModel API *
504  * ---------------- */
505
506 static GtkTreeModelFlags
507 e_destination_store_get_flags (GtkTreeModel *tree_model)
508 {
509         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), 0);
510
511         return GTK_TREE_MODEL_LIST_ONLY;
512 }
513
514 static gint
515 e_destination_store_get_n_columns (GtkTreeModel *tree_model)
516 {
517         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), 0);
518
519         return E_CONTACT_FIELD_LAST;
520 }
521
522 static GType
523 e_destination_store_get_column_type (GtkTreeModel *tree_model,
524                                      gint index)
525 {
526         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), G_TYPE_INVALID);
527         g_return_val_if_fail (index >= 0 && index < E_DESTINATION_STORE_NUM_COLUMNS, G_TYPE_INVALID);
528
529         return column_types[index];
530 }
531
532 static gboolean
533 e_destination_store_get_iter (GtkTreeModel *tree_model,
534                               GtkTreeIter *iter,
535                               GtkTreePath *path)
536 {
537         EDestinationStore *destination_store;
538         GPtrArray *array;
539         gint index;
540
541         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
542         g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
543
544         destination_store = E_DESTINATION_STORE (tree_model);
545
546         index = gtk_tree_path_get_indices (path)[0];
547         array = destination_store->priv->destinations;
548
549         if (index >= array->len)
550                 return FALSE;
551
552         ITER_SET (destination_store, iter, index);
553         return TRUE;
554 }
555
556 GtkTreePath *
557 e_destination_store_get_path (GtkTreeModel *tree_model,
558                               GtkTreeIter *iter)
559 {
560         EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
561         GtkTreePath       *path;
562         gint               index;
563
564         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), NULL);
565         g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), NULL);
566
567         index = ITER_GET (iter);
568         path = gtk_tree_path_new ();
569         gtk_tree_path_append_index (path, index);
570
571         return path;
572 }
573
574 static gboolean
575 e_destination_store_iter_next (GtkTreeModel *tree_model,
576                                GtkTreeIter *iter)
577 {
578         EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
579         gint           index;
580
581         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
582         g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), FALSE);
583
584         index = ITER_GET (iter);
585
586         if (index + 1 < destination_store->priv->destinations->len) {
587                 ITER_SET (destination_store, iter, index + 1);
588                 return TRUE;
589         }
590
591         return FALSE;
592 }
593
594 static gboolean
595 e_destination_store_iter_children (GtkTreeModel *tree_model,
596                                    GtkTreeIter *iter,
597                                    GtkTreeIter *parent)
598 {
599         EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
600
601         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
602
603         /* This is a list, nodes have no children. */
604         if (parent)
605                 return FALSE;
606
607         /* But if parent == NULL we return the list itself as children of the root. */
608         if (destination_store->priv->destinations->len <= 0)
609                 return FALSE;
610
611         ITER_SET (destination_store, iter, 0);
612         return TRUE;
613 }
614
615 static gboolean
616 e_destination_store_iter_has_child (GtkTreeModel *tree_model,
617                                     GtkTreeIter *iter)
618 {
619         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
620
621         if (iter == NULL)
622                 return TRUE;
623
624         return FALSE;
625 }
626
627 static gint
628 e_destination_store_iter_n_children (GtkTreeModel *tree_model,
629                                      GtkTreeIter *iter)
630 {
631         EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
632
633         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), -1);
634
635         if (iter == NULL)
636                 return destination_store->priv->destinations->len;
637
638         g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), -1);
639         return 0;
640 }
641
642 static gboolean
643 e_destination_store_iter_nth_child (GtkTreeModel *tree_model,
644                                     GtkTreeIter *iter,
645                                     GtkTreeIter *parent,
646                                     gint n)
647 {
648         EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
649
650         g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
651
652         if (parent)
653                 return FALSE;
654
655         if (n < destination_store->priv->destinations->len) {
656                 ITER_SET (destination_store, iter, n);
657                 return TRUE;
658         }
659
660         return FALSE;
661 }
662
663 static gboolean
664 e_destination_store_iter_parent (GtkTreeModel *tree_model,
665                                  GtkTreeIter *iter,
666                                  GtkTreeIter *child)
667 {
668         return FALSE;
669 }
670
671 static void
672 e_destination_store_get_value (GtkTreeModel *tree_model,
673                                GtkTreeIter *iter,
674                                gint column,
675                                GValue *value)
676 {
677         EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
678         EDestination *destination;
679         GString *string_new;
680         EContact *contact;
681         GPtrArray *array;
682         const gchar *string;
683         gint row;
684
685         g_return_if_fail (E_IS_DESTINATION_STORE (tree_model));
686         g_return_if_fail (column < E_DESTINATION_STORE_NUM_COLUMNS);
687         g_return_if_fail (ITER_IS_VALID (destination_store, iter));
688
689         g_value_init (value, column_types[column]);
690
691         array = destination_store->priv->destinations;
692
693         row = ITER_GET (iter);
694         if (row >= array->len)
695                 return;
696
697         destination = g_ptr_array_index (array, row);
698         g_assert (destination);
699
700         switch (column) {
701                 case E_DESTINATION_STORE_COLUMN_NAME:
702                         string = e_destination_get_name (destination);
703                         g_value_set_string (value, string);
704                         break;
705
706                 case E_DESTINATION_STORE_COLUMN_EMAIL:
707                         string = e_destination_get_email (destination);
708                         g_value_set_string (value, string);
709                         break;
710
711                 case E_DESTINATION_STORE_COLUMN_ADDRESS:
712                         contact = e_destination_get_contact (destination);
713                         if (contact && E_IS_CONTACT (contact)) {
714                                 if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
715                                         string = e_destination_get_name (destination);
716                                         string_new = g_string_new (string);
717                                         string_new = g_string_append (string_new, " mailing list");
718                                         g_value_set_string (value, string_new->str);
719                                         g_string_free (string_new, TRUE);
720                                 }
721                                 else {
722                                         string = e_destination_get_address (destination);
723                                         g_value_set_string (value, string);
724                                 }
725                         }
726                         else {
727                                 string = e_destination_get_address (destination);
728                                 g_value_set_string (value, string);
729
730                         }
731                         break;
732
733                 default:
734                         g_assert_not_reached ();
735                         break;
736         }
737 }
738
739 /**
740  * e_destination_store_get_stamp:
741  * @destination_store: an #EDestinationStore
742  *
743  * Since: 2.32
744  **/
745 gint
746 e_destination_store_get_stamp (EDestinationStore *destination_store)
747 {
748         g_return_val_if_fail (E_IS_DESTINATION_STORE (destination_store), 0);
749
750         return destination_store->priv->stamp;
751 }