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>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
55 #include "stock_pixmap.h"
57 #include "prefs_gtk.h"
63 #include "addr_compl.h"
66 #include "addressitem.h"
68 #include "addrcache.h"
70 #include "addrindex.h"
71 #include "addressadd.h"
72 #include "addrduplicates.h"
73 #include "addressbook_foldersel.h"
75 #include "editvcard.h"
76 #include "editgroup.h"
77 #include "editaddress.h"
79 #include "importldif.h"
80 #include "importmutt.h"
81 #include "importpine.h"
86 #include "editjpilot.h"
91 #include "ldapserver.h"
93 #include "ldapupdate.h"
95 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
98 #include "addrquery.h"
99 #include "addrselect.h"
100 #include "addrclip.h"
101 #include "addrgather.h"
102 #include "adbookbase.h"
103 #include "exphtmldlg.h"
104 #include "expldifdlg.h"
105 #include "browseldap.h"
111 } AddressIndexColumns;
119 } AddressListColumns;
122 AddressBookFile *book;
130 AddressDataSource *book;
134 static gchar *list_titles[] = { N_("Name"),
138 #define COL_NAME_WIDTH 164
139 #define COL_ADDRESS_WIDTH 156
141 #define COL_FOLDER_WIDTH 170
142 #define ADDRESSBOOK_WIDTH 640
143 #define ADDRESSBOOK_HEIGHT 360
145 #define ADDRESSBOOK_MSGBUF_SIZE 2048
147 static GdkPixmap *folderxpm;
148 static GdkBitmap *folderxpmmask;
149 static GdkPixmap *folderopenxpm;
150 static GdkBitmap *folderopenxpmmask;
151 static GdkPixmap *groupxpm;
152 static GdkBitmap *groupxpmmask;
153 static GdkPixmap *interfacexpm;
154 static GdkBitmap *interfacexpmmask;
155 static GdkPixmap *bookxpm;
156 static GdkBitmap *bookxpmmask;
157 static GdkPixmap *addressxpm;
158 static GdkBitmap *addressxpmmask;
159 static GdkPixmap *vcardxpm;
160 static GdkBitmap *vcardxpmmask;
161 static GdkPixmap *jpilotxpm;
162 static GdkBitmap *jpilotxpmmask;
163 static GdkPixmap *categoryxpm;
164 static GdkBitmap *categoryxpmmask;
165 static GdkPixmap *ldapxpm;
166 static GdkBitmap *ldapxpmmask;
167 static GdkPixmap *addrsearchxpm;
168 static GdkPixmap *addrsearchxpmmask;
171 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
173 /* Address list selection */
174 static AddrSelectList *_addressSelect_ = NULL;
175 static AddressClipboard *_clipBoard_ = NULL;
177 /* Address index file and interfaces */
178 static AddressIndex *_addressIndex_ = NULL;
179 static GList *_addressInterfaceList_ = NULL;
180 static GList *_addressIFaceSelection_ = NULL;
181 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
183 static AddressBook_win addrbook;
185 static GHashTable *_addressBookTypeHash_ = NULL;
186 static GList *_addressBookTypeList_ = NULL;
188 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
189 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
190 static void addressbook_edit_address_post_cb( ItemPerson *person );
192 static void addressbook_create (void);
193 static gint addressbook_close (void);
194 static void addressbook_button_set_sensitive (void);
196 static gboolean address_index_has_focus = FALSE;
197 static gboolean address_list_has_focus = FALSE;
199 /* callback functions */
200 static void addressbook_del_clicked (GtkButton *button,
202 static void addressbook_reg_clicked (GtkButton *button,
204 static void addressbook_to_clicked (GtkButton *button,
206 static void addressbook_lup_clicked (GtkButton *button,
208 static void addressbook_close_clicked (GtkButton *button,
211 static void addressbook_tree_selected (GtkCTree *ctree,
215 static void addressbook_select_row_tree (GtkCTree *ctree,
219 static void addressbook_list_row_selected (GtkCTree *clist,
223 static void addressbook_list_row_unselected (GtkCTree *clist,
227 static void addressbook_person_expand_node (GtkCTree *ctree,
230 static void addressbook_person_collapse_node (GtkCTree *ctree,
234 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
235 GdkEventButton *event,
237 static gboolean addressbook_list_button_released(GtkWidget *widget,
238 GdkEventButton *event,
240 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
241 GdkEventButton *event,
243 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
244 GdkEventButton *event,
247 static void addressbook_new_folder_cb (gpointer data,
250 static void addressbook_new_group_cb (gpointer data,
253 static void addressbook_treenode_edit_cb (gpointer data,
256 static void addressbook_treenode_delete_cb (gpointer data,
260 static void addressbook_change_node_name (GtkCTreeNode *node,
263 static void addressbook_new_address_cb (gpointer data,
266 static void addressbook_edit_address_cb (gpointer data,
269 static void addressbook_delete_address_cb (gpointer data,
273 static void close_cb (gpointer data,
276 static void addressbook_file_save_cb (gpointer data,
280 /* Data source edit stuff */
281 static void addressbook_new_book_cb (gpointer data,
284 static void addressbook_new_vcard_cb (gpointer data,
289 static void addressbook_new_jpilot_cb (gpointer data,
295 static void addressbook_new_ldap_cb (gpointer data,
300 static void addressbook_set_clist (AddressObject *obj,
303 static void addressbook_load_tree (void);
304 void addressbook_read_file (void);
306 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
308 static void addressbook_treenode_remove_item ( void );
310 static AddressDataSource *addressbook_find_datasource
311 (GtkCTreeNode *node );
313 static AddressBookFile *addressbook_get_book_file(void);
315 static GtkCTreeNode *addressbook_node_add_folder
317 AddressDataSource *ds,
318 ItemFolder *itemFolder,
319 AddressObjectType otype);
320 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
321 AddressDataSource *ds,
322 ItemGroup *itemGroup);
323 static void addressbook_tree_remove_children (GtkCTree *ctree,
324 GtkCTreeNode *parent);
325 static void addressbook_move_nodes_up (GtkCTree *ctree,
327 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
329 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
332 static gint addressbook_treenode_compare_func (GtkCList *clist,
335 static void addressbook_folder_load_one_person (GtkCTree *clist,
337 AddressTypeControlItem *atci,
338 AddressTypeControlItem *atciMail);
339 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
341 static void addressbook_folder_remove_one_person(GtkCTree *clist,
343 static void addressbook_folder_remove_node (GtkCTree *clist,
346 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
347 gboolean force_focus );
349 /* LUT's and IF stuff */
350 static void addressbook_free_treenode ( gpointer data );
351 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
352 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
354 static void addrbookctl_build_map (GtkWidget *window);
355 static void addrbookctl_build_iflist (void);
356 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
357 static void addrbookctl_build_ifselect (void);
359 static void addrbookctl_free_interface (AdapterInterface *adapter);
360 static void addrbookctl_free_datasource (AdapterDSource *adapter);
361 static void addrbookctl_free_folder (AdapterFolder *adapter);
362 static void addrbookctl_free_group (AdapterGroup *adapter);
364 static void addressbook_list_select_clear ( void );
365 static void addressbook_list_select_add ( AddrItemObject *aio,
366 AddressDataSource *ds );
367 static void addressbook_list_select_remove ( AddrItemObject *aio );
369 static void addressbook_import_ldif_cb ( void );
370 static void addressbook_find_duplicates_cb ( void );
371 static void addressbook_import_mutt_cb ( void );
372 static void addressbook_import_pine_cb ( void );
373 static void addressbook_export_html_cb ( void );
374 static void addressbook_export_ldif_cb ( void );
375 static void addressbook_select_all_cb ( void );
376 static void addressbook_clip_cut_cb ( void );
377 static void addressbook_clip_copy_cb ( void );
378 static void addressbook_clip_paste_cb ( void );
379 static void addressbook_treenode_cut_cb ( void );
380 static void addressbook_treenode_copy_cb ( void );
381 static void addressbook_treenode_paste_cb ( void );
383 static void addressbook_mail_to_cb ( void );
386 static void addressbook_browse_entry_cb ( void );
388 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
390 static void addressbook_start_drag(GtkWidget *widget, gint button,
393 static void addressbook_drag_data_get(GtkWidget *widget,
394 GdkDragContext *drag_context,
395 GtkSelectionData *selection_data,
399 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
400 GdkDragContext *context,
405 static void addressbook_drag_leave_cb(GtkWidget *widget,
406 GdkDragContext *context,
409 static void addressbook_drag_received_cb(GtkWidget *widget,
410 GdkDragContext *drag_context,
413 GtkSelectionData *data,
417 static void addressbook_list_menu_setup( void );
419 static GtkTargetEntry addressbook_drag_types[] =
421 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
424 static GtkTargetList *addressbook_target_list = NULL;
427 static GtkItemFactoryEntry addressbook_entries[] =
429 {N_("/_Book"), NULL, NULL, 0, "<Branch>", NULL},
430 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL, NULL},
431 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL, NULL},
432 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL, NULL},
434 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL, NULL},
437 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL, NULL},
439 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
440 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
441 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
442 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
443 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL, NULL},
444 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL, NULL},
445 {N_("/_Address"), NULL, NULL, 0, "<Branch>", NULL},
446 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL, NULL},
447 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
448 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL, NULL},
449 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL, NULL},
450 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL, NULL},
451 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
452 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL, NULL},
453 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL, NULL},
454 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
455 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL, NULL},
456 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL, NULL},
457 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
458 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
459 {N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL},
460 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL, NULL},
461 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL, NULL},
462 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL, NULL},
463 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
464 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL, NULL},
465 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL, NULL},
466 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
467 {N_("/_Tools/Find duplicates..."), NULL, addressbook_find_duplicates_cb, 0, NULL, NULL},
468 {N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL},
469 {N_("/_Help/_About"), NULL, about_show, 0, NULL, NULL}
472 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
474 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
475 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
476 {"/---", NULL, NULL, 0, "<Separator>", NULL},
477 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL, NULL},
478 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL, NULL},
479 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
480 {"/---", NULL, NULL, 0, "<Separator>", NULL},
481 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL, NULL},
482 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL, NULL},
483 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL, NULL}
486 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
488 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL, NULL},
489 {"/---", NULL, NULL, 0, "<Separator>", NULL},
490 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL, NULL},
491 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL, NULL},
492 {"/---", NULL, NULL, 0, "<Separator>", NULL},
493 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL, NULL},
494 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
495 {"/---", NULL, NULL, 0, "<Separator>", NULL},
496 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL, NULL},
497 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL, NULL},
498 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL, NULL},
499 {"/---", NULL, NULL, 0, "<Separator>", NULL},
500 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL, NULL},*/
501 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
503 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL, NULL},
508 * Structure of error message table.
510 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
511 struct _ErrMsgTableEntry {
516 static gchar *_errMsgUnknown_ = N_( "Unknown" );
519 * Lookup table of error messages for general errors. Note that a NULL
520 * description signifies the end of the table.
522 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
523 { MGU_SUCCESS, N_("Success") },
524 { MGU_BAD_ARGS, N_("Bad arguments") },
525 { MGU_NO_FILE, N_("File not specified") },
526 { MGU_OPEN_FILE, N_("Error opening file") },
527 { MGU_ERROR_READ, N_("Error reading file") },
528 { MGU_EOF, N_("End of file encountered") },
529 { MGU_OO_MEMORY, N_("Error allocating memory") },
530 { MGU_BAD_FORMAT, N_("Bad file format") },
531 { MGU_ERROR_WRITE, N_("Error writing to file") },
532 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
533 { MGU_NO_PATH, N_("No path specified") },
539 * Lookup table of error messages for LDAP errors.
541 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
542 { LDAPRC_SUCCESS, N_("Success") },
543 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
544 { LDAPRC_INIT, N_("Error initializing LDAP") },
545 { LDAPRC_BIND, N_("Error binding to LDAP server") },
546 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
547 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
548 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
549 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
550 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
551 { LDAPRC_TLS, N_("Error starting TLS connection") },
552 { LDAPRC_NODN, N_("Distinguised Name (dn) is missing") },
553 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
554 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
555 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
561 * Lookup message for specified error code.
562 * \param lut Lookup table.
563 * \param code Code to lookup.
564 * \return Description associated to code.
566 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
568 ErrMsgTableEntry entry;
571 for( i = 0; ; i++ ) {
573 if( entry.description == NULL ) break;
574 if( entry.code == code ) {
575 desc = entry.description;
580 desc = _errMsgUnknown_;
585 static gboolean lastCanLookup = FALSE;
587 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
589 if (add_and_delete) {
590 gtk_widget_show(addrbook.edit_btn);
591 gtk_widget_show(addrbook.del_btn);
592 gtk_widget_show(addrbook.reg_btn);
594 gtk_widget_hide(addrbook.edit_btn);
595 gtk_widget_hide(addrbook.del_btn);
596 gtk_widget_hide(addrbook.reg_btn);
600 gtk_widget_show(addrbook.lup_btn);
601 gtk_widget_show(addrbook.entry);
602 gtk_widget_show(addrbook.label);
604 gtk_widget_hide(addrbook.lup_btn);
605 gtk_widget_hide(addrbook.entry);
606 gtk_widget_hide(addrbook.label);
609 lastCanLookup = lookup;
612 gtk_widget_show(addrbook.to_btn);
613 gtk_widget_show(addrbook.cc_btn);
614 gtk_widget_show(addrbook.bcc_btn);
616 gtk_widget_hide(addrbook.to_btn);
617 gtk_widget_hide(addrbook.cc_btn);
618 gtk_widget_hide(addrbook.bcc_btn);
622 void addressbook_open(Compose *target)
624 /* Initialize all static members */
625 if( _clipBoard_ == NULL ) {
626 _clipBoard_ = addrclip_create();
628 if( _addressIndex_ != NULL ) {
629 addrclip_set_index( _clipBoard_, _addressIndex_ );
631 if( _addressSelect_ == NULL ) {
632 _addressSelect_ = addrselect_list_create();
634 if (!addrbook.window) {
635 addressbook_read_file();
636 addressbook_create();
637 addressbook_load_tree();
638 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
639 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
642 gtk_widget_hide(addrbook.window);
645 gtk_widget_show_all(addrbook.window);
647 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
648 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
650 if (!prefs_common.addressbook_use_editaddress_dialog)
651 addressbook_edit_person_widgetset_hide();
653 address_completion_start(addrbook.window);
655 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
656 addressbook_set_target_compose(target);
660 * Destroy addressbook.
662 void addressbook_destroy( void ) {
663 /* Free up address stuff */
664 if( _addressSelect_ != NULL ) {
665 addrselect_list_free( _addressSelect_ );
667 if( _clipBoard_ != NULL ) {
668 addrclip_free( _clipBoard_ );
670 if( _addressIndex_ != NULL ) {
671 addrindex_free_index( _addressIndex_ );
672 addrindex_teardown();
674 _addressSelect_ = NULL;
676 _addressIndex_ = NULL;
679 void addressbook_set_target_compose(Compose *target)
681 addrbook.target_compose = target;
682 addressbook_button_set_sensitive();
685 Compose *addressbook_get_target_compose(void)
687 return addrbook.target_compose;
691 * Refresh addressbook and save to file(s).
693 void addressbook_refresh( void )
695 if (addrbook.window) {
696 if (addrbook.treeSelected) {
697 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
698 addrbook.treeSelected);
699 addressbook_set_clist(
700 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
701 addrbook.treeSelected),
706 addressbook_export_to_file();
709 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
711 if (event && event->keyval == GDK_Escape)
713 else if (event && event->keyval == GDK_Delete) {
714 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
715 if ( /* address_index_has_focus || */ address_list_has_focus )
716 addressbook_del_clicked(NULL, NULL);
722 *\brief Save Gtk object size to prefs dataset
724 static void addressbook_size_allocate_cb(GtkWidget *widget,
725 GtkAllocation *allocation)
727 g_return_if_fail(allocation != NULL);
729 prefs_common.addressbookwin_width = allocation->width;
730 prefs_common.addressbookwin_height = allocation->height;
733 static gint sort_column_number = 0;
734 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
736 static gint list_case_sort(
737 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
739 GtkCListRow *row1 = (GtkCListRow *) ptr1;
740 GtkCListRow *row2 = (GtkCListRow *) ptr2;
741 gchar *name1 = NULL, *name2 = NULL;
742 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
743 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
745 if( aio1->type == aio2->type ) {
747 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
749 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
750 if( ! name1 ) return ( name2 != NULL );
751 if( ! name2 ) return -1;
752 return g_utf8_collate( name1, name2 );
754 /* Order groups before person */
755 if( aio1->type == ITEMTYPE_GROUP ) {
756 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
757 } else if( aio2->type == ITEMTYPE_GROUP ) {
758 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
764 static void addressbook_sort_list(GtkCList *clist, const gint col,
765 const GtkSortType sort_type)
768 GtkWidget *hbox, *label, *arrow;
770 sort_column_number = col;
771 sort_column_type = sort_type;
772 gtk_clist_set_compare_func(clist, list_case_sort);
773 gtk_clist_set_sort_type(clist, sort_type);
774 gtk_clist_set_sort_column(clist, col);
776 gtk_clist_freeze(clist);
777 gtk_clist_sort(clist);
779 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
780 hbox = gtk_hbox_new(FALSE, 4);
781 label = gtk_label_new(gettext(list_titles[pos]));
782 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
785 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
786 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
787 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
790 gtk_widget_show_all(hbox);
791 gtk_clist_set_column_widget(clist, pos, hbox);
794 gtk_clist_thaw(clist);
797 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
799 static GtkSortType sort_type = GTK_SORT_ASCENDING;
801 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
803 addressbook_sort_list(clist, COL_NAME, sort_type);
806 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
808 static GtkSortType sort_type = GTK_SORT_ASCENDING;
810 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
812 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
815 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
817 static GtkSortType sort_type = GTK_SORT_ASCENDING;
819 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
821 addressbook_sort_list(clist, COL_REMARKS, sort_type);
824 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
827 address_index_has_focus = TRUE;
831 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
834 address_index_has_focus = FALSE;
835 if (!prefs_common.addressbook_use_editaddress_dialog
836 && !address_list_has_focus)
837 addressbook_address_list_disable_some_actions();
841 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
844 address_list_has_focus = TRUE;
848 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
851 address_list_has_focus = FALSE;
852 if (!prefs_common.addressbook_use_editaddress_dialog
853 && !address_index_has_focus)
854 addressbook_address_list_disable_some_actions();
858 /* save hpane and vpane's handle position when it moves */
859 static void addressbook_pane_save_position(void)
862 prefs_common.addressbook_hpaned_pos =
863 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
865 prefs_common.addressbook_vpaned_pos =
866 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
870 * Create the address book widgets. The address book contains two CTree widgets: the
871 * address index tree on the left and the address list on the right.
873 * The address index tree displays a hierarchy of interfaces and groups. Each node in
874 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
875 * data sources and folder objects.
877 * The address list displays group, person and email objects. These items are linked
878 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
881 * In the tradition of MVC architecture, the data stores have been separated from the
882 * GUI components. The addrindex.c file provides the interface to all data stores.
884 static void addressbook_create(void)
890 GtkWidget *ctree_swin;
892 GtkWidget *editaddress_vbox;
893 GtkWidget *clist_vbox;
894 GtkWidget *clist_swin;
901 GtkWidget *statusbar;
912 GtkWidget *close_btn;
913 GtkWidget *tree_popup;
914 GtkWidget *list_popup;
915 GtkItemFactory *tree_factory;
916 GtkItemFactory *list_factory;
917 GtkItemFactory *menu_factory;
921 gchar *index_titles[N_INDEX_COLS];
925 static GdkGeometry geometry;
927 debug_print("Creating addressbook window...\n");
929 index_titles[COL_SOURCES] = _("Sources");
931 /* Address book window */
932 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
933 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
934 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
935 gtk_widget_realize(window);
937 g_signal_connect(G_OBJECT(window), "delete_event",
938 G_CALLBACK(addressbook_close), NULL);
939 g_signal_connect(G_OBJECT(window), "size_allocate",
940 G_CALLBACK(addressbook_size_allocate_cb), NULL);
941 g_signal_connect(G_OBJECT(window), "key_press_event",
942 G_CALLBACK(key_pressed), NULL);
943 MANAGE_WINDOW_SIGNALS_CONNECT(window);
945 vbox = gtk_vbox_new(FALSE, 0);
946 gtk_container_add(GTK_CONTAINER(window), vbox);
949 n_entries = sizeof(addressbook_entries) /
950 sizeof(addressbook_entries[0]);
951 menubar = menubar_create(window, addressbook_entries, n_entries,
952 "<AddressBook>", NULL);
953 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
954 menu_factory = gtk_item_factory_from_widget(menubar);
956 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
957 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
958 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
960 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
961 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
962 GTK_POLICY_AUTOMATIC,
963 GTK_POLICY_AUTOMATIC);
964 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
967 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
968 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
969 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
970 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
971 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
972 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
973 GTK_CTREE_EXPANDER_SQUARE);
974 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
975 gtk_clist_set_compare_func(GTK_CLIST(ctree),
976 addressbook_treenode_compare_func);
978 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
979 G_CALLBACK(addressbook_tree_selected), NULL);
980 g_signal_connect(G_OBJECT(ctree), "button_press_event",
981 G_CALLBACK(addressbook_tree_button_pressed),
983 g_signal_connect(G_OBJECT(ctree), "button_release_event",
984 G_CALLBACK(addressbook_tree_button_released),
987 g_signal_connect(G_OBJECT(ctree), "select_row",
988 G_CALLBACK(addressbook_select_row_tree), NULL);
990 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
991 addressbook_drag_types, 1,
992 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
993 g_signal_connect(G_OBJECT(ctree), "drag_motion",
994 G_CALLBACK(addressbook_drag_motion_cb),
996 g_signal_connect(G_OBJECT(ctree), "drag_leave",
997 G_CALLBACK(addressbook_drag_leave_cb),
999 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1000 G_CALLBACK(addressbook_drag_received_cb),
1002 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1003 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1004 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1005 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1007 clist_vbox = gtk_vbox_new(FALSE, 4);
1009 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1010 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1011 GTK_POLICY_AUTOMATIC,
1012 GTK_POLICY_AUTOMATIC);
1013 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1016 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1017 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1018 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1019 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1020 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1021 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1022 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1024 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1026 gtk_widget_set_size_request(clist, -1, 80);
1028 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1029 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1030 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1031 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1032 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1033 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1034 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1035 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1036 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1037 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1038 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1040 for (i = 0; i < N_LIST_COLS; i++)
1041 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1044 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1045 G_CALLBACK(addressbook_list_row_selected), NULL);
1046 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1047 G_CALLBACK(addressbook_list_row_unselected), NULL);
1048 g_signal_connect(G_OBJECT(clist), "button_press_event",
1049 G_CALLBACK(addressbook_list_button_pressed),
1051 g_signal_connect(G_OBJECT(clist), "button_release_event",
1052 G_CALLBACK(addressbook_list_button_released),
1054 g_signal_connect(G_OBJECT(clist), "tree_expand",
1055 G_CALLBACK(addressbook_person_expand_node), NULL );
1056 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1057 G_CALLBACK(addressbook_person_collapse_node), NULL );
1058 g_signal_connect(G_OBJECT(clist), "start_drag",
1059 G_CALLBACK(addressbook_start_drag), NULL);
1060 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1061 G_CALLBACK(addressbook_drag_data_get), NULL);
1062 hbox = gtk_hbox_new(FALSE, 4);
1063 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1065 label = gtk_label_new(_("Lookup name:"));
1066 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1068 entry = gtk_entry_new();
1069 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1071 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1073 g_signal_connect(G_OBJECT(entry), "key_press_event",
1074 G_CALLBACK(addressbook_entry_key_pressed),
1077 if (!prefs_common.addressbook_use_editaddress_dialog) {
1078 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1079 vpaned = gtk_vpaned_new();
1080 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1081 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1084 editaddress_vbox = NULL;
1086 hpaned = gtk_hpaned_new();
1087 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1088 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1089 if (prefs_common.addressbook_use_editaddress_dialog)
1090 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1092 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1095 hsbox = gtk_hbox_new(FALSE, 0);
1096 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1097 statusbar = gtk_statusbar_new();
1098 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1101 hbbox = gtk_hbutton_box_new();
1102 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1103 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1104 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1105 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1107 gtkut_stock_button_add_help(hbbox, &help_btn);
1109 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1110 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1111 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1112 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1113 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1114 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1115 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1116 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1117 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1120 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1121 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1122 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1124 g_signal_connect(G_OBJECT(help_btn), "clicked",
1125 G_CALLBACK(manual_open_with_anchor_cb),
1126 MANUAL_ANCHOR_ADDRBOOK);
1128 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1129 G_CALLBACK(addressbook_edit_clicked), NULL);
1130 g_signal_connect(G_OBJECT(del_btn), "clicked",
1131 G_CALLBACK(addressbook_del_clicked), NULL);
1132 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1133 G_CALLBACK(addressbook_reg_clicked), NULL);
1134 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1135 G_CALLBACK(addressbook_lup_clicked), NULL);
1137 to_btn = gtk_button_new_with_label
1138 (prefs_common_translated_header_name("To:"));
1139 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1140 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1141 cc_btn = gtk_button_new_with_label
1142 (prefs_common_translated_header_name("Cc:"));
1143 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1144 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1145 bcc_btn = gtk_button_new_with_label
1146 (prefs_common_translated_header_name("Bcc:"));
1147 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1148 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1150 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1151 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1152 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1154 g_signal_connect(G_OBJECT(to_btn), "clicked",
1155 G_CALLBACK(addressbook_to_clicked),
1156 GINT_TO_POINTER(COMPOSE_TO));
1157 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1158 G_CALLBACK(addressbook_to_clicked),
1159 GINT_TO_POINTER(COMPOSE_CC));
1160 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1161 G_CALLBACK(addressbook_to_clicked),
1162 GINT_TO_POINTER(COMPOSE_BCC));
1163 g_signal_connect(G_OBJECT(close_btn), "clicked",
1164 G_CALLBACK(addressbook_close_clicked), NULL);
1166 /* Build icons for interface */
1167 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1168 &interfacexpm, &interfacexpmmask );
1170 /* Build control tables */
1171 addrbookctl_build_map(window);
1172 addrbookctl_build_iflist();
1173 addrbookctl_build_ifselect();
1175 addrbook.clist = NULL;
1177 /* Add each interface into the tree as a root level folder */
1178 nodeIf = _addressInterfaceList_;
1180 AdapterInterface *adapter = nodeIf->data;
1181 AddressInterface *iface = adapter->interface;
1182 nodeIf = g_list_next(nodeIf);
1184 if(iface->useInterface) {
1185 AddressTypeControlItem *atci = adapter->atci;
1186 text = atci->displayName;
1188 gtk_sctree_insert_node( GTK_CTREE(ctree),
1189 NULL, NULL, &text, FOLDER_SPACING,
1190 interfacexpm, interfacexpmmask,
1191 interfacexpm, interfacexpmmask,
1193 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1194 gtk_ctree_node_set_row_data_full(
1195 GTK_CTREE(ctree), adapter->treeNode, adapter,
1196 addressbook_free_treenode );
1201 n_entries = sizeof(addressbook_tree_popup_entries) /
1202 sizeof(addressbook_tree_popup_entries[0]);
1203 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1205 "<AddressBookTree>", &tree_factory,
1207 n_entries = sizeof(addressbook_list_popup_entries) /
1208 sizeof(addressbook_list_popup_entries[0]);
1209 list_popup = menu_create_items(addressbook_list_popup_entries,
1211 "<AddressBookList>", &list_factory,
1214 addrbook.window = window;
1215 addrbook.hpaned = hpaned;
1216 addrbook.vpaned = vpaned;
1217 addrbook.menubar = menubar;
1218 addrbook.ctree = ctree;
1221 addrbook.editaddress_vbox = editaddress_vbox;
1222 addrbook.clist = clist;
1223 addrbook.label = label;
1224 addrbook.entry = entry;
1225 addrbook.statusbar = statusbar;
1226 addrbook.status_cid = gtk_statusbar_get_context_id(
1227 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1229 addrbook.help_btn = help_btn;
1230 addrbook.edit_btn = edit_btn;
1231 addrbook.del_btn = del_btn;
1232 addrbook.reg_btn = reg_btn;
1233 addrbook.lup_btn = lup_btn;
1234 addrbook.to_btn = to_btn;
1235 addrbook.cc_btn = cc_btn;
1236 addrbook.bcc_btn = bcc_btn;
1238 addrbook.tree_popup = tree_popup;
1239 addrbook.list_popup = list_popup;
1240 addrbook.tree_factory = tree_factory;
1241 addrbook.list_factory = list_factory;
1242 addrbook.menu_factory = menu_factory;
1244 addrbook.listSelected = NULL;
1246 if (!geometry.min_height) {
1247 geometry.min_width = ADDRESSBOOK_WIDTH;
1248 geometry.min_height = ADDRESSBOOK_HEIGHT;
1251 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1253 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1254 prefs_common.addressbookwin_height);
1256 if (!prefs_common.addressbook_use_editaddress_dialog) {
1257 if (prefs_common.addressbook_vpaned_pos > 0)
1258 gtk_paned_set_position(GTK_PANED(vpaned),
1259 prefs_common.addressbook_vpaned_pos);
1261 if (prefs_common.addressbook_hpaned_pos > 0)
1262 gtk_paned_set_position(GTK_PANED(hpaned),
1263 prefs_common.addressbook_hpaned_pos);
1266 gtk_widget_show_all(window);
1270 * Close address book window and save to file(s).
1272 static gint addressbook_close( void ) {
1273 address_completion_end(addrbook.window);
1274 if (!prefs_common.addressbook_use_editaddress_dialog)
1275 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1277 addressbook_pane_save_position();
1279 gtk_widget_hide(addrbook.window);
1280 addressbook_export_to_file();
1285 * Display message in status line.
1286 * \param msg Message to display.
1288 static void addressbook_status_show( gchar *msg ) {
1289 if( addrbook.statusbar != NULL ) {
1291 GTK_STATUSBAR(addrbook.statusbar),
1292 addrbook.status_cid );
1295 GTK_STATUSBAR(addrbook.statusbar),
1296 addrbook.status_cid, msg );
1301 static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
1302 *addressbook_msgbuf = '\0';
1306 name = addrindex_ds_get_name( ds );
1307 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1308 "%s: %s", name, msg );
1311 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1314 addressbook_status_show( addressbook_msgbuf );
1317 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1321 *addressbook_msgbuf = '\0';
1323 name = addrindex_ds_get_name( ds );
1324 retVal = addrindex_ds_get_status_code( ds );
1325 if( retVal == MGU_SUCCESS ) {
1326 g_snprintf( addressbook_msgbuf,
1327 sizeof(addressbook_msgbuf), "%s", name );
1330 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1331 g_snprintf( addressbook_msgbuf,
1332 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1335 addressbook_status_show( addressbook_msgbuf );
1338 static void addressbook_button_set_sensitive(void)
1340 gboolean to_sens = FALSE;
1341 gboolean cc_sens = FALSE;
1342 gboolean bcc_sens = FALSE;
1344 if (!addrbook.window) return;
1346 if (addrbook.target_compose) {
1352 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1353 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1354 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1357 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1359 addressbook_edit_address_cb(NULL, 0, NULL);
1363 * Delete one or more objects from address list.
1365 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1367 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1368 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1369 AddressObject *pobj;
1370 AdapterDSource *ads = NULL;
1371 GtkCTreeNode *nodeList;
1374 AddressBookFile *abf = NULL;
1375 AddressDataSource *ds = NULL;
1376 AddressInterface *iface;
1377 AddrItemObject *aio;
1378 AddrSelectItem *item;
1380 gboolean refreshList = FALSE;
1382 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1383 g_return_if_fail(pobj != NULL);
1385 /* Test whether anything selected for deletion */
1386 nodeList = addrbook.listSelected;
1388 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1389 if( aio == NULL) return;
1390 ds = addressbook_find_datasource( addrbook.treeSelected );
1391 if( ds == NULL ) return;
1393 /* Test for read only */
1394 iface = ds->interface;
1395 if( iface->readOnly ) {
1396 alertpanel( _("Delete address(es)"),
1397 _("This address data is readonly and cannot be deleted."),
1398 GTK_STOCK_CLOSE, NULL, NULL );
1402 /* Test whether Ok to proceed */
1404 if( pobj->type == ADDR_DATASOURCE ) {
1405 ads = ADAPTER_DSOURCE(pobj);
1406 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1408 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1411 else if( pobj->type == ADDR_ITEM_GROUP ) {
1414 if( ! procFlag ) return;
1415 abf = ds->rawDataSource;
1416 if( abf == NULL ) return;
1419 /* Process deletions */
1420 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1421 gboolean group_delete = TRUE;
1422 /* Items inside folders */
1423 list = addrselect_get_list( _addressSelect_ );
1424 /* Confirm deletion */
1428 node = g_list_next( node );
1429 aio = ( AddrItemObject * ) item->addressItem;
1430 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1431 group_delete = FALSE;
1436 aval = alertpanel( _("Delete group"),
1437 _("Really delete the group(s)?\n"
1438 "The addresses it contains will not be lost."),
1439 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1440 if( aval != G_ALERTALTERNATE ) return;
1442 aval = alertpanel( _("Delete address(es)"),
1443 _("Really delete the address(es)?"),
1444 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1445 if( aval != G_ALERTALTERNATE ) return;
1451 node = g_list_next( node );
1452 aio = ( AddrItemObject * ) item->addressItem;
1453 if( aio->type == ADDR_ITEM_GROUP ) {
1454 ItemGroup *item = ( ItemGroup * ) aio;
1455 GtkCTreeNode *nd = NULL;
1457 nd = addressbook_find_group_node( addrbook.opened, item );
1458 item = addrbook_remove_group( abf, item );
1460 addritem_free_item_group( item );
1462 /* Remove group from parent node */
1463 gtk_ctree_remove_node( ctree, nd );
1466 else if( aio->type == ADDR_ITEM_PERSON ) {
1467 ItemPerson *item = ( ItemPerson * ) aio;
1468 item->status = DELETE_ENTRY;
1469 addressbook_folder_remove_one_person( clist, item );
1470 if (pobj->type == ADDR_ITEM_FOLDER)
1471 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1472 item = addrbook_remove_person( abf, item );
1474 if (ds && ds->type == ADDR_IF_LDAP) {
1475 LdapServer *server = ds->rawDataSource;
1476 ldapsvr_set_modified(server, TRUE);
1477 ldapsvr_update_book(server, item);
1481 addritem_free_item_person( item );
1484 else if( aio->type == ADDR_ITEM_EMAIL ) {
1485 ItemEMail *item = ( ItemEMail * ) aio;
1486 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1487 item = addrbook_person_remove_email( abf, person, item );
1489 addrcache_remove_email(abf->addressCache, item);
1490 addritem_free_item_email( item );
1492 addressbook_folder_refresh_one_person( clist, person );
1495 g_list_free( list );
1496 addressbook_list_select_clear();
1498 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1499 addressbook_set_clist(
1500 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1504 addrbook_set_dirty(abf, TRUE);
1505 addressbook_export_to_file();
1506 addressbook_list_menu_setup();
1509 else if( pobj->type == ADDR_ITEM_GROUP ) {
1510 /* Items inside groups */
1511 list = addrselect_get_list( _addressSelect_ );
1515 node = g_list_next( node );
1516 aio = ( AddrItemObject * ) item->addressItem;
1517 if( aio->type == ADDR_ITEM_EMAIL ) {
1518 ItemEMail *item = ( ItemEMail * ) aio;
1519 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1520 item = addrbook_person_remove_email( abf, person, item );
1522 addritem_free_item_email( item );
1526 g_list_free( list );
1527 addressbook_list_select_clear();
1528 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1529 addressbook_set_clist(
1530 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1534 addrbook_set_dirty(abf, TRUE);
1535 addressbook_export_to_file();
1536 addressbook_list_menu_setup();
1540 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1541 gtk_ctree_remove_node( clist, nodeList );
1545 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1547 addressbook_new_address_cb( NULL, 0, NULL );
1550 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1553 gchar *address = NULL;
1555 if( aio->type == ADDR_ITEM_EMAIL ) {
1556 ItemPerson *person = NULL;
1557 ItemEMail *email = ( ItemEMail * ) aio;
1559 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1560 if( email->address ) {
1561 if( ADDRITEM_NAME(email) ) {
1562 name = ADDRITEM_NAME(email);
1563 if( *name == '\0' ) {
1564 name = ADDRITEM_NAME(person);
1567 else if( ADDRITEM_NAME(person) ) {
1568 name = ADDRITEM_NAME(person);
1571 buf = g_strdup( email->address );
1573 address = email->address;
1576 else if( aio->type == ADDR_ITEM_PERSON ) {
1577 ItemPerson *person = ( ItemPerson * ) aio;
1578 GList *node = person->listEMail;
1580 name = ADDRITEM_NAME(person);
1582 ItemEMail *email = ( ItemEMail * ) node->data;
1583 address = email->address;
1587 if( name && name[0] != '\0' ) {
1588 if( strchr_with_skip_quote( name, '"', ',' ) )
1589 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1591 buf = g_strdup_printf( "%s <%s>", name, address );
1594 buf = g_strdup( address );
1601 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1605 AddrSelectItem *item;
1606 AddrItemObject *aio;
1609 compose = addrbook.target_compose;
1610 if( ! compose ) return;
1612 /* Nothing selected, but maybe there is something in text entry */
1613 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1615 compose_entry_append(
1616 compose, addr, (ComposeEntryType)data );
1619 /* Select from address list */
1620 list = addrselect_get_list( _addressSelect_ );
1625 node = g_list_next( node );
1626 aio = item->addressItem;
1627 if( aio->type == ADDR_ITEM_PERSON ||
1628 aio->type == ADDR_ITEM_EMAIL ) {
1629 addr = addressbook_format_address( aio );
1630 compose_entry_append(
1631 compose, addr, (ComposeEntryType) data );
1634 else if( aio->type == ADDR_ITEM_GROUP ) {
1635 ItemGroup *group = ( ItemGroup * ) aio;
1636 GList *nodeMail = group->listEMail;
1638 ItemEMail *email = nodeMail->data;
1640 addr = addressbook_format_address(
1641 ( AddrItemObject * ) email );
1642 compose_entry_append(
1643 compose, addr, (ComposeEntryType) data );
1645 nodeMail = g_list_next( nodeMail );
1650 AddressObject *obj = NULL;
1652 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1654 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1655 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1656 GList *nodeMail = itemGroup->listEMail;
1658 ItemEMail *email = nodeMail->data;
1660 addr = addressbook_format_address(
1661 ( AddrItemObject * ) email );
1662 compose_entry_append(
1663 compose, addr, (ComposeEntryType) data );
1665 nodeMail = g_list_next( nodeMail );
1669 g_list_free( list );
1672 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1673 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1674 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1675 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1677 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1678 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1679 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1680 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1682 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1683 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1684 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1685 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1686 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1687 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1690 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1691 gboolean canEdit = FALSE;
1692 gboolean canDelete = TRUE;
1693 gboolean canAdd = FALSE;
1694 gboolean canEditTr = TRUE;
1695 gboolean editAddress = FALSE;
1696 gboolean canExport = TRUE;
1697 AddressTypeControlItem *atci = NULL;
1698 AddressDataSource *ds = NULL;
1699 AddressInterface *iface = NULL;
1701 if( obj == NULL ) return;
1702 if( obj->type == ADDR_INTERFACE ) {
1703 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1704 iface = adapter->interface;
1706 if( iface->haveLibrary ) {
1707 /* Enable appropriate File / New command */
1708 atci = adapter->atci;
1709 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1712 canEditTr = canExport = FALSE;
1714 else if( obj->type == ADDR_DATASOURCE ) {
1715 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1716 ds = ads->dataSource;
1717 iface = ds->interface;
1718 if( ! iface->readOnly ) {
1719 canAdd = canEdit = editAddress = canDelete = TRUE;
1721 if( ! iface->haveLibrary ) {
1722 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1725 else if( obj->type == ADDR_ITEM_FOLDER ) {
1726 ds = addressbook_find_datasource( addrbook.treeSelected );
1728 iface = ds->interface;
1729 if( iface->readOnly ) {
1734 canAdd = editAddress = TRUE;
1738 else if( obj->type == ADDR_ITEM_GROUP ) {
1739 ds = addressbook_find_datasource( addrbook.treeSelected );
1741 iface = ds->interface;
1742 if( ! iface->readOnly ) {
1748 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1751 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1752 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1753 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1754 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1757 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1758 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1759 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1760 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1762 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1763 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1766 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1767 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1770 static void addressbook_list_menu_setup( void );
1773 * Address book tree callback function that responds to selection of tree
1776 * \param ctree Tree widget.
1777 * \param node Node that was selected.
1778 * \param column Column number where selected occurred.
1779 * \param data Pointer to user data.
1781 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1782 gint column, gpointer data)
1784 AddressObject *obj = NULL;
1785 AdapterDSource *ads = NULL;
1786 AddressDataSource *ds = NULL;
1787 ItemFolder *rootFolder = NULL;
1788 AddressObjectType aot;
1790 addrbook.treeSelected = node;
1791 addrbook.listSelected = NULL;
1792 addressbook_status_show( "" );
1793 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1795 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1797 addressbook_set_clist(NULL, TRUE);
1800 addrbook.opened = node;
1802 if( obj->type == ADDR_DATASOURCE ) {
1803 /* Read from file */
1804 static gboolean tVal = TRUE;
1806 ads = ADAPTER_DSOURCE(obj);
1807 if( ads == NULL ) return;
1808 ds = ads->dataSource;
1809 if( ds == NULL ) return;
1811 if( addrindex_ds_get_modify_flag( ds ) ) {
1812 addrindex_ds_read_data( ds );
1815 if( ! addrindex_ds_get_read_flag( ds ) ) {
1816 addrindex_ds_read_data( ds );
1818 addressbook_ds_show_message( ds );
1820 if( ! addrindex_ds_get_access_flag( ds ) ) {
1821 /* Remove existing folders and groups */
1822 gtk_clist_freeze( GTK_CLIST(ctree) );
1823 addressbook_tree_remove_children( ctree, node );
1824 gtk_clist_thaw( GTK_CLIST(ctree) );
1826 /* Load folders into the tree */
1827 rootFolder = addrindex_ds_get_root_folder( ds );
1828 if( ds && ds->type == ADDR_IF_JPILOT ) {
1829 aot = ADDR_CATEGORY;
1831 else if( ds && ds->type == ADDR_IF_LDAP ) {
1832 aot = ADDR_LDAP_QUERY;
1835 aot = ADDR_ITEM_FOLDER;
1837 addressbook_node_add_folder( node, ds, rootFolder, aot );
1838 addrindex_ds_set_access_flag( ds, &tVal );
1839 gtk_ctree_expand( ctree, node );
1842 addressbook_set_clist(NULL, TRUE);
1845 /* Update address list */
1846 g_signal_handlers_block_by_func
1848 G_CALLBACK(addressbook_tree_selected), NULL);
1849 addressbook_set_clist( obj, FALSE );
1850 g_signal_handlers_unblock_by_func
1852 G_CALLBACK(addressbook_tree_selected), NULL);
1853 if (!prefs_common.addressbook_use_editaddress_dialog)
1854 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1856 /* Setup main menu selections */
1857 addressbook_menubar_set_sensitive( FALSE );
1858 addressbook_list_menu_setup();
1859 addressbook_menuitem_set_sensitive( obj, node );
1861 addressbook_list_select_clear();
1862 addressbook_list_menu_setup();
1867 * Setup address list popup menu items. Items are enabled or disabled as
1870 static void addressbook_list_menu_setup( void ) {
1871 GtkCTree *clist = NULL;
1872 AddressObject *pobj = NULL;
1873 AddressObject *obj = NULL;
1874 AdapterDSource *ads = NULL;
1875 AddressInterface *iface = NULL;
1876 AddressDataSource *ds = NULL;
1877 gboolean canEdit = FALSE;
1878 gboolean canDelete = FALSE;
1879 gboolean canCut = FALSE;
1880 gboolean canCopy = FALSE;
1881 gboolean canPaste = FALSE;
1882 gboolean canBrowse = FALSE;
1884 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1885 if( pobj == NULL ) return;
1887 clist = GTK_CTREE(addrbook.clist);
1888 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1889 if( obj == NULL ) canEdit = FALSE;
1891 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1892 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1894 if( pobj->type == ADDR_DATASOURCE ) {
1895 /* Parent object is a data source */
1896 ads = ADAPTER_DSOURCE(pobj);
1897 ds = ads->dataSource;
1898 iface = ds->interface;
1899 if( ! iface->readOnly ) {
1900 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1901 if (iface->type != ADDR_IF_LDAP)
1902 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1903 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1904 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1905 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1906 if( obj ) canEdit = TRUE;
1908 canDelete = canEdit;
1910 else if( pobj->type != ADDR_INTERFACE ) {
1911 /* Parent object is not an interface */
1912 ds = addressbook_find_datasource( addrbook.treeSelected );
1915 iface = ds->interface;
1916 if( ! iface->readOnly ) {
1917 /* Folder or group */
1918 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1919 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1920 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1921 if( obj ) canEdit = TRUE;
1924 if( pobj->type == ADDR_ITEM_FOLDER ) {
1925 if (iface->type != ADDR_IF_LDAP)
1926 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1927 if( obj ) canEdit = TRUE;
1929 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1930 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1931 canDelete = canEdit;
1933 if( iface && iface->type == ADDR_IF_LDAP ) {
1934 if( obj ) canBrowse = TRUE;
1939 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1941 /* Disable edit or browse if more than one row selected */
1942 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1947 /* Now go finalize menu items */
1948 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1949 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1951 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1952 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1953 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1954 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1956 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1958 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1959 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1960 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1961 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1963 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1964 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1965 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1967 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1968 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1969 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1971 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1972 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1975 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1979 static void addressbook_select_row_tree (GtkCTree *ctree,
1987 * Add list of items into tree node below specified tree node.
1988 * \param treeNode Tree node.
1989 * \param ds Data source.
1990 * \param listItems List of items.
1992 static void addressbook_treenode_add_list(
1993 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
1999 AddrItemObject *aio;
2003 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2006 group = ( ItemGroup * ) aio;
2007 nn = addressbook_node_add_group( treeNode, ds, group );
2009 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2012 folder = ( ItemFolder * ) aio;
2013 nn = addressbook_node_add_folder(
2014 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2016 node = g_list_next( node );
2020 static void addressbook_select_all_cb( void ) {
2021 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2025 * Cut from address list widget.
2027 static void addressbook_clip_cut_cb( void ) {
2028 _clipBoard_->cutFlag = TRUE;
2029 addrclip_clear( _clipBoard_ );
2030 addrclip_add( _clipBoard_, _addressSelect_ );
2031 /* addrclip_list_show( _clipBoard_, stdout ); */
2035 * Copy from address list widget.
2037 static void addressbook_clip_copy_cb( void ) {
2038 _clipBoard_->cutFlag = FALSE;
2039 addrclip_clear( _clipBoard_ );
2040 addrclip_add( _clipBoard_, _addressSelect_ );
2041 /* addrclip_list_show( _clipBoard_, stdout ); */
2045 * Paste clipboard into address list widget.
2047 static void addressbook_clip_paste_cb( void ) {
2048 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2049 AddressObject *pobj = NULL;
2050 AddressDataSource *ds = NULL;
2051 AddressBookFile *abf = NULL;
2052 ItemFolder *folder = NULL;
2053 GList *folderGroup = NULL;
2055 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2056 if( ds == NULL ) return;
2057 if( addrindex_ds_get_readonly( ds ) ) {
2058 addressbook_ds_status_message(
2059 ds, _( "Cannot paste. Target address book is readonly." ) );
2063 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2065 if( pobj->type == ADDR_ITEM_FOLDER ) {
2066 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2068 else if( pobj->type == ADDR_ITEM_GROUP ) {
2069 addressbook_ds_status_message(
2070 ds, _( "Cannot paste into an address group." ) );
2075 /* Get an address book */
2076 abf = addressbook_get_book_file();
2077 if( abf == NULL ) return;
2079 if( _clipBoard_->cutFlag ) {
2081 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2083 /* Remove all groups and folders in clipboard from tree node */
2084 addressbook_treenode_remove_item();
2086 /* Remove all "cut" items */
2087 addrclip_delete_item( _clipBoard_ );
2089 /* Clear clipboard - cut items??? */
2090 addrclip_clear( _clipBoard_ );
2094 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2097 /* addrclip_list_show( _clipBoard_, stdout ); */
2099 /* Update tree by inserting node for each folder or group */
2100 addressbook_treenode_add_list(
2101 addrbook.treeSelected, ds, folderGroup );
2102 gtk_ctree_expand( ctree, addrbook.treeSelected );
2103 g_list_free( folderGroup );
2107 /* Display items pasted */
2108 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2109 addressbook_set_clist(
2110 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2118 * Add current treenode object to clipboard. Note that widget only allows
2119 * one entry from the tree list to be selected.
2121 static void addressbook_treenode_to_clipboard( void ) {
2122 AddressObject *obj = NULL;
2123 AddressDataSource *ds = NULL;
2124 AddrSelectItem *item;
2125 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2128 node = addrbook.treeSelected;
2129 if( node == NULL ) return;
2130 obj = gtk_ctree_node_get_row_data( ctree, node );
2131 if( obj == NULL ) return;
2133 ds = addressbook_find_datasource( node );
2134 if( ds == NULL ) return;
2137 if( obj->type == ADDR_ITEM_FOLDER ) {
2138 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2139 ItemFolder *folder = adapter->itemFolder;
2141 item = addrselect_create_node( obj );
2142 item->uid = g_strdup( ADDRITEM_ID(folder) );
2144 else if( obj->type == ADDR_ITEM_GROUP ) {
2145 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2146 ItemGroup *group = adapter->itemGroup;
2148 item = addrselect_create_node( obj );
2149 item->uid = g_strdup( ADDRITEM_ID(group) );
2151 else if( obj->type == ADDR_DATASOURCE ) {
2153 item = addrselect_create_node( obj );
2158 /* Clear existing list and add item into list */
2161 addressbook_list_select_clear();
2162 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2163 addrselect_list_add( _addressSelect_, item, cacheID );
2169 * Cut from tree widget.
2171 static void addressbook_treenode_cut_cb( void ) {
2172 _clipBoard_->cutFlag = TRUE;
2173 addressbook_treenode_to_clipboard();
2174 addrclip_clear( _clipBoard_ );
2175 addrclip_add( _clipBoard_, _addressSelect_ );
2176 /* addrclip_list_show( _clipBoard_, stdout ); */
2180 * Copy from tree widget.
2182 static void addressbook_treenode_copy_cb( void ) {
2183 _clipBoard_->cutFlag = FALSE;
2184 addressbook_treenode_to_clipboard();
2185 addrclip_clear( _clipBoard_ );
2186 addrclip_add( _clipBoard_, _addressSelect_ );
2187 /* addrclip_list_show( _clipBoard_, stdout ); */
2191 * Paste clipboard into address tree widget.
2193 static void addressbook_treenode_paste_cb( void ) {
2194 addressbook_clip_paste_cb();
2198 * Clear selected entries in clipboard.
2200 static void addressbook_list_select_clear( void ) {
2201 addrselect_list_clear( _addressSelect_ );
2205 * Add specified address item to selected address list.
2206 * \param aio Address item object.
2207 * \param ds Datasource.
2209 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2212 if( ds == NULL ) return;
2213 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2214 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2219 * Remove specified address item from selected address list.
2220 * \param aio Address item object.
2222 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2223 addrselect_list_remove( _addressSelect_, aio );
2227 * Invoke EMail compose window with addresses in selected address list.
2229 static void addressbook_mail_to_cb( void ) {
2232 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2233 listAddress = addrselect_build_list( _addressSelect_ );
2234 compose_new_with_list( NULL, listAddress );
2235 mgu_free_dlist( listAddress );
2240 static void addressbook_list_row_selected( GtkCTree *clist,
2245 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2246 AddrItemObject *aio = NULL;
2247 AddressObject *pobj = NULL;
2248 AdapterDSource *ads = NULL;
2249 AddressDataSource *ds = NULL;
2251 gtk_entry_set_text( entry, "" );
2252 addrbook.listSelected = node;
2254 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2255 if( pobj == NULL ) return;
2257 if( pobj->type == ADDR_DATASOURCE ) {
2258 ads = ADAPTER_DSOURCE(pobj);
2259 ds = ads->dataSource;
2261 else if( pobj->type != ADDR_INTERFACE ) {
2262 ds = addressbook_find_datasource( addrbook.treeSelected );
2265 aio = gtk_ctree_node_get_row_data( clist, node );
2267 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2268 addressbook_list_select_add( aio, ds );
2271 addressbook_list_menu_setup();
2273 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog)
2274 addressbook_edit_address(NULL, 0, NULL, FALSE);
2277 static void addressbook_list_row_unselected( GtkCTree *ctree,
2282 AddrItemObject *aio;
2284 aio = gtk_ctree_node_get_row_data( ctree, node );
2286 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2287 addressbook_list_select_remove( aio );
2290 if (!prefs_common.addressbook_use_editaddress_dialog)
2291 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2294 /* from gdkevents.c */
2295 #define DOUBLE_CLICK_TIME 250
2297 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2298 GdkEventButton *event,
2301 static guint32 lasttime = 0;
2302 if( ! event ) return FALSE;
2304 addressbook_list_menu_setup();
2306 if( event->button == 3 ) {
2307 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2308 event->button, event->time );
2309 } else if (event->button == 1) {
2310 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2311 if (prefs_common.add_address_by_click &&
2312 addrbook.target_compose)
2313 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2315 if (prefs_common.addressbook_use_editaddress_dialog)
2316 addressbook_edit_address_cb(NULL, 0, NULL);
2320 lasttime = event->time;
2326 static gboolean addressbook_list_button_released(GtkWidget *widget,
2327 GdkEventButton *event,
2333 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2334 GdkEventButton *event,
2337 GtkCList *clist = GTK_CLIST(ctree);
2339 AddressObject *obj = NULL;
2340 AdapterDSource *ads = NULL;
2341 AddressInterface *iface = NULL;
2342 AddressDataSource *ds = NULL;
2343 gboolean canEdit = FALSE;
2344 gboolean canDelete = FALSE;
2345 gboolean canCut = FALSE;
2346 gboolean canCopy = FALSE;
2347 gboolean canPaste = FALSE;
2348 gboolean canTreeCut = FALSE;
2349 gboolean canTreeCopy = FALSE;
2350 gboolean canTreePaste = FALSE;
2351 gboolean canLookup = FALSE;
2352 GtkCTreeNode *node = NULL;
2354 if( ! event ) return FALSE;
2355 addressbook_menubar_set_sensitive( FALSE );
2357 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2358 gtkut_clist_set_focus_row(clist, row);
2359 obj = gtk_clist_get_row_data( clist, row );
2362 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2364 if( obj == NULL ) return FALSE;
2365 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2367 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2368 canTreePaste = TRUE;
2371 if (obj->type == ADDR_INTERFACE) {
2372 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2373 iface = adapter->interface;
2376 canTreeCopy = FALSE;
2377 if( iface->readOnly ) {
2378 canTreePaste = FALSE;
2381 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2382 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2384 if( iface->externalQuery ) canLookup = TRUE;
2386 if (obj->type == ADDR_DATASOURCE) {
2387 ads = ADAPTER_DSOURCE(obj);
2388 ds = ads->dataSource;
2391 iface = ds->interface;
2396 if( iface->readOnly ) {
2397 canTreePaste = FALSE;
2400 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2401 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2402 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2405 if( iface->externalQuery ) canLookup = TRUE;
2407 else if (obj->type == ADDR_ITEM_FOLDER) {
2408 ds = addressbook_find_datasource( node );
2412 iface = ds->interface;
2415 if( iface->readOnly ) {
2416 canTreePaste = FALSE;
2422 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2423 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2424 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2428 if( iface->externalQuery ) {
2429 /* Enable deletion of LDAP folder */
2434 else if (obj->type == ADDR_ITEM_GROUP) {
2435 ds = addressbook_find_datasource( node );
2438 iface = ds->interface;
2441 if( ! iface->readOnly ) {
2444 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2445 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2448 else if (obj->type == ADDR_INTERFACE) {
2449 canTreePaste = FALSE;
2453 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2455 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2456 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2460 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2461 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2462 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2463 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2464 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2466 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2467 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2468 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2469 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2470 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2471 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2473 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2474 if( event->button == 3 ) {
2475 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2476 event->button, event->time);
2482 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2483 GdkEventButton *event,
2486 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2490 static void addressbook_new_folder_cb(gpointer data, guint action,
2493 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2494 AddressObject *obj = NULL;
2495 AddressDataSource *ds = NULL;
2496 AddressBookFile *abf = NULL;
2497 ItemFolder *parentFolder = NULL;
2498 ItemFolder *folder = NULL;
2500 if( ! addrbook.treeSelected ) return;
2501 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2502 if( obj == NULL ) return;
2503 ds = addressbook_find_datasource( addrbook.treeSelected );
2504 if( ds == NULL ) return;
2506 if( obj->type == ADDR_DATASOURCE ) {
2507 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2509 else if( obj->type == ADDR_ITEM_FOLDER ) {
2510 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2516 abf = ds->rawDataSource;
2517 if( abf == NULL ) return;
2518 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2521 nn = addressbook_node_add_folder(
2522 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2523 gtk_ctree_expand( ctree, addrbook.treeSelected );
2524 if( addrbook.treeSelected == addrbook.opened )
2525 addressbook_set_clist(obj, TRUE);
2530 static void addressbook_new_group_cb(gpointer data, guint action,
2533 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2534 AddressObject *obj = NULL;
2535 AddressDataSource *ds = NULL;
2536 AddressBookFile *abf = NULL;
2537 ItemFolder *parentFolder = NULL;
2538 ItemGroup *group = NULL;
2540 if( ! addrbook.treeSelected ) return;
2541 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2542 if( obj == NULL ) return;
2543 ds = addressbook_find_datasource( addrbook.treeSelected );
2544 if( ds == NULL ) return;
2546 if( obj->type == ADDR_DATASOURCE ) {
2547 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2549 else if( obj->type == ADDR_ITEM_FOLDER ) {
2550 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2556 abf = ds->rawDataSource;
2557 if( abf == NULL ) return;
2558 group = addressbook_edit_group( abf, parentFolder, NULL );
2561 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2562 gtk_ctree_expand( ctree, addrbook.treeSelected );
2563 if( addrbook.treeSelected == addrbook.opened )
2564 addressbook_set_clist(obj, TRUE);
2569 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2571 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2574 GdkPixmap *pix_cl, *pix_op;
2575 GdkBitmap *mask_cl, *mask_op;
2576 gboolean is_leaf, expanded;
2578 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2579 &pix_cl, &mask_cl, &pix_op, &mask_op,
2580 &is_leaf, &expanded);
2581 gtk_sctree_set_node_info(ctree, node, name, spacing,
2582 pix_cl, mask_cl, pix_op, mask_op,
2588 * \param obj Address object to edit.
2589 * \param node Node in tree.
2590 * \return New name of data source.
2592 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2593 gchar *newName = NULL;
2594 AddressDataSource *ds = NULL;
2595 AddressInterface *iface = NULL;
2596 AdapterDSource *ads = NULL;
2598 ds = addressbook_find_datasource( node );
2599 if( ds == NULL ) return NULL;
2600 iface = ds->interface;
2601 if( ! iface->haveLibrary ) return NULL;
2603 /* Read data from data source */
2604 if( addrindex_ds_get_modify_flag( ds ) ) {
2605 addrindex_ds_read_data( ds );
2608 if( ! addrindex_ds_get_read_flag( ds ) ) {
2609 addrindex_ds_read_data( ds );
2613 ads = ADAPTER_DSOURCE(obj);
2614 if( ads->subType == ADDR_BOOK ) {
2615 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2617 else if( ads->subType == ADDR_VCARD ) {
2618 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2621 else if( ads->subType == ADDR_JPILOT ) {
2622 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2626 else if( ads->subType == ADDR_LDAP ) {
2627 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2633 newName = obj->name;
2638 * Edit an object that is in the address tree area.
2640 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2643 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2645 AddressDataSource *ds = NULL;
2646 AddressBookFile *abf = NULL;
2647 GtkCTreeNode *node = NULL, *parentNode = NULL;
2650 if( ! addrbook.treeSelected ) return;
2651 node = addrbook.treeSelected;
2652 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2653 obj = gtk_ctree_node_get_row_data( ctree, node );
2654 if( obj == NULL ) return;
2655 parentNode = GTK_CTREE_ROW(node)->parent;
2657 ds = addressbook_find_datasource( node );
2658 if( ds == NULL ) return;
2660 if( obj->type == ADDR_DATASOURCE ) {
2661 name = addressbook_edit_datasource( obj, node );
2662 if( name == NULL ) return;
2665 abf = ds->rawDataSource;
2666 if( abf == NULL ) return;
2667 if( obj->type == ADDR_ITEM_FOLDER ) {
2668 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2669 ItemFolder *item = adapter->itemFolder;
2670 ItemFolder *parentFolder = NULL;
2671 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2672 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2673 name = ADDRITEM_NAME(item);
2675 else if( obj->type == ADDR_ITEM_GROUP ) {
2676 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2677 ItemGroup *item = adapter->itemGroup;
2678 ItemFolder *parentFolder = NULL;
2679 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2680 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2681 name = ADDRITEM_NAME(item);
2684 if( name && parentNode ) {
2685 /* Update node in tree view */
2686 addressbook_change_node_name( node, name );
2687 gtk_sctree_sort_node(ctree, parentNode);
2688 gtk_ctree_expand( ctree, node );
2689 gtk_sctree_select( GTK_SCTREE( ctree), node );
2696 ADDRTREE_DEL_FOLDER_ONLY,
2697 ADDRTREE_DEL_FOLDER_ADDR
2701 * Delete an item from the tree widget.
2702 * \param data Data passed in.
2703 * \param action Action.
2704 * \param widget Widget issuing callback.
2706 static void addressbook_treenode_delete_cb(
2707 gpointer data, guint action, GtkWidget *widget )
2709 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2710 GtkCTreeNode *node = NULL;
2714 AddrBookBase *adbase;
2715 AddressCache *cache;
2716 AdapterDSource *ads = NULL;
2717 AddressInterface *iface = NULL;
2718 AddressDataSource *ds = NULL;
2719 gboolean remFlag = FALSE;
2720 TreeItemDelType delType;
2722 if( ! addrbook.treeSelected ) return;
2723 node = addrbook.treeSelected;
2724 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2726 obj = gtk_ctree_node_get_row_data( ctree, node );
2727 g_return_if_fail(obj != NULL);
2729 if( obj->type == ADDR_DATASOURCE ) {
2730 ads = ADAPTER_DSOURCE(obj);
2731 if( ads == NULL ) return;
2732 ds = ads->dataSource;
2733 if( ds == NULL ) return;
2736 /* Must be folder or something else */
2737 ds = addressbook_find_datasource( node );
2738 if( ds == NULL ) return;
2740 /* Only allow deletion from non-readOnly */
2741 iface = ds->interface;
2742 if( iface->readOnly ) {
2743 /* Allow deletion of query results */
2744 if( ! iface->externalQuery ) return;
2748 /* Confirm deletion */
2749 delType = ADDRTREE_DEL_NONE;
2750 if( obj->type == ADDR_ITEM_FOLDER ) {
2751 if( iface->externalQuery ) {
2752 message = g_strdup_printf( _(
2753 "Do you want to delete the query " \
2754 "results and addresses in '%s' ?" ),
2756 aval = alertpanel( _("Delete"), message,
2757 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2759 if( aval == G_ALERTALTERNATE ) {
2760 delType = ADDRTREE_DEL_FOLDER_ADDR;
2764 message = g_strdup_printf
2765 ( _( "Do you want to delete '%s' ?"
2766 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2768 aval = alertpanel( _("Delete folder"), message,
2769 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2771 if( aval == G_ALERTALTERNATE ) {
2772 delType = ADDRTREE_DEL_FOLDER_ONLY;
2774 else if( aval == G_ALERTOTHER ) {
2775 delType = ADDRTREE_DEL_FOLDER_ADDR;
2779 else if( obj->type == ADDR_ITEM_GROUP ) {
2780 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2781 "The addresses it contains will not be lost."), obj->name);
2782 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2783 "+" GTK_STOCK_DELETE, NULL);
2785 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2787 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2788 "The addresses it contains will be lost."), obj->name);
2789 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2790 "+" GTK_STOCK_DELETE, NULL);
2792 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2794 if( delType == ADDRTREE_DEL_NONE ) return;
2796 /* Proceed with deletion */
2797 if( obj->type == ADDR_DATASOURCE ) {
2798 /* Remove node from tree */
2799 gtk_ctree_remove_node( ctree, node );
2801 /* Remove data source. */
2802 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2803 addrindex_free_datasource( ds );
2808 /* Get reference to cache */
2809 adbase = ( AddrBookBase * ) ds->rawDataSource;
2810 if( adbase == NULL ) return;
2811 cache = adbase->addressCache;
2813 /* Remove query results folder */
2814 if( iface->externalQuery ) {
2815 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2816 ItemFolder *folder = adapter->itemFolder;
2818 adapter->itemFolder = NULL;
2820 g_print( "remove folder for ::%s::\n", obj->name );
2821 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2822 g_print( "-------------- remove results\n" );
2824 addrindex_remove_results( ds, folder );
2825 /* g_print( "-------------- remove node\n" ); */
2826 gtk_ctree_remove_node( ctree, node );
2830 /* Code below is valid for regular address book deletion */
2831 if( obj->type == ADDR_ITEM_FOLDER ) {
2832 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2833 ItemFolder *item = adapter->itemFolder;
2835 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2836 /* Remove folder only */
2837 item = addrcache_remove_folder( cache, item );
2839 addritem_free_item_folder( item );
2840 addressbook_move_nodes_up( ctree, node );
2844 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2845 /* Remove folder and addresses */
2846 item = addrcache_remove_folder_delete( cache, item );
2848 addritem_free_item_folder( item );
2853 else if( obj->type == ADDR_ITEM_GROUP ) {
2854 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2855 ItemGroup *item = adapter->itemGroup;
2857 item = addrcache_remove_group( cache, item );
2859 addritem_free_item_group( item );
2866 gtk_ctree_remove_node(ctree, node );
2870 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2872 if( person && addrbook.treeSelected == addrbook.opened ) {
2873 person->status = ADD_ENTRY;
2874 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2875 addressbook_folder_refresh_one_person(
2876 GTK_CTREE(addrbook.clist), person );
2878 addressbook_address_list_set_focus();
2881 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2883 if( person && addrbook.treeSelected == addrbook.opened) {
2884 person->status = ADD_ENTRY;
2885 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2886 addressbook_set_clist(
2887 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2891 addressbook_address_list_set_focus();
2895 * Label (a format string) that is used to name each folder.
2897 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
2900 * Search ctree widget callback function.
2901 * \param pA Pointer to node.
2902 * \param pB Pointer to data item being sought.
2903 * \return Zero (0) if folder found.
2905 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
2908 aoA = ( AddressObject * ) pA;
2909 if( aoA->type == ADDR_ITEM_FOLDER ) {
2910 ItemFolder *folder, *fld;
2912 fld = ADAPTER_FOLDER(aoA)->itemFolder;
2913 folder = ( ItemFolder * ) pB;
2914 if( fld == folder ) return 0; /* Found folder */
2919 static ItemFolder * addressbook_setup_subf(
2920 AddressDataSource *ds, gchar *title,
2921 GtkCTreeNode *pNode )
2923 AddrBookBase *adbase;
2924 AddressCache *cache;
2927 GtkCTreeNode *nNode;
2929 AddressObjectType aoType = ADDR_NONE;
2932 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
2934 if( ds && ds->type == ADDR_IF_LDAP ) {
2936 aoType = ADDR_LDAP_QUERY;
2943 ctree = GTK_CTREE(addrbook.ctree);
2944 /* Get reference to address cache */
2945 adbase = ( AddrBookBase * ) ds->rawDataSource;
2946 cache = adbase->addressCache;
2948 if ((children = addrcache_get_list_folder(cache)) != NULL) {
2949 GList *cur = children;
2950 for (; cur; cur = cur->next) {
2951 ItemFolder *child = (ItemFolder *) cur->data;
2952 if (!strcmp2(ADDRITEM_NAME(child), title)) {
2953 nNode = gtk_ctree_find_by_row_data_custom(
2955 addressbook_treenode_find_folder_cb );
2957 addrindex_remove_results( ds, child );
2958 while( child->listPerson ) {
2959 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
2960 item = addrcache_remove_person( cache, item );
2962 addritem_free_item_person( item );
2966 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2967 addrbook.treeSelected = nNode;
2974 /* Create a folder */
2975 folder = addrcache_add_new_folder( cache, NULL );
2976 name = g_strdup_printf( "%s", title );
2977 addritem_folder_set_name( folder, name );
2978 addritem_folder_set_remarks( folder, "" );
2981 /* Now let's see the folder */
2982 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
2983 gtk_ctree_expand( ctree, pNode );
2985 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2986 addrbook.treeSelected = nNode;
2992 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2993 AddressObject *pobj = NULL;
2994 AddressDataSource *ds = NULL;
2995 AddressBookFile *abf = NULL;
2996 debug_print("adding address\n");
2997 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
2998 if( pobj == NULL ) {
2999 debug_print("no row data\n");
3002 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3004 debug_print("no datasource\n");
3008 abf = ds->rawDataSource;
3010 g_print("no addressbook file\n");
3014 if( pobj->type == ADDR_DATASOURCE ) {
3015 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3016 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3018 ItemFolder *folder = NULL;
3020 if (abf && abf->type == ADDR_IF_LDAP) {
3021 GtkCTreeNode *parentNode;
3022 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3023 if( ds == NULL ) return;
3025 /* We must have a datasource that is an external interface */
3026 if( ! ds->interface->haveLibrary ) return;
3027 if( ! ds->interface->externalQuery ) return;
3029 if( pobj->type == ADDR_ITEM_FOLDER ) {
3030 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3033 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3035 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3037 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3038 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3039 abf = ds->rawDataSource;
3042 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3043 addrbook.editaddress_vbox,
3044 addressbook_new_address_from_book_post_cb,
3047 if (abf && abf->type == ADDR_IF_LDAP) {
3048 LdapServer *server = ds->rawDataSource;
3049 ldapsvr_set_modified(server, TRUE);
3050 ldapsvr_update_book(server, NULL);
3051 if (server->retVal != LDAPRC_SUCCESS) {
3052 alertpanel( _("Add address(es)"),
3053 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3054 GTK_STOCK_CLOSE, NULL, NULL );
3055 server->retVal = LDAPRC_SUCCESS;
3060 if (prefs_common.addressbook_use_editaddress_dialog)
3061 addressbook_new_address_from_book_post_cb( person );
3064 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3066 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3069 if (abf && abf->type == ADDR_IF_LDAP) {
3070 GtkCTreeNode *parentNode;
3071 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3072 if( ds == NULL ) return;
3074 /* We must have a datasource that is an external interface */
3075 if( ! ds->interface->haveLibrary ) return;
3076 if( ! ds->interface->externalQuery ) return;
3078 if( pobj->type == ADDR_ITEM_FOLDER ) {
3079 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3082 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3084 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3087 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3088 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3089 abf = ds->rawDataSource;
3092 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3093 addrbook.editaddress_vbox,
3094 addressbook_new_address_from_folder_post_cb,
3097 if (abf && abf->type == ADDR_IF_LDAP) {
3098 LdapServer *server = ds->rawDataSource;
3099 ldapsvr_set_modified(server, TRUE);
3100 ldapsvr_update_book(server, NULL);
3101 if (server->retVal != LDAPRC_SUCCESS) {
3102 alertpanel( _("Add address(es)"),
3103 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3104 GTK_STOCK_CLOSE, NULL, NULL );
3109 if (prefs_common.addressbook_use_editaddress_dialog)
3110 addressbook_new_address_from_folder_post_cb( person );
3112 else if( pobj->type == ADDR_ITEM_GROUP ) {
3113 /* New address in group */
3114 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3115 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3116 if (addrbook.treeSelected == addrbook.opened) {
3117 /* Change node name in tree. */
3118 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3119 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3120 addressbook_set_clist(
3121 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3129 * Search for specified child group node in address index tree.
3130 * \param parent Parent node.
3131 * \param group Group to find.
3133 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3134 GtkCTreeNode *node = NULL;
3135 GtkCTreeRow *currRow;
3137 currRow = GTK_CTREE_ROW( parent );
3139 node = currRow->children;
3143 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3144 if( obj->type == ADDR_ITEM_GROUP ) {
3145 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3146 if( g == group ) return node;
3148 currRow = GTK_CTREE_ROW(node);
3149 node = currRow->sibling;
3155 static AddressBookFile *addressbook_get_book_file() {
3156 AddressBookFile *abf = NULL;
3157 AddressDataSource *ds = NULL;
3159 ds = addressbook_find_datasource( addrbook.treeSelected );
3160 if( ds == NULL ) return NULL;
3161 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3165 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3169 /* Remove existing folders and groups */
3170 row = GTK_CTREE_ROW( parent );
3172 while( (node = row->children) ) {
3173 gtk_ctree_remove_node( ctree, node );
3178 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3179 GtkCTreeNode *parent, *child;
3180 GtkCTreeRow *currRow;
3181 currRow = GTK_CTREE_ROW( node );
3183 parent = currRow->parent;
3184 while( (child = currRow->children) ) {
3185 gtk_ctree_move( ctree, child, parent, node );
3187 gtk_sctree_sort_node( ctree, parent );
3191 static void addressbook_edit_address_post_cb( ItemPerson *person )
3195 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3196 invalidate_address_completion();
3198 addressbook_address_list_set_focus();
3201 void addressbook_address_list_set_focus( void )
3203 if (!prefs_common.addressbook_use_editaddress_dialog) {
3204 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3205 addressbook_list_menu_setup();
3209 void addressbook_address_list_disable_some_actions(void)
3211 /* disable address copy/pasting when editing contact's detail (embedded form) */
3212 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3213 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3214 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3216 /* we're already editing contact's detail here */
3217 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", FALSE );
3218 gtk_widget_set_sensitive( addrbook.edit_btn, FALSE );
3221 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3222 addressbook_edit_address(data, action, widget, TRUE);
3225 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3226 gboolean force_focus ) {
3227 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3229 AddressObject *obj = NULL, *pobj = NULL;
3230 AddressDataSource *ds = NULL;
3231 GtkCTreeNode *node = NULL, *parentNode = NULL;
3233 AddressBookFile *abf = NULL;
3235 if( addrbook.listSelected == NULL ) return;
3236 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3237 g_return_if_fail(obj != NULL);
3239 ctree = GTK_CTREE( addrbook.ctree );
3240 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3241 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3243 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3244 if( ds == NULL ) return;
3246 abf = addressbook_get_book_file();
3248 if( obj->type == ADDR_ITEM_EMAIL ) {
3249 ItemEMail *email = ( ItemEMail * ) obj;
3250 if( email == NULL ) return;
3251 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3252 /* Edit parent group */
3253 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3254 ItemGroup *itemGrp = adapter->itemGroup;
3255 if( abf == NULL ) return;
3256 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3257 name = ADDRITEM_NAME(itemGrp);
3258 node = addrbook.treeSelected;
3259 parentNode = GTK_CTREE_ROW(node)->parent;
3262 /* Edit person - email page */
3264 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3265 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3266 addressbook_edit_address_post_cb,
3267 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3270 if (abf && abf->type == ADDR_IF_LDAP) {
3271 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3272 person->status = UPDATE_ENTRY;
3275 if (prefs_common.addressbook_use_editaddress_dialog)
3276 addressbook_edit_address_post_cb( person );
3281 else if( obj->type == ADDR_ITEM_PERSON ) {
3282 /* Edit person - basic page */
3283 ItemPerson *person = ( ItemPerson * ) obj;
3284 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3285 addressbook_edit_address_post_cb,
3286 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3289 if (abf && abf->type == ADDR_IF_LDAP) {
3290 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3291 person->status = UPDATE_ENTRY;
3294 if (prefs_common.addressbook_use_editaddress_dialog)
3295 addressbook_edit_address_post_cb( person );
3299 else if( obj->type == ADDR_ITEM_GROUP ) {
3300 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3301 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3302 parentNode = addrbook.treeSelected;
3303 node = addressbook_find_group_node( parentNode, itemGrp );
3304 name = ADDRITEM_NAME(itemGrp);
3305 invalidate_address_completion();
3311 /* Update tree node with node name */
3312 if( node == NULL ) return;
3313 addressbook_change_node_name( node, name );
3314 gtk_sctree_sort_node( ctree, parentNode );
3315 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3316 addressbook_set_clist(
3317 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3322 static void addressbook_delete_address_cb(gpointer data, guint action,
3325 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3326 addressbook_del_clicked(NULL, NULL);
3327 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3330 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3332 addressbook_close();
3335 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3336 addressbook_export_to_file();
3339 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3341 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3342 if( person ) addritem_person_set_opened( person, TRUE );
3346 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3348 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3349 if( person ) addritem_person_set_opened( person, FALSE );
3353 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3355 gchar *eMailAlias = ADDRITEM_NAME(email);
3356 if( eMailAlias && *eMailAlias != '\0' ) {
3358 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3361 str = g_strdup( eMailAlias );
3367 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3368 GList *items = itemGroup->listEMail;
3369 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3370 for( ; items != NULL; items = g_list_next( items ) ) {
3371 GtkCTreeNode *nodeEMail = NULL;
3372 gchar *text[N_LIST_COLS];
3373 ItemEMail *email = items->data;
3377 if( ! email ) continue;
3379 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3380 str = addressbook_format_item_clist( person, email );
3382 text[COL_NAME] = str;
3385 text[COL_NAME] = ADDRITEM_NAME(person);
3387 text[COL_ADDRESS] = email->address;
3388 text[COL_REMARKS] = email->remarks;
3389 nodeEMail = gtk_sctree_insert_node(
3391 text, FOLDER_SPACING,
3392 atci->iconXpm, atci->maskXpm,
3393 atci->iconXpmOpen, atci->maskXpmOpen,
3395 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3401 static void addressbook_folder_load_one_person(
3402 GtkCTree *clist, ItemPerson *person,
3403 AddressTypeControlItem *atci,
3404 AddressTypeControlItem *atciMail )
3406 GtkCTreeNode *nodePerson = NULL;
3407 GtkCTreeNode *nodeEMail = NULL;
3408 gchar *text[N_LIST_COLS];
3409 gboolean flgFirst = TRUE, haveAddr = FALSE;
3412 AddressBookFile *abf = addressbook_get_book_file();
3415 if( person == NULL ) return;
3417 text[COL_NAME] = "";
3418 node = person->listEMail;
3420 ItemEMail *email = node->data;
3421 gchar *eMailAddr = NULL;
3422 node = g_list_next( node );
3424 text[COL_ADDRESS] = email->address;
3425 text[COL_REMARKS] = email->remarks;
3426 eMailAddr = ADDRITEM_NAME(email);
3427 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3429 /* First email belongs with person */
3430 gchar *str = addressbook_format_item_clist( person, email );
3432 text[COL_NAME] = str;
3435 else if( abf && abf->type == ADDR_IF_LDAP &&
3436 person && person->nickName ) {
3437 if (person->nickName) {
3438 if (strcmp(person->nickName, "") != 0) {
3439 text[COL_NAME] = person->nickName;
3442 text[COL_NAME] = ADDRITEM_NAME(person);
3448 text[COL_NAME] = ADDRITEM_NAME(person);
3450 nodePerson = gtk_sctree_insert_node(
3452 text, FOLDER_SPACING,
3453 atci->iconXpm, atci->maskXpm,
3454 atci->iconXpmOpen, atci->maskXpmOpen,
3455 FALSE, person->isOpened );
3458 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3461 /* Subsequent email is a child node of person */
3462 text[COL_NAME] = ADDRITEM_NAME(email);
3463 nodeEMail = gtk_sctree_insert_node(
3464 clist, nodePerson, NULL,
3465 text, FOLDER_SPACING,
3466 atciMail->iconXpm, atciMail->maskXpm,
3467 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3469 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3475 /* Have name without EMail */
3476 text[COL_NAME] = ADDRITEM_NAME(person);
3477 text[COL_ADDRESS] = "";
3478 text[COL_REMARKS] = "";
3479 nodePerson = gtk_sctree_insert_node(
3481 text, FOLDER_SPACING,
3482 atci->iconXpm, atci->maskXpm,
3483 atci->iconXpmOpen, atci->maskXpmOpen,
3484 FALSE, person->isOpened );
3485 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3490 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3492 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3493 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3495 if( atci == NULL ) return;
3496 if( atciMail == NULL ) return;
3498 /* Load email addresses */
3499 items = addritem_folder_get_person_list( itemFolder );
3500 for( ; items != NULL; items = g_list_next( items ) ) {
3501 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3503 /* Free up the list */
3504 mgu_clear_list( items );
3505 g_list_free( items );
3508 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3509 addrbook.listSelected = NULL;
3510 gtk_ctree_remove_node( clist, node );
3511 addressbook_menubar_set_sensitive( FALSE );
3512 addressbook_menuitem_set_sensitive(
3513 gtk_ctree_node_get_row_data(
3514 GTK_CTREE(clist), addrbook.treeSelected ),
3515 addrbook.treeSelected );
3518 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3519 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3520 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3522 if( atci == NULL ) return;
3523 if( atciMail == NULL ) return;
3524 if( person == NULL ) return;
3525 /* unload the person */
3527 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3529 addressbook_folder_remove_node( clist, node );
3530 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3531 gtk_sctree_sort_node( clist, NULL );
3532 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3534 gtk_sctree_select( GTK_SCTREE(clist), node );
3535 if (!gtk_ctree_node_is_visible( clist, node ) )
3536 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3540 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3544 if( person == NULL ) return;
3545 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3546 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3548 addressbook_folder_remove_node( clist, node );
3552 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3554 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3556 /* Load any groups */
3557 if( ! atci ) return;
3558 items = addritem_folder_get_group_list( itemFolder );
3559 for( ; items != NULL; items = g_list_next( items ) ) {
3560 GtkCTreeNode *nodeGroup = NULL;
3561 gchar *text[N_LIST_COLS];
3562 ItemGroup *group = items->data;
3563 if( group == NULL ) continue;
3564 text[COL_NAME] = ADDRITEM_NAME(group);
3565 text[COL_ADDRESS] = "";
3566 text[COL_REMARKS] = "";
3567 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3568 text, FOLDER_SPACING,
3569 atci->iconXpm, atci->maskXpm,
3570 atci->iconXpmOpen, atci->maskXpmOpen,
3572 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3573 gtk_sctree_sort_node(clist, NULL);
3575 /* Free up the list */
3576 mgu_clear_list( items );
3577 g_list_free( items );
3581 * Search ctree widget callback function.
3582 * \param pA Pointer to node.
3583 * \param pB Pointer to data item being sought.
3584 * \return Zero (0) if group found.
3586 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3589 aoA = ( AddressObject * ) pA;
3590 if( aoA->type == ADDR_ITEM_GROUP ) {
3591 ItemGroup *group, *grp;
3593 grp = ADAPTER_GROUP(aoA)->itemGroup;
3594 group = ( ItemGroup * ) pB;
3595 if( grp == group ) return 0; /* Found group */
3601 * Remove folder and group nodes from tree widget for items contained ("cut")
3604 static void addressbook_treenode_remove_item( void ) {
3606 AddrSelectItem *cutItem;
3607 AddressCache *cache;
3608 AddrItemObject *aio;
3609 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3612 node = _clipBoard_->objectList;
3614 cutItem = node->data;
3615 node = g_list_next( node );
3616 cache = addrindex_get_cache(
3617 _clipBoard_->addressIndex, cutItem->cacheID );
3618 if( cache == NULL ) continue;
3619 aio = addrcache_get_object( cache, cutItem->uid );
3622 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3625 folder = ( ItemFolder * ) aio;
3626 tn = gtk_ctree_find_by_row_data_custom(
3627 ctree, NULL, folder,
3628 addressbook_treenode_find_folder_cb );
3630 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3633 group = ( ItemGroup * ) aio;
3634 tn = gtk_ctree_find_by_row_data_custom(
3636 addressbook_treenode_find_group_cb );
3640 /* Free up adapter and remove node. */
3641 gtk_ctree_remove_node( ctree, tn );
3648 * Find parent datasource for specified tree node.
3649 * \param node Node to test.
3650 * \return Data source, or NULL if not found.
3652 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3653 AddressDataSource *ds = NULL;
3656 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3659 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3660 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3662 /* g_print( "ao->type = %d\n", ao->type ); */
3663 if( ao->type == ADDR_DATASOURCE ) {
3664 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3665 /* g_print( "found it\n" ); */
3666 ds = ads->dataSource;
3670 node = GTK_CTREE_ROW(node)->parent;
3676 * Load address list widget with children of specified object.
3677 * \param obj Parent object to be loaded.
3679 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3680 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3681 GtkCList *clist = GTK_CLIST(addrbook.clist);
3682 AddressDataSource *ds = NULL;
3683 AdapterDSource *ads = NULL;
3684 static AddressObject *last_obj = NULL;
3686 if (addrbook.clist == NULL) {
3689 if (obj == last_obj && !refresh)
3694 gtk_clist_clear(clist);
3698 if( obj->type == ADDR_INTERFACE ) {
3699 /* g_print( "set_clist: loading datasource...\n" ); */
3700 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3704 gtk_clist_freeze(clist);
3705 gtk_clist_clear(clist);
3707 if( obj->type == ADDR_DATASOURCE ) {
3708 ads = ADAPTER_DSOURCE(obj);
3709 ds = ADAPTER_DSOURCE(obj)->dataSource;
3711 /* Load root folder */
3712 ItemFolder *rootFolder = NULL;
3713 rootFolder = addrindex_ds_get_root_folder( ds );
3714 addressbook_folder_load_person(
3715 ctreelist, addrindex_ds_get_root_folder( ds ) );
3716 addressbook_folder_load_group(
3717 ctreelist, addrindex_ds_get_root_folder( ds ) );
3721 if( obj->type == ADDR_ITEM_GROUP ) {
3723 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3724 addressbook_load_group( ctreelist, itemGroup );
3726 else if( obj->type == ADDR_ITEM_FOLDER ) {
3728 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3729 addressbook_folder_load_person( ctreelist, itemFolder );
3730 addressbook_folder_load_group( ctreelist, itemFolder );
3733 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3734 clist->focus_row = -1;
3735 gtk_clist_thaw(clist);
3739 * Call back function to free adaptor. Call back is setup by function
3740 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3741 * called when the address book tree widget node is removed by calling
3742 * function gtk_ctree_remove_node().
3744 * \param data Tree node's row data.
3746 static void addressbook_free_treenode( gpointer data ) {
3749 ao = ( AddressObject * ) data;
3750 if( ao == NULL ) return;
3751 if( ao->type == ADDR_INTERFACE ) {
3752 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3753 addrbookctl_free_interface( ai );
3755 else if( ao->type == ADDR_DATASOURCE ) {
3756 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3757 addrbookctl_free_datasource( ads );
3759 else if( ao->type == ADDR_ITEM_FOLDER ) {
3760 AdapterFolder *af = ADAPTER_FOLDER(ao);
3761 addrbookctl_free_folder( af );
3763 else if( ao->type == ADDR_ITEM_GROUP ) {
3764 AdapterGroup *ag = ADAPTER_GROUP(ao);
3765 addrbookctl_free_group( ag );
3770 * Create new adaptor for specified data source.
3772 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3773 AddressObjectType otype, gchar *name )
3775 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3776 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3777 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3778 adapter->dataSource = ds;
3779 adapter->subType = otype;
3783 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3784 ADDRESS_OBJECT_NAME(adapter) =
3785 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3789 * Load tree from address index with the initial data.
3791 static void addressbook_load_tree( void ) {
3792 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3793 GList *nodeIf, *nodeDS;
3794 AdapterInterface *adapter;
3795 AddressInterface *iface;
3796 AddressTypeControlItem *atci;
3797 AddressDataSource *ds;
3798 AdapterDSource *ads;
3799 GtkCTreeNode *node, *newNode;
3802 nodeIf = _addressInterfaceList_;
3804 adapter = nodeIf->data;
3805 node = adapter->treeNode;
3806 iface = adapter->interface;
3807 atci = adapter->atci;
3809 if( iface->useInterface ) {
3810 /* Load data sources below interface node */
3811 nodeDS = iface->listSource;
3815 name = addrindex_ds_get_name( ds );
3816 ads = addressbook_create_ds_adapter(
3817 ds, atci->objectType, name );
3818 newNode = addressbook_add_object(
3819 node, ADDRESS_OBJECT(ads) );
3820 nodeDS = g_list_next( nodeDS );
3822 gtk_ctree_expand( ctree, node );
3825 nodeIf = g_list_next( nodeIf );
3830 * Convert the old address book to new format.
3832 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3833 gboolean retVal = FALSE;
3834 gboolean errFlag = TRUE;
3837 /* Read old address book, performing conversion */
3838 debug_print( "Reading and converting old address book...\n" );
3839 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3840 addrindex_read_data( addrIndex );
3841 if( addrIndex->retVal == MGU_NO_FILE ) {
3842 /* We do not have a file - new user */
3843 debug_print( "New user... create new books...\n" );
3844 addrindex_create_new_books( addrIndex );
3845 if( addrIndex->retVal == MGU_SUCCESS ) {
3846 /* Save index file */
3847 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3848 addrindex_save_data( addrIndex );
3849 if( addrIndex->retVal == MGU_SUCCESS ) {
3854 msg = _( "New user, could not save index file." );
3858 msg = _( "New user, could not save address book files." );
3862 /* We have an old file */
3863 if( addrIndex->wasConverted ) {
3864 /* Converted successfully - save address index */
3865 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3866 addrindex_save_data( addrIndex );
3867 if( addrIndex->retVal == MGU_SUCCESS ) {
3868 msg = _( "Old address book converted successfully." );
3873 msg = _("Old address book converted,\n"
3874 "could not save new address index file." );
3878 /* File conversion failed - just create new books */
3879 debug_print( "File conversion failed... just create new books...\n" );
3880 addrindex_create_new_books( addrIndex );
3881 if( addrIndex->retVal == MGU_SUCCESS ) {
3883 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3884 addrindex_save_data( addrIndex );
3885 if( addrIndex->retVal == MGU_SUCCESS ) {
3886 msg = _("Could not convert address book,\n"
3887 "but created empty new address book files." );
3892 msg = _("Could not convert address book,\n"
3893 "could not save new address index file." );
3897 msg = _("Could not convert address book\n"
3898 "and could not create new address book files." );
3903 debug_print( "Error\n%s\n", msg );
3904 alertpanel_full(_("Addressbook conversion error"), msg,
3905 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3906 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3909 debug_print( "Warning\n%s\n", msg );
3910 alertpanel_full(_("Addressbook conversion error"), msg,
3911 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3912 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3918 void addressbook_read_file( void ) {
3919 AddressIndex *addrIndex = NULL;
3921 debug_print( "Reading address index...\n" );
3922 if( _addressIndex_ ) {
3923 debug_print( "address book already read!!!\n" );
3927 addrIndex = addrindex_create_index();
3928 addrindex_initialize();
3930 /* Use new address book index. */
3931 addrindex_set_file_path( addrIndex, get_rc_dir() );
3932 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3933 addrindex_read_data( addrIndex );
3934 if( addrIndex->retVal == MGU_NO_FILE ) {
3935 /* Conversion required */
3936 debug_print( "Converting...\n" );
3937 if( addressbook_convert( addrIndex ) ) {
3938 _addressIndex_ = addrIndex;
3941 else if( addrIndex->retVal == MGU_SUCCESS ) {
3942 _addressIndex_ = addrIndex;
3945 /* Error reading address book */
3946 debug_print( "Could not read address index.\n" );
3947 addrindex_print_index( addrIndex, stdout );
3948 alertpanel_full(_("Addressbook Error"),
3949 _("Could not read address index"),
3950 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3951 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3953 debug_print( "done.\n" );
3957 * Add object into the address index tree widget.
3958 * Enter: node Parent node.
3959 * obj Object to add.
3960 * Return: Node that was added, or NULL if object not added.
3962 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
3965 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3966 GtkCTreeNode *added;
3967 AddressObject *pobj;
3968 AddressObjectType otype;
3969 AddressTypeControlItem *atci = NULL;
3971 g_return_val_if_fail(node != NULL, NULL);
3972 g_return_val_if_fail(obj != NULL, NULL);
3974 pobj = gtk_ctree_node_get_row_data(ctree, node);
3975 g_return_val_if_fail(pobj != NULL, NULL);
3977 /* Determine object type to be displayed */
3978 if( obj->type == ADDR_DATASOURCE ) {
3979 otype = ADAPTER_DSOURCE(obj)->subType;
3985 /* Handle any special conditions. */
3987 atci = addrbookctl_lookup( otype );
3989 if( atci->showInTree ) {
3990 /* Add object to tree */
3993 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3994 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
3995 atci->treeLeaf, atci->treeExpand );
3996 gtk_ctree_node_set_row_data_full( ctree, added, obj,
3997 addressbook_free_treenode );
4001 gtk_sctree_sort_node(ctree, node);
4007 * Add group into the address index tree.
4008 * \param node Parent node.
4009 * \param ds Data source.
4010 * \param itemGroup Group to add.
4011 * \return Inserted node.
4013 static GtkCTreeNode *addressbook_node_add_group(
4014 GtkCTreeNode *node, AddressDataSource *ds,
4015 ItemGroup *itemGroup )
4017 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4018 GtkCTreeNode *newNode;
4019 AdapterGroup *adapter;
4020 AddressTypeControlItem *atci = NULL;
4023 if( ds == NULL ) return NULL;
4024 if( node == NULL || itemGroup == NULL ) return NULL;
4026 name = &itemGroup->obj.name;
4028 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4030 adapter = g_new0( AdapterGroup, 1 );
4031 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4032 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4033 adapter->itemGroup = itemGroup;
4035 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4036 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4037 atci->treeLeaf, atci->treeExpand );
4038 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4039 addressbook_free_treenode );
4040 gtk_sctree_sort_node( ctree, node );
4045 * Add folder into the address index tree. Only visible folders are loaded into
4046 * the address index tree. Note that the root folder is not inserted into the
4049 * \param node Parent node.
4050 * \param ds Data source.
4051 * \param itemFolder Folder to add.
4052 * \param otype Object type to display.
4053 * \return Inserted node for the folder.
4055 static GtkCTreeNode *addressbook_node_add_folder(
4056 GtkCTreeNode *node, AddressDataSource *ds,
4057 ItemFolder *itemFolder, AddressObjectType otype )
4059 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4060 GtkCTreeNode *newNode = NULL;
4061 AdapterFolder *adapter;
4062 AddressTypeControlItem *atci = NULL;
4063 GList *listItems = NULL;
4065 ItemFolder *rootFolder;
4067 /* Only visible folders */
4068 if( itemFolder->isHidden ) return NULL;
4070 if( ds == NULL ) return NULL;
4071 if( node == NULL || itemFolder == NULL ) return NULL;
4073 /* Determine object type */
4074 atci = addrbookctl_lookup( otype );
4075 if( atci == NULL ) return NULL;
4077 rootFolder = addrindex_ds_get_root_folder( ds );
4078 if( itemFolder == rootFolder ) {
4082 adapter = g_new0( AdapterFolder, 1 );
4083 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4084 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4085 adapter->itemFolder = itemFolder;
4087 name = ADDRITEM_NAME(itemFolder);
4088 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4089 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4090 atci->treeLeaf, atci->treeExpand );
4092 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4093 addressbook_free_treenode );
4097 listItems = itemFolder->listFolder;
4098 while( listItems ) {
4099 ItemFolder *item = listItems->data;
4100 addressbook_node_add_folder( newNode, ds, item, otype );
4101 listItems = g_list_next( listItems );
4103 listItems = itemFolder->listGroup;
4104 while( listItems ) {
4105 ItemGroup *item = listItems->data;
4106 addressbook_node_add_group( newNode, ds, item );
4107 listItems = g_list_next( listItems );
4109 gtk_sctree_sort_node( ctree, node );
4113 void addressbook_export_to_file( void ) {
4114 if( _addressIndex_ ) {
4115 /* Save all new address book data */
4116 debug_print( "Saving address books...\n" );
4117 addrindex_save_all_books( _addressIndex_ );
4119 debug_print( "Exporting addressbook to file...\n" );
4120 addrindex_save_data( _addressIndex_ );
4121 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4122 addrindex_print_index( _addressIndex_, stdout );
4125 /* Notify address completion of new data */
4126 invalidate_address_completion();
4130 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4132 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4133 addressbook_lup_clicked(NULL, NULL);
4138 * Comparison using cell contents (text in first column). Used for sort
4139 * address index widget.
4141 static gint addressbook_treenode_compare_func(
4142 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4144 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4145 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4146 gchar *name1 = NULL, *name2 = NULL;
4147 if( cell1 ) name1 = cell1->u.text;
4148 if( cell2 ) name2 = cell2->u.text;
4149 if( ! name1 ) return ( name2 != NULL );
4150 if( ! name2 ) return -1;
4151 return g_utf8_collate( name1, name2 );
4154 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4155 AdapterDSource *ads;
4156 AdapterInterface *adapter;
4157 GtkCTreeNode *newNode;
4159 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4160 if( adapter == NULL ) return;
4161 ads = addressbook_edit_book( _addressIndex_, NULL );
4163 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4165 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4166 addrbook.treeSelected = newNode;
4171 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4172 AdapterDSource *ads;
4173 AdapterInterface *adapter;
4174 GtkCTreeNode *newNode;
4176 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4177 if( adapter == NULL ) return;
4178 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4180 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4182 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4183 addrbook.treeSelected = newNode;
4189 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4190 AdapterDSource *ads;
4191 AdapterInterface *adapter;
4192 AddressInterface *iface;
4193 GtkCTreeNode *newNode;
4195 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4196 if( adapter == NULL ) return;
4197 iface = adapter->interface;
4198 if( ! iface->haveLibrary ) return;
4199 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4201 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4203 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4204 addrbook.treeSelected = newNode;
4211 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4212 AdapterDSource *ads;
4213 AdapterInterface *adapter;
4214 AddressInterface *iface;
4215 GtkCTreeNode *newNode;
4217 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4218 if( adapter == NULL ) return;
4219 iface = adapter->interface;
4220 if( ! iface->haveLibrary ) return;
4221 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4223 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4225 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4226 addrbook.treeSelected = newNode;
4233 * Display address search status message.
4234 * \param queryType Query type.
4235 * \param status Status/Error code.
4237 static void addressbook_search_message( gint queryType, gint sts ) {
4239 *addressbook_msgbuf = '\0';
4241 if( sts != MGU_SUCCESS ) {
4242 if( queryType == ADDRQUERY_LDAP ) {
4244 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4249 g_snprintf( addressbook_msgbuf,
4250 sizeof(addressbook_msgbuf), "%s", desc );
4251 addressbook_status_show( addressbook_msgbuf );
4254 addressbook_status_show( "" );
4259 * Refresh addressbook by forcing refresh of current selected object in
4262 static void addressbook_refresh_current( void ) {
4266 ctree = GTK_CTREE(addrbook.ctree);
4267 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4268 if( obj == NULL ) return;
4269 addressbook_set_clist( obj, TRUE );
4273 * Message that is displayed whilst a query is executing in a background
4276 static gchar *_tempMessage_ = N_( "Busy searching..." );
4279 * Address search idle function. This function is called during UI idle time
4280 * while a search is in progress.
4282 * \param data Idler data.
4284 static void addressbook_search_idle( gpointer data ) {
4288 queryID = GPOINTER_TO_INT( data );
4289 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4294 * Search completion callback function. This removes the query from the idle
4297 * \param sender Sender of query.
4298 * \param queryID Query ID of search request.
4299 * \param status Search status.
4300 * \param data Query data.
4302 static void addressbook_search_callback_end(
4303 gpointer sender, gint queryID, gint status, gpointer data )
4307 AddrQueryObject *aqo;
4309 /* Remove idler function */
4310 ptrQID = GINT_TO_POINTER( queryID );
4312 g_idle_remove_by_data( ptrQID );
4315 /* Refresh addressbook contents */
4316 addressbook_refresh_current();
4317 req = qrymgr_find_request( queryID );
4319 aqo = ( AddrQueryObject * ) req->queryList->data;
4320 addressbook_search_message( aqo->queryType, status );
4323 /* Stop the search */
4324 addrindex_stop_search( queryID );
4330 * \param ds Data source to search.
4331 * \param searchTerm String to lookup.
4332 * \param pNode Parent data source node.
4334 static void addressbook_perform_search(
4335 AddressDataSource *ds, gchar *searchTerm,
4336 GtkCTreeNode *pNode )
4338 AddrBookBase *adbase;
4339 AddressCache *cache;
4345 AddressObjectType aoType = ADDR_NONE;
4349 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4351 if( ds && ds->type == ADDR_IF_LDAP ) {
4353 aoType = ADDR_LDAP_QUERY;
4359 /* Get reference to address cache */
4360 adbase = ( AddrBookBase * ) ds->rawDataSource;
4361 cache = adbase->addressCache;
4363 /* Create a folder for the search results */
4364 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4365 folder = addressbook_setup_subf(ds, name, pNode);
4368 /* Setup the search */
4369 queryID = addrindex_setup_explicit_search(
4370 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4371 if( queryID == 0 ) return;
4373 /* Set up idler function */
4374 idleID = g_idle_add(
4375 ( GtkFunction ) addressbook_search_idle,
4376 GINT_TO_POINTER( queryID ) );
4378 /* Start search, sit back and wait for something to happen */
4379 addrindex_start_search( queryID );
4381 addressbook_status_show( _tempMessage_ );
4385 * Lookup button handler. Address search is only performed against
4386 * address interfaces for external queries.
4388 * \param button Lookup button widget.
4389 * \param data Data object.
4391 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4394 AddressDataSource *ds;
4395 AddressInterface *iface;
4397 GtkCTreeNode *node, *parentNode;
4399 node = addrbook.treeSelected;
4400 if( ! node ) return;
4401 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4403 ctree = GTK_CTREE(addrbook.ctree);
4404 obj = gtk_ctree_node_get_row_data( ctree, node );
4405 if( obj == NULL ) return;
4407 ds = addressbook_find_datasource( node );
4408 if( ds == NULL ) return;
4410 /* We must have a datasource that is an external interface */
4411 iface = ds->interface;
4412 if( ! iface->haveLibrary ) return;
4413 if( ! iface->externalQuery ) return;
4416 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4417 g_strchomp( searchTerm );
4419 if( obj->type == ADDR_ITEM_FOLDER ) {
4420 parentNode = GTK_CTREE_ROW(node)->parent;
4425 addressbook_perform_search( ds, searchTerm, parentNode );
4427 gtk_widget_grab_focus( addrbook.entry );
4429 g_free( searchTerm );
4432 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4433 addressbook_close();
4438 * Browse address entry for highlighted entry.
4440 static void addressbook_browse_entry_cb(void)
4442 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4444 AddressDataSource *ds;
4445 AddressInterface *iface;
4449 if(addrbook.listSelected == NULL)
4452 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4456 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4460 iface = ds->interface;
4461 if(! iface->haveLibrary )
4465 if (obj->type == ADDR_ITEM_EMAIL) {
4466 email = ( ItemEMail * ) obj;
4470 person = (ItemPerson *) ADDRITEM_PARENT(email);
4472 else if (obj->type == ADDR_ITEM_PERSON) {
4473 person = (ItemPerson *) obj;
4480 if( iface && iface->type == ADDR_IF_LDAP ) {
4481 browseldap_entry(ds, person->externalID);
4486 /* **********************************************************************
4487 * Build lookup tables.
4488 * ***********************************************************************
4492 * Remap object types.
4493 * Enter: abType AddressObjectType (used in tree node).
4494 * Return: ItemObjectType (used in address cache data).
4496 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4497 ItemObjectType ioType;
4500 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4501 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4502 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4503 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4504 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4505 default: ioType = ITEMTYPE_NONE; break;
4511 * Build table that controls the rendering of object types.
4513 static void addrbookctl_build_map( GtkWidget *window ) {
4514 AddressTypeControlItem *atci;
4517 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4518 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4519 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4520 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4521 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4522 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4523 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4524 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4525 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4526 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4528 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4529 _addressBookTypeList_ = NULL;
4532 atci = g_new0( AddressTypeControlItem, 1 );
4533 atci->objectType = ADDR_INTERFACE;
4534 atci->interfaceType = ADDR_IF_NONE;
4535 atci->showInTree = TRUE;
4536 atci->treeExpand = TRUE;
4537 atci->treeLeaf = FALSE;
4538 atci->displayName = _( "Interface" );
4539 atci->iconXpm = folderxpm;
4540 atci->maskXpm = folderxpmmask;
4541 atci->iconXpmOpen = folderopenxpm;
4542 atci->maskXpmOpen = folderopenxpmmask;
4543 atci->menuCommand = NULL;
4544 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4545 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4548 atci = g_new0( AddressTypeControlItem, 1 );
4549 atci->objectType = ADDR_BOOK;
4550 atci->interfaceType = ADDR_IF_BOOK;
4551 atci->showInTree = TRUE;
4552 atci->treeExpand = TRUE;
4553 atci->treeLeaf = FALSE;
4554 atci->displayName = _( "Address Book" );
4555 atci->iconXpm = bookxpm;
4556 atci->maskXpm = bookxpmmask;
4557 atci->iconXpmOpen = bookxpm;
4558 atci->maskXpmOpen = bookxpmmask;
4559 atci->menuCommand = "/Book/New Book";
4560 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4561 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4564 atci = g_new0( AddressTypeControlItem, 1 );
4565 atci->objectType = ADDR_ITEM_PERSON;
4566 atci->interfaceType = ADDR_IF_NONE;
4567 atci->showInTree = FALSE;
4568 atci->treeExpand = FALSE;
4569 atci->treeLeaf = FALSE;
4570 atci->displayName = _( "Person" );
4571 atci->iconXpm = NULL;
4572 atci->maskXpm = NULL;
4573 atci->iconXpmOpen = NULL;
4574 atci->maskXpmOpen = NULL;
4575 atci->menuCommand = NULL;
4576 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4577 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4580 atci = g_new0( AddressTypeControlItem, 1 );
4581 atci->objectType = ADDR_ITEM_EMAIL;
4582 atci->interfaceType = ADDR_IF_NONE;
4583 atci->showInTree = FALSE;
4584 atci->treeExpand = FALSE;
4585 atci->treeLeaf = TRUE;
4586 atci->displayName = _( "EMail Address" );
4587 atci->iconXpm = addressxpm;
4588 atci->maskXpm = addressxpmmask;
4589 atci->iconXpmOpen = addressxpm;
4590 atci->maskXpmOpen = addressxpmmask;
4591 atci->menuCommand = NULL;
4592 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4593 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4596 atci = g_new0( AddressTypeControlItem, 1 );
4597 atci->objectType = ADDR_ITEM_GROUP;
4598 atci->interfaceType = ADDR_IF_BOOK;
4599 atci->showInTree = TRUE;
4600 atci->treeExpand = FALSE;
4601 atci->treeLeaf = FALSE;
4602 atci->displayName = _( "Group" );
4603 atci->iconXpm = groupxpm;
4604 atci->maskXpm = groupxpmmask;
4605 atci->iconXpmOpen = groupxpm;
4606 atci->maskXpmOpen = groupxpmmask;
4607 atci->menuCommand = NULL;
4608 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4609 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4612 atci = g_new0( AddressTypeControlItem, 1 );
4613 atci->objectType = ADDR_ITEM_FOLDER;
4614 atci->interfaceType = ADDR_IF_BOOK;
4615 atci->showInTree = TRUE;
4616 atci->treeExpand = FALSE;
4617 atci->treeLeaf = FALSE;
4618 atci->displayName = _( "Folder" );
4619 atci->iconXpm = folderxpm;
4620 atci->maskXpm = folderxpmmask;
4621 atci->iconXpmOpen = folderopenxpm;
4622 atci->maskXpmOpen = folderopenxpmmask;
4623 atci->menuCommand = NULL;
4624 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4625 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4628 atci = g_new0( AddressTypeControlItem, 1 );
4629 atci->objectType = ADDR_VCARD;
4630 atci->interfaceType = ADDR_IF_VCARD;
4631 atci->showInTree = TRUE;
4632 atci->treeExpand = TRUE;
4633 atci->treeLeaf = TRUE;
4634 atci->displayName = _( "vCard" );
4635 atci->iconXpm = vcardxpm;
4636 atci->maskXpm = vcardxpmmask;
4637 atci->iconXpmOpen = vcardxpm;
4638 atci->maskXpmOpen = vcardxpmmask;
4639 atci->menuCommand = "/Book/New vCard";
4640 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4641 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4644 atci = g_new0( AddressTypeControlItem, 1 );
4645 atci->objectType = ADDR_JPILOT;
4646 atci->interfaceType = ADDR_IF_JPILOT;
4647 atci->showInTree = TRUE;
4648 atci->treeExpand = TRUE;
4649 atci->treeLeaf = FALSE;
4650 atci->displayName = _( "JPilot" );
4651 atci->iconXpm = jpilotxpm;
4652 atci->maskXpm = jpilotxpmmask;
4653 atci->iconXpmOpen = jpilotxpm;
4654 atci->maskXpmOpen = jpilotxpmmask;
4655 atci->menuCommand = "/Book/New JPilot";
4656 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4657 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4660 atci = g_new0( AddressTypeControlItem, 1 );
4661 atci->objectType = ADDR_CATEGORY;
4662 atci->interfaceType = ADDR_IF_JPILOT;
4663 atci->showInTree = TRUE;
4664 atci->treeExpand = TRUE;
4665 atci->treeLeaf = TRUE;
4666 atci->displayName = _( "JPilot" );
4667 atci->iconXpm = categoryxpm;
4668 atci->maskXpm = categoryxpmmask;
4669 atci->iconXpmOpen = categoryxpm;
4670 atci->maskXpmOpen = categoryxpmmask;
4671 atci->menuCommand = NULL;
4672 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4673 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4676 atci = g_new0( AddressTypeControlItem, 1 );
4677 atci->objectType = ADDR_LDAP;
4678 atci->interfaceType = ADDR_IF_LDAP;
4679 atci->showInTree = TRUE;
4680 atci->treeExpand = TRUE;
4681 atci->treeLeaf = FALSE;
4682 atci->displayName = _( "LDAP servers" );
4683 atci->iconXpm = ldapxpm;
4684 atci->maskXpm = ldapxpmmask;
4685 atci->iconXpmOpen = ldapxpm;
4686 atci->maskXpmOpen = ldapxpmmask;
4687 atci->menuCommand = "/Book/New LDAP Server";
4688 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4689 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4692 atci = g_new0( AddressTypeControlItem, 1 );
4693 atci->objectType = ADDR_LDAP_QUERY;
4694 atci->interfaceType = ADDR_IF_LDAP;
4695 atci->showInTree = TRUE;
4696 atci->treeExpand = FALSE;
4697 atci->treeLeaf = TRUE;
4698 atci->displayName = _( "LDAP Query" );
4699 atci->iconXpm = addrsearchxpm;
4700 atci->maskXpm = addrsearchxpmmask;
4701 atci->iconXpmOpen = addrsearchxpm;
4702 atci->maskXpmOpen = addrsearchxpmmask;
4703 atci->menuCommand = NULL;
4704 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4705 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4710 * Search for specified object type.
4712 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4714 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4718 * Search for specified interface type.
4720 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4721 GList *node = _addressBookTypeList_;
4723 AddressTypeControlItem *atci = node->data;
4724 if( atci->interfaceType == ifType ) return atci;
4725 node = g_list_next( node );
4730 static void addrbookctl_free_address( AddressObject *obj ) {
4731 g_free( obj->name );
4732 obj->type = ADDR_NONE;
4736 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4737 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4738 adapter->interface = NULL;
4739 adapter->interfaceType = ADDR_IF_NONE;
4740 adapter->atci = NULL;
4741 adapter->enabled = FALSE;
4742 adapter->haveLibrary = FALSE;
4743 adapter->treeNode = NULL;
4747 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4748 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4749 adapter->dataSource = NULL;
4750 adapter->subType = ADDR_NONE;
4754 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4755 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4756 adapter->itemFolder = NULL;
4760 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4761 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4762 adapter->itemGroup = NULL;
4767 * Build GUI interface list.
4769 static void addrbookctl_build_iflist( void ) {
4770 AddressTypeControlItem *atci;
4771 AdapterInterface *adapter;
4774 if( _addressIndex_ == NULL ) {
4775 _addressIndex_ = addrindex_create_index();
4776 if( _clipBoard_ == NULL ) {
4777 _clipBoard_ = addrclip_create();
4779 addrclip_set_index( _clipBoard_, _addressIndex_ );
4781 _addressInterfaceList_ = NULL;
4782 list = addrindex_get_interface_list( _addressIndex_ );
4784 AddressInterface *interface = list->data;
4785 atci = addrbookctl_lookup_iface( interface->type );
4787 adapter = g_new0( AdapterInterface, 1 );
4788 adapter->interfaceType = interface->type;
4789 adapter->atci = atci;
4790 adapter->interface = interface;
4791 adapter->treeNode = NULL;
4792 adapter->enabled = TRUE;
4793 adapter->haveLibrary = interface->haveLibrary;
4794 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4795 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4796 _addressInterfaceList_ =
4797 g_list_append( _addressInterfaceList_, adapter );
4799 list = g_list_next( list );
4804 * Find GUI interface type specified interface type.
4805 * \param ifType Interface type.
4806 * \return Interface item, or NULL if not found.
4808 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4809 GList *node = _addressInterfaceList_;
4811 AdapterInterface *adapter = node->data;
4812 if( adapter->interfaceType == ifType ) return adapter;
4813 node = g_list_next( node );
4819 * Build interface list selection.
4821 static void addrbookctl_build_ifselect( void ) {
4822 GList *newList = NULL;
4827 gchar *endptr = NULL;
4829 AdapterInterface *adapter;
4831 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4834 splitStr = g_strsplit( selectStr, ",", -1 );
4835 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4837 /* g_print( "%d : %s\n", i, splitStr[i] ); */
4838 ifType = strtol( splitStr[i], &endptr, 10 );
4841 if( strcmp( endptr, "/n" ) == 0 ) {
4845 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4846 adapter = addrbookctl_find_interface( ifType );
4848 newList = g_list_append( newList, adapter );
4855 /* g_print( "i=%d\n", i ); */
4856 g_strfreev( splitStr );
4857 g_free( selectStr );
4859 /* Replace existing list */
4860 mgu_clear_list( _addressIFaceSelection_ );
4861 g_list_free( _addressIFaceSelection_ );
4862 _addressIFaceSelection_ = newList;
4866 /* ***********************************************************************
4867 * Add sender to address book.
4868 * ***********************************************************************
4872 * This function is used by the Add sender to address book function.
4874 gboolean addressbook_add_contact(
4875 const gchar *name, const gchar *address, const gchar *remarks )
4877 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4878 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4879 debug_print( "addressbook_add_contact - added\n" );
4880 addressbook_refresh();
4885 /* ***********************************************************************
4886 * Book/folder selection.
4887 * ***********************************************************************
4891 * This function is used by the matcher dialog to select a book/folder.
4893 gboolean addressbook_folder_selection( gchar **folderpath )
4895 AddressBookFile *book = NULL;
4896 ItemFolder *folder = NULL;
4899 g_return_val_if_fail( folderpath != NULL, FALSE);
4903 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4905 if ( folder != NULL) {
4907 gchar *oldtmp = NULL;
4908 AddrItemObject *obj = NULL;
4910 /* walk thru folder->parent to build the full folder path */
4911 /* TODO: wwp: optimize this */
4913 tmp = g_strdup(obj->uid);
4914 while ( obj->parent ) {
4916 if ( obj->name != NULL ) {
4917 oldtmp = g_strdup(tmp);
4919 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4923 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4926 *folderpath = g_strdup_printf("%s", book->fileName);
4928 debug_print( "addressbook_foldersel: %s\n", *folderpath?*folderpath:"(null)");
4929 return (*folderpath != NULL);
4934 /* ***********************************************************************
4935 * Book/folder checking.
4936 * ***********************************************************************
4939 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
4941 FolderInfo *fi = g_new0( FolderInfo, 1 );
4943 fi->folder = folder;
4947 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
4948 FolderInfo *fiParent, FolderPathMatch *match )
4954 FolderPathMatch *nextmatch = NULL;
4959 list = parentFolder->listFolder;
4961 folder = list->data;
4962 fName = g_strdup( ADDRITEM_NAME(folder) );
4964 /* match folder name, match pointer will be set to NULL if next recursive call
4965 doesn't need to match subfolder name */
4966 if ( match != NULL &&
4967 match->matched == FALSE ) {
4968 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
4969 /* folder name matches, prepare next subfolder match */
4970 debug_print("matched folder name '%s'\n", fName);
4972 if ( match->folder_path[match->index] == NULL ) {
4973 /* we've matched all elements */
4974 match->matched = TRUE;
4975 match->folder = folder;
4976 debug_print("book/folder path matched!\n");
4978 /* keep on matching */
4986 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
4987 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
4989 list = g_list_next( list );
4994 * This function is used by to check if a matcher book/folder path corresponds to an
4995 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
4996 Caution: returned book and folder pointers can be NULL even when returning TRUE:
4997 if book AND folder are NULL this means that folderpath was empty or Any.
4998 If folderpath is a simple book name (without folder), book will not be NULL and folder
4999 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5002 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5003 AddressDataSource **book,
5004 ItemFolder **folder )
5006 AddressDataSource *ds;
5007 GList *list, *nodeDS;
5008 ItemFolder *rootFolder;
5009 AddressBookFile *abf;
5011 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5018 if ( folderpath == NULL )
5021 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5024 /* split the folder path we've received, we'll try to match this path, subpath by
5025 subpath against the book/folder structure in order */
5026 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5027 if (!folder_path_match.folder_path)
5030 list = addrindex_get_interface_list( _addressIndex_ );
5031 while ( list && !folder_path_match.matched ) {
5032 AddressInterface *interface = list->data;
5033 if ( interface && interface->type == ADDR_IF_BOOK ) {
5034 nodeDS = interface->listSource;
5035 while ( nodeDS && !folder_path_match.matched ) {
5038 /* Read address book */
5039 if( ! addrindex_ds_get_read_flag( ds ) ) {
5040 addrindex_ds_read_data( ds );
5043 /* Add node for address book */
5044 abf = ds->rawDataSource;
5046 /* match book name */
5047 if ( abf && abf->fileName &&
5048 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5050 debug_print("matched book name '%s'\n", abf->fileName);
5051 folder_path_match.book = ds;
5053 if ( folder_path_match.folder_path[1] == NULL ) {
5054 /* no folder part to match */
5056 folder_path_match.matched = TRUE;
5057 folder_path_match.folder = NULL;
5058 debug_print("book path matched!\n");
5061 /* match folder part */
5063 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5064 rootFolder = addrindex_ds_get_root_folder( ds );
5066 /* prepare for recursive call */
5067 folder_path_match.index = 1;
5068 /* this call will set folder_path_match.matched and folder_path_match.folder */
5069 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5074 nodeDS = g_list_next( nodeDS );
5077 list = g_list_next( list );
5080 g_strfreev( folder_path_match.folder_path );
5083 *book = folder_path_match.book;
5085 *folder = folder_path_match.folder;
5086 return folder_path_match.matched;
5090 /* **********************************************************************
5092 * ***********************************************************************
5098 static void addressbook_import_ldif_cb( void ) {
5099 AddressDataSource *ds = NULL;
5100 AdapterDSource *ads = NULL;
5101 AddressBookFile *abf = NULL;
5102 AdapterInterface *adapter;
5103 GtkCTreeNode *newNode;
5105 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5107 if( adapter->treeNode ) {
5108 abf = addressbook_imp_ldif( _addressIndex_ );
5110 ds = addrindex_index_add_datasource(
5111 _addressIndex_, ADDR_IF_BOOK, abf );
5112 ads = addressbook_create_ds_adapter(
5113 ds, ADDR_BOOK, NULL );
5114 addressbook_ads_set_name(
5115 ads, addrbook_get_name( abf ) );
5116 newNode = addressbook_add_object(
5118 ADDRESS_OBJECT(ads) );
5120 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5122 addrbook.treeSelected = newNode;
5125 /* Notify address completion */
5126 invalidate_address_completion();
5135 static void addressbook_import_mutt_cb( void ) {
5136 AddressDataSource *ds = NULL;
5137 AdapterDSource *ads = NULL;
5138 AddressBookFile *abf = NULL;
5139 AdapterInterface *adapter;
5140 GtkCTreeNode *newNode;
5142 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5144 if( adapter->treeNode ) {
5145 abf = addressbook_imp_mutt( _addressIndex_ );
5147 ds = addrindex_index_add_datasource(
5148 _addressIndex_, ADDR_IF_BOOK, abf );
5149 ads = addressbook_create_ds_adapter(
5150 ds, ADDR_BOOK, NULL );
5151 addressbook_ads_set_name(
5152 ads, addrbook_get_name( abf ) );
5153 newNode = addressbook_add_object(
5155 ADDRESS_OBJECT(ads) );
5157 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5159 addrbook.treeSelected = newNode;
5162 /* Notify address completion */
5163 invalidate_address_completion();
5172 static void addressbook_import_pine_cb( void ) {
5173 AddressDataSource *ds = NULL;
5174 AdapterDSource *ads = NULL;
5175 AddressBookFile *abf = NULL;
5176 AdapterInterface *adapter;
5177 GtkCTreeNode *newNode;
5179 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5181 if( adapter->treeNode ) {
5182 abf = addressbook_imp_pine( _addressIndex_ );
5184 ds = addrindex_index_add_datasource(
5185 _addressIndex_, ADDR_IF_BOOK, abf );
5186 ads = addressbook_create_ds_adapter(
5187 ds, ADDR_BOOK, NULL );
5188 addressbook_ads_set_name(
5189 ads, addrbook_get_name( abf ) );
5190 newNode = addressbook_add_object(
5192 ADDRESS_OBJECT(ads) );
5194 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5196 addrbook.treeSelected = newNode;
5199 /* Notify address completion */
5200 invalidate_address_completion();
5207 * Harvest addresses.
5208 * \param folderItem Folder to import.
5209 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5210 * \param msgList List of message numbers, or NULL to process folder.
5212 void addressbook_harvest(
5213 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5215 AddressDataSource *ds = NULL;
5216 AdapterDSource *ads = NULL;
5217 AddressBookFile *abf = NULL;
5218 AdapterInterface *adapter;
5219 GtkCTreeNode *newNode;
5221 abf = addrgather_dlg_execute(
5222 folderItem, _addressIndex_, sourceInd, msgList );
5224 ds = addrindex_index_add_datasource(
5225 _addressIndex_, ADDR_IF_BOOK, abf );
5227 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5229 if( adapter->treeNode ) {
5230 ads = addressbook_create_ds_adapter(
5231 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5232 newNode = addressbook_add_object(
5234 ADDRESS_OBJECT(ads) );
5238 /* Notify address completion */
5239 invalidate_address_completion();
5246 static void addressbook_export_html_cb( void ) {
5247 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5249 AddressDataSource *ds = NULL;
5250 AddrBookBase *adbase;
5251 AddressCache *cache;
5252 GtkCTreeNode *node = NULL;
5254 if( ! addrbook.treeSelected ) return;
5255 node = addrbook.treeSelected;
5256 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5257 obj = gtk_ctree_node_get_row_data( ctree, node );
5258 if( obj == NULL ) return;
5260 ds = addressbook_find_datasource( node );
5261 if( ds == NULL ) return;
5262 adbase = ( AddrBookBase * ) ds->rawDataSource;
5263 cache = adbase->addressCache;
5264 addressbook_exp_html( cache );
5270 static void addressbook_export_ldif_cb( void ) {
5271 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5273 AddressDataSource *ds = NULL;
5274 AddrBookBase *adbase;
5275 AddressCache *cache;
5276 GtkCTreeNode *node = NULL;
5278 if( ! addrbook.treeSelected ) return;
5279 node = addrbook.treeSelected;
5280 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5281 obj = gtk_ctree_node_get_row_data( ctree, node );
5282 if( obj == NULL ) return;
5284 ds = addressbook_find_datasource( node );
5285 if( ds == NULL ) return;
5286 adbase = ( AddrBookBase * ) ds->rawDataSource;
5287 cache = adbase->addressCache;
5288 addressbook_exp_ldif( cache );
5291 static void addressbook_find_duplicates_cb(void)
5293 addrduplicates_find(GTK_WINDOW(addrbook.window));
5296 static void addressbook_start_drag(GtkWidget *widget, gint button,
5300 GdkDragContext *context;
5301 if (addressbook_target_list == NULL)
5302 addressbook_target_list = gtk_target_list_new(
5303 addressbook_drag_types, 1);
5304 context = gtk_drag_begin(widget, addressbook_target_list,
5305 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5306 gtk_drag_set_icon_default(context);
5309 static void addressbook_drag_data_get(GtkWidget *widget,
5310 GdkDragContext *drag_context,
5311 GtkSelectionData *selection_data,
5316 AddrItemObject *aio = NULL;
5317 AddressObject *pobj = NULL;
5318 AdapterDSource *ads = NULL;
5319 AddressDataSource *ds = NULL;
5322 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5324 if( pobj == NULL ) return;
5326 if( pobj->type == ADDR_DATASOURCE ) {
5327 ads = ADAPTER_DSOURCE(pobj);
5328 ds = ads->dataSource;
5329 } else if (pobj->type == ADDR_ITEM_GROUP) {
5334 else if( pobj->type != ADDR_INTERFACE ) {
5335 ds = addressbook_find_datasource( addrbook.treeSelected );
5341 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5342 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5343 GTK_CTREE_NODE(cur->data));
5344 while (aio && aio->type != ADDR_ITEM_PERSON) {
5349 if (aio && aio->type == ADDR_ITEM_PERSON) {
5350 if( ds && ds->interface && ds->interface->readOnly)
5351 gtk_selection_data_set(selection_data,
5352 selection_data->target, 8,
5353 "Dummy_addr_copy", 15);
5355 gtk_selection_data_set(selection_data,
5356 selection_data->target, 8,
5357 "Dummy_addr_move", 15);
5361 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5362 GdkDragContext *context,
5369 GtkCTreeNode *node = NULL;
5370 gboolean acceptable = FALSE;
5371 gint height = addrbook.ctree->allocation.height;
5372 gint total_height = addrbook.ctree->requisition.height;
5373 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5374 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5375 gfloat vpos = pos->value;
5377 if (gtk_clist_get_selection_info
5378 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5380 if (y > height - 24 && height + vpos < total_height) {
5381 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5382 gtk_adjustment_changed(pos);
5384 if (y < 24 && y > 0) {
5385 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5386 gtk_adjustment_changed(pos);
5388 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5391 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5392 if( obj->type == ADDR_ITEM_FOLDER
5393 || obj->type == ADDR_ITEM_GROUP)
5396 AdapterDSource *ads = NULL;
5397 AddressDataSource *ds = NULL;
5398 ads = ADAPTER_DSOURCE(obj);
5399 if (ads == NULL ){ return FALSE;}
5400 ds = ads->dataSource;
5401 if (ds == NULL ) { return FALSE;}
5409 g_signal_handlers_block_by_func
5411 G_CALLBACK(addressbook_tree_selected), NULL);
5412 gtk_sctree_select( GTK_SCTREE(widget), node);
5413 g_signal_handlers_unblock_by_func
5415 G_CALLBACK(addressbook_tree_selected), NULL);
5416 gdk_drag_status(context,
5417 (context->actions == GDK_ACTION_COPY ?
5418 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5420 gdk_drag_status(context, 0, time);
5426 static void addressbook_drag_leave_cb(GtkWidget *widget,
5427 GdkDragContext *context,
5431 if (addrbook.treeSelected) {
5432 g_signal_handlers_block_by_func
5434 G_CALLBACK(addressbook_tree_selected), NULL);
5435 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5436 g_signal_handlers_unblock_by_func
5438 G_CALLBACK(addressbook_tree_selected), NULL);
5443 static void addressbook_drag_received_cb(GtkWidget *widget,
5444 GdkDragContext *drag_context,
5447 GtkSelectionData *data,
5454 GtkCTreeNode *lastopened = addrbook.opened;
5456 if (!strncmp(data->data, "Dummy_addr", 10)) {
5457 if (gtk_clist_get_selection_info
5458 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5462 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5463 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5466 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5467 if (drag_context->action == GDK_ACTION_COPY ||
5468 !strcmp(data->data, "Dummy_addr_copy"))
5469 addressbook_clip_copy_cb();
5471 addressbook_clip_cut_cb();
5472 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5473 addressbook_clip_paste_cb();
5474 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5475 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5476 gtk_drag_finish(drag_context, TRUE, TRUE, time);