2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "claws-features.h"
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
32 #include <sys/types.h>
36 #include "addressbook.h"
37 #include "manage_window.h"
38 #include "prefs_common.h"
39 #include "alertpanel.h"
40 #include "inputdialog.h"
42 #include "stock_pixmap.h"
44 #include "prefs_gtk.h"
46 #include "file-utils.h"
51 #include "addr_compl.h"
55 #include "addressitem.h"
57 #include "addrcache.h"
59 #include "addrindex.h"
60 #include "addrmerge.h"
61 #include "addressadd.h"
62 #include "addrduplicates.h"
63 #include "addressbook_foldersel.h"
65 #include "editvcard.h"
66 #include "editgroup.h"
67 #include "editaddress.h"
69 #include "importldif.h"
70 #include "importmutt.h"
71 #include "importpine.h"
76 #include "editjpilot.h"
81 #include "ldapserver.h"
83 #include "ldapupdate.h"
85 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
88 #include "addrquery.h"
89 #include "addrselect.h"
91 #include "addrgather.h"
92 #include "adbookbase.h"
93 #include "exphtmldlg.h"
94 #include "expldifdlg.h"
95 #include "browseldap.h"
96 #include "addrcustomattr.h"
104 } AddressIndexColumns
;
112 } AddressListColumns
;
115 AddressBookFile
*book
;
123 AddressDataSource
*book
;
127 static gchar
*list_titles
[] = { N_("Name"),
131 #define COL_NAME_WIDTH 164
132 #define COL_ADDRESS_WIDTH 156
134 #define COL_FOLDER_WIDTH 170
135 #define ADDRESSBOOK_WIDTH 640
136 #define ADDRESSBOOK_HEIGHT 360
138 #define ADDRESSBOOK_MSGBUF_SIZE 2048
140 static GdkPixbuf
*folderxpm
= NULL
;
141 static GdkPixbuf
*folderopenxpm
= NULL
;
142 static GdkPixbuf
*groupxpm
= NULL
;
143 static GdkPixbuf
*interfacexpm
= NULL
;
144 static GdkPixbuf
*bookxpm
= NULL
;
145 static GdkPixbuf
*addressxpm
= NULL
;
146 static GdkPixbuf
*vcardxpm
= NULL
;
147 static GdkPixbuf
*jpilotxpm
= NULL
;
148 static GdkPixbuf
*categoryxpm
= NULL
;
149 static GdkPixbuf
*ldapxpm
= NULL
;
150 static GdkPixbuf
*addrsearchxpm
= NULL
;
153 static gchar addressbook_msgbuf
[ ADDRESSBOOK_MSGBUF_SIZE
];
155 /* Address list selection */
156 static AddrSelectList
*_addressSelect_
= NULL
;
157 static AddressClipboard
*_clipBoard_
= NULL
;
159 /* Address index file and interfaces */
160 static AddressIndex
*_addressIndex_
= NULL
;
161 static GList
*_addressInterfaceList_
= NULL
;
162 static GList
*_addressIFaceSelection_
= NULL
;
163 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
165 static AddressBook_win addrbook
;
167 static GHashTable
*_addressBookTypeHash_
= NULL
;
168 static GList
*_addressBookTypeList_
= NULL
;
170 static void addressbook_new_address_from_book_post_cb( ItemPerson
*person
);
171 static void addressbook_new_address_from_folder_post_cb( ItemPerson
*person
);
172 static void addressbook_edit_address_post_cb( ItemPerson
*person
);
174 static void addressbook_create (void);
175 static gint
addressbook_close (void);
177 static gboolean address_index_has_focus
= FALSE
;
178 static gboolean address_list_has_focus
= FALSE
;
180 /* callback functions */
181 static void addressbook_del_clicked (GtkButton
*button
,
183 static void addressbook_reg_clicked (GtkButton
*button
,
185 static void addressbook_to_clicked (GtkButton
*button
,
187 static void addressbook_lup_clicked (GtkButton
*button
,
189 static void addressbook_close_clicked (GtkButton
*button
,
192 static void addressbook_tree_selected (GtkCMCTree
*ctree
,
193 GtkCMCTreeNode
*node
,
196 static void addressbook_select_row_tree (GtkCMCTree
*ctree
,
197 GtkCMCTreeNode
*node
,
200 static void addressbook_list_row_selected (GtkCMCTree
*clist
,
201 GtkCMCTreeNode
*node
,
204 static void addressbook_list_row_unselected (GtkCMCTree
*clist
,
205 GtkCMCTreeNode
*node
,
208 static void addressbook_person_expand_node (GtkCMCTree
*ctree
,
211 static void addressbook_person_collapse_node (GtkCMCTree
*ctree
,
215 static void addressbook_entry_activated (GtkWidget
*widget
,
218 static gboolean
addressbook_list_button_pressed (GtkWidget
*widget
,
219 GdkEventButton
*event
,
221 static gboolean
addressbook_list_button_released(GtkWidget
*widget
,
222 GdkEventButton
*event
,
224 static gboolean
addressbook_tree_button_pressed (GtkWidget
*ctree
,
225 GdkEventButton
*event
,
227 static gboolean
addressbook_tree_button_released(GtkWidget
*ctree
,
228 GdkEventButton
*event
,
231 static void addressbook_new_folder_cb (GtkAction
*action
,
233 static void addressbook_new_group_cb (GtkAction
*action
,
235 static void addressbook_treenode_edit_cb (GtkAction
*action
,
237 static void addressbook_treenode_delete_cb (GtkAction
*action
,
240 static void addressbook_change_node_name (GtkCMCTreeNode
*node
,
243 static void addressbook_new_address_cb (GtkAction
*action
,
245 static void addressbook_edit_address_cb (GtkAction
*action
,
247 static void addressbook_delete_address_cb (GtkAction
*action
,
250 static void close_cb (GtkAction
*action
,
252 static void addressbook_file_save_cb (GtkAction
*action
,
255 /* Data source edit stuff */
256 static void addressbook_new_book_cb (GtkAction
*action
,
258 static void addressbook_new_vcard_cb (GtkAction
*action
,
262 static void addressbook_new_jpilot_cb (GtkAction
*action
,
267 static void addressbook_new_ldap_cb (GtkAction
*action
,
271 static void addressbook_set_clist (AddressObject
*obj
,
274 static void addressbook_load_tree (void);
275 void addressbook_read_file (void);
277 static GtkCMCTreeNode
*addressbook_add_object (GtkCMCTreeNode
*node
,
279 static void addressbook_treenode_remove_item ( void );
281 static AddressDataSource
*addressbook_find_datasource
282 (GtkCMCTreeNode
*node
);
284 static AddressBookFile
*addressbook_get_book_file(void);
286 static GtkCMCTreeNode
*addressbook_node_add_folder
287 (GtkCMCTreeNode
*node
,
288 AddressDataSource
*ds
,
289 ItemFolder
*itemFolder
,
290 AddressObjectType otype
);
291 static GtkCMCTreeNode
*addressbook_node_add_group (GtkCMCTreeNode
*node
,
292 AddressDataSource
*ds
,
293 ItemGroup
*itemGroup
);
294 static void addressbook_tree_remove_children (GtkCMCTree
*ctree
,
295 GtkCMCTreeNode
*parent
);
296 static void addressbook_move_nodes_up (GtkCMCTree
*ctree
,
297 GtkCMCTreeNode
*node
);
298 static GtkCMCTreeNode
*addressbook_find_group_node (GtkCMCTreeNode
*parent
,
300 static gboolean
addressbook_entry_key_pressed (GtkWidget
*widget
,
303 static gint
addressbook_treenode_compare_func (GtkCMCList
*clist
,
306 static void addressbook_folder_load_one_person (GtkCMCTree
*clist
,
308 AddressTypeControlItem
*atci
,
309 AddressTypeControlItem
*atciMail
);
310 static void addressbook_folder_remove_node (GtkCMCTree
*clist
,
311 GtkCMCTreeNode
*node
);
313 static void addressbook_edit_address( gpointer data
, guint action
, GtkWidget
*widget
,
314 gboolean force_focus
);
316 /* LUT's and IF stuff */
317 static void addressbook_free_treenode ( gpointer data
);
318 static AddressTypeControlItem
*addrbookctl_lookup (gint ot
);
319 static AddressTypeControlItem
*addrbookctl_lookup_iface(AddressIfType ifType
);
321 static void addrbookctl_build_map (GtkWidget
*window
);
322 static void addrbookctl_build_iflist (void);
323 static AdapterInterface
*addrbookctl_find_interface (AddressIfType ifType
);
324 static void addrbookctl_build_ifselect (void);
326 static void addrbookctl_free_interface (AdapterInterface
*adapter
);
327 static void addrbookctl_free_datasource (AdapterDSource
*adapter
);
328 static void addrbookctl_free_folder (AdapterFolder
*adapter
);
329 static void addrbookctl_free_group (AdapterGroup
*adapter
);
331 static void addressbook_list_select_clear ( void );
332 static void addressbook_list_select_add ( AddrItemObject
*aio
,
333 AddressDataSource
*ds
);
334 static void addressbook_list_select_remove ( AddrItemObject
*aio
);
336 static void addressbook_import_ldif_cb ( GtkAction
*action
, gpointer data
);
337 static void addressbook_find_duplicates_cb ( GtkAction
*action
, gpointer data
);
338 static void addressbook_edit_custom_attr_cb ( GtkAction
*action
, gpointer data
);
339 static void addressbook_import_mutt_cb ( GtkAction
*action
, gpointer data
);
340 static void addressbook_import_pine_cb ( GtkAction
*action
, gpointer data
);
341 static void addressbook_export_html_cb ( GtkAction
*action
, gpointer data
);
342 static void addressbook_export_ldif_cb ( GtkAction
*action
, gpointer data
);
343 static void addressbook_select_all_cb ( GtkAction
*action
, gpointer data
);
344 static void addressbook_clip_cut_cb ( GtkAction
*action
, gpointer data
);
345 static void addressbook_clip_copy_cb ( GtkAction
*action
, gpointer data
);
346 static void addressbook_clip_paste_cb ( GtkAction
*action
, gpointer data
);
347 static void addressbook_treenode_cut_cb ( GtkAction
*action
, gpointer data
);
348 static void addressbook_treenode_copy_cb ( GtkAction
*action
, gpointer data
);
349 static void addressbook_treenode_paste_cb ( GtkAction
*action
, gpointer data
);
351 static void addressbook_mail_to_cb ( GtkAction
*action
, gpointer data
);
352 static void addressbook_merge_cb ( GtkAction
*action
, gpointer data
);
355 static void addressbook_browse_entry_cb ( GtkAction
*action
, gpointer data
);
357 static void addressbook_edit_clicked(GtkButton
*button
, gpointer data
);
359 static void addressbook_start_drag(GtkWidget
*widget
, gint button
,
362 static void addressbook_drag_data_get(GtkWidget
*widget
,
363 GdkDragContext
*drag_context
,
364 GtkSelectionData
*selection_data
,
368 static gboolean
addressbook_drag_motion_cb(GtkWidget
*widget
,
369 GdkDragContext
*context
,
374 static void addressbook_drag_leave_cb(GtkWidget
*widget
,
375 GdkDragContext
*context
,
378 static void addressbook_drag_received_cb(GtkWidget
*widget
,
379 GdkDragContext
*drag_context
,
382 GtkSelectionData
*data
,
386 static void addressbook_list_menu_setup( void );
388 static GtkTargetEntry addressbook_drag_types
[] =
390 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
}
393 static GtkTargetList
*addressbook_target_list
= NULL
;
395 static GtkActionEntry addressbook_entries
[] =
397 {"Menu", NULL
, "Menu", NULL
, NULL
, NULL
},
399 {"Book", NULL
, N_("_Book"), NULL
, NULL
, NULL
},
400 {"Edit", NULL
, N_("_Edit"), NULL
, NULL
, NULL
},
401 {"Tools", NULL
, N_("_Tools"), NULL
, NULL
, NULL
},
404 {"Book/NewBook", NULL
, N_("New _Book"), "<control>B", NULL
, G_CALLBACK(addressbook_new_book_cb
) },
405 {"Book/NewFolder", NULL
, N_("New _Folder"), "<control>R", NULL
, G_CALLBACK(addressbook_new_folder_cb
) },
406 {"Book/NewVCard", NULL
, N_("New _vCard"), "<control><shift>D", NULL
, G_CALLBACK(addressbook_new_vcard_cb
) },
410 {"Book/NewJPilot", NULL
, N_("New _JPilot"), "<control>J", NULL
, G_CALLBACK(addressbook_new_jpilot_cb
) },
413 {"Book/NewLDAPServer", NULL
, N_("New LDAP _Server"), "<control><shift>S", NULL
, G_CALLBACK(addressbook_new_ldap_cb
) },
415 {"Book/---", NULL
, "---", NULL
, NULL
, NULL
},
417 {"Book/EditBook", NULL
, N_("_Edit book"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_edit_cb
) },
418 {"Book/DeleteBook", NULL
, N_("_Delete book"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_delete_cb
) },
419 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
420 {"Book/Save", NULL
, N_("_Save"), "<control>S", NULL
, G_CALLBACK(addressbook_file_save_cb
) },
421 {"Book/Close", NULL
, N_("_Close"), "<control>W", NULL
, G_CALLBACK(close_cb
) },
424 {"Address/SelectAll", NULL
, N_("_Select all"), "<control>A", NULL
, G_CALLBACK(addressbook_select_all_cb
) },
425 {"Address/---", NULL
, "---", NULL
, NULL
, NULL
},
426 {"Address/Cut", NULL
, N_("C_ut"), "<control>X", NULL
, G_CALLBACK(addressbook_clip_cut_cb
) },
427 {"Address/Copy", NULL
, N_("_Copy"), "<control>C", NULL
, G_CALLBACK(addressbook_clip_copy_cb
) },
428 {"Address/Paste", NULL
, N_("_Paste"), "<control>V", NULL
, G_CALLBACK(addressbook_clip_paste_cb
) },
429 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
430 {"Address/Edit", NULL
, N_("_Edit"), "<control>Return", NULL
, G_CALLBACK(addressbook_edit_address_cb
) },
431 {"Address/Delete", NULL
, N_("_Delete"), "<control>D", NULL
, G_CALLBACK(addressbook_delete_address_cb
) },
432 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
433 {"Address/NewAddress", NULL
, N_("New _Address"), "<control>N", NULL
, G_CALLBACK(addressbook_new_address_cb
) },
434 {"Address/NewGroup", NULL
, N_("New _Group"), "<control>G", NULL
, G_CALLBACK(addressbook_new_group_cb
) },
435 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
436 {"Address/Mailto", NULL
, N_("_Mail To"), "<control>M", NULL
, G_CALLBACK(addressbook_mail_to_cb
) },
437 {"Address/Merge", NULL
, N_("_Merge"), "<control>E", NULL
, G_CALLBACK(addressbook_merge_cb
) },
441 {"Tools/ImportLDIF", NULL
, N_("Import _LDIF file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_ldif_cb
) },
442 {"Tools/ImportMutt", NULL
, N_("Import M_utt file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_mutt_cb
) },
443 {"Tools/ImportPine", NULL
, N_("Import _Pine file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_pine_cb
) },
444 {"Tools/---", NULL
, "---", NULL
, NULL
, NULL
},
445 {"Tools/ExportHTML", NULL
, N_("Export _HTML..."), NULL
, NULL
, G_CALLBACK(addressbook_export_html_cb
) },
446 {"Tools/ExportLDIF", NULL
, N_("Export LDI_F..."), NULL
, NULL
, G_CALLBACK(addressbook_export_ldif_cb
) },
447 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
448 {"Tools/FindDuplicates", NULL
, N_("Find duplicates..."), NULL
, NULL
, G_CALLBACK(addressbook_find_duplicates_cb
) },
449 {"Tools/EditAttrs", NULL
, N_("Edit custom attributes..."), NULL
, NULL
, G_CALLBACK(addressbook_edit_custom_attr_cb
) },
452 static GtkActionEntry addressbook_tree_popup_entries
[] =
454 {"ABTreePopup", NULL
, "ABTreePopup", NULL
, NULL
, NULL
},
455 {"ABTreePopup/EditBook", NULL
, N_("_Edit"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_edit_cb
) },
456 {"ABTreePopup/DeleteBook", NULL
, N_("_Delete"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_delete_cb
) },
457 {"ABTreePopup/---", NULL
, "---", NULL
, NULL
, NULL
},
458 {"ABTreePopup/NewBook", NULL
, N_("New _Book"), NULL
, NULL
, G_CALLBACK(addressbook_new_book_cb
) },
459 {"ABTreePopup/NewFolder", NULL
, N_("New _Folder"), NULL
, NULL
, G_CALLBACK(addressbook_new_folder_cb
) },
460 {"ABTreePopup/NewGroup", NULL
, N_("New _Group"), NULL
, NULL
, G_CALLBACK(addressbook_new_group_cb
) },
461 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
462 {"ABTreePopup/Cut", NULL
, N_("C_ut"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_cut_cb
) },
463 {"ABTreePopup/Copy", NULL
, N_("_Copy"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_copy_cb
) },
464 {"ABTreePopup/Paste", NULL
, N_("_Paste"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_paste_cb
) },
467 static GtkActionEntry addressbook_list_popup_entries
[] =
469 {"ABListPopup", NULL
, "ABListPopup", NULL
, NULL
, NULL
},
470 {"ABListPopup/SelectAll", NULL
, N_("_Select all"), NULL
, NULL
, G_CALLBACK(addressbook_select_all_cb
) },
471 {"ABListPopup/---", NULL
, "---", NULL
, NULL
, NULL
},
472 {"ABListPopup/Edit", NULL
, N_("_Edit"), NULL
, NULL
, G_CALLBACK(addressbook_edit_address_cb
) },
473 {"ABListPopup/Delete", NULL
, N_("_Delete"), NULL
, NULL
, G_CALLBACK(addressbook_delete_address_cb
) },
474 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
475 {"ABListPopup/NewAddress", NULL
, N_("New _Address"), NULL
, NULL
, G_CALLBACK(addressbook_new_address_cb
) },
476 {"ABListPopup/NewGroup", NULL
, N_("New _Group"), NULL
, NULL
, G_CALLBACK(addressbook_new_group_cb
) },
477 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
478 {"ABListPopup/Cut", NULL
, N_("C_ut"), NULL
, NULL
, G_CALLBACK(addressbook_clip_cut_cb
) },
479 {"ABListPopup/Copy", NULL
, N_("_Copy"), NULL
, NULL
, G_CALLBACK(addressbook_clip_copy_cb
) },
480 {"ABListPopup/Paste", NULL
, N_("_Paste"), NULL
, NULL
, G_CALLBACK(addressbook_clip_paste_cb
) },
481 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
482 {"ABListPopup/Mailto", NULL
, N_("_Mail To"), NULL
, NULL
, G_CALLBACK(addressbook_mail_to_cb
) },
484 {"ABListPopup/BrowseEntry", NULL
, N_("_Browse Entry"), NULL
, NULL
, G_CALLBACK(addressbook_browse_entry_cb
) },
486 {"ABListPopup/Merge", NULL
, N_("_Merge"), NULL
, NULL
, G_CALLBACK(addressbook_merge_cb
) },
490 * Structure of error message table.
492 typedef struct _ErrMsgTableEntry ErrMsgTableEntry
;
493 struct _ErrMsgTableEntry
{
498 static gchar
*_errMsgUnknown_
= N_( "Unknown" );
501 * Lookup table of error messages for general errors. Note that a NULL
502 * description signifies the end of the table.
504 static ErrMsgTableEntry _lutErrorsGeneral_
[] = {
505 { MGU_SUCCESS
, N_("Success") },
506 { MGU_BAD_ARGS
, N_("Bad arguments") },
507 { MGU_NO_FILE
, N_("File not specified") },
508 { MGU_OPEN_FILE
, N_("Error opening file") },
509 { MGU_ERROR_READ
, N_("Error reading file") },
510 { MGU_EOF
, N_("End of file encountered") },
511 { MGU_OO_MEMORY
, N_("Error allocating memory") },
512 { MGU_BAD_FORMAT
, N_("Bad file format") },
513 { MGU_ERROR_WRITE
, N_("Error writing to file") },
514 { MGU_OPEN_DIRECTORY
, N_("Error opening directory") },
515 { MGU_NO_PATH
, N_("No path specified") },
521 * Lookup table of error messages for LDAP errors.
523 static ErrMsgTableEntry _lutErrorsLDAP_
[] = {
524 { LDAPRC_SUCCESS
, N_("Success") },
525 { LDAPRC_CONNECT
, N_("Error connecting to LDAP server") },
526 { LDAPRC_INIT
, N_("Error initializing LDAP") },
527 { LDAPRC_BIND
, N_("Error binding to LDAP server") },
528 { LDAPRC_SEARCH
, N_("Error searching LDAP database") },
529 { LDAPRC_TIMEOUT
, N_("Timeout performing LDAP operation") },
530 { LDAPRC_CRITERIA
, N_("Error in LDAP search criteria") },
531 { LDAPRC_NOENTRIES
, N_("No LDAP entries found for search criteria") },
532 { LDAPRC_STOP_FLAG
, N_("LDAP search terminated on request") },
533 { LDAPRC_TLS
, N_("Error starting STARTTLS connection") },
534 { LDAPRC_NODN
, N_("Distinguished Name (dn) is missing") },
535 { LDAPRC_NAMING_VIOLATION
, N_("Missing required information") },
536 { LDAPRC_ALREADY_EXIST
, N_("Another contact exists with that key") },
537 { LDAPRC_STRONG_AUTH
, N_("Strong(er) authentication required") },
543 * Lookup message for specified error code.
544 * \param lut Lookup table.
545 * \param code Code to lookup.
546 * \return Description associated to code.
548 static gchar
*addressbook_err2string( ErrMsgTableEntry lut
[], gint code
) {
550 ErrMsgTableEntry entry
;
553 for( i
= 0; ; i
++ ) {
555 if( entry
.description
== NULL
) break;
556 if( entry
.code
== code
) {
557 desc
= entry
.description
;
562 desc
= _errMsgUnknown_
;
567 static gboolean lastCanLookup
= FALSE
;
569 static void addressbook_show_buttons(gboolean add_and_delete
, gboolean lookup
, gboolean mail_ops
)
571 if (add_and_delete
) {
572 gtk_widget_show(addrbook
.edit_btn
);
573 gtk_widget_show(addrbook
.del_btn
);
574 gtk_widget_show(addrbook
.reg_btn
);
576 gtk_widget_hide(addrbook
.edit_btn
);
577 gtk_widget_hide(addrbook
.del_btn
);
578 gtk_widget_hide(addrbook
.reg_btn
);
582 gtk_widget_show(addrbook
.lup_btn
);
583 gtk_widget_show(addrbook
.entry
);
584 gtk_widget_show(addrbook
.label
);
586 gtk_widget_hide(addrbook
.lup_btn
);
587 gtk_widget_hide(addrbook
.entry
);
588 gtk_widget_hide(addrbook
.label
);
591 lastCanLookup
= lookup
;
594 gtk_widget_show(addrbook
.to_btn
);
595 gtk_widget_show(addrbook
.cc_btn
);
596 gtk_widget_show(addrbook
.bcc_btn
);
598 gtk_widget_hide(addrbook
.to_btn
);
599 gtk_widget_hide(addrbook
.cc_btn
);
600 gtk_widget_hide(addrbook
.bcc_btn
);
604 void addressbook_open(Compose
*target
)
606 /* Initialize all static members */
607 if( _clipBoard_
== NULL
) {
608 _clipBoard_
= addrclip_create();
610 if( _addressIndex_
!= NULL
) {
611 addrclip_set_index( _clipBoard_
, _addressIndex_
);
613 if( _addressSelect_
== NULL
) {
614 _addressSelect_
= addrselect_list_create();
616 if (!addrbook
.window
) {
617 addressbook_read_file();
618 addressbook_create();
619 addressbook_load_tree();
620 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
621 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook
.ctree
)->row_list
));
624 gtk_widget_hide(addrbook
.window
);
627 gtk_widget_show_all(addrbook
.window
);
629 if (!prefs_common
.addressbook_use_editaddress_dialog
)
630 addressbook_edit_person_widgetset_hide();
632 address_completion_start(addrbook
.window
);
634 addressbook_show_buttons(target
== NULL
, lastCanLookup
, target
!= NULL
);
635 addressbook_set_target_compose(target
);
639 * Destroy addressbook.
641 void addressbook_destroy( void ) {
642 /* Free up address stuff */
643 if( _addressSelect_
!= NULL
) {
644 addrselect_list_free( _addressSelect_
);
646 if( _clipBoard_
!= NULL
) {
647 addrclip_free( _clipBoard_
);
650 if( _addressIndex_
!= NULL
) {
651 addrindex_free_index( _addressIndex_
);
652 addrindex_teardown();
654 _addressSelect_
= NULL
;
656 _addressIndex_
= NULL
;
659 void addressbook_set_target_compose(Compose
*target
)
661 addrbook
.target_compose
= target
;
664 Compose
*addressbook_get_target_compose(void)
666 return addrbook
.target_compose
;
670 * Refresh addressbook and save to file(s).
672 void addressbook_refresh( void )
674 if (addrbook
.window
) {
675 if (addrbook
.treeSelected
) {
676 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
677 addrbook
.treeSelected
);
678 addressbook_set_clist(
679 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
680 addrbook
.treeSelected
),
685 addressbook_export_to_file();
688 static gboolean
key_pressed(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
690 if (event
&& event
->keyval
== GDK_KEY_Escape
)
692 else if (event
&& event
->keyval
== GDK_KEY_Delete
) {
693 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
694 if ( /* address_index_has_focus || */ address_list_has_focus
)
695 addressbook_del_clicked(NULL
, NULL
);
701 *\brief Save Gtk object size to prefs dataset
703 static void addressbook_size_allocate_cb(GtkWidget
*widget
,
704 GtkAllocation
*allocation
)
706 cm_return_if_fail(allocation
!= NULL
);
708 gtk_window_get_size(GTK_WINDOW(widget
),
709 &prefs_common
.addressbookwin_width
, &prefs_common
.addressbookwin_height
);
712 static gint sort_column_number
= 0;
713 static GtkSortType sort_column_type
= GTK_SORT_ASCENDING
;
715 static gint
list_case_sort(
716 GtkCMCList
*clist
, gconstpointer ptr1
, gconstpointer ptr2
)
718 GtkCMCListRow
*row1
= (GtkCMCListRow
*) ptr1
;
719 GtkCMCListRow
*row2
= (GtkCMCListRow
*) ptr2
;
720 gchar
*name1
= NULL
, *name2
= NULL
;
721 AddrItemObject
*aio1
= ((GtkCMCListRow
*)ptr1
)->data
;
722 AddrItemObject
*aio2
= ((GtkCMCListRow
*)ptr2
)->data
;
724 if( aio1
->type
== aio2
->type
) {
726 name1
= GTK_CMCELL_TEXT (row1
->cell
[sort_column_number
])->text
;
728 name2
= GTK_CMCELL_TEXT (row2
->cell
[sort_column_number
])->text
;
729 if( ! name1
) return ( name2
!= NULL
);
730 if( ! name2
) return -1;
731 return g_utf8_collate( name1
, name2
);
733 /* Order groups before person */
734 if( aio1
->type
== ITEMTYPE_GROUP
) {
735 return (sort_column_type
==GTK_SORT_ASCENDING
) ? -1:+1;
736 } else if( aio2
->type
== ITEMTYPE_GROUP
) {
737 return (sort_column_type
==GTK_SORT_ASCENDING
) ? +1:-1;
743 static void addressbook_sort_list(GtkCMCList
*clist
, const gint col
,
744 const GtkSortType sort_type
)
747 GtkWidget
*hbox
, *label
, *arrow
;
749 sort_column_number
= col
;
750 sort_column_type
= sort_type
;
751 gtk_cmclist_set_compare_func(clist
, list_case_sort
);
752 gtk_cmclist_set_sort_type(clist
, sort_type
);
753 gtk_cmclist_set_sort_column(clist
, col
);
755 gtk_cmclist_freeze(clist
);
756 gtk_cmclist_sort(clist
);
758 for(pos
= 0 ; pos
< N_LIST_COLS
; pos
++) {
759 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
760 label
= gtk_label_new(gettext(list_titles
[pos
]));
761 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
764 arrow
= gtk_image_new_from_icon_name(sort_type
== GTK_SORT_ASCENDING
?
765 "pan-down-symbolic" : "pan-up-symbolic", GTK_ICON_SIZE_MENU
);
766 gtk_box_pack_end(GTK_BOX(hbox
), arrow
, FALSE
, FALSE
, 0);
769 gtk_widget_show_all(hbox
);
770 gtk_cmclist_set_column_widget(clist
, pos
, hbox
);
773 gtk_cmclist_thaw(clist
);
776 static void addressbook_name_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
778 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
780 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
782 addressbook_sort_list(clist
, COL_NAME
, sort_type
);
785 static void addressbook_address_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
787 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
789 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
791 addressbook_sort_list(clist
, COL_ADDRESS
, sort_type
);
794 static void addressbook_remarks_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
796 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
798 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
800 addressbook_sort_list(clist
, COL_REMARKS
, sort_type
);
803 static gboolean
addressbook_address_index_focus_evt_in(GtkWidget
*widget
, GdkEventFocus
*event
,
806 address_index_has_focus
= TRUE
;
810 static gboolean
addressbook_address_index_focus_evt_out(GtkWidget
*widget
, GdkEventFocus
*event
,
813 address_index_has_focus
= FALSE
;
814 if (!prefs_common
.addressbook_use_editaddress_dialog
815 && !address_list_has_focus
)
816 addressbook_address_list_disable_some_actions();
820 static gboolean
addressbook_address_list_focus_evt_in(GtkWidget
*widget
, GdkEventFocus
*event
,
823 address_list_has_focus
= TRUE
;
827 static gboolean
addressbook_address_list_focus_evt_out(GtkWidget
*widget
, GdkEventFocus
*event
,
830 address_list_has_focus
= FALSE
;
831 if (!prefs_common
.addressbook_use_editaddress_dialog
832 && !address_index_has_focus
)
833 addressbook_address_list_disable_some_actions();
837 /* save hpane and vpane's handle position when it moves */
838 static void addressbook_pane_save_position(void)
841 prefs_common
.addressbook_hpaned_pos
=
842 gtk_paned_get_position(GTK_PANED(addrbook
.hpaned
));
844 prefs_common
.addressbook_vpaned_pos
=
845 gtk_paned_get_position(GTK_PANED(addrbook
.vpaned
));
849 * Create the address book widgets. The address book contains two CTree widgets: the
850 * address index tree on the left and the address list on the right.
852 * The address index tree displays a hierarchy of interfaces and groups. Each node in
853 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
854 * data sources and folder objects.
856 * The address list displays group, person and email objects. These items are linked
857 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
860 * In the tradition of MVC architecture, the data stores have been separated from the
861 * GUI components. The addrindex.c file provides the interface to all data stores.
863 static void addressbook_create(void)
869 GtkWidget
*ctree_swin
;
871 GtkWidget
*editaddress_vbox
;
872 GtkWidget
*clist_vbox
;
873 GtkWidget
*clist_swin
;
880 GtkWidget
*statusbar
;
891 GtkWidget
*close_btn
;
892 GtkWidget
*tree_popup
;
893 GtkWidget
*list_popup
;
895 GtkUIManager
*ui_manager
;
896 GtkActionGroup
*action_group
;
897 gchar
*index_titles
[N_INDEX_COLS
];
901 static GdkGeometry geometry
;
903 debug_print("Creating addressbook window...\n");
905 index_titles
[COL_SOURCES
] = _("Sources");
907 /* Address book window */
908 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "addressbook");
909 gtk_window_set_title(GTK_WINDOW(window
), _("Address book"));
910 gtk_window_set_resizable(GTK_WINDOW(window
), TRUE
);
911 gtk_window_set_type_hint(GTK_WINDOW(window
), GDK_WINDOW_TYPE_HINT_DIALOG
);
912 gtk_widget_realize(window
);
914 g_signal_connect(G_OBJECT(window
), "delete_event",
915 G_CALLBACK(addressbook_close
), NULL
);
916 g_signal_connect(G_OBJECT(window
), "size_allocate",
917 G_CALLBACK(addressbook_size_allocate_cb
), NULL
);
918 g_signal_connect(G_OBJECT(window
), "key_press_event",
919 G_CALLBACK(key_pressed
), NULL
);
920 MANAGE_WINDOW_SIGNALS_CONNECT(window
);
922 vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0);
923 gtk_container_add(GTK_CONTAINER(window
), vbox
);
926 ui_manager
= gtk_ui_manager_new();
927 action_group
= cm_menu_create_action_group_full(ui_manager
,"Menu", addressbook_entries
,
928 G_N_ELEMENTS(addressbook_entries
), NULL
);
929 gtk_action_group_add_actions(action_group
, addressbook_tree_popup_entries
,
930 G_N_ELEMENTS(addressbook_tree_popup_entries
), NULL
);
931 gtk_action_group_add_actions(action_group
, addressbook_list_popup_entries
,
932 G_N_ELEMENTS(addressbook_list_popup_entries
), NULL
);
934 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Menu", NULL
, GTK_UI_MANAGER_MENUBAR
)
936 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU
)
937 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU
)
938 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU
)
941 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM
)
942 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM
)
943 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM
)
945 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM
)
948 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM
)
950 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR
)
951 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM
)
952 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM
)
953 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR
)
954 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM
)
955 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM
)
958 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM
)
959 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
960 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM
)
961 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM
)
962 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM
)
963 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
964 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM
)
965 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM
)
966 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
967 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM
)
968 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM
)
969 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
970 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM
)
971 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM
)
974 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM
)
975 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM
)
976 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM
)
977 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR
)
978 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM
)
979 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM
)
980 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR
)
981 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM
)
982 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM
)
984 gtk_window_add_accel_group(GTK_WINDOW(window
),
985 gtk_ui_manager_get_accel_group(ui_manager
));
987 menubar
= gtk_ui_manager_get_widget(ui_manager
, "/Menu");
989 gtk_box_pack_start(GTK_BOX(vbox
), menubar
, FALSE
, TRUE
, 0);
991 vbox2
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, BORDER_WIDTH
);
992 gtk_container_set_border_width(GTK_CONTAINER(vbox2
), BORDER_WIDTH
);
993 gtk_box_pack_start(GTK_BOX(vbox
), vbox2
, TRUE
, TRUE
, 0);
995 ctree_swin
= gtk_scrolled_window_new(NULL
, NULL
);
996 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin
),
997 GTK_POLICY_AUTOMATIC
,
998 GTK_POLICY_AUTOMATIC
);
1001 ctree
= gtk_sctree_new_with_titles(N_INDEX_COLS
, 0, index_titles
);
1002 gtk_widget_set_can_focus(GTK_CMCLIST(ctree
)->column
[0].button
, FALSE
);
1004 gtk_container_add(GTK_CONTAINER(ctree_swin
), ctree
);
1005 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree
), GTK_SELECTION_BROWSE
);
1006 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree
), 0, COL_FOLDER_WIDTH
);
1007 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree
),
1008 GTK_CMCTREE_EXPANDER_TRIANGLE
);
1009 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
1010 gtk_cmctree_set_indent(GTK_CMCTREE(ctree
), CTREE_INDENT
);
1011 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree
),
1012 addressbook_treenode_compare_func
);
1014 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
1015 G_CALLBACK(addressbook_tree_selected
), NULL
);
1016 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
1017 G_CALLBACK(addressbook_tree_button_pressed
),
1019 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
1020 G_CALLBACK(addressbook_tree_button_released
),
1023 g_signal_connect(G_OBJECT(ctree
), "select_row",
1024 G_CALLBACK(addressbook_select_row_tree
), NULL
);
1026 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
1027 addressbook_drag_types
, 1,
1028 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
1029 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
1030 G_CALLBACK(addressbook_drag_motion_cb
),
1032 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
1033 G_CALLBACK(addressbook_drag_leave_cb
),
1035 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
1036 G_CALLBACK(addressbook_drag_received_cb
),
1038 g_signal_connect(G_OBJECT(ctree
), "focus_in_event",
1039 G_CALLBACK(addressbook_address_index_focus_evt_in
), NULL
);
1040 g_signal_connect(G_OBJECT(ctree
), "focus_out_event",
1041 G_CALLBACK(addressbook_address_index_focus_evt_out
), NULL
);
1043 clist_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 4);
1045 clist_swin
= gtk_scrolled_window_new(NULL
, NULL
);
1046 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin
),
1047 GTK_POLICY_AUTOMATIC
,
1048 GTK_POLICY_AUTOMATIC
);
1049 gtk_box_pack_start(GTK_BOX(clist_vbox
), clist_swin
, TRUE
, TRUE
, 0);
1052 clist
= gtk_sctree_new_with_titles(N_LIST_COLS
, 0, list_titles
);
1053 gtk_container_add(GTK_CONTAINER(clist_swin
), clist
);
1054 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist
), GTK_SELECTION_MULTIPLE
);
1055 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist
),
1056 GTK_CMCTREE_EXPANDER_TRIANGLE
);
1057 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
1058 gtk_cmctree_set_indent(GTK_CMCTREE(clist
), CTREE_INDENT
);
1059 gtk_cmclist_set_column_width(GTK_CMCLIST(clist
), COL_NAME
,
1061 gtk_cmclist_set_column_width(GTK_CMCLIST(clist
), COL_ADDRESS
,
1063 gtk_widget_set_size_request(clist
, -1, 80);
1065 addressbook_sort_list(GTK_CMCLIST(clist
), COL_NAME
, GTK_SORT_ASCENDING
);
1066 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_NAME
].button
),
1067 "clicked", G_CALLBACK(addressbook_name_clicked
), clist
);
1068 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_ADDRESS
].button
),
1069 "clicked", G_CALLBACK(addressbook_address_clicked
), clist
);
1070 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_REMARKS
].button
),
1071 "clicked", G_CALLBACK(addressbook_remarks_clicked
), clist
);
1072 g_signal_connect(G_OBJECT(clist
), "focus_in_event",
1073 G_CALLBACK(addressbook_address_list_focus_evt_in
), NULL
);
1074 g_signal_connect(G_OBJECT(clist
), "focus_out_event",
1075 G_CALLBACK(addressbook_address_list_focus_evt_out
), NULL
);
1077 for (i
= 0; i
< N_LIST_COLS
; i
++)
1078 gtk_widget_set_can_focus(GTK_CMCLIST(clist
)->column
[i
].button
,
1081 g_signal_connect(G_OBJECT(clist
), "tree_select_row",
1082 G_CALLBACK(addressbook_list_row_selected
), NULL
);
1083 g_signal_connect(G_OBJECT(clist
), "tree_unselect_row",
1084 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1085 g_signal_connect(G_OBJECT(clist
), "button_press_event",
1086 G_CALLBACK(addressbook_list_button_pressed
),
1088 g_signal_connect(G_OBJECT(clist
), "button_release_event",
1089 G_CALLBACK(addressbook_list_button_released
),
1091 g_signal_connect(G_OBJECT(clist
), "tree_expand",
1092 G_CALLBACK(addressbook_person_expand_node
), NULL
);
1093 g_signal_connect(G_OBJECT(clist
), "tree_collapse",
1094 G_CALLBACK(addressbook_person_collapse_node
), NULL
);
1095 g_signal_connect(G_OBJECT(clist
), "start_drag",
1096 G_CALLBACK(addressbook_start_drag
), NULL
);
1097 g_signal_connect(G_OBJECT(clist
), "drag_data_get",
1098 G_CALLBACK(addressbook_drag_data_get
), NULL
);
1099 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
1100 gtk_box_pack_start(GTK_BOX(clist_vbox
), hbox
, FALSE
, FALSE
, 0);
1102 label
= gtk_label_new(_("Search"));
1103 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1105 entry
= gtk_entry_new();
1106 gtk_box_pack_start(GTK_BOX(hbox
), entry
, TRUE
, TRUE
, 0);
1108 address_completion_register_entry(GTK_ENTRY(entry
), FALSE
);
1110 g_signal_connect(G_OBJECT(entry
), "key_press_event",
1111 G_CALLBACK(addressbook_entry_key_pressed
),
1113 g_signal_connect(G_OBJECT(entry
), "activate",
1114 G_CALLBACK(addressbook_entry_activated
), NULL
);
1116 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
1117 editaddress_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 4);
1118 vpaned
= gtk_paned_new(GTK_ORIENTATION_VERTICAL
);
1119 gtk_paned_pack1(GTK_PANED(vpaned
), clist_vbox
, FALSE
, FALSE
);
1120 gtk_paned_pack2(GTK_PANED(vpaned
), editaddress_vbox
, TRUE
, FALSE
);
1123 editaddress_vbox
= NULL
;
1125 hpaned
= gtk_paned_new(GTK_ORIENTATION_HORIZONTAL
);
1126 gtk_box_pack_start(GTK_BOX(vbox2
), hpaned
, TRUE
, TRUE
, 0);
1127 gtk_paned_pack1(GTK_PANED(hpaned
), ctree_swin
, FALSE
, FALSE
);
1128 if (prefs_common
.addressbook_use_editaddress_dialog
)
1129 gtk_paned_pack2(GTK_PANED(hpaned
), clist_vbox
, TRUE
, FALSE
);
1131 gtk_paned_pack2(GTK_PANED(hpaned
), vpaned
, TRUE
, FALSE
);
1134 hsbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
1135 gtk_box_pack_end(GTK_BOX(vbox
), hsbox
, FALSE
, FALSE
, BORDER_WIDTH
);
1136 statusbar
= gtk_statusbar_new();
1137 gtk_box_pack_start(GTK_BOX(hsbox
), statusbar
, TRUE
, TRUE
, BORDER_WIDTH
);
1140 hbbox
= gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL
);
1141 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox
), GTK_BUTTONBOX_END
);
1142 gtk_box_set_spacing(GTK_BOX(hbbox
), 2);
1143 gtk_container_set_border_width(GTK_CONTAINER(hbbox
), 4);
1144 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
1146 gtkut_stock_button_add_help(hbbox
, &help_btn
);
1148 edit_btn
= gtk_button_new_with_mnemonic("_Edit");
1149 gtk_widget_set_can_default(edit_btn
, TRUE
);
1150 gtk_box_pack_start(GTK_BOX(hbbox
), edit_btn
, TRUE
, TRUE
, 0);
1151 del_btn
= gtk_button_new_with_mnemonic("_Delete");
1152 gtk_widget_set_can_default(del_btn
, TRUE
);
1153 gtk_box_pack_start(GTK_BOX(hbbox
), del_btn
, TRUE
, TRUE
, 0);
1154 reg_btn
= gtk_button_new_with_mnemonic("_New");
1155 gtk_widget_set_can_default(reg_btn
, TRUE
);
1156 gtk_box_pack_start(GTK_BOX(hbbox
), reg_btn
, TRUE
, TRUE
, 0);
1159 lup_btn
= gtkut_stock_button("edit-find", _("_Find"));
1160 gtk_widget_set_can_default(lup_btn
, TRUE
);
1161 gtk_box_pack_start(GTK_BOX(hbox
), lup_btn
, TRUE
, TRUE
, 0);
1163 g_signal_connect(G_OBJECT(help_btn
), "clicked",
1164 G_CALLBACK(manual_open_with_anchor_cb
),
1165 MANUAL_ANCHOR_ADDRBOOK
);
1167 g_signal_connect(G_OBJECT(edit_btn
), "clicked",
1168 G_CALLBACK(addressbook_edit_clicked
), NULL
);
1169 g_signal_connect(G_OBJECT(del_btn
), "clicked",
1170 G_CALLBACK(addressbook_del_clicked
), NULL
);
1171 g_signal_connect(G_OBJECT(reg_btn
), "clicked",
1172 G_CALLBACK(addressbook_reg_clicked
), NULL
);
1173 g_signal_connect(G_OBJECT(lup_btn
), "clicked",
1174 G_CALLBACK(addressbook_lup_clicked
), NULL
);
1176 to_btn
= gtk_button_new_with_label
1177 (prefs_common_translated_header_name("To:"));
1178 gtk_widget_set_can_default(to_btn
, TRUE
);
1179 gtk_box_pack_start(GTK_BOX(hbbox
), to_btn
, TRUE
, TRUE
, 0);
1180 cc_btn
= gtk_button_new_with_label
1181 (prefs_common_translated_header_name("Cc:"));
1182 gtk_widget_set_can_default(cc_btn
, TRUE
);
1183 gtk_box_pack_start(GTK_BOX(hbbox
), cc_btn
, TRUE
, TRUE
, 0);
1184 bcc_btn
= gtk_button_new_with_label
1185 (prefs_common_translated_header_name("Bcc:"));
1186 gtk_widget_set_can_default(bcc_btn
, TRUE
);
1187 gtk_box_pack_start(GTK_BOX(hbbox
), bcc_btn
, TRUE
, TRUE
, 0);
1189 close_btn
= gtkut_stock_button("window-close", "_Close");
1190 gtk_widget_set_can_default(close_btn
, TRUE
);
1191 gtk_box_pack_start(GTK_BOX(hbbox
), close_btn
, TRUE
, TRUE
, 0);
1193 g_signal_connect(G_OBJECT(to_btn
), "clicked",
1194 G_CALLBACK(addressbook_to_clicked
),
1195 GINT_TO_POINTER(COMPOSE_TO
));
1196 g_signal_connect(G_OBJECT(cc_btn
), "clicked",
1197 G_CALLBACK(addressbook_to_clicked
),
1198 GINT_TO_POINTER(COMPOSE_CC
));
1199 g_signal_connect(G_OBJECT(bcc_btn
), "clicked",
1200 G_CALLBACK(addressbook_to_clicked
),
1201 GINT_TO_POINTER(COMPOSE_BCC
));
1202 g_signal_connect(G_OBJECT(close_btn
), "clicked",
1203 G_CALLBACK(addressbook_close_clicked
), NULL
);
1205 /* Build icons for interface */
1207 /* Build control tables */
1208 addrbookctl_build_map(window
);
1209 addrbookctl_build_iflist();
1210 addrbookctl_build_ifselect();
1212 addrbook
.clist
= NULL
;
1214 /* Add each interface into the tree as a root level folder */
1215 nodeIf
= _addressInterfaceList_
;
1217 AdapterInterface
*adapter
= nodeIf
->data
;
1218 AddressInterface
*iface
= adapter
->interface
;
1219 nodeIf
= g_list_next(nodeIf
);
1221 if(iface
->useInterface
) {
1222 AddressTypeControlItem
*atci
= adapter
->atci
;
1223 text
= atci
->displayName
;
1225 gtk_sctree_insert_node( GTK_CMCTREE(ctree
),
1226 NULL
, NULL
, &text
, FOLDER_SPACING
,
1230 cm_menu_set_sensitive_full(ui_manager
, atci
->menuCommand
, adapter
->haveLibrary
);
1231 gtk_cmctree_node_set_row_data_full(
1232 GTK_CMCTREE(ctree
), adapter
->treeNode
, adapter
,
1233 addressbook_free_treenode
);
1239 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Popups", NULL
, GTK_UI_MANAGER_MENUBAR
);
1240 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU
)
1241 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM
)
1242 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM
)
1243 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR
)
1244 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM
)
1245 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM
)
1246 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM
)
1247 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR
)
1248 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM
)
1249 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM
)
1250 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM
)
1252 tree_popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1253 gtk_ui_manager_get_widget(ui_manager
, "/Popups/ABTreePopup")));
1255 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU
)
1256 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM
)
1257 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1258 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM
)
1259 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM
)
1260 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1261 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM
)
1262 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM
)
1263 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1264 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM
)
1265 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM
)
1266 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM
)
1267 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1268 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM
)
1270 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM
)
1272 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM
)
1273 list_popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1274 gtk_ui_manager_get_widget(ui_manager
, "/Popups/ABListPopup")));
1276 addrbook
.window
= window
;
1277 addrbook
.hpaned
= hpaned
;
1278 addrbook
.vpaned
= vpaned
;
1279 addrbook
.menubar
= menubar
;
1280 addrbook
.ctree
= ctree
;
1283 addrbook
.editaddress_vbox
= editaddress_vbox
;
1284 addrbook
.clist
= clist
;
1285 addrbook
.label
= label
;
1286 addrbook
.entry
= entry
;
1287 addrbook
.statusbar
= statusbar
;
1288 addrbook
.status_cid
= gtk_statusbar_get_context_id(
1289 GTK_STATUSBAR(statusbar
), "Addressbook Window" );
1291 addrbook
.help_btn
= help_btn
;
1292 addrbook
.edit_btn
= edit_btn
;
1293 addrbook
.del_btn
= del_btn
;
1294 addrbook
.reg_btn
= reg_btn
;
1295 addrbook
.lup_btn
= lup_btn
;
1296 addrbook
.to_btn
= to_btn
;
1297 addrbook
.cc_btn
= cc_btn
;
1298 addrbook
.bcc_btn
= bcc_btn
;
1300 addrbook
.tree_popup
= tree_popup
;
1301 addrbook
.list_popup
= list_popup
;
1302 addrbook
.ui_manager
= ui_manager
;
1304 addrbook
.listSelected
= NULL
;
1306 if (!geometry
.min_height
) {
1307 geometry
.min_width
= ADDRESSBOOK_WIDTH
;
1308 geometry
.min_height
= ADDRESSBOOK_HEIGHT
;
1311 gtk_window_set_geometry_hints(GTK_WINDOW(window
), NULL
, &geometry
,
1313 gtk_window_set_default_size(GTK_WINDOW(window
), prefs_common
.addressbookwin_width
,
1314 prefs_common
.addressbookwin_height
);
1316 gtk_window_move(GTK_WINDOW(window
), 48, 48);
1319 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
1320 if (prefs_common
.addressbook_vpaned_pos
> 0)
1321 gtk_paned_set_position(GTK_PANED(vpaned
),
1322 prefs_common
.addressbook_vpaned_pos
);
1324 if (prefs_common
.addressbook_hpaned_pos
> 0)
1325 gtk_paned_set_position(GTK_PANED(hpaned
),
1326 prefs_common
.addressbook_hpaned_pos
);
1329 gtk_widget_show_all(window
);
1333 * Close address book window and save to file(s).
1335 static gint
addressbook_close( void ) {
1336 address_completion_end(addrbook
.window
);
1337 if (!prefs_common
.addressbook_use_editaddress_dialog
)
1338 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
1340 addressbook_pane_save_position();
1342 gtk_widget_hide(addrbook
.window
);
1343 addressbook_export_to_file();
1348 * Display message in status line.
1349 * \param msg Message to display.
1351 static void addressbook_status_show( gchar
*msg
) {
1352 if( addrbook
.statusbar
!= NULL
) {
1354 GTK_STATUSBAR(addrbook
.statusbar
),
1355 addrbook
.status_cid
);
1358 GTK_STATUSBAR(addrbook
.statusbar
),
1359 addrbook
.status_cid
, msg
);
1364 static void addressbook_ds_show_message( AddressDataSource
*ds
) {
1368 *addressbook_msgbuf
= '\0';
1370 name
= addrindex_ds_get_name( ds
);
1371 retVal
= addrindex_ds_get_status_code( ds
);
1372 if( retVal
== MGU_SUCCESS
) {
1373 g_snprintf( addressbook_msgbuf
,
1374 sizeof(addressbook_msgbuf
), "%s", name
);
1377 desc
= addressbook_err2string( _lutErrorsGeneral_
, retVal
);
1378 g_snprintf( addressbook_msgbuf
,
1379 sizeof(addressbook_msgbuf
), "%s: %s", name
, desc
);
1382 addressbook_status_show( addressbook_msgbuf
);
1385 static void addressbook_edit_clicked(GtkButton
*button
, gpointer data
)
1387 addressbook_edit_address_cb(NULL
, NULL
);
1390 static gboolean
find_person(AddrSelectItem
*item_a
, ItemPerson
*person
)
1392 return ((ItemPerson
*)item_a
->addressItem
== person
)?0:-1;
1396 * Delete one or more objects from address list.
1398 static void addressbook_del_clicked(GtkButton
*button
, gpointer data
)
1400 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
1401 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
1402 AddressObject
*pobj
;
1403 AdapterDSource
*ads
= NULL
;
1404 GtkCMCTreeNode
*nodeList
;
1407 AddressBookFile
*abf
= NULL
;
1408 AddressDataSource
*ds
= NULL
;
1409 AddressInterface
*iface
;
1410 AddrItemObject
*aio
;
1411 AddrSelectItem
*item
;
1413 gboolean refreshList
= FALSE
;
1415 pobj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.opened
);
1416 cm_return_if_fail(pobj
!= NULL
);
1418 /* Test whether anything selected for deletion */
1419 nodeList
= addrbook
.listSelected
;
1421 aio
= gtk_cmctree_node_get_row_data( clist
, nodeList
);
1422 if( aio
== NULL
) return;
1423 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1424 if( ds
== NULL
) return;
1426 /* Test for read only */
1427 iface
= ds
->interface
;
1428 if( iface
->readOnly
) {
1429 alertpanel( _("Delete address(es)"),
1430 _("This address data is read-only and cannot be deleted."),
1431 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
, ALERTFOCUS_FIRST
);
1435 /* Test whether Ok to proceed */
1437 if( pobj
->type
== ADDR_DATASOURCE
) {
1438 ads
= ADAPTER_DSOURCE(pobj
);
1439 if( ads
->subType
== ADDR_BOOK
) procFlag
= TRUE
;
1441 else if( pobj
->type
== ADDR_ITEM_FOLDER
) {
1444 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
1447 if( ! procFlag
) return;
1448 abf
= ds
->rawDataSource
;
1449 if( abf
== NULL
) return;
1451 gtk_cmclist_freeze(GTK_CMCLIST(addrbook
.clist
));
1452 g_signal_handlers_block_by_func
1453 (G_OBJECT(addrbook
.clist
),
1454 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1456 /* Process deletions */
1457 if( pobj
->type
== ADDR_DATASOURCE
|| pobj
->type
== ADDR_ITEM_FOLDER
) {
1458 GList
*groups
= NULL
, *persons
= NULL
, *emails
= NULL
;
1459 gboolean group_delete
= TRUE
;
1460 /* Items inside folders */
1461 list
= addrselect_get_list( _addressSelect_
);
1462 /* Confirm deletion */
1466 node
= g_list_next( node
);
1467 aio
= ( AddrItemObject
* ) item
->addressItem
;
1468 if( aio
->type
== ITEMTYPE_PERSON
|| aio
->type
== ITEMTYPE_EMAIL
) {
1469 group_delete
= FALSE
;
1474 aval
= alertpanel( _("Delete group"),
1475 _("Really delete the group(s)?\n"
1476 "The addresses it contains will not be lost."),
1477 NULL
, _("_Cancel"), "edit-delete", _("D_elete"), NULL
, NULL
,
1478 ALERTFOCUS_SECOND
);
1479 if( aval
!= G_ALERTALTERNATE
) {
1483 aval
= alertpanel( _("Delete address(es)"),
1484 _("Really delete the address(es)?"),
1485 NULL
, _("_Cancel"), "edit-delete", _("D_elete"), NULL
, NULL
,
1486 ALERTFOCUS_SECOND
);
1487 if( aval
!= G_ALERTALTERNATE
) {
1492 /* first, set lists of groups and persons to remove */
1496 node
= g_list_next( node
);
1497 aio
= ( AddrItemObject
* ) item
->addressItem
;
1500 if( aio
->type
== ITEMTYPE_GROUP
) {
1501 groups
= g_list_prepend(groups
, item
);
1503 else if( aio
->type
== ITEMTYPE_PERSON
) {
1504 persons
= g_list_prepend(persons
, item
);
1507 /* then set list of emails to remove *if* they're not children of
1508 * persons to remove */
1512 node
= g_list_next( node
);
1513 aio
= ( AddrItemObject
* ) item
->addressItem
;
1516 if( aio
->type
== ITEMTYPE_EMAIL
) {
1517 ItemEMail
*sitem
= ( ItemEMail
* ) aio
;
1518 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(sitem
);
1519 if (!g_list_find_custom(persons
, person
, (GCompareFunc
)(find_person
))) {
1520 emails
= g_list_prepend(emails
, item
);
1522 /* else, the email will be removed via the parent person */
1525 /* then delete groups */
1529 node
= g_list_next( node
);
1530 aio
= ( AddrItemObject
* ) item
->addressItem
;
1533 if( aio
->type
== ITEMTYPE_GROUP
) {
1534 ItemGroup
*item
= ( ItemGroup
* ) aio
;
1535 GtkCMCTreeNode
*nd
= NULL
;
1536 nd
= addressbook_find_group_node( addrbook
.opened
, item
);
1537 item
= addrbook_remove_group( abf
, item
);
1539 addritem_free_item_group( item
);
1541 /* Remove group from parent node */
1542 gtk_cmctree_remove_node( ctree
, nd
);
1546 /* then delete persons */
1550 node
= g_list_next( node
);
1551 aio
= ( AddrItemObject
* ) item
->addressItem
;
1554 if( aio
->type
== ITEMTYPE_PERSON
) {
1555 ItemPerson
*item
= ( ItemPerson
* ) aio
;
1556 item
->status
= DELETE_ENTRY
;
1557 addressbook_folder_remove_one_person( clist
, item
);
1558 if (pobj
->type
== ADDR_ITEM_FOLDER
)
1559 addritem_folder_remove_person(ADAPTER_FOLDER(pobj
)->itemFolder
, item
);
1560 item
= addrbook_remove_person( abf
, item
);
1562 if (ds
&& ds
->type
== ADDR_IF_LDAP
) {
1563 LdapServer
*server
= ds
->rawDataSource
;
1564 ldapsvr_set_modified(server
, TRUE
);
1565 ldapsvr_update_book(server
, item
);
1569 addritem_person_remove_picture(item
);
1570 addritem_free_item_person( item
);
1574 /* then delete emails */
1578 node
= g_list_next( node
);
1579 aio
= ( AddrItemObject
* ) item
->addressItem
;
1583 if( aio
->type
== ITEMTYPE_EMAIL
) {
1584 ItemEMail
*sitem
= ( ItemEMail
* ) aio
;
1585 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(sitem
);
1586 sitem
= addrbook_person_remove_email( abf
, person
, sitem
);
1588 addrcache_remove_email(abf
->addressCache
, sitem
);
1589 addritem_free_item_email( sitem
);
1591 addressbook_folder_refresh_one_person( clist
, person
);
1594 g_list_free( groups
);
1595 g_list_free( persons
);
1596 g_list_free( emails
);
1597 g_list_free( list
);
1598 addressbook_list_select_clear();
1600 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
1601 addressbook_set_clist(
1602 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
1606 addrbook_set_dirty(abf
, TRUE
);
1607 addressbook_export_to_file();
1608 addressbook_list_menu_setup();
1611 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
1612 /* Items inside groups */
1613 list
= addrselect_get_list( _addressSelect_
);
1617 node
= g_list_next( node
);
1618 aio
= ( AddrItemObject
* ) item
->addressItem
;
1619 if( aio
->type
== ITEMTYPE_EMAIL
) {
1620 ItemEMail
*item
= ( ItemEMail
* ) aio
;
1621 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(item
);
1622 item
= addrbook_person_remove_email( abf
, person
, item
);
1624 addritem_free_item_email( item
);
1628 g_list_free( list
);
1629 addressbook_list_select_clear();
1630 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
1631 addressbook_set_clist(
1632 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
1636 addrbook_set_dirty(abf
, TRUE
);
1637 addressbook_export_to_file();
1638 addressbook_list_menu_setup();
1642 gtk_cmctree_node_set_row_data( clist
, nodeList
, NULL
);
1643 gtk_cmctree_remove_node( clist
, nodeList
);
1645 gtk_cmclist_thaw(GTK_CMCLIST(addrbook
.clist
));
1646 g_signal_handlers_unblock_by_func
1647 (G_OBJECT(addrbook
.clist
),
1648 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1651 static void addressbook_reg_clicked(GtkButton
*button
, gpointer data
)
1653 addressbook_new_address_cb( NULL
, NULL
);
1656 static gchar
*addressbook_format_address( AddrItemObject
* aio
) {
1659 gchar
*address
= NULL
;
1661 if( aio
->type
== ITEMTYPE_EMAIL
) {
1662 ItemPerson
*person
= NULL
;
1663 ItemEMail
*email
= ( ItemEMail
* ) aio
;
1665 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
1666 if( email
->address
) {
1667 if( ADDRITEM_NAME(email
) ) {
1668 name
= ADDRITEM_NAME(email
);
1669 if( *name
== '\0' ) {
1670 name
= ADDRITEM_NAME(person
);
1673 else if( ADDRITEM_NAME(person
) ) {
1674 name
= ADDRITEM_NAME(person
);
1677 buf
= g_strdup( email
->address
);
1679 address
= email
->address
;
1682 else if( aio
->type
== ITEMTYPE_PERSON
) {
1683 ItemPerson
*person
= ( ItemPerson
* ) aio
;
1684 GList
*node
= person
->listEMail
;
1686 name
= ADDRITEM_NAME(person
);
1688 ItemEMail
*email
= ( ItemEMail
* ) node
->data
;
1689 address
= email
->address
;
1693 if( name
&& name
[0] != '\0' ) {
1694 if( strchr_with_skip_quote( name
, '"', ',' ) )
1695 buf
= g_strdup_printf( "\"%s\" <%s>", name
, address
);
1697 buf
= g_strdup_printf( "%s <%s>", name
, address
);
1700 buf
= g_strdup( address
);
1707 static void addressbook_to_clicked(GtkButton
*button
, gpointer data
)
1711 AddrSelectItem
*item
;
1712 AddrItemObject
*aio
;
1715 compose
= addrbook
.target_compose
;
1716 if( ! compose
) return;
1718 /* Nothing selected, but maybe there is something in text entry */
1719 addr
= (char *)gtk_entry_get_text( GTK_ENTRY( addrbook
.entry
) );
1721 compose_entry_append(
1722 compose
, addr
, (ComposeEntryType
)data
, PREF_NONE
);
1725 /* Select from address list */
1726 list
= addrselect_get_list( _addressSelect_
);
1731 node
= g_list_next( node
);
1732 aio
= item
->addressItem
;
1733 if( aio
->type
== ITEMTYPE_PERSON
||
1734 aio
->type
== ITEMTYPE_EMAIL
) {
1735 addr
= addressbook_format_address( aio
);
1736 compose_entry_append(
1737 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1740 else if( aio
->type
== ITEMTYPE_GROUP
) {
1741 ItemGroup
*group
= ( ItemGroup
* ) aio
;
1742 GList
*nodeMail
= group
->listEMail
;
1744 ItemEMail
*email
= nodeMail
->data
;
1746 addr
= addressbook_format_address(
1747 ( AddrItemObject
* ) email
);
1748 compose_entry_append(
1749 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1751 nodeMail
= g_list_next( nodeMail
);
1756 AddressObject
*obj
= NULL
;
1758 obj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
1760 if( obj
&& obj
->type
== ADDR_ITEM_GROUP
) {
1761 ItemGroup
*itemGroup
= ADAPTER_GROUP(obj
)->itemGroup
;
1762 GList
*nodeMail
= itemGroup
->listEMail
;
1764 ItemEMail
*email
= nodeMail
->data
;
1766 addr
= addressbook_format_address(
1767 ( AddrItemObject
* ) email
);
1768 compose_entry_append(
1769 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1771 nodeMail
= g_list_next( nodeMail
);
1775 g_list_free( list
);
1778 static void addressbook_menubar_set_sensitive( gboolean sensitive
) {
1779 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", sensitive
);
1780 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", sensitive
);
1781 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/NewFolder", sensitive
);
1783 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/SelectAll", TRUE
);
1784 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", sensitive
);
1785 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", sensitive
);
1786 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", sensitive
);
1788 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewAddress", sensitive
);
1789 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewGroup", sensitive
);
1790 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Mailto", sensitive
);
1791 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Merge", sensitive
);
1792 gtk_widget_set_sensitive( addrbook
.edit_btn
, sensitive
);
1793 gtk_widget_set_sensitive( addrbook
.del_btn
, sensitive
);
1796 static void addressbook_menuitem_set_sensitive( AddressObject
*obj
, GtkCMCTreeNode
*node
) {
1797 gboolean canEdit
= FALSE
;
1798 gboolean canDelete
= TRUE
;
1799 gboolean canAdd
= FALSE
;
1800 gboolean canEditTr
= TRUE
;
1801 gboolean editAddress
= FALSE
;
1802 gboolean canExport
= TRUE
;
1803 AddressTypeControlItem
*atci
= NULL
;
1804 AddressDataSource
*ds
= NULL
;
1805 AddressInterface
*iface
= NULL
;
1807 if( obj
== NULL
) return;
1808 if( obj
->type
== ADDR_INTERFACE
) {
1809 AdapterInterface
*adapter
= ADAPTER_INTERFACE(obj
);
1810 iface
= adapter
->interface
;
1812 if( iface
->haveLibrary
) {
1813 /* Enable appropriate File / New command */
1814 atci
= adapter
->atci
;
1815 cm_menu_set_sensitive_full(addrbook
.ui_manager
, atci
->menuCommand
, TRUE
);
1818 canEditTr
= canExport
= FALSE
;
1820 else if( obj
->type
== ADDR_DATASOURCE
) {
1821 AdapterDSource
*ads
= ADAPTER_DSOURCE(obj
);
1822 ds
= ads
->dataSource
;
1823 iface
= ds
->interface
;
1824 if( ! iface
->readOnly
) {
1825 canAdd
= canEdit
= editAddress
= canDelete
= TRUE
;
1827 if( ! iface
->haveLibrary
) {
1828 canAdd
= canEdit
= editAddress
= canExport
= canDelete
= FALSE
;
1831 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
1832 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1834 iface
= ds
->interface
;
1835 if( iface
->readOnly
) {
1840 canAdd
= editAddress
= TRUE
;
1844 else if( obj
->type
== ADDR_ITEM_GROUP
) {
1845 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1847 iface
= ds
->interface
;
1848 if( ! iface
->readOnly
) {
1854 if( addrbook
.listSelected
== NULL
)
1858 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewAddress", editAddress
);
1859 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewGroup", canAdd
);
1860 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/NewFolder", canAdd
);
1861 gtk_widget_set_sensitive( addrbook
.reg_btn
, editAddress
);
1864 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Edit", canEdit
);
1865 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Delete", canDelete
);
1866 gtk_widget_set_sensitive( addrbook
.edit_btn
, canEdit
);
1867 gtk_widget_set_sensitive( addrbook
.del_btn
, canDelete
);
1869 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", canEditTr
);
1870 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", canEditTr
);
1873 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Tools/ExportHTML", canExport
);
1874 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Tools/ExportLDIF", canExport
);
1878 * Address book tree callback function that responds to selection of tree
1881 * \param ctree Tree widget.
1882 * \param node Node that was selected.
1883 * \param column Column number where selected occurred.
1884 * \param data Pointer to user data.
1886 static void addressbook_tree_selected(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
1887 gint column
, gpointer data
)
1889 AddressObject
*obj
= NULL
;
1890 AdapterDSource
*ads
= NULL
;
1891 AddressDataSource
*ds
= NULL
;
1892 ItemFolder
*rootFolder
= NULL
;
1893 AddressObjectType aot
;
1895 addrbook
.treeSelected
= node
;
1896 addrbook
.listSelected
= NULL
;
1897 addressbook_status_show( "" );
1898 if( addrbook
.entry
!= NULL
) gtk_entry_set_text(GTK_ENTRY(addrbook
.entry
), "");
1900 if( node
) obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
1902 addressbook_set_clist(NULL
, TRUE
);
1905 addrbook
.opened
= node
;
1907 if( obj
->type
== ADDR_DATASOURCE
) {
1908 /* Read from file */
1909 static gboolean tVal
= TRUE
;
1911 ads
= ADAPTER_DSOURCE(obj
);
1913 ds
= ads
->dataSource
;
1914 if( ds
== NULL
) return;
1916 if( addrindex_ds_get_modify_flag( ds
) ) {
1917 addrindex_ds_read_data( ds
);
1920 if( ! addrindex_ds_get_read_flag( ds
) ) {
1921 addrindex_ds_read_data( ds
);
1923 addressbook_ds_show_message( ds
);
1925 if( ! addrindex_ds_get_access_flag( ds
) ) {
1926 /* Remove existing folders and groups */
1927 gtk_cmclist_freeze( GTK_CMCLIST(ctree
) );
1928 addressbook_tree_remove_children( ctree
, node
);
1929 gtk_cmclist_thaw( GTK_CMCLIST(ctree
) );
1931 /* Load folders into the tree */
1932 rootFolder
= addrindex_ds_get_root_folder( ds
);
1933 if( ds
&& ds
->type
== ADDR_IF_JPILOT
) {
1934 aot
= ADDR_CATEGORY
;
1936 else if( ds
&& ds
->type
== ADDR_IF_LDAP
) {
1937 aot
= ADDR_LDAP_QUERY
;
1940 aot
= ADDR_ITEM_FOLDER
;
1942 addressbook_node_add_folder( node
, ds
, rootFolder
, aot
);
1943 addrindex_ds_set_access_flag( ds
, &tVal
);
1944 gtk_cmctree_expand( ctree
, node
);
1947 addressbook_set_clist(NULL
, TRUE
);
1950 /* Update address list */
1951 g_signal_handlers_block_by_func
1953 G_CALLBACK(addressbook_tree_selected
), NULL
);
1954 addressbook_set_clist( obj
, FALSE
);
1955 g_signal_handlers_unblock_by_func
1957 G_CALLBACK(addressbook_tree_selected
), NULL
);
1958 if (!prefs_common
.addressbook_use_editaddress_dialog
)
1959 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
1961 /* Setup main menu selections */
1962 addressbook_menubar_set_sensitive( FALSE
);
1963 addressbook_menuitem_set_sensitive( obj
, node
);
1964 addressbook_list_select_clear();
1965 addressbook_list_menu_setup();
1970 * Setup address list popup menu items. Items are enabled or disabled as
1973 static void addressbook_list_menu_setup( void ) {
1974 GtkCMCTree
*clist
= NULL
;
1975 AddressObject
*pobj
= NULL
;
1976 AddressObject
*obj
= NULL
;
1977 AdapterDSource
*ads
= NULL
;
1978 AddressInterface
*iface
= NULL
;
1979 AddressDataSource
*ds
= NULL
;
1981 AddrItemObject
*aio
;
1982 AddrSelectItem
*item
;
1983 gboolean canEdit
= FALSE
;
1984 gboolean canDelete
= FALSE
;
1985 gboolean canCut
= FALSE
;
1986 gboolean canCopy
= FALSE
;
1987 gboolean canPaste
= FALSE
;
1988 gboolean canBrowse
= FALSE
;
1989 gboolean canMerge
= FALSE
;
1991 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
1992 if( pobj
== NULL
) return;
1994 clist
= GTK_CMCTREE(addrbook
.clist
);
1995 obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
1996 if( obj
== NULL
) canEdit
= FALSE
;
1998 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook
.list_popup
) );
1999 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/SelectAll", TRUE
);
2001 if( pobj
->type
== ADDR_DATASOURCE
) {
2002 /* Parent object is a data source */
2003 ads
= ADAPTER_DSOURCE(pobj
);
2004 ds
= ads
->dataSource
;
2007 iface
= ds
->interface
;
2010 if( ! iface
->readOnly
) {
2011 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2012 if (iface
->type
!= ADDR_IF_LDAP
)
2013 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewGroup", TRUE
);
2014 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2017 canDelete
= canEdit
;
2020 else if( pobj
->type
!= ADDR_INTERFACE
) {
2021 /* Parent object is not an interface */
2022 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2025 iface
= ds
->interface
;
2028 if( ! iface
->readOnly
) {
2029 /* Folder or group */
2030 if( pobj
->type
== ADDR_ITEM_FOLDER
|| pobj
->type
== ADDR_ITEM_GROUP
) {
2031 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2032 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2033 if( obj
) canEdit
= TRUE
;
2036 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
2037 if (iface
->type
!= ADDR_IF_LDAP
)
2038 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewGroup", TRUE
);
2039 if( obj
) canEdit
= TRUE
;
2041 canDelete
= canEdit
;
2043 if( iface
->type
== ADDR_IF_LDAP
) {
2044 if( obj
) canBrowse
= TRUE
;
2051 /* Enable cut and paste */
2052 if( ! addrclip_is_empty( _clipBoard_
) )
2054 if( ! addrselect_test_empty( _addressSelect_
) )
2056 /* Enable copy if something is selected */
2057 if( ! addrselect_test_empty( _addressSelect_
) )
2061 /* Disable edit or browse if more than one row selected */
2062 if( GTK_CMCLIST(clist
)->selection
&& GTK_CMCLIST(clist
)->selection
->next
) {
2067 /* Allow merging persons or emails are selected */
2068 list
= _addressSelect_
->listSelect
;
2069 if (list
&& list
->next
) {
2071 aio
= ( AddrItemObject
* ) item
->addressItem
;
2072 if( aio
->type
== ITEMTYPE_EMAIL
||
2073 aio
->type
== ITEMTYPE_PERSON
) {
2078 /* Forbid write changes when read-only */
2079 if( iface
&& iface
->readOnly
) {
2086 /* Now go finalize menu items */
2087 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Edit", canEdit
);
2088 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Delete", canDelete
);
2090 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Cut", canCut
);
2091 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Copy", canCopy
);
2092 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Paste", canPaste
);
2094 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Mailto", canCopy
);
2095 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Merge", canMerge
);
2097 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", canCut
);
2098 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", canCopy
);
2099 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", canPaste
);
2101 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Edit", canEdit
);
2102 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Delete", canDelete
);
2103 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Mailto", canCopy
);
2104 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Merge", canMerge
);
2106 gtk_widget_set_sensitive( addrbook
.edit_btn
, canEdit
);
2107 gtk_widget_set_sensitive( addrbook
.del_btn
, canDelete
);
2109 if (addrbook
.target_compose
) {
2110 gtk_widget_set_sensitive(addrbook
.to_btn
, obj
? TRUE
: FALSE
);
2111 gtk_widget_set_sensitive(addrbook
.cc_btn
, obj
? TRUE
: FALSE
);
2112 gtk_widget_set_sensitive(addrbook
.bcc_btn
, obj
? TRUE
: FALSE
);
2115 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/BrowseEntry", canBrowse
);
2119 static void addressbook_select_row_tree (GtkCMCTree
*ctree
,
2120 GtkCMCTreeNode
*node
,
2127 * Add list of items into tree node below specified tree node.
2128 * \param treeNode Tree node.
2129 * \param ds Data source.
2130 * \param listItems List of items.
2132 static void addressbook_treenode_add_list(
2133 GtkCMCTreeNode
*treeNode
, AddressDataSource
*ds
, GList
*listItems
)
2139 AddrItemObject
*aio
;
2143 if( ADDRESS_OBJECT_TYPE(aio
) == ADDR_ITEM_GROUP
) {
2146 group
= ( ItemGroup
* ) aio
;
2147 nn
= addressbook_node_add_group( treeNode
, ds
, group
);
2149 g_message("error adding addressbook group\n");
2152 else if( ADDRESS_OBJECT_TYPE(aio
) == ADDR_ITEM_FOLDER
) {
2155 folder
= ( ItemFolder
* ) aio
;
2156 nn
= addressbook_node_add_folder(
2157 treeNode
, ds
, folder
, ADDR_ITEM_FOLDER
);
2159 g_message("error adding addressbook folder\n");
2162 node
= g_list_next( node
);
2166 static void addressbook_select_all_cb( GtkAction
*action
, gpointer data
) {
2167 gtk_cmclist_select_all(GTK_CMCLIST(addrbook
.clist
));
2171 * Cut from address list widget.
2173 static void addressbook_clip_cut_cb( GtkAction
*action
, gpointer data
) {
2174 _clipBoard_
->cutFlag
= TRUE
;
2175 addrclip_clear( _clipBoard_
);
2176 addrclip_add( _clipBoard_
, _addressSelect_
);
2177 #ifdef DEBUG_ADDRBOOK
2178 addrclip_list_show( _clipBoard_
, stdout
);
2183 * Copy from address list widget.
2185 static void addressbook_clip_copy_cb(GtkAction
*action
, gpointer data
) {
2186 _clipBoard_
->cutFlag
= FALSE
;
2187 addrclip_clear( _clipBoard_
);
2188 addrclip_add( _clipBoard_
, _addressSelect_
);
2189 #ifdef DEBUG_ADDRBOOK
2190 addrclip_list_show( _clipBoard_
, stdout
);
2195 * Paste clipboard into address list widget.
2197 static void addressbook_clip_paste_cb( GtkAction
*action
, gpointer data
) {
2198 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
2199 AddressObject
*pobj
= NULL
;
2200 AddressDataSource
*ds
= NULL
;
2201 AddressBookFile
*abf
= NULL
;
2202 ItemFolder
*folder
= NULL
;
2203 GList
*folderGroup
= NULL
;
2205 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
2206 if( ds
== NULL
) return;
2207 if( addrindex_ds_get_readonly( ds
) ) {
2208 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2212 pobj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
2214 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
2215 folder
= ADAPTER_FOLDER(pobj
)->itemFolder
;
2217 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
2218 alertpanel_error( _("Cannot paste into an address group.") );
2223 /* Get an address book */
2224 abf
= addressbook_get_book_file();
2225 if( abf
== NULL
) return;
2227 if( _clipBoard_
->cutFlag
) {
2229 folderGroup
= addrclip_paste_cut( _clipBoard_
, abf
, folder
);
2231 /* Remove all groups and folders in clipboard from tree node */
2232 addressbook_treenode_remove_item();
2234 /* Remove all "cut" items */
2235 addrclip_delete_item( _clipBoard_
);
2237 /* Clear clipboard - cut items??? */
2238 addrclip_clear( _clipBoard_
);
2242 folderGroup
= addrclip_paste_copy( _clipBoard_
, abf
, folder
);
2245 #ifdef DEBUG_ADDRBOOK
2246 addrclip_list_show( _clipBoard_
, stdout
);
2249 /* Update tree by inserting node for each folder or group */
2250 addressbook_treenode_add_list(
2251 addrbook
.treeSelected
, ds
, folderGroup
);
2252 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2253 g_list_free( folderGroup
);
2257 /* Display items pasted */
2258 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
2259 addressbook_set_clist(
2260 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
2268 * Add current treenode object to clipboard. Note that widget only allows
2269 * one entry from the tree list to be selected.
2271 static void addressbook_treenode_to_clipboard( void ) {
2272 AddressObject
*obj
= NULL
;
2273 AddressDataSource
*ds
= NULL
;
2274 AddrSelectItem
*item
;
2275 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
2276 GtkCMCTreeNode
*node
;
2278 node
= addrbook
.treeSelected
;
2279 if( node
== NULL
) return;
2280 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2281 if( obj
== NULL
) return;
2283 ds
= addressbook_find_datasource( node
);
2284 if( ds
== NULL
) return;
2287 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2288 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
2289 ItemFolder
*folder
= adapter
->itemFolder
;
2291 item
= addrselect_create_node( obj
);
2292 item
->uid
= g_strdup( ADDRITEM_ID(folder
) );
2294 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2295 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
2296 ItemGroup
*group
= adapter
->itemGroup
;
2298 item
= addrselect_create_node( obj
);
2299 item
->uid
= g_strdup( ADDRITEM_ID(group
) );
2301 else if( obj
->type
== ADDR_DATASOURCE
) {
2303 item
= addrselect_create_node( obj
);
2308 /* Clear existing list and add item into list */
2311 addressbook_list_select_clear();
2312 cacheID
= addrindex_get_cache_id( _addressIndex_
, ds
);
2313 addrselect_list_add( _addressSelect_
, item
, cacheID
);
2319 * Cut from tree widget.
2321 static void addressbook_treenode_cut_cb( GtkAction
*action
, gpointer data
) {
2322 _clipBoard_
->cutFlag
= TRUE
;
2323 addressbook_treenode_to_clipboard();
2324 addrclip_clear( _clipBoard_
);
2325 addrclip_add( _clipBoard_
, _addressSelect_
);
2326 #ifdef DEBUG_ADDRBOOK
2327 addrclip_list_show( _clipBoard_
, stdout
);
2332 * Copy from tree widget.
2334 static void addressbook_treenode_copy_cb( GtkAction
*action
, gpointer data
) {
2335 _clipBoard_
->cutFlag
= FALSE
;
2336 addressbook_treenode_to_clipboard();
2337 addrclip_clear( _clipBoard_
);
2338 addrclip_add( _clipBoard_
, _addressSelect_
);
2339 #ifdef DEBUG_ADDRBOOK
2340 addrclip_list_show( _clipBoard_
, stdout
);
2345 * Paste clipboard into address tree widget.
2347 static void addressbook_treenode_paste_cb( GtkAction
*action
, gpointer data
) {
2348 addressbook_clip_paste_cb(NULL
,NULL
);
2352 * Clear selected entries in clipboard.
2354 static void addressbook_list_select_clear( void ) {
2355 addrselect_list_clear( _addressSelect_
);
2359 * Add specified address item to selected address list.
2360 * \param aio Address item object.
2361 * \param ds Datasource.
2363 static void addressbook_list_select_add( AddrItemObject
*aio
, AddressDataSource
*ds
) {
2366 if( ds
== NULL
) return;
2367 cacheID
= addrindex_get_cache_id( _addressIndex_
, ds
);
2368 addrselect_list_add_obj( _addressSelect_
, aio
, cacheID
);
2373 * Remove specified address item from selected address list.
2374 * \param aio Address item object.
2376 static void addressbook_list_select_remove( AddrItemObject
*aio
) {
2377 addrselect_list_remove( _addressSelect_
, aio
);
2381 * Invoke EMail compose window with addresses in selected address list.
2383 static void addressbook_mail_to_cb( GtkAction
*action
, gpointer data
) {
2386 if( ! addrselect_test_empty( _addressSelect_
) ) {
2387 listAddress
= addrselect_build_list( _addressSelect_
);
2388 compose_new_with_list( NULL
, listAddress
);
2389 g_list_free_full( listAddress
, g_free
);
2394 static void addressbook_merge_list( AddrSelectList
*list
) {
2395 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2396 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
2397 AddressObject
*pobj
;
2398 AddressDataSource
*ds
= NULL
;
2400 pobj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.opened
);
2401 cm_return_if_fail(pobj
!= NULL
);
2403 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2404 if( ds
== NULL
) return;
2406 addrmerge_merge(clist
, pobj
, ds
, list
);
2410 * Merge selected entries in the address list
2412 static void addressbook_merge_cb( GtkAction
*action
, gpointer data
) {
2413 if( addrselect_test_empty( _addressSelect_
) )
2416 addressbook_merge_list( _addressSelect_
);
2419 static void addressbook_list_row_selected( GtkCMCTree
*clist
,
2420 GtkCMCTreeNode
*node
,
2424 AddrItemObject
*aio
= NULL
;
2425 AddressObject
*pobj
= NULL
;
2426 AdapterDSource
*ads
= NULL
;
2427 AddressDataSource
*ds
= NULL
;
2429 addrbook
.listSelected
= node
;
2431 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
2432 if( pobj
== NULL
) return;
2434 if( pobj
->type
== ADDR_DATASOURCE
) {
2435 ads
= ADAPTER_DSOURCE(pobj
);
2436 ds
= ads
->dataSource
;
2438 else if( pobj
->type
!= ADDR_INTERFACE
) {
2439 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2442 aio
= gtk_cmctree_node_get_row_data( clist
, node
);
2444 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2445 addressbook_list_select_add( aio
, ds
);
2448 addressbook_list_menu_setup();
2450 if (!addrbook
.target_compose
&& !prefs_common
.addressbook_use_editaddress_dialog
) {
2451 AddressObject
*obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
2453 if (obj
&& obj
->type
!= ADDR_ITEM_GROUP
)
2454 addressbook_edit_address(NULL
, 0, NULL
, FALSE
);
2458 static void addressbook_list_row_unselected( GtkCMCTree
*ctree
,
2459 GtkCMCTreeNode
*node
,
2463 AddrItemObject
*aio
;
2465 aio
= gtk_cmctree_node_get_row_data( ctree
, node
);
2467 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2468 addressbook_list_select_remove( aio
);
2471 if (!prefs_common
.addressbook_use_editaddress_dialog
)
2472 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
2475 static void addressbook_entry_activated(GtkWidget
*widget
, gpointer data
)
2477 addressbook_lup_clicked(NULL
, NULL
);
2480 static gboolean
addressbook_list_button_pressed(GtkWidget
*widget
,
2481 GdkEventButton
*event
,
2484 if( ! event
) return FALSE
;
2485 if( event
->window
!= GTK_CMCLIST(widget
)->clist_window
) return FALSE
;
2487 addressbook_list_menu_setup();
2489 if( event
->button
== 3 ) {
2490 gtk_menu_popup_at_pointer(GTK_MENU(addrbook
.list_popup
), NULL
);
2491 } else if (event
->button
== 1) {
2492 if (event
->type
== GDK_2BUTTON_PRESS
) {
2493 if (prefs_common
.add_address_by_click
&&
2494 addrbook
.target_compose
)
2495 addressbook_to_clicked(NULL
, GINT_TO_POINTER(COMPOSE_TO
));
2497 if (prefs_common
.addressbook_use_editaddress_dialog
)
2498 addressbook_edit_address_cb(NULL
, NULL
);
2500 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
2501 AddressObject
*obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
2502 if( obj
&& obj
->type
== ADDR_ITEM_GROUP
)
2503 addressbook_edit_address_cb(NULL
, NULL
);
2511 static gboolean
addressbook_list_button_released(GtkWidget
*widget
,
2512 GdkEventButton
*event
,
2518 static gboolean
addressbook_tree_button_pressed(GtkWidget
*ctree
,
2519 GdkEventButton
*event
,
2522 GtkCMCList
*clist
= GTK_CMCLIST(ctree
);
2524 AddressObject
*obj
= NULL
;
2525 AdapterDSource
*ads
= NULL
;
2526 AddressInterface
*iface
= NULL
;
2527 AddressDataSource
*ds
= NULL
;
2528 gboolean canEdit
= FALSE
;
2529 gboolean canDelete
= FALSE
;
2530 gboolean canCut
= FALSE
;
2531 gboolean canCopy
= FALSE
;
2532 gboolean canPaste
= FALSE
;
2533 gboolean canTreeCut
= FALSE
;
2534 gboolean canTreeCopy
= FALSE
;
2535 gboolean canTreePaste
= FALSE
;
2536 gboolean canLookup
= FALSE
;
2537 GtkCMCTreeNode
*node
= NULL
;
2539 if( ! event
) return FALSE
;
2540 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2542 if( event
->window
!= clist
->clist_window
)
2545 if (event
->button
== 1) {
2546 if (event
->type
== GDK_2BUTTON_PRESS
) {
2547 if( gtk_cmclist_get_selection_info( clist
, event
->x
, event
->y
, &row
, &column
) ) {
2548 gtkut_clist_set_focus_row(clist
, row
);
2549 obj
= gtk_cmclist_get_row_data( clist
, row
);
2554 if (obj
->type
== ADDR_ITEM_GROUP
||
2555 obj
->type
== ADDR_DATASOURCE
) {
2557 addressbook_treenode_edit_cb(NULL
, NULL
);
2559 /* expand pr collapse */
2560 node
= gtk_cmctree_node_nth(GTK_CMCTREE(ctree
), row
);
2561 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree
), node
);
2567 addressbook_menubar_set_sensitive( FALSE
);
2569 if( gtk_cmclist_get_selection_info( clist
, event
->x
, event
->y
, &row
, &column
) ) {
2570 gtkut_clist_set_focus_row(clist
, row
);
2571 obj
= gtk_cmclist_get_row_data( clist
, row
);
2574 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook
.tree_popup
));
2578 node
= gtk_cmctree_node_nth(GTK_CMCTREE(clist
), row
);
2580 if( ! addrclip_is_empty( _clipBoard_
) )
2581 canTreePaste
= TRUE
;
2583 if (obj
->type
== ADDR_INTERFACE
) {
2584 AdapterInterface
*adapter
= ADAPTER_INTERFACE(obj
);
2585 iface
= adapter
->interface
;
2588 if( !iface
->readOnly
&& iface
->type
== ADDR_IF_BOOK
) {
2589 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewBook", TRUE
);
2591 if( iface
->externalQuery
)
2594 if (obj
->type
== ADDR_DATASOURCE
) {
2596 ads
= ADAPTER_DSOURCE(obj
);
2597 ds
= ads
->dataSource
;
2600 iface
= ds
->interface
;
2603 if( !iface
->readOnly
) {
2604 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewFolder", TRUE
);
2605 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewGroup", TRUE
);
2606 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2612 else if (obj
->type
== ADDR_ITEM_FOLDER
) {
2614 ds
= addressbook_find_datasource( node
);
2617 iface
= ds
->interface
;
2620 if( !iface
->readOnly
) {
2624 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewFolder", TRUE
);
2625 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewGroup", TRUE
);
2626 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2630 if( iface
->externalQuery
) {
2631 /* Enable deletion of LDAP folder */
2635 else if (obj
->type
== ADDR_ITEM_GROUP
) {
2637 ds
= addressbook_find_datasource( node
);
2640 iface
= ds
->interface
;
2643 if( ! iface
->readOnly
) {
2646 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2647 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2651 if( canEdit
&& !addrselect_test_empty( _addressSelect_
) )
2653 if( ! addrselect_test_empty( _addressSelect_
) )
2655 if( ! addrclip_is_empty( _clipBoard_
) )
2658 /* Forbid write changes when read-only */
2659 if( iface
&& iface
->readOnly
) {
2661 canTreePaste
= FALSE
;
2668 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/EditBook", canEdit
);
2669 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/DeleteBook", canDelete
);
2670 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Cut", canTreeCut
);
2671 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Copy", canTreeCopy
);
2672 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Paste", canTreePaste
);
2674 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", canEdit
);
2675 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", canDelete
);
2676 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", canCut
);
2677 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", canCopy
);
2678 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", canPaste
);
2680 addressbook_show_buttons(addrbook
.target_compose
== NULL
, canLookup
,
2681 addrbook
.target_compose
!= NULL
);
2683 if( event
->button
== 3 )
2684 gtk_menu_popup_at_pointer(GTK_MENU(addrbook
.tree_popup
), NULL
);
2689 static gboolean
addressbook_tree_button_released(GtkWidget
*ctree
,
2690 GdkEventButton
*event
,
2693 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook
.ctree
), addrbook
.opened
);
2697 static void addressbook_new_folder_cb(GtkAction
*action
, gpointer data
)
2699 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2700 AddressObject
*obj
= NULL
;
2701 AddressDataSource
*ds
= NULL
;
2702 AddressBookFile
*abf
= NULL
;
2703 ItemFolder
*parentFolder
= NULL
;
2704 ItemFolder
*folder
= NULL
;
2706 if( ! addrbook
.treeSelected
) return;
2707 obj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
2708 if( obj
== NULL
) return;
2709 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2710 if( ds
== NULL
) return;
2712 if( obj
->type
== ADDR_DATASOURCE
) {
2713 if( ADAPTER_DSOURCE(obj
)->subType
!= ADDR_BOOK
) return;
2715 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
2716 parentFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
2722 abf
= ds
->rawDataSource
;
2723 if( abf
== NULL
) return;
2724 folder
= addressbook_edit_folder( abf
, parentFolder
, NULL
);
2727 nn
= addressbook_node_add_folder(
2728 addrbook
.treeSelected
, ds
, folder
, ADDR_ITEM_FOLDER
);
2730 g_message("error adding addressbook folder\n");
2732 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2733 if( addrbook
.treeSelected
== addrbook
.opened
)
2734 addressbook_set_clist(obj
, TRUE
);
2738 static void addressbook_new_group_cb(GtkAction
*action
, gpointer data
)
2740 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2741 AddressObject
*obj
= NULL
;
2742 AddressDataSource
*ds
= NULL
;
2743 AddressBookFile
*abf
= NULL
;
2744 ItemFolder
*parentFolder
= NULL
;
2745 ItemGroup
*group
= NULL
;
2747 if( ! addrbook
.treeSelected
) return;
2748 obj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.treeSelected
);
2749 if( obj
== NULL
) return;
2750 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2751 if( ds
== NULL
) return;
2753 if( obj
->type
== ADDR_DATASOURCE
) {
2754 if( ADAPTER_DSOURCE(obj
)->subType
!= ADDR_BOOK
) return;
2756 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
2757 parentFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
2763 abf
= ds
->rawDataSource
;
2764 if( abf
== NULL
) return;
2765 group
= addressbook_edit_group( abf
, parentFolder
, NULL
);
2768 nn
= addressbook_node_add_group( addrbook
.treeSelected
, ds
, group
);
2770 g_message("error adding addressbook group\n");
2772 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2773 if( addrbook
.treeSelected
== addrbook
.opened
)
2774 addressbook_set_clist(obj
, TRUE
);
2778 static void addressbook_change_node_name(GtkCMCTreeNode
*node
, const gchar
*name
)
2780 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2783 GdkPixbuf
*pix_cl
, *pix_op
;
2784 gboolean is_leaf
, expanded
;
2786 gtk_cmctree_get_node_info(ctree
, node
, text
, &spacing
,
2788 &is_leaf
, &expanded
);
2789 gtk_cmctree_set_node_info(ctree
, node
, name
, spacing
,
2796 * \param obj Address object to edit.
2797 * \param node Node in tree.
2798 * \return New name of data source.
2800 static gchar
*addressbook_edit_datasource( AddressObject
*obj
, GtkCMCTreeNode
*node
) {
2801 gchar
*newName
= NULL
;
2802 AddressDataSource
*ds
= NULL
;
2803 AddressInterface
*iface
= NULL
;
2804 AdapterDSource
*ads
= NULL
;
2806 ds
= addressbook_find_datasource( node
);
2807 if( ds
== NULL
) return NULL
;
2808 iface
= ds
->interface
;
2809 if( ! iface
->haveLibrary
) return NULL
;
2811 /* Read data from data source */
2812 if( addrindex_ds_get_modify_flag( ds
) ) {
2813 addrindex_ds_read_data( ds
);
2816 if( ! addrindex_ds_get_read_flag( ds
) ) {
2817 addrindex_ds_read_data( ds
);
2821 ads
= ADAPTER_DSOURCE(obj
);
2822 if( ads
->subType
== ADDR_BOOK
) {
2823 if( addressbook_edit_book( _addressIndex_
, ads
) == NULL
) return NULL
;
2825 else if( ads
->subType
== ADDR_VCARD
) {
2826 if( addressbook_edit_vcard( _addressIndex_
, ads
) == NULL
) return NULL
;
2829 else if( ads
->subType
== ADDR_JPILOT
) {
2830 if( addressbook_edit_jpilot( _addressIndex_
, ads
) == NULL
) return NULL
;
2834 else if( ads
->subType
== ADDR_LDAP
) {
2835 if( addressbook_edit_ldap( _addressIndex_
, ads
) == NULL
) return NULL
;
2841 newName
= obj
->name
;
2846 * Edit an object that is in the address tree area.
2848 static void addressbook_treenode_edit_cb(GtkAction
*action
, gpointer data
)
2850 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2852 AddressDataSource
*ds
= NULL
;
2853 AddressBookFile
*abf
= NULL
;
2854 GtkCMCTreeNode
*node
= NULL
, *parentNode
= NULL
;
2857 if( ! addrbook
.treeSelected
) return;
2858 node
= addrbook
.treeSelected
;
2859 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
2860 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2861 if( obj
== NULL
) return;
2862 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
2864 ds
= addressbook_find_datasource( node
);
2865 if( ds
== NULL
) return;
2867 if( obj
->type
== ADDR_DATASOURCE
) {
2868 name
= addressbook_edit_datasource( obj
, node
);
2869 if( name
== NULL
) return;
2872 abf
= ds
->rawDataSource
;
2873 if( abf
== NULL
) return;
2874 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2875 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
2876 ItemFolder
*item
= adapter
->itemFolder
;
2877 ItemFolder
*parentFolder
= NULL
;
2878 parentFolder
= ( ItemFolder
* ) ADDRITEM_PARENT(item
);
2879 if( addressbook_edit_folder( abf
, parentFolder
, item
) == NULL
) return;
2880 name
= ADDRITEM_NAME(item
);
2882 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2883 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
2884 ItemGroup
*item
= adapter
->itemGroup
;
2885 ItemFolder
*parentFolder
= NULL
;
2886 parentFolder
= ( ItemFolder
* ) ADDRITEM_PARENT(item
);
2887 if( addressbook_edit_group( abf
, parentFolder
, item
) == NULL
) return;
2888 name
= ADDRITEM_NAME(item
);
2891 if( name
&& parentNode
) {
2892 /* Update node in tree view */
2893 addressbook_change_node_name( node
, name
);
2894 gtk_sctree_sort_node(ctree
, parentNode
);
2895 gtk_cmctree_expand( ctree
, node
);
2896 gtk_sctree_select( GTK_SCTREE( ctree
), node
);
2903 ADDRTREE_DEL_FOLDER_ONLY
,
2904 ADDRTREE_DEL_FOLDER_ADDR
2908 * Delete an item from the tree widget.
2909 * \param data Data passed in.
2910 * \param action Action.
2911 * \param widget Widget issuing callback.
2913 static void addressbook_treenode_delete_cb(GtkAction
*action
, gpointer data
)
2915 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2916 GtkCMCTreeNode
*node
= NULL
;
2920 AddrBookBase
*adbase
;
2921 AddressCache
*cache
;
2922 AdapterDSource
*ads
= NULL
;
2923 AddressInterface
*iface
= NULL
;
2924 AddressDataSource
*ds
= NULL
;
2925 gboolean remFlag
= FALSE
;
2926 TreeItemDelType delType
;
2928 if( ! addrbook
.treeSelected
) return;
2929 node
= addrbook
.treeSelected
;
2930 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
2932 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2933 cm_return_if_fail(obj
!= NULL
);
2935 if( obj
->type
== ADDR_DATASOURCE
) {
2936 ads
= ADAPTER_DSOURCE(obj
);
2938 ds
= ads
->dataSource
;
2939 if( ds
== NULL
) return;
2942 /* Must be folder or something else */
2943 ds
= addressbook_find_datasource( node
);
2944 if( ds
== NULL
) return;
2946 /* Only allow deletion from non-readOnly */
2947 iface
= ds
->interface
;
2948 if( iface
->readOnly
) {
2949 /* Allow deletion of query results */
2950 if( ! iface
->externalQuery
) return;
2954 /* Confirm deletion */
2955 delType
= ADDRTREE_DEL_NONE
;
2956 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2957 if( iface
&& iface
->externalQuery
) {
2958 message
= g_strdup_printf( _(
2959 "Do you want to delete the query " \
2960 "results and addresses in '%s'?" ),
2962 aval
= alertpanel( _("Delete"), message
,
2963 NULL
, _("_Cancel"), "edit-delete", _("D_elete"), NULL
, NULL
,
2964 ALERTFOCUS_SECOND
);
2966 if( aval
== G_ALERTALTERNATE
) {
2967 delType
= ADDRTREE_DEL_FOLDER_ADDR
;
2971 message
= g_strdup_printf
2972 ( _( "Do you want to delete '%s'? "
2973 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2975 aval
= alertpanel( _("Delete folder"), message
,
2976 NULL
, _("_Cancel"), "edit-delete", _("Delete _folder only"),
2977 "edit-delete", _("Delete folder and _addresses"), ALERTFOCUS_SECOND
);
2979 if( aval
== G_ALERTALTERNATE
) {
2980 delType
= ADDRTREE_DEL_FOLDER_ONLY
;
2982 else if( aval
== G_ALERTOTHER
) {
2983 delType
= ADDRTREE_DEL_FOLDER_ADDR
;
2987 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2988 message
= g_strdup_printf(_("Do you want to delete '%s'?\n"
2989 "The addresses it contains will not be lost."), obj
->name
);
2990 aval
= alertpanel(_("Delete"), message
, NULL
, _("_Cancel"),
2991 "edit-delete", _("D_elete"), NULL
, NULL
, ALERTFOCUS_SECOND
);
2993 if( aval
== G_ALERTALTERNATE
) delType
= ADDRTREE_DEL_FOLDER_ONLY
;
2995 message
= g_strdup_printf(_("Do you want to delete '%s'?\n"
2996 "The addresses it contains will be lost."), obj
->name
);
2997 aval
= alertpanel(_("Delete"), message
, NULL
, _("_Cancel"),
2998 "edit-delete", _("D_elete"), NULL
, NULL
, ALERTFOCUS_SECOND
);
3000 if( aval
== G_ALERTALTERNATE
) delType
= ADDRTREE_DEL_DATA
;
3002 if( delType
== ADDRTREE_DEL_NONE
) return;
3004 /* Proceed with deletion */
3005 if( obj
->type
== ADDR_DATASOURCE
) {
3006 /* Remove node from tree */
3007 gtk_cmctree_remove_node( ctree
, node
);
3009 if (delType
== ADDRTREE_DEL_DATA
&&
3010 ds
->interface
&& ds
->interface
->type
== ADDR_IF_BOOK
)
3011 addrbook_delete_book_file((AddressBookFile
*) ds
->rawDataSource
);
3013 /* Remove data source. */
3014 if( addrindex_index_remove_datasource( _addressIndex_
, ds
) ) {
3015 addrindex_free_datasource( ds
);
3020 /* Get reference to cache */
3021 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
3022 if( adbase
== NULL
) return;
3023 cache
= adbase
->addressCache
;
3025 /* Remove query results folder */
3026 if( iface
&& iface
->externalQuery
) {
3027 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
3028 ItemFolder
*folder
= adapter
->itemFolder
;
3030 adapter
->itemFolder
= NULL
;
3032 g_print( "remove folder for ::%s::\n", obj->name );
3033 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3034 g_print( "-------------- remove results\n" );
3036 addrindex_remove_results( ds
, folder
);
3037 /* g_print( "-------------- remove node\n" ); */
3038 gtk_cmctree_remove_node( ctree
, node
);
3042 /* Code below is valid for regular address book deletion */
3043 if( obj
->type
== ADDR_ITEM_FOLDER
) {
3044 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
3045 ItemFolder
*item
= adapter
->itemFolder
;
3047 if( delType
== ADDRTREE_DEL_FOLDER_ONLY
) {
3048 /* Remove folder only */
3049 item
= addrcache_remove_folder( cache
, item
);
3051 addritem_free_item_folder( item
);
3052 addressbook_move_nodes_up( ctree
, node
);
3056 else if( delType
== ADDRTREE_DEL_FOLDER_ADDR
) {
3057 /* Remove folder and addresses */
3058 item
= addrcache_remove_folder_delete( cache
, item
);
3060 addritem_free_item_folder( item
);
3065 else if( obj
->type
== ADDR_ITEM_GROUP
) {
3066 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
3067 ItemGroup
*item
= adapter
->itemGroup
;
3069 item
= addrcache_remove_group( cache
, item
);
3071 addritem_free_item_group( item
);
3078 gtk_cmctree_remove_node(ctree
, node
);
3082 static void addressbook_new_address_from_book_post_cb( ItemPerson
*person
)
3084 if( person
&& addrbook
.treeSelected
== addrbook
.opened
) {
3085 person
->status
= ADD_ENTRY
;
3086 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook
.clist
) );
3087 addressbook_folder_refresh_one_person(
3088 GTK_CMCTREE(addrbook
.clist
), person
);
3090 addressbook_address_list_set_focus();
3093 static void addressbook_new_address_from_folder_post_cb( ItemPerson
*person
)
3095 if( person
&& addrbook
.treeSelected
== addrbook
.opened
) {
3096 person
->status
= ADD_ENTRY
;
3097 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), addrbook
.opened
);
3098 addressbook_set_clist(
3099 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3103 addressbook_address_list_set_focus();
3107 * Label (a format string) that is used to name each folder.
3109 static gchar
*_queryFolderLabel_
= N_( "Search '%s'" );
3112 * Search ctree widget callback function.
3113 * \param pA Pointer to node.
3114 * \param pB Pointer to data item being sought.
3115 * \return Zero (0) if folder found.
3117 static int addressbook_treenode_find_folder_cb( gconstpointer pA
, gconstpointer pB
) {
3120 aoA
= ( AddressObject
* ) pA
;
3121 if( aoA
->type
== ADDR_ITEM_FOLDER
) {
3122 ItemFolder
*folder
, *fld
;
3124 fld
= ADAPTER_FOLDER(aoA
)->itemFolder
;
3125 folder
= ( ItemFolder
* ) pB
;
3126 if( fld
== folder
) return 0; /* Found folder */
3131 static ItemFolder
* addressbook_setup_subf(
3132 AddressDataSource
*ds
, gchar
*title
,
3133 GtkCMCTreeNode
*pNode
)
3135 AddrBookBase
*adbase
;
3136 AddressCache
*cache
;
3139 GtkCMCTreeNode
*nNode
;
3141 AddressObjectType aoType
= ADDR_NONE
;
3144 if( *title
== '\0' || strlen( title
) < 1 ) return NULL
;
3146 if( ds
&& ds
->type
== ADDR_IF_LDAP
) {
3148 aoType
= ADDR_LDAP_QUERY
;
3155 ctree
= GTK_CMCTREE(addrbook
.ctree
);
3156 /* Get reference to address cache */
3157 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
3158 cache
= adbase
->addressCache
;
3160 if ((children
= addrcache_get_list_folder(cache
)) != NULL
) {
3161 GList
*cur
= children
;
3162 for (; cur
; cur
= cur
->next
) {
3163 ItemFolder
*child
= (ItemFolder
*) cur
->data
;
3164 if (!g_strcmp0(ADDRITEM_NAME(child
), title
)) {
3165 nNode
= gtk_cmctree_find_by_row_data_custom(
3167 addressbook_treenode_find_folder_cb
);
3169 addrindex_remove_results( ds
, child
);
3170 while( child
->listPerson
) {
3171 ItemPerson
*item
= ( ItemPerson
* ) child
->listPerson
->data
;
3172 item
= addrcache_remove_person( cache
, item
);
3174 addritem_free_item_person( item
);
3178 gtk_sctree_select( GTK_SCTREE(ctree
), nNode
);
3179 addrbook
.treeSelected
= nNode
;
3186 /* Create a folder */
3187 folder
= addrcache_add_new_folder( cache
, NULL
);
3188 name
= g_strdup_printf( "%s", title
);
3189 addritem_folder_set_name( folder
, name
);
3190 addritem_folder_set_remarks( folder
, "" );
3193 /* Now let's see the folder */
3194 nNode
= addressbook_node_add_folder( pNode
, ds
, folder
, aoType
);
3195 gtk_cmctree_expand( ctree
, pNode
);
3197 gtk_sctree_select( GTK_SCTREE(ctree
), nNode
);
3198 addrbook
.treeSelected
= nNode
;
3204 static void addressbook_new_address_cb( GtkAction
*action
, gpointer data
) {
3205 AddressObject
*pobj
= NULL
;
3206 AddressDataSource
*ds
= NULL
;
3207 AddressBookFile
*abf
= NULL
;
3208 debug_print("adding address\n");
3209 pobj
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
3210 if( pobj
== NULL
) {
3211 debug_print("no row data\n");
3214 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3216 debug_print("no datasource\n");
3220 abf
= ds
->rawDataSource
;
3222 g_print("no addressbook file\n");
3226 if( pobj
->type
== ADDR_DATASOURCE
) {
3227 if (ADAPTER_DSOURCE(pobj
)->subType
== ADDR_BOOK
||
3228 ADAPTER_DSOURCE(pobj
)->subType
== ADDR_LDAP
) {
3230 ItemFolder
*folder
= NULL
;
3232 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3233 GtkCMCTreeNode
*parentNode
;
3234 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook
.treeSelected
) );
3235 if( ds
== NULL
) return;
3237 /* We must have a datasource that is an external interface */
3238 if( ! ds
->interface
->haveLibrary
) return;
3239 if( ! ds
->interface
->externalQuery
) return;
3241 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3242 parentNode
= GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook
.treeSelected
) )->parent
;
3245 parentNode
= GTK_CMCTREE_NODE( addrbook
.treeSelected
);
3247 folder
= addressbook_setup_subf( ds
, _("New Contacts"), parentNode
);
3249 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3251 abf
= ds
->rawDataSource
;
3254 person
= addressbook_edit_person( abf
, folder
, NULL
, FALSE
,
3255 addrbook
.editaddress_vbox
,
3256 addressbook_new_address_from_book_post_cb
,
3259 if (ds
&& abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3260 LdapServer
*server
= ds
->rawDataSource
;
3261 ldapsvr_set_modified(server
, TRUE
);
3262 ldapsvr_update_book(server
, NULL
);
3263 if (server
->retVal
!= LDAPRC_SUCCESS
) {
3264 alertpanel( _("Add address(es)"),
3265 addressbook_err2string(_lutErrorsLDAP_
, server
->retVal
),
3266 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
3268 server
->retVal
= LDAPRC_SUCCESS
;
3273 if (prefs_common
.addressbook_use_editaddress_dialog
)
3274 addressbook_new_address_from_book_post_cb( person
);
3277 else if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3279 ItemFolder
*folder
= ADAPTER_FOLDER(pobj
)->itemFolder
;
3282 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3283 GtkCMCTreeNode
*parentNode
;
3284 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook
.treeSelected
) );
3285 if( ds
== NULL
) return;
3287 /* We must have a datasource that is an external interface */
3288 if( ! ds
->interface
->haveLibrary
) return;
3289 if( ! ds
->interface
->externalQuery
) return;
3291 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3292 parentNode
= GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook
.treeSelected
) )->parent
;
3295 parentNode
= GTK_CMCTREE_NODE( addrbook
.treeSelected
);
3297 folder
= addressbook_setup_subf( ds
, _("New Contacts"), parentNode
);
3301 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3303 abf
= ds
->rawDataSource
;
3306 person
= addressbook_edit_person( abf
, folder
, NULL
, FALSE
,
3307 addrbook
.editaddress_vbox
,
3308 addressbook_new_address_from_folder_post_cb
,
3311 if (ds
&& abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3312 LdapServer
*server
= ds
->rawDataSource
;
3313 ldapsvr_set_modified(server
, TRUE
);
3314 ldapsvr_update_book(server
, NULL
);
3315 if (server
->retVal
!= LDAPRC_SUCCESS
) {
3316 alertpanel( _("Add address(es)"),
3317 addressbook_err2string(_lutErrorsLDAP_
, server
->retVal
),
3318 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
, ALERTFOCUS_FIRST
);
3323 if (prefs_common
.addressbook_use_editaddress_dialog
)
3324 addressbook_new_address_from_folder_post_cb( person
);
3326 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
3327 /* New address in group */
3328 ItemGroup
*group
= ADAPTER_GROUP(pobj
)->itemGroup
;
3329 if( addressbook_edit_group( abf
, NULL
, group
) == NULL
) return;
3330 if (addrbook
.treeSelected
== addrbook
.opened
) {
3331 /* Change node name in tree. */
3332 addressbook_change_node_name( addrbook
.treeSelected
, ADDRITEM_NAME(group
) );
3333 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), addrbook
.opened
);
3334 addressbook_set_clist(
3335 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3343 * Search for specified child group node in address index tree.
3344 * \param parent Parent node.
3345 * \param group Group to find.
3347 static GtkCMCTreeNode
*addressbook_find_group_node( GtkCMCTreeNode
*parent
, ItemGroup
*group
) {
3348 GtkCMCTreeNode
*node
= NULL
;
3349 GtkCMCTreeRow
*currRow
;
3351 currRow
= GTK_CMCTREE_ROW( parent
);
3353 node
= currRow
->children
;
3357 obj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), node
);
3358 if(obj
&& obj
->type
== ADDR_ITEM_GROUP
) {
3359 ItemGroup
*g
= ADAPTER_GROUP(obj
)->itemGroup
;
3360 if( g
== group
) return node
;
3362 currRow
= GTK_CMCTREE_ROW(node
);
3363 node
= currRow
->sibling
;
3369 static AddressBookFile
*addressbook_get_book_file() {
3370 AddressBookFile
*abf
= NULL
;
3371 AddressDataSource
*ds
= NULL
;
3373 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
3374 if( ds
== NULL
) return NULL
;
3375 if( ds
->type
== ADDR_IF_BOOK
|| ds
->type
== ADDR_IF_LDAP
) abf
= ds
->rawDataSource
;
3379 static void addressbook_tree_remove_children( GtkCMCTree
*ctree
, GtkCMCTreeNode
*parent
) {
3380 GtkCMCTreeNode
*node
;
3383 /* Remove existing folders and groups */
3384 row
= GTK_CMCTREE_ROW( parent
);
3386 while( (node
= row
->children
) ) {
3387 gtk_cmctree_remove_node( ctree
, node
);
3392 static void addressbook_move_nodes_up( GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
) {
3393 GtkCMCTreeNode
*parent
, *child
;
3394 GtkCMCTreeRow
*currRow
;
3395 currRow
= GTK_CMCTREE_ROW( node
);
3397 parent
= currRow
->parent
;
3398 while( (child
= currRow
->children
) ) {
3399 gtk_cmctree_move( ctree
, child
, parent
, node
);
3401 gtk_sctree_sort_node( ctree
, parent
);
3405 static void addressbook_edit_address_post_cb( ItemPerson
*person
)
3409 AddressBookFile
*abf
= addressbook_get_book_file();
3411 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3412 if (g_strcmp0(person
->nickName
, ADDRITEM_NAME(person
)))
3413 addritem_person_set_nick_name( person
, ADDRITEM_NAME(person
));
3416 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook
.clist
), person
);
3417 invalidate_address_completion();
3419 addressbook_address_list_set_focus();
3422 void addressbook_address_list_set_focus( void )
3424 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
3425 gtk_window_set_focus(GTK_WINDOW(addrbook
.window
), addrbook
.clist
);
3426 addressbook_list_menu_setup();
3430 void addressbook_address_list_disable_some_actions(void)
3432 /* disable address copy/pasting when editing contact's detail (embedded form) */
3433 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", FALSE
);
3434 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", FALSE
);
3435 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", FALSE
);
3438 static void addressbook_edit_address_cb( GtkAction
*action
, gpointer data
) {
3439 addressbook_edit_address(data
, 0, NULL
, TRUE
);
3442 static void addressbook_edit_address( gpointer data
, guint action
, GtkWidget
*widget
,
3443 gboolean force_focus
) {
3444 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
3446 AddressObject
*obj
= NULL
, *pobj
= NULL
;
3447 AddressDataSource
*ds
= NULL
;
3448 GtkCMCTreeNode
*node
= NULL
, *parentNode
= NULL
;
3450 AddressBookFile
*abf
= NULL
;
3452 if( addrbook
.listSelected
== NULL
) return;
3453 obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
3454 cm_return_if_fail(obj
!= NULL
);
3456 ctree
= GTK_CMCTREE( addrbook
.ctree
);
3457 pobj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
3459 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3460 if( ds
== NULL
) return;
3462 abf
= addressbook_get_book_file();
3464 if( obj
->type
== ADDR_ITEM_EMAIL
) {
3465 ItemEMail
*email
= ( ItemEMail
* ) obj
;
3467 if( pobj
&& pobj
->type
== ADDR_ITEM_GROUP
) {
3468 /* Edit parent group */
3469 AdapterGroup
*adapter
= ADAPTER_GROUP(pobj
);
3470 ItemGroup
*itemGrp
= adapter
->itemGroup
;
3471 if( abf
== NULL
) return;
3472 if( addressbook_edit_group( abf
, NULL
, itemGrp
) == NULL
) return;
3473 name
= ADDRITEM_NAME(itemGrp
);
3474 node
= addrbook
.treeSelected
;
3475 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
3478 /* Edit person - email page */
3480 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
3481 if ( addressbook_edit_person( abf
, NULL
, person
, TRUE
, addrbook
.editaddress_vbox
,
3482 addressbook_edit_address_post_cb
,
3483 (prefs_common
.addressbook_use_editaddress_dialog
||force_focus
) )
3486 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3487 ldapsvr_set_modified( (LdapServer
*) abf
, TRUE
);
3488 person
->status
= UPDATE_ENTRY
;
3491 if (prefs_common
.addressbook_use_editaddress_dialog
)
3492 addressbook_edit_address_post_cb( person
);
3497 else if( obj
->type
== ADDR_ITEM_PERSON
) {
3498 /* Edit person - basic page */
3499 ItemPerson
*person
= ( ItemPerson
* ) obj
;
3500 if( addressbook_edit_person( abf
, NULL
, person
, FALSE
, addrbook
.editaddress_vbox
,
3501 addressbook_edit_address_post_cb
,
3502 (prefs_common
.addressbook_use_editaddress_dialog
||force_focus
) )
3505 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3506 ldapsvr_set_modified( (LdapServer
*) abf
, TRUE
);
3507 person
->status
= UPDATE_ENTRY
;
3510 if (prefs_common
.addressbook_use_editaddress_dialog
)
3511 addressbook_edit_address_post_cb( person
);
3515 else if( obj
->type
== ADDR_ITEM_GROUP
) {
3516 ItemGroup
*itemGrp
= ( ItemGroup
* ) obj
;
3517 if( addressbook_edit_group( abf
, NULL
, itemGrp
) == NULL
) return;
3518 parentNode
= addrbook
.treeSelected
;
3519 node
= addressbook_find_group_node( parentNode
, itemGrp
);
3520 name
= ADDRITEM_NAME(itemGrp
);
3521 invalidate_address_completion();
3527 /* Update tree node with node name */
3528 if( node
== NULL
) return;
3529 addressbook_change_node_name( node
, name
);
3530 gtk_sctree_sort_node( ctree
, parentNode
);
3531 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
3532 addressbook_set_clist(
3533 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3538 static void addressbook_delete_address_cb(GtkAction
*action
, gpointer data
)
3540 addressbook_del_clicked(NULL
, NULL
);
3543 static void close_cb(GtkAction
*action
, gpointer data
)
3545 addressbook_close();
3548 static void addressbook_file_save_cb( GtkAction
*action
, gpointer data
) {
3549 addressbook_export_to_file();
3552 static void addressbook_person_expand_node( GtkCMCTree
*ctree
, GList
*node
, gpointer
*data
) {
3554 ItemPerson
*person
= gtk_cmctree_node_get_row_data( ctree
, GTK_CMCTREE_NODE(node
) );
3555 if( person
) addritem_person_set_opened( person
, TRUE
);
3559 static void addressbook_person_collapse_node( GtkCMCTree
*ctree
, GList
*node
, gpointer
*data
) {
3561 ItemPerson
*person
= gtk_cmctree_node_get_row_data( ctree
, GTK_CMCTREE_NODE(node
) );
3562 if( person
) addritem_person_set_opened( person
, FALSE
);
3566 static gchar
*addressbook_format_item_clist( ItemPerson
*person
, ItemEMail
*email
) {
3568 gchar
*eMailAlias
= ADDRITEM_NAME(email
);
3569 if( eMailAlias
&& *eMailAlias
!= '\0' ) {
3571 str
= g_strdup_printf( "%s - %s", ADDRITEM_NAME(person
), eMailAlias
);
3574 str
= g_strdup( eMailAlias
);
3580 static gboolean
addressbook_match_item(const gchar
*name
,
3581 const gchar
*email_alias
,
3583 const gchar
*remarks
,
3588 if (!str
|| str
[0] == '\0')
3590 if (strcasestr(name
, str
))
3592 else if (email_alias
&& strcasestr(email_alias
, str
))
3594 else if (addr
&& strcasestr(addr
, str
))
3596 else if (remarks
&& strcasestr(remarks
, str
))
3602 static void addressbook_load_group( GtkCMCTree
*clist
, ItemGroup
*itemGroup
) {
3603 GList
*items
= itemGroup
->listEMail
;
3604 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3605 const gchar
*search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3606 for( ; items
!= NULL
; items
= g_list_next( items
) ) {
3607 GtkCMCTreeNode
*nodeEMail
= NULL
;
3608 gchar
*text
[N_LIST_COLS
];
3609 ItemEMail
*email
= items
->data
;
3613 if( ! email
) continue;
3615 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
3617 if( !addressbook_match_item(ADDRITEM_NAME(person
),
3618 ADDRITEM_NAME(email
),
3619 email
->address
, email
->remarks
,
3623 str
= addressbook_format_item_clist( person
, email
);
3625 text
[COL_NAME
] = addressbook_set_col_name_guard(str
);
3628 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3630 text
[COL_ADDRESS
] = email
->address
;
3631 text
[COL_REMARKS
] = email
->remarks
;
3632 nodeEMail
= gtk_sctree_insert_node(
3634 text
, FOLDER_SPACING
,
3638 gtk_cmctree_node_set_row_data( clist
, nodeEMail
, email
);
3644 gchar
*addressbook_set_col_name_guard(gchar
*value
)
3646 gchar
*ret
= "<not set>";
3647 gchar
*tmp
= g_strdup(value
);
3657 static void addressbook_folder_load_one_person(
3658 GtkCMCTree
*clist
, ItemPerson
*person
,
3659 AddressTypeControlItem
*atci
,
3660 AddressTypeControlItem
*atciMail
)
3662 GtkCMCTreeNode
*nodePerson
= NULL
;
3663 GtkCMCTreeNode
*nodeEMail
= NULL
;
3664 gchar
*text
[N_LIST_COLS
];
3665 gboolean flgFirst
= TRUE
, haveAddr
= FALSE
;
3668 AddressBookFile
*abf
= addressbook_get_book_file();
3671 if( person
== NULL
) return;
3673 text
[COL_NAME
] = "";
3674 node
= person
->listEMail
;
3676 ItemEMail
*email
= node
->data
;
3677 gchar
*eMailAddr
= NULL
;
3678 node
= g_list_next( node
);
3680 text
[COL_ADDRESS
] = email
->address
;
3681 text
[COL_REMARKS
] = email
->remarks
;
3682 eMailAddr
= ADDRITEM_NAME(email
);
3683 if( eMailAddr
&& *eMailAddr
== '\0' ) eMailAddr
= NULL
;
3685 /* First email belongs with person */
3686 gchar
*str
= addressbook_format_item_clist( person
, email
);
3688 text
[COL_NAME
] = addressbook_set_col_name_guard(str
);
3691 else if( abf
&& abf
->type
== ADBOOKTYPE_LDAP
&&
3692 person
&& person
->nickName
) {
3693 if (person
->nickName
) {
3694 if (strcmp(person
->nickName
, "") != 0) {
3695 text
[COL_NAME
] = addressbook_set_col_name_guard(person
->nickName
);
3698 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3704 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3706 nodePerson
= gtk_sctree_insert_node(
3708 text
, FOLDER_SPACING
,
3711 FALSE
, person
->isOpened
);
3714 gtk_cmctree_node_set_row_data(clist
, nodePerson
, person
);
3717 /* Subsequent email is a child node of person */
3718 text
[COL_NAME
] = ADDRITEM_NAME(email
);
3719 nodeEMail
= gtk_sctree_insert_node(
3720 clist
, nodePerson
, NULL
,
3721 text
, FOLDER_SPACING
,
3723 atciMail
->iconXpmOpen
,
3725 gtk_cmctree_node_set_row_data(clist
, nodeEMail
, email
);
3731 /* Have name without EMail */
3732 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3733 text
[COL_ADDRESS
] = "";
3734 text
[COL_REMARKS
] = "";
3735 nodePerson
= gtk_sctree_insert_node(
3737 text
, FOLDER_SPACING
,
3740 FALSE
, person
->isOpened
);
3741 gtk_cmctree_node_set_row_data(clist
, nodePerson
, person
);
3746 static void addressbook_folder_load_person( GtkCMCTree
*clist
, ItemFolder
*itemFolder
) {
3748 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_PERSON
);
3749 AddressTypeControlItem
*atciMail
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3750 const gchar
*search_str
;
3752 if( atci
== NULL
) return;
3753 if( atciMail
== NULL
) return;
3755 search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3757 /* Load email addresses */
3758 items
= addritem_folder_get_person_list( itemFolder
);
3759 for(cur
= items
; cur
!= NULL
; cur
= g_list_next( cur
) ) {
3764 person
= (ItemPerson
*)cur
->data
;
3767 node
= person
->listEMail
;
3768 if (node
&& node
->data
) {
3770 if (!addressbook_match_item(ADDRITEM_NAME(person
), ADDRITEM_NAME(email
), email
->address
, email
->remarks
, search_str
))
3773 if (!addressbook_match_item(ADDRITEM_NAME(person
), NULL
, NULL
, NULL
, search_str
))
3777 addressbook_folder_load_one_person( clist
, cur
->data
, atci
, atciMail
);
3779 /* Free up the list */
3780 g_list_free( items
);
3783 static void addressbook_folder_remove_node( GtkCMCTree
*clist
, GtkCMCTreeNode
*node
) {
3784 addrbook
.listSelected
= NULL
;
3785 gtk_cmctree_remove_node( clist
, node
);
3786 addressbook_menubar_set_sensitive( FALSE
);
3787 addressbook_menuitem_set_sensitive(
3788 gtk_cmctree_node_get_row_data(
3789 GTK_CMCTREE(clist
), addrbook
.treeSelected
),
3790 addrbook
.treeSelected
);
3793 void addressbook_folder_refresh_one_person( GtkCMCTree
*clist
, ItemPerson
*person
) {
3794 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_PERSON
);
3795 AddressTypeControlItem
*atciMail
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3796 GtkCMCTreeNode
*node
;
3797 if( atci
== NULL
) return;
3798 if( atciMail
== NULL
) return;
3799 if( person
== NULL
) return;
3800 /* unload the person */
3802 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3804 addressbook_folder_remove_node( clist
, node
);
3805 addressbook_folder_load_one_person( clist
, person
, atci
, atciMail
);
3806 gtk_sctree_sort_node( clist
, NULL
);
3807 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3809 gtk_sctree_select( GTK_SCTREE(clist
), node
);
3810 if (!gtk_cmctree_node_is_visible( clist
, node
) )
3811 gtk_cmctree_node_moveto( clist
, node
, 0, 0, 0 );
3815 void addressbook_folder_remove_one_person( GtkCMCTree
*clist
, ItemPerson
*person
) {
3816 GtkCMCTreeNode
*node
;
3818 if( person
== NULL
) return;
3819 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3821 addressbook_folder_remove_node( clist
, node
);
3825 static void addressbook_folder_load_group( GtkCMCTree
*clist
, ItemFolder
*itemFolder
) {
3827 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_GROUP
);
3828 const gchar
*search_str
;
3830 /* Load any groups */
3831 if( ! atci
) return;
3833 search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3835 items
= addritem_folder_get_group_list( itemFolder
);
3836 for( ; items
!= NULL
; items
= g_list_next( items
) ) {
3837 GtkCMCTreeNode
*nodeGroup
= NULL
;
3838 gchar
*text
[N_LIST_COLS
];
3839 ItemGroup
*group
= items
->data
;
3840 if( group
== NULL
) continue;
3841 if( !addressbook_match_item(ADDRITEM_NAME(group
),
3842 NULL
, NULL
, NULL
, search_str
) )
3845 text
[COL_NAME
] = ADDRITEM_NAME(group
);
3846 text
[COL_ADDRESS
] = "";
3847 text
[COL_REMARKS
] = "";
3848 nodeGroup
= gtk_sctree_insert_node(clist
, NULL
, NULL
,
3849 text
, FOLDER_SPACING
,
3853 gtk_cmctree_node_set_row_data(clist
, nodeGroup
, group
);
3854 gtk_sctree_sort_node(clist
, NULL
);
3856 /* Free up the list */
3857 g_list_free( items
);
3861 * Search ctree widget callback function.
3862 * \param pA Pointer to node.
3863 * \param pB Pointer to data item being sought.
3864 * \return Zero (0) if group found.
3866 static int addressbook_treenode_find_group_cb( gconstpointer pA
, gconstpointer pB
) {
3869 aoA
= ( AddressObject
* ) pA
;
3870 if( aoA
->type
== ADDR_ITEM_GROUP
) {
3871 ItemGroup
*group
, *grp
;
3873 grp
= ADAPTER_GROUP(aoA
)->itemGroup
;
3874 group
= ( ItemGroup
* ) pB
;
3875 if( grp
== group
) return 0; /* Found group */
3881 * Remove folder and group nodes from tree widget for items contained ("cut")
3884 static void addressbook_treenode_remove_item( void ) {
3886 AddrSelectItem
*cutItem
;
3887 AddressCache
*cache
;
3888 AddrItemObject
*aio
;
3889 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
3892 node
= _clipBoard_
->objectList
;
3894 cutItem
= node
->data
;
3895 node
= g_list_next( node
);
3896 cache
= addrindex_get_cache(
3897 _clipBoard_
->addressIndex
, cutItem
->cacheID
);
3898 if( cache
== NULL
) continue;
3899 aio
= addrcache_get_object( cache
, cutItem
->uid
);
3902 if( ADDRITEM_TYPE(aio
) == ITEMTYPE_FOLDER
) {
3905 folder
= ( ItemFolder
* ) aio
;
3906 tn
= gtk_cmctree_find_by_row_data_custom(
3907 ctree
, NULL
, folder
,
3908 addressbook_treenode_find_folder_cb
);
3910 else if( ADDRITEM_TYPE(aio
) == ITEMTYPE_GROUP
) {
3913 group
= ( ItemGroup
* ) aio
;
3914 tn
= gtk_cmctree_find_by_row_data_custom(
3916 addressbook_treenode_find_group_cb
);
3920 /* Free up adapter and remove node. */
3921 gtk_cmctree_remove_node( ctree
, tn
);
3928 * Find parent datasource for specified tree node.
3929 * \param node Node to test.
3930 * \return Data source, or NULL if not found.
3932 static AddressDataSource
*addressbook_find_datasource( GtkCMCTreeNode
*node
) {
3933 AddressDataSource
*ds
= NULL
;
3936 cm_return_val_if_fail(addrbook
.ctree
!= NULL
, NULL
);
3939 if( GTK_CMCTREE_ROW(node
)->level
< 2 ) return NULL
;
3940 ao
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), node
);
3942 /* g_print( "ao->type = %d\n", ao->type ); */
3943 if( ao
->type
== ADDR_DATASOURCE
) {
3944 AdapterDSource
*ads
= ADAPTER_DSOURCE(ao
);
3945 /* g_print( "found it\n" ); */
3946 ds
= ads
->dataSource
;
3950 node
= GTK_CMCTREE_ROW(node
)->parent
;
3956 * Load address list widget with children of specified object.
3957 * \param obj Parent object to be loaded.
3959 static void addressbook_set_clist( AddressObject
*obj
, gboolean refresh
) {
3960 GtkCMCTree
*ctreelist
= GTK_CMCTREE(addrbook
.clist
);
3961 GtkCMCList
*clist
= GTK_CMCLIST(addrbook
.clist
);
3962 AddressDataSource
*ds
= NULL
;
3963 AdapterDSource
*ads
= NULL
;
3964 static AddressObject
*last_obj
= NULL
;
3966 if (addrbook
.clist
== NULL
) {
3969 if (obj
== last_obj
&& !refresh
)
3974 gtk_cmclist_clear(clist
);
3978 if( obj
->type
== ADDR_INTERFACE
) {
3979 /* g_print( "set_clist: loading datasource...\n" ); */
3980 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3984 gtk_cmclist_freeze(clist
);
3985 gtk_cmclist_clear(clist
);
3987 if( obj
->type
== ADDR_DATASOURCE
) {
3988 ads
= ADAPTER_DSOURCE(obj
);
3989 ds
= ads
->dataSource
;
3991 /* Load root folder */
3992 ItemFolder
*rootFolder
= NULL
;
3993 rootFolder
= addrindex_ds_get_root_folder( ds
);
3994 addressbook_folder_load_person(
3995 ctreelist
, rootFolder
);
3996 addressbook_folder_load_group(
3997 ctreelist
, rootFolder
);
4001 if( obj
->type
== ADDR_ITEM_GROUP
) {
4003 ItemGroup
*itemGroup
= ADAPTER_GROUP(obj
)->itemGroup
;
4004 addressbook_load_group( ctreelist
, itemGroup
);
4006 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
4008 ItemFolder
*itemFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
4009 addressbook_folder_load_person( ctreelist
, itemFolder
);
4010 addressbook_folder_load_group( ctreelist
, itemFolder
);
4013 gtk_sctree_sort_recursive(GTK_CMCTREE(clist
), NULL
);
4014 clist
->focus_row
= -1;
4015 gtk_cmclist_thaw(clist
);
4019 * Call back function to free adaptor. Call back is setup by function
4020 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4021 * called when the address book tree widget node is removed by calling
4022 * function gtk_cmctree_remove_node().
4024 * \param data Tree node's row data.
4026 static void addressbook_free_treenode( gpointer data
) {
4029 ao
= ( AddressObject
* ) data
;
4030 if( ao
== NULL
) return;
4031 if( ao
->type
== ADDR_INTERFACE
) {
4032 AdapterInterface
*ai
= ADAPTER_INTERFACE(ao
);
4033 addrbookctl_free_interface( ai
);
4035 else if( ao
->type
== ADDR_DATASOURCE
) {
4036 AdapterDSource
*ads
= ADAPTER_DSOURCE(ao
);
4037 addrbookctl_free_datasource( ads
);
4039 else if( ao
->type
== ADDR_ITEM_FOLDER
) {
4040 AdapterFolder
*af
= ADAPTER_FOLDER(ao
);
4041 addrbookctl_free_folder( af
);
4043 else if( ao
->type
== ADDR_ITEM_GROUP
) {
4044 AdapterGroup
*ag
= ADAPTER_GROUP(ao
);
4045 addrbookctl_free_group( ag
);
4050 * Create new adaptor for specified data source.
4052 AdapterDSource
*addressbook_create_ds_adapter( AddressDataSource
*ds
,
4053 AddressObjectType otype
, gchar
*name
)
4055 AdapterDSource
*adapter
= g_new0( AdapterDSource
, 1 );
4056 ADDRESS_OBJECT(adapter
)->type
= ADDR_DATASOURCE
;
4057 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( name
);
4058 adapter
->dataSource
= ds
;
4059 adapter
->subType
= otype
;
4063 void addressbook_ads_set_name( AdapterDSource
*adapter
, gchar
*value
) {
4064 ADDRESS_OBJECT_NAME(adapter
) =
4065 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter
), value
);
4069 * Load tree from address index with the initial data.
4071 static void addressbook_load_tree( void ) {
4072 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
4073 GList
*nodeIf
, *nodeDS
;
4074 AdapterInterface
*adapter
;
4075 AddressInterface
*iface
;
4076 AddressTypeControlItem
*atci
;
4077 AddressDataSource
*ds
;
4078 AdapterDSource
*ads
;
4079 GtkCMCTreeNode
*node
, *newNode
;
4082 nodeIf
= _addressInterfaceList_
;
4084 adapter
= nodeIf
->data
;
4085 node
= adapter
->treeNode
;
4086 iface
= adapter
->interface
;
4087 atci
= adapter
->atci
;
4089 if( iface
->useInterface
) {
4090 /* Load data sources below interface node */
4091 nodeDS
= iface
->listSource
;
4094 name
= addrindex_ds_get_name( ds
);
4095 ads
= addressbook_create_ds_adapter(
4096 ds
, atci
->objectType
, name
);
4097 newNode
= addressbook_add_object(
4098 node
, ADDRESS_OBJECT(ads
) );
4099 if (newNode
== NULL
) {
4100 g_message("error adding addressbook object\n");
4102 nodeDS
= g_list_next( nodeDS
);
4104 gtk_cmctree_expand( ctree
, node
);
4107 nodeIf
= g_list_next( nodeIf
);
4112 * Convert the old address book to new format.
4114 static gboolean
addressbook_convert( AddressIndex
*addrIndex
) {
4115 gboolean retVal
= FALSE
;
4116 gboolean errFlag
= TRUE
;
4119 /* Read old address book, performing conversion */
4120 debug_print( "Reading and converting old address book...\n" );
4121 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_OLD_FILE
);
4122 addrindex_read_data( addrIndex
);
4123 if( addrIndex
->retVal
== MGU_NO_FILE
) {
4124 /* We do not have a file - new user */
4125 debug_print( "New user... create new books...\n" );
4126 addrindex_create_new_books( addrIndex
);
4127 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4128 /* Save index file */
4129 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4130 addrindex_save_data( addrIndex
);
4131 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4136 msg
= _( "New user, could not save index file." );
4140 msg
= _( "New user, could not save address book files." );
4144 /* We have an old file */
4145 if( addrIndex
->wasConverted
) {
4146 /* Converted successfully - save address index */
4147 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4148 addrindex_save_data( addrIndex
);
4149 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4150 msg
= _( "Old address book converted successfully." );
4155 msg
= _("Old address book converted,\n"
4156 "could not save new address index file." );
4160 /* File conversion failed - just create new books */
4161 debug_print( "File conversion failed... just create new books...\n" );
4162 addrindex_create_new_books( addrIndex
);
4163 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4165 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4166 addrindex_save_data( addrIndex
);
4167 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4168 msg
= _("Could not convert address book,\n"
4169 "but created empty new address book files." );
4174 msg
= _("Could not convert address book,\n"
4175 "could not save new address index file." );
4179 msg
= _("Could not convert address book\n"
4180 "and could not create new address book files." );
4185 debug_print( "Error\n%s\n", msg
);
4186 alertpanel_full(_("Addressbook conversion error"), msg
,
4187 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
4188 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_ERROR
);
4190 debug_print( "Warning\n%s\n", msg
);
4191 alertpanel_full(_("Addressbook conversion error"), msg
,
4192 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
4193 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_WARNING
);
4199 static gboolean
migrate_addrbook(const gchar
*origdir
, const gchar
*destdir
)
4203 gboolean failed
= FALSE
;
4204 GError
*error
= NULL
;
4206 if( ( dp
= g_dir_open( origdir
, 0, &error
) ) == NULL
) {
4207 debug_print("opening '%s' failed: %d (%s)\n", origdir
,
4208 error
->code
, error
->message
);
4209 g_error_free(error
);
4213 while( ( d
= g_dir_read_name( dp
) ) != NULL
) {
4214 if (strncmp(d
, "addrbook-", strlen("addrbook-")))
4217 gchar
*orig_file
= g_strconcat(origdir
, G_DIR_SEPARATOR_S
,
4219 gchar
*dest_file
= g_strconcat(destdir
, G_DIR_SEPARATOR_S
,
4221 if (copy_file(orig_file
, dest_file
, FALSE
) < 0) {
4234 /* all copies succeeded, we can remove source files */
4235 if( ( dp
= g_dir_open( origdir
, 0, &error
) ) == NULL
) {
4236 debug_print("opening '%s' failed: %d (%s)\n", origdir
,
4237 error
->code
, error
->message
);
4238 g_error_free(error
);
4241 while( ( d
= g_dir_read_name( dp
) ) != NULL
) {
4242 if (strncmp(d
, "addrbook-", strlen("addrbook-")))
4245 gchar
*orig_file
= g_strconcat(origdir
, G_DIR_SEPARATOR_S
,
4247 claws_unlink(orig_file
);
4257 void addressbook_read_file( void ) {
4258 AddressIndex
*addrIndex
= NULL
;
4259 gchar
*indexdir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, ADDRBOOK_DIR
, NULL
);
4261 debug_print( "Reading address index...\n" );
4262 if( _addressIndex_
) {
4263 debug_print( "address book already read!!!\n" );
4268 addrIndex
= addrindex_create_index();
4269 addrindex_initialize();
4271 /* Use new address book index. */
4273 if ( !is_dir_exist(indexdir
) ) {
4274 if ( make_dir(indexdir
) < 0 ) {
4275 addrindex_set_file_path( addrIndex
, get_rc_dir() );
4276 g_warning("couldn't create dir '%s'", indexdir
);
4278 if (!migrate_addrbook(get_rc_dir(), indexdir
)) {
4279 remove_dir_recursive(indexdir
);
4280 addrindex_set_file_path( addrIndex
, get_rc_dir() );
4281 g_error("couldn't migrate dir %s", indexdir
);
4283 addrindex_set_file_path( addrIndex
, indexdir
);
4287 addrindex_set_file_path( addrIndex
, indexdir
);
4290 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4291 addrindex_read_data( addrIndex
);
4292 if( addrIndex
->retVal
== MGU_NO_FILE
) {
4293 /* Conversion required */
4294 debug_print( "Converting...\n" );
4295 if( addressbook_convert( addrIndex
) ) {
4296 _addressIndex_
= addrIndex
;
4299 else if( addrIndex
->retVal
== MGU_SUCCESS
) {
4300 _addressIndex_
= addrIndex
;
4303 /* Error reading address book */
4304 debug_print( "Could not read address index.\n" );
4305 addrindex_print_index( addrIndex
, stdout
);
4306 alertpanel_full(_("Addressbook Error"),
4307 _("Could not read address index"),
4308 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
4309 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_ERROR
);
4311 debug_print( "done.\n" );
4315 * Add object into the address index tree widget.
4316 * Enter: node Parent node.
4317 * obj Object to add.
4318 * Return: Node that was added, or NULL if object not added.
4320 static GtkCMCTreeNode
*addressbook_add_object(GtkCMCTreeNode
*node
,
4323 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4324 GtkCMCTreeNode
*added
;
4325 AddressObject
*pobj
;
4326 AddressObjectType otype
;
4327 AddressTypeControlItem
*atci
= NULL
;
4329 cm_return_val_if_fail(node
!= NULL
, NULL
);
4330 cm_return_val_if_fail(obj
!= NULL
, NULL
);
4332 pobj
= gtk_cmctree_node_get_row_data(ctree
, node
);
4333 cm_return_val_if_fail(pobj
!= NULL
, NULL
);
4335 /* Determine object type to be displayed */
4336 if( obj
->type
== ADDR_DATASOURCE
) {
4337 otype
= ADAPTER_DSOURCE(obj
)->subType
;
4343 /* Handle any special conditions. */
4345 atci
= addrbookctl_lookup( otype
);
4347 if( atci
->showInTree
) {
4348 /* Add object to tree */
4351 added
= gtk_sctree_insert_node( ctree
, node
, NULL
, name
, FOLDER_SPACING
,
4352 atci
->iconXpm
, atci
->iconXpmOpen
,
4353 atci
->treeLeaf
, atci
->treeExpand
);
4354 gtk_cmctree_node_set_row_data_full( ctree
, added
, obj
,
4355 addressbook_free_treenode
);
4359 gtk_sctree_sort_node(ctree
, node
);
4365 * Add group into the address index tree.
4366 * \param node Parent node.
4367 * \param ds Data source.
4368 * \param itemGroup Group to add.
4369 * \return Inserted node.
4371 static GtkCMCTreeNode
*addressbook_node_add_group(
4372 GtkCMCTreeNode
*node
, AddressDataSource
*ds
,
4373 ItemGroup
*itemGroup
)
4375 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4376 GtkCMCTreeNode
*newNode
;
4377 AdapterGroup
*adapter
;
4378 AddressTypeControlItem
*atci
= NULL
;
4381 if( ds
== NULL
) return NULL
;
4382 if( node
== NULL
|| itemGroup
== NULL
) return NULL
;
4384 name
= &itemGroup
->obj
.name
;
4386 atci
= addrbookctl_lookup( ADDR_ITEM_GROUP
);
4388 adapter
= g_new0( AdapterGroup
, 1 );
4389 ADDRESS_OBJECT_TYPE(adapter
) = ADDR_ITEM_GROUP
;
4390 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( ADDRITEM_NAME(itemGroup
) );
4391 adapter
->itemGroup
= itemGroup
;
4393 newNode
= gtk_sctree_insert_node( ctree
, node
, NULL
, name
, FOLDER_SPACING
,
4394 atci
->iconXpm
, atci
->iconXpm
,
4395 atci
->treeLeaf
, atci
->treeExpand
);
4396 gtk_cmctree_node_set_row_data_full( ctree
, newNode
, adapter
,
4397 addressbook_free_treenode
);
4398 gtk_sctree_sort_node( ctree
, node
);
4403 * Add folder into the address index tree. Only visible folders are loaded into
4404 * the address index tree. Note that the root folder is not inserted into the
4407 * \param node Parent node.
4408 * \param ds Data source.
4409 * \param itemFolder Folder to add.
4410 * \param otype Object type to display.
4411 * \return Inserted node for the folder.
4413 static GtkCMCTreeNode
*addressbook_node_add_folder(
4414 GtkCMCTreeNode
*node
, AddressDataSource
*ds
,
4415 ItemFolder
*itemFolder
, AddressObjectType otype
)
4417 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4418 GtkCMCTreeNode
*newNode
= NULL
;
4419 AddressTypeControlItem
*atci
= NULL
;
4420 GList
*listItems
= NULL
;
4422 ItemFolder
*rootFolder
;
4424 /* Only visible folders */
4425 if( itemFolder
== NULL
|| itemFolder
->isHidden
)
4430 if( node
== NULL
|| itemFolder
== NULL
)
4433 /* Determine object type */
4434 atci
= addrbookctl_lookup( otype
);
4438 rootFolder
= addrindex_ds_get_root_folder( ds
);
4439 if( itemFolder
== rootFolder
) {
4443 AdapterFolder
*adapter
= g_new0( AdapterFolder
, 1 );
4444 ADDRESS_OBJECT_TYPE(adapter
) = ADDR_ITEM_FOLDER
;
4445 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( ADDRITEM_NAME(itemFolder
) );
4446 adapter
->itemFolder
= itemFolder
;
4448 name
= ADDRITEM_NAME(itemFolder
);
4449 newNode
= gtk_sctree_insert_node( ctree
, node
, NULL
, &name
, FOLDER_SPACING
,
4450 atci
->iconXpm
, atci
->iconXpm
,
4451 atci
->treeLeaf
, atci
->treeExpand
);
4453 gtk_cmctree_node_set_row_data_full( ctree
, newNode
, adapter
,
4454 addressbook_free_treenode
);
4456 addrbookctl_free_folder(adapter
);
4460 listItems
= itemFolder
->listFolder
;
4461 while( listItems
) {
4462 ItemFolder
*item
= listItems
->data
;
4463 addressbook_node_add_folder( newNode
, ds
, item
, otype
);
4464 listItems
= g_list_next( listItems
);
4466 listItems
= itemFolder
->listGroup
;
4467 while( listItems
) {
4468 ItemGroup
*item
= listItems
->data
;
4469 addressbook_node_add_group( newNode
, ds
, item
);
4470 listItems
= g_list_next( listItems
);
4472 gtk_sctree_sort_node( ctree
, node
);
4476 void addressbook_export_to_file( void ) {
4477 if( _addressIndex_
) {
4478 /* Save all new address book data */
4479 debug_print( "Saving address books...\n" );
4480 addrindex_save_all_books( _addressIndex_
);
4482 debug_print( "Exporting addressbook to file...\n" );
4483 addrindex_save_data( _addressIndex_
);
4484 if( _addressIndex_
->retVal
!= MGU_SUCCESS
) {
4485 addrindex_print_index( _addressIndex_
, stdout
);
4488 /* Notify address completion of new data */
4489 invalidate_address_completion();
4493 static gboolean
addressbook_entry_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
4495 if (event
&& (event
->keyval
== GDK_KEY_Return
|| event
->keyval
== GDK_KEY_KP_Enter
))
4496 addressbook_lup_clicked(NULL
, NULL
);
4501 * Comparison using cell contents (text in first column). Used for sort
4502 * address index widget.
4504 static gint
addressbook_treenode_compare_func(
4505 GtkCMCList
*clist
, gconstpointer ptr1
, gconstpointer ptr2
)
4507 GtkCMCell
*cell1
= ((GtkCMCListRow
*)ptr1
)->cell
;
4508 GtkCMCell
*cell2
= ((GtkCMCListRow
*)ptr2
)->cell
;
4509 gchar
*name1
= NULL
, *name2
= NULL
;
4510 if( cell1
) name1
= cell1
->u
.text
;
4511 if( cell2
) name2
= cell2
->u
.text
;
4512 if( ! name1
) return ( name2
!= NULL
);
4513 if( ! name2
) return -1;
4514 return g_utf8_collate( name1
, name2
);
4517 static void addressbook_new_book_cb( GtkAction
*action
, gpointer data
) {
4518 AdapterDSource
*ads
;
4519 AdapterInterface
*adapter
;
4520 GtkCMCTreeNode
*newNode
;
4522 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
4523 if( adapter
== NULL
) return;
4524 ads
= addressbook_edit_book( _addressIndex_
, NULL
);
4526 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4528 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4529 addrbook
.treeSelected
= newNode
;
4534 static void addressbook_new_vcard_cb( GtkAction
*action
, gpointer data
) {
4535 AdapterDSource
*ads
;
4536 AdapterInterface
*adapter
;
4537 GtkCMCTreeNode
*newNode
;
4539 adapter
= addrbookctl_find_interface( ADDR_IF_VCARD
);
4540 if( adapter
== NULL
) return;
4541 ads
= addressbook_edit_vcard( _addressIndex_
, NULL
);
4543 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4545 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4546 addrbook
.treeSelected
= newNode
;
4552 static void addressbook_new_jpilot_cb( GtkAction
*action
, gpointer data
) {
4553 AdapterDSource
*ads
;
4554 AdapterInterface
*adapter
;
4555 AddressInterface
*iface
;
4556 GtkCMCTreeNode
*newNode
;
4558 adapter
= addrbookctl_find_interface( ADDR_IF_JPILOT
);
4559 if( adapter
== NULL
) return;
4560 iface
= adapter
->interface
;
4561 if( ! iface
->haveLibrary
) return;
4562 ads
= addressbook_edit_jpilot( _addressIndex_
, NULL
);
4564 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4566 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4567 addrbook
.treeSelected
= newNode
;
4574 static void addressbook_new_ldap_cb( GtkAction
*action
, gpointer data
) {
4575 AdapterDSource
*ads
;
4576 AdapterInterface
*adapter
;
4577 AddressInterface
*iface
;
4578 GtkCMCTreeNode
*newNode
;
4580 adapter
= addrbookctl_find_interface( ADDR_IF_LDAP
);
4581 if( adapter
== NULL
) return;
4582 iface
= adapter
->interface
;
4583 if( ! iface
->haveLibrary
) return;
4584 ads
= addressbook_edit_ldap( _addressIndex_
, NULL
);
4586 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4588 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4589 addrbook
.treeSelected
= newNode
;
4596 * Display address search status message.
4597 * \param queryType Query type.
4598 * \param status Status/Error code.
4600 static void addressbook_search_message( gint queryType
, gint sts
) {
4602 *addressbook_msgbuf
= '\0';
4604 if( sts
!= MGU_SUCCESS
) {
4605 if( queryType
== ADDRQUERY_LDAP
) {
4607 desc
= addressbook_err2string( _lutErrorsLDAP_
, sts
);
4612 g_snprintf( addressbook_msgbuf
,
4613 sizeof(addressbook_msgbuf
), "%s", desc
);
4614 addressbook_status_show( addressbook_msgbuf
);
4617 addressbook_status_show( "" );
4622 * Refresh addressbook by forcing refresh of current selected object in
4625 static void addressbook_refresh_current( void ) {
4629 ctree
= GTK_CMCTREE(addrbook
.ctree
);
4630 obj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
4631 if( obj
== NULL
) return;
4632 addressbook_set_clist( obj
, TRUE
);
4636 * Message that is displayed whilst a query is executing in a background
4639 static gchar
*_tempMessage_
= N_( "Busy searching..." );
4642 * Address search idle function. This function is called during UI idle time
4643 * while a search is in progress.
4645 * \param data Idler data.
4647 static void addressbook_search_idle( gpointer data
) {
4651 queryID = GPOINTER_TO_INT( data );
4652 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4657 * Search completion callback function. This removes the query from the idle
4660 * \param sender Sender of query.
4661 * \param queryID Query ID of search request.
4662 * \param status Search status.
4663 * \param data Query data.
4665 static void addressbook_search_callback_end(
4666 gpointer sender
, gint queryID
, gint status
, gpointer data
)
4670 AddrQueryObject
*aqo
;
4672 /* Remove idler function */
4673 ptrQID
= GINT_TO_POINTER( queryID
);
4675 g_idle_remove_by_data( ptrQID
);
4678 /* Refresh addressbook contents */
4679 addressbook_refresh_current();
4680 req
= qrymgr_find_request( queryID
);
4682 aqo
= ( AddrQueryObject
* ) req
->queryList
->data
;
4683 addressbook_search_message( aqo
->queryType
, status
);
4686 /* Stop the search */
4687 addrindex_stop_search( queryID
);
4693 * \param ds Data source to search.
4694 * \param searchTerm String to lookup.
4695 * \param pNode Parent data source node.
4697 static void addressbook_perform_search(
4698 AddressDataSource
*ds
, gchar
*searchTerm
,
4699 GtkCMCTreeNode
*pNode
)
4707 if( *searchTerm
== '\0' || strlen( searchTerm
) < 1 ) return;
4709 if( !ds
|| ds
->type
!= ADDR_IF_LDAP
) return;
4711 /* Create a folder for the search results */
4712 name
= g_strdup_printf( _queryFolderLabel_
, searchTerm
);
4713 folder
= addressbook_setup_subf(ds
, name
, pNode
);
4716 /* Setup the search */
4717 queryID
= addrindex_setup_explicit_search(
4718 ds
, searchTerm
, folder
, addressbook_search_callback_end
, NULL
);
4719 if( queryID
== 0 ) return;
4721 /* Set up idler function */
4722 idleID
= g_idle_add(
4723 (GSourceFunc
) addressbook_search_idle
,
4724 GINT_TO_POINTER( queryID
) );
4726 g_message("error adding addressbook_search_idle\n");
4729 /* Start search, sit back and wait for something to happen */
4730 addrindex_start_search( queryID
);
4732 addressbook_status_show( _tempMessage_
);
4736 * Lookup button handler. Address search is only performed against
4737 * address interfaces for external queries.
4739 * \param button Lookup button widget.
4740 * \param data Data object.
4742 static void addressbook_lup_clicked( GtkButton
*button
, gpointer data
) {
4745 AddressDataSource
*ds
;
4746 AddressInterface
*iface
;
4748 GtkCMCTreeNode
*node
, *parentNode
;
4750 LdapServer
*ldap_server
;
4751 LdapControl
*ldap_ctl
;
4754 node
= addrbook
.treeSelected
;
4755 if( ! node
) return;
4756 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
4758 ctree
= GTK_CMCTREE(addrbook
.ctree
);
4759 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
4760 if( obj
== NULL
) return;
4762 if (obj
->type
!= ADDR_DATASOURCE
||
4763 ADAPTER_DSOURCE(obj
)->subType
!= ADDR_LDAP
) {
4764 addressbook_set_clist(
4765 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
4766 addrbook
.treeSelected
),
4770 ds
= addressbook_find_datasource( node
);
4771 if( ds
== NULL
) return;
4773 /* We must have a datasource that is an external interface */
4774 iface
= ds
->interface
;
4775 if( ! iface
->haveLibrary
) return;
4776 if( ! iface
->externalQuery
) return;
4779 if (iface
->type
== ADDR_IF_LDAP
) {
4780 ldap_server
= ds
->rawDataSource
;
4781 ldap_ctl
= ldap_server
->control
;
4782 if (ldap_ctl
!= NULL
&&
4783 ldap_ctl
->bindDN
!= NULL
&& strlen(ldap_ctl
->bindDN
) > 0) {
4784 #ifndef PASSWORD_CRYPTO_OLD
4785 /* LDAP server is password-protected. */
4786 if (primary_passphrase() == NULL
) {
4787 /* User did not enter primary passphrase, do not start a search. */
4790 #endif /* PASSWORD_CRYPTO_OLD */
4793 #endif /* USE_LDAP */
4796 gtk_editable_get_chars( GTK_EDITABLE(addrbook
.entry
), 0, -1 );
4797 g_strchomp( searchTerm
);
4799 if( obj
->type
== ADDR_ITEM_FOLDER
) {
4800 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
4805 addressbook_perform_search( ds
, searchTerm
, parentNode
);
4807 gtk_widget_grab_focus( addrbook
.entry
);
4809 g_free( searchTerm
);
4812 static void addressbook_close_clicked( GtkButton
*button
, gpointer data
) {
4813 addressbook_close();
4818 * Browse address entry for highlighted entry.
4820 static void addressbook_browse_entry_cb( GtkAction
*action
, gpointer data
)
4822 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
4824 AddressDataSource
*ds
;
4825 AddressInterface
*iface
;
4829 if(addrbook
.listSelected
== NULL
)
4832 obj
= gtk_cmctree_node_get_row_data(clist
, addrbook
.listSelected
);
4836 ds
= addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook
.treeSelected
));
4840 iface
= ds
->interface
;
4841 if(!iface
|| !iface
->haveLibrary
)
4845 if (obj
->type
== ADDR_ITEM_EMAIL
) {
4846 email
= ( ItemEMail
* ) obj
;
4848 person
= (ItemPerson
*) ADDRITEM_PARENT(email
);
4850 else if (obj
->type
== ADDR_ITEM_PERSON
) {
4851 person
= (ItemPerson
*) obj
;
4858 if( iface
&& iface
->type
== ADDR_IF_LDAP
) {
4859 browseldap_entry(ds
, person
->externalID
);
4864 /* **********************************************************************
4865 * Build lookup tables.
4866 * ***********************************************************************
4870 * Remap object types.
4871 * Enter: abType AddressObjectType (used in tree node).
4872 * Return: ItemObjectType (used in address cache data).
4874 ItemObjectType
addressbook_type2item( AddressObjectType abType
) {
4875 ItemObjectType ioType
;
4878 case ADDR_ITEM_PERSON
: ioType
= ITEMTYPE_PERSON
; break;
4879 case ADDR_ITEM_EMAIL
: ioType
= ITEMTYPE_EMAIL
; break;
4880 case ADDR_ITEM_FOLDER
: ioType
= ITEMTYPE_FOLDER
; break;
4881 case ADDR_ITEM_GROUP
: ioType
= ITEMTYPE_GROUP
; break;
4882 case ADDR_DATASOURCE
: ioType
= ITEMTYPE_DATASOURCE
; break;
4883 default: ioType
= ITEMTYPE_NONE
; break;
4888 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4889 atci = addrbookctl_lookup(id); \
4891 atci->iconXpm = icon; \
4892 atci->iconXpmOpen = iconopen; \
4894 g_warning("can't get atci %d", id); \
4899 * Build table that controls the rendering of object types.
4901 static void addrbookctl_build_icons( GtkWidget
*window
) {
4902 AddressTypeControlItem
*atci
;
4906 g_object_unref(interfacexpm
);
4908 g_object_unref(folderxpm
);
4910 g_object_unref(folderopenxpm
);
4912 g_object_unref(groupxpm
);
4914 g_object_unref(vcardxpm
);
4916 g_object_unref(bookxpm
);
4918 g_object_unref(addressxpm
);
4920 g_object_unref(jpilotxpm
);
4922 g_object_unref(categoryxpm
);
4924 g_object_unref(ldapxpm
);
4926 g_object_unref(addrsearchxpm
);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE
, &interfacexpm
);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP
, &groupxpm
);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD
, &vcardxpm
);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK
, &bookxpm
);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS
, &addressxpm
);
4934 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT
, &jpilotxpm
);
4935 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY
, &categoryxpm
);
4936 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP
, &ldapxpm
);
4937 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH
, &addrsearchxpm
);
4939 UPDATE_ICON_ATCI(ADDR_INTERFACE
,folderxpm
,folderopenxpm
);
4940 UPDATE_ICON_ATCI(ADDR_BOOK
,bookxpm
,bookxpm
);
4941 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON
,NULL
,NULL
);
4942 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL
,addressxpm
,addressxpm
);
4943 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP
,groupxpm
,groupxpm
);
4944 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER
,folderxpm
,folderopenxpm
);
4945 UPDATE_ICON_ATCI(ADDR_VCARD
,vcardxpm
,vcardxpm
);
4946 UPDATE_ICON_ATCI(ADDR_JPILOT
,jpilotxpm
,jpilotxpm
);
4947 UPDATE_ICON_ATCI(ADDR_CATEGORY
,categoryxpm
,categoryxpm
);
4948 UPDATE_ICON_ATCI(ADDR_LDAP
,ldapxpm
,ldapxpm
);
4949 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY
,addrsearchxpm
,addrsearchxpm
);
4954 * Build table that controls the rendering of object types.
4956 static void addrbookctl_build_map( GtkWidget
*window
) {
4957 AddressTypeControlItem
*atci
;
4959 _addressBookTypeHash_
= g_hash_table_new( g_int_hash
, g_int_equal
);
4960 _addressBookTypeList_
= NULL
;
4963 atci
= g_new0( AddressTypeControlItem
, 1 );
4964 atci
->objectType
= ADDR_INTERFACE
;
4965 atci
->interfaceType
= ADDR_IF_NONE
;
4966 atci
->showInTree
= TRUE
;
4967 atci
->treeExpand
= TRUE
;
4968 atci
->treeLeaf
= FALSE
;
4969 atci
->displayName
= _( "Interface" );
4970 atci
->menuCommand
= NULL
;
4971 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4972 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4975 atci
= g_new0( AddressTypeControlItem
, 1 );
4976 atci
->objectType
= ADDR_BOOK
;
4977 atci
->interfaceType
= ADDR_IF_BOOK
;
4978 atci
->showInTree
= TRUE
;
4979 atci
->treeExpand
= TRUE
;
4980 atci
->treeLeaf
= FALSE
;
4981 atci
->displayName
= _("Address Books");
4982 atci
->menuCommand
= "Menu/Book/NewBook";
4983 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4984 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4987 atci
= g_new0( AddressTypeControlItem
, 1 );
4988 atci
->objectType
= ADDR_ITEM_PERSON
;
4989 atci
->interfaceType
= ADDR_IF_NONE
;
4990 atci
->showInTree
= FALSE
;
4991 atci
->treeExpand
= FALSE
;
4992 atci
->treeLeaf
= FALSE
;
4993 atci
->displayName
= _( "Person" );
4994 atci
->menuCommand
= NULL
;
4995 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4996 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4999 atci
= g_new0( AddressTypeControlItem
, 1 );
5000 atci
->objectType
= ADDR_ITEM_EMAIL
;
5001 atci
->interfaceType
= ADDR_IF_NONE
;
5002 atci
->showInTree
= FALSE
;
5003 atci
->treeExpand
= FALSE
;
5004 atci
->treeLeaf
= TRUE
;
5005 atci
->displayName
= _( "Email Address" );
5006 atci
->menuCommand
= NULL
;
5007 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5008 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5011 atci
= g_new0( AddressTypeControlItem
, 1 );
5012 atci
->objectType
= ADDR_ITEM_GROUP
;
5013 atci
->interfaceType
= ADDR_IF_BOOK
;
5014 atci
->showInTree
= TRUE
;
5015 atci
->treeExpand
= FALSE
;
5016 atci
->treeLeaf
= FALSE
;
5017 atci
->displayName
= _( "Group" );
5018 atci
->menuCommand
= NULL
;
5019 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5020 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5023 atci
= g_new0( AddressTypeControlItem
, 1 );
5024 atci
->objectType
= ADDR_ITEM_FOLDER
;
5025 atci
->interfaceType
= ADDR_IF_BOOK
;
5026 atci
->showInTree
= TRUE
;
5027 atci
->treeExpand
= FALSE
;
5028 atci
->treeLeaf
= FALSE
;
5029 atci
->displayName
= _( "Folder" );
5030 atci
->menuCommand
= NULL
;
5031 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5032 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5035 atci
= g_new0( AddressTypeControlItem
, 1 );
5036 atci
->objectType
= ADDR_VCARD
;
5037 atci
->interfaceType
= ADDR_IF_VCARD
;
5038 atci
->showInTree
= TRUE
;
5039 atci
->treeExpand
= TRUE
;
5040 atci
->treeLeaf
= TRUE
;
5041 atci
->displayName
= _( "vCard" );
5042 atci
->menuCommand
= "Menu/Book/NewVCard";
5043 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5044 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5047 atci
= g_new0( AddressTypeControlItem
, 1 );
5048 atci
->objectType
= ADDR_JPILOT
;
5049 atci
->interfaceType
= ADDR_IF_JPILOT
;
5050 atci
->showInTree
= TRUE
;
5051 atci
->treeExpand
= TRUE
;
5052 atci
->treeLeaf
= FALSE
;
5053 atci
->displayName
= _( "JPilot" );
5054 atci
->menuCommand
= "Menu/Book/NewJPilot";
5055 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5056 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5059 atci
= g_new0( AddressTypeControlItem
, 1 );
5060 atci
->objectType
= ADDR_CATEGORY
;
5061 atci
->interfaceType
= ADDR_IF_JPILOT
;
5062 atci
->showInTree
= TRUE
;
5063 atci
->treeExpand
= TRUE
;
5064 atci
->treeLeaf
= TRUE
;
5065 atci
->displayName
= _( "JPilot" );
5066 atci
->menuCommand
= NULL
;
5067 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5068 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5071 atci
= g_new0( AddressTypeControlItem
, 1 );
5072 atci
->objectType
= ADDR_LDAP
;
5073 atci
->interfaceType
= ADDR_IF_LDAP
;
5074 atci
->showInTree
= TRUE
;
5075 atci
->treeExpand
= TRUE
;
5076 atci
->treeLeaf
= FALSE
;
5077 atci
->displayName
= _( "LDAP servers" );
5078 atci
->menuCommand
= "Menu/Book/NewLDAPServer";
5079 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5080 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5083 atci
= g_new0( AddressTypeControlItem
, 1 );
5084 atci
->objectType
= ADDR_LDAP_QUERY
;
5085 atci
->interfaceType
= ADDR_IF_LDAP
;
5086 atci
->showInTree
= TRUE
;
5087 atci
->treeExpand
= FALSE
;
5088 atci
->treeLeaf
= TRUE
;
5089 atci
->displayName
= _( "LDAP Query" );
5090 atci
->menuCommand
= NULL
;
5091 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5092 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5094 addrbookctl_build_icons(window
);
5097 void addressbook_reflect_prefs_pixmap_theme(void)
5099 if (addrbook
.window
)
5100 addrbookctl_build_icons(addrbook
.window
);
5104 * Search for specified object type.
5106 static AddressTypeControlItem
*addrbookctl_lookup( gint ot
) {
5108 return ( AddressTypeControlItem
* ) g_hash_table_lookup( _addressBookTypeHash_
, &objType
);
5112 * Search for specified interface type.
5114 static AddressTypeControlItem
*addrbookctl_lookup_iface( AddressIfType ifType
) {
5115 GList
*node
= _addressBookTypeList_
;
5117 AddressTypeControlItem
*atci
= node
->data
;
5118 if( atci
->interfaceType
== ifType
) return atci
;
5119 node
= g_list_next( node
);
5124 static void addrbookctl_free_address( AddressObject
*obj
) {
5125 g_free( obj
->name
);
5126 obj
->type
= ADDR_NONE
;
5130 static void addrbookctl_free_interface( AdapterInterface
*adapter
) {
5131 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5132 adapter
->interface
= NULL
;
5133 adapter
->interfaceType
= ADDR_IF_NONE
;
5134 adapter
->atci
= NULL
;
5135 adapter
->enabled
= FALSE
;
5136 adapter
->haveLibrary
= FALSE
;
5137 adapter
->treeNode
= NULL
;
5141 static void addrbookctl_free_datasource( AdapterDSource
*adapter
) {
5142 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5143 adapter
->dataSource
= NULL
;
5144 adapter
->subType
= ADDR_NONE
;
5148 static void addrbookctl_free_folder( AdapterFolder
*adapter
) {
5149 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5150 adapter
->itemFolder
= NULL
;
5154 static void addrbookctl_free_group( AdapterGroup
*adapter
) {
5155 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5156 adapter
->itemGroup
= NULL
;
5161 * Build GUI interface list.
5163 static void addrbookctl_build_iflist( void ) {
5164 AddressTypeControlItem
*atci
;
5165 AdapterInterface
*adapter
;
5168 if( _addressIndex_
== NULL
) {
5169 _addressIndex_
= addrindex_create_index();
5170 if( _clipBoard_
== NULL
) {
5171 _clipBoard_
= addrclip_create();
5173 addrclip_set_index( _clipBoard_
, _addressIndex_
);
5175 _addressInterfaceList_
= NULL
;
5176 list
= addrindex_get_interface_list( _addressIndex_
);
5178 AddressInterface
*interface
= list
->data
;
5179 atci
= addrbookctl_lookup_iface( interface
->type
);
5181 adapter
= g_new0( AdapterInterface
, 1 );
5182 adapter
->interfaceType
= interface
->type
;
5183 adapter
->atci
= atci
;
5184 adapter
->interface
= interface
;
5185 adapter
->treeNode
= NULL
;
5186 adapter
->enabled
= TRUE
;
5187 adapter
->haveLibrary
= interface
->haveLibrary
;
5188 ADDRESS_OBJECT(adapter
)->type
= ADDR_INTERFACE
;
5189 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( atci
->displayName
);
5190 _addressInterfaceList_
=
5191 g_list_append( _addressInterfaceList_
, adapter
);
5193 list
= g_list_next( list
);
5198 * Find GUI interface type specified interface type.
5199 * \param ifType Interface type.
5200 * \return Interface item, or NULL if not found.
5202 static AdapterInterface
*addrbookctl_find_interface( AddressIfType ifType
) {
5203 GList
*node
= _addressInterfaceList_
;
5205 AdapterInterface
*adapter
= node
->data
;
5206 if( adapter
->interfaceType
== ifType
) return adapter
;
5207 node
= g_list_next( node
);
5213 * Build interface list selection.
5215 static void addrbookctl_build_ifselect( void ) {
5216 GList
*newList
= NULL
;
5221 gchar
*endptr
= NULL
;
5222 /* gboolean enabled; */
5223 AdapterInterface
*adapter
;
5225 selectStr
= g_strdup( ADDRESSBOOK_IFACE_SELECTION
);
5228 splitStr
= g_strsplit( selectStr
, ",", -1 );
5229 for( i
= 0; i
< ADDRESSBOOK_MAX_IFACE
; i
++ ) {
5231 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5232 ifType
= strtol( splitStr
[i
], &endptr
, 10 );
5235 if( strcmp( endptr, "/n" ) == 0 ) {
5240 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5241 adapter
= addrbookctl_find_interface( ifType
);
5243 newList
= g_list_append( newList
, adapter
);
5250 /* g_print( "i=%d\n", i ); */
5251 g_strfreev( splitStr
);
5252 g_free( selectStr
);
5254 /* Replace existing list */
5255 g_list_free( _addressIFaceSelection_
);
5256 _addressIFaceSelection_
= newList
;
5260 /* ***********************************************************************
5261 * Add sender to address book.
5262 * ***********************************************************************
5266 * This function is used by the Add sender to address book function.
5268 gboolean
addressbook_add_contact(
5269 const gchar
*name
, const gchar
*address
, const gchar
*remarks
,
5270 GdkPixbuf
*picture
)
5272 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name
, address
);
5273 if( addressadd_selection( _addressIndex_
, name
, address
, remarks
, picture
) ) {
5274 debug_print( "addressbook_add_contact - added\n" );
5275 addressbook_refresh();
5280 /* ***********************************************************************
5281 * Book/folder selection.
5282 * ***********************************************************************
5286 * This function is used by the matcher dialog to select a book/folder.
5288 gchar
*addressbook_folder_selection( const gchar
*folderpath
)
5290 AddressBookFile
*book
= NULL
;
5291 ItemFolder
*folder
= NULL
;
5294 cm_return_val_if_fail( folderpath
!= NULL
, NULL
);
5296 if ( addressbook_foldersel_selection( _addressIndex_
, &book
, &folder
, folderpath
)
5298 if ( folder
!= NULL
) {
5300 gchar
*oldtmp
= NULL
;
5301 AddrItemObject
*obj
= NULL
;
5303 /* walk thru folder->parent to build the full folder path */
5304 /* TODO: wwp: optimize this */
5306 tmp
= g_strdup(obj
->uid
);
5307 while ( obj
->parent
) {
5309 if ( obj
->name
!= NULL
) {
5310 oldtmp
= g_strdup(tmp
);
5312 tmp
= g_strdup_printf("%s/%s", obj
->uid
, oldtmp
);
5316 path
= g_strdup_printf("%s/%s", book
->fileName
, tmp
);
5319 path
= g_strdup_printf("%s", book
->fileName
);
5321 debug_print( "addressbook_foldersel: %s\n", path
?path
:"(null)");
5327 /* ***********************************************************************
5328 * Book/folder checking.
5329 * ***********************************************************************
5332 static FolderInfo
*addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile
*abf
, ItemFolder
*folder
)
5334 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
5336 fi
->folder
= folder
;
5340 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder
*parentFolder
,
5341 FolderInfo
*fiParent
, FolderPathMatch
*match
)
5347 FolderPathMatch
*nextmatch
= NULL
;
5352 list
= parentFolder
->listFolder
;
5354 folder
= list
->data
;
5355 fName
= g_strdup( ADDRITEM_NAME(folder
) );
5357 /* match folder name, match pointer will be set to NULL if next recursive call
5358 doesn't need to match subfolder name */
5359 if ( match
!= NULL
&&
5360 match
->matched
== FALSE
) {
5361 if ( strcmp(match
->folder_path
[match
->index
], folder
->obj
.uid
) == 0 ) {
5362 /* folder name matches, prepare next subfolder match */
5363 debug_print("matched folder name '%s'\n", fName
);
5365 if ( match
->folder_path
[match
->index
] == NULL
) {
5366 /* we've matched all elements */
5367 match
->matched
= TRUE
;
5368 match
->folder
= folder
;
5369 debug_print("book/folder path matched!\n");
5371 /* keep on matching */
5379 fi
= addressbook_peek_subfolder_exists_create_folderinfo( fiParent
->book
, folder
);
5380 addressbook_peek_subfolder_exists_load_folder( folder
, fi
, nextmatch
);
5382 list
= g_list_next( list
);
5387 * This function is used by to check if a matcher book/folder path corresponds to an
5388 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5389 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5390 if book AND folder are NULL this means that folderpath was empty or Any.
5391 If folderpath is a simple book name (without folder), book will not be NULL and folder
5392 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5395 gboolean
addressbook_peek_folder_exists( gchar
*folderpath
,
5396 AddressDataSource
**book
,
5397 ItemFolder
**folder
)
5399 AddressDataSource
*ds
;
5400 GList
*list
, *nodeDS
;
5401 ItemFolder
*rootFolder
;
5402 AddressBookFile
*abf
;
5404 FolderPathMatch folder_path_match
= { NULL
, FALSE
, 0, NULL
, NULL
};
5411 if ( folderpath
== NULL
)
5414 if ( strcasecmp(folderpath
, "Any") == 0 || *folderpath
== '\0' )
5417 /* split the folder path we've received, we'll try to match this path, subpath by
5418 subpath against the book/folder structure in order */
5419 folder_path_match
.folder_path
= g_strsplit( folderpath
, "/", 256 );
5420 if (!folder_path_match
.folder_path
)
5423 list
= addrindex_get_interface_list( _addressIndex_
);
5424 while ( list
&& !folder_path_match
.matched
) {
5425 AddressInterface
*interface
= list
->data
;
5426 if ( interface
&& interface
->type
== ADDR_IF_BOOK
) {
5427 nodeDS
= interface
->listSource
;
5428 while ( nodeDS
&& !folder_path_match
.matched
) {
5431 /* Read address book */
5432 if( ! addrindex_ds_get_read_flag( ds
) ) {
5433 addrindex_ds_read_data( ds
);
5436 /* Add node for address book */
5437 abf
= ds
->rawDataSource
;
5439 /* match book name */
5440 if ( abf
&& abf
->fileName
&&
5441 strcmp(folder_path_match
.folder_path
[0], abf
->fileName
) == 0 ) {
5443 debug_print("matched book name '%s'\n", abf
->fileName
);
5444 folder_path_match
.book
= ds
;
5446 if ( folder_path_match
.folder_path
[1] == NULL
) {
5447 /* no folder part to match */
5449 folder_path_match
.matched
= TRUE
;
5450 folder_path_match
.folder
= NULL
;
5451 debug_print("book path matched!\n");
5454 /* match folder part */
5456 fi
= addressbook_peek_subfolder_exists_create_folderinfo( abf
, NULL
);
5457 rootFolder
= addrindex_ds_get_root_folder( ds
);
5459 /* prepare for recursive call */
5460 folder_path_match
.index
= 1;
5461 /* this call will set folder_path_match.matched and folder_path_match.folder */
5462 addressbook_peek_subfolder_exists_load_folder( rootFolder
, fi
, &folder_path_match
);
5467 nodeDS
= g_list_next( nodeDS
);
5470 list
= g_list_next( list
);
5473 g_strfreev( folder_path_match
.folder_path
);
5476 *book
= folder_path_match
.book
;
5478 *folder
= folder_path_match
.folder
;
5479 return folder_path_match
.matched
;
5483 /* **********************************************************************
5485 * ***********************************************************************
5491 static void addressbook_import_ldif_cb( GtkAction
*action
, gpointer data
) {
5492 AddressDataSource
*ds
= NULL
;
5493 AdapterDSource
*ads
= NULL
;
5494 AddressBookFile
*abf
= NULL
;
5495 AdapterInterface
*adapter
;
5496 GtkCMCTreeNode
*newNode
;
5498 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5500 if( adapter
->treeNode
) {
5501 abf
= addressbook_imp_ldif( _addressIndex_
);
5503 ds
= addrindex_index_add_datasource(
5504 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5505 ads
= addressbook_create_ds_adapter(
5506 ds
, ADDR_BOOK
, NULL
);
5507 addressbook_ads_set_name(
5508 ads
, addrbook_get_name( abf
) );
5509 newNode
= addressbook_add_object(
5511 ADDRESS_OBJECT(ads
) );
5513 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5515 addrbook
.treeSelected
= newNode
;
5518 /* Notify address completion */
5519 invalidate_address_completion();
5528 static void addressbook_import_mutt_cb( GtkAction
*action
, gpointer data
) {
5529 AddressDataSource
*ds
= NULL
;
5530 AdapterDSource
*ads
= NULL
;
5531 AddressBookFile
*abf
= NULL
;
5532 AdapterInterface
*adapter
;
5533 GtkCMCTreeNode
*newNode
;
5535 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5537 if( adapter
->treeNode
) {
5538 abf
= addressbook_imp_mutt( _addressIndex_
);
5540 ds
= addrindex_index_add_datasource(
5541 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5542 ads
= addressbook_create_ds_adapter(
5543 ds
, ADDR_BOOK
, NULL
);
5544 addressbook_ads_set_name(
5545 ads
, addrbook_get_name( abf
) );
5546 newNode
= addressbook_add_object(
5548 ADDRESS_OBJECT(ads
) );
5550 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5552 addrbook
.treeSelected
= newNode
;
5555 /* Notify address completion */
5556 invalidate_address_completion();
5565 static void addressbook_import_pine_cb( GtkAction
*action
, gpointer data
) {
5566 AddressDataSource
*ds
= NULL
;
5567 AdapterDSource
*ads
= NULL
;
5568 AddressBookFile
*abf
= NULL
;
5569 AdapterInterface
*adapter
;
5570 GtkCMCTreeNode
*newNode
;
5572 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5574 if( adapter
->treeNode
) {
5575 abf
= addressbook_imp_pine( _addressIndex_
);
5577 ds
= addrindex_index_add_datasource(
5578 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5579 ads
= addressbook_create_ds_adapter(
5580 ds
, ADDR_BOOK
, NULL
);
5581 addressbook_ads_set_name(
5582 ads
, addrbook_get_name( abf
) );
5583 newNode
= addressbook_add_object(
5585 ADDRESS_OBJECT(ads
) );
5587 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5589 addrbook
.treeSelected
= newNode
;
5592 /* Notify address completion */
5593 invalidate_address_completion();
5600 * Harvest addresses.
5601 * \param folderItem Folder to import.
5602 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5603 * \param msgList List of message numbers, or NULL to process folder.
5605 void addressbook_harvest(
5606 FolderItem
*folderItem
, gboolean sourceInd
, GList
*msgList
)
5608 AddressDataSource
*ds
= NULL
;
5609 AdapterDSource
*ads
= NULL
;
5610 AddressBookFile
*abf
= NULL
;
5611 AdapterInterface
*adapter
;
5612 GtkCMCTreeNode
*newNode
;
5614 abf
= addrgather_dlg_execute(
5615 folderItem
, _addressIndex_
, sourceInd
, msgList
);
5617 ds
= addrindex_index_add_datasource(
5618 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5620 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5622 if( adapter
->treeNode
) {
5623 ads
= addressbook_create_ds_adapter(
5624 ds
, ADDR_BOOK
, addrbook_get_name( abf
) );
5625 newNode
= addressbook_add_object(
5627 ADDRESS_OBJECT(ads
) );
5628 if (newNode
== NULL
) {
5629 g_message("error adding addressbook object\n");
5634 /* Notify address completion */
5635 invalidate_address_completion();
5642 static void addressbook_export_html_cb( GtkAction
*action
, gpointer data
) {
5643 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
5645 AddressDataSource
*ds
= NULL
;
5646 AddrBookBase
*adbase
;
5647 AddressCache
*cache
;
5648 GtkCMCTreeNode
*node
= NULL
;
5650 if( ! addrbook
.treeSelected
) return;
5651 node
= addrbook
.treeSelected
;
5652 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
5653 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
5654 if( obj
== NULL
) return;
5656 ds
= addressbook_find_datasource( node
);
5657 if( ds
== NULL
) return;
5658 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
5659 cache
= adbase
->addressCache
;
5660 addressbook_exp_html( cache
);
5666 static void addressbook_export_ldif_cb( GtkAction
*action
, gpointer data
) {
5667 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
5669 AddressDataSource
*ds
= NULL
;
5670 AddrBookBase
*adbase
;
5671 AddressCache
*cache
;
5672 GtkCMCTreeNode
*node
= NULL
;
5674 if( ! addrbook
.treeSelected
) return;
5675 node
= addrbook
.treeSelected
;
5676 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
5677 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
5678 if( obj
== NULL
) return;
5680 ds
= addressbook_find_datasource( node
);
5681 if( ds
== NULL
) return;
5682 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
5683 cache
= adbase
->addressCache
;
5684 addressbook_exp_ldif( cache
);
5687 static void addressbook_find_duplicates_cb(GtkAction
*action
, gpointer data
)
5689 addrduplicates_find(GTK_WINDOW(addrbook
.window
));
5692 static void addressbook_edit_custom_attr_cb(GtkAction
*action
, gpointer data
)
5694 addressbook_custom_attr_edit();
5697 static void addressbook_start_drag(GtkWidget
*widget
, gint button
,
5701 GdkDragContext
*context
;
5702 if (addressbook_target_list
== NULL
)
5703 addressbook_target_list
= gtk_target_list_new(
5704 addressbook_drag_types
, 1);
5705 context
= gtk_drag_begin_with_coordinates(widget
, addressbook_target_list
,
5706 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
,
5708 gtk_drag_set_icon_default(context
);
5711 static void addressbook_drag_data_get(GtkWidget
*widget
,
5712 GdkDragContext
*drag_context
,
5713 GtkSelectionData
*selection_data
,
5718 AddrItemObject
*aio
= NULL
;
5719 AddressObject
*pobj
= NULL
;
5720 AdapterDSource
*ads
= NULL
;
5721 AddressDataSource
*ds
= NULL
;
5724 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
5726 if( pobj
== NULL
) return;
5728 if( pobj
->type
== ADDR_DATASOURCE
) {
5729 ads
= ADAPTER_DSOURCE(pobj
);
5730 ds
= ads
->dataSource
;
5731 } else if (pobj
->type
== ADDR_ITEM_GROUP
) {
5736 else if( pobj
->type
!= ADDR_INTERFACE
) {
5737 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
5743 for(cur
= GTK_CMCLIST(addrbook
.clist
)->selection
; cur
; cur
= cur
->next
) {
5744 aio
= (AddrItemObject
*)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.clist
),
5745 GTK_CMCTREE_NODE(cur
->data
));
5746 while (aio
&& aio
->type
!= ITEMTYPE_PERSON
) {
5751 if (aio
&& aio
->type
== ITEMTYPE_PERSON
) {
5752 if( ds
&& ds
->interface
&& ds
->interface
->readOnly
)
5753 gtk_selection_data_set(selection_data
,
5754 gtk_selection_data_get_target(selection_data
), 8,
5755 (const guchar
*)"Dummy_addr_copy", 15);
5757 gtk_selection_data_set(selection_data
,
5758 gtk_selection_data_get_target(selection_data
), 8,
5759 (const guchar
*)"Dummy_addr_move", 15);
5763 static gboolean
addressbook_drag_motion_cb(GtkWidget
*widget
,
5764 GdkDragContext
*context
,
5770 GtkAllocation allocation
;
5771 GtkRequisition requisition
;
5773 GtkCMCTreeNode
*node
= NULL
;
5774 gboolean acceptable
= FALSE
;
5775 gtk_widget_get_allocation(GTK_WIDGET(addrbook
.ctree
), &allocation
);
5776 gint height
= allocation
.height
;
5777 gtk_widget_get_requisition(GTK_WIDGET(addrbook
.ctree
), &requisition
);
5778 gint total_height
= requisition
.height
;
5779 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
5780 GTK_SCROLLED_WINDOW(addrbook
.ctree_swin
));
5781 gfloat vpos
= gtk_adjustment_get_value(pos
);
5783 if (gtk_cmclist_get_selection_info
5784 (GTK_CMCLIST(widget
), x
- 24, y
- 24, &row
, &column
)) {
5786 if (y
> height
- 24 && height
+ vpos
< total_height
) {
5787 gtk_adjustment_set_value(pos
, (vpos
+5 > height
? height
: vpos
+5));
5789 if (y
< 24 && y
> 0) {
5790 gtk_adjustment_set_value(pos
, (vpos
-5 < 0 ? 0 : vpos
-5));
5792 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
5795 AddressObject
*obj
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
5798 if( obj
->type
== ADDR_ITEM_FOLDER
5799 || obj
->type
== ADDR_ITEM_GROUP
)
5802 AdapterDSource
*ads
= NULL
;
5803 AddressDataSource
*ds
= NULL
;
5804 ads
= ADAPTER_DSOURCE(obj
);
5805 ds
= ads
->dataSource
;
5806 if (ds
== NULL
) { return FALSE
;}
5814 g_signal_handlers_block_by_func
5816 G_CALLBACK(addressbook_tree_selected
), NULL
);
5817 gtk_sctree_select( GTK_SCTREE(widget
), node
);
5818 g_signal_handlers_unblock_by_func
5820 G_CALLBACK(addressbook_tree_selected
), NULL
);
5821 gdk_drag_status(context
,
5822 (gdk_drag_context_get_actions(context
) == GDK_ACTION_COPY
?
5823 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
5825 gdk_drag_status(context
, 0, time
);
5830 static void addressbook_drag_leave_cb(GtkWidget
*widget
,
5831 GdkDragContext
*context
,
5835 if (addrbook
.treeSelected
) {
5836 g_signal_handlers_block_by_func
5838 G_CALLBACK(addressbook_tree_selected
), NULL
);
5839 gtk_sctree_select( GTK_SCTREE(widget
), addrbook
.opened
);
5840 g_signal_handlers_unblock_by_func
5842 G_CALLBACK(addressbook_tree_selected
), NULL
);
5847 static void addressbook_drag_received_cb(GtkWidget
*widget
,
5848 GdkDragContext
*drag_context
,
5851 GtkSelectionData
*data
,
5857 GtkCMCTreeNode
*node
;
5858 GtkCMCTreeNode
*lastopened
= addrbook
.opened
;
5860 if (!strncmp(gtk_selection_data_get_data(data
), "Dummy_addr", 10)) {
5861 if (gtk_cmclist_get_selection_info
5862 (GTK_CMCLIST(widget
), x
- 24, y
- 24, &row
, &column
) == 0) {
5866 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
5867 if( !node
|| !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
), node
))
5870 gtk_cmclist_freeze(GTK_CMCLIST(addrbook
.clist
));
5871 if (gdk_drag_context_get_selected_action(drag_context
) == GDK_ACTION_COPY
||
5872 !strcmp(gtk_selection_data_get_data(data
), "Dummy_addr_copy"))
5873 addressbook_clip_copy_cb(NULL
, NULL
);
5875 addressbook_clip_cut_cb(NULL
, NULL
);
5876 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), node
);
5877 addressbook_clip_paste_cb(NULL
,NULL
);
5878 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), lastopened
);
5879 gtk_cmclist_thaw(GTK_CMCLIST(addrbook
.clist
));
5880 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);