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 (GtkCMCTree *ctree,
200 GtkCMCTreeNode *node,
203 static void addressbook_select_row_tree (GtkCMCTree *ctree,
204 GtkCMCTreeNode *node,
207 static void addressbook_list_row_selected (GtkCMCTree *clist,
208 GtkCMCTreeNode *node,
211 static void addressbook_list_row_unselected (GtkCMCTree *clist,
212 GtkCMCTreeNode *node,
215 static void addressbook_person_expand_node (GtkCMCTree *ctree,
218 static void addressbook_person_collapse_node (GtkCMCTree *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 (GtkCMCTreeNode *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 GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
283 static void addressbook_treenode_remove_item ( void );
285 static AddressDataSource *addressbook_find_datasource
286 (GtkCMCTreeNode *node );
288 static AddressBookFile *addressbook_get_book_file(void);
290 static GtkCMCTreeNode *addressbook_node_add_folder
291 (GtkCMCTreeNode *node,
292 AddressDataSource *ds,
293 ItemFolder *itemFolder,
294 AddressObjectType otype);
295 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
296 AddressDataSource *ds,
297 ItemGroup *itemGroup);
298 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
299 GtkCMCTreeNode *parent);
300 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
301 GtkCMCTreeNode *node);
302 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
304 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
307 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
310 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
312 AddressTypeControlItem *atci,
313 AddressTypeControlItem *atciMail);
314 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
316 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
318 static void addressbook_folder_remove_node (GtkCMCTree *clist,
319 GtkCMCTreeNode *node);
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_("_Book") },
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_CMCTREE_NODE(GTK_CMCLIST(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_cmctree_node_get_row_data(GTK_CMCTREE(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 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
736 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
737 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
738 gchar *name1 = NULL, *name2 = NULL;
739 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
740 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
742 if( aio1->type == aio2->type ) {
744 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
746 name2 = GTK_CMCELL_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(GtkCMCList *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_cmclist_set_compare_func(clist, list_case_sort);
770 gtk_cmclist_set_sort_type(clist, sort_type);
771 gtk_cmclist_set_sort_column(clist, col);
773 gtk_cmclist_freeze(clist);
774 gtk_cmclist_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_cmclist_set_column_widget(clist, pos, hbox);
791 gtk_cmclist_thaw(clist);
794 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
796 static GtkSortType sort_type = GTK_SORT_ASCENDING;
798 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
800 addressbook_sort_list(clist, COL_NAME, sort_type);
803 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *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, GtkCMCList *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_POPUP)
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_WIDGET_UNSET_FLAGS(GTK_CMCLIST(ctree)->column[0].button,
1031 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1032 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1033 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1034 if (prefs_common.enable_dotted_lines) {
1035 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_DOTTED);
1036 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1037 GTK_CMCTREE_EXPANDER_SQUARE);
1039 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1040 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1041 GTK_CMCTREE_EXPANDER_TRIANGLE);
1043 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1044 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1045 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1046 addressbook_treenode_compare_func);
1048 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1049 G_CALLBACK(addressbook_tree_selected), NULL);
1050 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1051 G_CALLBACK(addressbook_tree_button_pressed),
1053 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1054 G_CALLBACK(addressbook_tree_button_released),
1057 g_signal_connect(G_OBJECT(ctree), "select_row",
1058 G_CALLBACK(addressbook_select_row_tree), NULL);
1060 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1061 addressbook_drag_types, 1,
1062 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1063 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1064 G_CALLBACK(addressbook_drag_motion_cb),
1066 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1067 G_CALLBACK(addressbook_drag_leave_cb),
1069 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1070 G_CALLBACK(addressbook_drag_received_cb),
1072 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1073 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1074 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1075 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1077 clist_vbox = gtk_vbox_new(FALSE, 4);
1079 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1080 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1081 GTK_POLICY_AUTOMATIC,
1082 GTK_POLICY_AUTOMATIC);
1083 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1086 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1087 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1088 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1089 if (prefs_common.enable_dotted_lines) {
1090 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_DOTTED);
1091 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1092 GTK_CMCTREE_EXPANDER_SQUARE);
1094 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1095 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1096 GTK_CMCTREE_EXPANDER_TRIANGLE);
1098 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1099 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1100 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1102 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1104 gtk_widget_set_size_request(clist, -1, 80);
1106 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1107 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1108 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1109 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1110 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1111 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1112 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1113 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1114 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1115 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1116 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1118 for (i = 0; i < N_LIST_COLS; i++)
1119 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(clist)->column[i].button,
1122 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1123 G_CALLBACK(addressbook_list_row_selected), NULL);
1124 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1125 G_CALLBACK(addressbook_list_row_unselected), NULL);
1126 g_signal_connect(G_OBJECT(clist), "button_press_event",
1127 G_CALLBACK(addressbook_list_button_pressed),
1129 g_signal_connect(G_OBJECT(clist), "button_release_event",
1130 G_CALLBACK(addressbook_list_button_released),
1132 g_signal_connect(G_OBJECT(clist), "tree_expand",
1133 G_CALLBACK(addressbook_person_expand_node), NULL );
1134 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1135 G_CALLBACK(addressbook_person_collapse_node), NULL );
1136 g_signal_connect(G_OBJECT(clist), "start_drag",
1137 G_CALLBACK(addressbook_start_drag), NULL);
1138 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1139 G_CALLBACK(addressbook_drag_data_get), NULL);
1140 hbox = gtk_hbox_new(FALSE, 4);
1141 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1143 label = gtk_label_new(_("Lookup name:"));
1144 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1146 entry = gtk_entry_new();
1147 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1149 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1151 g_signal_connect(G_OBJECT(entry), "key_press_event",
1152 G_CALLBACK(addressbook_entry_key_pressed),
1155 if (!prefs_common.addressbook_use_editaddress_dialog) {
1156 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1157 vpaned = gtk_vpaned_new();
1158 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1159 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1162 editaddress_vbox = NULL;
1164 hpaned = gtk_hpaned_new();
1165 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1166 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1167 if (prefs_common.addressbook_use_editaddress_dialog)
1168 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1170 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1173 hsbox = gtk_hbox_new(FALSE, 0);
1174 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1175 statusbar = gtk_statusbar_new();
1176 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1179 hbbox = gtk_hbutton_box_new();
1180 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1181 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1182 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1183 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1185 gtkut_stock_button_add_help(hbbox, &help_btn);
1187 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1188 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1189 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1190 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1191 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1192 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1193 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1194 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1195 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1198 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1199 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1200 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1202 g_signal_connect(G_OBJECT(help_btn), "clicked",
1203 G_CALLBACK(manual_open_with_anchor_cb),
1204 MANUAL_ANCHOR_ADDRBOOK);
1206 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1207 G_CALLBACK(addressbook_edit_clicked), NULL);
1208 g_signal_connect(G_OBJECT(del_btn), "clicked",
1209 G_CALLBACK(addressbook_del_clicked), NULL);
1210 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1211 G_CALLBACK(addressbook_reg_clicked), NULL);
1212 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1213 G_CALLBACK(addressbook_lup_clicked), NULL);
1215 to_btn = gtk_button_new_with_label
1216 (prefs_common_translated_header_name("To:"));
1217 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1218 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1219 cc_btn = gtk_button_new_with_label
1220 (prefs_common_translated_header_name("Cc:"));
1221 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1222 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1223 bcc_btn = gtk_button_new_with_label
1224 (prefs_common_translated_header_name("Bcc:"));
1225 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1226 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1228 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1229 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1230 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1232 g_signal_connect(G_OBJECT(to_btn), "clicked",
1233 G_CALLBACK(addressbook_to_clicked),
1234 GINT_TO_POINTER(COMPOSE_TO));
1235 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1236 G_CALLBACK(addressbook_to_clicked),
1237 GINT_TO_POINTER(COMPOSE_CC));
1238 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1239 G_CALLBACK(addressbook_to_clicked),
1240 GINT_TO_POINTER(COMPOSE_BCC));
1241 g_signal_connect(G_OBJECT(close_btn), "clicked",
1242 G_CALLBACK(addressbook_close_clicked), NULL);
1244 /* Build icons for interface */
1245 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1246 &interfacexpm, &interfacexpmmask );
1248 /* Build control tables */
1249 addrbookctl_build_map(window);
1250 addrbookctl_build_iflist();
1251 addrbookctl_build_ifselect();
1253 addrbook.clist = NULL;
1255 /* Add each interface into the tree as a root level folder */
1256 nodeIf = _addressInterfaceList_;
1258 AdapterInterface *adapter = nodeIf->data;
1259 AddressInterface *iface = adapter->interface;
1260 nodeIf = g_list_next(nodeIf);
1262 if(iface->useInterface) {
1263 AddressTypeControlItem *atci = adapter->atci;
1264 text = atci->displayName;
1266 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1267 NULL, NULL, &text, FOLDER_SPACING,
1268 interfacexpm, interfacexpmmask,
1269 interfacexpm, interfacexpmmask,
1271 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1272 gtk_cmctree_node_set_row_data_full(
1273 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1274 addressbook_free_treenode );
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1289 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1290 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1291 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1293 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1294 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1296 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1297 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1298 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1299 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1300 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1301 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1302 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1303 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1304 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1305 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1306 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1307 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1308 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1309 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1311 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1313 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1314 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1316 addrbook.window = window;
1317 addrbook.hpaned = hpaned;
1318 addrbook.vpaned = vpaned;
1319 addrbook.menubar = menubar;
1320 addrbook.ctree = ctree;
1323 addrbook.editaddress_vbox = editaddress_vbox;
1324 addrbook.clist = clist;
1325 addrbook.label = label;
1326 addrbook.entry = entry;
1327 addrbook.statusbar = statusbar;
1328 addrbook.status_cid = gtk_statusbar_get_context_id(
1329 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1331 addrbook.help_btn = help_btn;
1332 addrbook.edit_btn = edit_btn;
1333 addrbook.del_btn = del_btn;
1334 addrbook.reg_btn = reg_btn;
1335 addrbook.lup_btn = lup_btn;
1336 addrbook.to_btn = to_btn;
1337 addrbook.cc_btn = cc_btn;
1338 addrbook.bcc_btn = bcc_btn;
1340 addrbook.tree_popup = tree_popup;
1341 addrbook.list_popup = list_popup;
1342 addrbook.ui_manager = ui_manager;
1344 addrbook.listSelected = NULL;
1346 if (!geometry.min_height) {
1347 geometry.min_width = ADDRESSBOOK_WIDTH;
1348 geometry.min_height = ADDRESSBOOK_HEIGHT;
1351 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1353 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1354 prefs_common.addressbookwin_height);
1356 if (!prefs_common.addressbook_use_editaddress_dialog) {
1357 if (prefs_common.addressbook_vpaned_pos > 0)
1358 gtk_paned_set_position(GTK_PANED(vpaned),
1359 prefs_common.addressbook_vpaned_pos);
1361 if (prefs_common.addressbook_hpaned_pos > 0)
1362 gtk_paned_set_position(GTK_PANED(hpaned),
1363 prefs_common.addressbook_hpaned_pos);
1366 gtk_widget_show_all(window);
1370 * Close address book window and save to file(s).
1372 static gint addressbook_close( void ) {
1373 address_completion_end(addrbook.window);
1374 if (!prefs_common.addressbook_use_editaddress_dialog)
1375 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1377 addressbook_pane_save_position();
1379 gtk_widget_hide(addrbook.window);
1380 addressbook_export_to_file();
1385 * Display message in status line.
1386 * \param msg Message to display.
1388 static void addressbook_status_show( gchar *msg ) {
1389 if( addrbook.statusbar != NULL ) {
1391 GTK_STATUSBAR(addrbook.statusbar),
1392 addrbook.status_cid );
1395 GTK_STATUSBAR(addrbook.statusbar),
1396 addrbook.status_cid, msg );
1401 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1405 *addressbook_msgbuf = '\0';
1407 name = addrindex_ds_get_name( ds );
1408 retVal = addrindex_ds_get_status_code( ds );
1409 if( retVal == MGU_SUCCESS ) {
1410 g_snprintf( addressbook_msgbuf,
1411 sizeof(addressbook_msgbuf), "%s", name );
1414 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1415 g_snprintf( addressbook_msgbuf,
1416 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1419 addressbook_status_show( addressbook_msgbuf );
1422 static void addressbook_button_set_sensitive(void)
1424 gboolean to_sens = FALSE;
1425 gboolean cc_sens = FALSE;
1426 gboolean bcc_sens = FALSE;
1428 if (!addrbook.window) return;
1430 if (addrbook.target_compose) {
1436 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1437 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1438 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1441 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1443 addressbook_edit_address_cb(NULL, NULL);
1446 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1448 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1452 * Delete one or more objects from address list.
1454 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1456 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1457 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1458 AddressObject *pobj;
1459 AdapterDSource *ads = NULL;
1460 GtkCMCTreeNode *nodeList;
1463 AddressBookFile *abf = NULL;
1464 AddressDataSource *ds = NULL;
1465 AddressInterface *iface;
1466 AddrItemObject *aio;
1467 AddrSelectItem *item;
1469 gboolean refreshList = FALSE;
1471 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1472 g_return_if_fail(pobj != NULL);
1474 /* Test whether anything selected for deletion */
1475 nodeList = addrbook.listSelected;
1477 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1478 if( aio == NULL) return;
1479 ds = addressbook_find_datasource( addrbook.treeSelected );
1480 if( ds == NULL ) return;
1482 /* Test for read only */
1483 iface = ds->interface;
1484 if( iface->readOnly ) {
1485 alertpanel( _("Delete address(es)"),
1486 _("This address data is readonly and cannot be deleted."),
1487 GTK_STOCK_CLOSE, NULL, NULL );
1491 /* Test whether Ok to proceed */
1493 if( pobj->type == ADDR_DATASOURCE ) {
1494 ads = ADAPTER_DSOURCE(pobj);
1495 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1497 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1500 else if( pobj->type == ADDR_ITEM_GROUP ) {
1503 if( ! procFlag ) return;
1504 abf = ds->rawDataSource;
1505 if( abf == NULL ) return;
1507 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1508 g_signal_handlers_block_by_func
1509 (G_OBJECT(addrbook.clist),
1510 G_CALLBACK(addressbook_list_row_unselected), NULL);
1512 /* Process deletions */
1513 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1514 GList *groups = NULL, *persons = NULL, *emails = NULL;
1515 gboolean group_delete = TRUE;
1516 /* Items inside folders */
1517 list = addrselect_get_list( _addressSelect_ );
1518 /* Confirm deletion */
1522 node = g_list_next( node );
1523 aio = ( AddrItemObject * ) item->addressItem;
1524 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1525 group_delete = FALSE;
1530 aval = alertpanel( _("Delete group"),
1531 _("Really delete the group(s)?\n"
1532 "The addresses it contains will not be lost."),
1533 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1534 if( aval != G_ALERTALTERNATE ) {
1538 aval = alertpanel( _("Delete address(es)"),
1539 _("Really delete the address(es)?"),
1540 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1541 if( aval != G_ALERTALTERNATE ) {
1546 /* first, set lists of groups and persons to remove */
1550 node = g_list_next( node );
1551 aio = ( AddrItemObject * ) item->addressItem;
1554 if( aio->type == ADDR_ITEM_GROUP ) {
1555 groups = g_list_prepend(groups, item);
1557 else if( aio->type == ADDR_ITEM_PERSON ) {
1558 persons = g_list_prepend(persons, item);
1561 /* then set list of emails to remove *if* they're not children of
1562 * persons to remove */
1566 node = g_list_next( node );
1567 aio = ( AddrItemObject * ) item->addressItem;
1570 if( aio->type == ADDR_ITEM_EMAIL ) {
1571 ItemEMail *sitem = ( ItemEMail * ) aio;
1572 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1573 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1574 emails = g_list_prepend(emails, item);
1576 /* else, the email will be removed via the parent person */
1579 /* then delete groups */
1583 node = g_list_next( node );
1584 aio = ( AddrItemObject * ) item->addressItem;
1587 if( aio->type == ADDR_ITEM_GROUP ) {
1588 ItemGroup *item = ( ItemGroup * ) aio;
1589 GtkCMCTreeNode *nd = NULL;
1590 nd = addressbook_find_group_node( addrbook.opened, item );
1591 item = addrbook_remove_group( abf, item );
1593 addritem_free_item_group( item );
1595 /* Remove group from parent node */
1596 gtk_cmctree_remove_node( ctree, nd );
1600 /* then delete persons */
1604 node = g_list_next( node );
1605 aio = ( AddrItemObject * ) item->addressItem;
1608 if( aio->type == ADDR_ITEM_PERSON ) {
1609 ItemPerson *item = ( ItemPerson * ) aio;
1610 item->status = DELETE_ENTRY;
1611 addressbook_folder_remove_one_person( clist, item );
1612 if (pobj->type == ADDR_ITEM_FOLDER)
1613 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1614 item = addrbook_remove_person( abf, item );
1616 if (ds && ds->type == ADDR_IF_LDAP) {
1617 LdapServer *server = ds->rawDataSource;
1618 ldapsvr_set_modified(server, TRUE);
1619 ldapsvr_update_book(server, item);
1623 gchar *filename = addritem_person_get_picture(item);
1624 if (filename && is_file_exist(filename))
1625 claws_unlink(filename);
1627 addritem_free_item_person( item );
1631 /* then delete emails */
1635 node = g_list_next( node );
1636 aio = ( AddrItemObject * ) item->addressItem;
1640 if( aio->type == ADDR_ITEM_EMAIL ) {
1641 ItemEMail *sitem = ( ItemEMail * ) aio;
1642 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1643 sitem = addrbook_person_remove_email( abf, person, sitem );
1645 addrcache_remove_email(abf->addressCache, sitem);
1646 addritem_free_item_email( sitem );
1648 addressbook_folder_refresh_one_person( clist, person );
1651 g_list_free( groups );
1652 g_list_free( persons );
1653 g_list_free( emails );
1654 g_list_free( list );
1655 addressbook_list_select_clear();
1657 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1658 addressbook_set_clist(
1659 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1663 addrbook_set_dirty(abf, TRUE);
1664 addressbook_export_to_file();
1665 addressbook_list_menu_setup();
1668 else if( pobj->type == ADDR_ITEM_GROUP ) {
1669 /* Items inside groups */
1670 list = addrselect_get_list( _addressSelect_ );
1674 node = g_list_next( node );
1675 aio = ( AddrItemObject * ) item->addressItem;
1676 if( aio->type == ADDR_ITEM_EMAIL ) {
1677 ItemEMail *item = ( ItemEMail * ) aio;
1678 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1679 item = addrbook_person_remove_email( abf, person, item );
1681 addritem_free_item_email( item );
1685 g_list_free( list );
1686 addressbook_list_select_clear();
1687 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1688 addressbook_set_clist(
1689 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1693 addrbook_set_dirty(abf, TRUE);
1694 addressbook_export_to_file();
1695 addressbook_list_menu_setup();
1699 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1700 gtk_cmctree_remove_node( clist, nodeList );
1702 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1703 g_signal_handlers_unblock_by_func
1704 (G_OBJECT(addrbook.clist),
1705 G_CALLBACK(addressbook_list_row_unselected), NULL);
1708 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1710 addressbook_new_address_cb( NULL, NULL );
1713 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1716 gchar *address = NULL;
1718 if( aio->type == ADDR_ITEM_EMAIL ) {
1719 ItemPerson *person = NULL;
1720 ItemEMail *email = ( ItemEMail * ) aio;
1722 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1723 if( email->address ) {
1724 if( ADDRITEM_NAME(email) ) {
1725 name = ADDRITEM_NAME(email);
1726 if( *name == '\0' ) {
1727 name = ADDRITEM_NAME(person);
1730 else if( ADDRITEM_NAME(person) ) {
1731 name = ADDRITEM_NAME(person);
1734 buf = g_strdup( email->address );
1736 address = email->address;
1739 else if( aio->type == ADDR_ITEM_PERSON ) {
1740 ItemPerson *person = ( ItemPerson * ) aio;
1741 GList *node = person->listEMail;
1743 name = ADDRITEM_NAME(person);
1745 ItemEMail *email = ( ItemEMail * ) node->data;
1746 address = email->address;
1750 if( name && name[0] != '\0' ) {
1751 if( strchr_with_skip_quote( name, '"', ',' ) )
1752 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1754 buf = g_strdup_printf( "%s <%s>", name, address );
1757 buf = g_strdup( address );
1764 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1768 AddrSelectItem *item;
1769 AddrItemObject *aio;
1772 compose = addrbook.target_compose;
1773 if( ! compose ) return;
1775 /* Nothing selected, but maybe there is something in text entry */
1776 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1778 compose_entry_append(
1779 compose, addr, (ComposeEntryType)data );
1782 /* Select from address list */
1783 list = addrselect_get_list( _addressSelect_ );
1788 node = g_list_next( node );
1789 aio = item->addressItem;
1790 if( aio->type == ADDR_ITEM_PERSON ||
1791 aio->type == ADDR_ITEM_EMAIL ) {
1792 addr = addressbook_format_address( aio );
1793 compose_entry_append(
1794 compose, addr, (ComposeEntryType) data );
1797 else if( aio->type == ADDR_ITEM_GROUP ) {
1798 ItemGroup *group = ( ItemGroup * ) aio;
1799 GList *nodeMail = group->listEMail;
1801 ItemEMail *email = nodeMail->data;
1803 addr = addressbook_format_address(
1804 ( AddrItemObject * ) email );
1805 compose_entry_append(
1806 compose, addr, (ComposeEntryType) data );
1808 nodeMail = g_list_next( nodeMail );
1813 AddressObject *obj = NULL;
1815 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1817 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1818 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1819 GList *nodeMail = itemGroup->listEMail;
1821 ItemEMail *email = nodeMail->data;
1823 addr = addressbook_format_address(
1824 ( AddrItemObject * ) email );
1825 compose_entry_append(
1826 compose, addr, (ComposeEntryType) data );
1828 nodeMail = g_list_next( nodeMail );
1832 g_list_free( list );
1835 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1836 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1837 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1838 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1840 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1841 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1842 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1843 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1845 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1846 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1847 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1848 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1849 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1852 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1853 gboolean canEdit = FALSE;
1854 gboolean canDelete = TRUE;
1855 gboolean canAdd = FALSE;
1856 gboolean canEditTr = TRUE;
1857 gboolean editAddress = FALSE;
1858 gboolean canExport = TRUE;
1859 AddressTypeControlItem *atci = NULL;
1860 AddressDataSource *ds = NULL;
1861 AddressInterface *iface = NULL;
1863 if( obj == NULL ) return;
1864 if( obj->type == ADDR_INTERFACE ) {
1865 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1866 iface = adapter->interface;
1868 if( iface->haveLibrary ) {
1869 /* Enable appropriate File / New command */
1870 atci = adapter->atci;
1871 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1874 canEditTr = canExport = FALSE;
1876 else if( obj->type == ADDR_DATASOURCE ) {
1877 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1878 ds = ads->dataSource;
1879 iface = ds->interface;
1880 if( ! iface->readOnly ) {
1881 canAdd = canEdit = editAddress = canDelete = TRUE;
1883 if( ! iface->haveLibrary ) {
1884 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1887 else if( obj->type == ADDR_ITEM_FOLDER ) {
1888 ds = addressbook_find_datasource( addrbook.treeSelected );
1890 iface = ds->interface;
1891 if( iface->readOnly ) {
1896 canAdd = editAddress = TRUE;
1900 else if( obj->type == ADDR_ITEM_GROUP ) {
1901 ds = addressbook_find_datasource( addrbook.treeSelected );
1903 iface = ds->interface;
1904 if( ! iface->readOnly ) {
1910 if( addrbook.listSelected == NULL )
1914 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1915 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1916 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1917 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1920 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1921 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1922 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1923 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1925 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1926 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1929 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1930 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1934 * Address book tree callback function that responds to selection of tree
1937 * \param ctree Tree widget.
1938 * \param node Node that was selected.
1939 * \param column Column number where selected occurred.
1940 * \param data Pointer to user data.
1942 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1943 gint column, gpointer data)
1945 AddressObject *obj = NULL;
1946 AdapterDSource *ads = NULL;
1947 AddressDataSource *ds = NULL;
1948 ItemFolder *rootFolder = NULL;
1949 AddressObjectType aot;
1951 addrbook.treeSelected = node;
1952 addrbook.listSelected = NULL;
1953 addressbook_status_show( "" );
1954 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1956 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1958 addressbook_set_clist(NULL, TRUE);
1961 addrbook.opened = node;
1963 if( obj->type == ADDR_DATASOURCE ) {
1964 /* Read from file */
1965 static gboolean tVal = TRUE;
1967 ads = ADAPTER_DSOURCE(obj);
1968 if( ads == NULL ) return;
1969 ds = ads->dataSource;
1970 if( ds == NULL ) return;
1972 if( addrindex_ds_get_modify_flag( ds ) ) {
1973 addrindex_ds_read_data( ds );
1976 if( ! addrindex_ds_get_read_flag( ds ) ) {
1977 addrindex_ds_read_data( ds );
1979 addressbook_ds_show_message( ds );
1981 if( ! addrindex_ds_get_access_flag( ds ) ) {
1982 /* Remove existing folders and groups */
1983 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1984 addressbook_tree_remove_children( ctree, node );
1985 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1987 /* Load folders into the tree */
1988 rootFolder = addrindex_ds_get_root_folder( ds );
1989 if( ds && ds->type == ADDR_IF_JPILOT ) {
1990 aot = ADDR_CATEGORY;
1992 else if( ds && ds->type == ADDR_IF_LDAP ) {
1993 aot = ADDR_LDAP_QUERY;
1996 aot = ADDR_ITEM_FOLDER;
1998 addressbook_node_add_folder( node, ds, rootFolder, aot );
1999 addrindex_ds_set_access_flag( ds, &tVal );
2000 gtk_cmctree_expand( ctree, node );
2003 addressbook_set_clist(NULL, TRUE);
2006 /* Update address list */
2007 g_signal_handlers_block_by_func
2009 G_CALLBACK(addressbook_tree_selected), NULL);
2010 addressbook_set_clist( obj, FALSE );
2011 g_signal_handlers_unblock_by_func
2013 G_CALLBACK(addressbook_tree_selected), NULL);
2014 if (!prefs_common.addressbook_use_editaddress_dialog)
2015 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2017 /* Setup main menu selections */
2018 addressbook_menubar_set_sensitive( FALSE );
2019 addressbook_menuitem_set_sensitive( obj, node );
2020 addressbook_list_select_clear();
2021 addressbook_list_menu_setup();
2026 * Setup address list popup menu items. Items are enabled or disabled as
2029 static void addressbook_list_menu_setup( void ) {
2030 GtkCMCTree *clist = NULL;
2031 AddressObject *pobj = NULL;
2032 AddressObject *obj = NULL;
2033 AdapterDSource *ads = NULL;
2034 AddressInterface *iface = NULL;
2035 AddressDataSource *ds = NULL;
2036 gboolean canEdit = FALSE;
2037 gboolean canDelete = FALSE;
2038 gboolean canCut = FALSE;
2039 gboolean canCopy = FALSE;
2040 gboolean canPaste = FALSE;
2041 gboolean canBrowse = FALSE;
2043 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2044 if( pobj == NULL ) return;
2046 clist = GTK_CMCTREE(addrbook.clist);
2047 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2048 if( obj == NULL ) canEdit = FALSE;
2050 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2051 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2053 if( pobj->type == ADDR_DATASOURCE ) {
2054 /* Parent object is a data source */
2055 ads = ADAPTER_DSOURCE(pobj);
2056 ds = ads->dataSource;
2059 iface = ds->interface;
2062 if( ! iface->readOnly ) {
2063 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2064 if (iface->type != ADDR_IF_LDAP)
2065 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2066 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2069 canDelete = canEdit;
2072 else if( pobj->type != ADDR_INTERFACE ) {
2073 /* Parent object is not an interface */
2074 ds = addressbook_find_datasource( addrbook.treeSelected );
2077 iface = ds->interface;
2080 if( ! iface->readOnly ) {
2081 /* Folder or group */
2082 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2083 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2084 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2085 if( obj ) canEdit = TRUE;
2088 if( pobj->type == ADDR_ITEM_FOLDER ) {
2089 if (iface->type != ADDR_IF_LDAP)
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2091 if( obj ) canEdit = TRUE;
2093 canDelete = canEdit;
2095 if( iface->type == ADDR_IF_LDAP ) {
2096 if( obj ) canBrowse = TRUE;
2103 /* Enable cut and paste */
2104 if( ! addrclip_is_empty( _clipBoard_ ) )
2106 if( ! addrselect_test_empty( _addressSelect_ ) )
2108 /* Enable copy if something is selected */
2109 if( ! addrselect_test_empty( _addressSelect_ ) )
2113 /* Disable edit or browse if more than one row selected */
2114 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2119 /* Forbid write changes when read-only */
2120 if( iface && iface->readOnly ) {
2126 /* Now go finalize menu items */
2127 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2128 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2130 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2131 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2132 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2134 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2136 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2137 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2138 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2140 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2141 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2142 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2144 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2145 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2148 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2152 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2153 GtkCMCTreeNode *node,
2160 * Add list of items into tree node below specified tree node.
2161 * \param treeNode Tree node.
2162 * \param ds Data source.
2163 * \param listItems List of items.
2165 static void addressbook_treenode_add_list(
2166 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2172 AddrItemObject *aio;
2176 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2179 group = ( ItemGroup * ) aio;
2180 nn = addressbook_node_add_group( treeNode, ds, group );
2182 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2185 folder = ( ItemFolder * ) aio;
2186 nn = addressbook_node_add_folder(
2187 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2189 node = g_list_next( node );
2193 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2194 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2198 * Cut from address list widget.
2200 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2201 _clipBoard_->cutFlag = TRUE;
2202 addrclip_clear( _clipBoard_ );
2203 addrclip_add( _clipBoard_, _addressSelect_ );
2204 /* addrclip_list_show( _clipBoard_, stdout ); */
2208 * Copy from address list widget.
2210 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2211 _clipBoard_->cutFlag = FALSE;
2212 addrclip_clear( _clipBoard_ );
2213 addrclip_add( _clipBoard_, _addressSelect_ );
2214 /* addrclip_list_show( _clipBoard_, stdout ); */
2218 * Paste clipboard into address list widget.
2220 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2221 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2222 AddressObject *pobj = NULL;
2223 AddressDataSource *ds = NULL;
2224 AddressBookFile *abf = NULL;
2225 ItemFolder *folder = NULL;
2226 GList *folderGroup = NULL;
2228 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2229 if( ds == NULL ) return;
2230 if( addrindex_ds_get_readonly( ds ) ) {
2231 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2235 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2237 if( pobj->type == ADDR_ITEM_FOLDER ) {
2238 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2240 else if( pobj->type == ADDR_ITEM_GROUP ) {
2241 alertpanel_error( _("Cannot paste into an address group.") );
2246 /* Get an address book */
2247 abf = addressbook_get_book_file();
2248 if( abf == NULL ) return;
2250 if( _clipBoard_->cutFlag ) {
2252 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2254 /* Remove all groups and folders in clipboard from tree node */
2255 addressbook_treenode_remove_item();
2257 /* Remove all "cut" items */
2258 addrclip_delete_item( _clipBoard_ );
2260 /* Clear clipboard - cut items??? */
2261 addrclip_clear( _clipBoard_ );
2265 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2268 /* addrclip_list_show( _clipBoard_, stdout ); */
2270 /* Update tree by inserting node for each folder or group */
2271 addressbook_treenode_add_list(
2272 addrbook.treeSelected, ds, folderGroup );
2273 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2274 g_list_free( folderGroup );
2278 /* Display items pasted */
2279 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2280 addressbook_set_clist(
2281 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2289 * Add current treenode object to clipboard. Note that widget only allows
2290 * one entry from the tree list to be selected.
2292 static void addressbook_treenode_to_clipboard( void ) {
2293 AddressObject *obj = NULL;
2294 AddressDataSource *ds = NULL;
2295 AddrSelectItem *item;
2296 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2297 GtkCMCTreeNode *node;
2299 node = addrbook.treeSelected;
2300 if( node == NULL ) return;
2301 obj = gtk_cmctree_node_get_row_data( ctree, node );
2302 if( obj == NULL ) return;
2304 ds = addressbook_find_datasource( node );
2305 if( ds == NULL ) return;
2308 if( obj->type == ADDR_ITEM_FOLDER ) {
2309 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2310 ItemFolder *folder = adapter->itemFolder;
2312 item = addrselect_create_node( obj );
2313 item->uid = g_strdup( ADDRITEM_ID(folder) );
2315 else if( obj->type == ADDR_ITEM_GROUP ) {
2316 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2317 ItemGroup *group = adapter->itemGroup;
2319 item = addrselect_create_node( obj );
2320 item->uid = g_strdup( ADDRITEM_ID(group) );
2322 else if( obj->type == ADDR_DATASOURCE ) {
2324 item = addrselect_create_node( obj );
2329 /* Clear existing list and add item into list */
2332 addressbook_list_select_clear();
2333 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2334 addrselect_list_add( _addressSelect_, item, cacheID );
2340 * Cut from tree widget.
2342 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2343 _clipBoard_->cutFlag = TRUE;
2344 addressbook_treenode_to_clipboard();
2345 addrclip_clear( _clipBoard_ );
2346 addrclip_add( _clipBoard_, _addressSelect_ );
2347 /* addrclip_list_show( _clipBoard_, stdout ); */
2351 * Copy from tree widget.
2353 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2354 _clipBoard_->cutFlag = FALSE;
2355 addressbook_treenode_to_clipboard();
2356 addrclip_clear( _clipBoard_ );
2357 addrclip_add( _clipBoard_, _addressSelect_ );
2358 /* addrclip_list_show( _clipBoard_, stdout ); */
2362 * Paste clipboard into address tree widget.
2364 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2365 addressbook_clip_paste_cb(NULL,NULL);
2369 * Clear selected entries in clipboard.
2371 static void addressbook_list_select_clear( void ) {
2372 addrselect_list_clear( _addressSelect_ );
2376 * Add specified address item to selected address list.
2377 * \param aio Address item object.
2378 * \param ds Datasource.
2380 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2383 if( ds == NULL ) return;
2384 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2385 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2390 * Remove specified address item from selected address list.
2391 * \param aio Address item object.
2393 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2394 addrselect_list_remove( _addressSelect_, aio );
2398 * Invoke EMail compose window with addresses in selected address list.
2400 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2403 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2404 listAddress = addrselect_build_list( _addressSelect_ );
2405 compose_new_with_list( NULL, listAddress );
2406 mgu_free_dlist( listAddress );
2411 static void addressbook_list_row_selected( GtkCMCTree *clist,
2412 GtkCMCTreeNode *node,
2416 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2417 AddrItemObject *aio = NULL;
2418 AddressObject *pobj = NULL;
2419 AdapterDSource *ads = NULL;
2420 AddressDataSource *ds = NULL;
2422 gtk_entry_set_text( entry, "" );
2423 addrbook.listSelected = node;
2425 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2426 if( pobj == NULL ) return;
2428 if( pobj->type == ADDR_DATASOURCE ) {
2429 ads = ADAPTER_DSOURCE(pobj);
2430 ds = ads->dataSource;
2432 else if( pobj->type != ADDR_INTERFACE ) {
2433 ds = addressbook_find_datasource( addrbook.treeSelected );
2436 aio = gtk_cmctree_node_get_row_data( clist, node );
2438 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2439 addressbook_list_select_add( aio, ds );
2442 addressbook_list_menu_setup();
2444 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2445 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2447 if (obj && obj->type != ADDR_ITEM_GROUP)
2448 addressbook_edit_address(NULL, 0, NULL, FALSE);
2452 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2453 GtkCMCTreeNode *node,
2457 AddrItemObject *aio;
2459 aio = gtk_cmctree_node_get_row_data( ctree, node );
2461 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2462 addressbook_list_select_remove( aio );
2465 if (!prefs_common.addressbook_use_editaddress_dialog)
2466 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2469 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2470 GdkEventButton *event,
2473 if( ! event ) return FALSE;
2475 addressbook_list_menu_setup();
2477 if( event->button == 3 ) {
2478 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2479 event->button, event->time );
2480 } else if (event->button == 1) {
2481 if (event->type == GDK_2BUTTON_PRESS) {
2482 if (prefs_common.add_address_by_click &&
2483 addrbook.target_compose)
2484 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2486 if (prefs_common.addressbook_use_editaddress_dialog)
2487 addressbook_edit_address_cb(NULL, NULL);
2489 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2490 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2491 if( obj && obj->type == ADDR_ITEM_GROUP )
2492 addressbook_edit_address_cb(NULL, NULL);
2500 static gboolean addressbook_list_button_released(GtkWidget *widget,
2501 GdkEventButton *event,
2507 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2508 GdkEventButton *event,
2511 GtkCMCList *clist = GTK_CMCLIST(ctree);
2513 AddressObject *obj = NULL;
2514 AdapterDSource *ads = NULL;
2515 AddressInterface *iface = NULL;
2516 AddressDataSource *ds = NULL;
2517 gboolean canEdit = FALSE;
2518 gboolean canDelete = FALSE;
2519 gboolean canCut = FALSE;
2520 gboolean canCopy = FALSE;
2521 gboolean canPaste = FALSE;
2522 gboolean canTreeCut = FALSE;
2523 gboolean canTreeCopy = FALSE;
2524 gboolean canTreePaste = FALSE;
2525 gboolean canLookup = FALSE;
2526 GtkCMCTreeNode *node = NULL;
2528 if( ! event ) return FALSE;
2529 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2531 if (event->button == 1) {
2532 if (event->type == GDK_2BUTTON_PRESS) {
2533 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2534 gtkut_clist_set_focus_row(clist, row);
2535 obj = gtk_cmclist_get_row_data( clist, row );
2540 if (obj->type == ADDR_ITEM_GROUP) {
2542 addressbook_treenode_edit_cb(NULL, NULL);
2544 /* expand pr collapse */
2545 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2546 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2552 addressbook_menubar_set_sensitive( FALSE );
2554 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2555 gtkut_clist_set_focus_row(clist, row);
2556 obj = gtk_cmclist_get_row_data( clist, row );
2559 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2563 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2565 if( ! addrclip_is_empty( _clipBoard_ ) )
2566 canTreePaste = TRUE;
2568 if (obj->type == ADDR_INTERFACE) {
2569 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2572 iface = adapter->interface;
2575 if( !iface->readOnly ) {
2576 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2577 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2579 if( iface->externalQuery )
2582 if (obj->type == ADDR_DATASOURCE) {
2583 ads = ADAPTER_DSOURCE(obj);
2584 ds = ads->dataSource;
2587 iface = ds->interface;
2590 if( !iface->readOnly ) {
2592 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2593 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2594 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2598 if( iface->externalQuery )
2601 else if (obj->type == ADDR_ITEM_FOLDER) {
2602 ds = addressbook_find_datasource( node );
2605 iface = ds->interface;
2608 if( !iface->readOnly ) {
2612 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2613 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2614 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2618 if( iface->externalQuery ) {
2619 /* Enable deletion of LDAP folder */
2624 else if (obj->type == ADDR_ITEM_GROUP) {
2625 ds = addressbook_find_datasource( node );
2628 iface = ds->interface;
2631 if( ! iface->readOnly ) {
2634 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2635 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2639 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2641 if( ! addrselect_test_empty( _addressSelect_ ) )
2643 if( ! addrclip_is_empty( _clipBoard_ ) )
2646 /* Forbid write changes when read-only */
2647 if( iface && iface->readOnly ) {
2649 canTreePaste = FALSE;
2657 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2658 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2659 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2660 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2661 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2663 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2664 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2665 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2666 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2669 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2670 addrbook.target_compose != NULL);
2672 if( event->button == 3 )
2673 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2674 event->button, event->time);
2679 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2680 GdkEventButton *event,
2683 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2687 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2689 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2690 AddressObject *obj = NULL;
2691 AddressDataSource *ds = NULL;
2692 AddressBookFile *abf = NULL;
2693 ItemFolder *parentFolder = NULL;
2694 ItemFolder *folder = NULL;
2696 if( ! addrbook.treeSelected ) return;
2697 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2698 if( obj == NULL ) return;
2699 ds = addressbook_find_datasource( addrbook.treeSelected );
2700 if( ds == NULL ) return;
2702 if( obj->type == ADDR_DATASOURCE ) {
2703 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2705 else if( obj->type == ADDR_ITEM_FOLDER ) {
2706 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2712 abf = ds->rawDataSource;
2713 if( abf == NULL ) return;
2714 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2717 nn = addressbook_node_add_folder(
2718 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2719 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2720 if( addrbook.treeSelected == addrbook.opened )
2721 addressbook_set_clist(obj, TRUE);
2725 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2727 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2728 AddressObject *obj = NULL;
2729 AddressDataSource *ds = NULL;
2730 AddressBookFile *abf = NULL;
2731 ItemFolder *parentFolder = NULL;
2732 ItemGroup *group = NULL;
2734 if( ! addrbook.treeSelected ) return;
2735 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2736 if( obj == NULL ) return;
2737 ds = addressbook_find_datasource( addrbook.treeSelected );
2738 if( ds == NULL ) return;
2740 if( obj->type == ADDR_DATASOURCE ) {
2741 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2743 else if( obj->type == ADDR_ITEM_FOLDER ) {
2744 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2750 abf = ds->rawDataSource;
2751 if( abf == NULL ) return;
2752 group = addressbook_edit_group( abf, parentFolder, NULL );
2755 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2756 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2757 if( addrbook.treeSelected == addrbook.opened )
2758 addressbook_set_clist(obj, TRUE);
2762 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2764 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2767 GdkPixmap *pix_cl, *pix_op;
2768 GdkBitmap *mask_cl, *mask_op;
2769 gboolean is_leaf, expanded;
2771 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2772 &pix_cl, &mask_cl, &pix_op, &mask_op,
2773 &is_leaf, &expanded);
2774 gtk_sctree_set_node_info(ctree, node, name, spacing,
2775 pix_cl, mask_cl, pix_op, mask_op,
2781 * \param obj Address object to edit.
2782 * \param node Node in tree.
2783 * \return New name of data source.
2785 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2786 gchar *newName = NULL;
2787 AddressDataSource *ds = NULL;
2788 AddressInterface *iface = NULL;
2789 AdapterDSource *ads = NULL;
2791 ds = addressbook_find_datasource( node );
2792 if( ds == NULL ) return NULL;
2793 iface = ds->interface;
2794 if( ! iface->haveLibrary ) return NULL;
2796 /* Read data from data source */
2797 if( addrindex_ds_get_modify_flag( ds ) ) {
2798 addrindex_ds_read_data( ds );
2801 if( ! addrindex_ds_get_read_flag( ds ) ) {
2802 addrindex_ds_read_data( ds );
2806 ads = ADAPTER_DSOURCE(obj);
2807 if( ads->subType == ADDR_BOOK ) {
2808 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2810 else if( ads->subType == ADDR_VCARD ) {
2811 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2814 else if( ads->subType == ADDR_JPILOT ) {
2815 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2819 else if( ads->subType == ADDR_LDAP ) {
2820 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2826 newName = obj->name;
2831 * Edit an object that is in the address tree area.
2833 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2835 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2837 AddressDataSource *ds = NULL;
2838 AddressBookFile *abf = NULL;
2839 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2842 if( ! addrbook.treeSelected ) return;
2843 node = addrbook.treeSelected;
2844 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2845 obj = gtk_cmctree_node_get_row_data( ctree, node );
2846 if( obj == NULL ) return;
2847 parentNode = GTK_CMCTREE_ROW(node)->parent;
2849 ds = addressbook_find_datasource( node );
2850 if( ds == NULL ) return;
2852 if( obj->type == ADDR_DATASOURCE ) {
2853 name = addressbook_edit_datasource( obj, node );
2854 if( name == NULL ) return;
2857 abf = ds->rawDataSource;
2858 if( abf == NULL ) return;
2859 if( obj->type == ADDR_ITEM_FOLDER ) {
2860 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2861 ItemFolder *item = adapter->itemFolder;
2862 ItemFolder *parentFolder = NULL;
2863 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2864 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2865 name = ADDRITEM_NAME(item);
2867 else if( obj->type == ADDR_ITEM_GROUP ) {
2868 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2869 ItemGroup *item = adapter->itemGroup;
2870 ItemFolder *parentFolder = NULL;
2871 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2872 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2873 name = ADDRITEM_NAME(item);
2876 if( name && parentNode ) {
2877 /* Update node in tree view */
2878 addressbook_change_node_name( node, name );
2879 gtk_sctree_sort_node(ctree, parentNode);
2880 gtk_cmctree_expand( ctree, node );
2881 gtk_sctree_select( GTK_SCTREE( ctree), node );
2888 ADDRTREE_DEL_FOLDER_ONLY,
2889 ADDRTREE_DEL_FOLDER_ADDR
2893 * Delete an item from the tree widget.
2894 * \param data Data passed in.
2895 * \param action Action.
2896 * \param widget Widget issuing callback.
2898 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2900 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2901 GtkCMCTreeNode *node = NULL;
2905 AddrBookBase *adbase;
2906 AddressCache *cache;
2907 AdapterDSource *ads = NULL;
2908 AddressInterface *iface = NULL;
2909 AddressDataSource *ds = NULL;
2910 gboolean remFlag = FALSE;
2911 TreeItemDelType delType;
2913 if( ! addrbook.treeSelected ) return;
2914 node = addrbook.treeSelected;
2915 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2917 obj = gtk_cmctree_node_get_row_data( ctree, node );
2918 g_return_if_fail(obj != NULL);
2920 if( obj->type == ADDR_DATASOURCE ) {
2921 ads = ADAPTER_DSOURCE(obj);
2922 if( ads == NULL ) return;
2923 ds = ads->dataSource;
2924 if( ds == NULL ) return;
2927 /* Must be folder or something else */
2928 ds = addressbook_find_datasource( node );
2929 if( ds == NULL ) return;
2931 /* Only allow deletion from non-readOnly */
2932 iface = ds->interface;
2933 if( iface->readOnly ) {
2934 /* Allow deletion of query results */
2935 if( ! iface->externalQuery ) return;
2939 /* Confirm deletion */
2940 delType = ADDRTREE_DEL_NONE;
2941 if( obj->type == ADDR_ITEM_FOLDER ) {
2942 if( iface->externalQuery ) {
2943 message = g_strdup_printf( _(
2944 "Do you want to delete the query " \
2945 "results and addresses in '%s' ?" ),
2947 aval = alertpanel( _("Delete"), message,
2948 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2950 if( aval == G_ALERTALTERNATE ) {
2951 delType = ADDRTREE_DEL_FOLDER_ADDR;
2955 message = g_strdup_printf
2956 ( _( "Do you want to delete '%s' ? "
2957 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2959 aval = alertpanel( _("Delete folder"), message,
2960 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2962 if( aval == G_ALERTALTERNATE ) {
2963 delType = ADDRTREE_DEL_FOLDER_ONLY;
2965 else if( aval == G_ALERTOTHER ) {
2966 delType = ADDRTREE_DEL_FOLDER_ADDR;
2970 else if( obj->type == ADDR_ITEM_GROUP ) {
2971 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2972 "The addresses it contains will not be lost."), obj->name);
2973 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2974 "+" GTK_STOCK_DELETE, NULL);
2976 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2978 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2979 "The addresses it contains will be lost."), obj->name);
2980 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2981 "+" GTK_STOCK_DELETE, NULL);
2983 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2985 if( delType == ADDRTREE_DEL_NONE ) return;
2987 /* Proceed with deletion */
2988 if( obj->type == ADDR_DATASOURCE ) {
2989 /* Remove node from tree */
2990 gtk_cmctree_remove_node( ctree, node );
2992 /* Remove data source. */
2993 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2994 addrindex_free_datasource( ds );
2999 /* Get reference to cache */
3000 adbase = ( AddrBookBase * ) ds->rawDataSource;
3001 if( adbase == NULL ) return;
3002 cache = adbase->addressCache;
3004 /* Remove query results folder */
3005 if( iface->externalQuery ) {
3006 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3007 ItemFolder *folder = adapter->itemFolder;
3009 adapter->itemFolder = NULL;
3011 g_print( "remove folder for ::%s::\n", obj->name );
3012 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3013 g_print( "-------------- remove results\n" );
3015 addrindex_remove_results( ds, folder );
3016 /* g_print( "-------------- remove node\n" ); */
3017 gtk_cmctree_remove_node( ctree, node );
3021 /* Code below is valid for regular address book deletion */
3022 if( obj->type == ADDR_ITEM_FOLDER ) {
3023 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3024 ItemFolder *item = adapter->itemFolder;
3026 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3027 /* Remove folder only */
3028 item = addrcache_remove_folder( cache, item );
3030 addritem_free_item_folder( item );
3031 addressbook_move_nodes_up( ctree, node );
3035 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3036 /* Remove folder and addresses */
3037 item = addrcache_remove_folder_delete( cache, item );
3039 addritem_free_item_folder( item );
3044 else if( obj->type == ADDR_ITEM_GROUP ) {
3045 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3046 ItemGroup *item = adapter->itemGroup;
3048 item = addrcache_remove_group( cache, item );
3050 addritem_free_item_group( item );
3057 gtk_cmctree_remove_node(ctree, node );
3061 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3063 if( person && addrbook.treeSelected == addrbook.opened ) {
3064 person->status = ADD_ENTRY;
3065 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3066 addressbook_folder_refresh_one_person(
3067 GTK_CMCTREE(addrbook.clist), person );
3069 addressbook_address_list_set_focus();
3072 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3074 if( person && addrbook.treeSelected == addrbook.opened) {
3075 person->status = ADD_ENTRY;
3076 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3077 addressbook_set_clist(
3078 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3082 addressbook_address_list_set_focus();
3086 * Label (a format string) that is used to name each folder.
3088 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3091 * Search ctree widget callback function.
3092 * \param pA Pointer to node.
3093 * \param pB Pointer to data item being sought.
3094 * \return Zero (0) if folder found.
3096 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3099 aoA = ( AddressObject * ) pA;
3100 if( aoA->type == ADDR_ITEM_FOLDER ) {
3101 ItemFolder *folder, *fld;
3103 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3104 folder = ( ItemFolder * ) pB;
3105 if( fld == folder ) return 0; /* Found folder */
3110 static ItemFolder * addressbook_setup_subf(
3111 AddressDataSource *ds, gchar *title,
3112 GtkCMCTreeNode *pNode )
3114 AddrBookBase *adbase;
3115 AddressCache *cache;
3118 GtkCMCTreeNode *nNode;
3120 AddressObjectType aoType = ADDR_NONE;
3123 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3125 if( ds && ds->type == ADDR_IF_LDAP ) {
3127 aoType = ADDR_LDAP_QUERY;
3134 ctree = GTK_CMCTREE(addrbook.ctree);
3135 /* Get reference to address cache */
3136 adbase = ( AddrBookBase * ) ds->rawDataSource;
3137 cache = adbase->addressCache;
3139 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3140 GList *cur = children;
3141 for (; cur; cur = cur->next) {
3142 ItemFolder *child = (ItemFolder *) cur->data;
3143 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3144 nNode = gtk_cmctree_find_by_row_data_custom(
3146 addressbook_treenode_find_folder_cb );
3148 addrindex_remove_results( ds, child );
3149 while( child->listPerson ) {
3150 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3151 item = addrcache_remove_person( cache, item );
3153 addritem_free_item_person( item );
3157 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3158 addrbook.treeSelected = nNode;
3165 /* Create a folder */
3166 folder = addrcache_add_new_folder( cache, NULL );
3167 name = g_strdup_printf( "%s", title );
3168 addritem_folder_set_name( folder, name );
3169 addritem_folder_set_remarks( folder, "" );
3172 /* Now let's see the folder */
3173 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3174 gtk_cmctree_expand( ctree, pNode );
3176 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3177 addrbook.treeSelected = nNode;
3183 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3184 AddressObject *pobj = NULL;
3185 AddressDataSource *ds = NULL;
3186 AddressBookFile *abf = NULL;
3187 debug_print("adding address\n");
3188 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3189 if( pobj == NULL ) {
3190 debug_print("no row data\n");
3193 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3195 debug_print("no datasource\n");
3199 abf = ds->rawDataSource;
3201 g_print("no addressbook file\n");
3205 if( pobj->type == ADDR_DATASOURCE ) {
3206 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3207 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3209 ItemFolder *folder = NULL;
3211 if (abf && abf->type == ADDR_IF_LDAP) {
3212 GtkCMCTreeNode *parentNode;
3213 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3214 if( ds == NULL ) return;
3216 /* We must have a datasource that is an external interface */
3217 if( ! ds->interface->haveLibrary ) return;
3218 if( ! ds->interface->externalQuery ) return;
3220 if( pobj->type == ADDR_ITEM_FOLDER ) {
3221 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3224 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3226 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3228 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3229 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3230 abf = ds->rawDataSource;
3233 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3234 addrbook.editaddress_vbox,
3235 addressbook_new_address_from_book_post_cb,
3238 if (abf && abf->type == ADDR_IF_LDAP) {
3239 LdapServer *server = ds->rawDataSource;
3240 ldapsvr_set_modified(server, TRUE);
3241 ldapsvr_update_book(server, NULL);
3242 if (server->retVal != LDAPRC_SUCCESS) {
3243 alertpanel( _("Add address(es)"),
3244 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3245 GTK_STOCK_CLOSE, NULL, NULL );
3246 server->retVal = LDAPRC_SUCCESS;
3251 if (prefs_common.addressbook_use_editaddress_dialog)
3252 addressbook_new_address_from_book_post_cb( person );
3255 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3257 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3260 if (abf && abf->type == ADDR_IF_LDAP) {
3261 GtkCMCTreeNode *parentNode;
3262 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3263 if( ds == NULL ) return;
3265 /* We must have a datasource that is an external interface */
3266 if( ! ds->interface->haveLibrary ) return;
3267 if( ! ds->interface->externalQuery ) return;
3269 if( pobj->type == ADDR_ITEM_FOLDER ) {
3270 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3273 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3275 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3278 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3279 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3280 abf = ds->rawDataSource;
3283 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3284 addrbook.editaddress_vbox,
3285 addressbook_new_address_from_folder_post_cb,
3288 if (abf && abf->type == ADDR_IF_LDAP) {
3289 LdapServer *server = ds->rawDataSource;
3290 ldapsvr_set_modified(server, TRUE);
3291 ldapsvr_update_book(server, NULL);
3292 if (server->retVal != LDAPRC_SUCCESS) {
3293 alertpanel( _("Add address(es)"),
3294 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3295 GTK_STOCK_CLOSE, NULL, NULL );
3300 if (prefs_common.addressbook_use_editaddress_dialog)
3301 addressbook_new_address_from_folder_post_cb( person );
3303 else if( pobj->type == ADDR_ITEM_GROUP ) {
3304 /* New address in group */
3305 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3306 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3307 if (addrbook.treeSelected == addrbook.opened) {
3308 /* Change node name in tree. */
3309 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3310 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3311 addressbook_set_clist(
3312 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3320 * Search for specified child group node in address index tree.
3321 * \param parent Parent node.
3322 * \param group Group to find.
3324 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3325 GtkCMCTreeNode *node = NULL;
3326 GtkCMCTreeRow *currRow;
3328 currRow = GTK_CMCTREE_ROW( parent );
3330 node = currRow->children;
3334 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3335 if( obj->type == ADDR_ITEM_GROUP ) {
3336 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3337 if( g == group ) return node;
3339 currRow = GTK_CMCTREE_ROW(node);
3340 node = currRow->sibling;
3346 static AddressBookFile *addressbook_get_book_file() {
3347 AddressBookFile *abf = NULL;
3348 AddressDataSource *ds = NULL;
3350 ds = addressbook_find_datasource( addrbook.treeSelected );
3351 if( ds == NULL ) return NULL;
3352 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3356 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3357 GtkCMCTreeNode *node;
3360 /* Remove existing folders and groups */
3361 row = GTK_CMCTREE_ROW( parent );
3363 while( (node = row->children) ) {
3364 gtk_cmctree_remove_node( ctree, node );
3369 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3370 GtkCMCTreeNode *parent, *child;
3371 GtkCMCTreeRow *currRow;
3372 currRow = GTK_CMCTREE_ROW( node );
3374 parent = currRow->parent;
3375 while( (child = currRow->children) ) {
3376 gtk_cmctree_move( ctree, child, parent, node );
3378 gtk_sctree_sort_node( ctree, parent );
3382 static void addressbook_edit_address_post_cb( ItemPerson *person )
3386 AddressBookFile *abf = addressbook_get_book_file();
3388 if (abf && abf->type == ADDR_IF_LDAP) {
3389 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3390 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3393 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3394 invalidate_address_completion();
3396 addressbook_address_list_set_focus();
3399 void addressbook_address_list_set_focus( void )
3401 if (!prefs_common.addressbook_use_editaddress_dialog) {
3402 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3403 addressbook_list_menu_setup();
3407 void addressbook_address_list_disable_some_actions(void)
3409 /* disable address copy/pasting when editing contact's detail (embedded form) */
3410 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3411 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3412 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3415 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3416 addressbook_edit_address(data, 0, NULL, TRUE);
3419 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3420 gboolean force_focus ) {
3421 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3423 AddressObject *obj = NULL, *pobj = NULL;
3424 AddressDataSource *ds = NULL;
3425 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3427 AddressBookFile *abf = NULL;
3429 if( addrbook.listSelected == NULL ) return;
3430 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3431 g_return_if_fail(obj != NULL);
3433 ctree = GTK_CMCTREE( addrbook.ctree );
3434 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3435 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3437 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3438 if( ds == NULL ) return;
3440 abf = addressbook_get_book_file();
3442 if( obj->type == ADDR_ITEM_EMAIL ) {
3443 ItemEMail *email = ( ItemEMail * ) obj;
3444 if( email == NULL ) return;
3445 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3446 /* Edit parent group */
3447 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3448 ItemGroup *itemGrp = adapter->itemGroup;
3449 if( abf == NULL ) return;
3450 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3451 name = ADDRITEM_NAME(itemGrp);
3452 node = addrbook.treeSelected;
3453 parentNode = GTK_CMCTREE_ROW(node)->parent;
3456 /* Edit person - email page */
3458 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3459 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3460 addressbook_edit_address_post_cb,
3461 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3464 if (abf && abf->type == ADDR_IF_LDAP) {
3465 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3466 person->status = UPDATE_ENTRY;
3469 if (prefs_common.addressbook_use_editaddress_dialog)
3470 addressbook_edit_address_post_cb( person );
3475 else if( obj->type == ADDR_ITEM_PERSON ) {
3476 /* Edit person - basic page */
3477 ItemPerson *person = ( ItemPerson * ) obj;
3478 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3479 addressbook_edit_address_post_cb,
3480 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3483 if (abf && abf->type == ADDR_IF_LDAP) {
3484 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3485 person->status = UPDATE_ENTRY;
3488 if (prefs_common.addressbook_use_editaddress_dialog)
3489 addressbook_edit_address_post_cb( person );
3493 else if( obj->type == ADDR_ITEM_GROUP ) {
3494 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3495 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3496 parentNode = addrbook.treeSelected;
3497 node = addressbook_find_group_node( parentNode, itemGrp );
3498 name = ADDRITEM_NAME(itemGrp);
3499 invalidate_address_completion();
3505 /* Update tree node with node name */
3506 if( node == NULL ) return;
3507 addressbook_change_node_name( node, name );
3508 gtk_sctree_sort_node( ctree, parentNode );
3509 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3510 addressbook_set_clist(
3511 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3516 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3518 addressbook_del_clicked(NULL, NULL);
3521 static void close_cb(GtkAction *action, gpointer data)
3523 addressbook_close();
3526 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3527 addressbook_export_to_file();
3530 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3532 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3533 if( person ) addritem_person_set_opened( person, TRUE );
3537 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3539 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3540 if( person ) addritem_person_set_opened( person, FALSE );
3544 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3546 gchar *eMailAlias = ADDRITEM_NAME(email);
3547 if( eMailAlias && *eMailAlias != '\0' ) {
3549 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3552 str = g_strdup( eMailAlias );
3558 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3559 GList *items = itemGroup->listEMail;
3560 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3561 for( ; items != NULL; items = g_list_next( items ) ) {
3562 GtkCMCTreeNode *nodeEMail = NULL;
3563 gchar *text[N_LIST_COLS];
3564 ItemEMail *email = items->data;
3568 if( ! email ) continue;
3570 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3571 str = addressbook_format_item_clist( person, email );
3573 text[COL_NAME] = addressbook_set_col_name_guard(str);
3576 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3578 text[COL_ADDRESS] = email->address;
3579 text[COL_REMARKS] = email->remarks;
3580 nodeEMail = gtk_sctree_insert_node(
3582 text, FOLDER_SPACING,
3583 atci->iconXpm, atci->maskXpm,
3584 atci->iconXpmOpen, atci->maskXpmOpen,
3586 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3592 gchar *addressbook_set_col_name_guard(gchar *value)
3594 gchar *ret = "<not set>";
3595 gchar *tmp = g_strdup(value);
3597 if (tmp !=NULL && *tmp != '\0')
3603 static void addressbook_folder_load_one_person(
3604 GtkCMCTree *clist, ItemPerson *person,
3605 AddressTypeControlItem *atci,
3606 AddressTypeControlItem *atciMail )
3608 GtkCMCTreeNode *nodePerson = NULL;
3609 GtkCMCTreeNode *nodeEMail = NULL;
3610 gchar *text[N_LIST_COLS];
3611 gboolean flgFirst = TRUE, haveAddr = FALSE;
3614 AddressBookFile *abf = addressbook_get_book_file();
3617 if( person == NULL ) return;
3619 text[COL_NAME] = "";
3620 node = person->listEMail;
3622 ItemEMail *email = node->data;
3623 gchar *eMailAddr = NULL;
3624 node = g_list_next( node );
3626 text[COL_ADDRESS] = email->address;
3627 text[COL_REMARKS] = email->remarks;
3628 eMailAddr = ADDRITEM_NAME(email);
3629 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3631 /* First email belongs with person */
3632 gchar *str = addressbook_format_item_clist( person, email );
3634 text[COL_NAME] = addressbook_set_col_name_guard(str);
3637 else if( abf && abf->type == ADDR_IF_LDAP &&
3638 person && person->nickName ) {
3639 if (person->nickName) {
3640 if (strcmp(person->nickName, "") != 0) {
3641 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3644 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3650 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3652 nodePerson = gtk_sctree_insert_node(
3654 text, FOLDER_SPACING,
3655 atci->iconXpm, atci->maskXpm,
3656 atci->iconXpmOpen, atci->maskXpmOpen,
3657 FALSE, person->isOpened );
3660 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3663 /* Subsequent email is a child node of person */
3664 text[COL_NAME] = ADDRITEM_NAME(email);
3665 nodeEMail = gtk_sctree_insert_node(
3666 clist, nodePerson, NULL,
3667 text, FOLDER_SPACING,
3668 atciMail->iconXpm, atciMail->maskXpm,
3669 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3671 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3677 /* Have name without EMail */
3678 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3679 text[COL_ADDRESS] = "";
3680 text[COL_REMARKS] = "";
3681 nodePerson = gtk_sctree_insert_node(
3683 text, FOLDER_SPACING,
3684 atci->iconXpm, atci->maskXpm,
3685 atci->iconXpmOpen, atci->maskXpmOpen,
3686 FALSE, person->isOpened );
3687 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3692 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3694 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3695 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3697 if( atci == NULL ) return;
3698 if( atciMail == NULL ) return;
3700 /* Load email addresses */
3701 items = addritem_folder_get_person_list( itemFolder );
3702 for( ; items != NULL; items = g_list_next( items ) ) {
3703 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3705 /* Free up the list */
3706 mgu_clear_list( items );
3707 g_list_free( items );
3710 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3711 addrbook.listSelected = NULL;
3712 gtk_cmctree_remove_node( clist, node );
3713 addressbook_menubar_set_sensitive( FALSE );
3714 addressbook_menuitem_set_sensitive(
3715 gtk_cmctree_node_get_row_data(
3716 GTK_CMCTREE(clist), addrbook.treeSelected ),
3717 addrbook.treeSelected );
3720 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3721 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3722 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3723 GtkCMCTreeNode *node;
3724 if( atci == NULL ) return;
3725 if( atciMail == NULL ) return;
3726 if( person == NULL ) return;
3727 /* unload the person */
3729 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3731 addressbook_folder_remove_node( clist, node );
3732 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3733 gtk_sctree_sort_node( clist, NULL );
3734 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3736 gtk_sctree_select( GTK_SCTREE(clist), node );
3737 if (!gtk_cmctree_node_is_visible( clist, node ) )
3738 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3742 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3743 GtkCMCTreeNode *node;
3746 if( person == NULL ) return;
3747 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3748 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3750 addressbook_folder_remove_node( clist, node );
3754 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3756 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3758 /* Load any groups */
3759 if( ! atci ) return;
3760 items = addritem_folder_get_group_list( itemFolder );
3761 for( ; items != NULL; items = g_list_next( items ) ) {
3762 GtkCMCTreeNode *nodeGroup = NULL;
3763 gchar *text[N_LIST_COLS];
3764 ItemGroup *group = items->data;
3765 if( group == NULL ) continue;
3766 text[COL_NAME] = ADDRITEM_NAME(group);
3767 text[COL_ADDRESS] = "";
3768 text[COL_REMARKS] = "";
3769 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3770 text, FOLDER_SPACING,
3771 atci->iconXpm, atci->maskXpm,
3772 atci->iconXpmOpen, atci->maskXpmOpen,
3774 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3775 gtk_sctree_sort_node(clist, NULL);
3777 /* Free up the list */
3778 mgu_clear_list( items );
3779 g_list_free( items );
3783 * Search ctree widget callback function.
3784 * \param pA Pointer to node.
3785 * \param pB Pointer to data item being sought.
3786 * \return Zero (0) if group found.
3788 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3791 aoA = ( AddressObject * ) pA;
3792 if( aoA->type == ADDR_ITEM_GROUP ) {
3793 ItemGroup *group, *grp;
3795 grp = ADAPTER_GROUP(aoA)->itemGroup;
3796 group = ( ItemGroup * ) pB;
3797 if( grp == group ) return 0; /* Found group */
3803 * Remove folder and group nodes from tree widget for items contained ("cut")
3806 static void addressbook_treenode_remove_item( void ) {
3808 AddrSelectItem *cutItem;
3809 AddressCache *cache;
3810 AddrItemObject *aio;
3811 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3814 node = _clipBoard_->objectList;
3816 cutItem = node->data;
3817 node = g_list_next( node );
3818 cache = addrindex_get_cache(
3819 _clipBoard_->addressIndex, cutItem->cacheID );
3820 if( cache == NULL ) continue;
3821 aio = addrcache_get_object( cache, cutItem->uid );
3824 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3827 folder = ( ItemFolder * ) aio;
3828 tn = gtk_cmctree_find_by_row_data_custom(
3829 ctree, NULL, folder,
3830 addressbook_treenode_find_folder_cb );
3832 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3835 group = ( ItemGroup * ) aio;
3836 tn = gtk_cmctree_find_by_row_data_custom(
3838 addressbook_treenode_find_group_cb );
3842 /* Free up adapter and remove node. */
3843 gtk_cmctree_remove_node( ctree, tn );
3850 * Find parent datasource for specified tree node.
3851 * \param node Node to test.
3852 * \return Data source, or NULL if not found.
3854 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3855 AddressDataSource *ds = NULL;
3858 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3861 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3862 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3864 /* g_print( "ao->type = %d\n", ao->type ); */
3865 if( ao->type == ADDR_DATASOURCE ) {
3866 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3867 /* g_print( "found it\n" ); */
3868 ds = ads->dataSource;
3872 node = GTK_CMCTREE_ROW(node)->parent;
3878 * Load address list widget with children of specified object.
3879 * \param obj Parent object to be loaded.
3881 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3882 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3883 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3884 AddressDataSource *ds = NULL;
3885 AdapterDSource *ads = NULL;
3886 static AddressObject *last_obj = NULL;
3888 if (addrbook.clist == NULL) {
3891 if (obj == last_obj && !refresh)
3896 gtk_cmclist_clear(clist);
3900 if( obj->type == ADDR_INTERFACE ) {
3901 /* g_print( "set_clist: loading datasource...\n" ); */
3902 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3906 gtk_cmclist_freeze(clist);
3907 gtk_cmclist_clear(clist);
3909 if( obj->type == ADDR_DATASOURCE ) {
3910 ads = ADAPTER_DSOURCE(obj);
3911 ds = ADAPTER_DSOURCE(obj)->dataSource;
3913 /* Load root folder */
3914 ItemFolder *rootFolder = NULL;
3915 rootFolder = addrindex_ds_get_root_folder( ds );
3916 addressbook_folder_load_person(
3917 ctreelist, addrindex_ds_get_root_folder( ds ) );
3918 addressbook_folder_load_group(
3919 ctreelist, addrindex_ds_get_root_folder( ds ) );
3923 if( obj->type == ADDR_ITEM_GROUP ) {
3925 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3926 addressbook_load_group( ctreelist, itemGroup );
3928 else if( obj->type == ADDR_ITEM_FOLDER ) {
3930 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3931 addressbook_folder_load_person( ctreelist, itemFolder );
3932 addressbook_folder_load_group( ctreelist, itemFolder );
3935 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3936 clist->focus_row = -1;
3937 gtk_cmclist_thaw(clist);
3941 * Call back function to free adaptor. Call back is setup by function
3942 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3943 * called when the address book tree widget node is removed by calling
3944 * function gtk_cmctree_remove_node().
3946 * \param data Tree node's row data.
3948 static void addressbook_free_treenode( gpointer data ) {
3951 ao = ( AddressObject * ) data;
3952 if( ao == NULL ) return;
3953 if( ao->type == ADDR_INTERFACE ) {
3954 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3955 addrbookctl_free_interface( ai );
3957 else if( ao->type == ADDR_DATASOURCE ) {
3958 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3959 addrbookctl_free_datasource( ads );
3961 else if( ao->type == ADDR_ITEM_FOLDER ) {
3962 AdapterFolder *af = ADAPTER_FOLDER(ao);
3963 addrbookctl_free_folder( af );
3965 else if( ao->type == ADDR_ITEM_GROUP ) {
3966 AdapterGroup *ag = ADAPTER_GROUP(ao);
3967 addrbookctl_free_group( ag );
3972 * Create new adaptor for specified data source.
3974 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3975 AddressObjectType otype, gchar *name )
3977 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3978 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3979 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3980 adapter->dataSource = ds;
3981 adapter->subType = otype;
3985 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3986 ADDRESS_OBJECT_NAME(adapter) =
3987 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3991 * Load tree from address index with the initial data.
3993 static void addressbook_load_tree( void ) {
3994 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3995 GList *nodeIf, *nodeDS;
3996 AdapterInterface *adapter;
3997 AddressInterface *iface;
3998 AddressTypeControlItem *atci;
3999 AddressDataSource *ds;
4000 AdapterDSource *ads;
4001 GtkCMCTreeNode *node, *newNode;
4004 nodeIf = _addressInterfaceList_;
4006 adapter = nodeIf->data;
4007 node = adapter->treeNode;
4008 iface = adapter->interface;
4009 atci = adapter->atci;
4011 if( iface->useInterface ) {
4012 /* Load data sources below interface node */
4013 nodeDS = iface->listSource;
4017 name = addrindex_ds_get_name( ds );
4018 ads = addressbook_create_ds_adapter(
4019 ds, atci->objectType, name );
4020 newNode = addressbook_add_object(
4021 node, ADDRESS_OBJECT(ads) );
4022 nodeDS = g_list_next( nodeDS );
4024 gtk_cmctree_expand( ctree, node );
4027 nodeIf = g_list_next( nodeIf );
4032 * Convert the old address book to new format.
4034 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4035 gboolean retVal = FALSE;
4036 gboolean errFlag = TRUE;
4039 /* Read old address book, performing conversion */
4040 debug_print( "Reading and converting old address book...\n" );
4041 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4042 addrindex_read_data( addrIndex );
4043 if( addrIndex->retVal == MGU_NO_FILE ) {
4044 /* We do not have a file - new user */
4045 debug_print( "New user... create new books...\n" );
4046 addrindex_create_new_books( addrIndex );
4047 if( addrIndex->retVal == MGU_SUCCESS ) {
4048 /* Save index file */
4049 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4050 addrindex_save_data( addrIndex );
4051 if( addrIndex->retVal == MGU_SUCCESS ) {
4056 msg = _( "New user, could not save index file." );
4060 msg = _( "New user, could not save address book files." );
4064 /* We have an old file */
4065 if( addrIndex->wasConverted ) {
4066 /* Converted successfully - save address index */
4067 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4068 addrindex_save_data( addrIndex );
4069 if( addrIndex->retVal == MGU_SUCCESS ) {
4070 msg = _( "Old address book converted successfully." );
4075 msg = _("Old address book converted,\n"
4076 "could not save new address index file." );
4080 /* File conversion failed - just create new books */
4081 debug_print( "File conversion failed... just create new books...\n" );
4082 addrindex_create_new_books( addrIndex );
4083 if( addrIndex->retVal == MGU_SUCCESS ) {
4085 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4086 addrindex_save_data( addrIndex );
4087 if( addrIndex->retVal == MGU_SUCCESS ) {
4088 msg = _("Could not convert address book,\n"
4089 "but created empty new address book files." );
4094 msg = _("Could not convert address book,\n"
4095 "could not save new address index file." );
4099 msg = _("Could not convert address book\n"
4100 "and could not create new address book files." );
4105 debug_print( "Error\n%s\n", msg );
4106 alertpanel_full(_("Addressbook conversion error"), msg,
4107 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4108 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4111 debug_print( "Warning\n%s\n", msg );
4112 alertpanel_full(_("Addressbook conversion error"), msg,
4113 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4114 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4120 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4124 gboolean failed = FALSE;
4126 if( ( dp = opendir( origdir ) ) == NULL ) {
4130 while( ( d = readdir( dp ) ) != NULL ) {
4131 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4134 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4136 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4138 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4151 /* all copies succeeded, we can remove source files */
4152 if( ( dp = opendir( origdir ) ) == NULL ) {
4155 while( ( d = readdir( dp ) ) != NULL ) {
4156 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4159 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4161 claws_unlink(orig_file);
4171 void addressbook_read_file( void ) {
4172 AddressIndex *addrIndex = NULL;
4173 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4175 debug_print( "Reading address index...\n" );
4176 if( _addressIndex_ ) {
4177 debug_print( "address book already read!!!\n" );
4181 addrIndex = addrindex_create_index();
4182 addrindex_initialize();
4184 /* Use new address book index. */
4186 if ( !is_dir_exist(indexdir) ) {
4187 if ( make_dir(indexdir) < 0 ) {
4188 addrindex_set_file_path( addrIndex, get_rc_dir() );
4189 g_warning( "couldn't create dir %s\n", indexdir);
4191 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4192 remove_dir_recursive(indexdir);
4193 addrindex_set_file_path( addrIndex, get_rc_dir() );
4194 g_error("couldn't migrate dir %s", indexdir);
4196 addrindex_set_file_path( addrIndex, indexdir);
4200 addrindex_set_file_path( addrIndex, indexdir);
4203 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4204 addrindex_read_data( addrIndex );
4205 if( addrIndex->retVal == MGU_NO_FILE ) {
4206 /* Conversion required */
4207 debug_print( "Converting...\n" );
4208 if( addressbook_convert( addrIndex ) ) {
4209 _addressIndex_ = addrIndex;
4212 else if( addrIndex->retVal == MGU_SUCCESS ) {
4213 _addressIndex_ = addrIndex;
4216 /* Error reading address book */
4217 debug_print( "Could not read address index.\n" );
4218 addrindex_print_index( addrIndex, stdout );
4219 alertpanel_full(_("Addressbook Error"),
4220 _("Could not read address index"),
4221 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4222 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4224 debug_print( "done.\n" );
4228 * Add object into the address index tree widget.
4229 * Enter: node Parent node.
4230 * obj Object to add.
4231 * Return: Node that was added, or NULL if object not added.
4233 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4236 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4237 GtkCMCTreeNode *added;
4238 AddressObject *pobj;
4239 AddressObjectType otype;
4240 AddressTypeControlItem *atci = NULL;
4242 g_return_val_if_fail(node != NULL, NULL);
4243 g_return_val_if_fail(obj != NULL, NULL);
4245 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4246 g_return_val_if_fail(pobj != NULL, NULL);
4248 /* Determine object type to be displayed */
4249 if( obj->type == ADDR_DATASOURCE ) {
4250 otype = ADAPTER_DSOURCE(obj)->subType;
4256 /* Handle any special conditions. */
4258 atci = addrbookctl_lookup( otype );
4260 if( atci->showInTree ) {
4261 /* Add object to tree */
4264 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4265 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4266 atci->treeLeaf, atci->treeExpand );
4267 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4268 addressbook_free_treenode );
4272 gtk_sctree_sort_node(ctree, node);
4278 * Add group into the address index tree.
4279 * \param node Parent node.
4280 * \param ds Data source.
4281 * \param itemGroup Group to add.
4282 * \return Inserted node.
4284 static GtkCMCTreeNode *addressbook_node_add_group(
4285 GtkCMCTreeNode *node, AddressDataSource *ds,
4286 ItemGroup *itemGroup )
4288 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4289 GtkCMCTreeNode *newNode;
4290 AdapterGroup *adapter;
4291 AddressTypeControlItem *atci = NULL;
4294 if( ds == NULL ) return NULL;
4295 if( node == NULL || itemGroup == NULL ) return NULL;
4297 name = &itemGroup->obj.name;
4299 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4301 adapter = g_new0( AdapterGroup, 1 );
4302 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4303 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4304 adapter->itemGroup = itemGroup;
4306 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4307 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4308 atci->treeLeaf, atci->treeExpand );
4309 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4310 addressbook_free_treenode );
4311 gtk_sctree_sort_node( ctree, node );
4316 * Add folder into the address index tree. Only visible folders are loaded into
4317 * the address index tree. Note that the root folder is not inserted into the
4320 * \param node Parent node.
4321 * \param ds Data source.
4322 * \param itemFolder Folder to add.
4323 * \param otype Object type to display.
4324 * \return Inserted node for the folder.
4326 static GtkCMCTreeNode *addressbook_node_add_folder(
4327 GtkCMCTreeNode *node, AddressDataSource *ds,
4328 ItemFolder *itemFolder, AddressObjectType otype )
4330 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4331 GtkCMCTreeNode *newNode = NULL;
4332 AdapterFolder *adapter;
4333 AddressTypeControlItem *atci = NULL;
4334 GList *listItems = NULL;
4336 ItemFolder *rootFolder;
4338 /* Only visible folders */
4339 if( itemFolder->isHidden ) return NULL;
4341 if( ds == NULL ) return NULL;
4342 if( node == NULL || itemFolder == NULL ) return NULL;
4344 /* Determine object type */
4345 atci = addrbookctl_lookup( otype );
4346 if( atci == NULL ) return NULL;
4348 rootFolder = addrindex_ds_get_root_folder( ds );
4349 if( itemFolder == rootFolder ) {
4353 adapter = g_new0( AdapterFolder, 1 );
4354 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4355 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4356 adapter->itemFolder = itemFolder;
4358 name = ADDRITEM_NAME(itemFolder);
4359 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4360 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4361 atci->treeLeaf, atci->treeExpand );
4363 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4364 addressbook_free_treenode );
4368 listItems = itemFolder->listFolder;
4369 while( listItems ) {
4370 ItemFolder *item = listItems->data;
4371 addressbook_node_add_folder( newNode, ds, item, otype );
4372 listItems = g_list_next( listItems );
4374 listItems = itemFolder->listGroup;
4375 while( listItems ) {
4376 ItemGroup *item = listItems->data;
4377 addressbook_node_add_group( newNode, ds, item );
4378 listItems = g_list_next( listItems );
4380 gtk_sctree_sort_node( ctree, node );
4384 void addressbook_export_to_file( void ) {
4385 if( _addressIndex_ ) {
4386 /* Save all new address book data */
4387 debug_print( "Saving address books...\n" );
4388 addrindex_save_all_books( _addressIndex_ );
4390 debug_print( "Exporting addressbook to file...\n" );
4391 addrindex_save_data( _addressIndex_ );
4392 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4393 addrindex_print_index( _addressIndex_, stdout );
4396 /* Notify address completion of new data */
4397 invalidate_address_completion();
4401 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4403 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4404 addressbook_lup_clicked(NULL, NULL);
4409 * Comparison using cell contents (text in first column). Used for sort
4410 * address index widget.
4412 static gint addressbook_treenode_compare_func(
4413 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4415 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4416 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4417 gchar *name1 = NULL, *name2 = NULL;
4418 if( cell1 ) name1 = cell1->u.text;
4419 if( cell2 ) name2 = cell2->u.text;
4420 if( ! name1 ) return ( name2 != NULL );
4421 if( ! name2 ) return -1;
4422 return g_utf8_collate( name1, name2 );
4425 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4426 AdapterDSource *ads;
4427 AdapterInterface *adapter;
4428 GtkCMCTreeNode *newNode;
4430 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4431 if( adapter == NULL ) return;
4432 ads = addressbook_edit_book( _addressIndex_, NULL );
4434 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4436 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4437 addrbook.treeSelected = newNode;
4442 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4443 AdapterDSource *ads;
4444 AdapterInterface *adapter;
4445 GtkCMCTreeNode *newNode;
4447 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4448 if( adapter == NULL ) return;
4449 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4451 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4453 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4454 addrbook.treeSelected = newNode;
4460 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4461 AdapterDSource *ads;
4462 AdapterInterface *adapter;
4463 AddressInterface *iface;
4464 GtkCMCTreeNode *newNode;
4466 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4467 if( adapter == NULL ) return;
4468 iface = adapter->interface;
4469 if( ! iface->haveLibrary ) return;
4470 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4472 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4474 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4475 addrbook.treeSelected = newNode;
4482 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4483 AdapterDSource *ads;
4484 AdapterInterface *adapter;
4485 AddressInterface *iface;
4486 GtkCMCTreeNode *newNode;
4488 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4489 if( adapter == NULL ) return;
4490 iface = adapter->interface;
4491 if( ! iface->haveLibrary ) return;
4492 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4494 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4496 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4497 addrbook.treeSelected = newNode;
4504 * Display address search status message.
4505 * \param queryType Query type.
4506 * \param status Status/Error code.
4508 static void addressbook_search_message( gint queryType, gint sts ) {
4510 *addressbook_msgbuf = '\0';
4512 if( sts != MGU_SUCCESS ) {
4513 if( queryType == ADDRQUERY_LDAP ) {
4515 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4520 g_snprintf( addressbook_msgbuf,
4521 sizeof(addressbook_msgbuf), "%s", desc );
4522 addressbook_status_show( addressbook_msgbuf );
4525 addressbook_status_show( "" );
4530 * Refresh addressbook by forcing refresh of current selected object in
4533 static void addressbook_refresh_current( void ) {
4537 ctree = GTK_CMCTREE(addrbook.ctree);
4538 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4539 if( obj == NULL ) return;
4540 addressbook_set_clist( obj, TRUE );
4544 * Message that is displayed whilst a query is executing in a background
4547 static gchar *_tempMessage_ = N_( "Busy searching..." );
4550 * Address search idle function. This function is called during UI idle time
4551 * while a search is in progress.
4553 * \param data Idler data.
4555 static void addressbook_search_idle( gpointer data ) {
4559 queryID = GPOINTER_TO_INT( data );
4560 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4565 * Search completion callback function. This removes the query from the idle
4568 * \param sender Sender of query.
4569 * \param queryID Query ID of search request.
4570 * \param status Search status.
4571 * \param data Query data.
4573 static void addressbook_search_callback_end(
4574 gpointer sender, gint queryID, gint status, gpointer data )
4578 AddrQueryObject *aqo;
4580 /* Remove idler function */
4581 ptrQID = GINT_TO_POINTER( queryID );
4583 g_idle_remove_by_data( ptrQID );
4586 /* Refresh addressbook contents */
4587 addressbook_refresh_current();
4588 req = qrymgr_find_request( queryID );
4590 aqo = ( AddrQueryObject * ) req->queryList->data;
4591 addressbook_search_message( aqo->queryType, status );
4594 /* Stop the search */
4595 addrindex_stop_search( queryID );
4601 * \param ds Data source to search.
4602 * \param searchTerm String to lookup.
4603 * \param pNode Parent data source node.
4605 static void addressbook_perform_search(
4606 AddressDataSource *ds, gchar *searchTerm,
4607 GtkCMCTreeNode *pNode )
4609 AddrBookBase *adbase;
4610 AddressCache *cache;
4616 AddressObjectType aoType = ADDR_NONE;
4620 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4622 if( ds && ds->type == ADDR_IF_LDAP ) {
4624 aoType = ADDR_LDAP_QUERY;
4630 /* Get reference to address cache */
4631 adbase = ( AddrBookBase * ) ds->rawDataSource;
4632 cache = adbase->addressCache;
4634 /* Create a folder for the search results */
4635 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4636 folder = addressbook_setup_subf(ds, name, pNode);
4639 /* Setup the search */
4640 queryID = addrindex_setup_explicit_search(
4641 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4642 if( queryID == 0 ) return;
4644 /* Set up idler function */
4645 idleID = g_idle_add(
4646 ( GtkFunction ) addressbook_search_idle,
4647 GINT_TO_POINTER( queryID ) );
4649 /* Start search, sit back and wait for something to happen */
4650 addrindex_start_search( queryID );
4652 addressbook_status_show( _tempMessage_ );
4656 * Lookup button handler. Address search is only performed against
4657 * address interfaces for external queries.
4659 * \param button Lookup button widget.
4660 * \param data Data object.
4662 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4665 AddressDataSource *ds;
4666 AddressInterface *iface;
4668 GtkCMCTreeNode *node, *parentNode;
4670 node = addrbook.treeSelected;
4671 if( ! node ) return;
4672 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4674 ctree = GTK_CMCTREE(addrbook.ctree);
4675 obj = gtk_cmctree_node_get_row_data( ctree, node );
4676 if( obj == NULL ) return;
4678 ds = addressbook_find_datasource( node );
4679 if( ds == NULL ) return;
4681 /* We must have a datasource that is an external interface */
4682 iface = ds->interface;
4683 if( ! iface->haveLibrary ) return;
4684 if( ! iface->externalQuery ) return;
4687 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4688 g_strchomp( searchTerm );
4690 if( obj->type == ADDR_ITEM_FOLDER ) {
4691 parentNode = GTK_CMCTREE_ROW(node)->parent;
4696 addressbook_perform_search( ds, searchTerm, parentNode );
4698 gtk_widget_grab_focus( addrbook.entry );
4700 g_free( searchTerm );
4703 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4704 addressbook_close();
4709 * Browse address entry for highlighted entry.
4711 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4713 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4715 AddressDataSource *ds;
4716 AddressInterface *iface;
4720 if(addrbook.listSelected == NULL)
4723 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4727 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4731 iface = ds->interface;
4732 if(! iface->haveLibrary )
4736 if (obj->type == ADDR_ITEM_EMAIL) {
4737 email = ( ItemEMail * ) obj;
4741 person = (ItemPerson *) ADDRITEM_PARENT(email);
4743 else if (obj->type == ADDR_ITEM_PERSON) {
4744 person = (ItemPerson *) obj;
4751 if( iface && iface->type == ADDR_IF_LDAP ) {
4752 browseldap_entry(ds, person->externalID);
4757 /* **********************************************************************
4758 * Build lookup tables.
4759 * ***********************************************************************
4763 * Remap object types.
4764 * Enter: abType AddressObjectType (used in tree node).
4765 * Return: ItemObjectType (used in address cache data).
4767 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4768 ItemObjectType ioType;
4771 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4772 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4773 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4774 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4775 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4776 default: ioType = ITEMTYPE_NONE; break;
4782 * Build table that controls the rendering of object types.
4784 static void addrbookctl_build_map( GtkWidget *window ) {
4785 AddressTypeControlItem *atci;
4788 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4789 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4790 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4791 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4792 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4793 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4794 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4795 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4796 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4797 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4799 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4800 _addressBookTypeList_ = NULL;
4803 atci = g_new0( AddressTypeControlItem, 1 );
4804 atci->objectType = ADDR_INTERFACE;
4805 atci->interfaceType = ADDR_IF_NONE;
4806 atci->showInTree = TRUE;
4807 atci->treeExpand = TRUE;
4808 atci->treeLeaf = FALSE;
4809 atci->displayName = _( "Interface" );
4810 atci->iconXpm = folderxpm;
4811 atci->maskXpm = folderxpmmask;
4812 atci->iconXpmOpen = folderopenxpm;
4813 atci->maskXpmOpen = folderopenxpmmask;
4814 atci->menuCommand = NULL;
4815 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4816 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4819 atci = g_new0( AddressTypeControlItem, 1 );
4820 atci->objectType = ADDR_BOOK;
4821 atci->interfaceType = ADDR_IF_BOOK;
4822 atci->showInTree = TRUE;
4823 atci->treeExpand = TRUE;
4824 atci->treeLeaf = FALSE;
4825 atci->displayName = _( "Address Book" );
4826 atci->iconXpm = bookxpm;
4827 atci->maskXpm = bookxpmmask;
4828 atci->iconXpmOpen = bookxpm;
4829 atci->maskXpmOpen = bookxpmmask;
4830 atci->menuCommand = "Menu/Book/NewBook";
4831 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4832 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4835 atci = g_new0( AddressTypeControlItem, 1 );
4836 atci->objectType = ADDR_ITEM_PERSON;
4837 atci->interfaceType = ADDR_IF_NONE;
4838 atci->showInTree = FALSE;
4839 atci->treeExpand = FALSE;
4840 atci->treeLeaf = FALSE;
4841 atci->displayName = _( "Person" );
4842 atci->iconXpm = NULL;
4843 atci->maskXpm = NULL;
4844 atci->iconXpmOpen = NULL;
4845 atci->maskXpmOpen = NULL;
4846 atci->menuCommand = NULL;
4847 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4848 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4851 atci = g_new0( AddressTypeControlItem, 1 );
4852 atci->objectType = ADDR_ITEM_EMAIL;
4853 atci->interfaceType = ADDR_IF_NONE;
4854 atci->showInTree = FALSE;
4855 atci->treeExpand = FALSE;
4856 atci->treeLeaf = TRUE;
4857 atci->displayName = _( "Email Address" );
4858 atci->iconXpm = addressxpm;
4859 atci->maskXpm = addressxpmmask;
4860 atci->iconXpmOpen = addressxpm;
4861 atci->maskXpmOpen = addressxpmmask;
4862 atci->menuCommand = NULL;
4863 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4864 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4867 atci = g_new0( AddressTypeControlItem, 1 );
4868 atci->objectType = ADDR_ITEM_GROUP;
4869 atci->interfaceType = ADDR_IF_BOOK;
4870 atci->showInTree = TRUE;
4871 atci->treeExpand = FALSE;
4872 atci->treeLeaf = FALSE;
4873 atci->displayName = _( "Group" );
4874 atci->iconXpm = groupxpm;
4875 atci->maskXpm = groupxpmmask;
4876 atci->iconXpmOpen = groupxpm;
4877 atci->maskXpmOpen = groupxpmmask;
4878 atci->menuCommand = NULL;
4879 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4880 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4883 atci = g_new0( AddressTypeControlItem, 1 );
4884 atci->objectType = ADDR_ITEM_FOLDER;
4885 atci->interfaceType = ADDR_IF_BOOK;
4886 atci->showInTree = TRUE;
4887 atci->treeExpand = FALSE;
4888 atci->treeLeaf = FALSE;
4889 atci->displayName = _( "Folder" );
4890 atci->iconXpm = folderxpm;
4891 atci->maskXpm = folderxpmmask;
4892 atci->iconXpmOpen = folderopenxpm;
4893 atci->maskXpmOpen = folderopenxpmmask;
4894 atci->menuCommand = NULL;
4895 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4896 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4899 atci = g_new0( AddressTypeControlItem, 1 );
4900 atci->objectType = ADDR_VCARD;
4901 atci->interfaceType = ADDR_IF_VCARD;
4902 atci->showInTree = TRUE;
4903 atci->treeExpand = TRUE;
4904 atci->treeLeaf = TRUE;
4905 atci->displayName = _( "vCard" );
4906 atci->iconXpm = vcardxpm;
4907 atci->maskXpm = vcardxpmmask;
4908 atci->iconXpmOpen = vcardxpm;
4909 atci->maskXpmOpen = vcardxpmmask;
4910 atci->menuCommand = "Menu/Book/NewVCard";
4911 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4912 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4915 atci = g_new0( AddressTypeControlItem, 1 );
4916 atci->objectType = ADDR_JPILOT;
4917 atci->interfaceType = ADDR_IF_JPILOT;
4918 atci->showInTree = TRUE;
4919 atci->treeExpand = TRUE;
4920 atci->treeLeaf = FALSE;
4921 atci->displayName = _( "JPilot" );
4922 atci->iconXpm = jpilotxpm;
4923 atci->maskXpm = jpilotxpmmask;
4924 atci->iconXpmOpen = jpilotxpm;
4925 atci->maskXpmOpen = jpilotxpmmask;
4926 atci->menuCommand = "Menu/Book/NewJPilot";
4927 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4928 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4931 atci = g_new0( AddressTypeControlItem, 1 );
4932 atci->objectType = ADDR_CATEGORY;
4933 atci->interfaceType = ADDR_IF_JPILOT;
4934 atci->showInTree = TRUE;
4935 atci->treeExpand = TRUE;
4936 atci->treeLeaf = TRUE;
4937 atci->displayName = _( "JPilot" );
4938 atci->iconXpm = categoryxpm;
4939 atci->maskXpm = categoryxpmmask;
4940 atci->iconXpmOpen = categoryxpm;
4941 atci->maskXpmOpen = categoryxpmmask;
4942 atci->menuCommand = NULL;
4943 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4944 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4947 atci = g_new0( AddressTypeControlItem, 1 );
4948 atci->objectType = ADDR_LDAP;
4949 atci->interfaceType = ADDR_IF_LDAP;
4950 atci->showInTree = TRUE;
4951 atci->treeExpand = TRUE;
4952 atci->treeLeaf = FALSE;
4953 atci->displayName = _( "LDAP servers" );
4954 atci->iconXpm = ldapxpm;
4955 atci->maskXpm = ldapxpmmask;
4956 atci->iconXpmOpen = ldapxpm;
4957 atci->maskXpmOpen = ldapxpmmask;
4958 atci->menuCommand = "Menu/Book/NewLDAPServer";
4959 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4960 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4963 atci = g_new0( AddressTypeControlItem, 1 );
4964 atci->objectType = ADDR_LDAP_QUERY;
4965 atci->interfaceType = ADDR_IF_LDAP;
4966 atci->showInTree = TRUE;
4967 atci->treeExpand = FALSE;
4968 atci->treeLeaf = TRUE;
4969 atci->displayName = _( "LDAP Query" );
4970 atci->iconXpm = addrsearchxpm;
4971 atci->maskXpm = addrsearchxpmmask;
4972 atci->iconXpmOpen = addrsearchxpm;
4973 atci->maskXpmOpen = addrsearchxpmmask;
4974 atci->menuCommand = NULL;
4975 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4976 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4981 * Search for specified object type.
4983 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4985 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4989 * Search for specified interface type.
4991 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4992 GList *node = _addressBookTypeList_;
4994 AddressTypeControlItem *atci = node->data;
4995 if( atci->interfaceType == ifType ) return atci;
4996 node = g_list_next( node );
5001 static void addrbookctl_free_address( AddressObject *obj ) {
5002 g_free( obj->name );
5003 obj->type = ADDR_NONE;
5007 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5008 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5009 adapter->interface = NULL;
5010 adapter->interfaceType = ADDR_IF_NONE;
5011 adapter->atci = NULL;
5012 adapter->enabled = FALSE;
5013 adapter->haveLibrary = FALSE;
5014 adapter->treeNode = NULL;
5018 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5019 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5020 adapter->dataSource = NULL;
5021 adapter->subType = ADDR_NONE;
5025 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5026 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5027 adapter->itemFolder = NULL;
5031 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5032 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5033 adapter->itemGroup = NULL;
5038 * Build GUI interface list.
5040 static void addrbookctl_build_iflist( void ) {
5041 AddressTypeControlItem *atci;
5042 AdapterInterface *adapter;
5045 if( _addressIndex_ == NULL ) {
5046 _addressIndex_ = addrindex_create_index();
5047 if( _clipBoard_ == NULL ) {
5048 _clipBoard_ = addrclip_create();
5050 addrclip_set_index( _clipBoard_, _addressIndex_ );
5052 _addressInterfaceList_ = NULL;
5053 list = addrindex_get_interface_list( _addressIndex_ );
5055 AddressInterface *interface = list->data;
5056 atci = addrbookctl_lookup_iface( interface->type );
5058 adapter = g_new0( AdapterInterface, 1 );
5059 adapter->interfaceType = interface->type;
5060 adapter->atci = atci;
5061 adapter->interface = interface;
5062 adapter->treeNode = NULL;
5063 adapter->enabled = TRUE;
5064 adapter->haveLibrary = interface->haveLibrary;
5065 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5066 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5067 _addressInterfaceList_ =
5068 g_list_append( _addressInterfaceList_, adapter );
5070 list = g_list_next( list );
5075 * Find GUI interface type specified interface type.
5076 * \param ifType Interface type.
5077 * \return Interface item, or NULL if not found.
5079 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5080 GList *node = _addressInterfaceList_;
5082 AdapterInterface *adapter = node->data;
5083 if( adapter->interfaceType == ifType ) return adapter;
5084 node = g_list_next( node );
5090 * Build interface list selection.
5092 static void addrbookctl_build_ifselect( void ) {
5093 GList *newList = NULL;
5098 gchar *endptr = NULL;
5100 AdapterInterface *adapter;
5102 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5105 splitStr = g_strsplit( selectStr, ",", -1 );
5106 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5108 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5109 ifType = strtol( splitStr[i], &endptr, 10 );
5112 if( strcmp( endptr, "/n" ) == 0 ) {
5116 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5117 adapter = addrbookctl_find_interface( ifType );
5119 newList = g_list_append( newList, adapter );
5126 /* g_print( "i=%d\n", i ); */
5127 g_strfreev( splitStr );
5128 g_free( selectStr );
5130 /* Replace existing list */
5131 mgu_clear_list( _addressIFaceSelection_ );
5132 g_list_free( _addressIFaceSelection_ );
5133 _addressIFaceSelection_ = newList;
5137 /* ***********************************************************************
5138 * Add sender to address book.
5139 * ***********************************************************************
5143 * This function is used by the Add sender to address book function.
5145 gboolean addressbook_add_contact(
5146 const gchar *name, const gchar *address, const gchar *remarks,
5147 GdkPixbuf *picture )
5149 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5150 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5151 debug_print( "addressbook_add_contact - added\n" );
5152 addressbook_refresh();
5157 /* ***********************************************************************
5158 * Book/folder selection.
5159 * ***********************************************************************
5163 * This function is used by the matcher dialog to select a book/folder.
5165 gchar *addressbook_folder_selection( const gchar *folderpath)
5167 AddressBookFile *book = NULL;
5168 ItemFolder *folder = NULL;
5171 g_return_val_if_fail( folderpath != NULL, NULL);
5173 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5175 if ( folder != NULL) {
5177 gchar *oldtmp = NULL;
5178 AddrItemObject *obj = NULL;
5180 /* walk thru folder->parent to build the full folder path */
5181 /* TODO: wwp: optimize this */
5183 tmp = g_strdup(obj->uid);
5184 while ( obj->parent ) {
5186 if ( obj->name != NULL ) {
5187 oldtmp = g_strdup(tmp);
5189 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5193 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5196 path = g_strdup_printf("%s", book->fileName);
5198 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5204 /* ***********************************************************************
5205 * Book/folder checking.
5206 * ***********************************************************************
5209 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5211 FolderInfo *fi = g_new0( FolderInfo, 1 );
5213 fi->folder = folder;
5217 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5218 FolderInfo *fiParent, FolderPathMatch *match )
5224 FolderPathMatch *nextmatch = NULL;
5229 list = parentFolder->listFolder;
5231 folder = list->data;
5232 fName = g_strdup( ADDRITEM_NAME(folder) );
5234 /* match folder name, match pointer will be set to NULL if next recursive call
5235 doesn't need to match subfolder name */
5236 if ( match != NULL &&
5237 match->matched == FALSE ) {
5238 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5239 /* folder name matches, prepare next subfolder match */
5240 debug_print("matched folder name '%s'\n", fName);
5242 if ( match->folder_path[match->index] == NULL ) {
5243 /* we've matched all elements */
5244 match->matched = TRUE;
5245 match->folder = folder;
5246 debug_print("book/folder path matched!\n");
5248 /* keep on matching */
5256 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5257 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5259 list = g_list_next( list );
5264 * This function is used by to check if a matcher book/folder path corresponds to an
5265 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5266 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5267 if book AND folder are NULL this means that folderpath was empty or Any.
5268 If folderpath is a simple book name (without folder), book will not be NULL and folder
5269 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5272 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5273 AddressDataSource **book,
5274 ItemFolder **folder )
5276 AddressDataSource *ds;
5277 GList *list, *nodeDS;
5278 ItemFolder *rootFolder;
5279 AddressBookFile *abf;
5281 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5288 if ( folderpath == NULL )
5291 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5294 /* split the folder path we've received, we'll try to match this path, subpath by
5295 subpath against the book/folder structure in order */
5296 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5297 if (!folder_path_match.folder_path)
5300 list = addrindex_get_interface_list( _addressIndex_ );
5301 while ( list && !folder_path_match.matched ) {
5302 AddressInterface *interface = list->data;
5303 if ( interface && interface->type == ADDR_IF_BOOK ) {
5304 nodeDS = interface->listSource;
5305 while ( nodeDS && !folder_path_match.matched ) {
5308 /* Read address book */
5309 if( ! addrindex_ds_get_read_flag( ds ) ) {
5310 addrindex_ds_read_data( ds );
5313 /* Add node for address book */
5314 abf = ds->rawDataSource;
5316 /* match book name */
5317 if ( abf && abf->fileName &&
5318 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5320 debug_print("matched book name '%s'\n", abf->fileName);
5321 folder_path_match.book = ds;
5323 if ( folder_path_match.folder_path[1] == NULL ) {
5324 /* no folder part to match */
5326 folder_path_match.matched = TRUE;
5327 folder_path_match.folder = NULL;
5328 debug_print("book path matched!\n");
5331 /* match folder part */
5333 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5334 rootFolder = addrindex_ds_get_root_folder( ds );
5336 /* prepare for recursive call */
5337 folder_path_match.index = 1;
5338 /* this call will set folder_path_match.matched and folder_path_match.folder */
5339 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5344 nodeDS = g_list_next( nodeDS );
5347 list = g_list_next( list );
5350 g_strfreev( folder_path_match.folder_path );
5353 *book = folder_path_match.book;
5355 *folder = folder_path_match.folder;
5356 return folder_path_match.matched;
5360 /* **********************************************************************
5362 * ***********************************************************************
5368 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5369 AddressDataSource *ds = NULL;
5370 AdapterDSource *ads = NULL;
5371 AddressBookFile *abf = NULL;
5372 AdapterInterface *adapter;
5373 GtkCMCTreeNode *newNode;
5375 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5377 if( adapter->treeNode ) {
5378 abf = addressbook_imp_ldif( _addressIndex_ );
5380 ds = addrindex_index_add_datasource(
5381 _addressIndex_, ADDR_IF_BOOK, abf );
5382 ads = addressbook_create_ds_adapter(
5383 ds, ADDR_BOOK, NULL );
5384 addressbook_ads_set_name(
5385 ads, addrbook_get_name( abf ) );
5386 newNode = addressbook_add_object(
5388 ADDRESS_OBJECT(ads) );
5390 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5392 addrbook.treeSelected = newNode;
5395 /* Notify address completion */
5396 invalidate_address_completion();
5405 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5406 AddressDataSource *ds = NULL;
5407 AdapterDSource *ads = NULL;
5408 AddressBookFile *abf = NULL;
5409 AdapterInterface *adapter;
5410 GtkCMCTreeNode *newNode;
5412 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5414 if( adapter->treeNode ) {
5415 abf = addressbook_imp_mutt( _addressIndex_ );
5417 ds = addrindex_index_add_datasource(
5418 _addressIndex_, ADDR_IF_BOOK, abf );
5419 ads = addressbook_create_ds_adapter(
5420 ds, ADDR_BOOK, NULL );
5421 addressbook_ads_set_name(
5422 ads, addrbook_get_name( abf ) );
5423 newNode = addressbook_add_object(
5425 ADDRESS_OBJECT(ads) );
5427 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5429 addrbook.treeSelected = newNode;
5432 /* Notify address completion */
5433 invalidate_address_completion();
5442 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5443 AddressDataSource *ds = NULL;
5444 AdapterDSource *ads = NULL;
5445 AddressBookFile *abf = NULL;
5446 AdapterInterface *adapter;
5447 GtkCMCTreeNode *newNode;
5449 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5451 if( adapter->treeNode ) {
5452 abf = addressbook_imp_pine( _addressIndex_ );
5454 ds = addrindex_index_add_datasource(
5455 _addressIndex_, ADDR_IF_BOOK, abf );
5456 ads = addressbook_create_ds_adapter(
5457 ds, ADDR_BOOK, NULL );
5458 addressbook_ads_set_name(
5459 ads, addrbook_get_name( abf ) );
5460 newNode = addressbook_add_object(
5462 ADDRESS_OBJECT(ads) );
5464 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5466 addrbook.treeSelected = newNode;
5469 /* Notify address completion */
5470 invalidate_address_completion();
5477 * Harvest addresses.
5478 * \param folderItem Folder to import.
5479 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5480 * \param msgList List of message numbers, or NULL to process folder.
5482 void addressbook_harvest(
5483 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5485 AddressDataSource *ds = NULL;
5486 AdapterDSource *ads = NULL;
5487 AddressBookFile *abf = NULL;
5488 AdapterInterface *adapter;
5489 GtkCMCTreeNode *newNode;
5491 abf = addrgather_dlg_execute(
5492 folderItem, _addressIndex_, sourceInd, msgList );
5494 ds = addrindex_index_add_datasource(
5495 _addressIndex_, ADDR_IF_BOOK, abf );
5497 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5499 if( adapter->treeNode ) {
5500 ads = addressbook_create_ds_adapter(
5501 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5502 newNode = addressbook_add_object(
5504 ADDRESS_OBJECT(ads) );
5508 /* Notify address completion */
5509 invalidate_address_completion();
5516 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5517 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5519 AddressDataSource *ds = NULL;
5520 AddrBookBase *adbase;
5521 AddressCache *cache;
5522 GtkCMCTreeNode *node = NULL;
5524 if( ! addrbook.treeSelected ) return;
5525 node = addrbook.treeSelected;
5526 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5527 obj = gtk_cmctree_node_get_row_data( ctree, node );
5528 if( obj == NULL ) return;
5530 ds = addressbook_find_datasource( node );
5531 if( ds == NULL ) return;
5532 adbase = ( AddrBookBase * ) ds->rawDataSource;
5533 cache = adbase->addressCache;
5534 addressbook_exp_html( cache );
5540 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5541 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5543 AddressDataSource *ds = NULL;
5544 AddrBookBase *adbase;
5545 AddressCache *cache;
5546 GtkCMCTreeNode *node = NULL;
5548 if( ! addrbook.treeSelected ) return;
5549 node = addrbook.treeSelected;
5550 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5551 obj = gtk_cmctree_node_get_row_data( ctree, node );
5552 if( obj == NULL ) return;
5554 ds = addressbook_find_datasource( node );
5555 if( ds == NULL ) return;
5556 adbase = ( AddrBookBase * ) ds->rawDataSource;
5557 cache = adbase->addressCache;
5558 addressbook_exp_ldif( cache );
5561 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5563 addrduplicates_find(GTK_WINDOW(addrbook.window));
5566 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5568 addressbook_custom_attr_edit();
5571 static void addressbook_start_drag(GtkWidget *widget, gint button,
5575 GdkDragContext *context;
5576 if (addressbook_target_list == NULL)
5577 addressbook_target_list = gtk_target_list_new(
5578 addressbook_drag_types, 1);
5579 context = gtk_drag_begin(widget, addressbook_target_list,
5580 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5581 gtk_drag_set_icon_default(context);
5584 static void addressbook_drag_data_get(GtkWidget *widget,
5585 GdkDragContext *drag_context,
5586 GtkSelectionData *selection_data,
5591 AddrItemObject *aio = NULL;
5592 AddressObject *pobj = NULL;
5593 AdapterDSource *ads = NULL;
5594 AddressDataSource *ds = NULL;
5597 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5599 if( pobj == NULL ) return;
5601 if( pobj->type == ADDR_DATASOURCE ) {
5602 ads = ADAPTER_DSOURCE(pobj);
5603 ds = ads->dataSource;
5604 } else if (pobj->type == ADDR_ITEM_GROUP) {
5609 else if( pobj->type != ADDR_INTERFACE ) {
5610 ds = addressbook_find_datasource( addrbook.treeSelected );
5616 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5617 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5618 GTK_CMCTREE_NODE(cur->data));
5619 while (aio && aio->type != ADDR_ITEM_PERSON) {
5624 if (aio && aio->type == ADDR_ITEM_PERSON) {
5625 if( ds && ds->interface && ds->interface->readOnly)
5626 gtk_selection_data_set(selection_data,
5627 selection_data->target, 8,
5628 (const guchar *)"Dummy_addr_copy", 15);
5630 gtk_selection_data_set(selection_data,
5631 selection_data->target, 8,
5632 (const guchar *)"Dummy_addr_move", 15);
5636 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5637 GdkDragContext *context,
5644 GtkCMCTreeNode *node = NULL;
5645 gboolean acceptable = FALSE;
5646 gint height = addrbook.ctree->allocation.height;
5647 gint total_height = addrbook.ctree->requisition.height;
5648 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5649 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5650 gfloat vpos = pos->value;
5652 if (gtk_cmclist_get_selection_info
5653 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5655 if (y > height - 24 && height + vpos < total_height) {
5656 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5657 gtk_adjustment_changed(pos);
5659 if (y < 24 && y > 0) {
5660 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5661 gtk_adjustment_changed(pos);
5663 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5666 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5667 if( obj->type == ADDR_ITEM_FOLDER
5668 || obj->type == ADDR_ITEM_GROUP)
5671 AdapterDSource *ads = NULL;
5672 AddressDataSource *ds = NULL;
5673 ads = ADAPTER_DSOURCE(obj);
5674 if (ads == NULL ){ return FALSE;}
5675 ds = ads->dataSource;
5676 if (ds == NULL ) { return FALSE;}
5684 g_signal_handlers_block_by_func
5686 G_CALLBACK(addressbook_tree_selected), NULL);
5687 gtk_sctree_select( GTK_SCTREE(widget), node);
5688 g_signal_handlers_unblock_by_func
5690 G_CALLBACK(addressbook_tree_selected), NULL);
5691 gdk_drag_status(context,
5692 (context->actions == GDK_ACTION_COPY ?
5693 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5695 gdk_drag_status(context, 0, time);
5700 static void addressbook_drag_leave_cb(GtkWidget *widget,
5701 GdkDragContext *context,
5705 if (addrbook.treeSelected) {
5706 g_signal_handlers_block_by_func
5708 G_CALLBACK(addressbook_tree_selected), NULL);
5709 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5710 g_signal_handlers_unblock_by_func
5712 G_CALLBACK(addressbook_tree_selected), NULL);
5717 static void addressbook_drag_received_cb(GtkWidget *widget,
5718 GdkDragContext *drag_context,
5721 GtkSelectionData *data,
5727 GtkCMCTreeNode *node;
5728 GtkCMCTreeNode *lastopened = addrbook.opened;
5730 if (!strncmp(data->data, "Dummy_addr", 10)) {
5731 if (gtk_cmclist_get_selection_info
5732 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5736 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5737 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5740 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5741 if (drag_context->action == GDK_ACTION_COPY ||
5742 !strcmp(data->data, "Dummy_addr_copy"))
5743 addressbook_clip_copy_cb(NULL, NULL);
5745 addressbook_clip_cut_cb(NULL, NULL);
5746 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5747 addressbook_clip_paste_cb(NULL,NULL);
5748 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5749 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5750 gtk_drag_finish(drag_context, TRUE, TRUE, time);