2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
55 #include "stock_pixmap.h"
57 #include "prefs_gtk.h"
63 #include "addr_compl.h"
66 #include "addressitem.h"
68 #include "addrcache.h"
70 #include "addrindex.h"
71 #include "addressadd.h"
72 #include "addressbook_foldersel.h"
74 #include "editvcard.h"
75 #include "editgroup.h"
76 #include "editaddress.h"
78 #include "importldif.h"
79 #include "importmutt.h"
80 #include "importpine.h"
85 #include "editjpilot.h"
90 #include "ldapserver.h"
93 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
96 #include "addrquery.h"
97 #include "addrselect.h"
99 #include "addrgather.h"
100 #include "adbookbase.h"
101 #include "exphtmldlg.h"
102 #include "expldifdlg.h"
103 #include "browseldap.h"
109 } AddressIndexColumns;
117 } AddressListColumns;
120 AddressBookFile *book;
128 AddressDataSource *book;
132 static gchar *list_titles[] = { N_("Name"),
136 #define COL_NAME_WIDTH 164
137 #define COL_ADDRESS_WIDTH 156
139 #define COL_FOLDER_WIDTH 170
140 #define ADDRESSBOOK_WIDTH 640
141 #define ADDRESSBOOK_HEIGHT 360
143 #define ADDRESSBOOK_MSGBUF_SIZE 2048
145 static GdkPixmap *folderxpm;
146 static GdkBitmap *folderxpmmask;
147 static GdkPixmap *folderopenxpm;
148 static GdkBitmap *folderopenxpmmask;
149 static GdkPixmap *groupxpm;
150 static GdkBitmap *groupxpmmask;
151 static GdkPixmap *interfacexpm;
152 static GdkBitmap *interfacexpmmask;
153 static GdkPixmap *bookxpm;
154 static GdkBitmap *bookxpmmask;
155 static GdkPixmap *addressxpm;
156 static GdkBitmap *addressxpmmask;
157 static GdkPixmap *vcardxpm;
158 static GdkBitmap *vcardxpmmask;
159 static GdkPixmap *jpilotxpm;
160 static GdkBitmap *jpilotxpmmask;
161 static GdkPixmap *categoryxpm;
162 static GdkBitmap *categoryxpmmask;
163 static GdkPixmap *ldapxpm;
164 static GdkBitmap *ldapxpmmask;
165 static GdkPixmap *addrsearchxpm;
166 static GdkPixmap *addrsearchxpmmask;
169 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
171 /* Address list selection */
172 static AddrSelectList *_addressSelect_ = NULL;
173 static AddressClipboard *_clipBoard_ = NULL;
175 /* Address index file and interfaces */
176 static AddressIndex *_addressIndex_ = NULL;
177 static GList *_addressInterfaceList_ = NULL;
178 static GList *_addressIFaceSelection_ = NULL;
179 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
181 static AddressBook_win addrbook;
183 static GHashTable *_addressBookTypeHash_ = NULL;
184 static GList *_addressBookTypeList_ = NULL;
186 static void addressbook_create (void);
187 static gint addressbook_close (void);
188 static void addressbook_button_set_sensitive (void);
190 /* callback functions */
191 static void addressbook_del_clicked (GtkButton *button,
193 static void addressbook_reg_clicked (GtkButton *button,
195 static void addressbook_to_clicked (GtkButton *button,
197 static void addressbook_lup_clicked (GtkButton *button,
199 static void addressbook_close_clicked (GtkButton *button,
202 static void addressbook_tree_selected (GtkCTree *ctree,
206 static void addressbook_select_row_tree (GtkCTree *ctree,
210 static void addressbook_list_row_selected (GtkCTree *clist,
214 static void addressbook_list_row_unselected (GtkCTree *clist,
218 static void addressbook_person_expand_node (GtkCTree *ctree,
221 static void addressbook_person_collapse_node (GtkCTree *ctree,
225 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
226 GdkEventButton *event,
228 static gboolean addressbook_list_button_released(GtkWidget *widget,
229 GdkEventButton *event,
231 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
232 GdkEventButton *event,
234 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
235 GdkEventButton *event,
238 static void addressbook_new_folder_cb (gpointer data,
241 static void addressbook_new_group_cb (gpointer data,
244 static void addressbook_treenode_edit_cb (gpointer data,
247 static void addressbook_treenode_delete_cb (gpointer data,
251 static void addressbook_change_node_name (GtkCTreeNode *node,
254 static void addressbook_new_address_cb (gpointer data,
257 static void addressbook_edit_address_cb (gpointer data,
260 static void addressbook_delete_address_cb (gpointer data,
264 static void close_cb (gpointer data,
267 static void addressbook_file_save_cb (gpointer data,
271 /* Data source edit stuff */
272 static void addressbook_new_book_cb (gpointer data,
275 static void addressbook_new_vcard_cb (gpointer data,
280 static void addressbook_new_jpilot_cb (gpointer data,
286 static void addressbook_new_ldap_cb (gpointer data,
291 static void addressbook_set_clist (AddressObject *obj,
294 static void addressbook_load_tree (void);
295 void addressbook_read_file (void);
297 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
299 static void addressbook_treenode_remove_item ( void );
301 static AddressDataSource *addressbook_find_datasource
302 (GtkCTreeNode *node );
304 static AddressBookFile *addressbook_get_book_file(void);
306 static GtkCTreeNode *addressbook_node_add_folder
308 AddressDataSource *ds,
309 ItemFolder *itemFolder,
310 AddressObjectType otype);
311 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
312 AddressDataSource *ds,
313 ItemGroup *itemGroup);
314 static void addressbook_tree_remove_children (GtkCTree *ctree,
315 GtkCTreeNode *parent);
316 static void addressbook_move_nodes_up (GtkCTree *ctree,
318 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
320 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
323 static gint addressbook_treenode_compare_func (GtkCList *clist,
326 static void addressbook_folder_load_one_person (GtkCTree *clist,
328 AddressTypeControlItem *atci,
329 AddressTypeControlItem *atciMail);
330 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
332 static void addressbook_folder_remove_one_person(GtkCTree *clist,
334 static void addressbook_folder_remove_node (GtkCTree *clist,
337 /* LUT's and IF stuff */
338 static void addressbook_free_treenode ( gpointer data );
339 AddressTypeControlItem *addrbookctl_lookup (gint ot);
340 AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
342 void addrbookctl_build_map (GtkWidget *window);
343 void addrbookctl_build_iflist (void);
344 AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
345 void addrbookctl_build_ifselect (void);
347 static void addrbookctl_free_interface (AdapterInterface *adapter);
348 static void addrbookctl_free_datasource (AdapterDSource *adapter);
349 static void addrbookctl_free_folder (AdapterFolder *adapter);
350 static void addrbookctl_free_group (AdapterGroup *adapter);
352 static void addressbook_list_select_clear ( void );
353 static void addressbook_list_select_add ( AddrItemObject *aio,
354 AddressDataSource *ds );
355 static void addressbook_list_select_remove ( AddrItemObject *aio );
357 static void addressbook_import_ldif_cb ( void );
358 static void addressbook_import_mutt_cb ( void );
359 static void addressbook_import_pine_cb ( void );
360 static void addressbook_export_html_cb ( void );
361 static void addressbook_export_ldif_cb ( void );
362 static void addressbook_select_all_cb ( void );
363 static void addressbook_clip_cut_cb ( void );
364 static void addressbook_clip_copy_cb ( void );
365 static void addressbook_clip_paste_cb ( void );
366 static void addressbook_treenode_cut_cb ( void );
367 static void addressbook_treenode_copy_cb ( void );
368 static void addressbook_treenode_paste_cb ( void );
370 static void addressbook_mail_to_cb ( void );
373 static void addressbook_browse_entry_cb ( void );
375 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
377 static void addressbook_start_drag(GtkWidget *widget, gint button,
380 static void addressbook_drag_data_get(GtkWidget *widget,
381 GdkDragContext *drag_context,
382 GtkSelectionData *selection_data,
386 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
387 GdkDragContext *context,
392 static void addressbook_drag_leave_cb(GtkWidget *widget,
393 GdkDragContext *context,
396 static void addressbook_drag_received_cb(GtkWidget *widget,
397 GdkDragContext *drag_context,
400 GtkSelectionData *data,
404 static void addressbook_list_menu_setup( void );
406 static GtkTargetEntry addressbook_drag_types[] =
408 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
411 static GtkTargetList *addressbook_target_list = NULL;
414 static GtkItemFactoryEntry addressbook_entries[] =
416 {N_("/_Book"), NULL, NULL, 0, "<Branch>"},
417 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL},
418 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL},
419 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL},
421 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL},
424 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL},
426 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
427 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL},
428 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL},
429 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
430 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL},
431 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL},
432 {N_("/_Address"), NULL, NULL, 0, "<Branch>"},
433 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL},
434 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
435 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL},
436 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL},
437 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL},
438 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
439 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL},
440 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL},
441 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
442 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL},
443 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL},
444 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
445 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
446 {N_("/_Tools"), NULL, NULL, 0, "<Branch>"},
447 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL},
448 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL},
449 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL},
450 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>"},
451 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL},
452 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL},
453 {N_("/_Help"), NULL, NULL, 0, "<Branch>"},
454 {N_("/_Help/_About"), NULL, about_show, 0, NULL}
457 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
459 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL},
460 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL},
461 {N_("/---"), NULL, NULL, 0, "<Separator>"},
462 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL},
463 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
464 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
465 {N_("/---"), NULL, NULL, 0, "<Separator>"},
466 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL},
467 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL},
468 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL}
471 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
473 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL},
474 {N_("/---"), NULL, NULL, 0, "<Separator>"},
475 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL},
476 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL},
477 {N_("/---"), NULL, NULL, 0, "<Separator>"},
478 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
479 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
480 {N_("/---"), NULL, NULL, 0, "<Separator>"},
481 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL},
482 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL},
483 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL},
484 {N_("/---"), NULL, NULL, 0, "<Separator>"},
485 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},*/
486 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
488 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL},
493 * Structure of error message table.
495 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
496 struct _ErrMsgTableEntry {
501 static gchar *_errMsgUnknown_ = N_( "Unknown" );
504 * Lookup table of error messages for general errors. Note that a NULL
505 * description signifies the end of the table.
507 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
508 { MGU_SUCCESS, N_("Success") },
509 { MGU_BAD_ARGS, N_("Bad arguments") },
510 { MGU_NO_FILE, N_("File not specified") },
511 { MGU_OPEN_FILE, N_("Error opening file") },
512 { MGU_ERROR_READ, N_("Error reading file") },
513 { MGU_EOF, N_("End of file encountered") },
514 { MGU_OO_MEMORY, N_("Error allocating memory") },
515 { MGU_BAD_FORMAT, N_("Bad file format") },
516 { MGU_ERROR_WRITE, N_("Error writing to file") },
517 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
518 { MGU_NO_PATH, N_("No path specified") },
524 * Lookup table of error messages for LDAP errors.
526 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
527 { LDAPRC_SUCCESS, N_("Success") },
528 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
529 { LDAPRC_INIT, N_("Error initializing LDAP") },
530 { LDAPRC_BIND, N_("Error binding to LDAP server") },
531 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
532 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
533 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
534 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
535 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
536 { LDAPRC_TLS, N_("Error starting TLS connection") },
542 * Lookup message for specified error code.
543 * \param lut Lookup table.
544 * \param code Code to lookup.
545 * \return Description associated to code.
547 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
549 ErrMsgTableEntry entry;
552 for( i = 0; ; i++ ) {
554 if( entry.description == NULL ) break;
555 if( entry.code == code ) {
556 desc = entry.description;
561 desc = _errMsgUnknown_;
566 static gboolean lastCanLookup = FALSE;
568 void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
570 if (add_and_delete) {
571 gtk_widget_show(addrbook.edit_btn);
572 gtk_widget_show(addrbook.del_btn);
573 gtk_widget_show(addrbook.reg_btn);
575 gtk_widget_hide(addrbook.edit_btn);
576 gtk_widget_hide(addrbook.del_btn);
577 gtk_widget_hide(addrbook.reg_btn);
581 gtk_widget_show(addrbook.lup_btn);
582 gtk_widget_show(addrbook.entry);
583 gtk_widget_show(addrbook.label);
585 gtk_widget_hide(addrbook.lup_btn);
586 gtk_widget_hide(addrbook.entry);
587 gtk_widget_hide(addrbook.label);
590 lastCanLookup = lookup;
593 gtk_widget_show(addrbook.to_btn);
594 gtk_widget_show(addrbook.cc_btn);
595 gtk_widget_show(addrbook.bcc_btn);
597 gtk_widget_hide(addrbook.to_btn);
598 gtk_widget_hide(addrbook.cc_btn);
599 gtk_widget_hide(addrbook.bcc_btn);
603 void addressbook_open(Compose *target)
605 /* Initialize all static members */
606 if( _clipBoard_ == NULL ) {
607 _clipBoard_ = addrclip_create();
609 if( _addressIndex_ != NULL ) {
610 addrclip_set_index( _clipBoard_, _addressIndex_ );
612 if( _addressSelect_ == NULL ) {
613 _addressSelect_ = addrselect_list_create();
615 if (!addrbook.window) {
616 addressbook_read_file();
617 addressbook_create();
618 addressbook_load_tree();
619 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
620 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
623 gtk_widget_hide(addrbook.window);
626 gtk_widget_show_all(addrbook.window);
627 address_completion_start(addrbook.window);
629 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
630 addressbook_set_target_compose(target);
634 * Destroy addressbook.
636 void addressbook_destroy( void ) {
637 /* Free up address stuff */
638 if( _addressSelect_ != NULL ) {
639 addrselect_list_free( _addressSelect_ );
641 if( _clipBoard_ != NULL ) {
642 addrclip_free( _clipBoard_ );
644 if( _addressIndex_ != NULL ) {
645 addrindex_free_index( _addressIndex_ );
646 addrindex_teardown();
648 _addressSelect_ = NULL;
650 _addressIndex_ = NULL;
653 void addressbook_set_target_compose(Compose *target)
655 addrbook.target_compose = target;
656 addressbook_button_set_sensitive();
659 Compose *addressbook_get_target_compose(void)
661 return addrbook.target_compose;
665 * Refresh addressbook and save to file(s).
667 void addressbook_refresh( void )
669 if (addrbook.window) {
670 if (addrbook.treeSelected) {
671 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
672 addrbook.treeSelected);
673 addressbook_set_clist(
674 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
675 addrbook.treeSelected),
680 addressbook_export_to_file();
683 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
685 if (event && event->keyval == GDK_Escape)
687 else if (event && event->keyval == GDK_Delete)
688 addressbook_del_clicked(NULL, NULL);
693 *\brief Save Gtk object size to prefs dataset
695 static void addressbook_size_allocate_cb(GtkWidget *widget,
696 GtkAllocation *allocation)
698 g_return_if_fail(allocation != NULL);
700 prefs_common.addressbookwin_width = allocation->width;
701 prefs_common.addressbookwin_height = allocation->height;
704 static gint sort_column_number = 0;
705 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
707 static gint list_case_sort(
708 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
710 GtkCListRow *row1 = (GtkCListRow *) ptr1;
711 GtkCListRow *row2 = (GtkCListRow *) ptr2;
712 gchar *name1 = NULL, *name2 = NULL;
713 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
714 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
716 if( aio1->type == aio2->type ) {
718 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
720 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
721 if( ! name1 ) return ( name2 != NULL );
722 if( ! name2 ) return -1;
723 return strcasecmp( name1, name2 );
725 /* Order groups before person */
726 if( aio1->type == ITEMTYPE_GROUP ) {
727 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
728 } else if( aio2->type == ITEMTYPE_GROUP ) {
729 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
735 static void addressbook_sort_list(GtkCList *clist, const gint col,
736 const GtkSortType sort_type)
739 GtkWidget *hbox, *label, *arrow;
741 sort_column_number = col;
742 sort_column_type = sort_type;
743 gtk_clist_set_compare_func(clist, list_case_sort);
744 gtk_clist_set_sort_type(clist, sort_type);
745 gtk_clist_set_sort_column(clist, col);
747 gtk_clist_freeze(clist);
748 gtk_clist_sort(clist);
750 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
751 hbox = gtk_hbox_new(FALSE, 4);
752 label = gtk_label_new(gettext(list_titles[pos]));
753 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
756 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
757 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
758 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
761 gtk_widget_show_all(hbox);
762 gtk_clist_set_column_widget(clist, pos, hbox);
765 gtk_clist_thaw(clist);
768 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
770 static GtkSortType sort_type = GTK_SORT_ASCENDING;
772 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
774 addressbook_sort_list(clist, COL_NAME, sort_type);
777 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
779 static GtkSortType sort_type = GTK_SORT_ASCENDING;
781 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
783 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
786 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
788 static GtkSortType sort_type = GTK_SORT_ASCENDING;
790 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
792 addressbook_sort_list(clist, COL_REMARKS, sort_type);
796 * Create the address book widgets. The address book contains two CTree widgets: the
797 * address index tree on the left and the address list on the right.
799 * The address index tree displays a hierarchy of interfaces and groups. Each node in
800 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
801 * data sources and folder objects.
803 * The address list displays group, person and email objects. These items are linked
804 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
807 * In the tradition of MVC architecture, the data stores have been separated from the
808 * GUI components. The addrindex.c file provides the interface to all data stores.
810 static void addressbook_create(void)
816 GtkWidget *ctree_swin;
818 GtkWidget *clist_vbox;
819 GtkWidget *clist_swin;
825 GtkWidget *statusbar;
836 GtkWidget *close_btn;
837 GtkWidget *tree_popup;
838 GtkWidget *list_popup;
839 GtkItemFactory *tree_factory;
840 GtkItemFactory *list_factory;
841 GtkItemFactory *menu_factory;
845 gchar *index_titles[N_INDEX_COLS];
849 static GdkGeometry geometry;
851 debug_print("Creating addressbook window...\n");
853 index_titles[COL_SOURCES] = _("Sources");
855 /* Address book window */
856 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
857 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
858 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
859 gtk_widget_realize(window);
861 g_signal_connect(G_OBJECT(window), "delete_event",
862 G_CALLBACK(addressbook_close), NULL);
863 g_signal_connect(G_OBJECT(window), "size_allocate",
864 G_CALLBACK(addressbook_size_allocate_cb), NULL);
865 g_signal_connect(G_OBJECT(window), "key_press_event",
866 G_CALLBACK(key_pressed), NULL);
867 MANAGE_WINDOW_SIGNALS_CONNECT(window);
869 vbox = gtk_vbox_new(FALSE, 0);
870 gtk_container_add(GTK_CONTAINER(window), vbox);
873 n_entries = sizeof(addressbook_entries) /
874 sizeof(addressbook_entries[0]);
875 menubar = menubar_create(window, addressbook_entries, n_entries,
876 "<AddressBook>", NULL);
877 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
878 menu_factory = gtk_item_factory_from_widget(menubar);
880 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
881 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
882 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
884 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
885 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
886 GTK_POLICY_AUTOMATIC,
887 GTK_POLICY_AUTOMATIC);
888 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 40, -1);
891 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
892 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
893 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
894 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
895 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
896 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
897 GTK_CTREE_EXPANDER_SQUARE);
898 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
899 gtk_clist_set_compare_func(GTK_CLIST(ctree),
900 addressbook_treenode_compare_func);
902 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
903 G_CALLBACK(addressbook_tree_selected), NULL);
904 g_signal_connect(G_OBJECT(ctree), "button_press_event",
905 G_CALLBACK(addressbook_tree_button_pressed),
907 g_signal_connect(G_OBJECT(ctree), "button_release_event",
908 G_CALLBACK(addressbook_tree_button_released),
911 g_signal_connect(G_OBJECT(ctree), "select_row",
912 G_CALLBACK(addressbook_select_row_tree), NULL);
914 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
915 addressbook_drag_types, 1,
916 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
917 g_signal_connect(G_OBJECT(ctree), "drag_motion",
918 G_CALLBACK(addressbook_drag_motion_cb),
920 g_signal_connect(G_OBJECT(ctree), "drag_leave",
921 G_CALLBACK(addressbook_drag_leave_cb),
923 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
924 G_CALLBACK(addressbook_drag_received_cb),
927 clist_vbox = gtk_vbox_new(FALSE, 4);
929 clist_swin = gtk_scrolled_window_new(NULL, NULL);
930 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
931 GTK_POLICY_AUTOMATIC,
932 GTK_POLICY_AUTOMATIC);
933 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
936 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
937 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
938 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
939 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
940 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
941 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
942 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
944 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
947 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
948 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
949 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
950 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
951 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
952 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
953 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
955 for (i = 0; i < N_LIST_COLS; i++)
956 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
959 g_signal_connect(G_OBJECT(clist), "tree_select_row",
960 G_CALLBACK(addressbook_list_row_selected), NULL);
961 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
962 G_CALLBACK(addressbook_list_row_unselected), NULL);
963 g_signal_connect(G_OBJECT(clist), "button_press_event",
964 G_CALLBACK(addressbook_list_button_pressed),
966 g_signal_connect(G_OBJECT(clist), "button_release_event",
967 G_CALLBACK(addressbook_list_button_released),
969 g_signal_connect(G_OBJECT(clist), "tree_expand",
970 G_CALLBACK(addressbook_person_expand_node), NULL );
971 g_signal_connect(G_OBJECT(clist), "tree_collapse",
972 G_CALLBACK(addressbook_person_collapse_node), NULL );
973 g_signal_connect(G_OBJECT(clist), "start_drag",
974 G_CALLBACK(addressbook_start_drag), NULL);
975 g_signal_connect(G_OBJECT(clist), "drag_data_get",
976 G_CALLBACK(addressbook_drag_data_get), NULL);
977 hbox = gtk_hbox_new(FALSE, 4);
978 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
980 label = gtk_label_new(_("Lookup name:"));
981 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
983 entry = gtk_entry_new();
984 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
986 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
988 g_signal_connect(G_OBJECT(entry), "key_press_event",
989 G_CALLBACK(addressbook_entry_key_pressed),
991 paned = gtk_hpaned_new();
992 gtk_box_pack_start(GTK_BOX(vbox2), paned, TRUE, TRUE, 0);
993 gtk_paned_add1(GTK_PANED(paned), ctree_swin);
994 gtk_paned_add2(GTK_PANED(paned), clist_vbox);
997 hsbox = gtk_hbox_new(FALSE, 0);
998 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
999 statusbar = gtk_statusbar_new();
1000 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1003 hbbox = gtk_hbutton_box_new();
1004 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1005 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1006 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1007 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1009 gtkut_stock_button_add_help(hbbox, &help_btn);
1011 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1012 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1013 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1014 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1015 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1016 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1017 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1018 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1019 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1022 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1023 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1024 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1026 g_signal_connect(G_OBJECT(help_btn), "clicked",
1027 G_CALLBACK(manual_open_with_anchor_cb),
1028 MANUAL_ANCHOR_ADDRBOOK);
1030 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1031 G_CALLBACK(addressbook_edit_clicked), NULL);
1032 g_signal_connect(G_OBJECT(del_btn), "clicked",
1033 G_CALLBACK(addressbook_del_clicked), NULL);
1034 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1035 G_CALLBACK(addressbook_reg_clicked), NULL);
1036 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1037 G_CALLBACK(addressbook_lup_clicked), NULL);
1039 to_btn = gtk_button_new_with_label
1040 (prefs_common.trans_hdr ? _("To:") : "To:");
1041 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1042 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1043 cc_btn = gtk_button_new_with_label
1044 (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
1045 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1046 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1047 bcc_btn = gtk_button_new_with_label
1048 (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
1049 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1050 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1052 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1053 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1054 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1056 g_signal_connect(G_OBJECT(to_btn), "clicked",
1057 G_CALLBACK(addressbook_to_clicked),
1058 GINT_TO_POINTER(COMPOSE_TO));
1059 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1060 G_CALLBACK(addressbook_to_clicked),
1061 GINT_TO_POINTER(COMPOSE_CC));
1062 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1063 G_CALLBACK(addressbook_to_clicked),
1064 GINT_TO_POINTER(COMPOSE_BCC));
1065 g_signal_connect(G_OBJECT(close_btn), "clicked",
1066 G_CALLBACK(addressbook_close_clicked), NULL);
1068 /* Build icons for interface */
1069 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1070 &interfacexpm, &interfacexpmmask );
1072 /* Build control tables */
1073 addrbookctl_build_map(window);
1074 addrbookctl_build_iflist();
1075 addrbookctl_build_ifselect();
1077 addrbook.clist = NULL;
1079 /* Add each interface into the tree as a root level folder */
1080 nodeIf = _addressInterfaceList_;
1082 AdapterInterface *adapter = nodeIf->data;
1083 AddressInterface *iface = adapter->interface;
1084 nodeIf = g_list_next(nodeIf);
1086 if(iface->useInterface) {
1087 AddressTypeControlItem *atci = adapter->atci;
1088 text = atci->displayName;
1090 gtk_sctree_insert_node( GTK_CTREE(ctree),
1091 NULL, NULL, &text, FOLDER_SPACING,
1092 interfacexpm, interfacexpmmask,
1093 interfacexpm, interfacexpmmask,
1095 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1096 gtk_ctree_node_set_row_data_full(
1097 GTK_CTREE(ctree), adapter->treeNode, adapter,
1098 addressbook_free_treenode );
1103 n_entries = sizeof(addressbook_tree_popup_entries) /
1104 sizeof(addressbook_tree_popup_entries[0]);
1105 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1107 "<AddressBookTree>", &tree_factory,
1109 n_entries = sizeof(addressbook_list_popup_entries) /
1110 sizeof(addressbook_list_popup_entries[0]);
1111 list_popup = menu_create_items(addressbook_list_popup_entries,
1113 "<AddressBookList>", &list_factory,
1116 addrbook.window = window;
1117 addrbook.menubar = menubar;
1118 addrbook.ctree = ctree;
1121 addrbook.clist = clist;
1122 addrbook.label = label;
1123 addrbook.entry = entry;
1124 addrbook.statusbar = statusbar;
1125 addrbook.status_cid = gtk_statusbar_get_context_id(
1126 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1128 addrbook.help_btn = help_btn;
1129 addrbook.edit_btn = edit_btn;
1130 addrbook.del_btn = del_btn;
1131 addrbook.reg_btn = reg_btn;
1132 addrbook.lup_btn = lup_btn;
1133 addrbook.to_btn = to_btn;
1134 addrbook.cc_btn = cc_btn;
1135 addrbook.bcc_btn = bcc_btn;
1137 addrbook.tree_popup = tree_popup;
1138 addrbook.list_popup = list_popup;
1139 addrbook.tree_factory = tree_factory;
1140 addrbook.list_factory = list_factory;
1141 addrbook.menu_factory = menu_factory;
1143 addrbook.listSelected = NULL;
1145 if (!geometry.min_height) {
1146 geometry.min_width = ADDRESSBOOK_WIDTH;
1147 geometry.min_height = ADDRESSBOOK_HEIGHT;
1150 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1152 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1153 prefs_common.addressbookwin_height);
1155 gtk_widget_show_all(window);
1159 * Close address book window and save to file(s).
1161 static gint addressbook_close( void ) {
1162 address_completion_end(addrbook.window);
1163 gtk_widget_hide(addrbook.window);
1164 addressbook_export_to_file();
1169 * Display message in status line.
1170 * \param msg Message to display.
1172 static void addressbook_status_show( gchar *msg ) {
1173 if( addrbook.statusbar != NULL ) {
1175 GTK_STATUSBAR(addrbook.statusbar),
1176 addrbook.status_cid );
1179 GTK_STATUSBAR(addrbook.statusbar),
1180 addrbook.status_cid, msg );
1185 static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
1186 *addressbook_msgbuf = '\0';
1190 name = addrindex_ds_get_name( ds );
1191 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1192 "%s: %s", name, msg );
1195 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1198 addressbook_status_show( addressbook_msgbuf );
1201 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1205 *addressbook_msgbuf = '\0';
1207 name = addrindex_ds_get_name( ds );
1208 retVal = addrindex_ds_get_status_code( ds );
1209 if( retVal == MGU_SUCCESS ) {
1210 g_snprintf( addressbook_msgbuf,
1211 sizeof(addressbook_msgbuf), "%s", name );
1214 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1215 g_snprintf( addressbook_msgbuf,
1216 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1219 addressbook_status_show( addressbook_msgbuf );
1222 static void addressbook_button_set_sensitive(void)
1224 gboolean to_sens = FALSE;
1225 gboolean cc_sens = FALSE;
1226 gboolean bcc_sens = FALSE;
1228 if (!addrbook.window) return;
1230 if (addrbook.target_compose) {
1234 if (addrbook.target_compose->use_bcc)
1239 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1240 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1241 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1244 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1246 addressbook_edit_address_cb(NULL, 0, NULL);
1250 * Delete one or more objects from address list.
1252 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1254 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1255 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1256 AddressObject *pobj;
1257 AdapterDSource *ads = NULL;
1258 GtkCTreeNode *nodeList;
1261 AddressBookFile *abf = NULL;
1262 AddressDataSource *ds = NULL;
1263 AddressInterface *iface;
1264 AddrItemObject *aio;
1265 AddrSelectItem *item;
1267 gboolean refreshList = FALSE;
1269 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1270 g_return_if_fail(pobj != NULL);
1272 /* Test whether anything selected for deletion */
1273 nodeList = addrbook.listSelected;
1275 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1276 if( aio == NULL) return;
1277 ds = addressbook_find_datasource( addrbook.treeSelected );
1278 if( ds == NULL ) return;
1280 /* Test for read only */
1281 iface = ds->interface;
1282 if( iface->readOnly ) {
1283 alertpanel( _("Delete address(es)"),
1284 _("This address data is readonly and cannot be deleted."),
1285 GTK_STOCK_CLOSE, NULL, NULL );
1289 /* Test whether Ok to proceed */
1291 if( pobj->type == ADDR_DATASOURCE ) {
1292 ads = ADAPTER_DSOURCE(pobj);
1293 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1295 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1298 else if( pobj->type == ADDR_ITEM_GROUP ) {
1301 if( ! procFlag ) return;
1302 abf = ds->rawDataSource;
1303 if( abf == NULL ) return;
1306 /* Process deletions */
1307 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1308 gboolean group_delete = TRUE;
1309 /* Items inside folders */
1310 list = addrselect_get_list( _addressSelect_ );
1311 /* Confirm deletion */
1315 node = g_list_next( node );
1316 aio = ( AddrItemObject * ) item->addressItem;
1317 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1318 group_delete = FALSE;
1323 aval = alertpanel( _("Delete group"),
1324 _("Really delete the group(s)?\n"
1325 "The addresses it contains will not be lost."),
1326 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1327 if( aval != G_ALERTALTERNATE ) return;
1329 aval = alertpanel( _("Delete address(es)"),
1330 _("Really delete the address(es)?"),
1331 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1332 if( aval != G_ALERTALTERNATE ) return;
1338 node = g_list_next( node );
1339 aio = ( AddrItemObject * ) item->addressItem;
1340 if( aio->type == ADDR_ITEM_GROUP ) {
1341 ItemGroup *item = ( ItemGroup * ) aio;
1342 GtkCTreeNode *nd = NULL;
1344 nd = addressbook_find_group_node( addrbook.opened, item );
1345 item = addrbook_remove_group( abf, item );
1347 addritem_free_item_group( item );
1349 /* Remove group from parent node */
1350 gtk_ctree_remove_node( ctree, nd );
1353 else if( aio->type == ADDR_ITEM_PERSON ) {
1354 ItemPerson *item = ( ItemPerson * ) aio;
1355 addressbook_folder_remove_one_person( clist, item );
1356 if (pobj->type == ADDR_ITEM_FOLDER)
1357 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1358 item = addrbook_remove_person( abf, item );
1360 addritem_free_item_person( item );
1363 else if( aio->type == ADDR_ITEM_EMAIL ) {
1364 ItemEMail *item = ( ItemEMail * ) aio;
1365 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1366 item = addrbook_person_remove_email( abf, person, item );
1368 addrcache_remove_email(abf->addressCache, item);
1369 addritem_free_item_email( item );
1371 addressbook_folder_refresh_one_person( clist, person );
1374 g_list_free( list );
1375 addressbook_list_select_clear();
1377 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1378 addressbook_set_clist(
1379 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1383 addrbook_set_dirty(abf, TRUE);
1384 addressbook_export_to_file();
1385 addressbook_list_menu_setup();
1388 else if( pobj->type == ADDR_ITEM_GROUP ) {
1389 /* Items inside groups */
1390 list = addrselect_get_list( _addressSelect_ );
1394 node = g_list_next( node );
1395 aio = ( AddrItemObject * ) item->addressItem;
1396 if( aio->type == ADDR_ITEM_EMAIL ) {
1397 ItemEMail *item = ( ItemEMail * ) aio;
1398 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1399 item = addrbook_person_remove_email( abf, person, item );
1401 addritem_free_item_email( item );
1405 g_list_free( list );
1406 addressbook_list_select_clear();
1407 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1408 addressbook_set_clist(
1409 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1413 addrbook_set_dirty(abf, TRUE);
1414 addressbook_export_to_file();
1415 addressbook_list_menu_setup();
1419 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1420 gtk_ctree_remove_node( clist, nodeList );
1424 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1426 addressbook_new_address_cb( NULL, 0, NULL );
1429 gchar *addressbook_format_address( AddrItemObject * aio ) {
1432 gchar *address = NULL;
1434 if( aio->type == ADDR_ITEM_EMAIL ) {
1435 ItemPerson *person = NULL;
1436 ItemEMail *email = ( ItemEMail * ) aio;
1438 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1439 if( email->address ) {
1440 if( ADDRITEM_NAME(email) ) {
1441 name = ADDRITEM_NAME(email);
1442 if( *name == '\0' ) {
1443 name = ADDRITEM_NAME(person);
1446 else if( ADDRITEM_NAME(person) ) {
1447 name = ADDRITEM_NAME(person);
1450 buf = g_strdup( email->address );
1452 address = email->address;
1455 else if( aio->type == ADDR_ITEM_PERSON ) {
1456 ItemPerson *person = ( ItemPerson * ) aio;
1457 GList *node = person->listEMail;
1459 name = ADDRITEM_NAME(person);
1461 ItemEMail *email = ( ItemEMail * ) node->data;
1462 address = email->address;
1466 if( name && name[0] != '\0' ) {
1467 if( strchr_with_skip_quote( name, '"', ',' ) )
1468 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1470 buf = g_strdup_printf( "%s <%s>", name, address );
1473 buf = g_strdup( address );
1480 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1484 AddrSelectItem *item;
1485 AddrItemObject *aio;
1488 compose = addrbook.target_compose;
1489 if( ! compose ) return;
1491 /* Nothing selected, but maybe there is something in text entry */
1492 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1494 compose_entry_append(
1495 compose, addr, (ComposeEntryType)data );
1498 /* Select from address list */
1499 list = addrselect_get_list( _addressSelect_ );
1503 node = g_list_next( node );
1504 aio = item->addressItem;
1505 if( aio->type == ADDR_ITEM_PERSON ||
1506 aio->type == ADDR_ITEM_EMAIL ) {
1507 addr = addressbook_format_address( aio );
1508 compose_entry_append(
1509 compose, addr, (ComposeEntryType) data );
1512 else if( aio->type == ADDR_ITEM_GROUP ) {
1513 ItemGroup *group = ( ItemGroup * ) aio;
1514 GList *nodeMail = group->listEMail;
1516 ItemEMail *email = nodeMail->data;
1518 addr = addressbook_format_address(
1519 ( AddrItemObject * ) email );
1520 compose_entry_append(
1521 compose, addr, (ComposeEntryType) data );
1523 nodeMail = g_list_next( nodeMail );
1527 g_list_free( list );
1530 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1531 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1532 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1533 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1535 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1536 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1537 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1538 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1540 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1541 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1542 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1543 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1544 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1545 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1548 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1549 gboolean canEdit = FALSE;
1550 gboolean canDelete = TRUE;
1551 gboolean canAdd = FALSE;
1552 gboolean canEditTr = TRUE;
1553 gboolean editAddress = FALSE;
1554 gboolean canExport = TRUE;
1555 AddressTypeControlItem *atci = NULL;
1556 AddressDataSource *ds = NULL;
1557 AddressInterface *iface = NULL;
1559 if( obj == NULL ) return;
1560 if( obj->type == ADDR_INTERFACE ) {
1561 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1562 iface = adapter->interface;
1564 if( iface->haveLibrary ) {
1565 /* Enable appropriate File / New command */
1566 atci = adapter->atci;
1567 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1570 canEditTr = canExport = FALSE;
1572 else if( obj->type == ADDR_DATASOURCE ) {
1573 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1574 ds = ads->dataSource;
1575 iface = ds->interface;
1576 if( ! iface->readOnly ) {
1577 canAdd = canEdit = editAddress = canDelete = TRUE;
1579 if( ! iface->haveLibrary ) {
1580 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1583 else if( obj->type == ADDR_ITEM_FOLDER ) {
1584 ds = addressbook_find_datasource( addrbook.treeSelected );
1586 iface = ds->interface;
1587 if( iface->readOnly ) {
1592 canAdd = editAddress = TRUE;
1596 else if( obj->type == ADDR_ITEM_GROUP ) {
1597 ds = addressbook_find_datasource( addrbook.treeSelected );
1599 iface = ds->interface;
1600 if( ! iface->readOnly ) {
1606 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1609 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1610 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1611 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1612 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1615 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1616 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1617 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1618 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1620 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1621 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1624 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1625 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1628 static void addressbook_list_menu_setup( void );
1631 * Address book tree callback function that responds to selection of tree
1634 * \param ctree Tree widget.
1635 * \param node Node that was selected.
1636 * \param column Column number where selected occurred.
1637 * \param data Pointer to user data.
1639 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1640 gint column, gpointer data)
1642 AddressObject *obj = NULL;
1643 AdapterDSource *ads = NULL;
1644 AddressDataSource *ds = NULL;
1645 ItemFolder *rootFolder = NULL;
1646 AddressObjectType aot;
1648 addrbook.treeSelected = node;
1649 addrbook.listSelected = NULL;
1650 addressbook_status_show( "" );
1651 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1653 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1655 addressbook_set_clist(NULL, TRUE);
1658 addrbook.opened = node;
1660 if( obj->type == ADDR_DATASOURCE ) {
1661 /* Read from file */
1662 static gboolean tVal = TRUE;
1664 ads = ADAPTER_DSOURCE(obj);
1665 if( ads == NULL ) return;
1666 ds = ads->dataSource;
1667 if( ds == NULL ) return;
1669 if( addrindex_ds_get_modify_flag( ds ) ) {
1670 addrindex_ds_read_data( ds );
1673 if( ! addrindex_ds_get_read_flag( ds ) ) {
1674 addrindex_ds_read_data( ds );
1676 addressbook_ds_show_message( ds );
1678 if( ! addrindex_ds_get_access_flag( ds ) ) {
1679 /* Remove existing folders and groups */
1680 gtk_clist_freeze( GTK_CLIST(ctree) );
1681 addressbook_tree_remove_children( ctree, node );
1682 gtk_clist_thaw( GTK_CLIST(ctree) );
1684 /* Load folders into the tree */
1685 rootFolder = addrindex_ds_get_root_folder( ds );
1686 if( ds->type == ADDR_IF_JPILOT ) {
1687 aot = ADDR_CATEGORY;
1689 else if( ds->type == ADDR_IF_LDAP ) {
1690 aot = ADDR_LDAP_QUERY;
1693 aot = ADDR_ITEM_FOLDER;
1695 addressbook_node_add_folder( node, ds, rootFolder, aot );
1696 addrindex_ds_set_access_flag( ds, &tVal );
1697 gtk_ctree_expand( ctree, node );
1700 addressbook_set_clist(NULL, TRUE);
1703 /* Update address list */
1704 g_signal_handlers_block_by_func
1706 G_CALLBACK(addressbook_tree_selected), NULL);
1707 addressbook_set_clist( obj, FALSE );
1708 g_signal_handlers_unblock_by_func
1710 G_CALLBACK(addressbook_tree_selected), NULL);
1712 /* Setup main menu selections */
1713 addressbook_menubar_set_sensitive( FALSE );
1714 addressbook_list_menu_setup();
1715 addressbook_menuitem_set_sensitive( obj, node );
1717 addressbook_list_select_clear();
1718 addressbook_list_menu_setup();
1723 * Setup address list popup menu items. Items are enabled or disabled as
1726 static void addressbook_list_menu_setup( void ) {
1727 GtkCTree *clist = NULL;
1728 AddressObject *pobj = NULL;
1729 AddressObject *obj = NULL;
1730 AdapterDSource *ads = NULL;
1731 AddressInterface *iface = NULL;
1732 AddressDataSource *ds = NULL;
1733 gboolean canEdit = FALSE;
1734 gboolean canDelete = FALSE;
1735 gboolean canCut = FALSE;
1736 gboolean canCopy = FALSE;
1737 gboolean canPaste = FALSE;
1738 gboolean canBrowse = FALSE;
1740 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1741 if( pobj == NULL ) return;
1743 clist = GTK_CTREE(addrbook.clist);
1744 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1745 if( obj == NULL ) canEdit = FALSE;
1747 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1748 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1750 if( pobj->type == ADDR_DATASOURCE ) {
1751 /* Parent object is a data source */
1752 ads = ADAPTER_DSOURCE(pobj);
1753 ds = ads->dataSource;
1754 iface = ds->interface;
1755 if( ! iface->readOnly ) {
1756 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1757 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1758 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1759 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1760 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1761 if( obj ) canEdit = TRUE;
1763 canDelete = canEdit;
1765 else if( pobj->type != ADDR_INTERFACE ) {
1766 /* Parent object is not an interface */
1767 ds = addressbook_find_datasource( addrbook.treeSelected );
1768 iface = ds->interface;
1769 if( ! iface->readOnly ) {
1770 /* Folder or group */
1771 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1772 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1773 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1774 if( obj ) canEdit = TRUE;
1777 if( pobj->type == ADDR_ITEM_FOLDER ) {
1778 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1779 if( obj ) canEdit = TRUE;
1781 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1782 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1783 canDelete = canEdit;
1785 if( iface->type == ADDR_IF_LDAP ) {
1786 if( obj ) canBrowse = TRUE;
1791 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1793 /* Disable edit or browse if more than one row selected */
1794 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1799 /* Now go finalize menu items */
1800 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1801 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1803 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1804 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1805 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1806 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1808 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1810 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1811 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1812 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1813 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1815 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1816 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1817 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1819 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1820 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1821 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1823 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1824 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1827 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1831 static void addressbook_select_row_tree (GtkCTree *ctree,
1839 * Add list of items into tree node below specified tree node.
1840 * \param treeNode Tree node.
1841 * \param ds Data source.
1842 * \param listItems List of items.
1844 static void addressbook_treenode_add_list(
1845 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
1851 AddrItemObject *aio;
1855 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
1858 group = ( ItemGroup * ) aio;
1859 nn = addressbook_node_add_group( treeNode, ds, group );
1861 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
1864 folder = ( ItemFolder * ) aio;
1865 nn = addressbook_node_add_folder(
1866 treeNode, ds, folder, ADDR_ITEM_FOLDER );
1868 node = g_list_next( node );
1872 static void addressbook_select_all_cb( void ) {
1873 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
1877 * Cut from address list widget.
1879 static void addressbook_clip_cut_cb( void ) {
1880 _clipBoard_->cutFlag = TRUE;
1881 addrclip_clear( _clipBoard_ );
1882 addrclip_add( _clipBoard_, _addressSelect_ );
1883 /* addrclip_list_show( _clipBoard_, stdout ); */
1887 * Copy from address list widget.
1889 static void addressbook_clip_copy_cb( void ) {
1890 _clipBoard_->cutFlag = FALSE;
1891 addrclip_clear( _clipBoard_ );
1892 addrclip_add( _clipBoard_, _addressSelect_ );
1893 /* addrclip_list_show( _clipBoard_, stdout ); */
1897 * Paste clipboard into address list widget.
1899 static void addressbook_clip_paste_cb( void ) {
1900 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
1901 AddressObject *pobj = NULL;
1902 AddressDataSource *ds = NULL;
1903 AddressBookFile *abf = NULL;
1904 ItemFolder *folder = NULL;
1905 GList *folderGroup = NULL;
1907 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
1908 if( ds == NULL ) return;
1909 if( addrindex_ds_get_readonly( ds ) ) {
1910 addressbook_ds_status_message(
1911 ds, _( "Cannot paste. Target address book is readonly." ) );
1915 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
1917 if( pobj->type == ADDR_ITEM_FOLDER ) {
1918 folder = ADAPTER_FOLDER(pobj)->itemFolder;
1920 else if( pobj->type == ADDR_ITEM_GROUP ) {
1921 addressbook_ds_status_message(
1922 ds, _( "Cannot paste into an address group." ) );
1927 /* Get an address book */
1928 abf = addressbook_get_book_file();
1929 if( abf == NULL ) return;
1931 if( _clipBoard_->cutFlag ) {
1933 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
1935 /* Remove all groups and folders in clipboard from tree node */
1936 addressbook_treenode_remove_item();
1938 /* Remove all "cut" items */
1939 addrclip_delete_item( _clipBoard_ );
1941 /* Clear clipboard - cut items??? */
1942 addrclip_clear( _clipBoard_ );
1946 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
1949 /* addrclip_list_show( _clipBoard_, stdout ); */
1951 /* Update tree by inserting node for each folder or group */
1952 addressbook_treenode_add_list(
1953 addrbook.treeSelected, ds, folderGroup );
1954 gtk_ctree_expand( ctree, addrbook.treeSelected );
1955 g_list_free( folderGroup );
1959 /* Display items pasted */
1960 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
1961 addressbook_set_clist(
1962 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1970 * Add current treenode object to clipboard. Note that widget only allows
1971 * one entry from the tree list to be selected.
1973 static void addressbook_treenode_to_clipboard( void ) {
1974 AddressObject *obj = NULL;
1975 AddressDataSource *ds = NULL;
1976 AddrSelectItem *item;
1977 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
1980 node = addrbook.treeSelected;
1981 if( node == NULL ) return;
1982 obj = gtk_ctree_node_get_row_data( ctree, node );
1983 if( obj == NULL ) return;
1985 ds = addressbook_find_datasource( node );
1986 if( ds == NULL ) return;
1989 if( obj->type == ADDR_ITEM_FOLDER ) {
1990 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
1991 ItemFolder *folder = adapter->itemFolder;
1993 item = addrselect_create_node( obj );
1994 item->uid = g_strdup( ADDRITEM_ID(folder) );
1996 else if( obj->type == ADDR_ITEM_GROUP ) {
1997 AdapterGroup *adapter = ADAPTER_GROUP(obj);
1998 ItemGroup *group = adapter->itemGroup;
2000 item = addrselect_create_node( obj );
2001 item->uid = g_strdup( ADDRITEM_ID(group) );
2003 else if( obj->type == ADDR_DATASOURCE ) {
2005 item = addrselect_create_node( obj );
2010 /* Clear existing list and add item into list */
2013 addressbook_list_select_clear();
2014 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2015 addrselect_list_add( _addressSelect_, item, cacheID );
2021 * Cut from tree widget.
2023 static void addressbook_treenode_cut_cb( void ) {
2024 _clipBoard_->cutFlag = TRUE;
2025 addressbook_treenode_to_clipboard();
2026 addrclip_clear( _clipBoard_ );
2027 addrclip_add( _clipBoard_, _addressSelect_ );
2028 /* addrclip_list_show( _clipBoard_, stdout ); */
2032 * Copy from tree widget.
2034 static void addressbook_treenode_copy_cb( void ) {
2035 _clipBoard_->cutFlag = FALSE;
2036 addressbook_treenode_to_clipboard();
2037 addrclip_clear( _clipBoard_ );
2038 addrclip_add( _clipBoard_, _addressSelect_ );
2039 /* addrclip_list_show( _clipBoard_, stdout ); */
2043 * Paste clipboard into address tree widget.
2045 static void addressbook_treenode_paste_cb( void ) {
2046 addressbook_clip_paste_cb();
2050 * Clear selected entries in clipboard.
2052 static void addressbook_list_select_clear( void ) {
2053 addrselect_list_clear( _addressSelect_ );
2057 * Add specified address item to selected address list.
2058 * \param aio Address item object.
2059 * \param ds Datasource.
2061 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2064 if( ds == NULL ) return;
2065 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2066 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2071 * Remove specified address item from selected address list.
2072 * \param aio Address item object.
2074 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2075 addrselect_list_remove( _addressSelect_, aio );
2079 * Invoke EMail compose window with addresses in selected address list.
2081 static void addressbook_mail_to_cb( void ) {
2084 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2085 listAddress = addrselect_build_list( _addressSelect_ );
2086 compose_new_with_list( NULL, listAddress );
2087 mgu_free_dlist( listAddress );
2092 static void addressbook_list_row_selected( GtkCTree *clist,
2097 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2098 AddrItemObject *aio = NULL;
2099 AddressObject *pobj = NULL;
2100 AdapterDSource *ads = NULL;
2101 AddressDataSource *ds = NULL;
2103 gtk_entry_set_text( entry, "" );
2104 addrbook.listSelected = node;
2106 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2107 if( pobj == NULL ) return;
2109 if( pobj->type == ADDR_DATASOURCE ) {
2110 ads = ADAPTER_DSOURCE(pobj);
2111 ds = ads->dataSource;
2113 else if( pobj->type != ADDR_INTERFACE ) {
2114 ds = addressbook_find_datasource( addrbook.treeSelected );
2117 aio = gtk_ctree_node_get_row_data( clist, node );
2119 /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
2120 addressbook_list_select_add( aio, ds );
2123 addressbook_list_menu_setup();
2126 static void addressbook_list_row_unselected( GtkCTree *ctree,
2131 AddrItemObject *aio;
2133 aio = gtk_ctree_node_get_row_data( ctree, node );
2135 /* printf( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2136 addressbook_list_select_remove( aio );
2140 /* from gdkevents.c */
2141 #define DOUBLE_CLICK_TIME 250
2143 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2144 GdkEventButton *event,
2147 static guint32 lasttime = 0;
2148 if( ! event ) return FALSE;
2150 addressbook_list_menu_setup();
2152 if( event->button == 3 ) {
2153 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2154 event->button, event->time );
2155 } else if (event->button == 1) {
2156 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2157 if (prefs_common.add_address_by_click &&
2158 addrbook.target_compose)
2159 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2161 addressbook_edit_address_cb(NULL, 0, NULL);
2165 lasttime = event->time;
2171 static gboolean addressbook_list_button_released(GtkWidget *widget,
2172 GdkEventButton *event,
2178 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2179 GdkEventButton *event,
2182 GtkCList *clist = GTK_CLIST(ctree);
2184 AddressObject *obj = NULL;
2185 AdapterDSource *ads = NULL;
2186 AddressInterface *iface = NULL;
2187 AddressDataSource *ds = NULL;
2188 gboolean canEdit = FALSE;
2189 gboolean canDelete = FALSE;
2190 gboolean canCut = FALSE;
2191 gboolean canCopy = FALSE;
2192 gboolean canPaste = FALSE;
2193 gboolean canTreeCut = FALSE;
2194 gboolean canTreeCopy = FALSE;
2195 gboolean canTreePaste = FALSE;
2196 gboolean canLookup = FALSE;
2197 GtkCTreeNode *node = NULL;
2199 if( ! event ) return FALSE;
2200 addressbook_menubar_set_sensitive( FALSE );
2202 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2203 gtkut_clist_set_focus_row(clist, row);
2204 obj = gtk_clist_get_row_data( clist, row );
2207 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2209 if( obj == NULL ) return FALSE;
2210 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2212 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2213 canTreePaste = TRUE;
2216 if (obj->type == ADDR_INTERFACE) {
2217 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2218 iface = adapter->interface;
2221 canTreeCopy = FALSE;
2222 if( iface->readOnly ) {
2223 canTreePaste = FALSE;
2226 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2227 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2229 if( iface->externalQuery ) canLookup = TRUE;
2231 if (obj->type == ADDR_DATASOURCE) {
2232 ads = ADAPTER_DSOURCE(obj);
2233 ds = ads->dataSource;
2236 iface = ds->interface;
2241 if( iface->readOnly ) {
2242 canTreePaste = FALSE;
2245 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2246 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2247 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2250 if( iface->externalQuery ) canLookup = TRUE;
2252 else if (obj->type == ADDR_ITEM_FOLDER) {
2253 ds = addressbook_find_datasource( node );
2258 iface = ds->interface;
2261 if( iface->readOnly ) {
2262 canTreePaste = FALSE;
2268 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2269 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2270 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2274 if( iface->externalQuery ) {
2275 /* Enable deletion of LDAP folder */
2280 else if (obj->type == ADDR_ITEM_GROUP) {
2281 ds = addressbook_find_datasource( node );
2284 iface = ds->interface;
2287 if( ! iface->readOnly ) {
2290 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2291 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2294 else if (obj->type == ADDR_INTERFACE) {
2295 canTreePaste = FALSE;
2299 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2301 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2302 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2306 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2307 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2308 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2309 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2310 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2312 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2313 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2314 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2315 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2316 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2317 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2319 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2320 if( event->button == 3 ) {
2321 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2322 event->button, event->time);
2328 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2329 GdkEventButton *event,
2332 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2336 static void addressbook_new_folder_cb(gpointer data, guint action,
2339 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2340 AddressObject *obj = NULL;
2341 AddressDataSource *ds = NULL;
2342 AddressBookFile *abf = NULL;
2343 ItemFolder *parentFolder = NULL;
2344 ItemFolder *folder = NULL;
2346 if( ! addrbook.treeSelected ) return;
2347 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2348 if( obj == NULL ) return;
2349 ds = addressbook_find_datasource( addrbook.treeSelected );
2350 if( ds == NULL ) return;
2352 if( obj->type == ADDR_DATASOURCE ) {
2353 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2355 else if( obj->type == ADDR_ITEM_FOLDER ) {
2356 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2362 abf = ds->rawDataSource;
2363 if( abf == NULL ) return;
2364 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2367 nn = addressbook_node_add_folder(
2368 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2369 gtk_ctree_expand( ctree, addrbook.treeSelected );
2370 if( addrbook.treeSelected == addrbook.opened )
2371 addressbook_set_clist(obj, TRUE);
2376 static void addressbook_new_group_cb(gpointer data, guint action,
2379 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2380 AddressObject *obj = NULL;
2381 AddressDataSource *ds = NULL;
2382 AddressBookFile *abf = NULL;
2383 ItemFolder *parentFolder = NULL;
2384 ItemGroup *group = NULL;
2386 if( ! addrbook.treeSelected ) return;
2387 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2388 if( obj == NULL ) return;
2389 ds = addressbook_find_datasource( addrbook.treeSelected );
2390 if( ds == NULL ) return;
2392 if( obj->type == ADDR_DATASOURCE ) {
2393 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2395 else if( obj->type == ADDR_ITEM_FOLDER ) {
2396 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2402 abf = ds->rawDataSource;
2403 if( abf == NULL ) return;
2404 group = addressbook_edit_group( abf, parentFolder, NULL );
2407 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2408 gtk_ctree_expand( ctree, addrbook.treeSelected );
2409 if( addrbook.treeSelected == addrbook.opened )
2410 addressbook_set_clist(obj, TRUE);
2415 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2417 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2420 GdkPixmap *pix_cl, *pix_op;
2421 GdkBitmap *mask_cl, *mask_op;
2422 gboolean is_leaf, expanded;
2424 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2425 &pix_cl, &mask_cl, &pix_op, &mask_op,
2426 &is_leaf, &expanded);
2427 gtk_sctree_set_node_info(ctree, node, name, spacing,
2428 pix_cl, mask_cl, pix_op, mask_op,
2434 * \param obj Address object to edit.
2435 * \param node Node in tree.
2436 * \return New name of data source.
2438 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2439 gchar *newName = NULL;
2440 AddressDataSource *ds = NULL;
2441 AddressInterface *iface = NULL;
2442 AdapterDSource *ads = NULL;
2444 ds = addressbook_find_datasource( node );
2445 if( ds == NULL ) return NULL;
2446 iface = ds->interface;
2447 if( ! iface->haveLibrary ) return NULL;
2449 /* Read data from data source */
2450 if( addrindex_ds_get_modify_flag( ds ) ) {
2451 addrindex_ds_read_data( ds );
2454 if( ! addrindex_ds_get_read_flag( ds ) ) {
2455 addrindex_ds_read_data( ds );
2459 ads = ADAPTER_DSOURCE(obj);
2460 if( ads->subType == ADDR_BOOK ) {
2461 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2463 else if( ads->subType == ADDR_VCARD ) {
2464 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2467 else if( ads->subType == ADDR_JPILOT ) {
2468 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2472 else if( ads->subType == ADDR_LDAP ) {
2473 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2479 newName = obj->name;
2484 * Edit an object that is in the address tree area.
2486 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2489 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2491 AddressDataSource *ds = NULL;
2492 AddressBookFile *abf = NULL;
2493 GtkCTreeNode *node = NULL, *parentNode = NULL;
2496 if( ! addrbook.treeSelected ) return;
2497 node = addrbook.treeSelected;
2498 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2499 obj = gtk_ctree_node_get_row_data( ctree, node );
2500 if( obj == NULL ) return;
2501 parentNode = GTK_CTREE_ROW(node)->parent;
2503 ds = addressbook_find_datasource( node );
2504 if( ds == NULL ) return;
2506 if( obj->type == ADDR_DATASOURCE ) {
2507 name = addressbook_edit_datasource( obj, node );
2508 if( name == NULL ) return;
2511 abf = ds->rawDataSource;
2512 if( abf == NULL ) return;
2513 if( obj->type == ADDR_ITEM_FOLDER ) {
2514 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2515 ItemFolder *item = adapter->itemFolder;
2516 ItemFolder *parentFolder = NULL;
2517 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2518 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2519 name = ADDRITEM_NAME(item);
2521 else if( obj->type == ADDR_ITEM_GROUP ) {
2522 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2523 ItemGroup *item = adapter->itemGroup;
2524 ItemFolder *parentFolder = NULL;
2525 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2526 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2527 name = ADDRITEM_NAME(item);
2530 if( name && parentNode ) {
2531 /* Update node in tree view */
2532 addressbook_change_node_name( node, name );
2533 gtk_sctree_sort_node(ctree, parentNode);
2534 gtk_ctree_expand( ctree, node );
2535 gtk_sctree_select( GTK_SCTREE( ctree), node );
2542 ADDRTREE_DEL_FOLDER_ONLY,
2543 ADDRTREE_DEL_FOLDER_ADDR
2547 * Delete an item from the tree widget.
2548 * \param data Data passed in.
2549 * \param action Action.
2550 * \param widget Widget issuing callback.
2552 static void addressbook_treenode_delete_cb(
2553 gpointer data, guint action, GtkWidget *widget )
2555 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2556 GtkCTreeNode *node = NULL;
2560 AddrBookBase *adbase;
2561 AddressCache *cache;
2562 AdapterDSource *ads = NULL;
2563 AddressInterface *iface = NULL;
2564 AddressDataSource *ds = NULL;
2565 gboolean remFlag = FALSE;
2566 TreeItemDelType delType;
2568 if( ! addrbook.treeSelected ) return;
2569 node = addrbook.treeSelected;
2570 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2572 obj = gtk_ctree_node_get_row_data( ctree, node );
2573 g_return_if_fail(obj != NULL);
2575 if( obj->type == ADDR_DATASOURCE ) {
2576 ads = ADAPTER_DSOURCE(obj);
2577 if( ads == NULL ) return;
2578 ds = ads->dataSource;
2579 if( ds == NULL ) return;
2582 /* Must be folder or something else */
2583 ds = addressbook_find_datasource( node );
2584 if( ds == NULL ) return;
2586 /* Only allow deletion from non-readOnly */
2587 iface = ds->interface;
2588 if( iface->readOnly ) {
2589 /* Allow deletion of query results */
2590 if( ! iface->externalQuery ) return;
2594 /* Confirm deletion */
2595 delType = ADDRTREE_DEL_NONE;
2596 if( obj->type == ADDR_ITEM_FOLDER ) {
2597 if( iface->externalQuery ) {
2598 message = g_strdup_printf( _(
2599 "Do you want to delete the query " \
2600 "results and addresses in '%s' ?" ),
2602 aval = alertpanel( _("Delete"), message,
2603 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2605 if( aval == G_ALERTALTERNATE ) {
2606 delType = ADDRTREE_DEL_FOLDER_ADDR;
2610 message = g_strdup_printf
2611 ( _( "Do you want to delete '%s' ?"
2612 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2614 aval = alertpanel( _("Delete folder"), message,
2615 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2617 if( aval == G_ALERTALTERNATE ) {
2618 delType = ADDRTREE_DEL_FOLDER_ONLY;
2620 else if( aval == G_ALERTOTHER ) {
2621 delType = ADDRTREE_DEL_FOLDER_ADDR;
2625 else if( obj->type == ADDR_ITEM_GROUP ) {
2626 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2627 "The addresses it contains will not be lost."), obj->name);
2628 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2629 "+" GTK_STOCK_DELETE, NULL);
2631 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2633 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2634 "The addresses it contains will be lost."), obj->name);
2635 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2636 "+" GTK_STOCK_DELETE, NULL);
2638 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2640 if( delType == ADDRTREE_DEL_NONE ) return;
2642 /* Proceed with deletion */
2643 if( obj->type == ADDR_DATASOURCE ) {
2644 /* Remove node from tree */
2645 gtk_ctree_remove_node( ctree, node );
2647 /* Remove data source. */
2648 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2649 addrindex_free_datasource( ds );
2654 /* Get reference to cache */
2655 adbase = ( AddrBookBase * ) ds->rawDataSource;
2656 if( adbase == NULL ) return;
2657 cache = adbase->addressCache;
2659 /* Remove query results folder */
2660 if( iface->externalQuery ) {
2661 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2662 ItemFolder *folder = adapter->itemFolder;
2664 adapter->itemFolder = NULL;
2666 printf( "remove folder for ::%s::\n", obj->name );
2667 printf( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2668 printf( "-------------- remove results\n" );
2670 addrindex_remove_results( ds, folder );
2671 /* printf( "-------------- remove node\n" ); */
2672 gtk_ctree_remove_node( ctree, node );
2676 /* Code below is valid for regular address book deletion */
2677 if( obj->type == ADDR_ITEM_FOLDER ) {
2678 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2679 ItemFolder *item = adapter->itemFolder;
2681 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2682 /* Remove folder only */
2683 item = addrcache_remove_folder( cache, item );
2685 addritem_free_item_folder( item );
2686 addressbook_move_nodes_up( ctree, node );
2690 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2691 /* Remove folder and addresses */
2692 item = addrcache_remove_folder_delete( cache, item );
2694 addritem_free_item_folder( item );
2699 else if( obj->type == ADDR_ITEM_GROUP ) {
2700 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2701 ItemGroup *item = adapter->itemGroup;
2703 item = addrcache_remove_group( cache, item );
2705 addritem_free_item_group( item );
2712 gtk_ctree_remove_node(ctree, node );
2716 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2717 AddressObject *pobj = NULL;
2718 AddressDataSource *ds = NULL;
2719 AddressBookFile *abf = NULL;
2721 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
2722 if( pobj == NULL ) return;
2723 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2724 if( ds == NULL ) return;
2726 abf = ds->rawDataSource;
2727 if( abf == NULL ) return;
2729 if( pobj->type == ADDR_DATASOURCE ) {
2730 if( ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ) {
2732 ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE );
2733 if( person && addrbook.treeSelected == addrbook.opened ) {
2734 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2735 addressbook_folder_refresh_one_person(
2736 GTK_CTREE(addrbook.clist), person );
2740 else if( pobj->type == ADDR_ITEM_FOLDER ) {
2742 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
2743 ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE );
2745 if (addrbook.treeSelected == addrbook.opened) {
2746 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2747 addressbook_set_clist(
2748 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2754 else if( pobj->type == ADDR_ITEM_GROUP ) {
2755 /* New address in group */
2756 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
2757 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
2758 if (addrbook.treeSelected == addrbook.opened) {
2759 /* Change node name in tree. */
2760 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
2761 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2762 addressbook_set_clist(
2763 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2771 * Search for specified child group node in address index tree.
2772 * \param parent Parent node.
2773 * \param group Group to find.
2775 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
2776 GtkCTreeNode *node = NULL;
2777 GtkCTreeRow *currRow;
2779 currRow = GTK_CTREE_ROW( parent );
2781 node = currRow->children;
2785 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2786 if( obj->type == ADDR_ITEM_GROUP ) {
2787 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
2788 if( g == group ) return node;
2790 currRow = GTK_CTREE_ROW(node);
2791 node = currRow->sibling;
2797 static AddressBookFile *addressbook_get_book_file() {
2798 AddressBookFile *abf = NULL;
2799 AddressDataSource *ds = NULL;
2801 ds = addressbook_find_datasource( addrbook.treeSelected );
2802 if( ds == NULL ) return NULL;
2803 if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
2807 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
2811 /* Remove existing folders and groups */
2812 row = GTK_CTREE_ROW( parent );
2814 while( (node = row->children) ) {
2815 gtk_ctree_remove_node( ctree, node );
2820 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
2821 GtkCTreeNode *parent, *child;
2822 GtkCTreeRow *currRow;
2823 currRow = GTK_CTREE_ROW( node );
2825 parent = currRow->parent;
2826 while( (child = currRow->children) ) {
2827 gtk_ctree_move( ctree, child, parent, node );
2829 gtk_sctree_sort_node( ctree, parent );
2833 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2834 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2836 AddressObject *obj = NULL, *pobj = NULL;
2837 AddressDataSource *ds = NULL;
2838 GtkCTreeNode *node = NULL, *parentNode = NULL;
2840 AddressBookFile *abf = NULL;
2842 if( addrbook.listSelected == NULL ) return;
2843 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2844 g_return_if_fail(obj != NULL);
2846 ctree = GTK_CTREE( addrbook.ctree );
2847 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2848 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
2850 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2851 if( ds == NULL ) return;
2853 abf = addressbook_get_book_file();
2855 if( obj->type == ADDR_ITEM_EMAIL ) {
2856 ItemEMail *email = ( ItemEMail * ) obj;
2857 if( email == NULL ) return;
2858 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
2859 /* Edit parent group */
2860 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
2861 ItemGroup *itemGrp = adapter->itemGroup;
2862 if( abf == NULL ) return;
2863 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
2864 name = ADDRITEM_NAME(itemGrp);
2865 node = addrbook.treeSelected;
2866 parentNode = GTK_CTREE_ROW(node)->parent;
2869 /* Edit person - email page */
2871 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
2872 if( addressbook_edit_person( abf, NULL, person, TRUE ) == NULL ) return;
2873 addressbook_folder_refresh_one_person( clist, person );
2874 invalidate_address_completion();
2878 else if( obj->type == ADDR_ITEM_PERSON ) {
2879 /* Edit person - basic page */
2880 ItemPerson *person = ( ItemPerson * ) obj;
2881 if( addressbook_edit_person( abf, NULL, person, FALSE ) == NULL ) return;
2882 addressbook_folder_refresh_one_person( clist, person );
2883 invalidate_address_completion();
2886 else if( obj->type == ADDR_ITEM_GROUP ) {
2887 ItemGroup *itemGrp = ( ItemGroup * ) obj;
2888 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
2889 parentNode = addrbook.treeSelected;
2890 node = addressbook_find_group_node( parentNode, itemGrp );
2891 name = ADDRITEM_NAME(itemGrp);
2892 invalidate_address_completion();
2898 /* Update tree node with node name */
2899 if( node == NULL ) return;
2900 addressbook_change_node_name( node, name );
2901 gtk_sctree_sort_node( ctree, parentNode );
2902 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2903 addressbook_set_clist(
2904 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2909 static void addressbook_delete_address_cb(gpointer data, guint action,
2912 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
2913 addressbook_del_clicked(NULL, NULL);
2914 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
2917 static void close_cb(gpointer data, guint action, GtkWidget *widget)
2919 addressbook_close();
2922 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
2923 addressbook_export_to_file();
2926 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
2928 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
2929 if( person ) addritem_person_set_opened( person, TRUE );
2933 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
2935 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
2936 if( person ) addritem_person_set_opened( person, FALSE );
2940 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
2942 gchar *eMailAlias = ADDRITEM_NAME(email);
2943 if( eMailAlias && *eMailAlias != '\0' ) {
2945 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
2948 str = g_strdup( eMailAlias );
2954 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
2955 GList *items = itemGroup->listEMail;
2956 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
2957 for( ; items != NULL; items = g_list_next( items ) ) {
2958 GtkCTreeNode *nodeEMail = NULL;
2959 gchar *text[N_LIST_COLS];
2960 ItemEMail *email = items->data;
2964 if( ! email ) continue;
2966 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
2967 str = addressbook_format_item_clist( person, email );
2969 text[COL_NAME] = str;
2972 text[COL_NAME] = ADDRITEM_NAME(person);
2974 text[COL_ADDRESS] = email->address;
2975 text[COL_REMARKS] = email->remarks;
2976 nodeEMail = gtk_sctree_insert_node(
2978 text, FOLDER_SPACING,
2979 atci->iconXpm, atci->maskXpm,
2980 atci->iconXpmOpen, atci->maskXpmOpen,
2982 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
2988 static void addressbook_folder_load_one_person(
2989 GtkCTree *clist, ItemPerson *person,
2990 AddressTypeControlItem *atci,
2991 AddressTypeControlItem *atciMail )
2993 GtkCTreeNode *nodePerson = NULL;
2994 GtkCTreeNode *nodeEMail = NULL;
2995 gchar *text[N_LIST_COLS];
2996 gboolean flgFirst = TRUE, haveAddr = FALSE;
2999 if( person == NULL ) return;
3001 text[COL_NAME] = "";
3002 node = person->listEMail;
3004 ItemEMail *email = node->data;
3005 gchar *eMailAddr = NULL;
3006 node = g_list_next( node );
3008 text[COL_ADDRESS] = email->address;
3009 text[COL_REMARKS] = email->remarks;
3010 eMailAddr = ADDRITEM_NAME(email);
3011 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3013 /* First email belongs with person */
3014 gchar *str = addressbook_format_item_clist( person, email );
3016 text[COL_NAME] = str;
3019 text[COL_NAME] = ADDRITEM_NAME(person);
3021 nodePerson = gtk_sctree_insert_node(
3023 text, FOLDER_SPACING,
3024 atci->iconXpm, atci->maskXpm,
3025 atci->iconXpmOpen, atci->maskXpmOpen,
3026 FALSE, person->isOpened );
3029 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3032 /* Subsequent email is a child node of person */
3033 text[COL_NAME] = ADDRITEM_NAME(email);
3034 nodeEMail = gtk_sctree_insert_node(
3035 clist, nodePerson, NULL,
3036 text, FOLDER_SPACING,
3037 atciMail->iconXpm, atciMail->maskXpm,
3038 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3040 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3046 /* Have name without EMail */
3047 text[COL_NAME] = ADDRITEM_NAME(person);
3048 text[COL_ADDRESS] = "";
3049 text[COL_REMARKS] = "";
3050 nodePerson = gtk_sctree_insert_node(
3052 text, FOLDER_SPACING,
3053 atci->iconXpm, atci->maskXpm,
3054 atci->iconXpmOpen, atci->maskXpmOpen,
3055 FALSE, person->isOpened );
3056 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3061 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3063 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3064 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3066 if( atci == NULL ) return;
3067 if( atciMail == NULL ) return;
3069 /* Load email addresses */
3070 items = addritem_folder_get_person_list( itemFolder );
3071 for( ; items != NULL; items = g_list_next( items ) ) {
3072 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3074 /* Free up the list */
3075 mgu_clear_list( items );
3076 g_list_free( items );
3079 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3080 addrbook.listSelected = NULL;
3081 gtk_ctree_remove_node( clist, node );
3082 addressbook_menubar_set_sensitive( FALSE );
3083 addressbook_menuitem_set_sensitive(
3084 gtk_ctree_node_get_row_data(
3085 GTK_CTREE(clist), addrbook.treeSelected ),
3086 addrbook.treeSelected );
3089 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3090 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3091 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3093 if( atci == NULL ) return;
3094 if( atciMail == NULL ) return;
3095 if( person == NULL ) return;
3096 /* unload the person */
3098 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3100 addressbook_folder_remove_node( clist, node );
3101 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3102 gtk_sctree_sort_node( clist, NULL );
3103 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3105 gtk_sctree_select( GTK_SCTREE(clist), node );
3106 if (!gtk_ctree_node_is_visible( clist, node ) )
3107 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3111 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3115 if( person == NULL ) return;
3116 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3117 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3119 addressbook_folder_remove_node( clist, node );
3123 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3125 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3127 /* Load any groups */
3128 if( ! atci ) return;
3129 items = addritem_folder_get_group_list( itemFolder );
3130 for( ; items != NULL; items = g_list_next( items ) ) {
3131 GtkCTreeNode *nodeGroup = NULL;
3132 gchar *text[N_LIST_COLS];
3133 ItemGroup *group = items->data;
3134 if( group == NULL ) continue;
3135 text[COL_NAME] = ADDRITEM_NAME(group);
3136 text[COL_ADDRESS] = "";
3137 text[COL_REMARKS] = "";
3138 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3139 text, FOLDER_SPACING,
3140 atci->iconXpm, atci->maskXpm,
3141 atci->iconXpmOpen, atci->maskXpmOpen,
3143 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3144 gtk_sctree_sort_node(clist, NULL);
3146 /* Free up the list */
3147 mgu_clear_list( items );
3148 g_list_free( items );
3152 * Search ctree widget callback function.
3153 * \param pA Pointer to node.
3154 * \param pB Pointer to data item being sought.
3155 * \return Zero (0) if group found.
3157 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3160 aoA = ( AddressObject * ) pA;
3161 if( aoA->type == ADDR_ITEM_GROUP ) {
3162 ItemGroup *group, *grp;
3164 grp = ADAPTER_GROUP(aoA)->itemGroup;
3165 group = ( ItemGroup * ) pB;
3166 if( grp == group ) return 0; /* Found group */
3172 * Search ctree widget callback function.
3173 * \param pA Pointer to node.
3174 * \param pB Pointer to data item being sought.
3175 * \return Zero (0) if folder found.
3177 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3180 aoA = ( AddressObject * ) pA;
3181 if( aoA->type == ADDR_ITEM_FOLDER ) {
3182 ItemFolder *folder, *fld;
3184 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3185 folder = ( ItemFolder * ) pB;
3186 if( fld == folder ) return 0; /* Found folder */
3192 * Remove folder and group nodes from tree widget for items contained ("cut")
3195 static void addressbook_treenode_remove_item( void ) {
3197 AddrSelectItem *cutItem;
3198 AddressCache *cache;
3199 AddrItemObject *aio;
3200 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3203 node = _clipBoard_->objectList;
3205 cutItem = node->data;
3206 node = g_list_next( node );
3207 cache = addrindex_get_cache(
3208 _clipBoard_->addressIndex, cutItem->cacheID );
3209 if( cache == NULL ) continue;
3210 aio = addrcache_get_object( cache, cutItem->uid );
3213 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3216 folder = ( ItemFolder * ) aio;
3217 tn = gtk_ctree_find_by_row_data_custom(
3218 ctree, NULL, folder,
3219 addressbook_treenode_find_folder_cb );
3221 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3224 group = ( ItemGroup * ) aio;
3225 tn = gtk_ctree_find_by_row_data_custom(
3227 addressbook_treenode_find_group_cb );
3231 /* Free up adapter and remove node. */
3232 gtk_ctree_remove_node( ctree, tn );
3239 * Find parent datasource for specified tree node.
3240 * \param node Node to test.
3241 * \return Data source, or NULL if not found.
3243 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3244 AddressDataSource *ds = NULL;
3247 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3250 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3251 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3253 /* printf( "ao->type = %d\n", ao->type ); */
3254 if( ao->type == ADDR_DATASOURCE ) {
3255 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3256 /* printf( "found it\n" ); */
3257 ds = ads->dataSource;
3261 node = GTK_CTREE_ROW(node)->parent;
3267 * Load address list widget with children of specified object.
3268 * \param obj Parent object to be loaded.
3270 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3271 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3272 GtkCList *clist = GTK_CLIST(addrbook.clist);
3273 AddressDataSource *ds = NULL;
3274 AdapterDSource *ads = NULL;
3275 static AddressObject *last_obj = NULL;
3277 if (addrbook.clist == NULL) {
3280 if (obj == last_obj && !refresh)
3285 gtk_clist_clear(clist);
3289 if( obj->type == ADDR_INTERFACE ) {
3290 /* printf( "set_clist: loading datasource...\n" ); */
3291 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3295 gtk_clist_freeze(clist);
3296 gtk_clist_clear(clist);
3298 if( obj->type == ADDR_DATASOURCE ) {
3299 ads = ADAPTER_DSOURCE(obj);
3300 ds = ADAPTER_DSOURCE(obj)->dataSource;
3302 /* Load root folder */
3303 ItemFolder *rootFolder = NULL;
3304 rootFolder = addrindex_ds_get_root_folder( ds );
3305 addressbook_folder_load_person(
3306 ctreelist, addrindex_ds_get_root_folder( ds ) );
3307 addressbook_folder_load_group(
3308 ctreelist, addrindex_ds_get_root_folder( ds ) );
3312 if( obj->type == ADDR_ITEM_GROUP ) {
3314 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3315 addressbook_load_group( ctreelist, itemGroup );
3317 else if( obj->type == ADDR_ITEM_FOLDER ) {
3319 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3320 addressbook_folder_load_person( ctreelist, itemFolder );
3321 addressbook_folder_load_group( ctreelist, itemFolder );
3324 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3325 clist->focus_row = -1;
3326 gtk_clist_thaw(clist);
3330 * Call back function to free adaptor. Call back is setup by function
3331 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3332 * called when the address book tree widget node is removed by calling
3333 * function gtk_ctree_remove_node().
3335 * \param data Tree node's row data.
3337 static void addressbook_free_treenode( gpointer data ) {
3340 ao = ( AddressObject * ) data;
3341 if( ao == NULL ) return;
3342 if( ao->type == ADDR_INTERFACE ) {
3343 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3344 addrbookctl_free_interface( ai );
3346 else if( ao->type == ADDR_DATASOURCE ) {
3347 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3348 addrbookctl_free_datasource( ads );
3350 else if( ao->type == ADDR_ITEM_FOLDER ) {
3351 AdapterFolder *af = ADAPTER_FOLDER(ao);
3352 addrbookctl_free_folder( af );
3354 else if( ao->type == ADDR_ITEM_GROUP ) {
3355 AdapterGroup *ag = ADAPTER_GROUP(ao);
3356 addrbookctl_free_group( ag );
3361 * Create new adaptor for specified data source.
3363 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3364 AddressObjectType otype, gchar *name )
3366 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3367 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3368 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3369 adapter->dataSource = ds;
3370 adapter->subType = otype;
3374 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3375 ADDRESS_OBJECT_NAME(adapter) =
3376 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3380 * Load tree from address index with the initial data.
3382 static void addressbook_load_tree( void ) {
3383 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3384 GList *nodeIf, *nodeDS;
3385 AdapterInterface *adapter;
3386 AddressInterface *iface;
3387 AddressTypeControlItem *atci;
3388 AddressDataSource *ds;
3389 AdapterDSource *ads;
3390 GtkCTreeNode *node, *newNode;
3393 nodeIf = _addressInterfaceList_;
3395 adapter = nodeIf->data;
3396 node = adapter->treeNode;
3397 iface = adapter->interface;
3398 atci = adapter->atci;
3400 if( iface->useInterface ) {
3401 /* Load data sources below interface node */
3402 nodeDS = iface->listSource;
3406 name = addrindex_ds_get_name( ds );
3407 ads = addressbook_create_ds_adapter(
3408 ds, atci->objectType, name );
3409 newNode = addressbook_add_object(
3410 node, ADDRESS_OBJECT(ads) );
3411 nodeDS = g_list_next( nodeDS );
3413 gtk_ctree_expand( ctree, node );
3416 nodeIf = g_list_next( nodeIf );
3421 * Convert the old address book to new format.
3423 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3424 gboolean retVal = FALSE;
3425 gboolean errFlag = TRUE;
3428 /* Read old address book, performing conversion */
3429 debug_print( "Reading and converting old address book...\n" );
3430 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3431 addrindex_read_data( addrIndex );
3432 if( addrIndex->retVal == MGU_NO_FILE ) {
3433 /* We do not have a file - new user */
3434 debug_print( "New user... create new books...\n" );
3435 addrindex_create_new_books( addrIndex );
3436 if( addrIndex->retVal == MGU_SUCCESS ) {
3437 /* Save index file */
3438 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3439 addrindex_save_data( addrIndex );
3440 if( addrIndex->retVal == MGU_SUCCESS ) {
3445 msg = _( "New user, could not save index file." );
3449 msg = _( "New user, could not save address book files." );
3453 /* We have an old file */
3454 if( addrIndex->wasConverted ) {
3455 /* Converted successfully - save address index */
3456 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3457 addrindex_save_data( addrIndex );
3458 if( addrIndex->retVal == MGU_SUCCESS ) {
3459 msg = _( "Old address book converted successfully." );
3464 msg = _("Old address book converted,\n"
3465 "could not save new address index file." );
3469 /* File conversion failed - just create new books */
3470 debug_print( "File conversion failed... just create new books...\n" );
3471 addrindex_create_new_books( addrIndex );
3472 if( addrIndex->retVal == MGU_SUCCESS ) {
3474 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3475 addrindex_save_data( addrIndex );
3476 if( addrIndex->retVal == MGU_SUCCESS ) {
3477 msg = _("Could not convert address book,\n"
3478 "but created empty new address book files." );
3483 msg = _("Could not convert address book,\n"
3484 "could not save new address index file." );
3488 msg = _("Could not convert address book\n"
3489 "and could not create new address book files." );
3494 debug_print( "Error\n%s\n", msg );
3495 alertpanel_full(_("Addressbook conversion error"), msg,
3496 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3497 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3500 debug_print( "Warning\n%s\n", msg );
3501 alertpanel_full(_("Addressbook conversion error"), msg,
3502 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3503 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3509 void addressbook_read_file( void ) {
3510 AddressIndex *addrIndex = NULL;
3512 debug_print( "Reading address index...\n" );
3513 if( _addressIndex_ ) {
3514 debug_print( "address book already read!!!\n" );
3518 addrIndex = addrindex_create_index();
3519 addrindex_initialize();
3521 /* Use new address book index. */
3522 addrindex_set_file_path( addrIndex, get_rc_dir() );
3523 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3524 addrindex_read_data( addrIndex );
3525 if( addrIndex->retVal == MGU_NO_FILE ) {
3526 /* Conversion required */
3527 debug_print( "Converting...\n" );
3528 if( addressbook_convert( addrIndex ) ) {
3529 _addressIndex_ = addrIndex;
3532 else if( addrIndex->retVal == MGU_SUCCESS ) {
3533 _addressIndex_ = addrIndex;
3536 /* Error reading address book */
3537 debug_print( "Could not read address index.\n" );
3538 addrindex_print_index( addrIndex, stdout );
3539 alertpanel_full(_("Addressbook Error"),
3540 _("Could not read address index"),
3541 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3542 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3544 debug_print( "done.\n" );
3548 * Add object into the address index tree widget.
3549 * Enter: node Parent node.
3550 * obj Object to add.
3551 * Return: Node that was added, or NULL if object not added.
3553 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
3556 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3557 GtkCTreeNode *added;
3558 AddressObject *pobj;
3559 AddressObjectType otype;
3560 AddressTypeControlItem *atci = NULL;
3562 g_return_val_if_fail(node != NULL, NULL);
3563 g_return_val_if_fail(obj != NULL, NULL);
3565 pobj = gtk_ctree_node_get_row_data(ctree, node);
3566 g_return_val_if_fail(pobj != NULL, NULL);
3568 /* Determine object type to be displayed */
3569 if( obj->type == ADDR_DATASOURCE ) {
3570 otype = ADAPTER_DSOURCE(obj)->subType;
3576 /* Handle any special conditions. */
3578 atci = addrbookctl_lookup( otype );
3580 if( atci->showInTree ) {
3581 /* Add object to tree */
3584 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3585 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
3586 atci->treeLeaf, atci->treeExpand );
3587 gtk_ctree_node_set_row_data_full( ctree, added, obj,
3588 addressbook_free_treenode );
3592 gtk_sctree_sort_node(ctree, node);
3598 * Add group into the address index tree.
3599 * \param node Parent node.
3600 * \param ds Data source.
3601 * \param itemGroup Group to add.
3602 * \return Inserted node.
3604 static GtkCTreeNode *addressbook_node_add_group(
3605 GtkCTreeNode *node, AddressDataSource *ds,
3606 ItemGroup *itemGroup )
3608 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3609 GtkCTreeNode *newNode;
3610 AdapterGroup *adapter;
3611 AddressTypeControlItem *atci = NULL;
3614 if( ds == NULL ) return NULL;
3615 if( node == NULL || itemGroup == NULL ) return NULL;
3617 name = &itemGroup->obj.name;
3619 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3621 adapter = g_new0( AdapterGroup, 1 );
3622 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
3623 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
3624 adapter->itemGroup = itemGroup;
3626 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3627 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3628 atci->treeLeaf, atci->treeExpand );
3629 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3630 addressbook_free_treenode );
3631 gtk_sctree_sort_node( ctree, node );
3636 * Add folder into the address index tree. Only visible folders are loaded into
3637 * the address index tree. Note that the root folder is not inserted into the
3640 * \param node Parent node.
3641 * \param ds Data source.
3642 * \param itemFolder Folder to add.
3643 * \param otype Object type to display.
3644 * \return Inserted node for the folder.
3646 static GtkCTreeNode *addressbook_node_add_folder(
3647 GtkCTreeNode *node, AddressDataSource *ds,
3648 ItemFolder *itemFolder, AddressObjectType otype )
3650 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3651 GtkCTreeNode *newNode = NULL;
3652 AdapterFolder *adapter;
3653 AddressTypeControlItem *atci = NULL;
3654 GList *listItems = NULL;
3656 ItemFolder *rootFolder;
3658 /* Only visible folders */
3659 if( itemFolder->isHidden ) return NULL;
3661 if( ds == NULL ) return NULL;
3662 if( node == NULL || itemFolder == NULL ) return NULL;
3664 /* Determine object type */
3665 atci = addrbookctl_lookup( otype );
3666 if( atci == NULL ) return NULL;
3668 rootFolder = addrindex_ds_get_root_folder( ds );
3669 if( itemFolder == rootFolder ) {
3673 adapter = g_new0( AdapterFolder, 1 );
3674 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
3675 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
3676 adapter->itemFolder = itemFolder;
3678 name = ADDRITEM_NAME(itemFolder);
3679 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
3680 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3681 atci->treeLeaf, atci->treeExpand );
3683 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3684 addressbook_free_treenode );
3688 listItems = itemFolder->listFolder;
3689 while( listItems ) {
3690 ItemFolder *item = listItems->data;
3691 addressbook_node_add_folder( newNode, ds, item, otype );
3692 listItems = g_list_next( listItems );
3694 listItems = itemFolder->listGroup;
3695 while( listItems ) {
3696 ItemGroup *item = listItems->data;
3697 addressbook_node_add_group( newNode, ds, item );
3698 listItems = g_list_next( listItems );
3700 gtk_sctree_sort_node( ctree, node );
3704 void addressbook_export_to_file( void ) {
3705 if( _addressIndex_ ) {
3706 /* Save all new address book data */
3707 debug_print( "Saving address books...\n" );
3708 addrindex_save_all_books( _addressIndex_ );
3710 debug_print( "Exporting addressbook to file...\n" );
3711 addrindex_save_data( _addressIndex_ );
3712 if( _addressIndex_->retVal != MGU_SUCCESS ) {
3713 addrindex_print_index( _addressIndex_, stdout );
3716 /* Notify address completion of new data */
3717 invalidate_address_completion();
3721 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
3723 if (event && event->keyval == GDK_Return)
3724 addressbook_lup_clicked(NULL, NULL);
3729 * Comparison using cell contents (text in first column). Used for sort
3730 * address index widget.
3732 static gint addressbook_treenode_compare_func(
3733 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
3735 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
3736 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
3737 gchar *name1 = NULL, *name2 = NULL;
3738 if( cell1 ) name1 = cell1->u.text;
3739 if( cell2 ) name2 = cell2->u.text;
3740 if( ! name1 ) return ( name2 != NULL );
3741 if( ! name2 ) return -1;
3742 return g_utf8_collate( name1, name2 );
3745 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
3746 AdapterDSource *ads;
3747 AdapterInterface *adapter;
3748 GtkCTreeNode *newNode;
3750 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
3751 if( adapter == NULL ) return;
3752 ads = addressbook_edit_book( _addressIndex_, NULL );
3754 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3756 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3757 addrbook.treeSelected = newNode;
3762 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
3763 AdapterDSource *ads;
3764 AdapterInterface *adapter;
3765 GtkCTreeNode *newNode;
3767 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
3768 if( adapter == NULL ) return;
3769 ads = addressbook_edit_vcard( _addressIndex_, NULL );
3771 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3773 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3774 addrbook.treeSelected = newNode;
3780 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
3781 AdapterDSource *ads;
3782 AdapterInterface *adapter;
3783 AddressInterface *iface;
3784 GtkCTreeNode *newNode;
3786 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
3787 if( adapter == NULL ) return;
3788 iface = adapter->interface;
3789 if( ! iface->haveLibrary ) return;
3790 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
3792 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3794 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3795 addrbook.treeSelected = newNode;
3802 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
3803 AdapterDSource *ads;
3804 AdapterInterface *adapter;
3805 AddressInterface *iface;
3806 GtkCTreeNode *newNode;
3808 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
3809 if( adapter == NULL ) return;
3810 iface = adapter->interface;
3811 if( ! iface->haveLibrary ) return;
3812 ads = addressbook_edit_ldap( _addressIndex_, NULL );
3814 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3816 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3817 addrbook.treeSelected = newNode;
3824 * Display address search status message.
3825 * \param queryType Query type.
3826 * \param status Status/Error code.
3828 static void addressbook_search_message( gint queryType, gint sts ) {
3830 *addressbook_msgbuf = '\0';
3832 if( sts != MGU_SUCCESS ) {
3833 if( queryType == ADDRQUERY_LDAP ) {
3835 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
3840 g_snprintf( addressbook_msgbuf,
3841 sizeof(addressbook_msgbuf), "%s", desc );
3842 addressbook_status_show( addressbook_msgbuf );
3845 addressbook_status_show( "" );
3850 * Refresh addressbook by forcing refresh of current selected object in
3853 static void addressbook_refresh_current( void ) {
3857 ctree = GTK_CTREE(addrbook.ctree);
3858 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3859 if( obj == NULL ) return;
3860 addressbook_set_clist( obj, TRUE );
3864 * Message that is displayed whilst a query is executing in a background
3867 static gchar *_tempMessage_ = N_( "Busy searching..." );
3870 * Address search idle function. This function is called during UI idle time
3871 * while a search is in progress.
3873 * \param data Idler data.
3875 static void addressbook_search_idle( gpointer data ) {
3879 queryID = GPOINTER_TO_INT( data );
3880 printf( "addressbook_ldap_idle... queryID=%d\n", queryID );
3885 * Search completion callback function. This removes the query from the idle
3888 * \param queryID Query ID of search request.
3890 void addressbook_clear_idler( gint queryID ) {
3893 /* Remove idler function */
3894 /* printf( "addressbook_clear_idler::%d::\n", queryID ); */
3895 ptrQID = GINT_TO_POINTER( queryID );
3897 gtk_idle_remove_by_data( ptrQID );
3902 * Search completion callback function. This removes the query from the idle
3905 * \param sender Sender of query.
3906 * \param queryID Query ID of search request.
3907 * \param status Search status.
3908 * \param data Query data.
3910 static void addressbook_search_callback_end(
3911 gpointer sender, gint queryID, gint status, gpointer data )
3915 AddrQueryObject *aqo;
3917 /* Remove idler function */
3918 ptrQID = GINT_TO_POINTER( queryID );
3920 gtk_idle_remove_by_data( ptrQID );
3923 /* Refresh addressbook contents */
3924 addressbook_refresh_current();
3925 req = qrymgr_find_request( queryID );
3927 aqo = ( AddrQueryObject * ) req->queryList->data;
3928 addressbook_search_message( aqo->queryType, status );
3931 /* Stop the search */
3932 addrindex_stop_search( queryID );
3936 * Label (a format string) that is used to name each folder.
3938 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3943 * \param ds Data source to search.
3944 * \param searchTerm String to lookup.
3945 * \param pNode Parent data source node.
3947 static void addressbook_perform_search(
3948 AddressDataSource *ds, gchar *searchTerm,
3949 GtkCTreeNode *pNode )
3951 AddrBookBase *adbase;
3952 AddressCache *cache;
3955 GtkCTreeNode *nNode;
3959 AddressObjectType aoType = ADDR_NONE;
3962 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
3964 if( ds->type == ADDR_IF_LDAP ) {
3966 aoType = ADDR_LDAP_QUERY;
3973 /* Get reference to address cache */
3974 adbase = ( AddrBookBase * ) ds->rawDataSource;
3975 cache = adbase->addressCache;
3977 /* Create a folder for the search results */
3978 folder = addrcache_add_new_folder( cache, NULL );
3979 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
3980 addritem_folder_set_name( folder, name );
3981 addritem_folder_set_remarks( folder, "" );
3984 /* Now let's see the folder */
3985 ctree = GTK_CTREE(addrbook.ctree);
3986 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3987 gtk_ctree_expand( ctree, pNode );
3989 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3990 addrbook.treeSelected = nNode;
3993 /* Setup the search */
3994 queryID = addrindex_setup_explicit_search(
3995 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
3996 if( queryID == 0 ) return;
3998 /* Set up idler function */
3999 idleID = gtk_idle_add(
4000 ( GtkFunction ) addressbook_search_idle,
4001 GINT_TO_POINTER( queryID ) );
4003 /* Start search, sit back and wait for something to happen */
4004 addrindex_start_search( queryID );
4006 addressbook_status_show( _tempMessage_ );
4010 * Lookup button handler. Address search is only performed against
4011 * address interfaces for external queries.
4013 * \param button Lookup button widget.
4014 * \param data Data object.
4016 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4019 AddressDataSource *ds;
4020 AddressInterface *iface;
4022 GtkCTreeNode *node, *parentNode;
4024 node = addrbook.treeSelected;
4025 if( ! node ) return;
4026 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4028 ctree = GTK_CTREE(addrbook.ctree);
4029 obj = gtk_ctree_node_get_row_data( ctree, node );
4030 if( obj == NULL ) return;
4032 ds = addressbook_find_datasource( node );
4033 if( ds == NULL ) return;
4035 /* We must have a datasource that is an external interface */
4036 iface = ds->interface;
4037 if( ! iface->haveLibrary ) return;
4038 if( ! iface->externalQuery ) return;
4041 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4042 g_strchomp( searchTerm );
4044 if( obj->type == ADDR_ITEM_FOLDER ) {
4045 parentNode = GTK_CTREE_ROW(node)->parent;
4050 addressbook_perform_search( ds, searchTerm, parentNode );
4052 gtk_widget_grab_focus( addrbook.entry );
4054 g_free( searchTerm );
4057 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4058 addressbook_close();
4063 * Browse address entry for highlighted entry.
4065 static void addressbook_browse_entry_cb(void)
4067 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4069 AddressDataSource *ds;
4070 AddressInterface *iface;
4074 if(addrbook.listSelected == NULL)
4077 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4081 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4085 iface = ds->interface;
4086 if(! iface->haveLibrary )
4090 if (obj->type == ADDR_ITEM_EMAIL) {
4091 email = ( ItemEMail * ) obj;
4095 person = (ItemPerson *) ADDRITEM_PARENT(email);
4097 else if (obj->type == ADDR_ITEM_PERSON) {
4098 person = (ItemPerson *) obj;
4105 if( iface->type == ADDR_IF_LDAP ) {
4106 browseldap_entry(ds, person->externalID);
4111 /* **********************************************************************
4112 * Build lookup tables.
4113 * ***********************************************************************
4117 * Remap object types.
4118 * Enter: abType AddressObjectType (used in tree node).
4119 * Return: ItemObjectType (used in address cache data).
4121 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4122 ItemObjectType ioType;
4125 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4126 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4127 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4128 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4129 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4130 default: ioType = ITEMTYPE_NONE; break;
4136 * Build table that controls the rendering of object types.
4138 void addrbookctl_build_map( GtkWidget *window ) {
4139 AddressTypeControlItem *atci;
4142 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4143 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4144 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4145 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4146 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4147 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4148 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4149 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4150 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4151 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4153 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4154 _addressBookTypeList_ = NULL;
4157 atci = g_new0( AddressTypeControlItem, 1 );
4158 atci->objectType = ADDR_INTERFACE;
4159 atci->interfaceType = ADDR_IF_NONE;
4160 atci->showInTree = TRUE;
4161 atci->treeExpand = TRUE;
4162 atci->treeLeaf = FALSE;
4163 atci->displayName = _( "Interface" );
4164 atci->iconXpm = folderxpm;
4165 atci->maskXpm = folderxpmmask;
4166 atci->iconXpmOpen = folderopenxpm;
4167 atci->maskXpmOpen = folderopenxpmmask;
4168 atci->menuCommand = NULL;
4169 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4170 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4173 atci = g_new0( AddressTypeControlItem, 1 );
4174 atci->objectType = ADDR_BOOK;
4175 atci->interfaceType = ADDR_IF_BOOK;
4176 atci->showInTree = TRUE;
4177 atci->treeExpand = TRUE;
4178 atci->treeLeaf = FALSE;
4179 atci->displayName = _( "Address Book" );
4180 atci->iconXpm = bookxpm;
4181 atci->maskXpm = bookxpmmask;
4182 atci->iconXpmOpen = bookxpm;
4183 atci->maskXpmOpen = bookxpmmask;
4184 atci->menuCommand = "/Book/New Book";
4185 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4186 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4189 atci = g_new0( AddressTypeControlItem, 1 );
4190 atci->objectType = ADDR_ITEM_PERSON;
4191 atci->interfaceType = ADDR_IF_NONE;
4192 atci->showInTree = FALSE;
4193 atci->treeExpand = FALSE;
4194 atci->treeLeaf = FALSE;
4195 atci->displayName = _( "Person" );
4196 atci->iconXpm = NULL;
4197 atci->maskXpm = NULL;
4198 atci->iconXpmOpen = NULL;
4199 atci->maskXpmOpen = NULL;
4200 atci->menuCommand = NULL;
4201 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4202 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4205 atci = g_new0( AddressTypeControlItem, 1 );
4206 atci->objectType = ADDR_ITEM_EMAIL;
4207 atci->interfaceType = ADDR_IF_NONE;
4208 atci->showInTree = FALSE;
4209 atci->treeExpand = FALSE;
4210 atci->treeLeaf = TRUE;
4211 atci->displayName = _( "EMail Address" );
4212 atci->iconXpm = addressxpm;
4213 atci->maskXpm = addressxpmmask;
4214 atci->iconXpmOpen = addressxpm;
4215 atci->maskXpmOpen = addressxpmmask;
4216 atci->menuCommand = NULL;
4217 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4218 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4221 atci = g_new0( AddressTypeControlItem, 1 );
4222 atci->objectType = ADDR_ITEM_GROUP;
4223 atci->interfaceType = ADDR_IF_BOOK;
4224 atci->showInTree = TRUE;
4225 atci->treeExpand = FALSE;
4226 atci->treeLeaf = FALSE;
4227 atci->displayName = _( "Group" );
4228 atci->iconXpm = groupxpm;
4229 atci->maskXpm = groupxpmmask;
4230 atci->iconXpmOpen = groupxpm;
4231 atci->maskXpmOpen = groupxpmmask;
4232 atci->menuCommand = NULL;
4233 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4234 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4237 atci = g_new0( AddressTypeControlItem, 1 );
4238 atci->objectType = ADDR_ITEM_FOLDER;
4239 atci->interfaceType = ADDR_IF_BOOK;
4240 atci->showInTree = TRUE;
4241 atci->treeExpand = FALSE;
4242 atci->treeLeaf = FALSE;
4243 atci->displayName = _( "Folder" );
4244 atci->iconXpm = folderxpm;
4245 atci->maskXpm = folderxpmmask;
4246 atci->iconXpmOpen = folderopenxpm;
4247 atci->maskXpmOpen = folderopenxpmmask;
4248 atci->menuCommand = NULL;
4249 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4250 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4253 atci = g_new0( AddressTypeControlItem, 1 );
4254 atci->objectType = ADDR_VCARD;
4255 atci->interfaceType = ADDR_IF_VCARD;
4256 atci->showInTree = TRUE;
4257 atci->treeExpand = TRUE;
4258 atci->treeLeaf = TRUE;
4259 atci->displayName = _( "vCard" );
4260 atci->iconXpm = vcardxpm;
4261 atci->maskXpm = vcardxpmmask;
4262 atci->iconXpmOpen = vcardxpm;
4263 atci->maskXpmOpen = vcardxpmmask;
4264 atci->menuCommand = "/Book/New vCard";
4265 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4266 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4269 atci = g_new0( AddressTypeControlItem, 1 );
4270 atci->objectType = ADDR_JPILOT;
4271 atci->interfaceType = ADDR_IF_JPILOT;
4272 atci->showInTree = TRUE;
4273 atci->treeExpand = TRUE;
4274 atci->treeLeaf = FALSE;
4275 atci->displayName = _( "JPilot" );
4276 atci->iconXpm = jpilotxpm;
4277 atci->maskXpm = jpilotxpmmask;
4278 atci->iconXpmOpen = jpilotxpm;
4279 atci->maskXpmOpen = jpilotxpmmask;
4280 atci->menuCommand = "/Book/New JPilot";
4281 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4282 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4285 atci = g_new0( AddressTypeControlItem, 1 );
4286 atci->objectType = ADDR_CATEGORY;
4287 atci->interfaceType = ADDR_IF_JPILOT;
4288 atci->showInTree = TRUE;
4289 atci->treeExpand = TRUE;
4290 atci->treeLeaf = TRUE;
4291 atci->displayName = _( "JPilot" );
4292 atci->iconXpm = categoryxpm;
4293 atci->maskXpm = categoryxpmmask;
4294 atci->iconXpmOpen = categoryxpm;
4295 atci->maskXpmOpen = categoryxpmmask;
4296 atci->menuCommand = NULL;
4297 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4298 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4301 atci = g_new0( AddressTypeControlItem, 1 );
4302 atci->objectType = ADDR_LDAP;
4303 atci->interfaceType = ADDR_IF_LDAP;
4304 atci->showInTree = TRUE;
4305 atci->treeExpand = TRUE;
4306 atci->treeLeaf = FALSE;
4307 atci->displayName = _( "LDAP servers" );
4308 atci->iconXpm = ldapxpm;
4309 atci->maskXpm = ldapxpmmask;
4310 atci->iconXpmOpen = ldapxpm;
4311 atci->maskXpmOpen = ldapxpmmask;
4312 atci->menuCommand = "/Book/New LDAP Server";
4313 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4314 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4317 atci = g_new0( AddressTypeControlItem, 1 );
4318 atci->objectType = ADDR_LDAP_QUERY;
4319 atci->interfaceType = ADDR_IF_LDAP;
4320 atci->showInTree = TRUE;
4321 atci->treeExpand = FALSE;
4322 atci->treeLeaf = TRUE;
4323 atci->displayName = _( "LDAP Query" );
4324 atci->iconXpm = addrsearchxpm;
4325 atci->maskXpm = addrsearchxpmmask;
4326 atci->iconXpmOpen = addrsearchxpm;
4327 atci->maskXpmOpen = addrsearchxpmmask;
4328 atci->menuCommand = NULL;
4329 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4330 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4335 * Search for specified object type.
4337 AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4339 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4343 * Search for specified interface type.
4345 AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4346 GList *node = _addressBookTypeList_;
4348 AddressTypeControlItem *atci = node->data;
4349 if( atci->interfaceType == ifType ) return atci;
4350 node = g_list_next( node );
4355 static void addrbookctl_free_address( AddressObject *obj ) {
4356 g_free( obj->name );
4357 obj->type = ADDR_NONE;
4361 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4362 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4363 adapter->interface = NULL;
4364 adapter->interfaceType = ADDR_IF_NONE;
4365 adapter->atci = NULL;
4366 adapter->enabled = FALSE;
4367 adapter->haveLibrary = FALSE;
4368 adapter->treeNode = NULL;
4372 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4373 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4374 adapter->dataSource = NULL;
4375 adapter->subType = ADDR_NONE;
4379 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4380 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4381 adapter->itemFolder = NULL;
4385 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4386 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4387 adapter->itemGroup = NULL;
4392 * Build GUI interface list.
4394 void addrbookctl_build_iflist( void ) {
4395 AddressTypeControlItem *atci;
4396 AdapterInterface *adapter;
4399 if( _addressIndex_ == NULL ) {
4400 _addressIndex_ = addrindex_create_index();
4401 if( _clipBoard_ == NULL ) {
4402 _clipBoard_ = addrclip_create();
4404 addrclip_set_index( _clipBoard_, _addressIndex_ );
4406 _addressInterfaceList_ = NULL;
4407 list = addrindex_get_interface_list( _addressIndex_ );
4409 AddressInterface *interface = list->data;
4410 atci = addrbookctl_lookup_iface( interface->type );
4412 adapter = g_new0( AdapterInterface, 1 );
4413 adapter->interfaceType = interface->type;
4414 adapter->atci = atci;
4415 adapter->interface = interface;
4416 adapter->treeNode = NULL;
4417 adapter->enabled = TRUE;
4418 adapter->haveLibrary = interface->haveLibrary;
4419 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4420 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4421 _addressInterfaceList_ =
4422 g_list_append( _addressInterfaceList_, adapter );
4424 list = g_list_next( list );
4429 * Find GUI interface type specified interface type.
4430 * \param ifType Interface type.
4431 * \return Interface item, or NULL if not found.
4433 AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4434 GList *node = _addressInterfaceList_;
4436 AdapterInterface *adapter = node->data;
4437 if( adapter->interfaceType == ifType ) return adapter;
4438 node = g_list_next( node );
4444 * Build interface list selection.
4446 void addrbookctl_build_ifselect( void ) {
4447 GList *newList = NULL;
4452 gchar *endptr = NULL;
4454 AdapterInterface *adapter;
4456 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4459 splitStr = g_strsplit( selectStr, ",", -1 );
4460 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4462 /* printf( "%d : %s\n", i, splitStr[i] ); */
4463 ifType = strtol( splitStr[i], &endptr, 10 );
4466 if( strcmp( endptr, "/n" ) == 0 ) {
4470 /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4471 adapter = addrbookctl_find_interface( ifType );
4473 newList = g_list_append( newList, adapter );
4480 /* printf( "i=%d\n", i ); */
4481 g_strfreev( splitStr );
4482 g_free( selectStr );
4484 /* Replace existing list */
4485 mgu_clear_list( _addressIFaceSelection_ );
4486 g_list_free( _addressIFaceSelection_ );
4487 _addressIFaceSelection_ = newList;
4491 /* ***********************************************************************
4492 * Add sender to address book.
4493 * ***********************************************************************
4497 * This function is used by the Add sender to address book function.
4499 gboolean addressbook_add_contact(
4500 const gchar *name, const gchar *address, const gchar *remarks )
4502 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4503 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4504 debug_print( "addressbook_add_contact - added\n" );
4505 addressbook_refresh();
4510 /* ***********************************************************************
4511 * Book/folder selection.
4512 * ***********************************************************************
4516 * This function is used by the matcher dialog to select a book/folder.
4518 gboolean addressbook_folder_selection( gchar **folderpath )
4520 AddressBookFile *book = NULL;
4521 ItemFolder *folder = NULL;
4524 g_return_val_if_fail( folderpath != NULL, FALSE);
4528 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4530 if ( folder != NULL) {
4532 gchar *oldtmp = NULL;
4533 AddrItemObject *obj = NULL;
4535 /* walk thru folder->parent to build the full folder path */
4536 /* TODO: wwp: optimize this */
4538 tmp = g_strdup(obj->uid);
4539 while ( obj->parent ) {
4541 if ( obj->name != NULL ) {
4542 oldtmp = g_strdup(tmp);
4544 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4548 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4551 *folderpath = g_strdup_printf("%s", book->fileName);
4553 debug_print( "addressbook_foldersel: %s\n", *folderpath);
4554 return (*folderpath != NULL);
4559 /* ***********************************************************************
4560 * Book/folder checking.
4561 * ***********************************************************************
4564 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
4566 FolderInfo *fi = g_new0( FolderInfo, 1 );
4568 fi->folder = folder;
4572 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
4573 FolderInfo *fiParent, FolderPathMatch *match )
4579 FolderPathMatch *nextmatch = NULL;
4581 list = parentFolder->listFolder;
4583 folder = list->data;
4584 fName = g_strdup( ADDRITEM_NAME(folder) );
4586 /* match folder name, match pointer will be set to NULL if next recursive call
4587 doesn't need to match subfolder name */
4588 if ( match != NULL &&
4589 match->matched == FALSE ) {
4590 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
4591 /* folder name matches, prepare next subfolder match */
4592 debug_print("matched folder name '%s'\n", fName);
4594 if ( match->folder_path[match->index] == NULL ) {
4595 /* we've matched all elements */
4596 match->matched = TRUE;
4597 match->folder = folder;
4598 debug_print("book/folder path matched!\n");
4600 /* keep on matching */
4608 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
4609 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
4610 list = g_list_next( list );
4615 * This function is used by to check if a matcher book/folder path corresponds to an
4616 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
4619 gboolean addressbook_peek_folder_exists( gchar *folderpath,
4620 AddressDataSource **book,
4621 ItemFolder **folder )
4623 AddressDataSource *ds;
4624 GList *list, *nodeDS;
4625 ItemFolder *rootFolder;
4626 AddressBookFile *abf;
4628 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
4629 FolderPathMatch *nextmatch;
4636 if ( folderpath == NULL )
4639 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
4642 /* split the folder path we've received, we'll try to match this path, subpath by
4643 subpath against the book/folder structure in order */
4644 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
4646 list = addrindex_get_interface_list( _addressIndex_ );
4648 AddressInterface *interface = list->data;
4649 if ( interface->type == ADDR_IF_BOOK ) {
4650 nodeDS = interface->listSource;
4654 /* Read address book */
4655 if( ! addrindex_ds_get_read_flag( ds ) ) {
4656 addrindex_ds_read_data( ds );
4659 /* Add node for address book */
4660 abf = ds->rawDataSource;
4662 /* try to match subfolders if this book is the right book
4663 (and if there's smth to match, and not yet matched) */
4665 if ( folder_path_match.folder_path != NULL &&
4666 folder_path_match.matched == FALSE &&
4667 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
4668 debug_print("matched book name '%s'\n", abf->fileName);
4669 folder_path_match.index = 1;
4670 if ( folder_path_match.folder_path[folder_path_match.index] == NULL ) {
4671 /* we've matched all elements */
4672 folder_path_match.matched = TRUE;
4673 folder_path_match.book = ds;
4674 debug_print("book path matched!\n");
4676 /* keep on matching */
4677 nextmatch = &folder_path_match;
4681 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
4683 rootFolder = addrindex_ds_get_root_folder( ds );
4684 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, nextmatch );
4686 nodeDS = g_list_next( nodeDS );
4689 list = g_list_next( list );
4692 g_strfreev( folder_path_match.folder_path );
4695 *book = folder_path_match.book;
4697 *folder = folder_path_match.folder;
4698 return folder_path_match.matched;
4702 /* **********************************************************************
4704 * ***********************************************************************
4710 static void addressbook_import_ldif_cb( void ) {
4711 AddressDataSource *ds = NULL;
4712 AdapterDSource *ads = NULL;
4713 AddressBookFile *abf = NULL;
4714 AdapterInterface *adapter;
4715 GtkCTreeNode *newNode;
4717 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4719 if( adapter->treeNode ) {
4720 abf = addressbook_imp_ldif( _addressIndex_ );
4722 ds = addrindex_index_add_datasource(
4723 _addressIndex_, ADDR_IF_BOOK, abf );
4724 ads = addressbook_create_ds_adapter(
4725 ds, ADDR_BOOK, NULL );
4726 addressbook_ads_set_name(
4727 ads, addrbook_get_name( abf ) );
4728 newNode = addressbook_add_object(
4730 ADDRESS_OBJECT(ads) );
4732 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4734 addrbook.treeSelected = newNode;
4737 /* Notify address completion */
4738 invalidate_address_completion();
4747 static void addressbook_import_mutt_cb( void ) {
4748 AddressDataSource *ds = NULL;
4749 AdapterDSource *ads = NULL;
4750 AddressBookFile *abf = NULL;
4751 AdapterInterface *adapter;
4752 GtkCTreeNode *newNode;
4754 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4756 if( adapter->treeNode ) {
4757 abf = addressbook_imp_mutt( _addressIndex_ );
4759 ds = addrindex_index_add_datasource(
4760 _addressIndex_, ADDR_IF_BOOK, abf );
4761 ads = addressbook_create_ds_adapter(
4762 ds, ADDR_BOOK, NULL );
4763 addressbook_ads_set_name(
4764 ads, addrbook_get_name( abf ) );
4765 newNode = addressbook_add_object(
4767 ADDRESS_OBJECT(ads) );
4769 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4771 addrbook.treeSelected = newNode;
4774 /* Notify address completion */
4775 invalidate_address_completion();
4784 static void addressbook_import_pine_cb( void ) {
4785 AddressDataSource *ds = NULL;
4786 AdapterDSource *ads = NULL;
4787 AddressBookFile *abf = NULL;
4788 AdapterInterface *adapter;
4789 GtkCTreeNode *newNode;
4791 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4793 if( adapter->treeNode ) {
4794 abf = addressbook_imp_pine( _addressIndex_ );
4796 ds = addrindex_index_add_datasource(
4797 _addressIndex_, ADDR_IF_BOOK, abf );
4798 ads = addressbook_create_ds_adapter(
4799 ds, ADDR_BOOK, NULL );
4800 addressbook_ads_set_name(
4801 ads, addrbook_get_name( abf ) );
4802 newNode = addressbook_add_object(
4804 ADDRESS_OBJECT(ads) );
4806 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4808 addrbook.treeSelected = newNode;
4811 /* Notify address completion */
4812 invalidate_address_completion();
4819 * Harvest addresses.
4820 * \param folderItem Folder to import.
4821 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
4822 * \param msgList List of message numbers, or NULL to process folder.
4824 void addressbook_harvest(
4825 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
4827 AddressDataSource *ds = NULL;
4828 AdapterDSource *ads = NULL;
4829 AddressBookFile *abf = NULL;
4830 AdapterInterface *adapter;
4831 GtkCTreeNode *newNode;
4833 abf = addrgather_dlg_execute(
4834 folderItem, _addressIndex_, sourceInd, msgList );
4836 ds = addrindex_index_add_datasource(
4837 _addressIndex_, ADDR_IF_BOOK, abf );
4839 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4841 if( adapter->treeNode ) {
4842 ads = addressbook_create_ds_adapter(
4843 ds, ADDR_BOOK, addrbook_get_name( abf ) );
4844 newNode = addressbook_add_object(
4846 ADDRESS_OBJECT(ads) );
4850 /* Notify address completion */
4851 invalidate_address_completion();
4858 static void addressbook_export_html_cb( void ) {
4859 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4861 AddressDataSource *ds = NULL;
4862 AddrBookBase *adbase;
4863 AddressCache *cache;
4864 GtkCTreeNode *node = NULL;
4866 if( ! addrbook.treeSelected ) return;
4867 node = addrbook.treeSelected;
4868 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4869 obj = gtk_ctree_node_get_row_data( ctree, node );
4870 if( obj == NULL ) return;
4872 ds = addressbook_find_datasource( node );
4873 if( ds == NULL ) return;
4874 adbase = ( AddrBookBase * ) ds->rawDataSource;
4875 cache = adbase->addressCache;
4876 addressbook_exp_html( cache );
4882 static void addressbook_export_ldif_cb( void ) {
4883 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4885 AddressDataSource *ds = NULL;
4886 AddrBookBase *adbase;
4887 AddressCache *cache;
4888 GtkCTreeNode *node = NULL;
4890 if( ! addrbook.treeSelected ) return;
4891 node = addrbook.treeSelected;
4892 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4893 obj = gtk_ctree_node_get_row_data( ctree, node );
4894 if( obj == NULL ) return;
4896 ds = addressbook_find_datasource( node );
4897 if( ds == NULL ) return;
4898 adbase = ( AddrBookBase * ) ds->rawDataSource;
4899 cache = adbase->addressCache;
4900 addressbook_exp_ldif( cache );
4903 static void addressbook_start_drag(GtkWidget *widget, gint button,
4907 GdkDragContext *context;
4908 if (addressbook_target_list == NULL)
4909 addressbook_target_list = gtk_target_list_new(
4910 addressbook_drag_types, 1);
4911 context = gtk_drag_begin(widget, addressbook_target_list,
4912 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
4913 gtk_drag_set_icon_default(context);
4916 static void addressbook_drag_data_get(GtkWidget *widget,
4917 GdkDragContext *drag_context,
4918 GtkSelectionData *selection_data,
4923 AddrItemObject *aio = NULL;
4924 AddressObject *pobj = NULL;
4925 AdapterDSource *ads = NULL;
4926 AddressDataSource *ds = NULL;
4929 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
4931 if( pobj == NULL ) return;
4933 if( pobj->type == ADDR_DATASOURCE ) {
4934 ads = ADAPTER_DSOURCE(pobj);
4935 ds = ads->dataSource;
4936 } else if (pobj->type == ADDR_ITEM_GROUP) {
4941 else if( pobj->type != ADDR_INTERFACE ) {
4942 ds = addressbook_find_datasource( addrbook.treeSelected );
4948 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
4949 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
4950 GTK_CTREE_NODE(cur->data));
4951 while (aio && aio->type != ADDR_ITEM_PERSON) {
4956 if (aio && aio->type == ADDR_ITEM_PERSON) {
4957 if( ds && ds->interface && ds->interface->readOnly)
4958 gtk_selection_data_set(selection_data,
4959 selection_data->target, 8,
4960 "Dummy_addr_copy", 15);
4962 gtk_selection_data_set(selection_data,
4963 selection_data->target, 8,
4964 "Dummy_addr_move", 15);
4968 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
4969 GdkDragContext *context,
4976 GtkCTreeNode *node = NULL;
4977 gboolean acceptable = FALSE;
4978 gint height = addrbook.ctree->allocation.height;
4979 gint total_height = addrbook.ctree->requisition.height;
4980 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
4981 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
4982 gfloat vpos = pos->value;
4984 if (gtk_clist_get_selection_info
4985 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
4987 if (y > height - 24 && height + vpos < total_height)
4988 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
4990 if (y < 24 && y > 0)
4991 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
4993 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
4996 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
4997 if( obj->type == ADDR_ITEM_FOLDER
4998 || obj->type == ADDR_ITEM_GROUP)
5001 AdapterDSource *ads = NULL;
5002 AddressDataSource *ds = NULL;
5003 ads = ADAPTER_DSOURCE(obj);
5004 if (ads == NULL ){ return FALSE;}
5005 ds = ads->dataSource;
5006 if (ds == NULL ) { return FALSE;}
5014 g_signal_handlers_block_by_func
5016 G_CALLBACK(addressbook_tree_selected), NULL);
5017 gtk_sctree_select( GTK_SCTREE(widget), node);
5018 g_signal_handlers_unblock_by_func
5020 G_CALLBACK(addressbook_tree_selected), NULL);
5021 gdk_drag_status(context,
5022 (context->actions == GDK_ACTION_COPY ?
5023 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5025 gdk_drag_status(context, 0, time);
5031 static void addressbook_drag_leave_cb(GtkWidget *widget,
5032 GdkDragContext *context,
5036 if (addrbook.treeSelected) {
5037 g_signal_handlers_block_by_func
5039 G_CALLBACK(addressbook_tree_selected), NULL);
5040 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5041 g_signal_handlers_unblock_by_func
5043 G_CALLBACK(addressbook_tree_selected), NULL);
5048 static void addressbook_drag_received_cb(GtkWidget *widget,
5049 GdkDragContext *drag_context,
5052 GtkSelectionData *data,
5059 GtkCTreeNode *lastopened = addrbook.opened;
5061 if (!strncmp(data->data, "Dummy_addr", 10)) {
5062 if (gtk_clist_get_selection_info
5063 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5067 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5068 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5071 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5072 if (drag_context->action == GDK_ACTION_COPY ||
5073 !strcmp(data->data, "Dummy_addr_copy"))
5074 addressbook_clip_copy_cb();
5076 addressbook_clip_cut_cb();
5077 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5078 addressbook_clip_paste_cb();
5079 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5080 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5081 gtk_drag_finish(drag_context, TRUE, TRUE, time);