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_("Distinguised 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_status_message( AddressDataSource *ds, gchar *msg ) {
1304 *addressbook_msgbuf = '\0';
1308 name = addrindex_ds_get_name( ds );
1309 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1310 "%s: %s", name, msg );
1313 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1316 addressbook_status_show( addressbook_msgbuf );
1319 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1323 *addressbook_msgbuf = '\0';
1325 name = addrindex_ds_get_name( ds );
1326 retVal = addrindex_ds_get_status_code( ds );
1327 if( retVal == MGU_SUCCESS ) {
1328 g_snprintf( addressbook_msgbuf,
1329 sizeof(addressbook_msgbuf), "%s", name );
1332 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1333 g_snprintf( addressbook_msgbuf,
1334 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1337 addressbook_status_show( addressbook_msgbuf );
1340 static void addressbook_button_set_sensitive(void)
1342 gboolean to_sens = FALSE;
1343 gboolean cc_sens = FALSE;
1344 gboolean bcc_sens = FALSE;
1346 if (!addrbook.window) return;
1348 if (addrbook.target_compose) {
1354 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1355 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1356 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1359 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1361 addressbook_edit_address_cb(NULL, 0, NULL);
1365 * Delete one or more objects from address list.
1367 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1369 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1370 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1371 AddressObject *pobj;
1372 AdapterDSource *ads = NULL;
1373 GtkCTreeNode *nodeList;
1376 AddressBookFile *abf = NULL;
1377 AddressDataSource *ds = NULL;
1378 AddressInterface *iface;
1379 AddrItemObject *aio;
1380 AddrSelectItem *item;
1382 gboolean refreshList = FALSE;
1384 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1385 g_return_if_fail(pobj != NULL);
1387 /* Test whether anything selected for deletion */
1388 nodeList = addrbook.listSelected;
1390 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1391 if( aio == NULL) return;
1392 ds = addressbook_find_datasource( addrbook.treeSelected );
1393 if( ds == NULL ) return;
1395 /* Test for read only */
1396 iface = ds->interface;
1397 if( iface->readOnly ) {
1398 alertpanel( _("Delete address(es)"),
1399 _("This address data is readonly and cannot be deleted."),
1400 GTK_STOCK_CLOSE, NULL, NULL );
1404 /* Test whether Ok to proceed */
1406 if( pobj->type == ADDR_DATASOURCE ) {
1407 ads = ADAPTER_DSOURCE(pobj);
1408 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1410 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1413 else if( pobj->type == ADDR_ITEM_GROUP ) {
1416 if( ! procFlag ) return;
1417 abf = ds->rawDataSource;
1418 if( abf == NULL ) return;
1421 /* Process deletions */
1422 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1423 gboolean group_delete = TRUE;
1424 /* Items inside folders */
1425 list = addrselect_get_list( _addressSelect_ );
1426 /* Confirm deletion */
1430 node = g_list_next( node );
1431 aio = ( AddrItemObject * ) item->addressItem;
1432 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1433 group_delete = FALSE;
1438 aval = alertpanel( _("Delete group"),
1439 _("Really delete the group(s)?\n"
1440 "The addresses it contains will not be lost."),
1441 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1442 if( aval != G_ALERTALTERNATE ) return;
1444 aval = alertpanel( _("Delete address(es)"),
1445 _("Really delete the address(es)?"),
1446 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1447 if( aval != G_ALERTALTERNATE ) return;
1453 node = g_list_next( node );
1454 aio = ( AddrItemObject * ) item->addressItem;
1455 if( aio->type == ADDR_ITEM_GROUP ) {
1456 ItemGroup *item = ( ItemGroup * ) aio;
1457 GtkCTreeNode *nd = NULL;
1459 nd = addressbook_find_group_node( addrbook.opened, item );
1460 item = addrbook_remove_group( abf, item );
1462 addritem_free_item_group( item );
1464 /* Remove group from parent node */
1465 gtk_ctree_remove_node( ctree, nd );
1468 else if( aio->type == ADDR_ITEM_PERSON ) {
1469 ItemPerson *item = ( ItemPerson * ) aio;
1470 item->status = DELETE_ENTRY;
1471 addressbook_folder_remove_one_person( clist, item );
1472 if (pobj->type == ADDR_ITEM_FOLDER)
1473 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1474 item = addrbook_remove_person( abf, item );
1476 if (ds && ds->type == ADDR_IF_LDAP) {
1477 LdapServer *server = ds->rawDataSource;
1478 ldapsvr_set_modified(server, TRUE);
1479 ldapsvr_update_book(server, item);
1483 addritem_free_item_person( item );
1486 else if( aio->type == ADDR_ITEM_EMAIL ) {
1487 ItemEMail *item = ( ItemEMail * ) aio;
1488 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1489 item = addrbook_person_remove_email( abf, person, item );
1491 addrcache_remove_email(abf->addressCache, item);
1492 addritem_free_item_email( item );
1494 addressbook_folder_refresh_one_person( clist, person );
1497 g_list_free( list );
1498 addressbook_list_select_clear();
1500 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1501 addressbook_set_clist(
1502 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1506 addrbook_set_dirty(abf, TRUE);
1507 addressbook_export_to_file();
1508 addressbook_list_menu_setup();
1511 else if( pobj->type == ADDR_ITEM_GROUP ) {
1512 /* Items inside groups */
1513 list = addrselect_get_list( _addressSelect_ );
1517 node = g_list_next( node );
1518 aio = ( AddrItemObject * ) item->addressItem;
1519 if( aio->type == ADDR_ITEM_EMAIL ) {
1520 ItemEMail *item = ( ItemEMail * ) aio;
1521 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1522 item = addrbook_person_remove_email( abf, person, item );
1524 addritem_free_item_email( item );
1528 g_list_free( list );
1529 addressbook_list_select_clear();
1530 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1531 addressbook_set_clist(
1532 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1536 addrbook_set_dirty(abf, TRUE);
1537 addressbook_export_to_file();
1538 addressbook_list_menu_setup();
1542 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1543 gtk_ctree_remove_node( clist, nodeList );
1547 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1549 addressbook_new_address_cb( NULL, 0, NULL );
1552 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1555 gchar *address = NULL;
1557 if( aio->type == ADDR_ITEM_EMAIL ) {
1558 ItemPerson *person = NULL;
1559 ItemEMail *email = ( ItemEMail * ) aio;
1561 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1562 if( email->address ) {
1563 if( ADDRITEM_NAME(email) ) {
1564 name = ADDRITEM_NAME(email);
1565 if( *name == '\0' ) {
1566 name = ADDRITEM_NAME(person);
1569 else if( ADDRITEM_NAME(person) ) {
1570 name = ADDRITEM_NAME(person);
1573 buf = g_strdup( email->address );
1575 address = email->address;
1578 else if( aio->type == ADDR_ITEM_PERSON ) {
1579 ItemPerson *person = ( ItemPerson * ) aio;
1580 GList *node = person->listEMail;
1582 name = ADDRITEM_NAME(person);
1584 ItemEMail *email = ( ItemEMail * ) node->data;
1585 address = email->address;
1589 if( name && name[0] != '\0' ) {
1590 if( strchr_with_skip_quote( name, '"', ',' ) )
1591 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1593 buf = g_strdup_printf( "%s <%s>", name, address );
1596 buf = g_strdup( address );
1603 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1607 AddrSelectItem *item;
1608 AddrItemObject *aio;
1611 compose = addrbook.target_compose;
1612 if( ! compose ) return;
1614 /* Nothing selected, but maybe there is something in text entry */
1615 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1617 compose_entry_append(
1618 compose, addr, (ComposeEntryType)data );
1621 /* Select from address list */
1622 list = addrselect_get_list( _addressSelect_ );
1627 node = g_list_next( node );
1628 aio = item->addressItem;
1629 if( aio->type == ADDR_ITEM_PERSON ||
1630 aio->type == ADDR_ITEM_EMAIL ) {
1631 addr = addressbook_format_address( aio );
1632 compose_entry_append(
1633 compose, addr, (ComposeEntryType) data );
1636 else if( aio->type == ADDR_ITEM_GROUP ) {
1637 ItemGroup *group = ( ItemGroup * ) aio;
1638 GList *nodeMail = group->listEMail;
1640 ItemEMail *email = nodeMail->data;
1642 addr = addressbook_format_address(
1643 ( AddrItemObject * ) email );
1644 compose_entry_append(
1645 compose, addr, (ComposeEntryType) data );
1647 nodeMail = g_list_next( nodeMail );
1652 AddressObject *obj = NULL;
1654 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1656 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1657 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1658 GList *nodeMail = itemGroup->listEMail;
1660 ItemEMail *email = nodeMail->data;
1662 addr = addressbook_format_address(
1663 ( AddrItemObject * ) email );
1664 compose_entry_append(
1665 compose, addr, (ComposeEntryType) data );
1667 nodeMail = g_list_next( nodeMail );
1671 g_list_free( list );
1674 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1675 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1676 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1677 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1679 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1680 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1681 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1682 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1684 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1685 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1686 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1687 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1688 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1689 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1692 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1693 gboolean canEdit = FALSE;
1694 gboolean canDelete = TRUE;
1695 gboolean canAdd = FALSE;
1696 gboolean canEditTr = TRUE;
1697 gboolean editAddress = FALSE;
1698 gboolean canExport = TRUE;
1699 AddressTypeControlItem *atci = NULL;
1700 AddressDataSource *ds = NULL;
1701 AddressInterface *iface = NULL;
1703 if( obj == NULL ) return;
1704 if( obj->type == ADDR_INTERFACE ) {
1705 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1706 iface = adapter->interface;
1708 if( iface->haveLibrary ) {
1709 /* Enable appropriate File / New command */
1710 atci = adapter->atci;
1711 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1714 canEditTr = canExport = FALSE;
1716 else if( obj->type == ADDR_DATASOURCE ) {
1717 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1718 ds = ads->dataSource;
1719 iface = ds->interface;
1720 if( ! iface->readOnly ) {
1721 canAdd = canEdit = editAddress = canDelete = TRUE;
1723 if( ! iface->haveLibrary ) {
1724 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1727 else if( obj->type == ADDR_ITEM_FOLDER ) {
1728 ds = addressbook_find_datasource( addrbook.treeSelected );
1730 iface = ds->interface;
1731 if( iface->readOnly ) {
1736 canAdd = editAddress = TRUE;
1740 else if( obj->type == ADDR_ITEM_GROUP ) {
1741 ds = addressbook_find_datasource( addrbook.treeSelected );
1743 iface = ds->interface;
1744 if( ! iface->readOnly ) {
1750 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1753 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1754 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1755 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1756 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1759 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1760 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1761 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1762 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1764 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1765 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1768 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1769 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1772 static void addressbook_list_menu_setup( void );
1775 * Address book tree callback function that responds to selection of tree
1778 * \param ctree Tree widget.
1779 * \param node Node that was selected.
1780 * \param column Column number where selected occurred.
1781 * \param data Pointer to user data.
1783 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1784 gint column, gpointer data)
1786 AddressObject *obj = NULL;
1787 AdapterDSource *ads = NULL;
1788 AddressDataSource *ds = NULL;
1789 ItemFolder *rootFolder = NULL;
1790 AddressObjectType aot;
1792 addrbook.treeSelected = node;
1793 addrbook.listSelected = NULL;
1794 addressbook_status_show( "" );
1795 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1797 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1799 addressbook_set_clist(NULL, TRUE);
1802 addrbook.opened = node;
1804 if( obj->type == ADDR_DATASOURCE ) {
1805 /* Read from file */
1806 static gboolean tVal = TRUE;
1808 ads = ADAPTER_DSOURCE(obj);
1809 if( ads == NULL ) return;
1810 ds = ads->dataSource;
1811 if( ds == NULL ) return;
1813 if( addrindex_ds_get_modify_flag( ds ) ) {
1814 addrindex_ds_read_data( ds );
1817 if( ! addrindex_ds_get_read_flag( ds ) ) {
1818 addrindex_ds_read_data( ds );
1820 addressbook_ds_show_message( ds );
1822 if( ! addrindex_ds_get_access_flag( ds ) ) {
1823 /* Remove existing folders and groups */
1824 gtk_clist_freeze( GTK_CLIST(ctree) );
1825 addressbook_tree_remove_children( ctree, node );
1826 gtk_clist_thaw( GTK_CLIST(ctree) );
1828 /* Load folders into the tree */
1829 rootFolder = addrindex_ds_get_root_folder( ds );
1830 if( ds && ds->type == ADDR_IF_JPILOT ) {
1831 aot = ADDR_CATEGORY;
1833 else if( ds && ds->type == ADDR_IF_LDAP ) {
1834 aot = ADDR_LDAP_QUERY;
1837 aot = ADDR_ITEM_FOLDER;
1839 addressbook_node_add_folder( node, ds, rootFolder, aot );
1840 addrindex_ds_set_access_flag( ds, &tVal );
1841 gtk_ctree_expand( ctree, node );
1844 addressbook_set_clist(NULL, TRUE);
1847 /* Update address list */
1848 g_signal_handlers_block_by_func
1850 G_CALLBACK(addressbook_tree_selected), NULL);
1851 addressbook_set_clist( obj, FALSE );
1852 g_signal_handlers_unblock_by_func
1854 G_CALLBACK(addressbook_tree_selected), NULL);
1855 if (!prefs_common.addressbook_use_editaddress_dialog)
1856 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1858 /* Setup main menu selections */
1859 addressbook_menubar_set_sensitive( FALSE );
1860 addressbook_list_menu_setup();
1861 addressbook_menuitem_set_sensitive( obj, node );
1863 addressbook_list_select_clear();
1864 addressbook_list_menu_setup();
1869 * Setup address list popup menu items. Items are enabled or disabled as
1872 static void addressbook_list_menu_setup( void ) {
1873 GtkCTree *clist = NULL;
1874 AddressObject *pobj = NULL;
1875 AddressObject *obj = NULL;
1876 AdapterDSource *ads = NULL;
1877 AddressInterface *iface = NULL;
1878 AddressDataSource *ds = NULL;
1879 gboolean canEdit = FALSE;
1880 gboolean canDelete = FALSE;
1881 gboolean canCut = FALSE;
1882 gboolean canCopy = FALSE;
1883 gboolean canPaste = FALSE;
1884 gboolean canBrowse = FALSE;
1886 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1887 if( pobj == NULL ) return;
1889 clist = GTK_CTREE(addrbook.clist);
1890 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1891 if( obj == NULL ) canEdit = FALSE;
1893 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1894 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1896 if( pobj->type == ADDR_DATASOURCE ) {
1897 /* Parent object is a data source */
1898 ads = ADAPTER_DSOURCE(pobj);
1899 ds = ads->dataSource;
1900 iface = ds->interface;
1901 if( ! iface->readOnly ) {
1902 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1903 if (iface->type != ADDR_IF_LDAP)
1904 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1905 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1906 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1907 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1908 if( obj ) canEdit = TRUE;
1910 canDelete = canEdit;
1912 else if( pobj->type != ADDR_INTERFACE ) {
1913 /* Parent object is not an interface */
1914 ds = addressbook_find_datasource( addrbook.treeSelected );
1917 iface = ds->interface;
1918 if( ! iface->readOnly ) {
1919 /* Folder or group */
1920 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1921 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1922 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1923 if( obj ) canEdit = TRUE;
1926 if( pobj->type == ADDR_ITEM_FOLDER ) {
1927 if (iface->type != ADDR_IF_LDAP)
1928 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1929 if( obj ) canEdit = TRUE;
1931 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1932 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1933 canDelete = canEdit;
1935 if( iface && iface->type == ADDR_IF_LDAP ) {
1936 if( obj ) canBrowse = TRUE;
1941 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1943 /* Disable edit or browse if more than one row selected */
1944 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1949 /* Now go finalize menu items */
1950 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1951 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1953 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1954 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1955 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1956 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1958 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1960 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1961 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1962 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1963 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1965 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1966 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1967 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1969 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1970 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1971 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1973 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1974 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1977 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1981 static void addressbook_select_row_tree (GtkCTree *ctree,
1989 * Add list of items into tree node below specified tree node.
1990 * \param treeNode Tree node.
1991 * \param ds Data source.
1992 * \param listItems List of items.
1994 static void addressbook_treenode_add_list(
1995 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2001 AddrItemObject *aio;
2005 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2008 group = ( ItemGroup * ) aio;
2009 nn = addressbook_node_add_group( treeNode, ds, group );
2011 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2014 folder = ( ItemFolder * ) aio;
2015 nn = addressbook_node_add_folder(
2016 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2018 node = g_list_next( node );
2022 static void addressbook_select_all_cb( void ) {
2023 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2027 * Cut from address list widget.
2029 static void addressbook_clip_cut_cb( void ) {
2030 _clipBoard_->cutFlag = TRUE;
2031 addrclip_clear( _clipBoard_ );
2032 addrclip_add( _clipBoard_, _addressSelect_ );
2033 /* addrclip_list_show( _clipBoard_, stdout ); */
2037 * Copy from address list widget.
2039 static void addressbook_clip_copy_cb( void ) {
2040 _clipBoard_->cutFlag = FALSE;
2041 addrclip_clear( _clipBoard_ );
2042 addrclip_add( _clipBoard_, _addressSelect_ );
2043 /* addrclip_list_show( _clipBoard_, stdout ); */
2047 * Paste clipboard into address list widget.
2049 static void addressbook_clip_paste_cb( void ) {
2050 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2051 AddressObject *pobj = NULL;
2052 AddressDataSource *ds = NULL;
2053 AddressBookFile *abf = NULL;
2054 ItemFolder *folder = NULL;
2055 GList *folderGroup = NULL;
2057 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2058 if( ds == NULL ) return;
2059 if( addrindex_ds_get_readonly( ds ) ) {
2060 addressbook_ds_status_message(
2061 ds, _( "Cannot paste. Target address book is readonly." ) );
2065 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2067 if( pobj->type == ADDR_ITEM_FOLDER ) {
2068 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2070 else if( pobj->type == ADDR_ITEM_GROUP ) {
2071 addressbook_ds_status_message(
2072 ds, _( "Cannot paste into an address group." ) );
2077 /* Get an address book */
2078 abf = addressbook_get_book_file();
2079 if( abf == NULL ) return;
2081 if( _clipBoard_->cutFlag ) {
2083 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2085 /* Remove all groups and folders in clipboard from tree node */
2086 addressbook_treenode_remove_item();
2088 /* Remove all "cut" items */
2089 addrclip_delete_item( _clipBoard_ );
2091 /* Clear clipboard - cut items??? */
2092 addrclip_clear( _clipBoard_ );
2096 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2099 /* addrclip_list_show( _clipBoard_, stdout ); */
2101 /* Update tree by inserting node for each folder or group */
2102 addressbook_treenode_add_list(
2103 addrbook.treeSelected, ds, folderGroup );
2104 gtk_ctree_expand( ctree, addrbook.treeSelected );
2105 g_list_free( folderGroup );
2109 /* Display items pasted */
2110 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2111 addressbook_set_clist(
2112 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2120 * Add current treenode object to clipboard. Note that widget only allows
2121 * one entry from the tree list to be selected.
2123 static void addressbook_treenode_to_clipboard( void ) {
2124 AddressObject *obj = NULL;
2125 AddressDataSource *ds = NULL;
2126 AddrSelectItem *item;
2127 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2130 node = addrbook.treeSelected;
2131 if( node == NULL ) return;
2132 obj = gtk_ctree_node_get_row_data( ctree, node );
2133 if( obj == NULL ) return;
2135 ds = addressbook_find_datasource( node );
2136 if( ds == NULL ) return;
2139 if( obj->type == ADDR_ITEM_FOLDER ) {
2140 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2141 ItemFolder *folder = adapter->itemFolder;
2143 item = addrselect_create_node( obj );
2144 item->uid = g_strdup( ADDRITEM_ID(folder) );
2146 else if( obj->type == ADDR_ITEM_GROUP ) {
2147 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2148 ItemGroup *group = adapter->itemGroup;
2150 item = addrselect_create_node( obj );
2151 item->uid = g_strdup( ADDRITEM_ID(group) );
2153 else if( obj->type == ADDR_DATASOURCE ) {
2155 item = addrselect_create_node( obj );
2160 /* Clear existing list and add item into list */
2163 addressbook_list_select_clear();
2164 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2165 addrselect_list_add( _addressSelect_, item, cacheID );
2171 * Cut from tree widget.
2173 static void addressbook_treenode_cut_cb( void ) {
2174 _clipBoard_->cutFlag = TRUE;
2175 addressbook_treenode_to_clipboard();
2176 addrclip_clear( _clipBoard_ );
2177 addrclip_add( _clipBoard_, _addressSelect_ );
2178 /* addrclip_list_show( _clipBoard_, stdout ); */
2182 * Copy from tree widget.
2184 static void addressbook_treenode_copy_cb( void ) {
2185 _clipBoard_->cutFlag = FALSE;
2186 addressbook_treenode_to_clipboard();
2187 addrclip_clear( _clipBoard_ );
2188 addrclip_add( _clipBoard_, _addressSelect_ );
2189 /* addrclip_list_show( _clipBoard_, stdout ); */
2193 * Paste clipboard into address tree widget.
2195 static void addressbook_treenode_paste_cb( void ) {
2196 addressbook_clip_paste_cb();
2200 * Clear selected entries in clipboard.
2202 static void addressbook_list_select_clear( void ) {
2203 addrselect_list_clear( _addressSelect_ );
2207 * Add specified address item to selected address list.
2208 * \param aio Address item object.
2209 * \param ds Datasource.
2211 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2214 if( ds == NULL ) return;
2215 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2216 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2221 * Remove specified address item from selected address list.
2222 * \param aio Address item object.
2224 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2225 addrselect_list_remove( _addressSelect_, aio );
2229 * Invoke EMail compose window with addresses in selected address list.
2231 static void addressbook_mail_to_cb( void ) {
2234 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2235 listAddress = addrselect_build_list( _addressSelect_ );
2236 compose_new_with_list( NULL, listAddress );
2237 mgu_free_dlist( listAddress );
2242 static void addressbook_list_row_selected( GtkCTree *clist,
2247 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2248 AddrItemObject *aio = NULL;
2249 AddressObject *pobj = NULL;
2250 AdapterDSource *ads = NULL;
2251 AddressDataSource *ds = NULL;
2253 gtk_entry_set_text( entry, "" );
2254 addrbook.listSelected = node;
2256 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2257 if( pobj == NULL ) return;
2259 if( pobj->type == ADDR_DATASOURCE ) {
2260 ads = ADAPTER_DSOURCE(pobj);
2261 ds = ads->dataSource;
2263 else if( pobj->type != ADDR_INTERFACE ) {
2264 ds = addressbook_find_datasource( addrbook.treeSelected );
2267 aio = gtk_ctree_node_get_row_data( clist, node );
2269 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2270 addressbook_list_select_add( aio, ds );
2273 addressbook_list_menu_setup();
2275 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog)
2276 addressbook_edit_address(NULL, 0, NULL, FALSE);
2279 static void addressbook_list_row_unselected( GtkCTree *ctree,
2284 AddrItemObject *aio;
2286 aio = gtk_ctree_node_get_row_data( ctree, node );
2288 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2289 addressbook_list_select_remove( aio );
2292 if (!prefs_common.addressbook_use_editaddress_dialog)
2293 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2296 /* from gdkevents.c */
2297 #define DOUBLE_CLICK_TIME 250
2299 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2300 GdkEventButton *event,
2303 static guint32 lasttime = 0;
2304 if( ! event ) return FALSE;
2306 addressbook_list_menu_setup();
2308 if( event->button == 3 ) {
2309 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2310 event->button, event->time );
2311 } else if (event->button == 1) {
2312 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2313 if (prefs_common.add_address_by_click &&
2314 addrbook.target_compose)
2315 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2317 if (prefs_common.addressbook_use_editaddress_dialog)
2318 addressbook_edit_address_cb(NULL, 0, NULL);
2322 lasttime = event->time;
2328 static gboolean addressbook_list_button_released(GtkWidget *widget,
2329 GdkEventButton *event,
2335 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2336 GdkEventButton *event,
2339 GtkCList *clist = GTK_CLIST(ctree);
2341 AddressObject *obj = NULL;
2342 AdapterDSource *ads = NULL;
2343 AddressInterface *iface = NULL;
2344 AddressDataSource *ds = NULL;
2345 gboolean canEdit = FALSE;
2346 gboolean canDelete = FALSE;
2347 gboolean canCut = FALSE;
2348 gboolean canCopy = FALSE;
2349 gboolean canPaste = FALSE;
2350 gboolean canTreeCut = FALSE;
2351 gboolean canTreeCopy = FALSE;
2352 gboolean canTreePaste = FALSE;
2353 gboolean canLookup = FALSE;
2354 GtkCTreeNode *node = NULL;
2356 if( ! event ) return FALSE;
2357 addressbook_menubar_set_sensitive( FALSE );
2359 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2360 gtkut_clist_set_focus_row(clist, row);
2361 obj = gtk_clist_get_row_data( clist, row );
2364 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2366 if( obj == NULL ) return FALSE;
2367 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2369 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2370 canTreePaste = TRUE;
2373 if (obj->type == ADDR_INTERFACE) {
2374 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2375 iface = adapter->interface;
2378 canTreeCopy = FALSE;
2379 if( iface->readOnly ) {
2380 canTreePaste = FALSE;
2383 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2384 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2386 if( iface->externalQuery ) canLookup = TRUE;
2388 if (obj->type == ADDR_DATASOURCE) {
2389 ads = ADAPTER_DSOURCE(obj);
2390 ds = ads->dataSource;
2393 iface = ds->interface;
2398 if( iface->readOnly ) {
2399 canTreePaste = FALSE;
2402 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2403 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2404 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2407 if( iface->externalQuery ) canLookup = TRUE;
2409 else if (obj->type == ADDR_ITEM_FOLDER) {
2410 ds = addressbook_find_datasource( node );
2414 iface = ds->interface;
2417 if( iface->readOnly ) {
2418 canTreePaste = FALSE;
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 ) {
2431 /* Enable deletion of LDAP folder */
2436 else if (obj->type == ADDR_ITEM_GROUP) {
2437 ds = addressbook_find_datasource( node );
2440 iface = ds->interface;
2443 if( ! iface->readOnly ) {
2446 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2447 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2450 else if (obj->type == ADDR_INTERFACE) {
2451 canTreePaste = FALSE;
2455 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2457 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2458 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2462 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2463 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2464 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2465 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2466 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2468 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2469 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2470 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2471 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2472 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2473 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2475 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2476 if( event->button == 3 ) {
2477 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2478 event->button, event->time);
2484 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2485 GdkEventButton *event,
2488 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2492 static void addressbook_new_folder_cb(gpointer data, guint action,
2495 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2496 AddressObject *obj = NULL;
2497 AddressDataSource *ds = NULL;
2498 AddressBookFile *abf = NULL;
2499 ItemFolder *parentFolder = NULL;
2500 ItemFolder *folder = NULL;
2502 if( ! addrbook.treeSelected ) return;
2503 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2504 if( obj == NULL ) return;
2505 ds = addressbook_find_datasource( addrbook.treeSelected );
2506 if( ds == NULL ) return;
2508 if( obj->type == ADDR_DATASOURCE ) {
2509 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2511 else if( obj->type == ADDR_ITEM_FOLDER ) {
2512 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2518 abf = ds->rawDataSource;
2519 if( abf == NULL ) return;
2520 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2523 nn = addressbook_node_add_folder(
2524 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2525 gtk_ctree_expand( ctree, addrbook.treeSelected );
2526 if( addrbook.treeSelected == addrbook.opened )
2527 addressbook_set_clist(obj, TRUE);
2532 static void addressbook_new_group_cb(gpointer data, guint action,
2535 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2536 AddressObject *obj = NULL;
2537 AddressDataSource *ds = NULL;
2538 AddressBookFile *abf = NULL;
2539 ItemFolder *parentFolder = NULL;
2540 ItemGroup *group = NULL;
2542 if( ! addrbook.treeSelected ) return;
2543 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2544 if( obj == NULL ) return;
2545 ds = addressbook_find_datasource( addrbook.treeSelected );
2546 if( ds == NULL ) return;
2548 if( obj->type == ADDR_DATASOURCE ) {
2549 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2551 else if( obj->type == ADDR_ITEM_FOLDER ) {
2552 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2558 abf = ds->rawDataSource;
2559 if( abf == NULL ) return;
2560 group = addressbook_edit_group( abf, parentFolder, NULL );
2563 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2564 gtk_ctree_expand( ctree, addrbook.treeSelected );
2565 if( addrbook.treeSelected == addrbook.opened )
2566 addressbook_set_clist(obj, TRUE);
2571 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2573 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2576 GdkPixmap *pix_cl, *pix_op;
2577 GdkBitmap *mask_cl, *mask_op;
2578 gboolean is_leaf, expanded;
2580 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2581 &pix_cl, &mask_cl, &pix_op, &mask_op,
2582 &is_leaf, &expanded);
2583 gtk_sctree_set_node_info(ctree, node, name, spacing,
2584 pix_cl, mask_cl, pix_op, mask_op,
2590 * \param obj Address object to edit.
2591 * \param node Node in tree.
2592 * \return New name of data source.
2594 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2595 gchar *newName = NULL;
2596 AddressDataSource *ds = NULL;
2597 AddressInterface *iface = NULL;
2598 AdapterDSource *ads = NULL;
2600 ds = addressbook_find_datasource( node );
2601 if( ds == NULL ) return NULL;
2602 iface = ds->interface;
2603 if( ! iface->haveLibrary ) return NULL;
2605 /* Read data from data source */
2606 if( addrindex_ds_get_modify_flag( ds ) ) {
2607 addrindex_ds_read_data( ds );
2610 if( ! addrindex_ds_get_read_flag( ds ) ) {
2611 addrindex_ds_read_data( ds );
2615 ads = ADAPTER_DSOURCE(obj);
2616 if( ads->subType == ADDR_BOOK ) {
2617 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2619 else if( ads->subType == ADDR_VCARD ) {
2620 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2623 else if( ads->subType == ADDR_JPILOT ) {
2624 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2628 else if( ads->subType == ADDR_LDAP ) {
2629 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2635 newName = obj->name;
2640 * Edit an object that is in the address tree area.
2642 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2645 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2647 AddressDataSource *ds = NULL;
2648 AddressBookFile *abf = NULL;
2649 GtkCTreeNode *node = NULL, *parentNode = NULL;
2652 if( ! addrbook.treeSelected ) return;
2653 node = addrbook.treeSelected;
2654 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2655 obj = gtk_ctree_node_get_row_data( ctree, node );
2656 if( obj == NULL ) return;
2657 parentNode = GTK_CTREE_ROW(node)->parent;
2659 ds = addressbook_find_datasource( node );
2660 if( ds == NULL ) return;
2662 if( obj->type == ADDR_DATASOURCE ) {
2663 name = addressbook_edit_datasource( obj, node );
2664 if( name == NULL ) return;
2667 abf = ds->rawDataSource;
2668 if( abf == NULL ) return;
2669 if( obj->type == ADDR_ITEM_FOLDER ) {
2670 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2671 ItemFolder *item = adapter->itemFolder;
2672 ItemFolder *parentFolder = NULL;
2673 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2674 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2675 name = ADDRITEM_NAME(item);
2677 else if( obj->type == ADDR_ITEM_GROUP ) {
2678 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2679 ItemGroup *item = adapter->itemGroup;
2680 ItemFolder *parentFolder = NULL;
2681 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2682 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2683 name = ADDRITEM_NAME(item);
2686 if( name && parentNode ) {
2687 /* Update node in tree view */
2688 addressbook_change_node_name( node, name );
2689 gtk_sctree_sort_node(ctree, parentNode);
2690 gtk_ctree_expand( ctree, node );
2691 gtk_sctree_select( GTK_SCTREE( ctree), node );
2698 ADDRTREE_DEL_FOLDER_ONLY,
2699 ADDRTREE_DEL_FOLDER_ADDR
2703 * Delete an item from the tree widget.
2704 * \param data Data passed in.
2705 * \param action Action.
2706 * \param widget Widget issuing callback.
2708 static void addressbook_treenode_delete_cb(
2709 gpointer data, guint action, GtkWidget *widget )
2711 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2712 GtkCTreeNode *node = NULL;
2716 AddrBookBase *adbase;
2717 AddressCache *cache;
2718 AdapterDSource *ads = NULL;
2719 AddressInterface *iface = NULL;
2720 AddressDataSource *ds = NULL;
2721 gboolean remFlag = FALSE;
2722 TreeItemDelType delType;
2724 if( ! addrbook.treeSelected ) return;
2725 node = addrbook.treeSelected;
2726 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2728 obj = gtk_ctree_node_get_row_data( ctree, node );
2729 g_return_if_fail(obj != NULL);
2731 if( obj->type == ADDR_DATASOURCE ) {
2732 ads = ADAPTER_DSOURCE(obj);
2733 if( ads == NULL ) return;
2734 ds = ads->dataSource;
2735 if( ds == NULL ) return;
2738 /* Must be folder or something else */
2739 ds = addressbook_find_datasource( node );
2740 if( ds == NULL ) return;
2742 /* Only allow deletion from non-readOnly */
2743 iface = ds->interface;
2744 if( iface->readOnly ) {
2745 /* Allow deletion of query results */
2746 if( ! iface->externalQuery ) return;
2750 /* Confirm deletion */
2751 delType = ADDRTREE_DEL_NONE;
2752 if( obj->type == ADDR_ITEM_FOLDER ) {
2753 if( iface->externalQuery ) {
2754 message = g_strdup_printf( _(
2755 "Do you want to delete the query " \
2756 "results and addresses in '%s' ?" ),
2758 aval = alertpanel( _("Delete"), message,
2759 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2761 if( aval == G_ALERTALTERNATE ) {
2762 delType = ADDRTREE_DEL_FOLDER_ADDR;
2766 message = g_strdup_printf
2767 ( _( "Do you want to delete '%s' ?"
2768 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2770 aval = alertpanel( _("Delete folder"), message,
2771 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2773 if( aval == G_ALERTALTERNATE ) {
2774 delType = ADDRTREE_DEL_FOLDER_ONLY;
2776 else if( aval == G_ALERTOTHER ) {
2777 delType = ADDRTREE_DEL_FOLDER_ADDR;
2781 else if( obj->type == ADDR_ITEM_GROUP ) {
2782 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2783 "The addresses it contains will not be lost."), obj->name);
2784 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2785 "+" GTK_STOCK_DELETE, NULL);
2787 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2789 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2790 "The addresses it contains will be lost."), obj->name);
2791 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2792 "+" GTK_STOCK_DELETE, NULL);
2794 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2796 if( delType == ADDRTREE_DEL_NONE ) return;
2798 /* Proceed with deletion */
2799 if( obj->type == ADDR_DATASOURCE ) {
2800 /* Remove node from tree */
2801 gtk_ctree_remove_node( ctree, node );
2803 /* Remove data source. */
2804 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2805 addrindex_free_datasource( ds );
2810 /* Get reference to cache */
2811 adbase = ( AddrBookBase * ) ds->rawDataSource;
2812 if( adbase == NULL ) return;
2813 cache = adbase->addressCache;
2815 /* Remove query results folder */
2816 if( iface->externalQuery ) {
2817 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2818 ItemFolder *folder = adapter->itemFolder;
2820 adapter->itemFolder = NULL;
2822 g_print( "remove folder for ::%s::\n", obj->name );
2823 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2824 g_print( "-------------- remove results\n" );
2826 addrindex_remove_results( ds, folder );
2827 /* g_print( "-------------- remove node\n" ); */
2828 gtk_ctree_remove_node( ctree, node );
2832 /* Code below is valid for regular address book deletion */
2833 if( obj->type == ADDR_ITEM_FOLDER ) {
2834 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2835 ItemFolder *item = adapter->itemFolder;
2837 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2838 /* Remove folder only */
2839 item = addrcache_remove_folder( cache, item );
2841 addritem_free_item_folder( item );
2842 addressbook_move_nodes_up( ctree, node );
2846 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2847 /* Remove folder and addresses */
2848 item = addrcache_remove_folder_delete( cache, item );
2850 addritem_free_item_folder( item );
2855 else if( obj->type == ADDR_ITEM_GROUP ) {
2856 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2857 ItemGroup *item = adapter->itemGroup;
2859 item = addrcache_remove_group( cache, item );
2861 addritem_free_item_group( item );
2868 gtk_ctree_remove_node(ctree, node );
2872 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2874 if( person && addrbook.treeSelected == addrbook.opened ) {
2875 person->status = ADD_ENTRY;
2876 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2877 addressbook_folder_refresh_one_person(
2878 GTK_CTREE(addrbook.clist), person );
2880 addressbook_address_list_set_focus();
2883 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2885 if( person && addrbook.treeSelected == addrbook.opened) {
2886 person->status = ADD_ENTRY;
2887 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2888 addressbook_set_clist(
2889 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2893 addressbook_address_list_set_focus();
2897 * Label (a format string) that is used to name each folder.
2899 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
2902 * Search ctree widget callback function.
2903 * \param pA Pointer to node.
2904 * \param pB Pointer to data item being sought.
2905 * \return Zero (0) if folder found.
2907 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
2910 aoA = ( AddressObject * ) pA;
2911 if( aoA->type == ADDR_ITEM_FOLDER ) {
2912 ItemFolder *folder, *fld;
2914 fld = ADAPTER_FOLDER(aoA)->itemFolder;
2915 folder = ( ItemFolder * ) pB;
2916 if( fld == folder ) return 0; /* Found folder */
2921 static ItemFolder * addressbook_setup_subf(
2922 AddressDataSource *ds, gchar *title,
2923 GtkCTreeNode *pNode )
2925 AddrBookBase *adbase;
2926 AddressCache *cache;
2929 GtkCTreeNode *nNode;
2931 AddressObjectType aoType = ADDR_NONE;
2934 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
2936 if( ds && ds->type == ADDR_IF_LDAP ) {
2938 aoType = ADDR_LDAP_QUERY;
2945 ctree = GTK_CTREE(addrbook.ctree);
2946 /* Get reference to address cache */
2947 adbase = ( AddrBookBase * ) ds->rawDataSource;
2948 cache = adbase->addressCache;
2950 if ((children = addrcache_get_list_folder(cache)) != NULL) {
2951 GList *cur = children;
2952 for (; cur; cur = cur->next) {
2953 ItemFolder *child = (ItemFolder *) cur->data;
2954 if (!strcmp2(ADDRITEM_NAME(child), title)) {
2955 nNode = gtk_ctree_find_by_row_data_custom(
2957 addressbook_treenode_find_folder_cb );
2959 addrindex_remove_results( ds, child );
2960 while( child->listPerson ) {
2961 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
2962 item = addrcache_remove_person( cache, item );
2964 addritem_free_item_person( item );
2968 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2969 addrbook.treeSelected = nNode;
2976 /* Create a folder */
2977 folder = addrcache_add_new_folder( cache, NULL );
2978 name = g_strdup_printf( "%s", title );
2979 addritem_folder_set_name( folder, name );
2980 addritem_folder_set_remarks( folder, "" );
2983 /* Now let's see the folder */
2984 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
2985 gtk_ctree_expand( ctree, pNode );
2987 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2988 addrbook.treeSelected = nNode;
2994 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2995 AddressObject *pobj = NULL;
2996 AddressDataSource *ds = NULL;
2997 AddressBookFile *abf = NULL;
2998 debug_print("adding address\n");
2999 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3000 if( pobj == NULL ) {
3001 debug_print("no row data\n");
3004 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3006 debug_print("no datasource\n");
3010 abf = ds->rawDataSource;
3012 g_print("no addressbook file\n");
3016 if( pobj->type == ADDR_DATASOURCE ) {
3017 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3018 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3020 ItemFolder *folder = NULL;
3022 if (abf && abf->type == ADDR_IF_LDAP) {
3023 GtkCTreeNode *parentNode;
3024 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3025 if( ds == NULL ) return;
3027 /* We must have a datasource that is an external interface */
3028 if( ! ds->interface->haveLibrary ) return;
3029 if( ! ds->interface->externalQuery ) return;
3031 if( pobj->type == ADDR_ITEM_FOLDER ) {
3032 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3035 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3037 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3039 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3040 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3041 abf = ds->rawDataSource;
3044 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3045 addrbook.editaddress_vbox,
3046 addressbook_new_address_from_book_post_cb,
3049 if (abf && abf->type == ADDR_IF_LDAP) {
3050 LdapServer *server = ds->rawDataSource;
3051 ldapsvr_set_modified(server, TRUE);
3052 ldapsvr_update_book(server, NULL);
3053 if (server->retVal != LDAPRC_SUCCESS) {
3054 alertpanel( _("Add address(es)"),
3055 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3056 GTK_STOCK_CLOSE, NULL, NULL );
3057 server->retVal = LDAPRC_SUCCESS;
3062 if (prefs_common.addressbook_use_editaddress_dialog)
3063 addressbook_new_address_from_book_post_cb( person );
3066 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3068 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3071 if (abf && abf->type == ADDR_IF_LDAP) {
3072 GtkCTreeNode *parentNode;
3073 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3074 if( ds == NULL ) return;
3076 /* We must have a datasource that is an external interface */
3077 if( ! ds->interface->haveLibrary ) return;
3078 if( ! ds->interface->externalQuery ) return;
3080 if( pobj->type == ADDR_ITEM_FOLDER ) {
3081 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3084 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3086 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3089 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3090 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3091 abf = ds->rawDataSource;
3094 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3095 addrbook.editaddress_vbox,
3096 addressbook_new_address_from_folder_post_cb,
3099 if (abf && abf->type == ADDR_IF_LDAP) {
3100 LdapServer *server = ds->rawDataSource;
3101 ldapsvr_set_modified(server, TRUE);
3102 ldapsvr_update_book(server, NULL);
3103 if (server->retVal != LDAPRC_SUCCESS) {
3104 alertpanel( _("Add address(es)"),
3105 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3106 GTK_STOCK_CLOSE, NULL, NULL );
3111 if (prefs_common.addressbook_use_editaddress_dialog)
3112 addressbook_new_address_from_folder_post_cb( person );
3114 else if( pobj->type == ADDR_ITEM_GROUP ) {
3115 /* New address in group */
3116 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3117 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3118 if (addrbook.treeSelected == addrbook.opened) {
3119 /* Change node name in tree. */
3120 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3121 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3122 addressbook_set_clist(
3123 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3131 * Search for specified child group node in address index tree.
3132 * \param parent Parent node.
3133 * \param group Group to find.
3135 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3136 GtkCTreeNode *node = NULL;
3137 GtkCTreeRow *currRow;
3139 currRow = GTK_CTREE_ROW( parent );
3141 node = currRow->children;
3145 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3146 if( obj->type == ADDR_ITEM_GROUP ) {
3147 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3148 if( g == group ) return node;
3150 currRow = GTK_CTREE_ROW(node);
3151 node = currRow->sibling;
3157 static AddressBookFile *addressbook_get_book_file() {
3158 AddressBookFile *abf = NULL;
3159 AddressDataSource *ds = NULL;
3161 ds = addressbook_find_datasource( addrbook.treeSelected );
3162 if( ds == NULL ) return NULL;
3163 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3167 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3171 /* Remove existing folders and groups */
3172 row = GTK_CTREE_ROW( parent );
3174 while( (node = row->children) ) {
3175 gtk_ctree_remove_node( ctree, node );
3180 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3181 GtkCTreeNode *parent, *child;
3182 GtkCTreeRow *currRow;
3183 currRow = GTK_CTREE_ROW( node );
3185 parent = currRow->parent;
3186 while( (child = currRow->children) ) {
3187 gtk_ctree_move( ctree, child, parent, node );
3189 gtk_sctree_sort_node( ctree, parent );
3193 static void addressbook_edit_address_post_cb( ItemPerson *person )
3197 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3198 invalidate_address_completion();
3200 addressbook_address_list_set_focus();
3203 void addressbook_address_list_set_focus( void )
3205 if (!prefs_common.addressbook_use_editaddress_dialog) {
3206 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3207 addressbook_list_menu_setup();
3211 void addressbook_address_list_disable_some_actions(void)
3213 /* disable address copy/pasting when editing contact's detail (embedded form) */
3214 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3215 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3216 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3218 /* we're already editing contact's detail here */
3219 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", FALSE );
3220 gtk_widget_set_sensitive( addrbook.edit_btn, FALSE );
3223 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3224 addressbook_edit_address(data, action, widget, TRUE);
3227 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3228 gboolean force_focus ) {
3229 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3231 AddressObject *obj = NULL, *pobj = NULL;
3232 AddressDataSource *ds = NULL;
3233 GtkCTreeNode *node = NULL, *parentNode = NULL;
3235 AddressBookFile *abf = NULL;
3237 if( addrbook.listSelected == NULL ) return;
3238 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3239 g_return_if_fail(obj != NULL);
3241 ctree = GTK_CTREE( addrbook.ctree );
3242 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3243 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3245 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3246 if( ds == NULL ) return;
3248 abf = addressbook_get_book_file();
3250 if( obj->type == ADDR_ITEM_EMAIL ) {
3251 ItemEMail *email = ( ItemEMail * ) obj;
3252 if( email == NULL ) return;
3253 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3254 /* Edit parent group */
3255 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3256 ItemGroup *itemGrp = adapter->itemGroup;
3257 if( abf == NULL ) return;
3258 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3259 name = ADDRITEM_NAME(itemGrp);
3260 node = addrbook.treeSelected;
3261 parentNode = GTK_CTREE_ROW(node)->parent;
3264 /* Edit person - email page */
3266 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3267 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3268 addressbook_edit_address_post_cb,
3269 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3272 if (abf && abf->type == ADDR_IF_LDAP) {
3273 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3274 person->status = UPDATE_ENTRY;
3277 if (prefs_common.addressbook_use_editaddress_dialog)
3278 addressbook_edit_address_post_cb( person );
3283 else if( obj->type == ADDR_ITEM_PERSON ) {
3284 /* Edit person - basic page */
3285 ItemPerson *person = ( ItemPerson * ) obj;
3286 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3287 addressbook_edit_address_post_cb,
3288 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3291 if (abf && abf->type == ADDR_IF_LDAP) {
3292 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3293 person->status = UPDATE_ENTRY;
3296 if (prefs_common.addressbook_use_editaddress_dialog)
3297 addressbook_edit_address_post_cb( person );
3301 else if( obj->type == ADDR_ITEM_GROUP ) {
3302 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3303 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3304 parentNode = addrbook.treeSelected;
3305 node = addressbook_find_group_node( parentNode, itemGrp );
3306 name = ADDRITEM_NAME(itemGrp);
3307 invalidate_address_completion();
3313 /* Update tree node with node name */
3314 if( node == NULL ) return;
3315 addressbook_change_node_name( node, name );
3316 gtk_sctree_sort_node( ctree, parentNode );
3317 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3318 addressbook_set_clist(
3319 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3324 static void addressbook_delete_address_cb(gpointer data, guint action,
3327 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3328 addressbook_del_clicked(NULL, NULL);
3329 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3332 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3334 addressbook_close();
3337 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3338 addressbook_export_to_file();
3341 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3343 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3344 if( person ) addritem_person_set_opened( person, TRUE );
3348 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3350 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3351 if( person ) addritem_person_set_opened( person, FALSE );
3355 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3357 gchar *eMailAlias = ADDRITEM_NAME(email);
3358 if( eMailAlias && *eMailAlias != '\0' ) {
3360 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3363 str = g_strdup( eMailAlias );
3369 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3370 GList *items = itemGroup->listEMail;
3371 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3372 for( ; items != NULL; items = g_list_next( items ) ) {
3373 GtkCTreeNode *nodeEMail = NULL;
3374 gchar *text[N_LIST_COLS];
3375 ItemEMail *email = items->data;
3379 if( ! email ) continue;
3381 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3382 str = addressbook_format_item_clist( person, email );
3384 text[COL_NAME] = str;
3387 text[COL_NAME] = ADDRITEM_NAME(person);
3389 text[COL_ADDRESS] = email->address;
3390 text[COL_REMARKS] = email->remarks;
3391 nodeEMail = gtk_sctree_insert_node(
3393 text, FOLDER_SPACING,
3394 atci->iconXpm, atci->maskXpm,
3395 atci->iconXpmOpen, atci->maskXpmOpen,
3397 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3403 static void addressbook_folder_load_one_person(
3404 GtkCTree *clist, ItemPerson *person,
3405 AddressTypeControlItem *atci,
3406 AddressTypeControlItem *atciMail )
3408 GtkCTreeNode *nodePerson = NULL;
3409 GtkCTreeNode *nodeEMail = NULL;
3410 gchar *text[N_LIST_COLS];
3411 gboolean flgFirst = TRUE, haveAddr = FALSE;
3414 AddressBookFile *abf = addressbook_get_book_file();
3417 if( person == NULL ) return;
3419 text[COL_NAME] = "";
3420 node = person->listEMail;
3422 ItemEMail *email = node->data;
3423 gchar *eMailAddr = NULL;
3424 node = g_list_next( node );
3426 text[COL_ADDRESS] = email->address;
3427 text[COL_REMARKS] = email->remarks;
3428 eMailAddr = ADDRITEM_NAME(email);
3429 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3431 /* First email belongs with person */
3432 gchar *str = addressbook_format_item_clist( person, email );
3434 text[COL_NAME] = str;
3437 else if( abf && abf->type == ADDR_IF_LDAP &&
3438 person && person->nickName ) {
3439 if (person->nickName) {
3440 if (strcmp(person->nickName, "") != 0) {
3441 text[COL_NAME] = person->nickName;
3444 text[COL_NAME] = ADDRITEM_NAME(person);
3450 text[COL_NAME] = ADDRITEM_NAME(person);
3452 nodePerson = gtk_sctree_insert_node(
3454 text, FOLDER_SPACING,
3455 atci->iconXpm, atci->maskXpm,
3456 atci->iconXpmOpen, atci->maskXpmOpen,
3457 FALSE, person->isOpened );
3460 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3463 /* Subsequent email is a child node of person */
3464 text[COL_NAME] = ADDRITEM_NAME(email);
3465 nodeEMail = gtk_sctree_insert_node(
3466 clist, nodePerson, NULL,
3467 text, FOLDER_SPACING,
3468 atciMail->iconXpm, atciMail->maskXpm,
3469 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3471 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3477 /* Have name without EMail */
3478 text[COL_NAME] = ADDRITEM_NAME(person);
3479 text[COL_ADDRESS] = "";
3480 text[COL_REMARKS] = "";
3481 nodePerson = gtk_sctree_insert_node(
3483 text, FOLDER_SPACING,
3484 atci->iconXpm, atci->maskXpm,
3485 atci->iconXpmOpen, atci->maskXpmOpen,
3486 FALSE, person->isOpened );
3487 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3492 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3494 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3495 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3497 if( atci == NULL ) return;
3498 if( atciMail == NULL ) return;
3500 /* Load email addresses */
3501 items = addritem_folder_get_person_list( itemFolder );
3502 for( ; items != NULL; items = g_list_next( items ) ) {
3503 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3505 /* Free up the list */
3506 mgu_clear_list( items );
3507 g_list_free( items );
3510 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3511 addrbook.listSelected = NULL;
3512 gtk_ctree_remove_node( clist, node );
3513 addressbook_menubar_set_sensitive( FALSE );
3514 addressbook_menuitem_set_sensitive(
3515 gtk_ctree_node_get_row_data(
3516 GTK_CTREE(clist), addrbook.treeSelected ),
3517 addrbook.treeSelected );
3520 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3521 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3522 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3524 if( atci == NULL ) return;
3525 if( atciMail == NULL ) return;
3526 if( person == NULL ) return;
3527 /* unload the person */
3529 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3531 addressbook_folder_remove_node( clist, node );
3532 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3533 gtk_sctree_sort_node( clist, NULL );
3534 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3536 gtk_sctree_select( GTK_SCTREE(clist), node );
3537 if (!gtk_ctree_node_is_visible( clist, node ) )
3538 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3542 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3546 if( person == NULL ) return;
3547 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3548 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3550 addressbook_folder_remove_node( clist, node );
3554 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3556 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3558 /* Load any groups */
3559 if( ! atci ) return;
3560 items = addritem_folder_get_group_list( itemFolder );
3561 for( ; items != NULL; items = g_list_next( items ) ) {
3562 GtkCTreeNode *nodeGroup = NULL;
3563 gchar *text[N_LIST_COLS];
3564 ItemGroup *group = items->data;
3565 if( group == NULL ) continue;
3566 text[COL_NAME] = ADDRITEM_NAME(group);
3567 text[COL_ADDRESS] = "";
3568 text[COL_REMARKS] = "";
3569 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3570 text, FOLDER_SPACING,
3571 atci->iconXpm, atci->maskXpm,
3572 atci->iconXpmOpen, atci->maskXpmOpen,
3574 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3575 gtk_sctree_sort_node(clist, NULL);
3577 /* Free up the list */
3578 mgu_clear_list( items );
3579 g_list_free( items );
3583 * Search ctree widget callback function.
3584 * \param pA Pointer to node.
3585 * \param pB Pointer to data item being sought.
3586 * \return Zero (0) if group found.
3588 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3591 aoA = ( AddressObject * ) pA;
3592 if( aoA->type == ADDR_ITEM_GROUP ) {
3593 ItemGroup *group, *grp;
3595 grp = ADAPTER_GROUP(aoA)->itemGroup;
3596 group = ( ItemGroup * ) pB;
3597 if( grp == group ) return 0; /* Found group */
3603 * Remove folder and group nodes from tree widget for items contained ("cut")
3606 static void addressbook_treenode_remove_item( void ) {
3608 AddrSelectItem *cutItem;
3609 AddressCache *cache;
3610 AddrItemObject *aio;
3611 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3614 node = _clipBoard_->objectList;
3616 cutItem = node->data;
3617 node = g_list_next( node );
3618 cache = addrindex_get_cache(
3619 _clipBoard_->addressIndex, cutItem->cacheID );
3620 if( cache == NULL ) continue;
3621 aio = addrcache_get_object( cache, cutItem->uid );
3624 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3627 folder = ( ItemFolder * ) aio;
3628 tn = gtk_ctree_find_by_row_data_custom(
3629 ctree, NULL, folder,
3630 addressbook_treenode_find_folder_cb );
3632 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3635 group = ( ItemGroup * ) aio;
3636 tn = gtk_ctree_find_by_row_data_custom(
3638 addressbook_treenode_find_group_cb );
3642 /* Free up adapter and remove node. */
3643 gtk_ctree_remove_node( ctree, tn );
3650 * Find parent datasource for specified tree node.
3651 * \param node Node to test.
3652 * \return Data source, or NULL if not found.
3654 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3655 AddressDataSource *ds = NULL;
3658 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3661 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3662 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3664 /* g_print( "ao->type = %d\n", ao->type ); */
3665 if( ao->type == ADDR_DATASOURCE ) {
3666 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3667 /* g_print( "found it\n" ); */
3668 ds = ads->dataSource;
3672 node = GTK_CTREE_ROW(node)->parent;
3678 * Load address list widget with children of specified object.
3679 * \param obj Parent object to be loaded.
3681 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3682 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3683 GtkCList *clist = GTK_CLIST(addrbook.clist);
3684 AddressDataSource *ds = NULL;
3685 AdapterDSource *ads = NULL;
3686 static AddressObject *last_obj = NULL;
3688 if (addrbook.clist == NULL) {
3691 if (obj == last_obj && !refresh)
3696 gtk_clist_clear(clist);
3700 if( obj->type == ADDR_INTERFACE ) {
3701 /* g_print( "set_clist: loading datasource...\n" ); */
3702 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3706 gtk_clist_freeze(clist);
3707 gtk_clist_clear(clist);
3709 if( obj->type == ADDR_DATASOURCE ) {
3710 ads = ADAPTER_DSOURCE(obj);
3711 ds = ADAPTER_DSOURCE(obj)->dataSource;
3713 /* Load root folder */
3714 ItemFolder *rootFolder = NULL;
3715 rootFolder = addrindex_ds_get_root_folder( ds );
3716 addressbook_folder_load_person(
3717 ctreelist, addrindex_ds_get_root_folder( ds ) );
3718 addressbook_folder_load_group(
3719 ctreelist, addrindex_ds_get_root_folder( ds ) );
3723 if( obj->type == ADDR_ITEM_GROUP ) {
3725 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3726 addressbook_load_group( ctreelist, itemGroup );
3728 else if( obj->type == ADDR_ITEM_FOLDER ) {
3730 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3731 addressbook_folder_load_person( ctreelist, itemFolder );
3732 addressbook_folder_load_group( ctreelist, itemFolder );
3735 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3736 clist->focus_row = -1;
3737 gtk_clist_thaw(clist);
3741 * Call back function to free adaptor. Call back is setup by function
3742 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3743 * called when the address book tree widget node is removed by calling
3744 * function gtk_ctree_remove_node().
3746 * \param data Tree node's row data.
3748 static void addressbook_free_treenode( gpointer data ) {
3751 ao = ( AddressObject * ) data;
3752 if( ao == NULL ) return;
3753 if( ao->type == ADDR_INTERFACE ) {
3754 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3755 addrbookctl_free_interface( ai );
3757 else if( ao->type == ADDR_DATASOURCE ) {
3758 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3759 addrbookctl_free_datasource( ads );
3761 else if( ao->type == ADDR_ITEM_FOLDER ) {
3762 AdapterFolder *af = ADAPTER_FOLDER(ao);
3763 addrbookctl_free_folder( af );
3765 else if( ao->type == ADDR_ITEM_GROUP ) {
3766 AdapterGroup *ag = ADAPTER_GROUP(ao);
3767 addrbookctl_free_group( ag );
3772 * Create new adaptor for specified data source.
3774 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3775 AddressObjectType otype, gchar *name )
3777 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3778 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3779 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3780 adapter->dataSource = ds;
3781 adapter->subType = otype;
3785 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3786 ADDRESS_OBJECT_NAME(adapter) =
3787 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3791 * Load tree from address index with the initial data.
3793 static void addressbook_load_tree( void ) {
3794 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3795 GList *nodeIf, *nodeDS;
3796 AdapterInterface *adapter;
3797 AddressInterface *iface;
3798 AddressTypeControlItem *atci;
3799 AddressDataSource *ds;
3800 AdapterDSource *ads;
3801 GtkCTreeNode *node, *newNode;
3804 nodeIf = _addressInterfaceList_;
3806 adapter = nodeIf->data;
3807 node = adapter->treeNode;
3808 iface = adapter->interface;
3809 atci = adapter->atci;
3811 if( iface->useInterface ) {
3812 /* Load data sources below interface node */
3813 nodeDS = iface->listSource;
3817 name = addrindex_ds_get_name( ds );
3818 ads = addressbook_create_ds_adapter(
3819 ds, atci->objectType, name );
3820 newNode = addressbook_add_object(
3821 node, ADDRESS_OBJECT(ads) );
3822 nodeDS = g_list_next( nodeDS );
3824 gtk_ctree_expand( ctree, node );
3827 nodeIf = g_list_next( nodeIf );
3832 * Convert the old address book to new format.
3834 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3835 gboolean retVal = FALSE;
3836 gboolean errFlag = TRUE;
3839 /* Read old address book, performing conversion */
3840 debug_print( "Reading and converting old address book...\n" );
3841 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3842 addrindex_read_data( addrIndex );
3843 if( addrIndex->retVal == MGU_NO_FILE ) {
3844 /* We do not have a file - new user */
3845 debug_print( "New user... create new books...\n" );
3846 addrindex_create_new_books( addrIndex );
3847 if( addrIndex->retVal == MGU_SUCCESS ) {
3848 /* Save index file */
3849 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3850 addrindex_save_data( addrIndex );
3851 if( addrIndex->retVal == MGU_SUCCESS ) {
3856 msg = _( "New user, could not save index file." );
3860 msg = _( "New user, could not save address book files." );
3864 /* We have an old file */
3865 if( addrIndex->wasConverted ) {
3866 /* Converted successfully - save address index */
3867 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3868 addrindex_save_data( addrIndex );
3869 if( addrIndex->retVal == MGU_SUCCESS ) {
3870 msg = _( "Old address book converted successfully." );
3875 msg = _("Old address book converted,\n"
3876 "could not save new address index file." );
3880 /* File conversion failed - just create new books */
3881 debug_print( "File conversion failed... just create new books...\n" );
3882 addrindex_create_new_books( addrIndex );
3883 if( addrIndex->retVal == MGU_SUCCESS ) {
3885 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3886 addrindex_save_data( addrIndex );
3887 if( addrIndex->retVal == MGU_SUCCESS ) {
3888 msg = _("Could not convert address book,\n"
3889 "but created empty new address book files." );
3894 msg = _("Could not convert address book,\n"
3895 "could not save new address index file." );
3899 msg = _("Could not convert address book\n"
3900 "and could not create new address book files." );
3905 debug_print( "Error\n%s\n", msg );
3906 alertpanel_full(_("Addressbook conversion error"), msg,
3907 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3908 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3911 debug_print( "Warning\n%s\n", msg );
3912 alertpanel_full(_("Addressbook conversion error"), msg,
3913 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3914 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3920 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
3924 gboolean failed = FALSE;
3926 if( ( dp = opendir( origdir ) ) == NULL ) {
3930 while( ( d = readdir( dp ) ) != NULL ) {
3931 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3934 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
3936 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
3938 if (copy_file(orig_file, dest_file, FALSE) < 0) {
3951 /* all copies succeeded, we can remove source files */
3952 if( ( dp = opendir( origdir ) ) == NULL ) {
3955 while( ( d = readdir( dp ) ) != NULL ) {
3956 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3959 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
3961 g_unlink(orig_file);
3971 void addressbook_read_file( void ) {
3972 AddressIndex *addrIndex = NULL;
3973 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
3975 debug_print( "Reading address index...\n" );
3976 if( _addressIndex_ ) {
3977 debug_print( "address book already read!!!\n" );
3981 addrIndex = addrindex_create_index();
3982 addrindex_initialize();
3984 /* Use new address book index. */
3986 if ( !is_dir_exist(indexdir) ) {
3987 if ( make_dir(indexdir) < 0 ) {
3988 addrindex_set_file_path( addrIndex, get_rc_dir() );
3989 g_warning( "couldn't create dir %s\n", indexdir);
3991 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
3992 remove_dir_recursive(indexdir);
3993 addrindex_set_file_path( addrIndex, get_rc_dir() );
3994 g_error("couldn't migrate dir %s", indexdir);
3996 addrindex_set_file_path( addrIndex, indexdir);
4000 addrindex_set_file_path( addrIndex, indexdir);
4003 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4004 addrindex_read_data( addrIndex );
4005 if( addrIndex->retVal == MGU_NO_FILE ) {
4006 /* Conversion required */
4007 debug_print( "Converting...\n" );
4008 if( addressbook_convert( addrIndex ) ) {
4009 _addressIndex_ = addrIndex;
4012 else if( addrIndex->retVal == MGU_SUCCESS ) {
4013 _addressIndex_ = addrIndex;
4016 /* Error reading address book */
4017 debug_print( "Could not read address index.\n" );
4018 addrindex_print_index( addrIndex, stdout );
4019 alertpanel_full(_("Addressbook Error"),
4020 _("Could not read address index"),
4021 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4022 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4024 debug_print( "done.\n" );
4028 * Add object into the address index tree widget.
4029 * Enter: node Parent node.
4030 * obj Object to add.
4031 * Return: Node that was added, or NULL if object not added.
4033 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
4036 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4037 GtkCTreeNode *added;
4038 AddressObject *pobj;
4039 AddressObjectType otype;
4040 AddressTypeControlItem *atci = NULL;
4042 g_return_val_if_fail(node != NULL, NULL);
4043 g_return_val_if_fail(obj != NULL, NULL);
4045 pobj = gtk_ctree_node_get_row_data(ctree, node);
4046 g_return_val_if_fail(pobj != NULL, NULL);
4048 /* Determine object type to be displayed */
4049 if( obj->type == ADDR_DATASOURCE ) {
4050 otype = ADAPTER_DSOURCE(obj)->subType;
4056 /* Handle any special conditions. */
4058 atci = addrbookctl_lookup( otype );
4060 if( atci->showInTree ) {
4061 /* Add object to tree */
4064 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4065 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4066 atci->treeLeaf, atci->treeExpand );
4067 gtk_ctree_node_set_row_data_full( ctree, added, obj,
4068 addressbook_free_treenode );
4072 gtk_sctree_sort_node(ctree, node);
4078 * Add group into the address index tree.
4079 * \param node Parent node.
4080 * \param ds Data source.
4081 * \param itemGroup Group to add.
4082 * \return Inserted node.
4084 static GtkCTreeNode *addressbook_node_add_group(
4085 GtkCTreeNode *node, AddressDataSource *ds,
4086 ItemGroup *itemGroup )
4088 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4089 GtkCTreeNode *newNode;
4090 AdapterGroup *adapter;
4091 AddressTypeControlItem *atci = NULL;
4094 if( ds == NULL ) return NULL;
4095 if( node == NULL || itemGroup == NULL ) return NULL;
4097 name = &itemGroup->obj.name;
4099 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4101 adapter = g_new0( AdapterGroup, 1 );
4102 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4103 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4104 adapter->itemGroup = itemGroup;
4106 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4107 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4108 atci->treeLeaf, atci->treeExpand );
4109 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4110 addressbook_free_treenode );
4111 gtk_sctree_sort_node( ctree, node );
4116 * Add folder into the address index tree. Only visible folders are loaded into
4117 * the address index tree. Note that the root folder is not inserted into the
4120 * \param node Parent node.
4121 * \param ds Data source.
4122 * \param itemFolder Folder to add.
4123 * \param otype Object type to display.
4124 * \return Inserted node for the folder.
4126 static GtkCTreeNode *addressbook_node_add_folder(
4127 GtkCTreeNode *node, AddressDataSource *ds,
4128 ItemFolder *itemFolder, AddressObjectType otype )
4130 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4131 GtkCTreeNode *newNode = NULL;
4132 AdapterFolder *adapter;
4133 AddressTypeControlItem *atci = NULL;
4134 GList *listItems = NULL;
4136 ItemFolder *rootFolder;
4138 /* Only visible folders */
4139 if( itemFolder->isHidden ) return NULL;
4141 if( ds == NULL ) return NULL;
4142 if( node == NULL || itemFolder == NULL ) return NULL;
4144 /* Determine object type */
4145 atci = addrbookctl_lookup( otype );
4146 if( atci == NULL ) return NULL;
4148 rootFolder = addrindex_ds_get_root_folder( ds );
4149 if( itemFolder == rootFolder ) {
4153 adapter = g_new0( AdapterFolder, 1 );
4154 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4155 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4156 adapter->itemFolder = itemFolder;
4158 name = ADDRITEM_NAME(itemFolder);
4159 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4160 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4161 atci->treeLeaf, atci->treeExpand );
4163 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4164 addressbook_free_treenode );
4168 listItems = itemFolder->listFolder;
4169 while( listItems ) {
4170 ItemFolder *item = listItems->data;
4171 addressbook_node_add_folder( newNode, ds, item, otype );
4172 listItems = g_list_next( listItems );
4174 listItems = itemFolder->listGroup;
4175 while( listItems ) {
4176 ItemGroup *item = listItems->data;
4177 addressbook_node_add_group( newNode, ds, item );
4178 listItems = g_list_next( listItems );
4180 gtk_sctree_sort_node( ctree, node );
4184 void addressbook_export_to_file( void ) {
4185 if( _addressIndex_ ) {
4186 /* Save all new address book data */
4187 debug_print( "Saving address books...\n" );
4188 addrindex_save_all_books( _addressIndex_ );
4190 debug_print( "Exporting addressbook to file...\n" );
4191 addrindex_save_data( _addressIndex_ );
4192 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4193 addrindex_print_index( _addressIndex_, stdout );
4196 /* Notify address completion of new data */
4197 invalidate_address_completion();
4201 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4203 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4204 addressbook_lup_clicked(NULL, NULL);
4209 * Comparison using cell contents (text in first column). Used for sort
4210 * address index widget.
4212 static gint addressbook_treenode_compare_func(
4213 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4215 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4216 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4217 gchar *name1 = NULL, *name2 = NULL;
4218 if( cell1 ) name1 = cell1->u.text;
4219 if( cell2 ) name2 = cell2->u.text;
4220 if( ! name1 ) return ( name2 != NULL );
4221 if( ! name2 ) return -1;
4222 return g_utf8_collate( name1, name2 );
4225 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4226 AdapterDSource *ads;
4227 AdapterInterface *adapter;
4228 GtkCTreeNode *newNode;
4230 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4231 if( adapter == NULL ) return;
4232 ads = addressbook_edit_book( _addressIndex_, NULL );
4234 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4236 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4237 addrbook.treeSelected = newNode;
4242 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4243 AdapterDSource *ads;
4244 AdapterInterface *adapter;
4245 GtkCTreeNode *newNode;
4247 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4248 if( adapter == NULL ) return;
4249 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4251 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4253 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4254 addrbook.treeSelected = newNode;
4260 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4261 AdapterDSource *ads;
4262 AdapterInterface *adapter;
4263 AddressInterface *iface;
4264 GtkCTreeNode *newNode;
4266 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4267 if( adapter == NULL ) return;
4268 iface = adapter->interface;
4269 if( ! iface->haveLibrary ) return;
4270 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4272 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4274 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4275 addrbook.treeSelected = newNode;
4282 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4283 AdapterDSource *ads;
4284 AdapterInterface *adapter;
4285 AddressInterface *iface;
4286 GtkCTreeNode *newNode;
4288 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4289 if( adapter == NULL ) return;
4290 iface = adapter->interface;
4291 if( ! iface->haveLibrary ) return;
4292 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4294 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4296 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4297 addrbook.treeSelected = newNode;
4304 * Display address search status message.
4305 * \param queryType Query type.
4306 * \param status Status/Error code.
4308 static void addressbook_search_message( gint queryType, gint sts ) {
4310 *addressbook_msgbuf = '\0';
4312 if( sts != MGU_SUCCESS ) {
4313 if( queryType == ADDRQUERY_LDAP ) {
4315 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4320 g_snprintf( addressbook_msgbuf,
4321 sizeof(addressbook_msgbuf), "%s", desc );
4322 addressbook_status_show( addressbook_msgbuf );
4325 addressbook_status_show( "" );
4330 * Refresh addressbook by forcing refresh of current selected object in
4333 static void addressbook_refresh_current( void ) {
4337 ctree = GTK_CTREE(addrbook.ctree);
4338 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4339 if( obj == NULL ) return;
4340 addressbook_set_clist( obj, TRUE );
4344 * Message that is displayed whilst a query is executing in a background
4347 static gchar *_tempMessage_ = N_( "Busy searching..." );
4350 * Address search idle function. This function is called during UI idle time
4351 * while a search is in progress.
4353 * \param data Idler data.
4355 static void addressbook_search_idle( gpointer data ) {
4359 queryID = GPOINTER_TO_INT( data );
4360 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4365 * Search completion callback function. This removes the query from the idle
4368 * \param sender Sender of query.
4369 * \param queryID Query ID of search request.
4370 * \param status Search status.
4371 * \param data Query data.
4373 static void addressbook_search_callback_end(
4374 gpointer sender, gint queryID, gint status, gpointer data )
4378 AddrQueryObject *aqo;
4380 /* Remove idler function */
4381 ptrQID = GINT_TO_POINTER( queryID );
4383 g_idle_remove_by_data( ptrQID );
4386 /* Refresh addressbook contents */
4387 addressbook_refresh_current();
4388 req = qrymgr_find_request( queryID );
4390 aqo = ( AddrQueryObject * ) req->queryList->data;
4391 addressbook_search_message( aqo->queryType, status );
4394 /* Stop the search */
4395 addrindex_stop_search( queryID );
4401 * \param ds Data source to search.
4402 * \param searchTerm String to lookup.
4403 * \param pNode Parent data source node.
4405 static void addressbook_perform_search(
4406 AddressDataSource *ds, gchar *searchTerm,
4407 GtkCTreeNode *pNode )
4409 AddrBookBase *adbase;
4410 AddressCache *cache;
4416 AddressObjectType aoType = ADDR_NONE;
4420 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4422 if( ds && ds->type == ADDR_IF_LDAP ) {
4424 aoType = ADDR_LDAP_QUERY;
4430 /* Get reference to address cache */
4431 adbase = ( AddrBookBase * ) ds->rawDataSource;
4432 cache = adbase->addressCache;
4434 /* Create a folder for the search results */
4435 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4436 folder = addressbook_setup_subf(ds, name, pNode);
4439 /* Setup the search */
4440 queryID = addrindex_setup_explicit_search(
4441 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4442 if( queryID == 0 ) return;
4444 /* Set up idler function */
4445 idleID = g_idle_add(
4446 ( GtkFunction ) addressbook_search_idle,
4447 GINT_TO_POINTER( queryID ) );
4449 /* Start search, sit back and wait for something to happen */
4450 addrindex_start_search( queryID );
4452 addressbook_status_show( _tempMessage_ );
4456 * Lookup button handler. Address search is only performed against
4457 * address interfaces for external queries.
4459 * \param button Lookup button widget.
4460 * \param data Data object.
4462 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4465 AddressDataSource *ds;
4466 AddressInterface *iface;
4468 GtkCTreeNode *node, *parentNode;
4470 node = addrbook.treeSelected;
4471 if( ! node ) return;
4472 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4474 ctree = GTK_CTREE(addrbook.ctree);
4475 obj = gtk_ctree_node_get_row_data( ctree, node );
4476 if( obj == NULL ) return;
4478 ds = addressbook_find_datasource( node );
4479 if( ds == NULL ) return;
4481 /* We must have a datasource that is an external interface */
4482 iface = ds->interface;
4483 if( ! iface->haveLibrary ) return;
4484 if( ! iface->externalQuery ) return;
4487 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4488 g_strchomp( searchTerm );
4490 if( obj->type == ADDR_ITEM_FOLDER ) {
4491 parentNode = GTK_CTREE_ROW(node)->parent;
4496 addressbook_perform_search( ds, searchTerm, parentNode );
4498 gtk_widget_grab_focus( addrbook.entry );
4500 g_free( searchTerm );
4503 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4504 addressbook_close();
4509 * Browse address entry for highlighted entry.
4511 static void addressbook_browse_entry_cb(void)
4513 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4515 AddressDataSource *ds;
4516 AddressInterface *iface;
4520 if(addrbook.listSelected == NULL)
4523 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4527 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4531 iface = ds->interface;
4532 if(! iface->haveLibrary )
4536 if (obj->type == ADDR_ITEM_EMAIL) {
4537 email = ( ItemEMail * ) obj;
4541 person = (ItemPerson *) ADDRITEM_PARENT(email);
4543 else if (obj->type == ADDR_ITEM_PERSON) {
4544 person = (ItemPerson *) obj;
4551 if( iface && iface->type == ADDR_IF_LDAP ) {
4552 browseldap_entry(ds, person->externalID);
4557 /* **********************************************************************
4558 * Build lookup tables.
4559 * ***********************************************************************
4563 * Remap object types.
4564 * Enter: abType AddressObjectType (used in tree node).
4565 * Return: ItemObjectType (used in address cache data).
4567 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4568 ItemObjectType ioType;
4571 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4572 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4573 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4574 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4575 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4576 default: ioType = ITEMTYPE_NONE; break;
4582 * Build table that controls the rendering of object types.
4584 static void addrbookctl_build_map( GtkWidget *window ) {
4585 AddressTypeControlItem *atci;
4588 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4589 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4590 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4591 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4592 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4593 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4594 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4595 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4596 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4597 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4599 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4600 _addressBookTypeList_ = NULL;
4603 atci = g_new0( AddressTypeControlItem, 1 );
4604 atci->objectType = ADDR_INTERFACE;
4605 atci->interfaceType = ADDR_IF_NONE;
4606 atci->showInTree = TRUE;
4607 atci->treeExpand = TRUE;
4608 atci->treeLeaf = FALSE;
4609 atci->displayName = _( "Interface" );
4610 atci->iconXpm = folderxpm;
4611 atci->maskXpm = folderxpmmask;
4612 atci->iconXpmOpen = folderopenxpm;
4613 atci->maskXpmOpen = folderopenxpmmask;
4614 atci->menuCommand = NULL;
4615 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4616 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4619 atci = g_new0( AddressTypeControlItem, 1 );
4620 atci->objectType = ADDR_BOOK;
4621 atci->interfaceType = ADDR_IF_BOOK;
4622 atci->showInTree = TRUE;
4623 atci->treeExpand = TRUE;
4624 atci->treeLeaf = FALSE;
4625 atci->displayName = _( "Address Book" );
4626 atci->iconXpm = bookxpm;
4627 atci->maskXpm = bookxpmmask;
4628 atci->iconXpmOpen = bookxpm;
4629 atci->maskXpmOpen = bookxpmmask;
4630 atci->menuCommand = "/Book/New Book";
4631 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4632 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4635 atci = g_new0( AddressTypeControlItem, 1 );
4636 atci->objectType = ADDR_ITEM_PERSON;
4637 atci->interfaceType = ADDR_IF_NONE;
4638 atci->showInTree = FALSE;
4639 atci->treeExpand = FALSE;
4640 atci->treeLeaf = FALSE;
4641 atci->displayName = _( "Person" );
4642 atci->iconXpm = NULL;
4643 atci->maskXpm = NULL;
4644 atci->iconXpmOpen = NULL;
4645 atci->maskXpmOpen = NULL;
4646 atci->menuCommand = NULL;
4647 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4648 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4651 atci = g_new0( AddressTypeControlItem, 1 );
4652 atci->objectType = ADDR_ITEM_EMAIL;
4653 atci->interfaceType = ADDR_IF_NONE;
4654 atci->showInTree = FALSE;
4655 atci->treeExpand = FALSE;
4656 atci->treeLeaf = TRUE;
4657 atci->displayName = _( "EMail Address" );
4658 atci->iconXpm = addressxpm;
4659 atci->maskXpm = addressxpmmask;
4660 atci->iconXpmOpen = addressxpm;
4661 atci->maskXpmOpen = addressxpmmask;
4662 atci->menuCommand = NULL;
4663 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4664 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4667 atci = g_new0( AddressTypeControlItem, 1 );
4668 atci->objectType = ADDR_ITEM_GROUP;
4669 atci->interfaceType = ADDR_IF_BOOK;
4670 atci->showInTree = TRUE;
4671 atci->treeExpand = FALSE;
4672 atci->treeLeaf = FALSE;
4673 atci->displayName = _( "Group" );
4674 atci->iconXpm = groupxpm;
4675 atci->maskXpm = groupxpmmask;
4676 atci->iconXpmOpen = groupxpm;
4677 atci->maskXpmOpen = groupxpmmask;
4678 atci->menuCommand = NULL;
4679 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4680 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4683 atci = g_new0( AddressTypeControlItem, 1 );
4684 atci->objectType = ADDR_ITEM_FOLDER;
4685 atci->interfaceType = ADDR_IF_BOOK;
4686 atci->showInTree = TRUE;
4687 atci->treeExpand = FALSE;
4688 atci->treeLeaf = FALSE;
4689 atci->displayName = _( "Folder" );
4690 atci->iconXpm = folderxpm;
4691 atci->maskXpm = folderxpmmask;
4692 atci->iconXpmOpen = folderopenxpm;
4693 atci->maskXpmOpen = folderopenxpmmask;
4694 atci->menuCommand = NULL;
4695 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4696 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4699 atci = g_new0( AddressTypeControlItem, 1 );
4700 atci->objectType = ADDR_VCARD;
4701 atci->interfaceType = ADDR_IF_VCARD;
4702 atci->showInTree = TRUE;
4703 atci->treeExpand = TRUE;
4704 atci->treeLeaf = TRUE;
4705 atci->displayName = _( "vCard" );
4706 atci->iconXpm = vcardxpm;
4707 atci->maskXpm = vcardxpmmask;
4708 atci->iconXpmOpen = vcardxpm;
4709 atci->maskXpmOpen = vcardxpmmask;
4710 atci->menuCommand = "/Book/New vCard";
4711 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4712 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4715 atci = g_new0( AddressTypeControlItem, 1 );
4716 atci->objectType = ADDR_JPILOT;
4717 atci->interfaceType = ADDR_IF_JPILOT;
4718 atci->showInTree = TRUE;
4719 atci->treeExpand = TRUE;
4720 atci->treeLeaf = FALSE;
4721 atci->displayName = _( "JPilot" );
4722 atci->iconXpm = jpilotxpm;
4723 atci->maskXpm = jpilotxpmmask;
4724 atci->iconXpmOpen = jpilotxpm;
4725 atci->maskXpmOpen = jpilotxpmmask;
4726 atci->menuCommand = "/Book/New JPilot";
4727 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4728 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4731 atci = g_new0( AddressTypeControlItem, 1 );
4732 atci->objectType = ADDR_CATEGORY;
4733 atci->interfaceType = ADDR_IF_JPILOT;
4734 atci->showInTree = TRUE;
4735 atci->treeExpand = TRUE;
4736 atci->treeLeaf = TRUE;
4737 atci->displayName = _( "JPilot" );
4738 atci->iconXpm = categoryxpm;
4739 atci->maskXpm = categoryxpmmask;
4740 atci->iconXpmOpen = categoryxpm;
4741 atci->maskXpmOpen = categoryxpmmask;
4742 atci->menuCommand = NULL;
4743 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4744 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4747 atci = g_new0( AddressTypeControlItem, 1 );
4748 atci->objectType = ADDR_LDAP;
4749 atci->interfaceType = ADDR_IF_LDAP;
4750 atci->showInTree = TRUE;
4751 atci->treeExpand = TRUE;
4752 atci->treeLeaf = FALSE;
4753 atci->displayName = _( "LDAP servers" );
4754 atci->iconXpm = ldapxpm;
4755 atci->maskXpm = ldapxpmmask;
4756 atci->iconXpmOpen = ldapxpm;
4757 atci->maskXpmOpen = ldapxpmmask;
4758 atci->menuCommand = "/Book/New LDAP Server";
4759 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4760 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4763 atci = g_new0( AddressTypeControlItem, 1 );
4764 atci->objectType = ADDR_LDAP_QUERY;
4765 atci->interfaceType = ADDR_IF_LDAP;
4766 atci->showInTree = TRUE;
4767 atci->treeExpand = FALSE;
4768 atci->treeLeaf = TRUE;
4769 atci->displayName = _( "LDAP Query" );
4770 atci->iconXpm = addrsearchxpm;
4771 atci->maskXpm = addrsearchxpmmask;
4772 atci->iconXpmOpen = addrsearchxpm;
4773 atci->maskXpmOpen = addrsearchxpmmask;
4774 atci->menuCommand = NULL;
4775 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4776 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4781 * Search for specified object type.
4783 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4785 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4789 * Search for specified interface type.
4791 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4792 GList *node = _addressBookTypeList_;
4794 AddressTypeControlItem *atci = node->data;
4795 if( atci->interfaceType == ifType ) return atci;
4796 node = g_list_next( node );
4801 static void addrbookctl_free_address( AddressObject *obj ) {
4802 g_free( obj->name );
4803 obj->type = ADDR_NONE;
4807 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4808 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4809 adapter->interface = NULL;
4810 adapter->interfaceType = ADDR_IF_NONE;
4811 adapter->atci = NULL;
4812 adapter->enabled = FALSE;
4813 adapter->haveLibrary = FALSE;
4814 adapter->treeNode = NULL;
4818 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4819 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4820 adapter->dataSource = NULL;
4821 adapter->subType = ADDR_NONE;
4825 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4826 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4827 adapter->itemFolder = NULL;
4831 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4832 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4833 adapter->itemGroup = NULL;
4838 * Build GUI interface list.
4840 static void addrbookctl_build_iflist( void ) {
4841 AddressTypeControlItem *atci;
4842 AdapterInterface *adapter;
4845 if( _addressIndex_ == NULL ) {
4846 _addressIndex_ = addrindex_create_index();
4847 if( _clipBoard_ == NULL ) {
4848 _clipBoard_ = addrclip_create();
4850 addrclip_set_index( _clipBoard_, _addressIndex_ );
4852 _addressInterfaceList_ = NULL;
4853 list = addrindex_get_interface_list( _addressIndex_ );
4855 AddressInterface *interface = list->data;
4856 atci = addrbookctl_lookup_iface( interface->type );
4858 adapter = g_new0( AdapterInterface, 1 );
4859 adapter->interfaceType = interface->type;
4860 adapter->atci = atci;
4861 adapter->interface = interface;
4862 adapter->treeNode = NULL;
4863 adapter->enabled = TRUE;
4864 adapter->haveLibrary = interface->haveLibrary;
4865 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4866 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4867 _addressInterfaceList_ =
4868 g_list_append( _addressInterfaceList_, adapter );
4870 list = g_list_next( list );
4875 * Find GUI interface type specified interface type.
4876 * \param ifType Interface type.
4877 * \return Interface item, or NULL if not found.
4879 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4880 GList *node = _addressInterfaceList_;
4882 AdapterInterface *adapter = node->data;
4883 if( adapter->interfaceType == ifType ) return adapter;
4884 node = g_list_next( node );
4890 * Build interface list selection.
4892 static void addrbookctl_build_ifselect( void ) {
4893 GList *newList = NULL;
4898 gchar *endptr = NULL;
4900 AdapterInterface *adapter;
4902 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4905 splitStr = g_strsplit( selectStr, ",", -1 );
4906 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4908 /* g_print( "%d : %s\n", i, splitStr[i] ); */
4909 ifType = strtol( splitStr[i], &endptr, 10 );
4912 if( strcmp( endptr, "/n" ) == 0 ) {
4916 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4917 adapter = addrbookctl_find_interface( ifType );
4919 newList = g_list_append( newList, adapter );
4926 /* g_print( "i=%d\n", i ); */
4927 g_strfreev( splitStr );
4928 g_free( selectStr );
4930 /* Replace existing list */
4931 mgu_clear_list( _addressIFaceSelection_ );
4932 g_list_free( _addressIFaceSelection_ );
4933 _addressIFaceSelection_ = newList;
4937 /* ***********************************************************************
4938 * Add sender to address book.
4939 * ***********************************************************************
4943 * This function is used by the Add sender to address book function.
4945 gboolean addressbook_add_contact(
4946 const gchar *name, const gchar *address, const gchar *remarks )
4948 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4949 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4950 debug_print( "addressbook_add_contact - added\n" );
4951 addressbook_refresh();
4956 /* ***********************************************************************
4957 * Book/folder selection.
4958 * ***********************************************************************
4962 * This function is used by the matcher dialog to select a book/folder.
4964 gboolean addressbook_folder_selection( gchar **folderpath )
4966 AddressBookFile *book = NULL;
4967 ItemFolder *folder = NULL;
4970 g_return_val_if_fail( folderpath != NULL, FALSE);
4974 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4976 if ( folder != NULL) {
4978 gchar *oldtmp = NULL;
4979 AddrItemObject *obj = NULL;
4981 /* walk thru folder->parent to build the full folder path */
4982 /* TODO: wwp: optimize this */
4984 tmp = g_strdup(obj->uid);
4985 while ( obj->parent ) {
4987 if ( obj->name != NULL ) {
4988 oldtmp = g_strdup(tmp);
4990 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4994 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4997 *folderpath = g_strdup_printf("%s", book->fileName);
4999 debug_print( "addressbook_foldersel: %s\n", *folderpath?*folderpath:"(null)");
5000 return (*folderpath != NULL);
5005 /* ***********************************************************************
5006 * Book/folder checking.
5007 * ***********************************************************************
5010 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5012 FolderInfo *fi = g_new0( FolderInfo, 1 );
5014 fi->folder = folder;
5018 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5019 FolderInfo *fiParent, FolderPathMatch *match )
5025 FolderPathMatch *nextmatch = NULL;
5030 list = parentFolder->listFolder;
5032 folder = list->data;
5033 fName = g_strdup( ADDRITEM_NAME(folder) );
5035 /* match folder name, match pointer will be set to NULL if next recursive call
5036 doesn't need to match subfolder name */
5037 if ( match != NULL &&
5038 match->matched == FALSE ) {
5039 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5040 /* folder name matches, prepare next subfolder match */
5041 debug_print("matched folder name '%s'\n", fName);
5043 if ( match->folder_path[match->index] == NULL ) {
5044 /* we've matched all elements */
5045 match->matched = TRUE;
5046 match->folder = folder;
5047 debug_print("book/folder path matched!\n");
5049 /* keep on matching */
5057 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5058 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5060 list = g_list_next( list );
5065 * This function is used by to check if a matcher book/folder path corresponds to an
5066 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5067 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5068 if book AND folder are NULL this means that folderpath was empty or Any.
5069 If folderpath is a simple book name (without folder), book will not be NULL and folder
5070 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5073 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5074 AddressDataSource **book,
5075 ItemFolder **folder )
5077 AddressDataSource *ds;
5078 GList *list, *nodeDS;
5079 ItemFolder *rootFolder;
5080 AddressBookFile *abf;
5082 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5089 if ( folderpath == NULL )
5092 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5095 /* split the folder path we've received, we'll try to match this path, subpath by
5096 subpath against the book/folder structure in order */
5097 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5098 if (!folder_path_match.folder_path)
5101 list = addrindex_get_interface_list( _addressIndex_ );
5102 while ( list && !folder_path_match.matched ) {
5103 AddressInterface *interface = list->data;
5104 if ( interface && interface->type == ADDR_IF_BOOK ) {
5105 nodeDS = interface->listSource;
5106 while ( nodeDS && !folder_path_match.matched ) {
5109 /* Read address book */
5110 if( ! addrindex_ds_get_read_flag( ds ) ) {
5111 addrindex_ds_read_data( ds );
5114 /* Add node for address book */
5115 abf = ds->rawDataSource;
5117 /* match book name */
5118 if ( abf && abf->fileName &&
5119 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5121 debug_print("matched book name '%s'\n", abf->fileName);
5122 folder_path_match.book = ds;
5124 if ( folder_path_match.folder_path[1] == NULL ) {
5125 /* no folder part to match */
5127 folder_path_match.matched = TRUE;
5128 folder_path_match.folder = NULL;
5129 debug_print("book path matched!\n");
5132 /* match folder part */
5134 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5135 rootFolder = addrindex_ds_get_root_folder( ds );
5137 /* prepare for recursive call */
5138 folder_path_match.index = 1;
5139 /* this call will set folder_path_match.matched and folder_path_match.folder */
5140 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5145 nodeDS = g_list_next( nodeDS );
5148 list = g_list_next( list );
5151 g_strfreev( folder_path_match.folder_path );
5154 *book = folder_path_match.book;
5156 *folder = folder_path_match.folder;
5157 return folder_path_match.matched;
5161 /* **********************************************************************
5163 * ***********************************************************************
5169 static void addressbook_import_ldif_cb( void ) {
5170 AddressDataSource *ds = NULL;
5171 AdapterDSource *ads = NULL;
5172 AddressBookFile *abf = NULL;
5173 AdapterInterface *adapter;
5174 GtkCTreeNode *newNode;
5176 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5178 if( adapter->treeNode ) {
5179 abf = addressbook_imp_ldif( _addressIndex_ );
5181 ds = addrindex_index_add_datasource(
5182 _addressIndex_, ADDR_IF_BOOK, abf );
5183 ads = addressbook_create_ds_adapter(
5184 ds, ADDR_BOOK, NULL );
5185 addressbook_ads_set_name(
5186 ads, addrbook_get_name( abf ) );
5187 newNode = addressbook_add_object(
5189 ADDRESS_OBJECT(ads) );
5191 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5193 addrbook.treeSelected = newNode;
5196 /* Notify address completion */
5197 invalidate_address_completion();
5206 static void addressbook_import_mutt_cb( void ) {
5207 AddressDataSource *ds = NULL;
5208 AdapterDSource *ads = NULL;
5209 AddressBookFile *abf = NULL;
5210 AdapterInterface *adapter;
5211 GtkCTreeNode *newNode;
5213 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5215 if( adapter->treeNode ) {
5216 abf = addressbook_imp_mutt( _addressIndex_ );
5218 ds = addrindex_index_add_datasource(
5219 _addressIndex_, ADDR_IF_BOOK, abf );
5220 ads = addressbook_create_ds_adapter(
5221 ds, ADDR_BOOK, NULL );
5222 addressbook_ads_set_name(
5223 ads, addrbook_get_name( abf ) );
5224 newNode = addressbook_add_object(
5226 ADDRESS_OBJECT(ads) );
5228 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5230 addrbook.treeSelected = newNode;
5233 /* Notify address completion */
5234 invalidate_address_completion();
5243 static void addressbook_import_pine_cb( void ) {
5244 AddressDataSource *ds = NULL;
5245 AdapterDSource *ads = NULL;
5246 AddressBookFile *abf = NULL;
5247 AdapterInterface *adapter;
5248 GtkCTreeNode *newNode;
5250 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5252 if( adapter->treeNode ) {
5253 abf = addressbook_imp_pine( _addressIndex_ );
5255 ds = addrindex_index_add_datasource(
5256 _addressIndex_, ADDR_IF_BOOK, abf );
5257 ads = addressbook_create_ds_adapter(
5258 ds, ADDR_BOOK, NULL );
5259 addressbook_ads_set_name(
5260 ads, addrbook_get_name( abf ) );
5261 newNode = addressbook_add_object(
5263 ADDRESS_OBJECT(ads) );
5265 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5267 addrbook.treeSelected = newNode;
5270 /* Notify address completion */
5271 invalidate_address_completion();
5278 * Harvest addresses.
5279 * \param folderItem Folder to import.
5280 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5281 * \param msgList List of message numbers, or NULL to process folder.
5283 void addressbook_harvest(
5284 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5286 AddressDataSource *ds = NULL;
5287 AdapterDSource *ads = NULL;
5288 AddressBookFile *abf = NULL;
5289 AdapterInterface *adapter;
5290 GtkCTreeNode *newNode;
5292 abf = addrgather_dlg_execute(
5293 folderItem, _addressIndex_, sourceInd, msgList );
5295 ds = addrindex_index_add_datasource(
5296 _addressIndex_, ADDR_IF_BOOK, abf );
5298 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5300 if( adapter->treeNode ) {
5301 ads = addressbook_create_ds_adapter(
5302 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5303 newNode = addressbook_add_object(
5305 ADDRESS_OBJECT(ads) );
5309 /* Notify address completion */
5310 invalidate_address_completion();
5317 static void addressbook_export_html_cb( void ) {
5318 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5320 AddressDataSource *ds = NULL;
5321 AddrBookBase *adbase;
5322 AddressCache *cache;
5323 GtkCTreeNode *node = NULL;
5325 if( ! addrbook.treeSelected ) return;
5326 node = addrbook.treeSelected;
5327 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5328 obj = gtk_ctree_node_get_row_data( ctree, node );
5329 if( obj == NULL ) return;
5331 ds = addressbook_find_datasource( node );
5332 if( ds == NULL ) return;
5333 adbase = ( AddrBookBase * ) ds->rawDataSource;
5334 cache = adbase->addressCache;
5335 addressbook_exp_html( cache );
5341 static void addressbook_export_ldif_cb( void ) {
5342 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5344 AddressDataSource *ds = NULL;
5345 AddrBookBase *adbase;
5346 AddressCache *cache;
5347 GtkCTreeNode *node = NULL;
5349 if( ! addrbook.treeSelected ) return;
5350 node = addrbook.treeSelected;
5351 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5352 obj = gtk_ctree_node_get_row_data( ctree, node );
5353 if( obj == NULL ) return;
5355 ds = addressbook_find_datasource( node );
5356 if( ds == NULL ) return;
5357 adbase = ( AddrBookBase * ) ds->rawDataSource;
5358 cache = adbase->addressCache;
5359 addressbook_exp_ldif( cache );
5362 static void addressbook_find_duplicates_cb(void)
5364 addrduplicates_find(GTK_WINDOW(addrbook.window));
5367 static void addressbook_start_drag(GtkWidget *widget, gint button,
5371 GdkDragContext *context;
5372 if (addressbook_target_list == NULL)
5373 addressbook_target_list = gtk_target_list_new(
5374 addressbook_drag_types, 1);
5375 context = gtk_drag_begin(widget, addressbook_target_list,
5376 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5377 gtk_drag_set_icon_default(context);
5380 static void addressbook_drag_data_get(GtkWidget *widget,
5381 GdkDragContext *drag_context,
5382 GtkSelectionData *selection_data,
5387 AddrItemObject *aio = NULL;
5388 AddressObject *pobj = NULL;
5389 AdapterDSource *ads = NULL;
5390 AddressDataSource *ds = NULL;
5393 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5395 if( pobj == NULL ) return;
5397 if( pobj->type == ADDR_DATASOURCE ) {
5398 ads = ADAPTER_DSOURCE(pobj);
5399 ds = ads->dataSource;
5400 } else if (pobj->type == ADDR_ITEM_GROUP) {
5405 else if( pobj->type != ADDR_INTERFACE ) {
5406 ds = addressbook_find_datasource( addrbook.treeSelected );
5412 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5413 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5414 GTK_CTREE_NODE(cur->data));
5415 while (aio && aio->type != ADDR_ITEM_PERSON) {
5420 if (aio && aio->type == ADDR_ITEM_PERSON) {
5421 if( ds && ds->interface && ds->interface->readOnly)
5422 gtk_selection_data_set(selection_data,
5423 selection_data->target, 8,
5424 (const guchar *)"Dummy_addr_copy", 15);
5426 gtk_selection_data_set(selection_data,
5427 selection_data->target, 8,
5428 (const guchar *)"Dummy_addr_move", 15);
5432 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5433 GdkDragContext *context,
5440 GtkCTreeNode *node = NULL;
5441 gboolean acceptable = FALSE;
5442 gint height = addrbook.ctree->allocation.height;
5443 gint total_height = addrbook.ctree->requisition.height;
5444 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5445 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5446 gfloat vpos = pos->value;
5448 if (gtk_clist_get_selection_info
5449 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5451 if (y > height - 24 && height + vpos < total_height) {
5452 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5453 gtk_adjustment_changed(pos);
5455 if (y < 24 && y > 0) {
5456 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5457 gtk_adjustment_changed(pos);
5459 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5462 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5463 if( obj->type == ADDR_ITEM_FOLDER
5464 || obj->type == ADDR_ITEM_GROUP)
5467 AdapterDSource *ads = NULL;
5468 AddressDataSource *ds = NULL;
5469 ads = ADAPTER_DSOURCE(obj);
5470 if (ads == NULL ){ return FALSE;}
5471 ds = ads->dataSource;
5472 if (ds == NULL ) { return FALSE;}
5480 g_signal_handlers_block_by_func
5482 G_CALLBACK(addressbook_tree_selected), NULL);
5483 gtk_sctree_select( GTK_SCTREE(widget), node);
5484 g_signal_handlers_unblock_by_func
5486 G_CALLBACK(addressbook_tree_selected), NULL);
5487 gdk_drag_status(context,
5488 (context->actions == GDK_ACTION_COPY ?
5489 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5491 gdk_drag_status(context, 0, time);
5497 static void addressbook_drag_leave_cb(GtkWidget *widget,
5498 GdkDragContext *context,
5502 if (addrbook.treeSelected) {
5503 g_signal_handlers_block_by_func
5505 G_CALLBACK(addressbook_tree_selected), NULL);
5506 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5507 g_signal_handlers_unblock_by_func
5509 G_CALLBACK(addressbook_tree_selected), NULL);
5514 static void addressbook_drag_received_cb(GtkWidget *widget,
5515 GdkDragContext *drag_context,
5518 GtkSelectionData *data,
5525 GtkCTreeNode *lastopened = addrbook.opened;
5527 if (!strncmp(data->data, "Dummy_addr", 10)) {
5528 if (gtk_clist_get_selection_info
5529 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5533 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5534 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5537 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5538 if (drag_context->action == GDK_ACTION_COPY ||
5539 !strcmp(data->data, "Dummy_addr_copy"))
5540 addressbook_clip_copy_cb();
5542 addressbook_clip_cut_cb();
5543 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5544 addressbook_clip_paste_cb();
5545 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5546 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5547 gtk_drag_finish(drag_context, TRUE, TRUE, time);