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 3 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, see <http://www.gnu.org/licenses/>.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
32 #include <sys/types.h>
36 #include "addressbook.h"
37 #include "manage_window.h"
38 #include "prefs_common.h"
39 #include "alertpanel.h"
40 #include "inputdialog.h"
42 #include "stock_pixmap.h"
44 #include "prefs_gtk.h"
50 #include "addr_compl.h"
53 #include "addressitem.h"
55 #include "addrcache.h"
57 #include "addrindex.h"
58 #include "addressadd.h"
59 #include "addrduplicates.h"
60 #include "addressbook_foldersel.h"
62 #include "editvcard.h"
63 #include "editgroup.h"
64 #include "editaddress.h"
66 #include "importldif.h"
67 #include "importmutt.h"
68 #include "importpine.h"
73 #include "editjpilot.h"
78 #include "ldapserver.h"
80 #include "ldapupdate.h"
82 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
85 #include "addrquery.h"
86 #include "addrselect.h"
88 #include "addrgather.h"
89 #include "adbookbase.h"
90 #include "exphtmldlg.h"
91 #include "expldifdlg.h"
92 #include "browseldap.h"
93 #include "addrcustomattr.h"
99 } AddressIndexColumns;
107 } AddressListColumns;
110 AddressBookFile *book;
118 AddressDataSource *book;
122 static gchar *list_titles[] = { N_("Name"),
126 #define COL_NAME_WIDTH 164
127 #define COL_ADDRESS_WIDTH 156
129 #define COL_FOLDER_WIDTH 170
130 #define ADDRESSBOOK_WIDTH 640
131 #define ADDRESSBOOK_HEIGHT 360
133 #define ADDRESSBOOK_MSGBUF_SIZE 2048
135 static GdkPixmap *folderxpm;
136 static GdkBitmap *folderxpmmask;
137 static GdkPixmap *folderopenxpm;
138 static GdkBitmap *folderopenxpmmask;
139 static GdkPixmap *groupxpm;
140 static GdkBitmap *groupxpmmask;
141 static GdkPixmap *interfacexpm;
142 static GdkBitmap *interfacexpmmask;
143 static GdkPixmap *bookxpm;
144 static GdkBitmap *bookxpmmask;
145 static GdkPixmap *addressxpm;
146 static GdkBitmap *addressxpmmask;
147 static GdkPixmap *vcardxpm;
148 static GdkBitmap *vcardxpmmask;
149 static GdkPixmap *jpilotxpm;
150 static GdkBitmap *jpilotxpmmask;
151 static GdkPixmap *categoryxpm;
152 static GdkBitmap *categoryxpmmask;
153 static GdkPixmap *ldapxpm;
154 static GdkBitmap *ldapxpmmask;
155 static GdkPixmap *addrsearchxpm;
156 static GdkPixmap *addrsearchxpmmask;
159 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
161 /* Address list selection */
162 static AddrSelectList *_addressSelect_ = NULL;
163 static AddressClipboard *_clipBoard_ = NULL;
165 /* Address index file and interfaces */
166 static AddressIndex *_addressIndex_ = NULL;
167 static GList *_addressInterfaceList_ = NULL;
168 static GList *_addressIFaceSelection_ = NULL;
169 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
171 static AddressBook_win addrbook;
173 static GHashTable *_addressBookTypeHash_ = NULL;
174 static GList *_addressBookTypeList_ = NULL;
176 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
177 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
178 static void addressbook_edit_address_post_cb( ItemPerson *person );
180 static void addressbook_create (void);
181 static gint addressbook_close (void);
182 static void addressbook_button_set_sensitive (void);
184 static gboolean address_index_has_focus = FALSE;
185 static gboolean address_list_has_focus = FALSE;
187 /* callback functions */
188 static void addressbook_del_clicked (GtkButton *button,
190 static void addressbook_reg_clicked (GtkButton *button,
192 static void addressbook_to_clicked (GtkButton *button,
194 static void addressbook_lup_clicked (GtkButton *button,
196 static void addressbook_close_clicked (GtkButton *button,
199 static void addressbook_tree_selected (GtkCTree *ctree,
203 static void addressbook_select_row_tree (GtkCTree *ctree,
207 static void addressbook_list_row_selected (GtkCTree *clist,
211 static void addressbook_list_row_unselected (GtkCTree *clist,
215 static void addressbook_person_expand_node (GtkCTree *ctree,
218 static void addressbook_person_collapse_node (GtkCTree *ctree,
222 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
223 GdkEventButton *event,
225 static gboolean addressbook_list_button_released(GtkWidget *widget,
226 GdkEventButton *event,
228 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
229 GdkEventButton *event,
231 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
232 GdkEventButton *event,
235 static void addressbook_new_folder_cb (gpointer data,
238 static void addressbook_new_group_cb (gpointer data,
241 static void addressbook_treenode_edit_cb (gpointer data,
244 static void addressbook_treenode_delete_cb (gpointer data,
248 static void addressbook_change_node_name (GtkCTreeNode *node,
251 static void addressbook_new_address_cb (gpointer data,
254 static void addressbook_edit_address_cb (gpointer data,
257 static void addressbook_delete_address_cb (gpointer data,
261 static void close_cb (gpointer data,
264 static void addressbook_file_save_cb (gpointer data,
268 /* Data source edit stuff */
269 static void addressbook_new_book_cb (gpointer data,
272 static void addressbook_new_vcard_cb (gpointer data,
277 static void addressbook_new_jpilot_cb (gpointer data,
283 static void addressbook_new_ldap_cb (gpointer data,
288 static void addressbook_set_clist (AddressObject *obj,
291 static void addressbook_load_tree (void);
292 void addressbook_read_file (void);
294 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
296 static void addressbook_treenode_remove_item ( void );
298 static AddressDataSource *addressbook_find_datasource
299 (GtkCTreeNode *node );
301 static AddressBookFile *addressbook_get_book_file(void);
303 static GtkCTreeNode *addressbook_node_add_folder
305 AddressDataSource *ds,
306 ItemFolder *itemFolder,
307 AddressObjectType otype);
308 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
309 AddressDataSource *ds,
310 ItemGroup *itemGroup);
311 static void addressbook_tree_remove_children (GtkCTree *ctree,
312 GtkCTreeNode *parent);
313 static void addressbook_move_nodes_up (GtkCTree *ctree,
315 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
317 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
320 static gint addressbook_treenode_compare_func (GtkCList *clist,
323 static void addressbook_folder_load_one_person (GtkCTree *clist,
325 AddressTypeControlItem *atci,
326 AddressTypeControlItem *atciMail);
327 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
329 static void addressbook_folder_remove_one_person(GtkCTree *clist,
331 static void addressbook_folder_remove_node (GtkCTree *clist,
334 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
335 gboolean force_focus );
337 /* LUT's and IF stuff */
338 static void addressbook_free_treenode ( gpointer data );
339 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
340 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
342 static void addrbookctl_build_map (GtkWidget *window);
343 static void addrbookctl_build_iflist (void);
344 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
345 static void addrbookctl_build_ifselect (void);
347 static void addrbookctl_free_interface (AdapterInterface *adapter);
348 static void addrbookctl_free_datasource (AdapterDSource *adapter);
349 static void addrbookctl_free_folder (AdapterFolder *adapter);
350 static void addrbookctl_free_group (AdapterGroup *adapter);
352 static void addressbook_list_select_clear ( void );
353 static void addressbook_list_select_add ( AddrItemObject *aio,
354 AddressDataSource *ds );
355 static void addressbook_list_select_remove ( AddrItemObject *aio );
357 static void addressbook_import_ldif_cb ( void );
358 static void addressbook_find_duplicates_cb ( void );
359 static void addressbook_edit_custom_attr_cb ( void );
360 static void addressbook_import_mutt_cb ( void );
361 static void addressbook_import_pine_cb ( void );
362 static void addressbook_export_html_cb ( void );
363 static void addressbook_export_ldif_cb ( void );
364 static void addressbook_select_all_cb ( void );
365 static void addressbook_clip_cut_cb ( void );
366 static void addressbook_clip_copy_cb ( void );
367 static void addressbook_clip_paste_cb ( void );
368 static void addressbook_treenode_cut_cb ( void );
369 static void addressbook_treenode_copy_cb ( void );
370 static void addressbook_treenode_paste_cb ( void );
372 static void addressbook_mail_to_cb ( void );
375 static void addressbook_browse_entry_cb ( void );
377 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
379 static void addressbook_start_drag(GtkWidget *widget, gint button,
382 static void addressbook_drag_data_get(GtkWidget *widget,
383 GdkDragContext *drag_context,
384 GtkSelectionData *selection_data,
388 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
389 GdkDragContext *context,
394 static void addressbook_drag_leave_cb(GtkWidget *widget,
395 GdkDragContext *context,
398 static void addressbook_drag_received_cb(GtkWidget *widget,
399 GdkDragContext *drag_context,
402 GtkSelectionData *data,
406 static void addressbook_list_menu_setup( void );
408 static GtkTargetEntry addressbook_drag_types[] =
410 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
413 static GtkTargetList *addressbook_target_list = NULL;
416 static GtkItemFactoryEntry addressbook_entries[] =
418 {N_("/_Book"), NULL, NULL, 0, "<Branch>", NULL},
419 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL, NULL},
420 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL, NULL},
421 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL, NULL},
423 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL, NULL},
426 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL, NULL},
428 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
429 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
430 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
431 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
432 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL, NULL},
433 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL, NULL},
434 {N_("/_Address"), NULL, NULL, 0, "<Branch>", NULL},
435 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL, NULL},
436 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
437 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL, NULL},
438 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL, NULL},
439 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL, NULL},
440 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
441 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL, NULL},
442 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL, NULL},
443 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
444 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL, NULL},
445 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL, NULL},
446 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
447 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
448 {N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL},
449 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL, NULL},
450 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL, NULL},
451 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL, NULL},
452 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
453 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL, NULL},
454 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL, NULL},
455 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
456 {N_("/_Tools/Find duplicates..."), NULL, addressbook_find_duplicates_cb, 0, NULL, NULL},
457 {N_("/_Tools/Edit custom attributes..."), NULL, addressbook_edit_custom_attr_cb, 0, NULL, NULL},
458 {N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL},
459 {N_("/_Help/_About"), NULL, about_show, 0, NULL, NULL}
462 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
464 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
465 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
466 {"/---", NULL, NULL, 0, "<Separator>", NULL},
467 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL, NULL},
468 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL, NULL},
469 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
470 {"/---", NULL, NULL, 0, "<Separator>", NULL},
471 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL, NULL},
472 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL, NULL},
473 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL, NULL}
476 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
478 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL, NULL},
479 {"/---", NULL, NULL, 0, "<Separator>", NULL},
480 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL, NULL},
481 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL, NULL},
482 {"/---", NULL, NULL, 0, "<Separator>", NULL},
483 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL, NULL},
484 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
485 {"/---", NULL, NULL, 0, "<Separator>", NULL},
486 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL, NULL},
487 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL, NULL},
488 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL, NULL},
489 {"/---", NULL, NULL, 0, "<Separator>", NULL},
490 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL, NULL},*/
491 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
493 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL, NULL},
498 * Structure of error message table.
500 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
501 struct _ErrMsgTableEntry {
506 static gchar *_errMsgUnknown_ = N_( "Unknown" );
509 * Lookup table of error messages for general errors. Note that a NULL
510 * description signifies the end of the table.
512 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
513 { MGU_SUCCESS, N_("Success") },
514 { MGU_BAD_ARGS, N_("Bad arguments") },
515 { MGU_NO_FILE, N_("File not specified") },
516 { MGU_OPEN_FILE, N_("Error opening file") },
517 { MGU_ERROR_READ, N_("Error reading file") },
518 { MGU_EOF, N_("End of file encountered") },
519 { MGU_OO_MEMORY, N_("Error allocating memory") },
520 { MGU_BAD_FORMAT, N_("Bad file format") },
521 { MGU_ERROR_WRITE, N_("Error writing to file") },
522 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
523 { MGU_NO_PATH, N_("No path specified") },
529 * Lookup table of error messages for LDAP errors.
531 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
532 { LDAPRC_SUCCESS, N_("Success") },
533 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
534 { LDAPRC_INIT, N_("Error initializing LDAP") },
535 { LDAPRC_BIND, N_("Error binding to LDAP server") },
536 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
537 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
538 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
539 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
540 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
541 { LDAPRC_TLS, N_("Error starting TLS connection") },
542 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
543 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
544 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
545 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
551 * Lookup message for specified error code.
552 * \param lut Lookup table.
553 * \param code Code to lookup.
554 * \return Description associated to code.
556 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
558 ErrMsgTableEntry entry;
561 for( i = 0; ; i++ ) {
563 if( entry.description == NULL ) break;
564 if( entry.code == code ) {
565 desc = entry.description;
570 desc = _errMsgUnknown_;
575 static gboolean lastCanLookup = FALSE;
577 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
579 if (add_and_delete) {
580 gtk_widget_show(addrbook.edit_btn);
581 gtk_widget_show(addrbook.del_btn);
582 gtk_widget_show(addrbook.reg_btn);
584 gtk_widget_hide(addrbook.edit_btn);
585 gtk_widget_hide(addrbook.del_btn);
586 gtk_widget_hide(addrbook.reg_btn);
590 gtk_widget_show(addrbook.lup_btn);
591 gtk_widget_show(addrbook.entry);
592 gtk_widget_show(addrbook.label);
594 gtk_widget_hide(addrbook.lup_btn);
595 gtk_widget_hide(addrbook.entry);
596 gtk_widget_hide(addrbook.label);
599 lastCanLookup = lookup;
602 gtk_widget_show(addrbook.to_btn);
603 gtk_widget_show(addrbook.cc_btn);
604 gtk_widget_show(addrbook.bcc_btn);
606 gtk_widget_hide(addrbook.to_btn);
607 gtk_widget_hide(addrbook.cc_btn);
608 gtk_widget_hide(addrbook.bcc_btn);
612 void addressbook_open(Compose *target)
614 /* Initialize all static members */
615 if( _clipBoard_ == NULL ) {
616 _clipBoard_ = addrclip_create();
618 if( _addressIndex_ != NULL ) {
619 addrclip_set_index( _clipBoard_, _addressIndex_ );
621 if( _addressSelect_ == NULL ) {
622 _addressSelect_ = addrselect_list_create();
624 if (!addrbook.window) {
625 addressbook_read_file();
626 addressbook_create();
627 addressbook_load_tree();
628 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
629 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
632 gtk_widget_hide(addrbook.window);
635 gtk_widget_show_all(addrbook.window);
637 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
638 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
640 if (!prefs_common.addressbook_use_editaddress_dialog)
641 addressbook_edit_person_widgetset_hide();
643 address_completion_start(addrbook.window);
645 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
646 addressbook_set_target_compose(target);
650 * Destroy addressbook.
652 void addressbook_destroy( void ) {
653 /* Free up address stuff */
654 if( _addressSelect_ != NULL ) {
655 addrselect_list_free( _addressSelect_ );
657 if( _clipBoard_ != NULL ) {
658 addrclip_free( _clipBoard_ );
660 if( _addressIndex_ != NULL ) {
661 addrindex_free_index( _addressIndex_ );
662 addrindex_teardown();
664 _addressSelect_ = NULL;
666 _addressIndex_ = NULL;
669 void addressbook_set_target_compose(Compose *target)
671 addrbook.target_compose = target;
672 addressbook_button_set_sensitive();
675 Compose *addressbook_get_target_compose(void)
677 return addrbook.target_compose;
681 * Refresh addressbook and save to file(s).
683 void addressbook_refresh( void )
685 if (addrbook.window) {
686 if (addrbook.treeSelected) {
687 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
688 addrbook.treeSelected);
689 addressbook_set_clist(
690 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
691 addrbook.treeSelected),
696 addressbook_export_to_file();
699 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
701 if (event && event->keyval == GDK_Escape)
703 else if (event && event->keyval == GDK_Delete) {
704 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
705 if ( /* address_index_has_focus || */ address_list_has_focus )
706 addressbook_del_clicked(NULL, NULL);
712 *\brief Save Gtk object size to prefs dataset
714 static void addressbook_size_allocate_cb(GtkWidget *widget,
715 GtkAllocation *allocation)
717 g_return_if_fail(allocation != NULL);
719 prefs_common.addressbookwin_width = allocation->width;
720 prefs_common.addressbookwin_height = allocation->height;
723 static gint sort_column_number = 0;
724 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
726 static gint list_case_sort(
727 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
729 GtkCListRow *row1 = (GtkCListRow *) ptr1;
730 GtkCListRow *row2 = (GtkCListRow *) ptr2;
731 gchar *name1 = NULL, *name2 = NULL;
732 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
733 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
735 if( aio1->type == aio2->type ) {
737 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
739 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
740 if( ! name1 ) return ( name2 != NULL );
741 if( ! name2 ) return -1;
742 return g_utf8_collate( name1, name2 );
744 /* Order groups before person */
745 if( aio1->type == ITEMTYPE_GROUP ) {
746 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
747 } else if( aio2->type == ITEMTYPE_GROUP ) {
748 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
754 static void addressbook_sort_list(GtkCList *clist, const gint col,
755 const GtkSortType sort_type)
758 GtkWidget *hbox, *label, *arrow;
760 sort_column_number = col;
761 sort_column_type = sort_type;
762 gtk_clist_set_compare_func(clist, list_case_sort);
763 gtk_clist_set_sort_type(clist, sort_type);
764 gtk_clist_set_sort_column(clist, col);
766 gtk_clist_freeze(clist);
767 gtk_clist_sort(clist);
769 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
770 hbox = gtk_hbox_new(FALSE, 4);
771 label = gtk_label_new(gettext(list_titles[pos]));
772 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
775 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
776 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
777 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
780 gtk_widget_show_all(hbox);
781 gtk_clist_set_column_widget(clist, pos, hbox);
784 gtk_clist_thaw(clist);
787 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
789 static GtkSortType sort_type = GTK_SORT_ASCENDING;
791 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
793 addressbook_sort_list(clist, COL_NAME, sort_type);
796 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
798 static GtkSortType sort_type = GTK_SORT_ASCENDING;
800 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
802 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
805 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
807 static GtkSortType sort_type = GTK_SORT_ASCENDING;
809 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
811 addressbook_sort_list(clist, COL_REMARKS, sort_type);
814 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
817 address_index_has_focus = TRUE;
821 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
824 address_index_has_focus = FALSE;
825 if (!prefs_common.addressbook_use_editaddress_dialog
826 && !address_list_has_focus)
827 addressbook_address_list_disable_some_actions();
831 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
834 address_list_has_focus = TRUE;
838 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
841 address_list_has_focus = FALSE;
842 if (!prefs_common.addressbook_use_editaddress_dialog
843 && !address_index_has_focus)
844 addressbook_address_list_disable_some_actions();
848 /* save hpane and vpane's handle position when it moves */
849 static void addressbook_pane_save_position(void)
852 prefs_common.addressbook_hpaned_pos =
853 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
855 prefs_common.addressbook_vpaned_pos =
856 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
860 * Create the address book widgets. The address book contains two CTree widgets: the
861 * address index tree on the left and the address list on the right.
863 * The address index tree displays a hierarchy of interfaces and groups. Each node in
864 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
865 * data sources and folder objects.
867 * The address list displays group, person and email objects. These items are linked
868 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
871 * In the tradition of MVC architecture, the data stores have been separated from the
872 * GUI components. The addrindex.c file provides the interface to all data stores.
874 static void addressbook_create(void)
880 GtkWidget *ctree_swin;
882 GtkWidget *editaddress_vbox;
883 GtkWidget *clist_vbox;
884 GtkWidget *clist_swin;
891 GtkWidget *statusbar;
902 GtkWidget *close_btn;
903 GtkWidget *tree_popup;
904 GtkWidget *list_popup;
905 GtkItemFactory *tree_factory;
906 GtkItemFactory *list_factory;
907 GtkItemFactory *menu_factory;
911 gchar *index_titles[N_INDEX_COLS];
915 static GdkGeometry geometry;
917 debug_print("Creating addressbook window...\n");
919 index_titles[COL_SOURCES] = _("Sources");
921 /* Address book window */
922 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
923 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
924 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
925 gtk_widget_realize(window);
927 g_signal_connect(G_OBJECT(window), "delete_event",
928 G_CALLBACK(addressbook_close), NULL);
929 g_signal_connect(G_OBJECT(window), "size_allocate",
930 G_CALLBACK(addressbook_size_allocate_cb), NULL);
931 g_signal_connect(G_OBJECT(window), "key_press_event",
932 G_CALLBACK(key_pressed), NULL);
933 MANAGE_WINDOW_SIGNALS_CONNECT(window);
935 vbox = gtk_vbox_new(FALSE, 0);
936 gtk_container_add(GTK_CONTAINER(window), vbox);
939 n_entries = sizeof(addressbook_entries) /
940 sizeof(addressbook_entries[0]);
941 menubar = menubar_create(window, addressbook_entries, n_entries,
942 "<AddressBook>", NULL);
943 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
944 menu_factory = gtk_item_factory_from_widget(menubar);
946 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
947 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
948 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
950 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
951 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
952 GTK_POLICY_AUTOMATIC,
953 GTK_POLICY_AUTOMATIC);
954 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
957 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
958 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
959 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
960 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
961 if (prefs_common.enable_dotted_lines) {
962 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
963 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
964 GTK_CTREE_EXPANDER_SQUARE);
966 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
967 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
968 GTK_CTREE_EXPANDER_TRIANGLE);
970 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
971 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
972 gtk_clist_set_compare_func(GTK_CLIST(ctree),
973 addressbook_treenode_compare_func);
975 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
976 G_CALLBACK(addressbook_tree_selected), NULL);
977 g_signal_connect(G_OBJECT(ctree), "button_press_event",
978 G_CALLBACK(addressbook_tree_button_pressed),
980 g_signal_connect(G_OBJECT(ctree), "button_release_event",
981 G_CALLBACK(addressbook_tree_button_released),
984 g_signal_connect(G_OBJECT(ctree), "select_row",
985 G_CALLBACK(addressbook_select_row_tree), NULL);
987 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
988 addressbook_drag_types, 1,
989 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
990 g_signal_connect(G_OBJECT(ctree), "drag_motion",
991 G_CALLBACK(addressbook_drag_motion_cb),
993 g_signal_connect(G_OBJECT(ctree), "drag_leave",
994 G_CALLBACK(addressbook_drag_leave_cb),
996 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
997 G_CALLBACK(addressbook_drag_received_cb),
999 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1000 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1001 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1002 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1004 clist_vbox = gtk_vbox_new(FALSE, 4);
1006 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1007 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1008 GTK_POLICY_AUTOMATIC,
1009 GTK_POLICY_AUTOMATIC);
1010 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1013 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1014 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1015 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1016 if (prefs_common.enable_dotted_lines) {
1017 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_DOTTED);
1018 gtk_ctree_set_expander_style(GTK_CTREE(clist),
1019 GTK_CTREE_EXPANDER_SQUARE);
1021 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1022 gtk_ctree_set_expander_style(GTK_CTREE(clist),
1023 GTK_CTREE_EXPANDER_TRIANGLE);
1025 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1026 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1027 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1029 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1031 gtk_widget_set_size_request(clist, -1, 80);
1033 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1034 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1035 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1036 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1037 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1038 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1039 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1040 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1041 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1042 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1043 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1045 for (i = 0; i < N_LIST_COLS; i++)
1046 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1049 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1050 G_CALLBACK(addressbook_list_row_selected), NULL);
1051 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1052 G_CALLBACK(addressbook_list_row_unselected), NULL);
1053 g_signal_connect(G_OBJECT(clist), "button_press_event",
1054 G_CALLBACK(addressbook_list_button_pressed),
1056 g_signal_connect(G_OBJECT(clist), "button_release_event",
1057 G_CALLBACK(addressbook_list_button_released),
1059 g_signal_connect(G_OBJECT(clist), "tree_expand",
1060 G_CALLBACK(addressbook_person_expand_node), NULL );
1061 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1062 G_CALLBACK(addressbook_person_collapse_node), NULL );
1063 g_signal_connect(G_OBJECT(clist), "start_drag",
1064 G_CALLBACK(addressbook_start_drag), NULL);
1065 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1066 G_CALLBACK(addressbook_drag_data_get), NULL);
1067 hbox = gtk_hbox_new(FALSE, 4);
1068 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1070 label = gtk_label_new(_("Lookup name:"));
1071 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1073 entry = gtk_entry_new();
1074 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1076 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1078 g_signal_connect(G_OBJECT(entry), "key_press_event",
1079 G_CALLBACK(addressbook_entry_key_pressed),
1082 if (!prefs_common.addressbook_use_editaddress_dialog) {
1083 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1084 vpaned = gtk_vpaned_new();
1085 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1086 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1089 editaddress_vbox = NULL;
1091 hpaned = gtk_hpaned_new();
1092 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1093 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1094 if (prefs_common.addressbook_use_editaddress_dialog)
1095 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1097 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1100 hsbox = gtk_hbox_new(FALSE, 0);
1101 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1102 statusbar = gtk_statusbar_new();
1103 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1106 hbbox = gtk_hbutton_box_new();
1107 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1108 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1109 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1110 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1112 gtkut_stock_button_add_help(hbbox, &help_btn);
1114 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1115 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1116 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1117 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1118 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1119 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1120 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1121 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1122 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1125 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1126 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1127 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1129 g_signal_connect(G_OBJECT(help_btn), "clicked",
1130 G_CALLBACK(manual_open_with_anchor_cb),
1131 MANUAL_ANCHOR_ADDRBOOK);
1133 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1134 G_CALLBACK(addressbook_edit_clicked), NULL);
1135 g_signal_connect(G_OBJECT(del_btn), "clicked",
1136 G_CALLBACK(addressbook_del_clicked), NULL);
1137 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1138 G_CALLBACK(addressbook_reg_clicked), NULL);
1139 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1140 G_CALLBACK(addressbook_lup_clicked), NULL);
1142 to_btn = gtk_button_new_with_label
1143 (prefs_common_translated_header_name("To:"));
1144 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1145 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1146 cc_btn = gtk_button_new_with_label
1147 (prefs_common_translated_header_name("Cc:"));
1148 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1149 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1150 bcc_btn = gtk_button_new_with_label
1151 (prefs_common_translated_header_name("Bcc:"));
1152 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1153 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1155 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1156 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1157 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1159 g_signal_connect(G_OBJECT(to_btn), "clicked",
1160 G_CALLBACK(addressbook_to_clicked),
1161 GINT_TO_POINTER(COMPOSE_TO));
1162 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1163 G_CALLBACK(addressbook_to_clicked),
1164 GINT_TO_POINTER(COMPOSE_CC));
1165 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1166 G_CALLBACK(addressbook_to_clicked),
1167 GINT_TO_POINTER(COMPOSE_BCC));
1168 g_signal_connect(G_OBJECT(close_btn), "clicked",
1169 G_CALLBACK(addressbook_close_clicked), NULL);
1171 /* Build icons for interface */
1172 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1173 &interfacexpm, &interfacexpmmask );
1175 /* Build control tables */
1176 addrbookctl_build_map(window);
1177 addrbookctl_build_iflist();
1178 addrbookctl_build_ifselect();
1180 addrbook.clist = NULL;
1182 /* Add each interface into the tree as a root level folder */
1183 nodeIf = _addressInterfaceList_;
1185 AdapterInterface *adapter = nodeIf->data;
1186 AddressInterface *iface = adapter->interface;
1187 nodeIf = g_list_next(nodeIf);
1189 if(iface->useInterface) {
1190 AddressTypeControlItem *atci = adapter->atci;
1191 text = atci->displayName;
1193 gtk_sctree_insert_node( GTK_CTREE(ctree),
1194 NULL, NULL, &text, FOLDER_SPACING,
1195 interfacexpm, interfacexpmmask,
1196 interfacexpm, interfacexpmmask,
1198 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1199 gtk_ctree_node_set_row_data_full(
1200 GTK_CTREE(ctree), adapter->treeNode, adapter,
1201 addressbook_free_treenode );
1206 n_entries = sizeof(addressbook_tree_popup_entries) /
1207 sizeof(addressbook_tree_popup_entries[0]);
1208 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1210 "<AddressBookTree>", &tree_factory,
1212 n_entries = sizeof(addressbook_list_popup_entries) /
1213 sizeof(addressbook_list_popup_entries[0]);
1214 list_popup = menu_create_items(addressbook_list_popup_entries,
1216 "<AddressBookList>", &list_factory,
1219 addrbook.window = window;
1220 addrbook.hpaned = hpaned;
1221 addrbook.vpaned = vpaned;
1222 addrbook.menubar = menubar;
1223 addrbook.ctree = ctree;
1226 addrbook.editaddress_vbox = editaddress_vbox;
1227 addrbook.clist = clist;
1228 addrbook.label = label;
1229 addrbook.entry = entry;
1230 addrbook.statusbar = statusbar;
1231 addrbook.status_cid = gtk_statusbar_get_context_id(
1232 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1234 addrbook.help_btn = help_btn;
1235 addrbook.edit_btn = edit_btn;
1236 addrbook.del_btn = del_btn;
1237 addrbook.reg_btn = reg_btn;
1238 addrbook.lup_btn = lup_btn;
1239 addrbook.to_btn = to_btn;
1240 addrbook.cc_btn = cc_btn;
1241 addrbook.bcc_btn = bcc_btn;
1243 addrbook.tree_popup = tree_popup;
1244 addrbook.list_popup = list_popup;
1245 addrbook.tree_factory = tree_factory;
1246 addrbook.list_factory = list_factory;
1247 addrbook.menu_factory = menu_factory;
1249 addrbook.listSelected = NULL;
1251 if (!geometry.min_height) {
1252 geometry.min_width = ADDRESSBOOK_WIDTH;
1253 geometry.min_height = ADDRESSBOOK_HEIGHT;
1256 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1258 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1259 prefs_common.addressbookwin_height);
1261 if (!prefs_common.addressbook_use_editaddress_dialog) {
1262 if (prefs_common.addressbook_vpaned_pos > 0)
1263 gtk_paned_set_position(GTK_PANED(vpaned),
1264 prefs_common.addressbook_vpaned_pos);
1266 if (prefs_common.addressbook_hpaned_pos > 0)
1267 gtk_paned_set_position(GTK_PANED(hpaned),
1268 prefs_common.addressbook_hpaned_pos);
1271 gtk_widget_show_all(window);
1275 * Close address book window and save to file(s).
1277 static gint addressbook_close( void ) {
1278 address_completion_end(addrbook.window);
1279 if (!prefs_common.addressbook_use_editaddress_dialog)
1280 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1282 addressbook_pane_save_position();
1284 gtk_widget_hide(addrbook.window);
1285 addressbook_export_to_file();
1290 * Display message in status line.
1291 * \param msg Message to display.
1293 static void addressbook_status_show( gchar *msg ) {
1294 if( addrbook.statusbar != NULL ) {
1296 GTK_STATUSBAR(addrbook.statusbar),
1297 addrbook.status_cid );
1300 GTK_STATUSBAR(addrbook.statusbar),
1301 addrbook.status_cid, msg );
1306 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1310 *addressbook_msgbuf = '\0';
1312 name = addrindex_ds_get_name( ds );
1313 retVal = addrindex_ds_get_status_code( ds );
1314 if( retVal == MGU_SUCCESS ) {
1315 g_snprintf( addressbook_msgbuf,
1316 sizeof(addressbook_msgbuf), "%s", name );
1319 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1320 g_snprintf( addressbook_msgbuf,
1321 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1324 addressbook_status_show( addressbook_msgbuf );
1327 static void addressbook_button_set_sensitive(void)
1329 gboolean to_sens = FALSE;
1330 gboolean cc_sens = FALSE;
1331 gboolean bcc_sens = FALSE;
1333 if (!addrbook.window) return;
1335 if (addrbook.target_compose) {
1341 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1342 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1343 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1346 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1348 addressbook_edit_address_cb(NULL, 0, NULL);
1351 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1353 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1357 * Delete one or more objects from address list.
1359 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1361 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1362 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1363 AddressObject *pobj;
1364 AdapterDSource *ads = NULL;
1365 GtkCTreeNode *nodeList;
1368 AddressBookFile *abf = NULL;
1369 AddressDataSource *ds = NULL;
1370 AddressInterface *iface;
1371 AddrItemObject *aio;
1372 AddrSelectItem *item;
1374 gboolean refreshList = FALSE;
1376 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1377 g_return_if_fail(pobj != NULL);
1379 /* Test whether anything selected for deletion */
1380 nodeList = addrbook.listSelected;
1382 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1383 if( aio == NULL) return;
1384 ds = addressbook_find_datasource( addrbook.treeSelected );
1385 if( ds == NULL ) return;
1387 /* Test for read only */
1388 iface = ds->interface;
1389 if( iface->readOnly ) {
1390 alertpanel( _("Delete address(es)"),
1391 _("This address data is readonly and cannot be deleted."),
1392 GTK_STOCK_CLOSE, NULL, NULL );
1396 /* Test whether Ok to proceed */
1398 if( pobj->type == ADDR_DATASOURCE ) {
1399 ads = ADAPTER_DSOURCE(pobj);
1400 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1402 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1405 else if( pobj->type == ADDR_ITEM_GROUP ) {
1408 if( ! procFlag ) return;
1409 abf = ds->rawDataSource;
1410 if( abf == NULL ) return;
1412 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
1413 g_signal_handlers_block_by_func
1414 (G_OBJECT(addrbook.clist),
1415 G_CALLBACK(addressbook_list_row_unselected), NULL);
1417 /* Process deletions */
1418 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1419 GList *groups = NULL, *persons = NULL, *emails = NULL;
1420 gboolean group_delete = TRUE;
1421 /* Items inside folders */
1422 list = addrselect_get_list( _addressSelect_ );
1423 /* Confirm deletion */
1427 node = g_list_next( node );
1428 aio = ( AddrItemObject * ) item->addressItem;
1429 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1430 group_delete = FALSE;
1435 aval = alertpanel( _("Delete group"),
1436 _("Really delete the group(s)?\n"
1437 "The addresses it contains will not be lost."),
1438 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1439 if( aval != G_ALERTALTERNATE ) {
1443 aval = alertpanel( _("Delete address(es)"),
1444 _("Really delete the address(es)?"),
1445 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1446 if( aval != G_ALERTALTERNATE ) {
1451 /* first, set lists of groups and persons to remove */
1455 node = g_list_next( node );
1456 aio = ( AddrItemObject * ) item->addressItem;
1459 if( aio->type == ADDR_ITEM_GROUP ) {
1460 groups = g_list_prepend(groups, item);
1462 else if( aio->type == ADDR_ITEM_PERSON ) {
1463 persons = g_list_prepend(persons, item);
1466 /* then set list of emails to remove *if* they're not children of
1467 * persons to remove */
1471 node = g_list_next( node );
1472 aio = ( AddrItemObject * ) item->addressItem;
1475 if( aio->type == ADDR_ITEM_EMAIL ) {
1476 ItemEMail *sitem = ( ItemEMail * ) aio;
1477 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1478 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1479 emails = g_list_prepend(emails, item);
1481 /* else, the email will be removed via the parent person */
1484 /* then delete groups */
1488 node = g_list_next( node );
1489 aio = ( AddrItemObject * ) item->addressItem;
1492 if( aio->type == ADDR_ITEM_GROUP ) {
1493 ItemGroup *item = ( ItemGroup * ) aio;
1494 GtkCTreeNode *nd = NULL;
1495 nd = addressbook_find_group_node( addrbook.opened, item );
1496 item = addrbook_remove_group( abf, item );
1498 addritem_free_item_group( item );
1500 /* Remove group from parent node */
1501 gtk_ctree_remove_node( ctree, nd );
1505 /* then delete persons */
1509 node = g_list_next( node );
1510 aio = ( AddrItemObject * ) item->addressItem;
1513 if( aio->type == ADDR_ITEM_PERSON ) {
1514 ItemPerson *item = ( ItemPerson * ) aio;
1515 item->status = DELETE_ENTRY;
1516 addressbook_folder_remove_one_person( clist, item );
1517 if (pobj->type == ADDR_ITEM_FOLDER)
1518 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1519 item = addrbook_remove_person( abf, item );
1521 if (ds && ds->type == ADDR_IF_LDAP) {
1522 LdapServer *server = ds->rawDataSource;
1523 ldapsvr_set_modified(server, TRUE);
1524 ldapsvr_update_book(server, item);
1528 gchar *filename = addritem_person_get_picture(item);
1529 if (filename && is_file_exist(filename))
1530 claws_unlink(filename);
1532 addritem_free_item_person( item );
1536 /* then delete emails */
1540 node = g_list_next( node );
1541 aio = ( AddrItemObject * ) item->addressItem;
1545 if( aio->type == ADDR_ITEM_EMAIL ) {
1546 ItemEMail *sitem = ( ItemEMail * ) aio;
1547 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1548 sitem = addrbook_person_remove_email( abf, person, sitem );
1550 addrcache_remove_email(abf->addressCache, sitem);
1551 addritem_free_item_email( sitem );
1553 addressbook_folder_refresh_one_person( clist, person );
1556 g_list_free( groups );
1557 g_list_free( persons );
1558 g_list_free( emails );
1559 g_list_free( list );
1560 addressbook_list_select_clear();
1562 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1563 addressbook_set_clist(
1564 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1568 addrbook_set_dirty(abf, TRUE);
1569 addressbook_export_to_file();
1570 addressbook_list_menu_setup();
1573 else if( pobj->type == ADDR_ITEM_GROUP ) {
1574 /* Items inside groups */
1575 list = addrselect_get_list( _addressSelect_ );
1579 node = g_list_next( node );
1580 aio = ( AddrItemObject * ) item->addressItem;
1581 if( aio->type == ADDR_ITEM_EMAIL ) {
1582 ItemEMail *item = ( ItemEMail * ) aio;
1583 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1584 item = addrbook_person_remove_email( abf, person, item );
1586 addritem_free_item_email( item );
1590 g_list_free( list );
1591 addressbook_list_select_clear();
1592 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1593 addressbook_set_clist(
1594 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1598 addrbook_set_dirty(abf, TRUE);
1599 addressbook_export_to_file();
1600 addressbook_list_menu_setup();
1604 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1605 gtk_ctree_remove_node( clist, nodeList );
1607 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
1608 g_signal_handlers_unblock_by_func
1609 (G_OBJECT(addrbook.clist),
1610 G_CALLBACK(addressbook_list_row_unselected), NULL);
1613 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1615 addressbook_new_address_cb( NULL, 0, NULL );
1618 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1621 gchar *address = NULL;
1623 if( aio->type == ADDR_ITEM_EMAIL ) {
1624 ItemPerson *person = NULL;
1625 ItemEMail *email = ( ItemEMail * ) aio;
1627 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1628 if( email->address ) {
1629 if( ADDRITEM_NAME(email) ) {
1630 name = ADDRITEM_NAME(email);
1631 if( *name == '\0' ) {
1632 name = ADDRITEM_NAME(person);
1635 else if( ADDRITEM_NAME(person) ) {
1636 name = ADDRITEM_NAME(person);
1639 buf = g_strdup( email->address );
1641 address = email->address;
1644 else if( aio->type == ADDR_ITEM_PERSON ) {
1645 ItemPerson *person = ( ItemPerson * ) aio;
1646 GList *node = person->listEMail;
1648 name = ADDRITEM_NAME(person);
1650 ItemEMail *email = ( ItemEMail * ) node->data;
1651 address = email->address;
1655 if( name && name[0] != '\0' ) {
1656 if( strchr_with_skip_quote( name, '"', ',' ) )
1657 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1659 buf = g_strdup_printf( "%s <%s>", name, address );
1662 buf = g_strdup( address );
1669 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1673 AddrSelectItem *item;
1674 AddrItemObject *aio;
1677 compose = addrbook.target_compose;
1678 if( ! compose ) return;
1680 /* Nothing selected, but maybe there is something in text entry */
1681 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1683 compose_entry_append(
1684 compose, addr, (ComposeEntryType)data );
1687 /* Select from address list */
1688 list = addrselect_get_list( _addressSelect_ );
1693 node = g_list_next( node );
1694 aio = item->addressItem;
1695 if( aio->type == ADDR_ITEM_PERSON ||
1696 aio->type == ADDR_ITEM_EMAIL ) {
1697 addr = addressbook_format_address( aio );
1698 compose_entry_append(
1699 compose, addr, (ComposeEntryType) data );
1702 else if( aio->type == ADDR_ITEM_GROUP ) {
1703 ItemGroup *group = ( ItemGroup * ) aio;
1704 GList *nodeMail = group->listEMail;
1706 ItemEMail *email = nodeMail->data;
1708 addr = addressbook_format_address(
1709 ( AddrItemObject * ) email );
1710 compose_entry_append(
1711 compose, addr, (ComposeEntryType) data );
1713 nodeMail = g_list_next( nodeMail );
1718 AddressObject *obj = NULL;
1720 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1722 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1723 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1724 GList *nodeMail = itemGroup->listEMail;
1726 ItemEMail *email = nodeMail->data;
1728 addr = addressbook_format_address(
1729 ( AddrItemObject * ) email );
1730 compose_entry_append(
1731 compose, addr, (ComposeEntryType) data );
1733 nodeMail = g_list_next( nodeMail );
1737 g_list_free( list );
1740 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1741 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1742 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1743 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1745 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1746 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1747 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1748 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1750 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1751 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1752 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1753 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1754 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1757 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1758 gboolean canEdit = FALSE;
1759 gboolean canDelete = TRUE;
1760 gboolean canAdd = FALSE;
1761 gboolean canEditTr = TRUE;
1762 gboolean editAddress = FALSE;
1763 gboolean canExport = TRUE;
1764 AddressTypeControlItem *atci = NULL;
1765 AddressDataSource *ds = NULL;
1766 AddressInterface *iface = NULL;
1768 if( obj == NULL ) return;
1769 if( obj->type == ADDR_INTERFACE ) {
1770 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1771 iface = adapter->interface;
1773 if( iface->haveLibrary ) {
1774 /* Enable appropriate File / New command */
1775 atci = adapter->atci;
1776 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1779 canEditTr = canExport = FALSE;
1781 else if( obj->type == ADDR_DATASOURCE ) {
1782 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1783 ds = ads->dataSource;
1784 iface = ds->interface;
1785 if( ! iface->readOnly ) {
1786 canAdd = canEdit = editAddress = canDelete = TRUE;
1788 if( ! iface->haveLibrary ) {
1789 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1792 else if( obj->type == ADDR_ITEM_FOLDER ) {
1793 ds = addressbook_find_datasource( addrbook.treeSelected );
1795 iface = ds->interface;
1796 if( iface->readOnly ) {
1801 canAdd = editAddress = TRUE;
1805 else if( obj->type == ADDR_ITEM_GROUP ) {
1806 ds = addressbook_find_datasource( addrbook.treeSelected );
1808 iface = ds->interface;
1809 if( ! iface->readOnly ) {
1815 if( addrbook.listSelected == NULL )
1819 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1820 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1821 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1822 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1825 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1826 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1827 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1828 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1830 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1831 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1834 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1835 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1839 * Address book tree callback function that responds to selection of tree
1842 * \param ctree Tree widget.
1843 * \param node Node that was selected.
1844 * \param column Column number where selected occurred.
1845 * \param data Pointer to user data.
1847 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1848 gint column, gpointer data)
1850 AddressObject *obj = NULL;
1851 AdapterDSource *ads = NULL;
1852 AddressDataSource *ds = NULL;
1853 ItemFolder *rootFolder = NULL;
1854 AddressObjectType aot;
1856 addrbook.treeSelected = node;
1857 addrbook.listSelected = NULL;
1858 addressbook_status_show( "" );
1859 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1861 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1863 addressbook_set_clist(NULL, TRUE);
1866 addrbook.opened = node;
1868 if( obj->type == ADDR_DATASOURCE ) {
1869 /* Read from file */
1870 static gboolean tVal = TRUE;
1872 ads = ADAPTER_DSOURCE(obj);
1873 if( ads == NULL ) return;
1874 ds = ads->dataSource;
1875 if( ds == NULL ) return;
1877 if( addrindex_ds_get_modify_flag( ds ) ) {
1878 addrindex_ds_read_data( ds );
1881 if( ! addrindex_ds_get_read_flag( ds ) ) {
1882 addrindex_ds_read_data( ds );
1884 addressbook_ds_show_message( ds );
1886 if( ! addrindex_ds_get_access_flag( ds ) ) {
1887 /* Remove existing folders and groups */
1888 gtk_clist_freeze( GTK_CLIST(ctree) );
1889 addressbook_tree_remove_children( ctree, node );
1890 gtk_clist_thaw( GTK_CLIST(ctree) );
1892 /* Load folders into the tree */
1893 rootFolder = addrindex_ds_get_root_folder( ds );
1894 if( ds && ds->type == ADDR_IF_JPILOT ) {
1895 aot = ADDR_CATEGORY;
1897 else if( ds && ds->type == ADDR_IF_LDAP ) {
1898 aot = ADDR_LDAP_QUERY;
1901 aot = ADDR_ITEM_FOLDER;
1903 addressbook_node_add_folder( node, ds, rootFolder, aot );
1904 addrindex_ds_set_access_flag( ds, &tVal );
1905 gtk_ctree_expand( ctree, node );
1908 addressbook_set_clist(NULL, TRUE);
1911 /* Update address list */
1912 g_signal_handlers_block_by_func
1914 G_CALLBACK(addressbook_tree_selected), NULL);
1915 addressbook_set_clist( obj, FALSE );
1916 g_signal_handlers_unblock_by_func
1918 G_CALLBACK(addressbook_tree_selected), NULL);
1919 if (!prefs_common.addressbook_use_editaddress_dialog)
1920 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1922 /* Setup main menu selections */
1923 addressbook_menubar_set_sensitive( FALSE );
1924 addressbook_menuitem_set_sensitive( obj, node );
1925 addressbook_list_select_clear();
1926 addressbook_list_menu_setup();
1931 * Setup address list popup menu items. Items are enabled or disabled as
1934 static void addressbook_list_menu_setup( void ) {
1935 GtkCTree *clist = NULL;
1936 AddressObject *pobj = NULL;
1937 AddressObject *obj = NULL;
1938 AdapterDSource *ads = NULL;
1939 AddressInterface *iface = NULL;
1940 AddressDataSource *ds = NULL;
1941 gboolean canEdit = FALSE;
1942 gboolean canDelete = FALSE;
1943 gboolean canCut = FALSE;
1944 gboolean canCopy = FALSE;
1945 gboolean canPaste = FALSE;
1946 gboolean canBrowse = FALSE;
1948 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1949 if( pobj == NULL ) return;
1951 clist = GTK_CTREE(addrbook.clist);
1952 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1953 if( obj == NULL ) canEdit = FALSE;
1955 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1956 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1958 if( pobj->type == ADDR_DATASOURCE ) {
1959 /* Parent object is a data source */
1960 ads = ADAPTER_DSOURCE(pobj);
1961 ds = ads->dataSource;
1964 iface = ds->interface;
1967 if( ! iface->readOnly ) {
1968 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1969 if (iface->type != ADDR_IF_LDAP)
1970 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1971 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1974 canDelete = canEdit;
1977 else if( pobj->type != ADDR_INTERFACE ) {
1978 /* Parent object is not an interface */
1979 ds = addressbook_find_datasource( addrbook.treeSelected );
1982 iface = ds->interface;
1985 if( ! iface->readOnly ) {
1986 /* Folder or group */
1987 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1988 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1989 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1990 if( obj ) canEdit = TRUE;
1993 if( pobj->type == ADDR_ITEM_FOLDER ) {
1994 if (iface->type != ADDR_IF_LDAP)
1995 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1996 if( obj ) canEdit = TRUE;
1998 canDelete = canEdit;
2000 if( iface->type == ADDR_IF_LDAP ) {
2001 if( obj ) canBrowse = TRUE;
2008 /* Enable cut and paste */
2009 if( ! addrclip_is_empty( _clipBoard_ ) )
2011 if( ! addrselect_test_empty( _addressSelect_ ) )
2013 /* Enable copy if something is selected */
2014 if( ! addrselect_test_empty( _addressSelect_ ) )
2018 /* Disable edit or browse if more than one row selected */
2019 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
2024 /* Forbid write changes when read-only */
2025 if( iface && iface->readOnly ) {
2031 /* Now go finalize menu items */
2032 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
2033 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
2035 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
2036 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
2037 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
2039 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
2041 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2042 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2043 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2045 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
2046 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
2047 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
2049 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2050 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2053 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
2057 static void addressbook_select_row_tree (GtkCTree *ctree,
2065 * Add list of items into tree node below specified tree node.
2066 * \param treeNode Tree node.
2067 * \param ds Data source.
2068 * \param listItems List of items.
2070 static void addressbook_treenode_add_list(
2071 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2077 AddrItemObject *aio;
2081 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2084 group = ( ItemGroup * ) aio;
2085 nn = addressbook_node_add_group( treeNode, ds, group );
2087 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2090 folder = ( ItemFolder * ) aio;
2091 nn = addressbook_node_add_folder(
2092 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2094 node = g_list_next( node );
2098 static void addressbook_select_all_cb( void ) {
2099 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2103 * Cut from address list widget.
2105 static void addressbook_clip_cut_cb( void ) {
2106 _clipBoard_->cutFlag = TRUE;
2107 addrclip_clear( _clipBoard_ );
2108 addrclip_add( _clipBoard_, _addressSelect_ );
2109 /* addrclip_list_show( _clipBoard_, stdout ); */
2113 * Copy from address list widget.
2115 static void addressbook_clip_copy_cb( void ) {
2116 _clipBoard_->cutFlag = FALSE;
2117 addrclip_clear( _clipBoard_ );
2118 addrclip_add( _clipBoard_, _addressSelect_ );
2119 /* addrclip_list_show( _clipBoard_, stdout ); */
2123 * Paste clipboard into address list widget.
2125 static void addressbook_clip_paste_cb( void ) {
2126 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2127 AddressObject *pobj = NULL;
2128 AddressDataSource *ds = NULL;
2129 AddressBookFile *abf = NULL;
2130 ItemFolder *folder = NULL;
2131 GList *folderGroup = NULL;
2133 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2134 if( ds == NULL ) return;
2135 if( addrindex_ds_get_readonly( ds ) ) {
2136 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2140 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2142 if( pobj->type == ADDR_ITEM_FOLDER ) {
2143 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2145 else if( pobj->type == ADDR_ITEM_GROUP ) {
2146 alertpanel_error( _("Cannot paste into an address group.") );
2151 /* Get an address book */
2152 abf = addressbook_get_book_file();
2153 if( abf == NULL ) return;
2155 if( _clipBoard_->cutFlag ) {
2157 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2159 /* Remove all groups and folders in clipboard from tree node */
2160 addressbook_treenode_remove_item();
2162 /* Remove all "cut" items */
2163 addrclip_delete_item( _clipBoard_ );
2165 /* Clear clipboard - cut items??? */
2166 addrclip_clear( _clipBoard_ );
2170 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2173 /* addrclip_list_show( _clipBoard_, stdout ); */
2175 /* Update tree by inserting node for each folder or group */
2176 addressbook_treenode_add_list(
2177 addrbook.treeSelected, ds, folderGroup );
2178 gtk_ctree_expand( ctree, addrbook.treeSelected );
2179 g_list_free( folderGroup );
2183 /* Display items pasted */
2184 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2185 addressbook_set_clist(
2186 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2194 * Add current treenode object to clipboard. Note that widget only allows
2195 * one entry from the tree list to be selected.
2197 static void addressbook_treenode_to_clipboard( void ) {
2198 AddressObject *obj = NULL;
2199 AddressDataSource *ds = NULL;
2200 AddrSelectItem *item;
2201 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2204 node = addrbook.treeSelected;
2205 if( node == NULL ) return;
2206 obj = gtk_ctree_node_get_row_data( ctree, node );
2207 if( obj == NULL ) return;
2209 ds = addressbook_find_datasource( node );
2210 if( ds == NULL ) return;
2213 if( obj->type == ADDR_ITEM_FOLDER ) {
2214 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2215 ItemFolder *folder = adapter->itemFolder;
2217 item = addrselect_create_node( obj );
2218 item->uid = g_strdup( ADDRITEM_ID(folder) );
2220 else if( obj->type == ADDR_ITEM_GROUP ) {
2221 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2222 ItemGroup *group = adapter->itemGroup;
2224 item = addrselect_create_node( obj );
2225 item->uid = g_strdup( ADDRITEM_ID(group) );
2227 else if( obj->type == ADDR_DATASOURCE ) {
2229 item = addrselect_create_node( obj );
2234 /* Clear existing list and add item into list */
2237 addressbook_list_select_clear();
2238 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2239 addrselect_list_add( _addressSelect_, item, cacheID );
2245 * Cut from tree widget.
2247 static void addressbook_treenode_cut_cb( void ) {
2248 _clipBoard_->cutFlag = TRUE;
2249 addressbook_treenode_to_clipboard();
2250 addrclip_clear( _clipBoard_ );
2251 addrclip_add( _clipBoard_, _addressSelect_ );
2252 /* addrclip_list_show( _clipBoard_, stdout ); */
2256 * Copy from tree widget.
2258 static void addressbook_treenode_copy_cb( void ) {
2259 _clipBoard_->cutFlag = FALSE;
2260 addressbook_treenode_to_clipboard();
2261 addrclip_clear( _clipBoard_ );
2262 addrclip_add( _clipBoard_, _addressSelect_ );
2263 /* addrclip_list_show( _clipBoard_, stdout ); */
2267 * Paste clipboard into address tree widget.
2269 static void addressbook_treenode_paste_cb( void ) {
2270 addressbook_clip_paste_cb();
2274 * Clear selected entries in clipboard.
2276 static void addressbook_list_select_clear( void ) {
2277 addrselect_list_clear( _addressSelect_ );
2281 * Add specified address item to selected address list.
2282 * \param aio Address item object.
2283 * \param ds Datasource.
2285 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2288 if( ds == NULL ) return;
2289 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2290 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2295 * Remove specified address item from selected address list.
2296 * \param aio Address item object.
2298 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2299 addrselect_list_remove( _addressSelect_, aio );
2303 * Invoke EMail compose window with addresses in selected address list.
2305 static void addressbook_mail_to_cb( void ) {
2308 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2309 listAddress = addrselect_build_list( _addressSelect_ );
2310 compose_new_with_list( NULL, listAddress );
2311 mgu_free_dlist( listAddress );
2316 static void addressbook_list_row_selected( GtkCTree *clist,
2321 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2322 AddrItemObject *aio = NULL;
2323 AddressObject *pobj = NULL;
2324 AdapterDSource *ads = NULL;
2325 AddressDataSource *ds = NULL;
2327 gtk_entry_set_text( entry, "" );
2328 addrbook.listSelected = node;
2330 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2331 if( pobj == NULL ) return;
2333 if( pobj->type == ADDR_DATASOURCE ) {
2334 ads = ADAPTER_DSOURCE(pobj);
2335 ds = ads->dataSource;
2337 else if( pobj->type != ADDR_INTERFACE ) {
2338 ds = addressbook_find_datasource( addrbook.treeSelected );
2341 aio = gtk_ctree_node_get_row_data( clist, node );
2343 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2344 addressbook_list_select_add( aio, ds );
2347 addressbook_list_menu_setup();
2349 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2350 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2352 if (obj && obj->type != ADDR_ITEM_GROUP)
2353 addressbook_edit_address(NULL, 0, NULL, FALSE);
2357 static void addressbook_list_row_unselected( GtkCTree *ctree,
2362 AddrItemObject *aio;
2364 aio = gtk_ctree_node_get_row_data( ctree, node );
2366 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2367 addressbook_list_select_remove( aio );
2370 if (!prefs_common.addressbook_use_editaddress_dialog)
2371 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2374 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2375 GdkEventButton *event,
2378 if( ! event ) return FALSE;
2380 addressbook_list_menu_setup();
2382 if( event->button == 3 ) {
2383 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2384 event->button, event->time );
2385 } else if (event->button == 1) {
2386 if (event->type == GDK_2BUTTON_PRESS) {
2387 if (prefs_common.add_address_by_click &&
2388 addrbook.target_compose)
2389 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2391 if (prefs_common.addressbook_use_editaddress_dialog)
2392 addressbook_edit_address_cb(NULL, 0, NULL);
2394 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2395 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2396 if( obj && obj->type == ADDR_ITEM_GROUP )
2397 addressbook_edit_address_cb(NULL, 0, NULL);
2405 static gboolean addressbook_list_button_released(GtkWidget *widget,
2406 GdkEventButton *event,
2412 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2413 GdkEventButton *event,
2416 GtkCList *clist = GTK_CLIST(ctree);
2418 AddressObject *obj = NULL;
2419 AdapterDSource *ads = NULL;
2420 AddressInterface *iface = NULL;
2421 AddressDataSource *ds = NULL;
2422 gboolean canEdit = FALSE;
2423 gboolean canDelete = FALSE;
2424 gboolean canCut = FALSE;
2425 gboolean canCopy = FALSE;
2426 gboolean canPaste = FALSE;
2427 gboolean canTreeCut = FALSE;
2428 gboolean canTreeCopy = FALSE;
2429 gboolean canTreePaste = FALSE;
2430 gboolean canLookup = FALSE;
2431 GtkCTreeNode *node = NULL;
2433 if( ! event ) return FALSE;
2434 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2436 if (event->button == 1) {
2437 if (event->type == GDK_2BUTTON_PRESS) {
2438 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2439 gtkut_clist_set_focus_row(clist, row);
2440 obj = gtk_clist_get_row_data( clist, row );
2445 if (obj->type == ADDR_ITEM_GROUP) {
2447 addressbook_treenode_edit_cb(NULL, 0, NULL);
2449 /* expand pr collapse */
2450 node = gtk_ctree_node_nth(GTK_CTREE(ctree), row);
2451 gtk_ctree_toggle_expansion(GTK_CTREE(ctree), node);
2457 addressbook_menubar_set_sensitive( FALSE );
2459 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2460 gtkut_clist_set_focus_row(clist, row);
2461 obj = gtk_clist_get_row_data( clist, row );
2464 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2468 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2470 if( ! addrclip_is_empty( _clipBoard_ ) )
2471 canTreePaste = TRUE;
2473 if (obj->type == ADDR_INTERFACE) {
2474 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2477 iface = adapter->interface;
2480 if( !iface->readOnly ) {
2481 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2482 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2484 if( iface->externalQuery )
2487 if (obj->type == ADDR_DATASOURCE) {
2488 ads = ADAPTER_DSOURCE(obj);
2489 ds = ads->dataSource;
2492 iface = ds->interface;
2495 if( !iface->readOnly ) {
2497 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2498 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2499 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2503 if( iface->externalQuery )
2506 else if (obj->type == ADDR_ITEM_FOLDER) {
2507 ds = addressbook_find_datasource( node );
2510 iface = ds->interface;
2513 if( !iface->readOnly ) {
2517 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2518 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2519 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2523 if( iface->externalQuery ) {
2524 /* Enable deletion of LDAP folder */
2529 else if (obj->type == ADDR_ITEM_GROUP) {
2530 ds = addressbook_find_datasource( node );
2533 iface = ds->interface;
2536 if( ! iface->readOnly ) {
2539 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2540 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2544 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2546 if( ! addrselect_test_empty( _addressSelect_ ) )
2548 if( ! addrclip_is_empty( _clipBoard_ ) )
2551 /* Forbid write changes when read-only */
2552 if( iface && iface->readOnly ) {
2554 canTreePaste = FALSE;
2562 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2563 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2564 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2565 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2566 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2568 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2569 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2570 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2571 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2572 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2574 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2575 addrbook.target_compose != NULL);
2577 if( event->button == 3 )
2578 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2579 event->button, event->time);
2584 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2585 GdkEventButton *event,
2588 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2592 static void addressbook_new_folder_cb(gpointer data, guint action,
2595 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2596 AddressObject *obj = NULL;
2597 AddressDataSource *ds = NULL;
2598 AddressBookFile *abf = NULL;
2599 ItemFolder *parentFolder = NULL;
2600 ItemFolder *folder = NULL;
2602 if( ! addrbook.treeSelected ) return;
2603 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2604 if( obj == NULL ) return;
2605 ds = addressbook_find_datasource( addrbook.treeSelected );
2606 if( ds == NULL ) return;
2608 if( obj->type == ADDR_DATASOURCE ) {
2609 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2611 else if( obj->type == ADDR_ITEM_FOLDER ) {
2612 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2618 abf = ds->rawDataSource;
2619 if( abf == NULL ) return;
2620 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2623 nn = addressbook_node_add_folder(
2624 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2625 gtk_ctree_expand( ctree, addrbook.treeSelected );
2626 if( addrbook.treeSelected == addrbook.opened )
2627 addressbook_set_clist(obj, TRUE);
2631 static void addressbook_new_group_cb(gpointer data, guint action,
2634 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2635 AddressObject *obj = NULL;
2636 AddressDataSource *ds = NULL;
2637 AddressBookFile *abf = NULL;
2638 ItemFolder *parentFolder = NULL;
2639 ItemGroup *group = NULL;
2641 if( ! addrbook.treeSelected ) return;
2642 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2643 if( obj == NULL ) return;
2644 ds = addressbook_find_datasource( addrbook.treeSelected );
2645 if( ds == NULL ) return;
2647 if( obj->type == ADDR_DATASOURCE ) {
2648 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2650 else if( obj->type == ADDR_ITEM_FOLDER ) {
2651 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2657 abf = ds->rawDataSource;
2658 if( abf == NULL ) return;
2659 group = addressbook_edit_group( abf, parentFolder, NULL );
2662 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2663 gtk_ctree_expand( ctree, addrbook.treeSelected );
2664 if( addrbook.treeSelected == addrbook.opened )
2665 addressbook_set_clist(obj, TRUE);
2669 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2671 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2674 GdkPixmap *pix_cl, *pix_op;
2675 GdkBitmap *mask_cl, *mask_op;
2676 gboolean is_leaf, expanded;
2678 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2679 &pix_cl, &mask_cl, &pix_op, &mask_op,
2680 &is_leaf, &expanded);
2681 gtk_sctree_set_node_info(ctree, node, name, spacing,
2682 pix_cl, mask_cl, pix_op, mask_op,
2688 * \param obj Address object to edit.
2689 * \param node Node in tree.
2690 * \return New name of data source.
2692 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2693 gchar *newName = NULL;
2694 AddressDataSource *ds = NULL;
2695 AddressInterface *iface = NULL;
2696 AdapterDSource *ads = NULL;
2698 ds = addressbook_find_datasource( node );
2699 if( ds == NULL ) return NULL;
2700 iface = ds->interface;
2701 if( ! iface->haveLibrary ) return NULL;
2703 /* Read data from data source */
2704 if( addrindex_ds_get_modify_flag( ds ) ) {
2705 addrindex_ds_read_data( ds );
2708 if( ! addrindex_ds_get_read_flag( ds ) ) {
2709 addrindex_ds_read_data( ds );
2713 ads = ADAPTER_DSOURCE(obj);
2714 if( ads->subType == ADDR_BOOK ) {
2715 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2717 else if( ads->subType == ADDR_VCARD ) {
2718 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2721 else if( ads->subType == ADDR_JPILOT ) {
2722 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2726 else if( ads->subType == ADDR_LDAP ) {
2727 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2733 newName = obj->name;
2738 * Edit an object that is in the address tree area.
2740 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2743 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2745 AddressDataSource *ds = NULL;
2746 AddressBookFile *abf = NULL;
2747 GtkCTreeNode *node = NULL, *parentNode = NULL;
2750 if( ! addrbook.treeSelected ) return;
2751 node = addrbook.treeSelected;
2752 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2753 obj = gtk_ctree_node_get_row_data( ctree, node );
2754 if( obj == NULL ) return;
2755 parentNode = GTK_CTREE_ROW(node)->parent;
2757 ds = addressbook_find_datasource( node );
2758 if( ds == NULL ) return;
2760 if( obj->type == ADDR_DATASOURCE ) {
2761 name = addressbook_edit_datasource( obj, node );
2762 if( name == NULL ) return;
2765 abf = ds->rawDataSource;
2766 if( abf == NULL ) return;
2767 if( obj->type == ADDR_ITEM_FOLDER ) {
2768 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2769 ItemFolder *item = adapter->itemFolder;
2770 ItemFolder *parentFolder = NULL;
2771 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2772 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2773 name = ADDRITEM_NAME(item);
2775 else if( obj->type == ADDR_ITEM_GROUP ) {
2776 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2777 ItemGroup *item = adapter->itemGroup;
2778 ItemFolder *parentFolder = NULL;
2779 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2780 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2781 name = ADDRITEM_NAME(item);
2784 if( name && parentNode ) {
2785 /* Update node in tree view */
2786 addressbook_change_node_name( node, name );
2787 gtk_sctree_sort_node(ctree, parentNode);
2788 gtk_ctree_expand( ctree, node );
2789 gtk_sctree_select( GTK_SCTREE( ctree), node );
2796 ADDRTREE_DEL_FOLDER_ONLY,
2797 ADDRTREE_DEL_FOLDER_ADDR
2801 * Delete an item from the tree widget.
2802 * \param data Data passed in.
2803 * \param action Action.
2804 * \param widget Widget issuing callback.
2806 static void addressbook_treenode_delete_cb(
2807 gpointer data, guint action, GtkWidget *widget )
2809 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2810 GtkCTreeNode *node = NULL;
2814 AddrBookBase *adbase;
2815 AddressCache *cache;
2816 AdapterDSource *ads = NULL;
2817 AddressInterface *iface = NULL;
2818 AddressDataSource *ds = NULL;
2819 gboolean remFlag = FALSE;
2820 TreeItemDelType delType;
2822 if( ! addrbook.treeSelected ) return;
2823 node = addrbook.treeSelected;
2824 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2826 obj = gtk_ctree_node_get_row_data( ctree, node );
2827 g_return_if_fail(obj != NULL);
2829 if( obj->type == ADDR_DATASOURCE ) {
2830 ads = ADAPTER_DSOURCE(obj);
2831 if( ads == NULL ) return;
2832 ds = ads->dataSource;
2833 if( ds == NULL ) return;
2836 /* Must be folder or something else */
2837 ds = addressbook_find_datasource( node );
2838 if( ds == NULL ) return;
2840 /* Only allow deletion from non-readOnly */
2841 iface = ds->interface;
2842 if( iface->readOnly ) {
2843 /* Allow deletion of query results */
2844 if( ! iface->externalQuery ) return;
2848 /* Confirm deletion */
2849 delType = ADDRTREE_DEL_NONE;
2850 if( obj->type == ADDR_ITEM_FOLDER ) {
2851 if( iface->externalQuery ) {
2852 message = g_strdup_printf( _(
2853 "Do you want to delete the query " \
2854 "results and addresses in '%s' ?" ),
2856 aval = alertpanel( _("Delete"), message,
2857 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2859 if( aval == G_ALERTALTERNATE ) {
2860 delType = ADDRTREE_DEL_FOLDER_ADDR;
2864 message = g_strdup_printf
2865 ( _( "Do you want to delete '%s' ? "
2866 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2868 aval = alertpanel( _("Delete folder"), message,
2869 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2871 if( aval == G_ALERTALTERNATE ) {
2872 delType = ADDRTREE_DEL_FOLDER_ONLY;
2874 else if( aval == G_ALERTOTHER ) {
2875 delType = ADDRTREE_DEL_FOLDER_ADDR;
2879 else if( obj->type == ADDR_ITEM_GROUP ) {
2880 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2881 "The addresses it contains will not be lost."), obj->name);
2882 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2883 "+" GTK_STOCK_DELETE, NULL);
2885 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2887 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2888 "The addresses it contains will be lost."), obj->name);
2889 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2890 "+" GTK_STOCK_DELETE, NULL);
2892 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2894 if( delType == ADDRTREE_DEL_NONE ) return;
2896 /* Proceed with deletion */
2897 if( obj->type == ADDR_DATASOURCE ) {
2898 /* Remove node from tree */
2899 gtk_ctree_remove_node( ctree, node );
2901 /* Remove data source. */
2902 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2903 addrindex_free_datasource( ds );
2908 /* Get reference to cache */
2909 adbase = ( AddrBookBase * ) ds->rawDataSource;
2910 if( adbase == NULL ) return;
2911 cache = adbase->addressCache;
2913 /* Remove query results folder */
2914 if( iface->externalQuery ) {
2915 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2916 ItemFolder *folder = adapter->itemFolder;
2918 adapter->itemFolder = NULL;
2920 g_print( "remove folder for ::%s::\n", obj->name );
2921 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2922 g_print( "-------------- remove results\n" );
2924 addrindex_remove_results( ds, folder );
2925 /* g_print( "-------------- remove node\n" ); */
2926 gtk_ctree_remove_node( ctree, node );
2930 /* Code below is valid for regular address book deletion */
2931 if( obj->type == ADDR_ITEM_FOLDER ) {
2932 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2933 ItemFolder *item = adapter->itemFolder;
2935 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2936 /* Remove folder only */
2937 item = addrcache_remove_folder( cache, item );
2939 addritem_free_item_folder( item );
2940 addressbook_move_nodes_up( ctree, node );
2944 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2945 /* Remove folder and addresses */
2946 item = addrcache_remove_folder_delete( cache, item );
2948 addritem_free_item_folder( item );
2953 else if( obj->type == ADDR_ITEM_GROUP ) {
2954 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2955 ItemGroup *item = adapter->itemGroup;
2957 item = addrcache_remove_group( cache, item );
2959 addritem_free_item_group( item );
2966 gtk_ctree_remove_node(ctree, node );
2970 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2972 if( person && addrbook.treeSelected == addrbook.opened ) {
2973 person->status = ADD_ENTRY;
2974 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2975 addressbook_folder_refresh_one_person(
2976 GTK_CTREE(addrbook.clist), person );
2978 addressbook_address_list_set_focus();
2981 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2983 if( person && addrbook.treeSelected == addrbook.opened) {
2984 person->status = ADD_ENTRY;
2985 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2986 addressbook_set_clist(
2987 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2991 addressbook_address_list_set_focus();
2995 * Label (a format string) that is used to name each folder.
2997 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3000 * Search ctree widget callback function.
3001 * \param pA Pointer to node.
3002 * \param pB Pointer to data item being sought.
3003 * \return Zero (0) if folder found.
3005 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3008 aoA = ( AddressObject * ) pA;
3009 if( aoA->type == ADDR_ITEM_FOLDER ) {
3010 ItemFolder *folder, *fld;
3012 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3013 folder = ( ItemFolder * ) pB;
3014 if( fld == folder ) return 0; /* Found folder */
3019 static ItemFolder * addressbook_setup_subf(
3020 AddressDataSource *ds, gchar *title,
3021 GtkCTreeNode *pNode )
3023 AddrBookBase *adbase;
3024 AddressCache *cache;
3027 GtkCTreeNode *nNode;
3029 AddressObjectType aoType = ADDR_NONE;
3032 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3034 if( ds && ds->type == ADDR_IF_LDAP ) {
3036 aoType = ADDR_LDAP_QUERY;
3043 ctree = GTK_CTREE(addrbook.ctree);
3044 /* Get reference to address cache */
3045 adbase = ( AddrBookBase * ) ds->rawDataSource;
3046 cache = adbase->addressCache;
3048 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3049 GList *cur = children;
3050 for (; cur; cur = cur->next) {
3051 ItemFolder *child = (ItemFolder *) cur->data;
3052 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3053 nNode = gtk_ctree_find_by_row_data_custom(
3055 addressbook_treenode_find_folder_cb );
3057 addrindex_remove_results( ds, child );
3058 while( child->listPerson ) {
3059 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3060 item = addrcache_remove_person( cache, item );
3062 addritem_free_item_person( item );
3066 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3067 addrbook.treeSelected = nNode;
3074 /* Create a folder */
3075 folder = addrcache_add_new_folder( cache, NULL );
3076 name = g_strdup_printf( "%s", title );
3077 addritem_folder_set_name( folder, name );
3078 addritem_folder_set_remarks( folder, "" );
3081 /* Now let's see the folder */
3082 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3083 gtk_ctree_expand( ctree, pNode );
3085 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3086 addrbook.treeSelected = nNode;
3092 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3093 AddressObject *pobj = NULL;
3094 AddressDataSource *ds = NULL;
3095 AddressBookFile *abf = NULL;
3096 debug_print("adding address\n");
3097 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3098 if( pobj == NULL ) {
3099 debug_print("no row data\n");
3102 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3104 debug_print("no datasource\n");
3108 abf = ds->rawDataSource;
3110 g_print("no addressbook file\n");
3114 if( pobj->type == ADDR_DATASOURCE ) {
3115 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3116 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3118 ItemFolder *folder = NULL;
3120 if (abf && abf->type == ADDR_IF_LDAP) {
3121 GtkCTreeNode *parentNode;
3122 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3123 if( ds == NULL ) return;
3125 /* We must have a datasource that is an external interface */
3126 if( ! ds->interface->haveLibrary ) return;
3127 if( ! ds->interface->externalQuery ) return;
3129 if( pobj->type == ADDR_ITEM_FOLDER ) {
3130 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3133 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3135 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3137 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3138 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3139 abf = ds->rawDataSource;
3142 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3143 addrbook.editaddress_vbox,
3144 addressbook_new_address_from_book_post_cb,
3147 if (abf && abf->type == ADDR_IF_LDAP) {
3148 LdapServer *server = ds->rawDataSource;
3149 ldapsvr_set_modified(server, TRUE);
3150 ldapsvr_update_book(server, NULL);
3151 if (server->retVal != LDAPRC_SUCCESS) {
3152 alertpanel( _("Add address(es)"),
3153 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3154 GTK_STOCK_CLOSE, NULL, NULL );
3155 server->retVal = LDAPRC_SUCCESS;
3160 if (prefs_common.addressbook_use_editaddress_dialog)
3161 addressbook_new_address_from_book_post_cb( person );
3164 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3166 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3169 if (abf && abf->type == ADDR_IF_LDAP) {
3170 GtkCTreeNode *parentNode;
3171 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3172 if( ds == NULL ) return;
3174 /* We must have a datasource that is an external interface */
3175 if( ! ds->interface->haveLibrary ) return;
3176 if( ! ds->interface->externalQuery ) return;
3178 if( pobj->type == ADDR_ITEM_FOLDER ) {
3179 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3182 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3184 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3187 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3188 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3189 abf = ds->rawDataSource;
3192 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3193 addrbook.editaddress_vbox,
3194 addressbook_new_address_from_folder_post_cb,
3197 if (abf && abf->type == ADDR_IF_LDAP) {
3198 LdapServer *server = ds->rawDataSource;
3199 ldapsvr_set_modified(server, TRUE);
3200 ldapsvr_update_book(server, NULL);
3201 if (server->retVal != LDAPRC_SUCCESS) {
3202 alertpanel( _("Add address(es)"),
3203 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3204 GTK_STOCK_CLOSE, NULL, NULL );
3209 if (prefs_common.addressbook_use_editaddress_dialog)
3210 addressbook_new_address_from_folder_post_cb( person );
3212 else if( pobj->type == ADDR_ITEM_GROUP ) {
3213 /* New address in group */
3214 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3215 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3216 if (addrbook.treeSelected == addrbook.opened) {
3217 /* Change node name in tree. */
3218 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3219 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3220 addressbook_set_clist(
3221 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3229 * Search for specified child group node in address index tree.
3230 * \param parent Parent node.
3231 * \param group Group to find.
3233 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3234 GtkCTreeNode *node = NULL;
3235 GtkCTreeRow *currRow;
3237 currRow = GTK_CTREE_ROW( parent );
3239 node = currRow->children;
3243 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3244 if( obj->type == ADDR_ITEM_GROUP ) {
3245 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3246 if( g == group ) return node;
3248 currRow = GTK_CTREE_ROW(node);
3249 node = currRow->sibling;
3255 static AddressBookFile *addressbook_get_book_file() {
3256 AddressBookFile *abf = NULL;
3257 AddressDataSource *ds = NULL;
3259 ds = addressbook_find_datasource( addrbook.treeSelected );
3260 if( ds == NULL ) return NULL;
3261 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3265 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3269 /* Remove existing folders and groups */
3270 row = GTK_CTREE_ROW( parent );
3272 while( (node = row->children) ) {
3273 gtk_ctree_remove_node( ctree, node );
3278 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3279 GtkCTreeNode *parent, *child;
3280 GtkCTreeRow *currRow;
3281 currRow = GTK_CTREE_ROW( node );
3283 parent = currRow->parent;
3284 while( (child = currRow->children) ) {
3285 gtk_ctree_move( ctree, child, parent, node );
3287 gtk_sctree_sort_node( ctree, parent );
3291 static void addressbook_edit_address_post_cb( ItemPerson *person )
3295 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3296 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3298 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3299 invalidate_address_completion();
3301 addressbook_address_list_set_focus();
3304 void addressbook_address_list_set_focus( void )
3306 if (!prefs_common.addressbook_use_editaddress_dialog) {
3307 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3308 addressbook_list_menu_setup();
3312 void addressbook_address_list_disable_some_actions(void)
3314 /* disable address copy/pasting when editing contact's detail (embedded form) */
3315 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3316 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3317 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3320 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3321 addressbook_edit_address(data, action, widget, TRUE);
3324 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3325 gboolean force_focus ) {
3326 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3328 AddressObject *obj = NULL, *pobj = NULL;
3329 AddressDataSource *ds = NULL;
3330 GtkCTreeNode *node = NULL, *parentNode = NULL;
3332 AddressBookFile *abf = NULL;
3334 if( addrbook.listSelected == NULL ) return;
3335 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3336 g_return_if_fail(obj != NULL);
3338 ctree = GTK_CTREE( addrbook.ctree );
3339 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3340 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3342 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3343 if( ds == NULL ) return;
3345 abf = addressbook_get_book_file();
3347 if( obj->type == ADDR_ITEM_EMAIL ) {
3348 ItemEMail *email = ( ItemEMail * ) obj;
3349 if( email == NULL ) return;
3350 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3351 /* Edit parent group */
3352 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3353 ItemGroup *itemGrp = adapter->itemGroup;
3354 if( abf == NULL ) return;
3355 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3356 name = ADDRITEM_NAME(itemGrp);
3357 node = addrbook.treeSelected;
3358 parentNode = GTK_CTREE_ROW(node)->parent;
3361 /* Edit person - email page */
3363 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3364 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3365 addressbook_edit_address_post_cb,
3366 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3369 if (abf && abf->type == ADDR_IF_LDAP) {
3370 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3371 person->status = UPDATE_ENTRY;
3374 if (prefs_common.addressbook_use_editaddress_dialog)
3375 addressbook_edit_address_post_cb( person );
3380 else if( obj->type == ADDR_ITEM_PERSON ) {
3381 /* Edit person - basic page */
3382 ItemPerson *person = ( ItemPerson * ) obj;
3383 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3384 addressbook_edit_address_post_cb,
3385 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3388 if (abf && abf->type == ADDR_IF_LDAP) {
3389 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3390 person->status = UPDATE_ENTRY;
3393 if (prefs_common.addressbook_use_editaddress_dialog)
3394 addressbook_edit_address_post_cb( person );
3398 else if( obj->type == ADDR_ITEM_GROUP ) {
3399 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3400 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3401 parentNode = addrbook.treeSelected;
3402 node = addressbook_find_group_node( parentNode, itemGrp );
3403 name = ADDRITEM_NAME(itemGrp);
3404 invalidate_address_completion();
3410 /* Update tree node with node name */
3411 if( node == NULL ) return;
3412 addressbook_change_node_name( node, name );
3413 gtk_sctree_sort_node( ctree, parentNode );
3414 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3415 addressbook_set_clist(
3416 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3421 static void addressbook_delete_address_cb(gpointer data, guint action,
3424 addressbook_del_clicked(NULL, NULL);
3427 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3429 addressbook_close();
3432 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3433 addressbook_export_to_file();
3436 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3438 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3439 if( person ) addritem_person_set_opened( person, TRUE );
3443 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3445 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3446 if( person ) addritem_person_set_opened( person, FALSE );
3450 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3452 gchar *eMailAlias = ADDRITEM_NAME(email);
3453 if( eMailAlias && *eMailAlias != '\0' ) {
3455 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3458 str = g_strdup( eMailAlias );
3464 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3465 GList *items = itemGroup->listEMail;
3466 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3467 for( ; items != NULL; items = g_list_next( items ) ) {
3468 GtkCTreeNode *nodeEMail = NULL;
3469 gchar *text[N_LIST_COLS];
3470 ItemEMail *email = items->data;
3474 if( ! email ) continue;
3476 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3477 str = addressbook_format_item_clist( person, email );
3479 text[COL_NAME] = addressbook_set_col_name_guard(str);
3482 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3484 text[COL_ADDRESS] = email->address;
3485 text[COL_REMARKS] = email->remarks;
3486 nodeEMail = gtk_sctree_insert_node(
3488 text, FOLDER_SPACING,
3489 atci->iconXpm, atci->maskXpm,
3490 atci->iconXpmOpen, atci->maskXpmOpen,
3492 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3498 gchar *addressbook_set_col_name_guard(gchar *value)
3500 gchar *ret = "<not set>";
3501 gchar *tmp = g_strdup(value);
3503 if (tmp !=NULL && *tmp != '\0')
3509 static void addressbook_folder_load_one_person(
3510 GtkCTree *clist, ItemPerson *person,
3511 AddressTypeControlItem *atci,
3512 AddressTypeControlItem *atciMail )
3514 GtkCTreeNode *nodePerson = NULL;
3515 GtkCTreeNode *nodeEMail = NULL;
3516 gchar *text[N_LIST_COLS];
3517 gboolean flgFirst = TRUE, haveAddr = FALSE;
3520 AddressBookFile *abf = addressbook_get_book_file();
3523 if( person == NULL ) return;
3525 text[COL_NAME] = "";
3526 node = person->listEMail;
3528 ItemEMail *email = node->data;
3529 gchar *eMailAddr = NULL;
3530 node = g_list_next( node );
3532 text[COL_ADDRESS] = email->address;
3533 text[COL_REMARKS] = email->remarks;
3534 eMailAddr = ADDRITEM_NAME(email);
3535 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3537 /* First email belongs with person */
3538 gchar *str = addressbook_format_item_clist( person, email );
3540 text[COL_NAME] = addressbook_set_col_name_guard(str);
3543 else if( abf && abf->type == ADDR_IF_LDAP &&
3544 person && person->nickName ) {
3545 if (person->nickName) {
3546 if (strcmp(person->nickName, "") != 0) {
3547 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3550 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3556 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3558 nodePerson = gtk_sctree_insert_node(
3560 text, FOLDER_SPACING,
3561 atci->iconXpm, atci->maskXpm,
3562 atci->iconXpmOpen, atci->maskXpmOpen,
3563 FALSE, person->isOpened );
3566 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3569 /* Subsequent email is a child node of person */
3570 text[COL_NAME] = ADDRITEM_NAME(email);
3571 nodeEMail = gtk_sctree_insert_node(
3572 clist, nodePerson, NULL,
3573 text, FOLDER_SPACING,
3574 atciMail->iconXpm, atciMail->maskXpm,
3575 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3577 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3583 /* Have name without EMail */
3584 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3585 text[COL_ADDRESS] = "";
3586 text[COL_REMARKS] = "";
3587 nodePerson = gtk_sctree_insert_node(
3589 text, FOLDER_SPACING,
3590 atci->iconXpm, atci->maskXpm,
3591 atci->iconXpmOpen, atci->maskXpmOpen,
3592 FALSE, person->isOpened );
3593 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3598 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3600 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3601 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3603 if( atci == NULL ) return;
3604 if( atciMail == NULL ) return;
3606 /* Load email addresses */
3607 items = addritem_folder_get_person_list( itemFolder );
3608 for( ; items != NULL; items = g_list_next( items ) ) {
3609 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3611 /* Free up the list */
3612 mgu_clear_list( items );
3613 g_list_free( items );
3616 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3617 addrbook.listSelected = NULL;
3618 gtk_ctree_remove_node( clist, node );
3619 addressbook_menubar_set_sensitive( FALSE );
3620 addressbook_menuitem_set_sensitive(
3621 gtk_ctree_node_get_row_data(
3622 GTK_CTREE(clist), addrbook.treeSelected ),
3623 addrbook.treeSelected );
3626 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3627 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3628 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3630 if( atci == NULL ) return;
3631 if( atciMail == NULL ) return;
3632 if( person == NULL ) return;
3633 /* unload the person */
3635 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3637 addressbook_folder_remove_node( clist, node );
3638 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3639 gtk_sctree_sort_node( clist, NULL );
3640 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3642 gtk_sctree_select( GTK_SCTREE(clist), node );
3643 if (!gtk_ctree_node_is_visible( clist, node ) )
3644 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3648 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3652 if( person == NULL ) return;
3653 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3654 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3656 addressbook_folder_remove_node( clist, node );
3660 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3662 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3664 /* Load any groups */
3665 if( ! atci ) return;
3666 items = addritem_folder_get_group_list( itemFolder );
3667 for( ; items != NULL; items = g_list_next( items ) ) {
3668 GtkCTreeNode *nodeGroup = NULL;
3669 gchar *text[N_LIST_COLS];
3670 ItemGroup *group = items->data;
3671 if( group == NULL ) continue;
3672 text[COL_NAME] = ADDRITEM_NAME(group);
3673 text[COL_ADDRESS] = "";
3674 text[COL_REMARKS] = "";
3675 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3676 text, FOLDER_SPACING,
3677 atci->iconXpm, atci->maskXpm,
3678 atci->iconXpmOpen, atci->maskXpmOpen,
3680 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3681 gtk_sctree_sort_node(clist, NULL);
3683 /* Free up the list */
3684 mgu_clear_list( items );
3685 g_list_free( items );
3689 * Search ctree widget callback function.
3690 * \param pA Pointer to node.
3691 * \param pB Pointer to data item being sought.
3692 * \return Zero (0) if group found.
3694 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3697 aoA = ( AddressObject * ) pA;
3698 if( aoA->type == ADDR_ITEM_GROUP ) {
3699 ItemGroup *group, *grp;
3701 grp = ADAPTER_GROUP(aoA)->itemGroup;
3702 group = ( ItemGroup * ) pB;
3703 if( grp == group ) return 0; /* Found group */
3709 * Remove folder and group nodes from tree widget for items contained ("cut")
3712 static void addressbook_treenode_remove_item( void ) {
3714 AddrSelectItem *cutItem;
3715 AddressCache *cache;
3716 AddrItemObject *aio;
3717 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3720 node = _clipBoard_->objectList;
3722 cutItem = node->data;
3723 node = g_list_next( node );
3724 cache = addrindex_get_cache(
3725 _clipBoard_->addressIndex, cutItem->cacheID );
3726 if( cache == NULL ) continue;
3727 aio = addrcache_get_object( cache, cutItem->uid );
3730 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3733 folder = ( ItemFolder * ) aio;
3734 tn = gtk_ctree_find_by_row_data_custom(
3735 ctree, NULL, folder,
3736 addressbook_treenode_find_folder_cb );
3738 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3741 group = ( ItemGroup * ) aio;
3742 tn = gtk_ctree_find_by_row_data_custom(
3744 addressbook_treenode_find_group_cb );
3748 /* Free up adapter and remove node. */
3749 gtk_ctree_remove_node( ctree, tn );
3756 * Find parent datasource for specified tree node.
3757 * \param node Node to test.
3758 * \return Data source, or NULL if not found.
3760 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3761 AddressDataSource *ds = NULL;
3764 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3767 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3768 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3770 /* g_print( "ao->type = %d\n", ao->type ); */
3771 if( ao->type == ADDR_DATASOURCE ) {
3772 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3773 /* g_print( "found it\n" ); */
3774 ds = ads->dataSource;
3778 node = GTK_CTREE_ROW(node)->parent;
3784 * Load address list widget with children of specified object.
3785 * \param obj Parent object to be loaded.
3787 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3788 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3789 GtkCList *clist = GTK_CLIST(addrbook.clist);
3790 AddressDataSource *ds = NULL;
3791 AdapterDSource *ads = NULL;
3792 static AddressObject *last_obj = NULL;
3794 if (addrbook.clist == NULL) {
3797 if (obj == last_obj && !refresh)
3802 gtk_clist_clear(clist);
3806 if( obj->type == ADDR_INTERFACE ) {
3807 /* g_print( "set_clist: loading datasource...\n" ); */
3808 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3812 gtk_clist_freeze(clist);
3813 gtk_clist_clear(clist);
3815 if( obj->type == ADDR_DATASOURCE ) {
3816 ads = ADAPTER_DSOURCE(obj);
3817 ds = ADAPTER_DSOURCE(obj)->dataSource;
3819 /* Load root folder */
3820 ItemFolder *rootFolder = NULL;
3821 rootFolder = addrindex_ds_get_root_folder( ds );
3822 addressbook_folder_load_person(
3823 ctreelist, addrindex_ds_get_root_folder( ds ) );
3824 addressbook_folder_load_group(
3825 ctreelist, addrindex_ds_get_root_folder( ds ) );
3829 if( obj->type == ADDR_ITEM_GROUP ) {
3831 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3832 addressbook_load_group( ctreelist, itemGroup );
3834 else if( obj->type == ADDR_ITEM_FOLDER ) {
3836 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3837 addressbook_folder_load_person( ctreelist, itemFolder );
3838 addressbook_folder_load_group( ctreelist, itemFolder );
3841 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3842 clist->focus_row = -1;
3843 gtk_clist_thaw(clist);
3847 * Call back function to free adaptor. Call back is setup by function
3848 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3849 * called when the address book tree widget node is removed by calling
3850 * function gtk_ctree_remove_node().
3852 * \param data Tree node's row data.
3854 static void addressbook_free_treenode( gpointer data ) {
3857 ao = ( AddressObject * ) data;
3858 if( ao == NULL ) return;
3859 if( ao->type == ADDR_INTERFACE ) {
3860 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3861 addrbookctl_free_interface( ai );
3863 else if( ao->type == ADDR_DATASOURCE ) {
3864 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3865 addrbookctl_free_datasource( ads );
3867 else if( ao->type == ADDR_ITEM_FOLDER ) {
3868 AdapterFolder *af = ADAPTER_FOLDER(ao);
3869 addrbookctl_free_folder( af );
3871 else if( ao->type == ADDR_ITEM_GROUP ) {
3872 AdapterGroup *ag = ADAPTER_GROUP(ao);
3873 addrbookctl_free_group( ag );
3878 * Create new adaptor for specified data source.
3880 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3881 AddressObjectType otype, gchar *name )
3883 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3884 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3885 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3886 adapter->dataSource = ds;
3887 adapter->subType = otype;
3891 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3892 ADDRESS_OBJECT_NAME(adapter) =
3893 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3897 * Load tree from address index with the initial data.
3899 static void addressbook_load_tree( void ) {
3900 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3901 GList *nodeIf, *nodeDS;
3902 AdapterInterface *adapter;
3903 AddressInterface *iface;
3904 AddressTypeControlItem *atci;
3905 AddressDataSource *ds;
3906 AdapterDSource *ads;
3907 GtkCTreeNode *node, *newNode;
3910 nodeIf = _addressInterfaceList_;
3912 adapter = nodeIf->data;
3913 node = adapter->treeNode;
3914 iface = adapter->interface;
3915 atci = adapter->atci;
3917 if( iface->useInterface ) {
3918 /* Load data sources below interface node */
3919 nodeDS = iface->listSource;
3923 name = addrindex_ds_get_name( ds );
3924 ads = addressbook_create_ds_adapter(
3925 ds, atci->objectType, name );
3926 newNode = addressbook_add_object(
3927 node, ADDRESS_OBJECT(ads) );
3928 nodeDS = g_list_next( nodeDS );
3930 gtk_ctree_expand( ctree, node );
3933 nodeIf = g_list_next( nodeIf );
3938 * Convert the old address book to new format.
3940 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3941 gboolean retVal = FALSE;
3942 gboolean errFlag = TRUE;
3945 /* Read old address book, performing conversion */
3946 debug_print( "Reading and converting old address book...\n" );
3947 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3948 addrindex_read_data( addrIndex );
3949 if( addrIndex->retVal == MGU_NO_FILE ) {
3950 /* We do not have a file - new user */
3951 debug_print( "New user... create new books...\n" );
3952 addrindex_create_new_books( addrIndex );
3953 if( addrIndex->retVal == MGU_SUCCESS ) {
3954 /* Save index file */
3955 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3956 addrindex_save_data( addrIndex );
3957 if( addrIndex->retVal == MGU_SUCCESS ) {
3962 msg = _( "New user, could not save index file." );
3966 msg = _( "New user, could not save address book files." );
3970 /* We have an old file */
3971 if( addrIndex->wasConverted ) {
3972 /* Converted successfully - save address index */
3973 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3974 addrindex_save_data( addrIndex );
3975 if( addrIndex->retVal == MGU_SUCCESS ) {
3976 msg = _( "Old address book converted successfully." );
3981 msg = _("Old address book converted,\n"
3982 "could not save new address index file." );
3986 /* File conversion failed - just create new books */
3987 debug_print( "File conversion failed... just create new books...\n" );
3988 addrindex_create_new_books( addrIndex );
3989 if( addrIndex->retVal == MGU_SUCCESS ) {
3991 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3992 addrindex_save_data( addrIndex );
3993 if( addrIndex->retVal == MGU_SUCCESS ) {
3994 msg = _("Could not convert address book,\n"
3995 "but created empty new address book files." );
4000 msg = _("Could not convert address book,\n"
4001 "could not save new address index file." );
4005 msg = _("Could not convert address book\n"
4006 "and could not create new address book files." );
4011 debug_print( "Error\n%s\n", msg );
4012 alertpanel_full(_("Addressbook conversion error"), msg,
4013 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4014 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4017 debug_print( "Warning\n%s\n", msg );
4018 alertpanel_full(_("Addressbook conversion error"), msg,
4019 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4020 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4026 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4030 gboolean failed = FALSE;
4032 if( ( dp = opendir( origdir ) ) == NULL ) {
4036 while( ( d = readdir( dp ) ) != NULL ) {
4037 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4040 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4042 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4044 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4057 /* all copies succeeded, we can remove source files */
4058 if( ( dp = opendir( origdir ) ) == NULL ) {
4061 while( ( d = readdir( dp ) ) != NULL ) {
4062 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4065 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4067 claws_unlink(orig_file);
4077 void addressbook_read_file( void ) {
4078 AddressIndex *addrIndex = NULL;
4079 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4081 debug_print( "Reading address index...\n" );
4082 if( _addressIndex_ ) {
4083 debug_print( "address book already read!!!\n" );
4087 addrIndex = addrindex_create_index();
4088 addrindex_initialize();
4090 /* Use new address book index. */
4092 if ( !is_dir_exist(indexdir) ) {
4093 if ( make_dir(indexdir) < 0 ) {
4094 addrindex_set_file_path( addrIndex, get_rc_dir() );
4095 g_warning( "couldn't create dir %s\n", indexdir);
4097 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4098 remove_dir_recursive(indexdir);
4099 addrindex_set_file_path( addrIndex, get_rc_dir() );
4100 g_error("couldn't migrate dir %s", indexdir);
4102 addrindex_set_file_path( addrIndex, indexdir);
4106 addrindex_set_file_path( addrIndex, indexdir);
4109 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4110 addrindex_read_data( addrIndex );
4111 if( addrIndex->retVal == MGU_NO_FILE ) {
4112 /* Conversion required */
4113 debug_print( "Converting...\n" );
4114 if( addressbook_convert( addrIndex ) ) {
4115 _addressIndex_ = addrIndex;
4118 else if( addrIndex->retVal == MGU_SUCCESS ) {
4119 _addressIndex_ = addrIndex;
4122 /* Error reading address book */
4123 debug_print( "Could not read address index.\n" );
4124 addrindex_print_index( addrIndex, stdout );
4125 alertpanel_full(_("Addressbook Error"),
4126 _("Could not read address index"),
4127 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4128 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4130 debug_print( "done.\n" );
4134 * Add object into the address index tree widget.
4135 * Enter: node Parent node.
4136 * obj Object to add.
4137 * Return: Node that was added, or NULL if object not added.
4139 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
4142 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4143 GtkCTreeNode *added;
4144 AddressObject *pobj;
4145 AddressObjectType otype;
4146 AddressTypeControlItem *atci = NULL;
4148 g_return_val_if_fail(node != NULL, NULL);
4149 g_return_val_if_fail(obj != NULL, NULL);
4151 pobj = gtk_ctree_node_get_row_data(ctree, node);
4152 g_return_val_if_fail(pobj != NULL, NULL);
4154 /* Determine object type to be displayed */
4155 if( obj->type == ADDR_DATASOURCE ) {
4156 otype = ADAPTER_DSOURCE(obj)->subType;
4162 /* Handle any special conditions. */
4164 atci = addrbookctl_lookup( otype );
4166 if( atci->showInTree ) {
4167 /* Add object to tree */
4170 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4171 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4172 atci->treeLeaf, atci->treeExpand );
4173 gtk_ctree_node_set_row_data_full( ctree, added, obj,
4174 addressbook_free_treenode );
4178 gtk_sctree_sort_node(ctree, node);
4184 * Add group into the address index tree.
4185 * \param node Parent node.
4186 * \param ds Data source.
4187 * \param itemGroup Group to add.
4188 * \return Inserted node.
4190 static GtkCTreeNode *addressbook_node_add_group(
4191 GtkCTreeNode *node, AddressDataSource *ds,
4192 ItemGroup *itemGroup )
4194 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4195 GtkCTreeNode *newNode;
4196 AdapterGroup *adapter;
4197 AddressTypeControlItem *atci = NULL;
4200 if( ds == NULL ) return NULL;
4201 if( node == NULL || itemGroup == NULL ) return NULL;
4203 name = &itemGroup->obj.name;
4205 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4207 adapter = g_new0( AdapterGroup, 1 );
4208 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4209 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4210 adapter->itemGroup = itemGroup;
4212 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4213 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4214 atci->treeLeaf, atci->treeExpand );
4215 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4216 addressbook_free_treenode );
4217 gtk_sctree_sort_node( ctree, node );
4222 * Add folder into the address index tree. Only visible folders are loaded into
4223 * the address index tree. Note that the root folder is not inserted into the
4226 * \param node Parent node.
4227 * \param ds Data source.
4228 * \param itemFolder Folder to add.
4229 * \param otype Object type to display.
4230 * \return Inserted node for the folder.
4232 static GtkCTreeNode *addressbook_node_add_folder(
4233 GtkCTreeNode *node, AddressDataSource *ds,
4234 ItemFolder *itemFolder, AddressObjectType otype )
4236 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4237 GtkCTreeNode *newNode = NULL;
4238 AdapterFolder *adapter;
4239 AddressTypeControlItem *atci = NULL;
4240 GList *listItems = NULL;
4242 ItemFolder *rootFolder;
4244 /* Only visible folders */
4245 if( itemFolder->isHidden ) return NULL;
4247 if( ds == NULL ) return NULL;
4248 if( node == NULL || itemFolder == NULL ) return NULL;
4250 /* Determine object type */
4251 atci = addrbookctl_lookup( otype );
4252 if( atci == NULL ) return NULL;
4254 rootFolder = addrindex_ds_get_root_folder( ds );
4255 if( itemFolder == rootFolder ) {
4259 adapter = g_new0( AdapterFolder, 1 );
4260 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4261 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4262 adapter->itemFolder = itemFolder;
4264 name = ADDRITEM_NAME(itemFolder);
4265 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4266 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4267 atci->treeLeaf, atci->treeExpand );
4269 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4270 addressbook_free_treenode );
4274 listItems = itemFolder->listFolder;
4275 while( listItems ) {
4276 ItemFolder *item = listItems->data;
4277 addressbook_node_add_folder( newNode, ds, item, otype );
4278 listItems = g_list_next( listItems );
4280 listItems = itemFolder->listGroup;
4281 while( listItems ) {
4282 ItemGroup *item = listItems->data;
4283 addressbook_node_add_group( newNode, ds, item );
4284 listItems = g_list_next( listItems );
4286 gtk_sctree_sort_node( ctree, node );
4290 void addressbook_export_to_file( void ) {
4291 if( _addressIndex_ ) {
4292 /* Save all new address book data */
4293 debug_print( "Saving address books...\n" );
4294 addrindex_save_all_books( _addressIndex_ );
4296 debug_print( "Exporting addressbook to file...\n" );
4297 addrindex_save_data( _addressIndex_ );
4298 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4299 addrindex_print_index( _addressIndex_, stdout );
4302 /* Notify address completion of new data */
4303 invalidate_address_completion();
4307 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4309 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4310 addressbook_lup_clicked(NULL, NULL);
4315 * Comparison using cell contents (text in first column). Used for sort
4316 * address index widget.
4318 static gint addressbook_treenode_compare_func(
4319 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4321 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4322 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4323 gchar *name1 = NULL, *name2 = NULL;
4324 if( cell1 ) name1 = cell1->u.text;
4325 if( cell2 ) name2 = cell2->u.text;
4326 if( ! name1 ) return ( name2 != NULL );
4327 if( ! name2 ) return -1;
4328 return g_utf8_collate( name1, name2 );
4331 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4332 AdapterDSource *ads;
4333 AdapterInterface *adapter;
4334 GtkCTreeNode *newNode;
4336 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4337 if( adapter == NULL ) return;
4338 ads = addressbook_edit_book( _addressIndex_, NULL );
4340 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4342 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4343 addrbook.treeSelected = newNode;
4348 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4349 AdapterDSource *ads;
4350 AdapterInterface *adapter;
4351 GtkCTreeNode *newNode;
4353 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4354 if( adapter == NULL ) return;
4355 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4357 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4359 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4360 addrbook.treeSelected = newNode;
4366 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4367 AdapterDSource *ads;
4368 AdapterInterface *adapter;
4369 AddressInterface *iface;
4370 GtkCTreeNode *newNode;
4372 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4373 if( adapter == NULL ) return;
4374 iface = adapter->interface;
4375 if( ! iface->haveLibrary ) return;
4376 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4378 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4380 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4381 addrbook.treeSelected = newNode;
4388 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4389 AdapterDSource *ads;
4390 AdapterInterface *adapter;
4391 AddressInterface *iface;
4392 GtkCTreeNode *newNode;
4394 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4395 if( adapter == NULL ) return;
4396 iface = adapter->interface;
4397 if( ! iface->haveLibrary ) return;
4398 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4400 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4402 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4403 addrbook.treeSelected = newNode;
4410 * Display address search status message.
4411 * \param queryType Query type.
4412 * \param status Status/Error code.
4414 static void addressbook_search_message( gint queryType, gint sts ) {
4416 *addressbook_msgbuf = '\0';
4418 if( sts != MGU_SUCCESS ) {
4419 if( queryType == ADDRQUERY_LDAP ) {
4421 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4426 g_snprintf( addressbook_msgbuf,
4427 sizeof(addressbook_msgbuf), "%s", desc );
4428 addressbook_status_show( addressbook_msgbuf );
4431 addressbook_status_show( "" );
4436 * Refresh addressbook by forcing refresh of current selected object in
4439 static void addressbook_refresh_current( void ) {
4443 ctree = GTK_CTREE(addrbook.ctree);
4444 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4445 if( obj == NULL ) return;
4446 addressbook_set_clist( obj, TRUE );
4450 * Message that is displayed whilst a query is executing in a background
4453 static gchar *_tempMessage_ = N_( "Busy searching..." );
4456 * Address search idle function. This function is called during UI idle time
4457 * while a search is in progress.
4459 * \param data Idler data.
4461 static void addressbook_search_idle( gpointer data ) {
4465 queryID = GPOINTER_TO_INT( data );
4466 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4471 * Search completion callback function. This removes the query from the idle
4474 * \param sender Sender of query.
4475 * \param queryID Query ID of search request.
4476 * \param status Search status.
4477 * \param data Query data.
4479 static void addressbook_search_callback_end(
4480 gpointer sender, gint queryID, gint status, gpointer data )
4484 AddrQueryObject *aqo;
4486 /* Remove idler function */
4487 ptrQID = GINT_TO_POINTER( queryID );
4489 g_idle_remove_by_data( ptrQID );
4492 /* Refresh addressbook contents */
4493 addressbook_refresh_current();
4494 req = qrymgr_find_request( queryID );
4496 aqo = ( AddrQueryObject * ) req->queryList->data;
4497 addressbook_search_message( aqo->queryType, status );
4500 /* Stop the search */
4501 addrindex_stop_search( queryID );
4507 * \param ds Data source to search.
4508 * \param searchTerm String to lookup.
4509 * \param pNode Parent data source node.
4511 static void addressbook_perform_search(
4512 AddressDataSource *ds, gchar *searchTerm,
4513 GtkCTreeNode *pNode )
4515 AddrBookBase *adbase;
4516 AddressCache *cache;
4522 AddressObjectType aoType = ADDR_NONE;
4526 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4528 if( ds && ds->type == ADDR_IF_LDAP ) {
4530 aoType = ADDR_LDAP_QUERY;
4536 /* Get reference to address cache */
4537 adbase = ( AddrBookBase * ) ds->rawDataSource;
4538 cache = adbase->addressCache;
4540 /* Create a folder for the search results */
4541 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4542 folder = addressbook_setup_subf(ds, name, pNode);
4545 /* Setup the search */
4546 queryID = addrindex_setup_explicit_search(
4547 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4548 if( queryID == 0 ) return;
4550 /* Set up idler function */
4551 idleID = g_idle_add(
4552 ( GtkFunction ) addressbook_search_idle,
4553 GINT_TO_POINTER( queryID ) );
4555 /* Start search, sit back and wait for something to happen */
4556 addrindex_start_search( queryID );
4558 addressbook_status_show( _tempMessage_ );
4562 * Lookup button handler. Address search is only performed against
4563 * address interfaces for external queries.
4565 * \param button Lookup button widget.
4566 * \param data Data object.
4568 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4571 AddressDataSource *ds;
4572 AddressInterface *iface;
4574 GtkCTreeNode *node, *parentNode;
4576 node = addrbook.treeSelected;
4577 if( ! node ) return;
4578 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4580 ctree = GTK_CTREE(addrbook.ctree);
4581 obj = gtk_ctree_node_get_row_data( ctree, node );
4582 if( obj == NULL ) return;
4584 ds = addressbook_find_datasource( node );
4585 if( ds == NULL ) return;
4587 /* We must have a datasource that is an external interface */
4588 iface = ds->interface;
4589 if( ! iface->haveLibrary ) return;
4590 if( ! iface->externalQuery ) return;
4593 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4594 g_strchomp( searchTerm );
4596 if( obj->type == ADDR_ITEM_FOLDER ) {
4597 parentNode = GTK_CTREE_ROW(node)->parent;
4602 addressbook_perform_search( ds, searchTerm, parentNode );
4604 gtk_widget_grab_focus( addrbook.entry );
4606 g_free( searchTerm );
4609 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4610 addressbook_close();
4615 * Browse address entry for highlighted entry.
4617 static void addressbook_browse_entry_cb(void)
4619 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4621 AddressDataSource *ds;
4622 AddressInterface *iface;
4626 if(addrbook.listSelected == NULL)
4629 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4633 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4637 iface = ds->interface;
4638 if(! iface->haveLibrary )
4642 if (obj->type == ADDR_ITEM_EMAIL) {
4643 email = ( ItemEMail * ) obj;
4647 person = (ItemPerson *) ADDRITEM_PARENT(email);
4649 else if (obj->type == ADDR_ITEM_PERSON) {
4650 person = (ItemPerson *) obj;
4657 if( iface && iface->type == ADDR_IF_LDAP ) {
4658 browseldap_entry(ds, person->externalID);
4663 /* **********************************************************************
4664 * Build lookup tables.
4665 * ***********************************************************************
4669 * Remap object types.
4670 * Enter: abType AddressObjectType (used in tree node).
4671 * Return: ItemObjectType (used in address cache data).
4673 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4674 ItemObjectType ioType;
4677 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4678 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4679 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4680 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4681 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4682 default: ioType = ITEMTYPE_NONE; break;
4688 * Build table that controls the rendering of object types.
4690 static void addrbookctl_build_map( GtkWidget *window ) {
4691 AddressTypeControlItem *atci;
4694 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4695 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4696 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4697 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4698 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4699 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4700 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4701 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4702 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4703 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4705 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4706 _addressBookTypeList_ = NULL;
4709 atci = g_new0( AddressTypeControlItem, 1 );
4710 atci->objectType = ADDR_INTERFACE;
4711 atci->interfaceType = ADDR_IF_NONE;
4712 atci->showInTree = TRUE;
4713 atci->treeExpand = TRUE;
4714 atci->treeLeaf = FALSE;
4715 atci->displayName = _( "Interface" );
4716 atci->iconXpm = folderxpm;
4717 atci->maskXpm = folderxpmmask;
4718 atci->iconXpmOpen = folderopenxpm;
4719 atci->maskXpmOpen = folderopenxpmmask;
4720 atci->menuCommand = NULL;
4721 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4722 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4725 atci = g_new0( AddressTypeControlItem, 1 );
4726 atci->objectType = ADDR_BOOK;
4727 atci->interfaceType = ADDR_IF_BOOK;
4728 atci->showInTree = TRUE;
4729 atci->treeExpand = TRUE;
4730 atci->treeLeaf = FALSE;
4731 atci->displayName = _( "Address Book" );
4732 atci->iconXpm = bookxpm;
4733 atci->maskXpm = bookxpmmask;
4734 atci->iconXpmOpen = bookxpm;
4735 atci->maskXpmOpen = bookxpmmask;
4736 atci->menuCommand = "/Book/New Book";
4737 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4738 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4741 atci = g_new0( AddressTypeControlItem, 1 );
4742 atci->objectType = ADDR_ITEM_PERSON;
4743 atci->interfaceType = ADDR_IF_NONE;
4744 atci->showInTree = FALSE;
4745 atci->treeExpand = FALSE;
4746 atci->treeLeaf = FALSE;
4747 atci->displayName = _( "Person" );
4748 atci->iconXpm = NULL;
4749 atci->maskXpm = NULL;
4750 atci->iconXpmOpen = NULL;
4751 atci->maskXpmOpen = NULL;
4752 atci->menuCommand = NULL;
4753 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4754 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4757 atci = g_new0( AddressTypeControlItem, 1 );
4758 atci->objectType = ADDR_ITEM_EMAIL;
4759 atci->interfaceType = ADDR_IF_NONE;
4760 atci->showInTree = FALSE;
4761 atci->treeExpand = FALSE;
4762 atci->treeLeaf = TRUE;
4763 atci->displayName = _( "Email Address" );
4764 atci->iconXpm = addressxpm;
4765 atci->maskXpm = addressxpmmask;
4766 atci->iconXpmOpen = addressxpm;
4767 atci->maskXpmOpen = addressxpmmask;
4768 atci->menuCommand = NULL;
4769 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4770 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4773 atci = g_new0( AddressTypeControlItem, 1 );
4774 atci->objectType = ADDR_ITEM_GROUP;
4775 atci->interfaceType = ADDR_IF_BOOK;
4776 atci->showInTree = TRUE;
4777 atci->treeExpand = FALSE;
4778 atci->treeLeaf = FALSE;
4779 atci->displayName = _( "Group" );
4780 atci->iconXpm = groupxpm;
4781 atci->maskXpm = groupxpmmask;
4782 atci->iconXpmOpen = groupxpm;
4783 atci->maskXpmOpen = groupxpmmask;
4784 atci->menuCommand = NULL;
4785 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4786 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4789 atci = g_new0( AddressTypeControlItem, 1 );
4790 atci->objectType = ADDR_ITEM_FOLDER;
4791 atci->interfaceType = ADDR_IF_BOOK;
4792 atci->showInTree = TRUE;
4793 atci->treeExpand = FALSE;
4794 atci->treeLeaf = FALSE;
4795 atci->displayName = _( "Folder" );
4796 atci->iconXpm = folderxpm;
4797 atci->maskXpm = folderxpmmask;
4798 atci->iconXpmOpen = folderopenxpm;
4799 atci->maskXpmOpen = folderopenxpmmask;
4800 atci->menuCommand = NULL;
4801 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4802 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4805 atci = g_new0( AddressTypeControlItem, 1 );
4806 atci->objectType = ADDR_VCARD;
4807 atci->interfaceType = ADDR_IF_VCARD;
4808 atci->showInTree = TRUE;
4809 atci->treeExpand = TRUE;
4810 atci->treeLeaf = TRUE;
4811 atci->displayName = _( "vCard" );
4812 atci->iconXpm = vcardxpm;
4813 atci->maskXpm = vcardxpmmask;
4814 atci->iconXpmOpen = vcardxpm;
4815 atci->maskXpmOpen = vcardxpmmask;
4816 atci->menuCommand = "/Book/New vCard";
4817 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4818 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4821 atci = g_new0( AddressTypeControlItem, 1 );
4822 atci->objectType = ADDR_JPILOT;
4823 atci->interfaceType = ADDR_IF_JPILOT;
4824 atci->showInTree = TRUE;
4825 atci->treeExpand = TRUE;
4826 atci->treeLeaf = FALSE;
4827 atci->displayName = _( "JPilot" );
4828 atci->iconXpm = jpilotxpm;
4829 atci->maskXpm = jpilotxpmmask;
4830 atci->iconXpmOpen = jpilotxpm;
4831 atci->maskXpmOpen = jpilotxpmmask;
4832 atci->menuCommand = "/Book/New JPilot";
4833 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4834 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4837 atci = g_new0( AddressTypeControlItem, 1 );
4838 atci->objectType = ADDR_CATEGORY;
4839 atci->interfaceType = ADDR_IF_JPILOT;
4840 atci->showInTree = TRUE;
4841 atci->treeExpand = TRUE;
4842 atci->treeLeaf = TRUE;
4843 atci->displayName = _( "JPilot" );
4844 atci->iconXpm = categoryxpm;
4845 atci->maskXpm = categoryxpmmask;
4846 atci->iconXpmOpen = categoryxpm;
4847 atci->maskXpmOpen = categoryxpmmask;
4848 atci->menuCommand = NULL;
4849 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4850 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4853 atci = g_new0( AddressTypeControlItem, 1 );
4854 atci->objectType = ADDR_LDAP;
4855 atci->interfaceType = ADDR_IF_LDAP;
4856 atci->showInTree = TRUE;
4857 atci->treeExpand = TRUE;
4858 atci->treeLeaf = FALSE;
4859 atci->displayName = _( "LDAP servers" );
4860 atci->iconXpm = ldapxpm;
4861 atci->maskXpm = ldapxpmmask;
4862 atci->iconXpmOpen = ldapxpm;
4863 atci->maskXpmOpen = ldapxpmmask;
4864 atci->menuCommand = "/Book/New LDAP Server";
4865 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4866 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4869 atci = g_new0( AddressTypeControlItem, 1 );
4870 atci->objectType = ADDR_LDAP_QUERY;
4871 atci->interfaceType = ADDR_IF_LDAP;
4872 atci->showInTree = TRUE;
4873 atci->treeExpand = FALSE;
4874 atci->treeLeaf = TRUE;
4875 atci->displayName = _( "LDAP Query" );
4876 atci->iconXpm = addrsearchxpm;
4877 atci->maskXpm = addrsearchxpmmask;
4878 atci->iconXpmOpen = addrsearchxpm;
4879 atci->maskXpmOpen = addrsearchxpmmask;
4880 atci->menuCommand = NULL;
4881 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4882 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4887 * Search for specified object type.
4889 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4891 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4895 * Search for specified interface type.
4897 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4898 GList *node = _addressBookTypeList_;
4900 AddressTypeControlItem *atci = node->data;
4901 if( atci->interfaceType == ifType ) return atci;
4902 node = g_list_next( node );
4907 static void addrbookctl_free_address( AddressObject *obj ) {
4908 g_free( obj->name );
4909 obj->type = ADDR_NONE;
4913 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4914 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4915 adapter->interface = NULL;
4916 adapter->interfaceType = ADDR_IF_NONE;
4917 adapter->atci = NULL;
4918 adapter->enabled = FALSE;
4919 adapter->haveLibrary = FALSE;
4920 adapter->treeNode = NULL;
4924 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4925 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4926 adapter->dataSource = NULL;
4927 adapter->subType = ADDR_NONE;
4931 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4932 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4933 adapter->itemFolder = NULL;
4937 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4938 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4939 adapter->itemGroup = NULL;
4944 * Build GUI interface list.
4946 static void addrbookctl_build_iflist( void ) {
4947 AddressTypeControlItem *atci;
4948 AdapterInterface *adapter;
4951 if( _addressIndex_ == NULL ) {
4952 _addressIndex_ = addrindex_create_index();
4953 if( _clipBoard_ == NULL ) {
4954 _clipBoard_ = addrclip_create();
4956 addrclip_set_index( _clipBoard_, _addressIndex_ );
4958 _addressInterfaceList_ = NULL;
4959 list = addrindex_get_interface_list( _addressIndex_ );
4961 AddressInterface *interface = list->data;
4962 atci = addrbookctl_lookup_iface( interface->type );
4964 adapter = g_new0( AdapterInterface, 1 );
4965 adapter->interfaceType = interface->type;
4966 adapter->atci = atci;
4967 adapter->interface = interface;
4968 adapter->treeNode = NULL;
4969 adapter->enabled = TRUE;
4970 adapter->haveLibrary = interface->haveLibrary;
4971 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4972 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4973 _addressInterfaceList_ =
4974 g_list_append( _addressInterfaceList_, adapter );
4976 list = g_list_next( list );
4981 * Find GUI interface type specified interface type.
4982 * \param ifType Interface type.
4983 * \return Interface item, or NULL if not found.
4985 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4986 GList *node = _addressInterfaceList_;
4988 AdapterInterface *adapter = node->data;
4989 if( adapter->interfaceType == ifType ) return adapter;
4990 node = g_list_next( node );
4996 * Build interface list selection.
4998 static void addrbookctl_build_ifselect( void ) {
4999 GList *newList = NULL;
5004 gchar *endptr = NULL;
5006 AdapterInterface *adapter;
5008 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5011 splitStr = g_strsplit( selectStr, ",", -1 );
5012 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5014 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5015 ifType = strtol( splitStr[i], &endptr, 10 );
5018 if( strcmp( endptr, "/n" ) == 0 ) {
5022 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5023 adapter = addrbookctl_find_interface( ifType );
5025 newList = g_list_append( newList, adapter );
5032 /* g_print( "i=%d\n", i ); */
5033 g_strfreev( splitStr );
5034 g_free( selectStr );
5036 /* Replace existing list */
5037 mgu_clear_list( _addressIFaceSelection_ );
5038 g_list_free( _addressIFaceSelection_ );
5039 _addressIFaceSelection_ = newList;
5043 /* ***********************************************************************
5044 * Add sender to address book.
5045 * ***********************************************************************
5049 * This function is used by the Add sender to address book function.
5051 gboolean addressbook_add_contact(
5052 const gchar *name, const gchar *address, const gchar *remarks,
5053 GdkPixbuf *picture )
5055 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5056 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5057 debug_print( "addressbook_add_contact - added\n" );
5058 addressbook_refresh();
5063 /* ***********************************************************************
5064 * Book/folder selection.
5065 * ***********************************************************************
5069 * This function is used by the matcher dialog to select a book/folder.
5071 gchar *addressbook_folder_selection( const gchar *folderpath)
5073 AddressBookFile *book = NULL;
5074 ItemFolder *folder = NULL;
5077 g_return_val_if_fail( folderpath != NULL, NULL);
5079 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5081 if ( folder != NULL) {
5083 gchar *oldtmp = NULL;
5084 AddrItemObject *obj = NULL;
5086 /* walk thru folder->parent to build the full folder path */
5087 /* TODO: wwp: optimize this */
5089 tmp = g_strdup(obj->uid);
5090 while ( obj->parent ) {
5092 if ( obj->name != NULL ) {
5093 oldtmp = g_strdup(tmp);
5095 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5099 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5102 path = g_strdup_printf("%s", book->fileName);
5104 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5110 /* ***********************************************************************
5111 * Book/folder checking.
5112 * ***********************************************************************
5115 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5117 FolderInfo *fi = g_new0( FolderInfo, 1 );
5119 fi->folder = folder;
5123 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5124 FolderInfo *fiParent, FolderPathMatch *match )
5130 FolderPathMatch *nextmatch = NULL;
5135 list = parentFolder->listFolder;
5137 folder = list->data;
5138 fName = g_strdup( ADDRITEM_NAME(folder) );
5140 /* match folder name, match pointer will be set to NULL if next recursive call
5141 doesn't need to match subfolder name */
5142 if ( match != NULL &&
5143 match->matched == FALSE ) {
5144 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5145 /* folder name matches, prepare next subfolder match */
5146 debug_print("matched folder name '%s'\n", fName);
5148 if ( match->folder_path[match->index] == NULL ) {
5149 /* we've matched all elements */
5150 match->matched = TRUE;
5151 match->folder = folder;
5152 debug_print("book/folder path matched!\n");
5154 /* keep on matching */
5162 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5163 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5165 list = g_list_next( list );
5170 * This function is used by to check if a matcher book/folder path corresponds to an
5171 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5172 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5173 if book AND folder are NULL this means that folderpath was empty or Any.
5174 If folderpath is a simple book name (without folder), book will not be NULL and folder
5175 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5178 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5179 AddressDataSource **book,
5180 ItemFolder **folder )
5182 AddressDataSource *ds;
5183 GList *list, *nodeDS;
5184 ItemFolder *rootFolder;
5185 AddressBookFile *abf;
5187 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5194 if ( folderpath == NULL )
5197 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5200 /* split the folder path we've received, we'll try to match this path, subpath by
5201 subpath against the book/folder structure in order */
5202 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5203 if (!folder_path_match.folder_path)
5206 list = addrindex_get_interface_list( _addressIndex_ );
5207 while ( list && !folder_path_match.matched ) {
5208 AddressInterface *interface = list->data;
5209 if ( interface && interface->type == ADDR_IF_BOOK ) {
5210 nodeDS = interface->listSource;
5211 while ( nodeDS && !folder_path_match.matched ) {
5214 /* Read address book */
5215 if( ! addrindex_ds_get_read_flag( ds ) ) {
5216 addrindex_ds_read_data( ds );
5219 /* Add node for address book */
5220 abf = ds->rawDataSource;
5222 /* match book name */
5223 if ( abf && abf->fileName &&
5224 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5226 debug_print("matched book name '%s'\n", abf->fileName);
5227 folder_path_match.book = ds;
5229 if ( folder_path_match.folder_path[1] == NULL ) {
5230 /* no folder part to match */
5232 folder_path_match.matched = TRUE;
5233 folder_path_match.folder = NULL;
5234 debug_print("book path matched!\n");
5237 /* match folder part */
5239 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5240 rootFolder = addrindex_ds_get_root_folder( ds );
5242 /* prepare for recursive call */
5243 folder_path_match.index = 1;
5244 /* this call will set folder_path_match.matched and folder_path_match.folder */
5245 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5250 nodeDS = g_list_next( nodeDS );
5253 list = g_list_next( list );
5256 g_strfreev( folder_path_match.folder_path );
5259 *book = folder_path_match.book;
5261 *folder = folder_path_match.folder;
5262 return folder_path_match.matched;
5266 /* **********************************************************************
5268 * ***********************************************************************
5274 static void addressbook_import_ldif_cb( void ) {
5275 AddressDataSource *ds = NULL;
5276 AdapterDSource *ads = NULL;
5277 AddressBookFile *abf = NULL;
5278 AdapterInterface *adapter;
5279 GtkCTreeNode *newNode;
5281 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5283 if( adapter->treeNode ) {
5284 abf = addressbook_imp_ldif( _addressIndex_ );
5286 ds = addrindex_index_add_datasource(
5287 _addressIndex_, ADDR_IF_BOOK, abf );
5288 ads = addressbook_create_ds_adapter(
5289 ds, ADDR_BOOK, NULL );
5290 addressbook_ads_set_name(
5291 ads, addrbook_get_name( abf ) );
5292 newNode = addressbook_add_object(
5294 ADDRESS_OBJECT(ads) );
5296 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5298 addrbook.treeSelected = newNode;
5301 /* Notify address completion */
5302 invalidate_address_completion();
5311 static void addressbook_import_mutt_cb( void ) {
5312 AddressDataSource *ds = NULL;
5313 AdapterDSource *ads = NULL;
5314 AddressBookFile *abf = NULL;
5315 AdapterInterface *adapter;
5316 GtkCTreeNode *newNode;
5318 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5320 if( adapter->treeNode ) {
5321 abf = addressbook_imp_mutt( _addressIndex_ );
5323 ds = addrindex_index_add_datasource(
5324 _addressIndex_, ADDR_IF_BOOK, abf );
5325 ads = addressbook_create_ds_adapter(
5326 ds, ADDR_BOOK, NULL );
5327 addressbook_ads_set_name(
5328 ads, addrbook_get_name( abf ) );
5329 newNode = addressbook_add_object(
5331 ADDRESS_OBJECT(ads) );
5333 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5335 addrbook.treeSelected = newNode;
5338 /* Notify address completion */
5339 invalidate_address_completion();
5348 static void addressbook_import_pine_cb( void ) {
5349 AddressDataSource *ds = NULL;
5350 AdapterDSource *ads = NULL;
5351 AddressBookFile *abf = NULL;
5352 AdapterInterface *adapter;
5353 GtkCTreeNode *newNode;
5355 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5357 if( adapter->treeNode ) {
5358 abf = addressbook_imp_pine( _addressIndex_ );
5360 ds = addrindex_index_add_datasource(
5361 _addressIndex_, ADDR_IF_BOOK, abf );
5362 ads = addressbook_create_ds_adapter(
5363 ds, ADDR_BOOK, NULL );
5364 addressbook_ads_set_name(
5365 ads, addrbook_get_name( abf ) );
5366 newNode = addressbook_add_object(
5368 ADDRESS_OBJECT(ads) );
5370 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5372 addrbook.treeSelected = newNode;
5375 /* Notify address completion */
5376 invalidate_address_completion();
5383 * Harvest addresses.
5384 * \param folderItem Folder to import.
5385 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5386 * \param msgList List of message numbers, or NULL to process folder.
5388 void addressbook_harvest(
5389 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5391 AddressDataSource *ds = NULL;
5392 AdapterDSource *ads = NULL;
5393 AddressBookFile *abf = NULL;
5394 AdapterInterface *adapter;
5395 GtkCTreeNode *newNode;
5397 abf = addrgather_dlg_execute(
5398 folderItem, _addressIndex_, sourceInd, msgList );
5400 ds = addrindex_index_add_datasource(
5401 _addressIndex_, ADDR_IF_BOOK, abf );
5403 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5405 if( adapter->treeNode ) {
5406 ads = addressbook_create_ds_adapter(
5407 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5408 newNode = addressbook_add_object(
5410 ADDRESS_OBJECT(ads) );
5414 /* Notify address completion */
5415 invalidate_address_completion();
5422 static void addressbook_export_html_cb( void ) {
5423 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5425 AddressDataSource *ds = NULL;
5426 AddrBookBase *adbase;
5427 AddressCache *cache;
5428 GtkCTreeNode *node = NULL;
5430 if( ! addrbook.treeSelected ) return;
5431 node = addrbook.treeSelected;
5432 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5433 obj = gtk_ctree_node_get_row_data( ctree, node );
5434 if( obj == NULL ) return;
5436 ds = addressbook_find_datasource( node );
5437 if( ds == NULL ) return;
5438 adbase = ( AddrBookBase * ) ds->rawDataSource;
5439 cache = adbase->addressCache;
5440 addressbook_exp_html( cache );
5446 static void addressbook_export_ldif_cb( void ) {
5447 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5449 AddressDataSource *ds = NULL;
5450 AddrBookBase *adbase;
5451 AddressCache *cache;
5452 GtkCTreeNode *node = NULL;
5454 if( ! addrbook.treeSelected ) return;
5455 node = addrbook.treeSelected;
5456 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5457 obj = gtk_ctree_node_get_row_data( ctree, node );
5458 if( obj == NULL ) return;
5460 ds = addressbook_find_datasource( node );
5461 if( ds == NULL ) return;
5462 adbase = ( AddrBookBase * ) ds->rawDataSource;
5463 cache = adbase->addressCache;
5464 addressbook_exp_ldif( cache );
5467 static void addressbook_find_duplicates_cb(void)
5469 addrduplicates_find(GTK_WINDOW(addrbook.window));
5472 static void addressbook_edit_custom_attr_cb(void)
5474 addressbook_custom_attr_edit();
5477 static void addressbook_start_drag(GtkWidget *widget, gint button,
5481 GdkDragContext *context;
5482 if (addressbook_target_list == NULL)
5483 addressbook_target_list = gtk_target_list_new(
5484 addressbook_drag_types, 1);
5485 context = gtk_drag_begin(widget, addressbook_target_list,
5486 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5487 gtk_drag_set_icon_default(context);
5490 static void addressbook_drag_data_get(GtkWidget *widget,
5491 GdkDragContext *drag_context,
5492 GtkSelectionData *selection_data,
5497 AddrItemObject *aio = NULL;
5498 AddressObject *pobj = NULL;
5499 AdapterDSource *ads = NULL;
5500 AddressDataSource *ds = NULL;
5503 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5505 if( pobj == NULL ) return;
5507 if( pobj->type == ADDR_DATASOURCE ) {
5508 ads = ADAPTER_DSOURCE(pobj);
5509 ds = ads->dataSource;
5510 } else if (pobj->type == ADDR_ITEM_GROUP) {
5515 else if( pobj->type != ADDR_INTERFACE ) {
5516 ds = addressbook_find_datasource( addrbook.treeSelected );
5522 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5523 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5524 GTK_CTREE_NODE(cur->data));
5525 while (aio && aio->type != ADDR_ITEM_PERSON) {
5530 if (aio && aio->type == ADDR_ITEM_PERSON) {
5531 if( ds && ds->interface && ds->interface->readOnly)
5532 gtk_selection_data_set(selection_data,
5533 selection_data->target, 8,
5534 (const guchar *)"Dummy_addr_copy", 15);
5536 gtk_selection_data_set(selection_data,
5537 selection_data->target, 8,
5538 (const guchar *)"Dummy_addr_move", 15);
5542 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5543 GdkDragContext *context,
5550 GtkCTreeNode *node = NULL;
5551 gboolean acceptable = FALSE;
5552 gint height = addrbook.ctree->allocation.height;
5553 gint total_height = addrbook.ctree->requisition.height;
5554 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5555 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5556 gfloat vpos = pos->value;
5558 if (gtk_clist_get_selection_info
5559 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5561 if (y > height - 24 && height + vpos < total_height) {
5562 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5563 gtk_adjustment_changed(pos);
5565 if (y < 24 && y > 0) {
5566 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5567 gtk_adjustment_changed(pos);
5569 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5572 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5573 if( obj->type == ADDR_ITEM_FOLDER
5574 || obj->type == ADDR_ITEM_GROUP)
5577 AdapterDSource *ads = NULL;
5578 AddressDataSource *ds = NULL;
5579 ads = ADAPTER_DSOURCE(obj);
5580 if (ads == NULL ){ return FALSE;}
5581 ds = ads->dataSource;
5582 if (ds == NULL ) { return FALSE;}
5590 g_signal_handlers_block_by_func
5592 G_CALLBACK(addressbook_tree_selected), NULL);
5593 gtk_sctree_select( GTK_SCTREE(widget), node);
5594 g_signal_handlers_unblock_by_func
5596 G_CALLBACK(addressbook_tree_selected), NULL);
5597 gdk_drag_status(context,
5598 (context->actions == GDK_ACTION_COPY ?
5599 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5601 gdk_drag_status(context, 0, time);
5606 static void addressbook_drag_leave_cb(GtkWidget *widget,
5607 GdkDragContext *context,
5611 if (addrbook.treeSelected) {
5612 g_signal_handlers_block_by_func
5614 G_CALLBACK(addressbook_tree_selected), NULL);
5615 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5616 g_signal_handlers_unblock_by_func
5618 G_CALLBACK(addressbook_tree_selected), NULL);
5623 static void addressbook_drag_received_cb(GtkWidget *widget,
5624 GdkDragContext *drag_context,
5627 GtkSelectionData *data,
5634 GtkCTreeNode *lastopened = addrbook.opened;
5636 if (!strncmp(data->data, "Dummy_addr", 10)) {
5637 if (gtk_clist_get_selection_info
5638 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5642 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5643 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5646 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5647 if (drag_context->action == GDK_ACTION_COPY ||
5648 !strcmp(data->data, "Dummy_addr_copy"))
5649 addressbook_clip_copy_cb();
5651 addressbook_clip_cut_cb();
5652 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5653 addressbook_clip_paste_cb();
5654 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5655 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5656 gtk_drag_finish(drag_context, TRUE, TRUE, time);