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>
47 #include <sys/types.h>
51 #include "addressbook.h"
52 #include "manage_window.h"
53 #include "prefs_common.h"
54 #include "alertpanel.h"
55 #include "inputdialog.h"
57 #include "stock_pixmap.h"
59 #include "prefs_gtk.h"
65 #include "addr_compl.h"
68 #include "addressitem.h"
70 #include "addrcache.h"
72 #include "addrindex.h"
73 #include "addressadd.h"
74 #include "addrduplicates.h"
75 #include "addressbook_foldersel.h"
77 #include "editvcard.h"
78 #include "editgroup.h"
79 #include "editaddress.h"
81 #include "importldif.h"
82 #include "importmutt.h"
83 #include "importpine.h"
88 #include "editjpilot.h"
93 #include "ldapserver.h"
95 #include "ldapupdate.h"
97 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
100 #include "addrquery.h"
101 #include "addrselect.h"
102 #include "addrclip.h"
103 #include "addrgather.h"
104 #include "adbookbase.h"
105 #include "exphtmldlg.h"
106 #include "expldifdlg.h"
107 #include "browseldap.h"
113 } AddressIndexColumns;
121 } AddressListColumns;
124 AddressBookFile *book;
132 AddressDataSource *book;
136 static gchar *list_titles[] = { N_("Name"),
140 #define COL_NAME_WIDTH 164
141 #define COL_ADDRESS_WIDTH 156
143 #define COL_FOLDER_WIDTH 170
144 #define ADDRESSBOOK_WIDTH 640
145 #define ADDRESSBOOK_HEIGHT 360
147 #define ADDRESSBOOK_MSGBUF_SIZE 2048
149 static GdkPixmap *folderxpm;
150 static GdkBitmap *folderxpmmask;
151 static GdkPixmap *folderopenxpm;
152 static GdkBitmap *folderopenxpmmask;
153 static GdkPixmap *groupxpm;
154 static GdkBitmap *groupxpmmask;
155 static GdkPixmap *interfacexpm;
156 static GdkBitmap *interfacexpmmask;
157 static GdkPixmap *bookxpm;
158 static GdkBitmap *bookxpmmask;
159 static GdkPixmap *addressxpm;
160 static GdkBitmap *addressxpmmask;
161 static GdkPixmap *vcardxpm;
162 static GdkBitmap *vcardxpmmask;
163 static GdkPixmap *jpilotxpm;
164 static GdkBitmap *jpilotxpmmask;
165 static GdkPixmap *categoryxpm;
166 static GdkBitmap *categoryxpmmask;
167 static GdkPixmap *ldapxpm;
168 static GdkBitmap *ldapxpmmask;
169 static GdkPixmap *addrsearchxpm;
170 static GdkPixmap *addrsearchxpmmask;
173 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
175 /* Address list selection */
176 static AddrSelectList *_addressSelect_ = NULL;
177 static AddressClipboard *_clipBoard_ = NULL;
179 /* Address index file and interfaces */
180 static AddressIndex *_addressIndex_ = NULL;
181 static GList *_addressInterfaceList_ = NULL;
182 static GList *_addressIFaceSelection_ = NULL;
183 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
185 static AddressBook_win addrbook;
187 static GHashTable *_addressBookTypeHash_ = NULL;
188 static GList *_addressBookTypeList_ = NULL;
190 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
191 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
192 static void addressbook_edit_address_post_cb( ItemPerson *person );
194 static void addressbook_create (void);
195 static gint addressbook_close (void);
196 static void addressbook_button_set_sensitive (void);
198 static gboolean address_index_has_focus = FALSE;
199 static gboolean address_list_has_focus = FALSE;
201 /* callback functions */
202 static void addressbook_del_clicked (GtkButton *button,
204 static void addressbook_reg_clicked (GtkButton *button,
206 static void addressbook_to_clicked (GtkButton *button,
208 static void addressbook_lup_clicked (GtkButton *button,
210 static void addressbook_close_clicked (GtkButton *button,
213 static void addressbook_tree_selected (GtkCTree *ctree,
217 static void addressbook_select_row_tree (GtkCTree *ctree,
221 static void addressbook_list_row_selected (GtkCTree *clist,
225 static void addressbook_list_row_unselected (GtkCTree *clist,
229 static void addressbook_person_expand_node (GtkCTree *ctree,
232 static void addressbook_person_collapse_node (GtkCTree *ctree,
236 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
237 GdkEventButton *event,
239 static gboolean addressbook_list_button_released(GtkWidget *widget,
240 GdkEventButton *event,
242 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
243 GdkEventButton *event,
245 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
246 GdkEventButton *event,
249 static void addressbook_new_folder_cb (gpointer data,
252 static void addressbook_new_group_cb (gpointer data,
255 static void addressbook_treenode_edit_cb (gpointer data,
258 static void addressbook_treenode_delete_cb (gpointer data,
262 static void addressbook_change_node_name (GtkCTreeNode *node,
265 static void addressbook_new_address_cb (gpointer data,
268 static void addressbook_edit_address_cb (gpointer data,
271 static void addressbook_delete_address_cb (gpointer data,
275 static void close_cb (gpointer data,
278 static void addressbook_file_save_cb (gpointer data,
282 /* Data source edit stuff */
283 static void addressbook_new_book_cb (gpointer data,
286 static void addressbook_new_vcard_cb (gpointer data,
291 static void addressbook_new_jpilot_cb (gpointer data,
297 static void addressbook_new_ldap_cb (gpointer data,
302 static void addressbook_set_clist (AddressObject *obj,
305 static void addressbook_load_tree (void);
306 void addressbook_read_file (void);
308 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
310 static void addressbook_treenode_remove_item ( void );
312 static AddressDataSource *addressbook_find_datasource
313 (GtkCTreeNode *node );
315 static AddressBookFile *addressbook_get_book_file(void);
317 static GtkCTreeNode *addressbook_node_add_folder
319 AddressDataSource *ds,
320 ItemFolder *itemFolder,
321 AddressObjectType otype);
322 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
323 AddressDataSource *ds,
324 ItemGroup *itemGroup);
325 static void addressbook_tree_remove_children (GtkCTree *ctree,
326 GtkCTreeNode *parent);
327 static void addressbook_move_nodes_up (GtkCTree *ctree,
329 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
331 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
334 static gint addressbook_treenode_compare_func (GtkCList *clist,
337 static void addressbook_folder_load_one_person (GtkCTree *clist,
339 AddressTypeControlItem *atci,
340 AddressTypeControlItem *atciMail);
341 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
343 static void addressbook_folder_remove_one_person(GtkCTree *clist,
345 static void addressbook_folder_remove_node (GtkCTree *clist,
348 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
349 gboolean force_focus );
351 /* LUT's and IF stuff */
352 static void addressbook_free_treenode ( gpointer data );
353 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
354 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
356 static void addrbookctl_build_map (GtkWidget *window);
357 static void addrbookctl_build_iflist (void);
358 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
359 static void addrbookctl_build_ifselect (void);
361 static void addrbookctl_free_interface (AdapterInterface *adapter);
362 static void addrbookctl_free_datasource (AdapterDSource *adapter);
363 static void addrbookctl_free_folder (AdapterFolder *adapter);
364 static void addrbookctl_free_group (AdapterGroup *adapter);
366 static void addressbook_list_select_clear ( void );
367 static void addressbook_list_select_add ( AddrItemObject *aio,
368 AddressDataSource *ds );
369 static void addressbook_list_select_remove ( AddrItemObject *aio );
371 static void addressbook_import_ldif_cb ( void );
372 static void addressbook_find_duplicates_cb ( void );
373 static void addressbook_import_mutt_cb ( void );
374 static void addressbook_import_pine_cb ( void );
375 static void addressbook_export_html_cb ( void );
376 static void addressbook_export_ldif_cb ( void );
377 static void addressbook_select_all_cb ( void );
378 static void addressbook_clip_cut_cb ( void );
379 static void addressbook_clip_copy_cb ( void );
380 static void addressbook_clip_paste_cb ( void );
381 static void addressbook_treenode_cut_cb ( void );
382 static void addressbook_treenode_copy_cb ( void );
383 static void addressbook_treenode_paste_cb ( void );
385 static void addressbook_mail_to_cb ( void );
388 static void addressbook_browse_entry_cb ( void );
390 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
392 static void addressbook_start_drag(GtkWidget *widget, gint button,
395 static void addressbook_drag_data_get(GtkWidget *widget,
396 GdkDragContext *drag_context,
397 GtkSelectionData *selection_data,
401 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
402 GdkDragContext *context,
407 static void addressbook_drag_leave_cb(GtkWidget *widget,
408 GdkDragContext *context,
411 static void addressbook_drag_received_cb(GtkWidget *widget,
412 GdkDragContext *drag_context,
415 GtkSelectionData *data,
419 static void addressbook_list_menu_setup( void );
421 static GtkTargetEntry addressbook_drag_types[] =
423 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
426 static GtkTargetList *addressbook_target_list = NULL;
429 static GtkItemFactoryEntry addressbook_entries[] =
431 {N_("/_Book"), NULL, NULL, 0, "<Branch>", NULL},
432 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL, NULL},
433 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL, NULL},
434 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL, NULL},
436 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL, NULL},
439 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL, NULL},
441 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
442 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
443 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
444 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
445 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL, NULL},
446 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL, NULL},
447 {N_("/_Address"), NULL, NULL, 0, "<Branch>", NULL},
448 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL, NULL},
449 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
450 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL, NULL},
451 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL, NULL},
452 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL, NULL},
453 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
454 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL, NULL},
455 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL, NULL},
456 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
457 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL, NULL},
458 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL, NULL},
459 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
460 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
461 {N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL},
462 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL, NULL},
463 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL, NULL},
464 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL, NULL},
465 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
466 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL, NULL},
467 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL, NULL},
468 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
469 {N_("/_Tools/Find duplicates..."), NULL, addressbook_find_duplicates_cb, 0, NULL, NULL},
470 {N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL},
471 {N_("/_Help/_About"), NULL, about_show, 0, NULL, NULL}
474 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
476 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
477 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
478 {"/---", NULL, NULL, 0, "<Separator>", NULL},
479 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL, NULL},
480 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL, NULL},
481 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
482 {"/---", NULL, NULL, 0, "<Separator>", NULL},
483 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL, NULL},
484 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL, NULL},
485 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL, NULL}
488 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
490 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL, NULL},
491 {"/---", NULL, NULL, 0, "<Separator>", NULL},
492 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL, NULL},
493 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL, NULL},
494 {"/---", NULL, NULL, 0, "<Separator>", NULL},
495 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL, NULL},
496 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
497 {"/---", NULL, NULL, 0, "<Separator>", NULL},
498 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL, NULL},
499 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL, NULL},
500 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL, NULL},
501 {"/---", NULL, NULL, 0, "<Separator>", NULL},
502 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL, NULL},*/
503 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
505 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL, NULL},
510 * Structure of error message table.
512 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
513 struct _ErrMsgTableEntry {
518 static gchar *_errMsgUnknown_ = N_( "Unknown" );
521 * Lookup table of error messages for general errors. Note that a NULL
522 * description signifies the end of the table.
524 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
525 { MGU_SUCCESS, N_("Success") },
526 { MGU_BAD_ARGS, N_("Bad arguments") },
527 { MGU_NO_FILE, N_("File not specified") },
528 { MGU_OPEN_FILE, N_("Error opening file") },
529 { MGU_ERROR_READ, N_("Error reading file") },
530 { MGU_EOF, N_("End of file encountered") },
531 { MGU_OO_MEMORY, N_("Error allocating memory") },
532 { MGU_BAD_FORMAT, N_("Bad file format") },
533 { MGU_ERROR_WRITE, N_("Error writing to file") },
534 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
535 { MGU_NO_PATH, N_("No path specified") },
541 * Lookup table of error messages for LDAP errors.
543 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
544 { LDAPRC_SUCCESS, N_("Success") },
545 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
546 { LDAPRC_INIT, N_("Error initializing LDAP") },
547 { LDAPRC_BIND, N_("Error binding to LDAP server") },
548 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
549 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
550 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
551 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
552 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
553 { LDAPRC_TLS, N_("Error starting TLS connection") },
554 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
555 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
556 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
557 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
563 * Lookup message for specified error code.
564 * \param lut Lookup table.
565 * \param code Code to lookup.
566 * \return Description associated to code.
568 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
570 ErrMsgTableEntry entry;
573 for( i = 0; ; i++ ) {
575 if( entry.description == NULL ) break;
576 if( entry.code == code ) {
577 desc = entry.description;
582 desc = _errMsgUnknown_;
587 static gboolean lastCanLookup = FALSE;
589 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
591 if (add_and_delete) {
592 gtk_widget_show(addrbook.edit_btn);
593 gtk_widget_show(addrbook.del_btn);
594 gtk_widget_show(addrbook.reg_btn);
596 gtk_widget_hide(addrbook.edit_btn);
597 gtk_widget_hide(addrbook.del_btn);
598 gtk_widget_hide(addrbook.reg_btn);
602 gtk_widget_show(addrbook.lup_btn);
603 gtk_widget_show(addrbook.entry);
604 gtk_widget_show(addrbook.label);
606 gtk_widget_hide(addrbook.lup_btn);
607 gtk_widget_hide(addrbook.entry);
608 gtk_widget_hide(addrbook.label);
611 lastCanLookup = lookup;
614 gtk_widget_show(addrbook.to_btn);
615 gtk_widget_show(addrbook.cc_btn);
616 gtk_widget_show(addrbook.bcc_btn);
618 gtk_widget_hide(addrbook.to_btn);
619 gtk_widget_hide(addrbook.cc_btn);
620 gtk_widget_hide(addrbook.bcc_btn);
624 void addressbook_open(Compose *target)
626 /* Initialize all static members */
627 if( _clipBoard_ == NULL ) {
628 _clipBoard_ = addrclip_create();
630 if( _addressIndex_ != NULL ) {
631 addrclip_set_index( _clipBoard_, _addressIndex_ );
633 if( _addressSelect_ == NULL ) {
634 _addressSelect_ = addrselect_list_create();
636 if (!addrbook.window) {
637 addressbook_read_file();
638 addressbook_create();
639 addressbook_load_tree();
640 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
641 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
644 gtk_widget_hide(addrbook.window);
647 gtk_widget_show_all(addrbook.window);
649 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
650 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
652 if (!prefs_common.addressbook_use_editaddress_dialog)
653 addressbook_edit_person_widgetset_hide();
655 address_completion_start(addrbook.window);
657 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
658 addressbook_set_target_compose(target);
662 * Destroy addressbook.
664 void addressbook_destroy( void ) {
665 /* Free up address stuff */
666 if( _addressSelect_ != NULL ) {
667 addrselect_list_free( _addressSelect_ );
669 if( _clipBoard_ != NULL ) {
670 addrclip_free( _clipBoard_ );
672 if( _addressIndex_ != NULL ) {
673 addrindex_free_index( _addressIndex_ );
674 addrindex_teardown();
676 _addressSelect_ = NULL;
678 _addressIndex_ = NULL;
681 void addressbook_set_target_compose(Compose *target)
683 addrbook.target_compose = target;
684 addressbook_button_set_sensitive();
687 Compose *addressbook_get_target_compose(void)
689 return addrbook.target_compose;
693 * Refresh addressbook and save to file(s).
695 void addressbook_refresh( void )
697 if (addrbook.window) {
698 if (addrbook.treeSelected) {
699 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
700 addrbook.treeSelected);
701 addressbook_set_clist(
702 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
703 addrbook.treeSelected),
708 addressbook_export_to_file();
711 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
713 if (event && event->keyval == GDK_Escape)
715 else if (event && event->keyval == GDK_Delete) {
716 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
717 if ( /* address_index_has_focus || */ address_list_has_focus )
718 addressbook_del_clicked(NULL, NULL);
724 *\brief Save Gtk object size to prefs dataset
726 static void addressbook_size_allocate_cb(GtkWidget *widget,
727 GtkAllocation *allocation)
729 g_return_if_fail(allocation != NULL);
731 prefs_common.addressbookwin_width = allocation->width;
732 prefs_common.addressbookwin_height = allocation->height;
735 static gint sort_column_number = 0;
736 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
738 static gint list_case_sort(
739 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
741 GtkCListRow *row1 = (GtkCListRow *) ptr1;
742 GtkCListRow *row2 = (GtkCListRow *) ptr2;
743 gchar *name1 = NULL, *name2 = NULL;
744 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
745 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
747 if( aio1->type == aio2->type ) {
749 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
751 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
752 if( ! name1 ) return ( name2 != NULL );
753 if( ! name2 ) return -1;
754 return g_utf8_collate( name1, name2 );
756 /* Order groups before person */
757 if( aio1->type == ITEMTYPE_GROUP ) {
758 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
759 } else if( aio2->type == ITEMTYPE_GROUP ) {
760 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
766 static void addressbook_sort_list(GtkCList *clist, const gint col,
767 const GtkSortType sort_type)
770 GtkWidget *hbox, *label, *arrow;
772 sort_column_number = col;
773 sort_column_type = sort_type;
774 gtk_clist_set_compare_func(clist, list_case_sort);
775 gtk_clist_set_sort_type(clist, sort_type);
776 gtk_clist_set_sort_column(clist, col);
778 gtk_clist_freeze(clist);
779 gtk_clist_sort(clist);
781 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
782 hbox = gtk_hbox_new(FALSE, 4);
783 label = gtk_label_new(gettext(list_titles[pos]));
784 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
787 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
788 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
789 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
792 gtk_widget_show_all(hbox);
793 gtk_clist_set_column_widget(clist, pos, hbox);
796 gtk_clist_thaw(clist);
799 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
801 static GtkSortType sort_type = GTK_SORT_ASCENDING;
803 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
805 addressbook_sort_list(clist, COL_NAME, sort_type);
808 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
810 static GtkSortType sort_type = GTK_SORT_ASCENDING;
812 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
814 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
817 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
819 static GtkSortType sort_type = GTK_SORT_ASCENDING;
821 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
823 addressbook_sort_list(clist, COL_REMARKS, sort_type);
826 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
829 address_index_has_focus = TRUE;
833 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
836 address_index_has_focus = FALSE;
837 if (!prefs_common.addressbook_use_editaddress_dialog
838 && !address_list_has_focus)
839 addressbook_address_list_disable_some_actions();
843 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
846 address_list_has_focus = TRUE;
850 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
853 address_list_has_focus = FALSE;
854 if (!prefs_common.addressbook_use_editaddress_dialog
855 && !address_index_has_focus)
856 addressbook_address_list_disable_some_actions();
860 /* save hpane and vpane's handle position when it moves */
861 static void addressbook_pane_save_position(void)
864 prefs_common.addressbook_hpaned_pos =
865 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
867 prefs_common.addressbook_vpaned_pos =
868 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
872 * Create the address book widgets. The address book contains two CTree widgets: the
873 * address index tree on the left and the address list on the right.
875 * The address index tree displays a hierarchy of interfaces and groups. Each node in
876 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
877 * data sources and folder objects.
879 * The address list displays group, person and email objects. These items are linked
880 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
883 * In the tradition of MVC architecture, the data stores have been separated from the
884 * GUI components. The addrindex.c file provides the interface to all data stores.
886 static void addressbook_create(void)
892 GtkWidget *ctree_swin;
894 GtkWidget *editaddress_vbox;
895 GtkWidget *clist_vbox;
896 GtkWidget *clist_swin;
903 GtkWidget *statusbar;
914 GtkWidget *close_btn;
915 GtkWidget *tree_popup;
916 GtkWidget *list_popup;
917 GtkItemFactory *tree_factory;
918 GtkItemFactory *list_factory;
919 GtkItemFactory *menu_factory;
923 gchar *index_titles[N_INDEX_COLS];
927 static GdkGeometry geometry;
929 debug_print("Creating addressbook window...\n");
931 index_titles[COL_SOURCES] = _("Sources");
933 /* Address book window */
934 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
935 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
936 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
937 gtk_widget_realize(window);
939 g_signal_connect(G_OBJECT(window), "delete_event",
940 G_CALLBACK(addressbook_close), NULL);
941 g_signal_connect(G_OBJECT(window), "size_allocate",
942 G_CALLBACK(addressbook_size_allocate_cb), NULL);
943 g_signal_connect(G_OBJECT(window), "key_press_event",
944 G_CALLBACK(key_pressed), NULL);
945 MANAGE_WINDOW_SIGNALS_CONNECT(window);
947 vbox = gtk_vbox_new(FALSE, 0);
948 gtk_container_add(GTK_CONTAINER(window), vbox);
951 n_entries = sizeof(addressbook_entries) /
952 sizeof(addressbook_entries[0]);
953 menubar = menubar_create(window, addressbook_entries, n_entries,
954 "<AddressBook>", NULL);
955 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
956 menu_factory = gtk_item_factory_from_widget(menubar);
958 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
959 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
960 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
962 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
963 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
964 GTK_POLICY_AUTOMATIC,
965 GTK_POLICY_AUTOMATIC);
966 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
969 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
970 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
971 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
972 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
973 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
974 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
975 GTK_CTREE_EXPANDER_SQUARE);
976 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
977 gtk_clist_set_compare_func(GTK_CLIST(ctree),
978 addressbook_treenode_compare_func);
980 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
981 G_CALLBACK(addressbook_tree_selected), NULL);
982 g_signal_connect(G_OBJECT(ctree), "button_press_event",
983 G_CALLBACK(addressbook_tree_button_pressed),
985 g_signal_connect(G_OBJECT(ctree), "button_release_event",
986 G_CALLBACK(addressbook_tree_button_released),
989 g_signal_connect(G_OBJECT(ctree), "select_row",
990 G_CALLBACK(addressbook_select_row_tree), NULL);
992 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
993 addressbook_drag_types, 1,
994 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
995 g_signal_connect(G_OBJECT(ctree), "drag_motion",
996 G_CALLBACK(addressbook_drag_motion_cb),
998 g_signal_connect(G_OBJECT(ctree), "drag_leave",
999 G_CALLBACK(addressbook_drag_leave_cb),
1001 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1002 G_CALLBACK(addressbook_drag_received_cb),
1004 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1005 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1006 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1007 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1009 clist_vbox = gtk_vbox_new(FALSE, 4);
1011 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1012 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1013 GTK_POLICY_AUTOMATIC,
1014 GTK_POLICY_AUTOMATIC);
1015 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1018 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1019 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1020 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1021 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1022 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1023 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1024 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1026 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1028 gtk_widget_set_size_request(clist, -1, 80);
1030 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1031 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1032 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1033 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1034 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1035 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1036 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1037 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1038 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1039 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1040 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1042 for (i = 0; i < N_LIST_COLS; i++)
1043 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1046 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1047 G_CALLBACK(addressbook_list_row_selected), NULL);
1048 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1049 G_CALLBACK(addressbook_list_row_unselected), NULL);
1050 g_signal_connect(G_OBJECT(clist), "button_press_event",
1051 G_CALLBACK(addressbook_list_button_pressed),
1053 g_signal_connect(G_OBJECT(clist), "button_release_event",
1054 G_CALLBACK(addressbook_list_button_released),
1056 g_signal_connect(G_OBJECT(clist), "tree_expand",
1057 G_CALLBACK(addressbook_person_expand_node), NULL );
1058 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1059 G_CALLBACK(addressbook_person_collapse_node), NULL );
1060 g_signal_connect(G_OBJECT(clist), "start_drag",
1061 G_CALLBACK(addressbook_start_drag), NULL);
1062 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1063 G_CALLBACK(addressbook_drag_data_get), NULL);
1064 hbox = gtk_hbox_new(FALSE, 4);
1065 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1067 label = gtk_label_new(_("Lookup name:"));
1068 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1070 entry = gtk_entry_new();
1071 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1073 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1075 g_signal_connect(G_OBJECT(entry), "key_press_event",
1076 G_CALLBACK(addressbook_entry_key_pressed),
1079 if (!prefs_common.addressbook_use_editaddress_dialog) {
1080 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1081 vpaned = gtk_vpaned_new();
1082 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1083 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1086 editaddress_vbox = NULL;
1088 hpaned = gtk_hpaned_new();
1089 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1090 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1091 if (prefs_common.addressbook_use_editaddress_dialog)
1092 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1094 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1097 hsbox = gtk_hbox_new(FALSE, 0);
1098 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1099 statusbar = gtk_statusbar_new();
1100 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1103 hbbox = gtk_hbutton_box_new();
1104 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1105 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1106 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1107 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1109 gtkut_stock_button_add_help(hbbox, &help_btn);
1111 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1112 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1113 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1114 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1115 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1116 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1117 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1118 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1119 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1122 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1123 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1124 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1126 g_signal_connect(G_OBJECT(help_btn), "clicked",
1127 G_CALLBACK(manual_open_with_anchor_cb),
1128 MANUAL_ANCHOR_ADDRBOOK);
1130 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1131 G_CALLBACK(addressbook_edit_clicked), NULL);
1132 g_signal_connect(G_OBJECT(del_btn), "clicked",
1133 G_CALLBACK(addressbook_del_clicked), NULL);
1134 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1135 G_CALLBACK(addressbook_reg_clicked), NULL);
1136 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1137 G_CALLBACK(addressbook_lup_clicked), NULL);
1139 to_btn = gtk_button_new_with_label
1140 (prefs_common_translated_header_name("To:"));
1141 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1142 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1143 cc_btn = gtk_button_new_with_label
1144 (prefs_common_translated_header_name("Cc:"));
1145 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1146 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1147 bcc_btn = gtk_button_new_with_label
1148 (prefs_common_translated_header_name("Bcc:"));
1149 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1150 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1152 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1153 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1154 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1156 g_signal_connect(G_OBJECT(to_btn), "clicked",
1157 G_CALLBACK(addressbook_to_clicked),
1158 GINT_TO_POINTER(COMPOSE_TO));
1159 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1160 G_CALLBACK(addressbook_to_clicked),
1161 GINT_TO_POINTER(COMPOSE_CC));
1162 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1163 G_CALLBACK(addressbook_to_clicked),
1164 GINT_TO_POINTER(COMPOSE_BCC));
1165 g_signal_connect(G_OBJECT(close_btn), "clicked",
1166 G_CALLBACK(addressbook_close_clicked), NULL);
1168 /* Build icons for interface */
1169 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1170 &interfacexpm, &interfacexpmmask );
1172 /* Build control tables */
1173 addrbookctl_build_map(window);
1174 addrbookctl_build_iflist();
1175 addrbookctl_build_ifselect();
1177 addrbook.clist = NULL;
1179 /* Add each interface into the tree as a root level folder */
1180 nodeIf = _addressInterfaceList_;
1182 AdapterInterface *adapter = nodeIf->data;
1183 AddressInterface *iface = adapter->interface;
1184 nodeIf = g_list_next(nodeIf);
1186 if(iface->useInterface) {
1187 AddressTypeControlItem *atci = adapter->atci;
1188 text = atci->displayName;
1190 gtk_sctree_insert_node( GTK_CTREE(ctree),
1191 NULL, NULL, &text, FOLDER_SPACING,
1192 interfacexpm, interfacexpmmask,
1193 interfacexpm, interfacexpmmask,
1195 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1196 gtk_ctree_node_set_row_data_full(
1197 GTK_CTREE(ctree), adapter->treeNode, adapter,
1198 addressbook_free_treenode );
1203 n_entries = sizeof(addressbook_tree_popup_entries) /
1204 sizeof(addressbook_tree_popup_entries[0]);
1205 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1207 "<AddressBookTree>", &tree_factory,
1209 n_entries = sizeof(addressbook_list_popup_entries) /
1210 sizeof(addressbook_list_popup_entries[0]);
1211 list_popup = menu_create_items(addressbook_list_popup_entries,
1213 "<AddressBookList>", &list_factory,
1216 addrbook.window = window;
1217 addrbook.hpaned = hpaned;
1218 addrbook.vpaned = vpaned;
1219 addrbook.menubar = menubar;
1220 addrbook.ctree = ctree;
1223 addrbook.editaddress_vbox = editaddress_vbox;
1224 addrbook.clist = clist;
1225 addrbook.label = label;
1226 addrbook.entry = entry;
1227 addrbook.statusbar = statusbar;
1228 addrbook.status_cid = gtk_statusbar_get_context_id(
1229 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1231 addrbook.help_btn = help_btn;
1232 addrbook.edit_btn = edit_btn;
1233 addrbook.del_btn = del_btn;
1234 addrbook.reg_btn = reg_btn;
1235 addrbook.lup_btn = lup_btn;
1236 addrbook.to_btn = to_btn;
1237 addrbook.cc_btn = cc_btn;
1238 addrbook.bcc_btn = bcc_btn;
1240 addrbook.tree_popup = tree_popup;
1241 addrbook.list_popup = list_popup;
1242 addrbook.tree_factory = tree_factory;
1243 addrbook.list_factory = list_factory;
1244 addrbook.menu_factory = menu_factory;
1246 addrbook.listSelected = NULL;
1248 if (!geometry.min_height) {
1249 geometry.min_width = ADDRESSBOOK_WIDTH;
1250 geometry.min_height = ADDRESSBOOK_HEIGHT;
1253 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1255 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1256 prefs_common.addressbookwin_height);
1258 if (!prefs_common.addressbook_use_editaddress_dialog) {
1259 if (prefs_common.addressbook_vpaned_pos > 0)
1260 gtk_paned_set_position(GTK_PANED(vpaned),
1261 prefs_common.addressbook_vpaned_pos);
1263 if (prefs_common.addressbook_hpaned_pos > 0)
1264 gtk_paned_set_position(GTK_PANED(hpaned),
1265 prefs_common.addressbook_hpaned_pos);
1268 gtk_widget_show_all(window);
1272 * Close address book window and save to file(s).
1274 static gint addressbook_close( void ) {
1275 address_completion_end(addrbook.window);
1276 if (!prefs_common.addressbook_use_editaddress_dialog)
1277 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1279 addressbook_pane_save_position();
1281 gtk_widget_hide(addrbook.window);
1282 addressbook_export_to_file();
1287 * Display message in status line.
1288 * \param msg Message to display.
1290 static void addressbook_status_show( gchar *msg ) {
1291 if( addrbook.statusbar != NULL ) {
1293 GTK_STATUSBAR(addrbook.statusbar),
1294 addrbook.status_cid );
1297 GTK_STATUSBAR(addrbook.statusbar),
1298 addrbook.status_cid, msg );
1303 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1307 *addressbook_msgbuf = '\0';
1309 name = addrindex_ds_get_name( ds );
1310 retVal = addrindex_ds_get_status_code( ds );
1311 if( retVal == MGU_SUCCESS ) {
1312 g_snprintf( addressbook_msgbuf,
1313 sizeof(addressbook_msgbuf), "%s", name );
1316 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1317 g_snprintf( addressbook_msgbuf,
1318 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1321 addressbook_status_show( addressbook_msgbuf );
1324 static void addressbook_button_set_sensitive(void)
1326 gboolean to_sens = FALSE;
1327 gboolean cc_sens = FALSE;
1328 gboolean bcc_sens = FALSE;
1330 if (!addrbook.window) return;
1332 if (addrbook.target_compose) {
1338 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1339 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1340 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1343 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1345 addressbook_edit_address_cb(NULL, 0, NULL);
1349 * Delete one or more objects from address list.
1351 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1353 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1354 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1355 AddressObject *pobj;
1356 AdapterDSource *ads = NULL;
1357 GtkCTreeNode *nodeList;
1360 AddressBookFile *abf = NULL;
1361 AddressDataSource *ds = NULL;
1362 AddressInterface *iface;
1363 AddrItemObject *aio;
1364 AddrSelectItem *item;
1366 gboolean refreshList = FALSE;
1368 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1369 g_return_if_fail(pobj != NULL);
1371 /* Test whether anything selected for deletion */
1372 nodeList = addrbook.listSelected;
1374 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1375 if( aio == NULL) return;
1376 ds = addressbook_find_datasource( addrbook.treeSelected );
1377 if( ds == NULL ) return;
1379 /* Test for read only */
1380 iface = ds->interface;
1381 if( iface->readOnly ) {
1382 alertpanel( _("Delete address(es)"),
1383 _("This address data is readonly and cannot be deleted."),
1384 GTK_STOCK_CLOSE, NULL, NULL );
1388 /* Test whether Ok to proceed */
1390 if( pobj->type == ADDR_DATASOURCE ) {
1391 ads = ADAPTER_DSOURCE(pobj);
1392 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1394 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1397 else if( pobj->type == ADDR_ITEM_GROUP ) {
1400 if( ! procFlag ) return;
1401 abf = ds->rawDataSource;
1402 if( abf == NULL ) return;
1405 /* Process deletions */
1406 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1407 gboolean group_delete = TRUE;
1408 /* Items inside folders */
1409 list = addrselect_get_list( _addressSelect_ );
1410 /* Confirm deletion */
1414 node = g_list_next( node );
1415 aio = ( AddrItemObject * ) item->addressItem;
1416 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1417 group_delete = FALSE;
1422 aval = alertpanel( _("Delete group"),
1423 _("Really delete the group(s)?\n"
1424 "The addresses it contains will not be lost."),
1425 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1426 if( aval != G_ALERTALTERNATE ) return;
1428 aval = alertpanel( _("Delete address(es)"),
1429 _("Really delete the address(es)?"),
1430 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1431 if( aval != G_ALERTALTERNATE ) return;
1437 node = g_list_next( node );
1438 aio = ( AddrItemObject * ) item->addressItem;
1441 if( aio->type == ADDR_ITEM_GROUP ) {
1442 ItemGroup *item = ( ItemGroup * ) aio;
1443 GtkCTreeNode *nd = NULL;
1445 nd = addressbook_find_group_node( addrbook.opened, item );
1446 item = addrbook_remove_group( abf, item );
1448 addritem_free_item_group( item );
1450 /* Remove group from parent node */
1451 gtk_ctree_remove_node( ctree, nd );
1454 else if( aio->type == ADDR_ITEM_PERSON ) {
1455 ItemPerson *item = ( ItemPerson * ) aio;
1456 item->status = DELETE_ENTRY;
1457 addressbook_folder_remove_one_person( clist, item );
1458 if (pobj->type == ADDR_ITEM_FOLDER)
1459 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1460 item = addrbook_remove_person( abf, item );
1462 if (ds && ds->type == ADDR_IF_LDAP) {
1463 LdapServer *server = ds->rawDataSource;
1464 ldapsvr_set_modified(server, TRUE);
1465 ldapsvr_update_book(server, item);
1469 gchar *filename = addritem_person_get_picture(item);
1470 if (filename && is_file_exist(filename))
1473 addritem_free_item_person( item );
1476 else if( aio->type == ADDR_ITEM_EMAIL ) {
1477 ItemEMail *item = ( ItemEMail * ) aio;
1478 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1479 item = addrbook_person_remove_email( abf, person, item );
1481 addrcache_remove_email(abf->addressCache, item);
1482 addritem_free_item_email( item );
1484 addressbook_folder_refresh_one_person( clist, person );
1487 g_list_free( list );
1488 addressbook_list_select_clear();
1490 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1491 addressbook_set_clist(
1492 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1496 addrbook_set_dirty(abf, TRUE);
1497 addressbook_export_to_file();
1498 addressbook_list_menu_setup();
1501 else if( pobj->type == ADDR_ITEM_GROUP ) {
1502 /* Items inside groups */
1503 list = addrselect_get_list( _addressSelect_ );
1507 node = g_list_next( node );
1508 aio = ( AddrItemObject * ) item->addressItem;
1509 if( aio->type == ADDR_ITEM_EMAIL ) {
1510 ItemEMail *item = ( ItemEMail * ) aio;
1511 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1512 item = addrbook_person_remove_email( abf, person, item );
1514 addritem_free_item_email( item );
1518 g_list_free( list );
1519 addressbook_list_select_clear();
1520 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1521 addressbook_set_clist(
1522 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1526 addrbook_set_dirty(abf, TRUE);
1527 addressbook_export_to_file();
1528 addressbook_list_menu_setup();
1532 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1533 gtk_ctree_remove_node( clist, nodeList );
1537 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1539 addressbook_new_address_cb( NULL, 0, NULL );
1542 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1545 gchar *address = NULL;
1547 if( aio->type == ADDR_ITEM_EMAIL ) {
1548 ItemPerson *person = NULL;
1549 ItemEMail *email = ( ItemEMail * ) aio;
1551 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1552 if( email->address ) {
1553 if( ADDRITEM_NAME(email) ) {
1554 name = ADDRITEM_NAME(email);
1555 if( *name == '\0' ) {
1556 name = ADDRITEM_NAME(person);
1559 else if( ADDRITEM_NAME(person) ) {
1560 name = ADDRITEM_NAME(person);
1563 buf = g_strdup( email->address );
1565 address = email->address;
1568 else if( aio->type == ADDR_ITEM_PERSON ) {
1569 ItemPerson *person = ( ItemPerson * ) aio;
1570 GList *node = person->listEMail;
1572 name = ADDRITEM_NAME(person);
1574 ItemEMail *email = ( ItemEMail * ) node->data;
1575 address = email->address;
1579 if( name && name[0] != '\0' ) {
1580 if( strchr_with_skip_quote( name, '"', ',' ) )
1581 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1583 buf = g_strdup_printf( "%s <%s>", name, address );
1586 buf = g_strdup( address );
1593 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1597 AddrSelectItem *item;
1598 AddrItemObject *aio;
1601 compose = addrbook.target_compose;
1602 if( ! compose ) return;
1604 /* Nothing selected, but maybe there is something in text entry */
1605 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1607 compose_entry_append(
1608 compose, addr, (ComposeEntryType)data );
1611 /* Select from address list */
1612 list = addrselect_get_list( _addressSelect_ );
1617 node = g_list_next( node );
1618 aio = item->addressItem;
1619 if( aio->type == ADDR_ITEM_PERSON ||
1620 aio->type == ADDR_ITEM_EMAIL ) {
1621 addr = addressbook_format_address( aio );
1622 compose_entry_append(
1623 compose, addr, (ComposeEntryType) data );
1626 else if( aio->type == ADDR_ITEM_GROUP ) {
1627 ItemGroup *group = ( ItemGroup * ) aio;
1628 GList *nodeMail = group->listEMail;
1630 ItemEMail *email = nodeMail->data;
1632 addr = addressbook_format_address(
1633 ( AddrItemObject * ) email );
1634 compose_entry_append(
1635 compose, addr, (ComposeEntryType) data );
1637 nodeMail = g_list_next( nodeMail );
1642 AddressObject *obj = NULL;
1644 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1646 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1647 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1648 GList *nodeMail = itemGroup->listEMail;
1650 ItemEMail *email = nodeMail->data;
1652 addr = addressbook_format_address(
1653 ( AddrItemObject * ) email );
1654 compose_entry_append(
1655 compose, addr, (ComposeEntryType) data );
1657 nodeMail = g_list_next( nodeMail );
1661 g_list_free( list );
1664 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1665 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1666 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1667 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1669 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1670 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1671 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1672 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1674 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1675 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1676 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1677 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1678 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1679 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1682 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1683 gboolean canEdit = FALSE;
1684 gboolean canDelete = TRUE;
1685 gboolean canAdd = FALSE;
1686 gboolean canEditTr = TRUE;
1687 gboolean editAddress = FALSE;
1688 gboolean canExport = TRUE;
1689 AddressTypeControlItem *atci = NULL;
1690 AddressDataSource *ds = NULL;
1691 AddressInterface *iface = NULL;
1693 if( obj == NULL ) return;
1694 if( obj->type == ADDR_INTERFACE ) {
1695 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1696 iface = adapter->interface;
1698 if( iface->haveLibrary ) {
1699 /* Enable appropriate File / New command */
1700 atci = adapter->atci;
1701 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1704 canEditTr = canExport = FALSE;
1706 else if( obj->type == ADDR_DATASOURCE ) {
1707 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1708 ds = ads->dataSource;
1709 iface = ds->interface;
1710 if( ! iface->readOnly ) {
1711 canAdd = canEdit = editAddress = canDelete = TRUE;
1713 if( ! iface->haveLibrary ) {
1714 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1717 else if( obj->type == ADDR_ITEM_FOLDER ) {
1718 ds = addressbook_find_datasource( addrbook.treeSelected );
1720 iface = ds->interface;
1721 if( iface->readOnly ) {
1726 canAdd = editAddress = TRUE;
1730 else if( obj->type == ADDR_ITEM_GROUP ) {
1731 ds = addressbook_find_datasource( addrbook.treeSelected );
1733 iface = ds->interface;
1734 if( ! iface->readOnly ) {
1740 if( addrbook.listSelected == NULL )
1744 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1745 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1746 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1747 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1750 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1751 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1752 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1753 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1755 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1756 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1759 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1760 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1764 * Address book tree callback function that responds to selection of tree
1767 * \param ctree Tree widget.
1768 * \param node Node that was selected.
1769 * \param column Column number where selected occurred.
1770 * \param data Pointer to user data.
1772 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1773 gint column, gpointer data)
1775 AddressObject *obj = NULL;
1776 AdapterDSource *ads = NULL;
1777 AddressDataSource *ds = NULL;
1778 ItemFolder *rootFolder = NULL;
1779 AddressObjectType aot;
1781 addrbook.treeSelected = node;
1782 addrbook.listSelected = NULL;
1783 addressbook_status_show( "" );
1784 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1786 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1788 addressbook_set_clist(NULL, TRUE);
1791 addrbook.opened = node;
1793 if( obj->type == ADDR_DATASOURCE ) {
1794 /* Read from file */
1795 static gboolean tVal = TRUE;
1797 ads = ADAPTER_DSOURCE(obj);
1798 if( ads == NULL ) return;
1799 ds = ads->dataSource;
1800 if( ds == NULL ) return;
1802 if( addrindex_ds_get_modify_flag( ds ) ) {
1803 addrindex_ds_read_data( ds );
1806 if( ! addrindex_ds_get_read_flag( ds ) ) {
1807 addrindex_ds_read_data( ds );
1809 addressbook_ds_show_message( ds );
1811 if( ! addrindex_ds_get_access_flag( ds ) ) {
1812 /* Remove existing folders and groups */
1813 gtk_clist_freeze( GTK_CLIST(ctree) );
1814 addressbook_tree_remove_children( ctree, node );
1815 gtk_clist_thaw( GTK_CLIST(ctree) );
1817 /* Load folders into the tree */
1818 rootFolder = addrindex_ds_get_root_folder( ds );
1819 if( ds && ds->type == ADDR_IF_JPILOT ) {
1820 aot = ADDR_CATEGORY;
1822 else if( ds && ds->type == ADDR_IF_LDAP ) {
1823 aot = ADDR_LDAP_QUERY;
1826 aot = ADDR_ITEM_FOLDER;
1828 addressbook_node_add_folder( node, ds, rootFolder, aot );
1829 addrindex_ds_set_access_flag( ds, &tVal );
1830 gtk_ctree_expand( ctree, node );
1833 addressbook_set_clist(NULL, TRUE);
1836 /* Update address list */
1837 g_signal_handlers_block_by_func
1839 G_CALLBACK(addressbook_tree_selected), NULL);
1840 addressbook_set_clist( obj, FALSE );
1841 g_signal_handlers_unblock_by_func
1843 G_CALLBACK(addressbook_tree_selected), NULL);
1844 if (!prefs_common.addressbook_use_editaddress_dialog)
1845 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1847 /* Setup main menu selections */
1848 addressbook_menubar_set_sensitive( FALSE );
1849 addressbook_menuitem_set_sensitive( obj, node );
1850 addressbook_list_select_clear();
1851 addressbook_list_menu_setup();
1856 * Setup address list popup menu items. Items are enabled or disabled as
1859 static void addressbook_list_menu_setup( void ) {
1860 GtkCTree *clist = NULL;
1861 AddressObject *pobj = NULL;
1862 AddressObject *obj = NULL;
1863 AdapterDSource *ads = NULL;
1864 AddressInterface *iface = NULL;
1865 AddressDataSource *ds = NULL;
1866 gboolean canEdit = FALSE;
1867 gboolean canDelete = FALSE;
1868 gboolean canCut = FALSE;
1869 gboolean canCopy = FALSE;
1870 gboolean canPaste = FALSE;
1871 gboolean canBrowse = FALSE;
1872 AddrSelectItem *item;
1873 AddrItemObject *aio;
1876 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1877 if( pobj == NULL ) return;
1879 clist = GTK_CTREE(addrbook.clist);
1880 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1881 if( obj == NULL ) canEdit = FALSE;
1883 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1884 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1886 if( pobj->type == ADDR_DATASOURCE ) {
1887 /* Parent object is a data source */
1888 ads = ADAPTER_DSOURCE(pobj);
1889 ds = ads->dataSource;
1892 iface = ds->interface;
1895 if( ! iface->readOnly ) {
1896 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1897 if (iface->type != ADDR_IF_LDAP)
1898 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1899 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1902 canDelete = canEdit;
1905 else if( pobj->type != ADDR_INTERFACE ) {
1906 /* Parent object is not an interface */
1907 ds = addressbook_find_datasource( addrbook.treeSelected );
1910 iface = ds->interface;
1913 if( ! iface->readOnly ) {
1914 /* Folder or group */
1915 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1916 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1917 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1918 if( obj ) canEdit = TRUE;
1921 if( pobj->type == ADDR_ITEM_FOLDER ) {
1922 if (iface->type != ADDR_IF_LDAP)
1923 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1924 if( obj ) canEdit = TRUE;
1926 canDelete = canEdit;
1928 if( iface->type == ADDR_IF_LDAP ) {
1929 if( obj ) canBrowse = TRUE;
1936 /* Enable cut and paste */
1937 if( ! addrclip_is_empty( _clipBoard_ ) )
1939 if( ! addrselect_test_empty( _addressSelect_ ) )
1941 /* Enable copy if something is selected */
1942 if( ! addrselect_test_empty( _addressSelect_ ) )
1946 /* Disable edit or browse if more than one row selected */
1947 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1952 /* Forbid cut/copy when selection contains a group */
1953 list = addrselect_get_list( _addressSelect_ );
1957 aio = ( AddrItemObject * ) item->addressItem;
1958 if (aio && aio->type == ADDR_ITEM_GROUP) {
1963 node = g_list_next( node );
1965 g_list_free( list );
1967 /* Forbid write changes when read-only */
1968 if( iface && iface->readOnly ) {
1974 /* Now go finalize menu items */
1975 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1976 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1978 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1979 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1980 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1982 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1984 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1985 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1986 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1988 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1989 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1990 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1992 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1993 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1996 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
2000 static void addressbook_select_row_tree (GtkCTree *ctree,
2008 * Add list of items into tree node below specified tree node.
2009 * \param treeNode Tree node.
2010 * \param ds Data source.
2011 * \param listItems List of items.
2013 static void addressbook_treenode_add_list(
2014 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2020 AddrItemObject *aio;
2024 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2027 group = ( ItemGroup * ) aio;
2028 nn = addressbook_node_add_group( treeNode, ds, group );
2030 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2033 folder = ( ItemFolder * ) aio;
2034 nn = addressbook_node_add_folder(
2035 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2037 node = g_list_next( node );
2041 static void addressbook_select_all_cb( void ) {
2042 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2046 * Cut from address list widget.
2048 static void addressbook_clip_cut_cb( void ) {
2049 _clipBoard_->cutFlag = TRUE;
2050 addrclip_clear( _clipBoard_ );
2051 addrclip_add( _clipBoard_, _addressSelect_ );
2052 /* addrclip_list_show( _clipBoard_, stdout ); */
2056 * Copy from address list widget.
2058 static void addressbook_clip_copy_cb( void ) {
2059 _clipBoard_->cutFlag = FALSE;
2060 addrclip_clear( _clipBoard_ );
2061 addrclip_add( _clipBoard_, _addressSelect_ );
2062 /* addrclip_list_show( _clipBoard_, stdout ); */
2066 * Paste clipboard into address list widget.
2068 static void addressbook_clip_paste_cb( void ) {
2069 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2070 AddressObject *pobj = NULL;
2071 AddressDataSource *ds = NULL;
2072 AddressBookFile *abf = NULL;
2073 ItemFolder *folder = NULL;
2074 GList *folderGroup = NULL;
2076 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2077 if( ds == NULL ) return;
2078 if( addrindex_ds_get_readonly( ds ) ) {
2079 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2083 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2085 if( pobj->type == ADDR_ITEM_FOLDER ) {
2086 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2088 else if( pobj->type == ADDR_ITEM_GROUP ) {
2089 alertpanel_error( _("Cannot paste into an address group.") );
2094 /* Get an address book */
2095 abf = addressbook_get_book_file();
2096 if( abf == NULL ) return;
2098 if( _clipBoard_->cutFlag ) {
2100 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2103 /* Remove all groups and folders in clipboard from tree node */
2104 addressbook_treenode_remove_item();
2106 /* Remove all "cut" items */
2107 addrclip_delete_item( _clipBoard_ );
2110 /* Clear clipboard - cut items??? */
2111 addrclip_clear( _clipBoard_ );
2115 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2118 /* addrclip_list_show( _clipBoard_, stdout ); */
2120 /* Update tree by inserting node for each folder or group */
2121 addressbook_treenode_add_list(
2122 addrbook.treeSelected, ds, folderGroup );
2123 gtk_ctree_expand( ctree, addrbook.treeSelected );
2124 g_list_free( folderGroup );
2128 /* Display items pasted */
2129 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2130 addressbook_set_clist(
2131 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2139 * Add current treenode object to clipboard. Note that widget only allows
2140 * one entry from the tree list to be selected.
2142 static void addressbook_treenode_to_clipboard( void ) {
2143 AddressObject *obj = NULL;
2144 AddressDataSource *ds = NULL;
2145 AddrSelectItem *item;
2146 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2149 node = addrbook.treeSelected;
2150 if( node == NULL ) return;
2151 obj = gtk_ctree_node_get_row_data( ctree, node );
2152 if( obj == NULL ) return;
2154 ds = addressbook_find_datasource( node );
2155 if( ds == NULL ) return;
2158 if( obj->type == ADDR_ITEM_FOLDER ) {
2159 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2160 ItemFolder *folder = adapter->itemFolder;
2162 item = addrselect_create_node( obj );
2163 item->uid = g_strdup( ADDRITEM_ID(folder) );
2165 else if( obj->type == ADDR_ITEM_GROUP ) {
2166 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2167 ItemGroup *group = adapter->itemGroup;
2169 item = addrselect_create_node( obj );
2170 item->uid = g_strdup( ADDRITEM_ID(group) );
2172 else if( obj->type == ADDR_DATASOURCE ) {
2174 item = addrselect_create_node( obj );
2179 /* Clear existing list and add item into list */
2182 addressbook_list_select_clear();
2183 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2184 addrselect_list_add( _addressSelect_, item, cacheID );
2190 * Cut from tree widget.
2192 static void addressbook_treenode_cut_cb( void ) {
2193 _clipBoard_->cutFlag = TRUE;
2194 addressbook_treenode_to_clipboard();
2195 addrclip_clear( _clipBoard_ );
2196 addrclip_add( _clipBoard_, _addressSelect_ );
2197 /* addrclip_list_show( _clipBoard_, stdout ); */
2201 * Copy from tree widget.
2203 static void addressbook_treenode_copy_cb( void ) {
2204 _clipBoard_->cutFlag = FALSE;
2205 addressbook_treenode_to_clipboard();
2206 addrclip_clear( _clipBoard_ );
2207 addrclip_add( _clipBoard_, _addressSelect_ );
2208 /* addrclip_list_show( _clipBoard_, stdout ); */
2212 * Paste clipboard into address tree widget.
2214 static void addressbook_treenode_paste_cb( void ) {
2215 addressbook_clip_paste_cb();
2219 * Clear selected entries in clipboard.
2221 static void addressbook_list_select_clear( void ) {
2222 addrselect_list_clear( _addressSelect_ );
2226 * Add specified address item to selected address list.
2227 * \param aio Address item object.
2228 * \param ds Datasource.
2230 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2233 if( ds == NULL ) return;
2234 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2235 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2240 * Remove specified address item from selected address list.
2241 * \param aio Address item object.
2243 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2244 addrselect_list_remove( _addressSelect_, aio );
2248 * Invoke EMail compose window with addresses in selected address list.
2250 static void addressbook_mail_to_cb( void ) {
2253 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2254 listAddress = addrselect_build_list( _addressSelect_ );
2255 compose_new_with_list( NULL, listAddress );
2256 mgu_free_dlist( listAddress );
2261 static void addressbook_list_row_selected( GtkCTree *clist,
2266 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2267 AddrItemObject *aio = NULL;
2268 AddressObject *pobj = NULL;
2269 AdapterDSource *ads = NULL;
2270 AddressDataSource *ds = NULL;
2272 gtk_entry_set_text( entry, "" );
2273 addrbook.listSelected = node;
2275 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2276 if( pobj == NULL ) return;
2278 if( pobj->type == ADDR_DATASOURCE ) {
2279 ads = ADAPTER_DSOURCE(pobj);
2280 ds = ads->dataSource;
2282 else if( pobj->type != ADDR_INTERFACE ) {
2283 ds = addressbook_find_datasource( addrbook.treeSelected );
2286 aio = gtk_ctree_node_get_row_data( clist, node );
2288 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2289 addressbook_list_select_add( aio, ds );
2292 addressbook_list_menu_setup();
2294 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2295 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2297 if (obj && obj->type != ADDR_ITEM_GROUP)
2298 addressbook_edit_address(NULL, 0, NULL, FALSE);
2302 static void addressbook_list_row_unselected( GtkCTree *ctree,
2307 AddrItemObject *aio;
2309 aio = gtk_ctree_node_get_row_data( ctree, node );
2311 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2312 addressbook_list_select_remove( aio );
2315 if (!prefs_common.addressbook_use_editaddress_dialog)
2316 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2319 /* from gdkevents.c */
2320 #define DOUBLE_CLICK_TIME 250
2322 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2323 GdkEventButton *event,
2326 static guint32 lasttime = 0;
2327 if( ! event ) return FALSE;
2329 addressbook_list_menu_setup();
2331 if( event->button == 3 ) {
2332 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2333 event->button, event->time );
2334 } else if (event->button == 1) {
2335 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2336 if (prefs_common.add_address_by_click &&
2337 addrbook.target_compose)
2338 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2340 if (prefs_common.addressbook_use_editaddress_dialog)
2341 addressbook_edit_address_cb(NULL, 0, NULL);
2343 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2344 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2345 if( obj && obj->type == ADDR_ITEM_GROUP )
2346 addressbook_edit_address_cb(NULL, 0, NULL);
2351 lasttime = event->time;
2357 static gboolean addressbook_list_button_released(GtkWidget *widget,
2358 GdkEventButton *event,
2364 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2365 GdkEventButton *event,
2368 GtkCList *clist = GTK_CLIST(ctree);
2370 AddressObject *obj = NULL;
2371 AdapterDSource *ads = NULL;
2372 AddressInterface *iface = NULL;
2373 AddressDataSource *ds = NULL;
2374 gboolean canEdit = FALSE;
2375 gboolean canDelete = FALSE;
2376 gboolean canCut = FALSE;
2377 gboolean canCopy = FALSE;
2378 gboolean canPaste = FALSE;
2379 gboolean canTreeCut = FALSE;
2380 gboolean canTreeCopy = FALSE;
2381 gboolean canTreePaste = FALSE;
2382 gboolean canLookup = FALSE;
2383 GtkCTreeNode *node = NULL;
2385 if( ! event ) return FALSE;
2386 addressbook_menubar_set_sensitive( FALSE );
2388 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2389 gtkut_clist_set_focus_row(clist, row);
2390 obj = gtk_clist_get_row_data( clist, row );
2393 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2395 if( obj == NULL ) return FALSE;
2396 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2398 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2399 canTreePaste = TRUE;
2401 if (obj->type == ADDR_INTERFACE) {
2402 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2405 iface = adapter->interface;
2408 if( !iface->readOnly ) {
2409 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2410 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2412 if( iface->externalQuery ) canLookup = TRUE;
2414 if (obj->type == ADDR_DATASOURCE) {
2415 ads = ADAPTER_DSOURCE(obj);
2416 ds = ads->dataSource;
2419 iface = ds->interface;
2422 if( !iface->readOnly ) {
2424 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2425 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2426 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2430 if( iface->externalQuery ) canLookup = TRUE;
2432 else if (obj->type == ADDR_ITEM_FOLDER) {
2433 ds = addressbook_find_datasource( node );
2436 iface = ds->interface;
2439 if( !iface->readOnly ) {
2443 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2444 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2445 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2449 if( iface->externalQuery ) {
2450 /* Enable deletion of LDAP folder */
2455 else if (obj->type == ADDR_ITEM_GROUP) {
2456 ds = addressbook_find_datasource( node );
2459 iface = ds->interface;
2462 if( ! iface->readOnly ) {
2465 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2466 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2471 if( ! addrselect_test_empty( _addressSelect_ ) )
2474 if( ! addrselect_test_empty( _addressSelect_ ) )
2476 if( ! addrclip_is_empty( _clipBoard_ ) )
2479 /* Forbid write changes when read-only */
2480 if( iface && iface->readOnly ) {
2482 canTreePaste = FALSE;
2490 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2491 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2492 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2493 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2494 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2496 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2497 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2498 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2499 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2500 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2502 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2503 addrbook.target_compose != NULL);
2505 if( event->button == 3 ) {
2506 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2507 event->button, event->time);
2513 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2514 GdkEventButton *event,
2517 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2521 static void addressbook_new_folder_cb(gpointer data, guint action,
2524 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2525 AddressObject *obj = NULL;
2526 AddressDataSource *ds = NULL;
2527 AddressBookFile *abf = NULL;
2528 ItemFolder *parentFolder = NULL;
2529 ItemFolder *folder = NULL;
2531 if( ! addrbook.treeSelected ) return;
2532 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2533 if( obj == NULL ) return;
2534 ds = addressbook_find_datasource( addrbook.treeSelected );
2535 if( ds == NULL ) return;
2537 if( obj->type == ADDR_DATASOURCE ) {
2538 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2540 else if( obj->type == ADDR_ITEM_FOLDER ) {
2541 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2547 abf = ds->rawDataSource;
2548 if( abf == NULL ) return;
2549 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2552 nn = addressbook_node_add_folder(
2553 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2554 gtk_ctree_expand( ctree, addrbook.treeSelected );
2555 if( addrbook.treeSelected == addrbook.opened )
2556 addressbook_set_clist(obj, TRUE);
2561 static void addressbook_new_group_cb(gpointer data, guint action,
2564 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2565 AddressObject *obj = NULL;
2566 AddressDataSource *ds = NULL;
2567 AddressBookFile *abf = NULL;
2568 ItemFolder *parentFolder = NULL;
2569 ItemGroup *group = NULL;
2571 if( ! addrbook.treeSelected ) return;
2572 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2573 if( obj == NULL ) return;
2574 ds = addressbook_find_datasource( addrbook.treeSelected );
2575 if( ds == NULL ) return;
2577 if( obj->type == ADDR_DATASOURCE ) {
2578 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2580 else if( obj->type == ADDR_ITEM_FOLDER ) {
2581 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2587 abf = ds->rawDataSource;
2588 if( abf == NULL ) return;
2589 group = addressbook_edit_group( abf, parentFolder, NULL );
2592 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2593 gtk_ctree_expand( ctree, addrbook.treeSelected );
2594 if( addrbook.treeSelected == addrbook.opened )
2595 addressbook_set_clist(obj, TRUE);
2600 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2602 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2605 GdkPixmap *pix_cl, *pix_op;
2606 GdkBitmap *mask_cl, *mask_op;
2607 gboolean is_leaf, expanded;
2609 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2610 &pix_cl, &mask_cl, &pix_op, &mask_op,
2611 &is_leaf, &expanded);
2612 gtk_sctree_set_node_info(ctree, node, name, spacing,
2613 pix_cl, mask_cl, pix_op, mask_op,
2619 * \param obj Address object to edit.
2620 * \param node Node in tree.
2621 * \return New name of data source.
2623 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2624 gchar *newName = NULL;
2625 AddressDataSource *ds = NULL;
2626 AddressInterface *iface = NULL;
2627 AdapterDSource *ads = NULL;
2629 ds = addressbook_find_datasource( node );
2630 if( ds == NULL ) return NULL;
2631 iface = ds->interface;
2632 if( ! iface->haveLibrary ) return NULL;
2634 /* Read data from data source */
2635 if( addrindex_ds_get_modify_flag( ds ) ) {
2636 addrindex_ds_read_data( ds );
2639 if( ! addrindex_ds_get_read_flag( ds ) ) {
2640 addrindex_ds_read_data( ds );
2644 ads = ADAPTER_DSOURCE(obj);
2645 if( ads->subType == ADDR_BOOK ) {
2646 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2648 else if( ads->subType == ADDR_VCARD ) {
2649 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2652 else if( ads->subType == ADDR_JPILOT ) {
2653 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2657 else if( ads->subType == ADDR_LDAP ) {
2658 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2664 newName = obj->name;
2669 * Edit an object that is in the address tree area.
2671 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2674 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2676 AddressDataSource *ds = NULL;
2677 AddressBookFile *abf = NULL;
2678 GtkCTreeNode *node = NULL, *parentNode = NULL;
2681 if( ! addrbook.treeSelected ) return;
2682 node = addrbook.treeSelected;
2683 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2684 obj = gtk_ctree_node_get_row_data( ctree, node );
2685 if( obj == NULL ) return;
2686 parentNode = GTK_CTREE_ROW(node)->parent;
2688 ds = addressbook_find_datasource( node );
2689 if( ds == NULL ) return;
2691 if( obj->type == ADDR_DATASOURCE ) {
2692 name = addressbook_edit_datasource( obj, node );
2693 if( name == NULL ) return;
2696 abf = ds->rawDataSource;
2697 if( abf == NULL ) return;
2698 if( obj->type == ADDR_ITEM_FOLDER ) {
2699 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2700 ItemFolder *item = adapter->itemFolder;
2701 ItemFolder *parentFolder = NULL;
2702 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2703 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2704 name = ADDRITEM_NAME(item);
2706 else if( obj->type == ADDR_ITEM_GROUP ) {
2707 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2708 ItemGroup *item = adapter->itemGroup;
2709 ItemFolder *parentFolder = NULL;
2710 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2711 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2712 name = ADDRITEM_NAME(item);
2715 if( name && parentNode ) {
2716 /* Update node in tree view */
2717 addressbook_change_node_name( node, name );
2718 gtk_sctree_sort_node(ctree, parentNode);
2719 gtk_ctree_expand( ctree, node );
2720 gtk_sctree_select( GTK_SCTREE( ctree), node );
2727 ADDRTREE_DEL_FOLDER_ONLY,
2728 ADDRTREE_DEL_FOLDER_ADDR
2732 * Delete an item from the tree widget.
2733 * \param data Data passed in.
2734 * \param action Action.
2735 * \param widget Widget issuing callback.
2737 static void addressbook_treenode_delete_cb(
2738 gpointer data, guint action, GtkWidget *widget )
2740 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2741 GtkCTreeNode *node = NULL;
2745 AddrBookBase *adbase;
2746 AddressCache *cache;
2747 AdapterDSource *ads = NULL;
2748 AddressInterface *iface = NULL;
2749 AddressDataSource *ds = NULL;
2750 gboolean remFlag = FALSE;
2751 TreeItemDelType delType;
2753 if( ! addrbook.treeSelected ) return;
2754 node = addrbook.treeSelected;
2755 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2757 obj = gtk_ctree_node_get_row_data( ctree, node );
2758 g_return_if_fail(obj != NULL);
2760 if( obj->type == ADDR_DATASOURCE ) {
2761 ads = ADAPTER_DSOURCE(obj);
2762 if( ads == NULL ) return;
2763 ds = ads->dataSource;
2764 if( ds == NULL ) return;
2767 /* Must be folder or something else */
2768 ds = addressbook_find_datasource( node );
2769 if( ds == NULL ) return;
2771 /* Only allow deletion from non-readOnly */
2772 iface = ds->interface;
2773 if( iface->readOnly ) {
2774 /* Allow deletion of query results */
2775 if( ! iface->externalQuery ) return;
2779 /* Confirm deletion */
2780 delType = ADDRTREE_DEL_NONE;
2781 if( obj->type == ADDR_ITEM_FOLDER ) {
2782 if( iface->externalQuery ) {
2783 message = g_strdup_printf( _(
2784 "Do you want to delete the query " \
2785 "results and addresses in '%s' ?" ),
2787 aval = alertpanel( _("Delete"), message,
2788 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2790 if( aval == G_ALERTALTERNATE ) {
2791 delType = ADDRTREE_DEL_FOLDER_ADDR;
2795 message = g_strdup_printf
2796 ( _( "Do you want to delete '%s' ?"
2797 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2799 aval = alertpanel( _("Delete folder"), message,
2800 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2802 if( aval == G_ALERTALTERNATE ) {
2803 delType = ADDRTREE_DEL_FOLDER_ONLY;
2805 else if( aval == G_ALERTOTHER ) {
2806 delType = ADDRTREE_DEL_FOLDER_ADDR;
2810 else if( obj->type == ADDR_ITEM_GROUP ) {
2811 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2812 "The addresses it contains will not be lost."), obj->name);
2813 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2814 "+" GTK_STOCK_DELETE, NULL);
2816 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2818 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2819 "The addresses it contains will be lost."), obj->name);
2820 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2821 "+" GTK_STOCK_DELETE, NULL);
2823 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2825 if( delType == ADDRTREE_DEL_NONE ) return;
2827 /* Proceed with deletion */
2828 if( obj->type == ADDR_DATASOURCE ) {
2829 /* Remove node from tree */
2830 gtk_ctree_remove_node( ctree, node );
2832 /* Remove data source. */
2833 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2834 addrindex_free_datasource( ds );
2839 /* Get reference to cache */
2840 adbase = ( AddrBookBase * ) ds->rawDataSource;
2841 if( adbase == NULL ) return;
2842 cache = adbase->addressCache;
2844 /* Remove query results folder */
2845 if( iface->externalQuery ) {
2846 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2847 ItemFolder *folder = adapter->itemFolder;
2849 adapter->itemFolder = NULL;
2851 g_print( "remove folder for ::%s::\n", obj->name );
2852 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2853 g_print( "-------------- remove results\n" );
2855 addrindex_remove_results( ds, folder );
2856 /* g_print( "-------------- remove node\n" ); */
2857 gtk_ctree_remove_node( ctree, node );
2861 /* Code below is valid for regular address book deletion */
2862 if( obj->type == ADDR_ITEM_FOLDER ) {
2863 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2864 ItemFolder *item = adapter->itemFolder;
2866 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2867 /* Remove folder only */
2868 item = addrcache_remove_folder( cache, item );
2870 addritem_free_item_folder( item );
2871 addressbook_move_nodes_up( ctree, node );
2875 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2876 /* Remove folder and addresses */
2877 item = addrcache_remove_folder_delete( cache, item );
2879 addritem_free_item_folder( item );
2884 else if( obj->type == ADDR_ITEM_GROUP ) {
2885 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2886 ItemGroup *item = adapter->itemGroup;
2888 item = addrcache_remove_group( cache, item );
2890 addritem_free_item_group( item );
2897 gtk_ctree_remove_node(ctree, node );
2901 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2903 if( person && addrbook.treeSelected == addrbook.opened ) {
2904 person->status = ADD_ENTRY;
2905 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2906 addressbook_folder_refresh_one_person(
2907 GTK_CTREE(addrbook.clist), person );
2909 addressbook_address_list_set_focus();
2912 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2914 if( person && addrbook.treeSelected == addrbook.opened) {
2915 person->status = ADD_ENTRY;
2916 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2917 addressbook_set_clist(
2918 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2922 addressbook_address_list_set_focus();
2926 * Label (a format string) that is used to name each folder.
2928 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
2931 * Search ctree widget callback function.
2932 * \param pA Pointer to node.
2933 * \param pB Pointer to data item being sought.
2934 * \return Zero (0) if folder found.
2936 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
2939 aoA = ( AddressObject * ) pA;
2940 if( aoA->type == ADDR_ITEM_FOLDER ) {
2941 ItemFolder *folder, *fld;
2943 fld = ADAPTER_FOLDER(aoA)->itemFolder;
2944 folder = ( ItemFolder * ) pB;
2945 if( fld == folder ) return 0; /* Found folder */
2950 static ItemFolder * addressbook_setup_subf(
2951 AddressDataSource *ds, gchar *title,
2952 GtkCTreeNode *pNode )
2954 AddrBookBase *adbase;
2955 AddressCache *cache;
2958 GtkCTreeNode *nNode;
2960 AddressObjectType aoType = ADDR_NONE;
2963 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
2965 if( ds && ds->type == ADDR_IF_LDAP ) {
2967 aoType = ADDR_LDAP_QUERY;
2974 ctree = GTK_CTREE(addrbook.ctree);
2975 /* Get reference to address cache */
2976 adbase = ( AddrBookBase * ) ds->rawDataSource;
2977 cache = adbase->addressCache;
2979 if ((children = addrcache_get_list_folder(cache)) != NULL) {
2980 GList *cur = children;
2981 for (; cur; cur = cur->next) {
2982 ItemFolder *child = (ItemFolder *) cur->data;
2983 if (!strcmp2(ADDRITEM_NAME(child), title)) {
2984 nNode = gtk_ctree_find_by_row_data_custom(
2986 addressbook_treenode_find_folder_cb );
2988 addrindex_remove_results( ds, child );
2989 while( child->listPerson ) {
2990 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
2991 item = addrcache_remove_person( cache, item );
2993 addritem_free_item_person( item );
2997 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2998 addrbook.treeSelected = nNode;
3005 /* Create a folder */
3006 folder = addrcache_add_new_folder( cache, NULL );
3007 name = g_strdup_printf( "%s", title );
3008 addritem_folder_set_name( folder, name );
3009 addritem_folder_set_remarks( folder, "" );
3012 /* Now let's see the folder */
3013 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3014 gtk_ctree_expand( ctree, pNode );
3016 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3017 addrbook.treeSelected = nNode;
3023 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3024 AddressObject *pobj = NULL;
3025 AddressDataSource *ds = NULL;
3026 AddressBookFile *abf = NULL;
3027 debug_print("adding address\n");
3028 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3029 if( pobj == NULL ) {
3030 debug_print("no row data\n");
3033 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3035 debug_print("no datasource\n");
3039 abf = ds->rawDataSource;
3041 g_print("no addressbook file\n");
3045 if( pobj->type == ADDR_DATASOURCE ) {
3046 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3047 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3049 ItemFolder *folder = NULL;
3051 if (abf && abf->type == ADDR_IF_LDAP) {
3052 GtkCTreeNode *parentNode;
3053 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3054 if( ds == NULL ) return;
3056 /* We must have a datasource that is an external interface */
3057 if( ! ds->interface->haveLibrary ) return;
3058 if( ! ds->interface->externalQuery ) return;
3060 if( pobj->type == ADDR_ITEM_FOLDER ) {
3061 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3064 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3066 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3068 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3069 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3070 abf = ds->rawDataSource;
3073 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3074 addrbook.editaddress_vbox,
3075 addressbook_new_address_from_book_post_cb,
3078 if (abf && abf->type == ADDR_IF_LDAP) {
3079 LdapServer *server = ds->rawDataSource;
3080 ldapsvr_set_modified(server, TRUE);
3081 ldapsvr_update_book(server, NULL);
3082 if (server->retVal != LDAPRC_SUCCESS) {
3083 alertpanel( _("Add address(es)"),
3084 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3085 GTK_STOCK_CLOSE, NULL, NULL );
3086 server->retVal = LDAPRC_SUCCESS;
3091 if (prefs_common.addressbook_use_editaddress_dialog)
3092 addressbook_new_address_from_book_post_cb( person );
3095 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3097 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3100 if (abf && abf->type == ADDR_IF_LDAP) {
3101 GtkCTreeNode *parentNode;
3102 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3103 if( ds == NULL ) return;
3105 /* We must have a datasource that is an external interface */
3106 if( ! ds->interface->haveLibrary ) return;
3107 if( ! ds->interface->externalQuery ) return;
3109 if( pobj->type == ADDR_ITEM_FOLDER ) {
3110 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3113 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3115 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3118 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3119 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3120 abf = ds->rawDataSource;
3123 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3124 addrbook.editaddress_vbox,
3125 addressbook_new_address_from_folder_post_cb,
3128 if (abf && abf->type == ADDR_IF_LDAP) {
3129 LdapServer *server = ds->rawDataSource;
3130 ldapsvr_set_modified(server, TRUE);
3131 ldapsvr_update_book(server, NULL);
3132 if (server->retVal != LDAPRC_SUCCESS) {
3133 alertpanel( _("Add address(es)"),
3134 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3135 GTK_STOCK_CLOSE, NULL, NULL );
3140 if (prefs_common.addressbook_use_editaddress_dialog)
3141 addressbook_new_address_from_folder_post_cb( person );
3143 else if( pobj->type == ADDR_ITEM_GROUP ) {
3144 /* New address in group */
3145 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3146 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3147 if (addrbook.treeSelected == addrbook.opened) {
3148 /* Change node name in tree. */
3149 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3150 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3151 addressbook_set_clist(
3152 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3160 * Search for specified child group node in address index tree.
3161 * \param parent Parent node.
3162 * \param group Group to find.
3164 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3165 GtkCTreeNode *node = NULL;
3166 GtkCTreeRow *currRow;
3168 currRow = GTK_CTREE_ROW( parent );
3170 node = currRow->children;
3174 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3175 if( obj->type == ADDR_ITEM_GROUP ) {
3176 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3177 if( g == group ) return node;
3179 currRow = GTK_CTREE_ROW(node);
3180 node = currRow->sibling;
3186 static AddressBookFile *addressbook_get_book_file() {
3187 AddressBookFile *abf = NULL;
3188 AddressDataSource *ds = NULL;
3190 ds = addressbook_find_datasource( addrbook.treeSelected );
3191 if( ds == NULL ) return NULL;
3192 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3196 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3200 /* Remove existing folders and groups */
3201 row = GTK_CTREE_ROW( parent );
3203 while( (node = row->children) ) {
3204 gtk_ctree_remove_node( ctree, node );
3209 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3210 GtkCTreeNode *parent, *child;
3211 GtkCTreeRow *currRow;
3212 currRow = GTK_CTREE_ROW( node );
3214 parent = currRow->parent;
3215 while( (child = currRow->children) ) {
3216 gtk_ctree_move( ctree, child, parent, node );
3218 gtk_sctree_sort_node( ctree, parent );
3222 static void addressbook_edit_address_post_cb( ItemPerson *person )
3226 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3227 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3229 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3230 invalidate_address_completion();
3232 addressbook_address_list_set_focus();
3235 void addressbook_address_list_set_focus( void )
3237 if (!prefs_common.addressbook_use_editaddress_dialog) {
3238 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3239 addressbook_list_menu_setup();
3243 void addressbook_address_list_disable_some_actions(void)
3245 /* disable address copy/pasting when editing contact's detail (embedded form) */
3246 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3247 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3248 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3251 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3252 addressbook_edit_address(data, action, widget, TRUE);
3255 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3256 gboolean force_focus ) {
3257 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3259 AddressObject *obj = NULL, *pobj = NULL;
3260 AddressDataSource *ds = NULL;
3261 GtkCTreeNode *node = NULL, *parentNode = NULL;
3263 AddressBookFile *abf = NULL;
3265 if( addrbook.listSelected == NULL ) return;
3266 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3267 g_return_if_fail(obj != NULL);
3269 ctree = GTK_CTREE( addrbook.ctree );
3270 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3271 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3273 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3274 if( ds == NULL ) return;
3276 abf = addressbook_get_book_file();
3278 if( obj->type == ADDR_ITEM_EMAIL ) {
3279 ItemEMail *email = ( ItemEMail * ) obj;
3280 if( email == NULL ) return;
3281 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3282 /* Edit parent group */
3283 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3284 ItemGroup *itemGrp = adapter->itemGroup;
3285 if( abf == NULL ) return;
3286 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3287 name = ADDRITEM_NAME(itemGrp);
3288 node = addrbook.treeSelected;
3289 parentNode = GTK_CTREE_ROW(node)->parent;
3292 /* Edit person - email page */
3294 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3295 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3296 addressbook_edit_address_post_cb,
3297 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3300 if (abf && abf->type == ADDR_IF_LDAP) {
3301 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3302 person->status = UPDATE_ENTRY;
3305 if (prefs_common.addressbook_use_editaddress_dialog)
3306 addressbook_edit_address_post_cb( person );
3311 else if( obj->type == ADDR_ITEM_PERSON ) {
3312 /* Edit person - basic page */
3313 ItemPerson *person = ( ItemPerson * ) obj;
3314 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3315 addressbook_edit_address_post_cb,
3316 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3319 if (abf && abf->type == ADDR_IF_LDAP) {
3320 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3321 person->status = UPDATE_ENTRY;
3324 if (prefs_common.addressbook_use_editaddress_dialog)
3325 addressbook_edit_address_post_cb( person );
3329 else if( obj->type == ADDR_ITEM_GROUP ) {
3330 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3331 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3332 parentNode = addrbook.treeSelected;
3333 node = addressbook_find_group_node( parentNode, itemGrp );
3334 name = ADDRITEM_NAME(itemGrp);
3335 invalidate_address_completion();
3341 /* Update tree node with node name */
3342 if( node == NULL ) return;
3343 addressbook_change_node_name( node, name );
3344 gtk_sctree_sort_node( ctree, parentNode );
3345 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3346 addressbook_set_clist(
3347 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3352 static void addressbook_delete_address_cb(gpointer data, guint action,
3355 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3356 addressbook_del_clicked(NULL, NULL);
3357 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3360 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3362 addressbook_close();
3365 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3366 addressbook_export_to_file();
3369 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3371 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3372 if( person ) addritem_person_set_opened( person, TRUE );
3376 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3378 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3379 if( person ) addritem_person_set_opened( person, FALSE );
3383 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3385 gchar *eMailAlias = ADDRITEM_NAME(email);
3386 if( eMailAlias && *eMailAlias != '\0' ) {
3388 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3391 str = g_strdup( eMailAlias );
3397 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3398 GList *items = itemGroup->listEMail;
3399 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3400 for( ; items != NULL; items = g_list_next( items ) ) {
3401 GtkCTreeNode *nodeEMail = NULL;
3402 gchar *text[N_LIST_COLS];
3403 ItemEMail *email = items->data;
3407 if( ! email ) continue;
3409 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3410 str = addressbook_format_item_clist( person, email );
3412 text[COL_NAME] = addressbook_set_col_name_guard(str);
3415 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3417 text[COL_ADDRESS] = email->address;
3418 text[COL_REMARKS] = email->remarks;
3419 nodeEMail = gtk_sctree_insert_node(
3421 text, FOLDER_SPACING,
3422 atci->iconXpm, atci->maskXpm,
3423 atci->iconXpmOpen, atci->maskXpmOpen,
3425 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3431 gchar *addressbook_set_col_name_guard(gchar *value)
3433 gchar *ret = "<not set>";
3434 gchar *tmp = g_strdup(value);
3436 if (tmp !=NULL && *tmp != '\0')
3442 static void addressbook_folder_load_one_person(
3443 GtkCTree *clist, ItemPerson *person,
3444 AddressTypeControlItem *atci,
3445 AddressTypeControlItem *atciMail )
3447 GtkCTreeNode *nodePerson = NULL;
3448 GtkCTreeNode *nodeEMail = NULL;
3449 gchar *text[N_LIST_COLS];
3450 gboolean flgFirst = TRUE, haveAddr = FALSE;
3453 AddressBookFile *abf = addressbook_get_book_file();
3456 if( person == NULL ) return;
3458 text[COL_NAME] = "";
3459 node = person->listEMail;
3461 ItemEMail *email = node->data;
3462 gchar *eMailAddr = NULL;
3463 node = g_list_next( node );
3465 text[COL_ADDRESS] = email->address;
3466 text[COL_REMARKS] = email->remarks;
3467 eMailAddr = ADDRITEM_NAME(email);
3468 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3470 /* First email belongs with person */
3471 gchar *str = addressbook_format_item_clist( person, email );
3473 text[COL_NAME] = addressbook_set_col_name_guard(str);
3476 else if( abf && abf->type == ADDR_IF_LDAP &&
3477 person && person->nickName ) {
3478 if (person->nickName) {
3479 if (strcmp(person->nickName, "") != 0) {
3480 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3483 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3489 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3491 nodePerson = gtk_sctree_insert_node(
3493 text, FOLDER_SPACING,
3494 atci->iconXpm, atci->maskXpm,
3495 atci->iconXpmOpen, atci->maskXpmOpen,
3496 FALSE, person->isOpened );
3499 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3502 /* Subsequent email is a child node of person */
3503 text[COL_NAME] = ADDRITEM_NAME(email);
3504 nodeEMail = gtk_sctree_insert_node(
3505 clist, nodePerson, NULL,
3506 text, FOLDER_SPACING,
3507 atciMail->iconXpm, atciMail->maskXpm,
3508 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3510 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3516 /* Have name without EMail */
3517 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3518 text[COL_ADDRESS] = "";
3519 text[COL_REMARKS] = "";
3520 nodePerson = gtk_sctree_insert_node(
3522 text, FOLDER_SPACING,
3523 atci->iconXpm, atci->maskXpm,
3524 atci->iconXpmOpen, atci->maskXpmOpen,
3525 FALSE, person->isOpened );
3526 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3531 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3533 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3534 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3536 if( atci == NULL ) return;
3537 if( atciMail == NULL ) return;
3539 /* Load email addresses */
3540 items = addritem_folder_get_person_list( itemFolder );
3541 for( ; items != NULL; items = g_list_next( items ) ) {
3542 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3544 /* Free up the list */
3545 mgu_clear_list( items );
3546 g_list_free( items );
3549 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3550 addrbook.listSelected = NULL;
3551 gtk_ctree_remove_node( clist, node );
3552 addressbook_menubar_set_sensitive( FALSE );
3553 addressbook_menuitem_set_sensitive(
3554 gtk_ctree_node_get_row_data(
3555 GTK_CTREE(clist), addrbook.treeSelected ),
3556 addrbook.treeSelected );
3559 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3560 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3561 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3563 if( atci == NULL ) return;
3564 if( atciMail == NULL ) return;
3565 if( person == NULL ) return;
3566 /* unload the person */
3568 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3570 addressbook_folder_remove_node( clist, node );
3571 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3572 gtk_sctree_sort_node( clist, NULL );
3573 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3575 gtk_sctree_select( GTK_SCTREE(clist), node );
3576 if (!gtk_ctree_node_is_visible( clist, node ) )
3577 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3581 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3585 if( person == NULL ) return;
3586 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3587 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3589 addressbook_folder_remove_node( clist, node );
3593 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3595 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3597 /* Load any groups */
3598 if( ! atci ) return;
3599 items = addritem_folder_get_group_list( itemFolder );
3600 for( ; items != NULL; items = g_list_next( items ) ) {
3601 GtkCTreeNode *nodeGroup = NULL;
3602 gchar *text[N_LIST_COLS];
3603 ItemGroup *group = items->data;
3604 if( group == NULL ) continue;
3605 text[COL_NAME] = ADDRITEM_NAME(group);
3606 text[COL_ADDRESS] = "";
3607 text[COL_REMARKS] = "";
3608 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3609 text, FOLDER_SPACING,
3610 atci->iconXpm, atci->maskXpm,
3611 atci->iconXpmOpen, atci->maskXpmOpen,
3613 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3614 gtk_sctree_sort_node(clist, NULL);
3616 /* Free up the list */
3617 mgu_clear_list( items );
3618 g_list_free( items );
3622 * Search ctree widget callback function.
3623 * \param pA Pointer to node.
3624 * \param pB Pointer to data item being sought.
3625 * \return Zero (0) if group found.
3627 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3630 aoA = ( AddressObject * ) pA;
3631 if( aoA->type == ADDR_ITEM_GROUP ) {
3632 ItemGroup *group, *grp;
3634 grp = ADAPTER_GROUP(aoA)->itemGroup;
3635 group = ( ItemGroup * ) pB;
3636 if( grp == group ) return 0; /* Found group */
3642 * Remove folder and group nodes from tree widget for items contained ("cut")
3645 static void addressbook_treenode_remove_item( void ) {
3647 AddrSelectItem *cutItem;
3648 AddressCache *cache;
3649 AddrItemObject *aio;
3650 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3653 node = _clipBoard_->objectList;
3655 cutItem = node->data;
3656 node = g_list_next( node );
3657 cache = addrindex_get_cache(
3658 _clipBoard_->addressIndex, cutItem->cacheID );
3659 if( cache == NULL ) continue;
3660 aio = addrcache_get_object( cache, cutItem->uid );
3663 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3666 folder = ( ItemFolder * ) aio;
3667 tn = gtk_ctree_find_by_row_data_custom(
3668 ctree, NULL, folder,
3669 addressbook_treenode_find_folder_cb );
3671 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3674 group = ( ItemGroup * ) aio;
3675 tn = gtk_ctree_find_by_row_data_custom(
3677 addressbook_treenode_find_group_cb );
3681 /* Free up adapter and remove node. */
3682 gtk_ctree_remove_node( ctree, tn );
3689 * Find parent datasource for specified tree node.
3690 * \param node Node to test.
3691 * \return Data source, or NULL if not found.
3693 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3694 AddressDataSource *ds = NULL;
3697 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3700 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3701 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3703 /* g_print( "ao->type = %d\n", ao->type ); */
3704 if( ao->type == ADDR_DATASOURCE ) {
3705 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3706 /* g_print( "found it\n" ); */
3707 ds = ads->dataSource;
3711 node = GTK_CTREE_ROW(node)->parent;
3717 * Load address list widget with children of specified object.
3718 * \param obj Parent object to be loaded.
3720 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3721 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3722 GtkCList *clist = GTK_CLIST(addrbook.clist);
3723 AddressDataSource *ds = NULL;
3724 AdapterDSource *ads = NULL;
3725 static AddressObject *last_obj = NULL;
3727 if (addrbook.clist == NULL) {
3730 if (obj == last_obj && !refresh)
3735 gtk_clist_clear(clist);
3739 if( obj->type == ADDR_INTERFACE ) {
3740 /* g_print( "set_clist: loading datasource...\n" ); */
3741 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3745 gtk_clist_freeze(clist);
3746 gtk_clist_clear(clist);
3748 if( obj->type == ADDR_DATASOURCE ) {
3749 ads = ADAPTER_DSOURCE(obj);
3750 ds = ADAPTER_DSOURCE(obj)->dataSource;
3752 /* Load root folder */
3753 ItemFolder *rootFolder = NULL;
3754 rootFolder = addrindex_ds_get_root_folder( ds );
3755 addressbook_folder_load_person(
3756 ctreelist, addrindex_ds_get_root_folder( ds ) );
3757 addressbook_folder_load_group(
3758 ctreelist, addrindex_ds_get_root_folder( ds ) );
3762 if( obj->type == ADDR_ITEM_GROUP ) {
3764 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3765 addressbook_load_group( ctreelist, itemGroup );
3767 else if( obj->type == ADDR_ITEM_FOLDER ) {
3769 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3770 addressbook_folder_load_person( ctreelist, itemFolder );
3771 addressbook_folder_load_group( ctreelist, itemFolder );
3774 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3775 clist->focus_row = -1;
3776 gtk_clist_thaw(clist);
3780 * Call back function to free adaptor. Call back is setup by function
3781 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3782 * called when the address book tree widget node is removed by calling
3783 * function gtk_ctree_remove_node().
3785 * \param data Tree node's row data.
3787 static void addressbook_free_treenode( gpointer data ) {
3790 ao = ( AddressObject * ) data;
3791 if( ao == NULL ) return;
3792 if( ao->type == ADDR_INTERFACE ) {
3793 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3794 addrbookctl_free_interface( ai );
3796 else if( ao->type == ADDR_DATASOURCE ) {
3797 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3798 addrbookctl_free_datasource( ads );
3800 else if( ao->type == ADDR_ITEM_FOLDER ) {
3801 AdapterFolder *af = ADAPTER_FOLDER(ao);
3802 addrbookctl_free_folder( af );
3804 else if( ao->type == ADDR_ITEM_GROUP ) {
3805 AdapterGroup *ag = ADAPTER_GROUP(ao);
3806 addrbookctl_free_group( ag );
3811 * Create new adaptor for specified data source.
3813 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3814 AddressObjectType otype, gchar *name )
3816 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3817 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3818 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3819 adapter->dataSource = ds;
3820 adapter->subType = otype;
3824 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3825 ADDRESS_OBJECT_NAME(adapter) =
3826 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3830 * Load tree from address index with the initial data.
3832 static void addressbook_load_tree( void ) {
3833 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3834 GList *nodeIf, *nodeDS;
3835 AdapterInterface *adapter;
3836 AddressInterface *iface;
3837 AddressTypeControlItem *atci;
3838 AddressDataSource *ds;
3839 AdapterDSource *ads;
3840 GtkCTreeNode *node, *newNode;
3843 nodeIf = _addressInterfaceList_;
3845 adapter = nodeIf->data;
3846 node = adapter->treeNode;
3847 iface = adapter->interface;
3848 atci = adapter->atci;
3850 if( iface->useInterface ) {
3851 /* Load data sources below interface node */
3852 nodeDS = iface->listSource;
3856 name = addrindex_ds_get_name( ds );
3857 ads = addressbook_create_ds_adapter(
3858 ds, atci->objectType, name );
3859 newNode = addressbook_add_object(
3860 node, ADDRESS_OBJECT(ads) );
3861 nodeDS = g_list_next( nodeDS );
3863 gtk_ctree_expand( ctree, node );
3866 nodeIf = g_list_next( nodeIf );
3871 * Convert the old address book to new format.
3873 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3874 gboolean retVal = FALSE;
3875 gboolean errFlag = TRUE;
3878 /* Read old address book, performing conversion */
3879 debug_print( "Reading and converting old address book...\n" );
3880 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3881 addrindex_read_data( addrIndex );
3882 if( addrIndex->retVal == MGU_NO_FILE ) {
3883 /* We do not have a file - new user */
3884 debug_print( "New user... create new books...\n" );
3885 addrindex_create_new_books( addrIndex );
3886 if( addrIndex->retVal == MGU_SUCCESS ) {
3887 /* Save index file */
3888 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3889 addrindex_save_data( addrIndex );
3890 if( addrIndex->retVal == MGU_SUCCESS ) {
3895 msg = _( "New user, could not save index file." );
3899 msg = _( "New user, could not save address book files." );
3903 /* We have an old file */
3904 if( addrIndex->wasConverted ) {
3905 /* Converted successfully - save address index */
3906 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3907 addrindex_save_data( addrIndex );
3908 if( addrIndex->retVal == MGU_SUCCESS ) {
3909 msg = _( "Old address book converted successfully." );
3914 msg = _("Old address book converted,\n"
3915 "could not save new address index file." );
3919 /* File conversion failed - just create new books */
3920 debug_print( "File conversion failed... just create new books...\n" );
3921 addrindex_create_new_books( addrIndex );
3922 if( addrIndex->retVal == MGU_SUCCESS ) {
3924 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3925 addrindex_save_data( addrIndex );
3926 if( addrIndex->retVal == MGU_SUCCESS ) {
3927 msg = _("Could not convert address book,\n"
3928 "but created empty new address book files." );
3933 msg = _("Could not convert address book,\n"
3934 "could not save new address index file." );
3938 msg = _("Could not convert address book\n"
3939 "and could not create new address book files." );
3944 debug_print( "Error\n%s\n", msg );
3945 alertpanel_full(_("Addressbook conversion error"), msg,
3946 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3947 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3950 debug_print( "Warning\n%s\n", msg );
3951 alertpanel_full(_("Addressbook conversion error"), msg,
3952 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3953 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3959 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
3963 gboolean failed = FALSE;
3965 if( ( dp = opendir( origdir ) ) == NULL ) {
3969 while( ( d = readdir( dp ) ) != NULL ) {
3970 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3973 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
3975 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
3977 if (copy_file(orig_file, dest_file, FALSE) < 0) {
3990 /* all copies succeeded, we can remove source files */
3991 if( ( dp = opendir( origdir ) ) == NULL ) {
3994 while( ( d = readdir( dp ) ) != NULL ) {
3995 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3998 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4000 g_unlink(orig_file);
4010 void addressbook_read_file( void ) {
4011 AddressIndex *addrIndex = NULL;
4012 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4014 debug_print( "Reading address index...\n" );
4015 if( _addressIndex_ ) {
4016 debug_print( "address book already read!!!\n" );
4020 addrIndex = addrindex_create_index();
4021 addrindex_initialize();
4023 /* Use new address book index. */
4025 if ( !is_dir_exist(indexdir) ) {
4026 if ( make_dir(indexdir) < 0 ) {
4027 addrindex_set_file_path( addrIndex, get_rc_dir() );
4028 g_warning( "couldn't create dir %s\n", indexdir);
4030 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4031 remove_dir_recursive(indexdir);
4032 addrindex_set_file_path( addrIndex, get_rc_dir() );
4033 g_error("couldn't migrate dir %s", indexdir);
4035 addrindex_set_file_path( addrIndex, indexdir);
4039 addrindex_set_file_path( addrIndex, indexdir);
4042 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4043 addrindex_read_data( addrIndex );
4044 if( addrIndex->retVal == MGU_NO_FILE ) {
4045 /* Conversion required */
4046 debug_print( "Converting...\n" );
4047 if( addressbook_convert( addrIndex ) ) {
4048 _addressIndex_ = addrIndex;
4051 else if( addrIndex->retVal == MGU_SUCCESS ) {
4052 _addressIndex_ = addrIndex;
4055 /* Error reading address book */
4056 debug_print( "Could not read address index.\n" );
4057 addrindex_print_index( addrIndex, stdout );
4058 alertpanel_full(_("Addressbook Error"),
4059 _("Could not read address index"),
4060 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4061 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4063 debug_print( "done.\n" );
4067 * Add object into the address index tree widget.
4068 * Enter: node Parent node.
4069 * obj Object to add.
4070 * Return: Node that was added, or NULL if object not added.
4072 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
4075 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4076 GtkCTreeNode *added;
4077 AddressObject *pobj;
4078 AddressObjectType otype;
4079 AddressTypeControlItem *atci = NULL;
4081 g_return_val_if_fail(node != NULL, NULL);
4082 g_return_val_if_fail(obj != NULL, NULL);
4084 pobj = gtk_ctree_node_get_row_data(ctree, node);
4085 g_return_val_if_fail(pobj != NULL, NULL);
4087 /* Determine object type to be displayed */
4088 if( obj->type == ADDR_DATASOURCE ) {
4089 otype = ADAPTER_DSOURCE(obj)->subType;
4095 /* Handle any special conditions. */
4097 atci = addrbookctl_lookup( otype );
4099 if( atci->showInTree ) {
4100 /* Add object to tree */
4103 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4104 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4105 atci->treeLeaf, atci->treeExpand );
4106 gtk_ctree_node_set_row_data_full( ctree, added, obj,
4107 addressbook_free_treenode );
4111 gtk_sctree_sort_node(ctree, node);
4117 * Add group into the address index tree.
4118 * \param node Parent node.
4119 * \param ds Data source.
4120 * \param itemGroup Group to add.
4121 * \return Inserted node.
4123 static GtkCTreeNode *addressbook_node_add_group(
4124 GtkCTreeNode *node, AddressDataSource *ds,
4125 ItemGroup *itemGroup )
4127 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4128 GtkCTreeNode *newNode;
4129 AdapterGroup *adapter;
4130 AddressTypeControlItem *atci = NULL;
4133 if( ds == NULL ) return NULL;
4134 if( node == NULL || itemGroup == NULL ) return NULL;
4136 name = &itemGroup->obj.name;
4138 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4140 adapter = g_new0( AdapterGroup, 1 );
4141 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4142 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4143 adapter->itemGroup = itemGroup;
4145 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4146 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4147 atci->treeLeaf, atci->treeExpand );
4148 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4149 addressbook_free_treenode );
4150 gtk_sctree_sort_node( ctree, node );
4155 * Add folder into the address index tree. Only visible folders are loaded into
4156 * the address index tree. Note that the root folder is not inserted into the
4159 * \param node Parent node.
4160 * \param ds Data source.
4161 * \param itemFolder Folder to add.
4162 * \param otype Object type to display.
4163 * \return Inserted node for the folder.
4165 static GtkCTreeNode *addressbook_node_add_folder(
4166 GtkCTreeNode *node, AddressDataSource *ds,
4167 ItemFolder *itemFolder, AddressObjectType otype )
4169 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4170 GtkCTreeNode *newNode = NULL;
4171 AdapterFolder *adapter;
4172 AddressTypeControlItem *atci = NULL;
4173 GList *listItems = NULL;
4175 ItemFolder *rootFolder;
4177 /* Only visible folders */
4178 if( itemFolder->isHidden ) return NULL;
4180 if( ds == NULL ) return NULL;
4181 if( node == NULL || itemFolder == NULL ) return NULL;
4183 /* Determine object type */
4184 atci = addrbookctl_lookup( otype );
4185 if( atci == NULL ) return NULL;
4187 rootFolder = addrindex_ds_get_root_folder( ds );
4188 if( itemFolder == rootFolder ) {
4192 adapter = g_new0( AdapterFolder, 1 );
4193 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4194 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4195 adapter->itemFolder = itemFolder;
4197 name = ADDRITEM_NAME(itemFolder);
4198 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4199 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4200 atci->treeLeaf, atci->treeExpand );
4202 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4203 addressbook_free_treenode );
4207 listItems = itemFolder->listFolder;
4208 while( listItems ) {
4209 ItemFolder *item = listItems->data;
4210 addressbook_node_add_folder( newNode, ds, item, otype );
4211 listItems = g_list_next( listItems );
4213 listItems = itemFolder->listGroup;
4214 while( listItems ) {
4215 ItemGroup *item = listItems->data;
4216 addressbook_node_add_group( newNode, ds, item );
4217 listItems = g_list_next( listItems );
4219 gtk_sctree_sort_node( ctree, node );
4223 void addressbook_export_to_file( void ) {
4224 if( _addressIndex_ ) {
4225 /* Save all new address book data */
4226 debug_print( "Saving address books...\n" );
4227 addrindex_save_all_books( _addressIndex_ );
4229 debug_print( "Exporting addressbook to file...\n" );
4230 addrindex_save_data( _addressIndex_ );
4231 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4232 addrindex_print_index( _addressIndex_, stdout );
4235 /* Notify address completion of new data */
4236 invalidate_address_completion();
4240 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4242 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4243 addressbook_lup_clicked(NULL, NULL);
4248 * Comparison using cell contents (text in first column). Used for sort
4249 * address index widget.
4251 static gint addressbook_treenode_compare_func(
4252 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4254 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4255 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4256 gchar *name1 = NULL, *name2 = NULL;
4257 if( cell1 ) name1 = cell1->u.text;
4258 if( cell2 ) name2 = cell2->u.text;
4259 if( ! name1 ) return ( name2 != NULL );
4260 if( ! name2 ) return -1;
4261 return g_utf8_collate( name1, name2 );
4264 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4265 AdapterDSource *ads;
4266 AdapterInterface *adapter;
4267 GtkCTreeNode *newNode;
4269 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4270 if( adapter == NULL ) return;
4271 ads = addressbook_edit_book( _addressIndex_, NULL );
4273 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4275 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4276 addrbook.treeSelected = newNode;
4281 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4282 AdapterDSource *ads;
4283 AdapterInterface *adapter;
4284 GtkCTreeNode *newNode;
4286 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4287 if( adapter == NULL ) return;
4288 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4290 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4292 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4293 addrbook.treeSelected = newNode;
4299 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4300 AdapterDSource *ads;
4301 AdapterInterface *adapter;
4302 AddressInterface *iface;
4303 GtkCTreeNode *newNode;
4305 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4306 if( adapter == NULL ) return;
4307 iface = adapter->interface;
4308 if( ! iface->haveLibrary ) return;
4309 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4311 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4313 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4314 addrbook.treeSelected = newNode;
4321 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4322 AdapterDSource *ads;
4323 AdapterInterface *adapter;
4324 AddressInterface *iface;
4325 GtkCTreeNode *newNode;
4327 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4328 if( adapter == NULL ) return;
4329 iface = adapter->interface;
4330 if( ! iface->haveLibrary ) return;
4331 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4333 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4335 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4336 addrbook.treeSelected = newNode;
4343 * Display address search status message.
4344 * \param queryType Query type.
4345 * \param status Status/Error code.
4347 static void addressbook_search_message( gint queryType, gint sts ) {
4349 *addressbook_msgbuf = '\0';
4351 if( sts != MGU_SUCCESS ) {
4352 if( queryType == ADDRQUERY_LDAP ) {
4354 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4359 g_snprintf( addressbook_msgbuf,
4360 sizeof(addressbook_msgbuf), "%s", desc );
4361 addressbook_status_show( addressbook_msgbuf );
4364 addressbook_status_show( "" );
4369 * Refresh addressbook by forcing refresh of current selected object in
4372 static void addressbook_refresh_current( void ) {
4376 ctree = GTK_CTREE(addrbook.ctree);
4377 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4378 if( obj == NULL ) return;
4379 addressbook_set_clist( obj, TRUE );
4383 * Message that is displayed whilst a query is executing in a background
4386 static gchar *_tempMessage_ = N_( "Busy searching..." );
4389 * Address search idle function. This function is called during UI idle time
4390 * while a search is in progress.
4392 * \param data Idler data.
4394 static void addressbook_search_idle( gpointer data ) {
4398 queryID = GPOINTER_TO_INT( data );
4399 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4404 * Search completion callback function. This removes the query from the idle
4407 * \param sender Sender of query.
4408 * \param queryID Query ID of search request.
4409 * \param status Search status.
4410 * \param data Query data.
4412 static void addressbook_search_callback_end(
4413 gpointer sender, gint queryID, gint status, gpointer data )
4417 AddrQueryObject *aqo;
4419 /* Remove idler function */
4420 ptrQID = GINT_TO_POINTER( queryID );
4422 g_idle_remove_by_data( ptrQID );
4425 /* Refresh addressbook contents */
4426 addressbook_refresh_current();
4427 req = qrymgr_find_request( queryID );
4429 aqo = ( AddrQueryObject * ) req->queryList->data;
4430 addressbook_search_message( aqo->queryType, status );
4433 /* Stop the search */
4434 addrindex_stop_search( queryID );
4440 * \param ds Data source to search.
4441 * \param searchTerm String to lookup.
4442 * \param pNode Parent data source node.
4444 static void addressbook_perform_search(
4445 AddressDataSource *ds, gchar *searchTerm,
4446 GtkCTreeNode *pNode )
4448 AddrBookBase *adbase;
4449 AddressCache *cache;
4455 AddressObjectType aoType = ADDR_NONE;
4459 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4461 if( ds && ds->type == ADDR_IF_LDAP ) {
4463 aoType = ADDR_LDAP_QUERY;
4469 /* Get reference to address cache */
4470 adbase = ( AddrBookBase * ) ds->rawDataSource;
4471 cache = adbase->addressCache;
4473 /* Create a folder for the search results */
4474 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4475 folder = addressbook_setup_subf(ds, name, pNode);
4478 /* Setup the search */
4479 queryID = addrindex_setup_explicit_search(
4480 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4481 if( queryID == 0 ) return;
4483 /* Set up idler function */
4484 idleID = g_idle_add(
4485 ( GtkFunction ) addressbook_search_idle,
4486 GINT_TO_POINTER( queryID ) );
4488 /* Start search, sit back and wait for something to happen */
4489 addrindex_start_search( queryID );
4491 addressbook_status_show( _tempMessage_ );
4495 * Lookup button handler. Address search is only performed against
4496 * address interfaces for external queries.
4498 * \param button Lookup button widget.
4499 * \param data Data object.
4501 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4504 AddressDataSource *ds;
4505 AddressInterface *iface;
4507 GtkCTreeNode *node, *parentNode;
4509 node = addrbook.treeSelected;
4510 if( ! node ) return;
4511 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4513 ctree = GTK_CTREE(addrbook.ctree);
4514 obj = gtk_ctree_node_get_row_data( ctree, node );
4515 if( obj == NULL ) return;
4517 ds = addressbook_find_datasource( node );
4518 if( ds == NULL ) return;
4520 /* We must have a datasource that is an external interface */
4521 iface = ds->interface;
4522 if( ! iface->haveLibrary ) return;
4523 if( ! iface->externalQuery ) return;
4526 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4527 g_strchomp( searchTerm );
4529 if( obj->type == ADDR_ITEM_FOLDER ) {
4530 parentNode = GTK_CTREE_ROW(node)->parent;
4535 addressbook_perform_search( ds, searchTerm, parentNode );
4537 gtk_widget_grab_focus( addrbook.entry );
4539 g_free( searchTerm );
4542 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4543 addressbook_close();
4548 * Browse address entry for highlighted entry.
4550 static void addressbook_browse_entry_cb(void)
4552 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4554 AddressDataSource *ds;
4555 AddressInterface *iface;
4559 if(addrbook.listSelected == NULL)
4562 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4566 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4570 iface = ds->interface;
4571 if(! iface->haveLibrary )
4575 if (obj->type == ADDR_ITEM_EMAIL) {
4576 email = ( ItemEMail * ) obj;
4580 person = (ItemPerson *) ADDRITEM_PARENT(email);
4582 else if (obj->type == ADDR_ITEM_PERSON) {
4583 person = (ItemPerson *) obj;
4590 if( iface && iface->type == ADDR_IF_LDAP ) {
4591 browseldap_entry(ds, person->externalID);
4596 /* **********************************************************************
4597 * Build lookup tables.
4598 * ***********************************************************************
4602 * Remap object types.
4603 * Enter: abType AddressObjectType (used in tree node).
4604 * Return: ItemObjectType (used in address cache data).
4606 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4607 ItemObjectType ioType;
4610 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4611 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4612 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4613 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4614 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4615 default: ioType = ITEMTYPE_NONE; break;
4621 * Build table that controls the rendering of object types.
4623 static void addrbookctl_build_map( GtkWidget *window ) {
4624 AddressTypeControlItem *atci;
4627 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4628 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4629 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4630 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4631 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4632 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4633 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4634 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4635 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4636 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4638 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4639 _addressBookTypeList_ = NULL;
4642 atci = g_new0( AddressTypeControlItem, 1 );
4643 atci->objectType = ADDR_INTERFACE;
4644 atci->interfaceType = ADDR_IF_NONE;
4645 atci->showInTree = TRUE;
4646 atci->treeExpand = TRUE;
4647 atci->treeLeaf = FALSE;
4648 atci->displayName = _( "Interface" );
4649 atci->iconXpm = folderxpm;
4650 atci->maskXpm = folderxpmmask;
4651 atci->iconXpmOpen = folderopenxpm;
4652 atci->maskXpmOpen = folderopenxpmmask;
4653 atci->menuCommand = NULL;
4654 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4655 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4658 atci = g_new0( AddressTypeControlItem, 1 );
4659 atci->objectType = ADDR_BOOK;
4660 atci->interfaceType = ADDR_IF_BOOK;
4661 atci->showInTree = TRUE;
4662 atci->treeExpand = TRUE;
4663 atci->treeLeaf = FALSE;
4664 atci->displayName = _( "Address Book" );
4665 atci->iconXpm = bookxpm;
4666 atci->maskXpm = bookxpmmask;
4667 atci->iconXpmOpen = bookxpm;
4668 atci->maskXpmOpen = bookxpmmask;
4669 atci->menuCommand = "/Book/New Book";
4670 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4671 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4674 atci = g_new0( AddressTypeControlItem, 1 );
4675 atci->objectType = ADDR_ITEM_PERSON;
4676 atci->interfaceType = ADDR_IF_NONE;
4677 atci->showInTree = FALSE;
4678 atci->treeExpand = FALSE;
4679 atci->treeLeaf = FALSE;
4680 atci->displayName = _( "Person" );
4681 atci->iconXpm = NULL;
4682 atci->maskXpm = NULL;
4683 atci->iconXpmOpen = NULL;
4684 atci->maskXpmOpen = NULL;
4685 atci->menuCommand = NULL;
4686 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4687 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4690 atci = g_new0( AddressTypeControlItem, 1 );
4691 atci->objectType = ADDR_ITEM_EMAIL;
4692 atci->interfaceType = ADDR_IF_NONE;
4693 atci->showInTree = FALSE;
4694 atci->treeExpand = FALSE;
4695 atci->treeLeaf = TRUE;
4696 atci->displayName = _( "Email Address" );
4697 atci->iconXpm = addressxpm;
4698 atci->maskXpm = addressxpmmask;
4699 atci->iconXpmOpen = addressxpm;
4700 atci->maskXpmOpen = addressxpmmask;
4701 atci->menuCommand = NULL;
4702 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4703 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4706 atci = g_new0( AddressTypeControlItem, 1 );
4707 atci->objectType = ADDR_ITEM_GROUP;
4708 atci->interfaceType = ADDR_IF_BOOK;
4709 atci->showInTree = TRUE;
4710 atci->treeExpand = FALSE;
4711 atci->treeLeaf = FALSE;
4712 atci->displayName = _( "Group" );
4713 atci->iconXpm = groupxpm;
4714 atci->maskXpm = groupxpmmask;
4715 atci->iconXpmOpen = groupxpm;
4716 atci->maskXpmOpen = groupxpmmask;
4717 atci->menuCommand = NULL;
4718 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4719 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4722 atci = g_new0( AddressTypeControlItem, 1 );
4723 atci->objectType = ADDR_ITEM_FOLDER;
4724 atci->interfaceType = ADDR_IF_BOOK;
4725 atci->showInTree = TRUE;
4726 atci->treeExpand = FALSE;
4727 atci->treeLeaf = FALSE;
4728 atci->displayName = _( "Folder" );
4729 atci->iconXpm = folderxpm;
4730 atci->maskXpm = folderxpmmask;
4731 atci->iconXpmOpen = folderopenxpm;
4732 atci->maskXpmOpen = folderopenxpmmask;
4733 atci->menuCommand = NULL;
4734 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4735 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4738 atci = g_new0( AddressTypeControlItem, 1 );
4739 atci->objectType = ADDR_VCARD;
4740 atci->interfaceType = ADDR_IF_VCARD;
4741 atci->showInTree = TRUE;
4742 atci->treeExpand = TRUE;
4743 atci->treeLeaf = TRUE;
4744 atci->displayName = _( "vCard" );
4745 atci->iconXpm = vcardxpm;
4746 atci->maskXpm = vcardxpmmask;
4747 atci->iconXpmOpen = vcardxpm;
4748 atci->maskXpmOpen = vcardxpmmask;
4749 atci->menuCommand = "/Book/New vCard";
4750 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4751 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4754 atci = g_new0( AddressTypeControlItem, 1 );
4755 atci->objectType = ADDR_JPILOT;
4756 atci->interfaceType = ADDR_IF_JPILOT;
4757 atci->showInTree = TRUE;
4758 atci->treeExpand = TRUE;
4759 atci->treeLeaf = FALSE;
4760 atci->displayName = _( "JPilot" );
4761 atci->iconXpm = jpilotxpm;
4762 atci->maskXpm = jpilotxpmmask;
4763 atci->iconXpmOpen = jpilotxpm;
4764 atci->maskXpmOpen = jpilotxpmmask;
4765 atci->menuCommand = "/Book/New JPilot";
4766 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4767 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4770 atci = g_new0( AddressTypeControlItem, 1 );
4771 atci->objectType = ADDR_CATEGORY;
4772 atci->interfaceType = ADDR_IF_JPILOT;
4773 atci->showInTree = TRUE;
4774 atci->treeExpand = TRUE;
4775 atci->treeLeaf = TRUE;
4776 atci->displayName = _( "JPilot" );
4777 atci->iconXpm = categoryxpm;
4778 atci->maskXpm = categoryxpmmask;
4779 atci->iconXpmOpen = categoryxpm;
4780 atci->maskXpmOpen = categoryxpmmask;
4781 atci->menuCommand = NULL;
4782 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4783 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4786 atci = g_new0( AddressTypeControlItem, 1 );
4787 atci->objectType = ADDR_LDAP;
4788 atci->interfaceType = ADDR_IF_LDAP;
4789 atci->showInTree = TRUE;
4790 atci->treeExpand = TRUE;
4791 atci->treeLeaf = FALSE;
4792 atci->displayName = _( "LDAP servers" );
4793 atci->iconXpm = ldapxpm;
4794 atci->maskXpm = ldapxpmmask;
4795 atci->iconXpmOpen = ldapxpm;
4796 atci->maskXpmOpen = ldapxpmmask;
4797 atci->menuCommand = "/Book/New LDAP Server";
4798 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4799 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4802 atci = g_new0( AddressTypeControlItem, 1 );
4803 atci->objectType = ADDR_LDAP_QUERY;
4804 atci->interfaceType = ADDR_IF_LDAP;
4805 atci->showInTree = TRUE;
4806 atci->treeExpand = FALSE;
4807 atci->treeLeaf = TRUE;
4808 atci->displayName = _( "LDAP Query" );
4809 atci->iconXpm = addrsearchxpm;
4810 atci->maskXpm = addrsearchxpmmask;
4811 atci->iconXpmOpen = addrsearchxpm;
4812 atci->maskXpmOpen = addrsearchxpmmask;
4813 atci->menuCommand = NULL;
4814 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4815 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4820 * Search for specified object type.
4822 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4824 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4828 * Search for specified interface type.
4830 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4831 GList *node = _addressBookTypeList_;
4833 AddressTypeControlItem *atci = node->data;
4834 if( atci->interfaceType == ifType ) return atci;
4835 node = g_list_next( node );
4840 static void addrbookctl_free_address( AddressObject *obj ) {
4841 g_free( obj->name );
4842 obj->type = ADDR_NONE;
4846 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4847 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4848 adapter->interface = NULL;
4849 adapter->interfaceType = ADDR_IF_NONE;
4850 adapter->atci = NULL;
4851 adapter->enabled = FALSE;
4852 adapter->haveLibrary = FALSE;
4853 adapter->treeNode = NULL;
4857 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4858 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4859 adapter->dataSource = NULL;
4860 adapter->subType = ADDR_NONE;
4864 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4865 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4866 adapter->itemFolder = NULL;
4870 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4871 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4872 adapter->itemGroup = NULL;
4877 * Build GUI interface list.
4879 static void addrbookctl_build_iflist( void ) {
4880 AddressTypeControlItem *atci;
4881 AdapterInterface *adapter;
4884 if( _addressIndex_ == NULL ) {
4885 _addressIndex_ = addrindex_create_index();
4886 if( _clipBoard_ == NULL ) {
4887 _clipBoard_ = addrclip_create();
4889 addrclip_set_index( _clipBoard_, _addressIndex_ );
4891 _addressInterfaceList_ = NULL;
4892 list = addrindex_get_interface_list( _addressIndex_ );
4894 AddressInterface *interface = list->data;
4895 atci = addrbookctl_lookup_iface( interface->type );
4897 adapter = g_new0( AdapterInterface, 1 );
4898 adapter->interfaceType = interface->type;
4899 adapter->atci = atci;
4900 adapter->interface = interface;
4901 adapter->treeNode = NULL;
4902 adapter->enabled = TRUE;
4903 adapter->haveLibrary = interface->haveLibrary;
4904 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4905 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4906 _addressInterfaceList_ =
4907 g_list_append( _addressInterfaceList_, adapter );
4909 list = g_list_next( list );
4914 * Find GUI interface type specified interface type.
4915 * \param ifType Interface type.
4916 * \return Interface item, or NULL if not found.
4918 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4919 GList *node = _addressInterfaceList_;
4921 AdapterInterface *adapter = node->data;
4922 if( adapter->interfaceType == ifType ) return adapter;
4923 node = g_list_next( node );
4929 * Build interface list selection.
4931 static void addrbookctl_build_ifselect( void ) {
4932 GList *newList = NULL;
4937 gchar *endptr = NULL;
4939 AdapterInterface *adapter;
4941 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4944 splitStr = g_strsplit( selectStr, ",", -1 );
4945 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4947 /* g_print( "%d : %s\n", i, splitStr[i] ); */
4948 ifType = strtol( splitStr[i], &endptr, 10 );
4951 if( strcmp( endptr, "/n" ) == 0 ) {
4955 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4956 adapter = addrbookctl_find_interface( ifType );
4958 newList = g_list_append( newList, adapter );
4965 /* g_print( "i=%d\n", i ); */
4966 g_strfreev( splitStr );
4967 g_free( selectStr );
4969 /* Replace existing list */
4970 mgu_clear_list( _addressIFaceSelection_ );
4971 g_list_free( _addressIFaceSelection_ );
4972 _addressIFaceSelection_ = newList;
4976 /* ***********************************************************************
4977 * Add sender to address book.
4978 * ***********************************************************************
4982 * This function is used by the Add sender to address book function.
4984 gboolean addressbook_add_contact(
4985 const gchar *name, const gchar *address, const gchar *remarks,
4986 GdkPixbuf *picture )
4988 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4989 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
4990 debug_print( "addressbook_add_contact - added\n" );
4991 addressbook_refresh();
4996 /* ***********************************************************************
4997 * Book/folder selection.
4998 * ***********************************************************************
5002 * This function is used by the matcher dialog to select a book/folder.
5004 gboolean addressbook_folder_selection( gchar **folderpath )
5006 AddressBookFile *book = NULL;
5007 ItemFolder *folder = NULL;
5010 g_return_val_if_fail( folderpath != NULL, FALSE);
5014 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
5016 if ( folder != NULL) {
5018 gchar *oldtmp = NULL;
5019 AddrItemObject *obj = NULL;
5021 /* walk thru folder->parent to build the full folder path */
5022 /* TODO: wwp: optimize this */
5024 tmp = g_strdup(obj->uid);
5025 while ( obj->parent ) {
5027 if ( obj->name != NULL ) {
5028 oldtmp = g_strdup(tmp);
5030 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5034 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
5037 *folderpath = g_strdup_printf("%s", book->fileName);
5039 debug_print( "addressbook_foldersel: %s\n", *folderpath?*folderpath:"(null)");
5040 return (*folderpath != NULL);
5045 /* ***********************************************************************
5046 * Book/folder checking.
5047 * ***********************************************************************
5050 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5052 FolderInfo *fi = g_new0( FolderInfo, 1 );
5054 fi->folder = folder;
5058 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5059 FolderInfo *fiParent, FolderPathMatch *match )
5065 FolderPathMatch *nextmatch = NULL;
5070 list = parentFolder->listFolder;
5072 folder = list->data;
5073 fName = g_strdup( ADDRITEM_NAME(folder) );
5075 /* match folder name, match pointer will be set to NULL if next recursive call
5076 doesn't need to match subfolder name */
5077 if ( match != NULL &&
5078 match->matched == FALSE ) {
5079 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5080 /* folder name matches, prepare next subfolder match */
5081 debug_print("matched folder name '%s'\n", fName);
5083 if ( match->folder_path[match->index] == NULL ) {
5084 /* we've matched all elements */
5085 match->matched = TRUE;
5086 match->folder = folder;
5087 debug_print("book/folder path matched!\n");
5089 /* keep on matching */
5097 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5098 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5100 list = g_list_next( list );
5105 * This function is used by to check if a matcher book/folder path corresponds to an
5106 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5107 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5108 if book AND folder are NULL this means that folderpath was empty or Any.
5109 If folderpath is a simple book name (without folder), book will not be NULL and folder
5110 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5113 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5114 AddressDataSource **book,
5115 ItemFolder **folder )
5117 AddressDataSource *ds;
5118 GList *list, *nodeDS;
5119 ItemFolder *rootFolder;
5120 AddressBookFile *abf;
5122 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5129 if ( folderpath == NULL )
5132 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5135 /* split the folder path we've received, we'll try to match this path, subpath by
5136 subpath against the book/folder structure in order */
5137 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5138 if (!folder_path_match.folder_path)
5141 list = addrindex_get_interface_list( _addressIndex_ );
5142 while ( list && !folder_path_match.matched ) {
5143 AddressInterface *interface = list->data;
5144 if ( interface && interface->type == ADDR_IF_BOOK ) {
5145 nodeDS = interface->listSource;
5146 while ( nodeDS && !folder_path_match.matched ) {
5149 /* Read address book */
5150 if( ! addrindex_ds_get_read_flag( ds ) ) {
5151 addrindex_ds_read_data( ds );
5154 /* Add node for address book */
5155 abf = ds->rawDataSource;
5157 /* match book name */
5158 if ( abf && abf->fileName &&
5159 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5161 debug_print("matched book name '%s'\n", abf->fileName);
5162 folder_path_match.book = ds;
5164 if ( folder_path_match.folder_path[1] == NULL ) {
5165 /* no folder part to match */
5167 folder_path_match.matched = TRUE;
5168 folder_path_match.folder = NULL;
5169 debug_print("book path matched!\n");
5172 /* match folder part */
5174 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5175 rootFolder = addrindex_ds_get_root_folder( ds );
5177 /* prepare for recursive call */
5178 folder_path_match.index = 1;
5179 /* this call will set folder_path_match.matched and folder_path_match.folder */
5180 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5185 nodeDS = g_list_next( nodeDS );
5188 list = g_list_next( list );
5191 g_strfreev( folder_path_match.folder_path );
5194 *book = folder_path_match.book;
5196 *folder = folder_path_match.folder;
5197 return folder_path_match.matched;
5201 /* **********************************************************************
5203 * ***********************************************************************
5209 static void addressbook_import_ldif_cb( void ) {
5210 AddressDataSource *ds = NULL;
5211 AdapterDSource *ads = NULL;
5212 AddressBookFile *abf = NULL;
5213 AdapterInterface *adapter;
5214 GtkCTreeNode *newNode;
5216 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5218 if( adapter->treeNode ) {
5219 abf = addressbook_imp_ldif( _addressIndex_ );
5221 ds = addrindex_index_add_datasource(
5222 _addressIndex_, ADDR_IF_BOOK, abf );
5223 ads = addressbook_create_ds_adapter(
5224 ds, ADDR_BOOK, NULL );
5225 addressbook_ads_set_name(
5226 ads, addrbook_get_name( abf ) );
5227 newNode = addressbook_add_object(
5229 ADDRESS_OBJECT(ads) );
5231 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5233 addrbook.treeSelected = newNode;
5236 /* Notify address completion */
5237 invalidate_address_completion();
5246 static void addressbook_import_mutt_cb( void ) {
5247 AddressDataSource *ds = NULL;
5248 AdapterDSource *ads = NULL;
5249 AddressBookFile *abf = NULL;
5250 AdapterInterface *adapter;
5251 GtkCTreeNode *newNode;
5253 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5255 if( adapter->treeNode ) {
5256 abf = addressbook_imp_mutt( _addressIndex_ );
5258 ds = addrindex_index_add_datasource(
5259 _addressIndex_, ADDR_IF_BOOK, abf );
5260 ads = addressbook_create_ds_adapter(
5261 ds, ADDR_BOOK, NULL );
5262 addressbook_ads_set_name(
5263 ads, addrbook_get_name( abf ) );
5264 newNode = addressbook_add_object(
5266 ADDRESS_OBJECT(ads) );
5268 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5270 addrbook.treeSelected = newNode;
5273 /* Notify address completion */
5274 invalidate_address_completion();
5283 static void addressbook_import_pine_cb( void ) {
5284 AddressDataSource *ds = NULL;
5285 AdapterDSource *ads = NULL;
5286 AddressBookFile *abf = NULL;
5287 AdapterInterface *adapter;
5288 GtkCTreeNode *newNode;
5290 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5292 if( adapter->treeNode ) {
5293 abf = addressbook_imp_pine( _addressIndex_ );
5295 ds = addrindex_index_add_datasource(
5296 _addressIndex_, ADDR_IF_BOOK, abf );
5297 ads = addressbook_create_ds_adapter(
5298 ds, ADDR_BOOK, NULL );
5299 addressbook_ads_set_name(
5300 ads, addrbook_get_name( abf ) );
5301 newNode = addressbook_add_object(
5303 ADDRESS_OBJECT(ads) );
5305 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5307 addrbook.treeSelected = newNode;
5310 /* Notify address completion */
5311 invalidate_address_completion();
5318 * Harvest addresses.
5319 * \param folderItem Folder to import.
5320 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5321 * \param msgList List of message numbers, or NULL to process folder.
5323 void addressbook_harvest(
5324 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5326 AddressDataSource *ds = NULL;
5327 AdapterDSource *ads = NULL;
5328 AddressBookFile *abf = NULL;
5329 AdapterInterface *adapter;
5330 GtkCTreeNode *newNode;
5332 abf = addrgather_dlg_execute(
5333 folderItem, _addressIndex_, sourceInd, msgList );
5335 ds = addrindex_index_add_datasource(
5336 _addressIndex_, ADDR_IF_BOOK, abf );
5338 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5340 if( adapter->treeNode ) {
5341 ads = addressbook_create_ds_adapter(
5342 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5343 newNode = addressbook_add_object(
5345 ADDRESS_OBJECT(ads) );
5349 /* Notify address completion */
5350 invalidate_address_completion();
5357 static void addressbook_export_html_cb( void ) {
5358 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5360 AddressDataSource *ds = NULL;
5361 AddrBookBase *adbase;
5362 AddressCache *cache;
5363 GtkCTreeNode *node = NULL;
5365 if( ! addrbook.treeSelected ) return;
5366 node = addrbook.treeSelected;
5367 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5368 obj = gtk_ctree_node_get_row_data( ctree, node );
5369 if( obj == NULL ) return;
5371 ds = addressbook_find_datasource( node );
5372 if( ds == NULL ) return;
5373 adbase = ( AddrBookBase * ) ds->rawDataSource;
5374 cache = adbase->addressCache;
5375 addressbook_exp_html( cache );
5381 static void addressbook_export_ldif_cb( void ) {
5382 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5384 AddressDataSource *ds = NULL;
5385 AddrBookBase *adbase;
5386 AddressCache *cache;
5387 GtkCTreeNode *node = NULL;
5389 if( ! addrbook.treeSelected ) return;
5390 node = addrbook.treeSelected;
5391 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5392 obj = gtk_ctree_node_get_row_data( ctree, node );
5393 if( obj == NULL ) return;
5395 ds = addressbook_find_datasource( node );
5396 if( ds == NULL ) return;
5397 adbase = ( AddrBookBase * ) ds->rawDataSource;
5398 cache = adbase->addressCache;
5399 addressbook_exp_ldif( cache );
5402 static void addressbook_find_duplicates_cb(void)
5404 addrduplicates_find(GTK_WINDOW(addrbook.window));
5407 static void addressbook_start_drag(GtkWidget *widget, gint button,
5411 GdkDragContext *context;
5412 if (addressbook_target_list == NULL)
5413 addressbook_target_list = gtk_target_list_new(
5414 addressbook_drag_types, 1);
5415 context = gtk_drag_begin(widget, addressbook_target_list,
5416 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5417 gtk_drag_set_icon_default(context);
5420 static void addressbook_drag_data_get(GtkWidget *widget,
5421 GdkDragContext *drag_context,
5422 GtkSelectionData *selection_data,
5427 AddrItemObject *aio = NULL;
5428 AddressObject *pobj = NULL;
5429 AdapterDSource *ads = NULL;
5430 AddressDataSource *ds = NULL;
5433 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5435 if( pobj == NULL ) return;
5437 if( pobj->type == ADDR_DATASOURCE ) {
5438 ads = ADAPTER_DSOURCE(pobj);
5439 ds = ads->dataSource;
5440 } else if (pobj->type == ADDR_ITEM_GROUP) {
5445 else if( pobj->type != ADDR_INTERFACE ) {
5446 ds = addressbook_find_datasource( addrbook.treeSelected );
5452 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5453 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5454 GTK_CTREE_NODE(cur->data));
5455 while (aio && aio->type != ADDR_ITEM_PERSON) {
5460 if (aio && aio->type == ADDR_ITEM_PERSON) {
5461 if( ds && ds->interface && ds->interface->readOnly)
5462 gtk_selection_data_set(selection_data,
5463 selection_data->target, 8,
5464 (const guchar *)"Dummy_addr_copy", 15);
5466 gtk_selection_data_set(selection_data,
5467 selection_data->target, 8,
5468 (const guchar *)"Dummy_addr_move", 15);
5472 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5473 GdkDragContext *context,
5480 GtkCTreeNode *node = NULL;
5481 gboolean acceptable = FALSE;
5482 gint height = addrbook.ctree->allocation.height;
5483 gint total_height = addrbook.ctree->requisition.height;
5484 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5485 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5486 gfloat vpos = pos->value;
5488 if (gtk_clist_get_selection_info
5489 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5491 if (y > height - 24 && height + vpos < total_height) {
5492 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5493 gtk_adjustment_changed(pos);
5495 if (y < 24 && y > 0) {
5496 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5497 gtk_adjustment_changed(pos);
5499 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5502 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5503 if( obj->type == ADDR_ITEM_FOLDER
5504 || obj->type == ADDR_ITEM_GROUP)
5507 AdapterDSource *ads = NULL;
5508 AddressDataSource *ds = NULL;
5509 ads = ADAPTER_DSOURCE(obj);
5510 if (ads == NULL ){ return FALSE;}
5511 ds = ads->dataSource;
5512 if (ds == NULL ) { return FALSE;}
5520 g_signal_handlers_block_by_func
5522 G_CALLBACK(addressbook_tree_selected), NULL);
5523 gtk_sctree_select( GTK_SCTREE(widget), node);
5524 g_signal_handlers_unblock_by_func
5526 G_CALLBACK(addressbook_tree_selected), NULL);
5527 gdk_drag_status(context,
5528 (context->actions == GDK_ACTION_COPY ?
5529 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5531 gdk_drag_status(context, 0, time);
5536 static void addressbook_drag_leave_cb(GtkWidget *widget,
5537 GdkDragContext *context,
5541 if (addrbook.treeSelected) {
5542 g_signal_handlers_block_by_func
5544 G_CALLBACK(addressbook_tree_selected), NULL);
5545 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5546 g_signal_handlers_unblock_by_func
5548 G_CALLBACK(addressbook_tree_selected), NULL);
5553 static void addressbook_drag_received_cb(GtkWidget *widget,
5554 GdkDragContext *drag_context,
5557 GtkSelectionData *data,
5564 GtkCTreeNode *lastopened = addrbook.opened;
5566 if (!strncmp(data->data, "Dummy_addr", 10)) {
5567 if (gtk_clist_get_selection_info
5568 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5572 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5573 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5576 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5577 if (drag_context->action == GDK_ACTION_COPY ||
5578 !strcmp(data->data, "Dummy_addr_copy"))
5579 addressbook_clip_copy_cb();
5581 addressbook_clip_cut_cb();
5582 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5583 addressbook_clip_paste_cb();
5584 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5585 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5586 gtk_drag_finish(drag_context, TRUE, TRUE, time);