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