2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
32 #include <sys/types.h>
36 #include "addressbook.h"
37 #include "manage_window.h"
38 #include "prefs_common.h"
39 #include "alertpanel.h"
40 #include "inputdialog.h"
42 #include "stock_pixmap.h"
44 #include "prefs_gtk.h"
50 #include "addr_compl.h"
53 #include "addressitem.h"
55 #include "addrcache.h"
57 #include "addrindex.h"
58 #include "addressadd.h"
59 #include "addrduplicates.h"
60 #include "addressbook_foldersel.h"
62 #include "editvcard.h"
63 #include "editgroup.h"
64 #include "editaddress.h"
66 #include "importldif.h"
67 #include "importmutt.h"
68 #include "importpine.h"
73 #include "editjpilot.h"
78 #include "ldapserver.h"
80 #include "ldapupdate.h"
82 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
85 #include "addrquery.h"
86 #include "addrselect.h"
88 #include "addrgather.h"
89 #include "adbookbase.h"
90 #include "exphtmldlg.h"
91 #include "expldifdlg.h"
92 #include "browseldap.h"
93 #include "addrcustomattr.h"
99 } AddressIndexColumns;
107 } AddressListColumns;
110 AddressBookFile *book;
118 AddressDataSource *book;
122 static gchar *list_titles[] = { N_("Name"),
126 #define COL_NAME_WIDTH 164
127 #define COL_ADDRESS_WIDTH 156
129 #define COL_FOLDER_WIDTH 170
130 #define ADDRESSBOOK_WIDTH 640
131 #define ADDRESSBOOK_HEIGHT 360
133 #define ADDRESSBOOK_MSGBUF_SIZE 2048
135 static GdkPixmap *folderxpm;
136 static GdkBitmap *folderxpmmask;
137 static GdkPixmap *folderopenxpm;
138 static GdkBitmap *folderopenxpmmask;
139 static GdkPixmap *groupxpm;
140 static GdkBitmap *groupxpmmask;
141 static GdkPixmap *interfacexpm;
142 static GdkBitmap *interfacexpmmask;
143 static GdkPixmap *bookxpm;
144 static GdkBitmap *bookxpmmask;
145 static GdkPixmap *addressxpm;
146 static GdkBitmap *addressxpmmask;
147 static GdkPixmap *vcardxpm;
148 static GdkBitmap *vcardxpmmask;
149 static GdkPixmap *jpilotxpm;
150 static GdkBitmap *jpilotxpmmask;
151 static GdkPixmap *categoryxpm;
152 static GdkBitmap *categoryxpmmask;
153 static GdkPixmap *ldapxpm;
154 static GdkBitmap *ldapxpmmask;
155 static GdkPixmap *addrsearchxpm;
156 static GdkPixmap *addrsearchxpmmask;
159 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
161 /* Address list selection */
162 static AddrSelectList *_addressSelect_ = NULL;
163 static AddressClipboard *_clipBoard_ = NULL;
165 /* Address index file and interfaces */
166 static AddressIndex *_addressIndex_ = NULL;
167 static GList *_addressInterfaceList_ = NULL;
168 static GList *_addressIFaceSelection_ = NULL;
169 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
171 static AddressBook_win addrbook;
173 static GHashTable *_addressBookTypeHash_ = NULL;
174 static GList *_addressBookTypeList_ = NULL;
176 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
177 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
178 static void addressbook_edit_address_post_cb( ItemPerson *person );
180 static void addressbook_create (void);
181 static gint addressbook_close (void);
182 static void addressbook_button_set_sensitive (void);
184 static gboolean address_index_has_focus = FALSE;
185 static gboolean address_list_has_focus = FALSE;
187 /* callback functions */
188 static void addressbook_del_clicked (GtkButton *button,
190 static void addressbook_reg_clicked (GtkButton *button,
192 static void addressbook_to_clicked (GtkButton *button,
194 static void addressbook_lup_clicked (GtkButton *button,
196 static void addressbook_close_clicked (GtkButton *button,
199 static void addressbook_tree_selected (GtkCTree *ctree,
203 static void addressbook_select_row_tree (GtkCTree *ctree,
207 static void addressbook_list_row_selected (GtkCTree *clist,
211 static void addressbook_list_row_unselected (GtkCTree *clist,
215 static void addressbook_person_expand_node (GtkCTree *ctree,
218 static void addressbook_person_collapse_node (GtkCTree *ctree,
222 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
223 GdkEventButton *event,
225 static gboolean addressbook_list_button_released(GtkWidget *widget,
226 GdkEventButton *event,
228 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
229 GdkEventButton *event,
231 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
232 GdkEventButton *event,
235 static void addressbook_new_folder_cb (GtkAction *action,
237 static void addressbook_new_group_cb (GtkAction *action,
239 static void addressbook_treenode_edit_cb (GtkAction *action,
241 static void addressbook_treenode_delete_cb (GtkAction *action,
244 static void addressbook_change_node_name (GtkCTreeNode *node,
247 static void addressbook_new_address_cb (GtkAction *action,
249 static void addressbook_edit_address_cb (GtkAction *action,
251 static void addressbook_delete_address_cb (GtkAction *action,
254 static void close_cb (GtkAction *action,
256 static void addressbook_file_save_cb (GtkAction *action,
259 /* Data source edit stuff */
260 static void addressbook_new_book_cb (GtkAction *action,
262 static void addressbook_new_vcard_cb (GtkAction *action,
266 static void addressbook_new_jpilot_cb (GtkAction *action,
271 static void addressbook_new_ldap_cb (GtkAction *action,
275 static void addressbook_set_clist (AddressObject *obj,
278 static void addressbook_load_tree (void);
279 void addressbook_read_file (void);
281 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
283 static void addressbook_treenode_remove_item ( void );
285 static AddressDataSource *addressbook_find_datasource
286 (GtkCTreeNode *node );
288 static AddressBookFile *addressbook_get_book_file(void);
290 static GtkCTreeNode *addressbook_node_add_folder
292 AddressDataSource *ds,
293 ItemFolder *itemFolder,
294 AddressObjectType otype);
295 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
296 AddressDataSource *ds,
297 ItemGroup *itemGroup);
298 static void addressbook_tree_remove_children (GtkCTree *ctree,
299 GtkCTreeNode *parent);
300 static void addressbook_move_nodes_up (GtkCTree *ctree,
302 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
304 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
307 static gint addressbook_treenode_compare_func (GtkCList *clist,
310 static void addressbook_folder_load_one_person (GtkCTree *clist,
312 AddressTypeControlItem *atci,
313 AddressTypeControlItem *atciMail);
314 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
316 static void addressbook_folder_remove_one_person(GtkCTree *clist,
318 static void addressbook_folder_remove_node (GtkCTree *clist,
321 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
322 gboolean force_focus );
324 /* LUT's and IF stuff */
325 static void addressbook_free_treenode ( gpointer data );
326 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
327 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
329 static void addrbookctl_build_map (GtkWidget *window);
330 static void addrbookctl_build_iflist (void);
331 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
332 static void addrbookctl_build_ifselect (void);
334 static void addrbookctl_free_interface (AdapterInterface *adapter);
335 static void addrbookctl_free_datasource (AdapterDSource *adapter);
336 static void addrbookctl_free_folder (AdapterFolder *adapter);
337 static void addrbookctl_free_group (AdapterGroup *adapter);
339 static void addressbook_list_select_clear ( void );
340 static void addressbook_list_select_add ( AddrItemObject *aio,
341 AddressDataSource *ds );
342 static void addressbook_list_select_remove ( AddrItemObject *aio );
344 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
345 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
346 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
347 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
348 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
349 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
350 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
351 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
352 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
353 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
354 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
355 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
356 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
357 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
359 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
362 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
364 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
366 static void addressbook_start_drag(GtkWidget *widget, gint button,
369 static void addressbook_drag_data_get(GtkWidget *widget,
370 GdkDragContext *drag_context,
371 GtkSelectionData *selection_data,
375 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
376 GdkDragContext *context,
381 static void addressbook_drag_leave_cb(GtkWidget *widget,
382 GdkDragContext *context,
385 static void addressbook_drag_received_cb(GtkWidget *widget,
386 GdkDragContext *drag_context,
389 GtkSelectionData *data,
393 static void addressbook_list_menu_setup( void );
395 static GtkTargetEntry addressbook_drag_types[] =
397 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
400 static GtkTargetList *addressbook_target_list = NULL;
402 static void about_show_cb(GtkAction *action, gpointer data)
407 static GtkActionEntry addressbook_entries[] =
409 {"Menu", NULL, "Menu" },
411 {"Book", NULL, N_("_Message") },
412 {"Address", NULL, N_("_Edit") },
413 {"Tools", NULL, N_("_Tools") },
414 {"Help", NULL, N_("_Help") },
417 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
418 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
419 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
423 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
426 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
428 {"Book/---", NULL, "---", NULL, NULL, NULL },
430 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
431 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
432 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
433 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
434 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
437 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
438 {"Address/---", NULL, "---", NULL, NULL, NULL },
439 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
440 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
441 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
442 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
443 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
444 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
445 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
446 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
447 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
448 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
449 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
453 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
454 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
455 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
456 {"Tools/---", NULL, "---", NULL, NULL, NULL },
457 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
458 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
459 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
460 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
461 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
464 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
468 static GtkActionEntry addressbook_tree_popup_entries[] =
470 {"ABTreePopup", NULL, "ABTreePopup" },
471 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
472 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
473 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
474 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
475 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
476 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
477 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
478 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
479 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
480 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
483 static GtkActionEntry addressbook_list_popup_entries[] =
485 {"ABListPopup", NULL, "ABListPopup" },
486 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
487 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
488 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
489 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
490 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
491 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
492 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
493 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
494 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
495 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
496 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
497 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
498 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
500 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
505 * Structure of error message table.
507 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
508 struct _ErrMsgTableEntry {
513 static gchar *_errMsgUnknown_ = N_( "Unknown" );
516 * Lookup table of error messages for general errors. Note that a NULL
517 * description signifies the end of the table.
519 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
520 { MGU_SUCCESS, N_("Success") },
521 { MGU_BAD_ARGS, N_("Bad arguments") },
522 { MGU_NO_FILE, N_("File not specified") },
523 { MGU_OPEN_FILE, N_("Error opening file") },
524 { MGU_ERROR_READ, N_("Error reading file") },
525 { MGU_EOF, N_("End of file encountered") },
526 { MGU_OO_MEMORY, N_("Error allocating memory") },
527 { MGU_BAD_FORMAT, N_("Bad file format") },
528 { MGU_ERROR_WRITE, N_("Error writing to file") },
529 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
530 { MGU_NO_PATH, N_("No path specified") },
536 * Lookup table of error messages for LDAP errors.
538 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
539 { LDAPRC_SUCCESS, N_("Success") },
540 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
541 { LDAPRC_INIT, N_("Error initializing LDAP") },
542 { LDAPRC_BIND, N_("Error binding to LDAP server") },
543 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
544 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
545 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
546 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
547 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
548 { LDAPRC_TLS, N_("Error starting TLS connection") },
549 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
550 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
551 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
552 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
558 * Lookup message for specified error code.
559 * \param lut Lookup table.
560 * \param code Code to lookup.
561 * \return Description associated to code.
563 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
565 ErrMsgTableEntry entry;
568 for( i = 0; ; i++ ) {
570 if( entry.description == NULL ) break;
571 if( entry.code == code ) {
572 desc = entry.description;
577 desc = _errMsgUnknown_;
582 static gboolean lastCanLookup = FALSE;
584 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
586 if (add_and_delete) {
587 gtk_widget_show(addrbook.edit_btn);
588 gtk_widget_show(addrbook.del_btn);
589 gtk_widget_show(addrbook.reg_btn);
591 gtk_widget_hide(addrbook.edit_btn);
592 gtk_widget_hide(addrbook.del_btn);
593 gtk_widget_hide(addrbook.reg_btn);
597 gtk_widget_show(addrbook.lup_btn);
598 gtk_widget_show(addrbook.entry);
599 gtk_widget_show(addrbook.label);
601 gtk_widget_hide(addrbook.lup_btn);
602 gtk_widget_hide(addrbook.entry);
603 gtk_widget_hide(addrbook.label);
606 lastCanLookup = lookup;
609 gtk_widget_show(addrbook.to_btn);
610 gtk_widget_show(addrbook.cc_btn);
611 gtk_widget_show(addrbook.bcc_btn);
613 gtk_widget_hide(addrbook.to_btn);
614 gtk_widget_hide(addrbook.cc_btn);
615 gtk_widget_hide(addrbook.bcc_btn);
619 void addressbook_open(Compose *target)
621 /* Initialize all static members */
622 if( _clipBoard_ == NULL ) {
623 _clipBoard_ = addrclip_create();
625 if( _addressIndex_ != NULL ) {
626 addrclip_set_index( _clipBoard_, _addressIndex_ );
628 if( _addressSelect_ == NULL ) {
629 _addressSelect_ = addrselect_list_create();
631 if (!addrbook.window) {
632 addressbook_read_file();
633 addressbook_create();
634 addressbook_load_tree();
635 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
636 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
639 gtk_widget_hide(addrbook.window);
642 gtk_widget_show_all(addrbook.window);
644 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
645 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
647 if (!prefs_common.addressbook_use_editaddress_dialog)
648 addressbook_edit_person_widgetset_hide();
650 address_completion_start(addrbook.window);
652 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
653 addressbook_set_target_compose(target);
657 * Destroy addressbook.
659 void addressbook_destroy( void ) {
660 /* Free up address stuff */
661 if( _addressSelect_ != NULL ) {
662 addrselect_list_free( _addressSelect_ );
664 if( _clipBoard_ != NULL ) {
665 addrclip_free( _clipBoard_ );
667 if( _addressIndex_ != NULL ) {
668 addrindex_free_index( _addressIndex_ );
669 addrindex_teardown();
671 _addressSelect_ = NULL;
673 _addressIndex_ = NULL;
676 void addressbook_set_target_compose(Compose *target)
678 addrbook.target_compose = target;
679 addressbook_button_set_sensitive();
682 Compose *addressbook_get_target_compose(void)
684 return addrbook.target_compose;
688 * Refresh addressbook and save to file(s).
690 void addressbook_refresh( void )
692 if (addrbook.window) {
693 if (addrbook.treeSelected) {
694 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
695 addrbook.treeSelected);
696 addressbook_set_clist(
697 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
698 addrbook.treeSelected),
703 addressbook_export_to_file();
706 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
708 if (event && event->keyval == GDK_Escape)
710 else if (event && event->keyval == GDK_Delete) {
711 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
712 if ( /* address_index_has_focus || */ address_list_has_focus )
713 addressbook_del_clicked(NULL, NULL);
719 *\brief Save Gtk object size to prefs dataset
721 static void addressbook_size_allocate_cb(GtkWidget *widget,
722 GtkAllocation *allocation)
724 g_return_if_fail(allocation != NULL);
726 prefs_common.addressbookwin_width = allocation->width;
727 prefs_common.addressbookwin_height = allocation->height;
730 static gint sort_column_number = 0;
731 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
733 static gint list_case_sort(
734 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
736 GtkCListRow *row1 = (GtkCListRow *) ptr1;
737 GtkCListRow *row2 = (GtkCListRow *) ptr2;
738 gchar *name1 = NULL, *name2 = NULL;
739 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
740 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
742 if( aio1->type == aio2->type ) {
744 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
746 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
747 if( ! name1 ) return ( name2 != NULL );
748 if( ! name2 ) return -1;
749 return g_utf8_collate( name1, name2 );
751 /* Order groups before person */
752 if( aio1->type == ITEMTYPE_GROUP ) {
753 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
754 } else if( aio2->type == ITEMTYPE_GROUP ) {
755 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
761 static void addressbook_sort_list(GtkCList *clist, const gint col,
762 const GtkSortType sort_type)
765 GtkWidget *hbox, *label, *arrow;
767 sort_column_number = col;
768 sort_column_type = sort_type;
769 gtk_clist_set_compare_func(clist, list_case_sort);
770 gtk_clist_set_sort_type(clist, sort_type);
771 gtk_clist_set_sort_column(clist, col);
773 gtk_clist_freeze(clist);
774 gtk_clist_sort(clist);
776 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
777 hbox = gtk_hbox_new(FALSE, 4);
778 label = gtk_label_new(gettext(list_titles[pos]));
779 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
782 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
783 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
784 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
787 gtk_widget_show_all(hbox);
788 gtk_clist_set_column_widget(clist, pos, hbox);
791 gtk_clist_thaw(clist);
794 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
796 static GtkSortType sort_type = GTK_SORT_ASCENDING;
798 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
800 addressbook_sort_list(clist, COL_NAME, sort_type);
803 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
805 static GtkSortType sort_type = GTK_SORT_ASCENDING;
807 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
809 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
812 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
814 static GtkSortType sort_type = GTK_SORT_ASCENDING;
816 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
818 addressbook_sort_list(clist, COL_REMARKS, sort_type);
821 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
824 address_index_has_focus = TRUE;
828 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
831 address_index_has_focus = FALSE;
832 if (!prefs_common.addressbook_use_editaddress_dialog
833 && !address_list_has_focus)
834 addressbook_address_list_disable_some_actions();
838 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
841 address_list_has_focus = TRUE;
845 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
848 address_list_has_focus = FALSE;
849 if (!prefs_common.addressbook_use_editaddress_dialog
850 && !address_index_has_focus)
851 addressbook_address_list_disable_some_actions();
855 /* save hpane and vpane's handle position when it moves */
856 static void addressbook_pane_save_position(void)
859 prefs_common.addressbook_hpaned_pos =
860 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
862 prefs_common.addressbook_vpaned_pos =
863 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
867 * Create the address book widgets. The address book contains two CTree widgets: the
868 * address index tree on the left and the address list on the right.
870 * The address index tree displays a hierarchy of interfaces and groups. Each node in
871 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
872 * data sources and folder objects.
874 * The address list displays group, person and email objects. These items are linked
875 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
878 * In the tradition of MVC architecture, the data stores have been separated from the
879 * GUI components. The addrindex.c file provides the interface to all data stores.
881 static void addressbook_create(void)
887 GtkWidget *ctree_swin;
889 GtkWidget *editaddress_vbox;
890 GtkWidget *clist_vbox;
891 GtkWidget *clist_swin;
898 GtkWidget *statusbar;
909 GtkWidget *close_btn;
910 GtkWidget *tree_popup;
911 GtkWidget *list_popup;
913 GtkUIManager *ui_manager;
914 GtkActionGroup *action_group;
915 gchar *index_titles[N_INDEX_COLS];
919 static GdkGeometry geometry;
921 debug_print("Creating addressbook window...\n");
923 index_titles[COL_SOURCES] = _("Sources");
925 /* Address book window */
926 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
927 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
928 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
929 gtk_widget_realize(window);
931 g_signal_connect(G_OBJECT(window), "delete_event",
932 G_CALLBACK(addressbook_close), NULL);
933 g_signal_connect(G_OBJECT(window), "size_allocate",
934 G_CALLBACK(addressbook_size_allocate_cb), NULL);
935 g_signal_connect(G_OBJECT(window), "key_press_event",
936 G_CALLBACK(key_pressed), NULL);
937 MANAGE_WINDOW_SIGNALS_CONNECT(window);
939 vbox = gtk_vbox_new(FALSE, 0);
940 gtk_container_add(GTK_CONTAINER(window), vbox);
943 ui_manager = gtk_ui_manager_new();
944 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
945 G_N_ELEMENTS(addressbook_entries), NULL);
946 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
947 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
948 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
949 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENU)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
995 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
996 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
997 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
998 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
999 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
1000 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
1001 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
1002 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
1003 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
1006 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
1008 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1011 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1013 hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
1016 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1017 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1018 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1020 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1021 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1022 GTK_POLICY_AUTOMATIC,
1023 GTK_POLICY_AUTOMATIC);
1024 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1027 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1028 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1029 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
1030 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
1031 if (prefs_common.enable_dotted_lines) {
1032 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
1033 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
1034 GTK_CTREE_EXPANDER_SQUARE);
1036 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
1037 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
1038 GTK_CTREE_EXPANDER_TRIANGLE);
1040 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1041 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
1042 gtk_clist_set_compare_func(GTK_CLIST(ctree),
1043 addressbook_treenode_compare_func);
1045 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1046 G_CALLBACK(addressbook_tree_selected), NULL);
1047 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1048 G_CALLBACK(addressbook_tree_button_pressed),
1050 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1051 G_CALLBACK(addressbook_tree_button_released),
1054 g_signal_connect(G_OBJECT(ctree), "select_row",
1055 G_CALLBACK(addressbook_select_row_tree), NULL);
1057 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1058 addressbook_drag_types, 1,
1059 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1060 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1061 G_CALLBACK(addressbook_drag_motion_cb),
1063 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1064 G_CALLBACK(addressbook_drag_leave_cb),
1066 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1067 G_CALLBACK(addressbook_drag_received_cb),
1069 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1070 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1071 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1072 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1074 clist_vbox = gtk_vbox_new(FALSE, 4);
1076 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1077 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1078 GTK_POLICY_AUTOMATIC,
1079 GTK_POLICY_AUTOMATIC);
1080 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1083 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1084 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1085 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1086 if (prefs_common.enable_dotted_lines) {
1087 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_DOTTED);
1088 gtk_ctree_set_expander_style(GTK_CTREE(clist),
1089 GTK_CTREE_EXPANDER_SQUARE);
1091 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1092 gtk_ctree_set_expander_style(GTK_CTREE(clist),
1093 GTK_CTREE_EXPANDER_TRIANGLE);
1095 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1096 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1097 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1099 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1101 gtk_widget_set_size_request(clist, -1, 80);
1103 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1104 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1105 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1106 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1107 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1108 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1109 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1110 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1111 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1112 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1113 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1115 for (i = 0; i < N_LIST_COLS; i++)
1116 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1119 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1120 G_CALLBACK(addressbook_list_row_selected), NULL);
1121 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1122 G_CALLBACK(addressbook_list_row_unselected), NULL);
1123 g_signal_connect(G_OBJECT(clist), "button_press_event",
1124 G_CALLBACK(addressbook_list_button_pressed),
1126 g_signal_connect(G_OBJECT(clist), "button_release_event",
1127 G_CALLBACK(addressbook_list_button_released),
1129 g_signal_connect(G_OBJECT(clist), "tree_expand",
1130 G_CALLBACK(addressbook_person_expand_node), NULL );
1131 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1132 G_CALLBACK(addressbook_person_collapse_node), NULL );
1133 g_signal_connect(G_OBJECT(clist), "start_drag",
1134 G_CALLBACK(addressbook_start_drag), NULL);
1135 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1136 G_CALLBACK(addressbook_drag_data_get), NULL);
1137 hbox = gtk_hbox_new(FALSE, 4);
1138 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1140 label = gtk_label_new(_("Lookup name:"));
1141 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1143 entry = gtk_entry_new();
1144 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1146 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1148 g_signal_connect(G_OBJECT(entry), "key_press_event",
1149 G_CALLBACK(addressbook_entry_key_pressed),
1152 if (!prefs_common.addressbook_use_editaddress_dialog) {
1153 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1154 vpaned = gtk_vpaned_new();
1155 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1156 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1159 editaddress_vbox = NULL;
1161 hpaned = gtk_hpaned_new();
1162 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1163 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1164 if (prefs_common.addressbook_use_editaddress_dialog)
1165 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1167 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1170 hsbox = gtk_hbox_new(FALSE, 0);
1171 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1172 statusbar = gtk_statusbar_new();
1173 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1176 hbbox = gtk_hbutton_box_new();
1177 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1178 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1179 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1180 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1182 gtkut_stock_button_add_help(hbbox, &help_btn);
1184 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1185 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1186 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1187 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1188 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1189 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1190 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1191 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1192 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1195 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1196 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1197 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1199 g_signal_connect(G_OBJECT(help_btn), "clicked",
1200 G_CALLBACK(manual_open_with_anchor_cb),
1201 MANUAL_ANCHOR_ADDRBOOK);
1203 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1204 G_CALLBACK(addressbook_edit_clicked), NULL);
1205 g_signal_connect(G_OBJECT(del_btn), "clicked",
1206 G_CALLBACK(addressbook_del_clicked), NULL);
1207 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1208 G_CALLBACK(addressbook_reg_clicked), NULL);
1209 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1210 G_CALLBACK(addressbook_lup_clicked), NULL);
1212 to_btn = gtk_button_new_with_label
1213 (prefs_common_translated_header_name("To:"));
1214 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1215 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1216 cc_btn = gtk_button_new_with_label
1217 (prefs_common_translated_header_name("Cc:"));
1218 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1219 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1220 bcc_btn = gtk_button_new_with_label
1221 (prefs_common_translated_header_name("Bcc:"));
1222 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1223 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1225 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1226 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1227 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1229 g_signal_connect(G_OBJECT(to_btn), "clicked",
1230 G_CALLBACK(addressbook_to_clicked),
1231 GINT_TO_POINTER(COMPOSE_TO));
1232 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1233 G_CALLBACK(addressbook_to_clicked),
1234 GINT_TO_POINTER(COMPOSE_CC));
1235 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1236 G_CALLBACK(addressbook_to_clicked),
1237 GINT_TO_POINTER(COMPOSE_BCC));
1238 g_signal_connect(G_OBJECT(close_btn), "clicked",
1239 G_CALLBACK(addressbook_close_clicked), NULL);
1241 /* Build icons for interface */
1242 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1243 &interfacexpm, &interfacexpmmask );
1245 /* Build control tables */
1246 addrbookctl_build_map(window);
1247 addrbookctl_build_iflist();
1248 addrbookctl_build_ifselect();
1250 addrbook.clist = NULL;
1252 /* Add each interface into the tree as a root level folder */
1253 nodeIf = _addressInterfaceList_;
1255 AdapterInterface *adapter = nodeIf->data;
1256 AddressInterface *iface = adapter->interface;
1257 nodeIf = g_list_next(nodeIf);
1259 if(iface->useInterface) {
1260 AddressTypeControlItem *atci = adapter->atci;
1261 text = atci->displayName;
1263 gtk_sctree_insert_node( GTK_CTREE(ctree),
1264 NULL, NULL, &text, FOLDER_SPACING,
1265 interfacexpm, interfacexpmmask,
1266 interfacexpm, interfacexpmmask,
1268 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1269 gtk_ctree_node_set_row_data_full(
1270 GTK_CTREE(ctree), adapter->treeNode, adapter,
1271 addressbook_free_treenode );
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1290 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1291 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1293 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1294 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1295 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1296 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1297 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1298 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1299 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1300 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1301 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1302 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1303 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1304 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1305 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1306 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1308 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1310 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1311 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1313 addrbook.window = window;
1314 addrbook.hpaned = hpaned;
1315 addrbook.vpaned = vpaned;
1316 addrbook.menubar = menubar;
1317 addrbook.ctree = ctree;
1320 addrbook.editaddress_vbox = editaddress_vbox;
1321 addrbook.clist = clist;
1322 addrbook.label = label;
1323 addrbook.entry = entry;
1324 addrbook.statusbar = statusbar;
1325 addrbook.status_cid = gtk_statusbar_get_context_id(
1326 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1328 addrbook.help_btn = help_btn;
1329 addrbook.edit_btn = edit_btn;
1330 addrbook.del_btn = del_btn;
1331 addrbook.reg_btn = reg_btn;
1332 addrbook.lup_btn = lup_btn;
1333 addrbook.to_btn = to_btn;
1334 addrbook.cc_btn = cc_btn;
1335 addrbook.bcc_btn = bcc_btn;
1337 addrbook.tree_popup = tree_popup;
1338 addrbook.list_popup = list_popup;
1339 addrbook.ui_manager = ui_manager;
1341 addrbook.listSelected = NULL;
1343 if (!geometry.min_height) {
1344 geometry.min_width = ADDRESSBOOK_WIDTH;
1345 geometry.min_height = ADDRESSBOOK_HEIGHT;
1348 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1350 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1351 prefs_common.addressbookwin_height);
1353 if (!prefs_common.addressbook_use_editaddress_dialog) {
1354 if (prefs_common.addressbook_vpaned_pos > 0)
1355 gtk_paned_set_position(GTK_PANED(vpaned),
1356 prefs_common.addressbook_vpaned_pos);
1358 if (prefs_common.addressbook_hpaned_pos > 0)
1359 gtk_paned_set_position(GTK_PANED(hpaned),
1360 prefs_common.addressbook_hpaned_pos);
1363 gtk_widget_show_all(window);
1367 * Close address book window and save to file(s).
1369 static gint addressbook_close( void ) {
1370 address_completion_end(addrbook.window);
1371 if (!prefs_common.addressbook_use_editaddress_dialog)
1372 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1374 addressbook_pane_save_position();
1376 gtk_widget_hide(addrbook.window);
1377 addressbook_export_to_file();
1382 * Display message in status line.
1383 * \param msg Message to display.
1385 static void addressbook_status_show( gchar *msg ) {
1386 if( addrbook.statusbar != NULL ) {
1388 GTK_STATUSBAR(addrbook.statusbar),
1389 addrbook.status_cid );
1392 GTK_STATUSBAR(addrbook.statusbar),
1393 addrbook.status_cid, msg );
1398 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1402 *addressbook_msgbuf = '\0';
1404 name = addrindex_ds_get_name( ds );
1405 retVal = addrindex_ds_get_status_code( ds );
1406 if( retVal == MGU_SUCCESS ) {
1407 g_snprintf( addressbook_msgbuf,
1408 sizeof(addressbook_msgbuf), "%s", name );
1411 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1412 g_snprintf( addressbook_msgbuf,
1413 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1416 addressbook_status_show( addressbook_msgbuf );
1419 static void addressbook_button_set_sensitive(void)
1421 gboolean to_sens = FALSE;
1422 gboolean cc_sens = FALSE;
1423 gboolean bcc_sens = FALSE;
1425 if (!addrbook.window) return;
1427 if (addrbook.target_compose) {
1433 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1434 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1435 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1438 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1440 addressbook_edit_address_cb(NULL, NULL);
1443 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1445 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1449 * Delete one or more objects from address list.
1451 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1453 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1454 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1455 AddressObject *pobj;
1456 AdapterDSource *ads = NULL;
1457 GtkCTreeNode *nodeList;
1460 AddressBookFile *abf = NULL;
1461 AddressDataSource *ds = NULL;
1462 AddressInterface *iface;
1463 AddrItemObject *aio;
1464 AddrSelectItem *item;
1466 gboolean refreshList = FALSE;
1468 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1469 g_return_if_fail(pobj != NULL);
1471 /* Test whether anything selected for deletion */
1472 nodeList = addrbook.listSelected;
1474 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1475 if( aio == NULL) return;
1476 ds = addressbook_find_datasource( addrbook.treeSelected );
1477 if( ds == NULL ) return;
1479 /* Test for read only */
1480 iface = ds->interface;
1481 if( iface->readOnly ) {
1482 alertpanel( _("Delete address(es)"),
1483 _("This address data is readonly and cannot be deleted."),
1484 GTK_STOCK_CLOSE, NULL, NULL );
1488 /* Test whether Ok to proceed */
1490 if( pobj->type == ADDR_DATASOURCE ) {
1491 ads = ADAPTER_DSOURCE(pobj);
1492 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1494 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1497 else if( pobj->type == ADDR_ITEM_GROUP ) {
1500 if( ! procFlag ) return;
1501 abf = ds->rawDataSource;
1502 if( abf == NULL ) return;
1504 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
1505 g_signal_handlers_block_by_func
1506 (G_OBJECT(addrbook.clist),
1507 G_CALLBACK(addressbook_list_row_unselected), NULL);
1509 /* Process deletions */
1510 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1511 GList *groups = NULL, *persons = NULL, *emails = NULL;
1512 gboolean group_delete = TRUE;
1513 /* Items inside folders */
1514 list = addrselect_get_list( _addressSelect_ );
1515 /* Confirm deletion */
1519 node = g_list_next( node );
1520 aio = ( AddrItemObject * ) item->addressItem;
1521 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1522 group_delete = FALSE;
1527 aval = alertpanel( _("Delete group"),
1528 _("Really delete the group(s)?\n"
1529 "The addresses it contains will not be lost."),
1530 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1531 if( aval != G_ALERTALTERNATE ) {
1535 aval = alertpanel( _("Delete address(es)"),
1536 _("Really delete the address(es)?"),
1537 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1538 if( aval != G_ALERTALTERNATE ) {
1543 /* first, set lists of groups and persons to remove */
1547 node = g_list_next( node );
1548 aio = ( AddrItemObject * ) item->addressItem;
1551 if( aio->type == ADDR_ITEM_GROUP ) {
1552 groups = g_list_prepend(groups, item);
1554 else if( aio->type == ADDR_ITEM_PERSON ) {
1555 persons = g_list_prepend(persons, item);
1558 /* then set list of emails to remove *if* they're not children of
1559 * persons to remove */
1563 node = g_list_next( node );
1564 aio = ( AddrItemObject * ) item->addressItem;
1567 if( aio->type == ADDR_ITEM_EMAIL ) {
1568 ItemEMail *sitem = ( ItemEMail * ) aio;
1569 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1570 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1571 emails = g_list_prepend(emails, item);
1573 /* else, the email will be removed via the parent person */
1576 /* then delete groups */
1580 node = g_list_next( node );
1581 aio = ( AddrItemObject * ) item->addressItem;
1584 if( aio->type == ADDR_ITEM_GROUP ) {
1585 ItemGroup *item = ( ItemGroup * ) aio;
1586 GtkCTreeNode *nd = NULL;
1587 nd = addressbook_find_group_node( addrbook.opened, item );
1588 item = addrbook_remove_group( abf, item );
1590 addritem_free_item_group( item );
1592 /* Remove group from parent node */
1593 gtk_ctree_remove_node( ctree, nd );
1597 /* then delete persons */
1601 node = g_list_next( node );
1602 aio = ( AddrItemObject * ) item->addressItem;
1605 if( aio->type == ADDR_ITEM_PERSON ) {
1606 ItemPerson *item = ( ItemPerson * ) aio;
1607 item->status = DELETE_ENTRY;
1608 addressbook_folder_remove_one_person( clist, item );
1609 if (pobj->type == ADDR_ITEM_FOLDER)
1610 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1611 item = addrbook_remove_person( abf, item );
1613 if (ds && ds->type == ADDR_IF_LDAP) {
1614 LdapServer *server = ds->rawDataSource;
1615 ldapsvr_set_modified(server, TRUE);
1616 ldapsvr_update_book(server, item);
1620 gchar *filename = addritem_person_get_picture(item);
1621 if (filename && is_file_exist(filename))
1622 claws_unlink(filename);
1624 addritem_free_item_person( item );
1628 /* then delete emails */
1632 node = g_list_next( node );
1633 aio = ( AddrItemObject * ) item->addressItem;
1637 if( aio->type == ADDR_ITEM_EMAIL ) {
1638 ItemEMail *sitem = ( ItemEMail * ) aio;
1639 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1640 sitem = addrbook_person_remove_email( abf, person, sitem );
1642 addrcache_remove_email(abf->addressCache, sitem);
1643 addritem_free_item_email( sitem );
1645 addressbook_folder_refresh_one_person( clist, person );
1648 g_list_free( groups );
1649 g_list_free( persons );
1650 g_list_free( emails );
1651 g_list_free( list );
1652 addressbook_list_select_clear();
1654 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1655 addressbook_set_clist(
1656 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1660 addrbook_set_dirty(abf, TRUE);
1661 addressbook_export_to_file();
1662 addressbook_list_menu_setup();
1665 else if( pobj->type == ADDR_ITEM_GROUP ) {
1666 /* Items inside groups */
1667 list = addrselect_get_list( _addressSelect_ );
1671 node = g_list_next( node );
1672 aio = ( AddrItemObject * ) item->addressItem;
1673 if( aio->type == ADDR_ITEM_EMAIL ) {
1674 ItemEMail *item = ( ItemEMail * ) aio;
1675 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1676 item = addrbook_person_remove_email( abf, person, item );
1678 addritem_free_item_email( item );
1682 g_list_free( list );
1683 addressbook_list_select_clear();
1684 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1685 addressbook_set_clist(
1686 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1690 addrbook_set_dirty(abf, TRUE);
1691 addressbook_export_to_file();
1692 addressbook_list_menu_setup();
1696 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1697 gtk_ctree_remove_node( clist, nodeList );
1699 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
1700 g_signal_handlers_unblock_by_func
1701 (G_OBJECT(addrbook.clist),
1702 G_CALLBACK(addressbook_list_row_unselected), NULL);
1705 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1707 addressbook_new_address_cb( NULL, NULL );
1710 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1713 gchar *address = NULL;
1715 if( aio->type == ADDR_ITEM_EMAIL ) {
1716 ItemPerson *person = NULL;
1717 ItemEMail *email = ( ItemEMail * ) aio;
1719 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1720 if( email->address ) {
1721 if( ADDRITEM_NAME(email) ) {
1722 name = ADDRITEM_NAME(email);
1723 if( *name == '\0' ) {
1724 name = ADDRITEM_NAME(person);
1727 else if( ADDRITEM_NAME(person) ) {
1728 name = ADDRITEM_NAME(person);
1731 buf = g_strdup( email->address );
1733 address = email->address;
1736 else if( aio->type == ADDR_ITEM_PERSON ) {
1737 ItemPerson *person = ( ItemPerson * ) aio;
1738 GList *node = person->listEMail;
1740 name = ADDRITEM_NAME(person);
1742 ItemEMail *email = ( ItemEMail * ) node->data;
1743 address = email->address;
1747 if( name && name[0] != '\0' ) {
1748 if( strchr_with_skip_quote( name, '"', ',' ) )
1749 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1751 buf = g_strdup_printf( "%s <%s>", name, address );
1754 buf = g_strdup( address );
1761 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1765 AddrSelectItem *item;
1766 AddrItemObject *aio;
1769 compose = addrbook.target_compose;
1770 if( ! compose ) return;
1772 /* Nothing selected, but maybe there is something in text entry */
1773 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1775 compose_entry_append(
1776 compose, addr, (ComposeEntryType)data );
1779 /* Select from address list */
1780 list = addrselect_get_list( _addressSelect_ );
1785 node = g_list_next( node );
1786 aio = item->addressItem;
1787 if( aio->type == ADDR_ITEM_PERSON ||
1788 aio->type == ADDR_ITEM_EMAIL ) {
1789 addr = addressbook_format_address( aio );
1790 compose_entry_append(
1791 compose, addr, (ComposeEntryType) data );
1794 else if( aio->type == ADDR_ITEM_GROUP ) {
1795 ItemGroup *group = ( ItemGroup * ) aio;
1796 GList *nodeMail = group->listEMail;
1798 ItemEMail *email = nodeMail->data;
1800 addr = addressbook_format_address(
1801 ( AddrItemObject * ) email );
1802 compose_entry_append(
1803 compose, addr, (ComposeEntryType) data );
1805 nodeMail = g_list_next( nodeMail );
1810 AddressObject *obj = NULL;
1812 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1814 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1815 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1816 GList *nodeMail = itemGroup->listEMail;
1818 ItemEMail *email = nodeMail->data;
1820 addr = addressbook_format_address(
1821 ( AddrItemObject * ) email );
1822 compose_entry_append(
1823 compose, addr, (ComposeEntryType) data );
1825 nodeMail = g_list_next( nodeMail );
1829 g_list_free( list );
1832 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1833 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1834 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1835 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1837 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1838 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1839 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1840 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1842 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1843 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1844 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1845 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1846 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1849 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1850 gboolean canEdit = FALSE;
1851 gboolean canDelete = TRUE;
1852 gboolean canAdd = FALSE;
1853 gboolean canEditTr = TRUE;
1854 gboolean editAddress = FALSE;
1855 gboolean canExport = TRUE;
1856 AddressTypeControlItem *atci = NULL;
1857 AddressDataSource *ds = NULL;
1858 AddressInterface *iface = NULL;
1860 if( obj == NULL ) return;
1861 if( obj->type == ADDR_INTERFACE ) {
1862 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1863 iface = adapter->interface;
1865 if( iface->haveLibrary ) {
1866 /* Enable appropriate File / New command */
1867 atci = adapter->atci;
1868 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1871 canEditTr = canExport = FALSE;
1873 else if( obj->type == ADDR_DATASOURCE ) {
1874 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1875 ds = ads->dataSource;
1876 iface = ds->interface;
1877 if( ! iface->readOnly ) {
1878 canAdd = canEdit = editAddress = canDelete = TRUE;
1880 if( ! iface->haveLibrary ) {
1881 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1884 else if( obj->type == ADDR_ITEM_FOLDER ) {
1885 ds = addressbook_find_datasource( addrbook.treeSelected );
1887 iface = ds->interface;
1888 if( iface->readOnly ) {
1893 canAdd = editAddress = TRUE;
1897 else if( obj->type == ADDR_ITEM_GROUP ) {
1898 ds = addressbook_find_datasource( addrbook.treeSelected );
1900 iface = ds->interface;
1901 if( ! iface->readOnly ) {
1907 if( addrbook.listSelected == NULL )
1911 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1912 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1913 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1914 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1917 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1918 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1919 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1920 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1922 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1923 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1926 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1927 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1931 * Address book tree callback function that responds to selection of tree
1934 * \param ctree Tree widget.
1935 * \param node Node that was selected.
1936 * \param column Column number where selected occurred.
1937 * \param data Pointer to user data.
1939 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1940 gint column, gpointer data)
1942 AddressObject *obj = NULL;
1943 AdapterDSource *ads = NULL;
1944 AddressDataSource *ds = NULL;
1945 ItemFolder *rootFolder = NULL;
1946 AddressObjectType aot;
1948 addrbook.treeSelected = node;
1949 addrbook.listSelected = NULL;
1950 addressbook_status_show( "" );
1951 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1953 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1955 addressbook_set_clist(NULL, TRUE);
1958 addrbook.opened = node;
1960 if( obj->type == ADDR_DATASOURCE ) {
1961 /* Read from file */
1962 static gboolean tVal = TRUE;
1964 ads = ADAPTER_DSOURCE(obj);
1965 if( ads == NULL ) return;
1966 ds = ads->dataSource;
1967 if( ds == NULL ) return;
1969 if( addrindex_ds_get_modify_flag( ds ) ) {
1970 addrindex_ds_read_data( ds );
1973 if( ! addrindex_ds_get_read_flag( ds ) ) {
1974 addrindex_ds_read_data( ds );
1976 addressbook_ds_show_message( ds );
1978 if( ! addrindex_ds_get_access_flag( ds ) ) {
1979 /* Remove existing folders and groups */
1980 gtk_clist_freeze( GTK_CLIST(ctree) );
1981 addressbook_tree_remove_children( ctree, node );
1982 gtk_clist_thaw( GTK_CLIST(ctree) );
1984 /* Load folders into the tree */
1985 rootFolder = addrindex_ds_get_root_folder( ds );
1986 if( ds && ds->type == ADDR_IF_JPILOT ) {
1987 aot = ADDR_CATEGORY;
1989 else if( ds && ds->type == ADDR_IF_LDAP ) {
1990 aot = ADDR_LDAP_QUERY;
1993 aot = ADDR_ITEM_FOLDER;
1995 addressbook_node_add_folder( node, ds, rootFolder, aot );
1996 addrindex_ds_set_access_flag( ds, &tVal );
1997 gtk_ctree_expand( ctree, node );
2000 addressbook_set_clist(NULL, TRUE);
2003 /* Update address list */
2004 g_signal_handlers_block_by_func
2006 G_CALLBACK(addressbook_tree_selected), NULL);
2007 addressbook_set_clist( obj, FALSE );
2008 g_signal_handlers_unblock_by_func
2010 G_CALLBACK(addressbook_tree_selected), NULL);
2011 if (!prefs_common.addressbook_use_editaddress_dialog)
2012 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2014 /* Setup main menu selections */
2015 addressbook_menubar_set_sensitive( FALSE );
2016 addressbook_menuitem_set_sensitive( obj, node );
2017 addressbook_list_select_clear();
2018 addressbook_list_menu_setup();
2023 * Setup address list popup menu items. Items are enabled or disabled as
2026 static void addressbook_list_menu_setup( void ) {
2027 GtkCTree *clist = NULL;
2028 AddressObject *pobj = NULL;
2029 AddressObject *obj = NULL;
2030 AdapterDSource *ads = NULL;
2031 AddressInterface *iface = NULL;
2032 AddressDataSource *ds = NULL;
2033 gboolean canEdit = FALSE;
2034 gboolean canDelete = FALSE;
2035 gboolean canCut = FALSE;
2036 gboolean canCopy = FALSE;
2037 gboolean canPaste = FALSE;
2038 gboolean canBrowse = FALSE;
2040 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2041 if( pobj == NULL ) return;
2043 clist = GTK_CTREE(addrbook.clist);
2044 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2045 if( obj == NULL ) canEdit = FALSE;
2047 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2048 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2050 if( pobj->type == ADDR_DATASOURCE ) {
2051 /* Parent object is a data source */
2052 ads = ADAPTER_DSOURCE(pobj);
2053 ds = ads->dataSource;
2056 iface = ds->interface;
2059 if( ! iface->readOnly ) {
2060 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2061 if (iface->type != ADDR_IF_LDAP)
2062 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2063 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2066 canDelete = canEdit;
2069 else if( pobj->type != ADDR_INTERFACE ) {
2070 /* Parent object is not an interface */
2071 ds = addressbook_find_datasource( addrbook.treeSelected );
2074 iface = ds->interface;
2077 if( ! iface->readOnly ) {
2078 /* Folder or group */
2079 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2081 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2082 if( obj ) canEdit = TRUE;
2085 if( pobj->type == ADDR_ITEM_FOLDER ) {
2086 if (iface->type != ADDR_IF_LDAP)
2087 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2088 if( obj ) canEdit = TRUE;
2090 canDelete = canEdit;
2092 if( iface->type == ADDR_IF_LDAP ) {
2093 if( obj ) canBrowse = TRUE;
2100 /* Enable cut and paste */
2101 if( ! addrclip_is_empty( _clipBoard_ ) )
2103 if( ! addrselect_test_empty( _addressSelect_ ) )
2105 /* Enable copy if something is selected */
2106 if( ! addrselect_test_empty( _addressSelect_ ) )
2110 /* Disable edit or browse if more than one row selected */
2111 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
2116 /* Forbid write changes when read-only */
2117 if( iface && iface->readOnly ) {
2123 /* Now go finalize menu items */
2124 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2125 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2127 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2128 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2129 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2131 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2133 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2134 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2135 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2137 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2138 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2139 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2141 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2142 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2145 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2149 static void addressbook_select_row_tree (GtkCTree *ctree,
2157 * Add list of items into tree node below specified tree node.
2158 * \param treeNode Tree node.
2159 * \param ds Data source.
2160 * \param listItems List of items.
2162 static void addressbook_treenode_add_list(
2163 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2169 AddrItemObject *aio;
2173 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2176 group = ( ItemGroup * ) aio;
2177 nn = addressbook_node_add_group( treeNode, ds, group );
2179 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2182 folder = ( ItemFolder * ) aio;
2183 nn = addressbook_node_add_folder(
2184 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2186 node = g_list_next( node );
2190 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2191 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2195 * Cut from address list widget.
2197 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2198 _clipBoard_->cutFlag = TRUE;
2199 addrclip_clear( _clipBoard_ );
2200 addrclip_add( _clipBoard_, _addressSelect_ );
2201 /* addrclip_list_show( _clipBoard_, stdout ); */
2205 * Copy from address list widget.
2207 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2208 _clipBoard_->cutFlag = FALSE;
2209 addrclip_clear( _clipBoard_ );
2210 addrclip_add( _clipBoard_, _addressSelect_ );
2211 /* addrclip_list_show( _clipBoard_, stdout ); */
2215 * Paste clipboard into address list widget.
2217 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2218 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2219 AddressObject *pobj = NULL;
2220 AddressDataSource *ds = NULL;
2221 AddressBookFile *abf = NULL;
2222 ItemFolder *folder = NULL;
2223 GList *folderGroup = NULL;
2225 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2226 if( ds == NULL ) return;
2227 if( addrindex_ds_get_readonly( ds ) ) {
2228 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2232 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2234 if( pobj->type == ADDR_ITEM_FOLDER ) {
2235 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2237 else if( pobj->type == ADDR_ITEM_GROUP ) {
2238 alertpanel_error( _("Cannot paste into an address group.") );
2243 /* Get an address book */
2244 abf = addressbook_get_book_file();
2245 if( abf == NULL ) return;
2247 if( _clipBoard_->cutFlag ) {
2249 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2251 /* Remove all groups and folders in clipboard from tree node */
2252 addressbook_treenode_remove_item();
2254 /* Remove all "cut" items */
2255 addrclip_delete_item( _clipBoard_ );
2257 /* Clear clipboard - cut items??? */
2258 addrclip_clear( _clipBoard_ );
2262 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2265 /* addrclip_list_show( _clipBoard_, stdout ); */
2267 /* Update tree by inserting node for each folder or group */
2268 addressbook_treenode_add_list(
2269 addrbook.treeSelected, ds, folderGroup );
2270 gtk_ctree_expand( ctree, addrbook.treeSelected );
2271 g_list_free( folderGroup );
2275 /* Display items pasted */
2276 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2277 addressbook_set_clist(
2278 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2286 * Add current treenode object to clipboard. Note that widget only allows
2287 * one entry from the tree list to be selected.
2289 static void addressbook_treenode_to_clipboard( void ) {
2290 AddressObject *obj = NULL;
2291 AddressDataSource *ds = NULL;
2292 AddrSelectItem *item;
2293 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2296 node = addrbook.treeSelected;
2297 if( node == NULL ) return;
2298 obj = gtk_ctree_node_get_row_data( ctree, node );
2299 if( obj == NULL ) return;
2301 ds = addressbook_find_datasource( node );
2302 if( ds == NULL ) return;
2305 if( obj->type == ADDR_ITEM_FOLDER ) {
2306 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2307 ItemFolder *folder = adapter->itemFolder;
2309 item = addrselect_create_node( obj );
2310 item->uid = g_strdup( ADDRITEM_ID(folder) );
2312 else if( obj->type == ADDR_ITEM_GROUP ) {
2313 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2314 ItemGroup *group = adapter->itemGroup;
2316 item = addrselect_create_node( obj );
2317 item->uid = g_strdup( ADDRITEM_ID(group) );
2319 else if( obj->type == ADDR_DATASOURCE ) {
2321 item = addrselect_create_node( obj );
2326 /* Clear existing list and add item into list */
2329 addressbook_list_select_clear();
2330 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2331 addrselect_list_add( _addressSelect_, item, cacheID );
2337 * Cut from tree widget.
2339 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2340 _clipBoard_->cutFlag = TRUE;
2341 addressbook_treenode_to_clipboard();
2342 addrclip_clear( _clipBoard_ );
2343 addrclip_add( _clipBoard_, _addressSelect_ );
2344 /* addrclip_list_show( _clipBoard_, stdout ); */
2348 * Copy from tree widget.
2350 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2351 _clipBoard_->cutFlag = FALSE;
2352 addressbook_treenode_to_clipboard();
2353 addrclip_clear( _clipBoard_ );
2354 addrclip_add( _clipBoard_, _addressSelect_ );
2355 /* addrclip_list_show( _clipBoard_, stdout ); */
2359 * Paste clipboard into address tree widget.
2361 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2362 addressbook_clip_paste_cb(NULL,NULL);
2366 * Clear selected entries in clipboard.
2368 static void addressbook_list_select_clear( void ) {
2369 addrselect_list_clear( _addressSelect_ );
2373 * Add specified address item to selected address list.
2374 * \param aio Address item object.
2375 * \param ds Datasource.
2377 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2380 if( ds == NULL ) return;
2381 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2382 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2387 * Remove specified address item from selected address list.
2388 * \param aio Address item object.
2390 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2391 addrselect_list_remove( _addressSelect_, aio );
2395 * Invoke EMail compose window with addresses in selected address list.
2397 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2400 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2401 listAddress = addrselect_build_list( _addressSelect_ );
2402 compose_new_with_list( NULL, listAddress );
2403 mgu_free_dlist( listAddress );
2408 static void addressbook_list_row_selected( GtkCTree *clist,
2413 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2414 AddrItemObject *aio = NULL;
2415 AddressObject *pobj = NULL;
2416 AdapterDSource *ads = NULL;
2417 AddressDataSource *ds = NULL;
2419 gtk_entry_set_text( entry, "" );
2420 addrbook.listSelected = node;
2422 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2423 if( pobj == NULL ) return;
2425 if( pobj->type == ADDR_DATASOURCE ) {
2426 ads = ADAPTER_DSOURCE(pobj);
2427 ds = ads->dataSource;
2429 else if( pobj->type != ADDR_INTERFACE ) {
2430 ds = addressbook_find_datasource( addrbook.treeSelected );
2433 aio = gtk_ctree_node_get_row_data( clist, node );
2435 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2436 addressbook_list_select_add( aio, ds );
2439 addressbook_list_menu_setup();
2441 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2442 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2444 if (obj && obj->type != ADDR_ITEM_GROUP)
2445 addressbook_edit_address(NULL, 0, NULL, FALSE);
2449 static void addressbook_list_row_unselected( GtkCTree *ctree,
2454 AddrItemObject *aio;
2456 aio = gtk_ctree_node_get_row_data( ctree, node );
2458 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2459 addressbook_list_select_remove( aio );
2462 if (!prefs_common.addressbook_use_editaddress_dialog)
2463 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2466 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2467 GdkEventButton *event,
2470 if( ! event ) return FALSE;
2472 addressbook_list_menu_setup();
2474 if( event->button == 3 ) {
2475 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2476 event->button, event->time );
2477 } else if (event->button == 1) {
2478 if (event->type == GDK_2BUTTON_PRESS) {
2479 if (prefs_common.add_address_by_click &&
2480 addrbook.target_compose)
2481 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2483 if (prefs_common.addressbook_use_editaddress_dialog)
2484 addressbook_edit_address_cb(NULL, NULL);
2486 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2487 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2488 if( obj && obj->type == ADDR_ITEM_GROUP )
2489 addressbook_edit_address_cb(NULL, NULL);
2497 static gboolean addressbook_list_button_released(GtkWidget *widget,
2498 GdkEventButton *event,
2504 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2505 GdkEventButton *event,
2508 GtkCList *clist = GTK_CLIST(ctree);
2510 AddressObject *obj = NULL;
2511 AdapterDSource *ads = NULL;
2512 AddressInterface *iface = NULL;
2513 AddressDataSource *ds = NULL;
2514 gboolean canEdit = FALSE;
2515 gboolean canDelete = FALSE;
2516 gboolean canCut = FALSE;
2517 gboolean canCopy = FALSE;
2518 gboolean canPaste = FALSE;
2519 gboolean canTreeCut = FALSE;
2520 gboolean canTreeCopy = FALSE;
2521 gboolean canTreePaste = FALSE;
2522 gboolean canLookup = FALSE;
2523 GtkCTreeNode *node = NULL;
2525 if( ! event ) return FALSE;
2526 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2528 if (event->button == 1) {
2529 if (event->type == GDK_2BUTTON_PRESS) {
2530 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2531 gtkut_clist_set_focus_row(clist, row);
2532 obj = gtk_clist_get_row_data( clist, row );
2537 if (obj->type == ADDR_ITEM_GROUP) {
2539 addressbook_treenode_edit_cb(NULL, NULL);
2541 /* expand pr collapse */
2542 node = gtk_ctree_node_nth(GTK_CTREE(ctree), row);
2543 gtk_ctree_toggle_expansion(GTK_CTREE(ctree), node);
2549 addressbook_menubar_set_sensitive( FALSE );
2551 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2552 gtkut_clist_set_focus_row(clist, row);
2553 obj = gtk_clist_get_row_data( clist, row );
2556 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2560 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2562 if( ! addrclip_is_empty( _clipBoard_ ) )
2563 canTreePaste = TRUE;
2565 if (obj->type == ADDR_INTERFACE) {
2566 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2569 iface = adapter->interface;
2572 if( !iface->readOnly ) {
2573 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2574 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2576 if( iface->externalQuery )
2579 if (obj->type == ADDR_DATASOURCE) {
2580 ads = ADAPTER_DSOURCE(obj);
2581 ds = ads->dataSource;
2584 iface = ds->interface;
2587 if( !iface->readOnly ) {
2589 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2590 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2591 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2595 if( iface->externalQuery )
2598 else if (obj->type == ADDR_ITEM_FOLDER) {
2599 ds = addressbook_find_datasource( node );
2602 iface = ds->interface;
2605 if( !iface->readOnly ) {
2609 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2610 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2611 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2615 if( iface->externalQuery ) {
2616 /* Enable deletion of LDAP folder */
2621 else if (obj->type == ADDR_ITEM_GROUP) {
2622 ds = addressbook_find_datasource( node );
2625 iface = ds->interface;
2628 if( ! iface->readOnly ) {
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2632 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2636 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2638 if( ! addrselect_test_empty( _addressSelect_ ) )
2640 if( ! addrclip_is_empty( _clipBoard_ ) )
2643 /* Forbid write changes when read-only */
2644 if( iface && iface->readOnly ) {
2646 canTreePaste = FALSE;
2654 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2655 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2656 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2657 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2658 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2660 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2661 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2662 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2663 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2664 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2666 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2667 addrbook.target_compose != NULL);
2669 if( event->button == 3 )
2670 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2671 event->button, event->time);
2676 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2677 GdkEventButton *event,
2680 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2684 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2686 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2687 AddressObject *obj = NULL;
2688 AddressDataSource *ds = NULL;
2689 AddressBookFile *abf = NULL;
2690 ItemFolder *parentFolder = NULL;
2691 ItemFolder *folder = NULL;
2693 if( ! addrbook.treeSelected ) return;
2694 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2695 if( obj == NULL ) return;
2696 ds = addressbook_find_datasource( addrbook.treeSelected );
2697 if( ds == NULL ) return;
2699 if( obj->type == ADDR_DATASOURCE ) {
2700 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2702 else if( obj->type == ADDR_ITEM_FOLDER ) {
2703 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2709 abf = ds->rawDataSource;
2710 if( abf == NULL ) return;
2711 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2714 nn = addressbook_node_add_folder(
2715 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2716 gtk_ctree_expand( ctree, addrbook.treeSelected );
2717 if( addrbook.treeSelected == addrbook.opened )
2718 addressbook_set_clist(obj, TRUE);
2722 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2724 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2725 AddressObject *obj = NULL;
2726 AddressDataSource *ds = NULL;
2727 AddressBookFile *abf = NULL;
2728 ItemFolder *parentFolder = NULL;
2729 ItemGroup *group = NULL;
2731 if( ! addrbook.treeSelected ) return;
2732 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2733 if( obj == NULL ) return;
2734 ds = addressbook_find_datasource( addrbook.treeSelected );
2735 if( ds == NULL ) return;
2737 if( obj->type == ADDR_DATASOURCE ) {
2738 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2740 else if( obj->type == ADDR_ITEM_FOLDER ) {
2741 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2747 abf = ds->rawDataSource;
2748 if( abf == NULL ) return;
2749 group = addressbook_edit_group( abf, parentFolder, NULL );
2752 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2753 gtk_ctree_expand( ctree, addrbook.treeSelected );
2754 if( addrbook.treeSelected == addrbook.opened )
2755 addressbook_set_clist(obj, TRUE);
2759 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2761 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2764 GdkPixmap *pix_cl, *pix_op;
2765 GdkBitmap *mask_cl, *mask_op;
2766 gboolean is_leaf, expanded;
2768 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2769 &pix_cl, &mask_cl, &pix_op, &mask_op,
2770 &is_leaf, &expanded);
2771 gtk_sctree_set_node_info(ctree, node, name, spacing,
2772 pix_cl, mask_cl, pix_op, mask_op,
2778 * \param obj Address object to edit.
2779 * \param node Node in tree.
2780 * \return New name of data source.
2782 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2783 gchar *newName = NULL;
2784 AddressDataSource *ds = NULL;
2785 AddressInterface *iface = NULL;
2786 AdapterDSource *ads = NULL;
2788 ds = addressbook_find_datasource( node );
2789 if( ds == NULL ) return NULL;
2790 iface = ds->interface;
2791 if( ! iface->haveLibrary ) return NULL;
2793 /* Read data from data source */
2794 if( addrindex_ds_get_modify_flag( ds ) ) {
2795 addrindex_ds_read_data( ds );
2798 if( ! addrindex_ds_get_read_flag( ds ) ) {
2799 addrindex_ds_read_data( ds );
2803 ads = ADAPTER_DSOURCE(obj);
2804 if( ads->subType == ADDR_BOOK ) {
2805 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2807 else if( ads->subType == ADDR_VCARD ) {
2808 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2811 else if( ads->subType == ADDR_JPILOT ) {
2812 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2816 else if( ads->subType == ADDR_LDAP ) {
2817 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2823 newName = obj->name;
2828 * Edit an object that is in the address tree area.
2830 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2832 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2834 AddressDataSource *ds = NULL;
2835 AddressBookFile *abf = NULL;
2836 GtkCTreeNode *node = NULL, *parentNode = NULL;
2839 if( ! addrbook.treeSelected ) return;
2840 node = addrbook.treeSelected;
2841 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2842 obj = gtk_ctree_node_get_row_data( ctree, node );
2843 if( obj == NULL ) return;
2844 parentNode = GTK_CTREE_ROW(node)->parent;
2846 ds = addressbook_find_datasource( node );
2847 if( ds == NULL ) return;
2849 if( obj->type == ADDR_DATASOURCE ) {
2850 name = addressbook_edit_datasource( obj, node );
2851 if( name == NULL ) return;
2854 abf = ds->rawDataSource;
2855 if( abf == NULL ) return;
2856 if( obj->type == ADDR_ITEM_FOLDER ) {
2857 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2858 ItemFolder *item = adapter->itemFolder;
2859 ItemFolder *parentFolder = NULL;
2860 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2861 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2862 name = ADDRITEM_NAME(item);
2864 else if( obj->type == ADDR_ITEM_GROUP ) {
2865 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2866 ItemGroup *item = adapter->itemGroup;
2867 ItemFolder *parentFolder = NULL;
2868 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2869 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2870 name = ADDRITEM_NAME(item);
2873 if( name && parentNode ) {
2874 /* Update node in tree view */
2875 addressbook_change_node_name( node, name );
2876 gtk_sctree_sort_node(ctree, parentNode);
2877 gtk_ctree_expand( ctree, node );
2878 gtk_sctree_select( GTK_SCTREE( ctree), node );
2885 ADDRTREE_DEL_FOLDER_ONLY,
2886 ADDRTREE_DEL_FOLDER_ADDR
2890 * Delete an item from the tree widget.
2891 * \param data Data passed in.
2892 * \param action Action.
2893 * \param widget Widget issuing callback.
2895 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2897 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2898 GtkCTreeNode *node = NULL;
2902 AddrBookBase *adbase;
2903 AddressCache *cache;
2904 AdapterDSource *ads = NULL;
2905 AddressInterface *iface = NULL;
2906 AddressDataSource *ds = NULL;
2907 gboolean remFlag = FALSE;
2908 TreeItemDelType delType;
2910 if( ! addrbook.treeSelected ) return;
2911 node = addrbook.treeSelected;
2912 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2914 obj = gtk_ctree_node_get_row_data( ctree, node );
2915 g_return_if_fail(obj != NULL);
2917 if( obj->type == ADDR_DATASOURCE ) {
2918 ads = ADAPTER_DSOURCE(obj);
2919 if( ads == NULL ) return;
2920 ds = ads->dataSource;
2921 if( ds == NULL ) return;
2924 /* Must be folder or something else */
2925 ds = addressbook_find_datasource( node );
2926 if( ds == NULL ) return;
2928 /* Only allow deletion from non-readOnly */
2929 iface = ds->interface;
2930 if( iface->readOnly ) {
2931 /* Allow deletion of query results */
2932 if( ! iface->externalQuery ) return;
2936 /* Confirm deletion */
2937 delType = ADDRTREE_DEL_NONE;
2938 if( obj->type == ADDR_ITEM_FOLDER ) {
2939 if( iface->externalQuery ) {
2940 message = g_strdup_printf( _(
2941 "Do you want to delete the query " \
2942 "results and addresses in '%s' ?" ),
2944 aval = alertpanel( _("Delete"), message,
2945 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2947 if( aval == G_ALERTALTERNATE ) {
2948 delType = ADDRTREE_DEL_FOLDER_ADDR;
2952 message = g_strdup_printf
2953 ( _( "Do you want to delete '%s' ? "
2954 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2956 aval = alertpanel( _("Delete folder"), message,
2957 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2959 if( aval == G_ALERTALTERNATE ) {
2960 delType = ADDRTREE_DEL_FOLDER_ONLY;
2962 else if( aval == G_ALERTOTHER ) {
2963 delType = ADDRTREE_DEL_FOLDER_ADDR;
2967 else if( obj->type == ADDR_ITEM_GROUP ) {
2968 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2969 "The addresses it contains will not be lost."), obj->name);
2970 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2971 "+" GTK_STOCK_DELETE, NULL);
2973 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2975 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2976 "The addresses it contains will be lost."), obj->name);
2977 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2978 "+" GTK_STOCK_DELETE, NULL);
2980 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2982 if( delType == ADDRTREE_DEL_NONE ) return;
2984 /* Proceed with deletion */
2985 if( obj->type == ADDR_DATASOURCE ) {
2986 /* Remove node from tree */
2987 gtk_ctree_remove_node( ctree, node );
2989 /* Remove data source. */
2990 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2991 addrindex_free_datasource( ds );
2996 /* Get reference to cache */
2997 adbase = ( AddrBookBase * ) ds->rawDataSource;
2998 if( adbase == NULL ) return;
2999 cache = adbase->addressCache;
3001 /* Remove query results folder */
3002 if( iface->externalQuery ) {
3003 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3004 ItemFolder *folder = adapter->itemFolder;
3006 adapter->itemFolder = NULL;
3008 g_print( "remove folder for ::%s::\n", obj->name );
3009 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3010 g_print( "-------------- remove results\n" );
3012 addrindex_remove_results( ds, folder );
3013 /* g_print( "-------------- remove node\n" ); */
3014 gtk_ctree_remove_node( ctree, node );
3018 /* Code below is valid for regular address book deletion */
3019 if( obj->type == ADDR_ITEM_FOLDER ) {
3020 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3021 ItemFolder *item = adapter->itemFolder;
3023 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3024 /* Remove folder only */
3025 item = addrcache_remove_folder( cache, item );
3027 addritem_free_item_folder( item );
3028 addressbook_move_nodes_up( ctree, node );
3032 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3033 /* Remove folder and addresses */
3034 item = addrcache_remove_folder_delete( cache, item );
3036 addritem_free_item_folder( item );
3041 else if( obj->type == ADDR_ITEM_GROUP ) {
3042 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3043 ItemGroup *item = adapter->itemGroup;
3045 item = addrcache_remove_group( cache, item );
3047 addritem_free_item_group( item );
3054 gtk_ctree_remove_node(ctree, node );
3058 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3060 if( person && addrbook.treeSelected == addrbook.opened ) {
3061 person->status = ADD_ENTRY;
3062 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
3063 addressbook_folder_refresh_one_person(
3064 GTK_CTREE(addrbook.clist), person );
3066 addressbook_address_list_set_focus();
3069 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3071 if( person && addrbook.treeSelected == addrbook.opened) {
3072 person->status = ADD_ENTRY;
3073 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3074 addressbook_set_clist(
3075 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3079 addressbook_address_list_set_focus();
3083 * Label (a format string) that is used to name each folder.
3085 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3088 * Search ctree widget callback function.
3089 * \param pA Pointer to node.
3090 * \param pB Pointer to data item being sought.
3091 * \return Zero (0) if folder found.
3093 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3096 aoA = ( AddressObject * ) pA;
3097 if( aoA->type == ADDR_ITEM_FOLDER ) {
3098 ItemFolder *folder, *fld;
3100 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3101 folder = ( ItemFolder * ) pB;
3102 if( fld == folder ) return 0; /* Found folder */
3107 static ItemFolder * addressbook_setup_subf(
3108 AddressDataSource *ds, gchar *title,
3109 GtkCTreeNode *pNode )
3111 AddrBookBase *adbase;
3112 AddressCache *cache;
3115 GtkCTreeNode *nNode;
3117 AddressObjectType aoType = ADDR_NONE;
3120 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3122 if( ds && ds->type == ADDR_IF_LDAP ) {
3124 aoType = ADDR_LDAP_QUERY;
3131 ctree = GTK_CTREE(addrbook.ctree);
3132 /* Get reference to address cache */
3133 adbase = ( AddrBookBase * ) ds->rawDataSource;
3134 cache = adbase->addressCache;
3136 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3137 GList *cur = children;
3138 for (; cur; cur = cur->next) {
3139 ItemFolder *child = (ItemFolder *) cur->data;
3140 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3141 nNode = gtk_ctree_find_by_row_data_custom(
3143 addressbook_treenode_find_folder_cb );
3145 addrindex_remove_results( ds, child );
3146 while( child->listPerson ) {
3147 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3148 item = addrcache_remove_person( cache, item );
3150 addritem_free_item_person( item );
3154 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3155 addrbook.treeSelected = nNode;
3162 /* Create a folder */
3163 folder = addrcache_add_new_folder( cache, NULL );
3164 name = g_strdup_printf( "%s", title );
3165 addritem_folder_set_name( folder, name );
3166 addritem_folder_set_remarks( folder, "" );
3169 /* Now let's see the folder */
3170 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3171 gtk_ctree_expand( ctree, pNode );
3173 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3174 addrbook.treeSelected = nNode;
3180 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3181 AddressObject *pobj = NULL;
3182 AddressDataSource *ds = NULL;
3183 AddressBookFile *abf = NULL;
3184 debug_print("adding address\n");
3185 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3186 if( pobj == NULL ) {
3187 debug_print("no row data\n");
3190 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3192 debug_print("no datasource\n");
3196 abf = ds->rawDataSource;
3198 g_print("no addressbook file\n");
3202 if( pobj->type == ADDR_DATASOURCE ) {
3203 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3204 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3206 ItemFolder *folder = NULL;
3208 if (abf && abf->type == ADDR_IF_LDAP) {
3209 GtkCTreeNode *parentNode;
3210 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3211 if( ds == NULL ) return;
3213 /* We must have a datasource that is an external interface */
3214 if( ! ds->interface->haveLibrary ) return;
3215 if( ! ds->interface->externalQuery ) return;
3217 if( pobj->type == ADDR_ITEM_FOLDER ) {
3218 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3221 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3223 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3225 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3226 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3227 abf = ds->rawDataSource;
3230 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3231 addrbook.editaddress_vbox,
3232 addressbook_new_address_from_book_post_cb,
3235 if (abf && abf->type == ADDR_IF_LDAP) {
3236 LdapServer *server = ds->rawDataSource;
3237 ldapsvr_set_modified(server, TRUE);
3238 ldapsvr_update_book(server, NULL);
3239 if (server->retVal != LDAPRC_SUCCESS) {
3240 alertpanel( _("Add address(es)"),
3241 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3242 GTK_STOCK_CLOSE, NULL, NULL );
3243 server->retVal = LDAPRC_SUCCESS;
3248 if (prefs_common.addressbook_use_editaddress_dialog)
3249 addressbook_new_address_from_book_post_cb( person );
3252 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3254 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3257 if (abf && abf->type == ADDR_IF_LDAP) {
3258 GtkCTreeNode *parentNode;
3259 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3260 if( ds == NULL ) return;
3262 /* We must have a datasource that is an external interface */
3263 if( ! ds->interface->haveLibrary ) return;
3264 if( ! ds->interface->externalQuery ) return;
3266 if( pobj->type == ADDR_ITEM_FOLDER ) {
3267 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3270 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3272 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3275 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3276 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3277 abf = ds->rawDataSource;
3280 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3281 addrbook.editaddress_vbox,
3282 addressbook_new_address_from_folder_post_cb,
3285 if (abf && abf->type == ADDR_IF_LDAP) {
3286 LdapServer *server = ds->rawDataSource;
3287 ldapsvr_set_modified(server, TRUE);
3288 ldapsvr_update_book(server, NULL);
3289 if (server->retVal != LDAPRC_SUCCESS) {
3290 alertpanel( _("Add address(es)"),
3291 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3292 GTK_STOCK_CLOSE, NULL, NULL );
3297 if (prefs_common.addressbook_use_editaddress_dialog)
3298 addressbook_new_address_from_folder_post_cb( person );
3300 else if( pobj->type == ADDR_ITEM_GROUP ) {
3301 /* New address in group */
3302 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3303 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3304 if (addrbook.treeSelected == addrbook.opened) {
3305 /* Change node name in tree. */
3306 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3307 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3308 addressbook_set_clist(
3309 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3317 * Search for specified child group node in address index tree.
3318 * \param parent Parent node.
3319 * \param group Group to find.
3321 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3322 GtkCTreeNode *node = NULL;
3323 GtkCTreeRow *currRow;
3325 currRow = GTK_CTREE_ROW( parent );
3327 node = currRow->children;
3331 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3332 if( obj->type == ADDR_ITEM_GROUP ) {
3333 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3334 if( g == group ) return node;
3336 currRow = GTK_CTREE_ROW(node);
3337 node = currRow->sibling;
3343 static AddressBookFile *addressbook_get_book_file() {
3344 AddressBookFile *abf = NULL;
3345 AddressDataSource *ds = NULL;
3347 ds = addressbook_find_datasource( addrbook.treeSelected );
3348 if( ds == NULL ) return NULL;
3349 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3353 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3357 /* Remove existing folders and groups */
3358 row = GTK_CTREE_ROW( parent );
3360 while( (node = row->children) ) {
3361 gtk_ctree_remove_node( ctree, node );
3366 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3367 GtkCTreeNode *parent, *child;
3368 GtkCTreeRow *currRow;
3369 currRow = GTK_CTREE_ROW( node );
3371 parent = currRow->parent;
3372 while( (child = currRow->children) ) {
3373 gtk_ctree_move( ctree, child, parent, node );
3375 gtk_sctree_sort_node( ctree, parent );
3379 static void addressbook_edit_address_post_cb( ItemPerson *person )
3383 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3384 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3386 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3387 invalidate_address_completion();
3389 addressbook_address_list_set_focus();
3392 void addressbook_address_list_set_focus( void )
3394 if (!prefs_common.addressbook_use_editaddress_dialog) {
3395 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3396 addressbook_list_menu_setup();
3400 void addressbook_address_list_disable_some_actions(void)
3402 /* disable address copy/pasting when editing contact's detail (embedded form) */
3403 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3404 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3405 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3408 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3409 addressbook_edit_address(data, 0, NULL, TRUE);
3412 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3413 gboolean force_focus ) {
3414 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3416 AddressObject *obj = NULL, *pobj = NULL;
3417 AddressDataSource *ds = NULL;
3418 GtkCTreeNode *node = NULL, *parentNode = NULL;
3420 AddressBookFile *abf = NULL;
3422 if( addrbook.listSelected == NULL ) return;
3423 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3424 g_return_if_fail(obj != NULL);
3426 ctree = GTK_CTREE( addrbook.ctree );
3427 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3428 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3430 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3431 if( ds == NULL ) return;
3433 abf = addressbook_get_book_file();
3435 if( obj->type == ADDR_ITEM_EMAIL ) {
3436 ItemEMail *email = ( ItemEMail * ) obj;
3437 if( email == NULL ) return;
3438 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3439 /* Edit parent group */
3440 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3441 ItemGroup *itemGrp = adapter->itemGroup;
3442 if( abf == NULL ) return;
3443 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3444 name = ADDRITEM_NAME(itemGrp);
3445 node = addrbook.treeSelected;
3446 parentNode = GTK_CTREE_ROW(node)->parent;
3449 /* Edit person - email page */
3451 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3452 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3453 addressbook_edit_address_post_cb,
3454 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3457 if (abf && abf->type == ADDR_IF_LDAP) {
3458 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3459 person->status = UPDATE_ENTRY;
3462 if (prefs_common.addressbook_use_editaddress_dialog)
3463 addressbook_edit_address_post_cb( person );
3468 else if( obj->type == ADDR_ITEM_PERSON ) {
3469 /* Edit person - basic page */
3470 ItemPerson *person = ( ItemPerson * ) obj;
3471 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3472 addressbook_edit_address_post_cb,
3473 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3476 if (abf && abf->type == ADDR_IF_LDAP) {
3477 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3478 person->status = UPDATE_ENTRY;
3481 if (prefs_common.addressbook_use_editaddress_dialog)
3482 addressbook_edit_address_post_cb( person );
3486 else if( obj->type == ADDR_ITEM_GROUP ) {
3487 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3488 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3489 parentNode = addrbook.treeSelected;
3490 node = addressbook_find_group_node( parentNode, itemGrp );
3491 name = ADDRITEM_NAME(itemGrp);
3492 invalidate_address_completion();
3498 /* Update tree node with node name */
3499 if( node == NULL ) return;
3500 addressbook_change_node_name( node, name );
3501 gtk_sctree_sort_node( ctree, parentNode );
3502 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3503 addressbook_set_clist(
3504 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3509 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3511 addressbook_del_clicked(NULL, NULL);
3514 static void close_cb(GtkAction *action, gpointer data)
3516 addressbook_close();
3519 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3520 addressbook_export_to_file();
3523 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3525 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3526 if( person ) addritem_person_set_opened( person, TRUE );
3530 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3532 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3533 if( person ) addritem_person_set_opened( person, FALSE );
3537 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3539 gchar *eMailAlias = ADDRITEM_NAME(email);
3540 if( eMailAlias && *eMailAlias != '\0' ) {
3542 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3545 str = g_strdup( eMailAlias );
3551 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3552 GList *items = itemGroup->listEMail;
3553 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3554 for( ; items != NULL; items = g_list_next( items ) ) {
3555 GtkCTreeNode *nodeEMail = NULL;
3556 gchar *text[N_LIST_COLS];
3557 ItemEMail *email = items->data;
3561 if( ! email ) continue;
3563 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3564 str = addressbook_format_item_clist( person, email );
3566 text[COL_NAME] = addressbook_set_col_name_guard(str);
3569 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3571 text[COL_ADDRESS] = email->address;
3572 text[COL_REMARKS] = email->remarks;
3573 nodeEMail = gtk_sctree_insert_node(
3575 text, FOLDER_SPACING,
3576 atci->iconXpm, atci->maskXpm,
3577 atci->iconXpmOpen, atci->maskXpmOpen,
3579 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3585 gchar *addressbook_set_col_name_guard(gchar *value)
3587 gchar *ret = "<not set>";
3588 gchar *tmp = g_strdup(value);
3590 if (tmp !=NULL && *tmp != '\0')
3596 static void addressbook_folder_load_one_person(
3597 GtkCTree *clist, ItemPerson *person,
3598 AddressTypeControlItem *atci,
3599 AddressTypeControlItem *atciMail )
3601 GtkCTreeNode *nodePerson = NULL;
3602 GtkCTreeNode *nodeEMail = NULL;
3603 gchar *text[N_LIST_COLS];
3604 gboolean flgFirst = TRUE, haveAddr = FALSE;
3607 AddressBookFile *abf = addressbook_get_book_file();
3610 if( person == NULL ) return;
3612 text[COL_NAME] = "";
3613 node = person->listEMail;
3615 ItemEMail *email = node->data;
3616 gchar *eMailAddr = NULL;
3617 node = g_list_next( node );
3619 text[COL_ADDRESS] = email->address;
3620 text[COL_REMARKS] = email->remarks;
3621 eMailAddr = ADDRITEM_NAME(email);
3622 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3624 /* First email belongs with person */
3625 gchar *str = addressbook_format_item_clist( person, email );
3627 text[COL_NAME] = addressbook_set_col_name_guard(str);
3630 else if( abf && abf->type == ADDR_IF_LDAP &&
3631 person && person->nickName ) {
3632 if (person->nickName) {
3633 if (strcmp(person->nickName, "") != 0) {
3634 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3637 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3643 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3645 nodePerson = gtk_sctree_insert_node(
3647 text, FOLDER_SPACING,
3648 atci->iconXpm, atci->maskXpm,
3649 atci->iconXpmOpen, atci->maskXpmOpen,
3650 FALSE, person->isOpened );
3653 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3656 /* Subsequent email is a child node of person */
3657 text[COL_NAME] = ADDRITEM_NAME(email);
3658 nodeEMail = gtk_sctree_insert_node(
3659 clist, nodePerson, NULL,
3660 text, FOLDER_SPACING,
3661 atciMail->iconXpm, atciMail->maskXpm,
3662 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3664 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3670 /* Have name without EMail */
3671 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3672 text[COL_ADDRESS] = "";
3673 text[COL_REMARKS] = "";
3674 nodePerson = gtk_sctree_insert_node(
3676 text, FOLDER_SPACING,
3677 atci->iconXpm, atci->maskXpm,
3678 atci->iconXpmOpen, atci->maskXpmOpen,
3679 FALSE, person->isOpened );
3680 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3685 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3687 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3688 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3690 if( atci == NULL ) return;
3691 if( atciMail == NULL ) return;
3693 /* Load email addresses */
3694 items = addritem_folder_get_person_list( itemFolder );
3695 for( ; items != NULL; items = g_list_next( items ) ) {
3696 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3698 /* Free up the list */
3699 mgu_clear_list( items );
3700 g_list_free( items );
3703 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3704 addrbook.listSelected = NULL;
3705 gtk_ctree_remove_node( clist, node );
3706 addressbook_menubar_set_sensitive( FALSE );
3707 addressbook_menuitem_set_sensitive(
3708 gtk_ctree_node_get_row_data(
3709 GTK_CTREE(clist), addrbook.treeSelected ),
3710 addrbook.treeSelected );
3713 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3714 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3715 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3717 if( atci == NULL ) return;
3718 if( atciMail == NULL ) return;
3719 if( person == NULL ) return;
3720 /* unload the person */
3722 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3724 addressbook_folder_remove_node( clist, node );
3725 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3726 gtk_sctree_sort_node( clist, NULL );
3727 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3729 gtk_sctree_select( GTK_SCTREE(clist), node );
3730 if (!gtk_ctree_node_is_visible( clist, node ) )
3731 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3735 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3739 if( person == NULL ) return;
3740 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3741 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3743 addressbook_folder_remove_node( clist, node );
3747 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3749 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3751 /* Load any groups */
3752 if( ! atci ) return;
3753 items = addritem_folder_get_group_list( itemFolder );
3754 for( ; items != NULL; items = g_list_next( items ) ) {
3755 GtkCTreeNode *nodeGroup = NULL;
3756 gchar *text[N_LIST_COLS];
3757 ItemGroup *group = items->data;
3758 if( group == NULL ) continue;
3759 text[COL_NAME] = ADDRITEM_NAME(group);
3760 text[COL_ADDRESS] = "";
3761 text[COL_REMARKS] = "";
3762 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3763 text, FOLDER_SPACING,
3764 atci->iconXpm, atci->maskXpm,
3765 atci->iconXpmOpen, atci->maskXpmOpen,
3767 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3768 gtk_sctree_sort_node(clist, NULL);
3770 /* Free up the list */
3771 mgu_clear_list( items );
3772 g_list_free( items );
3776 * Search ctree widget callback function.
3777 * \param pA Pointer to node.
3778 * \param pB Pointer to data item being sought.
3779 * \return Zero (0) if group found.
3781 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3784 aoA = ( AddressObject * ) pA;
3785 if( aoA->type == ADDR_ITEM_GROUP ) {
3786 ItemGroup *group, *grp;
3788 grp = ADAPTER_GROUP(aoA)->itemGroup;
3789 group = ( ItemGroup * ) pB;
3790 if( grp == group ) return 0; /* Found group */
3796 * Remove folder and group nodes from tree widget for items contained ("cut")
3799 static void addressbook_treenode_remove_item( void ) {
3801 AddrSelectItem *cutItem;
3802 AddressCache *cache;
3803 AddrItemObject *aio;
3804 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3807 node = _clipBoard_->objectList;
3809 cutItem = node->data;
3810 node = g_list_next( node );
3811 cache = addrindex_get_cache(
3812 _clipBoard_->addressIndex, cutItem->cacheID );
3813 if( cache == NULL ) continue;
3814 aio = addrcache_get_object( cache, cutItem->uid );
3817 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3820 folder = ( ItemFolder * ) aio;
3821 tn = gtk_ctree_find_by_row_data_custom(
3822 ctree, NULL, folder,
3823 addressbook_treenode_find_folder_cb );
3825 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3828 group = ( ItemGroup * ) aio;
3829 tn = gtk_ctree_find_by_row_data_custom(
3831 addressbook_treenode_find_group_cb );
3835 /* Free up adapter and remove node. */
3836 gtk_ctree_remove_node( ctree, tn );
3843 * Find parent datasource for specified tree node.
3844 * \param node Node to test.
3845 * \return Data source, or NULL if not found.
3847 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3848 AddressDataSource *ds = NULL;
3851 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3854 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3855 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3857 /* g_print( "ao->type = %d\n", ao->type ); */
3858 if( ao->type == ADDR_DATASOURCE ) {
3859 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3860 /* g_print( "found it\n" ); */
3861 ds = ads->dataSource;
3865 node = GTK_CTREE_ROW(node)->parent;
3871 * Load address list widget with children of specified object.
3872 * \param obj Parent object to be loaded.
3874 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3875 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3876 GtkCList *clist = GTK_CLIST(addrbook.clist);
3877 AddressDataSource *ds = NULL;
3878 AdapterDSource *ads = NULL;
3879 static AddressObject *last_obj = NULL;
3881 if (addrbook.clist == NULL) {
3884 if (obj == last_obj && !refresh)
3889 gtk_clist_clear(clist);
3893 if( obj->type == ADDR_INTERFACE ) {
3894 /* g_print( "set_clist: loading datasource...\n" ); */
3895 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3899 gtk_clist_freeze(clist);
3900 gtk_clist_clear(clist);
3902 if( obj->type == ADDR_DATASOURCE ) {
3903 ads = ADAPTER_DSOURCE(obj);
3904 ds = ADAPTER_DSOURCE(obj)->dataSource;
3906 /* Load root folder */
3907 ItemFolder *rootFolder = NULL;
3908 rootFolder = addrindex_ds_get_root_folder( ds );
3909 addressbook_folder_load_person(
3910 ctreelist, addrindex_ds_get_root_folder( ds ) );
3911 addressbook_folder_load_group(
3912 ctreelist, addrindex_ds_get_root_folder( ds ) );
3916 if( obj->type == ADDR_ITEM_GROUP ) {
3918 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3919 addressbook_load_group( ctreelist, itemGroup );
3921 else if( obj->type == ADDR_ITEM_FOLDER ) {
3923 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3924 addressbook_folder_load_person( ctreelist, itemFolder );
3925 addressbook_folder_load_group( ctreelist, itemFolder );
3928 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3929 clist->focus_row = -1;
3930 gtk_clist_thaw(clist);
3934 * Call back function to free adaptor. Call back is setup by function
3935 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3936 * called when the address book tree widget node is removed by calling
3937 * function gtk_ctree_remove_node().
3939 * \param data Tree node's row data.
3941 static void addressbook_free_treenode( gpointer data ) {
3944 ao = ( AddressObject * ) data;
3945 if( ao == NULL ) return;
3946 if( ao->type == ADDR_INTERFACE ) {
3947 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3948 addrbookctl_free_interface( ai );
3950 else if( ao->type == ADDR_DATASOURCE ) {
3951 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3952 addrbookctl_free_datasource( ads );
3954 else if( ao->type == ADDR_ITEM_FOLDER ) {
3955 AdapterFolder *af = ADAPTER_FOLDER(ao);
3956 addrbookctl_free_folder( af );
3958 else if( ao->type == ADDR_ITEM_GROUP ) {
3959 AdapterGroup *ag = ADAPTER_GROUP(ao);
3960 addrbookctl_free_group( ag );
3965 * Create new adaptor for specified data source.
3967 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3968 AddressObjectType otype, gchar *name )
3970 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3971 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3972 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3973 adapter->dataSource = ds;
3974 adapter->subType = otype;
3978 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3979 ADDRESS_OBJECT_NAME(adapter) =
3980 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3984 * Load tree from address index with the initial data.
3986 static void addressbook_load_tree( void ) {
3987 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3988 GList *nodeIf, *nodeDS;
3989 AdapterInterface *adapter;
3990 AddressInterface *iface;
3991 AddressTypeControlItem *atci;
3992 AddressDataSource *ds;
3993 AdapterDSource *ads;
3994 GtkCTreeNode *node, *newNode;
3997 nodeIf = _addressInterfaceList_;
3999 adapter = nodeIf->data;
4000 node = adapter->treeNode;
4001 iface = adapter->interface;
4002 atci = adapter->atci;
4004 if( iface->useInterface ) {
4005 /* Load data sources below interface node */
4006 nodeDS = iface->listSource;
4010 name = addrindex_ds_get_name( ds );
4011 ads = addressbook_create_ds_adapter(
4012 ds, atci->objectType, name );
4013 newNode = addressbook_add_object(
4014 node, ADDRESS_OBJECT(ads) );
4015 nodeDS = g_list_next( nodeDS );
4017 gtk_ctree_expand( ctree, node );
4020 nodeIf = g_list_next( nodeIf );
4025 * Convert the old address book to new format.
4027 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4028 gboolean retVal = FALSE;
4029 gboolean errFlag = TRUE;
4032 /* Read old address book, performing conversion */
4033 debug_print( "Reading and converting old address book...\n" );
4034 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4035 addrindex_read_data( addrIndex );
4036 if( addrIndex->retVal == MGU_NO_FILE ) {
4037 /* We do not have a file - new user */
4038 debug_print( "New user... create new books...\n" );
4039 addrindex_create_new_books( addrIndex );
4040 if( addrIndex->retVal == MGU_SUCCESS ) {
4041 /* Save index file */
4042 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4043 addrindex_save_data( addrIndex );
4044 if( addrIndex->retVal == MGU_SUCCESS ) {
4049 msg = _( "New user, could not save index file." );
4053 msg = _( "New user, could not save address book files." );
4057 /* We have an old file */
4058 if( addrIndex->wasConverted ) {
4059 /* Converted successfully - save address index */
4060 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4061 addrindex_save_data( addrIndex );
4062 if( addrIndex->retVal == MGU_SUCCESS ) {
4063 msg = _( "Old address book converted successfully." );
4068 msg = _("Old address book converted,\n"
4069 "could not save new address index file." );
4073 /* File conversion failed - just create new books */
4074 debug_print( "File conversion failed... just create new books...\n" );
4075 addrindex_create_new_books( addrIndex );
4076 if( addrIndex->retVal == MGU_SUCCESS ) {
4078 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4079 addrindex_save_data( addrIndex );
4080 if( addrIndex->retVal == MGU_SUCCESS ) {
4081 msg = _("Could not convert address book,\n"
4082 "but created empty new address book files." );
4087 msg = _("Could not convert address book,\n"
4088 "could not save new address index file." );
4092 msg = _("Could not convert address book\n"
4093 "and could not create new address book files." );
4098 debug_print( "Error\n%s\n", msg );
4099 alertpanel_full(_("Addressbook conversion error"), msg,
4100 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4101 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4104 debug_print( "Warning\n%s\n", msg );
4105 alertpanel_full(_("Addressbook conversion error"), msg,
4106 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4107 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4113 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4117 gboolean failed = FALSE;
4119 if( ( dp = opendir( origdir ) ) == NULL ) {
4123 while( ( d = readdir( dp ) ) != NULL ) {
4124 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4127 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4129 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4131 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4144 /* all copies succeeded, we can remove source files */
4145 if( ( dp = opendir( origdir ) ) == NULL ) {
4148 while( ( d = readdir( dp ) ) != NULL ) {
4149 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4152 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4154 claws_unlink(orig_file);
4164 void addressbook_read_file( void ) {
4165 AddressIndex *addrIndex = NULL;
4166 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4168 debug_print( "Reading address index...\n" );
4169 if( _addressIndex_ ) {
4170 debug_print( "address book already read!!!\n" );
4174 addrIndex = addrindex_create_index();
4175 addrindex_initialize();
4177 /* Use new address book index. */
4179 if ( !is_dir_exist(indexdir) ) {
4180 if ( make_dir(indexdir) < 0 ) {
4181 addrindex_set_file_path( addrIndex, get_rc_dir() );
4182 g_warning( "couldn't create dir %s\n", indexdir);
4184 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4185 remove_dir_recursive(indexdir);
4186 addrindex_set_file_path( addrIndex, get_rc_dir() );
4187 g_error("couldn't migrate dir %s", indexdir);
4189 addrindex_set_file_path( addrIndex, indexdir);
4193 addrindex_set_file_path( addrIndex, indexdir);
4196 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4197 addrindex_read_data( addrIndex );
4198 if( addrIndex->retVal == MGU_NO_FILE ) {
4199 /* Conversion required */
4200 debug_print( "Converting...\n" );
4201 if( addressbook_convert( addrIndex ) ) {
4202 _addressIndex_ = addrIndex;
4205 else if( addrIndex->retVal == MGU_SUCCESS ) {
4206 _addressIndex_ = addrIndex;
4209 /* Error reading address book */
4210 debug_print( "Could not read address index.\n" );
4211 addrindex_print_index( addrIndex, stdout );
4212 alertpanel_full(_("Addressbook Error"),
4213 _("Could not read address index"),
4214 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4215 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4217 debug_print( "done.\n" );
4221 * Add object into the address index tree widget.
4222 * Enter: node Parent node.
4223 * obj Object to add.
4224 * Return: Node that was added, or NULL if object not added.
4226 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
4229 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4230 GtkCTreeNode *added;
4231 AddressObject *pobj;
4232 AddressObjectType otype;
4233 AddressTypeControlItem *atci = NULL;
4235 g_return_val_if_fail(node != NULL, NULL);
4236 g_return_val_if_fail(obj != NULL, NULL);
4238 pobj = gtk_ctree_node_get_row_data(ctree, node);
4239 g_return_val_if_fail(pobj != NULL, NULL);
4241 /* Determine object type to be displayed */
4242 if( obj->type == ADDR_DATASOURCE ) {
4243 otype = ADAPTER_DSOURCE(obj)->subType;
4249 /* Handle any special conditions. */
4251 atci = addrbookctl_lookup( otype );
4253 if( atci->showInTree ) {
4254 /* Add object to tree */
4257 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4258 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4259 atci->treeLeaf, atci->treeExpand );
4260 gtk_ctree_node_set_row_data_full( ctree, added, obj,
4261 addressbook_free_treenode );
4265 gtk_sctree_sort_node(ctree, node);
4271 * Add group into the address index tree.
4272 * \param node Parent node.
4273 * \param ds Data source.
4274 * \param itemGroup Group to add.
4275 * \return Inserted node.
4277 static GtkCTreeNode *addressbook_node_add_group(
4278 GtkCTreeNode *node, AddressDataSource *ds,
4279 ItemGroup *itemGroup )
4281 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4282 GtkCTreeNode *newNode;
4283 AdapterGroup *adapter;
4284 AddressTypeControlItem *atci = NULL;
4287 if( ds == NULL ) return NULL;
4288 if( node == NULL || itemGroup == NULL ) return NULL;
4290 name = &itemGroup->obj.name;
4292 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4294 adapter = g_new0( AdapterGroup, 1 );
4295 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4296 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4297 adapter->itemGroup = itemGroup;
4299 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4300 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4301 atci->treeLeaf, atci->treeExpand );
4302 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4303 addressbook_free_treenode );
4304 gtk_sctree_sort_node( ctree, node );
4309 * Add folder into the address index tree. Only visible folders are loaded into
4310 * the address index tree. Note that the root folder is not inserted into the
4313 * \param node Parent node.
4314 * \param ds Data source.
4315 * \param itemFolder Folder to add.
4316 * \param otype Object type to display.
4317 * \return Inserted node for the folder.
4319 static GtkCTreeNode *addressbook_node_add_folder(
4320 GtkCTreeNode *node, AddressDataSource *ds,
4321 ItemFolder *itemFolder, AddressObjectType otype )
4323 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4324 GtkCTreeNode *newNode = NULL;
4325 AdapterFolder *adapter;
4326 AddressTypeControlItem *atci = NULL;
4327 GList *listItems = NULL;
4329 ItemFolder *rootFolder;
4331 /* Only visible folders */
4332 if( itemFolder->isHidden ) return NULL;
4334 if( ds == NULL ) return NULL;
4335 if( node == NULL || itemFolder == NULL ) return NULL;
4337 /* Determine object type */
4338 atci = addrbookctl_lookup( otype );
4339 if( atci == NULL ) return NULL;
4341 rootFolder = addrindex_ds_get_root_folder( ds );
4342 if( itemFolder == rootFolder ) {
4346 adapter = g_new0( AdapterFolder, 1 );
4347 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4348 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4349 adapter->itemFolder = itemFolder;
4351 name = ADDRITEM_NAME(itemFolder);
4352 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4353 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4354 atci->treeLeaf, atci->treeExpand );
4356 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4357 addressbook_free_treenode );
4361 listItems = itemFolder->listFolder;
4362 while( listItems ) {
4363 ItemFolder *item = listItems->data;
4364 addressbook_node_add_folder( newNode, ds, item, otype );
4365 listItems = g_list_next( listItems );
4367 listItems = itemFolder->listGroup;
4368 while( listItems ) {
4369 ItemGroup *item = listItems->data;
4370 addressbook_node_add_group( newNode, ds, item );
4371 listItems = g_list_next( listItems );
4373 gtk_sctree_sort_node( ctree, node );
4377 void addressbook_export_to_file( void ) {
4378 if( _addressIndex_ ) {
4379 /* Save all new address book data */
4380 debug_print( "Saving address books...\n" );
4381 addrindex_save_all_books( _addressIndex_ );
4383 debug_print( "Exporting addressbook to file...\n" );
4384 addrindex_save_data( _addressIndex_ );
4385 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4386 addrindex_print_index( _addressIndex_, stdout );
4389 /* Notify address completion of new data */
4390 invalidate_address_completion();
4394 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4396 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4397 addressbook_lup_clicked(NULL, NULL);
4402 * Comparison using cell contents (text in first column). Used for sort
4403 * address index widget.
4405 static gint addressbook_treenode_compare_func(
4406 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4408 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4409 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4410 gchar *name1 = NULL, *name2 = NULL;
4411 if( cell1 ) name1 = cell1->u.text;
4412 if( cell2 ) name2 = cell2->u.text;
4413 if( ! name1 ) return ( name2 != NULL );
4414 if( ! name2 ) return -1;
4415 return g_utf8_collate( name1, name2 );
4418 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4419 AdapterDSource *ads;
4420 AdapterInterface *adapter;
4421 GtkCTreeNode *newNode;
4423 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4424 if( adapter == NULL ) return;
4425 ads = addressbook_edit_book( _addressIndex_, NULL );
4427 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4429 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4430 addrbook.treeSelected = newNode;
4435 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4436 AdapterDSource *ads;
4437 AdapterInterface *adapter;
4438 GtkCTreeNode *newNode;
4440 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4441 if( adapter == NULL ) return;
4442 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4444 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4446 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4447 addrbook.treeSelected = newNode;
4453 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4454 AdapterDSource *ads;
4455 AdapterInterface *adapter;
4456 AddressInterface *iface;
4457 GtkCTreeNode *newNode;
4459 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4460 if( adapter == NULL ) return;
4461 iface = adapter->interface;
4462 if( ! iface->haveLibrary ) return;
4463 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4465 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4467 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4468 addrbook.treeSelected = newNode;
4475 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4476 AdapterDSource *ads;
4477 AdapterInterface *adapter;
4478 AddressInterface *iface;
4479 GtkCTreeNode *newNode;
4481 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4482 if( adapter == NULL ) return;
4483 iface = adapter->interface;
4484 if( ! iface->haveLibrary ) return;
4485 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4487 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4489 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4490 addrbook.treeSelected = newNode;
4497 * Display address search status message.
4498 * \param queryType Query type.
4499 * \param status Status/Error code.
4501 static void addressbook_search_message( gint queryType, gint sts ) {
4503 *addressbook_msgbuf = '\0';
4505 if( sts != MGU_SUCCESS ) {
4506 if( queryType == ADDRQUERY_LDAP ) {
4508 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4513 g_snprintf( addressbook_msgbuf,
4514 sizeof(addressbook_msgbuf), "%s", desc );
4515 addressbook_status_show( addressbook_msgbuf );
4518 addressbook_status_show( "" );
4523 * Refresh addressbook by forcing refresh of current selected object in
4526 static void addressbook_refresh_current( void ) {
4530 ctree = GTK_CTREE(addrbook.ctree);
4531 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4532 if( obj == NULL ) return;
4533 addressbook_set_clist( obj, TRUE );
4537 * Message that is displayed whilst a query is executing in a background
4540 static gchar *_tempMessage_ = N_( "Busy searching..." );
4543 * Address search idle function. This function is called during UI idle time
4544 * while a search is in progress.
4546 * \param data Idler data.
4548 static void addressbook_search_idle( gpointer data ) {
4552 queryID = GPOINTER_TO_INT( data );
4553 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4558 * Search completion callback function. This removes the query from the idle
4561 * \param sender Sender of query.
4562 * \param queryID Query ID of search request.
4563 * \param status Search status.
4564 * \param data Query data.
4566 static void addressbook_search_callback_end(
4567 gpointer sender, gint queryID, gint status, gpointer data )
4571 AddrQueryObject *aqo;
4573 /* Remove idler function */
4574 ptrQID = GINT_TO_POINTER( queryID );
4576 g_idle_remove_by_data( ptrQID );
4579 /* Refresh addressbook contents */
4580 addressbook_refresh_current();
4581 req = qrymgr_find_request( queryID );
4583 aqo = ( AddrQueryObject * ) req->queryList->data;
4584 addressbook_search_message( aqo->queryType, status );
4587 /* Stop the search */
4588 addrindex_stop_search( queryID );
4594 * \param ds Data source to search.
4595 * \param searchTerm String to lookup.
4596 * \param pNode Parent data source node.
4598 static void addressbook_perform_search(
4599 AddressDataSource *ds, gchar *searchTerm,
4600 GtkCTreeNode *pNode )
4602 AddrBookBase *adbase;
4603 AddressCache *cache;
4609 AddressObjectType aoType = ADDR_NONE;
4613 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4615 if( ds && ds->type == ADDR_IF_LDAP ) {
4617 aoType = ADDR_LDAP_QUERY;
4623 /* Get reference to address cache */
4624 adbase = ( AddrBookBase * ) ds->rawDataSource;
4625 cache = adbase->addressCache;
4627 /* Create a folder for the search results */
4628 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4629 folder = addressbook_setup_subf(ds, name, pNode);
4632 /* Setup the search */
4633 queryID = addrindex_setup_explicit_search(
4634 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4635 if( queryID == 0 ) return;
4637 /* Set up idler function */
4638 idleID = g_idle_add(
4639 ( GtkFunction ) addressbook_search_idle,
4640 GINT_TO_POINTER( queryID ) );
4642 /* Start search, sit back and wait for something to happen */
4643 addrindex_start_search( queryID );
4645 addressbook_status_show( _tempMessage_ );
4649 * Lookup button handler. Address search is only performed against
4650 * address interfaces for external queries.
4652 * \param button Lookup button widget.
4653 * \param data Data object.
4655 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4658 AddressDataSource *ds;
4659 AddressInterface *iface;
4661 GtkCTreeNode *node, *parentNode;
4663 node = addrbook.treeSelected;
4664 if( ! node ) return;
4665 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4667 ctree = GTK_CTREE(addrbook.ctree);
4668 obj = gtk_ctree_node_get_row_data( ctree, node );
4669 if( obj == NULL ) return;
4671 ds = addressbook_find_datasource( node );
4672 if( ds == NULL ) return;
4674 /* We must have a datasource that is an external interface */
4675 iface = ds->interface;
4676 if( ! iface->haveLibrary ) return;
4677 if( ! iface->externalQuery ) return;
4680 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4681 g_strchomp( searchTerm );
4683 if( obj->type == ADDR_ITEM_FOLDER ) {
4684 parentNode = GTK_CTREE_ROW(node)->parent;
4689 addressbook_perform_search( ds, searchTerm, parentNode );
4691 gtk_widget_grab_focus( addrbook.entry );
4693 g_free( searchTerm );
4696 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4697 addressbook_close();
4702 * Browse address entry for highlighted entry.
4704 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4706 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4708 AddressDataSource *ds;
4709 AddressInterface *iface;
4713 if(addrbook.listSelected == NULL)
4716 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4720 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4724 iface = ds->interface;
4725 if(! iface->haveLibrary )
4729 if (obj->type == ADDR_ITEM_EMAIL) {
4730 email = ( ItemEMail * ) obj;
4734 person = (ItemPerson *) ADDRITEM_PARENT(email);
4736 else if (obj->type == ADDR_ITEM_PERSON) {
4737 person = (ItemPerson *) obj;
4744 if( iface && iface->type == ADDR_IF_LDAP ) {
4745 browseldap_entry(ds, person->externalID);
4750 /* **********************************************************************
4751 * Build lookup tables.
4752 * ***********************************************************************
4756 * Remap object types.
4757 * Enter: abType AddressObjectType (used in tree node).
4758 * Return: ItemObjectType (used in address cache data).
4760 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4761 ItemObjectType ioType;
4764 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4765 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4766 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4767 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4768 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4769 default: ioType = ITEMTYPE_NONE; break;
4775 * Build table that controls the rendering of object types.
4777 static void addrbookctl_build_map( GtkWidget *window ) {
4778 AddressTypeControlItem *atci;
4781 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4782 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4783 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4784 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4785 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4786 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4787 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4788 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4789 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4790 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4792 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4793 _addressBookTypeList_ = NULL;
4796 atci = g_new0( AddressTypeControlItem, 1 );
4797 atci->objectType = ADDR_INTERFACE;
4798 atci->interfaceType = ADDR_IF_NONE;
4799 atci->showInTree = TRUE;
4800 atci->treeExpand = TRUE;
4801 atci->treeLeaf = FALSE;
4802 atci->displayName = _( "Interface" );
4803 atci->iconXpm = folderxpm;
4804 atci->maskXpm = folderxpmmask;
4805 atci->iconXpmOpen = folderopenxpm;
4806 atci->maskXpmOpen = folderopenxpmmask;
4807 atci->menuCommand = NULL;
4808 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4809 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4812 atci = g_new0( AddressTypeControlItem, 1 );
4813 atci->objectType = ADDR_BOOK;
4814 atci->interfaceType = ADDR_IF_BOOK;
4815 atci->showInTree = TRUE;
4816 atci->treeExpand = TRUE;
4817 atci->treeLeaf = FALSE;
4818 atci->displayName = _( "Address Book" );
4819 atci->iconXpm = bookxpm;
4820 atci->maskXpm = bookxpmmask;
4821 atci->iconXpmOpen = bookxpm;
4822 atci->maskXpmOpen = bookxpmmask;
4823 atci->menuCommand = "Menu/Book/NewBook";
4824 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4825 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4828 atci = g_new0( AddressTypeControlItem, 1 );
4829 atci->objectType = ADDR_ITEM_PERSON;
4830 atci->interfaceType = ADDR_IF_NONE;
4831 atci->showInTree = FALSE;
4832 atci->treeExpand = FALSE;
4833 atci->treeLeaf = FALSE;
4834 atci->displayName = _( "Person" );
4835 atci->iconXpm = NULL;
4836 atci->maskXpm = NULL;
4837 atci->iconXpmOpen = NULL;
4838 atci->maskXpmOpen = NULL;
4839 atci->menuCommand = NULL;
4840 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4841 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4844 atci = g_new0( AddressTypeControlItem, 1 );
4845 atci->objectType = ADDR_ITEM_EMAIL;
4846 atci->interfaceType = ADDR_IF_NONE;
4847 atci->showInTree = FALSE;
4848 atci->treeExpand = FALSE;
4849 atci->treeLeaf = TRUE;
4850 atci->displayName = _( "Email Address" );
4851 atci->iconXpm = addressxpm;
4852 atci->maskXpm = addressxpmmask;
4853 atci->iconXpmOpen = addressxpm;
4854 atci->maskXpmOpen = addressxpmmask;
4855 atci->menuCommand = NULL;
4856 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4857 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4860 atci = g_new0( AddressTypeControlItem, 1 );
4861 atci->objectType = ADDR_ITEM_GROUP;
4862 atci->interfaceType = ADDR_IF_BOOK;
4863 atci->showInTree = TRUE;
4864 atci->treeExpand = FALSE;
4865 atci->treeLeaf = FALSE;
4866 atci->displayName = _( "Group" );
4867 atci->iconXpm = groupxpm;
4868 atci->maskXpm = groupxpmmask;
4869 atci->iconXpmOpen = groupxpm;
4870 atci->maskXpmOpen = groupxpmmask;
4871 atci->menuCommand = NULL;
4872 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4873 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4876 atci = g_new0( AddressTypeControlItem, 1 );
4877 atci->objectType = ADDR_ITEM_FOLDER;
4878 atci->interfaceType = ADDR_IF_BOOK;
4879 atci->showInTree = TRUE;
4880 atci->treeExpand = FALSE;
4881 atci->treeLeaf = FALSE;
4882 atci->displayName = _( "Folder" );
4883 atci->iconXpm = folderxpm;
4884 atci->maskXpm = folderxpmmask;
4885 atci->iconXpmOpen = folderopenxpm;
4886 atci->maskXpmOpen = folderopenxpmmask;
4887 atci->menuCommand = NULL;
4888 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4889 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4892 atci = g_new0( AddressTypeControlItem, 1 );
4893 atci->objectType = ADDR_VCARD;
4894 atci->interfaceType = ADDR_IF_VCARD;
4895 atci->showInTree = TRUE;
4896 atci->treeExpand = TRUE;
4897 atci->treeLeaf = TRUE;
4898 atci->displayName = _( "vCard" );
4899 atci->iconXpm = vcardxpm;
4900 atci->maskXpm = vcardxpmmask;
4901 atci->iconXpmOpen = vcardxpm;
4902 atci->maskXpmOpen = vcardxpmmask;
4903 atci->menuCommand = "Menu/Book/NewVCard";
4904 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4905 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4908 atci = g_new0( AddressTypeControlItem, 1 );
4909 atci->objectType = ADDR_JPILOT;
4910 atci->interfaceType = ADDR_IF_JPILOT;
4911 atci->showInTree = TRUE;
4912 atci->treeExpand = TRUE;
4913 atci->treeLeaf = FALSE;
4914 atci->displayName = _( "JPilot" );
4915 atci->iconXpm = jpilotxpm;
4916 atci->maskXpm = jpilotxpmmask;
4917 atci->iconXpmOpen = jpilotxpm;
4918 atci->maskXpmOpen = jpilotxpmmask;
4919 atci->menuCommand = "Menu/Book/NewJPilot";
4920 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4921 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4924 atci = g_new0( AddressTypeControlItem, 1 );
4925 atci->objectType = ADDR_CATEGORY;
4926 atci->interfaceType = ADDR_IF_JPILOT;
4927 atci->showInTree = TRUE;
4928 atci->treeExpand = TRUE;
4929 atci->treeLeaf = TRUE;
4930 atci->displayName = _( "JPilot" );
4931 atci->iconXpm = categoryxpm;
4932 atci->maskXpm = categoryxpmmask;
4933 atci->iconXpmOpen = categoryxpm;
4934 atci->maskXpmOpen = categoryxpmmask;
4935 atci->menuCommand = NULL;
4936 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4937 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4940 atci = g_new0( AddressTypeControlItem, 1 );
4941 atci->objectType = ADDR_LDAP;
4942 atci->interfaceType = ADDR_IF_LDAP;
4943 atci->showInTree = TRUE;
4944 atci->treeExpand = TRUE;
4945 atci->treeLeaf = FALSE;
4946 atci->displayName = _( "LDAP servers" );
4947 atci->iconXpm = ldapxpm;
4948 atci->maskXpm = ldapxpmmask;
4949 atci->iconXpmOpen = ldapxpm;
4950 atci->maskXpmOpen = ldapxpmmask;
4951 atci->menuCommand = "Menu/Book/NewLDAPServer";
4952 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4953 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4956 atci = g_new0( AddressTypeControlItem, 1 );
4957 atci->objectType = ADDR_LDAP_QUERY;
4958 atci->interfaceType = ADDR_IF_LDAP;
4959 atci->showInTree = TRUE;
4960 atci->treeExpand = FALSE;
4961 atci->treeLeaf = TRUE;
4962 atci->displayName = _( "LDAP Query" );
4963 atci->iconXpm = addrsearchxpm;
4964 atci->maskXpm = addrsearchxpmmask;
4965 atci->iconXpmOpen = addrsearchxpm;
4966 atci->maskXpmOpen = addrsearchxpmmask;
4967 atci->menuCommand = NULL;
4968 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4969 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4974 * Search for specified object type.
4976 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4978 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4982 * Search for specified interface type.
4984 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4985 GList *node = _addressBookTypeList_;
4987 AddressTypeControlItem *atci = node->data;
4988 if( atci->interfaceType == ifType ) return atci;
4989 node = g_list_next( node );
4994 static void addrbookctl_free_address( AddressObject *obj ) {
4995 g_free( obj->name );
4996 obj->type = ADDR_NONE;
5000 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5001 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5002 adapter->interface = NULL;
5003 adapter->interfaceType = ADDR_IF_NONE;
5004 adapter->atci = NULL;
5005 adapter->enabled = FALSE;
5006 adapter->haveLibrary = FALSE;
5007 adapter->treeNode = NULL;
5011 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5012 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5013 adapter->dataSource = NULL;
5014 adapter->subType = ADDR_NONE;
5018 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5019 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5020 adapter->itemFolder = NULL;
5024 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5025 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5026 adapter->itemGroup = NULL;
5031 * Build GUI interface list.
5033 static void addrbookctl_build_iflist( void ) {
5034 AddressTypeControlItem *atci;
5035 AdapterInterface *adapter;
5038 if( _addressIndex_ == NULL ) {
5039 _addressIndex_ = addrindex_create_index();
5040 if( _clipBoard_ == NULL ) {
5041 _clipBoard_ = addrclip_create();
5043 addrclip_set_index( _clipBoard_, _addressIndex_ );
5045 _addressInterfaceList_ = NULL;
5046 list = addrindex_get_interface_list( _addressIndex_ );
5048 AddressInterface *interface = list->data;
5049 atci = addrbookctl_lookup_iface( interface->type );
5051 adapter = g_new0( AdapterInterface, 1 );
5052 adapter->interfaceType = interface->type;
5053 adapter->atci = atci;
5054 adapter->interface = interface;
5055 adapter->treeNode = NULL;
5056 adapter->enabled = TRUE;
5057 adapter->haveLibrary = interface->haveLibrary;
5058 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5059 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5060 _addressInterfaceList_ =
5061 g_list_append( _addressInterfaceList_, adapter );
5063 list = g_list_next( list );
5068 * Find GUI interface type specified interface type.
5069 * \param ifType Interface type.
5070 * \return Interface item, or NULL if not found.
5072 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5073 GList *node = _addressInterfaceList_;
5075 AdapterInterface *adapter = node->data;
5076 if( adapter->interfaceType == ifType ) return adapter;
5077 node = g_list_next( node );
5083 * Build interface list selection.
5085 static void addrbookctl_build_ifselect( void ) {
5086 GList *newList = NULL;
5091 gchar *endptr = NULL;
5093 AdapterInterface *adapter;
5095 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5098 splitStr = g_strsplit( selectStr, ",", -1 );
5099 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5101 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5102 ifType = strtol( splitStr[i], &endptr, 10 );
5105 if( strcmp( endptr, "/n" ) == 0 ) {
5109 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5110 adapter = addrbookctl_find_interface( ifType );
5112 newList = g_list_append( newList, adapter );
5119 /* g_print( "i=%d\n", i ); */
5120 g_strfreev( splitStr );
5121 g_free( selectStr );
5123 /* Replace existing list */
5124 mgu_clear_list( _addressIFaceSelection_ );
5125 g_list_free( _addressIFaceSelection_ );
5126 _addressIFaceSelection_ = newList;
5130 /* ***********************************************************************
5131 * Add sender to address book.
5132 * ***********************************************************************
5136 * This function is used by the Add sender to address book function.
5138 gboolean addressbook_add_contact(
5139 const gchar *name, const gchar *address, const gchar *remarks,
5140 GdkPixbuf *picture )
5142 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5143 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5144 debug_print( "addressbook_add_contact - added\n" );
5145 addressbook_refresh();
5150 /* ***********************************************************************
5151 * Book/folder selection.
5152 * ***********************************************************************
5156 * This function is used by the matcher dialog to select a book/folder.
5158 gchar *addressbook_folder_selection( const gchar *folderpath)
5160 AddressBookFile *book = NULL;
5161 ItemFolder *folder = NULL;
5164 g_return_val_if_fail( folderpath != NULL, NULL);
5166 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5168 if ( folder != NULL) {
5170 gchar *oldtmp = NULL;
5171 AddrItemObject *obj = NULL;
5173 /* walk thru folder->parent to build the full folder path */
5174 /* TODO: wwp: optimize this */
5176 tmp = g_strdup(obj->uid);
5177 while ( obj->parent ) {
5179 if ( obj->name != NULL ) {
5180 oldtmp = g_strdup(tmp);
5182 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5186 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5189 path = g_strdup_printf("%s", book->fileName);
5191 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5197 /* ***********************************************************************
5198 * Book/folder checking.
5199 * ***********************************************************************
5202 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5204 FolderInfo *fi = g_new0( FolderInfo, 1 );
5206 fi->folder = folder;
5210 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5211 FolderInfo *fiParent, FolderPathMatch *match )
5217 FolderPathMatch *nextmatch = NULL;
5222 list = parentFolder->listFolder;
5224 folder = list->data;
5225 fName = g_strdup( ADDRITEM_NAME(folder) );
5227 /* match folder name, match pointer will be set to NULL if next recursive call
5228 doesn't need to match subfolder name */
5229 if ( match != NULL &&
5230 match->matched == FALSE ) {
5231 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5232 /* folder name matches, prepare next subfolder match */
5233 debug_print("matched folder name '%s'\n", fName);
5235 if ( match->folder_path[match->index] == NULL ) {
5236 /* we've matched all elements */
5237 match->matched = TRUE;
5238 match->folder = folder;
5239 debug_print("book/folder path matched!\n");
5241 /* keep on matching */
5249 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5250 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5252 list = g_list_next( list );
5257 * This function is used by to check if a matcher book/folder path corresponds to an
5258 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5259 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5260 if book AND folder are NULL this means that folderpath was empty or Any.
5261 If folderpath is a simple book name (without folder), book will not be NULL and folder
5262 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5265 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5266 AddressDataSource **book,
5267 ItemFolder **folder )
5269 AddressDataSource *ds;
5270 GList *list, *nodeDS;
5271 ItemFolder *rootFolder;
5272 AddressBookFile *abf;
5274 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5281 if ( folderpath == NULL )
5284 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5287 /* split the folder path we've received, we'll try to match this path, subpath by
5288 subpath against the book/folder structure in order */
5289 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5290 if (!folder_path_match.folder_path)
5293 list = addrindex_get_interface_list( _addressIndex_ );
5294 while ( list && !folder_path_match.matched ) {
5295 AddressInterface *interface = list->data;
5296 if ( interface && interface->type == ADDR_IF_BOOK ) {
5297 nodeDS = interface->listSource;
5298 while ( nodeDS && !folder_path_match.matched ) {
5301 /* Read address book */
5302 if( ! addrindex_ds_get_read_flag( ds ) ) {
5303 addrindex_ds_read_data( ds );
5306 /* Add node for address book */
5307 abf = ds->rawDataSource;
5309 /* match book name */
5310 if ( abf && abf->fileName &&
5311 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5313 debug_print("matched book name '%s'\n", abf->fileName);
5314 folder_path_match.book = ds;
5316 if ( folder_path_match.folder_path[1] == NULL ) {
5317 /* no folder part to match */
5319 folder_path_match.matched = TRUE;
5320 folder_path_match.folder = NULL;
5321 debug_print("book path matched!\n");
5324 /* match folder part */
5326 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5327 rootFolder = addrindex_ds_get_root_folder( ds );
5329 /* prepare for recursive call */
5330 folder_path_match.index = 1;
5331 /* this call will set folder_path_match.matched and folder_path_match.folder */
5332 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5337 nodeDS = g_list_next( nodeDS );
5340 list = g_list_next( list );
5343 g_strfreev( folder_path_match.folder_path );
5346 *book = folder_path_match.book;
5348 *folder = folder_path_match.folder;
5349 return folder_path_match.matched;
5353 /* **********************************************************************
5355 * ***********************************************************************
5361 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5362 AddressDataSource *ds = NULL;
5363 AdapterDSource *ads = NULL;
5364 AddressBookFile *abf = NULL;
5365 AdapterInterface *adapter;
5366 GtkCTreeNode *newNode;
5368 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5370 if( adapter->treeNode ) {
5371 abf = addressbook_imp_ldif( _addressIndex_ );
5373 ds = addrindex_index_add_datasource(
5374 _addressIndex_, ADDR_IF_BOOK, abf );
5375 ads = addressbook_create_ds_adapter(
5376 ds, ADDR_BOOK, NULL );
5377 addressbook_ads_set_name(
5378 ads, addrbook_get_name( abf ) );
5379 newNode = addressbook_add_object(
5381 ADDRESS_OBJECT(ads) );
5383 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5385 addrbook.treeSelected = newNode;
5388 /* Notify address completion */
5389 invalidate_address_completion();
5398 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5399 AddressDataSource *ds = NULL;
5400 AdapterDSource *ads = NULL;
5401 AddressBookFile *abf = NULL;
5402 AdapterInterface *adapter;
5403 GtkCTreeNode *newNode;
5405 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5407 if( adapter->treeNode ) {
5408 abf = addressbook_imp_mutt( _addressIndex_ );
5410 ds = addrindex_index_add_datasource(
5411 _addressIndex_, ADDR_IF_BOOK, abf );
5412 ads = addressbook_create_ds_adapter(
5413 ds, ADDR_BOOK, NULL );
5414 addressbook_ads_set_name(
5415 ads, addrbook_get_name( abf ) );
5416 newNode = addressbook_add_object(
5418 ADDRESS_OBJECT(ads) );
5420 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5422 addrbook.treeSelected = newNode;
5425 /* Notify address completion */
5426 invalidate_address_completion();
5435 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5436 AddressDataSource *ds = NULL;
5437 AdapterDSource *ads = NULL;
5438 AddressBookFile *abf = NULL;
5439 AdapterInterface *adapter;
5440 GtkCTreeNode *newNode;
5442 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5444 if( adapter->treeNode ) {
5445 abf = addressbook_imp_pine( _addressIndex_ );
5447 ds = addrindex_index_add_datasource(
5448 _addressIndex_, ADDR_IF_BOOK, abf );
5449 ads = addressbook_create_ds_adapter(
5450 ds, ADDR_BOOK, NULL );
5451 addressbook_ads_set_name(
5452 ads, addrbook_get_name( abf ) );
5453 newNode = addressbook_add_object(
5455 ADDRESS_OBJECT(ads) );
5457 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5459 addrbook.treeSelected = newNode;
5462 /* Notify address completion */
5463 invalidate_address_completion();
5470 * Harvest addresses.
5471 * \param folderItem Folder to import.
5472 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5473 * \param msgList List of message numbers, or NULL to process folder.
5475 void addressbook_harvest(
5476 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5478 AddressDataSource *ds = NULL;
5479 AdapterDSource *ads = NULL;
5480 AddressBookFile *abf = NULL;
5481 AdapterInterface *adapter;
5482 GtkCTreeNode *newNode;
5484 abf = addrgather_dlg_execute(
5485 folderItem, _addressIndex_, sourceInd, msgList );
5487 ds = addrindex_index_add_datasource(
5488 _addressIndex_, ADDR_IF_BOOK, abf );
5490 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5492 if( adapter->treeNode ) {
5493 ads = addressbook_create_ds_adapter(
5494 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5495 newNode = addressbook_add_object(
5497 ADDRESS_OBJECT(ads) );
5501 /* Notify address completion */
5502 invalidate_address_completion();
5509 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5510 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5512 AddressDataSource *ds = NULL;
5513 AddrBookBase *adbase;
5514 AddressCache *cache;
5515 GtkCTreeNode *node = NULL;
5517 if( ! addrbook.treeSelected ) return;
5518 node = addrbook.treeSelected;
5519 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5520 obj = gtk_ctree_node_get_row_data( ctree, node );
5521 if( obj == NULL ) return;
5523 ds = addressbook_find_datasource( node );
5524 if( ds == NULL ) return;
5525 adbase = ( AddrBookBase * ) ds->rawDataSource;
5526 cache = adbase->addressCache;
5527 addressbook_exp_html( cache );
5533 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5534 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5536 AddressDataSource *ds = NULL;
5537 AddrBookBase *adbase;
5538 AddressCache *cache;
5539 GtkCTreeNode *node = NULL;
5541 if( ! addrbook.treeSelected ) return;
5542 node = addrbook.treeSelected;
5543 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5544 obj = gtk_ctree_node_get_row_data( ctree, node );
5545 if( obj == NULL ) return;
5547 ds = addressbook_find_datasource( node );
5548 if( ds == NULL ) return;
5549 adbase = ( AddrBookBase * ) ds->rawDataSource;
5550 cache = adbase->addressCache;
5551 addressbook_exp_ldif( cache );
5554 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5556 addrduplicates_find(GTK_WINDOW(addrbook.window));
5559 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5561 addressbook_custom_attr_edit();
5564 static void addressbook_start_drag(GtkWidget *widget, gint button,
5568 GdkDragContext *context;
5569 if (addressbook_target_list == NULL)
5570 addressbook_target_list = gtk_target_list_new(
5571 addressbook_drag_types, 1);
5572 context = gtk_drag_begin(widget, addressbook_target_list,
5573 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5574 gtk_drag_set_icon_default(context);
5577 static void addressbook_drag_data_get(GtkWidget *widget,
5578 GdkDragContext *drag_context,
5579 GtkSelectionData *selection_data,
5584 AddrItemObject *aio = NULL;
5585 AddressObject *pobj = NULL;
5586 AdapterDSource *ads = NULL;
5587 AddressDataSource *ds = NULL;
5590 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5592 if( pobj == NULL ) return;
5594 if( pobj->type == ADDR_DATASOURCE ) {
5595 ads = ADAPTER_DSOURCE(pobj);
5596 ds = ads->dataSource;
5597 } else if (pobj->type == ADDR_ITEM_GROUP) {
5602 else if( pobj->type != ADDR_INTERFACE ) {
5603 ds = addressbook_find_datasource( addrbook.treeSelected );
5609 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5610 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5611 GTK_CTREE_NODE(cur->data));
5612 while (aio && aio->type != ADDR_ITEM_PERSON) {
5617 if (aio && aio->type == ADDR_ITEM_PERSON) {
5618 if( ds && ds->interface && ds->interface->readOnly)
5619 gtk_selection_data_set(selection_data,
5620 selection_data->target, 8,
5621 (const guchar *)"Dummy_addr_copy", 15);
5623 gtk_selection_data_set(selection_data,
5624 selection_data->target, 8,
5625 (const guchar *)"Dummy_addr_move", 15);
5629 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5630 GdkDragContext *context,
5637 GtkCTreeNode *node = NULL;
5638 gboolean acceptable = FALSE;
5639 gint height = addrbook.ctree->allocation.height;
5640 gint total_height = addrbook.ctree->requisition.height;
5641 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5642 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5643 gfloat vpos = pos->value;
5645 if (gtk_clist_get_selection_info
5646 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5648 if (y > height - 24 && height + vpos < total_height) {
5649 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5650 gtk_adjustment_changed(pos);
5652 if (y < 24 && y > 0) {
5653 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5654 gtk_adjustment_changed(pos);
5656 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5659 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5660 if( obj->type == ADDR_ITEM_FOLDER
5661 || obj->type == ADDR_ITEM_GROUP)
5664 AdapterDSource *ads = NULL;
5665 AddressDataSource *ds = NULL;
5666 ads = ADAPTER_DSOURCE(obj);
5667 if (ads == NULL ){ return FALSE;}
5668 ds = ads->dataSource;
5669 if (ds == NULL ) { return FALSE;}
5677 g_signal_handlers_block_by_func
5679 G_CALLBACK(addressbook_tree_selected), NULL);
5680 gtk_sctree_select( GTK_SCTREE(widget), node);
5681 g_signal_handlers_unblock_by_func
5683 G_CALLBACK(addressbook_tree_selected), NULL);
5684 gdk_drag_status(context,
5685 (context->actions == GDK_ACTION_COPY ?
5686 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5688 gdk_drag_status(context, 0, time);
5693 static void addressbook_drag_leave_cb(GtkWidget *widget,
5694 GdkDragContext *context,
5698 if (addrbook.treeSelected) {
5699 g_signal_handlers_block_by_func
5701 G_CALLBACK(addressbook_tree_selected), NULL);
5702 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5703 g_signal_handlers_unblock_by_func
5705 G_CALLBACK(addressbook_tree_selected), NULL);
5710 static void addressbook_drag_received_cb(GtkWidget *widget,
5711 GdkDragContext *drag_context,
5714 GtkSelectionData *data,
5721 GtkCTreeNode *lastopened = addrbook.opened;
5723 if (!strncmp(data->data, "Dummy_addr", 10)) {
5724 if (gtk_clist_get_selection_info
5725 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5729 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5730 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5733 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5734 if (drag_context->action == GDK_ACTION_COPY ||
5735 !strcmp(data->data, "Dummy_addr_copy"))
5736 addressbook_clip_copy_cb(NULL, NULL);
5738 addressbook_clip_cut_cb(NULL, NULL);
5739 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5740 addressbook_clip_paste_cb(NULL,NULL);
5741 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5742 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5743 gtk_drag_finish(drag_context, TRUE, TRUE, time);