2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
55 #include "stock_pixmap.h"
57 #include "prefs_gtk.h"
63 #include "addr_compl.h"
66 #include "addressitem.h"
68 #include "addrcache.h"
70 #include "addrindex.h"
71 #include "addressadd.h"
72 #include "addressbook_foldersel.h"
74 #include "editvcard.h"
75 #include "editgroup.h"
76 #include "editaddress.h"
78 #include "importldif.h"
79 #include "importmutt.h"
80 #include "importpine.h"
85 #include "editjpilot.h"
90 #include "ldapserver.h"
92 #include "ldapupdate.h"
94 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
97 #include "addrquery.h"
98 #include "addrselect.h"
100 #include "addrgather.h"
101 #include "adbookbase.h"
102 #include "exphtmldlg.h"
103 #include "expldifdlg.h"
104 #include "browseldap.h"
110 } AddressIndexColumns;
118 } AddressListColumns;
121 AddressBookFile *book;
129 AddressDataSource *book;
133 static gchar *list_titles[] = { N_("Name"),
137 #define COL_NAME_WIDTH 164
138 #define COL_ADDRESS_WIDTH 156
140 #define COL_FOLDER_WIDTH 170
141 #define ADDRESSBOOK_WIDTH 640
142 #define ADDRESSBOOK_HEIGHT 360
144 #define ADDRESSBOOK_MSGBUF_SIZE 2048
146 static GdkPixmap *folderxpm;
147 static GdkBitmap *folderxpmmask;
148 static GdkPixmap *folderopenxpm;
149 static GdkBitmap *folderopenxpmmask;
150 static GdkPixmap *groupxpm;
151 static GdkBitmap *groupxpmmask;
152 static GdkPixmap *interfacexpm;
153 static GdkBitmap *interfacexpmmask;
154 static GdkPixmap *bookxpm;
155 static GdkBitmap *bookxpmmask;
156 static GdkPixmap *addressxpm;
157 static GdkBitmap *addressxpmmask;
158 static GdkPixmap *vcardxpm;
159 static GdkBitmap *vcardxpmmask;
160 static GdkPixmap *jpilotxpm;
161 static GdkBitmap *jpilotxpmmask;
162 static GdkPixmap *categoryxpm;
163 static GdkBitmap *categoryxpmmask;
164 static GdkPixmap *ldapxpm;
165 static GdkBitmap *ldapxpmmask;
166 static GdkPixmap *addrsearchxpm;
167 static GdkPixmap *addrsearchxpmmask;
170 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
172 /* Address list selection */
173 static AddrSelectList *_addressSelect_ = NULL;
174 static AddressClipboard *_clipBoard_ = NULL;
176 /* Address index file and interfaces */
177 static AddressIndex *_addressIndex_ = NULL;
178 static GList *_addressInterfaceList_ = NULL;
179 static GList *_addressIFaceSelection_ = NULL;
180 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
182 static AddressBook_win addrbook;
184 static GHashTable *_addressBookTypeHash_ = NULL;
185 static GList *_addressBookTypeList_ = NULL;
187 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
188 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
189 static void addressbook_edit_address_post_cb( ItemPerson *person );
191 static void addressbook_create (void);
192 static gint addressbook_close (void);
193 static void addressbook_button_set_sensitive (void);
195 static gboolean address_index_has_focus = FALSE;
196 static gboolean address_list_has_focus = FALSE;
198 /* callback functions */
199 static void addressbook_del_clicked (GtkButton *button,
201 static void addressbook_reg_clicked (GtkButton *button,
203 static void addressbook_to_clicked (GtkButton *button,
205 static void addressbook_lup_clicked (GtkButton *button,
207 static void addressbook_close_clicked (GtkButton *button,
210 static void addressbook_tree_selected (GtkCTree *ctree,
214 static void addressbook_select_row_tree (GtkCTree *ctree,
218 static void addressbook_list_row_selected (GtkCTree *clist,
222 static void addressbook_list_row_unselected (GtkCTree *clist,
226 static void addressbook_person_expand_node (GtkCTree *ctree,
229 static void addressbook_person_collapse_node (GtkCTree *ctree,
233 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
234 GdkEventButton *event,
236 static gboolean addressbook_list_button_released(GtkWidget *widget,
237 GdkEventButton *event,
239 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
240 GdkEventButton *event,
242 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
243 GdkEventButton *event,
246 static void addressbook_new_folder_cb (gpointer data,
249 static void addressbook_new_group_cb (gpointer data,
252 static void addressbook_treenode_edit_cb (gpointer data,
255 static void addressbook_treenode_delete_cb (gpointer data,
259 static void addressbook_change_node_name (GtkCTreeNode *node,
262 static void addressbook_new_address_cb (gpointer data,
265 static void addressbook_edit_address_cb (gpointer data,
268 static void addressbook_delete_address_cb (gpointer data,
272 static void close_cb (gpointer data,
275 static void addressbook_file_save_cb (gpointer data,
279 /* Data source edit stuff */
280 static void addressbook_new_book_cb (gpointer data,
283 static void addressbook_new_vcard_cb (gpointer data,
288 static void addressbook_new_jpilot_cb (gpointer data,
294 static void addressbook_new_ldap_cb (gpointer data,
299 static void addressbook_set_clist (AddressObject *obj,
302 static void addressbook_load_tree (void);
303 void addressbook_read_file (void);
305 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
307 static void addressbook_treenode_remove_item ( void );
309 static AddressDataSource *addressbook_find_datasource
310 (GtkCTreeNode *node );
312 static AddressBookFile *addressbook_get_book_file(void);
314 static GtkCTreeNode *addressbook_node_add_folder
316 AddressDataSource *ds,
317 ItemFolder *itemFolder,
318 AddressObjectType otype);
319 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
320 AddressDataSource *ds,
321 ItemGroup *itemGroup);
322 static void addressbook_tree_remove_children (GtkCTree *ctree,
323 GtkCTreeNode *parent);
324 static void addressbook_move_nodes_up (GtkCTree *ctree,
326 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
328 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
331 static gint addressbook_treenode_compare_func (GtkCList *clist,
334 static void addressbook_folder_load_one_person (GtkCTree *clist,
336 AddressTypeControlItem *atci,
337 AddressTypeControlItem *atciMail);
338 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
340 static void addressbook_folder_remove_one_person(GtkCTree *clist,
342 static void addressbook_folder_remove_node (GtkCTree *clist,
345 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
346 gboolean force_focus );
348 /* LUT's and IF stuff */
349 static void addressbook_free_treenode ( gpointer data );
350 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
351 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
353 static void addrbookctl_build_map (GtkWidget *window);
354 static void addrbookctl_build_iflist (void);
355 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
356 static void addrbookctl_build_ifselect (void);
358 static void addrbookctl_free_interface (AdapterInterface *adapter);
359 static void addrbookctl_free_datasource (AdapterDSource *adapter);
360 static void addrbookctl_free_folder (AdapterFolder *adapter);
361 static void addrbookctl_free_group (AdapterGroup *adapter);
363 static void addressbook_list_select_clear ( void );
364 static void addressbook_list_select_add ( AddrItemObject *aio,
365 AddressDataSource *ds );
366 static void addressbook_list_select_remove ( AddrItemObject *aio );
368 static void addressbook_import_ldif_cb ( void );
369 static void addressbook_import_mutt_cb ( void );
370 static void addressbook_import_pine_cb ( void );
371 static void addressbook_export_html_cb ( void );
372 static void addressbook_export_ldif_cb ( void );
373 static void addressbook_select_all_cb ( void );
374 static void addressbook_clip_cut_cb ( void );
375 static void addressbook_clip_copy_cb ( void );
376 static void addressbook_clip_paste_cb ( void );
377 static void addressbook_treenode_cut_cb ( void );
378 static void addressbook_treenode_copy_cb ( void );
379 static void addressbook_treenode_paste_cb ( void );
381 static void addressbook_mail_to_cb ( void );
384 static void addressbook_browse_entry_cb ( void );
386 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
388 static void addressbook_start_drag(GtkWidget *widget, gint button,
391 static void addressbook_drag_data_get(GtkWidget *widget,
392 GdkDragContext *drag_context,
393 GtkSelectionData *selection_data,
397 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
398 GdkDragContext *context,
403 static void addressbook_drag_leave_cb(GtkWidget *widget,
404 GdkDragContext *context,
407 static void addressbook_drag_received_cb(GtkWidget *widget,
408 GdkDragContext *drag_context,
411 GtkSelectionData *data,
415 static void addressbook_list_menu_setup( void );
417 static GtkTargetEntry addressbook_drag_types[] =
419 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
422 static GtkTargetList *addressbook_target_list = NULL;
425 static GtkItemFactoryEntry addressbook_entries[] =
427 {N_("/_Book"), NULL, NULL, 0, "<Branch>"},
428 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL},
429 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL},
430 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL},
432 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL},
435 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL},
437 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
438 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL},
439 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL},
440 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
441 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL},
442 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL},
443 {N_("/_Address"), NULL, NULL, 0, "<Branch>"},
444 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL},
445 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
446 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL},
447 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL},
448 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL},
449 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
450 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL},
451 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL},
452 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
453 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL},
454 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL},
455 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
456 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
457 {N_("/_Tools"), NULL, NULL, 0, "<Branch>"},
458 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL},
459 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL},
460 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL},
461 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>"},
462 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL},
463 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL},
464 {N_("/_Help"), NULL, NULL, 0, "<Branch>"},
465 {N_("/_Help/_About"), NULL, about_show, 0, NULL}
468 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
470 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL},
471 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL},
472 {"/---", NULL, NULL, 0, "<Separator>"},
473 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL},
474 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
475 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
476 {"/---", NULL, NULL, 0, "<Separator>"},
477 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL},
478 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL},
479 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL}
482 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
484 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL},
485 {"/---", NULL, NULL, 0, "<Separator>"},
486 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL},
487 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL},
488 {"/---", NULL, NULL, 0, "<Separator>"},
489 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
490 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
491 {"/---", NULL, NULL, 0, "<Separator>"},
492 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL},
493 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL},
494 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL},
495 {"/---", NULL, NULL, 0, "<Separator>"},
496 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},*/
497 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
499 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL},
504 * Structure of error message table.
506 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
507 struct _ErrMsgTableEntry {
512 static gchar *_errMsgUnknown_ = N_( "Unknown" );
515 * Lookup table of error messages for general errors. Note that a NULL
516 * description signifies the end of the table.
518 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
519 { MGU_SUCCESS, N_("Success") },
520 { MGU_BAD_ARGS, N_("Bad arguments") },
521 { MGU_NO_FILE, N_("File not specified") },
522 { MGU_OPEN_FILE, N_("Error opening file") },
523 { MGU_ERROR_READ, N_("Error reading file") },
524 { MGU_EOF, N_("End of file encountered") },
525 { MGU_OO_MEMORY, N_("Error allocating memory") },
526 { MGU_BAD_FORMAT, N_("Bad file format") },
527 { MGU_ERROR_WRITE, N_("Error writing to file") },
528 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
529 { MGU_NO_PATH, N_("No path specified") },
535 * Lookup table of error messages for LDAP errors.
537 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
538 { LDAPRC_SUCCESS, N_("Success") },
539 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
540 { LDAPRC_INIT, N_("Error initializing LDAP") },
541 { LDAPRC_BIND, N_("Error binding to LDAP server") },
542 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
543 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
544 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
545 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
546 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
547 { LDAPRC_TLS, N_("Error starting TLS connection") },
548 { LDAPRC_NODN, N_("Distinguised Name (dn) is missing") },
549 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
550 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
551 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
557 * Lookup message for specified error code.
558 * \param lut Lookup table.
559 * \param code Code to lookup.
560 * \return Description associated to code.
562 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
564 ErrMsgTableEntry entry;
567 for( i = 0; ; i++ ) {
569 if( entry.description == NULL ) break;
570 if( entry.code == code ) {
571 desc = entry.description;
576 desc = _errMsgUnknown_;
581 static gboolean lastCanLookup = FALSE;
583 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
585 if (add_and_delete) {
586 gtk_widget_show(addrbook.edit_btn);
587 gtk_widget_show(addrbook.del_btn);
588 gtk_widget_show(addrbook.reg_btn);
590 gtk_widget_hide(addrbook.edit_btn);
591 gtk_widget_hide(addrbook.del_btn);
592 gtk_widget_hide(addrbook.reg_btn);
596 gtk_widget_show(addrbook.lup_btn);
597 gtk_widget_show(addrbook.entry);
598 gtk_widget_show(addrbook.label);
600 gtk_widget_hide(addrbook.lup_btn);
601 gtk_widget_hide(addrbook.entry);
602 gtk_widget_hide(addrbook.label);
605 lastCanLookup = lookup;
608 gtk_widget_show(addrbook.to_btn);
609 gtk_widget_show(addrbook.cc_btn);
610 gtk_widget_show(addrbook.bcc_btn);
612 gtk_widget_hide(addrbook.to_btn);
613 gtk_widget_hide(addrbook.cc_btn);
614 gtk_widget_hide(addrbook.bcc_btn);
618 void addressbook_open(Compose *target)
620 /* Initialize all static members */
621 if( _clipBoard_ == NULL ) {
622 _clipBoard_ = addrclip_create();
624 if( _addressIndex_ != NULL ) {
625 addrclip_set_index( _clipBoard_, _addressIndex_ );
627 if( _addressSelect_ == NULL ) {
628 _addressSelect_ = addrselect_list_create();
630 if (!addrbook.window) {
631 addressbook_read_file();
632 addressbook_create();
633 addressbook_load_tree();
634 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
635 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
638 gtk_widget_hide(addrbook.window);
641 gtk_widget_show_all(addrbook.window);
643 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
644 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
646 if (!prefs_common.addressbook_use_editaddress_dialog)
647 addressbook_edit_person_widgetset_hide();
649 address_completion_start(addrbook.window);
651 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
652 addressbook_set_target_compose(target);
656 * Destroy addressbook.
658 void addressbook_destroy( void ) {
659 /* Free up address stuff */
660 if( _addressSelect_ != NULL ) {
661 addrselect_list_free( _addressSelect_ );
663 if( _clipBoard_ != NULL ) {
664 addrclip_free( _clipBoard_ );
666 if( _addressIndex_ != NULL ) {
667 addrindex_free_index( _addressIndex_ );
668 addrindex_teardown();
670 _addressSelect_ = NULL;
672 _addressIndex_ = NULL;
675 void addressbook_set_target_compose(Compose *target)
677 addrbook.target_compose = target;
678 addressbook_button_set_sensitive();
681 Compose *addressbook_get_target_compose(void)
683 return addrbook.target_compose;
687 * Refresh addressbook and save to file(s).
689 static void addressbook_refresh( void )
691 if (addrbook.window) {
692 if (addrbook.treeSelected) {
693 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
694 addrbook.treeSelected);
695 addressbook_set_clist(
696 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
697 addrbook.treeSelected),
702 addressbook_export_to_file();
705 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
707 if (event && event->keyval == GDK_Escape)
709 else if (event && event->keyval == GDK_Delete) {
710 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
711 if ( /* address_index_has_focus || */ address_list_has_focus )
712 addressbook_del_clicked(NULL, NULL);
718 *\brief Save Gtk object size to prefs dataset
720 static void addressbook_size_allocate_cb(GtkWidget *widget,
721 GtkAllocation *allocation)
723 g_return_if_fail(allocation != NULL);
725 prefs_common.addressbookwin_width = allocation->width;
726 prefs_common.addressbookwin_height = allocation->height;
729 static gint sort_column_number = 0;
730 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
732 static gint list_case_sort(
733 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
735 GtkCListRow *row1 = (GtkCListRow *) ptr1;
736 GtkCListRow *row2 = (GtkCListRow *) ptr2;
737 gchar *name1 = NULL, *name2 = NULL;
738 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
739 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
741 if( aio1->type == aio2->type ) {
743 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
745 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
746 if( ! name1 ) return ( name2 != NULL );
747 if( ! name2 ) return -1;
748 return strcasecmp( name1, name2 );
750 /* Order groups before person */
751 if( aio1->type == ITEMTYPE_GROUP ) {
752 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
753 } else if( aio2->type == ITEMTYPE_GROUP ) {
754 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
760 static void addressbook_sort_list(GtkCList *clist, const gint col,
761 const GtkSortType sort_type)
764 GtkWidget *hbox, *label, *arrow;
766 sort_column_number = col;
767 sort_column_type = sort_type;
768 gtk_clist_set_compare_func(clist, list_case_sort);
769 gtk_clist_set_sort_type(clist, sort_type);
770 gtk_clist_set_sort_column(clist, col);
772 gtk_clist_freeze(clist);
773 gtk_clist_sort(clist);
775 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
776 hbox = gtk_hbox_new(FALSE, 4);
777 label = gtk_label_new(gettext(list_titles[pos]));
778 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
781 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
782 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
783 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
786 gtk_widget_show_all(hbox);
787 gtk_clist_set_column_widget(clist, pos, hbox);
790 gtk_clist_thaw(clist);
793 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
795 static GtkSortType sort_type = GTK_SORT_ASCENDING;
797 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
799 addressbook_sort_list(clist, COL_NAME, sort_type);
802 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
804 static GtkSortType sort_type = GTK_SORT_ASCENDING;
806 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
808 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
811 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
813 static GtkSortType sort_type = GTK_SORT_ASCENDING;
815 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
817 addressbook_sort_list(clist, COL_REMARKS, sort_type);
820 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
823 address_index_has_focus = TRUE;
827 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
830 address_index_has_focus = FALSE;
831 if (!prefs_common.addressbook_use_editaddress_dialog
832 && !address_list_has_focus)
833 addressbook_address_list_disable_some_actions();
837 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
840 address_list_has_focus = TRUE;
844 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
847 address_list_has_focus = FALSE;
848 if (!prefs_common.addressbook_use_editaddress_dialog
849 && !address_index_has_focus)
850 addressbook_address_list_disable_some_actions();
854 /* save hpane and vpane's handle position when it moves */
855 static void addressbook_pane_save_position(void)
858 prefs_common.addressbook_hpaned_pos =
859 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
861 prefs_common.addressbook_vpaned_pos =
862 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
866 * Create the address book widgets. The address book contains two CTree widgets: the
867 * address index tree on the left and the address list on the right.
869 * The address index tree displays a hierarchy of interfaces and groups. Each node in
870 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
871 * data sources and folder objects.
873 * The address list displays group, person and email objects. These items are linked
874 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
877 * In the tradition of MVC architecture, the data stores have been separated from the
878 * GUI components. The addrindex.c file provides the interface to all data stores.
880 static void addressbook_create(void)
886 GtkWidget *ctree_swin;
888 GtkWidget *editaddress_vbox;
889 GtkWidget *clist_vbox;
890 GtkWidget *clist_swin;
897 GtkWidget *statusbar;
908 GtkWidget *close_btn;
909 GtkWidget *tree_popup;
910 GtkWidget *list_popup;
911 GtkItemFactory *tree_factory;
912 GtkItemFactory *list_factory;
913 GtkItemFactory *menu_factory;
917 gchar *index_titles[N_INDEX_COLS];
921 static GdkGeometry geometry;
923 debug_print("Creating addressbook window...\n");
925 index_titles[COL_SOURCES] = _("Sources");
927 /* Address book window */
928 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
929 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
930 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
931 gtk_widget_realize(window);
933 g_signal_connect(G_OBJECT(window), "delete_event",
934 G_CALLBACK(addressbook_close), NULL);
935 g_signal_connect(G_OBJECT(window), "size_allocate",
936 G_CALLBACK(addressbook_size_allocate_cb), NULL);
937 g_signal_connect(G_OBJECT(window), "key_press_event",
938 G_CALLBACK(key_pressed), NULL);
939 MANAGE_WINDOW_SIGNALS_CONNECT(window);
941 vbox = gtk_vbox_new(FALSE, 0);
942 gtk_container_add(GTK_CONTAINER(window), vbox);
945 n_entries = sizeof(addressbook_entries) /
946 sizeof(addressbook_entries[0]);
947 menubar = menubar_create(window, addressbook_entries, n_entries,
948 "<AddressBook>", NULL);
949 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
950 menu_factory = gtk_item_factory_from_widget(menubar);
952 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
953 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
954 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
956 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
957 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
958 GTK_POLICY_AUTOMATIC,
959 GTK_POLICY_AUTOMATIC);
960 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
963 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
964 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
965 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
966 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
967 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
968 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
969 GTK_CTREE_EXPANDER_SQUARE);
970 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
971 gtk_clist_set_compare_func(GTK_CLIST(ctree),
972 addressbook_treenode_compare_func);
974 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
975 G_CALLBACK(addressbook_tree_selected), NULL);
976 g_signal_connect(G_OBJECT(ctree), "button_press_event",
977 G_CALLBACK(addressbook_tree_button_pressed),
979 g_signal_connect(G_OBJECT(ctree), "button_release_event",
980 G_CALLBACK(addressbook_tree_button_released),
983 g_signal_connect(G_OBJECT(ctree), "select_row",
984 G_CALLBACK(addressbook_select_row_tree), NULL);
986 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
987 addressbook_drag_types, 1,
988 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
989 g_signal_connect(G_OBJECT(ctree), "drag_motion",
990 G_CALLBACK(addressbook_drag_motion_cb),
992 g_signal_connect(G_OBJECT(ctree), "drag_leave",
993 G_CALLBACK(addressbook_drag_leave_cb),
995 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
996 G_CALLBACK(addressbook_drag_received_cb),
998 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
999 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1000 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1001 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1003 clist_vbox = gtk_vbox_new(FALSE, 4);
1005 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1006 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1007 GTK_POLICY_AUTOMATIC,
1008 GTK_POLICY_AUTOMATIC);
1009 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1012 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1013 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1014 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1015 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1016 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1017 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1018 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1020 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1022 gtk_widget_set_size_request(clist, -1, 80);
1024 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1025 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1026 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1027 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1028 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1029 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1030 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1031 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1032 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1033 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1034 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1036 for (i = 0; i < N_LIST_COLS; i++)
1037 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1040 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1041 G_CALLBACK(addressbook_list_row_selected), NULL);
1042 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1043 G_CALLBACK(addressbook_list_row_unselected), NULL);
1044 g_signal_connect(G_OBJECT(clist), "button_press_event",
1045 G_CALLBACK(addressbook_list_button_pressed),
1047 g_signal_connect(G_OBJECT(clist), "button_release_event",
1048 G_CALLBACK(addressbook_list_button_released),
1050 g_signal_connect(G_OBJECT(clist), "tree_expand",
1051 G_CALLBACK(addressbook_person_expand_node), NULL );
1052 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1053 G_CALLBACK(addressbook_person_collapse_node), NULL );
1054 g_signal_connect(G_OBJECT(clist), "start_drag",
1055 G_CALLBACK(addressbook_start_drag), NULL);
1056 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1057 G_CALLBACK(addressbook_drag_data_get), NULL);
1058 hbox = gtk_hbox_new(FALSE, 4);
1059 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1061 label = gtk_label_new(_("Lookup name:"));
1062 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1064 entry = gtk_entry_new();
1065 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1067 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1069 g_signal_connect(G_OBJECT(entry), "key_press_event",
1070 G_CALLBACK(addressbook_entry_key_pressed),
1073 if (!prefs_common.addressbook_use_editaddress_dialog) {
1074 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1075 vpaned = gtk_vpaned_new();
1076 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1077 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1080 editaddress_vbox = NULL;
1082 hpaned = gtk_hpaned_new();
1083 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1084 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1085 if (prefs_common.addressbook_use_editaddress_dialog)
1086 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1088 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1091 hsbox = gtk_hbox_new(FALSE, 0);
1092 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1093 statusbar = gtk_statusbar_new();
1094 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1097 hbbox = gtk_hbutton_box_new();
1098 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1099 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1100 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1101 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1103 gtkut_stock_button_add_help(hbbox, &help_btn);
1105 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1106 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1107 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1108 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1109 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1110 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1111 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1112 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1113 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1116 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1117 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1118 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1120 g_signal_connect(G_OBJECT(help_btn), "clicked",
1121 G_CALLBACK(manual_open_with_anchor_cb),
1122 MANUAL_ANCHOR_ADDRBOOK);
1124 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1125 G_CALLBACK(addressbook_edit_clicked), NULL);
1126 g_signal_connect(G_OBJECT(del_btn), "clicked",
1127 G_CALLBACK(addressbook_del_clicked), NULL);
1128 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1129 G_CALLBACK(addressbook_reg_clicked), NULL);
1130 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1131 G_CALLBACK(addressbook_lup_clicked), NULL);
1133 to_btn = gtk_button_new_with_label
1134 (prefs_common.trans_hdr ? _("To:") : "To:");
1135 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1136 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1137 cc_btn = gtk_button_new_with_label
1138 (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
1139 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1140 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1141 bcc_btn = gtk_button_new_with_label
1142 (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
1143 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1144 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1146 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1147 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1148 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1150 g_signal_connect(G_OBJECT(to_btn), "clicked",
1151 G_CALLBACK(addressbook_to_clicked),
1152 GINT_TO_POINTER(COMPOSE_TO));
1153 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1154 G_CALLBACK(addressbook_to_clicked),
1155 GINT_TO_POINTER(COMPOSE_CC));
1156 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1157 G_CALLBACK(addressbook_to_clicked),
1158 GINT_TO_POINTER(COMPOSE_BCC));
1159 g_signal_connect(G_OBJECT(close_btn), "clicked",
1160 G_CALLBACK(addressbook_close_clicked), NULL);
1162 /* Build icons for interface */
1163 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1164 &interfacexpm, &interfacexpmmask );
1166 /* Build control tables */
1167 addrbookctl_build_map(window);
1168 addrbookctl_build_iflist();
1169 addrbookctl_build_ifselect();
1171 addrbook.clist = NULL;
1173 /* Add each interface into the tree as a root level folder */
1174 nodeIf = _addressInterfaceList_;
1176 AdapterInterface *adapter = nodeIf->data;
1177 AddressInterface *iface = adapter->interface;
1178 nodeIf = g_list_next(nodeIf);
1180 if(iface->useInterface) {
1181 AddressTypeControlItem *atci = adapter->atci;
1182 text = atci->displayName;
1184 gtk_sctree_insert_node( GTK_CTREE(ctree),
1185 NULL, NULL, &text, FOLDER_SPACING,
1186 interfacexpm, interfacexpmmask,
1187 interfacexpm, interfacexpmmask,
1189 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1190 gtk_ctree_node_set_row_data_full(
1191 GTK_CTREE(ctree), adapter->treeNode, adapter,
1192 addressbook_free_treenode );
1197 n_entries = sizeof(addressbook_tree_popup_entries) /
1198 sizeof(addressbook_tree_popup_entries[0]);
1199 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1201 "<AddressBookTree>", &tree_factory,
1203 n_entries = sizeof(addressbook_list_popup_entries) /
1204 sizeof(addressbook_list_popup_entries[0]);
1205 list_popup = menu_create_items(addressbook_list_popup_entries,
1207 "<AddressBookList>", &list_factory,
1210 addrbook.window = window;
1211 addrbook.hpaned = hpaned;
1212 addrbook.vpaned = vpaned;
1213 addrbook.menubar = menubar;
1214 addrbook.ctree = ctree;
1217 addrbook.editaddress_vbox = editaddress_vbox;
1218 addrbook.clist = clist;
1219 addrbook.label = label;
1220 addrbook.entry = entry;
1221 addrbook.statusbar = statusbar;
1222 addrbook.status_cid = gtk_statusbar_get_context_id(
1223 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1225 addrbook.help_btn = help_btn;
1226 addrbook.edit_btn = edit_btn;
1227 addrbook.del_btn = del_btn;
1228 addrbook.reg_btn = reg_btn;
1229 addrbook.lup_btn = lup_btn;
1230 addrbook.to_btn = to_btn;
1231 addrbook.cc_btn = cc_btn;
1232 addrbook.bcc_btn = bcc_btn;
1234 addrbook.tree_popup = tree_popup;
1235 addrbook.list_popup = list_popup;
1236 addrbook.tree_factory = tree_factory;
1237 addrbook.list_factory = list_factory;
1238 addrbook.menu_factory = menu_factory;
1240 addrbook.listSelected = NULL;
1242 if (!geometry.min_height) {
1243 geometry.min_width = ADDRESSBOOK_WIDTH;
1244 geometry.min_height = ADDRESSBOOK_HEIGHT;
1247 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1249 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1250 prefs_common.addressbookwin_height);
1252 if (!prefs_common.addressbook_use_editaddress_dialog) {
1253 if (prefs_common.addressbook_vpaned_pos > 0)
1254 gtk_paned_set_position(GTK_PANED(vpaned),
1255 prefs_common.addressbook_vpaned_pos);
1257 if (prefs_common.addressbook_hpaned_pos > 0)
1258 gtk_paned_set_position(GTK_PANED(hpaned),
1259 prefs_common.addressbook_hpaned_pos);
1262 gtk_widget_show_all(window);
1266 * Close address book window and save to file(s).
1268 static gint addressbook_close( void ) {
1269 address_completion_end(addrbook.window);
1270 if (!prefs_common.addressbook_use_editaddress_dialog)
1271 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1273 addressbook_pane_save_position();
1275 gtk_widget_hide(addrbook.window);
1276 addressbook_export_to_file();
1281 * Display message in status line.
1282 * \param msg Message to display.
1284 static void addressbook_status_show( gchar *msg ) {
1285 if( addrbook.statusbar != NULL ) {
1287 GTK_STATUSBAR(addrbook.statusbar),
1288 addrbook.status_cid );
1291 GTK_STATUSBAR(addrbook.statusbar),
1292 addrbook.status_cid, msg );
1297 static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
1298 *addressbook_msgbuf = '\0';
1302 name = addrindex_ds_get_name( ds );
1303 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1304 "%s: %s", name, msg );
1307 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1310 addressbook_status_show( addressbook_msgbuf );
1313 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1317 *addressbook_msgbuf = '\0';
1319 name = addrindex_ds_get_name( ds );
1320 retVal = addrindex_ds_get_status_code( ds );
1321 if( retVal == MGU_SUCCESS ) {
1322 g_snprintf( addressbook_msgbuf,
1323 sizeof(addressbook_msgbuf), "%s", name );
1326 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1327 g_snprintf( addressbook_msgbuf,
1328 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1331 addressbook_status_show( addressbook_msgbuf );
1334 static void addressbook_button_set_sensitive(void)
1336 gboolean to_sens = FALSE;
1337 gboolean cc_sens = FALSE;
1338 gboolean bcc_sens = FALSE;
1340 if (!addrbook.window) return;
1342 if (addrbook.target_compose) {
1348 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1349 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1350 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1353 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1355 addressbook_edit_address_cb(NULL, 0, NULL);
1359 * Delete one or more objects from address list.
1361 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1363 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1364 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1365 AddressObject *pobj;
1366 AdapterDSource *ads = NULL;
1367 GtkCTreeNode *nodeList;
1370 AddressBookFile *abf = NULL;
1371 AddressDataSource *ds = NULL;
1372 AddressInterface *iface;
1373 AddrItemObject *aio;
1374 AddrSelectItem *item;
1376 gboolean refreshList = FALSE;
1378 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1379 g_return_if_fail(pobj != NULL);
1381 /* Test whether anything selected for deletion */
1382 nodeList = addrbook.listSelected;
1384 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1385 if( aio == NULL) return;
1386 ds = addressbook_find_datasource( addrbook.treeSelected );
1387 if( ds == NULL ) return;
1389 /* Test for read only */
1390 iface = ds->interface;
1391 if( iface->readOnly ) {
1392 alertpanel( _("Delete address(es)"),
1393 _("This address data is readonly and cannot be deleted."),
1394 GTK_STOCK_CLOSE, NULL, NULL );
1398 /* Test whether Ok to proceed */
1400 if( pobj->type == ADDR_DATASOURCE ) {
1401 ads = ADAPTER_DSOURCE(pobj);
1402 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1404 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1407 else if( pobj->type == ADDR_ITEM_GROUP ) {
1410 if( ! procFlag ) return;
1411 abf = ds->rawDataSource;
1412 if( abf == NULL ) return;
1415 /* Process deletions */
1416 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1417 gboolean group_delete = TRUE;
1418 /* Items inside folders */
1419 list = addrselect_get_list( _addressSelect_ );
1420 /* Confirm deletion */
1424 node = g_list_next( node );
1425 aio = ( AddrItemObject * ) item->addressItem;
1426 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1427 group_delete = FALSE;
1432 aval = alertpanel( _("Delete group"),
1433 _("Really delete the group(s)?\n"
1434 "The addresses it contains will not be lost."),
1435 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1436 if( aval != G_ALERTALTERNATE ) return;
1438 aval = alertpanel( _("Delete address(es)"),
1439 _("Really delete the address(es)?"),
1440 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1441 if( aval != G_ALERTALTERNATE ) return;
1447 node = g_list_next( node );
1448 aio = ( AddrItemObject * ) item->addressItem;
1449 if( aio->type == ADDR_ITEM_GROUP ) {
1450 ItemGroup *item = ( ItemGroup * ) aio;
1451 GtkCTreeNode *nd = NULL;
1453 nd = addressbook_find_group_node( addrbook.opened, item );
1454 item = addrbook_remove_group( abf, item );
1456 addritem_free_item_group( item );
1458 /* Remove group from parent node */
1459 gtk_ctree_remove_node( ctree, nd );
1462 else if( aio->type == ADDR_ITEM_PERSON ) {
1463 ItemPerson *item = ( ItemPerson * ) aio;
1464 item->status = DELETE_ENTRY;
1465 addressbook_folder_remove_one_person( clist, item );
1466 if (pobj->type == ADDR_ITEM_FOLDER)
1467 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1468 item = addrbook_remove_person( abf, item );
1469 if (ds->type == ADDR_IF_LDAP) {
1470 LdapServer *server = ds->rawDataSource;
1471 ldapsvr_set_modified(server, TRUE);
1472 ldapsvr_update_book(server, item);
1475 addritem_free_item_person( item );
1478 else if( aio->type == ADDR_ITEM_EMAIL ) {
1479 ItemEMail *item = ( ItemEMail * ) aio;
1480 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1481 item = addrbook_person_remove_email( abf, person, item );
1483 addrcache_remove_email(abf->addressCache, item);
1484 addritem_free_item_email( item );
1486 addressbook_folder_refresh_one_person( clist, person );
1489 g_list_free( list );
1490 addressbook_list_select_clear();
1492 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1493 addressbook_set_clist(
1494 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1498 addrbook_set_dirty(abf, TRUE);
1499 addressbook_export_to_file();
1500 addressbook_list_menu_setup();
1503 else if( pobj->type == ADDR_ITEM_GROUP ) {
1504 /* Items inside groups */
1505 list = addrselect_get_list( _addressSelect_ );
1509 node = g_list_next( node );
1510 aio = ( AddrItemObject * ) item->addressItem;
1511 if( aio->type == ADDR_ITEM_EMAIL ) {
1512 ItemEMail *item = ( ItemEMail * ) aio;
1513 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1514 item = addrbook_person_remove_email( abf, person, item );
1516 addritem_free_item_email( item );
1520 g_list_free( list );
1521 addressbook_list_select_clear();
1522 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1523 addressbook_set_clist(
1524 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1528 addrbook_set_dirty(abf, TRUE);
1529 addressbook_export_to_file();
1530 addressbook_list_menu_setup();
1534 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1535 gtk_ctree_remove_node( clist, nodeList );
1539 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1541 addressbook_new_address_cb( NULL, 0, NULL );
1544 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1547 gchar *address = NULL;
1549 if( aio->type == ADDR_ITEM_EMAIL ) {
1550 ItemPerson *person = NULL;
1551 ItemEMail *email = ( ItemEMail * ) aio;
1553 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1554 if( email->address ) {
1555 if( ADDRITEM_NAME(email) ) {
1556 name = ADDRITEM_NAME(email);
1557 if( *name == '\0' ) {
1558 name = ADDRITEM_NAME(person);
1561 else if( ADDRITEM_NAME(person) ) {
1562 name = ADDRITEM_NAME(person);
1565 buf = g_strdup( email->address );
1567 address = email->address;
1570 else if( aio->type == ADDR_ITEM_PERSON ) {
1571 ItemPerson *person = ( ItemPerson * ) aio;
1572 GList *node = person->listEMail;
1574 name = ADDRITEM_NAME(person);
1576 ItemEMail *email = ( ItemEMail * ) node->data;
1577 address = email->address;
1581 if( name && name[0] != '\0' ) {
1582 if( strchr_with_skip_quote( name, '"', ',' ) )
1583 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1585 buf = g_strdup_printf( "%s <%s>", name, address );
1588 buf = g_strdup( address );
1595 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1599 AddrSelectItem *item;
1600 AddrItemObject *aio;
1603 compose = addrbook.target_compose;
1604 if( ! compose ) return;
1606 /* Nothing selected, but maybe there is something in text entry */
1607 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1609 compose_entry_append(
1610 compose, addr, (ComposeEntryType)data );
1613 /* Select from address list */
1614 list = addrselect_get_list( _addressSelect_ );
1619 node = g_list_next( node );
1620 aio = item->addressItem;
1621 if( aio->type == ADDR_ITEM_PERSON ||
1622 aio->type == ADDR_ITEM_EMAIL ) {
1623 addr = addressbook_format_address( aio );
1624 compose_entry_append(
1625 compose, addr, (ComposeEntryType) data );
1628 else if( aio->type == ADDR_ITEM_GROUP ) {
1629 ItemGroup *group = ( ItemGroup * ) aio;
1630 GList *nodeMail = group->listEMail;
1632 ItemEMail *email = nodeMail->data;
1634 addr = addressbook_format_address(
1635 ( AddrItemObject * ) email );
1636 compose_entry_append(
1637 compose, addr, (ComposeEntryType) data );
1639 nodeMail = g_list_next( nodeMail );
1644 AddressObject *obj = NULL;
1646 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1648 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1649 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1650 GList *nodeMail = itemGroup->listEMail;
1652 ItemEMail *email = nodeMail->data;
1654 addr = addressbook_format_address(
1655 ( AddrItemObject * ) email );
1656 compose_entry_append(
1657 compose, addr, (ComposeEntryType) data );
1659 nodeMail = g_list_next( nodeMail );
1663 g_list_free( list );
1666 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1667 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1668 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1669 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1671 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1672 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1673 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1674 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1676 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1677 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1678 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1679 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1680 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1681 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1684 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1685 gboolean canEdit = FALSE;
1686 gboolean canDelete = TRUE;
1687 gboolean canAdd = FALSE;
1688 gboolean canEditTr = TRUE;
1689 gboolean editAddress = FALSE;
1690 gboolean canExport = TRUE;
1691 AddressTypeControlItem *atci = NULL;
1692 AddressDataSource *ds = NULL;
1693 AddressInterface *iface = NULL;
1695 if( obj == NULL ) return;
1696 if( obj->type == ADDR_INTERFACE ) {
1697 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1698 iface = adapter->interface;
1700 if( iface->haveLibrary ) {
1701 /* Enable appropriate File / New command */
1702 atci = adapter->atci;
1703 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1706 canEditTr = canExport = FALSE;
1708 else if( obj->type == ADDR_DATASOURCE ) {
1709 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1710 ds = ads->dataSource;
1711 iface = ds->interface;
1712 if( ! iface->readOnly ) {
1713 canAdd = canEdit = editAddress = canDelete = TRUE;
1715 if( ! iface->haveLibrary ) {
1716 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1719 else if( obj->type == ADDR_ITEM_FOLDER ) {
1720 ds = addressbook_find_datasource( addrbook.treeSelected );
1722 iface = ds->interface;
1723 if( iface->readOnly ) {
1728 canAdd = editAddress = TRUE;
1732 else if( obj->type == ADDR_ITEM_GROUP ) {
1733 ds = addressbook_find_datasource( addrbook.treeSelected );
1735 iface = ds->interface;
1736 if( ! iface->readOnly ) {
1742 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1745 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1746 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1747 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1748 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1751 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1752 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1753 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1754 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1756 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1757 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1760 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1761 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1764 static void addressbook_list_menu_setup( void );
1767 * Address book tree callback function that responds to selection of tree
1770 * \param ctree Tree widget.
1771 * \param node Node that was selected.
1772 * \param column Column number where selected occurred.
1773 * \param data Pointer to user data.
1775 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1776 gint column, gpointer data)
1778 AddressObject *obj = NULL;
1779 AdapterDSource *ads = NULL;
1780 AddressDataSource *ds = NULL;
1781 ItemFolder *rootFolder = NULL;
1782 AddressObjectType aot;
1784 addrbook.treeSelected = node;
1785 addrbook.listSelected = NULL;
1786 addressbook_status_show( "" );
1787 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1789 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1791 addressbook_set_clist(NULL, TRUE);
1794 addrbook.opened = node;
1796 if( obj->type == ADDR_DATASOURCE ) {
1797 /* Read from file */
1798 static gboolean tVal = TRUE;
1800 ads = ADAPTER_DSOURCE(obj);
1801 if( ads == NULL ) return;
1802 ds = ads->dataSource;
1803 if( ds == NULL ) return;
1805 if( addrindex_ds_get_modify_flag( ds ) ) {
1806 addrindex_ds_read_data( ds );
1809 if( ! addrindex_ds_get_read_flag( ds ) ) {
1810 addrindex_ds_read_data( ds );
1812 addressbook_ds_show_message( ds );
1814 if( ! addrindex_ds_get_access_flag( ds ) ) {
1815 /* Remove existing folders and groups */
1816 gtk_clist_freeze( GTK_CLIST(ctree) );
1817 addressbook_tree_remove_children( ctree, node );
1818 gtk_clist_thaw( GTK_CLIST(ctree) );
1820 /* Load folders into the tree */
1821 rootFolder = addrindex_ds_get_root_folder( ds );
1822 if( ds->type == ADDR_IF_JPILOT ) {
1823 aot = ADDR_CATEGORY;
1825 else if( ds->type == ADDR_IF_LDAP ) {
1826 aot = ADDR_LDAP_QUERY;
1829 aot = ADDR_ITEM_FOLDER;
1831 addressbook_node_add_folder( node, ds, rootFolder, aot );
1832 addrindex_ds_set_access_flag( ds, &tVal );
1833 gtk_ctree_expand( ctree, node );
1836 addressbook_set_clist(NULL, TRUE);
1839 /* Update address list */
1840 g_signal_handlers_block_by_func
1842 G_CALLBACK(addressbook_tree_selected), NULL);
1843 addressbook_set_clist( obj, FALSE );
1844 g_signal_handlers_unblock_by_func
1846 G_CALLBACK(addressbook_tree_selected), NULL);
1847 if (!prefs_common.addressbook_use_editaddress_dialog)
1848 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1850 /* Setup main menu selections */
1851 addressbook_menubar_set_sensitive( FALSE );
1852 addressbook_list_menu_setup();
1853 addressbook_menuitem_set_sensitive( obj, node );
1855 addressbook_list_select_clear();
1856 addressbook_list_menu_setup();
1861 * Setup address list popup menu items. Items are enabled or disabled as
1864 static void addressbook_list_menu_setup( void ) {
1865 GtkCTree *clist = NULL;
1866 AddressObject *pobj = NULL;
1867 AddressObject *obj = NULL;
1868 AdapterDSource *ads = NULL;
1869 AddressInterface *iface = NULL;
1870 AddressDataSource *ds = NULL;
1871 gboolean canEdit = FALSE;
1872 gboolean canDelete = FALSE;
1873 gboolean canCut = FALSE;
1874 gboolean canCopy = FALSE;
1875 gboolean canPaste = FALSE;
1876 gboolean canBrowse = FALSE;
1878 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1879 if( pobj == NULL ) return;
1881 clist = GTK_CTREE(addrbook.clist);
1882 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1883 if( obj == NULL ) canEdit = FALSE;
1885 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1886 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1888 if( pobj->type == ADDR_DATASOURCE ) {
1889 /* Parent object is a data source */
1890 ads = ADAPTER_DSOURCE(pobj);
1891 ds = ads->dataSource;
1892 iface = ds->interface;
1893 if( ! iface->readOnly ) {
1894 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1895 if (iface->type != ADDR_IF_LDAP)
1896 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1897 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1898 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1899 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1900 if( obj ) canEdit = TRUE;
1902 canDelete = canEdit;
1904 else if( pobj->type != ADDR_INTERFACE ) {
1905 /* Parent object is not an interface */
1906 ds = addressbook_find_datasource( addrbook.treeSelected );
1907 iface = ds->interface;
1908 if( ! iface->readOnly ) {
1909 /* Folder or group */
1910 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1911 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1912 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1913 if( obj ) canEdit = TRUE;
1916 if( pobj->type == ADDR_ITEM_FOLDER ) {
1917 if (iface->type != ADDR_IF_LDAP)
1918 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1919 if( obj ) canEdit = TRUE;
1921 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1922 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1923 canDelete = canEdit;
1925 if( iface->type == ADDR_IF_LDAP ) {
1926 if( obj ) canBrowse = TRUE;
1931 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1933 /* Disable edit or browse if more than one row selected */
1934 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1939 /* Now go finalize menu items */
1940 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1941 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1943 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1944 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1945 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1946 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1948 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1950 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1951 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1952 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1953 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1955 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1956 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1957 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1959 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1960 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1961 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1963 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1964 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1967 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1971 static void addressbook_select_row_tree (GtkCTree *ctree,
1979 * Add list of items into tree node below specified tree node.
1980 * \param treeNode Tree node.
1981 * \param ds Data source.
1982 * \param listItems List of items.
1984 static void addressbook_treenode_add_list(
1985 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
1991 AddrItemObject *aio;
1995 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
1998 group = ( ItemGroup * ) aio;
1999 nn = addressbook_node_add_group( treeNode, ds, group );
2001 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2004 folder = ( ItemFolder * ) aio;
2005 nn = addressbook_node_add_folder(
2006 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2008 node = g_list_next( node );
2012 static void addressbook_select_all_cb( void ) {
2013 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2017 * Cut from address list widget.
2019 static void addressbook_clip_cut_cb( void ) {
2020 _clipBoard_->cutFlag = TRUE;
2021 addrclip_clear( _clipBoard_ );
2022 addrclip_add( _clipBoard_, _addressSelect_ );
2023 /* addrclip_list_show( _clipBoard_, stdout ); */
2027 * Copy from address list widget.
2029 static void addressbook_clip_copy_cb( void ) {
2030 _clipBoard_->cutFlag = FALSE;
2031 addrclip_clear( _clipBoard_ );
2032 addrclip_add( _clipBoard_, _addressSelect_ );
2033 /* addrclip_list_show( _clipBoard_, stdout ); */
2037 * Paste clipboard into address list widget.
2039 static void addressbook_clip_paste_cb( void ) {
2040 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2041 AddressObject *pobj = NULL;
2042 AddressDataSource *ds = NULL;
2043 AddressBookFile *abf = NULL;
2044 ItemFolder *folder = NULL;
2045 GList *folderGroup = NULL;
2047 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2048 if( ds == NULL ) return;
2049 if( addrindex_ds_get_readonly( ds ) ) {
2050 addressbook_ds_status_message(
2051 ds, _( "Cannot paste. Target address book is readonly." ) );
2055 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2057 if( pobj->type == ADDR_ITEM_FOLDER ) {
2058 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2060 else if( pobj->type == ADDR_ITEM_GROUP ) {
2061 addressbook_ds_status_message(
2062 ds, _( "Cannot paste into an address group." ) );
2067 /* Get an address book */
2068 abf = addressbook_get_book_file();
2069 if( abf == NULL ) return;
2071 if( _clipBoard_->cutFlag ) {
2073 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2075 /* Remove all groups and folders in clipboard from tree node */
2076 addressbook_treenode_remove_item();
2078 /* Remove all "cut" items */
2079 addrclip_delete_item( _clipBoard_ );
2081 /* Clear clipboard - cut items??? */
2082 addrclip_clear( _clipBoard_ );
2086 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2089 /* addrclip_list_show( _clipBoard_, stdout ); */
2091 /* Update tree by inserting node for each folder or group */
2092 addressbook_treenode_add_list(
2093 addrbook.treeSelected, ds, folderGroup );
2094 gtk_ctree_expand( ctree, addrbook.treeSelected );
2095 g_list_free( folderGroup );
2099 /* Display items pasted */
2100 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2101 addressbook_set_clist(
2102 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2110 * Add current treenode object to clipboard. Note that widget only allows
2111 * one entry from the tree list to be selected.
2113 static void addressbook_treenode_to_clipboard( void ) {
2114 AddressObject *obj = NULL;
2115 AddressDataSource *ds = NULL;
2116 AddrSelectItem *item;
2117 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2120 node = addrbook.treeSelected;
2121 if( node == NULL ) return;
2122 obj = gtk_ctree_node_get_row_data( ctree, node );
2123 if( obj == NULL ) return;
2125 ds = addressbook_find_datasource( node );
2126 if( ds == NULL ) return;
2129 if( obj->type == ADDR_ITEM_FOLDER ) {
2130 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2131 ItemFolder *folder = adapter->itemFolder;
2133 item = addrselect_create_node( obj );
2134 item->uid = g_strdup( ADDRITEM_ID(folder) );
2136 else if( obj->type == ADDR_ITEM_GROUP ) {
2137 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2138 ItemGroup *group = adapter->itemGroup;
2140 item = addrselect_create_node( obj );
2141 item->uid = g_strdup( ADDRITEM_ID(group) );
2143 else if( obj->type == ADDR_DATASOURCE ) {
2145 item = addrselect_create_node( obj );
2150 /* Clear existing list and add item into list */
2153 addressbook_list_select_clear();
2154 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2155 addrselect_list_add( _addressSelect_, item, cacheID );
2161 * Cut from tree widget.
2163 static void addressbook_treenode_cut_cb( void ) {
2164 _clipBoard_->cutFlag = TRUE;
2165 addressbook_treenode_to_clipboard();
2166 addrclip_clear( _clipBoard_ );
2167 addrclip_add( _clipBoard_, _addressSelect_ );
2168 /* addrclip_list_show( _clipBoard_, stdout ); */
2172 * Copy from tree widget.
2174 static void addressbook_treenode_copy_cb( void ) {
2175 _clipBoard_->cutFlag = FALSE;
2176 addressbook_treenode_to_clipboard();
2177 addrclip_clear( _clipBoard_ );
2178 addrclip_add( _clipBoard_, _addressSelect_ );
2179 /* addrclip_list_show( _clipBoard_, stdout ); */
2183 * Paste clipboard into address tree widget.
2185 static void addressbook_treenode_paste_cb( void ) {
2186 addressbook_clip_paste_cb();
2190 * Clear selected entries in clipboard.
2192 static void addressbook_list_select_clear( void ) {
2193 addrselect_list_clear( _addressSelect_ );
2197 * Add specified address item to selected address list.
2198 * \param aio Address item object.
2199 * \param ds Datasource.
2201 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2204 if( ds == NULL ) return;
2205 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2206 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2211 * Remove specified address item from selected address list.
2212 * \param aio Address item object.
2214 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2215 addrselect_list_remove( _addressSelect_, aio );
2219 * Invoke EMail compose window with addresses in selected address list.
2221 static void addressbook_mail_to_cb( void ) {
2224 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2225 listAddress = addrselect_build_list( _addressSelect_ );
2226 compose_new_with_list( NULL, listAddress );
2227 mgu_free_dlist( listAddress );
2232 static void addressbook_list_row_selected( GtkCTree *clist,
2237 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2238 AddrItemObject *aio = NULL;
2239 AddressObject *pobj = NULL;
2240 AdapterDSource *ads = NULL;
2241 AddressDataSource *ds = NULL;
2243 gtk_entry_set_text( entry, "" );
2244 addrbook.listSelected = node;
2246 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2247 if( pobj == NULL ) return;
2249 if( pobj->type == ADDR_DATASOURCE ) {
2250 ads = ADAPTER_DSOURCE(pobj);
2251 ds = ads->dataSource;
2253 else if( pobj->type != ADDR_INTERFACE ) {
2254 ds = addressbook_find_datasource( addrbook.treeSelected );
2257 aio = gtk_ctree_node_get_row_data( clist, node );
2259 /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
2260 addressbook_list_select_add( aio, ds );
2263 addressbook_list_menu_setup();
2265 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog)
2266 addressbook_edit_address(NULL, 0, NULL, FALSE);
2269 static void addressbook_list_row_unselected( GtkCTree *ctree,
2274 AddrItemObject *aio;
2276 aio = gtk_ctree_node_get_row_data( ctree, node );
2278 /* printf( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2279 addressbook_list_select_remove( aio );
2282 if (!prefs_common.addressbook_use_editaddress_dialog)
2283 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2286 /* from gdkevents.c */
2287 #define DOUBLE_CLICK_TIME 250
2289 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2290 GdkEventButton *event,
2293 static guint32 lasttime = 0;
2294 if( ! event ) return FALSE;
2296 addressbook_list_menu_setup();
2298 if( event->button == 3 ) {
2299 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2300 event->button, event->time );
2301 } else if (event->button == 1) {
2302 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2303 if (prefs_common.add_address_by_click &&
2304 addrbook.target_compose)
2305 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2307 if (prefs_common.addressbook_use_editaddress_dialog)
2308 addressbook_edit_address_cb(NULL, 0, NULL);
2312 lasttime = event->time;
2318 static gboolean addressbook_list_button_released(GtkWidget *widget,
2319 GdkEventButton *event,
2325 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2326 GdkEventButton *event,
2329 GtkCList *clist = GTK_CLIST(ctree);
2331 AddressObject *obj = NULL;
2332 AdapterDSource *ads = NULL;
2333 AddressInterface *iface = NULL;
2334 AddressDataSource *ds = NULL;
2335 gboolean canEdit = FALSE;
2336 gboolean canDelete = FALSE;
2337 gboolean canCut = FALSE;
2338 gboolean canCopy = FALSE;
2339 gboolean canPaste = FALSE;
2340 gboolean canTreeCut = FALSE;
2341 gboolean canTreeCopy = FALSE;
2342 gboolean canTreePaste = FALSE;
2343 gboolean canLookup = FALSE;
2344 GtkCTreeNode *node = NULL;
2346 if( ! event ) return FALSE;
2347 addressbook_menubar_set_sensitive( FALSE );
2349 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2350 gtkut_clist_set_focus_row(clist, row);
2351 obj = gtk_clist_get_row_data( clist, row );
2354 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2356 if( obj == NULL ) return FALSE;
2357 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2359 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2360 canTreePaste = TRUE;
2363 if (obj->type == ADDR_INTERFACE) {
2364 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2365 iface = adapter->interface;
2368 canTreeCopy = FALSE;
2369 if( iface->readOnly ) {
2370 canTreePaste = FALSE;
2373 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2374 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2376 if( iface->externalQuery ) canLookup = TRUE;
2378 if (obj->type == ADDR_DATASOURCE) {
2379 ads = ADAPTER_DSOURCE(obj);
2380 ds = ads->dataSource;
2383 iface = ds->interface;
2388 if( iface->readOnly ) {
2389 canTreePaste = FALSE;
2392 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2393 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2394 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2397 if( iface->externalQuery ) canLookup = TRUE;
2399 else if (obj->type == ADDR_ITEM_FOLDER) {
2400 ds = addressbook_find_datasource( node );
2404 iface = ds->interface;
2407 if( iface->readOnly ) {
2408 canTreePaste = FALSE;
2414 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2415 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2416 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2420 if( iface->externalQuery ) {
2421 /* Enable deletion of LDAP folder */
2426 else if (obj->type == ADDR_ITEM_GROUP) {
2427 ds = addressbook_find_datasource( node );
2430 iface = ds->interface;
2433 if( ! iface->readOnly ) {
2436 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2437 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2440 else if (obj->type == ADDR_INTERFACE) {
2441 canTreePaste = FALSE;
2445 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2447 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2448 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2452 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2453 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2454 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2455 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2456 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2458 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2459 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2460 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2461 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2462 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2463 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2465 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2466 if( event->button == 3 ) {
2467 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2468 event->button, event->time);
2474 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2475 GdkEventButton *event,
2478 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2482 static void addressbook_new_folder_cb(gpointer data, guint action,
2485 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2486 AddressObject *obj = NULL;
2487 AddressDataSource *ds = NULL;
2488 AddressBookFile *abf = NULL;
2489 ItemFolder *parentFolder = NULL;
2490 ItemFolder *folder = NULL;
2492 if( ! addrbook.treeSelected ) return;
2493 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2494 if( obj == NULL ) return;
2495 ds = addressbook_find_datasource( addrbook.treeSelected );
2496 if( ds == NULL ) return;
2498 if( obj->type == ADDR_DATASOURCE ) {
2499 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2501 else if( obj->type == ADDR_ITEM_FOLDER ) {
2502 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2508 abf = ds->rawDataSource;
2509 if( abf == NULL ) return;
2510 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2513 nn = addressbook_node_add_folder(
2514 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2515 gtk_ctree_expand( ctree, addrbook.treeSelected );
2516 if( addrbook.treeSelected == addrbook.opened )
2517 addressbook_set_clist(obj, TRUE);
2522 static void addressbook_new_group_cb(gpointer data, guint action,
2525 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2526 AddressObject *obj = NULL;
2527 AddressDataSource *ds = NULL;
2528 AddressBookFile *abf = NULL;
2529 ItemFolder *parentFolder = NULL;
2530 ItemGroup *group = NULL;
2532 if( ! addrbook.treeSelected ) return;
2533 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2534 if( obj == NULL ) return;
2535 ds = addressbook_find_datasource( addrbook.treeSelected );
2536 if( ds == NULL ) return;
2538 if( obj->type == ADDR_DATASOURCE ) {
2539 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2541 else if( obj->type == ADDR_ITEM_FOLDER ) {
2542 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2548 abf = ds->rawDataSource;
2549 if( abf == NULL ) return;
2550 group = addressbook_edit_group( abf, parentFolder, NULL );
2553 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2554 gtk_ctree_expand( ctree, addrbook.treeSelected );
2555 if( addrbook.treeSelected == addrbook.opened )
2556 addressbook_set_clist(obj, TRUE);
2561 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2563 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2566 GdkPixmap *pix_cl, *pix_op;
2567 GdkBitmap *mask_cl, *mask_op;
2568 gboolean is_leaf, expanded;
2570 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2571 &pix_cl, &mask_cl, &pix_op, &mask_op,
2572 &is_leaf, &expanded);
2573 gtk_sctree_set_node_info(ctree, node, name, spacing,
2574 pix_cl, mask_cl, pix_op, mask_op,
2580 * \param obj Address object to edit.
2581 * \param node Node in tree.
2582 * \return New name of data source.
2584 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2585 gchar *newName = NULL;
2586 AddressDataSource *ds = NULL;
2587 AddressInterface *iface = NULL;
2588 AdapterDSource *ads = NULL;
2590 ds = addressbook_find_datasource( node );
2591 if( ds == NULL ) return NULL;
2592 iface = ds->interface;
2593 if( ! iface->haveLibrary ) return NULL;
2595 /* Read data from data source */
2596 if( addrindex_ds_get_modify_flag( ds ) ) {
2597 addrindex_ds_read_data( ds );
2600 if( ! addrindex_ds_get_read_flag( ds ) ) {
2601 addrindex_ds_read_data( ds );
2605 ads = ADAPTER_DSOURCE(obj);
2606 if( ads->subType == ADDR_BOOK ) {
2607 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2609 else if( ads->subType == ADDR_VCARD ) {
2610 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2613 else if( ads->subType == ADDR_JPILOT ) {
2614 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2618 else if( ads->subType == ADDR_LDAP ) {
2619 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2625 newName = obj->name;
2630 * Edit an object that is in the address tree area.
2632 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2635 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2637 AddressDataSource *ds = NULL;
2638 AddressBookFile *abf = NULL;
2639 GtkCTreeNode *node = NULL, *parentNode = NULL;
2642 if( ! addrbook.treeSelected ) return;
2643 node = addrbook.treeSelected;
2644 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2645 obj = gtk_ctree_node_get_row_data( ctree, node );
2646 if( obj == NULL ) return;
2647 parentNode = GTK_CTREE_ROW(node)->parent;
2649 ds = addressbook_find_datasource( node );
2650 if( ds == NULL ) return;
2652 if( obj->type == ADDR_DATASOURCE ) {
2653 name = addressbook_edit_datasource( obj, node );
2654 if( name == NULL ) return;
2657 abf = ds->rawDataSource;
2658 if( abf == NULL ) return;
2659 if( obj->type == ADDR_ITEM_FOLDER ) {
2660 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2661 ItemFolder *item = adapter->itemFolder;
2662 ItemFolder *parentFolder = NULL;
2663 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2664 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2665 name = ADDRITEM_NAME(item);
2667 else if( obj->type == ADDR_ITEM_GROUP ) {
2668 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2669 ItemGroup *item = adapter->itemGroup;
2670 ItemFolder *parentFolder = NULL;
2671 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2672 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2673 name = ADDRITEM_NAME(item);
2676 if( name && parentNode ) {
2677 /* Update node in tree view */
2678 addressbook_change_node_name( node, name );
2679 gtk_sctree_sort_node(ctree, parentNode);
2680 gtk_ctree_expand( ctree, node );
2681 gtk_sctree_select( GTK_SCTREE( ctree), node );
2688 ADDRTREE_DEL_FOLDER_ONLY,
2689 ADDRTREE_DEL_FOLDER_ADDR
2693 * Delete an item from the tree widget.
2694 * \param data Data passed in.
2695 * \param action Action.
2696 * \param widget Widget issuing callback.
2698 static void addressbook_treenode_delete_cb(
2699 gpointer data, guint action, GtkWidget *widget )
2701 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2702 GtkCTreeNode *node = NULL;
2706 AddrBookBase *adbase;
2707 AddressCache *cache;
2708 AdapterDSource *ads = NULL;
2709 AddressInterface *iface = NULL;
2710 AddressDataSource *ds = NULL;
2711 gboolean remFlag = FALSE;
2712 TreeItemDelType delType;
2714 if( ! addrbook.treeSelected ) return;
2715 node = addrbook.treeSelected;
2716 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2718 obj = gtk_ctree_node_get_row_data( ctree, node );
2719 g_return_if_fail(obj != NULL);
2721 if( obj->type == ADDR_DATASOURCE ) {
2722 ads = ADAPTER_DSOURCE(obj);
2723 if( ads == NULL ) return;
2724 ds = ads->dataSource;
2725 if( ds == NULL ) return;
2728 /* Must be folder or something else */
2729 ds = addressbook_find_datasource( node );
2730 if( ds == NULL ) return;
2732 /* Only allow deletion from non-readOnly */
2733 iface = ds->interface;
2734 if( iface->readOnly ) {
2735 /* Allow deletion of query results */
2736 if( ! iface->externalQuery ) return;
2740 /* Confirm deletion */
2741 delType = ADDRTREE_DEL_NONE;
2742 if( obj->type == ADDR_ITEM_FOLDER ) {
2743 if( iface->externalQuery ) {
2744 message = g_strdup_printf( _(
2745 "Do you want to delete the query " \
2746 "results and addresses in '%s' ?" ),
2748 aval = alertpanel( _("Delete"), message,
2749 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2751 if( aval == G_ALERTALTERNATE ) {
2752 delType = ADDRTREE_DEL_FOLDER_ADDR;
2756 message = g_strdup_printf
2757 ( _( "Do you want to delete '%s' ?"
2758 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2760 aval = alertpanel( _("Delete folder"), message,
2761 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2763 if( aval == G_ALERTALTERNATE ) {
2764 delType = ADDRTREE_DEL_FOLDER_ONLY;
2766 else if( aval == G_ALERTOTHER ) {
2767 delType = ADDRTREE_DEL_FOLDER_ADDR;
2771 else if( obj->type == ADDR_ITEM_GROUP ) {
2772 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2773 "The addresses it contains will not be lost."), obj->name);
2774 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2775 "+" GTK_STOCK_DELETE, NULL);
2777 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2779 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2780 "The addresses it contains will be lost."), obj->name);
2781 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2782 "+" GTK_STOCK_DELETE, NULL);
2784 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2786 if( delType == ADDRTREE_DEL_NONE ) return;
2788 /* Proceed with deletion */
2789 if( obj->type == ADDR_DATASOURCE ) {
2790 /* Remove node from tree */
2791 gtk_ctree_remove_node( ctree, node );
2793 /* Remove data source. */
2794 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2795 addrindex_free_datasource( ds );
2800 /* Get reference to cache */
2801 adbase = ( AddrBookBase * ) ds->rawDataSource;
2802 if( adbase == NULL ) return;
2803 cache = adbase->addressCache;
2805 /* Remove query results folder */
2806 if( iface->externalQuery ) {
2807 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2808 ItemFolder *folder = adapter->itemFolder;
2810 adapter->itemFolder = NULL;
2812 printf( "remove folder for ::%s::\n", obj->name );
2813 printf( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2814 printf( "-------------- remove results\n" );
2816 addrindex_remove_results( ds, folder );
2817 /* printf( "-------------- remove node\n" ); */
2818 gtk_ctree_remove_node( ctree, node );
2822 /* Code below is valid for regular address book deletion */
2823 if( obj->type == ADDR_ITEM_FOLDER ) {
2824 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2825 ItemFolder *item = adapter->itemFolder;
2827 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2828 /* Remove folder only */
2829 item = addrcache_remove_folder( cache, item );
2831 addritem_free_item_folder( item );
2832 addressbook_move_nodes_up( ctree, node );
2836 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2837 /* Remove folder and addresses */
2838 item = addrcache_remove_folder_delete( cache, item );
2840 addritem_free_item_folder( item );
2845 else if( obj->type == ADDR_ITEM_GROUP ) {
2846 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2847 ItemGroup *item = adapter->itemGroup;
2849 item = addrcache_remove_group( cache, item );
2851 addritem_free_item_group( item );
2858 gtk_ctree_remove_node(ctree, node );
2862 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2864 if( person && addrbook.treeSelected == addrbook.opened ) {
2865 person->status = ADD_ENTRY;
2866 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2867 addressbook_folder_refresh_one_person(
2868 GTK_CTREE(addrbook.clist), person );
2870 addressbook_address_list_set_focus();
2873 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2875 if( person && addrbook.treeSelected == addrbook.opened) {
2876 person->status = ADD_ENTRY;
2877 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2878 addressbook_set_clist(
2879 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2883 addressbook_address_list_set_focus();
2886 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2887 AddressObject *pobj = NULL;
2888 AddressDataSource *ds = NULL;
2889 AddressBookFile *abf = NULL;
2890 debug_print("adding address\n");
2891 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
2892 if( pobj == NULL ) {
2893 debug_print("no row data\n");
2896 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2898 debug_print("no datasource\n");
2902 abf = ds->rawDataSource;
2904 printf("no addressbook file\n");
2908 if( pobj->type == ADDR_DATASOURCE ) {
2909 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
2910 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
2912 ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE,
2913 addrbook.editaddress_vbox,
2914 addressbook_new_address_from_book_post_cb,
2916 if (abf->type == ADDR_IF_LDAP) {
2917 LdapServer *server = ds->rawDataSource;
2918 ldapsvr_set_modified(server, TRUE);
2919 ldapsvr_update_book(server, NULL);
2920 if (server->retVal != LDAPRC_SUCCESS) {
2921 alertpanel( _("Add address(es)"),
2922 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
2923 GTK_STOCK_CLOSE, NULL, NULL );
2927 if (prefs_common.addressbook_use_editaddress_dialog)
2928 addressbook_new_address_from_book_post_cb( person );
2931 else if( pobj->type == ADDR_ITEM_FOLDER ) {
2933 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
2934 ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE,
2935 addrbook.editaddress_vbox,
2936 addressbook_new_address_from_folder_post_cb,
2938 if (abf->type == ADDR_IF_LDAP) {
2939 LdapServer *server = ds->rawDataSource;
2940 ldapsvr_set_modified(server, TRUE);
2941 ldapsvr_update_book(server, NULL);
2942 if (server->retVal != LDAPRC_SUCCESS) {
2943 alertpanel( _("Add address(es)"),
2944 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
2945 GTK_STOCK_CLOSE, NULL, NULL );
2949 if (prefs_common.addressbook_use_editaddress_dialog)
2950 addressbook_new_address_from_folder_post_cb( person );
2952 else if( pobj->type == ADDR_ITEM_GROUP ) {
2953 /* New address in group */
2954 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
2955 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
2956 if (addrbook.treeSelected == addrbook.opened) {
2957 /* Change node name in tree. */
2958 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
2959 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2960 addressbook_set_clist(
2961 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2969 * Search for specified child group node in address index tree.
2970 * \param parent Parent node.
2971 * \param group Group to find.
2973 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
2974 GtkCTreeNode *node = NULL;
2975 GtkCTreeRow *currRow;
2977 currRow = GTK_CTREE_ROW( parent );
2979 node = currRow->children;
2983 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2984 if( obj->type == ADDR_ITEM_GROUP ) {
2985 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
2986 if( g == group ) return node;
2988 currRow = GTK_CTREE_ROW(node);
2989 node = currRow->sibling;
2995 static AddressBookFile *addressbook_get_book_file() {
2996 AddressBookFile *abf = NULL;
2997 AddressDataSource *ds = NULL;
2999 ds = addressbook_find_datasource( addrbook.treeSelected );
3000 if( ds == NULL ) return NULL;
3001 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3005 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3009 /* Remove existing folders and groups */
3010 row = GTK_CTREE_ROW( parent );
3012 while( (node = row->children) ) {
3013 gtk_ctree_remove_node( ctree, node );
3018 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3019 GtkCTreeNode *parent, *child;
3020 GtkCTreeRow *currRow;
3021 currRow = GTK_CTREE_ROW( node );
3023 parent = currRow->parent;
3024 while( (child = currRow->children) ) {
3025 gtk_ctree_move( ctree, child, parent, node );
3027 gtk_sctree_sort_node( ctree, parent );
3031 static void addressbook_edit_address_post_cb( ItemPerson *person )
3035 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3036 invalidate_address_completion();
3038 addressbook_address_list_set_focus();
3041 void addressbook_address_list_set_focus( void )
3043 if (!prefs_common.addressbook_use_editaddress_dialog) {
3044 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3045 addressbook_list_menu_setup();
3049 void addressbook_address_list_disable_some_actions(void)
3051 /* disable address copy/pasting when editing contact's detail (embedded form) */
3052 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3053 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3054 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3056 /* we're already editing contact's detail here */
3057 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", FALSE );
3058 gtk_widget_set_sensitive( addrbook.edit_btn, FALSE );
3061 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3062 addressbook_edit_address(data, action, widget, TRUE);
3065 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3066 gboolean force_focus ) {
3067 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3069 AddressObject *obj = NULL, *pobj = NULL;
3070 AddressDataSource *ds = NULL;
3071 GtkCTreeNode *node = NULL, *parentNode = NULL;
3073 AddressBookFile *abf = NULL;
3075 if( addrbook.listSelected == NULL ) return;
3076 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3077 g_return_if_fail(obj != NULL);
3079 ctree = GTK_CTREE( addrbook.ctree );
3080 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3081 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3083 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3084 if( ds == NULL ) return;
3086 abf = addressbook_get_book_file();
3088 if( obj->type == ADDR_ITEM_EMAIL ) {
3089 ItemEMail *email = ( ItemEMail * ) obj;
3090 if( email == NULL ) return;
3091 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3092 /* Edit parent group */
3093 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3094 ItemGroup *itemGrp = adapter->itemGroup;
3095 if( abf == NULL ) return;
3096 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3097 name = ADDRITEM_NAME(itemGrp);
3098 node = addrbook.treeSelected;
3099 parentNode = GTK_CTREE_ROW(node)->parent;
3102 /* Edit person - email page */
3104 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3105 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3106 addressbook_edit_address_post_cb,
3107 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3109 if (abf->type == ADDR_IF_LDAP) {
3110 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3111 person->status = UPDATE_ENTRY;
3113 if (prefs_common.addressbook_use_editaddress_dialog)
3114 addressbook_edit_address_post_cb( person );
3119 else if( obj->type == ADDR_ITEM_PERSON ) {
3120 /* Edit person - basic page */
3121 ItemPerson *person = ( ItemPerson * ) obj;
3122 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3123 addressbook_edit_address_post_cb,
3124 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3126 if (abf->type == ADDR_IF_LDAP) {
3127 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3128 person->status = UPDATE_ENTRY;
3130 if (prefs_common.addressbook_use_editaddress_dialog)
3131 addressbook_edit_address_post_cb( person );
3135 else if( obj->type == ADDR_ITEM_GROUP ) {
3136 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3137 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3138 parentNode = addrbook.treeSelected;
3139 node = addressbook_find_group_node( parentNode, itemGrp );
3140 name = ADDRITEM_NAME(itemGrp);
3141 invalidate_address_completion();
3147 /* Update tree node with node name */
3148 if( node == NULL ) return;
3149 addressbook_change_node_name( node, name );
3150 gtk_sctree_sort_node( ctree, parentNode );
3151 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3152 addressbook_set_clist(
3153 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3158 static void addressbook_delete_address_cb(gpointer data, guint action,
3161 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3162 addressbook_del_clicked(NULL, NULL);
3163 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3166 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3168 addressbook_close();
3171 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3172 addressbook_export_to_file();
3175 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3177 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3178 if( person ) addritem_person_set_opened( person, TRUE );
3182 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3184 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3185 if( person ) addritem_person_set_opened( person, FALSE );
3189 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3191 gchar *eMailAlias = ADDRITEM_NAME(email);
3192 if( eMailAlias && *eMailAlias != '\0' ) {
3194 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3197 str = g_strdup( eMailAlias );
3203 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3204 GList *items = itemGroup->listEMail;
3205 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3206 for( ; items != NULL; items = g_list_next( items ) ) {
3207 GtkCTreeNode *nodeEMail = NULL;
3208 gchar *text[N_LIST_COLS];
3209 ItemEMail *email = items->data;
3213 if( ! email ) continue;
3215 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3216 str = addressbook_format_item_clist( person, email );
3218 text[COL_NAME] = str;
3221 text[COL_NAME] = ADDRITEM_NAME(person);
3223 text[COL_ADDRESS] = email->address;
3224 text[COL_REMARKS] = email->remarks;
3225 nodeEMail = gtk_sctree_insert_node(
3227 text, FOLDER_SPACING,
3228 atci->iconXpm, atci->maskXpm,
3229 atci->iconXpmOpen, atci->maskXpmOpen,
3231 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3237 static void addressbook_folder_load_one_person(
3238 GtkCTree *clist, ItemPerson *person,
3239 AddressTypeControlItem *atci,
3240 AddressTypeControlItem *atciMail )
3242 GtkCTreeNode *nodePerson = NULL;
3243 GtkCTreeNode *nodeEMail = NULL;
3244 gchar *text[N_LIST_COLS];
3245 gboolean flgFirst = TRUE, haveAddr = FALSE;
3248 if( person == NULL ) return;
3250 text[COL_NAME] = "";
3251 node = person->listEMail;
3253 ItemEMail *email = node->data;
3254 gchar *eMailAddr = NULL;
3255 node = g_list_next( node );
3257 text[COL_ADDRESS] = email->address;
3258 text[COL_REMARKS] = email->remarks;
3259 eMailAddr = ADDRITEM_NAME(email);
3260 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3262 /* First email belongs with person */
3263 gchar *str = addressbook_format_item_clist( person, email );
3265 text[COL_NAME] = str;
3267 else if( person->nickName ) {
3268 text[COL_NAME] = person->nickName;
3271 text[COL_NAME] = ADDRITEM_NAME(person);
3273 nodePerson = gtk_sctree_insert_node(
3275 text, FOLDER_SPACING,
3276 atci->iconXpm, atci->maskXpm,
3277 atci->iconXpmOpen, atci->maskXpmOpen,
3278 FALSE, person->isOpened );
3281 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3284 /* Subsequent email is a child node of person */
3285 text[COL_NAME] = ADDRITEM_NAME(email);
3286 nodeEMail = gtk_sctree_insert_node(
3287 clist, nodePerson, NULL,
3288 text, FOLDER_SPACING,
3289 atciMail->iconXpm, atciMail->maskXpm,
3290 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3292 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3298 /* Have name without EMail */
3299 text[COL_NAME] = ADDRITEM_NAME(person);
3300 text[COL_ADDRESS] = "";
3301 text[COL_REMARKS] = "";
3302 nodePerson = gtk_sctree_insert_node(
3304 text, FOLDER_SPACING,
3305 atci->iconXpm, atci->maskXpm,
3306 atci->iconXpmOpen, atci->maskXpmOpen,
3307 FALSE, person->isOpened );
3308 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3313 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3315 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3316 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3318 if( atci == NULL ) return;
3319 if( atciMail == NULL ) return;
3321 /* Load email addresses */
3322 items = addritem_folder_get_person_list( itemFolder );
3323 for( ; items != NULL; items = g_list_next( items ) ) {
3324 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3326 /* Free up the list */
3327 mgu_clear_list( items );
3328 g_list_free( items );
3331 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3332 addrbook.listSelected = NULL;
3333 gtk_ctree_remove_node( clist, node );
3334 addressbook_menubar_set_sensitive( FALSE );
3335 addressbook_menuitem_set_sensitive(
3336 gtk_ctree_node_get_row_data(
3337 GTK_CTREE(clist), addrbook.treeSelected ),
3338 addrbook.treeSelected );
3341 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3342 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3343 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3345 if( atci == NULL ) return;
3346 if( atciMail == NULL ) return;
3347 if( person == NULL ) return;
3348 /* unload the person */
3350 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3352 addressbook_folder_remove_node( clist, node );
3353 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3354 gtk_sctree_sort_node( clist, NULL );
3355 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3357 gtk_sctree_select( GTK_SCTREE(clist), node );
3358 if (!gtk_ctree_node_is_visible( clist, node ) )
3359 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3363 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3367 if( person == NULL ) return;
3368 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3369 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3371 addressbook_folder_remove_node( clist, node );
3375 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3377 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3379 /* Load any groups */
3380 if( ! atci ) return;
3381 items = addritem_folder_get_group_list( itemFolder );
3382 for( ; items != NULL; items = g_list_next( items ) ) {
3383 GtkCTreeNode *nodeGroup = NULL;
3384 gchar *text[N_LIST_COLS];
3385 ItemGroup *group = items->data;
3386 if( group == NULL ) continue;
3387 text[COL_NAME] = ADDRITEM_NAME(group);
3388 text[COL_ADDRESS] = "";
3389 text[COL_REMARKS] = "";
3390 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3391 text, FOLDER_SPACING,
3392 atci->iconXpm, atci->maskXpm,
3393 atci->iconXpmOpen, atci->maskXpmOpen,
3395 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3396 gtk_sctree_sort_node(clist, NULL);
3398 /* Free up the list */
3399 mgu_clear_list( items );
3400 g_list_free( items );
3404 * Search ctree widget callback function.
3405 * \param pA Pointer to node.
3406 * \param pB Pointer to data item being sought.
3407 * \return Zero (0) if group found.
3409 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3412 aoA = ( AddressObject * ) pA;
3413 if( aoA->type == ADDR_ITEM_GROUP ) {
3414 ItemGroup *group, *grp;
3416 grp = ADAPTER_GROUP(aoA)->itemGroup;
3417 group = ( ItemGroup * ) pB;
3418 if( grp == group ) return 0; /* Found group */
3424 * Search ctree widget callback function.
3425 * \param pA Pointer to node.
3426 * \param pB Pointer to data item being sought.
3427 * \return Zero (0) if folder found.
3429 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3432 aoA = ( AddressObject * ) pA;
3433 if( aoA->type == ADDR_ITEM_FOLDER ) {
3434 ItemFolder *folder, *fld;
3436 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3437 folder = ( ItemFolder * ) pB;
3438 if( fld == folder ) return 0; /* Found folder */
3444 * Remove folder and group nodes from tree widget for items contained ("cut")
3447 static void addressbook_treenode_remove_item( void ) {
3449 AddrSelectItem *cutItem;
3450 AddressCache *cache;
3451 AddrItemObject *aio;
3452 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3455 node = _clipBoard_->objectList;
3457 cutItem = node->data;
3458 node = g_list_next( node );
3459 cache = addrindex_get_cache(
3460 _clipBoard_->addressIndex, cutItem->cacheID );
3461 if( cache == NULL ) continue;
3462 aio = addrcache_get_object( cache, cutItem->uid );
3465 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3468 folder = ( ItemFolder * ) aio;
3469 tn = gtk_ctree_find_by_row_data_custom(
3470 ctree, NULL, folder,
3471 addressbook_treenode_find_folder_cb );
3473 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3476 group = ( ItemGroup * ) aio;
3477 tn = gtk_ctree_find_by_row_data_custom(
3479 addressbook_treenode_find_group_cb );
3483 /* Free up adapter and remove node. */
3484 gtk_ctree_remove_node( ctree, tn );
3491 * Find parent datasource for specified tree node.
3492 * \param node Node to test.
3493 * \return Data source, or NULL if not found.
3495 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3496 AddressDataSource *ds = NULL;
3499 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3502 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3503 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3505 /* printf( "ao->type = %d\n", ao->type ); */
3506 if( ao->type == ADDR_DATASOURCE ) {
3507 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3508 /* printf( "found it\n" ); */
3509 ds = ads->dataSource;
3513 node = GTK_CTREE_ROW(node)->parent;
3519 * Load address list widget with children of specified object.
3520 * \param obj Parent object to be loaded.
3522 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3523 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3524 GtkCList *clist = GTK_CLIST(addrbook.clist);
3525 AddressDataSource *ds = NULL;
3526 AdapterDSource *ads = NULL;
3527 static AddressObject *last_obj = NULL;
3529 if (addrbook.clist == NULL) {
3532 if (obj == last_obj && !refresh)
3537 gtk_clist_clear(clist);
3541 if( obj->type == ADDR_INTERFACE ) {
3542 /* printf( "set_clist: loading datasource...\n" ); */
3543 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3547 gtk_clist_freeze(clist);
3548 gtk_clist_clear(clist);
3550 if( obj->type == ADDR_DATASOURCE ) {
3551 ads = ADAPTER_DSOURCE(obj);
3552 ds = ADAPTER_DSOURCE(obj)->dataSource;
3554 /* Load root folder */
3555 ItemFolder *rootFolder = NULL;
3556 rootFolder = addrindex_ds_get_root_folder( ds );
3557 addressbook_folder_load_person(
3558 ctreelist, addrindex_ds_get_root_folder( ds ) );
3559 addressbook_folder_load_group(
3560 ctreelist, addrindex_ds_get_root_folder( ds ) );
3564 if( obj->type == ADDR_ITEM_GROUP ) {
3566 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3567 addressbook_load_group( ctreelist, itemGroup );
3569 else if( obj->type == ADDR_ITEM_FOLDER ) {
3571 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3572 addressbook_folder_load_person( ctreelist, itemFolder );
3573 addressbook_folder_load_group( ctreelist, itemFolder );
3576 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3577 clist->focus_row = -1;
3578 gtk_clist_thaw(clist);
3582 * Call back function to free adaptor. Call back is setup by function
3583 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3584 * called when the address book tree widget node is removed by calling
3585 * function gtk_ctree_remove_node().
3587 * \param data Tree node's row data.
3589 static void addressbook_free_treenode( gpointer data ) {
3592 ao = ( AddressObject * ) data;
3593 if( ao == NULL ) return;
3594 if( ao->type == ADDR_INTERFACE ) {
3595 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3596 addrbookctl_free_interface( ai );
3598 else if( ao->type == ADDR_DATASOURCE ) {
3599 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3600 addrbookctl_free_datasource( ads );
3602 else if( ao->type == ADDR_ITEM_FOLDER ) {
3603 AdapterFolder *af = ADAPTER_FOLDER(ao);
3604 addrbookctl_free_folder( af );
3606 else if( ao->type == ADDR_ITEM_GROUP ) {
3607 AdapterGroup *ag = ADAPTER_GROUP(ao);
3608 addrbookctl_free_group( ag );
3613 * Create new adaptor for specified data source.
3615 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3616 AddressObjectType otype, gchar *name )
3618 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3619 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3620 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3621 adapter->dataSource = ds;
3622 adapter->subType = otype;
3626 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3627 ADDRESS_OBJECT_NAME(adapter) =
3628 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3632 * Load tree from address index with the initial data.
3634 static void addressbook_load_tree( void ) {
3635 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3636 GList *nodeIf, *nodeDS;
3637 AdapterInterface *adapter;
3638 AddressInterface *iface;
3639 AddressTypeControlItem *atci;
3640 AddressDataSource *ds;
3641 AdapterDSource *ads;
3642 GtkCTreeNode *node, *newNode;
3645 nodeIf = _addressInterfaceList_;
3647 adapter = nodeIf->data;
3648 node = adapter->treeNode;
3649 iface = adapter->interface;
3650 atci = adapter->atci;
3652 if( iface->useInterface ) {
3653 /* Load data sources below interface node */
3654 nodeDS = iface->listSource;
3658 name = addrindex_ds_get_name( ds );
3659 ads = addressbook_create_ds_adapter(
3660 ds, atci->objectType, name );
3661 newNode = addressbook_add_object(
3662 node, ADDRESS_OBJECT(ads) );
3663 nodeDS = g_list_next( nodeDS );
3665 gtk_ctree_expand( ctree, node );
3668 nodeIf = g_list_next( nodeIf );
3673 * Convert the old address book to new format.
3675 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3676 gboolean retVal = FALSE;
3677 gboolean errFlag = TRUE;
3680 /* Read old address book, performing conversion */
3681 debug_print( "Reading and converting old address book...\n" );
3682 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3683 addrindex_read_data( addrIndex );
3684 if( addrIndex->retVal == MGU_NO_FILE ) {
3685 /* We do not have a file - new user */
3686 debug_print( "New user... create new books...\n" );
3687 addrindex_create_new_books( addrIndex );
3688 if( addrIndex->retVal == MGU_SUCCESS ) {
3689 /* Save index file */
3690 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3691 addrindex_save_data( addrIndex );
3692 if( addrIndex->retVal == MGU_SUCCESS ) {
3697 msg = _( "New user, could not save index file." );
3701 msg = _( "New user, could not save address book files." );
3705 /* We have an old file */
3706 if( addrIndex->wasConverted ) {
3707 /* Converted successfully - save address index */
3708 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3709 addrindex_save_data( addrIndex );
3710 if( addrIndex->retVal == MGU_SUCCESS ) {
3711 msg = _( "Old address book converted successfully." );
3716 msg = _("Old address book converted,\n"
3717 "could not save new address index file." );
3721 /* File conversion failed - just create new books */
3722 debug_print( "File conversion failed... just create new books...\n" );
3723 addrindex_create_new_books( addrIndex );
3724 if( addrIndex->retVal == MGU_SUCCESS ) {
3726 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3727 addrindex_save_data( addrIndex );
3728 if( addrIndex->retVal == MGU_SUCCESS ) {
3729 msg = _("Could not convert address book,\n"
3730 "but created empty new address book files." );
3735 msg = _("Could not convert address book,\n"
3736 "could not save new address index file." );
3740 msg = _("Could not convert address book\n"
3741 "and could not create new address book files." );
3746 debug_print( "Error\n%s\n", msg );
3747 alertpanel_full(_("Addressbook conversion error"), msg,
3748 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3749 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3752 debug_print( "Warning\n%s\n", msg );
3753 alertpanel_full(_("Addressbook conversion error"), msg,
3754 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3755 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3761 void addressbook_read_file( void ) {
3762 AddressIndex *addrIndex = NULL;
3764 debug_print( "Reading address index...\n" );
3765 if( _addressIndex_ ) {
3766 debug_print( "address book already read!!!\n" );
3770 addrIndex = addrindex_create_index();
3771 addrindex_initialize();
3773 /* Use new address book index. */
3774 addrindex_set_file_path( addrIndex, get_rc_dir() );
3775 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3776 addrindex_read_data( addrIndex );
3777 if( addrIndex->retVal == MGU_NO_FILE ) {
3778 /* Conversion required */
3779 debug_print( "Converting...\n" );
3780 if( addressbook_convert( addrIndex ) ) {
3781 _addressIndex_ = addrIndex;
3784 else if( addrIndex->retVal == MGU_SUCCESS ) {
3785 _addressIndex_ = addrIndex;
3788 /* Error reading address book */
3789 debug_print( "Could not read address index.\n" );
3790 addrindex_print_index( addrIndex, stdout );
3791 alertpanel_full(_("Addressbook Error"),
3792 _("Could not read address index"),
3793 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3794 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3796 debug_print( "done.\n" );
3800 * Add object into the address index tree widget.
3801 * Enter: node Parent node.
3802 * obj Object to add.
3803 * Return: Node that was added, or NULL if object not added.
3805 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
3808 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3809 GtkCTreeNode *added;
3810 AddressObject *pobj;
3811 AddressObjectType otype;
3812 AddressTypeControlItem *atci = NULL;
3814 g_return_val_if_fail(node != NULL, NULL);
3815 g_return_val_if_fail(obj != NULL, NULL);
3817 pobj = gtk_ctree_node_get_row_data(ctree, node);
3818 g_return_val_if_fail(pobj != NULL, NULL);
3820 /* Determine object type to be displayed */
3821 if( obj->type == ADDR_DATASOURCE ) {
3822 otype = ADAPTER_DSOURCE(obj)->subType;
3828 /* Handle any special conditions. */
3830 atci = addrbookctl_lookup( otype );
3832 if( atci->showInTree ) {
3833 /* Add object to tree */
3836 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3837 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
3838 atci->treeLeaf, atci->treeExpand );
3839 gtk_ctree_node_set_row_data_full( ctree, added, obj,
3840 addressbook_free_treenode );
3844 gtk_sctree_sort_node(ctree, node);
3850 * Add group into the address index tree.
3851 * \param node Parent node.
3852 * \param ds Data source.
3853 * \param itemGroup Group to add.
3854 * \return Inserted node.
3856 static GtkCTreeNode *addressbook_node_add_group(
3857 GtkCTreeNode *node, AddressDataSource *ds,
3858 ItemGroup *itemGroup )
3860 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3861 GtkCTreeNode *newNode;
3862 AdapterGroup *adapter;
3863 AddressTypeControlItem *atci = NULL;
3866 if( ds == NULL ) return NULL;
3867 if( node == NULL || itemGroup == NULL ) return NULL;
3869 name = &itemGroup->obj.name;
3871 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3873 adapter = g_new0( AdapterGroup, 1 );
3874 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
3875 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
3876 adapter->itemGroup = itemGroup;
3878 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3879 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3880 atci->treeLeaf, atci->treeExpand );
3881 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3882 addressbook_free_treenode );
3883 gtk_sctree_sort_node( ctree, node );
3888 * Add folder into the address index tree. Only visible folders are loaded into
3889 * the address index tree. Note that the root folder is not inserted into the
3892 * \param node Parent node.
3893 * \param ds Data source.
3894 * \param itemFolder Folder to add.
3895 * \param otype Object type to display.
3896 * \return Inserted node for the folder.
3898 static GtkCTreeNode *addressbook_node_add_folder(
3899 GtkCTreeNode *node, AddressDataSource *ds,
3900 ItemFolder *itemFolder, AddressObjectType otype )
3902 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3903 GtkCTreeNode *newNode = NULL;
3904 AdapterFolder *adapter;
3905 AddressTypeControlItem *atci = NULL;
3906 GList *listItems = NULL;
3908 ItemFolder *rootFolder;
3910 /* Only visible folders */
3911 if( itemFolder->isHidden ) return NULL;
3913 if( ds == NULL ) return NULL;
3914 if( node == NULL || itemFolder == NULL ) return NULL;
3916 /* Determine object type */
3917 atci = addrbookctl_lookup( otype );
3918 if( atci == NULL ) return NULL;
3920 rootFolder = addrindex_ds_get_root_folder( ds );
3921 if( itemFolder == rootFolder ) {
3925 adapter = g_new0( AdapterFolder, 1 );
3926 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
3927 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
3928 adapter->itemFolder = itemFolder;
3930 name = ADDRITEM_NAME(itemFolder);
3931 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
3932 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3933 atci->treeLeaf, atci->treeExpand );
3935 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3936 addressbook_free_treenode );
3940 listItems = itemFolder->listFolder;
3941 while( listItems ) {
3942 ItemFolder *item = listItems->data;
3943 addressbook_node_add_folder( newNode, ds, item, otype );
3944 listItems = g_list_next( listItems );
3946 listItems = itemFolder->listGroup;
3947 while( listItems ) {
3948 ItemGroup *item = listItems->data;
3949 addressbook_node_add_group( newNode, ds, item );
3950 listItems = g_list_next( listItems );
3952 gtk_sctree_sort_node( ctree, node );
3956 void addressbook_export_to_file( void ) {
3957 if( _addressIndex_ ) {
3958 /* Save all new address book data */
3959 debug_print( "Saving address books...\n" );
3960 addrindex_save_all_books( _addressIndex_ );
3962 debug_print( "Exporting addressbook to file...\n" );
3963 addrindex_save_data( _addressIndex_ );
3964 if( _addressIndex_->retVal != MGU_SUCCESS ) {
3965 addrindex_print_index( _addressIndex_, stdout );
3968 /* Notify address completion of new data */
3969 invalidate_address_completion();
3973 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
3975 if (event && event->keyval == GDK_Return)
3976 addressbook_lup_clicked(NULL, NULL);
3981 * Comparison using cell contents (text in first column). Used for sort
3982 * address index widget.
3984 static gint addressbook_treenode_compare_func(
3985 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
3987 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
3988 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
3989 gchar *name1 = NULL, *name2 = NULL;
3990 if( cell1 ) name1 = cell1->u.text;
3991 if( cell2 ) name2 = cell2->u.text;
3992 if( ! name1 ) return ( name2 != NULL );
3993 if( ! name2 ) return -1;
3994 return g_utf8_collate( name1, name2 );
3997 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
3998 AdapterDSource *ads;
3999 AdapterInterface *adapter;
4000 GtkCTreeNode *newNode;
4002 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4003 if( adapter == NULL ) return;
4004 ads = addressbook_edit_book( _addressIndex_, NULL );
4006 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4008 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4009 addrbook.treeSelected = newNode;
4014 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4015 AdapterDSource *ads;
4016 AdapterInterface *adapter;
4017 GtkCTreeNode *newNode;
4019 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4020 if( adapter == NULL ) return;
4021 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4023 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4025 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4026 addrbook.treeSelected = newNode;
4032 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4033 AdapterDSource *ads;
4034 AdapterInterface *adapter;
4035 AddressInterface *iface;
4036 GtkCTreeNode *newNode;
4038 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4039 if( adapter == NULL ) return;
4040 iface = adapter->interface;
4041 if( ! iface->haveLibrary ) return;
4042 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4044 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4046 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4047 addrbook.treeSelected = newNode;
4054 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4055 AdapterDSource *ads;
4056 AdapterInterface *adapter;
4057 AddressInterface *iface;
4058 GtkCTreeNode *newNode;
4060 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4061 if( adapter == NULL ) return;
4062 iface = adapter->interface;
4063 if( ! iface->haveLibrary ) return;
4064 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4066 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4068 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4069 addrbook.treeSelected = newNode;
4076 * Display address search status message.
4077 * \param queryType Query type.
4078 * \param status Status/Error code.
4080 static void addressbook_search_message( gint queryType, gint sts ) {
4082 *addressbook_msgbuf = '\0';
4084 if( sts != MGU_SUCCESS ) {
4085 if( queryType == ADDRQUERY_LDAP ) {
4087 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4092 g_snprintf( addressbook_msgbuf,
4093 sizeof(addressbook_msgbuf), "%s", desc );
4094 addressbook_status_show( addressbook_msgbuf );
4097 addressbook_status_show( "" );
4102 * Refresh addressbook by forcing refresh of current selected object in
4105 static void addressbook_refresh_current( void ) {
4109 ctree = GTK_CTREE(addrbook.ctree);
4110 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4111 if( obj == NULL ) return;
4112 addressbook_set_clist( obj, TRUE );
4116 * Message that is displayed whilst a query is executing in a background
4119 static gchar *_tempMessage_ = N_( "Busy searching..." );
4122 * Address search idle function. This function is called during UI idle time
4123 * while a search is in progress.
4125 * \param data Idler data.
4127 static void addressbook_search_idle( gpointer data ) {
4131 queryID = GPOINTER_TO_INT( data );
4132 printf( "addressbook_ldap_idle... queryID=%d\n", queryID );
4137 * Search completion callback function. This removes the query from the idle
4140 * \param sender Sender of query.
4141 * \param queryID Query ID of search request.
4142 * \param status Search status.
4143 * \param data Query data.
4145 static void addressbook_search_callback_end(
4146 gpointer sender, gint queryID, gint status, gpointer data )
4150 AddrQueryObject *aqo;
4152 /* Remove idler function */
4153 ptrQID = GINT_TO_POINTER( queryID );
4155 g_idle_remove_by_data( ptrQID );
4158 /* Refresh addressbook contents */
4159 addressbook_refresh_current();
4160 req = qrymgr_find_request( queryID );
4162 aqo = ( AddrQueryObject * ) req->queryList->data;
4163 addressbook_search_message( aqo->queryType, status );
4166 /* Stop the search */
4167 addrindex_stop_search( queryID );
4171 * Label (a format string) that is used to name each folder.
4173 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
4178 * \param ds Data source to search.
4179 * \param searchTerm String to lookup.
4180 * \param pNode Parent data source node.
4182 static void addressbook_perform_search(
4183 AddressDataSource *ds, gchar *searchTerm,
4184 GtkCTreeNode *pNode )
4186 AddrBookBase *adbase;
4187 AddressCache *cache;
4190 GtkCTreeNode *nNode;
4194 AddressObjectType aoType = ADDR_NONE;
4197 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4199 if( ds->type == ADDR_IF_LDAP ) {
4201 aoType = ADDR_LDAP_QUERY;
4208 /* Get reference to address cache */
4209 adbase = ( AddrBookBase * ) ds->rawDataSource;
4210 cache = adbase->addressCache;
4212 /* Create a folder for the search results */
4213 folder = addrcache_add_new_folder( cache, NULL );
4214 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4215 addritem_folder_set_name( folder, name );
4216 addritem_folder_set_remarks( folder, "" );
4219 /* Now let's see the folder */
4220 ctree = GTK_CTREE(addrbook.ctree);
4221 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
4222 gtk_ctree_expand( ctree, pNode );
4224 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
4225 addrbook.treeSelected = nNode;
4228 /* Setup the search */
4229 queryID = addrindex_setup_explicit_search(
4230 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4231 if( queryID == 0 ) return;
4233 /* Set up idler function */
4234 idleID = g_idle_add(
4235 ( GtkFunction ) addressbook_search_idle,
4236 GINT_TO_POINTER( queryID ) );
4238 /* Start search, sit back and wait for something to happen */
4239 addrindex_start_search( queryID );
4241 addressbook_status_show( _tempMessage_ );
4245 * Lookup button handler. Address search is only performed against
4246 * address interfaces for external queries.
4248 * \param button Lookup button widget.
4249 * \param data Data object.
4251 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4254 AddressDataSource *ds;
4255 AddressInterface *iface;
4257 GtkCTreeNode *node, *parentNode;
4259 node = addrbook.treeSelected;
4260 if( ! node ) return;
4261 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4263 ctree = GTK_CTREE(addrbook.ctree);
4264 obj = gtk_ctree_node_get_row_data( ctree, node );
4265 if( obj == NULL ) return;
4267 ds = addressbook_find_datasource( node );
4268 if( ds == NULL ) return;
4270 /* We must have a datasource that is an external interface */
4271 iface = ds->interface;
4272 if( ! iface->haveLibrary ) return;
4273 if( ! iface->externalQuery ) return;
4276 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4277 g_strchomp( searchTerm );
4279 if( obj->type == ADDR_ITEM_FOLDER ) {
4280 parentNode = GTK_CTREE_ROW(node)->parent;
4285 addressbook_perform_search( ds, searchTerm, parentNode );
4287 gtk_widget_grab_focus( addrbook.entry );
4289 g_free( searchTerm );
4292 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4293 addressbook_close();
4298 * Browse address entry for highlighted entry.
4300 static void addressbook_browse_entry_cb(void)
4302 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4304 AddressDataSource *ds;
4305 AddressInterface *iface;
4309 if(addrbook.listSelected == NULL)
4312 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4316 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4320 iface = ds->interface;
4321 if(! iface->haveLibrary )
4325 if (obj->type == ADDR_ITEM_EMAIL) {
4326 email = ( ItemEMail * ) obj;
4330 person = (ItemPerson *) ADDRITEM_PARENT(email);
4332 else if (obj->type == ADDR_ITEM_PERSON) {
4333 person = (ItemPerson *) obj;
4340 if( iface->type == ADDR_IF_LDAP ) {
4341 browseldap_entry(ds, person->externalID);
4346 /* **********************************************************************
4347 * Build lookup tables.
4348 * ***********************************************************************
4352 * Remap object types.
4353 * Enter: abType AddressObjectType (used in tree node).
4354 * Return: ItemObjectType (used in address cache data).
4356 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4357 ItemObjectType ioType;
4360 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4361 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4362 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4363 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4364 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4365 default: ioType = ITEMTYPE_NONE; break;
4371 * Build table that controls the rendering of object types.
4373 static void addrbookctl_build_map( GtkWidget *window ) {
4374 AddressTypeControlItem *atci;
4377 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4378 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4379 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4380 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4381 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4382 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4383 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4384 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4385 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4386 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4388 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4389 _addressBookTypeList_ = NULL;
4392 atci = g_new0( AddressTypeControlItem, 1 );
4393 atci->objectType = ADDR_INTERFACE;
4394 atci->interfaceType = ADDR_IF_NONE;
4395 atci->showInTree = TRUE;
4396 atci->treeExpand = TRUE;
4397 atci->treeLeaf = FALSE;
4398 atci->displayName = _( "Interface" );
4399 atci->iconXpm = folderxpm;
4400 atci->maskXpm = folderxpmmask;
4401 atci->iconXpmOpen = folderopenxpm;
4402 atci->maskXpmOpen = folderopenxpmmask;
4403 atci->menuCommand = NULL;
4404 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4405 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4408 atci = g_new0( AddressTypeControlItem, 1 );
4409 atci->objectType = ADDR_BOOK;
4410 atci->interfaceType = ADDR_IF_BOOK;
4411 atci->showInTree = TRUE;
4412 atci->treeExpand = TRUE;
4413 atci->treeLeaf = FALSE;
4414 atci->displayName = _( "Address Book" );
4415 atci->iconXpm = bookxpm;
4416 atci->maskXpm = bookxpmmask;
4417 atci->iconXpmOpen = bookxpm;
4418 atci->maskXpmOpen = bookxpmmask;
4419 atci->menuCommand = "/Book/New Book";
4420 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4421 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4424 atci = g_new0( AddressTypeControlItem, 1 );
4425 atci->objectType = ADDR_ITEM_PERSON;
4426 atci->interfaceType = ADDR_IF_NONE;
4427 atci->showInTree = FALSE;
4428 atci->treeExpand = FALSE;
4429 atci->treeLeaf = FALSE;
4430 atci->displayName = _( "Person" );
4431 atci->iconXpm = NULL;
4432 atci->maskXpm = NULL;
4433 atci->iconXpmOpen = NULL;
4434 atci->maskXpmOpen = NULL;
4435 atci->menuCommand = NULL;
4436 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4437 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4440 atci = g_new0( AddressTypeControlItem, 1 );
4441 atci->objectType = ADDR_ITEM_EMAIL;
4442 atci->interfaceType = ADDR_IF_NONE;
4443 atci->showInTree = FALSE;
4444 atci->treeExpand = FALSE;
4445 atci->treeLeaf = TRUE;
4446 atci->displayName = _( "EMail Address" );
4447 atci->iconXpm = addressxpm;
4448 atci->maskXpm = addressxpmmask;
4449 atci->iconXpmOpen = addressxpm;
4450 atci->maskXpmOpen = addressxpmmask;
4451 atci->menuCommand = NULL;
4452 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4453 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4456 atci = g_new0( AddressTypeControlItem, 1 );
4457 atci->objectType = ADDR_ITEM_GROUP;
4458 atci->interfaceType = ADDR_IF_BOOK;
4459 atci->showInTree = TRUE;
4460 atci->treeExpand = FALSE;
4461 atci->treeLeaf = FALSE;
4462 atci->displayName = _( "Group" );
4463 atci->iconXpm = groupxpm;
4464 atci->maskXpm = groupxpmmask;
4465 atci->iconXpmOpen = groupxpm;
4466 atci->maskXpmOpen = groupxpmmask;
4467 atci->menuCommand = NULL;
4468 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4469 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4472 atci = g_new0( AddressTypeControlItem, 1 );
4473 atci->objectType = ADDR_ITEM_FOLDER;
4474 atci->interfaceType = ADDR_IF_BOOK;
4475 atci->showInTree = TRUE;
4476 atci->treeExpand = FALSE;
4477 atci->treeLeaf = FALSE;
4478 atci->displayName = _( "Folder" );
4479 atci->iconXpm = folderxpm;
4480 atci->maskXpm = folderxpmmask;
4481 atci->iconXpmOpen = folderopenxpm;
4482 atci->maskXpmOpen = folderopenxpmmask;
4483 atci->menuCommand = NULL;
4484 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4485 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4488 atci = g_new0( AddressTypeControlItem, 1 );
4489 atci->objectType = ADDR_VCARD;
4490 atci->interfaceType = ADDR_IF_VCARD;
4491 atci->showInTree = TRUE;
4492 atci->treeExpand = TRUE;
4493 atci->treeLeaf = TRUE;
4494 atci->displayName = _( "vCard" );
4495 atci->iconXpm = vcardxpm;
4496 atci->maskXpm = vcardxpmmask;
4497 atci->iconXpmOpen = vcardxpm;
4498 atci->maskXpmOpen = vcardxpmmask;
4499 atci->menuCommand = "/Book/New vCard";
4500 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4501 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4504 atci = g_new0( AddressTypeControlItem, 1 );
4505 atci->objectType = ADDR_JPILOT;
4506 atci->interfaceType = ADDR_IF_JPILOT;
4507 atci->showInTree = TRUE;
4508 atci->treeExpand = TRUE;
4509 atci->treeLeaf = FALSE;
4510 atci->displayName = _( "JPilot" );
4511 atci->iconXpm = jpilotxpm;
4512 atci->maskXpm = jpilotxpmmask;
4513 atci->iconXpmOpen = jpilotxpm;
4514 atci->maskXpmOpen = jpilotxpmmask;
4515 atci->menuCommand = "/Book/New JPilot";
4516 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4517 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4520 atci = g_new0( AddressTypeControlItem, 1 );
4521 atci->objectType = ADDR_CATEGORY;
4522 atci->interfaceType = ADDR_IF_JPILOT;
4523 atci->showInTree = TRUE;
4524 atci->treeExpand = TRUE;
4525 atci->treeLeaf = TRUE;
4526 atci->displayName = _( "JPilot" );
4527 atci->iconXpm = categoryxpm;
4528 atci->maskXpm = categoryxpmmask;
4529 atci->iconXpmOpen = categoryxpm;
4530 atci->maskXpmOpen = categoryxpmmask;
4531 atci->menuCommand = NULL;
4532 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4533 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4536 atci = g_new0( AddressTypeControlItem, 1 );
4537 atci->objectType = ADDR_LDAP;
4538 atci->interfaceType = ADDR_IF_LDAP;
4539 atci->showInTree = TRUE;
4540 atci->treeExpand = TRUE;
4541 atci->treeLeaf = FALSE;
4542 atci->displayName = _( "LDAP servers" );
4543 atci->iconXpm = ldapxpm;
4544 atci->maskXpm = ldapxpmmask;
4545 atci->iconXpmOpen = ldapxpm;
4546 atci->maskXpmOpen = ldapxpmmask;
4547 atci->menuCommand = "/Book/New LDAP Server";
4548 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4549 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4552 atci = g_new0( AddressTypeControlItem, 1 );
4553 atci->objectType = ADDR_LDAP_QUERY;
4554 atci->interfaceType = ADDR_IF_LDAP;
4555 atci->showInTree = TRUE;
4556 atci->treeExpand = FALSE;
4557 atci->treeLeaf = TRUE;
4558 atci->displayName = _( "LDAP Query" );
4559 atci->iconXpm = addrsearchxpm;
4560 atci->maskXpm = addrsearchxpmmask;
4561 atci->iconXpmOpen = addrsearchxpm;
4562 atci->maskXpmOpen = addrsearchxpmmask;
4563 atci->menuCommand = NULL;
4564 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4565 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4570 * Search for specified object type.
4572 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4574 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4578 * Search for specified interface type.
4580 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4581 GList *node = _addressBookTypeList_;
4583 AddressTypeControlItem *atci = node->data;
4584 if( atci->interfaceType == ifType ) return atci;
4585 node = g_list_next( node );
4590 static void addrbookctl_free_address( AddressObject *obj ) {
4591 g_free( obj->name );
4592 obj->type = ADDR_NONE;
4596 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4597 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4598 adapter->interface = NULL;
4599 adapter->interfaceType = ADDR_IF_NONE;
4600 adapter->atci = NULL;
4601 adapter->enabled = FALSE;
4602 adapter->haveLibrary = FALSE;
4603 adapter->treeNode = NULL;
4607 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4608 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4609 adapter->dataSource = NULL;
4610 adapter->subType = ADDR_NONE;
4614 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4615 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4616 adapter->itemFolder = NULL;
4620 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4621 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4622 adapter->itemGroup = NULL;
4627 * Build GUI interface list.
4629 static void addrbookctl_build_iflist( void ) {
4630 AddressTypeControlItem *atci;
4631 AdapterInterface *adapter;
4634 if( _addressIndex_ == NULL ) {
4635 _addressIndex_ = addrindex_create_index();
4636 if( _clipBoard_ == NULL ) {
4637 _clipBoard_ = addrclip_create();
4639 addrclip_set_index( _clipBoard_, _addressIndex_ );
4641 _addressInterfaceList_ = NULL;
4642 list = addrindex_get_interface_list( _addressIndex_ );
4644 AddressInterface *interface = list->data;
4645 atci = addrbookctl_lookup_iface( interface->type );
4647 adapter = g_new0( AdapterInterface, 1 );
4648 adapter->interfaceType = interface->type;
4649 adapter->atci = atci;
4650 adapter->interface = interface;
4651 adapter->treeNode = NULL;
4652 adapter->enabled = TRUE;
4653 adapter->haveLibrary = interface->haveLibrary;
4654 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4655 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4656 _addressInterfaceList_ =
4657 g_list_append( _addressInterfaceList_, adapter );
4659 list = g_list_next( list );
4664 * Find GUI interface type specified interface type.
4665 * \param ifType Interface type.
4666 * \return Interface item, or NULL if not found.
4668 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4669 GList *node = _addressInterfaceList_;
4671 AdapterInterface *adapter = node->data;
4672 if( adapter->interfaceType == ifType ) return adapter;
4673 node = g_list_next( node );
4679 * Build interface list selection.
4681 static void addrbookctl_build_ifselect( void ) {
4682 GList *newList = NULL;
4687 gchar *endptr = NULL;
4689 AdapterInterface *adapter;
4691 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4694 splitStr = g_strsplit( selectStr, ",", -1 );
4695 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4697 /* printf( "%d : %s\n", i, splitStr[i] ); */
4698 ifType = strtol( splitStr[i], &endptr, 10 );
4701 if( strcmp( endptr, "/n" ) == 0 ) {
4705 /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4706 adapter = addrbookctl_find_interface( ifType );
4708 newList = g_list_append( newList, adapter );
4715 /* printf( "i=%d\n", i ); */
4716 g_strfreev( splitStr );
4717 g_free( selectStr );
4719 /* Replace existing list */
4720 mgu_clear_list( _addressIFaceSelection_ );
4721 g_list_free( _addressIFaceSelection_ );
4722 _addressIFaceSelection_ = newList;
4726 /* ***********************************************************************
4727 * Add sender to address book.
4728 * ***********************************************************************
4732 * This function is used by the Add sender to address book function.
4734 gboolean addressbook_add_contact(
4735 const gchar *name, const gchar *address, const gchar *remarks )
4737 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4738 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4739 debug_print( "addressbook_add_contact - added\n" );
4740 addressbook_refresh();
4745 /* ***********************************************************************
4746 * Book/folder selection.
4747 * ***********************************************************************
4751 * This function is used by the matcher dialog to select a book/folder.
4753 gboolean addressbook_folder_selection( gchar **folderpath )
4755 AddressBookFile *book = NULL;
4756 ItemFolder *folder = NULL;
4759 g_return_val_if_fail( folderpath != NULL, FALSE);
4763 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4765 if ( folder != NULL) {
4767 gchar *oldtmp = NULL;
4768 AddrItemObject *obj = NULL;
4770 /* walk thru folder->parent to build the full folder path */
4771 /* TODO: wwp: optimize this */
4773 tmp = g_strdup(obj->uid);
4774 while ( obj->parent ) {
4776 if ( obj->name != NULL ) {
4777 oldtmp = g_strdup(tmp);
4779 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4783 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4786 *folderpath = g_strdup_printf("%s", book->fileName);
4788 debug_print( "addressbook_foldersel: %s\n", *folderpath);
4789 return (*folderpath != NULL);
4794 /* ***********************************************************************
4795 * Book/folder checking.
4796 * ***********************************************************************
4799 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
4801 FolderInfo *fi = g_new0( FolderInfo, 1 );
4803 fi->folder = folder;
4807 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
4808 FolderInfo *fiParent, FolderPathMatch *match )
4814 FolderPathMatch *nextmatch = NULL;
4819 list = parentFolder->listFolder;
4821 folder = list->data;
4822 fName = g_strdup( ADDRITEM_NAME(folder) );
4824 /* match folder name, match pointer will be set to NULL if next recursive call
4825 doesn't need to match subfolder name */
4826 if ( match != NULL &&
4827 match->matched == FALSE ) {
4828 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
4829 /* folder name matches, prepare next subfolder match */
4830 debug_print("matched folder name '%s'\n", fName);
4832 if ( match->folder_path[match->index] == NULL ) {
4833 /* we've matched all elements */
4834 match->matched = TRUE;
4835 match->folder = folder;
4836 debug_print("book/folder path matched!\n");
4838 /* keep on matching */
4846 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
4847 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
4849 list = g_list_next( list );
4854 * This function is used by to check if a matcher book/folder path corresponds to an
4855 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
4856 Caution: returned book and folder pointers can be NULL even when returning TRUE:
4857 if book AND folder are NULL this means that folderpath was empty or Any.
4858 If folderpath is a simple book name (without folder), book will not be NULL and folder
4859 will be NULL. It's not expected to return book as NULL and folder as non NULL.
4862 gboolean addressbook_peek_folder_exists( gchar *folderpath,
4863 AddressDataSource **book,
4864 ItemFolder **folder )
4866 AddressDataSource *ds;
4867 GList *list, *nodeDS;
4868 ItemFolder *rootFolder;
4869 AddressBookFile *abf;
4871 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
4878 if ( folderpath == NULL )
4881 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
4884 /* split the folder path we've received, we'll try to match this path, subpath by
4885 subpath against the book/folder structure in order */
4886 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
4887 if (!folder_path_match.folder_path)
4890 list = addrindex_get_interface_list( _addressIndex_ );
4891 while ( list && !folder_path_match.matched ) {
4892 AddressInterface *interface = list->data;
4893 if ( interface && interface->type == ADDR_IF_BOOK ) {
4894 nodeDS = interface->listSource;
4895 while ( nodeDS && !folder_path_match.matched ) {
4898 /* Read address book */
4899 if( ! addrindex_ds_get_read_flag( ds ) ) {
4900 addrindex_ds_read_data( ds );
4903 /* Add node for address book */
4904 abf = ds->rawDataSource;
4906 /* match book name */
4907 if ( abf && abf->fileName &&
4908 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
4910 debug_print("matched book name '%s'\n", abf->fileName);
4911 folder_path_match.book = ds;
4913 if ( folder_path_match.folder_path[1] == NULL ) {
4914 /* no folder part to match */
4916 folder_path_match.matched = TRUE;
4917 folder_path_match.folder = NULL;
4918 debug_print("book path matched!\n");
4921 /* match folder part */
4923 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
4924 rootFolder = addrindex_ds_get_root_folder( ds );
4926 /* prepare for recursive call */
4927 folder_path_match.index = 1;
4928 /* this call will set folder_path_match.matched and folder_path_match.folder */
4929 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
4934 nodeDS = g_list_next( nodeDS );
4937 list = g_list_next( list );
4940 g_strfreev( folder_path_match.folder_path );
4943 *book = folder_path_match.book;
4945 *folder = folder_path_match.folder;
4946 return folder_path_match.matched;
4950 /* **********************************************************************
4952 * ***********************************************************************
4958 static void addressbook_import_ldif_cb( void ) {
4959 AddressDataSource *ds = NULL;
4960 AdapterDSource *ads = NULL;
4961 AddressBookFile *abf = NULL;
4962 AdapterInterface *adapter;
4963 GtkCTreeNode *newNode;
4965 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4967 if( adapter->treeNode ) {
4968 abf = addressbook_imp_ldif( _addressIndex_ );
4970 ds = addrindex_index_add_datasource(
4971 _addressIndex_, ADDR_IF_BOOK, abf );
4972 ads = addressbook_create_ds_adapter(
4973 ds, ADDR_BOOK, NULL );
4974 addressbook_ads_set_name(
4975 ads, addrbook_get_name( abf ) );
4976 newNode = addressbook_add_object(
4978 ADDRESS_OBJECT(ads) );
4980 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4982 addrbook.treeSelected = newNode;
4985 /* Notify address completion */
4986 invalidate_address_completion();
4995 static void addressbook_import_mutt_cb( void ) {
4996 AddressDataSource *ds = NULL;
4997 AdapterDSource *ads = NULL;
4998 AddressBookFile *abf = NULL;
4999 AdapterInterface *adapter;
5000 GtkCTreeNode *newNode;
5002 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5004 if( adapter->treeNode ) {
5005 abf = addressbook_imp_mutt( _addressIndex_ );
5007 ds = addrindex_index_add_datasource(
5008 _addressIndex_, ADDR_IF_BOOK, abf );
5009 ads = addressbook_create_ds_adapter(
5010 ds, ADDR_BOOK, NULL );
5011 addressbook_ads_set_name(
5012 ads, addrbook_get_name( abf ) );
5013 newNode = addressbook_add_object(
5015 ADDRESS_OBJECT(ads) );
5017 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5019 addrbook.treeSelected = newNode;
5022 /* Notify address completion */
5023 invalidate_address_completion();
5032 static void addressbook_import_pine_cb( void ) {
5033 AddressDataSource *ds = NULL;
5034 AdapterDSource *ads = NULL;
5035 AddressBookFile *abf = NULL;
5036 AdapterInterface *adapter;
5037 GtkCTreeNode *newNode;
5039 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5041 if( adapter->treeNode ) {
5042 abf = addressbook_imp_pine( _addressIndex_ );
5044 ds = addrindex_index_add_datasource(
5045 _addressIndex_, ADDR_IF_BOOK, abf );
5046 ads = addressbook_create_ds_adapter(
5047 ds, ADDR_BOOK, NULL );
5048 addressbook_ads_set_name(
5049 ads, addrbook_get_name( abf ) );
5050 newNode = addressbook_add_object(
5052 ADDRESS_OBJECT(ads) );
5054 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5056 addrbook.treeSelected = newNode;
5059 /* Notify address completion */
5060 invalidate_address_completion();
5067 * Harvest addresses.
5068 * \param folderItem Folder to import.
5069 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5070 * \param msgList List of message numbers, or NULL to process folder.
5072 void addressbook_harvest(
5073 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5075 AddressDataSource *ds = NULL;
5076 AdapterDSource *ads = NULL;
5077 AddressBookFile *abf = NULL;
5078 AdapterInterface *adapter;
5079 GtkCTreeNode *newNode;
5081 abf = addrgather_dlg_execute(
5082 folderItem, _addressIndex_, sourceInd, msgList );
5084 ds = addrindex_index_add_datasource(
5085 _addressIndex_, ADDR_IF_BOOK, abf );
5087 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5089 if( adapter->treeNode ) {
5090 ads = addressbook_create_ds_adapter(
5091 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5092 newNode = addressbook_add_object(
5094 ADDRESS_OBJECT(ads) );
5098 /* Notify address completion */
5099 invalidate_address_completion();
5106 static void addressbook_export_html_cb( void ) {
5107 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5109 AddressDataSource *ds = NULL;
5110 AddrBookBase *adbase;
5111 AddressCache *cache;
5112 GtkCTreeNode *node = NULL;
5114 if( ! addrbook.treeSelected ) return;
5115 node = addrbook.treeSelected;
5116 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5117 obj = gtk_ctree_node_get_row_data( ctree, node );
5118 if( obj == NULL ) return;
5120 ds = addressbook_find_datasource( node );
5121 if( ds == NULL ) return;
5122 adbase = ( AddrBookBase * ) ds->rawDataSource;
5123 cache = adbase->addressCache;
5124 addressbook_exp_html( cache );
5130 static void addressbook_export_ldif_cb( void ) {
5131 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5133 AddressDataSource *ds = NULL;
5134 AddrBookBase *adbase;
5135 AddressCache *cache;
5136 GtkCTreeNode *node = NULL;
5138 if( ! addrbook.treeSelected ) return;
5139 node = addrbook.treeSelected;
5140 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5141 obj = gtk_ctree_node_get_row_data( ctree, node );
5142 if( obj == NULL ) return;
5144 ds = addressbook_find_datasource( node );
5145 if( ds == NULL ) return;
5146 adbase = ( AddrBookBase * ) ds->rawDataSource;
5147 cache = adbase->addressCache;
5148 addressbook_exp_ldif( cache );
5151 static void addressbook_start_drag(GtkWidget *widget, gint button,
5155 GdkDragContext *context;
5156 if (addressbook_target_list == NULL)
5157 addressbook_target_list = gtk_target_list_new(
5158 addressbook_drag_types, 1);
5159 context = gtk_drag_begin(widget, addressbook_target_list,
5160 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5161 gtk_drag_set_icon_default(context);
5164 static void addressbook_drag_data_get(GtkWidget *widget,
5165 GdkDragContext *drag_context,
5166 GtkSelectionData *selection_data,
5171 AddrItemObject *aio = NULL;
5172 AddressObject *pobj = NULL;
5173 AdapterDSource *ads = NULL;
5174 AddressDataSource *ds = NULL;
5177 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5179 if( pobj == NULL ) return;
5181 if( pobj->type == ADDR_DATASOURCE ) {
5182 ads = ADAPTER_DSOURCE(pobj);
5183 ds = ads->dataSource;
5184 } else if (pobj->type == ADDR_ITEM_GROUP) {
5189 else if( pobj->type != ADDR_INTERFACE ) {
5190 ds = addressbook_find_datasource( addrbook.treeSelected );
5196 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5197 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5198 GTK_CTREE_NODE(cur->data));
5199 while (aio && aio->type != ADDR_ITEM_PERSON) {
5204 if (aio && aio->type == ADDR_ITEM_PERSON) {
5205 if( ds && ds->interface && ds->interface->readOnly)
5206 gtk_selection_data_set(selection_data,
5207 selection_data->target, 8,
5208 "Dummy_addr_copy", 15);
5210 gtk_selection_data_set(selection_data,
5211 selection_data->target, 8,
5212 "Dummy_addr_move", 15);
5216 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5217 GdkDragContext *context,
5224 GtkCTreeNode *node = NULL;
5225 gboolean acceptable = FALSE;
5226 gint height = addrbook.ctree->allocation.height;
5227 gint total_height = addrbook.ctree->requisition.height;
5228 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5229 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5230 gfloat vpos = pos->value;
5232 if (gtk_clist_get_selection_info
5233 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5235 if (y > height - 24 && height + vpos < total_height)
5236 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5238 if (y < 24 && y > 0)
5239 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5241 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5244 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5245 if( obj->type == ADDR_ITEM_FOLDER
5246 || obj->type == ADDR_ITEM_GROUP)
5249 AdapterDSource *ads = NULL;
5250 AddressDataSource *ds = NULL;
5251 ads = ADAPTER_DSOURCE(obj);
5252 if (ads == NULL ){ return FALSE;}
5253 ds = ads->dataSource;
5254 if (ds == NULL ) { return FALSE;}
5262 g_signal_handlers_block_by_func
5264 G_CALLBACK(addressbook_tree_selected), NULL);
5265 gtk_sctree_select( GTK_SCTREE(widget), node);
5266 g_signal_handlers_unblock_by_func
5268 G_CALLBACK(addressbook_tree_selected), NULL);
5269 gdk_drag_status(context,
5270 (context->actions == GDK_ACTION_COPY ?
5271 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5273 gdk_drag_status(context, 0, time);
5279 static void addressbook_drag_leave_cb(GtkWidget *widget,
5280 GdkDragContext *context,
5284 if (addrbook.treeSelected) {
5285 g_signal_handlers_block_by_func
5287 G_CALLBACK(addressbook_tree_selected), NULL);
5288 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5289 g_signal_handlers_unblock_by_func
5291 G_CALLBACK(addressbook_tree_selected), NULL);
5296 static void addressbook_drag_received_cb(GtkWidget *widget,
5297 GdkDragContext *drag_context,
5300 GtkSelectionData *data,
5307 GtkCTreeNode *lastopened = addrbook.opened;
5309 if (!strncmp(data->data, "Dummy_addr", 10)) {
5310 if (gtk_clist_get_selection_info
5311 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5315 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5316 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5319 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5320 if (drag_context->action == GDK_ACTION_COPY ||
5321 !strcmp(data->data, "Dummy_addr_copy"))
5322 addressbook_clip_copy_cb();
5324 addressbook_clip_cut_cb();
5325 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5326 addressbook_clip_paste_cb();
5327 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5328 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5329 gtk_drag_finish(drag_context, TRUE, TRUE, time);