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