fix bug 4773, 'remove obsolescent AC_C_CONST'
[claws.git] / src / addressbook.c
blob413668ec450a11b1a5157e749dbb46c3da228919
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2024 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #include "claws-features.h"
22 #endif
24 #include "defs.h"
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtk.h>
30 #include <string.h>
31 #include <setjmp.h>
32 #include <sys/types.h>
34 #include "main.h"
35 #include "addressbook.h"
36 #include "manage_window.h"
37 #include "prefs_common.h"
38 #include "alertpanel.h"
39 #include "inputdialog.h"
40 #include "menu.h"
41 #include "stock_pixmap.h"
42 #include "xml.h"
43 #include "prefs_gtk.h"
44 #include "procmime.h"
45 #include "file-utils.h"
46 #include "utils.h"
47 #include "gtkutils.h"
48 #include "codeconv.h"
49 #include "about.h"
50 #include "addr_compl.h"
51 #include "password.h"
53 #include "mgutils.h"
54 #include "addressitem.h"
55 #include "addritem.h"
56 #include "addrcache.h"
57 #include "addrbook.h"
58 #include "addrindex.h"
59 #include "addrmerge.h"
60 #include "addressadd.h"
61 #include "addrduplicates.h"
62 #include "addressbook_foldersel.h"
63 #include "vcard.h"
64 #include "editvcard.h"
65 #include "editgroup.h"
66 #include "editaddress.h"
67 #include "editbook.h"
68 #include "importldif.h"
69 #include "importmutt.h"
70 #include "importpine.h"
71 #include "manual.h"
73 #ifdef USE_JPILOT
74 #include "jpilot.h"
75 #include "editjpilot.h"
76 #endif
78 #ifdef USE_LDAP
79 #include <pthread.h>
80 #include "ldapserver.h"
81 #include "editldap.h"
82 #include "ldapupdate.h"
84 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
85 #endif
87 #include "addrquery.h"
88 #include "addrselect.h"
89 #include "addrclip.h"
90 #include "addrgather.h"
91 #include "adbookbase.h"
92 #include "exphtmldlg.h"
93 #include "expldifdlg.h"
94 #include "browseldap.h"
95 #include "addrcustomattr.h"
96 #ifdef G_OS_WIN32
97 #undef interface
98 #endif
99 typedef enum
101 COL_SOURCES = 0,
102 N_INDEX_COLS = 1
103 } AddressIndexColumns;
105 typedef enum
107 COL_NAME = 0,
108 COL_ADDRESS = 1,
109 COL_REMARKS = 2,
110 N_LIST_COLS = 3
111 } AddressListColumns;
113 typedef struct {
114 AddressBookFile *book;
115 ItemFolder *folder;
116 } FolderInfo;
118 typedef struct {
119 gchar **folder_path;
120 gboolean matched;
121 gint index;
122 AddressDataSource *book;
123 ItemFolder *folder;
124 } FolderPathMatch;
126 static gchar *list_titles[] = { N_("Name"),
127 N_("Email Address"),
128 N_("Remarks") };
130 #define COL_NAME_WIDTH 164
131 #define COL_ADDRESS_WIDTH 156
133 #define COL_FOLDER_WIDTH 170
134 #define ADDRESSBOOK_WIDTH 640
135 #define ADDRESSBOOK_HEIGHT 360
137 #define ADDRESSBOOK_MSGBUF_SIZE 2048
139 static GdkPixbuf *folderxpm = NULL;
140 static GdkPixbuf *folderopenxpm = NULL;
141 static GdkPixbuf *groupxpm = NULL;
142 static GdkPixbuf *interfacexpm = NULL;
143 static GdkPixbuf *bookxpm = NULL;
144 static GdkPixbuf *addressxpm = NULL;
145 static GdkPixbuf *vcardxpm = NULL;
146 static GdkPixbuf *jpilotxpm = NULL;
147 static GdkPixbuf *categoryxpm = NULL;
148 static GdkPixbuf *ldapxpm = NULL;
149 static GdkPixbuf *addrsearchxpm = NULL;
151 /* Message buffer */
152 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
154 /* Address list selection */
155 static AddrSelectList *_addressSelect_ = NULL;
156 static AddressClipboard *_clipBoard_ = NULL;
158 /* Address index file and interfaces */
159 static AddressIndex *_addressIndex_ = NULL;
160 static GList *_addressInterfaceList_ = NULL;
161 static GList *_addressIFaceSelection_ = NULL;
162 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
164 static AddressBook_win addrbook;
166 static GHashTable *_addressBookTypeHash_ = NULL;
167 static GList *_addressBookTypeList_ = NULL;
169 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
170 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
171 static void addressbook_edit_address_post_cb( ItemPerson *person );
173 static void addressbook_create (void);
174 static gint addressbook_close (void);
176 static gboolean address_index_has_focus = FALSE;
177 static gboolean address_list_has_focus = FALSE;
179 /* callback functions */
180 static void addressbook_del_clicked (GtkButton *button,
181 gpointer data);
182 static void addressbook_reg_clicked (GtkButton *button,
183 gpointer data);
184 static void addressbook_to_clicked (GtkButton *button,
185 gpointer data);
186 static void addressbook_lup_clicked (GtkButton *button,
187 gpointer data);
188 static void addressbook_close_clicked (GtkButton *button,
189 gpointer data);
191 static void addressbook_tree_selected (GtkCMCTree *ctree,
192 GtkCMCTreeNode *node,
193 gint column,
194 gpointer data);
195 static void addressbook_select_row_tree (GtkCMCTree *ctree,
196 GtkCMCTreeNode *node,
197 gint column,
198 gpointer data);
199 static void addressbook_list_row_selected (GtkCMCTree *clist,
200 GtkCMCTreeNode *node,
201 gint column,
202 gpointer data);
203 static void addressbook_list_row_unselected (GtkCMCTree *clist,
204 GtkCMCTreeNode *node,
205 gint column,
206 gpointer data);
207 static void addressbook_person_expand_node (GtkCMCTree *ctree,
208 GList *node,
209 gpointer *data );
210 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
211 GList *node,
212 gpointer *data );
214 static void addressbook_entry_activated (GtkWidget *widget,
215 gpointer data);
217 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
218 GdkEventButton *event,
219 gpointer data);
220 static gboolean addressbook_list_button_released(GtkWidget *widget,
221 GdkEventButton *event,
222 gpointer data);
223 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
224 GdkEventButton *event,
225 gpointer data);
226 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
227 GdkEventButton *event,
228 gpointer data);
230 static void addressbook_new_folder_cb (GtkAction *action,
231 gpointer data);
232 static void addressbook_new_group_cb (GtkAction *action,
233 gpointer data);
234 static void addressbook_treenode_edit_cb (GtkAction *action,
235 gpointer data);
236 static void addressbook_treenode_delete_cb (GtkAction *action,
237 gpointer data);
239 static void addressbook_change_node_name (GtkCMCTreeNode *node,
240 const gchar *name);
242 static void addressbook_new_address_cb (GtkAction *action,
243 gpointer data);
244 static void addressbook_edit_address_cb (GtkAction *action,
245 gpointer data);
246 static void addressbook_delete_address_cb (GtkAction *action,
247 gpointer data);
249 static void close_cb (GtkAction *action,
250 gpointer data);
251 static void addressbook_file_save_cb (GtkAction *action,
252 gpointer data);
254 /* Data source edit stuff */
255 static void addressbook_new_book_cb (GtkAction *action,
256 gpointer data);
257 static void addressbook_new_vcard_cb (GtkAction *action,
258 gpointer data);
260 #ifdef USE_JPILOT
261 static void addressbook_new_jpilot_cb (GtkAction *action,
262 gpointer data);
263 #endif
265 #ifdef USE_LDAP
266 static void addressbook_new_ldap_cb (GtkAction *action,
267 gpointer data);
268 #endif
270 static void addressbook_set_clist (AddressObject *obj,
271 gboolean refresh);
273 static void addressbook_load_tree (void);
274 void addressbook_read_file (void);
276 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
277 AddressObject *obj);
278 static void addressbook_treenode_remove_item ( void );
280 static AddressDataSource *addressbook_find_datasource
281 (GtkCMCTreeNode *node );
283 static AddressBookFile *addressbook_get_book_file(void);
285 static GtkCMCTreeNode *addressbook_node_add_folder
286 (GtkCMCTreeNode *node,
287 AddressDataSource *ds,
288 ItemFolder *itemFolder,
289 AddressObjectType otype);
290 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
291 AddressDataSource *ds,
292 ItemGroup *itemGroup);
293 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
294 GtkCMCTreeNode *parent);
295 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
296 GtkCMCTreeNode *node);
297 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
298 ItemGroup *group);
299 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
300 GdkEventKey *event,
301 gpointer data);
302 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
303 gconstpointer ptr1,
304 gconstpointer ptr2);
305 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
306 ItemPerson *person,
307 AddressTypeControlItem *atci,
308 AddressTypeControlItem *atciMail);
309 static void addressbook_folder_remove_node (GtkCMCTree *clist,
310 GtkCMCTreeNode *node);
312 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
313 gboolean force_focus );
315 /* LUT's and IF stuff */
316 static void addressbook_free_treenode ( gpointer data );
317 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
318 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
320 static void addrbookctl_build_map (GtkWidget *window);
321 static void addrbookctl_build_iflist (void);
322 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
323 static void addrbookctl_build_ifselect (void);
325 static void addrbookctl_free_interface (AdapterInterface *adapter);
326 static void addrbookctl_free_datasource (AdapterDSource *adapter);
327 static void addrbookctl_free_folder (AdapterFolder *adapter);
328 static void addrbookctl_free_group (AdapterGroup *adapter);
330 static void addressbook_list_select_clear ( void );
331 static void addressbook_list_select_add ( AddrItemObject *aio,
332 AddressDataSource *ds );
333 static void addressbook_list_select_remove ( AddrItemObject *aio );
335 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
336 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
337 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
338 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
339 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
340 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
341 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
342 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
343 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
344 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
346 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
347 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
350 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
351 static void addressbook_merge_cb ( GtkAction *action, gpointer data );
353 #ifdef USE_LDAP
354 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
355 #endif
356 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
358 static void addressbook_start_drag(GtkWidget *widget, gint button,
359 GdkEvent *event,
360 void *data);
361 static void addressbook_drag_data_get(GtkWidget *widget,
362 GdkDragContext *drag_context,
363 GtkSelectionData *selection_data,
364 guint info,
365 guint time,
366 void *data);
367 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
368 GdkDragContext *context,
369 gint x,
370 gint y,
371 guint time,
372 void *data);
373 static void addressbook_drag_leave_cb(GtkWidget *widget,
374 GdkDragContext *context,
375 guint time,
376 void *data);
377 static void addressbook_drag_received_cb(GtkWidget *widget,
378 GdkDragContext *drag_context,
379 gint x,
380 gint y,
381 GtkSelectionData *data,
382 guint info,
383 guint time,
384 void *pdata);
385 static void addressbook_list_menu_setup( void );
387 static GtkTargetEntry addressbook_drag_types[] =
389 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
392 static GtkTargetList *addressbook_target_list = NULL;
394 static GtkActionEntry addressbook_entries[] =
396 {"Menu", NULL, "Menu", NULL, NULL, NULL },
397 /* menus */
398 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
399 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
400 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
402 /* Book menu */
403 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
404 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
405 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
408 #ifdef USE_JPILOT
409 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
410 #endif
411 #ifdef USE_LDAP
412 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
413 #endif
414 {"Book/---", NULL, "---", NULL, NULL, NULL },
416 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
417 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
418 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
419 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
420 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
422 /* Adress menu */
423 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
424 {"Address/---", NULL, "---", NULL, NULL, NULL },
425 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
426 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
427 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
428 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
429 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
430 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
431 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
432 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
433 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
434 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
435 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
436 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
439 /* Tools menu */
440 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
441 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
442 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
443 {"Tools/---", NULL, "---", NULL, NULL, NULL },
444 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
445 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
446 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
447 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
448 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
451 static GtkActionEntry addressbook_tree_popup_entries[] =
453 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
454 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
455 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
456 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
457 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
458 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
459 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
460 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
461 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
462 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
463 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
466 static GtkActionEntry addressbook_list_popup_entries[] =
468 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
469 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
470 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
471 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
472 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
473 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
474 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
475 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
476 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
477 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
478 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
479 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
480 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
481 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
482 #ifdef USE_LDAP
483 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
484 #endif
485 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
489 * Structure of error message table.
491 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
492 struct _ErrMsgTableEntry {
493 gint code;
494 gchar *description;
497 static gchar *_errMsgUnknown_ = N_( "Unknown" );
500 * Lookup table of error messages for general errors. Note that a NULL
501 * description signifies the end of the table.
503 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
504 { MGU_SUCCESS, N_("Success") },
505 { MGU_BAD_ARGS, N_("Bad arguments") },
506 { MGU_NO_FILE, N_("File not specified") },
507 { MGU_OPEN_FILE, N_("Error opening file") },
508 { MGU_ERROR_READ, N_("Error reading file") },
509 { MGU_EOF, N_("End of file encountered") },
510 { MGU_OO_MEMORY, N_("Error allocating memory") },
511 { MGU_BAD_FORMAT, N_("Bad file format") },
512 { MGU_ERROR_WRITE, N_("Error writing to file") },
513 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
514 { MGU_NO_PATH, N_("No path specified") },
515 { 0, NULL }
518 #ifdef USE_LDAP
520 * Lookup table of error messages for LDAP errors.
522 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
523 { LDAPRC_SUCCESS, N_("Success") },
524 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
525 { LDAPRC_INIT, N_("Error initializing LDAP") },
526 { LDAPRC_BIND, N_("Error binding to LDAP server") },
527 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
528 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
529 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
530 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
531 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
532 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
533 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
534 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
535 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
536 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
537 { 0, NULL }
539 #endif
542 * Lookup message for specified error code.
543 * \param lut Lookup table.
544 * \param code Code to lookup.
545 * \return Description associated to code.
547 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
548 gchar *desc = NULL;
549 ErrMsgTableEntry entry;
550 gint i;
552 for( i = 0; ; i++ ) {
553 entry = lut[ i ];
554 if( entry.description == NULL ) break;
555 if( entry.code == code ) {
556 desc = entry.description;
557 break;
560 if( ! desc ) {
561 desc = _errMsgUnknown_;
563 return desc;
566 static gboolean lastCanLookup = FALSE;
568 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
570 if (add_and_delete) {
571 gtk_widget_show(addrbook.edit_btn);
572 gtk_widget_show(addrbook.del_btn);
573 gtk_widget_show(addrbook.reg_btn);
574 } else {
575 gtk_widget_hide(addrbook.edit_btn);
576 gtk_widget_hide(addrbook.del_btn);
577 gtk_widget_hide(addrbook.reg_btn);
580 if (lookup) {
581 gtk_widget_show(addrbook.lup_btn);
582 gtk_widget_show(addrbook.entry);
583 gtk_widget_show(addrbook.label);
584 } else {
585 gtk_widget_hide(addrbook.lup_btn);
586 gtk_widget_hide(addrbook.entry);
587 gtk_widget_hide(addrbook.label);
590 lastCanLookup = lookup;
592 if (mail_ops) {
593 gtk_widget_show(addrbook.to_btn);
594 gtk_widget_show(addrbook.cc_btn);
595 gtk_widget_show(addrbook.bcc_btn);
596 } else {
597 gtk_widget_hide(addrbook.to_btn);
598 gtk_widget_hide(addrbook.cc_btn);
599 gtk_widget_hide(addrbook.bcc_btn);
603 void addressbook_open(Compose *target)
605 /* Initialize all static members */
606 if( _clipBoard_ == NULL ) {
607 _clipBoard_ = addrclip_create();
609 if( _addressIndex_ != NULL ) {
610 addrclip_set_index( _clipBoard_, _addressIndex_ );
612 if( _addressSelect_ == NULL ) {
613 _addressSelect_ = addrselect_list_create();
615 if (!addrbook.window) {
616 addressbook_read_file();
617 addressbook_create();
618 addressbook_load_tree();
619 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
620 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
622 else {
623 gtk_widget_hide(addrbook.window);
626 gtk_widget_show_all(addrbook.window);
628 if (!prefs_common.addressbook_use_editaddress_dialog)
629 addressbook_edit_person_widgetset_hide();
631 address_completion_start(addrbook.window);
633 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
634 addressbook_set_target_compose(target);
638 * Destroy addressbook.
640 void addressbook_destroy( void ) {
641 /* Free up address stuff */
642 if( _addressSelect_ != NULL ) {
643 addrselect_list_free( _addressSelect_ );
645 if( _clipBoard_ != NULL ) {
646 addrclip_free( _clipBoard_ );
647 _clipBoard_ = NULL;
649 if( _addressIndex_ != NULL ) {
650 addrindex_free_index( _addressIndex_ );
651 addrindex_teardown();
653 _addressSelect_ = NULL;
654 _clipBoard_ = NULL;
655 _addressIndex_ = NULL;
658 void addressbook_set_target_compose(Compose *target)
660 addrbook.target_compose = target;
663 Compose *addressbook_get_target_compose(void)
665 return addrbook.target_compose;
669 * Refresh addressbook and save to file(s).
671 void addressbook_refresh( void )
673 if (addrbook.window) {
674 if (addrbook.treeSelected) {
675 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
676 addrbook.treeSelected);
677 addressbook_set_clist(
678 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
679 addrbook.treeSelected),
680 TRUE);
684 addressbook_export_to_file();
687 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
689 if (event && event->keyval == GDK_KEY_Escape)
690 addressbook_close();
691 else if (event && event->keyval == GDK_KEY_Delete) {
692 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
693 if ( /* address_index_has_focus || */ address_list_has_focus )
694 addressbook_del_clicked(NULL, NULL);
696 return FALSE;
700 *\brief Save Gtk object size to prefs dataset
702 static void addressbook_size_allocate_cb(GtkWidget *widget,
703 GtkAllocation *allocation)
705 cm_return_if_fail(allocation != NULL);
707 gtk_window_get_size(GTK_WINDOW(widget),
708 &prefs_common.addressbookwin_width, &prefs_common.addressbookwin_height);
711 static gint sort_column_number = 0;
712 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
714 static gint list_case_sort(
715 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
717 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
718 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
719 gchar *name1 = NULL, *name2 = NULL;
720 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
721 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
723 if( aio1->type == aio2->type ) {
724 if( row1 )
725 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
726 if( row2 )
727 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
728 if( ! name1 ) return ( name2 != NULL );
729 if( ! name2 ) return -1;
730 return g_utf8_collate( name1, name2 );
731 } else {
732 /* Order groups before person */
733 if( aio1->type == ITEMTYPE_GROUP ) {
734 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
735 } else if( aio2->type == ITEMTYPE_GROUP ) {
736 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
738 return 0;
742 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
743 const GtkSortType sort_type)
745 gint pos;
746 GtkWidget *hbox, *label, *arrow;
748 sort_column_number = col;
749 sort_column_type = sort_type;
750 gtk_cmclist_set_compare_func(clist, list_case_sort);
751 gtk_cmclist_set_sort_type(clist, sort_type);
752 gtk_cmclist_set_sort_column(clist, col);
754 gtk_cmclist_freeze(clist);
755 gtk_cmclist_sort(clist);
757 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
758 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
759 label = gtk_label_new(gettext(list_titles[pos]));
760 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
762 if(pos == col) {
763 arrow = gtk_image_new_from_icon_name(sort_type == GTK_SORT_ASCENDING ?
764 "pan-down-symbolic" : "pan-up-symbolic", GTK_ICON_SIZE_MENU);
765 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
768 gtk_widget_show_all(hbox);
769 gtk_cmclist_set_column_widget(clist, pos, hbox);
772 gtk_cmclist_thaw(clist);
775 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
777 static GtkSortType sort_type = GTK_SORT_ASCENDING;
779 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
780 GTK_SORT_ASCENDING;
781 addressbook_sort_list(clist, COL_NAME, sort_type);
784 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
786 static GtkSortType sort_type = GTK_SORT_ASCENDING;
788 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
789 GTK_SORT_ASCENDING;
790 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
793 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
795 static GtkSortType sort_type = GTK_SORT_ASCENDING;
797 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
798 GTK_SORT_ASCENDING;
799 addressbook_sort_list(clist, COL_REMARKS, sort_type);
802 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
803 gpointer data)
805 address_index_has_focus = TRUE;
806 return FALSE;
809 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
810 gpointer data)
812 address_index_has_focus = FALSE;
813 if (!prefs_common.addressbook_use_editaddress_dialog
814 && !address_list_has_focus)
815 addressbook_address_list_disable_some_actions();
816 return FALSE;
819 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
820 gpointer data)
822 address_list_has_focus = TRUE;
823 return FALSE;
826 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
827 gpointer data)
829 address_list_has_focus = FALSE;
830 if (!prefs_common.addressbook_use_editaddress_dialog
831 && !address_index_has_focus)
832 addressbook_address_list_disable_some_actions();
833 return FALSE;
836 /* save hpane and vpane's handle position when it moves */
837 static void addressbook_pane_save_position(void)
839 if (addrbook.hpaned)
840 prefs_common.addressbook_hpaned_pos =
841 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
842 if (addrbook.vpaned)
843 prefs_common.addressbook_vpaned_pos =
844 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
848 * Create the address book widgets. The address book contains two CTree widgets: the
849 * address index tree on the left and the address list on the right.
851 * The address index tree displays a hierarchy of interfaces and groups. Each node in
852 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
853 * data sources and folder objects.
855 * The address list displays group, person and email objects. These items are linked
856 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
857 * sources.
859 * In the tradition of MVC architecture, the data stores have been separated from the
860 * GUI components. The addrindex.c file provides the interface to all data stores.
862 static void addressbook_create(void)
864 GtkWidget *window;
865 GtkWidget *vbox;
866 GtkWidget *menubar;
867 GtkWidget *vbox2;
868 GtkWidget *ctree_swin;
869 GtkWidget *ctree;
870 GtkWidget *editaddress_vbox;
871 GtkWidget *clist_vbox;
872 GtkWidget *clist_swin;
873 GtkWidget *clist;
874 GtkWidget *hpaned;
875 GtkWidget *vpaned;
876 GtkWidget *hbox;
877 GtkWidget *label;
878 GtkWidget *entry;
879 GtkWidget *statusbar;
880 GtkWidget *hbbox;
881 GtkWidget *hsbox;
882 GtkWidget *help_btn;
883 GtkWidget *del_btn;
884 GtkWidget *edit_btn;
885 GtkWidget *reg_btn;
886 GtkWidget *lup_btn;
887 GtkWidget *to_btn;
888 GtkWidget *cc_btn;
889 GtkWidget *bcc_btn;
890 GtkWidget *close_btn;
891 GtkWidget *tree_popup;
892 GtkWidget *list_popup;
893 GList *nodeIf;
894 GtkUIManager *ui_manager;
895 GtkActionGroup *action_group;
896 gchar *index_titles[N_INDEX_COLS];
897 gchar *text;
898 gint i;
900 static GdkGeometry geometry;
902 debug_print("Creating addressbook window...\n");
904 index_titles[COL_SOURCES] = _("Sources");
906 /* Address book window */
907 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
908 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
909 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
910 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
911 gtk_widget_realize(window);
913 g_signal_connect(G_OBJECT(window), "delete_event",
914 G_CALLBACK(addressbook_close), NULL);
915 g_signal_connect(G_OBJECT(window), "size_allocate",
916 G_CALLBACK(addressbook_size_allocate_cb), NULL);
917 g_signal_connect(G_OBJECT(window), "key_press_event",
918 G_CALLBACK(key_pressed), NULL);
919 MANAGE_WINDOW_SIGNALS_CONNECT(window);
921 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
922 gtk_container_add(GTK_CONTAINER(window), vbox);
924 /* Menu bar */
925 ui_manager = gtk_ui_manager_new();
926 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
927 G_N_ELEMENTS(addressbook_entries), NULL);
928 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
929 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
930 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
931 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
933 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
935 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
936 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
937 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
939 /* Book menu */
940 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
943 #ifdef USE_JPILOT
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
945 #endif
946 #ifdef USE_LDAP
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
948 #endif
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
956 /* Address menu */
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
972 /* Tools menu */
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
983 gtk_window_add_accel_group(GTK_WINDOW(window),
984 gtk_ui_manager_get_accel_group(ui_manager));
986 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
988 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
990 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, BORDER_WIDTH);
991 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
992 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
994 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
995 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
996 GTK_POLICY_AUTOMATIC,
997 GTK_POLICY_AUTOMATIC);
999 /* Address index */
1000 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1001 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1003 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1004 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1005 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1006 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1007 GTK_CMCTREE_EXPANDER_TRIANGLE);
1008 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1009 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1010 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1011 addressbook_treenode_compare_func);
1013 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1014 G_CALLBACK(addressbook_tree_selected), NULL);
1015 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1016 G_CALLBACK(addressbook_tree_button_pressed),
1017 NULL);
1018 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1019 G_CALLBACK(addressbook_tree_button_released),
1020 NULL);
1021 /* TEMPORARY */
1022 g_signal_connect(G_OBJECT(ctree), "select_row",
1023 G_CALLBACK(addressbook_select_row_tree), NULL);
1025 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1026 addressbook_drag_types, 1,
1027 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1028 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1029 G_CALLBACK(addressbook_drag_motion_cb),
1030 ctree);
1031 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1032 G_CALLBACK(addressbook_drag_leave_cb),
1033 ctree);
1034 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1035 G_CALLBACK(addressbook_drag_received_cb),
1036 ctree);
1037 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1038 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1039 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1040 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1042 clist_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1044 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1045 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1046 GTK_POLICY_AUTOMATIC,
1047 GTK_POLICY_AUTOMATIC);
1048 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1050 /* Address list */
1051 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1052 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1053 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1054 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1055 GTK_CMCTREE_EXPANDER_TRIANGLE);
1056 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1057 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1058 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1059 COL_NAME_WIDTH);
1060 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1061 COL_ADDRESS_WIDTH);
1062 gtk_widget_set_size_request(clist, -1, 80);
1064 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1065 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1066 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1067 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1068 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1069 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1070 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1071 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1072 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1073 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1074 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1076 for (i = 0; i < N_LIST_COLS; i++)
1077 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1078 FALSE);
1080 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1081 G_CALLBACK(addressbook_list_row_selected), NULL);
1082 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1083 G_CALLBACK(addressbook_list_row_unselected), NULL);
1084 g_signal_connect(G_OBJECT(clist), "button_press_event",
1085 G_CALLBACK(addressbook_list_button_pressed),
1086 NULL);
1087 g_signal_connect(G_OBJECT(clist), "button_release_event",
1088 G_CALLBACK(addressbook_list_button_released),
1089 NULL);
1090 g_signal_connect(G_OBJECT(clist), "tree_expand",
1091 G_CALLBACK(addressbook_person_expand_node), NULL );
1092 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1093 G_CALLBACK(addressbook_person_collapse_node), NULL );
1094 g_signal_connect(G_OBJECT(clist), "start_drag",
1095 G_CALLBACK(addressbook_start_drag), NULL);
1096 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1097 G_CALLBACK(addressbook_drag_data_get), NULL);
1098 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
1099 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1101 label = gtk_label_new(_("Search"));
1102 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1104 entry = gtk_entry_new();
1105 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1107 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1109 g_signal_connect(G_OBJECT(entry), "key_press_event",
1110 G_CALLBACK(addressbook_entry_key_pressed),
1111 NULL);
1112 g_signal_connect(G_OBJECT(entry), "activate",
1113 G_CALLBACK(addressbook_entry_activated), NULL);
1115 if (!prefs_common.addressbook_use_editaddress_dialog) {
1116 editaddress_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1117 vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
1118 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1119 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1120 } else {
1121 vpaned = NULL;
1122 editaddress_vbox = NULL;
1124 hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
1125 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1126 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1127 if (prefs_common.addressbook_use_editaddress_dialog)
1128 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1129 else
1130 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1132 /* Status bar */
1133 hsbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1134 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1135 statusbar = gtk_statusbar_new();
1136 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1138 /* Button panel */
1139 hbbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
1140 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1141 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1142 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1143 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1145 gtkut_stock_button_add_help(hbbox, &help_btn);
1147 edit_btn = gtk_button_new_with_mnemonic("_Edit");
1148 gtk_widget_set_can_default(edit_btn, TRUE);
1149 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1150 del_btn = gtk_button_new_with_mnemonic("_Delete");
1151 gtk_widget_set_can_default(del_btn, TRUE);
1152 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1153 reg_btn = gtk_button_new_with_mnemonic("_New");
1154 gtk_widget_set_can_default(reg_btn, TRUE);
1155 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1158 lup_btn = gtkut_stock_button("edit-find", _("_Find"));
1159 gtk_widget_set_can_default(lup_btn, TRUE);
1160 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1162 g_signal_connect(G_OBJECT(help_btn), "clicked",
1163 G_CALLBACK(manual_open_with_anchor_cb),
1164 MANUAL_ANCHOR_ADDRBOOK);
1166 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1167 G_CALLBACK(addressbook_edit_clicked), NULL);
1168 g_signal_connect(G_OBJECT(del_btn), "clicked",
1169 G_CALLBACK(addressbook_del_clicked), NULL);
1170 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1171 G_CALLBACK(addressbook_reg_clicked), NULL);
1172 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1173 G_CALLBACK(addressbook_lup_clicked), NULL);
1175 to_btn = gtk_button_new_with_label
1176 (prefs_common_translated_header_name("To:"));
1177 gtk_widget_set_can_default(to_btn, TRUE);
1178 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1179 cc_btn = gtk_button_new_with_label
1180 (prefs_common_translated_header_name("Cc:"));
1181 gtk_widget_set_can_default(cc_btn, TRUE);
1182 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1183 bcc_btn = gtk_button_new_with_label
1184 (prefs_common_translated_header_name("Bcc:"));
1185 gtk_widget_set_can_default(bcc_btn, TRUE);
1186 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1188 close_btn = gtkut_stock_button("window-close", "_Close");
1189 gtk_widget_set_can_default(close_btn, TRUE);
1190 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1192 g_signal_connect(G_OBJECT(to_btn), "clicked",
1193 G_CALLBACK(addressbook_to_clicked),
1194 GINT_TO_POINTER(COMPOSE_TO));
1195 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1196 G_CALLBACK(addressbook_to_clicked),
1197 GINT_TO_POINTER(COMPOSE_CC));
1198 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1199 G_CALLBACK(addressbook_to_clicked),
1200 GINT_TO_POINTER(COMPOSE_BCC));
1201 g_signal_connect(G_OBJECT(close_btn), "clicked",
1202 G_CALLBACK(addressbook_close_clicked), NULL);
1204 /* Build icons for interface */
1206 /* Build control tables */
1207 addrbookctl_build_map(window);
1208 addrbookctl_build_iflist();
1209 addrbookctl_build_ifselect();
1211 addrbook.clist = NULL;
1213 /* Add each interface into the tree as a root level folder */
1214 nodeIf = _addressInterfaceList_;
1215 while( nodeIf ) {
1216 AdapterInterface *adapter = nodeIf->data;
1217 AddressInterface *iface = adapter->interface;
1218 nodeIf = g_list_next(nodeIf);
1220 if(iface->useInterface) {
1221 AddressTypeControlItem *atci = adapter->atci;
1222 text = atci->displayName;
1223 adapter->treeNode =
1224 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1225 NULL, NULL, &text, FOLDER_SPACING,
1226 interfacexpm,
1227 interfacexpm,
1228 FALSE, FALSE );
1229 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1230 gtk_cmctree_node_set_row_data_full(
1231 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1232 addressbook_free_treenode );
1236 /* Popup menu */
1238 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1239 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1240 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1241 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1242 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1243 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1244 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1245 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1251 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1252 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1268 #ifdef USE_LDAP
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1270 #endif
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1272 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1273 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1275 addrbook.window = window;
1276 addrbook.hpaned = hpaned;
1277 addrbook.vpaned = vpaned;
1278 addrbook.menubar = menubar;
1279 addrbook.ctree = ctree;
1280 addrbook.ctree_swin
1281 = ctree_swin;
1282 addrbook.editaddress_vbox = editaddress_vbox;
1283 addrbook.clist = clist;
1284 addrbook.label = label;
1285 addrbook.entry = entry;
1286 addrbook.statusbar = statusbar;
1287 addrbook.status_cid = gtk_statusbar_get_context_id(
1288 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1290 addrbook.help_btn = help_btn;
1291 addrbook.edit_btn = edit_btn;
1292 addrbook.del_btn = del_btn;
1293 addrbook.reg_btn = reg_btn;
1294 addrbook.lup_btn = lup_btn;
1295 addrbook.to_btn = to_btn;
1296 addrbook.cc_btn = cc_btn;
1297 addrbook.bcc_btn = bcc_btn;
1299 addrbook.tree_popup = tree_popup;
1300 addrbook.list_popup = list_popup;
1301 addrbook.ui_manager = ui_manager;
1303 addrbook.listSelected = NULL;
1305 if (!geometry.min_height) {
1306 geometry.min_width = ADDRESSBOOK_WIDTH;
1307 geometry.min_height = ADDRESSBOOK_HEIGHT;
1310 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1311 GDK_HINT_MIN_SIZE);
1312 gtk_window_set_default_size(GTK_WINDOW(window), prefs_common.addressbookwin_width,
1313 prefs_common.addressbookwin_height);
1314 #ifdef G_OS_WIN32
1315 gtk_window_move(GTK_WINDOW(window), 48, 48);
1316 #endif
1318 if (!prefs_common.addressbook_use_editaddress_dialog) {
1319 if (prefs_common.addressbook_vpaned_pos > 0)
1320 gtk_paned_set_position(GTK_PANED(vpaned),
1321 prefs_common.addressbook_vpaned_pos);
1323 if (prefs_common.addressbook_hpaned_pos > 0)
1324 gtk_paned_set_position(GTK_PANED(hpaned),
1325 prefs_common.addressbook_hpaned_pos);
1328 gtk_widget_show_all(window);
1332 * Close address book window and save to file(s).
1334 static gint addressbook_close( void ) {
1335 address_completion_end(addrbook.window);
1336 if (!prefs_common.addressbook_use_editaddress_dialog)
1337 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1339 addressbook_pane_save_position();
1341 gtk_widget_hide(addrbook.window);
1342 addressbook_export_to_file();
1343 return TRUE;
1347 * Display message in status line.
1348 * \param msg Message to display.
1350 static void addressbook_status_show( gchar *msg ) {
1351 if( addrbook.statusbar != NULL ) {
1352 gtk_statusbar_pop(
1353 GTK_STATUSBAR(addrbook.statusbar),
1354 addrbook.status_cid );
1355 if( msg ) {
1356 gtk_statusbar_push(
1357 GTK_STATUSBAR(addrbook.statusbar),
1358 addrbook.status_cid, msg );
1363 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1364 gint retVal;
1365 gchar *name;
1366 gchar *desc;
1367 *addressbook_msgbuf = '\0';
1368 if( ds ) {
1369 name = addrindex_ds_get_name( ds );
1370 retVal = addrindex_ds_get_status_code( ds );
1371 if( retVal == MGU_SUCCESS ) {
1372 g_snprintf( addressbook_msgbuf,
1373 sizeof(addressbook_msgbuf), "%s", name );
1375 else {
1376 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1377 g_snprintf( addressbook_msgbuf,
1378 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1381 addressbook_status_show( addressbook_msgbuf );
1384 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1386 addressbook_edit_address_cb(NULL, NULL);
1389 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1391 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1395 * Delete one or more objects from address list.
1397 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1399 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1400 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1401 AddressObject *pobj;
1402 AdapterDSource *ads = NULL;
1403 GtkCMCTreeNode *nodeList;
1404 gboolean procFlag;
1405 AlertValue aval;
1406 AddressBookFile *abf = NULL;
1407 AddressDataSource *ds = NULL;
1408 AddressInterface *iface;
1409 AddrItemObject *aio;
1410 AddrSelectItem *item;
1411 GList *list, *node;
1412 gboolean refreshList = FALSE;
1414 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1415 cm_return_if_fail(pobj != NULL);
1417 /* Test whether anything selected for deletion */
1418 nodeList = addrbook.listSelected;
1420 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1421 if( aio == NULL) return;
1422 ds = addressbook_find_datasource( addrbook.treeSelected );
1423 if( ds == NULL ) return;
1425 /* Test for read only */
1426 iface = ds->interface;
1427 if( iface->readOnly ) {
1428 alertpanel( _("Delete address(es)"),
1429 _("This address data is read-only and cannot be deleted."),
1430 "window-close", _("_Close"), NULL, NULL, NULL, NULL, ALERTFOCUS_FIRST);
1431 return;
1434 /* Test whether Ok to proceed */
1435 procFlag = FALSE;
1436 if( pobj->type == ADDR_DATASOURCE ) {
1437 ads = ADAPTER_DSOURCE(pobj);
1438 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1440 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1441 procFlag = TRUE;
1443 else if( pobj->type == ADDR_ITEM_GROUP ) {
1444 procFlag = TRUE;
1446 if( ! procFlag ) return;
1447 abf = ds->rawDataSource;
1448 if( abf == NULL ) return;
1450 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1451 g_signal_handlers_block_by_func
1452 (G_OBJECT(addrbook.clist),
1453 G_CALLBACK(addressbook_list_row_unselected), NULL);
1455 /* Process deletions */
1456 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1457 GList *groups = NULL, *persons = NULL, *emails = NULL;
1458 gboolean group_delete = TRUE;
1459 /* Items inside folders */
1460 list = addrselect_get_list( _addressSelect_ );
1461 /* Confirm deletion */
1462 node = list;
1463 while( node ) {
1464 item = node->data;
1465 node = g_list_next( node );
1466 aio = ( AddrItemObject * ) item->addressItem;
1467 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1468 group_delete = FALSE;
1469 break;
1472 if (group_delete) {
1473 aval = alertpanel( _("Delete group"),
1474 _("Really delete the group(s)?\n"
1475 "The addresses it contains will not be lost."),
1476 NULL, _("_Cancel"), "edit-delete", _("D_elete"), NULL, NULL,
1477 ALERTFOCUS_SECOND );
1478 if( aval != G_ALERTALTERNATE ) {
1479 goto thaw_ret;
1481 } else {
1482 aval = alertpanel( _("Delete address(es)"),
1483 _("Really delete the address(es)?"),
1484 NULL, _("_Cancel"), "edit-delete", _("D_elete"), NULL, NULL,
1485 ALERTFOCUS_SECOND );
1486 if( aval != G_ALERTALTERNATE ) {
1487 goto thaw_ret;
1491 /* first, set lists of groups and persons to remove */
1492 node = list;
1493 while( node ) {
1494 item = node->data;
1495 node = g_list_next( node );
1496 aio = ( AddrItemObject * ) item->addressItem;
1497 if (!aio)
1498 continue;
1499 if( aio->type == ITEMTYPE_GROUP ) {
1500 groups = g_list_prepend(groups, item);
1502 else if( aio->type == ITEMTYPE_PERSON ) {
1503 persons = g_list_prepend(persons, item);
1506 /* then set list of emails to remove *if* they're not children of
1507 * persons to remove */
1508 node = list;
1509 while( node ) {
1510 item = node->data;
1511 node = g_list_next( node );
1512 aio = ( AddrItemObject * ) item->addressItem;
1513 if (!aio)
1514 continue;
1515 if( aio->type == ITEMTYPE_EMAIL ) {
1516 ItemEMail *sitem = ( ItemEMail * ) aio;
1517 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1518 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1519 emails = g_list_prepend(emails, item);
1521 /* else, the email will be removed via the parent person */
1524 /* then delete groups */
1525 node = groups;
1526 while( node ) {
1527 item = node->data;
1528 node = g_list_next( node );
1529 aio = ( AddrItemObject * ) item->addressItem;
1530 if (!aio)
1531 continue;
1532 if( aio->type == ITEMTYPE_GROUP ) {
1533 ItemGroup *item = ( ItemGroup * ) aio;
1534 GtkCMCTreeNode *nd = NULL;
1535 nd = addressbook_find_group_node( addrbook.opened, item );
1536 item = addrbook_remove_group( abf, item );
1537 if( item ) {
1538 addritem_free_item_group( item );
1540 /* Remove group from parent node */
1541 gtk_cmctree_remove_node( ctree, nd );
1542 refreshList = TRUE;
1545 /* then delete persons */
1546 node = persons;
1547 while( node ) {
1548 item = node->data;
1549 node = g_list_next( node );
1550 aio = ( AddrItemObject * ) item->addressItem;
1551 if (!aio)
1552 continue;
1553 if( aio->type == ITEMTYPE_PERSON ) {
1554 ItemPerson *item = ( ItemPerson * ) aio;
1555 item->status = DELETE_ENTRY;
1556 addressbook_folder_remove_one_person( clist, item );
1557 if (pobj->type == ADDR_ITEM_FOLDER)
1558 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1559 item = addrbook_remove_person( abf, item );
1560 #ifdef USE_LDAP
1561 if (ds && ds->type == ADDR_IF_LDAP) {
1562 LdapServer *server = ds->rawDataSource;
1563 ldapsvr_set_modified(server, TRUE);
1564 ldapsvr_update_book(server, item);
1566 #endif
1567 if( item ) {
1568 addritem_person_remove_picture(item);
1569 addritem_free_item_person( item );
1573 /* then delete emails */
1574 node = emails;
1575 while( node ) {
1576 item = node->data;
1577 node = g_list_next( node );
1578 aio = ( AddrItemObject * ) item->addressItem;
1579 if (!aio)
1580 continue;
1582 if( aio->type == ITEMTYPE_EMAIL ) {
1583 ItemEMail *sitem = ( ItemEMail * ) aio;
1584 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1585 sitem = addrbook_person_remove_email( abf, person, sitem );
1586 if( sitem ) {
1587 addrcache_remove_email(abf->addressCache, sitem);
1588 addritem_free_item_email( sitem );
1590 addressbook_folder_refresh_one_person( clist, person );
1593 g_list_free( groups );
1594 g_list_free( persons );
1595 g_list_free( emails );
1596 g_list_free( list );
1597 addressbook_list_select_clear();
1598 if( refreshList ) {
1599 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1600 addressbook_set_clist(
1601 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1602 addrbook.opened),
1603 TRUE);
1605 addrbook_set_dirty(abf, TRUE);
1606 addressbook_export_to_file();
1607 addressbook_list_menu_setup();
1608 goto thaw_ret;
1610 else if( pobj->type == ADDR_ITEM_GROUP ) {
1611 /* Items inside groups */
1612 list = addrselect_get_list( _addressSelect_ );
1613 node = list;
1614 while( node ) {
1615 item = node->data;
1616 node = g_list_next( node );
1617 aio = ( AddrItemObject * ) item->addressItem;
1618 if( aio->type == ITEMTYPE_EMAIL ) {
1619 ItemEMail *item = ( ItemEMail * ) aio;
1620 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1621 item = addrbook_person_remove_email( abf, person, item );
1622 if( item ) {
1623 addritem_free_item_email( item );
1627 g_list_free( list );
1628 addressbook_list_select_clear();
1629 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1630 addressbook_set_clist(
1631 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1632 addrbook.opened),
1633 TRUE);
1635 addrbook_set_dirty(abf, TRUE);
1636 addressbook_export_to_file();
1637 addressbook_list_menu_setup();
1638 goto thaw_ret;
1641 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1642 gtk_cmctree_remove_node( clist, nodeList );
1643 thaw_ret:
1644 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1645 g_signal_handlers_unblock_by_func
1646 (G_OBJECT(addrbook.clist),
1647 G_CALLBACK(addressbook_list_row_unselected), NULL);
1650 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1652 addressbook_new_address_cb( NULL, NULL );
1655 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1656 gchar *buf = NULL;
1657 gchar *name = NULL;
1658 gchar *address = NULL;
1660 if( aio->type == ITEMTYPE_EMAIL ) {
1661 ItemPerson *person = NULL;
1662 ItemEMail *email = ( ItemEMail * ) aio;
1664 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1665 if( email->address ) {
1666 if( ADDRITEM_NAME(email) ) {
1667 name = ADDRITEM_NAME(email);
1668 if( *name == '\0' ) {
1669 name = ADDRITEM_NAME(person);
1672 else if( ADDRITEM_NAME(person) ) {
1673 name = ADDRITEM_NAME(person);
1675 else {
1676 buf = g_strdup( email->address );
1678 address = email->address;
1681 else if( aio->type == ITEMTYPE_PERSON ) {
1682 ItemPerson *person = ( ItemPerson * ) aio;
1683 GList *node = person->listEMail;
1685 name = ADDRITEM_NAME(person);
1686 if( node ) {
1687 ItemEMail *email = ( ItemEMail * ) node->data;
1688 address = email->address;
1691 if( address ) {
1692 if( name && name[0] != '\0' ) {
1693 if( strchr_with_skip_quote( name, '"', ',' ) )
1694 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1695 else
1696 buf = g_strdup_printf( "%s <%s>", name, address );
1698 else {
1699 buf = g_strdup( address );
1703 return buf;
1706 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1708 GList *list, *node;
1709 Compose *compose;
1710 AddrSelectItem *item;
1711 AddrItemObject *aio;
1712 gchar *addr;
1714 compose = addrbook.target_compose;
1715 if( ! compose ) return;
1717 /* Nothing selected, but maybe there is something in text entry */
1718 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1719 if ( addr ) {
1720 compose_entry_append(
1721 compose, addr, (ComposeEntryType)data , PREF_NONE);
1724 /* Select from address list */
1725 list = addrselect_get_list( _addressSelect_ );
1726 node = list;
1727 if (node) {
1728 while( node ) {
1729 item = node->data;
1730 node = g_list_next( node );
1731 aio = item->addressItem;
1732 if( aio->type == ITEMTYPE_PERSON ||
1733 aio->type == ITEMTYPE_EMAIL ) {
1734 addr = addressbook_format_address( aio );
1735 compose_entry_append(
1736 compose, addr, (ComposeEntryType) data, PREF_NONE );
1737 g_free( addr );
1739 else if( aio->type == ITEMTYPE_GROUP ) {
1740 ItemGroup *group = ( ItemGroup * ) aio;
1741 GList *nodeMail = group->listEMail;
1742 while( nodeMail ) {
1743 ItemEMail *email = nodeMail->data;
1745 addr = addressbook_format_address(
1746 ( AddrItemObject * ) email );
1747 compose_entry_append(
1748 compose, addr, (ComposeEntryType) data, PREF_NONE );
1749 g_free( addr );
1750 nodeMail = g_list_next( nodeMail );
1754 } else {
1755 AddressObject *obj = NULL;
1757 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1759 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1760 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1761 GList *nodeMail = itemGroup->listEMail;
1762 while( nodeMail ) {
1763 ItemEMail *email = nodeMail->data;
1765 addr = addressbook_format_address(
1766 ( AddrItemObject * ) email );
1767 compose_entry_append(
1768 compose, addr, (ComposeEntryType) data, PREF_NONE );
1769 g_free( addr );
1770 nodeMail = g_list_next( nodeMail );
1774 g_list_free( list );
1777 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1778 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1779 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1780 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1782 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1783 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1787 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1791 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1792 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1795 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1796 gboolean canEdit = FALSE;
1797 gboolean canDelete = TRUE;
1798 gboolean canAdd = FALSE;
1799 gboolean canEditTr = TRUE;
1800 gboolean editAddress = FALSE;
1801 gboolean canExport = TRUE;
1802 AddressTypeControlItem *atci = NULL;
1803 AddressDataSource *ds = NULL;
1804 AddressInterface *iface = NULL;
1806 if( obj == NULL ) return;
1807 if( obj->type == ADDR_INTERFACE ) {
1808 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1809 iface = adapter->interface;
1810 if( iface ) {
1811 if( iface->haveLibrary ) {
1812 /* Enable appropriate File / New command */
1813 atci = adapter->atci;
1814 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1817 canEditTr = canExport = FALSE;
1819 else if( obj->type == ADDR_DATASOURCE ) {
1820 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1821 ds = ads->dataSource;
1822 iface = ds->interface;
1823 if( ! iface->readOnly ) {
1824 canAdd = canEdit = editAddress = canDelete = TRUE;
1826 if( ! iface->haveLibrary ) {
1827 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1830 else if( obj->type == ADDR_ITEM_FOLDER ) {
1831 ds = addressbook_find_datasource( addrbook.treeSelected );
1832 if( ds ) {
1833 iface = ds->interface;
1834 if( iface->readOnly ) {
1835 canEditTr = FALSE;
1836 canDelete = FALSE;
1838 else {
1839 canAdd = editAddress = TRUE;
1843 else if( obj->type == ADDR_ITEM_GROUP ) {
1844 ds = addressbook_find_datasource( addrbook.treeSelected );
1845 if( ds ) {
1846 iface = ds->interface;
1847 if( ! iface->readOnly ) {
1848 editAddress = TRUE;
1853 if( addrbook.listSelected == NULL )
1854 canEdit = FALSE;
1856 /* Enable add */
1857 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1858 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1859 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1860 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1862 /* Enable edit */
1863 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1865 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1866 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1868 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1871 /* Export data */
1872 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1877 * Address book tree callback function that responds to selection of tree
1878 * items.
1880 * \param ctree Tree widget.
1881 * \param node Node that was selected.
1882 * \param column Column number where selected occurred.
1883 * \param data Pointer to user data.
1885 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1886 gint column, gpointer data)
1888 AddressObject *obj = NULL;
1889 AdapterDSource *ads = NULL;
1890 AddressDataSource *ds = NULL;
1891 ItemFolder *rootFolder = NULL;
1892 AddressObjectType aot;
1894 addrbook.treeSelected = node;
1895 addrbook.listSelected = NULL;
1896 addressbook_status_show( "" );
1897 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1899 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1900 if( obj == NULL ) {
1901 addressbook_set_clist(NULL, TRUE);
1902 return;
1904 addrbook.opened = node;
1906 if( obj->type == ADDR_DATASOURCE ) {
1907 /* Read from file */
1908 static gboolean tVal = TRUE;
1910 ads = ADAPTER_DSOURCE(obj);
1912 ds = ads->dataSource;
1913 if( ds == NULL ) return;
1915 if( addrindex_ds_get_modify_flag( ds ) ) {
1916 addrindex_ds_read_data( ds );
1919 if( ! addrindex_ds_get_read_flag( ds ) ) {
1920 addrindex_ds_read_data( ds );
1922 addressbook_ds_show_message( ds );
1924 if( ! addrindex_ds_get_access_flag( ds ) ) {
1925 /* Remove existing folders and groups */
1926 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1927 addressbook_tree_remove_children( ctree, node );
1928 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1930 /* Load folders into the tree */
1931 rootFolder = addrindex_ds_get_root_folder( ds );
1932 if( ds && ds->type == ADDR_IF_JPILOT ) {
1933 aot = ADDR_CATEGORY;
1935 else if( ds && ds->type == ADDR_IF_LDAP ) {
1936 aot = ADDR_LDAP_QUERY;
1938 else {
1939 aot = ADDR_ITEM_FOLDER;
1941 addressbook_node_add_folder( node, ds, rootFolder, aot );
1942 addrindex_ds_set_access_flag( ds, &tVal );
1943 gtk_cmctree_expand( ctree, node );
1945 } else {
1946 addressbook_set_clist(NULL, TRUE);
1949 /* Update address list */
1950 g_signal_handlers_block_by_func
1951 (G_OBJECT(ctree),
1952 G_CALLBACK(addressbook_tree_selected), NULL);
1953 addressbook_set_clist( obj, FALSE );
1954 g_signal_handlers_unblock_by_func
1955 (G_OBJECT(ctree),
1956 G_CALLBACK(addressbook_tree_selected), NULL);
1957 if (!prefs_common.addressbook_use_editaddress_dialog)
1958 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1960 /* Setup main menu selections */
1961 addressbook_menubar_set_sensitive( FALSE );
1962 addressbook_menuitem_set_sensitive( obj, node );
1963 addressbook_list_select_clear();
1964 addressbook_list_menu_setup();
1965 return;
1969 * Setup address list popup menu items. Items are enabled or disabled as
1970 * required.
1972 static void addressbook_list_menu_setup( void ) {
1973 GtkCMCTree *clist = NULL;
1974 AddressObject *pobj = NULL;
1975 AddressObject *obj = NULL;
1976 AdapterDSource *ads = NULL;
1977 AddressInterface *iface = NULL;
1978 AddressDataSource *ds = NULL;
1979 GList *list;
1980 AddrItemObject *aio;
1981 AddrSelectItem *item;
1982 gboolean canEdit = FALSE;
1983 gboolean canDelete = FALSE;
1984 gboolean canCut = FALSE;
1985 gboolean canCopy = FALSE;
1986 gboolean canPaste = FALSE;
1987 gboolean canBrowse = FALSE;
1988 gboolean canMerge = FALSE;
1990 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1991 if( pobj == NULL ) return;
1993 clist = GTK_CMCTREE(addrbook.clist);
1994 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
1995 if( obj == NULL ) canEdit = FALSE;
1997 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1998 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2000 if( pobj->type == ADDR_DATASOURCE ) {
2001 /* Parent object is a data source */
2002 ads = ADAPTER_DSOURCE(pobj);
2003 ds = ads->dataSource;
2004 if (!ds)
2005 return;
2006 iface = ds->interface;
2007 if (!iface)
2008 return;
2009 if( ! iface->readOnly ) {
2010 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2011 if (iface->type != ADDR_IF_LDAP)
2012 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2013 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2014 if( obj )
2015 canEdit = TRUE;
2016 canDelete = canEdit;
2019 else if( pobj->type != ADDR_INTERFACE ) {
2020 /* Parent object is not an interface */
2021 ds = addressbook_find_datasource( addrbook.treeSelected );
2022 if (!ds)
2023 return;
2024 iface = ds->interface;
2025 if (!iface)
2026 return;
2027 if( ! iface->readOnly ) {
2028 /* Folder or group */
2029 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2030 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2031 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2032 if( obj ) canEdit = TRUE;
2034 /* Folder */
2035 if( pobj->type == ADDR_ITEM_FOLDER ) {
2036 if (iface->type != ADDR_IF_LDAP)
2037 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2038 if( obj ) canEdit = TRUE;
2040 canDelete = canEdit;
2042 if( iface->type == ADDR_IF_LDAP ) {
2043 if( obj ) canBrowse = TRUE;
2044 canEdit = TRUE;
2045 canDelete = TRUE;
2049 if( iface ) {
2050 /* Enable cut and paste */
2051 if( ! addrclip_is_empty( _clipBoard_ ) )
2052 canPaste = TRUE;
2053 if( ! addrselect_test_empty( _addressSelect_ ) )
2054 canCut = TRUE;
2055 /* Enable copy if something is selected */
2056 if( ! addrselect_test_empty( _addressSelect_ ) )
2057 canCopy = TRUE;
2060 /* Disable edit or browse if more than one row selected */
2061 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2062 canEdit = FALSE;
2063 canBrowse = FALSE;
2066 /* Allow merging persons or emails are selected */
2067 list = _addressSelect_->listSelect;
2068 if (list && list->next ) {
2069 item = list->data;
2070 aio = ( AddrItemObject * ) item->addressItem;
2071 if( aio->type == ITEMTYPE_EMAIL ||
2072 aio->type == ITEMTYPE_PERSON ) {
2073 canMerge = TRUE;
2077 /* Forbid write changes when read-only */
2078 if( iface && iface->readOnly ) {
2079 canCut = FALSE;
2080 canDelete = FALSE;
2081 canPaste = FALSE;
2082 canMerge = FALSE;
2085 /* Now go finalize menu items */
2086 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2087 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2091 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2094 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2105 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2106 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2108 if (addrbook.target_compose) {
2109 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2110 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2111 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2113 #ifdef USE_LDAP
2114 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2115 #endif
2118 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2119 GtkCMCTreeNode *node,
2120 gint column,
2121 gpointer data)
2126 * Add list of items into tree node below specified tree node.
2127 * \param treeNode Tree node.
2128 * \param ds Data source.
2129 * \param listItems List of items.
2131 static void addressbook_treenode_add_list(
2132 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2134 GList *node;
2136 node = listItems;
2137 while( node ) {
2138 AddrItemObject *aio;
2139 GtkCMCTreeNode *nn;
2141 aio = node->data;
2142 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2143 ItemGroup *group;
2145 group = ( ItemGroup * ) aio;
2146 nn = addressbook_node_add_group( treeNode, ds, group );
2147 if (nn == NULL) {
2148 g_message("error adding addressbook group\n");
2151 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2152 ItemFolder *folder;
2154 folder = ( ItemFolder * ) aio;
2155 nn = addressbook_node_add_folder(
2156 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2157 if (nn == NULL) {
2158 g_message("error adding addressbook folder\n");
2161 node = g_list_next( node );
2165 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2166 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2170 * Cut from address list widget.
2172 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2173 _clipBoard_->cutFlag = TRUE;
2174 addrclip_clear( _clipBoard_ );
2175 addrclip_add( _clipBoard_, _addressSelect_ );
2176 #ifdef DEBUG_ADDRBOOK
2177 addrclip_list_show( _clipBoard_, stdout );
2178 #endif
2182 * Copy from address list widget.
2184 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2185 _clipBoard_->cutFlag = FALSE;
2186 addrclip_clear( _clipBoard_ );
2187 addrclip_add( _clipBoard_, _addressSelect_ );
2188 #ifdef DEBUG_ADDRBOOK
2189 addrclip_list_show( _clipBoard_, stdout );
2190 #endif
2194 * Paste clipboard into address list widget.
2196 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2197 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2198 AddressObject *pobj = NULL;
2199 AddressDataSource *ds = NULL;
2200 AddressBookFile *abf = NULL;
2201 ItemFolder *folder = NULL;
2202 GList *folderGroup = NULL;
2204 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2205 if( ds == NULL ) return;
2206 if( addrindex_ds_get_readonly( ds ) ) {
2207 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2208 return;
2211 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2212 if( pobj ) {
2213 if( pobj->type == ADDR_ITEM_FOLDER ) {
2214 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2216 else if( pobj->type == ADDR_ITEM_GROUP ) {
2217 alertpanel_error( _("Cannot paste into an address group.") );
2218 return;
2222 /* Get an address book */
2223 abf = addressbook_get_book_file();
2224 if( abf == NULL ) return;
2226 if( _clipBoard_->cutFlag ) {
2227 /* Paste/Cut */
2228 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2230 /* Remove all groups and folders in clipboard from tree node */
2231 addressbook_treenode_remove_item();
2233 /* Remove all "cut" items */
2234 addrclip_delete_item( _clipBoard_ );
2236 /* Clear clipboard - cut items??? */
2237 addrclip_clear( _clipBoard_ );
2239 else {
2240 /* Paste/Copy */
2241 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2244 #ifdef DEBUG_ADDRBOOK
2245 addrclip_list_show( _clipBoard_, stdout );
2246 #endif
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 #ifdef DEBUG_ADDRBOOK
2326 addrclip_list_show( _clipBoard_, stdout );
2327 #endif
2331 * Copy from tree widget.
2333 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2334 _clipBoard_->cutFlag = FALSE;
2335 addressbook_treenode_to_clipboard();
2336 addrclip_clear( _clipBoard_ );
2337 addrclip_add( _clipBoard_, _addressSelect_ );
2338 #ifdef DEBUG_ADDRBOOK
2339 addrclip_list_show( _clipBoard_, stdout );
2340 #endif
2344 * Paste clipboard into address tree widget.
2346 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2347 addressbook_clip_paste_cb(NULL,NULL);
2351 * Clear selected entries in clipboard.
2353 static void addressbook_list_select_clear( void ) {
2354 addrselect_list_clear( _addressSelect_ );
2358 * Add specified address item to selected address list.
2359 * \param aio Address item object.
2360 * \param ds Datasource.
2362 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2363 gchar *cacheID;
2365 if( ds == NULL ) return;
2366 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2367 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2368 g_free( cacheID );
2372 * Remove specified address item from selected address list.
2373 * \param aio Address item object.
2375 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2376 addrselect_list_remove( _addressSelect_, aio );
2380 * Invoke EMail compose window with addresses in selected address list.
2382 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2383 GList *listAddress;
2385 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2386 listAddress = addrselect_build_list( _addressSelect_ );
2387 compose_new_with_list( NULL, listAddress );
2388 g_list_free_full( listAddress, g_free );
2389 listAddress = NULL;
2393 static void addressbook_merge_list( AddrSelectList *list ) {
2394 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2395 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2396 AddressObject *pobj;
2397 AddressDataSource *ds = NULL;
2399 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2400 cm_return_if_fail(pobj != NULL);
2402 ds = addressbook_find_datasource( addrbook.treeSelected );
2403 if( ds == NULL ) return;
2405 addrmerge_merge(clist, pobj, ds, list);
2409 * Merge selected entries in the address list
2411 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2412 if( addrselect_test_empty( _addressSelect_ ) )
2413 return;
2415 addressbook_merge_list( _addressSelect_ );
2418 static void addressbook_list_row_selected( GtkCMCTree *clist,
2419 GtkCMCTreeNode *node,
2420 gint column,
2421 gpointer data )
2423 AddrItemObject *aio = NULL;
2424 AddressObject *pobj = NULL;
2425 AdapterDSource *ads = NULL;
2426 AddressDataSource *ds = NULL;
2428 addrbook.listSelected = node;
2430 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2431 if( pobj == NULL ) return;
2433 if( pobj->type == ADDR_DATASOURCE ) {
2434 ads = ADAPTER_DSOURCE(pobj);
2435 ds = ads->dataSource;
2437 else if( pobj->type != ADDR_INTERFACE ) {
2438 ds = addressbook_find_datasource( addrbook.treeSelected );
2441 aio = gtk_cmctree_node_get_row_data( clist, node );
2442 if( aio ) {
2443 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2444 addressbook_list_select_add( aio, ds );
2447 addressbook_list_menu_setup();
2449 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2450 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2452 if (obj && obj->type != ADDR_ITEM_GROUP)
2453 addressbook_edit_address(NULL, 0, NULL, FALSE);
2457 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2458 GtkCMCTreeNode *node,
2459 gint column,
2460 gpointer data )
2462 AddrItemObject *aio;
2464 aio = gtk_cmctree_node_get_row_data( ctree, node );
2465 if( aio != NULL ) {
2466 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2467 addressbook_list_select_remove( aio );
2470 if (!prefs_common.addressbook_use_editaddress_dialog)
2471 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2474 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2476 addressbook_lup_clicked(NULL, NULL);
2479 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2480 GdkEventButton *event,
2481 gpointer data)
2483 if( ! event ) return FALSE;
2484 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2486 addressbook_list_menu_setup();
2488 if( event->button == 3 ) {
2489 gtk_menu_popup_at_pointer(GTK_MENU(addrbook.list_popup), NULL);
2490 } else if (event->button == 1) {
2491 if (event->type == GDK_2BUTTON_PRESS) {
2492 if (prefs_common.add_address_by_click &&
2493 addrbook.target_compose)
2494 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2495 else
2496 if (prefs_common.addressbook_use_editaddress_dialog)
2497 addressbook_edit_address_cb(NULL, NULL);
2498 else {
2499 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2500 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2501 if( obj && obj->type == ADDR_ITEM_GROUP )
2502 addressbook_edit_address_cb(NULL, NULL);
2507 return FALSE;
2510 static gboolean addressbook_list_button_released(GtkWidget *widget,
2511 GdkEventButton *event,
2512 gpointer data)
2514 return FALSE;
2517 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2518 GdkEventButton *event,
2519 gpointer data)
2521 GtkCMCList *clist = GTK_CMCLIST(ctree);
2522 gint row, column;
2523 AddressObject *obj = NULL;
2524 AdapterDSource *ads = NULL;
2525 AddressInterface *iface = NULL;
2526 AddressDataSource *ds = NULL;
2527 gboolean canEdit = FALSE;
2528 gboolean canDelete = FALSE;
2529 gboolean canCut = FALSE;
2530 gboolean canCopy = FALSE;
2531 gboolean canPaste = FALSE;
2532 gboolean canTreeCut = FALSE;
2533 gboolean canTreeCopy = FALSE;
2534 gboolean canTreePaste = FALSE;
2535 gboolean canLookup = FALSE;
2536 GtkCMCTreeNode *node = NULL;
2538 if( ! event ) return FALSE;
2539 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2541 if( event->window != clist->clist_window )
2542 return FALSE;
2544 if (event->button == 1) {
2545 if (event->type == GDK_2BUTTON_PRESS) {
2546 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2547 gtkut_clist_set_focus_row(clist, row);
2548 obj = gtk_cmclist_get_row_data( clist, row );
2550 if( obj == NULL )
2551 return FALSE;
2553 if (obj->type == ADDR_ITEM_GROUP ||
2554 obj->type == ADDR_DATASOURCE) {
2555 /* edit group */
2556 addressbook_treenode_edit_cb(NULL, NULL);
2557 } else {
2558 /* expand pr collapse */
2559 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2560 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2562 return FALSE;
2566 addressbook_menubar_set_sensitive( FALSE );
2568 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2569 gtkut_clist_set_focus_row(clist, row);
2570 obj = gtk_cmclist_get_row_data( clist, row );
2573 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2575 if( obj == NULL )
2576 return FALSE;
2577 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2579 if( ! addrclip_is_empty( _clipBoard_ ) )
2580 canTreePaste = TRUE;
2582 if (obj->type == ADDR_INTERFACE) {
2583 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2584 iface = adapter->interface;
2585 if( !iface )
2586 goto just_set_sens;
2587 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2588 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2590 if( iface->externalQuery )
2591 canLookup = TRUE;
2593 if (obj->type == ADDR_DATASOURCE) {
2594 canLookup = TRUE;
2595 ads = ADAPTER_DSOURCE(obj);
2596 ds = ads->dataSource;
2597 if( !ds )
2598 goto just_set_sens;
2599 iface = ds->interface;
2600 if( !iface )
2601 goto just_set_sens;
2602 if( !iface->readOnly ) {
2603 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2604 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2605 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2607 canDelete = TRUE;
2608 canEdit = TRUE;
2609 canTreeCopy = TRUE;
2611 else if (obj->type == ADDR_ITEM_FOLDER) {
2612 canLookup = TRUE;
2613 ds = addressbook_find_datasource( node );
2614 if( !ds )
2615 goto just_set_sens;
2616 iface = ds->interface;
2617 if( !iface )
2618 goto just_set_sens;
2619 if( !iface->readOnly ) {
2620 canEdit = TRUE;
2621 canDelete = TRUE;
2622 canTreeCut = TRUE;
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2625 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2627 canTreeCopy = TRUE;
2629 if( iface->externalQuery ) {
2630 /* Enable deletion of LDAP folder */
2631 canDelete = TRUE;
2634 else if (obj->type == ADDR_ITEM_GROUP) {
2635 canLookup = TRUE;
2636 ds = addressbook_find_datasource( node );
2637 if( !ds )
2638 goto just_set_sens;
2639 iface = ds->interface;
2640 if( !iface )
2641 goto just_set_sens;
2642 if( ! iface->readOnly ) {
2643 canEdit = TRUE;
2644 canDelete = TRUE;
2645 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2646 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2650 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2651 canCut = TRUE;
2652 if( ! addrselect_test_empty( _addressSelect_ ) )
2653 canCopy = TRUE;
2654 if( ! addrclip_is_empty( _clipBoard_ ) )
2655 canPaste = TRUE;
2657 /* Forbid write changes when read-only */
2658 if( iface && iface->readOnly ) {
2659 canTreeCut = FALSE;
2660 canTreePaste = FALSE;
2661 canCut = FALSE;
2662 canPaste = FALSE;
2665 just_set_sens:
2666 /* Enable edit */
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2669 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2670 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2671 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2675 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2676 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2677 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2679 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2680 addrbook.target_compose != NULL);
2682 if( event->button == 3 )
2683 gtk_menu_popup_at_pointer(GTK_MENU(addrbook.tree_popup), NULL);
2685 return FALSE;
2688 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2689 GdkEventButton *event,
2690 gpointer data)
2692 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2693 return FALSE;
2696 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2698 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2699 AddressObject *obj = NULL;
2700 AddressDataSource *ds = NULL;
2701 AddressBookFile *abf = NULL;
2702 ItemFolder *parentFolder = NULL;
2703 ItemFolder *folder = NULL;
2705 if( ! addrbook.treeSelected ) return;
2706 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2707 if( obj == NULL ) return;
2708 ds = addressbook_find_datasource( addrbook.treeSelected );
2709 if( ds == NULL ) return;
2711 if( obj->type == ADDR_DATASOURCE ) {
2712 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2714 else if( obj->type == ADDR_ITEM_FOLDER ) {
2715 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2717 else {
2718 return;
2721 abf = ds->rawDataSource;
2722 if( abf == NULL ) return;
2723 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2724 if( folder ) {
2725 GtkCMCTreeNode *nn;
2726 nn = addressbook_node_add_folder(
2727 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2728 if (nn == NULL) {
2729 g_message("error adding addressbook folder\n");
2731 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2732 if( addrbook.treeSelected == addrbook.opened )
2733 addressbook_set_clist(obj, TRUE);
2737 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2739 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2740 AddressObject *obj = NULL;
2741 AddressDataSource *ds = NULL;
2742 AddressBookFile *abf = NULL;
2743 ItemFolder *parentFolder = NULL;
2744 ItemGroup *group = NULL;
2746 if( ! addrbook.treeSelected ) return;
2747 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2748 if( obj == NULL ) return;
2749 ds = addressbook_find_datasource( addrbook.treeSelected );
2750 if( ds == NULL ) return;
2752 if( obj->type == ADDR_DATASOURCE ) {
2753 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2755 else if( obj->type == ADDR_ITEM_FOLDER ) {
2756 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2758 else {
2759 return;
2762 abf = ds->rawDataSource;
2763 if( abf == NULL ) return;
2764 group = addressbook_edit_group( abf, parentFolder, NULL );
2765 if( group ) {
2766 GtkCMCTreeNode *nn;
2767 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2768 if (nn == NULL) {
2769 g_message("error adding addressbook group\n");
2771 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2772 if( addrbook.treeSelected == addrbook.opened )
2773 addressbook_set_clist(obj, TRUE);
2777 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2779 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2780 gchar *text[1];
2781 guint8 spacing;
2782 GdkPixbuf *pix_cl, *pix_op;
2783 gboolean is_leaf, expanded;
2785 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2786 &pix_cl, &pix_op,
2787 &is_leaf, &expanded);
2788 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2789 pix_cl, pix_op,
2790 is_leaf, expanded);
2794 * Edit data source.
2795 * \param obj Address object to edit.
2796 * \param node Node in tree.
2797 * \return New name of data source.
2799 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2800 gchar *newName = NULL;
2801 AddressDataSource *ds = NULL;
2802 AddressInterface *iface = NULL;
2803 AdapterDSource *ads = NULL;
2805 ds = addressbook_find_datasource( node );
2806 if( ds == NULL ) return NULL;
2807 iface = ds->interface;
2808 if( ! iface->haveLibrary ) return NULL;
2810 /* Read data from data source */
2811 if( addrindex_ds_get_modify_flag( ds ) ) {
2812 addrindex_ds_read_data( ds );
2815 if( ! addrindex_ds_get_read_flag( ds ) ) {
2816 addrindex_ds_read_data( ds );
2819 /* Handle edit */
2820 ads = ADAPTER_DSOURCE(obj);
2821 if( ads->subType == ADDR_BOOK ) {
2822 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2824 else if( ads->subType == ADDR_VCARD ) {
2825 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2827 #ifdef USE_JPILOT
2828 else if( ads->subType == ADDR_JPILOT ) {
2829 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2831 #endif
2832 #ifdef USE_LDAP
2833 else if( ads->subType == ADDR_LDAP ) {
2834 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2836 #endif
2837 else {
2838 return NULL;
2840 newName = obj->name;
2841 return newName;
2845 * Edit an object that is in the address tree area.
2847 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2849 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2850 AddressObject *obj;
2851 AddressDataSource *ds = NULL;
2852 AddressBookFile *abf = NULL;
2853 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2854 gchar *name = NULL;
2856 if( ! addrbook.treeSelected ) return;
2857 node = addrbook.treeSelected;
2858 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2859 obj = gtk_cmctree_node_get_row_data( ctree, node );
2860 if( obj == NULL ) return;
2861 parentNode = GTK_CMCTREE_ROW(node)->parent;
2863 ds = addressbook_find_datasource( node );
2864 if( ds == NULL ) return;
2866 if( obj->type == ADDR_DATASOURCE ) {
2867 name = addressbook_edit_datasource( obj, node );
2868 if( name == NULL ) return;
2870 else {
2871 abf = ds->rawDataSource;
2872 if( abf == NULL ) return;
2873 if( obj->type == ADDR_ITEM_FOLDER ) {
2874 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2875 ItemFolder *item = adapter->itemFolder;
2876 ItemFolder *parentFolder = NULL;
2877 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2878 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2879 name = ADDRITEM_NAME(item);
2881 else if( obj->type == ADDR_ITEM_GROUP ) {
2882 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2883 ItemGroup *item = adapter->itemGroup;
2884 ItemFolder *parentFolder = NULL;
2885 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2886 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2887 name = ADDRITEM_NAME(item);
2890 if( name && parentNode ) {
2891 /* Update node in tree view */
2892 addressbook_change_node_name( node, name );
2893 gtk_sctree_sort_node(ctree, parentNode);
2894 gtk_cmctree_expand( ctree, node );
2895 gtk_sctree_select( GTK_SCTREE( ctree), node );
2899 typedef enum {
2900 ADDRTREE_DEL_NONE,
2901 ADDRTREE_DEL_DATA,
2902 ADDRTREE_DEL_FOLDER_ONLY,
2903 ADDRTREE_DEL_FOLDER_ADDR
2904 } TreeItemDelType ;
2907 * Delete an item from the tree widget.
2908 * \param data Data passed in.
2909 * \param action Action.
2910 * \param widget Widget issuing callback.
2912 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2914 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2915 GtkCMCTreeNode *node = NULL;
2916 AddressObject *obj;
2917 gchar *message;
2918 AlertValue aval;
2919 AddrBookBase *adbase;
2920 AddressCache *cache;
2921 AdapterDSource *ads = NULL;
2922 AddressInterface *iface = NULL;
2923 AddressDataSource *ds = NULL;
2924 gboolean remFlag = FALSE;
2925 TreeItemDelType delType;
2927 if( ! addrbook.treeSelected ) return;
2928 node = addrbook.treeSelected;
2929 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2931 obj = gtk_cmctree_node_get_row_data( ctree, node );
2932 cm_return_if_fail(obj != NULL);
2934 if( obj->type == ADDR_DATASOURCE ) {
2935 ads = ADAPTER_DSOURCE(obj);
2937 ds = ads->dataSource;
2938 if( ds == NULL ) return;
2940 else {
2941 /* Must be folder or something else */
2942 ds = addressbook_find_datasource( node );
2943 if( ds == NULL ) return;
2945 /* Only allow deletion from non-readOnly */
2946 iface = ds->interface;
2947 if( iface->readOnly ) {
2948 /* Allow deletion of query results */
2949 if( ! iface->externalQuery ) return;
2953 /* Confirm deletion */
2954 delType = ADDRTREE_DEL_NONE;
2955 if( obj->type == ADDR_ITEM_FOLDER ) {
2956 if( iface && iface->externalQuery ) {
2957 message = g_strdup_printf( _(
2958 "Do you want to delete the query " \
2959 "results and addresses in '%s'?" ),
2960 obj->name );
2961 aval = alertpanel( _("Delete"), message,
2962 NULL, _("_Cancel"), "edit-delete", _("D_elete"), NULL, NULL,
2963 ALERTFOCUS_SECOND );
2964 g_free(message);
2965 if( aval == G_ALERTALTERNATE ) {
2966 delType = ADDRTREE_DEL_FOLDER_ADDR;
2969 else {
2970 message = g_strdup_printf
2971 ( _( "Do you want to delete '%s'? "
2972 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2973 obj->name );
2974 aval = alertpanel( _("Delete folder"), message,
2975 NULL, _("_Cancel"), "edit-delete", _("Delete _folder only"),
2976 "edit-delete", _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2977 g_free(message);
2978 if( aval == G_ALERTALTERNATE ) {
2979 delType = ADDRTREE_DEL_FOLDER_ONLY;
2981 else if( aval == G_ALERTOTHER ) {
2982 delType = ADDRTREE_DEL_FOLDER_ADDR;
2986 else if( obj->type == ADDR_ITEM_GROUP ) {
2987 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2988 "The addresses it contains will not be lost."), obj->name);
2989 aval = alertpanel(_("Delete"), message, NULL, _("_Cancel"),
2990 "edit-delete", _("D_elete"), NULL, NULL, ALERTFOCUS_SECOND);
2991 g_free(message);
2992 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2993 } else {
2994 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2995 "The addresses it contains will be lost."), obj->name);
2996 aval = alertpanel(_("Delete"), message, NULL, _("_Cancel"),
2997 "edit-delete", _("D_elete"), NULL, NULL, ALERTFOCUS_SECOND);
2998 g_free(message);
2999 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
3001 if( delType == ADDRTREE_DEL_NONE ) return;
3003 /* Proceed with deletion */
3004 if( obj->type == ADDR_DATASOURCE ) {
3005 /* Remove node from tree */
3006 gtk_cmctree_remove_node( ctree, node );
3008 if (delType == ADDRTREE_DEL_DATA &&
3009 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3010 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3012 /* Remove data source. */
3013 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3014 addrindex_free_datasource( ds );
3016 return;
3019 /* Get reference to cache */
3020 adbase = ( AddrBookBase * ) ds->rawDataSource;
3021 if( adbase == NULL ) return;
3022 cache = adbase->addressCache;
3024 /* Remove query results folder */
3025 if( iface && iface->externalQuery ) {
3026 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3027 ItemFolder *folder = adapter->itemFolder;
3029 adapter->itemFolder = NULL;
3031 g_print( "remove folder for ::%s::\n", obj->name );
3032 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3033 g_print( "-------------- remove results\n" );
3035 addrindex_remove_results( ds, folder );
3036 /* g_print( "-------------- remove node\n" ); */
3037 gtk_cmctree_remove_node( ctree, node );
3038 return;
3041 /* Code below is valid for regular address book deletion */
3042 if( obj->type == ADDR_ITEM_FOLDER ) {
3043 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3044 ItemFolder *item = adapter->itemFolder;
3046 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3047 /* Remove folder only */
3048 item = addrcache_remove_folder( cache, item );
3049 if( item ) {
3050 addritem_free_item_folder( item );
3051 addressbook_move_nodes_up( ctree, node );
3052 remFlag = TRUE;
3055 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3056 /* Remove folder and addresses */
3057 item = addrcache_remove_folder_delete( cache, item );
3058 if( item ) {
3059 addritem_free_item_folder( item );
3060 remFlag = TRUE;
3064 else if( obj->type == ADDR_ITEM_GROUP ) {
3065 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3066 ItemGroup *item = adapter->itemGroup;
3068 item = addrcache_remove_group( cache, item );
3069 if( item ) {
3070 addritem_free_item_group( item );
3071 remFlag = TRUE;
3075 if( remFlag ) {
3076 /* Remove node. */
3077 gtk_cmctree_remove_node(ctree, node );
3081 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3083 if( person && addrbook.treeSelected == addrbook.opened ) {
3084 person->status = ADD_ENTRY;
3085 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3086 addressbook_folder_refresh_one_person(
3087 GTK_CMCTREE(addrbook.clist), person );
3089 addressbook_address_list_set_focus();
3092 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3094 if( person && addrbook.treeSelected == addrbook.opened) {
3095 person->status = ADD_ENTRY;
3096 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3097 addressbook_set_clist(
3098 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3099 addrbook.opened),
3100 TRUE);
3102 addressbook_address_list_set_focus();
3106 * Label (a format string) that is used to name each folder.
3108 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3111 * Search ctree widget callback function.
3112 * \param pA Pointer to node.
3113 * \param pB Pointer to data item being sought.
3114 * \return Zero (0) if folder found.
3116 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3117 AddressObject *aoA;
3119 aoA = ( AddressObject * ) pA;
3120 if( aoA->type == ADDR_ITEM_FOLDER ) {
3121 ItemFolder *folder, *fld;
3123 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3124 folder = ( ItemFolder * ) pB;
3125 if( fld == folder ) return 0; /* Found folder */
3127 return 1;
3130 static ItemFolder * addressbook_setup_subf(
3131 AddressDataSource *ds, gchar *title,
3132 GtkCMCTreeNode *pNode )
3134 AddrBookBase *adbase;
3135 AddressCache *cache;
3136 ItemFolder *folder;
3137 GtkCMCTree *ctree;
3138 GtkCMCTreeNode *nNode;
3139 gchar *name;
3140 AddressObjectType aoType = ADDR_NONE;
3141 GList *children;
3142 /* Setup a query */
3143 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3145 if( ds && ds->type == ADDR_IF_LDAP ) {
3146 #if USE_LDAP
3147 aoType = ADDR_LDAP_QUERY;
3148 #endif
3150 else {
3151 return NULL;
3154 ctree = GTK_CMCTREE(addrbook.ctree);
3155 /* Get reference to address cache */
3156 adbase = ( AddrBookBase * ) ds->rawDataSource;
3157 cache = adbase->addressCache;
3159 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3160 GList *cur = children;
3161 for (; cur; cur = cur->next) {
3162 ItemFolder *child = (ItemFolder *) cur->data;
3163 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3164 nNode = gtk_cmctree_find_by_row_data_custom(
3165 ctree, NULL, child,
3166 addressbook_treenode_find_folder_cb );
3167 if( nNode ) {
3168 addrindex_remove_results( ds, child );
3169 while( child->listPerson ) {
3170 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3171 item = addrcache_remove_person( cache, item );
3172 if( item ) {
3173 addritem_free_item_person( item );
3174 item = NULL;
3177 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3178 addrbook.treeSelected = nNode;
3180 return child;
3185 /* Create a folder */
3186 folder = addrcache_add_new_folder( cache, NULL );
3187 name = g_strdup_printf( "%s", title );
3188 addritem_folder_set_name( folder, name );
3189 addritem_folder_set_remarks( folder, "" );
3190 g_free( name );
3192 /* Now let's see the folder */
3193 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3194 gtk_cmctree_expand( ctree, pNode );
3195 if( nNode ) {
3196 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3197 addrbook.treeSelected = nNode;
3198 return folder;
3200 return NULL;
3203 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3204 AddressObject *pobj = NULL;
3205 AddressDataSource *ds = NULL;
3206 AddressBookFile *abf = NULL;
3207 debug_print("adding address\n");
3208 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3209 if( pobj == NULL ) {
3210 debug_print("no row data\n");
3211 return;
3213 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3214 if( ds == NULL ) {
3215 debug_print("no datasource\n");
3216 return;
3219 abf = ds->rawDataSource;
3220 if( abf == NULL ) {
3221 g_print("no addressbook file\n");
3222 return;
3225 if( pobj->type == ADDR_DATASOURCE ) {
3226 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3227 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3228 ItemPerson *person;
3229 ItemFolder *folder = NULL;
3230 #ifdef USE_LDAP
3231 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3232 GtkCMCTreeNode *parentNode;
3233 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3234 if( ds == NULL ) return;
3236 /* We must have a datasource that is an external interface */
3237 if( ! ds->interface->haveLibrary ) return;
3238 if( ! ds->interface->externalQuery ) return;
3240 if( pobj->type == ADDR_ITEM_FOLDER ) {
3241 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3243 else {
3244 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3246 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3248 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3249 if (ds)
3250 abf = ds->rawDataSource;
3252 #endif
3253 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3254 addrbook.editaddress_vbox,
3255 addressbook_new_address_from_book_post_cb,
3256 TRUE );
3257 #ifdef USE_LDAP
3258 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3259 LdapServer *server = ds->rawDataSource;
3260 ldapsvr_set_modified(server, TRUE);
3261 ldapsvr_update_book(server, NULL);
3262 if (server->retVal != LDAPRC_SUCCESS) {
3263 alertpanel( _("Add address(es)"),
3264 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3265 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
3266 ALERTFOCUS_FIRST );
3267 server->retVal = LDAPRC_SUCCESS;
3268 return;
3271 #endif
3272 if (prefs_common.addressbook_use_editaddress_dialog)
3273 addressbook_new_address_from_book_post_cb( person );
3276 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3277 /* New address */
3278 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3279 ItemPerson *person;
3280 #ifdef USE_LDAP
3281 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3282 GtkCMCTreeNode *parentNode;
3283 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3284 if( ds == NULL ) return;
3286 /* We must have a datasource that is an external interface */
3287 if( ! ds->interface->haveLibrary ) return;
3288 if( ! ds->interface->externalQuery ) return;
3290 if( pobj->type == ADDR_ITEM_FOLDER ) {
3291 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3293 else {
3294 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3296 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3297 if (!folder)
3298 return;
3300 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3301 if (ds)
3302 abf = ds->rawDataSource;
3304 #endif
3305 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3306 addrbook.editaddress_vbox,
3307 addressbook_new_address_from_folder_post_cb,
3308 TRUE );
3309 #ifdef USE_LDAP
3310 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3311 LdapServer *server = ds->rawDataSource;
3312 ldapsvr_set_modified(server, TRUE);
3313 ldapsvr_update_book(server, NULL);
3314 if (server->retVal != LDAPRC_SUCCESS) {
3315 alertpanel( _("Add address(es)"),
3316 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3317 "window-close", _("_Close"), NULL, NULL, NULL, NULL, ALERTFOCUS_FIRST );
3318 return;
3321 #endif
3322 if (prefs_common.addressbook_use_editaddress_dialog)
3323 addressbook_new_address_from_folder_post_cb( person );
3325 else if( pobj->type == ADDR_ITEM_GROUP ) {
3326 /* New address in group */
3327 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3328 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3329 if (addrbook.treeSelected == addrbook.opened) {
3330 /* Change node name in tree. */
3331 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3332 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3333 addressbook_set_clist(
3334 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3335 addrbook.opened),
3336 TRUE);
3342 * Search for specified child group node in address index tree.
3343 * \param parent Parent node.
3344 * \param group Group to find.
3346 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3347 GtkCMCTreeNode *node = NULL;
3348 GtkCMCTreeRow *currRow;
3350 currRow = GTK_CMCTREE_ROW( parent );
3351 if( currRow ) {
3352 node = currRow->children;
3353 while( node ) {
3354 AddressObject *obj;
3356 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3357 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3358 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3359 if( g == group ) return node;
3361 currRow = GTK_CMCTREE_ROW(node);
3362 node = currRow->sibling;
3365 return NULL;
3368 static AddressBookFile *addressbook_get_book_file() {
3369 AddressBookFile *abf = NULL;
3370 AddressDataSource *ds = NULL;
3372 ds = addressbook_find_datasource( addrbook.treeSelected );
3373 if( ds == NULL ) return NULL;
3374 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3375 return abf;
3378 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3379 GtkCMCTreeNode *node;
3380 GtkCMCTreeRow *row;
3382 /* Remove existing folders and groups */
3383 row = GTK_CMCTREE_ROW( parent );
3384 if( row ) {
3385 while( (node = row->children) ) {
3386 gtk_cmctree_remove_node( ctree, node );
3391 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3392 GtkCMCTreeNode *parent, *child;
3393 GtkCMCTreeRow *currRow;
3394 currRow = GTK_CMCTREE_ROW( node );
3395 if( currRow ) {
3396 parent = currRow->parent;
3397 while( (child = currRow->children) ) {
3398 gtk_cmctree_move( ctree, child, parent, node );
3400 gtk_sctree_sort_node( ctree, parent );
3404 static void addressbook_edit_address_post_cb( ItemPerson *person )
3406 if( person ) {
3407 #ifdef USE_LDAP
3408 AddressBookFile *abf = addressbook_get_book_file();
3410 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3411 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3412 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3414 #endif
3415 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3416 invalidate_address_completion();
3418 addressbook_address_list_set_focus();
3421 void addressbook_address_list_set_focus( void )
3423 if (!prefs_common.addressbook_use_editaddress_dialog) {
3424 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3425 addressbook_list_menu_setup();
3429 void addressbook_address_list_disable_some_actions(void)
3431 /* disable address copy/pasting when editing contact's detail (embedded form) */
3432 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", FALSE );
3433 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", FALSE );
3434 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
3437 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3438 addressbook_edit_address(data, 0, NULL, TRUE);
3441 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3442 gboolean force_focus ) {
3443 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3444 GtkCMCTree *ctree;
3445 AddressObject *obj = NULL, *pobj = NULL;
3446 AddressDataSource *ds = NULL;
3447 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3448 gchar *name = NULL;
3449 AddressBookFile *abf = NULL;
3451 if( addrbook.listSelected == NULL ) return;
3452 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3453 cm_return_if_fail(obj != NULL);
3455 ctree = GTK_CMCTREE( addrbook.ctree );
3456 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3458 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3459 if( ds == NULL ) return;
3461 abf = addressbook_get_book_file();
3463 if( obj->type == ADDR_ITEM_EMAIL ) {
3464 ItemEMail *email = ( ItemEMail * ) obj;
3466 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3467 /* Edit parent group */
3468 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3469 ItemGroup *itemGrp = adapter->itemGroup;
3470 if( abf == NULL ) return;
3471 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3472 name = ADDRITEM_NAME(itemGrp);
3473 node = addrbook.treeSelected;
3474 parentNode = GTK_CMCTREE_ROW(node)->parent;
3476 else {
3477 /* Edit person - email page */
3478 ItemPerson *person;
3479 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3480 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3481 addressbook_edit_address_post_cb,
3482 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3483 != NULL ) {
3484 #ifdef USE_LDAP
3485 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3486 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3487 person->status = UPDATE_ENTRY;
3489 #endif
3490 if (prefs_common.addressbook_use_editaddress_dialog)
3491 addressbook_edit_address_post_cb( person );
3493 return;
3496 else if( obj->type == ADDR_ITEM_PERSON ) {
3497 /* Edit person - basic page */
3498 ItemPerson *person = ( ItemPerson * ) obj;
3499 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3500 addressbook_edit_address_post_cb,
3501 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3502 != NULL ) {
3503 #ifdef USE_LDAP
3504 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3505 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3506 person->status = UPDATE_ENTRY;
3508 #endif
3509 if (prefs_common.addressbook_use_editaddress_dialog)
3510 addressbook_edit_address_post_cb( person );
3512 return;
3514 else if( obj->type == ADDR_ITEM_GROUP ) {
3515 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3516 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3517 parentNode = addrbook.treeSelected;
3518 node = addressbook_find_group_node( parentNode, itemGrp );
3519 name = ADDRITEM_NAME(itemGrp);
3520 invalidate_address_completion();
3522 else {
3523 return;
3526 /* Update tree node with node name */
3527 if( node == NULL ) return;
3528 addressbook_change_node_name( node, name );
3529 gtk_sctree_sort_node( ctree, parentNode );
3530 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3531 addressbook_set_clist(
3532 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3533 addrbook.opened),
3534 TRUE);
3537 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3539 addressbook_del_clicked(NULL, NULL);
3542 static void close_cb(GtkAction *action, gpointer data)
3544 addressbook_close();
3547 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3548 addressbook_export_to_file();
3551 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3552 if( node ) {
3553 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3554 if( person ) addritem_person_set_opened( person, TRUE );
3558 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3559 if( node ) {
3560 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3561 if( person ) addritem_person_set_opened( person, FALSE );
3565 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3566 gchar *str = NULL;
3567 gchar *eMailAlias = ADDRITEM_NAME(email);
3568 if( eMailAlias && *eMailAlias != '\0' ) {
3569 if( person ) {
3570 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3572 else {
3573 str = g_strdup( eMailAlias );
3576 return str;
3579 static gboolean addressbook_match_item(const gchar *name,
3580 const gchar *email_alias,
3581 const gchar *addr,
3582 const gchar *remarks,
3583 const gchar *str)
3585 if (!name)
3586 return FALSE;
3587 if (!str || str[0] == '\0')
3588 return TRUE;
3589 if (strcasestr(name, str))
3590 return TRUE;
3591 else if (email_alias && strcasestr(email_alias, str))
3592 return TRUE;
3593 else if (addr && strcasestr(addr, str))
3594 return TRUE;
3595 else if (remarks && strcasestr(remarks, str))
3596 return TRUE;
3598 return FALSE;
3601 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3602 GList *items = itemGroup->listEMail;
3603 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3604 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3605 for( ; items != NULL; items = g_list_next( items ) ) {
3606 GtkCMCTreeNode *nodeEMail = NULL;
3607 gchar *text[N_LIST_COLS];
3608 ItemEMail *email = items->data;
3609 ItemPerson *person;
3610 gchar *str = NULL;
3612 if( ! email ) continue;
3614 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3616 if( !addressbook_match_item(ADDRITEM_NAME(person),
3617 ADDRITEM_NAME(email),
3618 email->address, email->remarks,
3619 search_str))
3620 continue;
3622 str = addressbook_format_item_clist( person, email );
3623 if( str ) {
3624 text[COL_NAME] = addressbook_set_col_name_guard(str);
3626 else {
3627 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3629 text[COL_ADDRESS] = email->address;
3630 text[COL_REMARKS] = email->remarks;
3631 nodeEMail = gtk_sctree_insert_node(
3632 clist, NULL, NULL,
3633 text, FOLDER_SPACING,
3634 atci->iconXpm,
3635 atci->iconXpmOpen,
3636 FALSE, FALSE );
3637 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3638 g_free( str );
3639 str = NULL;
3643 gchar *addressbook_set_col_name_guard(gchar *value)
3645 gchar *ret = "<not set>";
3646 gchar *tmp = g_strdup(value);
3647 if (tmp) {
3648 g_strstrip(tmp);
3649 if (*tmp != '\0')
3650 ret = value;
3651 g_free(tmp);
3653 return ret;
3656 static void addressbook_folder_load_one_person(
3657 GtkCMCTree *clist, ItemPerson *person,
3658 AddressTypeControlItem *atci,
3659 AddressTypeControlItem *atciMail )
3661 GtkCMCTreeNode *nodePerson = NULL;
3662 GtkCMCTreeNode *nodeEMail = NULL;
3663 gchar *text[N_LIST_COLS];
3664 gboolean flgFirst = TRUE, haveAddr = FALSE;
3665 GList *node;
3666 #ifdef USE_LDAP
3667 AddressBookFile *abf = addressbook_get_book_file();
3668 #endif
3670 if( person == NULL ) return;
3672 text[COL_NAME] = "";
3673 node = person->listEMail;
3674 while( node ) {
3675 ItemEMail *email = node->data;
3676 gchar *eMailAddr = NULL;
3677 node = g_list_next( node );
3679 text[COL_ADDRESS] = email->address;
3680 text[COL_REMARKS] = email->remarks;
3681 eMailAddr = ADDRITEM_NAME(email);
3682 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3683 if( flgFirst ) {
3684 /* First email belongs with person */
3685 gchar *str = addressbook_format_item_clist( person, email );
3686 if( str ) {
3687 text[COL_NAME] = addressbook_set_col_name_guard(str);
3689 #ifdef USE_LDAP
3690 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3691 person && person->nickName ) {
3692 if (person->nickName) {
3693 if (strcmp(person->nickName, "") != 0) {
3694 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3696 else {
3697 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3701 #endif
3702 else {
3703 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3705 nodePerson = gtk_sctree_insert_node(
3706 clist, NULL, NULL,
3707 text, FOLDER_SPACING,
3708 atci->iconXpm,
3709 atci->iconXpmOpen,
3710 FALSE, person->isOpened );
3711 g_free( str );
3712 str = NULL;
3713 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3715 else {
3716 /* Subsequent email is a child node of person */
3717 text[COL_NAME] = ADDRITEM_NAME(email);
3718 nodeEMail = gtk_sctree_insert_node(
3719 clist, nodePerson, NULL,
3720 text, FOLDER_SPACING,
3721 atciMail->iconXpm,
3722 atciMail->iconXpmOpen,
3723 FALSE, TRUE );
3724 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3726 flgFirst = FALSE;
3727 haveAddr = TRUE;
3729 if( ! haveAddr ) {
3730 /* Have name without EMail */
3731 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3732 text[COL_ADDRESS] = "";
3733 text[COL_REMARKS] = "";
3734 nodePerson = gtk_sctree_insert_node(
3735 clist, NULL, NULL,
3736 text, FOLDER_SPACING,
3737 atci->iconXpm,
3738 atci->iconXpmOpen,
3739 FALSE, person->isOpened );
3740 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3742 return;
3745 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3746 GList *items, *cur;
3747 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3748 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3749 const gchar *search_str;
3751 if( atci == NULL ) return;
3752 if( atciMail == NULL ) return;
3754 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3756 /* Load email addresses */
3757 items = addritem_folder_get_person_list( itemFolder );
3758 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3759 ItemPerson *person;
3760 GList *node;
3761 ItemEMail *email;
3763 person = (ItemPerson *)cur->data;
3764 if (!person)
3765 continue;
3766 node = person->listEMail;
3767 if (node && node->data) {
3768 email = node->data;
3769 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3770 continue;
3771 } else {
3772 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3773 continue;
3776 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3778 /* Free up the list */
3779 g_list_free( items );
3782 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3783 addrbook.listSelected = NULL;
3784 gtk_cmctree_remove_node( clist, node );
3785 addressbook_menubar_set_sensitive( FALSE );
3786 addressbook_menuitem_set_sensitive(
3787 gtk_cmctree_node_get_row_data(
3788 GTK_CMCTREE(clist), addrbook.treeSelected ),
3789 addrbook.treeSelected );
3792 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3793 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3794 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3795 GtkCMCTreeNode *node;
3796 if( atci == NULL ) return;
3797 if( atciMail == NULL ) return;
3798 if( person == NULL ) return;
3799 /* unload the person */
3801 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3802 if( node )
3803 addressbook_folder_remove_node( clist, node );
3804 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3805 gtk_sctree_sort_node( clist, NULL );
3806 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3807 if( node ) {
3808 gtk_sctree_select( GTK_SCTREE(clist), node );
3809 if (!gtk_cmctree_node_is_visible( clist, node ) )
3810 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3814 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3815 GtkCMCTreeNode *node;
3817 if( person == NULL ) return;
3818 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3819 if( node ) {
3820 addressbook_folder_remove_node( clist, node );
3824 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3825 GList *items;
3826 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3827 const gchar *search_str;
3829 /* Load any groups */
3830 if( ! atci ) return;
3832 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3834 items = addritem_folder_get_group_list( itemFolder );
3835 for( ; items != NULL; items = g_list_next( items ) ) {
3836 GtkCMCTreeNode *nodeGroup = NULL;
3837 gchar *text[N_LIST_COLS];
3838 ItemGroup *group = items->data;
3839 if( group == NULL ) continue;
3840 if( !addressbook_match_item(ADDRITEM_NAME(group),
3841 NULL, NULL, NULL, search_str) )
3842 continue;
3844 text[COL_NAME] = ADDRITEM_NAME(group);
3845 text[COL_ADDRESS] = "";
3846 text[COL_REMARKS] = "";
3847 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3848 text, FOLDER_SPACING,
3849 atci->iconXpm,
3850 atci->iconXpmOpen,
3851 FALSE, FALSE);
3852 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3853 gtk_sctree_sort_node(clist, NULL);
3855 /* Free up the list */
3856 g_list_free( items );
3860 * Search ctree widget callback function.
3861 * \param pA Pointer to node.
3862 * \param pB Pointer to data item being sought.
3863 * \return Zero (0) if group found.
3865 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3866 AddressObject *aoA;
3868 aoA = ( AddressObject * ) pA;
3869 if( aoA->type == ADDR_ITEM_GROUP ) {
3870 ItemGroup *group, *grp;
3872 grp = ADAPTER_GROUP(aoA)->itemGroup;
3873 group = ( ItemGroup * ) pB;
3874 if( grp == group ) return 0; /* Found group */
3876 return 1;
3880 * Remove folder and group nodes from tree widget for items contained ("cut")
3881 * in clipboard.
3883 static void addressbook_treenode_remove_item( void ) {
3884 GList *node;
3885 AddrSelectItem *cutItem;
3886 AddressCache *cache;
3887 AddrItemObject *aio;
3888 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3889 GtkCMCTreeNode *tn;
3891 node = _clipBoard_->objectList;
3892 while( node ) {
3893 cutItem = node->data;
3894 node = g_list_next( node );
3895 cache = addrindex_get_cache(
3896 _clipBoard_->addressIndex, cutItem->cacheID );
3897 if( cache == NULL ) continue;
3898 aio = addrcache_get_object( cache, cutItem->uid );
3899 if( aio ) {
3900 tn = NULL;
3901 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3902 ItemFolder *folder;
3904 folder = ( ItemFolder * ) aio;
3905 tn = gtk_cmctree_find_by_row_data_custom(
3906 ctree, NULL, folder,
3907 addressbook_treenode_find_folder_cb );
3909 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3910 ItemGroup *group;
3912 group = ( ItemGroup * ) aio;
3913 tn = gtk_cmctree_find_by_row_data_custom(
3914 ctree, NULL, group,
3915 addressbook_treenode_find_group_cb );
3918 if( tn ) {
3919 /* Free up adapter and remove node. */
3920 gtk_cmctree_remove_node( ctree, tn );
3927 * Find parent datasource for specified tree node.
3928 * \param node Node to test.
3929 * \return Data source, or NULL if not found.
3931 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3932 AddressDataSource *ds = NULL;
3933 AddressObject *ao;
3935 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3937 while( node ) {
3938 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3939 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3940 if( ao ) {
3941 /* g_print( "ao->type = %d\n", ao->type ); */
3942 if( ao->type == ADDR_DATASOURCE ) {
3943 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3944 /* g_print( "found it\n" ); */
3945 ds = ads->dataSource;
3946 break;
3949 node = GTK_CMCTREE_ROW(node)->parent;
3951 return ds;
3955 * Load address list widget with children of specified object.
3956 * \param obj Parent object to be loaded.
3958 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3959 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3960 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3961 AddressDataSource *ds = NULL;
3962 AdapterDSource *ads = NULL;
3963 static AddressObject *last_obj = NULL;
3965 if (addrbook.clist == NULL) {
3966 return;
3968 if (obj == last_obj && !refresh)
3969 return;
3971 last_obj = obj;
3972 if( obj == NULL ) {
3973 gtk_cmclist_clear(clist);
3974 return;
3977 if( obj->type == ADDR_INTERFACE ) {
3978 /* g_print( "set_clist: loading datasource...\n" ); */
3979 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3980 return;
3983 gtk_cmclist_freeze(clist);
3984 gtk_cmclist_clear(clist);
3986 if( obj->type == ADDR_DATASOURCE ) {
3987 ads = ADAPTER_DSOURCE(obj);
3988 ds = ads->dataSource;
3989 if( ds ) {
3990 /* Load root folder */
3991 ItemFolder *rootFolder = NULL;
3992 rootFolder = addrindex_ds_get_root_folder( ds );
3993 addressbook_folder_load_person(
3994 ctreelist, rootFolder );
3995 addressbook_folder_load_group(
3996 ctreelist, rootFolder );
3999 else {
4000 if( obj->type == ADDR_ITEM_GROUP ) {
4001 /* Load groups */
4002 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
4003 addressbook_load_group( ctreelist, itemGroup );
4005 else if( obj->type == ADDR_ITEM_FOLDER ) {
4006 /* Load folders */
4007 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4008 addressbook_folder_load_person( ctreelist, itemFolder );
4009 addressbook_folder_load_group( ctreelist, itemFolder );
4012 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4013 clist->focus_row = -1;
4014 gtk_cmclist_thaw(clist);
4018 * Call back function to free adaptor. Call back is setup by function
4019 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4020 * called when the address book tree widget node is removed by calling
4021 * function gtk_cmctree_remove_node().
4023 * \param data Tree node's row data.
4025 static void addressbook_free_treenode( gpointer data ) {
4026 AddressObject *ao;
4028 ao = ( AddressObject * ) data;
4029 if( ao == NULL ) return;
4030 if( ao->type == ADDR_INTERFACE ) {
4031 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4032 addrbookctl_free_interface( ai );
4034 else if( ao->type == ADDR_DATASOURCE ) {
4035 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4036 addrbookctl_free_datasource( ads );
4038 else if( ao->type == ADDR_ITEM_FOLDER ) {
4039 AdapterFolder *af = ADAPTER_FOLDER(ao);
4040 addrbookctl_free_folder( af );
4042 else if( ao->type == ADDR_ITEM_GROUP ) {
4043 AdapterGroup *ag = ADAPTER_GROUP(ao);
4044 addrbookctl_free_group( ag );
4049 * Create new adaptor for specified data source.
4051 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4052 AddressObjectType otype, gchar *name )
4054 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4055 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4056 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4057 adapter->dataSource = ds;
4058 adapter->subType = otype;
4059 return adapter;
4062 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4063 ADDRESS_OBJECT_NAME(adapter) =
4064 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4068 * Load tree from address index with the initial data.
4070 static void addressbook_load_tree( void ) {
4071 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4072 GList *nodeIf, *nodeDS;
4073 AdapterInterface *adapter;
4074 AddressInterface *iface;
4075 AddressTypeControlItem *atci;
4076 AddressDataSource *ds;
4077 AdapterDSource *ads;
4078 GtkCMCTreeNode *node, *newNode;
4079 gchar *name;
4081 nodeIf = _addressInterfaceList_;
4082 while( nodeIf ) {
4083 adapter = nodeIf->data;
4084 node = adapter->treeNode;
4085 iface = adapter->interface;
4086 atci = adapter->atci;
4087 if( iface ) {
4088 if( iface->useInterface ) {
4089 /* Load data sources below interface node */
4090 nodeDS = iface->listSource;
4091 while( nodeDS ) {
4092 ds = nodeDS->data;
4093 name = addrindex_ds_get_name( ds );
4094 ads = addressbook_create_ds_adapter(
4095 ds, atci->objectType, name );
4096 newNode = addressbook_add_object(
4097 node, ADDRESS_OBJECT(ads) );
4098 if (newNode == NULL) {
4099 g_message("error adding addressbook object\n");
4101 nodeDS = g_list_next( nodeDS );
4103 gtk_cmctree_expand( ctree, node );
4106 nodeIf = g_list_next( nodeIf );
4111 * Convert the old address book to new format.
4113 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4114 gboolean retVal = FALSE;
4115 gboolean errFlag = TRUE;
4116 gchar *msg = NULL;
4118 /* Read old address book, performing conversion */
4119 debug_print( "Reading and converting old address book...\n" );
4120 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4121 addrindex_read_data( addrIndex );
4122 if( addrIndex->retVal == MGU_NO_FILE ) {
4123 /* We do not have a file - new user */
4124 debug_print( "New user... create new books...\n" );
4125 addrindex_create_new_books( addrIndex );
4126 if( addrIndex->retVal == MGU_SUCCESS ) {
4127 /* Save index file */
4128 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4129 addrindex_save_data( addrIndex );
4130 if( addrIndex->retVal == MGU_SUCCESS ) {
4131 retVal = TRUE;
4132 errFlag = FALSE;
4134 else {
4135 msg = _( "New user, could not save index file." );
4138 else {
4139 msg = _( "New user, could not save address book files." );
4142 else {
4143 /* We have an old file */
4144 if( addrIndex->wasConverted ) {
4145 /* Converted successfully - save address index */
4146 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4147 addrindex_save_data( addrIndex );
4148 if( addrIndex->retVal == MGU_SUCCESS ) {
4149 msg = _( "Old address book converted successfully." );
4150 retVal = TRUE;
4151 errFlag = FALSE;
4153 else {
4154 msg = _("Old address book converted,\n"
4155 "could not save new address index file." );
4158 else {
4159 /* File conversion failed - just create new books */
4160 debug_print( "File conversion failed... just create new books...\n" );
4161 addrindex_create_new_books( addrIndex );
4162 if( addrIndex->retVal == MGU_SUCCESS ) {
4163 /* Save index */
4164 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4165 addrindex_save_data( addrIndex );
4166 if( addrIndex->retVal == MGU_SUCCESS ) {
4167 msg = _("Could not convert address book,\n"
4168 "but created empty new address book files." );
4169 retVal = TRUE;
4170 errFlag = FALSE;
4172 else {
4173 msg = _("Could not convert address book,\n"
4174 "could not save new address index file." );
4177 else {
4178 msg = _("Could not convert address book\n"
4179 "and could not create new address book files." );
4183 if (errFlag) {
4184 debug_print( "Error\n%s\n", msg );
4185 alertpanel_full(_("Addressbook conversion error"), msg,
4186 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
4187 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_ERROR);
4188 } else if (msg) {
4189 debug_print( "Warning\n%s\n", msg );
4190 alertpanel_full(_("Addressbook conversion error"), msg,
4191 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
4192 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING);
4195 return retVal;
4198 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4200 GDir *dp;
4201 const gchar *d;
4202 gboolean failed = FALSE;
4203 GError *error = NULL;
4205 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4206 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4207 error->code, error->message);
4208 g_error_free(error);
4209 return FALSE;
4212 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4213 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4214 continue;
4215 else {
4216 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4217 d, NULL);
4218 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4219 d, NULL);
4220 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4221 failed = TRUE;
4223 g_free(orig_file);
4224 g_free(dest_file);
4225 if (failed) {
4226 break;
4230 g_dir_close( dp );
4232 if (!failed) {
4233 /* all copies succeeded, we can remove source files */
4234 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4235 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4236 error->code, error->message);
4237 g_error_free(error);
4238 return FALSE;
4240 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4241 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4242 continue;
4243 else {
4244 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4245 d, NULL);
4246 claws_unlink(orig_file);
4247 g_free(orig_file);
4250 g_dir_close( dp );
4253 return !failed;
4256 void addressbook_read_file( void ) {
4257 AddressIndex *addrIndex = NULL;
4258 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4260 debug_print( "Reading address index...\n" );
4261 if( _addressIndex_ ) {
4262 debug_print( "address book already read!!!\n" );
4263 g_free(indexdir);
4264 return;
4267 addrIndex = addrindex_create_index();
4268 addrindex_initialize();
4270 /* Use new address book index. */
4272 if ( !is_dir_exist(indexdir) ) {
4273 if ( make_dir(indexdir) < 0 ) {
4274 addrindex_set_file_path( addrIndex, get_rc_dir() );
4275 g_warning("couldn't create dir '%s'", indexdir);
4276 } else {
4277 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4278 remove_dir_recursive(indexdir);
4279 addrindex_set_file_path( addrIndex, get_rc_dir() );
4280 g_error("couldn't migrate dir %s", indexdir);
4281 } else {
4282 addrindex_set_file_path( addrIndex, indexdir);
4285 } else {
4286 addrindex_set_file_path( addrIndex, indexdir);
4288 g_free(indexdir);
4289 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4290 addrindex_read_data( addrIndex );
4291 if( addrIndex->retVal == MGU_NO_FILE ) {
4292 /* Conversion required */
4293 debug_print( "Converting...\n" );
4294 if( addressbook_convert( addrIndex ) ) {
4295 _addressIndex_ = addrIndex;
4298 else if( addrIndex->retVal == MGU_SUCCESS ) {
4299 _addressIndex_ = addrIndex;
4301 else {
4302 /* Error reading address book */
4303 debug_print( "Could not read address index.\n" );
4304 addrindex_print_index( addrIndex, stdout );
4305 alertpanel_full(_("Addressbook Error"),
4306 _("Could not read address index"),
4307 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
4308 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_ERROR);
4310 debug_print( "done.\n" );
4314 * Add object into the address index tree widget.
4315 * Enter: node Parent node.
4316 * obj Object to add.
4317 * Return: Node that was added, or NULL if object not added.
4319 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4320 AddressObject *obj)
4322 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4323 GtkCMCTreeNode *added;
4324 AddressObject *pobj;
4325 AddressObjectType otype;
4326 AddressTypeControlItem *atci = NULL;
4328 cm_return_val_if_fail(node != NULL, NULL);
4329 cm_return_val_if_fail(obj != NULL, NULL);
4331 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4332 cm_return_val_if_fail(pobj != NULL, NULL);
4334 /* Determine object type to be displayed */
4335 if( obj->type == ADDR_DATASOURCE ) {
4336 otype = ADAPTER_DSOURCE(obj)->subType;
4338 else {
4339 otype = obj->type;
4342 /* Handle any special conditions. */
4343 added = node;
4344 atci = addrbookctl_lookup( otype );
4345 if( atci ) {
4346 if( atci->showInTree ) {
4347 /* Add object to tree */
4348 gchar **name;
4349 name = &obj->name;
4350 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4351 atci->iconXpm, atci->iconXpmOpen,
4352 atci->treeLeaf, atci->treeExpand );
4353 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4354 addressbook_free_treenode );
4358 gtk_sctree_sort_node(ctree, node);
4360 return added;
4364 * Add group into the address index tree.
4365 * \param node Parent node.
4366 * \param ds Data source.
4367 * \param itemGroup Group to add.
4368 * \return Inserted node.
4370 static GtkCMCTreeNode *addressbook_node_add_group(
4371 GtkCMCTreeNode *node, AddressDataSource *ds,
4372 ItemGroup *itemGroup )
4374 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4375 GtkCMCTreeNode *newNode;
4376 AdapterGroup *adapter;
4377 AddressTypeControlItem *atci = NULL;
4378 gchar **name;
4380 if( ds == NULL ) return NULL;
4381 if( node == NULL || itemGroup == NULL ) return NULL;
4383 name = &itemGroup->obj.name;
4385 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4387 adapter = g_new0( AdapterGroup, 1 );
4388 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4389 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4390 adapter->itemGroup = itemGroup;
4392 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4393 atci->iconXpm, atci->iconXpm,
4394 atci->treeLeaf, atci->treeExpand );
4395 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4396 addressbook_free_treenode );
4397 gtk_sctree_sort_node( ctree, node );
4398 return newNode;
4402 * Add folder into the address index tree. Only visible folders are loaded into
4403 * the address index tree. Note that the root folder is not inserted into the
4404 * tree.
4406 * \param node Parent node.
4407 * \param ds Data source.
4408 * \param itemFolder Folder to add.
4409 * \param otype Object type to display.
4410 * \return Inserted node for the folder.
4412 static GtkCMCTreeNode *addressbook_node_add_folder(
4413 GtkCMCTreeNode *node, AddressDataSource *ds,
4414 ItemFolder *itemFolder, AddressObjectType otype )
4416 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4417 GtkCMCTreeNode *newNode = NULL;
4418 AddressTypeControlItem *atci = NULL;
4419 GList *listItems = NULL;
4420 gchar *name;
4421 ItemFolder *rootFolder;
4423 /* Only visible folders */
4424 if( itemFolder == NULL || itemFolder->isHidden )
4425 return NULL;
4427 if( ds == NULL )
4428 return NULL;
4429 if( node == NULL || itemFolder == NULL )
4430 return NULL;
4432 /* Determine object type */
4433 atci = addrbookctl_lookup( otype );
4434 if( atci == NULL )
4435 return NULL;
4437 rootFolder = addrindex_ds_get_root_folder( ds );
4438 if( itemFolder == rootFolder ) {
4439 newNode = node;
4441 else {
4442 AdapterFolder *adapter = g_new0( AdapterFolder, 1 );
4443 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4444 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4445 adapter->itemFolder = itemFolder;
4447 name = ADDRITEM_NAME(itemFolder);
4448 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4449 atci->iconXpm, atci->iconXpm,
4450 atci->treeLeaf, atci->treeExpand );
4451 if( newNode ) {
4452 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4453 addressbook_free_treenode );
4454 } else {
4455 addrbookctl_free_folder(adapter);
4459 listItems = itemFolder->listFolder;
4460 while( listItems ) {
4461 ItemFolder *item = listItems->data;
4462 addressbook_node_add_folder( newNode, ds, item, otype );
4463 listItems = g_list_next( listItems );
4465 listItems = itemFolder->listGroup;
4466 while( listItems ) {
4467 ItemGroup *item = listItems->data;
4468 addressbook_node_add_group( newNode, ds, item );
4469 listItems = g_list_next( listItems );
4471 gtk_sctree_sort_node( ctree, node );
4472 return newNode;
4475 void addressbook_export_to_file( void ) {
4476 if( _addressIndex_ ) {
4477 /* Save all new address book data */
4478 debug_print( "Saving address books...\n" );
4479 addrindex_save_all_books( _addressIndex_ );
4481 debug_print( "Exporting addressbook to file...\n" );
4482 addrindex_save_data( _addressIndex_ );
4483 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4484 addrindex_print_index( _addressIndex_, stdout );
4487 /* Notify address completion of new data */
4488 invalidate_address_completion();
4492 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4494 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4495 addressbook_lup_clicked(NULL, NULL);
4496 return FALSE;
4500 * Comparison using cell contents (text in first column). Used for sort
4501 * address index widget.
4503 static gint addressbook_treenode_compare_func(
4504 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4506 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4507 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4508 gchar *name1 = NULL, *name2 = NULL;
4509 if( cell1 ) name1 = cell1->u.text;
4510 if( cell2 ) name2 = cell2->u.text;
4511 if( ! name1 ) return ( name2 != NULL );
4512 if( ! name2 ) return -1;
4513 return g_utf8_collate( name1, name2 );
4516 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4517 AdapterDSource *ads;
4518 AdapterInterface *adapter;
4519 GtkCMCTreeNode *newNode;
4521 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4522 if( adapter == NULL ) return;
4523 ads = addressbook_edit_book( _addressIndex_, NULL );
4524 if( ads ) {
4525 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4526 if( newNode ) {
4527 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4528 addrbook.treeSelected = newNode;
4533 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4534 AdapterDSource *ads;
4535 AdapterInterface *adapter;
4536 GtkCMCTreeNode *newNode;
4538 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4539 if( adapter == NULL ) return;
4540 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4541 if( ads ) {
4542 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4543 if( newNode ) {
4544 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4545 addrbook.treeSelected = newNode;
4550 #ifdef USE_JPILOT
4551 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4552 AdapterDSource *ads;
4553 AdapterInterface *adapter;
4554 AddressInterface *iface;
4555 GtkCMCTreeNode *newNode;
4557 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4558 if( adapter == NULL ) return;
4559 iface = adapter->interface;
4560 if( ! iface->haveLibrary ) return;
4561 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4562 if( ads ) {
4563 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4564 if( newNode ) {
4565 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4566 addrbook.treeSelected = newNode;
4570 #endif
4572 #ifdef USE_LDAP
4573 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4574 AdapterDSource *ads;
4575 AdapterInterface *adapter;
4576 AddressInterface *iface;
4577 GtkCMCTreeNode *newNode;
4579 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4580 if( adapter == NULL ) return;
4581 iface = adapter->interface;
4582 if( ! iface->haveLibrary ) return;
4583 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4584 if( ads ) {
4585 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4586 if( newNode ) {
4587 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4588 addrbook.treeSelected = newNode;
4592 #endif
4595 * Display address search status message.
4596 * \param queryType Query type.
4597 * \param status Status/Error code.
4599 static void addressbook_search_message( gint queryType, gint sts ) {
4600 gchar *desc = NULL;
4601 *addressbook_msgbuf = '\0';
4603 if( sts != MGU_SUCCESS ) {
4604 if( queryType == ADDRQUERY_LDAP ) {
4605 #ifdef USE_LDAP
4606 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4607 #endif
4610 if( desc ) {
4611 g_snprintf( addressbook_msgbuf,
4612 sizeof(addressbook_msgbuf), "%s", desc );
4613 addressbook_status_show( addressbook_msgbuf );
4615 else {
4616 addressbook_status_show( "" );
4621 * Refresh addressbook by forcing refresh of current selected object in
4622 * tree.
4624 static void addressbook_refresh_current( void ) {
4625 AddressObject *obj;
4626 GtkCMCTree *ctree;
4628 ctree = GTK_CMCTREE(addrbook.ctree);
4629 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4630 if( obj == NULL ) return;
4631 addressbook_set_clist( obj, TRUE );
4635 * Message that is displayed whilst a query is executing in a background
4636 * thread.
4638 static gchar *_tempMessage_ = N_( "Busy searching..." );
4641 * Address search idle function. This function is called during UI idle time
4642 * while a search is in progress.
4644 * \param data Idler data.
4646 static void addressbook_search_idle( gpointer data ) {
4648 gint queryID;
4650 queryID = GPOINTER_TO_INT( data );
4651 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4656 * Search completion callback function. This removes the query from the idle
4657 * list.
4659 * \param sender Sender of query.
4660 * \param queryID Query ID of search request.
4661 * \param status Search status.
4662 * \param data Query data.
4664 static void addressbook_search_callback_end(
4665 gpointer sender, gint queryID, gint status, gpointer data )
4667 gpointer ptrQID;
4668 QueryRequest *req;
4669 AddrQueryObject *aqo;
4671 /* Remove idler function */
4672 ptrQID = GINT_TO_POINTER( queryID );
4673 if( ptrQID ) {
4674 g_idle_remove_by_data( ptrQID );
4677 /* Refresh addressbook contents */
4678 addressbook_refresh_current();
4679 req = qrymgr_find_request( queryID );
4680 if( req != NULL ) {
4681 aqo = ( AddrQueryObject * ) req->queryList->data;
4682 addressbook_search_message( aqo->queryType, status );
4685 /* Stop the search */
4686 addrindex_stop_search( queryID );
4690 * Perform search.
4692 * \param ds Data source to search.
4693 * \param searchTerm String to lookup.
4694 * \param pNode Parent data source node.
4696 static void addressbook_perform_search(
4697 AddressDataSource *ds, gchar *searchTerm,
4698 GtkCMCTreeNode *pNode )
4700 ItemFolder *folder;
4701 gchar *name;
4702 gint queryID;
4703 guint idleID;
4705 /* Setup a query */
4706 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4708 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4710 /* Create a folder for the search results */
4711 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4712 folder = addressbook_setup_subf(ds, name, pNode);
4713 g_free( name );
4715 /* Setup the search */
4716 queryID = addrindex_setup_explicit_search(
4717 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4718 if( queryID == 0 ) return;
4720 /* Set up idler function */
4721 idleID = g_idle_add(
4722 (GSourceFunc) addressbook_search_idle,
4723 GINT_TO_POINTER( queryID ) );
4724 if (idleID == 0) {
4725 g_message("error adding addressbook_search_idle\n");
4728 /* Start search, sit back and wait for something to happen */
4729 addrindex_start_search( queryID );
4731 addressbook_status_show( _tempMessage_ );
4735 * Lookup button handler. Address search is only performed against
4736 * address interfaces for external queries.
4738 * \param button Lookup button widget.
4739 * \param data Data object.
4741 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4742 GtkCMCTree *ctree;
4743 AddressObject *obj;
4744 AddressDataSource *ds;
4745 AddressInterface *iface;
4746 gchar *searchTerm;
4747 GtkCMCTreeNode *node, *parentNode;
4748 #ifdef USE_LDAP
4749 LdapServer *ldap_server;
4750 LdapControl *ldap_ctl;
4751 #endif
4753 node = addrbook.treeSelected;
4754 if( ! node ) return;
4755 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4757 ctree = GTK_CMCTREE(addrbook.ctree);
4758 obj = gtk_cmctree_node_get_row_data( ctree, node );
4759 if( obj == NULL ) return;
4761 if (obj->type != ADDR_DATASOURCE ||
4762 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4763 addressbook_set_clist(
4764 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4765 addrbook.treeSelected),
4766 TRUE);
4769 ds = addressbook_find_datasource( node );
4770 if( ds == NULL ) return;
4772 /* We must have a datasource that is an external interface */
4773 iface = ds->interface;
4774 if( ! iface->haveLibrary ) return;
4775 if( ! iface->externalQuery ) return;
4777 #ifdef USE_LDAP
4778 if (iface->type == ADDR_IF_LDAP) {
4779 ldap_server = ds->rawDataSource;
4780 ldap_ctl = ldap_server->control;
4781 if (ldap_ctl != NULL &&
4782 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4783 #ifndef PASSWORD_CRYPTO_OLD
4784 /* LDAP server is password-protected. */
4785 if (primary_passphrase() == NULL) {
4786 /* User did not enter primary passphrase, do not start a search. */
4787 return;
4789 #endif /* PASSWORD_CRYPTO_OLD */
4792 #endif /* USE_LDAP */
4794 searchTerm =
4795 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4796 g_strchomp( searchTerm );
4798 if( obj->type == ADDR_ITEM_FOLDER ) {
4799 parentNode = GTK_CMCTREE_ROW(node)->parent;
4801 else {
4802 parentNode = node;
4804 addressbook_perform_search( ds, searchTerm, parentNode );
4806 gtk_widget_grab_focus( addrbook.entry );
4808 g_free( searchTerm );
4811 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4812 addressbook_close();
4815 #ifdef USE_LDAP
4817 * Browse address entry for highlighted entry.
4819 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4821 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4822 AddressObject *obj;
4823 AddressDataSource *ds;
4824 AddressInterface *iface;
4825 ItemPerson *person;
4826 ItemEMail *email;
4828 if(addrbook.listSelected == NULL)
4829 return;
4831 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4832 if (obj == NULL)
4833 return;
4835 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4836 if(ds == NULL)
4837 return;
4839 iface = ds->interface;
4840 if(!iface || !iface->haveLibrary )
4841 return;
4843 person = NULL;
4844 if (obj->type == ADDR_ITEM_EMAIL) {
4845 email = ( ItemEMail * ) obj;
4847 person = (ItemPerson *) ADDRITEM_PARENT(email);
4849 else if (obj->type == ADDR_ITEM_PERSON) {
4850 person = (ItemPerson *) obj;
4852 else {
4853 /* None of these */
4854 return;
4857 if( iface && iface->type == ADDR_IF_LDAP ) {
4858 browseldap_entry(ds, person->externalID);
4861 #endif
4863 /* **********************************************************************
4864 * Build lookup tables.
4865 * ***********************************************************************
4869 * Remap object types.
4870 * Enter: abType AddressObjectType (used in tree node).
4871 * Return: ItemObjectType (used in address cache data).
4873 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4874 ItemObjectType ioType;
4876 switch( abType ) {
4877 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4878 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4879 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4880 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4881 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4882 default: ioType = ITEMTYPE_NONE; break;
4884 return ioType;
4887 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4888 atci = addrbookctl_lookup(id); \
4889 if (atci) { \
4890 atci->iconXpm = icon; \
4891 atci->iconXpmOpen = iconopen; \
4892 } else { \
4893 g_warning("can't get atci %d", id); \
4898 * Build table that controls the rendering of object types.
4900 static void addrbookctl_build_icons( GtkWidget *window ) {
4901 AddressTypeControlItem *atci;
4903 /* Build icons */
4904 if (interfacexpm)
4905 g_object_unref(interfacexpm);
4906 if (folderxpm)
4907 g_object_unref(folderxpm);
4908 if (folderopenxpm)
4909 g_object_unref(folderopenxpm);
4910 if (groupxpm)
4911 g_object_unref(groupxpm);
4912 if (vcardxpm)
4913 g_object_unref(vcardxpm);
4914 if (bookxpm)
4915 g_object_unref(bookxpm);
4916 if (addressxpm)
4917 g_object_unref(addressxpm);
4918 if (jpilotxpm)
4919 g_object_unref(jpilotxpm);
4920 if (categoryxpm)
4921 g_object_unref(categoryxpm);
4922 if (ldapxpm)
4923 g_object_unref(ldapxpm);
4924 if (addrsearchxpm)
4925 g_object_unref(addrsearchxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4927 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4934 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4935 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4936 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4938 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4939 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4940 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4941 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4942 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4943 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4944 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4945 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4946 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4947 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4948 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4953 * Build table that controls the rendering of object types.
4955 static void addrbookctl_build_map( GtkWidget *window ) {
4956 AddressTypeControlItem *atci;
4958 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4959 _addressBookTypeList_ = NULL;
4961 /* Interface */
4962 atci = g_new0( AddressTypeControlItem, 1 );
4963 atci->objectType = ADDR_INTERFACE;
4964 atci->interfaceType = ADDR_IF_NONE;
4965 atci->showInTree = TRUE;
4966 atci->treeExpand = TRUE;
4967 atci->treeLeaf = FALSE;
4968 atci->displayName = _( "Interface" );
4969 atci->menuCommand = NULL;
4970 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4971 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4973 /* Address book */
4974 atci = g_new0( AddressTypeControlItem, 1 );
4975 atci->objectType = ADDR_BOOK;
4976 atci->interfaceType = ADDR_IF_BOOK;
4977 atci->showInTree = TRUE;
4978 atci->treeExpand = TRUE;
4979 atci->treeLeaf = FALSE;
4980 atci->displayName = _("Address Books");
4981 atci->menuCommand = "Menu/Book/NewBook";
4982 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4983 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4985 /* Item person */
4986 atci = g_new0( AddressTypeControlItem, 1 );
4987 atci->objectType = ADDR_ITEM_PERSON;
4988 atci->interfaceType = ADDR_IF_NONE;
4989 atci->showInTree = FALSE;
4990 atci->treeExpand = FALSE;
4991 atci->treeLeaf = FALSE;
4992 atci->displayName = _( "Person" );
4993 atci->menuCommand = NULL;
4994 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4995 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4997 /* Item email */
4998 atci = g_new0( AddressTypeControlItem, 1 );
4999 atci->objectType = ADDR_ITEM_EMAIL;
5000 atci->interfaceType = ADDR_IF_NONE;
5001 atci->showInTree = FALSE;
5002 atci->treeExpand = FALSE;
5003 atci->treeLeaf = TRUE;
5004 atci->displayName = _( "Email Address" );
5005 atci->menuCommand = NULL;
5006 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5007 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5009 /* Item group */
5010 atci = g_new0( AddressTypeControlItem, 1 );
5011 atci->objectType = ADDR_ITEM_GROUP;
5012 atci->interfaceType = ADDR_IF_BOOK;
5013 atci->showInTree = TRUE;
5014 atci->treeExpand = FALSE;
5015 atci->treeLeaf = FALSE;
5016 atci->displayName = _( "Group" );
5017 atci->menuCommand = NULL;
5018 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5019 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5021 /* Item folder */
5022 atci = g_new0( AddressTypeControlItem, 1 );
5023 atci->objectType = ADDR_ITEM_FOLDER;
5024 atci->interfaceType = ADDR_IF_BOOK;
5025 atci->showInTree = TRUE;
5026 atci->treeExpand = FALSE;
5027 atci->treeLeaf = FALSE;
5028 atci->displayName = _( "Folder" );
5029 atci->menuCommand = NULL;
5030 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5031 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5033 /* vCard */
5034 atci = g_new0( AddressTypeControlItem, 1 );
5035 atci->objectType = ADDR_VCARD;
5036 atci->interfaceType = ADDR_IF_VCARD;
5037 atci->showInTree = TRUE;
5038 atci->treeExpand = TRUE;
5039 atci->treeLeaf = TRUE;
5040 atci->displayName = _( "vCard" );
5041 atci->menuCommand = "Menu/Book/NewVCard";
5042 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5043 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5045 /* J-Pilot */
5046 atci = g_new0( AddressTypeControlItem, 1 );
5047 atci->objectType = ADDR_JPILOT;
5048 atci->interfaceType = ADDR_IF_JPILOT;
5049 atci->showInTree = TRUE;
5050 atci->treeExpand = TRUE;
5051 atci->treeLeaf = FALSE;
5052 atci->displayName = _( "JPilot" );
5053 atci->menuCommand = "Menu/Book/NewJPilot";
5054 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5055 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5057 /* Category */
5058 atci = g_new0( AddressTypeControlItem, 1 );
5059 atci->objectType = ADDR_CATEGORY;
5060 atci->interfaceType = ADDR_IF_JPILOT;
5061 atci->showInTree = TRUE;
5062 atci->treeExpand = TRUE;
5063 atci->treeLeaf = TRUE;
5064 atci->displayName = _( "JPilot" );
5065 atci->menuCommand = NULL;
5066 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5067 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5069 /* LDAP Server */
5070 atci = g_new0( AddressTypeControlItem, 1 );
5071 atci->objectType = ADDR_LDAP;
5072 atci->interfaceType = ADDR_IF_LDAP;
5073 atci->showInTree = TRUE;
5074 atci->treeExpand = TRUE;
5075 atci->treeLeaf = FALSE;
5076 atci->displayName = _( "LDAP servers" );
5077 atci->menuCommand = "Menu/Book/NewLDAPServer";
5078 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5079 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5081 /* LDAP Query */
5082 atci = g_new0( AddressTypeControlItem, 1 );
5083 atci->objectType = ADDR_LDAP_QUERY;
5084 atci->interfaceType = ADDR_IF_LDAP;
5085 atci->showInTree = TRUE;
5086 atci->treeExpand = FALSE;
5087 atci->treeLeaf = TRUE;
5088 atci->displayName = _( "LDAP Query" );
5089 atci->menuCommand = NULL;
5090 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5091 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5093 addrbookctl_build_icons(window);
5096 void addressbook_reflect_prefs_pixmap_theme(void)
5098 if (addrbook.window)
5099 addrbookctl_build_icons(addrbook.window);
5103 * Search for specified object type.
5105 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5106 gint objType = ot;
5107 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5111 * Search for specified interface type.
5113 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5114 GList *node = _addressBookTypeList_;
5115 while( node ) {
5116 AddressTypeControlItem *atci = node->data;
5117 if( atci->interfaceType == ifType ) return atci;
5118 node = g_list_next( node );
5120 return NULL;
5123 static void addrbookctl_free_address( AddressObject *obj ) {
5124 g_free( obj->name );
5125 obj->type = ADDR_NONE;
5126 obj->name = NULL;
5129 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5130 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5131 adapter->interface = NULL;
5132 adapter->interfaceType = ADDR_IF_NONE;
5133 adapter->atci = NULL;
5134 adapter->enabled = FALSE;
5135 adapter->haveLibrary = FALSE;
5136 adapter->treeNode = NULL;
5137 g_free( adapter );
5140 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5141 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5142 adapter->dataSource = NULL;
5143 adapter->subType = ADDR_NONE;
5144 g_free( adapter );
5147 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5148 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5149 adapter->itemFolder = NULL;
5150 g_free( adapter );
5153 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5154 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5155 adapter->itemGroup = NULL;
5156 g_free( adapter );
5160 * Build GUI interface list.
5162 static void addrbookctl_build_iflist( void ) {
5163 AddressTypeControlItem *atci;
5164 AdapterInterface *adapter;
5165 GList *list = NULL;
5167 if( _addressIndex_ == NULL ) {
5168 _addressIndex_ = addrindex_create_index();
5169 if( _clipBoard_ == NULL ) {
5170 _clipBoard_ = addrclip_create();
5172 addrclip_set_index( _clipBoard_, _addressIndex_ );
5174 _addressInterfaceList_ = NULL;
5175 list = addrindex_get_interface_list( _addressIndex_ );
5176 while( list ) {
5177 AddressInterface *interface = list->data;
5178 atci = addrbookctl_lookup_iface( interface->type );
5179 if( atci ) {
5180 adapter = g_new0( AdapterInterface, 1 );
5181 adapter->interfaceType = interface->type;
5182 adapter->atci = atci;
5183 adapter->interface = interface;
5184 adapter->treeNode = NULL;
5185 adapter->enabled = TRUE;
5186 adapter->haveLibrary = interface->haveLibrary;
5187 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5188 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5189 _addressInterfaceList_ =
5190 g_list_append( _addressInterfaceList_, adapter );
5192 list = g_list_next( list );
5197 * Find GUI interface type specified interface type.
5198 * \param ifType Interface type.
5199 * \return Interface item, or NULL if not found.
5201 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5202 GList *node = _addressInterfaceList_;
5203 while( node ) {
5204 AdapterInterface *adapter = node->data;
5205 if( adapter->interfaceType == ifType ) return adapter;
5206 node = g_list_next( node );
5208 return NULL;
5212 * Build interface list selection.
5214 static void addrbookctl_build_ifselect( void ) {
5215 GList *newList = NULL;
5216 gchar *selectStr;
5217 gchar **splitStr;
5218 gint ifType;
5219 gint i;
5220 gchar *endptr = NULL;
5221 /* gboolean enabled; */
5222 AdapterInterface *adapter;
5224 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5226 /* Parse string */
5227 splitStr = g_strsplit( selectStr, ",", -1 );
5228 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5229 if( splitStr[i] ) {
5230 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5231 ifType = strtol( splitStr[i], &endptr, 10 );
5232 /* enabled = TRUE;
5233 if( *endptr ) {
5234 if( strcmp( endptr, "/n" ) == 0 ) {
5235 enabled = FALSE;
5239 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5240 adapter = addrbookctl_find_interface( ifType );
5241 if( adapter ) {
5242 newList = g_list_append( newList, adapter );
5245 else {
5246 break;
5249 /* g_print( "i=%d\n", i ); */
5250 g_strfreev( splitStr );
5251 g_free( selectStr );
5253 /* Replace existing list */
5254 g_list_free( _addressIFaceSelection_ );
5255 _addressIFaceSelection_ = newList;
5256 newList = NULL;
5259 /* ***********************************************************************
5260 * Add sender to address book.
5261 * ***********************************************************************
5265 * This function is used by the Add sender to address book function.
5267 gboolean addressbook_add_contact(
5268 const gchar *name, const gchar *address, const gchar *remarks,
5269 GdkPixbuf *picture )
5271 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5272 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5273 debug_print( "addressbook_add_contact - added\n" );
5274 addressbook_refresh();
5276 return TRUE;
5279 /* ***********************************************************************
5280 * Book/folder selection.
5281 * ***********************************************************************
5285 * This function is used by the matcher dialog to select a book/folder.
5287 gchar *addressbook_folder_selection( const gchar *folderpath)
5289 AddressBookFile *book = NULL;
5290 ItemFolder *folder = NULL;
5291 gchar *path = NULL;
5293 cm_return_val_if_fail( folderpath != NULL, NULL);
5295 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5296 && book != NULL ) {
5297 if ( folder != NULL) {
5298 gchar *tmp = NULL;
5299 gchar *oldtmp = NULL;
5300 AddrItemObject *obj = NULL;
5302 /* walk thru folder->parent to build the full folder path */
5303 /* TODO: wwp: optimize this */
5304 obj = &folder->obj;
5305 tmp = g_strdup(obj->uid);
5306 while ( obj->parent ) {
5307 obj = obj->parent;
5308 if ( obj->name != NULL ) {
5309 oldtmp = g_strdup(tmp);
5310 g_free(tmp);
5311 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5312 g_free(oldtmp);
5315 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5316 g_free(tmp);
5317 } else {
5318 path = g_strdup_printf("%s", book->fileName);
5320 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5321 return path;
5323 return NULL;
5326 /* ***********************************************************************
5327 * Book/folder checking.
5328 * ***********************************************************************
5331 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5333 FolderInfo *fi = g_new0( FolderInfo, 1 );
5334 fi->book = abf;
5335 fi->folder = folder;
5336 return fi;
5339 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5340 FolderInfo *fiParent, FolderPathMatch *match )
5342 GList *list;
5343 ItemFolder *folder;
5344 gchar *fName;
5345 FolderInfo *fi;
5346 FolderPathMatch *nextmatch = NULL;
5348 if (!parentFolder)
5349 return;
5351 list = parentFolder->listFolder;
5352 while ( list ) {
5353 folder = list->data;
5354 fName = g_strdup( ADDRITEM_NAME(folder) );
5356 /* match folder name, match pointer will be set to NULL if next recursive call
5357 doesn't need to match subfolder name */
5358 if ( match != NULL &&
5359 match->matched == FALSE ) {
5360 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5361 /* folder name matches, prepare next subfolder match */
5362 debug_print("matched folder name '%s'\n", fName);
5363 match->index++;
5364 if ( match->folder_path[match->index] == NULL ) {
5365 /* we've matched all elements */
5366 match->matched = TRUE;
5367 match->folder = folder;
5368 debug_print("book/folder path matched!\n");
5369 } else {
5370 /* keep on matching */
5371 nextmatch = match;
5376 g_free( fName );
5378 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5379 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5380 g_free(fi);
5381 list = g_list_next( list );
5386 * This function is used by to check if a matcher book/folder path corresponds to an
5387 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5388 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5389 if book AND folder are NULL this means that folderpath was empty or Any.
5390 If folderpath is a simple book name (without folder), book will not be NULL and folder
5391 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5394 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5395 AddressDataSource **book,
5396 ItemFolder **folder )
5398 AddressDataSource *ds;
5399 GList *list, *nodeDS;
5400 ItemFolder *rootFolder;
5401 AddressBookFile *abf;
5402 FolderInfo *fi;
5403 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5405 if ( book )
5406 *book = NULL;
5407 if ( folder )
5408 *folder = NULL;
5410 if ( folderpath == NULL )
5411 return FALSE;
5413 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5414 return TRUE;
5416 /* split the folder path we've received, we'll try to match this path, subpath by
5417 subpath against the book/folder structure in order */
5418 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5419 if (!folder_path_match.folder_path)
5420 return FALSE;
5422 list = addrindex_get_interface_list( _addressIndex_ );
5423 while ( list && !folder_path_match.matched ) {
5424 AddressInterface *interface = list->data;
5425 if ( interface && interface->type == ADDR_IF_BOOK ) {
5426 nodeDS = interface->listSource;
5427 while ( nodeDS && !folder_path_match.matched ) {
5428 ds = nodeDS->data;
5430 /* Read address book */
5431 if( ! addrindex_ds_get_read_flag( ds ) ) {
5432 addrindex_ds_read_data( ds );
5435 /* Add node for address book */
5436 abf = ds->rawDataSource;
5438 /* match book name */
5439 if ( abf && abf->fileName &&
5440 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5442 debug_print("matched book name '%s'\n", abf->fileName);
5443 folder_path_match.book = ds;
5445 if ( folder_path_match.folder_path[1] == NULL ) {
5446 /* no folder part to match */
5448 folder_path_match.matched = TRUE;
5449 folder_path_match.folder = NULL;
5450 debug_print("book path matched!\n");
5452 } else {
5453 /* match folder part */
5455 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5456 rootFolder = addrindex_ds_get_root_folder( ds );
5458 /* prepare for recursive call */
5459 folder_path_match.index = 1;
5460 /* this call will set folder_path_match.matched and folder_path_match.folder */
5461 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5462 g_free(fi);
5466 nodeDS = g_list_next( nodeDS );
5469 list = g_list_next( list );
5472 g_strfreev( folder_path_match.folder_path );
5474 if ( book )
5475 *book = folder_path_match.book;
5476 if ( folder )
5477 *folder = folder_path_match.folder;
5478 return folder_path_match.matched;
5482 /* **********************************************************************
5483 * Address Import.
5484 * ***********************************************************************
5488 * Import LDIF file.
5490 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5491 AddressDataSource *ds = NULL;
5492 AdapterDSource *ads = NULL;
5493 AddressBookFile *abf = NULL;
5494 AdapterInterface *adapter;
5495 GtkCMCTreeNode *newNode;
5497 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5498 if( adapter ) {
5499 if( adapter->treeNode ) {
5500 abf = addressbook_imp_ldif( _addressIndex_ );
5501 if( abf ) {
5502 ds = addrindex_index_add_datasource(
5503 _addressIndex_, ADDR_IF_BOOK, abf );
5504 ads = addressbook_create_ds_adapter(
5505 ds, ADDR_BOOK, NULL );
5506 addressbook_ads_set_name(
5507 ads, addrbook_get_name( abf ) );
5508 newNode = addressbook_add_object(
5509 adapter->treeNode,
5510 ADDRESS_OBJECT(ads) );
5511 if( newNode ) {
5512 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5513 newNode );
5514 addrbook.treeSelected = newNode;
5517 /* Notify address completion */
5518 invalidate_address_completion();
5525 * Import MUTT file.
5527 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5528 AddressDataSource *ds = NULL;
5529 AdapterDSource *ads = NULL;
5530 AddressBookFile *abf = NULL;
5531 AdapterInterface *adapter;
5532 GtkCMCTreeNode *newNode;
5534 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5535 if( adapter ) {
5536 if( adapter->treeNode ) {
5537 abf = addressbook_imp_mutt( _addressIndex_ );
5538 if( abf ) {
5539 ds = addrindex_index_add_datasource(
5540 _addressIndex_, ADDR_IF_BOOK, abf );
5541 ads = addressbook_create_ds_adapter(
5542 ds, ADDR_BOOK, NULL );
5543 addressbook_ads_set_name(
5544 ads, addrbook_get_name( abf ) );
5545 newNode = addressbook_add_object(
5546 adapter->treeNode,
5547 ADDRESS_OBJECT(ads) );
5548 if( newNode ) {
5549 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5550 newNode );
5551 addrbook.treeSelected = newNode;
5554 /* Notify address completion */
5555 invalidate_address_completion();
5562 * Import Pine file.
5564 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5565 AddressDataSource *ds = NULL;
5566 AdapterDSource *ads = NULL;
5567 AddressBookFile *abf = NULL;
5568 AdapterInterface *adapter;
5569 GtkCMCTreeNode *newNode;
5571 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5572 if( adapter ) {
5573 if( adapter->treeNode ) {
5574 abf = addressbook_imp_pine( _addressIndex_ );
5575 if( abf ) {
5576 ds = addrindex_index_add_datasource(
5577 _addressIndex_, ADDR_IF_BOOK, abf );
5578 ads = addressbook_create_ds_adapter(
5579 ds, ADDR_BOOK, NULL );
5580 addressbook_ads_set_name(
5581 ads, addrbook_get_name( abf ) );
5582 newNode = addressbook_add_object(
5583 adapter->treeNode,
5584 ADDRESS_OBJECT(ads) );
5585 if( newNode ) {
5586 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5587 newNode );
5588 addrbook.treeSelected = newNode;
5591 /* Notify address completion */
5592 invalidate_address_completion();
5599 * Harvest addresses.
5600 * \param folderItem Folder to import.
5601 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5602 * \param msgList List of message numbers, or NULL to process folder.
5604 void addressbook_harvest(
5605 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5607 AddressDataSource *ds = NULL;
5608 AdapterDSource *ads = NULL;
5609 AddressBookFile *abf = NULL;
5610 AdapterInterface *adapter;
5611 GtkCMCTreeNode *newNode;
5613 abf = addrgather_dlg_execute(
5614 folderItem, _addressIndex_, sourceInd, msgList );
5615 if( abf ) {
5616 ds = addrindex_index_add_datasource(
5617 _addressIndex_, ADDR_IF_BOOK, abf );
5619 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5620 if( adapter ) {
5621 if( adapter->treeNode ) {
5622 ads = addressbook_create_ds_adapter(
5623 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5624 newNode = addressbook_add_object(
5625 adapter->treeNode,
5626 ADDRESS_OBJECT(ads) );
5627 if (newNode == NULL) {
5628 g_message("error adding addressbook object\n");
5633 /* Notify address completion */
5634 invalidate_address_completion();
5639 * Export HTML file.
5641 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5642 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5643 AddressObject *obj;
5644 AddressDataSource *ds = NULL;
5645 AddrBookBase *adbase;
5646 AddressCache *cache;
5647 GtkCMCTreeNode *node = NULL;
5649 if( ! addrbook.treeSelected ) return;
5650 node = addrbook.treeSelected;
5651 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5652 obj = gtk_cmctree_node_get_row_data( ctree, node );
5653 if( obj == NULL ) return;
5655 ds = addressbook_find_datasource( node );
5656 if( ds == NULL ) return;
5657 adbase = ( AddrBookBase * ) ds->rawDataSource;
5658 cache = adbase->addressCache;
5659 addressbook_exp_html( cache );
5663 * Export LDIF file.
5665 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5666 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5667 AddressObject *obj;
5668 AddressDataSource *ds = NULL;
5669 AddrBookBase *adbase;
5670 AddressCache *cache;
5671 GtkCMCTreeNode *node = NULL;
5673 if( ! addrbook.treeSelected ) return;
5674 node = addrbook.treeSelected;
5675 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5676 obj = gtk_cmctree_node_get_row_data( ctree, node );
5677 if( obj == NULL ) return;
5679 ds = addressbook_find_datasource( node );
5680 if( ds == NULL ) return;
5681 adbase = ( AddrBookBase * ) ds->rawDataSource;
5682 cache = adbase->addressCache;
5683 addressbook_exp_ldif( cache );
5686 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5688 addrduplicates_find(GTK_WINDOW(addrbook.window));
5691 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5693 addressbook_custom_attr_edit();
5696 static void addressbook_start_drag(GtkWidget *widget, gint button,
5697 GdkEvent *event,
5698 void *data)
5700 GdkDragContext *context;
5701 if (addressbook_target_list == NULL)
5702 addressbook_target_list = gtk_target_list_new(
5703 addressbook_drag_types, 1);
5704 context = gtk_drag_begin_with_coordinates(widget, addressbook_target_list,
5705 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event,
5706 -1, -1);
5707 gtk_drag_set_icon_default(context);
5710 static void addressbook_drag_data_get(GtkWidget *widget,
5711 GdkDragContext *drag_context,
5712 GtkSelectionData *selection_data,
5713 guint info,
5714 guint time,
5715 void *data)
5717 AddrItemObject *aio = NULL;
5718 AddressObject *pobj = NULL;
5719 AdapterDSource *ads = NULL;
5720 AddressDataSource *ds = NULL;
5721 GList *cur;
5723 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5725 if( pobj == NULL ) return;
5727 if( pobj->type == ADDR_DATASOURCE ) {
5728 ads = ADAPTER_DSOURCE(pobj);
5729 ds = ads->dataSource;
5730 } else if (pobj->type == ADDR_ITEM_GROUP) {
5732 return;
5735 else if( pobj->type != ADDR_INTERFACE ) {
5736 ds = addressbook_find_datasource( addrbook.treeSelected );
5738 if (!ds)
5739 return;
5742 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5743 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5744 GTK_CMCTREE_NODE(cur->data));
5745 while (aio && aio->type != ITEMTYPE_PERSON) {
5746 aio = aio->parent;
5750 if (aio && aio->type == ITEMTYPE_PERSON) {
5751 if( ds && ds->interface && ds->interface->readOnly)
5752 gtk_selection_data_set(selection_data,
5753 gtk_selection_data_get_target(selection_data), 8,
5754 (const guchar *)"Dummy_addr_copy", 15);
5755 else
5756 gtk_selection_data_set(selection_data,
5757 gtk_selection_data_get_target(selection_data), 8,
5758 (const guchar *)"Dummy_addr_move", 15);
5762 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5763 GdkDragContext *context,
5764 gint x,
5765 gint y,
5766 guint time,
5767 void *data)
5769 GtkAllocation allocation;
5770 GtkRequisition requisition;
5771 gint row, column;
5772 GtkCMCTreeNode *node = NULL;
5773 gboolean acceptable = FALSE;
5774 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5775 gint height = allocation.height;
5776 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5777 gint total_height = requisition.height;
5778 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5779 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5780 gfloat vpos = gtk_adjustment_get_value(pos);
5782 if (gtk_cmclist_get_selection_info
5783 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5785 if (y > height - 24 && height + vpos < total_height) {
5786 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5788 if (y < 24 && y > 0) {
5789 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5791 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5793 if (node != NULL) {
5794 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5795 if (obj == NULL)
5796 return FALSE;
5797 if( obj->type == ADDR_ITEM_FOLDER
5798 || obj->type == ADDR_ITEM_GROUP)
5799 acceptable = TRUE;
5800 else {
5801 AdapterDSource *ads = NULL;
5802 AddressDataSource *ds = NULL;
5803 ads = ADAPTER_DSOURCE(obj);
5804 ds = ads->dataSource;
5805 if (ds == NULL ) { return FALSE;}
5807 acceptable = TRUE;
5812 if (acceptable) {
5813 g_signal_handlers_block_by_func
5814 (G_OBJECT(widget),
5815 G_CALLBACK(addressbook_tree_selected), NULL);
5816 gtk_sctree_select( GTK_SCTREE(widget), node);
5817 g_signal_handlers_unblock_by_func
5818 (G_OBJECT(widget),
5819 G_CALLBACK(addressbook_tree_selected), NULL);
5820 gdk_drag_status(context,
5821 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5822 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5823 } else {
5824 gdk_drag_status(context, 0, time);
5826 return acceptable;
5829 static void addressbook_drag_leave_cb(GtkWidget *widget,
5830 GdkDragContext *context,
5831 guint time,
5832 void *data)
5834 if (addrbook.treeSelected) {
5835 g_signal_handlers_block_by_func
5836 (G_OBJECT(widget),
5837 G_CALLBACK(addressbook_tree_selected), NULL);
5838 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5839 g_signal_handlers_unblock_by_func
5840 (G_OBJECT(widget),
5841 G_CALLBACK(addressbook_tree_selected), NULL);
5846 static void addressbook_drag_received_cb(GtkWidget *widget,
5847 GdkDragContext *drag_context,
5848 gint x,
5849 gint y,
5850 GtkSelectionData *data,
5851 guint info,
5852 guint time,
5853 void *pdata)
5855 gint row, column;
5856 GtkCMCTreeNode *node;
5857 GtkCMCTreeNode *lastopened = addrbook.opened;
5859 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5860 if (gtk_cmclist_get_selection_info
5861 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5862 return;
5865 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5866 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5867 return;
5869 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5870 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5871 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5872 addressbook_clip_copy_cb(NULL, NULL);
5873 else
5874 addressbook_clip_cut_cb(NULL, NULL);
5875 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5876 addressbook_clip_paste_cb(NULL,NULL);
5877 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5878 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5879 gtk_drag_finish(drag_context, TRUE, TRUE, time);
5884 * End of Source.