2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2024 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>
35 #include "addressbook.h"
36 #include "manage_window.h"
37 #include "prefs_common.h"
38 #include "alertpanel.h"
39 #include "inputdialog.h"
41 #include "stock_pixmap.h"
43 #include "prefs_gtk.h"
45 #include "file-utils.h"
50 #include "addr_compl.h"
54 #include "addressitem.h"
56 #include "addrcache.h"
58 #include "addrindex.h"
59 #include "addrmerge.h"
60 #include "addressadd.h"
61 #include "addrduplicates.h"
62 #include "addressbook_foldersel.h"
64 #include "editvcard.h"
65 #include "editgroup.h"
66 #include "editaddress.h"
68 #include "importldif.h"
69 #include "importmutt.h"
70 #include "importpine.h"
75 #include "editjpilot.h"
80 #include "ldapserver.h"
82 #include "ldapupdate.h"
84 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
87 #include "addrquery.h"
88 #include "addrselect.h"
90 #include "addrgather.h"
91 #include "adbookbase.h"
92 #include "exphtmldlg.h"
93 #include "expldifdlg.h"
94 #include "browseldap.h"
95 #include "addrcustomattr.h"
103 } AddressIndexColumns
;
111 } AddressListColumns
;
114 AddressBookFile
*book
;
122 AddressDataSource
*book
;
126 static gchar
*list_titles
[] = { N_("Name"),
130 #define COL_NAME_WIDTH 164
131 #define COL_ADDRESS_WIDTH 156
133 #define COL_FOLDER_WIDTH 170
134 #define ADDRESSBOOK_WIDTH 640
135 #define ADDRESSBOOK_HEIGHT 360
137 #define ADDRESSBOOK_MSGBUF_SIZE 2048
139 static GdkPixbuf
*folderxpm
= NULL
;
140 static GdkPixbuf
*folderopenxpm
= NULL
;
141 static GdkPixbuf
*groupxpm
= NULL
;
142 static GdkPixbuf
*interfacexpm
= NULL
;
143 static GdkPixbuf
*bookxpm
= NULL
;
144 static GdkPixbuf
*addressxpm
= NULL
;
145 static GdkPixbuf
*vcardxpm
= NULL
;
146 static GdkPixbuf
*jpilotxpm
= NULL
;
147 static GdkPixbuf
*categoryxpm
= NULL
;
148 static GdkPixbuf
*ldapxpm
= NULL
;
149 static GdkPixbuf
*addrsearchxpm
= NULL
;
152 static gchar addressbook_msgbuf
[ ADDRESSBOOK_MSGBUF_SIZE
];
154 /* Address list selection */
155 static AddrSelectList
*_addressSelect_
= NULL
;
156 static AddressClipboard
*_clipBoard_
= NULL
;
158 /* Address index file and interfaces */
159 static AddressIndex
*_addressIndex_
= NULL
;
160 static GList
*_addressInterfaceList_
= NULL
;
161 static GList
*_addressIFaceSelection_
= NULL
;
162 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
164 static AddressBook_win addrbook
;
166 static GHashTable
*_addressBookTypeHash_
= NULL
;
167 static GList
*_addressBookTypeList_
= NULL
;
169 static void addressbook_new_address_from_book_post_cb( ItemPerson
*person
);
170 static void addressbook_new_address_from_folder_post_cb( ItemPerson
*person
);
171 static void addressbook_edit_address_post_cb( ItemPerson
*person
);
173 static void addressbook_create (void);
174 static gint
addressbook_close (void);
176 static gboolean address_index_has_focus
= FALSE
;
177 static gboolean address_list_has_focus
= FALSE
;
179 /* callback functions */
180 static void addressbook_del_clicked (GtkButton
*button
,
182 static void addressbook_reg_clicked (GtkButton
*button
,
184 static void addressbook_to_clicked (GtkButton
*button
,
186 static void addressbook_lup_clicked (GtkButton
*button
,
188 static void addressbook_close_clicked (GtkButton
*button
,
191 static void addressbook_tree_selected (GtkCMCTree
*ctree
,
192 GtkCMCTreeNode
*node
,
195 static void addressbook_select_row_tree (GtkCMCTree
*ctree
,
196 GtkCMCTreeNode
*node
,
199 static void addressbook_list_row_selected (GtkCMCTree
*clist
,
200 GtkCMCTreeNode
*node
,
203 static void addressbook_list_row_unselected (GtkCMCTree
*clist
,
204 GtkCMCTreeNode
*node
,
207 static void addressbook_person_expand_node (GtkCMCTree
*ctree
,
210 static void addressbook_person_collapse_node (GtkCMCTree
*ctree
,
214 static void addressbook_entry_activated (GtkWidget
*widget
,
217 static gboolean
addressbook_list_button_pressed (GtkWidget
*widget
,
218 GdkEventButton
*event
,
220 static gboolean
addressbook_list_button_released(GtkWidget
*widget
,
221 GdkEventButton
*event
,
223 static gboolean
addressbook_tree_button_pressed (GtkWidget
*ctree
,
224 GdkEventButton
*event
,
226 static gboolean
addressbook_tree_button_released(GtkWidget
*ctree
,
227 GdkEventButton
*event
,
230 static void addressbook_new_folder_cb (GtkAction
*action
,
232 static void addressbook_new_group_cb (GtkAction
*action
,
234 static void addressbook_treenode_edit_cb (GtkAction
*action
,
236 static void addressbook_treenode_delete_cb (GtkAction
*action
,
239 static void addressbook_change_node_name (GtkCMCTreeNode
*node
,
242 static void addressbook_new_address_cb (GtkAction
*action
,
244 static void addressbook_edit_address_cb (GtkAction
*action
,
246 static void addressbook_delete_address_cb (GtkAction
*action
,
249 static void close_cb (GtkAction
*action
,
251 static void addressbook_file_save_cb (GtkAction
*action
,
254 /* Data source edit stuff */
255 static void addressbook_new_book_cb (GtkAction
*action
,
257 static void addressbook_new_vcard_cb (GtkAction
*action
,
261 static void addressbook_new_jpilot_cb (GtkAction
*action
,
266 static void addressbook_new_ldap_cb (GtkAction
*action
,
270 static void addressbook_set_clist (AddressObject
*obj
,
273 static void addressbook_load_tree (void);
274 void addressbook_read_file (void);
276 static GtkCMCTreeNode
*addressbook_add_object (GtkCMCTreeNode
*node
,
278 static void addressbook_treenode_remove_item ( void );
280 static AddressDataSource
*addressbook_find_datasource
281 (GtkCMCTreeNode
*node
);
283 static AddressBookFile
*addressbook_get_book_file(void);
285 static GtkCMCTreeNode
*addressbook_node_add_folder
286 (GtkCMCTreeNode
*node
,
287 AddressDataSource
*ds
,
288 ItemFolder
*itemFolder
,
289 AddressObjectType otype
);
290 static GtkCMCTreeNode
*addressbook_node_add_group (GtkCMCTreeNode
*node
,
291 AddressDataSource
*ds
,
292 ItemGroup
*itemGroup
);
293 static void addressbook_tree_remove_children (GtkCMCTree
*ctree
,
294 GtkCMCTreeNode
*parent
);
295 static void addressbook_move_nodes_up (GtkCMCTree
*ctree
,
296 GtkCMCTreeNode
*node
);
297 static GtkCMCTreeNode
*addressbook_find_group_node (GtkCMCTreeNode
*parent
,
299 static gboolean
addressbook_entry_key_pressed (GtkWidget
*widget
,
302 static gint
addressbook_treenode_compare_func (GtkCMCList
*clist
,
305 static void addressbook_folder_load_one_person (GtkCMCTree
*clist
,
307 AddressTypeControlItem
*atci
,
308 AddressTypeControlItem
*atciMail
);
309 static void addressbook_folder_remove_node (GtkCMCTree
*clist
,
310 GtkCMCTreeNode
*node
);
312 static void addressbook_edit_address( gpointer data
, guint action
, GtkWidget
*widget
,
313 gboolean force_focus
);
315 /* LUT's and IF stuff */
316 static void addressbook_free_treenode ( gpointer data
);
317 static AddressTypeControlItem
*addrbookctl_lookup (gint ot
);
318 static AddressTypeControlItem
*addrbookctl_lookup_iface(AddressIfType ifType
);
320 static void addrbookctl_build_map (GtkWidget
*window
);
321 static void addrbookctl_build_iflist (void);
322 static AdapterInterface
*addrbookctl_find_interface (AddressIfType ifType
);
323 static void addrbookctl_build_ifselect (void);
325 static void addrbookctl_free_interface (AdapterInterface
*adapter
);
326 static void addrbookctl_free_datasource (AdapterDSource
*adapter
);
327 static void addrbookctl_free_folder (AdapterFolder
*adapter
);
328 static void addrbookctl_free_group (AdapterGroup
*adapter
);
330 static void addressbook_list_select_clear ( void );
331 static void addressbook_list_select_add ( AddrItemObject
*aio
,
332 AddressDataSource
*ds
);
333 static void addressbook_list_select_remove ( AddrItemObject
*aio
);
335 static void addressbook_import_ldif_cb ( GtkAction
*action
, gpointer data
);
336 static void addressbook_find_duplicates_cb ( GtkAction
*action
, gpointer data
);
337 static void addressbook_edit_custom_attr_cb ( GtkAction
*action
, gpointer data
);
338 static void addressbook_import_mutt_cb ( GtkAction
*action
, gpointer data
);
339 static void addressbook_import_pine_cb ( GtkAction
*action
, gpointer data
);
340 static void addressbook_export_html_cb ( GtkAction
*action
, gpointer data
);
341 static void addressbook_export_ldif_cb ( GtkAction
*action
, gpointer data
);
342 static void addressbook_select_all_cb ( GtkAction
*action
, gpointer data
);
343 static void addressbook_clip_cut_cb ( GtkAction
*action
, gpointer data
);
344 static void addressbook_clip_copy_cb ( GtkAction
*action
, gpointer data
);
345 static void addressbook_clip_paste_cb ( GtkAction
*action
, gpointer data
);
346 static void addressbook_treenode_cut_cb ( GtkAction
*action
, gpointer data
);
347 static void addressbook_treenode_copy_cb ( GtkAction
*action
, gpointer data
);
348 static void addressbook_treenode_paste_cb ( GtkAction
*action
, gpointer data
);
350 static void addressbook_mail_to_cb ( GtkAction
*action
, gpointer data
);
351 static void addressbook_merge_cb ( GtkAction
*action
, gpointer data
);
354 static void addressbook_browse_entry_cb ( GtkAction
*action
, gpointer data
);
356 static void addressbook_edit_clicked(GtkButton
*button
, gpointer data
);
358 static void addressbook_start_drag(GtkWidget
*widget
, gint button
,
361 static void addressbook_drag_data_get(GtkWidget
*widget
,
362 GdkDragContext
*drag_context
,
363 GtkSelectionData
*selection_data
,
367 static gboolean
addressbook_drag_motion_cb(GtkWidget
*widget
,
368 GdkDragContext
*context
,
373 static void addressbook_drag_leave_cb(GtkWidget
*widget
,
374 GdkDragContext
*context
,
377 static void addressbook_drag_received_cb(GtkWidget
*widget
,
378 GdkDragContext
*drag_context
,
381 GtkSelectionData
*data
,
385 static void addressbook_list_menu_setup( void );
387 static GtkTargetEntry addressbook_drag_types
[] =
389 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
}
392 static GtkTargetList
*addressbook_target_list
= NULL
;
394 static GtkActionEntry addressbook_entries
[] =
396 {"Menu", NULL
, "Menu", NULL
, NULL
, NULL
},
398 {"Book", NULL
, N_("_Book"), NULL
, NULL
, NULL
},
399 {"Edit", NULL
, N_("_Edit"), NULL
, NULL
, NULL
},
400 {"Tools", NULL
, N_("_Tools"), NULL
, NULL
, NULL
},
403 {"Book/NewBook", NULL
, N_("New _Book"), "<control>B", NULL
, G_CALLBACK(addressbook_new_book_cb
) },
404 {"Book/NewFolder", NULL
, N_("New _Folder"), "<control>R", NULL
, G_CALLBACK(addressbook_new_folder_cb
) },
405 {"Book/NewVCard", NULL
, N_("New _vCard"), "<control><shift>D", NULL
, G_CALLBACK(addressbook_new_vcard_cb
) },
409 {"Book/NewJPilot", NULL
, N_("New _JPilot"), "<control>J", NULL
, G_CALLBACK(addressbook_new_jpilot_cb
) },
412 {"Book/NewLDAPServer", NULL
, N_("New LDAP _Server"), "<control><shift>S", NULL
, G_CALLBACK(addressbook_new_ldap_cb
) },
414 {"Book/---", NULL
, "---", NULL
, NULL
, NULL
},
416 {"Book/EditBook", NULL
, N_("_Edit book"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_edit_cb
) },
417 {"Book/DeleteBook", NULL
, N_("_Delete book"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_delete_cb
) },
418 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
419 {"Book/Save", NULL
, N_("_Save"), "<control>S", NULL
, G_CALLBACK(addressbook_file_save_cb
) },
420 {"Book/Close", NULL
, N_("_Close"), "<control>W", NULL
, G_CALLBACK(close_cb
) },
423 {"Address/SelectAll", NULL
, N_("_Select all"), "<control>A", NULL
, G_CALLBACK(addressbook_select_all_cb
) },
424 {"Address/---", NULL
, "---", NULL
, NULL
, NULL
},
425 {"Address/Cut", NULL
, N_("C_ut"), "<control>X", NULL
, G_CALLBACK(addressbook_clip_cut_cb
) },
426 {"Address/Copy", NULL
, N_("_Copy"), "<control>C", NULL
, G_CALLBACK(addressbook_clip_copy_cb
) },
427 {"Address/Paste", NULL
, N_("_Paste"), "<control>V", NULL
, G_CALLBACK(addressbook_clip_paste_cb
) },
428 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
429 {"Address/Edit", NULL
, N_("_Edit"), "<control>Return", NULL
, G_CALLBACK(addressbook_edit_address_cb
) },
430 {"Address/Delete", NULL
, N_("_Delete"), "<control>D", NULL
, G_CALLBACK(addressbook_delete_address_cb
) },
431 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
432 {"Address/NewAddress", NULL
, N_("New _Address"), "<control>N", NULL
, G_CALLBACK(addressbook_new_address_cb
) },
433 {"Address/NewGroup", NULL
, N_("New _Group"), "<control>G", NULL
, G_CALLBACK(addressbook_new_group_cb
) },
434 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
435 {"Address/Mailto", NULL
, N_("_Mail To"), "<control>M", NULL
, G_CALLBACK(addressbook_mail_to_cb
) },
436 {"Address/Merge", NULL
, N_("_Merge"), "<control>E", NULL
, G_CALLBACK(addressbook_merge_cb
) },
440 {"Tools/ImportLDIF", NULL
, N_("Import _LDIF file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_ldif_cb
) },
441 {"Tools/ImportMutt", NULL
, N_("Import M_utt file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_mutt_cb
) },
442 {"Tools/ImportPine", NULL
, N_("Import _Pine file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_pine_cb
) },
443 {"Tools/---", NULL
, "---", NULL
, NULL
, NULL
},
444 {"Tools/ExportHTML", NULL
, N_("Export _HTML..."), NULL
, NULL
, G_CALLBACK(addressbook_export_html_cb
) },
445 {"Tools/ExportLDIF", NULL
, N_("Export LDI_F..."), NULL
, NULL
, G_CALLBACK(addressbook_export_ldif_cb
) },
446 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
447 {"Tools/FindDuplicates", NULL
, N_("Find duplicates..."), NULL
, NULL
, G_CALLBACK(addressbook_find_duplicates_cb
) },
448 {"Tools/EditAttrs", NULL
, N_("Edit custom attributes..."), NULL
, NULL
, G_CALLBACK(addressbook_edit_custom_attr_cb
) },
451 static GtkActionEntry addressbook_tree_popup_entries
[] =
453 {"ABTreePopup", NULL
, "ABTreePopup", NULL
, NULL
, NULL
},
454 {"ABTreePopup/EditBook", NULL
, N_("_Edit"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_edit_cb
) },
455 {"ABTreePopup/DeleteBook", NULL
, N_("_Delete"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_delete_cb
) },
456 {"ABTreePopup/---", NULL
, "---", NULL
, NULL
, NULL
},
457 {"ABTreePopup/NewBook", NULL
, N_("New _Book"), NULL
, NULL
, G_CALLBACK(addressbook_new_book_cb
) },
458 {"ABTreePopup/NewFolder", NULL
, N_("New _Folder"), NULL
, NULL
, G_CALLBACK(addressbook_new_folder_cb
) },
459 {"ABTreePopup/NewGroup", NULL
, N_("New _Group"), NULL
, NULL
, G_CALLBACK(addressbook_new_group_cb
) },
460 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
461 {"ABTreePopup/Cut", NULL
, N_("C_ut"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_cut_cb
) },
462 {"ABTreePopup/Copy", NULL
, N_("_Copy"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_copy_cb
) },
463 {"ABTreePopup/Paste", NULL
, N_("_Paste"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_paste_cb
) },
466 static GtkActionEntry addressbook_list_popup_entries
[] =
468 {"ABListPopup", NULL
, "ABListPopup", NULL
, NULL
, NULL
},
469 {"ABListPopup/SelectAll", NULL
, N_("_Select all"), NULL
, NULL
, G_CALLBACK(addressbook_select_all_cb
) },
470 {"ABListPopup/---", NULL
, "---", NULL
, NULL
, NULL
},
471 {"ABListPopup/Edit", NULL
, N_("_Edit"), NULL
, NULL
, G_CALLBACK(addressbook_edit_address_cb
) },
472 {"ABListPopup/Delete", NULL
, N_("_Delete"), NULL
, NULL
, G_CALLBACK(addressbook_delete_address_cb
) },
473 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
474 {"ABListPopup/NewAddress", NULL
, N_("New _Address"), NULL
, NULL
, G_CALLBACK(addressbook_new_address_cb
) },
475 {"ABListPopup/NewGroup", NULL
, N_("New _Group"), NULL
, NULL
, G_CALLBACK(addressbook_new_group_cb
) },
476 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
477 {"ABListPopup/Cut", NULL
, N_("C_ut"), NULL
, NULL
, G_CALLBACK(addressbook_clip_cut_cb
) },
478 {"ABListPopup/Copy", NULL
, N_("_Copy"), NULL
, NULL
, G_CALLBACK(addressbook_clip_copy_cb
) },
479 {"ABListPopup/Paste", NULL
, N_("_Paste"), NULL
, NULL
, G_CALLBACK(addressbook_clip_paste_cb
) },
480 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
481 {"ABListPopup/Mailto", NULL
, N_("_Mail To"), NULL
, NULL
, G_CALLBACK(addressbook_mail_to_cb
) },
483 {"ABListPopup/BrowseEntry", NULL
, N_("_Browse Entry"), NULL
, NULL
, G_CALLBACK(addressbook_browse_entry_cb
) },
485 {"ABListPopup/Merge", NULL
, N_("_Merge"), NULL
, NULL
, G_CALLBACK(addressbook_merge_cb
) },
489 * Structure of error message table.
491 typedef struct _ErrMsgTableEntry ErrMsgTableEntry
;
492 struct _ErrMsgTableEntry
{
497 static gchar
*_errMsgUnknown_
= N_( "Unknown" );
500 * Lookup table of error messages for general errors. Note that a NULL
501 * description signifies the end of the table.
503 static ErrMsgTableEntry _lutErrorsGeneral_
[] = {
504 { MGU_SUCCESS
, N_("Success") },
505 { MGU_BAD_ARGS
, N_("Bad arguments") },
506 { MGU_NO_FILE
, N_("File not specified") },
507 { MGU_OPEN_FILE
, N_("Error opening file") },
508 { MGU_ERROR_READ
, N_("Error reading file") },
509 { MGU_EOF
, N_("End of file encountered") },
510 { MGU_OO_MEMORY
, N_("Error allocating memory") },
511 { MGU_BAD_FORMAT
, N_("Bad file format") },
512 { MGU_ERROR_WRITE
, N_("Error writing to file") },
513 { MGU_OPEN_DIRECTORY
, N_("Error opening directory") },
514 { MGU_NO_PATH
, N_("No path specified") },
520 * Lookup table of error messages for LDAP errors.
522 static ErrMsgTableEntry _lutErrorsLDAP_
[] = {
523 { LDAPRC_SUCCESS
, N_("Success") },
524 { LDAPRC_CONNECT
, N_("Error connecting to LDAP server") },
525 { LDAPRC_INIT
, N_("Error initializing LDAP") },
526 { LDAPRC_BIND
, N_("Error binding to LDAP server") },
527 { LDAPRC_SEARCH
, N_("Error searching LDAP database") },
528 { LDAPRC_TIMEOUT
, N_("Timeout performing LDAP operation") },
529 { LDAPRC_CRITERIA
, N_("Error in LDAP search criteria") },
530 { LDAPRC_NOENTRIES
, N_("No LDAP entries found for search criteria") },
531 { LDAPRC_STOP_FLAG
, N_("LDAP search terminated on request") },
532 { LDAPRC_TLS
, N_("Error starting STARTTLS connection") },
533 { LDAPRC_NODN
, N_("Distinguished Name (dn) is missing") },
534 { LDAPRC_NAMING_VIOLATION
, N_("Missing required information") },
535 { LDAPRC_ALREADY_EXIST
, N_("Another contact exists with that key") },
536 { LDAPRC_STRONG_AUTH
, N_("Strong(er) authentication required") },
542 * Lookup message for specified error code.
543 * \param lut Lookup table.
544 * \param code Code to lookup.
545 * \return Description associated to code.
547 static gchar
*addressbook_err2string( ErrMsgTableEntry lut
[], gint code
) {
549 ErrMsgTableEntry entry
;
552 for( i
= 0; ; i
++ ) {
554 if( entry
.description
== NULL
) break;
555 if( entry
.code
== code
) {
556 desc
= entry
.description
;
561 desc
= _errMsgUnknown_
;
566 static gboolean lastCanLookup
= FALSE
;
568 static void addressbook_show_buttons(gboolean add_and_delete
, gboolean lookup
, gboolean mail_ops
)
570 if (add_and_delete
) {
571 gtk_widget_show(addrbook
.edit_btn
);
572 gtk_widget_show(addrbook
.del_btn
);
573 gtk_widget_show(addrbook
.reg_btn
);
575 gtk_widget_hide(addrbook
.edit_btn
);
576 gtk_widget_hide(addrbook
.del_btn
);
577 gtk_widget_hide(addrbook
.reg_btn
);
581 gtk_widget_show(addrbook
.lup_btn
);
582 gtk_widget_show(addrbook
.entry
);
583 gtk_widget_show(addrbook
.label
);
585 gtk_widget_hide(addrbook
.lup_btn
);
586 gtk_widget_hide(addrbook
.entry
);
587 gtk_widget_hide(addrbook
.label
);
590 lastCanLookup
= lookup
;
593 gtk_widget_show(addrbook
.to_btn
);
594 gtk_widget_show(addrbook
.cc_btn
);
595 gtk_widget_show(addrbook
.bcc_btn
);
597 gtk_widget_hide(addrbook
.to_btn
);
598 gtk_widget_hide(addrbook
.cc_btn
);
599 gtk_widget_hide(addrbook
.bcc_btn
);
603 void addressbook_open(Compose
*target
)
605 /* Initialize all static members */
606 if( _clipBoard_
== NULL
) {
607 _clipBoard_
= addrclip_create();
609 if( _addressIndex_
!= NULL
) {
610 addrclip_set_index( _clipBoard_
, _addressIndex_
);
612 if( _addressSelect_
== NULL
) {
613 _addressSelect_
= addrselect_list_create();
615 if (!addrbook
.window
) {
616 addressbook_read_file();
617 addressbook_create();
618 addressbook_load_tree();
619 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
620 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook
.ctree
)->row_list
));
623 gtk_widget_hide(addrbook
.window
);
626 gtk_widget_show_all(addrbook
.window
);
628 if (!prefs_common
.addressbook_use_editaddress_dialog
)
629 addressbook_edit_person_widgetset_hide();
631 address_completion_start(addrbook
.window
);
633 addressbook_show_buttons(target
== NULL
, lastCanLookup
, target
!= NULL
);
634 addressbook_set_target_compose(target
);
638 * Destroy addressbook.
640 void addressbook_destroy( void ) {
641 /* Free up address stuff */
642 if( _addressSelect_
!= NULL
) {
643 addrselect_list_free( _addressSelect_
);
645 if( _clipBoard_
!= NULL
) {
646 addrclip_free( _clipBoard_
);
649 if( _addressIndex_
!= NULL
) {
650 addrindex_free_index( _addressIndex_
);
651 addrindex_teardown();
653 _addressSelect_
= NULL
;
655 _addressIndex_
= NULL
;
658 void addressbook_set_target_compose(Compose
*target
)
660 addrbook
.target_compose
= target
;
663 Compose
*addressbook_get_target_compose(void)
665 return addrbook
.target_compose
;
669 * Refresh addressbook and save to file(s).
671 void addressbook_refresh( void )
673 if (addrbook
.window
) {
674 if (addrbook
.treeSelected
) {
675 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
676 addrbook
.treeSelected
);
677 addressbook_set_clist(
678 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
679 addrbook
.treeSelected
),
684 addressbook_export_to_file();
687 static gboolean
key_pressed(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
689 if (event
&& event
->keyval
== GDK_KEY_Escape
)
691 else if (event
&& event
->keyval
== GDK_KEY_Delete
) {
692 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
693 if ( /* address_index_has_focus || */ address_list_has_focus
)
694 addressbook_del_clicked(NULL
, NULL
);
700 *\brief Save Gtk object size to prefs dataset
702 static void addressbook_size_allocate_cb(GtkWidget
*widget
,
703 GtkAllocation
*allocation
)
705 cm_return_if_fail(allocation
!= NULL
);
707 gtk_window_get_size(GTK_WINDOW(widget
),
708 &prefs_common
.addressbookwin_width
, &prefs_common
.addressbookwin_height
);
711 static gint sort_column_number
= 0;
712 static GtkSortType sort_column_type
= GTK_SORT_ASCENDING
;
714 static gint
list_case_sort(
715 GtkCMCList
*clist
, gconstpointer ptr1
, gconstpointer ptr2
)
717 GtkCMCListRow
*row1
= (GtkCMCListRow
*) ptr1
;
718 GtkCMCListRow
*row2
= (GtkCMCListRow
*) ptr2
;
719 gchar
*name1
= NULL
, *name2
= NULL
;
720 AddrItemObject
*aio1
= ((GtkCMCListRow
*)ptr1
)->data
;
721 AddrItemObject
*aio2
= ((GtkCMCListRow
*)ptr2
)->data
;
723 if( aio1
->type
== aio2
->type
) {
725 name1
= GTK_CMCELL_TEXT (row1
->cell
[sort_column_number
])->text
;
727 name2
= GTK_CMCELL_TEXT (row2
->cell
[sort_column_number
])->text
;
728 if( ! name1
) return ( name2
!= NULL
);
729 if( ! name2
) return -1;
730 return g_utf8_collate( name1
, name2
);
732 /* Order groups before person */
733 if( aio1
->type
== ITEMTYPE_GROUP
) {
734 return (sort_column_type
==GTK_SORT_ASCENDING
) ? -1:+1;
735 } else if( aio2
->type
== ITEMTYPE_GROUP
) {
736 return (sort_column_type
==GTK_SORT_ASCENDING
) ? +1:-1;
742 static void addressbook_sort_list(GtkCMCList
*clist
, const gint col
,
743 const GtkSortType sort_type
)
746 GtkWidget
*hbox
, *label
, *arrow
;
748 sort_column_number
= col
;
749 sort_column_type
= sort_type
;
750 gtk_cmclist_set_compare_func(clist
, list_case_sort
);
751 gtk_cmclist_set_sort_type(clist
, sort_type
);
752 gtk_cmclist_set_sort_column(clist
, col
);
754 gtk_cmclist_freeze(clist
);
755 gtk_cmclist_sort(clist
);
757 for(pos
= 0 ; pos
< N_LIST_COLS
; pos
++) {
758 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
759 label
= gtk_label_new(gettext(list_titles
[pos
]));
760 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
763 arrow
= gtk_image_new_from_icon_name(sort_type
== GTK_SORT_ASCENDING
?
764 "pan-down-symbolic" : "pan-up-symbolic", GTK_ICON_SIZE_MENU
);
765 gtk_box_pack_end(GTK_BOX(hbox
), arrow
, FALSE
, FALSE
, 0);
768 gtk_widget_show_all(hbox
);
769 gtk_cmclist_set_column_widget(clist
, pos
, hbox
);
772 gtk_cmclist_thaw(clist
);
775 static void addressbook_name_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
777 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
779 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
781 addressbook_sort_list(clist
, COL_NAME
, sort_type
);
784 static void addressbook_address_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
786 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
788 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
790 addressbook_sort_list(clist
, COL_ADDRESS
, sort_type
);
793 static void addressbook_remarks_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
795 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
797 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
799 addressbook_sort_list(clist
, COL_REMARKS
, sort_type
);
802 static gboolean
addressbook_address_index_focus_evt_in(GtkWidget
*widget
, GdkEventFocus
*event
,
805 address_index_has_focus
= TRUE
;
809 static gboolean
addressbook_address_index_focus_evt_out(GtkWidget
*widget
, GdkEventFocus
*event
,
812 address_index_has_focus
= FALSE
;
813 if (!prefs_common
.addressbook_use_editaddress_dialog
814 && !address_list_has_focus
)
815 addressbook_address_list_disable_some_actions();
819 static gboolean
addressbook_address_list_focus_evt_in(GtkWidget
*widget
, GdkEventFocus
*event
,
822 address_list_has_focus
= TRUE
;
826 static gboolean
addressbook_address_list_focus_evt_out(GtkWidget
*widget
, GdkEventFocus
*event
,
829 address_list_has_focus
= FALSE
;
830 if (!prefs_common
.addressbook_use_editaddress_dialog
831 && !address_index_has_focus
)
832 addressbook_address_list_disable_some_actions();
836 /* save hpane and vpane's handle position when it moves */
837 static void addressbook_pane_save_position(void)
840 prefs_common
.addressbook_hpaned_pos
=
841 gtk_paned_get_position(GTK_PANED(addrbook
.hpaned
));
843 prefs_common
.addressbook_vpaned_pos
=
844 gtk_paned_get_position(GTK_PANED(addrbook
.vpaned
));
848 * Create the address book widgets. The address book contains two CTree widgets: the
849 * address index tree on the left and the address list on the right.
851 * The address index tree displays a hierarchy of interfaces and groups. Each node in
852 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
853 * data sources and folder objects.
855 * The address list displays group, person and email objects. These items are linked
856 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
859 * In the tradition of MVC architecture, the data stores have been separated from the
860 * GUI components. The addrindex.c file provides the interface to all data stores.
862 static void addressbook_create(void)
868 GtkWidget
*ctree_swin
;
870 GtkWidget
*editaddress_vbox
;
871 GtkWidget
*clist_vbox
;
872 GtkWidget
*clist_swin
;
879 GtkWidget
*statusbar
;
890 GtkWidget
*close_btn
;
891 GtkWidget
*tree_popup
;
892 GtkWidget
*list_popup
;
894 GtkUIManager
*ui_manager
;
895 GtkActionGroup
*action_group
;
896 gchar
*index_titles
[N_INDEX_COLS
];
900 static GdkGeometry geometry
;
902 debug_print("Creating addressbook window...\n");
904 index_titles
[COL_SOURCES
] = _("Sources");
906 /* Address book window */
907 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "addressbook");
908 gtk_window_set_title(GTK_WINDOW(window
), _("Address book"));
909 gtk_window_set_resizable(GTK_WINDOW(window
), TRUE
);
910 gtk_window_set_type_hint(GTK_WINDOW(window
), GDK_WINDOW_TYPE_HINT_DIALOG
);
911 gtk_widget_realize(window
);
913 g_signal_connect(G_OBJECT(window
), "delete_event",
914 G_CALLBACK(addressbook_close
), NULL
);
915 g_signal_connect(G_OBJECT(window
), "size_allocate",
916 G_CALLBACK(addressbook_size_allocate_cb
), NULL
);
917 g_signal_connect(G_OBJECT(window
), "key_press_event",
918 G_CALLBACK(key_pressed
), NULL
);
919 MANAGE_WINDOW_SIGNALS_CONNECT(window
);
921 vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0);
922 gtk_container_add(GTK_CONTAINER(window
), vbox
);
925 ui_manager
= gtk_ui_manager_new();
926 action_group
= cm_menu_create_action_group_full(ui_manager
,"Menu", addressbook_entries
,
927 G_N_ELEMENTS(addressbook_entries
), NULL
);
928 gtk_action_group_add_actions(action_group
, addressbook_tree_popup_entries
,
929 G_N_ELEMENTS(addressbook_tree_popup_entries
), NULL
);
930 gtk_action_group_add_actions(action_group
, addressbook_list_popup_entries
,
931 G_N_ELEMENTS(addressbook_list_popup_entries
), NULL
);
933 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Menu", NULL
, GTK_UI_MANAGER_MENUBAR
)
935 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU
)
936 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU
)
937 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU
)
940 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM
)
941 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM
)
942 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM
)
944 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM
)
947 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM
)
949 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR
)
950 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM
)
951 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM
)
952 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR
)
953 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM
)
954 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM
)
957 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM
)
958 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
959 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM
)
960 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM
)
961 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM
)
962 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
963 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM
)
964 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM
)
965 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
966 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM
)
967 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM
)
968 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
969 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM
)
970 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM
)
973 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM
)
974 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM
)
975 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM
)
976 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR
)
977 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM
)
978 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM
)
979 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR
)
980 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM
)
981 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM
)
983 gtk_window_add_accel_group(GTK_WINDOW(window
),
984 gtk_ui_manager_get_accel_group(ui_manager
));
986 menubar
= gtk_ui_manager_get_widget(ui_manager
, "/Menu");
988 gtk_box_pack_start(GTK_BOX(vbox
), menubar
, FALSE
, TRUE
, 0);
990 vbox2
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, BORDER_WIDTH
);
991 gtk_container_set_border_width(GTK_CONTAINER(vbox2
), BORDER_WIDTH
);
992 gtk_box_pack_start(GTK_BOX(vbox
), vbox2
, TRUE
, TRUE
, 0);
994 ctree_swin
= gtk_scrolled_window_new(NULL
, NULL
);
995 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin
),
996 GTK_POLICY_AUTOMATIC
,
997 GTK_POLICY_AUTOMATIC
);
1000 ctree
= gtk_sctree_new_with_titles(N_INDEX_COLS
, 0, index_titles
);
1001 gtk_widget_set_can_focus(GTK_CMCLIST(ctree
)->column
[0].button
, FALSE
);
1003 gtk_container_add(GTK_CONTAINER(ctree_swin
), ctree
);
1004 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree
), GTK_SELECTION_BROWSE
);
1005 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree
), 0, COL_FOLDER_WIDTH
);
1006 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree
),
1007 GTK_CMCTREE_EXPANDER_TRIANGLE
);
1008 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
1009 gtk_cmctree_set_indent(GTK_CMCTREE(ctree
), CTREE_INDENT
);
1010 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree
),
1011 addressbook_treenode_compare_func
);
1013 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
1014 G_CALLBACK(addressbook_tree_selected
), NULL
);
1015 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
1016 G_CALLBACK(addressbook_tree_button_pressed
),
1018 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
1019 G_CALLBACK(addressbook_tree_button_released
),
1022 g_signal_connect(G_OBJECT(ctree
), "select_row",
1023 G_CALLBACK(addressbook_select_row_tree
), NULL
);
1025 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
1026 addressbook_drag_types
, 1,
1027 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
1028 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
1029 G_CALLBACK(addressbook_drag_motion_cb
),
1031 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
1032 G_CALLBACK(addressbook_drag_leave_cb
),
1034 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
1035 G_CALLBACK(addressbook_drag_received_cb
),
1037 g_signal_connect(G_OBJECT(ctree
), "focus_in_event",
1038 G_CALLBACK(addressbook_address_index_focus_evt_in
), NULL
);
1039 g_signal_connect(G_OBJECT(ctree
), "focus_out_event",
1040 G_CALLBACK(addressbook_address_index_focus_evt_out
), NULL
);
1042 clist_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 4);
1044 clist_swin
= gtk_scrolled_window_new(NULL
, NULL
);
1045 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin
),
1046 GTK_POLICY_AUTOMATIC
,
1047 GTK_POLICY_AUTOMATIC
);
1048 gtk_box_pack_start(GTK_BOX(clist_vbox
), clist_swin
, TRUE
, TRUE
, 0);
1051 clist
= gtk_sctree_new_with_titles(N_LIST_COLS
, 0, list_titles
);
1052 gtk_container_add(GTK_CONTAINER(clist_swin
), clist
);
1053 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist
), GTK_SELECTION_MULTIPLE
);
1054 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist
),
1055 GTK_CMCTREE_EXPANDER_TRIANGLE
);
1056 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
1057 gtk_cmctree_set_indent(GTK_CMCTREE(clist
), CTREE_INDENT
);
1058 gtk_cmclist_set_column_width(GTK_CMCLIST(clist
), COL_NAME
,
1060 gtk_cmclist_set_column_width(GTK_CMCLIST(clist
), COL_ADDRESS
,
1062 gtk_widget_set_size_request(clist
, -1, 80);
1064 addressbook_sort_list(GTK_CMCLIST(clist
), COL_NAME
, GTK_SORT_ASCENDING
);
1065 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_NAME
].button
),
1066 "clicked", G_CALLBACK(addressbook_name_clicked
), clist
);
1067 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_ADDRESS
].button
),
1068 "clicked", G_CALLBACK(addressbook_address_clicked
), clist
);
1069 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_REMARKS
].button
),
1070 "clicked", G_CALLBACK(addressbook_remarks_clicked
), clist
);
1071 g_signal_connect(G_OBJECT(clist
), "focus_in_event",
1072 G_CALLBACK(addressbook_address_list_focus_evt_in
), NULL
);
1073 g_signal_connect(G_OBJECT(clist
), "focus_out_event",
1074 G_CALLBACK(addressbook_address_list_focus_evt_out
), NULL
);
1076 for (i
= 0; i
< N_LIST_COLS
; i
++)
1077 gtk_widget_set_can_focus(GTK_CMCLIST(clist
)->column
[i
].button
,
1080 g_signal_connect(G_OBJECT(clist
), "tree_select_row",
1081 G_CALLBACK(addressbook_list_row_selected
), NULL
);
1082 g_signal_connect(G_OBJECT(clist
), "tree_unselect_row",
1083 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1084 g_signal_connect(G_OBJECT(clist
), "button_press_event",
1085 G_CALLBACK(addressbook_list_button_pressed
),
1087 g_signal_connect(G_OBJECT(clist
), "button_release_event",
1088 G_CALLBACK(addressbook_list_button_released
),
1090 g_signal_connect(G_OBJECT(clist
), "tree_expand",
1091 G_CALLBACK(addressbook_person_expand_node
), NULL
);
1092 g_signal_connect(G_OBJECT(clist
), "tree_collapse",
1093 G_CALLBACK(addressbook_person_collapse_node
), NULL
);
1094 g_signal_connect(G_OBJECT(clist
), "start_drag",
1095 G_CALLBACK(addressbook_start_drag
), NULL
);
1096 g_signal_connect(G_OBJECT(clist
), "drag_data_get",
1097 G_CALLBACK(addressbook_drag_data_get
), NULL
);
1098 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
1099 gtk_box_pack_start(GTK_BOX(clist_vbox
), hbox
, FALSE
, FALSE
, 0);
1101 label
= gtk_label_new(_("Search"));
1102 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1104 entry
= gtk_entry_new();
1105 gtk_box_pack_start(GTK_BOX(hbox
), entry
, TRUE
, TRUE
, 0);
1107 address_completion_register_entry(GTK_ENTRY(entry
), FALSE
);
1109 g_signal_connect(G_OBJECT(entry
), "key_press_event",
1110 G_CALLBACK(addressbook_entry_key_pressed
),
1112 g_signal_connect(G_OBJECT(entry
), "activate",
1113 G_CALLBACK(addressbook_entry_activated
), NULL
);
1115 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
1116 editaddress_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 4);
1117 vpaned
= gtk_paned_new(GTK_ORIENTATION_VERTICAL
);
1118 gtk_paned_pack1(GTK_PANED(vpaned
), clist_vbox
, FALSE
, FALSE
);
1119 gtk_paned_pack2(GTK_PANED(vpaned
), editaddress_vbox
, TRUE
, FALSE
);
1122 editaddress_vbox
= NULL
;
1124 hpaned
= gtk_paned_new(GTK_ORIENTATION_HORIZONTAL
);
1125 gtk_box_pack_start(GTK_BOX(vbox2
), hpaned
, TRUE
, TRUE
, 0);
1126 gtk_paned_pack1(GTK_PANED(hpaned
), ctree_swin
, FALSE
, FALSE
);
1127 if (prefs_common
.addressbook_use_editaddress_dialog
)
1128 gtk_paned_pack2(GTK_PANED(hpaned
), clist_vbox
, TRUE
, FALSE
);
1130 gtk_paned_pack2(GTK_PANED(hpaned
), vpaned
, TRUE
, FALSE
);
1133 hsbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
1134 gtk_box_pack_end(GTK_BOX(vbox
), hsbox
, FALSE
, FALSE
, BORDER_WIDTH
);
1135 statusbar
= gtk_statusbar_new();
1136 gtk_box_pack_start(GTK_BOX(hsbox
), statusbar
, TRUE
, TRUE
, BORDER_WIDTH
);
1139 hbbox
= gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL
);
1140 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox
), GTK_BUTTONBOX_END
);
1141 gtk_box_set_spacing(GTK_BOX(hbbox
), 2);
1142 gtk_container_set_border_width(GTK_CONTAINER(hbbox
), 4);
1143 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
1145 gtkut_stock_button_add_help(hbbox
, &help_btn
);
1147 edit_btn
= gtk_button_new_with_mnemonic(_("_Edit"));
1148 gtk_widget_set_can_default(edit_btn
, TRUE
);
1149 gtk_box_pack_start(GTK_BOX(hbbox
), edit_btn
, TRUE
, TRUE
, 0);
1150 del_btn
= gtk_button_new_with_mnemonic(_("_Delete"));
1151 gtk_widget_set_can_default(del_btn
, TRUE
);
1152 gtk_box_pack_start(GTK_BOX(hbbox
), del_btn
, TRUE
, TRUE
, 0);
1153 reg_btn
= gtk_button_new_with_mnemonic(_("_New"));
1154 gtk_widget_set_can_default(reg_btn
, TRUE
);
1155 gtk_box_pack_start(GTK_BOX(hbbox
), reg_btn
, TRUE
, TRUE
, 0);
1158 lup_btn
= gtkut_stock_button("edit-find", _("_Find"));
1159 gtk_widget_set_can_default(lup_btn
, TRUE
);
1160 gtk_box_pack_start(GTK_BOX(hbox
), lup_btn
, TRUE
, TRUE
, 0);
1162 g_signal_connect(G_OBJECT(help_btn
), "clicked",
1163 G_CALLBACK(manual_open_with_anchor_cb
),
1164 MANUAL_ANCHOR_ADDRBOOK
);
1166 g_signal_connect(G_OBJECT(edit_btn
), "clicked",
1167 G_CALLBACK(addressbook_edit_clicked
), NULL
);
1168 g_signal_connect(G_OBJECT(del_btn
), "clicked",
1169 G_CALLBACK(addressbook_del_clicked
), NULL
);
1170 g_signal_connect(G_OBJECT(reg_btn
), "clicked",
1171 G_CALLBACK(addressbook_reg_clicked
), NULL
);
1172 g_signal_connect(G_OBJECT(lup_btn
), "clicked",
1173 G_CALLBACK(addressbook_lup_clicked
), NULL
);
1175 to_btn
= gtk_button_new_with_label
1176 (prefs_common_translated_header_name("To:"));
1177 gtk_widget_set_can_default(to_btn
, TRUE
);
1178 gtk_box_pack_start(GTK_BOX(hbbox
), to_btn
, TRUE
, TRUE
, 0);
1179 cc_btn
= gtk_button_new_with_label
1180 (prefs_common_translated_header_name("Cc:"));
1181 gtk_widget_set_can_default(cc_btn
, TRUE
);
1182 gtk_box_pack_start(GTK_BOX(hbbox
), cc_btn
, TRUE
, TRUE
, 0);
1183 bcc_btn
= gtk_button_new_with_label
1184 (prefs_common_translated_header_name("Bcc:"));
1185 gtk_widget_set_can_default(bcc_btn
, TRUE
);
1186 gtk_box_pack_start(GTK_BOX(hbbox
), bcc_btn
, TRUE
, TRUE
, 0);
1188 close_btn
= gtkut_stock_button("window-close", "_Close");
1189 gtk_widget_set_can_default(close_btn
, TRUE
);
1190 gtk_box_pack_start(GTK_BOX(hbbox
), close_btn
, TRUE
, TRUE
, 0);
1192 g_signal_connect(G_OBJECT(to_btn
), "clicked",
1193 G_CALLBACK(addressbook_to_clicked
),
1194 GINT_TO_POINTER(COMPOSE_TO
));
1195 g_signal_connect(G_OBJECT(cc_btn
), "clicked",
1196 G_CALLBACK(addressbook_to_clicked
),
1197 GINT_TO_POINTER(COMPOSE_CC
));
1198 g_signal_connect(G_OBJECT(bcc_btn
), "clicked",
1199 G_CALLBACK(addressbook_to_clicked
),
1200 GINT_TO_POINTER(COMPOSE_BCC
));
1201 g_signal_connect(G_OBJECT(close_btn
), "clicked",
1202 G_CALLBACK(addressbook_close_clicked
), NULL
);
1204 /* Build icons for interface */
1206 /* Build control tables */
1207 addrbookctl_build_map(window
);
1208 addrbookctl_build_iflist();
1209 addrbookctl_build_ifselect();
1211 addrbook
.clist
= NULL
;
1213 /* Add each interface into the tree as a root level folder */
1214 nodeIf
= _addressInterfaceList_
;
1216 AdapterInterface
*adapter
= nodeIf
->data
;
1217 AddressInterface
*iface
= adapter
->interface
;
1218 nodeIf
= g_list_next(nodeIf
);
1220 if(iface
->useInterface
) {
1221 AddressTypeControlItem
*atci
= adapter
->atci
;
1222 text
= atci
->displayName
;
1224 gtk_sctree_insert_node( GTK_CMCTREE(ctree
),
1225 NULL
, NULL
, &text
, FOLDER_SPACING
,
1229 cm_menu_set_sensitive_full(ui_manager
, atci
->menuCommand
, adapter
->haveLibrary
);
1230 gtk_cmctree_node_set_row_data_full(
1231 GTK_CMCTREE(ctree
), adapter
->treeNode
, adapter
,
1232 addressbook_free_treenode
);
1238 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Popups", NULL
, GTK_UI_MANAGER_MENUBAR
);
1239 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU
)
1240 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM
)
1241 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM
)
1242 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR
)
1243 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM
)
1244 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM
)
1245 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM
)
1246 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR
)
1247 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM
)
1248 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM
)
1249 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM
)
1251 tree_popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1252 gtk_ui_manager_get_widget(ui_manager
, "/Popups/ABTreePopup")));
1254 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU
)
1255 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM
)
1256 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1257 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM
)
1258 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM
)
1259 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1260 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM
)
1261 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM
)
1262 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1263 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM
)
1264 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM
)
1265 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM
)
1266 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1267 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM
)
1269 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM
)
1271 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM
)
1272 list_popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1273 gtk_ui_manager_get_widget(ui_manager
, "/Popups/ABListPopup")));
1275 addrbook
.window
= window
;
1276 addrbook
.hpaned
= hpaned
;
1277 addrbook
.vpaned
= vpaned
;
1278 addrbook
.menubar
= menubar
;
1279 addrbook
.ctree
= ctree
;
1282 addrbook
.editaddress_vbox
= editaddress_vbox
;
1283 addrbook
.clist
= clist
;
1284 addrbook
.label
= label
;
1285 addrbook
.entry
= entry
;
1286 addrbook
.statusbar
= statusbar
;
1287 addrbook
.status_cid
= gtk_statusbar_get_context_id(
1288 GTK_STATUSBAR(statusbar
), "Addressbook Window" );
1290 addrbook
.help_btn
= help_btn
;
1291 addrbook
.edit_btn
= edit_btn
;
1292 addrbook
.del_btn
= del_btn
;
1293 addrbook
.reg_btn
= reg_btn
;
1294 addrbook
.lup_btn
= lup_btn
;
1295 addrbook
.to_btn
= to_btn
;
1296 addrbook
.cc_btn
= cc_btn
;
1297 addrbook
.bcc_btn
= bcc_btn
;
1299 addrbook
.tree_popup
= tree_popup
;
1300 addrbook
.list_popup
= list_popup
;
1301 addrbook
.ui_manager
= ui_manager
;
1303 addrbook
.listSelected
= NULL
;
1305 if (!geometry
.min_height
) {
1306 geometry
.min_width
= ADDRESSBOOK_WIDTH
;
1307 geometry
.min_height
= ADDRESSBOOK_HEIGHT
;
1310 gtk_window_set_geometry_hints(GTK_WINDOW(window
), NULL
, &geometry
,
1312 gtk_window_set_default_size(GTK_WINDOW(window
), prefs_common
.addressbookwin_width
,
1313 prefs_common
.addressbookwin_height
);
1315 gtk_window_move(GTK_WINDOW(window
), 48, 48);
1318 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
1319 if (prefs_common
.addressbook_vpaned_pos
> 0)
1320 gtk_paned_set_position(GTK_PANED(vpaned
),
1321 prefs_common
.addressbook_vpaned_pos
);
1323 if (prefs_common
.addressbook_hpaned_pos
> 0)
1324 gtk_paned_set_position(GTK_PANED(hpaned
),
1325 prefs_common
.addressbook_hpaned_pos
);
1328 gtk_widget_show_all(window
);
1332 * Close address book window and save to file(s).
1334 static gint
addressbook_close( void ) {
1335 address_completion_end(addrbook
.window
);
1336 if (!prefs_common
.addressbook_use_editaddress_dialog
)
1337 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
1339 addressbook_pane_save_position();
1341 gtk_widget_hide(addrbook
.window
);
1342 addressbook_export_to_file();
1347 * Display message in status line.
1348 * \param msg Message to display.
1350 static void addressbook_status_show( gchar
*msg
) {
1351 if( addrbook
.statusbar
!= NULL
) {
1353 GTK_STATUSBAR(addrbook
.statusbar
),
1354 addrbook
.status_cid
);
1357 GTK_STATUSBAR(addrbook
.statusbar
),
1358 addrbook
.status_cid
, msg
);
1363 static void addressbook_ds_show_message( AddressDataSource
*ds
) {
1367 *addressbook_msgbuf
= '\0';
1369 name
= addrindex_ds_get_name( ds
);
1370 retVal
= addrindex_ds_get_status_code( ds
);
1371 if( retVal
== MGU_SUCCESS
) {
1372 g_snprintf( addressbook_msgbuf
,
1373 sizeof(addressbook_msgbuf
), "%s", name
);
1376 desc
= addressbook_err2string( _lutErrorsGeneral_
, retVal
);
1377 g_snprintf( addressbook_msgbuf
,
1378 sizeof(addressbook_msgbuf
), "%s: %s", name
, desc
);
1381 addressbook_status_show( addressbook_msgbuf
);
1384 static void addressbook_edit_clicked(GtkButton
*button
, gpointer data
)
1386 addressbook_edit_address_cb(NULL
, NULL
);
1389 static gboolean
find_person(AddrSelectItem
*item_a
, ItemPerson
*person
)
1391 return ((ItemPerson
*)item_a
->addressItem
== person
)?0:-1;
1395 * Delete one or more objects from address list.
1397 static void addressbook_del_clicked(GtkButton
*button
, gpointer data
)
1399 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
1400 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
1401 AddressObject
*pobj
;
1402 AdapterDSource
*ads
= NULL
;
1403 GtkCMCTreeNode
*nodeList
;
1406 AddressBookFile
*abf
= NULL
;
1407 AddressDataSource
*ds
= NULL
;
1408 AddressInterface
*iface
;
1409 AddrItemObject
*aio
;
1410 AddrSelectItem
*item
;
1412 gboolean refreshList
= FALSE
;
1414 pobj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.opened
);
1415 cm_return_if_fail(pobj
!= NULL
);
1417 /* Test whether anything selected for deletion */
1418 nodeList
= addrbook
.listSelected
;
1420 aio
= gtk_cmctree_node_get_row_data( clist
, nodeList
);
1421 if( aio
== NULL
) return;
1422 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1423 if( ds
== NULL
) return;
1425 /* Test for read only */
1426 iface
= ds
->interface
;
1427 if( iface
->readOnly
) {
1428 alertpanel( _("Delete address(es)"),
1429 _("This address data is read-only and cannot be deleted."),
1430 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
, ALERTFOCUS_FIRST
);
1434 /* Test whether Ok to proceed */
1436 if( pobj
->type
== ADDR_DATASOURCE
) {
1437 ads
= ADAPTER_DSOURCE(pobj
);
1438 if( ads
->subType
== ADDR_BOOK
) procFlag
= TRUE
;
1440 else if( pobj
->type
== ADDR_ITEM_FOLDER
) {
1443 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
1446 if( ! procFlag
) return;
1447 abf
= ds
->rawDataSource
;
1448 if( abf
== NULL
) return;
1450 gtk_cmclist_freeze(GTK_CMCLIST(addrbook
.clist
));
1451 g_signal_handlers_block_by_func
1452 (G_OBJECT(addrbook
.clist
),
1453 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1455 /* Process deletions */
1456 if( pobj
->type
== ADDR_DATASOURCE
|| pobj
->type
== ADDR_ITEM_FOLDER
) {
1457 GList
*groups
= NULL
, *persons
= NULL
, *emails
= NULL
;
1458 gboolean group_delete
= TRUE
;
1459 /* Items inside folders */
1460 list
= addrselect_get_list( _addressSelect_
);
1461 /* Confirm deletion */
1465 node
= g_list_next( node
);
1466 aio
= ( AddrItemObject
* ) item
->addressItem
;
1467 if( aio
->type
== ITEMTYPE_PERSON
|| aio
->type
== ITEMTYPE_EMAIL
) {
1468 group_delete
= FALSE
;
1473 aval
= alertpanel( _("Delete group"),
1474 _("Really delete the group(s)?\n"
1475 "The addresses it contains will not be lost."),
1476 NULL
, _("_Cancel"), "edit-delete", _("D_elete"), NULL
, NULL
,
1477 ALERTFOCUS_SECOND
);
1478 if( aval
!= G_ALERTALTERNATE
) {
1482 aval
= alertpanel( _("Delete address(es)"),
1483 _("Really delete the address(es)?"),
1484 NULL
, _("_Cancel"), "edit-delete", _("D_elete"), NULL
, NULL
,
1485 ALERTFOCUS_SECOND
);
1486 if( aval
!= G_ALERTALTERNATE
) {
1491 /* first, set lists of groups and persons to remove */
1495 node
= g_list_next( node
);
1496 aio
= ( AddrItemObject
* ) item
->addressItem
;
1499 if( aio
->type
== ITEMTYPE_GROUP
) {
1500 groups
= g_list_prepend(groups
, item
);
1502 else if( aio
->type
== ITEMTYPE_PERSON
) {
1503 persons
= g_list_prepend(persons
, item
);
1506 /* then set list of emails to remove *if* they're not children of
1507 * persons to remove */
1511 node
= g_list_next( node
);
1512 aio
= ( AddrItemObject
* ) item
->addressItem
;
1515 if( aio
->type
== ITEMTYPE_EMAIL
) {
1516 ItemEMail
*sitem
= ( ItemEMail
* ) aio
;
1517 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(sitem
);
1518 if (!g_list_find_custom(persons
, person
, (GCompareFunc
)(find_person
))) {
1519 emails
= g_list_prepend(emails
, item
);
1521 /* else, the email will be removed via the parent person */
1524 /* then delete groups */
1528 node
= g_list_next( node
);
1529 aio
= ( AddrItemObject
* ) item
->addressItem
;
1532 if( aio
->type
== ITEMTYPE_GROUP
) {
1533 ItemGroup
*item
= ( ItemGroup
* ) aio
;
1534 GtkCMCTreeNode
*nd
= NULL
;
1535 nd
= addressbook_find_group_node( addrbook
.opened
, item
);
1536 item
= addrbook_remove_group( abf
, item
);
1538 addritem_free_item_group( item
);
1540 /* Remove group from parent node */
1541 gtk_cmctree_remove_node( ctree
, nd
);
1545 /* then delete persons */
1549 node
= g_list_next( node
);
1550 aio
= ( AddrItemObject
* ) item
->addressItem
;
1553 if( aio
->type
== ITEMTYPE_PERSON
) {
1554 ItemPerson
*item
= ( ItemPerson
* ) aio
;
1555 item
->status
= DELETE_ENTRY
;
1556 addressbook_folder_remove_one_person( clist
, item
);
1557 if (pobj
->type
== ADDR_ITEM_FOLDER
)
1558 addritem_folder_remove_person(ADAPTER_FOLDER(pobj
)->itemFolder
, item
);
1559 item
= addrbook_remove_person( abf
, item
);
1561 if (ds
&& ds
->type
== ADDR_IF_LDAP
) {
1562 LdapServer
*server
= ds
->rawDataSource
;
1563 ldapsvr_set_modified(server
, TRUE
);
1564 ldapsvr_update_book(server
, item
);
1568 addritem_person_remove_picture(item
);
1569 addritem_free_item_person( item
);
1573 /* then delete emails */
1577 node
= g_list_next( node
);
1578 aio
= ( AddrItemObject
* ) item
->addressItem
;
1582 if( aio
->type
== ITEMTYPE_EMAIL
) {
1583 ItemEMail
*sitem
= ( ItemEMail
* ) aio
;
1584 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(sitem
);
1585 sitem
= addrbook_person_remove_email( abf
, person
, sitem
);
1587 addrcache_remove_email(abf
->addressCache
, sitem
);
1588 addritem_free_item_email( sitem
);
1590 addressbook_folder_refresh_one_person( clist
, person
);
1593 g_list_free( groups
);
1594 g_list_free( persons
);
1595 g_list_free( emails
);
1596 g_list_free( list
);
1597 addressbook_list_select_clear();
1599 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
1600 addressbook_set_clist(
1601 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
1605 addrbook_set_dirty(abf
, TRUE
);
1606 addressbook_export_to_file();
1607 addressbook_list_menu_setup();
1610 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
1611 /* Items inside groups */
1612 list
= addrselect_get_list( _addressSelect_
);
1616 node
= g_list_next( node
);
1617 aio
= ( AddrItemObject
* ) item
->addressItem
;
1618 if( aio
->type
== ITEMTYPE_EMAIL
) {
1619 ItemEMail
*item
= ( ItemEMail
* ) aio
;
1620 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(item
);
1621 item
= addrbook_person_remove_email( abf
, person
, item
);
1623 addritem_free_item_email( item
);
1627 g_list_free( list
);
1628 addressbook_list_select_clear();
1629 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
1630 addressbook_set_clist(
1631 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
1635 addrbook_set_dirty(abf
, TRUE
);
1636 addressbook_export_to_file();
1637 addressbook_list_menu_setup();
1641 gtk_cmctree_node_set_row_data( clist
, nodeList
, NULL
);
1642 gtk_cmctree_remove_node( clist
, nodeList
);
1644 gtk_cmclist_thaw(GTK_CMCLIST(addrbook
.clist
));
1645 g_signal_handlers_unblock_by_func
1646 (G_OBJECT(addrbook
.clist
),
1647 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1650 static void addressbook_reg_clicked(GtkButton
*button
, gpointer data
)
1652 addressbook_new_address_cb( NULL
, NULL
);
1655 static gchar
*addressbook_format_address( AddrItemObject
* aio
) {
1658 gchar
*address
= NULL
;
1660 if( aio
->type
== ITEMTYPE_EMAIL
) {
1661 ItemPerson
*person
= NULL
;
1662 ItemEMail
*email
= ( ItemEMail
* ) aio
;
1664 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
1665 if( email
->address
) {
1666 if( ADDRITEM_NAME(email
) ) {
1667 name
= ADDRITEM_NAME(email
);
1668 if( *name
== '\0' ) {
1669 name
= ADDRITEM_NAME(person
);
1672 else if( ADDRITEM_NAME(person
) ) {
1673 name
= ADDRITEM_NAME(person
);
1676 buf
= g_strdup( email
->address
);
1678 address
= email
->address
;
1681 else if( aio
->type
== ITEMTYPE_PERSON
) {
1682 ItemPerson
*person
= ( ItemPerson
* ) aio
;
1683 GList
*node
= person
->listEMail
;
1685 name
= ADDRITEM_NAME(person
);
1687 ItemEMail
*email
= ( ItemEMail
* ) node
->data
;
1688 address
= email
->address
;
1692 if( name
&& name
[0] != '\0' ) {
1693 if( strchr_with_skip_quote( name
, '"', ',' ) )
1694 buf
= g_strdup_printf( "\"%s\" <%s>", name
, address
);
1696 buf
= g_strdup_printf( "%s <%s>", name
, address
);
1699 buf
= g_strdup( address
);
1706 static void addressbook_to_clicked(GtkButton
*button
, gpointer data
)
1710 AddrSelectItem
*item
;
1711 AddrItemObject
*aio
;
1714 compose
= addrbook
.target_compose
;
1715 if( ! compose
) return;
1717 /* Nothing selected, but maybe there is something in text entry */
1718 addr
= (char *)gtk_entry_get_text( GTK_ENTRY( addrbook
.entry
) );
1720 compose_entry_append(
1721 compose
, addr
, (ComposeEntryType
)data
, PREF_NONE
);
1724 /* Select from address list */
1725 list
= addrselect_get_list( _addressSelect_
);
1730 node
= g_list_next( node
);
1731 aio
= item
->addressItem
;
1732 if( aio
->type
== ITEMTYPE_PERSON
||
1733 aio
->type
== ITEMTYPE_EMAIL
) {
1734 addr
= addressbook_format_address( aio
);
1735 compose_entry_append(
1736 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1739 else if( aio
->type
== ITEMTYPE_GROUP
) {
1740 ItemGroup
*group
= ( ItemGroup
* ) aio
;
1741 GList
*nodeMail
= group
->listEMail
;
1743 ItemEMail
*email
= nodeMail
->data
;
1745 addr
= addressbook_format_address(
1746 ( AddrItemObject
* ) email
);
1747 compose_entry_append(
1748 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1750 nodeMail
= g_list_next( nodeMail
);
1755 AddressObject
*obj
= NULL
;
1757 obj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
1759 if( obj
&& obj
->type
== ADDR_ITEM_GROUP
) {
1760 ItemGroup
*itemGroup
= ADAPTER_GROUP(obj
)->itemGroup
;
1761 GList
*nodeMail
= itemGroup
->listEMail
;
1763 ItemEMail
*email
= nodeMail
->data
;
1765 addr
= addressbook_format_address(
1766 ( AddrItemObject
* ) email
);
1767 compose_entry_append(
1768 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1770 nodeMail
= g_list_next( nodeMail
);
1774 g_list_free( list
);
1777 static void addressbook_menubar_set_sensitive( gboolean sensitive
) {
1778 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", sensitive
);
1779 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", sensitive
);
1780 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/NewFolder", sensitive
);
1782 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/SelectAll", TRUE
);
1783 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", sensitive
);
1784 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", sensitive
);
1785 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", sensitive
);
1787 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewAddress", sensitive
);
1788 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewGroup", sensitive
);
1789 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Mailto", sensitive
);
1790 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Merge", sensitive
);
1791 gtk_widget_set_sensitive( addrbook
.edit_btn
, sensitive
);
1792 gtk_widget_set_sensitive( addrbook
.del_btn
, sensitive
);
1795 static void addressbook_menuitem_set_sensitive( AddressObject
*obj
, GtkCMCTreeNode
*node
) {
1796 gboolean canEdit
= FALSE
;
1797 gboolean canDelete
= TRUE
;
1798 gboolean canAdd
= FALSE
;
1799 gboolean canEditTr
= TRUE
;
1800 gboolean editAddress
= FALSE
;
1801 gboolean canExport
= TRUE
;
1802 AddressTypeControlItem
*atci
= NULL
;
1803 AddressDataSource
*ds
= NULL
;
1804 AddressInterface
*iface
= NULL
;
1806 if( obj
== NULL
) return;
1807 if( obj
->type
== ADDR_INTERFACE
) {
1808 AdapterInterface
*adapter
= ADAPTER_INTERFACE(obj
);
1809 iface
= adapter
->interface
;
1811 if( iface
->haveLibrary
) {
1812 /* Enable appropriate File / New command */
1813 atci
= adapter
->atci
;
1814 cm_menu_set_sensitive_full(addrbook
.ui_manager
, atci
->menuCommand
, TRUE
);
1817 canEditTr
= canExport
= FALSE
;
1819 else if( obj
->type
== ADDR_DATASOURCE
) {
1820 AdapterDSource
*ads
= ADAPTER_DSOURCE(obj
);
1821 ds
= ads
->dataSource
;
1822 iface
= ds
->interface
;
1823 if( ! iface
->readOnly
) {
1824 canAdd
= canEdit
= editAddress
= canDelete
= TRUE
;
1826 if( ! iface
->haveLibrary
) {
1827 canAdd
= canEdit
= editAddress
= canExport
= canDelete
= FALSE
;
1830 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
1831 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1833 iface
= ds
->interface
;
1834 if( iface
->readOnly
) {
1839 canAdd
= editAddress
= TRUE
;
1843 else if( obj
->type
== ADDR_ITEM_GROUP
) {
1844 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1846 iface
= ds
->interface
;
1847 if( ! iface
->readOnly
) {
1853 if( addrbook
.listSelected
== NULL
)
1857 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewAddress", editAddress
);
1858 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewGroup", canAdd
);
1859 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/NewFolder", canAdd
);
1860 gtk_widget_set_sensitive( addrbook
.reg_btn
, editAddress
);
1863 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Edit", canEdit
);
1864 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Delete", canDelete
);
1865 gtk_widget_set_sensitive( addrbook
.edit_btn
, canEdit
);
1866 gtk_widget_set_sensitive( addrbook
.del_btn
, canDelete
);
1868 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", canEditTr
);
1869 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", canEditTr
);
1872 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Tools/ExportHTML", canExport
);
1873 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Tools/ExportLDIF", canExport
);
1877 * Address book tree callback function that responds to selection of tree
1880 * \param ctree Tree widget.
1881 * \param node Node that was selected.
1882 * \param column Column number where selected occurred.
1883 * \param data Pointer to user data.
1885 static void addressbook_tree_selected(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
1886 gint column
, gpointer data
)
1888 AddressObject
*obj
= NULL
;
1889 AdapterDSource
*ads
= NULL
;
1890 AddressDataSource
*ds
= NULL
;
1891 ItemFolder
*rootFolder
= NULL
;
1892 AddressObjectType aot
;
1894 addrbook
.treeSelected
= node
;
1895 addrbook
.listSelected
= NULL
;
1896 addressbook_status_show( "" );
1897 if( addrbook
.entry
!= NULL
) gtk_entry_set_text(GTK_ENTRY(addrbook
.entry
), "");
1899 if( node
) obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
1901 addressbook_set_clist(NULL
, TRUE
);
1904 addrbook
.opened
= node
;
1906 if( obj
->type
== ADDR_DATASOURCE
) {
1907 /* Read from file */
1908 static gboolean tVal
= TRUE
;
1910 ads
= ADAPTER_DSOURCE(obj
);
1912 ds
= ads
->dataSource
;
1913 if( ds
== NULL
) return;
1915 if( addrindex_ds_get_modify_flag( ds
) ) {
1916 addrindex_ds_read_data( ds
);
1919 if( ! addrindex_ds_get_read_flag( ds
) ) {
1920 addrindex_ds_read_data( ds
);
1922 addressbook_ds_show_message( ds
);
1924 if( ! addrindex_ds_get_access_flag( ds
) ) {
1925 /* Remove existing folders and groups */
1926 gtk_cmclist_freeze( GTK_CMCLIST(ctree
) );
1927 addressbook_tree_remove_children( ctree
, node
);
1928 gtk_cmclist_thaw( GTK_CMCLIST(ctree
) );
1930 /* Load folders into the tree */
1931 rootFolder
= addrindex_ds_get_root_folder( ds
);
1932 if( ds
&& ds
->type
== ADDR_IF_JPILOT
) {
1933 aot
= ADDR_CATEGORY
;
1935 else if( ds
&& ds
->type
== ADDR_IF_LDAP
) {
1936 aot
= ADDR_LDAP_QUERY
;
1939 aot
= ADDR_ITEM_FOLDER
;
1941 addressbook_node_add_folder( node
, ds
, rootFolder
, aot
);
1942 addrindex_ds_set_access_flag( ds
, &tVal
);
1943 gtk_cmctree_expand( ctree
, node
);
1946 addressbook_set_clist(NULL
, TRUE
);
1949 /* Update address list */
1950 g_signal_handlers_block_by_func
1952 G_CALLBACK(addressbook_tree_selected
), NULL
);
1953 addressbook_set_clist( obj
, FALSE
);
1954 g_signal_handlers_unblock_by_func
1956 G_CALLBACK(addressbook_tree_selected
), NULL
);
1957 if (!prefs_common
.addressbook_use_editaddress_dialog
)
1958 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
1960 /* Setup main menu selections */
1961 addressbook_menubar_set_sensitive( FALSE
);
1962 addressbook_menuitem_set_sensitive( obj
, node
);
1963 addressbook_list_select_clear();
1964 addressbook_list_menu_setup();
1969 * Setup address list popup menu items. Items are enabled or disabled as
1972 static void addressbook_list_menu_setup( void ) {
1973 GtkCMCTree
*clist
= NULL
;
1974 AddressObject
*pobj
= NULL
;
1975 AddressObject
*obj
= NULL
;
1976 AdapterDSource
*ads
= NULL
;
1977 AddressInterface
*iface
= NULL
;
1978 AddressDataSource
*ds
= NULL
;
1980 AddrItemObject
*aio
;
1981 AddrSelectItem
*item
;
1982 gboolean canEdit
= FALSE
;
1983 gboolean canDelete
= FALSE
;
1984 gboolean canCut
= FALSE
;
1985 gboolean canCopy
= FALSE
;
1986 gboolean canPaste
= FALSE
;
1987 gboolean canBrowse
= FALSE
;
1988 gboolean canMerge
= FALSE
;
1990 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
1991 if( pobj
== NULL
) return;
1993 clist
= GTK_CMCTREE(addrbook
.clist
);
1994 obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
1995 if( obj
== NULL
) canEdit
= FALSE
;
1997 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook
.list_popup
) );
1998 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/SelectAll", TRUE
);
2000 if( pobj
->type
== ADDR_DATASOURCE
) {
2001 /* Parent object is a data source */
2002 ads
= ADAPTER_DSOURCE(pobj
);
2003 ds
= ads
->dataSource
;
2006 iface
= ds
->interface
;
2009 if( ! iface
->readOnly
) {
2010 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2011 if (iface
->type
!= ADDR_IF_LDAP
)
2012 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewGroup", TRUE
);
2013 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2016 canDelete
= canEdit
;
2019 else if( pobj
->type
!= ADDR_INTERFACE
) {
2020 /* Parent object is not an interface */
2021 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2024 iface
= ds
->interface
;
2027 if( ! iface
->readOnly
) {
2028 /* Folder or group */
2029 if( pobj
->type
== ADDR_ITEM_FOLDER
|| pobj
->type
== ADDR_ITEM_GROUP
) {
2030 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2031 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2032 if( obj
) canEdit
= TRUE
;
2035 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
2036 if (iface
->type
!= ADDR_IF_LDAP
)
2037 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewGroup", TRUE
);
2038 if( obj
) canEdit
= TRUE
;
2040 canDelete
= canEdit
;
2042 if( iface
->type
== ADDR_IF_LDAP
) {
2043 if( obj
) canBrowse
= TRUE
;
2050 /* Enable cut and paste */
2051 if( ! addrclip_is_empty( _clipBoard_
) )
2053 if( ! addrselect_test_empty( _addressSelect_
) )
2055 /* Enable copy if something is selected */
2056 if( ! addrselect_test_empty( _addressSelect_
) )
2060 /* Disable edit or browse if more than one row selected */
2061 if( GTK_CMCLIST(clist
)->selection
&& GTK_CMCLIST(clist
)->selection
->next
) {
2066 /* Allow merging persons or emails are selected */
2067 list
= _addressSelect_
->listSelect
;
2068 if (list
&& list
->next
) {
2070 aio
= ( AddrItemObject
* ) item
->addressItem
;
2071 if( aio
->type
== ITEMTYPE_EMAIL
||
2072 aio
->type
== ITEMTYPE_PERSON
) {
2077 /* Forbid write changes when read-only */
2078 if( iface
&& iface
->readOnly
) {
2085 /* Now go finalize menu items */
2086 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Edit", canEdit
);
2087 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Delete", canDelete
);
2089 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Cut", canCut
);
2090 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Copy", canCopy
);
2091 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Paste", canPaste
);
2093 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Mailto", canCopy
);
2094 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Merge", canMerge
);
2096 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", canCut
);
2097 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", canCopy
);
2098 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", canPaste
);
2100 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Edit", canEdit
);
2101 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Delete", canDelete
);
2102 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Mailto", canCopy
);
2103 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Merge", canMerge
);
2105 gtk_widget_set_sensitive( addrbook
.edit_btn
, canEdit
);
2106 gtk_widget_set_sensitive( addrbook
.del_btn
, canDelete
);
2108 if (addrbook
.target_compose
) {
2109 gtk_widget_set_sensitive(addrbook
.to_btn
, obj
? TRUE
: FALSE
);
2110 gtk_widget_set_sensitive(addrbook
.cc_btn
, obj
? TRUE
: FALSE
);
2111 gtk_widget_set_sensitive(addrbook
.bcc_btn
, obj
? TRUE
: FALSE
);
2114 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/BrowseEntry", canBrowse
);
2118 static void addressbook_select_row_tree (GtkCMCTree
*ctree
,
2119 GtkCMCTreeNode
*node
,
2126 * Add list of items into tree node below specified tree node.
2127 * \param treeNode Tree node.
2128 * \param ds Data source.
2129 * \param listItems List of items.
2131 static void addressbook_treenode_add_list(
2132 GtkCMCTreeNode
*treeNode
, AddressDataSource
*ds
, GList
*listItems
)
2138 AddrItemObject
*aio
;
2142 if( ADDRESS_OBJECT_TYPE(aio
) == ADDR_ITEM_GROUP
) {
2145 group
= ( ItemGroup
* ) aio
;
2146 nn
= addressbook_node_add_group( treeNode
, ds
, group
);
2148 g_message("error adding addressbook group\n");
2151 else if( ADDRESS_OBJECT_TYPE(aio
) == ADDR_ITEM_FOLDER
) {
2154 folder
= ( ItemFolder
* ) aio
;
2155 nn
= addressbook_node_add_folder(
2156 treeNode
, ds
, folder
, ADDR_ITEM_FOLDER
);
2158 g_message("error adding addressbook folder\n");
2161 node
= g_list_next( node
);
2165 static void addressbook_select_all_cb( GtkAction
*action
, gpointer data
) {
2166 gtk_cmclist_select_all(GTK_CMCLIST(addrbook
.clist
));
2170 * Cut from address list widget.
2172 static void addressbook_clip_cut_cb( GtkAction
*action
, gpointer data
) {
2173 _clipBoard_
->cutFlag
= TRUE
;
2174 addrclip_clear( _clipBoard_
);
2175 addrclip_add( _clipBoard_
, _addressSelect_
);
2176 #ifdef DEBUG_ADDRBOOK
2177 addrclip_list_show( _clipBoard_
, stdout
);
2182 * Copy from address list widget.
2184 static void addressbook_clip_copy_cb(GtkAction
*action
, gpointer data
) {
2185 _clipBoard_
->cutFlag
= FALSE
;
2186 addrclip_clear( _clipBoard_
);
2187 addrclip_add( _clipBoard_
, _addressSelect_
);
2188 #ifdef DEBUG_ADDRBOOK
2189 addrclip_list_show( _clipBoard_
, stdout
);
2194 * Paste clipboard into address list widget.
2196 static void addressbook_clip_paste_cb( GtkAction
*action
, gpointer data
) {
2197 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
2198 AddressObject
*pobj
= NULL
;
2199 AddressDataSource
*ds
= NULL
;
2200 AddressBookFile
*abf
= NULL
;
2201 ItemFolder
*folder
= NULL
;
2202 GList
*folderGroup
= NULL
;
2204 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
2205 if( ds
== NULL
) return;
2206 if( addrindex_ds_get_readonly( ds
) ) {
2207 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2211 pobj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
2213 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
2214 folder
= ADAPTER_FOLDER(pobj
)->itemFolder
;
2216 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
2217 alertpanel_error( _("Cannot paste into an address group.") );
2222 /* Get an address book */
2223 abf
= addressbook_get_book_file();
2224 if( abf
== NULL
) return;
2226 if( _clipBoard_
->cutFlag
) {
2228 folderGroup
= addrclip_paste_cut( _clipBoard_
, abf
, folder
);
2230 /* Remove all groups and folders in clipboard from tree node */
2231 addressbook_treenode_remove_item();
2233 /* Remove all "cut" items */
2234 addrclip_delete_item( _clipBoard_
);
2236 /* Clear clipboard - cut items??? */
2237 addrclip_clear( _clipBoard_
);
2241 folderGroup
= addrclip_paste_copy( _clipBoard_
, abf
, folder
);
2244 #ifdef DEBUG_ADDRBOOK
2245 addrclip_list_show( _clipBoard_
, stdout
);
2248 /* Update tree by inserting node for each folder or group */
2249 addressbook_treenode_add_list(
2250 addrbook
.treeSelected
, ds
, folderGroup
);
2251 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2252 g_list_free( folderGroup
);
2256 /* Display items pasted */
2257 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
2258 addressbook_set_clist(
2259 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
2267 * Add current treenode object to clipboard. Note that widget only allows
2268 * one entry from the tree list to be selected.
2270 static void addressbook_treenode_to_clipboard( void ) {
2271 AddressObject
*obj
= NULL
;
2272 AddressDataSource
*ds
= NULL
;
2273 AddrSelectItem
*item
;
2274 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
2275 GtkCMCTreeNode
*node
;
2277 node
= addrbook
.treeSelected
;
2278 if( node
== NULL
) return;
2279 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2280 if( obj
== NULL
) return;
2282 ds
= addressbook_find_datasource( node
);
2283 if( ds
== NULL
) return;
2286 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2287 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
2288 ItemFolder
*folder
= adapter
->itemFolder
;
2290 item
= addrselect_create_node( obj
);
2291 item
->uid
= g_strdup( ADDRITEM_ID(folder
) );
2293 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2294 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
2295 ItemGroup
*group
= adapter
->itemGroup
;
2297 item
= addrselect_create_node( obj
);
2298 item
->uid
= g_strdup( ADDRITEM_ID(group
) );
2300 else if( obj
->type
== ADDR_DATASOURCE
) {
2302 item
= addrselect_create_node( obj
);
2307 /* Clear existing list and add item into list */
2310 addressbook_list_select_clear();
2311 cacheID
= addrindex_get_cache_id( _addressIndex_
, ds
);
2312 addrselect_list_add( _addressSelect_
, item
, cacheID
);
2318 * Cut from tree widget.
2320 static void addressbook_treenode_cut_cb( GtkAction
*action
, gpointer data
) {
2321 _clipBoard_
->cutFlag
= TRUE
;
2322 addressbook_treenode_to_clipboard();
2323 addrclip_clear( _clipBoard_
);
2324 addrclip_add( _clipBoard_
, _addressSelect_
);
2325 #ifdef DEBUG_ADDRBOOK
2326 addrclip_list_show( _clipBoard_
, stdout
);
2331 * Copy from tree widget.
2333 static void addressbook_treenode_copy_cb( GtkAction
*action
, gpointer data
) {
2334 _clipBoard_
->cutFlag
= FALSE
;
2335 addressbook_treenode_to_clipboard();
2336 addrclip_clear( _clipBoard_
);
2337 addrclip_add( _clipBoard_
, _addressSelect_
);
2338 #ifdef DEBUG_ADDRBOOK
2339 addrclip_list_show( _clipBoard_
, stdout
);
2344 * Paste clipboard into address tree widget.
2346 static void addressbook_treenode_paste_cb( GtkAction
*action
, gpointer data
) {
2347 addressbook_clip_paste_cb(NULL
,NULL
);
2351 * Clear selected entries in clipboard.
2353 static void addressbook_list_select_clear( void ) {
2354 addrselect_list_clear( _addressSelect_
);
2358 * Add specified address item to selected address list.
2359 * \param aio Address item object.
2360 * \param ds Datasource.
2362 static void addressbook_list_select_add( AddrItemObject
*aio
, AddressDataSource
*ds
) {
2365 if( ds
== NULL
) return;
2366 cacheID
= addrindex_get_cache_id( _addressIndex_
, ds
);
2367 addrselect_list_add_obj( _addressSelect_
, aio
, cacheID
);
2372 * Remove specified address item from selected address list.
2373 * \param aio Address item object.
2375 static void addressbook_list_select_remove( AddrItemObject
*aio
) {
2376 addrselect_list_remove( _addressSelect_
, aio
);
2380 * Invoke EMail compose window with addresses in selected address list.
2382 static void addressbook_mail_to_cb( GtkAction
*action
, gpointer data
) {
2385 if( ! addrselect_test_empty( _addressSelect_
) ) {
2386 listAddress
= addrselect_build_list( _addressSelect_
);
2387 compose_new_with_list( NULL
, listAddress
);
2388 g_list_free_full( listAddress
, g_free
);
2393 static void addressbook_merge_list( AddrSelectList
*list
) {
2394 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2395 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
2396 AddressObject
*pobj
;
2397 AddressDataSource
*ds
= NULL
;
2399 pobj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.opened
);
2400 cm_return_if_fail(pobj
!= NULL
);
2402 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2403 if( ds
== NULL
) return;
2405 addrmerge_merge(clist
, pobj
, ds
, list
);
2409 * Merge selected entries in the address list
2411 static void addressbook_merge_cb( GtkAction
*action
, gpointer data
) {
2412 if( addrselect_test_empty( _addressSelect_
) )
2415 addressbook_merge_list( _addressSelect_
);
2418 static void addressbook_list_row_selected( GtkCMCTree
*clist
,
2419 GtkCMCTreeNode
*node
,
2423 AddrItemObject
*aio
= NULL
;
2424 AddressObject
*pobj
= NULL
;
2425 AdapterDSource
*ads
= NULL
;
2426 AddressDataSource
*ds
= NULL
;
2428 addrbook
.listSelected
= node
;
2430 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
2431 if( pobj
== NULL
) return;
2433 if( pobj
->type
== ADDR_DATASOURCE
) {
2434 ads
= ADAPTER_DSOURCE(pobj
);
2435 ds
= ads
->dataSource
;
2437 else if( pobj
->type
!= ADDR_INTERFACE
) {
2438 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2441 aio
= gtk_cmctree_node_get_row_data( clist
, node
);
2443 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2444 addressbook_list_select_add( aio
, ds
);
2447 addressbook_list_menu_setup();
2449 if (!addrbook
.target_compose
&& !prefs_common
.addressbook_use_editaddress_dialog
) {
2450 AddressObject
*obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
2452 if (obj
&& obj
->type
!= ADDR_ITEM_GROUP
)
2453 addressbook_edit_address(NULL
, 0, NULL
, FALSE
);
2457 static void addressbook_list_row_unselected( GtkCMCTree
*ctree
,
2458 GtkCMCTreeNode
*node
,
2462 AddrItemObject
*aio
;
2464 aio
= gtk_cmctree_node_get_row_data( ctree
, node
);
2466 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2467 addressbook_list_select_remove( aio
);
2470 if (!prefs_common
.addressbook_use_editaddress_dialog
)
2471 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
2474 static void addressbook_entry_activated(GtkWidget
*widget
, gpointer data
)
2476 addressbook_lup_clicked(NULL
, NULL
);
2479 static gboolean
addressbook_list_button_pressed(GtkWidget
*widget
,
2480 GdkEventButton
*event
,
2483 if( ! event
) return FALSE
;
2484 if( event
->window
!= GTK_CMCLIST(widget
)->clist_window
) return FALSE
;
2486 addressbook_list_menu_setup();
2488 if( event
->button
== 3 ) {
2489 gtk_menu_popup_at_pointer(GTK_MENU(addrbook
.list_popup
), NULL
);
2490 } else if (event
->button
== 1) {
2491 if (event
->type
== GDK_2BUTTON_PRESS
) {
2492 if (prefs_common
.add_address_by_click
&&
2493 addrbook
.target_compose
)
2494 addressbook_to_clicked(NULL
, GINT_TO_POINTER(COMPOSE_TO
));
2496 if (prefs_common
.addressbook_use_editaddress_dialog
)
2497 addressbook_edit_address_cb(NULL
, NULL
);
2499 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
2500 AddressObject
*obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
2501 if( obj
&& obj
->type
== ADDR_ITEM_GROUP
)
2502 addressbook_edit_address_cb(NULL
, NULL
);
2510 static gboolean
addressbook_list_button_released(GtkWidget
*widget
,
2511 GdkEventButton
*event
,
2517 static gboolean
addressbook_tree_button_pressed(GtkWidget
*ctree
,
2518 GdkEventButton
*event
,
2521 GtkCMCList
*clist
= GTK_CMCLIST(ctree
);
2523 AddressObject
*obj
= NULL
;
2524 AdapterDSource
*ads
= NULL
;
2525 AddressInterface
*iface
= NULL
;
2526 AddressDataSource
*ds
= NULL
;
2527 gboolean canEdit
= FALSE
;
2528 gboolean canDelete
= FALSE
;
2529 gboolean canCut
= FALSE
;
2530 gboolean canCopy
= FALSE
;
2531 gboolean canPaste
= FALSE
;
2532 gboolean canTreeCut
= FALSE
;
2533 gboolean canTreeCopy
= FALSE
;
2534 gboolean canTreePaste
= FALSE
;
2535 gboolean canLookup
= FALSE
;
2536 GtkCMCTreeNode
*node
= NULL
;
2538 if( ! event
) return FALSE
;
2539 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2541 if( event
->window
!= clist
->clist_window
)
2544 if (event
->button
== 1) {
2545 if (event
->type
== GDK_2BUTTON_PRESS
) {
2546 if( gtk_cmclist_get_selection_info( clist
, event
->x
, event
->y
, &row
, &column
) ) {
2547 gtkut_clist_set_focus_row(clist
, row
);
2548 obj
= gtk_cmclist_get_row_data( clist
, row
);
2553 if (obj
->type
== ADDR_ITEM_GROUP
||
2554 obj
->type
== ADDR_DATASOURCE
) {
2556 addressbook_treenode_edit_cb(NULL
, NULL
);
2558 /* expand pr collapse */
2559 node
= gtk_cmctree_node_nth(GTK_CMCTREE(ctree
), row
);
2560 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree
), node
);
2566 addressbook_menubar_set_sensitive( FALSE
);
2568 if( gtk_cmclist_get_selection_info( clist
, event
->x
, event
->y
, &row
, &column
) ) {
2569 gtkut_clist_set_focus_row(clist
, row
);
2570 obj
= gtk_cmclist_get_row_data( clist
, row
);
2573 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook
.tree_popup
));
2577 node
= gtk_cmctree_node_nth(GTK_CMCTREE(clist
), row
);
2579 if( ! addrclip_is_empty( _clipBoard_
) )
2580 canTreePaste
= TRUE
;
2582 if (obj
->type
== ADDR_INTERFACE
) {
2583 AdapterInterface
*adapter
= ADAPTER_INTERFACE(obj
);
2584 iface
= adapter
->interface
;
2587 if( !iface
->readOnly
&& iface
->type
== ADDR_IF_BOOK
) {
2588 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewBook", TRUE
);
2590 if( iface
->externalQuery
)
2593 if (obj
->type
== ADDR_DATASOURCE
) {
2595 ads
= ADAPTER_DSOURCE(obj
);
2596 ds
= ads
->dataSource
;
2599 iface
= ds
->interface
;
2602 if( !iface
->readOnly
) {
2603 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewFolder", TRUE
);
2604 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewGroup", TRUE
);
2605 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2611 else if (obj
->type
== ADDR_ITEM_FOLDER
) {
2613 ds
= addressbook_find_datasource( node
);
2616 iface
= ds
->interface
;
2619 if( !iface
->readOnly
) {
2623 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewFolder", TRUE
);
2624 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewGroup", TRUE
);
2625 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2629 if( iface
->externalQuery
) {
2630 /* Enable deletion of LDAP folder */
2634 else if (obj
->type
== ADDR_ITEM_GROUP
) {
2636 ds
= addressbook_find_datasource( node
);
2639 iface
= ds
->interface
;
2642 if( ! iface
->readOnly
) {
2645 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2646 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2650 if( canEdit
&& !addrselect_test_empty( _addressSelect_
) )
2652 if( ! addrselect_test_empty( _addressSelect_
) )
2654 if( ! addrclip_is_empty( _clipBoard_
) )
2657 /* Forbid write changes when read-only */
2658 if( iface
&& iface
->readOnly
) {
2660 canTreePaste
= FALSE
;
2667 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/EditBook", canEdit
);
2668 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/DeleteBook", canDelete
);
2669 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Cut", canTreeCut
);
2670 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Copy", canTreeCopy
);
2671 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Paste", canTreePaste
);
2673 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", canEdit
);
2674 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", canDelete
);
2675 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", canCut
);
2676 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", canCopy
);
2677 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", canPaste
);
2679 addressbook_show_buttons(addrbook
.target_compose
== NULL
, canLookup
,
2680 addrbook
.target_compose
!= NULL
);
2682 if( event
->button
== 3 )
2683 gtk_menu_popup_at_pointer(GTK_MENU(addrbook
.tree_popup
), NULL
);
2688 static gboolean
addressbook_tree_button_released(GtkWidget
*ctree
,
2689 GdkEventButton
*event
,
2692 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook
.ctree
), addrbook
.opened
);
2696 static void addressbook_new_folder_cb(GtkAction
*action
, gpointer data
)
2698 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2699 AddressObject
*obj
= NULL
;
2700 AddressDataSource
*ds
= NULL
;
2701 AddressBookFile
*abf
= NULL
;
2702 ItemFolder
*parentFolder
= NULL
;
2703 ItemFolder
*folder
= NULL
;
2705 if( ! addrbook
.treeSelected
) return;
2706 obj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
2707 if( obj
== NULL
) return;
2708 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2709 if( ds
== NULL
) return;
2711 if( obj
->type
== ADDR_DATASOURCE
) {
2712 if( ADAPTER_DSOURCE(obj
)->subType
!= ADDR_BOOK
) return;
2714 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
2715 parentFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
2721 abf
= ds
->rawDataSource
;
2722 if( abf
== NULL
) return;
2723 folder
= addressbook_edit_folder( abf
, parentFolder
, NULL
);
2726 nn
= addressbook_node_add_folder(
2727 addrbook
.treeSelected
, ds
, folder
, ADDR_ITEM_FOLDER
);
2729 g_message("error adding addressbook folder\n");
2731 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2732 if( addrbook
.treeSelected
== addrbook
.opened
)
2733 addressbook_set_clist(obj
, TRUE
);
2737 static void addressbook_new_group_cb(GtkAction
*action
, gpointer data
)
2739 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2740 AddressObject
*obj
= NULL
;
2741 AddressDataSource
*ds
= NULL
;
2742 AddressBookFile
*abf
= NULL
;
2743 ItemFolder
*parentFolder
= NULL
;
2744 ItemGroup
*group
= NULL
;
2746 if( ! addrbook
.treeSelected
) return;
2747 obj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.treeSelected
);
2748 if( obj
== NULL
) return;
2749 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2750 if( ds
== NULL
) return;
2752 if( obj
->type
== ADDR_DATASOURCE
) {
2753 if( ADAPTER_DSOURCE(obj
)->subType
!= ADDR_BOOK
) return;
2755 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
2756 parentFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
2762 abf
= ds
->rawDataSource
;
2763 if( abf
== NULL
) return;
2764 group
= addressbook_edit_group( abf
, parentFolder
, NULL
);
2767 nn
= addressbook_node_add_group( addrbook
.treeSelected
, ds
, group
);
2769 g_message("error adding addressbook group\n");
2771 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2772 if( addrbook
.treeSelected
== addrbook
.opened
)
2773 addressbook_set_clist(obj
, TRUE
);
2777 static void addressbook_change_node_name(GtkCMCTreeNode
*node
, const gchar
*name
)
2779 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2782 GdkPixbuf
*pix_cl
, *pix_op
;
2783 gboolean is_leaf
, expanded
;
2785 gtk_cmctree_get_node_info(ctree
, node
, text
, &spacing
,
2787 &is_leaf
, &expanded
);
2788 gtk_cmctree_set_node_info(ctree
, node
, name
, spacing
,
2795 * \param obj Address object to edit.
2796 * \param node Node in tree.
2797 * \return New name of data source.
2799 static gchar
*addressbook_edit_datasource( AddressObject
*obj
, GtkCMCTreeNode
*node
) {
2800 gchar
*newName
= NULL
;
2801 AddressDataSource
*ds
= NULL
;
2802 AddressInterface
*iface
= NULL
;
2803 AdapterDSource
*ads
= NULL
;
2805 ds
= addressbook_find_datasource( node
);
2806 if( ds
== NULL
) return NULL
;
2807 iface
= ds
->interface
;
2808 if( ! iface
->haveLibrary
) return NULL
;
2810 /* Read data from data source */
2811 if( addrindex_ds_get_modify_flag( ds
) ) {
2812 addrindex_ds_read_data( ds
);
2815 if( ! addrindex_ds_get_read_flag( ds
) ) {
2816 addrindex_ds_read_data( ds
);
2820 ads
= ADAPTER_DSOURCE(obj
);
2821 if( ads
->subType
== ADDR_BOOK
) {
2822 if( addressbook_edit_book( _addressIndex_
, ads
) == NULL
) return NULL
;
2824 else if( ads
->subType
== ADDR_VCARD
) {
2825 if( addressbook_edit_vcard( _addressIndex_
, ads
) == NULL
) return NULL
;
2828 else if( ads
->subType
== ADDR_JPILOT
) {
2829 if( addressbook_edit_jpilot( _addressIndex_
, ads
) == NULL
) return NULL
;
2833 else if( ads
->subType
== ADDR_LDAP
) {
2834 if( addressbook_edit_ldap( _addressIndex_
, ads
) == NULL
) return NULL
;
2840 newName
= obj
->name
;
2845 * Edit an object that is in the address tree area.
2847 static void addressbook_treenode_edit_cb(GtkAction
*action
, gpointer data
)
2849 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2851 AddressDataSource
*ds
= NULL
;
2852 AddressBookFile
*abf
= NULL
;
2853 GtkCMCTreeNode
*node
= NULL
, *parentNode
= NULL
;
2856 if( ! addrbook
.treeSelected
) return;
2857 node
= addrbook
.treeSelected
;
2858 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
2859 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2860 if( obj
== NULL
) return;
2861 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
2863 ds
= addressbook_find_datasource( node
);
2864 if( ds
== NULL
) return;
2866 if( obj
->type
== ADDR_DATASOURCE
) {
2867 name
= addressbook_edit_datasource( obj
, node
);
2868 if( name
== NULL
) return;
2871 abf
= ds
->rawDataSource
;
2872 if( abf
== NULL
) return;
2873 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2874 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
2875 ItemFolder
*item
= adapter
->itemFolder
;
2876 ItemFolder
*parentFolder
= NULL
;
2877 parentFolder
= ( ItemFolder
* ) ADDRITEM_PARENT(item
);
2878 if( addressbook_edit_folder( abf
, parentFolder
, item
) == NULL
) return;
2879 name
= ADDRITEM_NAME(item
);
2881 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2882 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
2883 ItemGroup
*item
= adapter
->itemGroup
;
2884 ItemFolder
*parentFolder
= NULL
;
2885 parentFolder
= ( ItemFolder
* ) ADDRITEM_PARENT(item
);
2886 if( addressbook_edit_group( abf
, parentFolder
, item
) == NULL
) return;
2887 name
= ADDRITEM_NAME(item
);
2890 if( name
&& parentNode
) {
2891 /* Update node in tree view */
2892 addressbook_change_node_name( node
, name
);
2893 gtk_sctree_sort_node(ctree
, parentNode
);
2894 gtk_cmctree_expand( ctree
, node
);
2895 gtk_sctree_select( GTK_SCTREE( ctree
), node
);
2902 ADDRTREE_DEL_FOLDER_ONLY
,
2903 ADDRTREE_DEL_FOLDER_ADDR
2907 * Delete an item from the tree widget.
2908 * \param data Data passed in.
2909 * \param action Action.
2910 * \param widget Widget issuing callback.
2912 static void addressbook_treenode_delete_cb(GtkAction
*action
, gpointer data
)
2914 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2915 GtkCMCTreeNode
*node
= NULL
;
2919 AddrBookBase
*adbase
;
2920 AddressCache
*cache
;
2921 AdapterDSource
*ads
= NULL
;
2922 AddressInterface
*iface
= NULL
;
2923 AddressDataSource
*ds
= NULL
;
2924 gboolean remFlag
= FALSE
;
2925 TreeItemDelType delType
;
2927 if( ! addrbook
.treeSelected
) return;
2928 node
= addrbook
.treeSelected
;
2929 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
2931 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2932 cm_return_if_fail(obj
!= NULL
);
2934 if( obj
->type
== ADDR_DATASOURCE
) {
2935 ads
= ADAPTER_DSOURCE(obj
);
2937 ds
= ads
->dataSource
;
2938 if( ds
== NULL
) return;
2941 /* Must be folder or something else */
2942 ds
= addressbook_find_datasource( node
);
2943 if( ds
== NULL
) return;
2945 /* Only allow deletion from non-readOnly */
2946 iface
= ds
->interface
;
2947 if( iface
->readOnly
) {
2948 /* Allow deletion of query results */
2949 if( ! iface
->externalQuery
) return;
2953 /* Confirm deletion */
2954 delType
= ADDRTREE_DEL_NONE
;
2955 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2956 if( iface
&& iface
->externalQuery
) {
2957 message
= g_strdup_printf( _(
2958 "Do you want to delete the query " \
2959 "results and addresses in '%s'?" ),
2961 aval
= alertpanel( _("Delete"), message
,
2962 NULL
, _("_Cancel"), "edit-delete", _("D_elete"), NULL
, NULL
,
2963 ALERTFOCUS_SECOND
);
2965 if( aval
== G_ALERTALTERNATE
) {
2966 delType
= ADDRTREE_DEL_FOLDER_ADDR
;
2970 message
= g_strdup_printf
2971 ( _( "Do you want to delete '%s'? "
2972 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2974 aval
= alertpanel( _("Delete folder"), message
,
2975 NULL
, _("_Cancel"), "edit-delete", _("Delete _folder only"),
2976 "edit-delete", _("Delete folder and _addresses"), ALERTFOCUS_SECOND
);
2978 if( aval
== G_ALERTALTERNATE
) {
2979 delType
= ADDRTREE_DEL_FOLDER_ONLY
;
2981 else if( aval
== G_ALERTOTHER
) {
2982 delType
= ADDRTREE_DEL_FOLDER_ADDR
;
2986 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2987 message
= g_strdup_printf(_("Do you want to delete '%s'?\n"
2988 "The addresses it contains will not be lost."), obj
->name
);
2989 aval
= alertpanel(_("Delete"), message
, NULL
, _("_Cancel"),
2990 "edit-delete", _("D_elete"), NULL
, NULL
, ALERTFOCUS_SECOND
);
2992 if( aval
== G_ALERTALTERNATE
) delType
= ADDRTREE_DEL_FOLDER_ONLY
;
2994 message
= g_strdup_printf(_("Do you want to delete '%s'?\n"
2995 "The addresses it contains will be lost."), obj
->name
);
2996 aval
= alertpanel(_("Delete"), message
, NULL
, _("_Cancel"),
2997 "edit-delete", _("D_elete"), NULL
, NULL
, ALERTFOCUS_SECOND
);
2999 if( aval
== G_ALERTALTERNATE
) delType
= ADDRTREE_DEL_DATA
;
3001 if( delType
== ADDRTREE_DEL_NONE
) return;
3003 /* Proceed with deletion */
3004 if( obj
->type
== ADDR_DATASOURCE
) {
3005 /* Remove node from tree */
3006 gtk_cmctree_remove_node( ctree
, node
);
3008 if (delType
== ADDRTREE_DEL_DATA
&&
3009 ds
->interface
&& ds
->interface
->type
== ADDR_IF_BOOK
)
3010 addrbook_delete_book_file((AddressBookFile
*) ds
->rawDataSource
);
3012 /* Remove data source. */
3013 if( addrindex_index_remove_datasource( _addressIndex_
, ds
) ) {
3014 addrindex_free_datasource( ds
);
3019 /* Get reference to cache */
3020 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
3021 if( adbase
== NULL
) return;
3022 cache
= adbase
->addressCache
;
3024 /* Remove query results folder */
3025 if( iface
&& iface
->externalQuery
) {
3026 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
3027 ItemFolder
*folder
= adapter
->itemFolder
;
3029 adapter
->itemFolder
= NULL
;
3031 g_print( "remove folder for ::%s::\n", obj->name );
3032 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3033 g_print( "-------------- remove results\n" );
3035 addrindex_remove_results( ds
, folder
);
3036 /* g_print( "-------------- remove node\n" ); */
3037 gtk_cmctree_remove_node( ctree
, node
);
3041 /* Code below is valid for regular address book deletion */
3042 if( obj
->type
== ADDR_ITEM_FOLDER
) {
3043 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
3044 ItemFolder
*item
= adapter
->itemFolder
;
3046 if( delType
== ADDRTREE_DEL_FOLDER_ONLY
) {
3047 /* Remove folder only */
3048 item
= addrcache_remove_folder( cache
, item
);
3050 addritem_free_item_folder( item
);
3051 addressbook_move_nodes_up( ctree
, node
);
3055 else if( delType
== ADDRTREE_DEL_FOLDER_ADDR
) {
3056 /* Remove folder and addresses */
3057 item
= addrcache_remove_folder_delete( cache
, item
);
3059 addritem_free_item_folder( item
);
3064 else if( obj
->type
== ADDR_ITEM_GROUP
) {
3065 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
3066 ItemGroup
*item
= adapter
->itemGroup
;
3068 item
= addrcache_remove_group( cache
, item
);
3070 addritem_free_item_group( item
);
3077 gtk_cmctree_remove_node(ctree
, node
);
3081 static void addressbook_new_address_from_book_post_cb( ItemPerson
*person
)
3083 if( person
&& addrbook
.treeSelected
== addrbook
.opened
) {
3084 person
->status
= ADD_ENTRY
;
3085 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook
.clist
) );
3086 addressbook_folder_refresh_one_person(
3087 GTK_CMCTREE(addrbook
.clist
), person
);
3089 addressbook_address_list_set_focus();
3092 static void addressbook_new_address_from_folder_post_cb( ItemPerson
*person
)
3094 if( person
&& addrbook
.treeSelected
== addrbook
.opened
) {
3095 person
->status
= ADD_ENTRY
;
3096 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), addrbook
.opened
);
3097 addressbook_set_clist(
3098 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3102 addressbook_address_list_set_focus();
3106 * Label (a format string) that is used to name each folder.
3108 static gchar
*_queryFolderLabel_
= N_( "Search '%s'" );
3111 * Search ctree widget callback function.
3112 * \param pA Pointer to node.
3113 * \param pB Pointer to data item being sought.
3114 * \return Zero (0) if folder found.
3116 static int addressbook_treenode_find_folder_cb( gconstpointer pA
, gconstpointer pB
) {
3119 aoA
= ( AddressObject
* ) pA
;
3120 if( aoA
->type
== ADDR_ITEM_FOLDER
) {
3121 ItemFolder
*folder
, *fld
;
3123 fld
= ADAPTER_FOLDER(aoA
)->itemFolder
;
3124 folder
= ( ItemFolder
* ) pB
;
3125 if( fld
== folder
) return 0; /* Found folder */
3130 static ItemFolder
* addressbook_setup_subf(
3131 AddressDataSource
*ds
, gchar
*title
,
3132 GtkCMCTreeNode
*pNode
)
3134 AddrBookBase
*adbase
;
3135 AddressCache
*cache
;
3138 GtkCMCTreeNode
*nNode
;
3140 AddressObjectType aoType
= ADDR_NONE
;
3143 if( *title
== '\0' || strlen( title
) < 1 ) return NULL
;
3145 if( ds
&& ds
->type
== ADDR_IF_LDAP
) {
3147 aoType
= ADDR_LDAP_QUERY
;
3154 ctree
= GTK_CMCTREE(addrbook
.ctree
);
3155 /* Get reference to address cache */
3156 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
3157 cache
= adbase
->addressCache
;
3159 if ((children
= addrcache_get_list_folder(cache
)) != NULL
) {
3160 GList
*cur
= children
;
3161 for (; cur
; cur
= cur
->next
) {
3162 ItemFolder
*child
= (ItemFolder
*) cur
->data
;
3163 if (!g_strcmp0(ADDRITEM_NAME(child
), title
)) {
3164 nNode
= gtk_cmctree_find_by_row_data_custom(
3166 addressbook_treenode_find_folder_cb
);
3168 addrindex_remove_results( ds
, child
);
3169 while( child
->listPerson
) {
3170 ItemPerson
*item
= ( ItemPerson
* ) child
->listPerson
->data
;
3171 item
= addrcache_remove_person( cache
, item
);
3173 addritem_free_item_person( item
);
3177 gtk_sctree_select( GTK_SCTREE(ctree
), nNode
);
3178 addrbook
.treeSelected
= nNode
;
3185 /* Create a folder */
3186 folder
= addrcache_add_new_folder( cache
, NULL
);
3187 name
= g_strdup_printf( "%s", title
);
3188 addritem_folder_set_name( folder
, name
);
3189 addritem_folder_set_remarks( folder
, "" );
3192 /* Now let's see the folder */
3193 nNode
= addressbook_node_add_folder( pNode
, ds
, folder
, aoType
);
3194 gtk_cmctree_expand( ctree
, pNode
);
3196 gtk_sctree_select( GTK_SCTREE(ctree
), nNode
);
3197 addrbook
.treeSelected
= nNode
;
3203 static void addressbook_new_address_cb( GtkAction
*action
, gpointer data
) {
3204 AddressObject
*pobj
= NULL
;
3205 AddressDataSource
*ds
= NULL
;
3206 AddressBookFile
*abf
= NULL
;
3207 debug_print("adding address\n");
3208 pobj
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
3209 if( pobj
== NULL
) {
3210 debug_print("no row data\n");
3213 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3215 debug_print("no datasource\n");
3219 abf
= ds
->rawDataSource
;
3221 g_print("no addressbook file\n");
3225 if( pobj
->type
== ADDR_DATASOURCE
) {
3226 if (ADAPTER_DSOURCE(pobj
)->subType
== ADDR_BOOK
||
3227 ADAPTER_DSOURCE(pobj
)->subType
== ADDR_LDAP
) {
3229 ItemFolder
*folder
= NULL
;
3231 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3232 GtkCMCTreeNode
*parentNode
;
3233 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook
.treeSelected
) );
3234 if( ds
== NULL
) return;
3236 /* We must have a datasource that is an external interface */
3237 if( ! ds
->interface
->haveLibrary
) return;
3238 if( ! ds
->interface
->externalQuery
) return;
3240 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3241 parentNode
= GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook
.treeSelected
) )->parent
;
3244 parentNode
= GTK_CMCTREE_NODE( addrbook
.treeSelected
);
3246 folder
= addressbook_setup_subf( ds
, _("New Contacts"), parentNode
);
3248 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3250 abf
= ds
->rawDataSource
;
3253 person
= addressbook_edit_person( abf
, folder
, NULL
, FALSE
,
3254 addrbook
.editaddress_vbox
,
3255 addressbook_new_address_from_book_post_cb
,
3258 if (ds
&& abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3259 LdapServer
*server
= ds
->rawDataSource
;
3260 ldapsvr_set_modified(server
, TRUE
);
3261 ldapsvr_update_book(server
, NULL
);
3262 if (server
->retVal
!= LDAPRC_SUCCESS
) {
3263 alertpanel( _("Add address(es)"),
3264 addressbook_err2string(_lutErrorsLDAP_
, server
->retVal
),
3265 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
3267 server
->retVal
= LDAPRC_SUCCESS
;
3272 if (prefs_common
.addressbook_use_editaddress_dialog
)
3273 addressbook_new_address_from_book_post_cb( person
);
3276 else if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3278 ItemFolder
*folder
= ADAPTER_FOLDER(pobj
)->itemFolder
;
3281 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3282 GtkCMCTreeNode
*parentNode
;
3283 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook
.treeSelected
) );
3284 if( ds
== NULL
) return;
3286 /* We must have a datasource that is an external interface */
3287 if( ! ds
->interface
->haveLibrary
) return;
3288 if( ! ds
->interface
->externalQuery
) return;
3290 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3291 parentNode
= GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook
.treeSelected
) )->parent
;
3294 parentNode
= GTK_CMCTREE_NODE( addrbook
.treeSelected
);
3296 folder
= addressbook_setup_subf( ds
, _("New Contacts"), parentNode
);
3300 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3302 abf
= ds
->rawDataSource
;
3305 person
= addressbook_edit_person( abf
, folder
, NULL
, FALSE
,
3306 addrbook
.editaddress_vbox
,
3307 addressbook_new_address_from_folder_post_cb
,
3310 if (ds
&& abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3311 LdapServer
*server
= ds
->rawDataSource
;
3312 ldapsvr_set_modified(server
, TRUE
);
3313 ldapsvr_update_book(server
, NULL
);
3314 if (server
->retVal
!= LDAPRC_SUCCESS
) {
3315 alertpanel( _("Add address(es)"),
3316 addressbook_err2string(_lutErrorsLDAP_
, server
->retVal
),
3317 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
, ALERTFOCUS_FIRST
);
3322 if (prefs_common
.addressbook_use_editaddress_dialog
)
3323 addressbook_new_address_from_folder_post_cb( person
);
3325 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
3326 /* New address in group */
3327 ItemGroup
*group
= ADAPTER_GROUP(pobj
)->itemGroup
;
3328 if( addressbook_edit_group( abf
, NULL
, group
) == NULL
) return;
3329 if (addrbook
.treeSelected
== addrbook
.opened
) {
3330 /* Change node name in tree. */
3331 addressbook_change_node_name( addrbook
.treeSelected
, ADDRITEM_NAME(group
) );
3332 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), addrbook
.opened
);
3333 addressbook_set_clist(
3334 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3342 * Search for specified child group node in address index tree.
3343 * \param parent Parent node.
3344 * \param group Group to find.
3346 static GtkCMCTreeNode
*addressbook_find_group_node( GtkCMCTreeNode
*parent
, ItemGroup
*group
) {
3347 GtkCMCTreeNode
*node
= NULL
;
3348 GtkCMCTreeRow
*currRow
;
3350 currRow
= GTK_CMCTREE_ROW( parent
);
3352 node
= currRow
->children
;
3356 obj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), node
);
3357 if(obj
&& obj
->type
== ADDR_ITEM_GROUP
) {
3358 ItemGroup
*g
= ADAPTER_GROUP(obj
)->itemGroup
;
3359 if( g
== group
) return node
;
3361 currRow
= GTK_CMCTREE_ROW(node
);
3362 node
= currRow
->sibling
;
3368 static AddressBookFile
*addressbook_get_book_file() {
3369 AddressBookFile
*abf
= NULL
;
3370 AddressDataSource
*ds
= NULL
;
3372 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
3373 if( ds
== NULL
) return NULL
;
3374 if( ds
->type
== ADDR_IF_BOOK
|| ds
->type
== ADDR_IF_LDAP
) abf
= ds
->rawDataSource
;
3378 static void addressbook_tree_remove_children( GtkCMCTree
*ctree
, GtkCMCTreeNode
*parent
) {
3379 GtkCMCTreeNode
*node
;
3382 /* Remove existing folders and groups */
3383 row
= GTK_CMCTREE_ROW( parent
);
3385 while( (node
= row
->children
) ) {
3386 gtk_cmctree_remove_node( ctree
, node
);
3391 static void addressbook_move_nodes_up( GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
) {
3392 GtkCMCTreeNode
*parent
, *child
;
3393 GtkCMCTreeRow
*currRow
;
3394 currRow
= GTK_CMCTREE_ROW( node
);
3396 parent
= currRow
->parent
;
3397 while( (child
= currRow
->children
) ) {
3398 gtk_cmctree_move( ctree
, child
, parent
, node
);
3400 gtk_sctree_sort_node( ctree
, parent
);
3404 static void addressbook_edit_address_post_cb( ItemPerson
*person
)
3408 AddressBookFile
*abf
= addressbook_get_book_file();
3410 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3411 if (g_strcmp0(person
->nickName
, ADDRITEM_NAME(person
)))
3412 addritem_person_set_nick_name( person
, ADDRITEM_NAME(person
));
3415 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook
.clist
), person
);
3416 invalidate_address_completion();
3418 addressbook_address_list_set_focus();
3421 void addressbook_address_list_set_focus( void )
3423 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
3424 gtk_window_set_focus(GTK_WINDOW(addrbook
.window
), addrbook
.clist
);
3425 addressbook_list_menu_setup();
3429 void addressbook_address_list_disable_some_actions(void)
3431 /* disable address copy/pasting when editing contact's detail (embedded form) */
3432 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", FALSE
);
3433 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", FALSE
);
3434 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", FALSE
);
3437 static void addressbook_edit_address_cb( GtkAction
*action
, gpointer data
) {
3438 addressbook_edit_address(data
, 0, NULL
, TRUE
);
3441 static void addressbook_edit_address( gpointer data
, guint action
, GtkWidget
*widget
,
3442 gboolean force_focus
) {
3443 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
3445 AddressObject
*obj
= NULL
, *pobj
= NULL
;
3446 AddressDataSource
*ds
= NULL
;
3447 GtkCMCTreeNode
*node
= NULL
, *parentNode
= NULL
;
3449 AddressBookFile
*abf
= NULL
;
3451 if( addrbook
.listSelected
== NULL
) return;
3452 obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
3453 cm_return_if_fail(obj
!= NULL
);
3455 ctree
= GTK_CMCTREE( addrbook
.ctree
);
3456 pobj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
3458 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3459 if( ds
== NULL
) return;
3461 abf
= addressbook_get_book_file();
3463 if( obj
->type
== ADDR_ITEM_EMAIL
) {
3464 ItemEMail
*email
= ( ItemEMail
* ) obj
;
3466 if( pobj
&& pobj
->type
== ADDR_ITEM_GROUP
) {
3467 /* Edit parent group */
3468 AdapterGroup
*adapter
= ADAPTER_GROUP(pobj
);
3469 ItemGroup
*itemGrp
= adapter
->itemGroup
;
3470 if( abf
== NULL
) return;
3471 if( addressbook_edit_group( abf
, NULL
, itemGrp
) == NULL
) return;
3472 name
= ADDRITEM_NAME(itemGrp
);
3473 node
= addrbook
.treeSelected
;
3474 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
3477 /* Edit person - email page */
3479 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
3480 if ( addressbook_edit_person( abf
, NULL
, person
, TRUE
, addrbook
.editaddress_vbox
,
3481 addressbook_edit_address_post_cb
,
3482 (prefs_common
.addressbook_use_editaddress_dialog
||force_focus
) )
3485 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3486 ldapsvr_set_modified( (LdapServer
*) abf
, TRUE
);
3487 person
->status
= UPDATE_ENTRY
;
3490 if (prefs_common
.addressbook_use_editaddress_dialog
)
3491 addressbook_edit_address_post_cb( person
);
3496 else if( obj
->type
== ADDR_ITEM_PERSON
) {
3497 /* Edit person - basic page */
3498 ItemPerson
*person
= ( ItemPerson
* ) obj
;
3499 if( addressbook_edit_person( abf
, NULL
, person
, FALSE
, addrbook
.editaddress_vbox
,
3500 addressbook_edit_address_post_cb
,
3501 (prefs_common
.addressbook_use_editaddress_dialog
||force_focus
) )
3504 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3505 ldapsvr_set_modified( (LdapServer
*) abf
, TRUE
);
3506 person
->status
= UPDATE_ENTRY
;
3509 if (prefs_common
.addressbook_use_editaddress_dialog
)
3510 addressbook_edit_address_post_cb( person
);
3514 else if( obj
->type
== ADDR_ITEM_GROUP
) {
3515 ItemGroup
*itemGrp
= ( ItemGroup
* ) obj
;
3516 if( addressbook_edit_group( abf
, NULL
, itemGrp
) == NULL
) return;
3517 parentNode
= addrbook
.treeSelected
;
3518 node
= addressbook_find_group_node( parentNode
, itemGrp
);
3519 name
= ADDRITEM_NAME(itemGrp
);
3520 invalidate_address_completion();
3526 /* Update tree node with node name */
3527 if( node
== NULL
) return;
3528 addressbook_change_node_name( node
, name
);
3529 gtk_sctree_sort_node( ctree
, parentNode
);
3530 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
3531 addressbook_set_clist(
3532 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3537 static void addressbook_delete_address_cb(GtkAction
*action
, gpointer data
)
3539 addressbook_del_clicked(NULL
, NULL
);
3542 static void close_cb(GtkAction
*action
, gpointer data
)
3544 addressbook_close();
3547 static void addressbook_file_save_cb( GtkAction
*action
, gpointer data
) {
3548 addressbook_export_to_file();
3551 static void addressbook_person_expand_node( GtkCMCTree
*ctree
, GList
*node
, gpointer
*data
) {
3553 ItemPerson
*person
= gtk_cmctree_node_get_row_data( ctree
, GTK_CMCTREE_NODE(node
) );
3554 if( person
) addritem_person_set_opened( person
, TRUE
);
3558 static void addressbook_person_collapse_node( GtkCMCTree
*ctree
, GList
*node
, gpointer
*data
) {
3560 ItemPerson
*person
= gtk_cmctree_node_get_row_data( ctree
, GTK_CMCTREE_NODE(node
) );
3561 if( person
) addritem_person_set_opened( person
, FALSE
);
3565 static gchar
*addressbook_format_item_clist( ItemPerson
*person
, ItemEMail
*email
) {
3567 gchar
*eMailAlias
= ADDRITEM_NAME(email
);
3568 if( eMailAlias
&& *eMailAlias
!= '\0' ) {
3570 str
= g_strdup_printf( "%s - %s", ADDRITEM_NAME(person
), eMailAlias
);
3573 str
= g_strdup( eMailAlias
);
3579 static gboolean
addressbook_match_item(const gchar
*name
,
3580 const gchar
*email_alias
,
3582 const gchar
*remarks
,
3587 if (!str
|| str
[0] == '\0')
3589 if (strcasestr(name
, str
))
3591 else if (email_alias
&& strcasestr(email_alias
, str
))
3593 else if (addr
&& strcasestr(addr
, str
))
3595 else if (remarks
&& strcasestr(remarks
, str
))
3601 static void addressbook_load_group( GtkCMCTree
*clist
, ItemGroup
*itemGroup
) {
3602 GList
*items
= itemGroup
->listEMail
;
3603 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3604 const gchar
*search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3605 for( ; items
!= NULL
; items
= g_list_next( items
) ) {
3606 GtkCMCTreeNode
*nodeEMail
= NULL
;
3607 gchar
*text
[N_LIST_COLS
];
3608 ItemEMail
*email
= items
->data
;
3612 if( ! email
) continue;
3614 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
3616 if( !addressbook_match_item(ADDRITEM_NAME(person
),
3617 ADDRITEM_NAME(email
),
3618 email
->address
, email
->remarks
,
3622 str
= addressbook_format_item_clist( person
, email
);
3624 text
[COL_NAME
] = addressbook_set_col_name_guard(str
);
3627 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3629 text
[COL_ADDRESS
] = email
->address
;
3630 text
[COL_REMARKS
] = email
->remarks
;
3631 nodeEMail
= gtk_sctree_insert_node(
3633 text
, FOLDER_SPACING
,
3637 gtk_cmctree_node_set_row_data( clist
, nodeEMail
, email
);
3643 gchar
*addressbook_set_col_name_guard(gchar
*value
)
3645 gchar
*ret
= "<not set>";
3646 gchar
*tmp
= g_strdup(value
);
3656 static void addressbook_folder_load_one_person(
3657 GtkCMCTree
*clist
, ItemPerson
*person
,
3658 AddressTypeControlItem
*atci
,
3659 AddressTypeControlItem
*atciMail
)
3661 GtkCMCTreeNode
*nodePerson
= NULL
;
3662 GtkCMCTreeNode
*nodeEMail
= NULL
;
3663 gchar
*text
[N_LIST_COLS
];
3664 gboolean flgFirst
= TRUE
, haveAddr
= FALSE
;
3667 AddressBookFile
*abf
= addressbook_get_book_file();
3670 if( person
== NULL
) return;
3672 text
[COL_NAME
] = "";
3673 node
= person
->listEMail
;
3675 ItemEMail
*email
= node
->data
;
3676 gchar
*eMailAddr
= NULL
;
3677 node
= g_list_next( node
);
3679 text
[COL_ADDRESS
] = email
->address
;
3680 text
[COL_REMARKS
] = email
->remarks
;
3681 eMailAddr
= ADDRITEM_NAME(email
);
3682 if( eMailAddr
&& *eMailAddr
== '\0' ) eMailAddr
= NULL
;
3684 /* First email belongs with person */
3685 gchar
*str
= addressbook_format_item_clist( person
, email
);
3687 text
[COL_NAME
] = addressbook_set_col_name_guard(str
);
3690 else if( abf
&& abf
->type
== ADBOOKTYPE_LDAP
&&
3691 person
&& person
->nickName
) {
3692 if (person
->nickName
) {
3693 if (strcmp(person
->nickName
, "") != 0) {
3694 text
[COL_NAME
] = addressbook_set_col_name_guard(person
->nickName
);
3697 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3703 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3705 nodePerson
= gtk_sctree_insert_node(
3707 text
, FOLDER_SPACING
,
3710 FALSE
, person
->isOpened
);
3713 gtk_cmctree_node_set_row_data(clist
, nodePerson
, person
);
3716 /* Subsequent email is a child node of person */
3717 text
[COL_NAME
] = ADDRITEM_NAME(email
);
3718 nodeEMail
= gtk_sctree_insert_node(
3719 clist
, nodePerson
, NULL
,
3720 text
, FOLDER_SPACING
,
3722 atciMail
->iconXpmOpen
,
3724 gtk_cmctree_node_set_row_data(clist
, nodeEMail
, email
);
3730 /* Have name without EMail */
3731 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3732 text
[COL_ADDRESS
] = "";
3733 text
[COL_REMARKS
] = "";
3734 nodePerson
= gtk_sctree_insert_node(
3736 text
, FOLDER_SPACING
,
3739 FALSE
, person
->isOpened
);
3740 gtk_cmctree_node_set_row_data(clist
, nodePerson
, person
);
3745 static void addressbook_folder_load_person( GtkCMCTree
*clist
, ItemFolder
*itemFolder
) {
3747 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_PERSON
);
3748 AddressTypeControlItem
*atciMail
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3749 const gchar
*search_str
;
3751 if( atci
== NULL
) return;
3752 if( atciMail
== NULL
) return;
3754 search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3756 /* Load email addresses */
3757 items
= addritem_folder_get_person_list( itemFolder
);
3758 for(cur
= items
; cur
!= NULL
; cur
= g_list_next( cur
) ) {
3763 person
= (ItemPerson
*)cur
->data
;
3766 node
= person
->listEMail
;
3767 if (node
&& node
->data
) {
3769 if (!addressbook_match_item(ADDRITEM_NAME(person
), ADDRITEM_NAME(email
), email
->address
, email
->remarks
, search_str
))
3772 if (!addressbook_match_item(ADDRITEM_NAME(person
), NULL
, NULL
, NULL
, search_str
))
3776 addressbook_folder_load_one_person( clist
, cur
->data
, atci
, atciMail
);
3778 /* Free up the list */
3779 g_list_free( items
);
3782 static void addressbook_folder_remove_node( GtkCMCTree
*clist
, GtkCMCTreeNode
*node
) {
3783 addrbook
.listSelected
= NULL
;
3784 gtk_cmctree_remove_node( clist
, node
);
3785 addressbook_menubar_set_sensitive( FALSE
);
3786 addressbook_menuitem_set_sensitive(
3787 gtk_cmctree_node_get_row_data(
3788 GTK_CMCTREE(clist
), addrbook
.treeSelected
),
3789 addrbook
.treeSelected
);
3792 void addressbook_folder_refresh_one_person( GtkCMCTree
*clist
, ItemPerson
*person
) {
3793 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_PERSON
);
3794 AddressTypeControlItem
*atciMail
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3795 GtkCMCTreeNode
*node
;
3796 if( atci
== NULL
) return;
3797 if( atciMail
== NULL
) return;
3798 if( person
== NULL
) return;
3799 /* unload the person */
3801 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3803 addressbook_folder_remove_node( clist
, node
);
3804 addressbook_folder_load_one_person( clist
, person
, atci
, atciMail
);
3805 gtk_sctree_sort_node( clist
, NULL
);
3806 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3808 gtk_sctree_select( GTK_SCTREE(clist
), node
);
3809 if (!gtk_cmctree_node_is_visible( clist
, node
) )
3810 gtk_cmctree_node_moveto( clist
, node
, 0, 0, 0 );
3814 void addressbook_folder_remove_one_person( GtkCMCTree
*clist
, ItemPerson
*person
) {
3815 GtkCMCTreeNode
*node
;
3817 if( person
== NULL
) return;
3818 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3820 addressbook_folder_remove_node( clist
, node
);
3824 static void addressbook_folder_load_group( GtkCMCTree
*clist
, ItemFolder
*itemFolder
) {
3826 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_GROUP
);
3827 const gchar
*search_str
;
3829 /* Load any groups */
3830 if( ! atci
) return;
3832 search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3834 items
= addritem_folder_get_group_list( itemFolder
);
3835 for( ; items
!= NULL
; items
= g_list_next( items
) ) {
3836 GtkCMCTreeNode
*nodeGroup
= NULL
;
3837 gchar
*text
[N_LIST_COLS
];
3838 ItemGroup
*group
= items
->data
;
3839 if( group
== NULL
) continue;
3840 if( !addressbook_match_item(ADDRITEM_NAME(group
),
3841 NULL
, NULL
, NULL
, search_str
) )
3844 text
[COL_NAME
] = ADDRITEM_NAME(group
);
3845 text
[COL_ADDRESS
] = "";
3846 text
[COL_REMARKS
] = "";
3847 nodeGroup
= gtk_sctree_insert_node(clist
, NULL
, NULL
,
3848 text
, FOLDER_SPACING
,
3852 gtk_cmctree_node_set_row_data(clist
, nodeGroup
, group
);
3853 gtk_sctree_sort_node(clist
, NULL
);
3855 /* Free up the list */
3856 g_list_free( items
);
3860 * Search ctree widget callback function.
3861 * \param pA Pointer to node.
3862 * \param pB Pointer to data item being sought.
3863 * \return Zero (0) if group found.
3865 static int addressbook_treenode_find_group_cb( gconstpointer pA
, gconstpointer pB
) {
3868 aoA
= ( AddressObject
* ) pA
;
3869 if( aoA
->type
== ADDR_ITEM_GROUP
) {
3870 ItemGroup
*group
, *grp
;
3872 grp
= ADAPTER_GROUP(aoA
)->itemGroup
;
3873 group
= ( ItemGroup
* ) pB
;
3874 if( grp
== group
) return 0; /* Found group */
3880 * Remove folder and group nodes from tree widget for items contained ("cut")
3883 static void addressbook_treenode_remove_item( void ) {
3885 AddrSelectItem
*cutItem
;
3886 AddressCache
*cache
;
3887 AddrItemObject
*aio
;
3888 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
3891 node
= _clipBoard_
->objectList
;
3893 cutItem
= node
->data
;
3894 node
= g_list_next( node
);
3895 cache
= addrindex_get_cache(
3896 _clipBoard_
->addressIndex
, cutItem
->cacheID
);
3897 if( cache
== NULL
) continue;
3898 aio
= addrcache_get_object( cache
, cutItem
->uid
);
3901 if( ADDRITEM_TYPE(aio
) == ITEMTYPE_FOLDER
) {
3904 folder
= ( ItemFolder
* ) aio
;
3905 tn
= gtk_cmctree_find_by_row_data_custom(
3906 ctree
, NULL
, folder
,
3907 addressbook_treenode_find_folder_cb
);
3909 else if( ADDRITEM_TYPE(aio
) == ITEMTYPE_GROUP
) {
3912 group
= ( ItemGroup
* ) aio
;
3913 tn
= gtk_cmctree_find_by_row_data_custom(
3915 addressbook_treenode_find_group_cb
);
3919 /* Free up adapter and remove node. */
3920 gtk_cmctree_remove_node( ctree
, tn
);
3927 * Find parent datasource for specified tree node.
3928 * \param node Node to test.
3929 * \return Data source, or NULL if not found.
3931 static AddressDataSource
*addressbook_find_datasource( GtkCMCTreeNode
*node
) {
3932 AddressDataSource
*ds
= NULL
;
3935 cm_return_val_if_fail(addrbook
.ctree
!= NULL
, NULL
);
3938 if( GTK_CMCTREE_ROW(node
)->level
< 2 ) return NULL
;
3939 ao
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), node
);
3941 /* g_print( "ao->type = %d\n", ao->type ); */
3942 if( ao
->type
== ADDR_DATASOURCE
) {
3943 AdapterDSource
*ads
= ADAPTER_DSOURCE(ao
);
3944 /* g_print( "found it\n" ); */
3945 ds
= ads
->dataSource
;
3949 node
= GTK_CMCTREE_ROW(node
)->parent
;
3955 * Load address list widget with children of specified object.
3956 * \param obj Parent object to be loaded.
3958 static void addressbook_set_clist( AddressObject
*obj
, gboolean refresh
) {
3959 GtkCMCTree
*ctreelist
= GTK_CMCTREE(addrbook
.clist
);
3960 GtkCMCList
*clist
= GTK_CMCLIST(addrbook
.clist
);
3961 AddressDataSource
*ds
= NULL
;
3962 AdapterDSource
*ads
= NULL
;
3963 static AddressObject
*last_obj
= NULL
;
3965 if (addrbook
.clist
== NULL
) {
3968 if (obj
== last_obj
&& !refresh
)
3973 gtk_cmclist_clear(clist
);
3977 if( obj
->type
== ADDR_INTERFACE
) {
3978 /* g_print( "set_clist: loading datasource...\n" ); */
3979 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3983 gtk_cmclist_freeze(clist
);
3984 gtk_cmclist_clear(clist
);
3986 if( obj
->type
== ADDR_DATASOURCE
) {
3987 ads
= ADAPTER_DSOURCE(obj
);
3988 ds
= ads
->dataSource
;
3990 /* Load root folder */
3991 ItemFolder
*rootFolder
= NULL
;
3992 rootFolder
= addrindex_ds_get_root_folder( ds
);
3993 addressbook_folder_load_person(
3994 ctreelist
, rootFolder
);
3995 addressbook_folder_load_group(
3996 ctreelist
, rootFolder
);
4000 if( obj
->type
== ADDR_ITEM_GROUP
) {
4002 ItemGroup
*itemGroup
= ADAPTER_GROUP(obj
)->itemGroup
;
4003 addressbook_load_group( ctreelist
, itemGroup
);
4005 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
4007 ItemFolder
*itemFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
4008 addressbook_folder_load_person( ctreelist
, itemFolder
);
4009 addressbook_folder_load_group( ctreelist
, itemFolder
);
4012 gtk_sctree_sort_recursive(GTK_CMCTREE(clist
), NULL
);
4013 clist
->focus_row
= -1;
4014 gtk_cmclist_thaw(clist
);
4018 * Call back function to free adaptor. Call back is setup by function
4019 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4020 * called when the address book tree widget node is removed by calling
4021 * function gtk_cmctree_remove_node().
4023 * \param data Tree node's row data.
4025 static void addressbook_free_treenode( gpointer data
) {
4028 ao
= ( AddressObject
* ) data
;
4029 if( ao
== NULL
) return;
4030 if( ao
->type
== ADDR_INTERFACE
) {
4031 AdapterInterface
*ai
= ADAPTER_INTERFACE(ao
);
4032 addrbookctl_free_interface( ai
);
4034 else if( ao
->type
== ADDR_DATASOURCE
) {
4035 AdapterDSource
*ads
= ADAPTER_DSOURCE(ao
);
4036 addrbookctl_free_datasource( ads
);
4038 else if( ao
->type
== ADDR_ITEM_FOLDER
) {
4039 AdapterFolder
*af
= ADAPTER_FOLDER(ao
);
4040 addrbookctl_free_folder( af
);
4042 else if( ao
->type
== ADDR_ITEM_GROUP
) {
4043 AdapterGroup
*ag
= ADAPTER_GROUP(ao
);
4044 addrbookctl_free_group( ag
);
4049 * Create new adaptor for specified data source.
4051 AdapterDSource
*addressbook_create_ds_adapter( AddressDataSource
*ds
,
4052 AddressObjectType otype
, gchar
*name
)
4054 AdapterDSource
*adapter
= g_new0( AdapterDSource
, 1 );
4055 ADDRESS_OBJECT(adapter
)->type
= ADDR_DATASOURCE
;
4056 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( name
);
4057 adapter
->dataSource
= ds
;
4058 adapter
->subType
= otype
;
4062 void addressbook_ads_set_name( AdapterDSource
*adapter
, gchar
*value
) {
4063 ADDRESS_OBJECT_NAME(adapter
) =
4064 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter
), value
);
4068 * Load tree from address index with the initial data.
4070 static void addressbook_load_tree( void ) {
4071 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
4072 GList
*nodeIf
, *nodeDS
;
4073 AdapterInterface
*adapter
;
4074 AddressInterface
*iface
;
4075 AddressTypeControlItem
*atci
;
4076 AddressDataSource
*ds
;
4077 AdapterDSource
*ads
;
4078 GtkCMCTreeNode
*node
, *newNode
;
4081 nodeIf
= _addressInterfaceList_
;
4083 adapter
= nodeIf
->data
;
4084 node
= adapter
->treeNode
;
4085 iface
= adapter
->interface
;
4086 atci
= adapter
->atci
;
4088 if( iface
->useInterface
) {
4089 /* Load data sources below interface node */
4090 nodeDS
= iface
->listSource
;
4093 name
= addrindex_ds_get_name( ds
);
4094 ads
= addressbook_create_ds_adapter(
4095 ds
, atci
->objectType
, name
);
4096 newNode
= addressbook_add_object(
4097 node
, ADDRESS_OBJECT(ads
) );
4098 if (newNode
== NULL
) {
4099 g_message("error adding addressbook object\n");
4101 nodeDS
= g_list_next( nodeDS
);
4103 gtk_cmctree_expand( ctree
, node
);
4106 nodeIf
= g_list_next( nodeIf
);
4111 * Convert the old address book to new format.
4113 static gboolean
addressbook_convert( AddressIndex
*addrIndex
) {
4114 gboolean retVal
= FALSE
;
4115 gboolean errFlag
= TRUE
;
4118 /* Read old address book, performing conversion */
4119 debug_print( "Reading and converting old address book...\n" );
4120 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_OLD_FILE
);
4121 addrindex_read_data( addrIndex
);
4122 if( addrIndex
->retVal
== MGU_NO_FILE
) {
4123 /* We do not have a file - new user */
4124 debug_print( "New user... create new books...\n" );
4125 addrindex_create_new_books( addrIndex
);
4126 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4127 /* Save index file */
4128 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4129 addrindex_save_data( addrIndex
);
4130 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4135 msg
= _( "New user, could not save index file." );
4139 msg
= _( "New user, could not save address book files." );
4143 /* We have an old file */
4144 if( addrIndex
->wasConverted
) {
4145 /* Converted successfully - save address index */
4146 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4147 addrindex_save_data( addrIndex
);
4148 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4149 msg
= _( "Old address book converted successfully." );
4154 msg
= _("Old address book converted,\n"
4155 "could not save new address index file." );
4159 /* File conversion failed - just create new books */
4160 debug_print( "File conversion failed... just create new books...\n" );
4161 addrindex_create_new_books( addrIndex
);
4162 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4164 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4165 addrindex_save_data( addrIndex
);
4166 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4167 msg
= _("Could not convert address book,\n"
4168 "but created empty new address book files." );
4173 msg
= _("Could not convert address book,\n"
4174 "could not save new address index file." );
4178 msg
= _("Could not convert address book\n"
4179 "and could not create new address book files." );
4184 debug_print( "Error\n%s\n", msg
);
4185 alertpanel_full(_("Addressbook conversion error"), msg
,
4186 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
4187 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_ERROR
);
4189 debug_print( "Warning\n%s\n", msg
);
4190 alertpanel_full(_("Addressbook conversion error"), msg
,
4191 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
4192 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_WARNING
);
4198 static gboolean
migrate_addrbook(const gchar
*origdir
, const gchar
*destdir
)
4202 gboolean failed
= FALSE
;
4203 GError
*error
= NULL
;
4205 if( ( dp
= g_dir_open( origdir
, 0, &error
) ) == NULL
) {
4206 debug_print("opening '%s' failed: %d (%s)\n", origdir
,
4207 error
->code
, error
->message
);
4208 g_error_free(error
);
4212 while( ( d
= g_dir_read_name( dp
) ) != NULL
) {
4213 if (strncmp(d
, "addrbook-", strlen("addrbook-")))
4216 gchar
*orig_file
= g_strconcat(origdir
, G_DIR_SEPARATOR_S
,
4218 gchar
*dest_file
= g_strconcat(destdir
, G_DIR_SEPARATOR_S
,
4220 if (copy_file(orig_file
, dest_file
, FALSE
) < 0) {
4233 /* all copies succeeded, we can remove source files */
4234 if( ( dp
= g_dir_open( origdir
, 0, &error
) ) == NULL
) {
4235 debug_print("opening '%s' failed: %d (%s)\n", origdir
,
4236 error
->code
, error
->message
);
4237 g_error_free(error
);
4240 while( ( d
= g_dir_read_name( dp
) ) != NULL
) {
4241 if (strncmp(d
, "addrbook-", strlen("addrbook-")))
4244 gchar
*orig_file
= g_strconcat(origdir
, G_DIR_SEPARATOR_S
,
4246 claws_unlink(orig_file
);
4256 void addressbook_read_file( void ) {
4257 AddressIndex
*addrIndex
= NULL
;
4258 gchar
*indexdir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, ADDRBOOK_DIR
, NULL
);
4260 debug_print( "Reading address index...\n" );
4261 if( _addressIndex_
) {
4262 debug_print( "address book already read!!!\n" );
4267 addrIndex
= addrindex_create_index();
4268 addrindex_initialize();
4270 /* Use new address book index. */
4272 if ( !is_dir_exist(indexdir
) ) {
4273 if ( make_dir(indexdir
) < 0 ) {
4274 addrindex_set_file_path( addrIndex
, get_rc_dir() );
4275 g_warning("couldn't create dir '%s'", indexdir
);
4277 if (!migrate_addrbook(get_rc_dir(), indexdir
)) {
4278 remove_dir_recursive(indexdir
);
4279 addrindex_set_file_path( addrIndex
, get_rc_dir() );
4280 g_error("couldn't migrate dir %s", indexdir
);
4282 addrindex_set_file_path( addrIndex
, indexdir
);
4286 addrindex_set_file_path( addrIndex
, indexdir
);
4289 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4290 addrindex_read_data( addrIndex
);
4291 if( addrIndex
->retVal
== MGU_NO_FILE
) {
4292 /* Conversion required */
4293 debug_print( "Converting...\n" );
4294 if( addressbook_convert( addrIndex
) ) {
4295 _addressIndex_
= addrIndex
;
4298 else if( addrIndex
->retVal
== MGU_SUCCESS
) {
4299 _addressIndex_
= addrIndex
;
4302 /* Error reading address book */
4303 debug_print( "Could not read address index.\n" );
4304 addrindex_print_index( addrIndex
, stdout
);
4305 alertpanel_full(_("Addressbook Error"),
4306 _("Could not read address index"),
4307 "window-close", _("_Close"), NULL
, NULL
, NULL
, NULL
,
4308 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_ERROR
);
4310 debug_print( "done.\n" );
4314 * Add object into the address index tree widget.
4315 * Enter: node Parent node.
4316 * obj Object to add.
4317 * Return: Node that was added, or NULL if object not added.
4319 static GtkCMCTreeNode
*addressbook_add_object(GtkCMCTreeNode
*node
,
4322 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4323 GtkCMCTreeNode
*added
;
4324 AddressObject
*pobj
;
4325 AddressObjectType otype
;
4326 AddressTypeControlItem
*atci
= NULL
;
4328 cm_return_val_if_fail(node
!= NULL
, NULL
);
4329 cm_return_val_if_fail(obj
!= NULL
, NULL
);
4331 pobj
= gtk_cmctree_node_get_row_data(ctree
, node
);
4332 cm_return_val_if_fail(pobj
!= NULL
, NULL
);
4334 /* Determine object type to be displayed */
4335 if( obj
->type
== ADDR_DATASOURCE
) {
4336 otype
= ADAPTER_DSOURCE(obj
)->subType
;
4342 /* Handle any special conditions. */
4344 atci
= addrbookctl_lookup( otype
);
4346 if( atci
->showInTree
) {
4347 /* Add object to tree */
4350 added
= gtk_sctree_insert_node( ctree
, node
, NULL
, name
, FOLDER_SPACING
,
4351 atci
->iconXpm
, atci
->iconXpmOpen
,
4352 atci
->treeLeaf
, atci
->treeExpand
);
4353 gtk_cmctree_node_set_row_data_full( ctree
, added
, obj
,
4354 addressbook_free_treenode
);
4358 gtk_sctree_sort_node(ctree
, node
);
4364 * Add group into the address index tree.
4365 * \param node Parent node.
4366 * \param ds Data source.
4367 * \param itemGroup Group to add.
4368 * \return Inserted node.
4370 static GtkCMCTreeNode
*addressbook_node_add_group(
4371 GtkCMCTreeNode
*node
, AddressDataSource
*ds
,
4372 ItemGroup
*itemGroup
)
4374 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4375 GtkCMCTreeNode
*newNode
;
4376 AdapterGroup
*adapter
;
4377 AddressTypeControlItem
*atci
= NULL
;
4380 if( ds
== NULL
) return NULL
;
4381 if( node
== NULL
|| itemGroup
== NULL
) return NULL
;
4383 name
= &itemGroup
->obj
.name
;
4385 atci
= addrbookctl_lookup( ADDR_ITEM_GROUP
);
4387 adapter
= g_new0( AdapterGroup
, 1 );
4388 ADDRESS_OBJECT_TYPE(adapter
) = ADDR_ITEM_GROUP
;
4389 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( ADDRITEM_NAME(itemGroup
) );
4390 adapter
->itemGroup
= itemGroup
;
4392 newNode
= gtk_sctree_insert_node( ctree
, node
, NULL
, name
, FOLDER_SPACING
,
4393 atci
->iconXpm
, atci
->iconXpm
,
4394 atci
->treeLeaf
, atci
->treeExpand
);
4395 gtk_cmctree_node_set_row_data_full( ctree
, newNode
, adapter
,
4396 addressbook_free_treenode
);
4397 gtk_sctree_sort_node( ctree
, node
);
4402 * Add folder into the address index tree. Only visible folders are loaded into
4403 * the address index tree. Note that the root folder is not inserted into the
4406 * \param node Parent node.
4407 * \param ds Data source.
4408 * \param itemFolder Folder to add.
4409 * \param otype Object type to display.
4410 * \return Inserted node for the folder.
4412 static GtkCMCTreeNode
*addressbook_node_add_folder(
4413 GtkCMCTreeNode
*node
, AddressDataSource
*ds
,
4414 ItemFolder
*itemFolder
, AddressObjectType otype
)
4416 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4417 GtkCMCTreeNode
*newNode
= NULL
;
4418 AddressTypeControlItem
*atci
= NULL
;
4419 GList
*listItems
= NULL
;
4421 ItemFolder
*rootFolder
;
4423 /* Only visible folders */
4424 if( itemFolder
== NULL
|| itemFolder
->isHidden
)
4429 if( node
== NULL
|| itemFolder
== NULL
)
4432 /* Determine object type */
4433 atci
= addrbookctl_lookup( otype
);
4437 rootFolder
= addrindex_ds_get_root_folder( ds
);
4438 if( itemFolder
== rootFolder
) {
4442 AdapterFolder
*adapter
= g_new0( AdapterFolder
, 1 );
4443 ADDRESS_OBJECT_TYPE(adapter
) = ADDR_ITEM_FOLDER
;
4444 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( ADDRITEM_NAME(itemFolder
) );
4445 adapter
->itemFolder
= itemFolder
;
4447 name
= ADDRITEM_NAME(itemFolder
);
4448 newNode
= gtk_sctree_insert_node( ctree
, node
, NULL
, &name
, FOLDER_SPACING
,
4449 atci
->iconXpm
, atci
->iconXpm
,
4450 atci
->treeLeaf
, atci
->treeExpand
);
4452 gtk_cmctree_node_set_row_data_full( ctree
, newNode
, adapter
,
4453 addressbook_free_treenode
);
4455 addrbookctl_free_folder(adapter
);
4459 listItems
= itemFolder
->listFolder
;
4460 while( listItems
) {
4461 ItemFolder
*item
= listItems
->data
;
4462 addressbook_node_add_folder( newNode
, ds
, item
, otype
);
4463 listItems
= g_list_next( listItems
);
4465 listItems
= itemFolder
->listGroup
;
4466 while( listItems
) {
4467 ItemGroup
*item
= listItems
->data
;
4468 addressbook_node_add_group( newNode
, ds
, item
);
4469 listItems
= g_list_next( listItems
);
4471 gtk_sctree_sort_node( ctree
, node
);
4475 void addressbook_export_to_file( void ) {
4476 if( _addressIndex_
) {
4477 /* Save all new address book data */
4478 debug_print( "Saving address books...\n" );
4479 addrindex_save_all_books( _addressIndex_
);
4481 debug_print( "Exporting addressbook to file...\n" );
4482 addrindex_save_data( _addressIndex_
);
4483 if( _addressIndex_
->retVal
!= MGU_SUCCESS
) {
4484 addrindex_print_index( _addressIndex_
, stdout
);
4487 /* Notify address completion of new data */
4488 invalidate_address_completion();
4492 static gboolean
addressbook_entry_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
4494 if (event
&& (event
->keyval
== GDK_KEY_Return
|| event
->keyval
== GDK_KEY_KP_Enter
))
4495 addressbook_lup_clicked(NULL
, NULL
);
4500 * Comparison using cell contents (text in first column). Used for sort
4501 * address index widget.
4503 static gint
addressbook_treenode_compare_func(
4504 GtkCMCList
*clist
, gconstpointer ptr1
, gconstpointer ptr2
)
4506 GtkCMCell
*cell1
= ((GtkCMCListRow
*)ptr1
)->cell
;
4507 GtkCMCell
*cell2
= ((GtkCMCListRow
*)ptr2
)->cell
;
4508 gchar
*name1
= NULL
, *name2
= NULL
;
4509 if( cell1
) name1
= cell1
->u
.text
;
4510 if( cell2
) name2
= cell2
->u
.text
;
4511 if( ! name1
) return ( name2
!= NULL
);
4512 if( ! name2
) return -1;
4513 return g_utf8_collate( name1
, name2
);
4516 static void addressbook_new_book_cb( GtkAction
*action
, gpointer data
) {
4517 AdapterDSource
*ads
;
4518 AdapterInterface
*adapter
;
4519 GtkCMCTreeNode
*newNode
;
4521 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
4522 if( adapter
== NULL
) return;
4523 ads
= addressbook_edit_book( _addressIndex_
, NULL
);
4525 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4527 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4528 addrbook
.treeSelected
= newNode
;
4533 static void addressbook_new_vcard_cb( GtkAction
*action
, gpointer data
) {
4534 AdapterDSource
*ads
;
4535 AdapterInterface
*adapter
;
4536 GtkCMCTreeNode
*newNode
;
4538 adapter
= addrbookctl_find_interface( ADDR_IF_VCARD
);
4539 if( adapter
== NULL
) return;
4540 ads
= addressbook_edit_vcard( _addressIndex_
, NULL
);
4542 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4544 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4545 addrbook
.treeSelected
= newNode
;
4551 static void addressbook_new_jpilot_cb( GtkAction
*action
, gpointer data
) {
4552 AdapterDSource
*ads
;
4553 AdapterInterface
*adapter
;
4554 AddressInterface
*iface
;
4555 GtkCMCTreeNode
*newNode
;
4557 adapter
= addrbookctl_find_interface( ADDR_IF_JPILOT
);
4558 if( adapter
== NULL
) return;
4559 iface
= adapter
->interface
;
4560 if( ! iface
->haveLibrary
) return;
4561 ads
= addressbook_edit_jpilot( _addressIndex_
, NULL
);
4563 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4565 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4566 addrbook
.treeSelected
= newNode
;
4573 static void addressbook_new_ldap_cb( GtkAction
*action
, gpointer data
) {
4574 AdapterDSource
*ads
;
4575 AdapterInterface
*adapter
;
4576 AddressInterface
*iface
;
4577 GtkCMCTreeNode
*newNode
;
4579 adapter
= addrbookctl_find_interface( ADDR_IF_LDAP
);
4580 if( adapter
== NULL
) return;
4581 iface
= adapter
->interface
;
4582 if( ! iface
->haveLibrary
) return;
4583 ads
= addressbook_edit_ldap( _addressIndex_
, NULL
);
4585 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4587 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4588 addrbook
.treeSelected
= newNode
;
4595 * Display address search status message.
4596 * \param queryType Query type.
4597 * \param status Status/Error code.
4599 static void addressbook_search_message( gint queryType
, gint sts
) {
4601 *addressbook_msgbuf
= '\0';
4603 if( sts
!= MGU_SUCCESS
) {
4604 if( queryType
== ADDRQUERY_LDAP
) {
4606 desc
= addressbook_err2string( _lutErrorsLDAP_
, sts
);
4611 g_snprintf( addressbook_msgbuf
,
4612 sizeof(addressbook_msgbuf
), "%s", desc
);
4613 addressbook_status_show( addressbook_msgbuf
);
4616 addressbook_status_show( "" );
4621 * Refresh addressbook by forcing refresh of current selected object in
4624 static void addressbook_refresh_current( void ) {
4628 ctree
= GTK_CMCTREE(addrbook
.ctree
);
4629 obj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
4630 if( obj
== NULL
) return;
4631 addressbook_set_clist( obj
, TRUE
);
4635 * Message that is displayed whilst a query is executing in a background
4638 static gchar
*_tempMessage_
= N_( "Busy searching..." );
4641 * Address search idle function. This function is called during UI idle time
4642 * while a search is in progress.
4644 * \param data Idler data.
4646 static void addressbook_search_idle( gpointer data
) {
4650 queryID = GPOINTER_TO_INT( data );
4651 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4656 * Search completion callback function. This removes the query from the idle
4659 * \param sender Sender of query.
4660 * \param queryID Query ID of search request.
4661 * \param status Search status.
4662 * \param data Query data.
4664 static void addressbook_search_callback_end(
4665 gpointer sender
, gint queryID
, gint status
, gpointer data
)
4669 AddrQueryObject
*aqo
;
4671 /* Remove idler function */
4672 ptrQID
= GINT_TO_POINTER( queryID
);
4674 g_idle_remove_by_data( ptrQID
);
4677 /* Refresh addressbook contents */
4678 addressbook_refresh_current();
4679 req
= qrymgr_find_request( queryID
);
4681 aqo
= ( AddrQueryObject
* ) req
->queryList
->data
;
4682 addressbook_search_message( aqo
->queryType
, status
);
4685 /* Stop the search */
4686 addrindex_stop_search( queryID
);
4692 * \param ds Data source to search.
4693 * \param searchTerm String to lookup.
4694 * \param pNode Parent data source node.
4696 static void addressbook_perform_search(
4697 AddressDataSource
*ds
, gchar
*searchTerm
,
4698 GtkCMCTreeNode
*pNode
)
4706 if( *searchTerm
== '\0' || strlen( searchTerm
) < 1 ) return;
4708 if( !ds
|| ds
->type
!= ADDR_IF_LDAP
) return;
4710 /* Create a folder for the search results */
4711 name
= g_strdup_printf( _queryFolderLabel_
, searchTerm
);
4712 folder
= addressbook_setup_subf(ds
, name
, pNode
);
4715 /* Setup the search */
4716 queryID
= addrindex_setup_explicit_search(
4717 ds
, searchTerm
, folder
, addressbook_search_callback_end
, NULL
);
4718 if( queryID
== 0 ) return;
4720 /* Set up idler function */
4721 idleID
= g_idle_add(
4722 (GSourceFunc
) addressbook_search_idle
,
4723 GINT_TO_POINTER( queryID
) );
4725 g_message("error adding addressbook_search_idle\n");
4728 /* Start search, sit back and wait for something to happen */
4729 addrindex_start_search( queryID
);
4731 addressbook_status_show( _tempMessage_
);
4735 * Lookup button handler. Address search is only performed against
4736 * address interfaces for external queries.
4738 * \param button Lookup button widget.
4739 * \param data Data object.
4741 static void addressbook_lup_clicked( GtkButton
*button
, gpointer data
) {
4744 AddressDataSource
*ds
;
4745 AddressInterface
*iface
;
4747 GtkCMCTreeNode
*node
, *parentNode
;
4749 LdapServer
*ldap_server
;
4750 LdapControl
*ldap_ctl
;
4753 node
= addrbook
.treeSelected
;
4754 if( ! node
) return;
4755 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
4757 ctree
= GTK_CMCTREE(addrbook
.ctree
);
4758 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
4759 if( obj
== NULL
) return;
4761 if (obj
->type
!= ADDR_DATASOURCE
||
4762 ADAPTER_DSOURCE(obj
)->subType
!= ADDR_LDAP
) {
4763 addressbook_set_clist(
4764 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
4765 addrbook
.treeSelected
),
4769 ds
= addressbook_find_datasource( node
);
4770 if( ds
== NULL
) return;
4772 /* We must have a datasource that is an external interface */
4773 iface
= ds
->interface
;
4774 if( ! iface
->haveLibrary
) return;
4775 if( ! iface
->externalQuery
) return;
4778 if (iface
->type
== ADDR_IF_LDAP
) {
4779 ldap_server
= ds
->rawDataSource
;
4780 ldap_ctl
= ldap_server
->control
;
4781 if (ldap_ctl
!= NULL
&&
4782 ldap_ctl
->bindDN
!= NULL
&& strlen(ldap_ctl
->bindDN
) > 0) {
4783 #ifndef PASSWORD_CRYPTO_OLD
4784 /* LDAP server is password-protected. */
4785 if (primary_passphrase() == NULL
) {
4786 /* User did not enter primary passphrase, do not start a search. */
4789 #endif /* PASSWORD_CRYPTO_OLD */
4792 #endif /* USE_LDAP */
4795 gtk_editable_get_chars( GTK_EDITABLE(addrbook
.entry
), 0, -1 );
4796 g_strchomp( searchTerm
);
4798 if( obj
->type
== ADDR_ITEM_FOLDER
) {
4799 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
4804 addressbook_perform_search( ds
, searchTerm
, parentNode
);
4806 gtk_widget_grab_focus( addrbook
.entry
);
4808 g_free( searchTerm
);
4811 static void addressbook_close_clicked( GtkButton
*button
, gpointer data
) {
4812 addressbook_close();
4817 * Browse address entry for highlighted entry.
4819 static void addressbook_browse_entry_cb( GtkAction
*action
, gpointer data
)
4821 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
4823 AddressDataSource
*ds
;
4824 AddressInterface
*iface
;
4828 if(addrbook
.listSelected
== NULL
)
4831 obj
= gtk_cmctree_node_get_row_data(clist
, addrbook
.listSelected
);
4835 ds
= addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook
.treeSelected
));
4839 iface
= ds
->interface
;
4840 if(!iface
|| !iface
->haveLibrary
)
4844 if (obj
->type
== ADDR_ITEM_EMAIL
) {
4845 email
= ( ItemEMail
* ) obj
;
4847 person
= (ItemPerson
*) ADDRITEM_PARENT(email
);
4849 else if (obj
->type
== ADDR_ITEM_PERSON
) {
4850 person
= (ItemPerson
*) obj
;
4857 if( iface
&& iface
->type
== ADDR_IF_LDAP
) {
4858 browseldap_entry(ds
, person
->externalID
);
4863 /* **********************************************************************
4864 * Build lookup tables.
4865 * ***********************************************************************
4869 * Remap object types.
4870 * Enter: abType AddressObjectType (used in tree node).
4871 * Return: ItemObjectType (used in address cache data).
4873 ItemObjectType
addressbook_type2item( AddressObjectType abType
) {
4874 ItemObjectType ioType
;
4877 case ADDR_ITEM_PERSON
: ioType
= ITEMTYPE_PERSON
; break;
4878 case ADDR_ITEM_EMAIL
: ioType
= ITEMTYPE_EMAIL
; break;
4879 case ADDR_ITEM_FOLDER
: ioType
= ITEMTYPE_FOLDER
; break;
4880 case ADDR_ITEM_GROUP
: ioType
= ITEMTYPE_GROUP
; break;
4881 case ADDR_DATASOURCE
: ioType
= ITEMTYPE_DATASOURCE
; break;
4882 default: ioType
= ITEMTYPE_NONE
; break;
4887 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4888 atci = addrbookctl_lookup(id); \
4890 atci->iconXpm = icon; \
4891 atci->iconXpmOpen = iconopen; \
4893 g_warning("can't get atci %d", id); \
4898 * Build table that controls the rendering of object types.
4900 static void addrbookctl_build_icons( GtkWidget
*window
) {
4901 AddressTypeControlItem
*atci
;
4905 g_object_unref(interfacexpm
);
4907 g_object_unref(folderxpm
);
4909 g_object_unref(folderopenxpm
);
4911 g_object_unref(groupxpm
);
4913 g_object_unref(vcardxpm
);
4915 g_object_unref(bookxpm
);
4917 g_object_unref(addressxpm
);
4919 g_object_unref(jpilotxpm
);
4921 g_object_unref(categoryxpm
);
4923 g_object_unref(ldapxpm
);
4925 g_object_unref(addrsearchxpm
);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE
, &interfacexpm
);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP
, &groupxpm
);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD
, &vcardxpm
);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK
, &bookxpm
);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS
, &addressxpm
);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT
, &jpilotxpm
);
4934 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY
, &categoryxpm
);
4935 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP
, &ldapxpm
);
4936 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH
, &addrsearchxpm
);
4938 UPDATE_ICON_ATCI(ADDR_INTERFACE
,folderxpm
,folderopenxpm
);
4939 UPDATE_ICON_ATCI(ADDR_BOOK
,bookxpm
,bookxpm
);
4940 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON
,NULL
,NULL
);
4941 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL
,addressxpm
,addressxpm
);
4942 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP
,groupxpm
,groupxpm
);
4943 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER
,folderxpm
,folderopenxpm
);
4944 UPDATE_ICON_ATCI(ADDR_VCARD
,vcardxpm
,vcardxpm
);
4945 UPDATE_ICON_ATCI(ADDR_JPILOT
,jpilotxpm
,jpilotxpm
);
4946 UPDATE_ICON_ATCI(ADDR_CATEGORY
,categoryxpm
,categoryxpm
);
4947 UPDATE_ICON_ATCI(ADDR_LDAP
,ldapxpm
,ldapxpm
);
4948 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY
,addrsearchxpm
,addrsearchxpm
);
4953 * Build table that controls the rendering of object types.
4955 static void addrbookctl_build_map( GtkWidget
*window
) {
4956 AddressTypeControlItem
*atci
;
4958 _addressBookTypeHash_
= g_hash_table_new( g_int_hash
, g_int_equal
);
4959 _addressBookTypeList_
= NULL
;
4962 atci
= g_new0( AddressTypeControlItem
, 1 );
4963 atci
->objectType
= ADDR_INTERFACE
;
4964 atci
->interfaceType
= ADDR_IF_NONE
;
4965 atci
->showInTree
= TRUE
;
4966 atci
->treeExpand
= TRUE
;
4967 atci
->treeLeaf
= FALSE
;
4968 atci
->displayName
= _( "Interface" );
4969 atci
->menuCommand
= NULL
;
4970 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4971 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4974 atci
= g_new0( AddressTypeControlItem
, 1 );
4975 atci
->objectType
= ADDR_BOOK
;
4976 atci
->interfaceType
= ADDR_IF_BOOK
;
4977 atci
->showInTree
= TRUE
;
4978 atci
->treeExpand
= TRUE
;
4979 atci
->treeLeaf
= FALSE
;
4980 atci
->displayName
= _("Address Books");
4981 atci
->menuCommand
= "Menu/Book/NewBook";
4982 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4983 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4986 atci
= g_new0( AddressTypeControlItem
, 1 );
4987 atci
->objectType
= ADDR_ITEM_PERSON
;
4988 atci
->interfaceType
= ADDR_IF_NONE
;
4989 atci
->showInTree
= FALSE
;
4990 atci
->treeExpand
= FALSE
;
4991 atci
->treeLeaf
= FALSE
;
4992 atci
->displayName
= _( "Person" );
4993 atci
->menuCommand
= NULL
;
4994 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4995 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4998 atci
= g_new0( AddressTypeControlItem
, 1 );
4999 atci
->objectType
= ADDR_ITEM_EMAIL
;
5000 atci
->interfaceType
= ADDR_IF_NONE
;
5001 atci
->showInTree
= FALSE
;
5002 atci
->treeExpand
= FALSE
;
5003 atci
->treeLeaf
= TRUE
;
5004 atci
->displayName
= _( "Email Address" );
5005 atci
->menuCommand
= NULL
;
5006 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5007 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5010 atci
= g_new0( AddressTypeControlItem
, 1 );
5011 atci
->objectType
= ADDR_ITEM_GROUP
;
5012 atci
->interfaceType
= ADDR_IF_BOOK
;
5013 atci
->showInTree
= TRUE
;
5014 atci
->treeExpand
= FALSE
;
5015 atci
->treeLeaf
= FALSE
;
5016 atci
->displayName
= _( "Group" );
5017 atci
->menuCommand
= NULL
;
5018 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5019 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5022 atci
= g_new0( AddressTypeControlItem
, 1 );
5023 atci
->objectType
= ADDR_ITEM_FOLDER
;
5024 atci
->interfaceType
= ADDR_IF_BOOK
;
5025 atci
->showInTree
= TRUE
;
5026 atci
->treeExpand
= FALSE
;
5027 atci
->treeLeaf
= FALSE
;
5028 atci
->displayName
= _( "Folder" );
5029 atci
->menuCommand
= NULL
;
5030 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5031 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5034 atci
= g_new0( AddressTypeControlItem
, 1 );
5035 atci
->objectType
= ADDR_VCARD
;
5036 atci
->interfaceType
= ADDR_IF_VCARD
;
5037 atci
->showInTree
= TRUE
;
5038 atci
->treeExpand
= TRUE
;
5039 atci
->treeLeaf
= TRUE
;
5040 atci
->displayName
= _( "vCard" );
5041 atci
->menuCommand
= "Menu/Book/NewVCard";
5042 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5043 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5046 atci
= g_new0( AddressTypeControlItem
, 1 );
5047 atci
->objectType
= ADDR_JPILOT
;
5048 atci
->interfaceType
= ADDR_IF_JPILOT
;
5049 atci
->showInTree
= TRUE
;
5050 atci
->treeExpand
= TRUE
;
5051 atci
->treeLeaf
= FALSE
;
5052 atci
->displayName
= _( "JPilot" );
5053 atci
->menuCommand
= "Menu/Book/NewJPilot";
5054 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5055 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5058 atci
= g_new0( AddressTypeControlItem
, 1 );
5059 atci
->objectType
= ADDR_CATEGORY
;
5060 atci
->interfaceType
= ADDR_IF_JPILOT
;
5061 atci
->showInTree
= TRUE
;
5062 atci
->treeExpand
= TRUE
;
5063 atci
->treeLeaf
= TRUE
;
5064 atci
->displayName
= _( "JPilot" );
5065 atci
->menuCommand
= NULL
;
5066 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5067 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5070 atci
= g_new0( AddressTypeControlItem
, 1 );
5071 atci
->objectType
= ADDR_LDAP
;
5072 atci
->interfaceType
= ADDR_IF_LDAP
;
5073 atci
->showInTree
= TRUE
;
5074 atci
->treeExpand
= TRUE
;
5075 atci
->treeLeaf
= FALSE
;
5076 atci
->displayName
= _( "LDAP servers" );
5077 atci
->menuCommand
= "Menu/Book/NewLDAPServer";
5078 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5079 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5082 atci
= g_new0( AddressTypeControlItem
, 1 );
5083 atci
->objectType
= ADDR_LDAP_QUERY
;
5084 atci
->interfaceType
= ADDR_IF_LDAP
;
5085 atci
->showInTree
= TRUE
;
5086 atci
->treeExpand
= FALSE
;
5087 atci
->treeLeaf
= TRUE
;
5088 atci
->displayName
= _( "LDAP Query" );
5089 atci
->menuCommand
= NULL
;
5090 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5091 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5093 addrbookctl_build_icons(window
);
5096 void addressbook_reflect_prefs_pixmap_theme(void)
5098 if (addrbook
.window
)
5099 addrbookctl_build_icons(addrbook
.window
);
5103 * Search for specified object type.
5105 static AddressTypeControlItem
*addrbookctl_lookup( gint ot
) {
5107 return ( AddressTypeControlItem
* ) g_hash_table_lookup( _addressBookTypeHash_
, &objType
);
5111 * Search for specified interface type.
5113 static AddressTypeControlItem
*addrbookctl_lookup_iface( AddressIfType ifType
) {
5114 GList
*node
= _addressBookTypeList_
;
5116 AddressTypeControlItem
*atci
= node
->data
;
5117 if( atci
->interfaceType
== ifType
) return atci
;
5118 node
= g_list_next( node
);
5123 static void addrbookctl_free_address( AddressObject
*obj
) {
5124 g_free( obj
->name
);
5125 obj
->type
= ADDR_NONE
;
5129 static void addrbookctl_free_interface( AdapterInterface
*adapter
) {
5130 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5131 adapter
->interface
= NULL
;
5132 adapter
->interfaceType
= ADDR_IF_NONE
;
5133 adapter
->atci
= NULL
;
5134 adapter
->enabled
= FALSE
;
5135 adapter
->haveLibrary
= FALSE
;
5136 adapter
->treeNode
= NULL
;
5140 static void addrbookctl_free_datasource( AdapterDSource
*adapter
) {
5141 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5142 adapter
->dataSource
= NULL
;
5143 adapter
->subType
= ADDR_NONE
;
5147 static void addrbookctl_free_folder( AdapterFolder
*adapter
) {
5148 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5149 adapter
->itemFolder
= NULL
;
5153 static void addrbookctl_free_group( AdapterGroup
*adapter
) {
5154 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5155 adapter
->itemGroup
= NULL
;
5160 * Build GUI interface list.
5162 static void addrbookctl_build_iflist( void ) {
5163 AddressTypeControlItem
*atci
;
5164 AdapterInterface
*adapter
;
5167 if( _addressIndex_
== NULL
) {
5168 _addressIndex_
= addrindex_create_index();
5169 if( _clipBoard_
== NULL
) {
5170 _clipBoard_
= addrclip_create();
5172 addrclip_set_index( _clipBoard_
, _addressIndex_
);
5174 _addressInterfaceList_
= NULL
;
5175 list
= addrindex_get_interface_list( _addressIndex_
);
5177 AddressInterface
*interface
= list
->data
;
5178 atci
= addrbookctl_lookup_iface( interface
->type
);
5180 adapter
= g_new0( AdapterInterface
, 1 );
5181 adapter
->interfaceType
= interface
->type
;
5182 adapter
->atci
= atci
;
5183 adapter
->interface
= interface
;
5184 adapter
->treeNode
= NULL
;
5185 adapter
->enabled
= TRUE
;
5186 adapter
->haveLibrary
= interface
->haveLibrary
;
5187 ADDRESS_OBJECT(adapter
)->type
= ADDR_INTERFACE
;
5188 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( atci
->displayName
);
5189 _addressInterfaceList_
=
5190 g_list_append( _addressInterfaceList_
, adapter
);
5192 list
= g_list_next( list
);
5197 * Find GUI interface type specified interface type.
5198 * \param ifType Interface type.
5199 * \return Interface item, or NULL if not found.
5201 static AdapterInterface
*addrbookctl_find_interface( AddressIfType ifType
) {
5202 GList
*node
= _addressInterfaceList_
;
5204 AdapterInterface
*adapter
= node
->data
;
5205 if( adapter
->interfaceType
== ifType
) return adapter
;
5206 node
= g_list_next( node
);
5212 * Build interface list selection.
5214 static void addrbookctl_build_ifselect( void ) {
5215 GList
*newList
= NULL
;
5220 gchar
*endptr
= NULL
;
5221 /* gboolean enabled; */
5222 AdapterInterface
*adapter
;
5224 selectStr
= g_strdup( ADDRESSBOOK_IFACE_SELECTION
);
5227 splitStr
= g_strsplit( selectStr
, ",", -1 );
5228 for( i
= 0; i
< ADDRESSBOOK_MAX_IFACE
; i
++ ) {
5230 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5231 ifType
= strtol( splitStr
[i
], &endptr
, 10 );
5234 if( strcmp( endptr, "/n" ) == 0 ) {
5239 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5240 adapter
= addrbookctl_find_interface( ifType
);
5242 newList
= g_list_append( newList
, adapter
);
5249 /* g_print( "i=%d\n", i ); */
5250 g_strfreev( splitStr
);
5251 g_free( selectStr
);
5253 /* Replace existing list */
5254 g_list_free( _addressIFaceSelection_
);
5255 _addressIFaceSelection_
= newList
;
5259 /* ***********************************************************************
5260 * Add sender to address book.
5261 * ***********************************************************************
5265 * This function is used by the Add sender to address book function.
5267 gboolean
addressbook_add_contact(
5268 const gchar
*name
, const gchar
*address
, const gchar
*remarks
,
5269 GdkPixbuf
*picture
)
5271 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name
, address
);
5272 if( addressadd_selection( _addressIndex_
, name
, address
, remarks
, picture
) ) {
5273 debug_print( "addressbook_add_contact - added\n" );
5274 addressbook_refresh();
5279 /* ***********************************************************************
5280 * Book/folder selection.
5281 * ***********************************************************************
5285 * This function is used by the matcher dialog to select a book/folder.
5287 gchar
*addressbook_folder_selection( const gchar
*folderpath
)
5289 AddressBookFile
*book
= NULL
;
5290 ItemFolder
*folder
= NULL
;
5293 cm_return_val_if_fail( folderpath
!= NULL
, NULL
);
5295 if ( addressbook_foldersel_selection( _addressIndex_
, &book
, &folder
, folderpath
)
5297 if ( folder
!= NULL
) {
5299 gchar
*oldtmp
= NULL
;
5300 AddrItemObject
*obj
= NULL
;
5302 /* walk thru folder->parent to build the full folder path */
5303 /* TODO: wwp: optimize this */
5305 tmp
= g_strdup(obj
->uid
);
5306 while ( obj
->parent
) {
5308 if ( obj
->name
!= NULL
) {
5309 oldtmp
= g_strdup(tmp
);
5311 tmp
= g_strdup_printf("%s/%s", obj
->uid
, oldtmp
);
5315 path
= g_strdup_printf("%s/%s", book
->fileName
, tmp
);
5318 path
= g_strdup_printf("%s", book
->fileName
);
5320 debug_print( "addressbook_foldersel: %s\n", path
?path
:"(null)");
5326 /* ***********************************************************************
5327 * Book/folder checking.
5328 * ***********************************************************************
5331 static FolderInfo
*addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile
*abf
, ItemFolder
*folder
)
5333 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
5335 fi
->folder
= folder
;
5339 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder
*parentFolder
,
5340 FolderInfo
*fiParent
, FolderPathMatch
*match
)
5346 FolderPathMatch
*nextmatch
= NULL
;
5351 list
= parentFolder
->listFolder
;
5353 folder
= list
->data
;
5354 fName
= g_strdup( ADDRITEM_NAME(folder
) );
5356 /* match folder name, match pointer will be set to NULL if next recursive call
5357 doesn't need to match subfolder name */
5358 if ( match
!= NULL
&&
5359 match
->matched
== FALSE
) {
5360 if ( strcmp(match
->folder_path
[match
->index
], folder
->obj
.uid
) == 0 ) {
5361 /* folder name matches, prepare next subfolder match */
5362 debug_print("matched folder name '%s'\n", fName
);
5364 if ( match
->folder_path
[match
->index
] == NULL
) {
5365 /* we've matched all elements */
5366 match
->matched
= TRUE
;
5367 match
->folder
= folder
;
5368 debug_print("book/folder path matched!\n");
5370 /* keep on matching */
5378 fi
= addressbook_peek_subfolder_exists_create_folderinfo( fiParent
->book
, folder
);
5379 addressbook_peek_subfolder_exists_load_folder( folder
, fi
, nextmatch
);
5381 list
= g_list_next( list
);
5386 * This function is used by to check if a matcher book/folder path corresponds to an
5387 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5388 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5389 if book AND folder are NULL this means that folderpath was empty or Any.
5390 If folderpath is a simple book name (without folder), book will not be NULL and folder
5391 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5394 gboolean
addressbook_peek_folder_exists( gchar
*folderpath
,
5395 AddressDataSource
**book
,
5396 ItemFolder
**folder
)
5398 AddressDataSource
*ds
;
5399 GList
*list
, *nodeDS
;
5400 ItemFolder
*rootFolder
;
5401 AddressBookFile
*abf
;
5403 FolderPathMatch folder_path_match
= { NULL
, FALSE
, 0, NULL
, NULL
};
5410 if ( folderpath
== NULL
)
5413 if ( strcasecmp(folderpath
, "Any") == 0 || *folderpath
== '\0' )
5416 /* split the folder path we've received, we'll try to match this path, subpath by
5417 subpath against the book/folder structure in order */
5418 folder_path_match
.folder_path
= g_strsplit( folderpath
, "/", 256 );
5419 if (!folder_path_match
.folder_path
)
5422 list
= addrindex_get_interface_list( _addressIndex_
);
5423 while ( list
&& !folder_path_match
.matched
) {
5424 AddressInterface
*interface
= list
->data
;
5425 if ( interface
&& interface
->type
== ADDR_IF_BOOK
) {
5426 nodeDS
= interface
->listSource
;
5427 while ( nodeDS
&& !folder_path_match
.matched
) {
5430 /* Read address book */
5431 if( ! addrindex_ds_get_read_flag( ds
) ) {
5432 addrindex_ds_read_data( ds
);
5435 /* Add node for address book */
5436 abf
= ds
->rawDataSource
;
5438 /* match book name */
5439 if ( abf
&& abf
->fileName
&&
5440 strcmp(folder_path_match
.folder_path
[0], abf
->fileName
) == 0 ) {
5442 debug_print("matched book name '%s'\n", abf
->fileName
);
5443 folder_path_match
.book
= ds
;
5445 if ( folder_path_match
.folder_path
[1] == NULL
) {
5446 /* no folder part to match */
5448 folder_path_match
.matched
= TRUE
;
5449 folder_path_match
.folder
= NULL
;
5450 debug_print("book path matched!\n");
5453 /* match folder part */
5455 fi
= addressbook_peek_subfolder_exists_create_folderinfo( abf
, NULL
);
5456 rootFolder
= addrindex_ds_get_root_folder( ds
);
5458 /* prepare for recursive call */
5459 folder_path_match
.index
= 1;
5460 /* this call will set folder_path_match.matched and folder_path_match.folder */
5461 addressbook_peek_subfolder_exists_load_folder( rootFolder
, fi
, &folder_path_match
);
5466 nodeDS
= g_list_next( nodeDS
);
5469 list
= g_list_next( list
);
5472 g_strfreev( folder_path_match
.folder_path
);
5475 *book
= folder_path_match
.book
;
5477 *folder
= folder_path_match
.folder
;
5478 return folder_path_match
.matched
;
5482 /* **********************************************************************
5484 * ***********************************************************************
5490 static void addressbook_import_ldif_cb( GtkAction
*action
, gpointer data
) {
5491 AddressDataSource
*ds
= NULL
;
5492 AdapterDSource
*ads
= NULL
;
5493 AddressBookFile
*abf
= NULL
;
5494 AdapterInterface
*adapter
;
5495 GtkCMCTreeNode
*newNode
;
5497 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5499 if( adapter
->treeNode
) {
5500 abf
= addressbook_imp_ldif( _addressIndex_
);
5502 ds
= addrindex_index_add_datasource(
5503 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5504 ads
= addressbook_create_ds_adapter(
5505 ds
, ADDR_BOOK
, NULL
);
5506 addressbook_ads_set_name(
5507 ads
, addrbook_get_name( abf
) );
5508 newNode
= addressbook_add_object(
5510 ADDRESS_OBJECT(ads
) );
5512 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5514 addrbook
.treeSelected
= newNode
;
5517 /* Notify address completion */
5518 invalidate_address_completion();
5527 static void addressbook_import_mutt_cb( GtkAction
*action
, gpointer data
) {
5528 AddressDataSource
*ds
= NULL
;
5529 AdapterDSource
*ads
= NULL
;
5530 AddressBookFile
*abf
= NULL
;
5531 AdapterInterface
*adapter
;
5532 GtkCMCTreeNode
*newNode
;
5534 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5536 if( adapter
->treeNode
) {
5537 abf
= addressbook_imp_mutt( _addressIndex_
);
5539 ds
= addrindex_index_add_datasource(
5540 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5541 ads
= addressbook_create_ds_adapter(
5542 ds
, ADDR_BOOK
, NULL
);
5543 addressbook_ads_set_name(
5544 ads
, addrbook_get_name( abf
) );
5545 newNode
= addressbook_add_object(
5547 ADDRESS_OBJECT(ads
) );
5549 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5551 addrbook
.treeSelected
= newNode
;
5554 /* Notify address completion */
5555 invalidate_address_completion();
5564 static void addressbook_import_pine_cb( GtkAction
*action
, gpointer data
) {
5565 AddressDataSource
*ds
= NULL
;
5566 AdapterDSource
*ads
= NULL
;
5567 AddressBookFile
*abf
= NULL
;
5568 AdapterInterface
*adapter
;
5569 GtkCMCTreeNode
*newNode
;
5571 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5573 if( adapter
->treeNode
) {
5574 abf
= addressbook_imp_pine( _addressIndex_
);
5576 ds
= addrindex_index_add_datasource(
5577 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5578 ads
= addressbook_create_ds_adapter(
5579 ds
, ADDR_BOOK
, NULL
);
5580 addressbook_ads_set_name(
5581 ads
, addrbook_get_name( abf
) );
5582 newNode
= addressbook_add_object(
5584 ADDRESS_OBJECT(ads
) );
5586 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5588 addrbook
.treeSelected
= newNode
;
5591 /* Notify address completion */
5592 invalidate_address_completion();
5599 * Harvest addresses.
5600 * \param folderItem Folder to import.
5601 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5602 * \param msgList List of message numbers, or NULL to process folder.
5604 void addressbook_harvest(
5605 FolderItem
*folderItem
, gboolean sourceInd
, GList
*msgList
)
5607 AddressDataSource
*ds
= NULL
;
5608 AdapterDSource
*ads
= NULL
;
5609 AddressBookFile
*abf
= NULL
;
5610 AdapterInterface
*adapter
;
5611 GtkCMCTreeNode
*newNode
;
5613 abf
= addrgather_dlg_execute(
5614 folderItem
, _addressIndex_
, sourceInd
, msgList
);
5616 ds
= addrindex_index_add_datasource(
5617 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5619 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5621 if( adapter
->treeNode
) {
5622 ads
= addressbook_create_ds_adapter(
5623 ds
, ADDR_BOOK
, addrbook_get_name( abf
) );
5624 newNode
= addressbook_add_object(
5626 ADDRESS_OBJECT(ads
) );
5627 if (newNode
== NULL
) {
5628 g_message("error adding addressbook object\n");
5633 /* Notify address completion */
5634 invalidate_address_completion();
5641 static void addressbook_export_html_cb( GtkAction
*action
, gpointer data
) {
5642 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
5644 AddressDataSource
*ds
= NULL
;
5645 AddrBookBase
*adbase
;
5646 AddressCache
*cache
;
5647 GtkCMCTreeNode
*node
= NULL
;
5649 if( ! addrbook
.treeSelected
) return;
5650 node
= addrbook
.treeSelected
;
5651 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
5652 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
5653 if( obj
== NULL
) return;
5655 ds
= addressbook_find_datasource( node
);
5656 if( ds
== NULL
) return;
5657 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
5658 cache
= adbase
->addressCache
;
5659 addressbook_exp_html( cache
);
5665 static void addressbook_export_ldif_cb( GtkAction
*action
, gpointer data
) {
5666 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
5668 AddressDataSource
*ds
= NULL
;
5669 AddrBookBase
*adbase
;
5670 AddressCache
*cache
;
5671 GtkCMCTreeNode
*node
= NULL
;
5673 if( ! addrbook
.treeSelected
) return;
5674 node
= addrbook
.treeSelected
;
5675 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
5676 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
5677 if( obj
== NULL
) return;
5679 ds
= addressbook_find_datasource( node
);
5680 if( ds
== NULL
) return;
5681 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
5682 cache
= adbase
->addressCache
;
5683 addressbook_exp_ldif( cache
);
5686 static void addressbook_find_duplicates_cb(GtkAction
*action
, gpointer data
)
5688 addrduplicates_find(GTK_WINDOW(addrbook
.window
));
5691 static void addressbook_edit_custom_attr_cb(GtkAction
*action
, gpointer data
)
5693 addressbook_custom_attr_edit();
5696 static void addressbook_start_drag(GtkWidget
*widget
, gint button
,
5700 GdkDragContext
*context
;
5701 if (addressbook_target_list
== NULL
)
5702 addressbook_target_list
= gtk_target_list_new(
5703 addressbook_drag_types
, 1);
5704 context
= gtk_drag_begin_with_coordinates(widget
, addressbook_target_list
,
5705 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
,
5707 gtk_drag_set_icon_default(context
);
5710 static void addressbook_drag_data_get(GtkWidget
*widget
,
5711 GdkDragContext
*drag_context
,
5712 GtkSelectionData
*selection_data
,
5717 AddrItemObject
*aio
= NULL
;
5718 AddressObject
*pobj
= NULL
;
5719 AdapterDSource
*ads
= NULL
;
5720 AddressDataSource
*ds
= NULL
;
5723 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
5725 if( pobj
== NULL
) return;
5727 if( pobj
->type
== ADDR_DATASOURCE
) {
5728 ads
= ADAPTER_DSOURCE(pobj
);
5729 ds
= ads
->dataSource
;
5730 } else if (pobj
->type
== ADDR_ITEM_GROUP
) {
5735 else if( pobj
->type
!= ADDR_INTERFACE
) {
5736 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
5742 for(cur
= GTK_CMCLIST(addrbook
.clist
)->selection
; cur
; cur
= cur
->next
) {
5743 aio
= (AddrItemObject
*)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.clist
),
5744 GTK_CMCTREE_NODE(cur
->data
));
5745 while (aio
&& aio
->type
!= ITEMTYPE_PERSON
) {
5750 if (aio
&& aio
->type
== ITEMTYPE_PERSON
) {
5751 if( ds
&& ds
->interface
&& ds
->interface
->readOnly
)
5752 gtk_selection_data_set(selection_data
,
5753 gtk_selection_data_get_target(selection_data
), 8,
5754 (const guchar
*)"Dummy_addr_copy", 15);
5756 gtk_selection_data_set(selection_data
,
5757 gtk_selection_data_get_target(selection_data
), 8,
5758 (const guchar
*)"Dummy_addr_move", 15);
5762 static gboolean
addressbook_drag_motion_cb(GtkWidget
*widget
,
5763 GdkDragContext
*context
,
5769 GtkAllocation allocation
;
5770 GtkRequisition requisition
;
5772 GtkCMCTreeNode
*node
= NULL
;
5773 gboolean acceptable
= FALSE
;
5774 gtk_widget_get_allocation(GTK_WIDGET(addrbook
.ctree
), &allocation
);
5775 gint height
= allocation
.height
;
5776 gtk_widget_get_requisition(GTK_WIDGET(addrbook
.ctree
), &requisition
);
5777 gint total_height
= requisition
.height
;
5778 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
5779 GTK_SCROLLED_WINDOW(addrbook
.ctree_swin
));
5780 gfloat vpos
= gtk_adjustment_get_value(pos
);
5782 if (gtk_cmclist_get_selection_info
5783 (GTK_CMCLIST(widget
), x
- 24, y
- 24, &row
, &column
)) {
5785 if (y
> height
- 24 && height
+ vpos
< total_height
) {
5786 gtk_adjustment_set_value(pos
, (vpos
+5 > height
? height
: vpos
+5));
5788 if (y
< 24 && y
> 0) {
5789 gtk_adjustment_set_value(pos
, (vpos
-5 < 0 ? 0 : vpos
-5));
5791 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
5794 AddressObject
*obj
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
5797 if( obj
->type
== ADDR_ITEM_FOLDER
5798 || obj
->type
== ADDR_ITEM_GROUP
)
5801 AdapterDSource
*ads
= NULL
;
5802 AddressDataSource
*ds
= NULL
;
5803 ads
= ADAPTER_DSOURCE(obj
);
5804 ds
= ads
->dataSource
;
5805 if (ds
== NULL
) { return FALSE
;}
5813 g_signal_handlers_block_by_func
5815 G_CALLBACK(addressbook_tree_selected
), NULL
);
5816 gtk_sctree_select( GTK_SCTREE(widget
), node
);
5817 g_signal_handlers_unblock_by_func
5819 G_CALLBACK(addressbook_tree_selected
), NULL
);
5820 gdk_drag_status(context
,
5821 (gdk_drag_context_get_actions(context
) == GDK_ACTION_COPY
?
5822 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
5824 gdk_drag_status(context
, 0, time
);
5829 static void addressbook_drag_leave_cb(GtkWidget
*widget
,
5830 GdkDragContext
*context
,
5834 if (addrbook
.treeSelected
) {
5835 g_signal_handlers_block_by_func
5837 G_CALLBACK(addressbook_tree_selected
), NULL
);
5838 gtk_sctree_select( GTK_SCTREE(widget
), addrbook
.opened
);
5839 g_signal_handlers_unblock_by_func
5841 G_CALLBACK(addressbook_tree_selected
), NULL
);
5846 static void addressbook_drag_received_cb(GtkWidget
*widget
,
5847 GdkDragContext
*drag_context
,
5850 GtkSelectionData
*data
,
5856 GtkCMCTreeNode
*node
;
5857 GtkCMCTreeNode
*lastopened
= addrbook
.opened
;
5859 if (!strncmp(gtk_selection_data_get_data(data
), "Dummy_addr", 10)) {
5860 if (gtk_cmclist_get_selection_info
5861 (GTK_CMCLIST(widget
), x
- 24, y
- 24, &row
, &column
) == 0) {
5865 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
5866 if( !node
|| !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
), node
))
5869 gtk_cmclist_freeze(GTK_CMCLIST(addrbook
.clist
));
5870 if (gdk_drag_context_get_selected_action(drag_context
) == GDK_ACTION_COPY
||
5871 !strcmp(gtk_selection_data_get_data(data
), "Dummy_addr_copy"))
5872 addressbook_clip_copy_cb(NULL
, NULL
);
5874 addressbook_clip_cut_cb(NULL
, NULL
);
5875 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), node
);
5876 addressbook_clip_paste_cb(NULL
,NULL
);
5877 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), lastopened
);
5878 gtk_cmclist_thaw(GTK_CMCLIST(addrbook
.clist
));
5879 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);