2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2020 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/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
33 #include <sys/types.h>
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
43 #include "stock_pixmap.h"
45 #include "prefs_gtk.h"
47 #include "file-utils.h"
52 #include "addr_compl.h"
56 #include "addressitem.h"
58 #include "addrcache.h"
60 #include "addrindex.h"
61 #include "addrmerge.h"
62 #include "addressadd.h"
63 #include "addrduplicates.h"
64 #include "addressbook_foldersel.h"
66 #include "editvcard.h"
67 #include "editgroup.h"
68 #include "editaddress.h"
70 #include "importldif.h"
71 #include "importmutt.h"
72 #include "importpine.h"
77 #include "editjpilot.h"
82 #include "ldapserver.h"
84 #include "ldapupdate.h"
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
89 #include "addrquery.h"
90 #include "addrselect.h"
92 #include "addrgather.h"
93 #include "adbookbase.h"
94 #include "exphtmldlg.h"
95 #include "expldifdlg.h"
96 #include "browseldap.h"
97 #include "addrcustomattr.h"
105 } AddressIndexColumns
;
113 } AddressListColumns
;
116 AddressBookFile
*book
;
124 AddressDataSource
*book
;
128 static gchar
*list_titles
[] = { N_("Name"),
132 #define COL_NAME_WIDTH 164
133 #define COL_ADDRESS_WIDTH 156
135 #define COL_FOLDER_WIDTH 170
136 #define ADDRESSBOOK_WIDTH 640
137 #define ADDRESSBOOK_HEIGHT 360
139 #define ADDRESSBOOK_MSGBUF_SIZE 2048
141 static GdkPixbuf
*folderxpm
= NULL
;
142 static GdkPixbuf
*folderopenxpm
= NULL
;
143 static GdkPixbuf
*groupxpm
= NULL
;
144 static GdkPixbuf
*interfacexpm
= NULL
;
145 static GdkPixbuf
*bookxpm
= NULL
;
146 static GdkPixbuf
*addressxpm
= NULL
;
147 static GdkPixbuf
*vcardxpm
= NULL
;
148 static GdkPixbuf
*jpilotxpm
= NULL
;
149 static GdkPixbuf
*categoryxpm
= NULL
;
150 static GdkPixbuf
*ldapxpm
= NULL
;
151 static GdkPixbuf
*addrsearchxpm
= NULL
;
154 static gchar addressbook_msgbuf
[ ADDRESSBOOK_MSGBUF_SIZE
];
156 /* Address list selection */
157 static AddrSelectList
*_addressSelect_
= NULL
;
158 static AddressClipboard
*_clipBoard_
= NULL
;
160 /* Address index file and interfaces */
161 static AddressIndex
*_addressIndex_
= NULL
;
162 static GList
*_addressInterfaceList_
= NULL
;
163 static GList
*_addressIFaceSelection_
= NULL
;
164 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
166 static AddressBook_win addrbook
;
168 static GHashTable
*_addressBookTypeHash_
= NULL
;
169 static GList
*_addressBookTypeList_
= NULL
;
171 static void addressbook_new_address_from_book_post_cb( ItemPerson
*person
);
172 static void addressbook_new_address_from_folder_post_cb( ItemPerson
*person
);
173 static void addressbook_edit_address_post_cb( ItemPerson
*person
);
175 static void addressbook_create (void);
176 static gint
addressbook_close (void);
178 static gboolean address_index_has_focus
= FALSE
;
179 static gboolean address_list_has_focus
= FALSE
;
181 /* callback functions */
182 static void addressbook_del_clicked (GtkButton
*button
,
184 static void addressbook_reg_clicked (GtkButton
*button
,
186 static void addressbook_to_clicked (GtkButton
*button
,
188 static void addressbook_lup_clicked (GtkButton
*button
,
190 static void addressbook_close_clicked (GtkButton
*button
,
193 static void addressbook_tree_selected (GtkCMCTree
*ctree
,
194 GtkCMCTreeNode
*node
,
197 static void addressbook_select_row_tree (GtkCMCTree
*ctree
,
198 GtkCMCTreeNode
*node
,
201 static void addressbook_list_row_selected (GtkCMCTree
*clist
,
202 GtkCMCTreeNode
*node
,
205 static void addressbook_list_row_unselected (GtkCMCTree
*clist
,
206 GtkCMCTreeNode
*node
,
209 static void addressbook_person_expand_node (GtkCMCTree
*ctree
,
212 static void addressbook_person_collapse_node (GtkCMCTree
*ctree
,
216 static void addressbook_entry_activated (GtkWidget
*widget
,
219 static gboolean
addressbook_list_button_pressed (GtkWidget
*widget
,
220 GdkEventButton
*event
,
222 static gboolean
addressbook_list_button_released(GtkWidget
*widget
,
223 GdkEventButton
*event
,
225 static gboolean
addressbook_tree_button_pressed (GtkWidget
*ctree
,
226 GdkEventButton
*event
,
228 static gboolean
addressbook_tree_button_released(GtkWidget
*ctree
,
229 GdkEventButton
*event
,
232 static void addressbook_new_folder_cb (GtkAction
*action
,
234 static void addressbook_new_group_cb (GtkAction
*action
,
236 static void addressbook_treenode_edit_cb (GtkAction
*action
,
238 static void addressbook_treenode_delete_cb (GtkAction
*action
,
241 static void addressbook_change_node_name (GtkCMCTreeNode
*node
,
244 static void addressbook_new_address_cb (GtkAction
*action
,
246 static void addressbook_edit_address_cb (GtkAction
*action
,
248 static void addressbook_delete_address_cb (GtkAction
*action
,
251 static void close_cb (GtkAction
*action
,
253 static void addressbook_file_save_cb (GtkAction
*action
,
256 /* Data source edit stuff */
257 static void addressbook_new_book_cb (GtkAction
*action
,
259 static void addressbook_new_vcard_cb (GtkAction
*action
,
263 static void addressbook_new_jpilot_cb (GtkAction
*action
,
268 static void addressbook_new_ldap_cb (GtkAction
*action
,
272 static void addressbook_set_clist (AddressObject
*obj
,
275 static void addressbook_load_tree (void);
276 void addressbook_read_file (void);
278 static GtkCMCTreeNode
*addressbook_add_object (GtkCMCTreeNode
*node
,
280 static void addressbook_treenode_remove_item ( void );
282 static AddressDataSource
*addressbook_find_datasource
283 (GtkCMCTreeNode
*node
);
285 static AddressBookFile
*addressbook_get_book_file(void);
287 static GtkCMCTreeNode
*addressbook_node_add_folder
288 (GtkCMCTreeNode
*node
,
289 AddressDataSource
*ds
,
290 ItemFolder
*itemFolder
,
291 AddressObjectType otype
);
292 static GtkCMCTreeNode
*addressbook_node_add_group (GtkCMCTreeNode
*node
,
293 AddressDataSource
*ds
,
294 ItemGroup
*itemGroup
);
295 static void addressbook_tree_remove_children (GtkCMCTree
*ctree
,
296 GtkCMCTreeNode
*parent
);
297 static void addressbook_move_nodes_up (GtkCMCTree
*ctree
,
298 GtkCMCTreeNode
*node
);
299 static GtkCMCTreeNode
*addressbook_find_group_node (GtkCMCTreeNode
*parent
,
301 static gboolean
addressbook_entry_key_pressed (GtkWidget
*widget
,
304 static gint
addressbook_treenode_compare_func (GtkCMCList
*clist
,
307 static void addressbook_folder_load_one_person (GtkCMCTree
*clist
,
309 AddressTypeControlItem
*atci
,
310 AddressTypeControlItem
*atciMail
);
311 static void addressbook_folder_remove_node (GtkCMCTree
*clist
,
312 GtkCMCTreeNode
*node
);
314 static void addressbook_edit_address( gpointer data
, guint action
, GtkWidget
*widget
,
315 gboolean force_focus
);
317 /* LUT's and IF stuff */
318 static void addressbook_free_treenode ( gpointer data
);
319 static AddressTypeControlItem
*addrbookctl_lookup (gint ot
);
320 static AddressTypeControlItem
*addrbookctl_lookup_iface(AddressIfType ifType
);
322 static void addrbookctl_build_map (GtkWidget
*window
);
323 static void addrbookctl_build_iflist (void);
324 static AdapterInterface
*addrbookctl_find_interface (AddressIfType ifType
);
325 static void addrbookctl_build_ifselect (void);
327 static void addrbookctl_free_interface (AdapterInterface
*adapter
);
328 static void addrbookctl_free_datasource (AdapterDSource
*adapter
);
329 static void addrbookctl_free_folder (AdapterFolder
*adapter
);
330 static void addrbookctl_free_group (AdapterGroup
*adapter
);
332 static void addressbook_list_select_clear ( void );
333 static void addressbook_list_select_add ( AddrItemObject
*aio
,
334 AddressDataSource
*ds
);
335 static void addressbook_list_select_remove ( AddrItemObject
*aio
);
337 static void addressbook_import_ldif_cb ( GtkAction
*action
, gpointer data
);
338 static void addressbook_find_duplicates_cb ( GtkAction
*action
, gpointer data
);
339 static void addressbook_edit_custom_attr_cb ( GtkAction
*action
, gpointer data
);
340 static void addressbook_import_mutt_cb ( GtkAction
*action
, gpointer data
);
341 static void addressbook_import_pine_cb ( GtkAction
*action
, gpointer data
);
342 static void addressbook_export_html_cb ( GtkAction
*action
, gpointer data
);
343 static void addressbook_export_ldif_cb ( GtkAction
*action
, gpointer data
);
344 static void addressbook_select_all_cb ( GtkAction
*action
, gpointer data
);
345 static void addressbook_clip_cut_cb ( GtkAction
*action
, gpointer data
);
346 static void addressbook_clip_copy_cb ( GtkAction
*action
, gpointer data
);
347 static void addressbook_clip_paste_cb ( GtkAction
*action
, gpointer data
);
348 static void addressbook_treenode_cut_cb ( GtkAction
*action
, gpointer data
);
349 static void addressbook_treenode_copy_cb ( GtkAction
*action
, gpointer data
);
350 static void addressbook_treenode_paste_cb ( GtkAction
*action
, gpointer data
);
352 static void addressbook_mail_to_cb ( GtkAction
*action
, gpointer data
);
353 static void addressbook_merge_cb ( GtkAction
*action
, gpointer data
);
356 static void addressbook_browse_entry_cb ( GtkAction
*action
, gpointer data
);
358 static void addressbook_edit_clicked(GtkButton
*button
, gpointer data
);
360 static void addressbook_start_drag(GtkWidget
*widget
, gint button
,
363 static void addressbook_drag_data_get(GtkWidget
*widget
,
364 GdkDragContext
*drag_context
,
365 GtkSelectionData
*selection_data
,
369 static gboolean
addressbook_drag_motion_cb(GtkWidget
*widget
,
370 GdkDragContext
*context
,
375 static void addressbook_drag_leave_cb(GtkWidget
*widget
,
376 GdkDragContext
*context
,
379 static void addressbook_drag_received_cb(GtkWidget
*widget
,
380 GdkDragContext
*drag_context
,
383 GtkSelectionData
*data
,
387 static void addressbook_list_menu_setup( void );
389 static GtkTargetEntry addressbook_drag_types
[] =
391 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
}
394 static GtkTargetList
*addressbook_target_list
= NULL
;
396 static void about_show_cb(GtkAction
*action
, gpointer data
)
401 static GtkActionEntry addressbook_entries
[] =
403 {"Menu", NULL
, "Menu", NULL
, NULL
, NULL
},
405 {"Book", NULL
, N_("_Book"), NULL
, NULL
, NULL
},
406 {"Edit", NULL
, N_("_Edit"), NULL
, NULL
, NULL
},
407 {"Tools", NULL
, N_("_Tools"), NULL
, NULL
, NULL
},
410 {"Book/NewBook", NULL
, N_("New _Book"), "<control>B", NULL
, G_CALLBACK(addressbook_new_book_cb
) },
411 {"Book/NewFolder", NULL
, N_("New _Folder"), "<control>R", NULL
, G_CALLBACK(addressbook_new_folder_cb
) },
412 {"Book/NewVCard", NULL
, N_("New _vCard"), "<control><shift>D", NULL
, G_CALLBACK(addressbook_new_vcard_cb
) },
416 {"Book/NewJPilot", NULL
, N_("New _JPilot"), "<control>J", NULL
, G_CALLBACK(addressbook_new_jpilot_cb
) },
419 {"Book/NewLDAPServer", NULL
, N_("New LDAP _Server"), "<control><shift>S", NULL
, G_CALLBACK(addressbook_new_ldap_cb
) },
421 {"Book/---", NULL
, "---", NULL
, NULL
, NULL
},
423 {"Book/EditBook", NULL
, N_("_Edit book"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_edit_cb
) },
424 {"Book/DeleteBook", NULL
, N_("_Delete book"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_delete_cb
) },
425 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
426 {"Book/Save", NULL
, N_("_Save"), "<control>S", NULL
, G_CALLBACK(addressbook_file_save_cb
) },
427 {"Book/Close", NULL
, N_("_Close"), "<control>W", NULL
, G_CALLBACK(close_cb
) },
430 {"Address/SelectAll", NULL
, N_("_Select all"), "<control>A", NULL
, G_CALLBACK(addressbook_select_all_cb
) },
431 {"Address/---", NULL
, "---", NULL
, NULL
, NULL
},
432 {"Address/Cut", NULL
, N_("C_ut"), "<control>X", NULL
, G_CALLBACK(addressbook_clip_cut_cb
) },
433 {"Address/Copy", NULL
, N_("_Copy"), "<control>C", NULL
, G_CALLBACK(addressbook_clip_copy_cb
) },
434 {"Address/Paste", NULL
, N_("_Paste"), "<control>V", NULL
, G_CALLBACK(addressbook_clip_paste_cb
) },
435 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
436 {"Address/Edit", NULL
, N_("_Edit"), "<control>Return", NULL
, G_CALLBACK(addressbook_edit_address_cb
) },
437 {"Address/Delete", NULL
, N_("_Delete"), "<control>D", NULL
, G_CALLBACK(addressbook_delete_address_cb
) },
438 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
439 {"Address/NewAddress", NULL
, N_("New _Address"), "<control>N", NULL
, G_CALLBACK(addressbook_new_address_cb
) },
440 {"Address/NewGroup", NULL
, N_("New _Group"), "<control>G", NULL
, G_CALLBACK(addressbook_new_group_cb
) },
441 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
442 {"Address/Mailto", NULL
, N_("_Mail To"), "<control>M", NULL
, G_CALLBACK(addressbook_mail_to_cb
) },
443 {"Address/Merge", NULL
, N_("_Merge"), "<control>E", NULL
, G_CALLBACK(addressbook_merge_cb
) },
447 {"Tools/ImportLDIF", NULL
, N_("Import _LDIF file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_ldif_cb
) },
448 {"Tools/ImportMutt", NULL
, N_("Import M_utt file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_mutt_cb
) },
449 {"Tools/ImportPine", NULL
, N_("Import _Pine file..."), NULL
, NULL
, G_CALLBACK(addressbook_import_pine_cb
) },
450 {"Tools/---", NULL
, "---", NULL
, NULL
, NULL
},
451 {"Tools/ExportHTML", NULL
, N_("Export _HTML..."), NULL
, NULL
, G_CALLBACK(addressbook_export_html_cb
) },
452 {"Tools/ExportLDIF", NULL
, N_("Export LDI_F..."), NULL
, NULL
, G_CALLBACK(addressbook_export_ldif_cb
) },
453 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
454 {"Tools/FindDuplicates", NULL
, N_("Find duplicates..."), NULL
, NULL
, G_CALLBACK(addressbook_find_duplicates_cb
) },
455 {"Tools/EditAttrs", NULL
, N_("Edit custom attributes..."), NULL
, NULL
, G_CALLBACK(addressbook_edit_custom_attr_cb
) },
458 static GtkActionEntry addressbook_tree_popup_entries
[] =
460 {"ABTreePopup", NULL
, "ABTreePopup", NULL
, NULL
, NULL
},
461 {"ABTreePopup/EditBook", NULL
, N_("_Edit"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_edit_cb
) },
462 {"ABTreePopup/DeleteBook", NULL
, N_("_Delete"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_delete_cb
) },
463 {"ABTreePopup/---", NULL
, "---", NULL
, NULL
, NULL
},
464 {"ABTreePopup/NewBook", NULL
, N_("New _Book"), NULL
, NULL
, G_CALLBACK(addressbook_new_book_cb
) },
465 {"ABTreePopup/NewFolder", NULL
, N_("New _Folder"), NULL
, NULL
, G_CALLBACK(addressbook_new_folder_cb
) },
466 {"ABTreePopup/NewGroup", NULL
, N_("New _Group"), NULL
, NULL
, G_CALLBACK(addressbook_new_group_cb
) },
467 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
468 {"ABTreePopup/Cut", NULL
, N_("C_ut"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_cut_cb
) },
469 {"ABTreePopup/Copy", NULL
, N_("_Copy"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_copy_cb
) },
470 {"ABTreePopup/Paste", NULL
, N_("_Paste"), NULL
, NULL
, G_CALLBACK(addressbook_treenode_paste_cb
) },
473 static GtkActionEntry addressbook_list_popup_entries
[] =
475 {"ABListPopup", NULL
, "ABListPopup", NULL
, NULL
, NULL
},
476 {"ABListPopup/SelectAll", NULL
, N_("_Select all"), NULL
, NULL
, G_CALLBACK(addressbook_select_all_cb
) },
477 {"ABListPopup/---", NULL
, "---", NULL
, NULL
, NULL
},
478 {"ABListPopup/Edit", NULL
, N_("_Edit"), NULL
, NULL
, G_CALLBACK(addressbook_edit_address_cb
) },
479 {"ABListPopup/Delete", NULL
, N_("_Delete"), NULL
, NULL
, G_CALLBACK(addressbook_delete_address_cb
) },
480 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
481 {"ABListPopup/NewAddress", NULL
, N_("New _Address"), NULL
, NULL
, G_CALLBACK(addressbook_new_address_cb
) },
482 {"ABListPopup/NewGroup", NULL
, N_("New _Group"), NULL
, NULL
, G_CALLBACK(addressbook_new_group_cb
) },
483 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
484 {"ABListPopup/Cut", NULL
, N_("C_ut"), NULL
, NULL
, G_CALLBACK(addressbook_clip_cut_cb
) },
485 {"ABListPopup/Copy", NULL
, N_("_Copy"), NULL
, NULL
, G_CALLBACK(addressbook_clip_copy_cb
) },
486 {"ABListPopup/Paste", NULL
, N_("_Paste"), NULL
, NULL
, G_CALLBACK(addressbook_clip_paste_cb
) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Mailto", NULL
, N_("_Mail To"), NULL
, NULL
, G_CALLBACK(addressbook_mail_to_cb
) },
490 {"ABListPopup/BrowseEntry", NULL
, N_("_Browse Entry"), NULL
, NULL
, G_CALLBACK(addressbook_browse_entry_cb
) },
492 {"ABListPopup/Merge", NULL
, N_("_Merge"), NULL
, NULL
, G_CALLBACK(addressbook_merge_cb
) },
496 * Structure of error message table.
498 typedef struct _ErrMsgTableEntry ErrMsgTableEntry
;
499 struct _ErrMsgTableEntry
{
504 static gchar
*_errMsgUnknown_
= N_( "Unknown" );
507 * Lookup table of error messages for general errors. Note that a NULL
508 * description signifies the end of the table.
510 static ErrMsgTableEntry _lutErrorsGeneral_
[] = {
511 { MGU_SUCCESS
, N_("Success") },
512 { MGU_BAD_ARGS
, N_("Bad arguments") },
513 { MGU_NO_FILE
, N_("File not specified") },
514 { MGU_OPEN_FILE
, N_("Error opening file") },
515 { MGU_ERROR_READ
, N_("Error reading file") },
516 { MGU_EOF
, N_("End of file encountered") },
517 { MGU_OO_MEMORY
, N_("Error allocating memory") },
518 { MGU_BAD_FORMAT
, N_("Bad file format") },
519 { MGU_ERROR_WRITE
, N_("Error writing to file") },
520 { MGU_OPEN_DIRECTORY
, N_("Error opening directory") },
521 { MGU_NO_PATH
, N_("No path specified") },
527 * Lookup table of error messages for LDAP errors.
529 static ErrMsgTableEntry _lutErrorsLDAP_
[] = {
530 { LDAPRC_SUCCESS
, N_("Success") },
531 { LDAPRC_CONNECT
, N_("Error connecting to LDAP server") },
532 { LDAPRC_INIT
, N_("Error initializing LDAP") },
533 { LDAPRC_BIND
, N_("Error binding to LDAP server") },
534 { LDAPRC_SEARCH
, N_("Error searching LDAP database") },
535 { LDAPRC_TIMEOUT
, N_("Timeout performing LDAP operation") },
536 { LDAPRC_CRITERIA
, N_("Error in LDAP search criteria") },
537 { LDAPRC_NOENTRIES
, N_("No LDAP entries found for search criteria") },
538 { LDAPRC_STOP_FLAG
, N_("LDAP search terminated on request") },
539 { LDAPRC_TLS
, N_("Error starting STARTTLS connection") },
540 { LDAPRC_NODN
, N_("Distinguished Name (dn) is missing") },
541 { LDAPRC_NAMING_VIOLATION
, N_("Missing required information") },
542 { LDAPRC_ALREADY_EXIST
, N_("Another contact exists with that key") },
543 { LDAPRC_STRONG_AUTH
, N_("Strong(er) authentication required") },
549 * Lookup message for specified error code.
550 * \param lut Lookup table.
551 * \param code Code to lookup.
552 * \return Description associated to code.
554 static gchar
*addressbook_err2string( ErrMsgTableEntry lut
[], gint code
) {
556 ErrMsgTableEntry entry
;
559 for( i
= 0; ; i
++ ) {
561 if( entry
.description
== NULL
) break;
562 if( entry
.code
== code
) {
563 desc
= entry
.description
;
568 desc
= _errMsgUnknown_
;
573 static gboolean lastCanLookup
= FALSE
;
575 static void addressbook_show_buttons(gboolean add_and_delete
, gboolean lookup
, gboolean mail_ops
)
577 if (add_and_delete
) {
578 gtk_widget_show(addrbook
.edit_btn
);
579 gtk_widget_show(addrbook
.del_btn
);
580 gtk_widget_show(addrbook
.reg_btn
);
582 gtk_widget_hide(addrbook
.edit_btn
);
583 gtk_widget_hide(addrbook
.del_btn
);
584 gtk_widget_hide(addrbook
.reg_btn
);
588 gtk_widget_show(addrbook
.lup_btn
);
589 gtk_widget_show(addrbook
.entry
);
590 gtk_widget_show(addrbook
.label
);
592 gtk_widget_hide(addrbook
.lup_btn
);
593 gtk_widget_hide(addrbook
.entry
);
594 gtk_widget_hide(addrbook
.label
);
597 lastCanLookup
= lookup
;
600 gtk_widget_show(addrbook
.to_btn
);
601 gtk_widget_show(addrbook
.cc_btn
);
602 gtk_widget_show(addrbook
.bcc_btn
);
604 gtk_widget_hide(addrbook
.to_btn
);
605 gtk_widget_hide(addrbook
.cc_btn
);
606 gtk_widget_hide(addrbook
.bcc_btn
);
610 void addressbook_open(Compose
*target
)
612 /* Initialize all static members */
613 if( _clipBoard_
== NULL
) {
614 _clipBoard_
= addrclip_create();
616 if( _addressIndex_
!= NULL
) {
617 addrclip_set_index( _clipBoard_
, _addressIndex_
);
619 if( _addressSelect_
== NULL
) {
620 _addressSelect_
= addrselect_list_create();
622 if (!addrbook
.window
) {
623 addressbook_read_file();
624 addressbook_create();
625 addressbook_load_tree();
626 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
627 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook
.ctree
)->row_list
));
630 gtk_widget_hide(addrbook
.window
);
633 gtk_widget_show_all(addrbook
.window
);
635 if (!prefs_common
.addressbook_use_editaddress_dialog
)
636 addressbook_edit_person_widgetset_hide();
638 address_completion_start(addrbook
.window
);
640 addressbook_show_buttons(target
== NULL
, lastCanLookup
, target
!= NULL
);
641 addressbook_set_target_compose(target
);
645 * Destroy addressbook.
647 void addressbook_destroy( void ) {
648 /* Free up address stuff */
649 if( _addressSelect_
!= NULL
) {
650 addrselect_list_free( _addressSelect_
);
652 if( _clipBoard_
!= NULL
) {
653 addrclip_free( _clipBoard_
);
656 if( _addressIndex_
!= NULL
) {
657 addrindex_free_index( _addressIndex_
);
658 addrindex_teardown();
660 _addressSelect_
= NULL
;
662 _addressIndex_
= NULL
;
665 void addressbook_set_target_compose(Compose
*target
)
667 addrbook
.target_compose
= target
;
670 Compose
*addressbook_get_target_compose(void)
672 return addrbook
.target_compose
;
676 * Refresh addressbook and save to file(s).
678 void addressbook_refresh( void )
680 if (addrbook
.window
) {
681 if (addrbook
.treeSelected
) {
682 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
683 addrbook
.treeSelected
);
684 addressbook_set_clist(
685 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
686 addrbook
.treeSelected
),
691 addressbook_export_to_file();
694 static gboolean
key_pressed(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
696 if (event
&& event
->keyval
== GDK_KEY_Escape
)
698 else if (event
&& event
->keyval
== GDK_KEY_Delete
) {
699 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
700 if ( /* address_index_has_focus || */ address_list_has_focus
)
701 addressbook_del_clicked(NULL
, NULL
);
707 *\brief Save Gtk object size to prefs dataset
709 static void addressbook_size_allocate_cb(GtkWidget
*widget
,
710 GtkAllocation
*allocation
)
712 cm_return_if_fail(allocation
!= NULL
);
714 prefs_common
.addressbookwin_width
= allocation
->width
;
715 prefs_common
.addressbookwin_height
= allocation
->height
;
718 static gint sort_column_number
= 0;
719 static GtkSortType sort_column_type
= GTK_SORT_ASCENDING
;
721 static gint
list_case_sort(
722 GtkCMCList
*clist
, gconstpointer ptr1
, gconstpointer ptr2
)
724 GtkCMCListRow
*row1
= (GtkCMCListRow
*) ptr1
;
725 GtkCMCListRow
*row2
= (GtkCMCListRow
*) ptr2
;
726 gchar
*name1
= NULL
, *name2
= NULL
;
727 AddrItemObject
*aio1
= ((GtkCMCListRow
*)ptr1
)->data
;
728 AddrItemObject
*aio2
= ((GtkCMCListRow
*)ptr2
)->data
;
730 if( aio1
->type
== aio2
->type
) {
732 name1
= GTK_CMCELL_TEXT (row1
->cell
[sort_column_number
])->text
;
734 name2
= GTK_CMCELL_TEXT (row2
->cell
[sort_column_number
])->text
;
735 if( ! name1
) return ( name2
!= NULL
);
736 if( ! name2
) return -1;
737 return g_utf8_collate( name1
, name2
);
739 /* Order groups before person */
740 if( aio1
->type
== ITEMTYPE_GROUP
) {
741 return (sort_column_type
==GTK_SORT_ASCENDING
) ? -1:+1;
742 } else if( aio2
->type
== ITEMTYPE_GROUP
) {
743 return (sort_column_type
==GTK_SORT_ASCENDING
) ? +1:-1;
749 static void addressbook_sort_list(GtkCMCList
*clist
, const gint col
,
750 const GtkSortType sort_type
)
753 GtkWidget
*hbox
, *label
, *arrow
;
755 sort_column_number
= col
;
756 sort_column_type
= sort_type
;
757 gtk_cmclist_set_compare_func(clist
, list_case_sort
);
758 gtk_cmclist_set_sort_type(clist
, sort_type
);
759 gtk_cmclist_set_sort_column(clist
, col
);
761 gtk_cmclist_freeze(clist
);
762 gtk_cmclist_sort(clist
);
764 for(pos
= 0 ; pos
< N_LIST_COLS
; pos
++) {
765 hbox
= gtk_hbox_new(FALSE
, 4);
766 label
= gtk_label_new(gettext(list_titles
[pos
]));
767 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
770 arrow
= gtk_arrow_new(sort_type
== GTK_SORT_ASCENDING
?
771 GTK_ARROW_DOWN
: GTK_ARROW_UP
, GTK_SHADOW_IN
);
772 gtk_box_pack_end(GTK_BOX(hbox
), arrow
, FALSE
, FALSE
, 0);
775 gtk_widget_show_all(hbox
);
776 gtk_cmclist_set_column_widget(clist
, pos
, hbox
);
779 gtk_cmclist_thaw(clist
);
782 static void addressbook_name_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
784 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
786 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
788 addressbook_sort_list(clist
, COL_NAME
, sort_type
);
791 static void addressbook_address_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
793 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
795 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
797 addressbook_sort_list(clist
, COL_ADDRESS
, sort_type
);
800 static void addressbook_remarks_clicked(GtkWidget
*button
, GtkCMCList
*clist
)
802 static GtkSortType sort_type
= GTK_SORT_ASCENDING
;
804 sort_type
= (sort_type
== GTK_SORT_ASCENDING
) ? GTK_SORT_DESCENDING
:
806 addressbook_sort_list(clist
, COL_REMARKS
, sort_type
);
809 static gboolean
addressbook_address_index_focus_evt_in(GtkWidget
*widget
, GdkEventFocus
*event
,
812 address_index_has_focus
= TRUE
;
816 static gboolean
addressbook_address_index_focus_evt_out(GtkWidget
*widget
, GdkEventFocus
*event
,
819 address_index_has_focus
= FALSE
;
820 if (!prefs_common
.addressbook_use_editaddress_dialog
821 && !address_list_has_focus
)
822 addressbook_address_list_disable_some_actions();
826 static gboolean
addressbook_address_list_focus_evt_in(GtkWidget
*widget
, GdkEventFocus
*event
,
829 address_list_has_focus
= TRUE
;
833 static gboolean
addressbook_address_list_focus_evt_out(GtkWidget
*widget
, GdkEventFocus
*event
,
836 address_list_has_focus
= FALSE
;
837 if (!prefs_common
.addressbook_use_editaddress_dialog
838 && !address_index_has_focus
)
839 addressbook_address_list_disable_some_actions();
843 /* save hpane and vpane's handle position when it moves */
844 static void addressbook_pane_save_position(void)
847 prefs_common
.addressbook_hpaned_pos
=
848 gtk_paned_get_position(GTK_PANED(addrbook
.hpaned
));
850 prefs_common
.addressbook_vpaned_pos
=
851 gtk_paned_get_position(GTK_PANED(addrbook
.vpaned
));
855 * Create the address book widgets. The address book contains two CTree widgets: the
856 * address index tree on the left and the address list on the right.
858 * The address index tree displays a hierarchy of interfaces and groups. Each node in
859 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
860 * data sources and folder objects.
862 * The address list displays group, person and email objects. These items are linked
863 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
866 * In the tradition of MVC architecture, the data stores have been separated from the
867 * GUI components. The addrindex.c file provides the interface to all data stores.
869 static void addressbook_create(void)
875 GtkWidget
*ctree_swin
;
877 GtkWidget
*editaddress_vbox
;
878 GtkWidget
*clist_vbox
;
879 GtkWidget
*clist_swin
;
886 GtkWidget
*statusbar
;
897 GtkWidget
*close_btn
;
898 GtkWidget
*tree_popup
;
899 GtkWidget
*list_popup
;
901 GtkUIManager
*ui_manager
;
902 GtkActionGroup
*action_group
;
903 gchar
*index_titles
[N_INDEX_COLS
];
907 static GdkGeometry geometry
;
909 debug_print("Creating addressbook window...\n");
911 index_titles
[COL_SOURCES
] = _("Sources");
913 /* Address book window */
914 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "addressbook");
915 gtk_window_set_title(GTK_WINDOW(window
), _("Address book"));
916 gtk_window_set_resizable(GTK_WINDOW(window
), TRUE
);
917 gtk_window_set_type_hint(GTK_WINDOW(window
), GDK_WINDOW_TYPE_HINT_DIALOG
);
918 gtk_widget_realize(window
);
920 g_signal_connect(G_OBJECT(window
), "delete_event",
921 G_CALLBACK(addressbook_close
), NULL
);
922 g_signal_connect(G_OBJECT(window
), "size_allocate",
923 G_CALLBACK(addressbook_size_allocate_cb
), NULL
);
924 g_signal_connect(G_OBJECT(window
), "key_press_event",
925 G_CALLBACK(key_pressed
), NULL
);
926 MANAGE_WINDOW_SIGNALS_CONNECT(window
);
928 vbox
= gtk_vbox_new(FALSE
, 0);
929 gtk_container_add(GTK_CONTAINER(window
), vbox
);
932 ui_manager
= gtk_ui_manager_new();
933 action_group
= cm_menu_create_action_group_full(ui_manager
,"Menu", addressbook_entries
,
934 G_N_ELEMENTS(addressbook_entries
), NULL
);
935 gtk_action_group_add_actions(action_group
, addressbook_tree_popup_entries
,
936 G_N_ELEMENTS(addressbook_tree_popup_entries
), NULL
);
937 gtk_action_group_add_actions(action_group
, addressbook_list_popup_entries
,
938 G_N_ELEMENTS(addressbook_list_popup_entries
), NULL
);
940 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Menu", NULL
, GTK_UI_MANAGER_MENUBAR
)
942 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU
)
943 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU
)
944 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU
)
947 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM
)
948 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM
)
949 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM
)
951 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM
)
954 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM
)
956 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR
)
957 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM
)
958 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM
)
959 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR
)
960 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM
)
961 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM
)
964 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM
)
965 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
966 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM
)
967 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM
)
968 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM
)
969 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
970 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM
)
971 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM
)
972 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
973 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM
)
974 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM
)
975 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR
)
976 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM
)
977 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM
)
980 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM
)
981 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM
)
982 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM
)
983 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR
)
984 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM
)
985 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM
)
986 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR
)
987 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM
)
988 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM
)
990 gtk_window_add_accel_group(GTK_WINDOW(window
),
991 gtk_ui_manager_get_accel_group(ui_manager
));
993 menubar
= gtk_ui_manager_get_widget(ui_manager
, "/Menu");
995 gtk_box_pack_start(GTK_BOX(vbox
), menubar
, FALSE
, TRUE
, 0);
997 vbox2
= gtk_vbox_new(FALSE
, BORDER_WIDTH
);
998 gtk_container_set_border_width(GTK_CONTAINER(vbox2
), BORDER_WIDTH
);
999 gtk_box_pack_start(GTK_BOX(vbox
), vbox2
, TRUE
, TRUE
, 0);
1001 ctree_swin
= gtk_scrolled_window_new(NULL
, NULL
);
1002 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin
),
1003 GTK_POLICY_AUTOMATIC
,
1004 GTK_POLICY_AUTOMATIC
);
1005 gtk_widget_set_size_request(ctree_swin
, COL_FOLDER_WIDTH
+ 20, -1);
1008 ctree
= gtk_sctree_new_with_titles(N_INDEX_COLS
, 0, index_titles
);
1009 gtk_widget_set_can_focus(GTK_CMCLIST(ctree
)->column
[0].button
, FALSE
);
1011 gtk_container_add(GTK_CONTAINER(ctree_swin
), ctree
);
1012 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree
), GTK_SELECTION_BROWSE
);
1013 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree
), 0, COL_FOLDER_WIDTH
);
1014 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree
),
1015 GTK_CMCTREE_EXPANDER_TRIANGLE
);
1016 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
1017 gtk_cmctree_set_indent(GTK_CMCTREE(ctree
), CTREE_INDENT
);
1018 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree
),
1019 addressbook_treenode_compare_func
);
1021 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
1022 G_CALLBACK(addressbook_tree_selected
), NULL
);
1023 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
1024 G_CALLBACK(addressbook_tree_button_pressed
),
1026 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
1027 G_CALLBACK(addressbook_tree_button_released
),
1030 g_signal_connect(G_OBJECT(ctree
), "select_row",
1031 G_CALLBACK(addressbook_select_row_tree
), NULL
);
1033 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
1034 addressbook_drag_types
, 1,
1035 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
1036 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
1037 G_CALLBACK(addressbook_drag_motion_cb
),
1039 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
1040 G_CALLBACK(addressbook_drag_leave_cb
),
1042 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
1043 G_CALLBACK(addressbook_drag_received_cb
),
1045 g_signal_connect(G_OBJECT(ctree
), "focus_in_event",
1046 G_CALLBACK(addressbook_address_index_focus_evt_in
), NULL
);
1047 g_signal_connect(G_OBJECT(ctree
), "focus_out_event",
1048 G_CALLBACK(addressbook_address_index_focus_evt_out
), NULL
);
1050 clist_vbox
= gtk_vbox_new(FALSE
, 4);
1052 clist_swin
= gtk_scrolled_window_new(NULL
, NULL
);
1053 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin
),
1054 GTK_POLICY_AUTOMATIC
,
1055 GTK_POLICY_AUTOMATIC
);
1056 gtk_box_pack_start(GTK_BOX(clist_vbox
), clist_swin
, TRUE
, TRUE
, 0);
1059 clist
= gtk_sctree_new_with_titles(N_LIST_COLS
, 0, list_titles
);
1060 gtk_container_add(GTK_CONTAINER(clist_swin
), clist
);
1061 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist
), GTK_SELECTION_MULTIPLE
);
1062 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist
),
1063 GTK_CMCTREE_EXPANDER_TRIANGLE
);
1064 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
1065 gtk_cmctree_set_indent(GTK_CMCTREE(clist
), CTREE_INDENT
);
1066 gtk_cmclist_set_column_width(GTK_CMCLIST(clist
), COL_NAME
,
1068 gtk_cmclist_set_column_width(GTK_CMCLIST(clist
), COL_ADDRESS
,
1070 gtk_widget_set_size_request(clist
, -1, 80);
1072 addressbook_sort_list(GTK_CMCLIST(clist
), COL_NAME
, GTK_SORT_ASCENDING
);
1073 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_NAME
].button
),
1074 "clicked", G_CALLBACK(addressbook_name_clicked
), clist
);
1075 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_ADDRESS
].button
),
1076 "clicked", G_CALLBACK(addressbook_address_clicked
), clist
);
1077 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist
)->column
[COL_REMARKS
].button
),
1078 "clicked", G_CALLBACK(addressbook_remarks_clicked
), clist
);
1079 g_signal_connect(G_OBJECT(clist
), "focus_in_event",
1080 G_CALLBACK(addressbook_address_list_focus_evt_in
), NULL
);
1081 g_signal_connect(G_OBJECT(clist
), "focus_out_event",
1082 G_CALLBACK(addressbook_address_list_focus_evt_out
), NULL
);
1084 for (i
= 0; i
< N_LIST_COLS
; i
++)
1085 gtk_widget_set_can_focus(GTK_CMCLIST(clist
)->column
[i
].button
,
1088 g_signal_connect(G_OBJECT(clist
), "tree_select_row",
1089 G_CALLBACK(addressbook_list_row_selected
), NULL
);
1090 g_signal_connect(G_OBJECT(clist
), "tree_unselect_row",
1091 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1092 g_signal_connect(G_OBJECT(clist
), "button_press_event",
1093 G_CALLBACK(addressbook_list_button_pressed
),
1095 g_signal_connect(G_OBJECT(clist
), "button_release_event",
1096 G_CALLBACK(addressbook_list_button_released
),
1098 g_signal_connect(G_OBJECT(clist
), "tree_expand",
1099 G_CALLBACK(addressbook_person_expand_node
), NULL
);
1100 g_signal_connect(G_OBJECT(clist
), "tree_collapse",
1101 G_CALLBACK(addressbook_person_collapse_node
), NULL
);
1102 g_signal_connect(G_OBJECT(clist
), "start_drag",
1103 G_CALLBACK(addressbook_start_drag
), NULL
);
1104 g_signal_connect(G_OBJECT(clist
), "drag_data_get",
1105 G_CALLBACK(addressbook_drag_data_get
), NULL
);
1106 hbox
= gtk_hbox_new(FALSE
, 4);
1107 gtk_box_pack_start(GTK_BOX(clist_vbox
), hbox
, FALSE
, FALSE
, 0);
1109 label
= gtk_label_new(_("Search"));
1110 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1112 entry
= gtk_entry_new();
1113 gtk_box_pack_start(GTK_BOX(hbox
), entry
, TRUE
, TRUE
, 0);
1115 address_completion_register_entry(GTK_ENTRY(entry
), FALSE
);
1117 g_signal_connect(G_OBJECT(entry
), "key_press_event",
1118 G_CALLBACK(addressbook_entry_key_pressed
),
1120 g_signal_connect(G_OBJECT(entry
), "activate",
1121 G_CALLBACK(addressbook_entry_activated
), NULL
);
1123 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
1124 editaddress_vbox
= gtk_vbox_new(FALSE
, 4);
1125 vpaned
= gtk_vpaned_new();
1126 gtk_paned_pack1(GTK_PANED(vpaned
), clist_vbox
, FALSE
, FALSE
);
1127 gtk_paned_pack2(GTK_PANED(vpaned
), editaddress_vbox
, TRUE
, FALSE
);
1130 editaddress_vbox
= NULL
;
1132 hpaned
= gtk_hpaned_new();
1133 gtk_box_pack_start(GTK_BOX(vbox2
), hpaned
, TRUE
, TRUE
, 0);
1134 gtk_paned_pack1(GTK_PANED(hpaned
), ctree_swin
, FALSE
, FALSE
);
1135 if (prefs_common
.addressbook_use_editaddress_dialog
)
1136 gtk_paned_pack2(GTK_PANED(hpaned
), clist_vbox
, TRUE
, FALSE
);
1138 gtk_paned_pack2(GTK_PANED(hpaned
), vpaned
, TRUE
, FALSE
);
1141 hsbox
= gtk_hbox_new(FALSE
, 0);
1142 gtk_box_pack_end(GTK_BOX(vbox
), hsbox
, FALSE
, FALSE
, BORDER_WIDTH
);
1143 statusbar
= gtk_statusbar_new();
1144 gtk_box_pack_start(GTK_BOX(hsbox
), statusbar
, TRUE
, TRUE
, BORDER_WIDTH
);
1147 hbbox
= gtk_hbutton_box_new();
1148 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox
), GTK_BUTTONBOX_END
);
1149 gtk_box_set_spacing(GTK_BOX(hbbox
), 2);
1150 gtk_container_set_border_width(GTK_CONTAINER(hbbox
), 4);
1151 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
1153 gtkut_stock_button_add_help(hbbox
, &help_btn
);
1155 edit_btn
= gtk_button_new_from_stock(GTK_STOCK_EDIT
);
1156 gtk_widget_set_can_default(edit_btn
, TRUE
);
1157 gtk_box_pack_start(GTK_BOX(hbbox
), edit_btn
, TRUE
, TRUE
, 0);
1158 del_btn
= gtk_button_new_from_stock(GTK_STOCK_DELETE
);
1159 gtk_widget_set_can_default(del_btn
, TRUE
);
1160 gtk_box_pack_start(GTK_BOX(hbbox
), del_btn
, TRUE
, TRUE
, 0);
1161 reg_btn
= gtk_button_new_from_stock(GTK_STOCK_NEW
);
1162 gtk_widget_set_can_default(reg_btn
, TRUE
);
1163 gtk_box_pack_start(GTK_BOX(hbbox
), reg_btn
, TRUE
, TRUE
, 0);
1166 lup_btn
= gtk_button_new_from_stock(GTK_STOCK_FIND
);
1167 gtk_widget_set_can_default(lup_btn
, TRUE
);
1168 gtk_box_pack_start(GTK_BOX(hbox
), lup_btn
, TRUE
, TRUE
, 0);
1170 g_signal_connect(G_OBJECT(help_btn
), "clicked",
1171 G_CALLBACK(manual_open_with_anchor_cb
),
1172 MANUAL_ANCHOR_ADDRBOOK
);
1174 g_signal_connect(G_OBJECT(edit_btn
), "clicked",
1175 G_CALLBACK(addressbook_edit_clicked
), NULL
);
1176 g_signal_connect(G_OBJECT(del_btn
), "clicked",
1177 G_CALLBACK(addressbook_del_clicked
), NULL
);
1178 g_signal_connect(G_OBJECT(reg_btn
), "clicked",
1179 G_CALLBACK(addressbook_reg_clicked
), NULL
);
1180 g_signal_connect(G_OBJECT(lup_btn
), "clicked",
1181 G_CALLBACK(addressbook_lup_clicked
), NULL
);
1183 to_btn
= gtk_button_new_with_label
1184 (prefs_common_translated_header_name("To:"));
1185 gtk_widget_set_can_default(to_btn
, TRUE
);
1186 gtk_box_pack_start(GTK_BOX(hbbox
), to_btn
, TRUE
, TRUE
, 0);
1187 cc_btn
= gtk_button_new_with_label
1188 (prefs_common_translated_header_name("Cc:"));
1189 gtk_widget_set_can_default(cc_btn
, TRUE
);
1190 gtk_box_pack_start(GTK_BOX(hbbox
), cc_btn
, TRUE
, TRUE
, 0);
1191 bcc_btn
= gtk_button_new_with_label
1192 (prefs_common_translated_header_name("Bcc:"));
1193 gtk_widget_set_can_default(bcc_btn
, TRUE
);
1194 gtk_box_pack_start(GTK_BOX(hbbox
), bcc_btn
, TRUE
, TRUE
, 0);
1196 close_btn
= gtk_button_new_from_stock(GTK_STOCK_CLOSE
);
1197 gtk_widget_set_can_default(close_btn
, TRUE
);
1198 gtk_box_pack_start(GTK_BOX(hbbox
), close_btn
, TRUE
, TRUE
, 0);
1200 g_signal_connect(G_OBJECT(to_btn
), "clicked",
1201 G_CALLBACK(addressbook_to_clicked
),
1202 GINT_TO_POINTER(COMPOSE_TO
));
1203 g_signal_connect(G_OBJECT(cc_btn
), "clicked",
1204 G_CALLBACK(addressbook_to_clicked
),
1205 GINT_TO_POINTER(COMPOSE_CC
));
1206 g_signal_connect(G_OBJECT(bcc_btn
), "clicked",
1207 G_CALLBACK(addressbook_to_clicked
),
1208 GINT_TO_POINTER(COMPOSE_BCC
));
1209 g_signal_connect(G_OBJECT(close_btn
), "clicked",
1210 G_CALLBACK(addressbook_close_clicked
), NULL
);
1212 /* Build icons for interface */
1214 /* Build control tables */
1215 addrbookctl_build_map(window
);
1216 addrbookctl_build_iflist();
1217 addrbookctl_build_ifselect();
1219 addrbook
.clist
= NULL
;
1221 /* Add each interface into the tree as a root level folder */
1222 nodeIf
= _addressInterfaceList_
;
1224 AdapterInterface
*adapter
= nodeIf
->data
;
1225 AddressInterface
*iface
= adapter
->interface
;
1226 nodeIf
= g_list_next(nodeIf
);
1228 if(iface
->useInterface
) {
1229 AddressTypeControlItem
*atci
= adapter
->atci
;
1230 text
= atci
->displayName
;
1232 gtk_sctree_insert_node( GTK_CMCTREE(ctree
),
1233 NULL
, NULL
, &text
, FOLDER_SPACING
,
1237 cm_menu_set_sensitive_full(ui_manager
, atci
->menuCommand
, adapter
->haveLibrary
);
1238 gtk_cmctree_node_set_row_data_full(
1239 GTK_CMCTREE(ctree
), adapter
->treeNode
, adapter
,
1240 addressbook_free_treenode
);
1246 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Popups", NULL
, GTK_UI_MANAGER_MENUBAR
);
1247 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU
)
1248 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM
)
1249 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM
)
1250 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR
)
1251 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM
)
1252 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM
)
1253 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM
)
1254 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR
)
1255 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM
)
1256 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM
)
1257 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM
)
1259 tree_popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1260 gtk_ui_manager_get_widget(ui_manager
, "/Popups/ABTreePopup")));
1262 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU
)
1263 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM
)
1264 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1265 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM
)
1266 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM
)
1267 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1268 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM
)
1269 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM
)
1270 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1271 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM
)
1272 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM
)
1273 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM
)
1274 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1275 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM
)
1277 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM
)
1279 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM
)
1280 list_popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1281 gtk_ui_manager_get_widget(ui_manager
, "/Popups/ABListPopup")));
1283 addrbook
.window
= window
;
1284 addrbook
.hpaned
= hpaned
;
1285 addrbook
.vpaned
= vpaned
;
1286 addrbook
.menubar
= menubar
;
1287 addrbook
.ctree
= ctree
;
1290 addrbook
.editaddress_vbox
= editaddress_vbox
;
1291 addrbook
.clist
= clist
;
1292 addrbook
.label
= label
;
1293 addrbook
.entry
= entry
;
1294 addrbook
.statusbar
= statusbar
;
1295 addrbook
.status_cid
= gtk_statusbar_get_context_id(
1296 GTK_STATUSBAR(statusbar
), "Addressbook Window" );
1298 addrbook
.help_btn
= help_btn
;
1299 addrbook
.edit_btn
= edit_btn
;
1300 addrbook
.del_btn
= del_btn
;
1301 addrbook
.reg_btn
= reg_btn
;
1302 addrbook
.lup_btn
= lup_btn
;
1303 addrbook
.to_btn
= to_btn
;
1304 addrbook
.cc_btn
= cc_btn
;
1305 addrbook
.bcc_btn
= bcc_btn
;
1307 addrbook
.tree_popup
= tree_popup
;
1308 addrbook
.list_popup
= list_popup
;
1309 addrbook
.ui_manager
= ui_manager
;
1311 addrbook
.listSelected
= NULL
;
1313 if (!geometry
.min_height
) {
1314 geometry
.min_width
= ADDRESSBOOK_WIDTH
;
1315 geometry
.min_height
= ADDRESSBOOK_HEIGHT
;
1318 gtk_window_set_geometry_hints(GTK_WINDOW(window
), NULL
, &geometry
,
1320 gtk_widget_set_size_request(window
, prefs_common
.addressbookwin_width
,
1321 prefs_common
.addressbookwin_height
);
1323 gtk_window_move(GTK_WINDOW(window
), 48, 48);
1326 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
1327 if (prefs_common
.addressbook_vpaned_pos
> 0)
1328 gtk_paned_set_position(GTK_PANED(vpaned
),
1329 prefs_common
.addressbook_vpaned_pos
);
1331 if (prefs_common
.addressbook_hpaned_pos
> 0)
1332 gtk_paned_set_position(GTK_PANED(hpaned
),
1333 prefs_common
.addressbook_hpaned_pos
);
1336 gtk_widget_show_all(window
);
1340 * Close address book window and save to file(s).
1342 static gint
addressbook_close( void ) {
1343 address_completion_end(addrbook
.window
);
1344 if (!prefs_common
.addressbook_use_editaddress_dialog
)
1345 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
1347 addressbook_pane_save_position();
1349 gtk_widget_hide(addrbook
.window
);
1350 addressbook_export_to_file();
1355 * Display message in status line.
1356 * \param msg Message to display.
1358 static void addressbook_status_show( gchar
*msg
) {
1359 if( addrbook
.statusbar
!= NULL
) {
1361 GTK_STATUSBAR(addrbook
.statusbar
),
1362 addrbook
.status_cid
);
1365 GTK_STATUSBAR(addrbook
.statusbar
),
1366 addrbook
.status_cid
, msg
);
1371 static void addressbook_ds_show_message( AddressDataSource
*ds
) {
1375 *addressbook_msgbuf
= '\0';
1377 name
= addrindex_ds_get_name( ds
);
1378 retVal
= addrindex_ds_get_status_code( ds
);
1379 if( retVal
== MGU_SUCCESS
) {
1380 g_snprintf( addressbook_msgbuf
,
1381 sizeof(addressbook_msgbuf
), "%s", name
);
1384 desc
= addressbook_err2string( _lutErrorsGeneral_
, retVal
);
1385 g_snprintf( addressbook_msgbuf
,
1386 sizeof(addressbook_msgbuf
), "%s: %s", name
, desc
);
1389 addressbook_status_show( addressbook_msgbuf
);
1392 static void addressbook_edit_clicked(GtkButton
*button
, gpointer data
)
1394 addressbook_edit_address_cb(NULL
, NULL
);
1397 static gboolean
find_person(AddrSelectItem
*item_a
, ItemPerson
*person
)
1399 return ((ItemPerson
*)item_a
->addressItem
== person
)?0:-1;
1403 * Delete one or more objects from address list.
1405 static void addressbook_del_clicked(GtkButton
*button
, gpointer data
)
1407 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
1408 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
1409 AddressObject
*pobj
;
1410 AdapterDSource
*ads
= NULL
;
1411 GtkCMCTreeNode
*nodeList
;
1414 AddressBookFile
*abf
= NULL
;
1415 AddressDataSource
*ds
= NULL
;
1416 AddressInterface
*iface
;
1417 AddrItemObject
*aio
;
1418 AddrSelectItem
*item
;
1420 gboolean refreshList
= FALSE
;
1422 pobj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.opened
);
1423 cm_return_if_fail(pobj
!= NULL
);
1425 /* Test whether anything selected for deletion */
1426 nodeList
= addrbook
.listSelected
;
1428 aio
= gtk_cmctree_node_get_row_data( clist
, nodeList
);
1429 if( aio
== NULL
) return;
1430 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1431 if( ds
== NULL
) return;
1433 /* Test for read only */
1434 iface
= ds
->interface
;
1435 if( iface
->readOnly
) {
1436 alertpanel( _("Delete address(es)"),
1437 _("This address data is read-only and cannot be deleted."),
1438 GTK_STOCK_CLOSE
, NULL
, NULL
, ALERTFOCUS_FIRST
);
1442 /* Test whether Ok to proceed */
1444 if( pobj
->type
== ADDR_DATASOURCE
) {
1445 ads
= ADAPTER_DSOURCE(pobj
);
1446 if( ads
->subType
== ADDR_BOOK
) procFlag
= TRUE
;
1448 else if( pobj
->type
== ADDR_ITEM_FOLDER
) {
1451 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
1454 if( ! procFlag
) return;
1455 abf
= ds
->rawDataSource
;
1456 if( abf
== NULL
) return;
1458 gtk_cmclist_freeze(GTK_CMCLIST(addrbook
.clist
));
1459 g_signal_handlers_block_by_func
1460 (G_OBJECT(addrbook
.clist
),
1461 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1463 /* Process deletions */
1464 if( pobj
->type
== ADDR_DATASOURCE
|| pobj
->type
== ADDR_ITEM_FOLDER
) {
1465 GList
*groups
= NULL
, *persons
= NULL
, *emails
= NULL
;
1466 gboolean group_delete
= TRUE
;
1467 /* Items inside folders */
1468 list
= addrselect_get_list( _addressSelect_
);
1469 /* Confirm deletion */
1473 node
= g_list_next( node
);
1474 aio
= ( AddrItemObject
* ) item
->addressItem
;
1475 if( aio
->type
== ITEMTYPE_PERSON
|| aio
->type
== ITEMTYPE_EMAIL
) {
1476 group_delete
= FALSE
;
1481 aval
= alertpanel( _("Delete group"),
1482 _("Really delete the group(s)?\n"
1483 "The addresses it contains will not be lost."),
1484 GTK_STOCK_CANCEL
, GTK_STOCK_DELETE
, NULL
, ALERTFOCUS_SECOND
);
1485 if( aval
!= G_ALERTALTERNATE
) {
1489 aval
= alertpanel( _("Delete address(es)"),
1490 _("Really delete the address(es)?"),
1491 GTK_STOCK_CANCEL
, GTK_STOCK_DELETE
, NULL
, ALERTFOCUS_SECOND
);
1492 if( aval
!= G_ALERTALTERNATE
) {
1497 /* first, set lists of groups and persons to remove */
1501 node
= g_list_next( node
);
1502 aio
= ( AddrItemObject
* ) item
->addressItem
;
1505 if( aio
->type
== ITEMTYPE_GROUP
) {
1506 groups
= g_list_prepend(groups
, item
);
1508 else if( aio
->type
== ITEMTYPE_PERSON
) {
1509 persons
= g_list_prepend(persons
, item
);
1512 /* then set list of emails to remove *if* they're not children of
1513 * persons to remove */
1517 node
= g_list_next( node
);
1518 aio
= ( AddrItemObject
* ) item
->addressItem
;
1521 if( aio
->type
== ITEMTYPE_EMAIL
) {
1522 ItemEMail
*sitem
= ( ItemEMail
* ) aio
;
1523 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(sitem
);
1524 if (!g_list_find_custom(persons
, person
, (GCompareFunc
)(find_person
))) {
1525 emails
= g_list_prepend(emails
, item
);
1527 /* else, the email will be removed via the parent person */
1530 /* then delete groups */
1534 node
= g_list_next( node
);
1535 aio
= ( AddrItemObject
* ) item
->addressItem
;
1538 if( aio
->type
== ITEMTYPE_GROUP
) {
1539 ItemGroup
*item
= ( ItemGroup
* ) aio
;
1540 GtkCMCTreeNode
*nd
= NULL
;
1541 nd
= addressbook_find_group_node( addrbook
.opened
, item
);
1542 item
= addrbook_remove_group( abf
, item
);
1544 addritem_free_item_group( item
);
1546 /* Remove group from parent node */
1547 gtk_cmctree_remove_node( ctree
, nd
);
1551 /* then delete persons */
1555 node
= g_list_next( node
);
1556 aio
= ( AddrItemObject
* ) item
->addressItem
;
1559 if( aio
->type
== ITEMTYPE_PERSON
) {
1560 ItemPerson
*item
= ( ItemPerson
* ) aio
;
1561 item
->status
= DELETE_ENTRY
;
1562 addressbook_folder_remove_one_person( clist
, item
);
1563 if (pobj
->type
== ADDR_ITEM_FOLDER
)
1564 addritem_folder_remove_person(ADAPTER_FOLDER(pobj
)->itemFolder
, item
);
1565 item
= addrbook_remove_person( abf
, item
);
1567 if (ds
&& ds
->type
== ADDR_IF_LDAP
) {
1568 LdapServer
*server
= ds
->rawDataSource
;
1569 ldapsvr_set_modified(server
, TRUE
);
1570 ldapsvr_update_book(server
, item
);
1574 addritem_person_remove_picture(item
);
1575 addritem_free_item_person( item
);
1579 /* then delete emails */
1583 node
= g_list_next( node
);
1584 aio
= ( AddrItemObject
* ) item
->addressItem
;
1588 if( aio
->type
== ITEMTYPE_EMAIL
) {
1589 ItemEMail
*sitem
= ( ItemEMail
* ) aio
;
1590 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(sitem
);
1591 sitem
= addrbook_person_remove_email( abf
, person
, sitem
);
1593 addrcache_remove_email(abf
->addressCache
, sitem
);
1594 addritem_free_item_email( sitem
);
1596 addressbook_folder_refresh_one_person( clist
, person
);
1599 g_list_free( groups
);
1600 g_list_free( persons
);
1601 g_list_free( emails
);
1602 g_list_free( list
);
1603 addressbook_list_select_clear();
1605 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
1606 addressbook_set_clist(
1607 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
1611 addrbook_set_dirty(abf
, TRUE
);
1612 addressbook_export_to_file();
1613 addressbook_list_menu_setup();
1616 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
1617 /* Items inside groups */
1618 list
= addrselect_get_list( _addressSelect_
);
1622 node
= g_list_next( node
);
1623 aio
= ( AddrItemObject
* ) item
->addressItem
;
1624 if( aio
->type
== ITEMTYPE_EMAIL
) {
1625 ItemEMail
*item
= ( ItemEMail
* ) aio
;
1626 ItemPerson
*person
= ( ItemPerson
* ) ADDRITEM_PARENT(item
);
1627 item
= addrbook_person_remove_email( abf
, person
, item
);
1629 addritem_free_item_email( item
);
1633 g_list_free( list
);
1634 addressbook_list_select_clear();
1635 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
1636 addressbook_set_clist(
1637 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
1641 addrbook_set_dirty(abf
, TRUE
);
1642 addressbook_export_to_file();
1643 addressbook_list_menu_setup();
1647 gtk_cmctree_node_set_row_data( clist
, nodeList
, NULL
);
1648 gtk_cmctree_remove_node( clist
, nodeList
);
1650 gtk_cmclist_thaw(GTK_CMCLIST(addrbook
.clist
));
1651 g_signal_handlers_unblock_by_func
1652 (G_OBJECT(addrbook
.clist
),
1653 G_CALLBACK(addressbook_list_row_unselected
), NULL
);
1656 static void addressbook_reg_clicked(GtkButton
*button
, gpointer data
)
1658 addressbook_new_address_cb( NULL
, NULL
);
1661 static gchar
*addressbook_format_address( AddrItemObject
* aio
) {
1664 gchar
*address
= NULL
;
1666 if( aio
->type
== ITEMTYPE_EMAIL
) {
1667 ItemPerson
*person
= NULL
;
1668 ItemEMail
*email
= ( ItemEMail
* ) aio
;
1670 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
1671 if( email
->address
) {
1672 if( ADDRITEM_NAME(email
) ) {
1673 name
= ADDRITEM_NAME(email
);
1674 if( *name
== '\0' ) {
1675 name
= ADDRITEM_NAME(person
);
1678 else if( ADDRITEM_NAME(person
) ) {
1679 name
= ADDRITEM_NAME(person
);
1682 buf
= g_strdup( email
->address
);
1684 address
= email
->address
;
1687 else if( aio
->type
== ITEMTYPE_PERSON
) {
1688 ItemPerson
*person
= ( ItemPerson
* ) aio
;
1689 GList
*node
= person
->listEMail
;
1691 name
= ADDRITEM_NAME(person
);
1693 ItemEMail
*email
= ( ItemEMail
* ) node
->data
;
1694 address
= email
->address
;
1698 if( name
&& name
[0] != '\0' ) {
1699 if( strchr_with_skip_quote( name
, '"', ',' ) )
1700 buf
= g_strdup_printf( "\"%s\" <%s>", name
, address
);
1702 buf
= g_strdup_printf( "%s <%s>", name
, address
);
1705 buf
= g_strdup( address
);
1712 static void addressbook_to_clicked(GtkButton
*button
, gpointer data
)
1716 AddrSelectItem
*item
;
1717 AddrItemObject
*aio
;
1720 compose
= addrbook
.target_compose
;
1721 if( ! compose
) return;
1723 /* Nothing selected, but maybe there is something in text entry */
1724 addr
= (char *)gtk_entry_get_text( GTK_ENTRY( addrbook
.entry
) );
1726 compose_entry_append(
1727 compose
, addr
, (ComposeEntryType
)data
, PREF_NONE
);
1730 /* Select from address list */
1731 list
= addrselect_get_list( _addressSelect_
);
1736 node
= g_list_next( node
);
1737 aio
= item
->addressItem
;
1738 if( aio
->type
== ITEMTYPE_PERSON
||
1739 aio
->type
== ITEMTYPE_EMAIL
) {
1740 addr
= addressbook_format_address( aio
);
1741 compose_entry_append(
1742 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1745 else if( aio
->type
== ITEMTYPE_GROUP
) {
1746 ItemGroup
*group
= ( ItemGroup
* ) aio
;
1747 GList
*nodeMail
= group
->listEMail
;
1749 ItemEMail
*email
= nodeMail
->data
;
1751 addr
= addressbook_format_address(
1752 ( AddrItemObject
* ) email
);
1753 compose_entry_append(
1754 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1756 nodeMail
= g_list_next( nodeMail
);
1761 AddressObject
*obj
= NULL
;
1763 obj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
1765 if( obj
&& obj
->type
== ADDR_ITEM_GROUP
) {
1766 ItemGroup
*itemGroup
= ADAPTER_GROUP(obj
)->itemGroup
;
1767 GList
*nodeMail
= itemGroup
->listEMail
;
1769 ItemEMail
*email
= nodeMail
->data
;
1771 addr
= addressbook_format_address(
1772 ( AddrItemObject
* ) email
);
1773 compose_entry_append(
1774 compose
, addr
, (ComposeEntryType
) data
, PREF_NONE
);
1776 nodeMail
= g_list_next( nodeMail
);
1780 g_list_free( list
);
1783 static void addressbook_menubar_set_sensitive( gboolean sensitive
) {
1784 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", sensitive
);
1785 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", sensitive
);
1786 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/NewFolder", sensitive
);
1788 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/SelectAll", TRUE
);
1789 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", sensitive
);
1790 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", sensitive
);
1791 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", sensitive
);
1793 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewAddress", sensitive
);
1794 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewGroup", sensitive
);
1795 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Mailto", sensitive
);
1796 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Merge", sensitive
);
1797 gtk_widget_set_sensitive( addrbook
.edit_btn
, sensitive
);
1798 gtk_widget_set_sensitive( addrbook
.del_btn
, sensitive
);
1801 static void addressbook_menuitem_set_sensitive( AddressObject
*obj
, GtkCMCTreeNode
*node
) {
1802 gboolean canEdit
= FALSE
;
1803 gboolean canDelete
= TRUE
;
1804 gboolean canAdd
= FALSE
;
1805 gboolean canEditTr
= TRUE
;
1806 gboolean editAddress
= FALSE
;
1807 gboolean canExport
= TRUE
;
1808 AddressTypeControlItem
*atci
= NULL
;
1809 AddressDataSource
*ds
= NULL
;
1810 AddressInterface
*iface
= NULL
;
1812 if( obj
== NULL
) return;
1813 if( obj
->type
== ADDR_INTERFACE
) {
1814 AdapterInterface
*adapter
= ADAPTER_INTERFACE(obj
);
1815 iface
= adapter
->interface
;
1817 if( iface
->haveLibrary
) {
1818 /* Enable appropriate File / New command */
1819 atci
= adapter
->atci
;
1820 cm_menu_set_sensitive_full(addrbook
.ui_manager
, atci
->menuCommand
, TRUE
);
1823 canEditTr
= canExport
= FALSE
;
1825 else if( obj
->type
== ADDR_DATASOURCE
) {
1826 AdapterDSource
*ads
= ADAPTER_DSOURCE(obj
);
1827 ds
= ads
->dataSource
;
1828 iface
= ds
->interface
;
1829 if( ! iface
->readOnly
) {
1830 canAdd
= canEdit
= editAddress
= canDelete
= TRUE
;
1832 if( ! iface
->haveLibrary
) {
1833 canAdd
= canEdit
= editAddress
= canExport
= canDelete
= FALSE
;
1836 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
1837 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1839 iface
= ds
->interface
;
1840 if( iface
->readOnly
) {
1845 canAdd
= editAddress
= TRUE
;
1849 else if( obj
->type
== ADDR_ITEM_GROUP
) {
1850 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
1852 iface
= ds
->interface
;
1853 if( ! iface
->readOnly
) {
1859 if( addrbook
.listSelected
== NULL
)
1863 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewAddress", editAddress
);
1864 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/NewGroup", canAdd
);
1865 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/NewFolder", canAdd
);
1866 gtk_widget_set_sensitive( addrbook
.reg_btn
, editAddress
);
1869 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Edit", canEdit
);
1870 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Delete", canDelete
);
1871 gtk_widget_set_sensitive( addrbook
.edit_btn
, canEdit
);
1872 gtk_widget_set_sensitive( addrbook
.del_btn
, canDelete
);
1874 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", canEditTr
);
1875 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", canEditTr
);
1878 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Tools/ExportHTML", canExport
);
1879 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Tools/ExportLDIF", canExport
);
1883 * Address book tree callback function that responds to selection of tree
1886 * \param ctree Tree widget.
1887 * \param node Node that was selected.
1888 * \param column Column number where selected occurred.
1889 * \param data Pointer to user data.
1891 static void addressbook_tree_selected(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
1892 gint column
, gpointer data
)
1894 AddressObject
*obj
= NULL
;
1895 AdapterDSource
*ads
= NULL
;
1896 AddressDataSource
*ds
= NULL
;
1897 ItemFolder
*rootFolder
= NULL
;
1898 AddressObjectType aot
;
1900 addrbook
.treeSelected
= node
;
1901 addrbook
.listSelected
= NULL
;
1902 addressbook_status_show( "" );
1903 if( addrbook
.entry
!= NULL
) gtk_entry_set_text(GTK_ENTRY(addrbook
.entry
), "");
1905 if( node
) obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
1907 addressbook_set_clist(NULL
, TRUE
);
1910 addrbook
.opened
= node
;
1912 if( obj
->type
== ADDR_DATASOURCE
) {
1913 /* Read from file */
1914 static gboolean tVal
= TRUE
;
1916 ads
= ADAPTER_DSOURCE(obj
);
1918 ds
= ads
->dataSource
;
1919 if( ds
== NULL
) return;
1921 if( addrindex_ds_get_modify_flag( ds
) ) {
1922 addrindex_ds_read_data( ds
);
1925 if( ! addrindex_ds_get_read_flag( ds
) ) {
1926 addrindex_ds_read_data( ds
);
1928 addressbook_ds_show_message( ds
);
1930 if( ! addrindex_ds_get_access_flag( ds
) ) {
1931 /* Remove existing folders and groups */
1932 gtk_cmclist_freeze( GTK_CMCLIST(ctree
) );
1933 addressbook_tree_remove_children( ctree
, node
);
1934 gtk_cmclist_thaw( GTK_CMCLIST(ctree
) );
1936 /* Load folders into the tree */
1937 rootFolder
= addrindex_ds_get_root_folder( ds
);
1938 if( ds
&& ds
->type
== ADDR_IF_JPILOT
) {
1939 aot
= ADDR_CATEGORY
;
1941 else if( ds
&& ds
->type
== ADDR_IF_LDAP
) {
1942 aot
= ADDR_LDAP_QUERY
;
1945 aot
= ADDR_ITEM_FOLDER
;
1947 addressbook_node_add_folder( node
, ds
, rootFolder
, aot
);
1948 addrindex_ds_set_access_flag( ds
, &tVal
);
1949 gtk_cmctree_expand( ctree
, node
);
1952 addressbook_set_clist(NULL
, TRUE
);
1955 /* Update address list */
1956 g_signal_handlers_block_by_func
1958 G_CALLBACK(addressbook_tree_selected
), NULL
);
1959 addressbook_set_clist( obj
, FALSE
);
1960 g_signal_handlers_unblock_by_func
1962 G_CALLBACK(addressbook_tree_selected
), NULL
);
1963 if (!prefs_common
.addressbook_use_editaddress_dialog
)
1964 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
1966 /* Setup main menu selections */
1967 addressbook_menubar_set_sensitive( FALSE
);
1968 addressbook_menuitem_set_sensitive( obj
, node
);
1969 addressbook_list_select_clear();
1970 addressbook_list_menu_setup();
1975 * Setup address list popup menu items. Items are enabled or disabled as
1978 static void addressbook_list_menu_setup( void ) {
1979 GtkCMCTree
*clist
= NULL
;
1980 AddressObject
*pobj
= NULL
;
1981 AddressObject
*obj
= NULL
;
1982 AdapterDSource
*ads
= NULL
;
1983 AddressInterface
*iface
= NULL
;
1984 AddressDataSource
*ds
= NULL
;
1986 AddrItemObject
*aio
;
1987 AddrSelectItem
*item
;
1988 gboolean canEdit
= FALSE
;
1989 gboolean canDelete
= FALSE
;
1990 gboolean canCut
= FALSE
;
1991 gboolean canCopy
= FALSE
;
1992 gboolean canPaste
= FALSE
;
1993 gboolean canBrowse
= FALSE
;
1994 gboolean canMerge
= FALSE
;
1996 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
1997 if( pobj
== NULL
) return;
1999 clist
= GTK_CMCTREE(addrbook
.clist
);
2000 obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
2001 if( obj
== NULL
) canEdit
= FALSE
;
2003 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook
.list_popup
) );
2004 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/SelectAll", TRUE
);
2006 if( pobj
->type
== ADDR_DATASOURCE
) {
2007 /* Parent object is a data source */
2008 ads
= ADAPTER_DSOURCE(pobj
);
2009 ds
= ads
->dataSource
;
2012 iface
= ds
->interface
;
2015 if( ! iface
->readOnly
) {
2016 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2017 if (iface
->type
!= ADDR_IF_LDAP
)
2018 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewGroup", TRUE
);
2019 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2022 canDelete
= canEdit
;
2025 else if( pobj
->type
!= ADDR_INTERFACE
) {
2026 /* Parent object is not an interface */
2027 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2030 iface
= ds
->interface
;
2033 if( ! iface
->readOnly
) {
2034 /* Folder or group */
2035 if( pobj
->type
== ADDR_ITEM_FOLDER
|| pobj
->type
== ADDR_ITEM_GROUP
) {
2036 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2037 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2038 if( obj
) canEdit
= TRUE
;
2041 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
2042 if (iface
->type
!= ADDR_IF_LDAP
)
2043 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewGroup", TRUE
);
2044 if( obj
) canEdit
= TRUE
;
2046 canDelete
= canEdit
;
2048 if( iface
->type
== ADDR_IF_LDAP
) {
2049 if( obj
) canBrowse
= TRUE
;
2056 /* Enable cut and paste */
2057 if( ! addrclip_is_empty( _clipBoard_
) )
2059 if( ! addrselect_test_empty( _addressSelect_
) )
2061 /* Enable copy if something is selected */
2062 if( ! addrselect_test_empty( _addressSelect_
) )
2066 /* Disable edit or browse if more than one row selected */
2067 if( GTK_CMCLIST(clist
)->selection
&& GTK_CMCLIST(clist
)->selection
->next
) {
2072 /* Allow merging persons or emails are selected */
2073 list
= _addressSelect_
->listSelect
;
2074 if (list
&& list
->next
) {
2076 aio
= ( AddrItemObject
* ) item
->addressItem
;
2077 if( aio
->type
== ITEMTYPE_EMAIL
||
2078 aio
->type
== ITEMTYPE_PERSON
) {
2083 /* Forbid write changes when read-only */
2084 if( iface
&& iface
->readOnly
) {
2091 /* Now go finalize menu items */
2092 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Edit", canEdit
);
2093 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Delete", canDelete
);
2095 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Cut", canCut
);
2096 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Copy", canCopy
);
2097 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Paste", canPaste
);
2099 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Mailto", canCopy
);
2100 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/Merge", canMerge
);
2102 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", canCut
);
2103 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", canCopy
);
2104 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", canPaste
);
2106 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Edit", canEdit
);
2107 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Delete", canDelete
);
2108 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Mailto", canCopy
);
2109 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Merge", canMerge
);
2111 gtk_widget_set_sensitive( addrbook
.edit_btn
, canEdit
);
2112 gtk_widget_set_sensitive( addrbook
.del_btn
, canDelete
);
2114 if (addrbook
.target_compose
) {
2115 gtk_widget_set_sensitive(addrbook
.to_btn
, obj
? TRUE
: FALSE
);
2116 gtk_widget_set_sensitive(addrbook
.cc_btn
, obj
? TRUE
: FALSE
);
2117 gtk_widget_set_sensitive(addrbook
.bcc_btn
, obj
? TRUE
: FALSE
);
2120 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/BrowseEntry", canBrowse
);
2124 static void addressbook_select_row_tree (GtkCMCTree
*ctree
,
2125 GtkCMCTreeNode
*node
,
2132 * Add list of items into tree node below specified tree node.
2133 * \param treeNode Tree node.
2134 * \param ds Data source.
2135 * \param listItems List of items.
2137 static void addressbook_treenode_add_list(
2138 GtkCMCTreeNode
*treeNode
, AddressDataSource
*ds
, GList
*listItems
)
2144 AddrItemObject
*aio
;
2148 if( ADDRESS_OBJECT_TYPE(aio
) == ADDR_ITEM_GROUP
) {
2151 group
= ( ItemGroup
* ) aio
;
2152 nn
= addressbook_node_add_group( treeNode
, ds
, group
);
2154 g_message("error adding addressbook group\n");
2157 else if( ADDRESS_OBJECT_TYPE(aio
) == ADDR_ITEM_FOLDER
) {
2160 folder
= ( ItemFolder
* ) aio
;
2161 nn
= addressbook_node_add_folder(
2162 treeNode
, ds
, folder
, ADDR_ITEM_FOLDER
);
2164 g_message("error adding addressbook folder\n");
2167 node
= g_list_next( node
);
2171 static void addressbook_select_all_cb( GtkAction
*action
, gpointer data
) {
2172 gtk_cmclist_select_all(GTK_CMCLIST(addrbook
.clist
));
2176 * Cut from address list widget.
2178 static void addressbook_clip_cut_cb( GtkAction
*action
, gpointer data
) {
2179 _clipBoard_
->cutFlag
= TRUE
;
2180 addrclip_clear( _clipBoard_
);
2181 addrclip_add( _clipBoard_
, _addressSelect_
);
2182 /* addrclip_list_show( _clipBoard_, stdout ); */
2186 * Copy from address list widget.
2188 static void addressbook_clip_copy_cb(GtkAction
*action
, gpointer data
) {
2189 _clipBoard_
->cutFlag
= FALSE
;
2190 addrclip_clear( _clipBoard_
);
2191 addrclip_add( _clipBoard_
, _addressSelect_
);
2192 /* addrclip_list_show( _clipBoard_, stdout ); */
2196 * Paste clipboard into address list widget.
2198 static void addressbook_clip_paste_cb( GtkAction
*action
, gpointer data
) {
2199 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
2200 AddressObject
*pobj
= NULL
;
2201 AddressDataSource
*ds
= NULL
;
2202 AddressBookFile
*abf
= NULL
;
2203 ItemFolder
*folder
= NULL
;
2204 GList
*folderGroup
= NULL
;
2206 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
2207 if( ds
== NULL
) return;
2208 if( addrindex_ds_get_readonly( ds
) ) {
2209 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2213 pobj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
2215 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
2216 folder
= ADAPTER_FOLDER(pobj
)->itemFolder
;
2218 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
2219 alertpanel_error( _("Cannot paste into an address group.") );
2224 /* Get an address book */
2225 abf
= addressbook_get_book_file();
2226 if( abf
== NULL
) return;
2228 if( _clipBoard_
->cutFlag
) {
2230 folderGroup
= addrclip_paste_cut( _clipBoard_
, abf
, folder
);
2232 /* Remove all groups and folders in clipboard from tree node */
2233 addressbook_treenode_remove_item();
2235 /* Remove all "cut" items */
2236 addrclip_delete_item( _clipBoard_
);
2238 /* Clear clipboard - cut items??? */
2239 addrclip_clear( _clipBoard_
);
2243 folderGroup
= addrclip_paste_copy( _clipBoard_
, abf
, folder
);
2246 /* 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 /* addrclip_list_show( _clipBoard_, stdout ); */
2329 * Copy from tree widget.
2331 static void addressbook_treenode_copy_cb( GtkAction
*action
, gpointer data
) {
2332 _clipBoard_
->cutFlag
= FALSE
;
2333 addressbook_treenode_to_clipboard();
2334 addrclip_clear( _clipBoard_
);
2335 addrclip_add( _clipBoard_
, _addressSelect_
);
2336 /* addrclip_list_show( _clipBoard_, stdout ); */
2340 * Paste clipboard into address tree widget.
2342 static void addressbook_treenode_paste_cb( GtkAction
*action
, gpointer data
) {
2343 addressbook_clip_paste_cb(NULL
,NULL
);
2347 * Clear selected entries in clipboard.
2349 static void addressbook_list_select_clear( void ) {
2350 addrselect_list_clear( _addressSelect_
);
2354 * Add specified address item to selected address list.
2355 * \param aio Address item object.
2356 * \param ds Datasource.
2358 static void addressbook_list_select_add( AddrItemObject
*aio
, AddressDataSource
*ds
) {
2361 if( ds
== NULL
) return;
2362 cacheID
= addrindex_get_cache_id( _addressIndex_
, ds
);
2363 addrselect_list_add_obj( _addressSelect_
, aio
, cacheID
);
2368 * Remove specified address item from selected address list.
2369 * \param aio Address item object.
2371 static void addressbook_list_select_remove( AddrItemObject
*aio
) {
2372 addrselect_list_remove( _addressSelect_
, aio
);
2376 * Invoke EMail compose window with addresses in selected address list.
2378 static void addressbook_mail_to_cb( GtkAction
*action
, gpointer data
) {
2381 if( ! addrselect_test_empty( _addressSelect_
) ) {
2382 listAddress
= addrselect_build_list( _addressSelect_
);
2383 compose_new_with_list( NULL
, listAddress
);
2384 g_list_free_full( listAddress
, g_free
);
2389 static void addressbook_merge_list( AddrSelectList
*list
) {
2390 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2391 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
2392 AddressObject
*pobj
;
2393 AddressDataSource
*ds
= NULL
;
2395 pobj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.opened
);
2396 cm_return_if_fail(pobj
!= NULL
);
2398 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2399 if( ds
== NULL
) return;
2401 addrmerge_merge(clist
, pobj
, ds
, list
);
2405 * Merge selected entries in the address list
2407 static void addressbook_merge_cb( GtkAction
*action
, gpointer data
) {
2408 if( addrselect_test_empty( _addressSelect_
) )
2411 addressbook_merge_list( _addressSelect_
);
2414 static void addressbook_list_row_selected( GtkCMCTree
*clist
,
2415 GtkCMCTreeNode
*node
,
2419 AddrItemObject
*aio
= NULL
;
2420 AddressObject
*pobj
= NULL
;
2421 AdapterDSource
*ads
= NULL
;
2422 AddressDataSource
*ds
= NULL
;
2424 addrbook
.listSelected
= node
;
2426 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
2427 if( pobj
== NULL
) return;
2429 if( pobj
->type
== ADDR_DATASOURCE
) {
2430 ads
= ADAPTER_DSOURCE(pobj
);
2431 ds
= ads
->dataSource
;
2433 else if( pobj
->type
!= ADDR_INTERFACE
) {
2434 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2437 aio
= gtk_cmctree_node_get_row_data( clist
, node
);
2439 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2440 addressbook_list_select_add( aio
, ds
);
2443 addressbook_list_menu_setup();
2445 if (!addrbook
.target_compose
&& !prefs_common
.addressbook_use_editaddress_dialog
) {
2446 AddressObject
*obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
2448 if (obj
&& obj
->type
!= ADDR_ITEM_GROUP
)
2449 addressbook_edit_address(NULL
, 0, NULL
, FALSE
);
2453 static void addressbook_list_row_unselected( GtkCMCTree
*ctree
,
2454 GtkCMCTreeNode
*node
,
2458 AddrItemObject
*aio
;
2460 aio
= gtk_cmctree_node_get_row_data( ctree
, node
);
2462 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2463 addressbook_list_select_remove( aio
);
2466 if (!prefs_common
.addressbook_use_editaddress_dialog
)
2467 addressbook_edit_person_invalidate(NULL
, NULL
, NULL
);
2470 static void addressbook_entry_activated(GtkWidget
*widget
, gpointer data
)
2472 addressbook_lup_clicked(NULL
, NULL
);
2475 static gboolean
addressbook_list_button_pressed(GtkWidget
*widget
,
2476 GdkEventButton
*event
,
2479 if( ! event
) return FALSE
;
2480 if( event
->window
!= GTK_CMCLIST(widget
)->clist_window
) return FALSE
;
2482 addressbook_list_menu_setup();
2484 if( event
->button
== 3 ) {
2485 gtk_menu_popup( GTK_MENU(addrbook
.list_popup
), NULL
, NULL
, NULL
, NULL
,
2486 event
->button
, event
->time
);
2487 } else if (event
->button
== 1) {
2488 if (event
->type
== GDK_2BUTTON_PRESS
) {
2489 if (prefs_common
.add_address_by_click
&&
2490 addrbook
.target_compose
)
2491 addressbook_to_clicked(NULL
, GINT_TO_POINTER(COMPOSE_TO
));
2493 if (prefs_common
.addressbook_use_editaddress_dialog
)
2494 addressbook_edit_address_cb(NULL
, NULL
);
2496 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
2497 AddressObject
*obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
2498 if( obj
&& obj
->type
== ADDR_ITEM_GROUP
)
2499 addressbook_edit_address_cb(NULL
, NULL
);
2507 static gboolean
addressbook_list_button_released(GtkWidget
*widget
,
2508 GdkEventButton
*event
,
2514 static gboolean
addressbook_tree_button_pressed(GtkWidget
*ctree
,
2515 GdkEventButton
*event
,
2518 GtkCMCList
*clist
= GTK_CMCLIST(ctree
);
2520 AddressObject
*obj
= NULL
;
2521 AdapterDSource
*ads
= NULL
;
2522 AddressInterface
*iface
= NULL
;
2523 AddressDataSource
*ds
= NULL
;
2524 gboolean canEdit
= FALSE
;
2525 gboolean canDelete
= FALSE
;
2526 gboolean canCut
= FALSE
;
2527 gboolean canCopy
= FALSE
;
2528 gboolean canPaste
= FALSE
;
2529 gboolean canTreeCut
= FALSE
;
2530 gboolean canTreeCopy
= FALSE
;
2531 gboolean canTreePaste
= FALSE
;
2532 gboolean canLookup
= FALSE
;
2533 GtkCMCTreeNode
*node
= NULL
;
2535 if( ! event
) return FALSE
;
2536 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2538 if( event
->window
!= clist
->clist_window
)
2541 if (event
->button
== 1) {
2542 if (event
->type
== GDK_2BUTTON_PRESS
) {
2543 if( gtk_cmclist_get_selection_info( clist
, event
->x
, event
->y
, &row
, &column
) ) {
2544 gtkut_clist_set_focus_row(clist
, row
);
2545 obj
= gtk_cmclist_get_row_data( clist
, row
);
2550 if (obj
->type
== ADDR_ITEM_GROUP
||
2551 obj
->type
== ADDR_DATASOURCE
) {
2553 addressbook_treenode_edit_cb(NULL
, NULL
);
2555 /* expand pr collapse */
2556 node
= gtk_cmctree_node_nth(GTK_CMCTREE(ctree
), row
);
2557 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree
), node
);
2563 addressbook_menubar_set_sensitive( FALSE
);
2565 if( gtk_cmclist_get_selection_info( clist
, event
->x
, event
->y
, &row
, &column
) ) {
2566 gtkut_clist_set_focus_row(clist
, row
);
2567 obj
= gtk_cmclist_get_row_data( clist
, row
);
2570 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook
.tree_popup
));
2574 node
= gtk_cmctree_node_nth(GTK_CMCTREE(clist
), row
);
2576 if( ! addrclip_is_empty( _clipBoard_
) )
2577 canTreePaste
= TRUE
;
2579 if (obj
->type
== ADDR_INTERFACE
) {
2580 AdapterInterface
*adapter
= ADAPTER_INTERFACE(obj
);
2581 iface
= adapter
->interface
;
2584 if( !iface
->readOnly
&& iface
->type
== ADDR_IF_BOOK
) {
2585 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewBook", TRUE
);
2587 if( iface
->externalQuery
)
2590 if (obj
->type
== ADDR_DATASOURCE
) {
2592 ads
= ADAPTER_DSOURCE(obj
);
2593 ds
= ads
->dataSource
;
2596 iface
= ds
->interface
;
2599 if( !iface
->readOnly
) {
2600 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewFolder", TRUE
);
2601 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewGroup", TRUE
);
2602 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2608 else if (obj
->type
== ADDR_ITEM_FOLDER
) {
2610 ds
= addressbook_find_datasource( node
);
2613 iface
= ds
->interface
;
2616 if( !iface
->readOnly
) {
2620 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewFolder", TRUE
);
2621 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/NewGroup", TRUE
);
2622 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2626 if( iface
->externalQuery
) {
2627 /* Enable deletion of LDAP folder */
2631 else if (obj
->type
== ADDR_ITEM_GROUP
) {
2633 ds
= addressbook_find_datasource( node
);
2636 iface
= ds
->interface
;
2639 if( ! iface
->readOnly
) {
2642 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABListPopup/NewAddress", TRUE
);
2643 gtk_widget_set_sensitive( addrbook
.reg_btn
, TRUE
);
2647 if( canEdit
&& !addrselect_test_empty( _addressSelect_
) )
2649 if( ! addrselect_test_empty( _addressSelect_
) )
2651 if( ! addrclip_is_empty( _clipBoard_
) )
2654 /* Forbid write changes when read-only */
2655 if( iface
&& iface
->readOnly
) {
2657 canTreePaste
= FALSE
;
2664 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/EditBook", canEdit
);
2665 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/DeleteBook", canDelete
);
2666 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Cut", canTreeCut
);
2667 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Copy", canTreeCopy
);
2668 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Popups/ABTreePopup/Paste", canTreePaste
);
2670 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/EditBook", canEdit
);
2671 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Book/DeleteBook", canDelete
);
2672 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", canCut
);
2673 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", canCopy
);
2674 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", canPaste
);
2676 addressbook_show_buttons(addrbook
.target_compose
== NULL
, canLookup
,
2677 addrbook
.target_compose
!= NULL
);
2679 if( event
->button
== 3 )
2680 gtk_menu_popup(GTK_MENU(addrbook
.tree_popup
), NULL
, NULL
, NULL
, NULL
,
2681 event
->button
, event
->time
);
2686 static gboolean
addressbook_tree_button_released(GtkWidget
*ctree
,
2687 GdkEventButton
*event
,
2690 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook
.ctree
), addrbook
.opened
);
2694 static void addressbook_new_folder_cb(GtkAction
*action
, gpointer data
)
2696 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2697 AddressObject
*obj
= NULL
;
2698 AddressDataSource
*ds
= NULL
;
2699 AddressBookFile
*abf
= NULL
;
2700 ItemFolder
*parentFolder
= NULL
;
2701 ItemFolder
*folder
= NULL
;
2703 if( ! addrbook
.treeSelected
) return;
2704 obj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
2705 if( obj
== NULL
) return;
2706 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2707 if( ds
== NULL
) return;
2709 if( obj
->type
== ADDR_DATASOURCE
) {
2710 if( ADAPTER_DSOURCE(obj
)->subType
!= ADDR_BOOK
) return;
2712 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
2713 parentFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
2719 abf
= ds
->rawDataSource
;
2720 if( abf
== NULL
) return;
2721 folder
= addressbook_edit_folder( abf
, parentFolder
, NULL
);
2724 nn
= addressbook_node_add_folder(
2725 addrbook
.treeSelected
, ds
, folder
, ADDR_ITEM_FOLDER
);
2727 g_message("error adding addressbook folder\n");
2729 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2730 if( addrbook
.treeSelected
== addrbook
.opened
)
2731 addressbook_set_clist(obj
, TRUE
);
2735 static void addressbook_new_group_cb(GtkAction
*action
, gpointer data
)
2737 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2738 AddressObject
*obj
= NULL
;
2739 AddressDataSource
*ds
= NULL
;
2740 AddressBookFile
*abf
= NULL
;
2741 ItemFolder
*parentFolder
= NULL
;
2742 ItemGroup
*group
= NULL
;
2744 if( ! addrbook
.treeSelected
) return;
2745 obj
= gtk_cmctree_node_get_row_data(ctree
, addrbook
.treeSelected
);
2746 if( obj
== NULL
) return;
2747 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
2748 if( ds
== NULL
) return;
2750 if( obj
->type
== ADDR_DATASOURCE
) {
2751 if( ADAPTER_DSOURCE(obj
)->subType
!= ADDR_BOOK
) return;
2753 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
2754 parentFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
2760 abf
= ds
->rawDataSource
;
2761 if( abf
== NULL
) return;
2762 group
= addressbook_edit_group( abf
, parentFolder
, NULL
);
2765 nn
= addressbook_node_add_group( addrbook
.treeSelected
, ds
, group
);
2767 g_message("error adding addressbook group\n");
2769 gtk_cmctree_expand( ctree
, addrbook
.treeSelected
);
2770 if( addrbook
.treeSelected
== addrbook
.opened
)
2771 addressbook_set_clist(obj
, TRUE
);
2775 static void addressbook_change_node_name(GtkCMCTreeNode
*node
, const gchar
*name
)
2777 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2780 GdkPixbuf
*pix_cl
, *pix_op
;
2781 gboolean is_leaf
, expanded
;
2783 gtk_cmctree_get_node_info(ctree
, node
, text
, &spacing
,
2785 &is_leaf
, &expanded
);
2786 gtk_cmctree_set_node_info(ctree
, node
, name
, spacing
,
2793 * \param obj Address object to edit.
2794 * \param node Node in tree.
2795 * \return New name of data source.
2797 static gchar
*addressbook_edit_datasource( AddressObject
*obj
, GtkCMCTreeNode
*node
) {
2798 gchar
*newName
= NULL
;
2799 AddressDataSource
*ds
= NULL
;
2800 AddressInterface
*iface
= NULL
;
2801 AdapterDSource
*ads
= NULL
;
2803 ds
= addressbook_find_datasource( node
);
2804 if( ds
== NULL
) return NULL
;
2805 iface
= ds
->interface
;
2806 if( ! iface
->haveLibrary
) return NULL
;
2808 /* Read data from data source */
2809 if( addrindex_ds_get_modify_flag( ds
) ) {
2810 addrindex_ds_read_data( ds
);
2813 if( ! addrindex_ds_get_read_flag( ds
) ) {
2814 addrindex_ds_read_data( ds
);
2818 ads
= ADAPTER_DSOURCE(obj
);
2819 if( ads
->subType
== ADDR_BOOK
) {
2820 if( addressbook_edit_book( _addressIndex_
, ads
) == NULL
) return NULL
;
2822 else if( ads
->subType
== ADDR_VCARD
) {
2823 if( addressbook_edit_vcard( _addressIndex_
, ads
) == NULL
) return NULL
;
2826 else if( ads
->subType
== ADDR_JPILOT
) {
2827 if( addressbook_edit_jpilot( _addressIndex_
, ads
) == NULL
) return NULL
;
2831 else if( ads
->subType
== ADDR_LDAP
) {
2832 if( addressbook_edit_ldap( _addressIndex_
, ads
) == NULL
) return NULL
;
2838 newName
= obj
->name
;
2843 * Edit an object that is in the address tree area.
2845 static void addressbook_treenode_edit_cb(GtkAction
*action
, gpointer data
)
2847 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2849 AddressDataSource
*ds
= NULL
;
2850 AddressBookFile
*abf
= NULL
;
2851 GtkCMCTreeNode
*node
= NULL
, *parentNode
= NULL
;
2854 if( ! addrbook
.treeSelected
) return;
2855 node
= addrbook
.treeSelected
;
2856 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
2857 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2858 if( obj
== NULL
) return;
2859 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
2861 ds
= addressbook_find_datasource( node
);
2862 if( ds
== NULL
) return;
2864 if( obj
->type
== ADDR_DATASOURCE
) {
2865 name
= addressbook_edit_datasource( obj
, node
);
2866 if( name
== NULL
) return;
2869 abf
= ds
->rawDataSource
;
2870 if( abf
== NULL
) return;
2871 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2872 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
2873 ItemFolder
*item
= adapter
->itemFolder
;
2874 ItemFolder
*parentFolder
= NULL
;
2875 parentFolder
= ( ItemFolder
* ) ADDRITEM_PARENT(item
);
2876 if( addressbook_edit_folder( abf
, parentFolder
, item
) == NULL
) return;
2877 name
= ADDRITEM_NAME(item
);
2879 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2880 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
2881 ItemGroup
*item
= adapter
->itemGroup
;
2882 ItemFolder
*parentFolder
= NULL
;
2883 parentFolder
= ( ItemFolder
* ) ADDRITEM_PARENT(item
);
2884 if( addressbook_edit_group( abf
, parentFolder
, item
) == NULL
) return;
2885 name
= ADDRITEM_NAME(item
);
2888 if( name
&& parentNode
) {
2889 /* Update node in tree view */
2890 addressbook_change_node_name( node
, name
);
2891 gtk_sctree_sort_node(ctree
, parentNode
);
2892 gtk_cmctree_expand( ctree
, node
);
2893 gtk_sctree_select( GTK_SCTREE( ctree
), node
);
2900 ADDRTREE_DEL_FOLDER_ONLY
,
2901 ADDRTREE_DEL_FOLDER_ADDR
2905 * Delete an item from the tree widget.
2906 * \param data Data passed in.
2907 * \param action Action.
2908 * \param widget Widget issuing callback.
2910 static void addressbook_treenode_delete_cb(GtkAction
*action
, gpointer data
)
2912 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
2913 GtkCMCTreeNode
*node
= NULL
;
2917 AddrBookBase
*adbase
;
2918 AddressCache
*cache
;
2919 AdapterDSource
*ads
= NULL
;
2920 AddressInterface
*iface
= NULL
;
2921 AddressDataSource
*ds
= NULL
;
2922 gboolean remFlag
= FALSE
;
2923 TreeItemDelType delType
;
2925 if( ! addrbook
.treeSelected
) return;
2926 node
= addrbook
.treeSelected
;
2927 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
2929 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
2930 cm_return_if_fail(obj
!= NULL
);
2932 if( obj
->type
== ADDR_DATASOURCE
) {
2933 ads
= ADAPTER_DSOURCE(obj
);
2935 ds
= ads
->dataSource
;
2936 if( ds
== NULL
) return;
2939 /* Must be folder or something else */
2940 ds
= addressbook_find_datasource( node
);
2941 if( ds
== NULL
) return;
2943 /* Only allow deletion from non-readOnly */
2944 iface
= ds
->interface
;
2945 if( iface
->readOnly
) {
2946 /* Allow deletion of query results */
2947 if( ! iface
->externalQuery
) return;
2951 /* Confirm deletion */
2952 delType
= ADDRTREE_DEL_NONE
;
2953 if( obj
->type
== ADDR_ITEM_FOLDER
) {
2954 if( iface
&& iface
->externalQuery
) {
2955 message
= g_strdup_printf( _(
2956 "Do you want to delete the query " \
2957 "results and addresses in '%s'?" ),
2959 aval
= alertpanel( _("Delete"), message
,
2960 GTK_STOCK_CANCEL
, GTK_STOCK_DELETE
, NULL
, ALERTFOCUS_SECOND
);
2962 if( aval
== G_ALERTALTERNATE
) {
2963 delType
= ADDRTREE_DEL_FOLDER_ADDR
;
2967 message
= g_strdup_printf
2968 ( _( "Do you want to delete '%s'? "
2969 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2971 aval
= alertpanel( _("Delete folder"), message
,
2972 GTK_STOCK_CANCEL
, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND
);
2974 if( aval
== G_ALERTALTERNATE
) {
2975 delType
= ADDRTREE_DEL_FOLDER_ONLY
;
2977 else if( aval
== G_ALERTOTHER
) {
2978 delType
= ADDRTREE_DEL_FOLDER_ADDR
;
2982 else if( obj
->type
== ADDR_ITEM_GROUP
) {
2983 message
= g_strdup_printf(_("Do you want to delete '%s'?\n"
2984 "The addresses it contains will not be lost."), obj
->name
);
2985 aval
= alertpanel(_("Delete"), message
, GTK_STOCK_CANCEL
,
2986 GTK_STOCK_DELETE
, NULL
, ALERTFOCUS_SECOND
);
2988 if( aval
== G_ALERTALTERNATE
) delType
= ADDRTREE_DEL_FOLDER_ONLY
;
2990 message
= g_strdup_printf(_("Do you want to delete '%s'?\n"
2991 "The addresses it contains will be lost."), obj
->name
);
2992 aval
= alertpanel(_("Delete"), message
, GTK_STOCK_CANCEL
,
2993 GTK_STOCK_DELETE
, NULL
, ALERTFOCUS_SECOND
);
2995 if( aval
== G_ALERTALTERNATE
) delType
= ADDRTREE_DEL_DATA
;
2997 if( delType
== ADDRTREE_DEL_NONE
) return;
2999 /* Proceed with deletion */
3000 if( obj
->type
== ADDR_DATASOURCE
) {
3001 /* Remove node from tree */
3002 gtk_cmctree_remove_node( ctree
, node
);
3004 if (delType
== ADDRTREE_DEL_DATA
&&
3005 ds
->interface
&& ds
->interface
->type
== ADDR_IF_BOOK
)
3006 addrbook_delete_book_file((AddressBookFile
*) ds
->rawDataSource
);
3008 /* Remove data source. */
3009 if( addrindex_index_remove_datasource( _addressIndex_
, ds
) ) {
3010 addrindex_free_datasource( ds
);
3015 /* Get reference to cache */
3016 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
3017 if( adbase
== NULL
) return;
3018 cache
= adbase
->addressCache
;
3020 /* Remove query results folder */
3021 if( iface
&& iface
->externalQuery
) {
3022 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
3023 ItemFolder
*folder
= adapter
->itemFolder
;
3025 adapter
->itemFolder
= NULL
;
3027 g_print( "remove folder for ::%s::\n", obj->name );
3028 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3029 g_print( "-------------- remove results\n" );
3031 addrindex_remove_results( ds
, folder
);
3032 /* g_print( "-------------- remove node\n" ); */
3033 gtk_cmctree_remove_node( ctree
, node
);
3037 /* Code below is valid for regular address book deletion */
3038 if( obj
->type
== ADDR_ITEM_FOLDER
) {
3039 AdapterFolder
*adapter
= ADAPTER_FOLDER(obj
);
3040 ItemFolder
*item
= adapter
->itemFolder
;
3042 if( delType
== ADDRTREE_DEL_FOLDER_ONLY
) {
3043 /* Remove folder only */
3044 item
= addrcache_remove_folder( cache
, item
);
3046 addritem_free_item_folder( item
);
3047 addressbook_move_nodes_up( ctree
, node
);
3051 else if( delType
== ADDRTREE_DEL_FOLDER_ADDR
) {
3052 /* Remove folder and addresses */
3053 item
= addrcache_remove_folder_delete( cache
, item
);
3055 addritem_free_item_folder( item
);
3060 else if( obj
->type
== ADDR_ITEM_GROUP
) {
3061 AdapterGroup
*adapter
= ADAPTER_GROUP(obj
);
3062 ItemGroup
*item
= adapter
->itemGroup
;
3064 item
= addrcache_remove_group( cache
, item
);
3066 addritem_free_item_group( item
);
3073 gtk_cmctree_remove_node(ctree
, node
);
3077 static void addressbook_new_address_from_book_post_cb( ItemPerson
*person
)
3079 if( person
&& addrbook
.treeSelected
== addrbook
.opened
) {
3080 person
->status
= ADD_ENTRY
;
3081 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook
.clist
) );
3082 addressbook_folder_refresh_one_person(
3083 GTK_CMCTREE(addrbook
.clist
), person
);
3085 addressbook_address_list_set_focus();
3088 static void addressbook_new_address_from_folder_post_cb( ItemPerson
*person
)
3090 if( person
&& addrbook
.treeSelected
== addrbook
.opened
) {
3091 person
->status
= ADD_ENTRY
;
3092 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), addrbook
.opened
);
3093 addressbook_set_clist(
3094 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3098 addressbook_address_list_set_focus();
3102 * Label (a format string) that is used to name each folder.
3104 static gchar
*_queryFolderLabel_
= N_( "Search '%s'" );
3107 * Search ctree widget callback function.
3108 * \param pA Pointer to node.
3109 * \param pB Pointer to data item being sought.
3110 * \return Zero (0) if folder found.
3112 static int addressbook_treenode_find_folder_cb( gconstpointer pA
, gconstpointer pB
) {
3115 aoA
= ( AddressObject
* ) pA
;
3116 if( aoA
->type
== ADDR_ITEM_FOLDER
) {
3117 ItemFolder
*folder
, *fld
;
3119 fld
= ADAPTER_FOLDER(aoA
)->itemFolder
;
3120 folder
= ( ItemFolder
* ) pB
;
3121 if( fld
== folder
) return 0; /* Found folder */
3126 static ItemFolder
* addressbook_setup_subf(
3127 AddressDataSource
*ds
, gchar
*title
,
3128 GtkCMCTreeNode
*pNode
)
3130 AddrBookBase
*adbase
;
3131 AddressCache
*cache
;
3134 GtkCMCTreeNode
*nNode
;
3136 AddressObjectType aoType
= ADDR_NONE
;
3139 if( *title
== '\0' || strlen( title
) < 1 ) return NULL
;
3141 if( ds
&& ds
->type
== ADDR_IF_LDAP
) {
3143 aoType
= ADDR_LDAP_QUERY
;
3150 ctree
= GTK_CMCTREE(addrbook
.ctree
);
3151 /* Get reference to address cache */
3152 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
3153 cache
= adbase
->addressCache
;
3155 if ((children
= addrcache_get_list_folder(cache
)) != NULL
) {
3156 GList
*cur
= children
;
3157 for (; cur
; cur
= cur
->next
) {
3158 ItemFolder
*child
= (ItemFolder
*) cur
->data
;
3159 if (!g_strcmp0(ADDRITEM_NAME(child
), title
)) {
3160 nNode
= gtk_cmctree_find_by_row_data_custom(
3162 addressbook_treenode_find_folder_cb
);
3164 addrindex_remove_results( ds
, child
);
3165 while( child
->listPerson
) {
3166 ItemPerson
*item
= ( ItemPerson
* ) child
->listPerson
->data
;
3167 item
= addrcache_remove_person( cache
, item
);
3169 addritem_free_item_person( item
);
3173 gtk_sctree_select( GTK_SCTREE(ctree
), nNode
);
3174 addrbook
.treeSelected
= nNode
;
3181 /* Create a folder */
3182 folder
= addrcache_add_new_folder( cache
, NULL
);
3183 name
= g_strdup_printf( "%s", title
);
3184 addritem_folder_set_name( folder
, name
);
3185 addritem_folder_set_remarks( folder
, "" );
3188 /* Now let's see the folder */
3189 nNode
= addressbook_node_add_folder( pNode
, ds
, folder
, aoType
);
3190 gtk_cmctree_expand( ctree
, pNode
);
3192 gtk_sctree_select( GTK_SCTREE(ctree
), nNode
);
3193 addrbook
.treeSelected
= nNode
;
3199 static void addressbook_new_address_cb( GtkAction
*action
, gpointer data
) {
3200 AddressObject
*pobj
= NULL
;
3201 AddressDataSource
*ds
= NULL
;
3202 AddressBookFile
*abf
= NULL
;
3203 debug_print("adding address\n");
3204 pobj
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
3205 if( pobj
== NULL
) {
3206 debug_print("no row data\n");
3209 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3211 debug_print("no datasource\n");
3215 abf
= ds
->rawDataSource
;
3217 g_print("no addressbook file\n");
3221 if( pobj
->type
== ADDR_DATASOURCE
) {
3222 if (ADAPTER_DSOURCE(pobj
)->subType
== ADDR_BOOK
||
3223 ADAPTER_DSOURCE(pobj
)->subType
== ADDR_LDAP
) {
3225 ItemFolder
*folder
= NULL
;
3227 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3228 GtkCMCTreeNode
*parentNode
;
3229 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook
.treeSelected
) );
3230 if( ds
== NULL
) return;
3232 /* We must have a datasource that is an external interface */
3233 if( ! ds
->interface
->haveLibrary
) return;
3234 if( ! ds
->interface
->externalQuery
) return;
3236 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3237 parentNode
= GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook
.treeSelected
) )->parent
;
3240 parentNode
= GTK_CMCTREE_NODE( addrbook
.treeSelected
);
3242 folder
= addressbook_setup_subf( ds
, _("New Contacts"), parentNode
);
3244 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3246 abf
= ds
->rawDataSource
;
3249 person
= addressbook_edit_person( abf
, folder
, NULL
, FALSE
,
3250 addrbook
.editaddress_vbox
,
3251 addressbook_new_address_from_book_post_cb
,
3254 if (ds
&& abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3255 LdapServer
*server
= ds
->rawDataSource
;
3256 ldapsvr_set_modified(server
, TRUE
);
3257 ldapsvr_update_book(server
, NULL
);
3258 if (server
->retVal
!= LDAPRC_SUCCESS
) {
3259 alertpanel( _("Add address(es)"),
3260 addressbook_err2string(_lutErrorsLDAP_
, server
->retVal
),
3261 GTK_STOCK_CLOSE
, NULL
, NULL
, ALERTFOCUS_FIRST
);
3262 server
->retVal
= LDAPRC_SUCCESS
;
3267 if (prefs_common
.addressbook_use_editaddress_dialog
)
3268 addressbook_new_address_from_book_post_cb( person
);
3271 else if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3273 ItemFolder
*folder
= ADAPTER_FOLDER(pobj
)->itemFolder
;
3276 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3277 GtkCMCTreeNode
*parentNode
;
3278 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook
.treeSelected
) );
3279 if( ds
== NULL
) return;
3281 /* We must have a datasource that is an external interface */
3282 if( ! ds
->interface
->haveLibrary
) return;
3283 if( ! ds
->interface
->externalQuery
) return;
3285 if( pobj
->type
== ADDR_ITEM_FOLDER
) {
3286 parentNode
= GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook
.treeSelected
) )->parent
;
3289 parentNode
= GTK_CMCTREE_NODE( addrbook
.treeSelected
);
3291 folder
= addressbook_setup_subf( ds
, _("New Contacts"), parentNode
);
3295 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3297 abf
= ds
->rawDataSource
;
3300 person
= addressbook_edit_person( abf
, folder
, NULL
, FALSE
,
3301 addrbook
.editaddress_vbox
,
3302 addressbook_new_address_from_folder_post_cb
,
3305 if (ds
&& abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3306 LdapServer
*server
= ds
->rawDataSource
;
3307 ldapsvr_set_modified(server
, TRUE
);
3308 ldapsvr_update_book(server
, NULL
);
3309 if (server
->retVal
!= LDAPRC_SUCCESS
) {
3310 alertpanel( _("Add address(es)"),
3311 addressbook_err2string(_lutErrorsLDAP_
, server
->retVal
),
3312 GTK_STOCK_CLOSE
, NULL
, NULL
, ALERTFOCUS_FIRST
);
3317 if (prefs_common
.addressbook_use_editaddress_dialog
)
3318 addressbook_new_address_from_folder_post_cb( person
);
3320 else if( pobj
->type
== ADDR_ITEM_GROUP
) {
3321 /* New address in group */
3322 ItemGroup
*group
= ADAPTER_GROUP(pobj
)->itemGroup
;
3323 if( addressbook_edit_group( abf
, NULL
, group
) == NULL
) return;
3324 if (addrbook
.treeSelected
== addrbook
.opened
) {
3325 /* Change node name in tree. */
3326 addressbook_change_node_name( addrbook
.treeSelected
, ADDRITEM_NAME(group
) );
3327 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), addrbook
.opened
);
3328 addressbook_set_clist(
3329 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3337 * Search for specified child group node in address index tree.
3338 * \param parent Parent node.
3339 * \param group Group to find.
3341 static GtkCMCTreeNode
*addressbook_find_group_node( GtkCMCTreeNode
*parent
, ItemGroup
*group
) {
3342 GtkCMCTreeNode
*node
= NULL
;
3343 GtkCMCTreeRow
*currRow
;
3345 currRow
= GTK_CMCTREE_ROW( parent
);
3347 node
= currRow
->children
;
3351 obj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), node
);
3352 if(obj
&& obj
->type
== ADDR_ITEM_GROUP
) {
3353 ItemGroup
*g
= ADAPTER_GROUP(obj
)->itemGroup
;
3354 if( g
== group
) return node
;
3356 currRow
= GTK_CMCTREE_ROW(node
);
3357 node
= currRow
->sibling
;
3363 static AddressBookFile
*addressbook_get_book_file() {
3364 AddressBookFile
*abf
= NULL
;
3365 AddressDataSource
*ds
= NULL
;
3367 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
3368 if( ds
== NULL
) return NULL
;
3369 if( ds
->type
== ADDR_IF_BOOK
|| ds
->type
== ADDR_IF_LDAP
) abf
= ds
->rawDataSource
;
3373 static void addressbook_tree_remove_children( GtkCMCTree
*ctree
, GtkCMCTreeNode
*parent
) {
3374 GtkCMCTreeNode
*node
;
3377 /* Remove existing folders and groups */
3378 row
= GTK_CMCTREE_ROW( parent
);
3380 while( (node
= row
->children
) ) {
3381 gtk_cmctree_remove_node( ctree
, node
);
3386 static void addressbook_move_nodes_up( GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
) {
3387 GtkCMCTreeNode
*parent
, *child
;
3388 GtkCMCTreeRow
*currRow
;
3389 currRow
= GTK_CMCTREE_ROW( node
);
3391 parent
= currRow
->parent
;
3392 while( (child
= currRow
->children
) ) {
3393 gtk_cmctree_move( ctree
, child
, parent
, node
);
3395 gtk_sctree_sort_node( ctree
, parent
);
3399 static void addressbook_edit_address_post_cb( ItemPerson
*person
)
3403 AddressBookFile
*abf
= addressbook_get_book_file();
3405 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3406 if (g_strcmp0(person
->nickName
, ADDRITEM_NAME(person
)))
3407 addritem_person_set_nick_name( person
, ADDRITEM_NAME(person
));
3410 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook
.clist
), person
);
3411 invalidate_address_completion();
3413 addressbook_address_list_set_focus();
3416 void addressbook_address_list_set_focus( void )
3418 if (!prefs_common
.addressbook_use_editaddress_dialog
) {
3419 gtk_window_set_focus(GTK_WINDOW(addrbook
.window
), addrbook
.clist
);
3420 addressbook_list_menu_setup();
3424 void addressbook_address_list_disable_some_actions(void)
3426 /* disable address copy/pasting when editing contact's detail (embedded form) */
3427 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Cut", FALSE
);
3428 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Copy", FALSE
);
3429 cm_menu_set_sensitive_full( addrbook
.ui_manager
, "Menu/Edit/Paste", FALSE
);
3432 static void addressbook_edit_address_cb( GtkAction
*action
, gpointer data
) {
3433 addressbook_edit_address(data
, 0, NULL
, TRUE
);
3436 static void addressbook_edit_address( gpointer data
, guint action
, GtkWidget
*widget
,
3437 gboolean force_focus
) {
3438 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
3440 AddressObject
*obj
= NULL
, *pobj
= NULL
;
3441 AddressDataSource
*ds
= NULL
;
3442 GtkCMCTreeNode
*node
= NULL
, *parentNode
= NULL
;
3444 AddressBookFile
*abf
= NULL
;
3446 if( addrbook
.listSelected
== NULL
) return;
3447 obj
= gtk_cmctree_node_get_row_data( clist
, addrbook
.listSelected
);
3448 cm_return_if_fail(obj
!= NULL
);
3450 ctree
= GTK_CMCTREE( addrbook
.ctree
);
3451 pobj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
3453 ds
= addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook
.treeSelected
) );
3454 if( ds
== NULL
) return;
3456 abf
= addressbook_get_book_file();
3458 if( obj
->type
== ADDR_ITEM_EMAIL
) {
3459 ItemEMail
*email
= ( ItemEMail
* ) obj
;
3461 if( pobj
&& pobj
->type
== ADDR_ITEM_GROUP
) {
3462 /* Edit parent group */
3463 AdapterGroup
*adapter
= ADAPTER_GROUP(pobj
);
3464 ItemGroup
*itemGrp
= adapter
->itemGroup
;
3465 if( abf
== NULL
) return;
3466 if( addressbook_edit_group( abf
, NULL
, itemGrp
) == NULL
) return;
3467 name
= ADDRITEM_NAME(itemGrp
);
3468 node
= addrbook
.treeSelected
;
3469 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
3472 /* Edit person - email page */
3474 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
3475 if ( addressbook_edit_person( abf
, NULL
, person
, TRUE
, addrbook
.editaddress_vbox
,
3476 addressbook_edit_address_post_cb
,
3477 (prefs_common
.addressbook_use_editaddress_dialog
||force_focus
) )
3480 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3481 ldapsvr_set_modified( (LdapServer
*) abf
, TRUE
);
3482 person
->status
= UPDATE_ENTRY
;
3485 if (prefs_common
.addressbook_use_editaddress_dialog
)
3486 addressbook_edit_address_post_cb( person
);
3491 else if( obj
->type
== ADDR_ITEM_PERSON
) {
3492 /* Edit person - basic page */
3493 ItemPerson
*person
= ( ItemPerson
* ) obj
;
3494 if( addressbook_edit_person( abf
, NULL
, person
, FALSE
, addrbook
.editaddress_vbox
,
3495 addressbook_edit_address_post_cb
,
3496 (prefs_common
.addressbook_use_editaddress_dialog
||force_focus
) )
3499 if (abf
&& abf
->type
== ADBOOKTYPE_LDAP
) {
3500 ldapsvr_set_modified( (LdapServer
*) abf
, TRUE
);
3501 person
->status
= UPDATE_ENTRY
;
3504 if (prefs_common
.addressbook_use_editaddress_dialog
)
3505 addressbook_edit_address_post_cb( person
);
3509 else if( obj
->type
== ADDR_ITEM_GROUP
) {
3510 ItemGroup
*itemGrp
= ( ItemGroup
* ) obj
;
3511 if( addressbook_edit_group( abf
, NULL
, itemGrp
) == NULL
) return;
3512 parentNode
= addrbook
.treeSelected
;
3513 node
= addressbook_find_group_node( parentNode
, itemGrp
);
3514 name
= ADDRITEM_NAME(itemGrp
);
3515 invalidate_address_completion();
3521 /* Update tree node with node name */
3522 if( node
== NULL
) return;
3523 addressbook_change_node_name( node
, name
);
3524 gtk_sctree_sort_node( ctree
, parentNode
);
3525 gtk_sctree_select( GTK_SCTREE(ctree
), addrbook
.opened
);
3526 addressbook_set_clist(
3527 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
3532 static void addressbook_delete_address_cb(GtkAction
*action
, gpointer data
)
3534 addressbook_del_clicked(NULL
, NULL
);
3537 static void close_cb(GtkAction
*action
, gpointer data
)
3539 addressbook_close();
3542 static void addressbook_file_save_cb( GtkAction
*action
, gpointer data
) {
3543 addressbook_export_to_file();
3546 static void addressbook_person_expand_node( GtkCMCTree
*ctree
, GList
*node
, gpointer
*data
) {
3548 ItemPerson
*person
= gtk_cmctree_node_get_row_data( ctree
, GTK_CMCTREE_NODE(node
) );
3549 if( person
) addritem_person_set_opened( person
, TRUE
);
3553 static void addressbook_person_collapse_node( GtkCMCTree
*ctree
, GList
*node
, gpointer
*data
) {
3555 ItemPerson
*person
= gtk_cmctree_node_get_row_data( ctree
, GTK_CMCTREE_NODE(node
) );
3556 if( person
) addritem_person_set_opened( person
, FALSE
);
3560 static gchar
*addressbook_format_item_clist( ItemPerson
*person
, ItemEMail
*email
) {
3562 gchar
*eMailAlias
= ADDRITEM_NAME(email
);
3563 if( eMailAlias
&& *eMailAlias
!= '\0' ) {
3565 str
= g_strdup_printf( "%s - %s", ADDRITEM_NAME(person
), eMailAlias
);
3568 str
= g_strdup( eMailAlias
);
3574 static gboolean
addressbook_match_item(const gchar
*name
,
3575 const gchar
*email_alias
,
3577 const gchar
*remarks
,
3582 if (!str
|| str
[0] == '\0')
3584 if (strcasestr(name
, str
))
3586 else if (email_alias
&& strcasestr(email_alias
, str
))
3588 else if (addr
&& strcasestr(addr
, str
))
3590 else if (remarks
&& strcasestr(remarks
, str
))
3596 static void addressbook_load_group( GtkCMCTree
*clist
, ItemGroup
*itemGroup
) {
3597 GList
*items
= itemGroup
->listEMail
;
3598 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3599 const gchar
*search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3600 for( ; items
!= NULL
; items
= g_list_next( items
) ) {
3601 GtkCMCTreeNode
*nodeEMail
= NULL
;
3602 gchar
*text
[N_LIST_COLS
];
3603 ItemEMail
*email
= items
->data
;
3607 if( ! email
) continue;
3609 person
= ( ItemPerson
* ) ADDRITEM_PARENT(email
);
3611 if( !addressbook_match_item(ADDRITEM_NAME(person
),
3612 ADDRITEM_NAME(email
),
3613 email
->address
, email
->remarks
,
3617 str
= addressbook_format_item_clist( person
, email
);
3619 text
[COL_NAME
] = addressbook_set_col_name_guard(str
);
3622 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3624 text
[COL_ADDRESS
] = email
->address
;
3625 text
[COL_REMARKS
] = email
->remarks
;
3626 nodeEMail
= gtk_sctree_insert_node(
3628 text
, FOLDER_SPACING
,
3632 gtk_cmctree_node_set_row_data( clist
, nodeEMail
, email
);
3638 gchar
*addressbook_set_col_name_guard(gchar
*value
)
3640 gchar
*ret
= "<not set>";
3641 gchar
*tmp
= g_strdup(value
);
3643 if (tmp
!=NULL
&& *tmp
!= '\0')
3649 static void addressbook_folder_load_one_person(
3650 GtkCMCTree
*clist
, ItemPerson
*person
,
3651 AddressTypeControlItem
*atci
,
3652 AddressTypeControlItem
*atciMail
)
3654 GtkCMCTreeNode
*nodePerson
= NULL
;
3655 GtkCMCTreeNode
*nodeEMail
= NULL
;
3656 gchar
*text
[N_LIST_COLS
];
3657 gboolean flgFirst
= TRUE
, haveAddr
= FALSE
;
3660 AddressBookFile
*abf
= addressbook_get_book_file();
3663 if( person
== NULL
) return;
3665 text
[COL_NAME
] = "";
3666 node
= person
->listEMail
;
3668 ItemEMail
*email
= node
->data
;
3669 gchar
*eMailAddr
= NULL
;
3670 node
= g_list_next( node
);
3672 text
[COL_ADDRESS
] = email
->address
;
3673 text
[COL_REMARKS
] = email
->remarks
;
3674 eMailAddr
= ADDRITEM_NAME(email
);
3675 if( eMailAddr
&& *eMailAddr
== '\0' ) eMailAddr
= NULL
;
3677 /* First email belongs with person */
3678 gchar
*str
= addressbook_format_item_clist( person
, email
);
3680 text
[COL_NAME
] = addressbook_set_col_name_guard(str
);
3683 else if( abf
&& abf
->type
== ADBOOKTYPE_LDAP
&&
3684 person
&& person
->nickName
) {
3685 if (person
->nickName
) {
3686 if (strcmp(person
->nickName
, "") != 0) {
3687 text
[COL_NAME
] = addressbook_set_col_name_guard(person
->nickName
);
3690 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3696 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3698 nodePerson
= gtk_sctree_insert_node(
3700 text
, FOLDER_SPACING
,
3703 FALSE
, person
->isOpened
);
3706 gtk_cmctree_node_set_row_data(clist
, nodePerson
, person
);
3709 /* Subsequent email is a child node of person */
3710 text
[COL_NAME
] = ADDRITEM_NAME(email
);
3711 nodeEMail
= gtk_sctree_insert_node(
3712 clist
, nodePerson
, NULL
,
3713 text
, FOLDER_SPACING
,
3715 atciMail
->iconXpmOpen
,
3717 gtk_cmctree_node_set_row_data(clist
, nodeEMail
, email
);
3723 /* Have name without EMail */
3724 text
[COL_NAME
] = addressbook_set_col_name_guard(ADDRITEM_NAME(person
));
3725 text
[COL_ADDRESS
] = "";
3726 text
[COL_REMARKS
] = "";
3727 nodePerson
= gtk_sctree_insert_node(
3729 text
, FOLDER_SPACING
,
3732 FALSE
, person
->isOpened
);
3733 gtk_cmctree_node_set_row_data(clist
, nodePerson
, person
);
3738 static void addressbook_folder_load_person( GtkCMCTree
*clist
, ItemFolder
*itemFolder
) {
3740 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_PERSON
);
3741 AddressTypeControlItem
*atciMail
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3742 const gchar
*search_str
;
3744 if( atci
== NULL
) return;
3745 if( atciMail
== NULL
) return;
3747 search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3749 /* Load email addresses */
3750 items
= addritem_folder_get_person_list( itemFolder
);
3751 for(cur
= items
; cur
!= NULL
; cur
= g_list_next( cur
) ) {
3756 person
= (ItemPerson
*)cur
->data
;
3759 node
= person
->listEMail
;
3760 if (node
&& node
->data
) {
3762 if (!addressbook_match_item(ADDRITEM_NAME(person
), ADDRITEM_NAME(email
), email
->address
, email
->remarks
, search_str
))
3765 if (!addressbook_match_item(ADDRITEM_NAME(person
), NULL
, NULL
, NULL
, search_str
))
3769 addressbook_folder_load_one_person( clist
, cur
->data
, atci
, atciMail
);
3771 /* Free up the list */
3772 g_list_free( items
);
3775 static void addressbook_folder_remove_node( GtkCMCTree
*clist
, GtkCMCTreeNode
*node
) {
3776 addrbook
.listSelected
= NULL
;
3777 gtk_cmctree_remove_node( clist
, node
);
3778 addressbook_menubar_set_sensitive( FALSE
);
3779 addressbook_menuitem_set_sensitive(
3780 gtk_cmctree_node_get_row_data(
3781 GTK_CMCTREE(clist
), addrbook
.treeSelected
),
3782 addrbook
.treeSelected
);
3785 void addressbook_folder_refresh_one_person( GtkCMCTree
*clist
, ItemPerson
*person
) {
3786 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_PERSON
);
3787 AddressTypeControlItem
*atciMail
= addrbookctl_lookup( ADDR_ITEM_EMAIL
);
3788 GtkCMCTreeNode
*node
;
3789 if( atci
== NULL
) return;
3790 if( atciMail
== NULL
) return;
3791 if( person
== NULL
) return;
3792 /* unload the person */
3794 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3796 addressbook_folder_remove_node( clist
, node
);
3797 addressbook_folder_load_one_person( clist
, person
, atci
, atciMail
);
3798 gtk_sctree_sort_node( clist
, NULL
);
3799 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3801 gtk_sctree_select( GTK_SCTREE(clist
), node
);
3802 if (!gtk_cmctree_node_is_visible( clist
, node
) )
3803 gtk_cmctree_node_moveto( clist
, node
, 0, 0, 0 );
3807 void addressbook_folder_remove_one_person( GtkCMCTree
*clist
, ItemPerson
*person
) {
3808 GtkCMCTreeNode
*node
;
3810 if( person
== NULL
) return;
3811 node
= gtk_cmctree_find_by_row_data( clist
, NULL
, person
);
3813 addressbook_folder_remove_node( clist
, node
);
3817 static void addressbook_folder_load_group( GtkCMCTree
*clist
, ItemFolder
*itemFolder
) {
3819 AddressTypeControlItem
*atci
= addrbookctl_lookup( ADDR_ITEM_GROUP
);
3820 const gchar
*search_str
;
3822 /* Load any groups */
3823 if( ! atci
) return;
3825 search_str
= gtk_entry_get_text(GTK_ENTRY(addrbook
.entry
));
3827 items
= addritem_folder_get_group_list( itemFolder
);
3828 for( ; items
!= NULL
; items
= g_list_next( items
) ) {
3829 GtkCMCTreeNode
*nodeGroup
= NULL
;
3830 gchar
*text
[N_LIST_COLS
];
3831 ItemGroup
*group
= items
->data
;
3832 if( group
== NULL
) continue;
3833 if( !addressbook_match_item(ADDRITEM_NAME(group
),
3834 NULL
, NULL
, NULL
, search_str
) )
3837 text
[COL_NAME
] = ADDRITEM_NAME(group
);
3838 text
[COL_ADDRESS
] = "";
3839 text
[COL_REMARKS
] = "";
3840 nodeGroup
= gtk_sctree_insert_node(clist
, NULL
, NULL
,
3841 text
, FOLDER_SPACING
,
3845 gtk_cmctree_node_set_row_data(clist
, nodeGroup
, group
);
3846 gtk_sctree_sort_node(clist
, NULL
);
3848 /* Free up the list */
3849 g_list_free( items
);
3853 * Search ctree widget callback function.
3854 * \param pA Pointer to node.
3855 * \param pB Pointer to data item being sought.
3856 * \return Zero (0) if group found.
3858 static int addressbook_treenode_find_group_cb( gconstpointer pA
, gconstpointer pB
) {
3861 aoA
= ( AddressObject
* ) pA
;
3862 if( aoA
->type
== ADDR_ITEM_GROUP
) {
3863 ItemGroup
*group
, *grp
;
3865 grp
= ADAPTER_GROUP(aoA
)->itemGroup
;
3866 group
= ( ItemGroup
* ) pB
;
3867 if( grp
== group
) return 0; /* Found group */
3873 * Remove folder and group nodes from tree widget for items contained ("cut")
3876 static void addressbook_treenode_remove_item( void ) {
3878 AddrSelectItem
*cutItem
;
3879 AddressCache
*cache
;
3880 AddrItemObject
*aio
;
3881 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
3884 node
= _clipBoard_
->objectList
;
3886 cutItem
= node
->data
;
3887 node
= g_list_next( node
);
3888 cache
= addrindex_get_cache(
3889 _clipBoard_
->addressIndex
, cutItem
->cacheID
);
3890 if( cache
== NULL
) continue;
3891 aio
= addrcache_get_object( cache
, cutItem
->uid
);
3894 if( ADDRITEM_TYPE(aio
) == ITEMTYPE_FOLDER
) {
3897 folder
= ( ItemFolder
* ) aio
;
3898 tn
= gtk_cmctree_find_by_row_data_custom(
3899 ctree
, NULL
, folder
,
3900 addressbook_treenode_find_folder_cb
);
3902 else if( ADDRITEM_TYPE(aio
) == ITEMTYPE_GROUP
) {
3905 group
= ( ItemGroup
* ) aio
;
3906 tn
= gtk_cmctree_find_by_row_data_custom(
3908 addressbook_treenode_find_group_cb
);
3912 /* Free up adapter and remove node. */
3913 gtk_cmctree_remove_node( ctree
, tn
);
3920 * Find parent datasource for specified tree node.
3921 * \param node Node to test.
3922 * \return Data source, or NULL if not found.
3924 static AddressDataSource
*addressbook_find_datasource( GtkCMCTreeNode
*node
) {
3925 AddressDataSource
*ds
= NULL
;
3928 cm_return_val_if_fail(addrbook
.ctree
!= NULL
, NULL
);
3931 if( GTK_CMCTREE_ROW(node
)->level
< 2 ) return NULL
;
3932 ao
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), node
);
3934 /* g_print( "ao->type = %d\n", ao->type ); */
3935 if( ao
->type
== ADDR_DATASOURCE
) {
3936 AdapterDSource
*ads
= ADAPTER_DSOURCE(ao
);
3937 /* g_print( "found it\n" ); */
3938 ds
= ads
->dataSource
;
3942 node
= GTK_CMCTREE_ROW(node
)->parent
;
3948 * Load address list widget with children of specified object.
3949 * \param obj Parent object to be loaded.
3951 static void addressbook_set_clist( AddressObject
*obj
, gboolean refresh
) {
3952 GtkCMCTree
*ctreelist
= GTK_CMCTREE(addrbook
.clist
);
3953 GtkCMCList
*clist
= GTK_CMCLIST(addrbook
.clist
);
3954 AddressDataSource
*ds
= NULL
;
3955 AdapterDSource
*ads
= NULL
;
3956 static AddressObject
*last_obj
= NULL
;
3958 if (addrbook
.clist
== NULL
) {
3961 if (obj
== last_obj
&& !refresh
)
3966 gtk_cmclist_clear(clist
);
3970 if( obj
->type
== ADDR_INTERFACE
) {
3971 /* g_print( "set_clist: loading datasource...\n" ); */
3972 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3976 gtk_cmclist_freeze(clist
);
3977 gtk_cmclist_clear(clist
);
3979 if( obj
->type
== ADDR_DATASOURCE
) {
3980 ads
= ADAPTER_DSOURCE(obj
);
3981 ds
= ads
->dataSource
;
3983 /* Load root folder */
3984 ItemFolder
*rootFolder
= NULL
;
3985 rootFolder
= addrindex_ds_get_root_folder( ds
);
3986 addressbook_folder_load_person(
3987 ctreelist
, rootFolder
);
3988 addressbook_folder_load_group(
3989 ctreelist
, rootFolder
);
3993 if( obj
->type
== ADDR_ITEM_GROUP
) {
3995 ItemGroup
*itemGroup
= ADAPTER_GROUP(obj
)->itemGroup
;
3996 addressbook_load_group( ctreelist
, itemGroup
);
3998 else if( obj
->type
== ADDR_ITEM_FOLDER
) {
4000 ItemFolder
*itemFolder
= ADAPTER_FOLDER(obj
)->itemFolder
;
4001 addressbook_folder_load_person( ctreelist
, itemFolder
);
4002 addressbook_folder_load_group( ctreelist
, itemFolder
);
4005 gtk_sctree_sort_recursive(GTK_CMCTREE(clist
), NULL
);
4006 clist
->focus_row
= -1;
4007 gtk_cmclist_thaw(clist
);
4011 * Call back function to free adaptor. Call back is setup by function
4012 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4013 * called when the address book tree widget node is removed by calling
4014 * function gtk_cmctree_remove_node().
4016 * \param data Tree node's row data.
4018 static void addressbook_free_treenode( gpointer data
) {
4021 ao
= ( AddressObject
* ) data
;
4022 if( ao
== NULL
) return;
4023 if( ao
->type
== ADDR_INTERFACE
) {
4024 AdapterInterface
*ai
= ADAPTER_INTERFACE(ao
);
4025 addrbookctl_free_interface( ai
);
4027 else if( ao
->type
== ADDR_DATASOURCE
) {
4028 AdapterDSource
*ads
= ADAPTER_DSOURCE(ao
);
4029 addrbookctl_free_datasource( ads
);
4031 else if( ao
->type
== ADDR_ITEM_FOLDER
) {
4032 AdapterFolder
*af
= ADAPTER_FOLDER(ao
);
4033 addrbookctl_free_folder( af
);
4035 else if( ao
->type
== ADDR_ITEM_GROUP
) {
4036 AdapterGroup
*ag
= ADAPTER_GROUP(ao
);
4037 addrbookctl_free_group( ag
);
4042 * Create new adaptor for specified data source.
4044 AdapterDSource
*addressbook_create_ds_adapter( AddressDataSource
*ds
,
4045 AddressObjectType otype
, gchar
*name
)
4047 AdapterDSource
*adapter
= g_new0( AdapterDSource
, 1 );
4048 ADDRESS_OBJECT(adapter
)->type
= ADDR_DATASOURCE
;
4049 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( name
);
4050 adapter
->dataSource
= ds
;
4051 adapter
->subType
= otype
;
4055 void addressbook_ads_set_name( AdapterDSource
*adapter
, gchar
*value
) {
4056 ADDRESS_OBJECT_NAME(adapter
) =
4057 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter
), value
);
4061 * Load tree from address index with the initial data.
4063 static void addressbook_load_tree( void ) {
4064 GtkCMCTree
*ctree
= GTK_CMCTREE( addrbook
.ctree
);
4065 GList
*nodeIf
, *nodeDS
;
4066 AdapterInterface
*adapter
;
4067 AddressInterface
*iface
;
4068 AddressTypeControlItem
*atci
;
4069 AddressDataSource
*ds
;
4070 AdapterDSource
*ads
;
4071 GtkCMCTreeNode
*node
, *newNode
;
4074 nodeIf
= _addressInterfaceList_
;
4076 adapter
= nodeIf
->data
;
4077 node
= adapter
->treeNode
;
4078 iface
= adapter
->interface
;
4079 atci
= adapter
->atci
;
4081 if( iface
->useInterface
) {
4082 /* Load data sources below interface node */
4083 nodeDS
= iface
->listSource
;
4086 name
= addrindex_ds_get_name( ds
);
4087 ads
= addressbook_create_ds_adapter(
4088 ds
, atci
->objectType
, name
);
4089 newNode
= addressbook_add_object(
4090 node
, ADDRESS_OBJECT(ads
) );
4091 if (newNode
== NULL
) {
4092 g_message("error adding addressbook object\n");
4094 nodeDS
= g_list_next( nodeDS
);
4096 gtk_cmctree_expand( ctree
, node
);
4099 nodeIf
= g_list_next( nodeIf
);
4104 * Convert the old address book to new format.
4106 static gboolean
addressbook_convert( AddressIndex
*addrIndex
) {
4107 gboolean retVal
= FALSE
;
4108 gboolean errFlag
= TRUE
;
4111 /* Read old address book, performing conversion */
4112 debug_print( "Reading and converting old address book...\n" );
4113 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_OLD_FILE
);
4114 addrindex_read_data( addrIndex
);
4115 if( addrIndex
->retVal
== MGU_NO_FILE
) {
4116 /* We do not have a file - new user */
4117 debug_print( "New user... create new books...\n" );
4118 addrindex_create_new_books( addrIndex
);
4119 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4120 /* Save index file */
4121 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4122 addrindex_save_data( addrIndex
);
4123 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4128 msg
= _( "New user, could not save index file." );
4132 msg
= _( "New user, could not save address book files." );
4136 /* We have an old file */
4137 if( addrIndex
->wasConverted
) {
4138 /* Converted successfully - save address index */
4139 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4140 addrindex_save_data( addrIndex
);
4141 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4142 msg
= _( "Old address book converted successfully." );
4147 msg
= _("Old address book converted,\n"
4148 "could not save new address index file." );
4152 /* File conversion failed - just create new books */
4153 debug_print( "File conversion failed... just create new books...\n" );
4154 addrindex_create_new_books( addrIndex
);
4155 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4157 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4158 addrindex_save_data( addrIndex
);
4159 if( addrIndex
->retVal
== MGU_SUCCESS
) {
4160 msg
= _("Could not convert address book,\n"
4161 "but created empty new address book files." );
4166 msg
= _("Could not convert address book,\n"
4167 "could not save new address index file." );
4171 msg
= _("Could not convert address book\n"
4172 "and could not create new address book files." );
4177 debug_print( "Error\n%s\n", msg
);
4178 alertpanel_full(_("Addressbook conversion error"), msg
,
4179 GTK_STOCK_CLOSE
, NULL
, NULL
, ALERTFOCUS_FIRST
, FALSE
,
4183 debug_print( "Warning\n%s\n", msg
);
4184 alertpanel_full(_("Addressbook conversion error"), msg
,
4185 GTK_STOCK_CLOSE
, NULL
, NULL
, ALERTFOCUS_FIRST
, FALSE
,
4186 NULL
, ALERT_WARNING
);
4192 static gboolean
migrate_addrbook(const gchar
*origdir
, const gchar
*destdir
)
4196 gboolean failed
= FALSE
;
4197 GError
*error
= NULL
;
4199 if( ( dp
= g_dir_open( origdir
, 0, &error
) ) == NULL
) {
4200 debug_print("opening '%s' failed: %d (%s)\n", origdir
,
4201 error
->code
, error
->message
);
4202 g_error_free(error
);
4206 while( ( d
= g_dir_read_name( dp
) ) != NULL
) {
4207 if (strncmp(d
, "addrbook-", strlen("addrbook-")))
4210 gchar
*orig_file
= g_strconcat(origdir
, G_DIR_SEPARATOR_S
,
4212 gchar
*dest_file
= g_strconcat(destdir
, G_DIR_SEPARATOR_S
,
4214 if (copy_file(orig_file
, dest_file
, FALSE
) < 0) {
4227 /* all copies succeeded, we can remove source files */
4228 if( ( dp
= g_dir_open( origdir
, 0, &error
) ) == NULL
) {
4229 debug_print("opening '%s' failed: %d (%s)\n", origdir
,
4230 error
->code
, error
->message
);
4231 g_error_free(error
);
4234 while( ( d
= g_dir_read_name( dp
) ) != NULL
) {
4235 if (strncmp(d
, "addrbook-", strlen("addrbook-")))
4238 gchar
*orig_file
= g_strconcat(origdir
, G_DIR_SEPARATOR_S
,
4240 claws_unlink(orig_file
);
4250 void addressbook_read_file( void ) {
4251 AddressIndex
*addrIndex
= NULL
;
4252 gchar
*indexdir
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, ADDRBOOK_DIR
, NULL
);
4254 debug_print( "Reading address index...\n" );
4255 if( _addressIndex_
) {
4256 debug_print( "address book already read!!!\n" );
4261 addrIndex
= addrindex_create_index();
4262 addrindex_initialize();
4264 /* Use new address book index. */
4266 if ( !is_dir_exist(indexdir
) ) {
4267 if ( make_dir(indexdir
) < 0 ) {
4268 addrindex_set_file_path( addrIndex
, get_rc_dir() );
4269 g_warning( "couldn't create dir '%s'", indexdir
);
4271 if (!migrate_addrbook(get_rc_dir(), indexdir
)) {
4272 remove_dir_recursive(indexdir
);
4273 addrindex_set_file_path( addrIndex
, get_rc_dir() );
4274 g_error("couldn't migrate dir %s", indexdir
);
4276 addrindex_set_file_path( addrIndex
, indexdir
);
4280 addrindex_set_file_path( addrIndex
, indexdir
);
4283 addrindex_set_file_name( addrIndex
, ADDRESSBOOK_INDEX_FILE
);
4284 addrindex_read_data( addrIndex
);
4285 if( addrIndex
->retVal
== MGU_NO_FILE
) {
4286 /* Conversion required */
4287 debug_print( "Converting...\n" );
4288 if( addressbook_convert( addrIndex
) ) {
4289 _addressIndex_
= addrIndex
;
4292 else if( addrIndex
->retVal
== MGU_SUCCESS
) {
4293 _addressIndex_
= addrIndex
;
4296 /* Error reading address book */
4297 debug_print( "Could not read address index.\n" );
4298 addrindex_print_index( addrIndex
, stdout
);
4299 alertpanel_full(_("Addressbook Error"),
4300 _("Could not read address index"),
4301 GTK_STOCK_CLOSE
, NULL
, NULL
, ALERTFOCUS_FIRST
, FALSE
,
4304 debug_print( "done.\n" );
4308 * Add object into the address index tree widget.
4309 * Enter: node Parent node.
4310 * obj Object to add.
4311 * Return: Node that was added, or NULL if object not added.
4313 static GtkCMCTreeNode
*addressbook_add_object(GtkCMCTreeNode
*node
,
4316 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4317 GtkCMCTreeNode
*added
;
4318 AddressObject
*pobj
;
4319 AddressObjectType otype
;
4320 AddressTypeControlItem
*atci
= NULL
;
4322 cm_return_val_if_fail(node
!= NULL
, NULL
);
4323 cm_return_val_if_fail(obj
!= NULL
, NULL
);
4325 pobj
= gtk_cmctree_node_get_row_data(ctree
, node
);
4326 cm_return_val_if_fail(pobj
!= NULL
, NULL
);
4328 /* Determine object type to be displayed */
4329 if( obj
->type
== ADDR_DATASOURCE
) {
4330 otype
= ADAPTER_DSOURCE(obj
)->subType
;
4336 /* Handle any special conditions. */
4338 atci
= addrbookctl_lookup( otype
);
4340 if( atci
->showInTree
) {
4341 /* Add object to tree */
4344 added
= gtk_sctree_insert_node( ctree
, node
, NULL
, name
, FOLDER_SPACING
,
4345 atci
->iconXpm
, atci
->iconXpmOpen
,
4346 atci
->treeLeaf
, atci
->treeExpand
);
4347 gtk_cmctree_node_set_row_data_full( ctree
, added
, obj
,
4348 addressbook_free_treenode
);
4352 gtk_sctree_sort_node(ctree
, node
);
4358 * Add group into the address index tree.
4359 * \param node Parent node.
4360 * \param ds Data source.
4361 * \param itemGroup Group to add.
4362 * \return Inserted node.
4364 static GtkCMCTreeNode
*addressbook_node_add_group(
4365 GtkCMCTreeNode
*node
, AddressDataSource
*ds
,
4366 ItemGroup
*itemGroup
)
4368 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4369 GtkCMCTreeNode
*newNode
;
4370 AdapterGroup
*adapter
;
4371 AddressTypeControlItem
*atci
= NULL
;
4374 if( ds
== NULL
) return NULL
;
4375 if( node
== NULL
|| itemGroup
== NULL
) return NULL
;
4377 name
= &itemGroup
->obj
.name
;
4379 atci
= addrbookctl_lookup( ADDR_ITEM_GROUP
);
4381 adapter
= g_new0( AdapterGroup
, 1 );
4382 ADDRESS_OBJECT_TYPE(adapter
) = ADDR_ITEM_GROUP
;
4383 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( ADDRITEM_NAME(itemGroup
) );
4384 adapter
->itemGroup
= itemGroup
;
4386 newNode
= gtk_sctree_insert_node( ctree
, node
, NULL
, name
, FOLDER_SPACING
,
4387 atci
->iconXpm
, atci
->iconXpm
,
4388 atci
->treeLeaf
, atci
->treeExpand
);
4389 gtk_cmctree_node_set_row_data_full( ctree
, newNode
, adapter
,
4390 addressbook_free_treenode
);
4391 gtk_sctree_sort_node( ctree
, node
);
4396 * Add folder into the address index tree. Only visible folders are loaded into
4397 * the address index tree. Note that the root folder is not inserted into the
4400 * \param node Parent node.
4401 * \param ds Data source.
4402 * \param itemFolder Folder to add.
4403 * \param otype Object type to display.
4404 * \return Inserted node for the folder.
4406 static GtkCMCTreeNode
*addressbook_node_add_folder(
4407 GtkCMCTreeNode
*node
, AddressDataSource
*ds
,
4408 ItemFolder
*itemFolder
, AddressObjectType otype
)
4410 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
4411 GtkCMCTreeNode
*newNode
= NULL
;
4412 AdapterFolder
*adapter
;
4413 AddressTypeControlItem
*atci
= NULL
;
4414 GList
*listItems
= NULL
;
4416 ItemFolder
*rootFolder
;
4418 /* Only visible folders */
4419 if( itemFolder
== NULL
|| itemFolder
->isHidden
)
4424 if( node
== NULL
|| itemFolder
== NULL
)
4427 /* Determine object type */
4428 atci
= addrbookctl_lookup( otype
);
4432 rootFolder
= addrindex_ds_get_root_folder( ds
);
4433 if( itemFolder
== rootFolder
) {
4437 adapter
= g_new0( AdapterFolder
, 1 );
4438 ADDRESS_OBJECT_TYPE(adapter
) = ADDR_ITEM_FOLDER
;
4439 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( ADDRITEM_NAME(itemFolder
) );
4440 adapter
->itemFolder
= itemFolder
;
4442 name
= ADDRITEM_NAME(itemFolder
);
4443 newNode
= gtk_sctree_insert_node( ctree
, node
, NULL
, &name
, FOLDER_SPACING
,
4444 atci
->iconXpm
, atci
->iconXpm
,
4445 atci
->treeLeaf
, atci
->treeExpand
);
4447 gtk_cmctree_node_set_row_data_full( ctree
, newNode
, adapter
,
4448 addressbook_free_treenode
);
4452 listItems
= itemFolder
->listFolder
;
4453 while( listItems
) {
4454 ItemFolder
*item
= listItems
->data
;
4455 addressbook_node_add_folder( newNode
, ds
, item
, otype
);
4456 listItems
= g_list_next( listItems
);
4458 listItems
= itemFolder
->listGroup
;
4459 while( listItems
) {
4460 ItemGroup
*item
= listItems
->data
;
4461 addressbook_node_add_group( newNode
, ds
, item
);
4462 listItems
= g_list_next( listItems
);
4464 gtk_sctree_sort_node( ctree
, node
);
4468 void addressbook_export_to_file( void ) {
4469 if( _addressIndex_
) {
4470 /* Save all new address book data */
4471 debug_print( "Saving address books...\n" );
4472 addrindex_save_all_books( _addressIndex_
);
4474 debug_print( "Exporting addressbook to file...\n" );
4475 addrindex_save_data( _addressIndex_
);
4476 if( _addressIndex_
->retVal
!= MGU_SUCCESS
) {
4477 addrindex_print_index( _addressIndex_
, stdout
);
4480 /* Notify address completion of new data */
4481 invalidate_address_completion();
4485 static gboolean
addressbook_entry_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
4487 if (event
&& (event
->keyval
== GDK_KEY_Return
|| event
->keyval
== GDK_KEY_KP_Enter
))
4488 addressbook_lup_clicked(NULL
, NULL
);
4493 * Comparison using cell contents (text in first column). Used for sort
4494 * address index widget.
4496 static gint
addressbook_treenode_compare_func(
4497 GtkCMCList
*clist
, gconstpointer ptr1
, gconstpointer ptr2
)
4499 GtkCMCell
*cell1
= ((GtkCMCListRow
*)ptr1
)->cell
;
4500 GtkCMCell
*cell2
= ((GtkCMCListRow
*)ptr2
)->cell
;
4501 gchar
*name1
= NULL
, *name2
= NULL
;
4502 if( cell1
) name1
= cell1
->u
.text
;
4503 if( cell2
) name2
= cell2
->u
.text
;
4504 if( ! name1
) return ( name2
!= NULL
);
4505 if( ! name2
) return -1;
4506 return g_utf8_collate( name1
, name2
);
4509 static void addressbook_new_book_cb( GtkAction
*action
, gpointer data
) {
4510 AdapterDSource
*ads
;
4511 AdapterInterface
*adapter
;
4512 GtkCMCTreeNode
*newNode
;
4514 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
4515 if( adapter
== NULL
) return;
4516 ads
= addressbook_edit_book( _addressIndex_
, NULL
);
4518 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4520 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4521 addrbook
.treeSelected
= newNode
;
4526 static void addressbook_new_vcard_cb( GtkAction
*action
, gpointer data
) {
4527 AdapterDSource
*ads
;
4528 AdapterInterface
*adapter
;
4529 GtkCMCTreeNode
*newNode
;
4531 adapter
= addrbookctl_find_interface( ADDR_IF_VCARD
);
4532 if( adapter
== NULL
) return;
4533 ads
= addressbook_edit_vcard( _addressIndex_
, NULL
);
4535 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4537 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4538 addrbook
.treeSelected
= newNode
;
4544 static void addressbook_new_jpilot_cb( GtkAction
*action
, gpointer data
) {
4545 AdapterDSource
*ads
;
4546 AdapterInterface
*adapter
;
4547 AddressInterface
*iface
;
4548 GtkCMCTreeNode
*newNode
;
4550 adapter
= addrbookctl_find_interface( ADDR_IF_JPILOT
);
4551 if( adapter
== NULL
) return;
4552 iface
= adapter
->interface
;
4553 if( ! iface
->haveLibrary
) return;
4554 ads
= addressbook_edit_jpilot( _addressIndex_
, NULL
);
4556 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4558 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4559 addrbook
.treeSelected
= newNode
;
4566 static void addressbook_new_ldap_cb( GtkAction
*action
, gpointer data
) {
4567 AdapterDSource
*ads
;
4568 AdapterInterface
*adapter
;
4569 AddressInterface
*iface
;
4570 GtkCMCTreeNode
*newNode
;
4572 adapter
= addrbookctl_find_interface( ADDR_IF_LDAP
);
4573 if( adapter
== NULL
) return;
4574 iface
= adapter
->interface
;
4575 if( ! iface
->haveLibrary
) return;
4576 ads
= addressbook_edit_ldap( _addressIndex_
, NULL
);
4578 newNode
= addressbook_add_object( adapter
->treeNode
, ADDRESS_OBJECT(ads
) );
4580 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), newNode
);
4581 addrbook
.treeSelected
= newNode
;
4588 * Display address search status message.
4589 * \param queryType Query type.
4590 * \param status Status/Error code.
4592 static void addressbook_search_message( gint queryType
, gint sts
) {
4594 *addressbook_msgbuf
= '\0';
4596 if( sts
!= MGU_SUCCESS
) {
4597 if( queryType
== ADDRQUERY_LDAP
) {
4599 desc
= addressbook_err2string( _lutErrorsLDAP_
, sts
);
4604 g_snprintf( addressbook_msgbuf
,
4605 sizeof(addressbook_msgbuf
), "%s", desc
);
4606 addressbook_status_show( addressbook_msgbuf
);
4609 addressbook_status_show( "" );
4614 * Refresh addressbook by forcing refresh of current selected object in
4617 static void addressbook_refresh_current( void ) {
4621 ctree
= GTK_CMCTREE(addrbook
.ctree
);
4622 obj
= gtk_cmctree_node_get_row_data( ctree
, addrbook
.treeSelected
);
4623 if( obj
== NULL
) return;
4624 addressbook_set_clist( obj
, TRUE
);
4628 * Message that is displayed whilst a query is executing in a background
4631 static gchar
*_tempMessage_
= N_( "Busy searching..." );
4634 * Address search idle function. This function is called during UI idle time
4635 * while a search is in progress.
4637 * \param data Idler data.
4639 static void addressbook_search_idle( gpointer data
) {
4643 queryID = GPOINTER_TO_INT( data );
4644 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4649 * Search completion callback function. This removes the query from the idle
4652 * \param sender Sender of query.
4653 * \param queryID Query ID of search request.
4654 * \param status Search status.
4655 * \param data Query data.
4657 static void addressbook_search_callback_end(
4658 gpointer sender
, gint queryID
, gint status
, gpointer data
)
4662 AddrQueryObject
*aqo
;
4664 /* Remove idler function */
4665 ptrQID
= GINT_TO_POINTER( queryID
);
4667 g_idle_remove_by_data( ptrQID
);
4670 /* Refresh addressbook contents */
4671 addressbook_refresh_current();
4672 req
= qrymgr_find_request( queryID
);
4674 aqo
= ( AddrQueryObject
* ) req
->queryList
->data
;
4675 addressbook_search_message( aqo
->queryType
, status
);
4678 /* Stop the search */
4679 addrindex_stop_search( queryID
);
4685 * \param ds Data source to search.
4686 * \param searchTerm String to lookup.
4687 * \param pNode Parent data source node.
4689 static void addressbook_perform_search(
4690 AddressDataSource
*ds
, gchar
*searchTerm
,
4691 GtkCMCTreeNode
*pNode
)
4699 if( *searchTerm
== '\0' || strlen( searchTerm
) < 1 ) return;
4701 if( !ds
|| ds
->type
!= ADDR_IF_LDAP
) return;
4703 /* Create a folder for the search results */
4704 name
= g_strdup_printf( _queryFolderLabel_
, searchTerm
);
4705 folder
= addressbook_setup_subf(ds
, name
, pNode
);
4708 /* Setup the search */
4709 queryID
= addrindex_setup_explicit_search(
4710 ds
, searchTerm
, folder
, addressbook_search_callback_end
, NULL
);
4711 if( queryID
== 0 ) return;
4713 /* Set up idler function */
4714 idleID
= g_idle_add(
4715 (GSourceFunc
) addressbook_search_idle
,
4716 GINT_TO_POINTER( queryID
) );
4718 g_message("error adding addressbook_search_idle\n");
4721 /* Start search, sit back and wait for something to happen */
4722 addrindex_start_search( queryID
);
4724 addressbook_status_show( _tempMessage_
);
4728 * Lookup button handler. Address search is only performed against
4729 * address interfaces for external queries.
4731 * \param button Lookup button widget.
4732 * \param data Data object.
4734 static void addressbook_lup_clicked( GtkButton
*button
, gpointer data
) {
4737 AddressDataSource
*ds
;
4738 AddressInterface
*iface
;
4740 GtkCMCTreeNode
*node
, *parentNode
;
4742 LdapServer
*ldap_server
;
4743 LdapControl
*ldap_ctl
;
4746 node
= addrbook
.treeSelected
;
4747 if( ! node
) return;
4748 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
4750 ctree
= GTK_CMCTREE(addrbook
.ctree
);
4751 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
4752 if( obj
== NULL
) return;
4754 if (obj
->type
!= ADDR_DATASOURCE
||
4755 ADAPTER_DSOURCE(obj
)->subType
!= ADDR_LDAP
) {
4756 addressbook_set_clist(
4757 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
),
4758 addrbook
.treeSelected
),
4762 ds
= addressbook_find_datasource( node
);
4763 if( ds
== NULL
) return;
4765 /* We must have a datasource that is an external interface */
4766 iface
= ds
->interface
;
4767 if( ! iface
->haveLibrary
) return;
4768 if( ! iface
->externalQuery
) return;
4771 if (iface
->type
== ADDR_IF_LDAP
) {
4772 ldap_server
= ds
->rawDataSource
;
4773 ldap_ctl
= ldap_server
->control
;
4774 if (ldap_ctl
!= NULL
&&
4775 ldap_ctl
->bindDN
!= NULL
&& strlen(ldap_ctl
->bindDN
) > 0) {
4776 #ifndef PASSWORD_CRYPTO_OLD
4777 /* LDAP server is password-protected. */
4778 if (master_passphrase() == NULL
) {
4779 /* User did not enter master passphrase, do not start a search. */
4782 #endif /* PASSWORD_CRYPTO_OLD */
4785 #endif /* USE_LDAP */
4788 gtk_editable_get_chars( GTK_EDITABLE(addrbook
.entry
), 0, -1 );
4789 g_strchomp( searchTerm
);
4791 if( obj
->type
== ADDR_ITEM_FOLDER
) {
4792 parentNode
= GTK_CMCTREE_ROW(node
)->parent
;
4797 addressbook_perform_search( ds
, searchTerm
, parentNode
);
4799 gtk_widget_grab_focus( addrbook
.entry
);
4801 g_free( searchTerm
);
4804 static void addressbook_close_clicked( GtkButton
*button
, gpointer data
) {
4805 addressbook_close();
4810 * Browse address entry for highlighted entry.
4812 static void addressbook_browse_entry_cb( GtkAction
*action
, gpointer data
)
4814 GtkCMCTree
*clist
= GTK_CMCTREE(addrbook
.clist
);
4816 AddressDataSource
*ds
;
4817 AddressInterface
*iface
;
4821 if(addrbook
.listSelected
== NULL
)
4824 obj
= gtk_cmctree_node_get_row_data(clist
, addrbook
.listSelected
);
4828 ds
= addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook
.treeSelected
));
4832 iface
= ds
->interface
;
4833 if(!iface
|| !iface
->haveLibrary
)
4837 if (obj
->type
== ADDR_ITEM_EMAIL
) {
4838 email
= ( ItemEMail
* ) obj
;
4840 person
= (ItemPerson
*) ADDRITEM_PARENT(email
);
4842 else if (obj
->type
== ADDR_ITEM_PERSON
) {
4843 person
= (ItemPerson
*) obj
;
4850 if( iface
&& iface
->type
== ADDR_IF_LDAP
) {
4851 browseldap_entry(ds
, person
->externalID
);
4856 /* **********************************************************************
4857 * Build lookup tables.
4858 * ***********************************************************************
4862 * Remap object types.
4863 * Enter: abType AddressObjectType (used in tree node).
4864 * Return: ItemObjectType (used in address cache data).
4866 ItemObjectType
addressbook_type2item( AddressObjectType abType
) {
4867 ItemObjectType ioType
;
4870 case ADDR_ITEM_PERSON
: ioType
= ITEMTYPE_PERSON
; break;
4871 case ADDR_ITEM_EMAIL
: ioType
= ITEMTYPE_EMAIL
; break;
4872 case ADDR_ITEM_FOLDER
: ioType
= ITEMTYPE_FOLDER
; break;
4873 case ADDR_ITEM_GROUP
: ioType
= ITEMTYPE_GROUP
; break;
4874 case ADDR_DATASOURCE
: ioType
= ITEMTYPE_DATASOURCE
; break;
4875 default: ioType
= ITEMTYPE_NONE
; break;
4880 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4881 atci = addrbookctl_lookup(id); \
4883 atci->iconXpm = icon; \
4884 atci->iconXpmOpen = iconopen; \
4886 g_warning("can't get atci %d", id); \
4891 * Build table that controls the rendering of object types.
4893 static void addrbookctl_build_icons( GtkWidget
*window
) {
4894 AddressTypeControlItem
*atci
;
4898 g_object_unref(interfacexpm
);
4900 g_object_unref(folderxpm
);
4902 g_object_unref(folderopenxpm
);
4904 g_object_unref(groupxpm
);
4906 g_object_unref(vcardxpm
);
4908 g_object_unref(bookxpm
);
4910 g_object_unref(addressxpm
);
4912 g_object_unref(jpilotxpm
);
4914 g_object_unref(categoryxpm
);
4916 g_object_unref(ldapxpm
);
4918 g_object_unref(addrsearchxpm
);
4919 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE
, &interfacexpm
);
4920 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
);
4921 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
);
4922 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP
, &groupxpm
);
4923 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD
, &vcardxpm
);
4924 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK
, &bookxpm
);
4925 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS
, &addressxpm
);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT
, &jpilotxpm
);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY
, &categoryxpm
);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP
, &ldapxpm
);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH
, &addrsearchxpm
);
4931 UPDATE_ICON_ATCI(ADDR_INTERFACE
,folderxpm
,folderopenxpm
);
4932 UPDATE_ICON_ATCI(ADDR_BOOK
,bookxpm
,bookxpm
);
4933 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON
,NULL
,NULL
);
4934 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL
,addressxpm
,addressxpm
);
4935 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP
,groupxpm
,groupxpm
);
4936 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER
,folderxpm
,folderopenxpm
);
4937 UPDATE_ICON_ATCI(ADDR_VCARD
,vcardxpm
,vcardxpm
);
4938 UPDATE_ICON_ATCI(ADDR_JPILOT
,jpilotxpm
,jpilotxpm
);
4939 UPDATE_ICON_ATCI(ADDR_CATEGORY
,categoryxpm
,categoryxpm
);
4940 UPDATE_ICON_ATCI(ADDR_LDAP
,ldapxpm
,ldapxpm
);
4941 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY
,addrsearchxpm
,addrsearchxpm
);
4946 * Build table that controls the rendering of object types.
4948 static void addrbookctl_build_map( GtkWidget
*window
) {
4949 AddressTypeControlItem
*atci
;
4951 _addressBookTypeHash_
= g_hash_table_new( g_int_hash
, g_int_equal
);
4952 _addressBookTypeList_
= NULL
;
4955 atci
= g_new0( AddressTypeControlItem
, 1 );
4956 atci
->objectType
= ADDR_INTERFACE
;
4957 atci
->interfaceType
= ADDR_IF_NONE
;
4958 atci
->showInTree
= TRUE
;
4959 atci
->treeExpand
= TRUE
;
4960 atci
->treeLeaf
= FALSE
;
4961 atci
->displayName
= _( "Interface" );
4962 atci
->menuCommand
= NULL
;
4963 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4964 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4967 atci
= g_new0( AddressTypeControlItem
, 1 );
4968 atci
->objectType
= ADDR_BOOK
;
4969 atci
->interfaceType
= ADDR_IF_BOOK
;
4970 atci
->showInTree
= TRUE
;
4971 atci
->treeExpand
= TRUE
;
4972 atci
->treeLeaf
= FALSE
;
4973 atci
->displayName
= _("Address Books");
4974 atci
->menuCommand
= "Menu/Book/NewBook";
4975 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4976 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4979 atci
= g_new0( AddressTypeControlItem
, 1 );
4980 atci
->objectType
= ADDR_ITEM_PERSON
;
4981 atci
->interfaceType
= ADDR_IF_NONE
;
4982 atci
->showInTree
= FALSE
;
4983 atci
->treeExpand
= FALSE
;
4984 atci
->treeLeaf
= FALSE
;
4985 atci
->displayName
= _( "Person" );
4986 atci
->menuCommand
= NULL
;
4987 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
4988 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
4991 atci
= g_new0( AddressTypeControlItem
, 1 );
4992 atci
->objectType
= ADDR_ITEM_EMAIL
;
4993 atci
->interfaceType
= ADDR_IF_NONE
;
4994 atci
->showInTree
= FALSE
;
4995 atci
->treeExpand
= FALSE
;
4996 atci
->treeLeaf
= TRUE
;
4997 atci
->displayName
= _( "Email Address" );
4998 atci
->menuCommand
= NULL
;
4999 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5000 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5003 atci
= g_new0( AddressTypeControlItem
, 1 );
5004 atci
->objectType
= ADDR_ITEM_GROUP
;
5005 atci
->interfaceType
= ADDR_IF_BOOK
;
5006 atci
->showInTree
= TRUE
;
5007 atci
->treeExpand
= FALSE
;
5008 atci
->treeLeaf
= FALSE
;
5009 atci
->displayName
= _( "Group" );
5010 atci
->menuCommand
= NULL
;
5011 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5012 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5015 atci
= g_new0( AddressTypeControlItem
, 1 );
5016 atci
->objectType
= ADDR_ITEM_FOLDER
;
5017 atci
->interfaceType
= ADDR_IF_BOOK
;
5018 atci
->showInTree
= TRUE
;
5019 atci
->treeExpand
= FALSE
;
5020 atci
->treeLeaf
= FALSE
;
5021 atci
->displayName
= _( "Folder" );
5022 atci
->menuCommand
= NULL
;
5023 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5024 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5027 atci
= g_new0( AddressTypeControlItem
, 1 );
5028 atci
->objectType
= ADDR_VCARD
;
5029 atci
->interfaceType
= ADDR_IF_VCARD
;
5030 atci
->showInTree
= TRUE
;
5031 atci
->treeExpand
= TRUE
;
5032 atci
->treeLeaf
= TRUE
;
5033 atci
->displayName
= _( "vCard" );
5034 atci
->menuCommand
= "Menu/Book/NewVCard";
5035 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5036 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5039 atci
= g_new0( AddressTypeControlItem
, 1 );
5040 atci
->objectType
= ADDR_JPILOT
;
5041 atci
->interfaceType
= ADDR_IF_JPILOT
;
5042 atci
->showInTree
= TRUE
;
5043 atci
->treeExpand
= TRUE
;
5044 atci
->treeLeaf
= FALSE
;
5045 atci
->displayName
= _( "JPilot" );
5046 atci
->menuCommand
= "Menu/Book/NewJPilot";
5047 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5048 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5051 atci
= g_new0( AddressTypeControlItem
, 1 );
5052 atci
->objectType
= ADDR_CATEGORY
;
5053 atci
->interfaceType
= ADDR_IF_JPILOT
;
5054 atci
->showInTree
= TRUE
;
5055 atci
->treeExpand
= TRUE
;
5056 atci
->treeLeaf
= TRUE
;
5057 atci
->displayName
= _( "JPilot" );
5058 atci
->menuCommand
= NULL
;
5059 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5060 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5063 atci
= g_new0( AddressTypeControlItem
, 1 );
5064 atci
->objectType
= ADDR_LDAP
;
5065 atci
->interfaceType
= ADDR_IF_LDAP
;
5066 atci
->showInTree
= TRUE
;
5067 atci
->treeExpand
= TRUE
;
5068 atci
->treeLeaf
= FALSE
;
5069 atci
->displayName
= _( "LDAP servers" );
5070 atci
->menuCommand
= "Menu/Book/NewLDAPServer";
5071 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5072 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5075 atci
= g_new0( AddressTypeControlItem
, 1 );
5076 atci
->objectType
= ADDR_LDAP_QUERY
;
5077 atci
->interfaceType
= ADDR_IF_LDAP
;
5078 atci
->showInTree
= TRUE
;
5079 atci
->treeExpand
= FALSE
;
5080 atci
->treeLeaf
= TRUE
;
5081 atci
->displayName
= _( "LDAP Query" );
5082 atci
->menuCommand
= NULL
;
5083 g_hash_table_insert( _addressBookTypeHash_
, &atci
->objectType
, atci
);
5084 _addressBookTypeList_
= g_list_append( _addressBookTypeList_
, atci
);
5086 addrbookctl_build_icons(window
);
5089 void addressbook_reflect_prefs_pixmap_theme(void)
5091 if (addrbook
.window
)
5092 addrbookctl_build_icons(addrbook
.window
);
5096 * Search for specified object type.
5098 static AddressTypeControlItem
*addrbookctl_lookup( gint ot
) {
5100 return ( AddressTypeControlItem
* ) g_hash_table_lookup( _addressBookTypeHash_
, &objType
);
5104 * Search for specified interface type.
5106 static AddressTypeControlItem
*addrbookctl_lookup_iface( AddressIfType ifType
) {
5107 GList
*node
= _addressBookTypeList_
;
5109 AddressTypeControlItem
*atci
= node
->data
;
5110 if( atci
->interfaceType
== ifType
) return atci
;
5111 node
= g_list_next( node
);
5116 static void addrbookctl_free_address( AddressObject
*obj
) {
5117 g_free( obj
->name
);
5118 obj
->type
= ADDR_NONE
;
5122 static void addrbookctl_free_interface( AdapterInterface
*adapter
) {
5123 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5124 adapter
->interface
= NULL
;
5125 adapter
->interfaceType
= ADDR_IF_NONE
;
5126 adapter
->atci
= NULL
;
5127 adapter
->enabled
= FALSE
;
5128 adapter
->haveLibrary
= FALSE
;
5129 adapter
->treeNode
= NULL
;
5133 static void addrbookctl_free_datasource( AdapterDSource
*adapter
) {
5134 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5135 adapter
->dataSource
= NULL
;
5136 adapter
->subType
= ADDR_NONE
;
5140 static void addrbookctl_free_folder( AdapterFolder
*adapter
) {
5141 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5142 adapter
->itemFolder
= NULL
;
5146 static void addrbookctl_free_group( AdapterGroup
*adapter
) {
5147 addrbookctl_free_address( ADDRESS_OBJECT(adapter
) );
5148 adapter
->itemGroup
= NULL
;
5153 * Build GUI interface list.
5155 static void addrbookctl_build_iflist( void ) {
5156 AddressTypeControlItem
*atci
;
5157 AdapterInterface
*adapter
;
5160 if( _addressIndex_
== NULL
) {
5161 _addressIndex_
= addrindex_create_index();
5162 if( _clipBoard_
== NULL
) {
5163 _clipBoard_
= addrclip_create();
5165 addrclip_set_index( _clipBoard_
, _addressIndex_
);
5167 _addressInterfaceList_
= NULL
;
5168 list
= addrindex_get_interface_list( _addressIndex_
);
5170 AddressInterface
*interface
= list
->data
;
5171 atci
= addrbookctl_lookup_iface( interface
->type
);
5173 adapter
= g_new0( AdapterInterface
, 1 );
5174 adapter
->interfaceType
= interface
->type
;
5175 adapter
->atci
= atci
;
5176 adapter
->interface
= interface
;
5177 adapter
->treeNode
= NULL
;
5178 adapter
->enabled
= TRUE
;
5179 adapter
->haveLibrary
= interface
->haveLibrary
;
5180 ADDRESS_OBJECT(adapter
)->type
= ADDR_INTERFACE
;
5181 ADDRESS_OBJECT_NAME(adapter
) = g_strdup( atci
->displayName
);
5182 _addressInterfaceList_
=
5183 g_list_append( _addressInterfaceList_
, adapter
);
5185 list
= g_list_next( list
);
5190 * Find GUI interface type specified interface type.
5191 * \param ifType Interface type.
5192 * \return Interface item, or NULL if not found.
5194 static AdapterInterface
*addrbookctl_find_interface( AddressIfType ifType
) {
5195 GList
*node
= _addressInterfaceList_
;
5197 AdapterInterface
*adapter
= node
->data
;
5198 if( adapter
->interfaceType
== ifType
) return adapter
;
5199 node
= g_list_next( node
);
5205 * Build interface list selection.
5207 static void addrbookctl_build_ifselect( void ) {
5208 GList
*newList
= NULL
;
5213 gchar
*endptr
= NULL
;
5214 /* gboolean enabled; */
5215 AdapterInterface
*adapter
;
5217 selectStr
= g_strdup( ADDRESSBOOK_IFACE_SELECTION
);
5220 splitStr
= g_strsplit( selectStr
, ",", -1 );
5221 for( i
= 0; i
< ADDRESSBOOK_MAX_IFACE
; i
++ ) {
5223 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5224 ifType
= strtol( splitStr
[i
], &endptr
, 10 );
5227 if( strcmp( endptr, "/n" ) == 0 ) {
5232 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5233 adapter
= addrbookctl_find_interface( ifType
);
5235 newList
= g_list_append( newList
, adapter
);
5242 /* g_print( "i=%d\n", i ); */
5243 g_strfreev( splitStr
);
5244 g_free( selectStr
);
5246 /* Replace existing list */
5247 g_list_free( _addressIFaceSelection_
);
5248 _addressIFaceSelection_
= newList
;
5252 /* ***********************************************************************
5253 * Add sender to address book.
5254 * ***********************************************************************
5258 * This function is used by the Add sender to address book function.
5260 gboolean
addressbook_add_contact(
5261 const gchar
*name
, const gchar
*address
, const gchar
*remarks
,
5262 GdkPixbuf
*picture
)
5264 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name
, address
);
5265 if( addressadd_selection( _addressIndex_
, name
, address
, remarks
, picture
) ) {
5266 debug_print( "addressbook_add_contact - added\n" );
5267 addressbook_refresh();
5272 /* ***********************************************************************
5273 * Book/folder selection.
5274 * ***********************************************************************
5278 * This function is used by the matcher dialog to select a book/folder.
5280 gchar
*addressbook_folder_selection( const gchar
*folderpath
)
5282 AddressBookFile
*book
= NULL
;
5283 ItemFolder
*folder
= NULL
;
5286 cm_return_val_if_fail( folderpath
!= NULL
, NULL
);
5288 if ( addressbook_foldersel_selection( _addressIndex_
, &book
, &folder
, folderpath
)
5290 if ( folder
!= NULL
) {
5292 gchar
*oldtmp
= NULL
;
5293 AddrItemObject
*obj
= NULL
;
5295 /* walk thru folder->parent to build the full folder path */
5296 /* TODO: wwp: optimize this */
5298 tmp
= g_strdup(obj
->uid
);
5299 while ( obj
->parent
) {
5301 if ( obj
->name
!= NULL
) {
5302 oldtmp
= g_strdup(tmp
);
5304 tmp
= g_strdup_printf("%s/%s", obj
->uid
, oldtmp
);
5308 path
= g_strdup_printf("%s/%s", book
->fileName
, tmp
);
5311 path
= g_strdup_printf("%s", book
->fileName
);
5313 debug_print( "addressbook_foldersel: %s\n", path
?path
:"(null)");
5319 /* ***********************************************************************
5320 * Book/folder checking.
5321 * ***********************************************************************
5324 static FolderInfo
*addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile
*abf
, ItemFolder
*folder
)
5326 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
5328 fi
->folder
= folder
;
5332 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder
*parentFolder
,
5333 FolderInfo
*fiParent
, FolderPathMatch
*match
)
5339 FolderPathMatch
*nextmatch
= NULL
;
5344 list
= parentFolder
->listFolder
;
5346 folder
= list
->data
;
5347 fName
= g_strdup( ADDRITEM_NAME(folder
) );
5349 /* match folder name, match pointer will be set to NULL if next recursive call
5350 doesn't need to match subfolder name */
5351 if ( match
!= NULL
&&
5352 match
->matched
== FALSE
) {
5353 if ( strcmp(match
->folder_path
[match
->index
], folder
->obj
.uid
) == 0 ) {
5354 /* folder name matches, prepare next subfolder match */
5355 debug_print("matched folder name '%s'\n", fName
);
5357 if ( match
->folder_path
[match
->index
] == NULL
) {
5358 /* we've matched all elements */
5359 match
->matched
= TRUE
;
5360 match
->folder
= folder
;
5361 debug_print("book/folder path matched!\n");
5363 /* keep on matching */
5371 fi
= addressbook_peek_subfolder_exists_create_folderinfo( fiParent
->book
, folder
);
5372 addressbook_peek_subfolder_exists_load_folder( folder
, fi
, nextmatch
);
5374 list
= g_list_next( list
);
5379 * This function is used by to check if a matcher book/folder path corresponds to an
5380 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5381 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5382 if book AND folder are NULL this means that folderpath was empty or Any.
5383 If folderpath is a simple book name (without folder), book will not be NULL and folder
5384 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5387 gboolean
addressbook_peek_folder_exists( gchar
*folderpath
,
5388 AddressDataSource
**book
,
5389 ItemFolder
**folder
)
5391 AddressDataSource
*ds
;
5392 GList
*list
, *nodeDS
;
5393 ItemFolder
*rootFolder
;
5394 AddressBookFile
*abf
;
5396 FolderPathMatch folder_path_match
= { NULL
, FALSE
, 0, NULL
, NULL
};
5403 if ( folderpath
== NULL
)
5406 if ( strcasecmp(folderpath
, "Any") == 0 || *folderpath
== '\0' )
5409 /* split the folder path we've received, we'll try to match this path, subpath by
5410 subpath against the book/folder structure in order */
5411 folder_path_match
.folder_path
= g_strsplit( folderpath
, "/", 256 );
5412 if (!folder_path_match
.folder_path
)
5415 list
= addrindex_get_interface_list( _addressIndex_
);
5416 while ( list
&& !folder_path_match
.matched
) {
5417 AddressInterface
*interface
= list
->data
;
5418 if ( interface
&& interface
->type
== ADDR_IF_BOOK
) {
5419 nodeDS
= interface
->listSource
;
5420 while ( nodeDS
&& !folder_path_match
.matched
) {
5423 /* Read address book */
5424 if( ! addrindex_ds_get_read_flag( ds
) ) {
5425 addrindex_ds_read_data( ds
);
5428 /* Add node for address book */
5429 abf
= ds
->rawDataSource
;
5431 /* match book name */
5432 if ( abf
&& abf
->fileName
&&
5433 strcmp(folder_path_match
.folder_path
[0], abf
->fileName
) == 0 ) {
5435 debug_print("matched book name '%s'\n", abf
->fileName
);
5436 folder_path_match
.book
= ds
;
5438 if ( folder_path_match
.folder_path
[1] == NULL
) {
5439 /* no folder part to match */
5441 folder_path_match
.matched
= TRUE
;
5442 folder_path_match
.folder
= NULL
;
5443 debug_print("book path matched!\n");
5446 /* match folder part */
5448 fi
= addressbook_peek_subfolder_exists_create_folderinfo( abf
, NULL
);
5449 rootFolder
= addrindex_ds_get_root_folder( ds
);
5451 /* prepare for recursive call */
5452 folder_path_match
.index
= 1;
5453 /* this call will set folder_path_match.matched and folder_path_match.folder */
5454 addressbook_peek_subfolder_exists_load_folder( rootFolder
, fi
, &folder_path_match
);
5459 nodeDS
= g_list_next( nodeDS
);
5462 list
= g_list_next( list
);
5465 g_strfreev( folder_path_match
.folder_path
);
5468 *book
= folder_path_match
.book
;
5470 *folder
= folder_path_match
.folder
;
5471 return folder_path_match
.matched
;
5475 /* **********************************************************************
5477 * ***********************************************************************
5483 static void addressbook_import_ldif_cb( GtkAction
*action
, gpointer data
) {
5484 AddressDataSource
*ds
= NULL
;
5485 AdapterDSource
*ads
= NULL
;
5486 AddressBookFile
*abf
= NULL
;
5487 AdapterInterface
*adapter
;
5488 GtkCMCTreeNode
*newNode
;
5490 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5492 if( adapter
->treeNode
) {
5493 abf
= addressbook_imp_ldif( _addressIndex_
);
5495 ds
= addrindex_index_add_datasource(
5496 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5497 ads
= addressbook_create_ds_adapter(
5498 ds
, ADDR_BOOK
, NULL
);
5499 addressbook_ads_set_name(
5500 ads
, addrbook_get_name( abf
) );
5501 newNode
= addressbook_add_object(
5503 ADDRESS_OBJECT(ads
) );
5505 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5507 addrbook
.treeSelected
= newNode
;
5510 /* Notify address completion */
5511 invalidate_address_completion();
5520 static void addressbook_import_mutt_cb( GtkAction
*action
, gpointer data
) {
5521 AddressDataSource
*ds
= NULL
;
5522 AdapterDSource
*ads
= NULL
;
5523 AddressBookFile
*abf
= NULL
;
5524 AdapterInterface
*adapter
;
5525 GtkCMCTreeNode
*newNode
;
5527 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5529 if( adapter
->treeNode
) {
5530 abf
= addressbook_imp_mutt( _addressIndex_
);
5532 ds
= addrindex_index_add_datasource(
5533 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5534 ads
= addressbook_create_ds_adapter(
5535 ds
, ADDR_BOOK
, NULL
);
5536 addressbook_ads_set_name(
5537 ads
, addrbook_get_name( abf
) );
5538 newNode
= addressbook_add_object(
5540 ADDRESS_OBJECT(ads
) );
5542 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5544 addrbook
.treeSelected
= newNode
;
5547 /* Notify address completion */
5548 invalidate_address_completion();
5557 static void addressbook_import_pine_cb( GtkAction
*action
, gpointer data
) {
5558 AddressDataSource
*ds
= NULL
;
5559 AdapterDSource
*ads
= NULL
;
5560 AddressBookFile
*abf
= NULL
;
5561 AdapterInterface
*adapter
;
5562 GtkCMCTreeNode
*newNode
;
5564 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5566 if( adapter
->treeNode
) {
5567 abf
= addressbook_imp_pine( _addressIndex_
);
5569 ds
= addrindex_index_add_datasource(
5570 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5571 ads
= addressbook_create_ds_adapter(
5572 ds
, ADDR_BOOK
, NULL
);
5573 addressbook_ads_set_name(
5574 ads
, addrbook_get_name( abf
) );
5575 newNode
= addressbook_add_object(
5577 ADDRESS_OBJECT(ads
) );
5579 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
),
5581 addrbook
.treeSelected
= newNode
;
5584 /* Notify address completion */
5585 invalidate_address_completion();
5592 * Harvest addresses.
5593 * \param folderItem Folder to import.
5594 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5595 * \param msgList List of message numbers, or NULL to process folder.
5597 void addressbook_harvest(
5598 FolderItem
*folderItem
, gboolean sourceInd
, GList
*msgList
)
5600 AddressDataSource
*ds
= NULL
;
5601 AdapterDSource
*ads
= NULL
;
5602 AddressBookFile
*abf
= NULL
;
5603 AdapterInterface
*adapter
;
5604 GtkCMCTreeNode
*newNode
;
5606 abf
= addrgather_dlg_execute(
5607 folderItem
, _addressIndex_
, sourceInd
, msgList
);
5609 ds
= addrindex_index_add_datasource(
5610 _addressIndex_
, ADDR_IF_BOOK
, abf
);
5612 adapter
= addrbookctl_find_interface( ADDR_IF_BOOK
);
5614 if( adapter
->treeNode
) {
5615 ads
= addressbook_create_ds_adapter(
5616 ds
, ADDR_BOOK
, addrbook_get_name( abf
) );
5617 newNode
= addressbook_add_object(
5619 ADDRESS_OBJECT(ads
) );
5620 if (newNode
== NULL
) {
5621 g_message("error adding addressbook object\n");
5626 /* Notify address completion */
5627 invalidate_address_completion();
5634 static void addressbook_export_html_cb( GtkAction
*action
, gpointer data
) {
5635 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
5637 AddressDataSource
*ds
= NULL
;
5638 AddrBookBase
*adbase
;
5639 AddressCache
*cache
;
5640 GtkCMCTreeNode
*node
= NULL
;
5642 if( ! addrbook
.treeSelected
) return;
5643 node
= addrbook
.treeSelected
;
5644 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
5645 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
5646 if( obj
== NULL
) return;
5648 ds
= addressbook_find_datasource( node
);
5649 if( ds
== NULL
) return;
5650 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
5651 cache
= adbase
->addressCache
;
5652 addressbook_exp_html( cache
);
5658 static void addressbook_export_ldif_cb( GtkAction
*action
, gpointer data
) {
5659 GtkCMCTree
*ctree
= GTK_CMCTREE(addrbook
.ctree
);
5661 AddressDataSource
*ds
= NULL
;
5662 AddrBookBase
*adbase
;
5663 AddressCache
*cache
;
5664 GtkCMCTreeNode
*node
= NULL
;
5666 if( ! addrbook
.treeSelected
) return;
5667 node
= addrbook
.treeSelected
;
5668 if( GTK_CMCTREE_ROW(node
)->level
== 1 ) return;
5669 obj
= gtk_cmctree_node_get_row_data( ctree
, node
);
5670 if( obj
== NULL
) return;
5672 ds
= addressbook_find_datasource( node
);
5673 if( ds
== NULL
) return;
5674 adbase
= ( AddrBookBase
* ) ds
->rawDataSource
;
5675 cache
= adbase
->addressCache
;
5676 addressbook_exp_ldif( cache
);
5679 static void addressbook_find_duplicates_cb(GtkAction
*action
, gpointer data
)
5681 addrduplicates_find(GTK_WINDOW(addrbook
.window
));
5684 static void addressbook_edit_custom_attr_cb(GtkAction
*action
, gpointer data
)
5686 addressbook_custom_attr_edit();
5689 static void addressbook_start_drag(GtkWidget
*widget
, gint button
,
5693 GdkDragContext
*context
;
5694 if (addressbook_target_list
== NULL
)
5695 addressbook_target_list
= gtk_target_list_new(
5696 addressbook_drag_types
, 1);
5697 context
= gtk_drag_begin(widget
, addressbook_target_list
,
5698 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
);
5699 gtk_drag_set_icon_default(context
);
5702 static void addressbook_drag_data_get(GtkWidget
*widget
,
5703 GdkDragContext
*drag_context
,
5704 GtkSelectionData
*selection_data
,
5709 AddrItemObject
*aio
= NULL
;
5710 AddressObject
*pobj
= NULL
;
5711 AdapterDSource
*ads
= NULL
;
5712 AddressDataSource
*ds
= NULL
;
5715 pobj
= gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook
.ctree
), addrbook
.treeSelected
);
5717 if( pobj
== NULL
) return;
5719 if( pobj
->type
== ADDR_DATASOURCE
) {
5720 ads
= ADAPTER_DSOURCE(pobj
);
5721 ds
= ads
->dataSource
;
5722 } else if (pobj
->type
== ADDR_ITEM_GROUP
) {
5727 else if( pobj
->type
!= ADDR_INTERFACE
) {
5728 ds
= addressbook_find_datasource( addrbook
.treeSelected
);
5734 for(cur
= GTK_CMCLIST(addrbook
.clist
)->selection
; cur
; cur
= cur
->next
) {
5735 aio
= (AddrItemObject
*)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.clist
),
5736 GTK_CMCTREE_NODE(cur
->data
));
5737 while (aio
&& aio
->type
!= ITEMTYPE_PERSON
) {
5742 if (aio
&& aio
->type
== ITEMTYPE_PERSON
) {
5743 if( ds
&& ds
->interface
&& ds
->interface
->readOnly
)
5744 gtk_selection_data_set(selection_data
,
5745 gtk_selection_data_get_target(selection_data
), 8,
5746 (const guchar
*)"Dummy_addr_copy", 15);
5748 gtk_selection_data_set(selection_data
,
5749 gtk_selection_data_get_target(selection_data
), 8,
5750 (const guchar
*)"Dummy_addr_move", 15);
5754 static gboolean
addressbook_drag_motion_cb(GtkWidget
*widget
,
5755 GdkDragContext
*context
,
5761 GtkAllocation allocation
;
5762 GtkRequisition requisition
;
5764 GtkCMCTreeNode
*node
= NULL
;
5765 gboolean acceptable
= FALSE
;
5766 gtk_widget_get_allocation(GTK_WIDGET(addrbook
.ctree
), &allocation
);
5767 gint height
= allocation
.height
;
5768 gtk_widget_get_requisition(GTK_WIDGET(addrbook
.ctree
), &requisition
);
5769 gint total_height
= requisition
.height
;
5770 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
5771 GTK_SCROLLED_WINDOW(addrbook
.ctree_swin
));
5772 gfloat vpos
= gtk_adjustment_get_value(pos
);
5774 if (gtk_cmclist_get_selection_info
5775 (GTK_CMCLIST(widget
), x
- 24, y
- 24, &row
, &column
)) {
5777 if (y
> height
- 24 && height
+ vpos
< total_height
) {
5778 gtk_adjustment_set_value(pos
, (vpos
+5 > height
? height
: vpos
+5));
5779 gtk_adjustment_changed(pos
);
5781 if (y
< 24 && y
> 0) {
5782 gtk_adjustment_set_value(pos
, (vpos
-5 < 0 ? 0 : vpos
-5));
5783 gtk_adjustment_changed(pos
);
5785 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
5788 AddressObject
*obj
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
5789 if( obj
->type
== ADDR_ITEM_FOLDER
5790 || obj
->type
== ADDR_ITEM_GROUP
)
5793 AdapterDSource
*ads
= NULL
;
5794 AddressDataSource
*ds
= NULL
;
5795 ads
= ADAPTER_DSOURCE(obj
);
5796 if (ads
== NULL
){ return FALSE
;}
5797 ds
= ads
->dataSource
;
5798 if (ds
== NULL
) { return FALSE
;}
5806 g_signal_handlers_block_by_func
5808 G_CALLBACK(addressbook_tree_selected
), NULL
);
5809 gtk_sctree_select( GTK_SCTREE(widget
), node
);
5810 g_signal_handlers_unblock_by_func
5812 G_CALLBACK(addressbook_tree_selected
), NULL
);
5813 gdk_drag_status(context
,
5814 (gdk_drag_context_get_actions(context
) == GDK_ACTION_COPY
?
5815 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
5817 gdk_drag_status(context
, 0, time
);
5822 static void addressbook_drag_leave_cb(GtkWidget
*widget
,
5823 GdkDragContext
*context
,
5827 if (addrbook
.treeSelected
) {
5828 g_signal_handlers_block_by_func
5830 G_CALLBACK(addressbook_tree_selected
), NULL
);
5831 gtk_sctree_select( GTK_SCTREE(widget
), addrbook
.opened
);
5832 g_signal_handlers_unblock_by_func
5834 G_CALLBACK(addressbook_tree_selected
), NULL
);
5839 static void addressbook_drag_received_cb(GtkWidget
*widget
,
5840 GdkDragContext
*drag_context
,
5843 GtkSelectionData
*data
,
5849 GtkCMCTreeNode
*node
;
5850 GtkCMCTreeNode
*lastopened
= addrbook
.opened
;
5852 if (!strncmp(gtk_selection_data_get_data(data
), "Dummy_addr", 10)) {
5853 if (gtk_cmclist_get_selection_info
5854 (GTK_CMCLIST(widget
), x
- 24, y
- 24, &row
, &column
) == 0) {
5858 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
5859 if( !node
|| !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook
.ctree
), node
))
5862 gtk_cmclist_freeze(GTK_CMCLIST(addrbook
.clist
));
5863 if (gdk_drag_context_get_selected_action(drag_context
) == GDK_ACTION_COPY
||
5864 !strcmp(gtk_selection_data_get_data(data
), "Dummy_addr_copy"))
5865 addressbook_clip_copy_cb(NULL
, NULL
);
5867 addressbook_clip_cut_cb(NULL
, NULL
);
5868 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), node
);
5869 addressbook_clip_paste_cb(NULL
,NULL
);
5870 gtk_sctree_select( GTK_SCTREE(addrbook
.ctree
), lastopened
);
5871 gtk_cmclist_thaw(GTK_CMCLIST(addrbook
.clist
));
5872 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);