Improve some sieve-related translations
[claws.git] / src / addressbook.c
bloba1e0bbc986f8ee137259ef5030ff8a1007640e44
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #include "claws-features.h"
23 #endif
25 #include "defs.h"
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <gtk/gtk.h>
31 #include <string.h>
32 #include <setjmp.h>
33 #include <sys/types.h>
34 #include <dirent.h>
36 #include "main.h"
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
42 #include "menu.h"
43 #include "stock_pixmap.h"
44 #include "xml.h"
45 #include "prefs_gtk.h"
46 #include "procmime.h"
47 #include "file-utils.h"
48 #include "utils.h"
49 #include "gtkutils.h"
50 #include "codeconv.h"
51 #include "about.h"
52 #include "addr_compl.h"
53 #include "password.h"
55 #include "mgutils.h"
56 #include "addressitem.h"
57 #include "addritem.h"
58 #include "addrcache.h"
59 #include "addrbook.h"
60 #include "addrindex.h"
61 #include "addrmerge.h"
62 #include "addressadd.h"
63 #include "addrduplicates.h"
64 #include "addressbook_foldersel.h"
65 #include "vcard.h"
66 #include "editvcard.h"
67 #include "editgroup.h"
68 #include "editaddress.h"
69 #include "editbook.h"
70 #include "importldif.h"
71 #include "importmutt.h"
72 #include "importpine.h"
73 #include "manual.h"
75 #ifdef USE_JPILOT
76 #include "jpilot.h"
77 #include "editjpilot.h"
78 #endif
80 #ifdef USE_LDAP
81 #include <pthread.h>
82 #include "ldapserver.h"
83 #include "editldap.h"
84 #include "ldapupdate.h"
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
87 #endif
89 #include "addrquery.h"
90 #include "addrselect.h"
91 #include "addrclip.h"
92 #include "addrgather.h"
93 #include "adbookbase.h"
94 #include "exphtmldlg.h"
95 #include "expldifdlg.h"
96 #include "browseldap.h"
97 #include "addrcustomattr.h"
98 #ifdef G_OS_WIN32
99 #undef interface
100 #endif
101 typedef enum
103 COL_SOURCES = 0,
104 N_INDEX_COLS = 1
105 } AddressIndexColumns;
107 typedef enum
109 COL_NAME = 0,
110 COL_ADDRESS = 1,
111 COL_REMARKS = 2,
112 N_LIST_COLS = 3
113 } AddressListColumns;
115 typedef struct {
116 AddressBookFile *book;
117 ItemFolder *folder;
118 } FolderInfo;
120 typedef struct {
121 gchar **folder_path;
122 gboolean matched;
123 gint index;
124 AddressDataSource *book;
125 ItemFolder *folder;
126 } FolderPathMatch;
128 static gchar *list_titles[] = { N_("Name"),
129 N_("Email Address"),
130 N_("Remarks") };
132 #define COL_NAME_WIDTH 164
133 #define COL_ADDRESS_WIDTH 156
135 #define COL_FOLDER_WIDTH 170
136 #define ADDRESSBOOK_WIDTH 640
137 #define ADDRESSBOOK_HEIGHT 360
139 #define ADDRESSBOOK_MSGBUF_SIZE 2048
141 static GdkPixbuf *folderxpm = NULL;
142 static GdkPixbuf *folderopenxpm = NULL;
143 static GdkPixbuf *groupxpm = NULL;
144 static GdkPixbuf *interfacexpm = NULL;
145 static GdkPixbuf *bookxpm = NULL;
146 static GdkPixbuf *addressxpm = NULL;
147 static GdkPixbuf *vcardxpm = NULL;
148 static GdkPixbuf *jpilotxpm = NULL;
149 static GdkPixbuf *categoryxpm = NULL;
150 static GdkPixbuf *ldapxpm = NULL;
151 static GdkPixbuf *addrsearchxpm = NULL;
153 /* Message buffer */
154 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
156 /* Address list selection */
157 static AddrSelectList *_addressSelect_ = NULL;
158 static AddressClipboard *_clipBoard_ = NULL;
160 /* Address index file and interfaces */
161 static AddressIndex *_addressIndex_ = NULL;
162 static GList *_addressInterfaceList_ = NULL;
163 static GList *_addressIFaceSelection_ = NULL;
164 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
166 static AddressBook_win addrbook;
168 static GHashTable *_addressBookTypeHash_ = NULL;
169 static GList *_addressBookTypeList_ = NULL;
171 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
172 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
173 static void addressbook_edit_address_post_cb( ItemPerson *person );
175 static void addressbook_create (void);
176 static gint addressbook_close (void);
178 static gboolean address_index_has_focus = FALSE;
179 static gboolean address_list_has_focus = FALSE;
181 /* callback functions */
182 static void addressbook_del_clicked (GtkButton *button,
183 gpointer data);
184 static void addressbook_reg_clicked (GtkButton *button,
185 gpointer data);
186 static void addressbook_to_clicked (GtkButton *button,
187 gpointer data);
188 static void addressbook_lup_clicked (GtkButton *button,
189 gpointer data);
190 static void addressbook_close_clicked (GtkButton *button,
191 gpointer data);
193 static void addressbook_tree_selected (GtkCMCTree *ctree,
194 GtkCMCTreeNode *node,
195 gint column,
196 gpointer data);
197 static void addressbook_select_row_tree (GtkCMCTree *ctree,
198 GtkCMCTreeNode *node,
199 gint column,
200 gpointer data);
201 static void addressbook_list_row_selected (GtkCMCTree *clist,
202 GtkCMCTreeNode *node,
203 gint column,
204 gpointer data);
205 static void addressbook_list_row_unselected (GtkCMCTree *clist,
206 GtkCMCTreeNode *node,
207 gint column,
208 gpointer data);
209 static void addressbook_person_expand_node (GtkCMCTree *ctree,
210 GList *node,
211 gpointer *data );
212 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
213 GList *node,
214 gpointer *data );
216 static void addressbook_entry_activated (GtkWidget *widget,
217 gpointer data);
219 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
220 GdkEventButton *event,
221 gpointer data);
222 static gboolean addressbook_list_button_released(GtkWidget *widget,
223 GdkEventButton *event,
224 gpointer data);
225 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
226 GdkEventButton *event,
227 gpointer data);
228 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
229 GdkEventButton *event,
230 gpointer data);
232 static void addressbook_new_folder_cb (GtkAction *action,
233 gpointer data);
234 static void addressbook_new_group_cb (GtkAction *action,
235 gpointer data);
236 static void addressbook_treenode_edit_cb (GtkAction *action,
237 gpointer data);
238 static void addressbook_treenode_delete_cb (GtkAction *action,
239 gpointer data);
241 static void addressbook_change_node_name (GtkCMCTreeNode *node,
242 const gchar *name);
244 static void addressbook_new_address_cb (GtkAction *action,
245 gpointer data);
246 static void addressbook_edit_address_cb (GtkAction *action,
247 gpointer data);
248 static void addressbook_delete_address_cb (GtkAction *action,
249 gpointer data);
251 static void close_cb (GtkAction *action,
252 gpointer data);
253 static void addressbook_file_save_cb (GtkAction *action,
254 gpointer data);
256 /* Data source edit stuff */
257 static void addressbook_new_book_cb (GtkAction *action,
258 gpointer data);
259 static void addressbook_new_vcard_cb (GtkAction *action,
260 gpointer data);
262 #ifdef USE_JPILOT
263 static void addressbook_new_jpilot_cb (GtkAction *action,
264 gpointer data);
265 #endif
267 #ifdef USE_LDAP
268 static void addressbook_new_ldap_cb (GtkAction *action,
269 gpointer data);
270 #endif
272 static void addressbook_set_clist (AddressObject *obj,
273 gboolean refresh);
275 static void addressbook_load_tree (void);
276 void addressbook_read_file (void);
278 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
279 AddressObject *obj);
280 static void addressbook_treenode_remove_item ( void );
282 static AddressDataSource *addressbook_find_datasource
283 (GtkCMCTreeNode *node );
285 static AddressBookFile *addressbook_get_book_file(void);
287 static GtkCMCTreeNode *addressbook_node_add_folder
288 (GtkCMCTreeNode *node,
289 AddressDataSource *ds,
290 ItemFolder *itemFolder,
291 AddressObjectType otype);
292 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
293 AddressDataSource *ds,
294 ItemGroup *itemGroup);
295 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
296 GtkCMCTreeNode *parent);
297 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
298 GtkCMCTreeNode *node);
299 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
300 ItemGroup *group);
301 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
302 GdkEventKey *event,
303 gpointer data);
304 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
305 gconstpointer ptr1,
306 gconstpointer ptr2);
307 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
308 ItemPerson *person,
309 AddressTypeControlItem *atci,
310 AddressTypeControlItem *atciMail);
311 static void addressbook_folder_remove_node (GtkCMCTree *clist,
312 GtkCMCTreeNode *node);
314 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
315 gboolean force_focus );
317 /* LUT's and IF stuff */
318 static void addressbook_free_treenode ( gpointer data );
319 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
320 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
322 static void addrbookctl_build_map (GtkWidget *window);
323 static void addrbookctl_build_iflist (void);
324 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
325 static void addrbookctl_build_ifselect (void);
327 static void addrbookctl_free_interface (AdapterInterface *adapter);
328 static void addrbookctl_free_datasource (AdapterDSource *adapter);
329 static void addrbookctl_free_folder (AdapterFolder *adapter);
330 static void addrbookctl_free_group (AdapterGroup *adapter);
332 static void addressbook_list_select_clear ( void );
333 static void addressbook_list_select_add ( AddrItemObject *aio,
334 AddressDataSource *ds );
335 static void addressbook_list_select_remove ( AddrItemObject *aio );
337 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
338 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
339 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
340 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
342 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
344 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
352 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
353 static void addressbook_merge_cb ( GtkAction *action, gpointer data );
355 #ifdef USE_LDAP
356 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
357 #endif
358 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
360 static void addressbook_start_drag(GtkWidget *widget, gint button,
361 GdkEvent *event,
362 void *data);
363 static void addressbook_drag_data_get(GtkWidget *widget,
364 GdkDragContext *drag_context,
365 GtkSelectionData *selection_data,
366 guint info,
367 guint time,
368 void *data);
369 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
370 GdkDragContext *context,
371 gint x,
372 gint y,
373 guint time,
374 void *data);
375 static void addressbook_drag_leave_cb(GtkWidget *widget,
376 GdkDragContext *context,
377 guint time,
378 void *data);
379 static void addressbook_drag_received_cb(GtkWidget *widget,
380 GdkDragContext *drag_context,
381 gint x,
382 gint y,
383 GtkSelectionData *data,
384 guint info,
385 guint time,
386 void *pdata);
387 static void addressbook_list_menu_setup( void );
389 static GtkTargetEntry addressbook_drag_types[] =
391 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
394 static GtkTargetList *addressbook_target_list = NULL;
396 static GtkActionEntry addressbook_entries[] =
398 {"Menu", NULL, "Menu", NULL, NULL, NULL },
399 /* menus */
400 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
401 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
402 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
404 /* Book menu */
405 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
406 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
407 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
410 #ifdef USE_JPILOT
411 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
412 #endif
413 #ifdef USE_LDAP
414 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
415 #endif
416 {"Book/---", NULL, "---", NULL, NULL, NULL },
418 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
419 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
420 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
421 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
422 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
424 /* Adress menu */
425 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
426 {"Address/---", NULL, "---", NULL, NULL, NULL },
427 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
428 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
429 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
430 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
431 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
432 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
433 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
434 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
435 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
438 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
441 /* Tools menu */
442 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
443 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
444 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
445 {"Tools/---", NULL, "---", NULL, NULL, NULL },
446 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
447 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
448 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
449 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
450 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
453 static GtkActionEntry addressbook_tree_popup_entries[] =
455 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
456 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
457 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
458 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
459 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
460 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
461 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
462 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
463 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
464 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
465 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
468 static GtkActionEntry addressbook_list_popup_entries[] =
470 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
471 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
472 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
473 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
474 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
475 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
476 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
477 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
478 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
479 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
480 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
481 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
482 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
483 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
484 #ifdef USE_LDAP
485 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
486 #endif
487 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
491 * Structure of error message table.
493 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
494 struct _ErrMsgTableEntry {
495 gint code;
496 gchar *description;
499 static gchar *_errMsgUnknown_ = N_( "Unknown" );
502 * Lookup table of error messages for general errors. Note that a NULL
503 * description signifies the end of the table.
505 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
506 { MGU_SUCCESS, N_("Success") },
507 { MGU_BAD_ARGS, N_("Bad arguments") },
508 { MGU_NO_FILE, N_("File not specified") },
509 { MGU_OPEN_FILE, N_("Error opening file") },
510 { MGU_ERROR_READ, N_("Error reading file") },
511 { MGU_EOF, N_("End of file encountered") },
512 { MGU_OO_MEMORY, N_("Error allocating memory") },
513 { MGU_BAD_FORMAT, N_("Bad file format") },
514 { MGU_ERROR_WRITE, N_("Error writing to file") },
515 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
516 { MGU_NO_PATH, N_("No path specified") },
517 { 0, NULL }
520 #ifdef USE_LDAP
522 * Lookup table of error messages for LDAP errors.
524 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
525 { LDAPRC_SUCCESS, N_("Success") },
526 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
527 { LDAPRC_INIT, N_("Error initializing LDAP") },
528 { LDAPRC_BIND, N_("Error binding to LDAP server") },
529 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
530 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
531 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
532 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
533 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
534 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
535 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
536 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
537 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
538 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
539 { 0, NULL }
541 #endif
544 * Lookup message for specified error code.
545 * \param lut Lookup table.
546 * \param code Code to lookup.
547 * \return Description associated to code.
549 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
550 gchar *desc = NULL;
551 ErrMsgTableEntry entry;
552 gint i;
554 for( i = 0; ; i++ ) {
555 entry = lut[ i ];
556 if( entry.description == NULL ) break;
557 if( entry.code == code ) {
558 desc = entry.description;
559 break;
562 if( ! desc ) {
563 desc = _errMsgUnknown_;
565 return desc;
568 static gboolean lastCanLookup = FALSE;
570 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
572 if (add_and_delete) {
573 gtk_widget_show(addrbook.edit_btn);
574 gtk_widget_show(addrbook.del_btn);
575 gtk_widget_show(addrbook.reg_btn);
576 } else {
577 gtk_widget_hide(addrbook.edit_btn);
578 gtk_widget_hide(addrbook.del_btn);
579 gtk_widget_hide(addrbook.reg_btn);
582 if (lookup) {
583 gtk_widget_show(addrbook.lup_btn);
584 gtk_widget_show(addrbook.entry);
585 gtk_widget_show(addrbook.label);
586 } else {
587 gtk_widget_hide(addrbook.lup_btn);
588 gtk_widget_hide(addrbook.entry);
589 gtk_widget_hide(addrbook.label);
592 lastCanLookup = lookup;
594 if (mail_ops) {
595 gtk_widget_show(addrbook.to_btn);
596 gtk_widget_show(addrbook.cc_btn);
597 gtk_widget_show(addrbook.bcc_btn);
598 } else {
599 gtk_widget_hide(addrbook.to_btn);
600 gtk_widget_hide(addrbook.cc_btn);
601 gtk_widget_hide(addrbook.bcc_btn);
605 void addressbook_open(Compose *target)
607 /* Initialize all static members */
608 if( _clipBoard_ == NULL ) {
609 _clipBoard_ = addrclip_create();
611 if( _addressIndex_ != NULL ) {
612 addrclip_set_index( _clipBoard_, _addressIndex_ );
614 if( _addressSelect_ == NULL ) {
615 _addressSelect_ = addrselect_list_create();
617 if (!addrbook.window) {
618 addressbook_read_file();
619 addressbook_create();
620 addressbook_load_tree();
621 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
622 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
624 else {
625 gtk_widget_hide(addrbook.window);
628 gtk_widget_show_all(addrbook.window);
630 if (!prefs_common.addressbook_use_editaddress_dialog)
631 addressbook_edit_person_widgetset_hide();
633 address_completion_start(addrbook.window);
635 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
636 addressbook_set_target_compose(target);
640 * Destroy addressbook.
642 void addressbook_destroy( void ) {
643 /* Free up address stuff */
644 if( _addressSelect_ != NULL ) {
645 addrselect_list_free( _addressSelect_ );
647 if( _clipBoard_ != NULL ) {
648 addrclip_free( _clipBoard_ );
649 _clipBoard_ = NULL;
651 if( _addressIndex_ != NULL ) {
652 addrindex_free_index( _addressIndex_ );
653 addrindex_teardown();
655 _addressSelect_ = NULL;
656 _clipBoard_ = NULL;
657 _addressIndex_ = NULL;
660 void addressbook_set_target_compose(Compose *target)
662 addrbook.target_compose = target;
665 Compose *addressbook_get_target_compose(void)
667 return addrbook.target_compose;
671 * Refresh addressbook and save to file(s).
673 void addressbook_refresh( void )
675 if (addrbook.window) {
676 if (addrbook.treeSelected) {
677 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
678 addrbook.treeSelected);
679 addressbook_set_clist(
680 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
681 addrbook.treeSelected),
682 TRUE);
686 addressbook_export_to_file();
689 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
691 if (event && event->keyval == GDK_KEY_Escape)
692 addressbook_close();
693 else if (event && event->keyval == GDK_KEY_Delete) {
694 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
695 if ( /* address_index_has_focus || */ address_list_has_focus )
696 addressbook_del_clicked(NULL, NULL);
698 return FALSE;
702 *\brief Save Gtk object size to prefs dataset
704 static void addressbook_size_allocate_cb(GtkWidget *widget,
705 GtkAllocation *allocation)
707 cm_return_if_fail(allocation != NULL);
709 gtk_window_get_size(GTK_WINDOW(widget),
710 &prefs_common.addressbookwin_width, &prefs_common.addressbookwin_height);
713 static gint sort_column_number = 0;
714 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
716 static gint list_case_sort(
717 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
719 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
720 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
721 gchar *name1 = NULL, *name2 = NULL;
722 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
723 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
725 if( aio1->type == aio2->type ) {
726 if( row1 )
727 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
728 if( row2 )
729 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
730 if( ! name1 ) return ( name2 != NULL );
731 if( ! name2 ) return -1;
732 return g_utf8_collate( name1, name2 );
733 } else {
734 /* Order groups before person */
735 if( aio1->type == ITEMTYPE_GROUP ) {
736 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
737 } else if( aio2->type == ITEMTYPE_GROUP ) {
738 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
740 return 0;
744 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
745 const GtkSortType sort_type)
747 gint pos;
748 GtkWidget *hbox, *label, *arrow;
750 sort_column_number = col;
751 sort_column_type = sort_type;
752 gtk_cmclist_set_compare_func(clist, list_case_sort);
753 gtk_cmclist_set_sort_type(clist, sort_type);
754 gtk_cmclist_set_sort_column(clist, col);
756 gtk_cmclist_freeze(clist);
757 gtk_cmclist_sort(clist);
759 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
760 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
761 label = gtk_label_new(gettext(list_titles[pos]));
762 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
764 if(pos == col) {
765 arrow = gtk_image_new_from_icon_name(sort_type == GTK_SORT_ASCENDING ?
766 "pan-down-symbolic" : "pan-up-symbolic", GTK_ICON_SIZE_MENU);
767 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
770 gtk_widget_show_all(hbox);
771 gtk_cmclist_set_column_widget(clist, pos, hbox);
774 gtk_cmclist_thaw(clist);
777 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
779 static GtkSortType sort_type = GTK_SORT_ASCENDING;
781 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
782 GTK_SORT_ASCENDING;
783 addressbook_sort_list(clist, COL_NAME, sort_type);
786 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
788 static GtkSortType sort_type = GTK_SORT_ASCENDING;
790 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
791 GTK_SORT_ASCENDING;
792 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
795 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
797 static GtkSortType sort_type = GTK_SORT_ASCENDING;
799 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
800 GTK_SORT_ASCENDING;
801 addressbook_sort_list(clist, COL_REMARKS, sort_type);
804 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
805 gpointer data)
807 address_index_has_focus = TRUE;
808 return FALSE;
811 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
812 gpointer data)
814 address_index_has_focus = FALSE;
815 if (!prefs_common.addressbook_use_editaddress_dialog
816 && !address_list_has_focus)
817 addressbook_address_list_disable_some_actions();
818 return FALSE;
821 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
822 gpointer data)
824 address_list_has_focus = TRUE;
825 return FALSE;
828 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
829 gpointer data)
831 address_list_has_focus = FALSE;
832 if (!prefs_common.addressbook_use_editaddress_dialog
833 && !address_index_has_focus)
834 addressbook_address_list_disable_some_actions();
835 return FALSE;
838 /* save hpane and vpane's handle position when it moves */
839 static void addressbook_pane_save_position(void)
841 if (addrbook.hpaned)
842 prefs_common.addressbook_hpaned_pos =
843 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
844 if (addrbook.vpaned)
845 prefs_common.addressbook_vpaned_pos =
846 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
850 * Create the address book widgets. The address book contains two CTree widgets: the
851 * address index tree on the left and the address list on the right.
853 * The address index tree displays a hierarchy of interfaces and groups. Each node in
854 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
855 * data sources and folder objects.
857 * The address list displays group, person and email objects. These items are linked
858 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
859 * sources.
861 * In the tradition of MVC architecture, the data stores have been separated from the
862 * GUI components. The addrindex.c file provides the interface to all data stores.
864 static void addressbook_create(void)
866 GtkWidget *window;
867 GtkWidget *vbox;
868 GtkWidget *menubar;
869 GtkWidget *vbox2;
870 GtkWidget *ctree_swin;
871 GtkWidget *ctree;
872 GtkWidget *editaddress_vbox;
873 GtkWidget *clist_vbox;
874 GtkWidget *clist_swin;
875 GtkWidget *clist;
876 GtkWidget *hpaned;
877 GtkWidget *vpaned;
878 GtkWidget *hbox;
879 GtkWidget *label;
880 GtkWidget *entry;
881 GtkWidget *statusbar;
882 GtkWidget *hbbox;
883 GtkWidget *hsbox;
884 GtkWidget *help_btn;
885 GtkWidget *del_btn;
886 GtkWidget *edit_btn;
887 GtkWidget *reg_btn;
888 GtkWidget *lup_btn;
889 GtkWidget *to_btn;
890 GtkWidget *cc_btn;
891 GtkWidget *bcc_btn;
892 GtkWidget *close_btn;
893 GtkWidget *tree_popup;
894 GtkWidget *list_popup;
895 GList *nodeIf;
896 GtkUIManager *ui_manager;
897 GtkActionGroup *action_group;
898 gchar *index_titles[N_INDEX_COLS];
899 gchar *text;
900 gint i;
902 static GdkGeometry geometry;
904 debug_print("Creating addressbook window...\n");
906 index_titles[COL_SOURCES] = _("Sources");
908 /* Address book window */
909 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
910 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
911 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
912 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
913 gtk_widget_realize(window);
915 g_signal_connect(G_OBJECT(window), "delete_event",
916 G_CALLBACK(addressbook_close), NULL);
917 g_signal_connect(G_OBJECT(window), "size_allocate",
918 G_CALLBACK(addressbook_size_allocate_cb), NULL);
919 g_signal_connect(G_OBJECT(window), "key_press_event",
920 G_CALLBACK(key_pressed), NULL);
921 MANAGE_WINDOW_SIGNALS_CONNECT(window);
923 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
924 gtk_container_add(GTK_CONTAINER(window), vbox);
926 /* Menu bar */
927 ui_manager = gtk_ui_manager_new();
928 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
929 G_N_ELEMENTS(addressbook_entries), NULL);
930 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
931 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
932 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
933 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
935 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
937 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
938 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
939 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
941 /* Book menu */
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
945 #ifdef USE_JPILOT
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
947 #endif
948 #ifdef USE_LDAP
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
950 #endif
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
958 /* Address menu */
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
974 /* Tools menu */
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
985 gtk_window_add_accel_group(GTK_WINDOW(window),
986 gtk_ui_manager_get_accel_group(ui_manager));
988 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
990 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
992 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, BORDER_WIDTH);
993 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
994 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
996 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
997 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
998 GTK_POLICY_AUTOMATIC,
999 GTK_POLICY_AUTOMATIC);
1001 /* Address index */
1002 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1003 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1005 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1006 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1007 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1008 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1009 GTK_CMCTREE_EXPANDER_TRIANGLE);
1010 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1011 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1012 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1013 addressbook_treenode_compare_func);
1015 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1016 G_CALLBACK(addressbook_tree_selected), NULL);
1017 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1018 G_CALLBACK(addressbook_tree_button_pressed),
1019 NULL);
1020 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1021 G_CALLBACK(addressbook_tree_button_released),
1022 NULL);
1023 /* TEMPORARY */
1024 g_signal_connect(G_OBJECT(ctree), "select_row",
1025 G_CALLBACK(addressbook_select_row_tree), NULL);
1027 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1028 addressbook_drag_types, 1,
1029 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1030 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1031 G_CALLBACK(addressbook_drag_motion_cb),
1032 ctree);
1033 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1034 G_CALLBACK(addressbook_drag_leave_cb),
1035 ctree);
1036 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1037 G_CALLBACK(addressbook_drag_received_cb),
1038 ctree);
1039 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1040 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1041 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1042 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1044 clist_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1046 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1047 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1048 GTK_POLICY_AUTOMATIC,
1049 GTK_POLICY_AUTOMATIC);
1050 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1052 /* Address list */
1053 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1054 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1055 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1056 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1057 GTK_CMCTREE_EXPANDER_TRIANGLE);
1058 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1059 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1060 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1061 COL_NAME_WIDTH);
1062 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1063 COL_ADDRESS_WIDTH);
1064 gtk_widget_set_size_request(clist, -1, 80);
1066 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1067 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1068 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1069 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1070 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1071 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1072 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1073 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1074 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1075 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1076 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1078 for (i = 0; i < N_LIST_COLS; i++)
1079 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1080 FALSE);
1082 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1083 G_CALLBACK(addressbook_list_row_selected), NULL);
1084 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1085 G_CALLBACK(addressbook_list_row_unselected), NULL);
1086 g_signal_connect(G_OBJECT(clist), "button_press_event",
1087 G_CALLBACK(addressbook_list_button_pressed),
1088 NULL);
1089 g_signal_connect(G_OBJECT(clist), "button_release_event",
1090 G_CALLBACK(addressbook_list_button_released),
1091 NULL);
1092 g_signal_connect(G_OBJECT(clist), "tree_expand",
1093 G_CALLBACK(addressbook_person_expand_node), NULL );
1094 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1095 G_CALLBACK(addressbook_person_collapse_node), NULL );
1096 g_signal_connect(G_OBJECT(clist), "start_drag",
1097 G_CALLBACK(addressbook_start_drag), NULL);
1098 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1099 G_CALLBACK(addressbook_drag_data_get), NULL);
1100 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
1101 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1103 label = gtk_label_new(_("Search"));
1104 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1106 entry = gtk_entry_new();
1107 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1109 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1111 g_signal_connect(G_OBJECT(entry), "key_press_event",
1112 G_CALLBACK(addressbook_entry_key_pressed),
1113 NULL);
1114 g_signal_connect(G_OBJECT(entry), "activate",
1115 G_CALLBACK(addressbook_entry_activated), NULL);
1117 if (!prefs_common.addressbook_use_editaddress_dialog) {
1118 editaddress_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1119 vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
1120 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1121 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1122 } else {
1123 vpaned = NULL;
1124 editaddress_vbox = NULL;
1126 hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
1127 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1128 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1129 if (prefs_common.addressbook_use_editaddress_dialog)
1130 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1131 else
1132 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1134 /* Status bar */
1135 hsbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1136 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1137 statusbar = gtk_statusbar_new();
1138 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1140 /* Button panel */
1141 hbbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
1142 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1143 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1144 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1145 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1147 gtkut_stock_button_add_help(hbbox, &help_btn);
1149 edit_btn = gtk_button_new_with_mnemonic("_Edit");
1150 gtk_widget_set_can_default(edit_btn, TRUE);
1151 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1152 del_btn = gtk_button_new_with_mnemonic("_Delete");
1153 gtk_widget_set_can_default(del_btn, TRUE);
1154 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1155 reg_btn = gtk_button_new_with_mnemonic("_New");
1156 gtk_widget_set_can_default(reg_btn, TRUE);
1157 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1160 lup_btn = gtkut_stock_button("edit-find", _("_Find"));
1161 gtk_widget_set_can_default(lup_btn, TRUE);
1162 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1164 g_signal_connect(G_OBJECT(help_btn), "clicked",
1165 G_CALLBACK(manual_open_with_anchor_cb),
1166 MANUAL_ANCHOR_ADDRBOOK);
1168 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1169 G_CALLBACK(addressbook_edit_clicked), NULL);
1170 g_signal_connect(G_OBJECT(del_btn), "clicked",
1171 G_CALLBACK(addressbook_del_clicked), NULL);
1172 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1173 G_CALLBACK(addressbook_reg_clicked), NULL);
1174 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1175 G_CALLBACK(addressbook_lup_clicked), NULL);
1177 to_btn = gtk_button_new_with_label
1178 (prefs_common_translated_header_name("To:"));
1179 gtk_widget_set_can_default(to_btn, TRUE);
1180 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1181 cc_btn = gtk_button_new_with_label
1182 (prefs_common_translated_header_name("Cc:"));
1183 gtk_widget_set_can_default(cc_btn, TRUE);
1184 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1185 bcc_btn = gtk_button_new_with_label
1186 (prefs_common_translated_header_name("Bcc:"));
1187 gtk_widget_set_can_default(bcc_btn, TRUE);
1188 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1190 close_btn = gtkut_stock_button("window-close", "_Close");
1191 gtk_widget_set_can_default(close_btn, TRUE);
1192 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1194 g_signal_connect(G_OBJECT(to_btn), "clicked",
1195 G_CALLBACK(addressbook_to_clicked),
1196 GINT_TO_POINTER(COMPOSE_TO));
1197 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1198 G_CALLBACK(addressbook_to_clicked),
1199 GINT_TO_POINTER(COMPOSE_CC));
1200 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1201 G_CALLBACK(addressbook_to_clicked),
1202 GINT_TO_POINTER(COMPOSE_BCC));
1203 g_signal_connect(G_OBJECT(close_btn), "clicked",
1204 G_CALLBACK(addressbook_close_clicked), NULL);
1206 /* Build icons for interface */
1208 /* Build control tables */
1209 addrbookctl_build_map(window);
1210 addrbookctl_build_iflist();
1211 addrbookctl_build_ifselect();
1213 addrbook.clist = NULL;
1215 /* Add each interface into the tree as a root level folder */
1216 nodeIf = _addressInterfaceList_;
1217 while( nodeIf ) {
1218 AdapterInterface *adapter = nodeIf->data;
1219 AddressInterface *iface = adapter->interface;
1220 nodeIf = g_list_next(nodeIf);
1222 if(iface->useInterface) {
1223 AddressTypeControlItem *atci = adapter->atci;
1224 text = atci->displayName;
1225 adapter->treeNode =
1226 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1227 NULL, NULL, &text, FOLDER_SPACING,
1228 interfacexpm,
1229 interfacexpm,
1230 FALSE, FALSE );
1231 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1232 gtk_cmctree_node_set_row_data_full(
1233 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1234 addressbook_free_treenode );
1238 /* Popup menu */
1240 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1241 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1242 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1243 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1244 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1245 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1253 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1254 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1270 #ifdef USE_LDAP
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1272 #endif
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1274 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1275 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1277 addrbook.window = window;
1278 addrbook.hpaned = hpaned;
1279 addrbook.vpaned = vpaned;
1280 addrbook.menubar = menubar;
1281 addrbook.ctree = ctree;
1282 addrbook.ctree_swin
1283 = ctree_swin;
1284 addrbook.editaddress_vbox = editaddress_vbox;
1285 addrbook.clist = clist;
1286 addrbook.label = label;
1287 addrbook.entry = entry;
1288 addrbook.statusbar = statusbar;
1289 addrbook.status_cid = gtk_statusbar_get_context_id(
1290 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1292 addrbook.help_btn = help_btn;
1293 addrbook.edit_btn = edit_btn;
1294 addrbook.del_btn = del_btn;
1295 addrbook.reg_btn = reg_btn;
1296 addrbook.lup_btn = lup_btn;
1297 addrbook.to_btn = to_btn;
1298 addrbook.cc_btn = cc_btn;
1299 addrbook.bcc_btn = bcc_btn;
1301 addrbook.tree_popup = tree_popup;
1302 addrbook.list_popup = list_popup;
1303 addrbook.ui_manager = ui_manager;
1305 addrbook.listSelected = NULL;
1307 if (!geometry.min_height) {
1308 geometry.min_width = ADDRESSBOOK_WIDTH;
1309 geometry.min_height = ADDRESSBOOK_HEIGHT;
1312 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1313 GDK_HINT_MIN_SIZE);
1314 gtk_window_set_default_size(GTK_WINDOW(window), prefs_common.addressbookwin_width,
1315 prefs_common.addressbookwin_height);
1316 #ifdef G_OS_WIN32
1317 gtk_window_move(GTK_WINDOW(window), 48, 48);
1318 #endif
1320 if (!prefs_common.addressbook_use_editaddress_dialog) {
1321 if (prefs_common.addressbook_vpaned_pos > 0)
1322 gtk_paned_set_position(GTK_PANED(vpaned),
1323 prefs_common.addressbook_vpaned_pos);
1325 if (prefs_common.addressbook_hpaned_pos > 0)
1326 gtk_paned_set_position(GTK_PANED(hpaned),
1327 prefs_common.addressbook_hpaned_pos);
1330 gtk_widget_show_all(window);
1334 * Close address book window and save to file(s).
1336 static gint addressbook_close( void ) {
1337 address_completion_end(addrbook.window);
1338 if (!prefs_common.addressbook_use_editaddress_dialog)
1339 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1341 addressbook_pane_save_position();
1343 gtk_widget_hide(addrbook.window);
1344 addressbook_export_to_file();
1345 return TRUE;
1349 * Display message in status line.
1350 * \param msg Message to display.
1352 static void addressbook_status_show( gchar *msg ) {
1353 if( addrbook.statusbar != NULL ) {
1354 gtk_statusbar_pop(
1355 GTK_STATUSBAR(addrbook.statusbar),
1356 addrbook.status_cid );
1357 if( msg ) {
1358 gtk_statusbar_push(
1359 GTK_STATUSBAR(addrbook.statusbar),
1360 addrbook.status_cid, msg );
1365 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1366 gint retVal;
1367 gchar *name;
1368 gchar *desc;
1369 *addressbook_msgbuf = '\0';
1370 if( ds ) {
1371 name = addrindex_ds_get_name( ds );
1372 retVal = addrindex_ds_get_status_code( ds );
1373 if( retVal == MGU_SUCCESS ) {
1374 g_snprintf( addressbook_msgbuf,
1375 sizeof(addressbook_msgbuf), "%s", name );
1377 else {
1378 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1379 g_snprintf( addressbook_msgbuf,
1380 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1383 addressbook_status_show( addressbook_msgbuf );
1386 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1388 addressbook_edit_address_cb(NULL, NULL);
1391 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1393 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1397 * Delete one or more objects from address list.
1399 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1401 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1402 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1403 AddressObject *pobj;
1404 AdapterDSource *ads = NULL;
1405 GtkCMCTreeNode *nodeList;
1406 gboolean procFlag;
1407 AlertValue aval;
1408 AddressBookFile *abf = NULL;
1409 AddressDataSource *ds = NULL;
1410 AddressInterface *iface;
1411 AddrItemObject *aio;
1412 AddrSelectItem *item;
1413 GList *list, *node;
1414 gboolean refreshList = FALSE;
1416 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1417 cm_return_if_fail(pobj != NULL);
1419 /* Test whether anything selected for deletion */
1420 nodeList = addrbook.listSelected;
1422 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1423 if( aio == NULL) return;
1424 ds = addressbook_find_datasource( addrbook.treeSelected );
1425 if( ds == NULL ) return;
1427 /* Test for read only */
1428 iface = ds->interface;
1429 if( iface->readOnly ) {
1430 alertpanel( _("Delete address(es)"),
1431 _("This address data is read-only and cannot be deleted."),
1432 "window-close", _("_Close"), NULL, NULL, NULL, NULL, ALERTFOCUS_FIRST);
1433 return;
1436 /* Test whether Ok to proceed */
1437 procFlag = FALSE;
1438 if( pobj->type == ADDR_DATASOURCE ) {
1439 ads = ADAPTER_DSOURCE(pobj);
1440 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1442 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1443 procFlag = TRUE;
1445 else if( pobj->type == ADDR_ITEM_GROUP ) {
1446 procFlag = TRUE;
1448 if( ! procFlag ) return;
1449 abf = ds->rawDataSource;
1450 if( abf == NULL ) return;
1452 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1453 g_signal_handlers_block_by_func
1454 (G_OBJECT(addrbook.clist),
1455 G_CALLBACK(addressbook_list_row_unselected), NULL);
1457 /* Process deletions */
1458 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1459 GList *groups = NULL, *persons = NULL, *emails = NULL;
1460 gboolean group_delete = TRUE;
1461 /* Items inside folders */
1462 list = addrselect_get_list( _addressSelect_ );
1463 /* Confirm deletion */
1464 node = list;
1465 while( node ) {
1466 item = node->data;
1467 node = g_list_next( node );
1468 aio = ( AddrItemObject * ) item->addressItem;
1469 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1470 group_delete = FALSE;
1471 break;
1474 if (group_delete) {
1475 aval = alertpanel( _("Delete group"),
1476 _("Really delete the group(s)?\n"
1477 "The addresses it contains will not be lost."),
1478 NULL, _("_Cancel"), "edit-delete", _("D_elete"), NULL, NULL,
1479 ALERTFOCUS_SECOND );
1480 if( aval != G_ALERTALTERNATE ) {
1481 goto thaw_ret;
1483 } else {
1484 aval = alertpanel( _("Delete address(es)"),
1485 _("Really delete the address(es)?"),
1486 NULL, _("_Cancel"), "edit-delete", _("D_elete"), NULL, NULL,
1487 ALERTFOCUS_SECOND );
1488 if( aval != G_ALERTALTERNATE ) {
1489 goto thaw_ret;
1493 /* first, set lists of groups and persons to remove */
1494 node = list;
1495 while( node ) {
1496 item = node->data;
1497 node = g_list_next( node );
1498 aio = ( AddrItemObject * ) item->addressItem;
1499 if (!aio)
1500 continue;
1501 if( aio->type == ITEMTYPE_GROUP ) {
1502 groups = g_list_prepend(groups, item);
1504 else if( aio->type == ITEMTYPE_PERSON ) {
1505 persons = g_list_prepend(persons, item);
1508 /* then set list of emails to remove *if* they're not children of
1509 * persons to remove */
1510 node = list;
1511 while( node ) {
1512 item = node->data;
1513 node = g_list_next( node );
1514 aio = ( AddrItemObject * ) item->addressItem;
1515 if (!aio)
1516 continue;
1517 if( aio->type == ITEMTYPE_EMAIL ) {
1518 ItemEMail *sitem = ( ItemEMail * ) aio;
1519 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1520 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1521 emails = g_list_prepend(emails, item);
1523 /* else, the email will be removed via the parent person */
1526 /* then delete groups */
1527 node = groups;
1528 while( node ) {
1529 item = node->data;
1530 node = g_list_next( node );
1531 aio = ( AddrItemObject * ) item->addressItem;
1532 if (!aio)
1533 continue;
1534 if( aio->type == ITEMTYPE_GROUP ) {
1535 ItemGroup *item = ( ItemGroup * ) aio;
1536 GtkCMCTreeNode *nd = NULL;
1537 nd = addressbook_find_group_node( addrbook.opened, item );
1538 item = addrbook_remove_group( abf, item );
1539 if( item ) {
1540 addritem_free_item_group( item );
1542 /* Remove group from parent node */
1543 gtk_cmctree_remove_node( ctree, nd );
1544 refreshList = TRUE;
1547 /* then delete persons */
1548 node = persons;
1549 while( node ) {
1550 item = node->data;
1551 node = g_list_next( node );
1552 aio = ( AddrItemObject * ) item->addressItem;
1553 if (!aio)
1554 continue;
1555 if( aio->type == ITEMTYPE_PERSON ) {
1556 ItemPerson *item = ( ItemPerson * ) aio;
1557 item->status = DELETE_ENTRY;
1558 addressbook_folder_remove_one_person( clist, item );
1559 if (pobj->type == ADDR_ITEM_FOLDER)
1560 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1561 item = addrbook_remove_person( abf, item );
1562 #ifdef USE_LDAP
1563 if (ds && ds->type == ADDR_IF_LDAP) {
1564 LdapServer *server = ds->rawDataSource;
1565 ldapsvr_set_modified(server, TRUE);
1566 ldapsvr_update_book(server, item);
1568 #endif
1569 if( item ) {
1570 addritem_person_remove_picture(item);
1571 addritem_free_item_person( item );
1575 /* then delete emails */
1576 node = emails;
1577 while( node ) {
1578 item = node->data;
1579 node = g_list_next( node );
1580 aio = ( AddrItemObject * ) item->addressItem;
1581 if (!aio)
1582 continue;
1584 if( aio->type == ITEMTYPE_EMAIL ) {
1585 ItemEMail *sitem = ( ItemEMail * ) aio;
1586 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1587 sitem = addrbook_person_remove_email( abf, person, sitem );
1588 if( sitem ) {
1589 addrcache_remove_email(abf->addressCache, sitem);
1590 addritem_free_item_email( sitem );
1592 addressbook_folder_refresh_one_person( clist, person );
1595 g_list_free( groups );
1596 g_list_free( persons );
1597 g_list_free( emails );
1598 g_list_free( list );
1599 addressbook_list_select_clear();
1600 if( refreshList ) {
1601 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1602 addressbook_set_clist(
1603 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1604 addrbook.opened),
1605 TRUE);
1607 addrbook_set_dirty(abf, TRUE);
1608 addressbook_export_to_file();
1609 addressbook_list_menu_setup();
1610 goto thaw_ret;
1612 else if( pobj->type == ADDR_ITEM_GROUP ) {
1613 /* Items inside groups */
1614 list = addrselect_get_list( _addressSelect_ );
1615 node = list;
1616 while( node ) {
1617 item = node->data;
1618 node = g_list_next( node );
1619 aio = ( AddrItemObject * ) item->addressItem;
1620 if( aio->type == ITEMTYPE_EMAIL ) {
1621 ItemEMail *item = ( ItemEMail * ) aio;
1622 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1623 item = addrbook_person_remove_email( abf, person, item );
1624 if( item ) {
1625 addritem_free_item_email( item );
1629 g_list_free( list );
1630 addressbook_list_select_clear();
1631 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1632 addressbook_set_clist(
1633 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1634 addrbook.opened),
1635 TRUE);
1637 addrbook_set_dirty(abf, TRUE);
1638 addressbook_export_to_file();
1639 addressbook_list_menu_setup();
1640 goto thaw_ret;
1643 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1644 gtk_cmctree_remove_node( clist, nodeList );
1645 thaw_ret:
1646 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1647 g_signal_handlers_unblock_by_func
1648 (G_OBJECT(addrbook.clist),
1649 G_CALLBACK(addressbook_list_row_unselected), NULL);
1652 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1654 addressbook_new_address_cb( NULL, NULL );
1657 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1658 gchar *buf = NULL;
1659 gchar *name = NULL;
1660 gchar *address = NULL;
1662 if( aio->type == ITEMTYPE_EMAIL ) {
1663 ItemPerson *person = NULL;
1664 ItemEMail *email = ( ItemEMail * ) aio;
1666 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1667 if( email->address ) {
1668 if( ADDRITEM_NAME(email) ) {
1669 name = ADDRITEM_NAME(email);
1670 if( *name == '\0' ) {
1671 name = ADDRITEM_NAME(person);
1674 else if( ADDRITEM_NAME(person) ) {
1675 name = ADDRITEM_NAME(person);
1677 else {
1678 buf = g_strdup( email->address );
1680 address = email->address;
1683 else if( aio->type == ITEMTYPE_PERSON ) {
1684 ItemPerson *person = ( ItemPerson * ) aio;
1685 GList *node = person->listEMail;
1687 name = ADDRITEM_NAME(person);
1688 if( node ) {
1689 ItemEMail *email = ( ItemEMail * ) node->data;
1690 address = email->address;
1693 if( address ) {
1694 if( name && name[0] != '\0' ) {
1695 if( strchr_with_skip_quote( name, '"', ',' ) )
1696 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1697 else
1698 buf = g_strdup_printf( "%s <%s>", name, address );
1700 else {
1701 buf = g_strdup( address );
1705 return buf;
1708 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1710 GList *list, *node;
1711 Compose *compose;
1712 AddrSelectItem *item;
1713 AddrItemObject *aio;
1714 gchar *addr;
1716 compose = addrbook.target_compose;
1717 if( ! compose ) return;
1719 /* Nothing selected, but maybe there is something in text entry */
1720 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1721 if ( addr ) {
1722 compose_entry_append(
1723 compose, addr, (ComposeEntryType)data , PREF_NONE);
1726 /* Select from address list */
1727 list = addrselect_get_list( _addressSelect_ );
1728 node = list;
1729 if (node) {
1730 while( node ) {
1731 item = node->data;
1732 node = g_list_next( node );
1733 aio = item->addressItem;
1734 if( aio->type == ITEMTYPE_PERSON ||
1735 aio->type == ITEMTYPE_EMAIL ) {
1736 addr = addressbook_format_address( aio );
1737 compose_entry_append(
1738 compose, addr, (ComposeEntryType) data, PREF_NONE );
1739 g_free( addr );
1741 else if( aio->type == ITEMTYPE_GROUP ) {
1742 ItemGroup *group = ( ItemGroup * ) aio;
1743 GList *nodeMail = group->listEMail;
1744 while( nodeMail ) {
1745 ItemEMail *email = nodeMail->data;
1747 addr = addressbook_format_address(
1748 ( AddrItemObject * ) email );
1749 compose_entry_append(
1750 compose, addr, (ComposeEntryType) data, PREF_NONE );
1751 g_free( addr );
1752 nodeMail = g_list_next( nodeMail );
1756 } else {
1757 AddressObject *obj = NULL;
1759 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1761 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1762 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1763 GList *nodeMail = itemGroup->listEMail;
1764 while( nodeMail ) {
1765 ItemEMail *email = nodeMail->data;
1767 addr = addressbook_format_address(
1768 ( AddrItemObject * ) email );
1769 compose_entry_append(
1770 compose, addr, (ComposeEntryType) data, PREF_NONE );
1771 g_free( addr );
1772 nodeMail = g_list_next( nodeMail );
1776 g_list_free( list );
1779 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1780 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1781 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1782 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1787 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1792 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1793 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1794 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1797 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1798 gboolean canEdit = FALSE;
1799 gboolean canDelete = TRUE;
1800 gboolean canAdd = FALSE;
1801 gboolean canEditTr = TRUE;
1802 gboolean editAddress = FALSE;
1803 gboolean canExport = TRUE;
1804 AddressTypeControlItem *atci = NULL;
1805 AddressDataSource *ds = NULL;
1806 AddressInterface *iface = NULL;
1808 if( obj == NULL ) return;
1809 if( obj->type == ADDR_INTERFACE ) {
1810 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1811 iface = adapter->interface;
1812 if( iface ) {
1813 if( iface->haveLibrary ) {
1814 /* Enable appropriate File / New command */
1815 atci = adapter->atci;
1816 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1819 canEditTr = canExport = FALSE;
1821 else if( obj->type == ADDR_DATASOURCE ) {
1822 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1823 ds = ads->dataSource;
1824 iface = ds->interface;
1825 if( ! iface->readOnly ) {
1826 canAdd = canEdit = editAddress = canDelete = TRUE;
1828 if( ! iface->haveLibrary ) {
1829 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1832 else if( obj->type == ADDR_ITEM_FOLDER ) {
1833 ds = addressbook_find_datasource( addrbook.treeSelected );
1834 if( ds ) {
1835 iface = ds->interface;
1836 if( iface->readOnly ) {
1837 canEditTr = FALSE;
1838 canDelete = FALSE;
1840 else {
1841 canAdd = editAddress = TRUE;
1845 else if( obj->type == ADDR_ITEM_GROUP ) {
1846 ds = addressbook_find_datasource( addrbook.treeSelected );
1847 if( ds ) {
1848 iface = ds->interface;
1849 if( ! iface->readOnly ) {
1850 editAddress = TRUE;
1855 if( addrbook.listSelected == NULL )
1856 canEdit = FALSE;
1858 /* Enable add */
1859 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1860 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1861 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1862 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1864 /* Enable edit */
1865 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1866 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1867 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1868 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1871 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1873 /* Export data */
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1879 * Address book tree callback function that responds to selection of tree
1880 * items.
1882 * \param ctree Tree widget.
1883 * \param node Node that was selected.
1884 * \param column Column number where selected occurred.
1885 * \param data Pointer to user data.
1887 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1888 gint column, gpointer data)
1890 AddressObject *obj = NULL;
1891 AdapterDSource *ads = NULL;
1892 AddressDataSource *ds = NULL;
1893 ItemFolder *rootFolder = NULL;
1894 AddressObjectType aot;
1896 addrbook.treeSelected = node;
1897 addrbook.listSelected = NULL;
1898 addressbook_status_show( "" );
1899 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1901 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1902 if( obj == NULL ) {
1903 addressbook_set_clist(NULL, TRUE);
1904 return;
1906 addrbook.opened = node;
1908 if( obj->type == ADDR_DATASOURCE ) {
1909 /* Read from file */
1910 static gboolean tVal = TRUE;
1912 ads = ADAPTER_DSOURCE(obj);
1914 ds = ads->dataSource;
1915 if( ds == NULL ) return;
1917 if( addrindex_ds_get_modify_flag( ds ) ) {
1918 addrindex_ds_read_data( ds );
1921 if( ! addrindex_ds_get_read_flag( ds ) ) {
1922 addrindex_ds_read_data( ds );
1924 addressbook_ds_show_message( ds );
1926 if( ! addrindex_ds_get_access_flag( ds ) ) {
1927 /* Remove existing folders and groups */
1928 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1929 addressbook_tree_remove_children( ctree, node );
1930 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1932 /* Load folders into the tree */
1933 rootFolder = addrindex_ds_get_root_folder( ds );
1934 if( ds && ds->type == ADDR_IF_JPILOT ) {
1935 aot = ADDR_CATEGORY;
1937 else if( ds && ds->type == ADDR_IF_LDAP ) {
1938 aot = ADDR_LDAP_QUERY;
1940 else {
1941 aot = ADDR_ITEM_FOLDER;
1943 addressbook_node_add_folder( node, ds, rootFolder, aot );
1944 addrindex_ds_set_access_flag( ds, &tVal );
1945 gtk_cmctree_expand( ctree, node );
1947 } else {
1948 addressbook_set_clist(NULL, TRUE);
1951 /* Update address list */
1952 g_signal_handlers_block_by_func
1953 (G_OBJECT(ctree),
1954 G_CALLBACK(addressbook_tree_selected), NULL);
1955 addressbook_set_clist( obj, FALSE );
1956 g_signal_handlers_unblock_by_func
1957 (G_OBJECT(ctree),
1958 G_CALLBACK(addressbook_tree_selected), NULL);
1959 if (!prefs_common.addressbook_use_editaddress_dialog)
1960 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1962 /* Setup main menu selections */
1963 addressbook_menubar_set_sensitive( FALSE );
1964 addressbook_menuitem_set_sensitive( obj, node );
1965 addressbook_list_select_clear();
1966 addressbook_list_menu_setup();
1967 return;
1971 * Setup address list popup menu items. Items are enabled or disabled as
1972 * required.
1974 static void addressbook_list_menu_setup( void ) {
1975 GtkCMCTree *clist = NULL;
1976 AddressObject *pobj = NULL;
1977 AddressObject *obj = NULL;
1978 AdapterDSource *ads = NULL;
1979 AddressInterface *iface = NULL;
1980 AddressDataSource *ds = NULL;
1981 GList *list;
1982 AddrItemObject *aio;
1983 AddrSelectItem *item;
1984 gboolean canEdit = FALSE;
1985 gboolean canDelete = FALSE;
1986 gboolean canCut = FALSE;
1987 gboolean canCopy = FALSE;
1988 gboolean canPaste = FALSE;
1989 gboolean canBrowse = FALSE;
1990 gboolean canMerge = FALSE;
1992 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1993 if( pobj == NULL ) return;
1995 clist = GTK_CMCTREE(addrbook.clist);
1996 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
1997 if( obj == NULL ) canEdit = FALSE;
1999 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2000 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2002 if( pobj->type == ADDR_DATASOURCE ) {
2003 /* Parent object is a data source */
2004 ads = ADAPTER_DSOURCE(pobj);
2005 ds = ads->dataSource;
2006 if (!ds)
2007 return;
2008 iface = ds->interface;
2009 if (!iface)
2010 return;
2011 if( ! iface->readOnly ) {
2012 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2013 if (iface->type != ADDR_IF_LDAP)
2014 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2015 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2016 if( obj )
2017 canEdit = TRUE;
2018 canDelete = canEdit;
2021 else if( pobj->type != ADDR_INTERFACE ) {
2022 /* Parent object is not an interface */
2023 ds = addressbook_find_datasource( addrbook.treeSelected );
2024 if (!ds)
2025 return;
2026 iface = ds->interface;
2027 if (!iface)
2028 return;
2029 if( ! iface->readOnly ) {
2030 /* Folder or group */
2031 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2032 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2033 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2034 if( obj ) canEdit = TRUE;
2036 /* Folder */
2037 if( pobj->type == ADDR_ITEM_FOLDER ) {
2038 if (iface->type != ADDR_IF_LDAP)
2039 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2040 if( obj ) canEdit = TRUE;
2042 canDelete = canEdit;
2044 if( iface->type == ADDR_IF_LDAP ) {
2045 if( obj ) canBrowse = TRUE;
2046 canEdit = TRUE;
2047 canDelete = TRUE;
2051 if( iface ) {
2052 /* Enable cut and paste */
2053 if( ! addrclip_is_empty( _clipBoard_ ) )
2054 canPaste = TRUE;
2055 if( ! addrselect_test_empty( _addressSelect_ ) )
2056 canCut = TRUE;
2057 /* Enable copy if something is selected */
2058 if( ! addrselect_test_empty( _addressSelect_ ) )
2059 canCopy = TRUE;
2062 /* Disable edit or browse if more than one row selected */
2063 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2064 canEdit = FALSE;
2065 canBrowse = FALSE;
2068 /* Allow merging persons or emails are selected */
2069 list = _addressSelect_->listSelect;
2070 if (list && list->next ) {
2071 item = list->data;
2072 aio = ( AddrItemObject * ) item->addressItem;
2073 if( aio->type == ITEMTYPE_EMAIL ||
2074 aio->type == ITEMTYPE_PERSON ) {
2075 canMerge = TRUE;
2079 /* Forbid write changes when read-only */
2080 if( iface && iface->readOnly ) {
2081 canCut = FALSE;
2082 canDelete = FALSE;
2083 canPaste = FALSE;
2084 canMerge = FALSE;
2087 /* Now go finalize menu items */
2088 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2091 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2107 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2108 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2110 if (addrbook.target_compose) {
2111 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2112 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2113 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2115 #ifdef USE_LDAP
2116 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2117 #endif
2120 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2121 GtkCMCTreeNode *node,
2122 gint column,
2123 gpointer data)
2128 * Add list of items into tree node below specified tree node.
2129 * \param treeNode Tree node.
2130 * \param ds Data source.
2131 * \param listItems List of items.
2133 static void addressbook_treenode_add_list(
2134 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2136 GList *node;
2138 node = listItems;
2139 while( node ) {
2140 AddrItemObject *aio;
2141 GtkCMCTreeNode *nn;
2143 aio = node->data;
2144 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2145 ItemGroup *group;
2147 group = ( ItemGroup * ) aio;
2148 nn = addressbook_node_add_group( treeNode, ds, group );
2149 if (nn == NULL) {
2150 g_message("error adding addressbook group\n");
2153 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2154 ItemFolder *folder;
2156 folder = ( ItemFolder * ) aio;
2157 nn = addressbook_node_add_folder(
2158 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2159 if (nn == NULL) {
2160 g_message("error adding addressbook folder\n");
2163 node = g_list_next( node );
2167 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2168 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2172 * Cut from address list widget.
2174 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2175 _clipBoard_->cutFlag = TRUE;
2176 addrclip_clear( _clipBoard_ );
2177 addrclip_add( _clipBoard_, _addressSelect_ );
2178 /* addrclip_list_show( _clipBoard_, stdout ); */
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 /* addrclip_list_show( _clipBoard_, stdout ); */
2192 * Paste clipboard into address list widget.
2194 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2195 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2196 AddressObject *pobj = NULL;
2197 AddressDataSource *ds = NULL;
2198 AddressBookFile *abf = NULL;
2199 ItemFolder *folder = NULL;
2200 GList *folderGroup = NULL;
2202 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2203 if( ds == NULL ) return;
2204 if( addrindex_ds_get_readonly( ds ) ) {
2205 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2206 return;
2209 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2210 if( pobj ) {
2211 if( pobj->type == ADDR_ITEM_FOLDER ) {
2212 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2214 else if( pobj->type == ADDR_ITEM_GROUP ) {
2215 alertpanel_error( _("Cannot paste into an address group.") );
2216 return;
2220 /* Get an address book */
2221 abf = addressbook_get_book_file();
2222 if( abf == NULL ) return;
2224 if( _clipBoard_->cutFlag ) {
2225 /* Paste/Cut */
2226 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2228 /* Remove all groups and folders in clipboard from tree node */
2229 addressbook_treenode_remove_item();
2231 /* Remove all "cut" items */
2232 addrclip_delete_item( _clipBoard_ );
2234 /* Clear clipboard - cut items??? */
2235 addrclip_clear( _clipBoard_ );
2237 else {
2238 /* Paste/Copy */
2239 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2242 /* addrclip_list_show( _clipBoard_, stdout ); */
2243 if( folderGroup ) {
2244 /* Update tree by inserting node for each folder or group */
2245 addressbook_treenode_add_list(
2246 addrbook.treeSelected, ds, folderGroup );
2247 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2248 g_list_free( folderGroup );
2249 folderGroup = NULL;
2252 /* Display items pasted */
2253 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2254 addressbook_set_clist(
2255 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2256 addrbook.opened),
2257 TRUE);
2263 * Add current treenode object to clipboard. Note that widget only allows
2264 * one entry from the tree list to be selected.
2266 static void addressbook_treenode_to_clipboard( void ) {
2267 AddressObject *obj = NULL;
2268 AddressDataSource *ds = NULL;
2269 AddrSelectItem *item;
2270 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2271 GtkCMCTreeNode *node;
2273 node = addrbook.treeSelected;
2274 if( node == NULL ) return;
2275 obj = gtk_cmctree_node_get_row_data( ctree, node );
2276 if( obj == NULL ) return;
2278 ds = addressbook_find_datasource( node );
2279 if( ds == NULL ) return;
2281 item = NULL;
2282 if( obj->type == ADDR_ITEM_FOLDER ) {
2283 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2284 ItemFolder *folder = adapter->itemFolder;
2286 item = addrselect_create_node( obj );
2287 item->uid = g_strdup( ADDRITEM_ID(folder) );
2289 else if( obj->type == ADDR_ITEM_GROUP ) {
2290 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2291 ItemGroup *group = adapter->itemGroup;
2293 item = addrselect_create_node( obj );
2294 item->uid = g_strdup( ADDRITEM_ID(group) );
2296 else if( obj->type == ADDR_DATASOURCE ) {
2297 /* Data source */
2298 item = addrselect_create_node( obj );
2299 item->uid = NULL;
2302 if( item ) {
2303 /* Clear existing list and add item into list */
2304 gchar *cacheID;
2306 addressbook_list_select_clear();
2307 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2308 addrselect_list_add( _addressSelect_, item, cacheID );
2309 g_free( cacheID );
2314 * Cut from tree widget.
2316 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2317 _clipBoard_->cutFlag = TRUE;
2318 addressbook_treenode_to_clipboard();
2319 addrclip_clear( _clipBoard_ );
2320 addrclip_add( _clipBoard_, _addressSelect_ );
2321 /* addrclip_list_show( _clipBoard_, stdout ); */
2325 * Copy from tree widget.
2327 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2328 _clipBoard_->cutFlag = FALSE;
2329 addressbook_treenode_to_clipboard();
2330 addrclip_clear( _clipBoard_ );
2331 addrclip_add( _clipBoard_, _addressSelect_ );
2332 /* addrclip_list_show( _clipBoard_, stdout ); */
2336 * Paste clipboard into address tree widget.
2338 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2339 addressbook_clip_paste_cb(NULL,NULL);
2343 * Clear selected entries in clipboard.
2345 static void addressbook_list_select_clear( void ) {
2346 addrselect_list_clear( _addressSelect_ );
2350 * Add specified address item to selected address list.
2351 * \param aio Address item object.
2352 * \param ds Datasource.
2354 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2355 gchar *cacheID;
2357 if( ds == NULL ) return;
2358 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2359 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2360 g_free( cacheID );
2364 * Remove specified address item from selected address list.
2365 * \param aio Address item object.
2367 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2368 addrselect_list_remove( _addressSelect_, aio );
2372 * Invoke EMail compose window with addresses in selected address list.
2374 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2375 GList *listAddress;
2377 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2378 listAddress = addrselect_build_list( _addressSelect_ );
2379 compose_new_with_list( NULL, listAddress );
2380 g_list_free_full( listAddress, g_free );
2381 listAddress = NULL;
2385 static void addressbook_merge_list( AddrSelectList *list ) {
2386 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2387 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2388 AddressObject *pobj;
2389 AddressDataSource *ds = NULL;
2391 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2392 cm_return_if_fail(pobj != NULL);
2394 ds = addressbook_find_datasource( addrbook.treeSelected );
2395 if( ds == NULL ) return;
2397 addrmerge_merge(clist, pobj, ds, list);
2401 * Merge selected entries in the address list
2403 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2404 if( addrselect_test_empty( _addressSelect_ ) )
2405 return;
2407 addressbook_merge_list( _addressSelect_ );
2410 static void addressbook_list_row_selected( GtkCMCTree *clist,
2411 GtkCMCTreeNode *node,
2412 gint column,
2413 gpointer data )
2415 AddrItemObject *aio = NULL;
2416 AddressObject *pobj = NULL;
2417 AdapterDSource *ads = NULL;
2418 AddressDataSource *ds = NULL;
2420 addrbook.listSelected = node;
2422 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2423 if( pobj == NULL ) return;
2425 if( pobj->type == ADDR_DATASOURCE ) {
2426 ads = ADAPTER_DSOURCE(pobj);
2427 ds = ads->dataSource;
2429 else if( pobj->type != ADDR_INTERFACE ) {
2430 ds = addressbook_find_datasource( addrbook.treeSelected );
2433 aio = gtk_cmctree_node_get_row_data( clist, node );
2434 if( aio ) {
2435 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2436 addressbook_list_select_add( aio, ds );
2439 addressbook_list_menu_setup();
2441 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2442 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2444 if (obj && obj->type != ADDR_ITEM_GROUP)
2445 addressbook_edit_address(NULL, 0, NULL, FALSE);
2449 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2450 GtkCMCTreeNode *node,
2451 gint column,
2452 gpointer data )
2454 AddrItemObject *aio;
2456 aio = gtk_cmctree_node_get_row_data( ctree, node );
2457 if( aio != NULL ) {
2458 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2459 addressbook_list_select_remove( aio );
2462 if (!prefs_common.addressbook_use_editaddress_dialog)
2463 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2466 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2468 addressbook_lup_clicked(NULL, NULL);
2471 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2472 GdkEventButton *event,
2473 gpointer data)
2475 if( ! event ) return FALSE;
2476 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2478 addressbook_list_menu_setup();
2480 if( event->button == 3 ) {
2481 gtk_menu_popup_at_pointer(GTK_MENU(addrbook.list_popup), NULL);
2482 } else if (event->button == 1) {
2483 if (event->type == GDK_2BUTTON_PRESS) {
2484 if (prefs_common.add_address_by_click &&
2485 addrbook.target_compose)
2486 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2487 else
2488 if (prefs_common.addressbook_use_editaddress_dialog)
2489 addressbook_edit_address_cb(NULL, NULL);
2490 else {
2491 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2492 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2493 if( obj && obj->type == ADDR_ITEM_GROUP )
2494 addressbook_edit_address_cb(NULL, NULL);
2499 return FALSE;
2502 static gboolean addressbook_list_button_released(GtkWidget *widget,
2503 GdkEventButton *event,
2504 gpointer data)
2506 return FALSE;
2509 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2510 GdkEventButton *event,
2511 gpointer data)
2513 GtkCMCList *clist = GTK_CMCLIST(ctree);
2514 gint row, column;
2515 AddressObject *obj = NULL;
2516 AdapterDSource *ads = NULL;
2517 AddressInterface *iface = NULL;
2518 AddressDataSource *ds = NULL;
2519 gboolean canEdit = FALSE;
2520 gboolean canDelete = FALSE;
2521 gboolean canCut = FALSE;
2522 gboolean canCopy = FALSE;
2523 gboolean canPaste = FALSE;
2524 gboolean canTreeCut = FALSE;
2525 gboolean canTreeCopy = FALSE;
2526 gboolean canTreePaste = FALSE;
2527 gboolean canLookup = FALSE;
2528 GtkCMCTreeNode *node = NULL;
2530 if( ! event ) return FALSE;
2531 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2533 if( event->window != clist->clist_window )
2534 return FALSE;
2536 if (event->button == 1) {
2537 if (event->type == GDK_2BUTTON_PRESS) {
2538 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2539 gtkut_clist_set_focus_row(clist, row);
2540 obj = gtk_cmclist_get_row_data( clist, row );
2542 if( obj == NULL )
2543 return FALSE;
2545 if (obj->type == ADDR_ITEM_GROUP ||
2546 obj->type == ADDR_DATASOURCE) {
2547 /* edit group */
2548 addressbook_treenode_edit_cb(NULL, NULL);
2549 } else {
2550 /* expand pr collapse */
2551 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2552 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2554 return FALSE;
2558 addressbook_menubar_set_sensitive( FALSE );
2560 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2561 gtkut_clist_set_focus_row(clist, row);
2562 obj = gtk_cmclist_get_row_data( clist, row );
2565 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2567 if( obj == NULL )
2568 return FALSE;
2569 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2571 if( ! addrclip_is_empty( _clipBoard_ ) )
2572 canTreePaste = TRUE;
2574 if (obj->type == ADDR_INTERFACE) {
2575 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2576 iface = adapter->interface;
2577 if( !iface )
2578 goto just_set_sens;
2579 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2580 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2582 if( iface->externalQuery )
2583 canLookup = TRUE;
2585 if (obj->type == ADDR_DATASOURCE) {
2586 canLookup = TRUE;
2587 ads = ADAPTER_DSOURCE(obj);
2588 ds = ads->dataSource;
2589 if( !ds )
2590 goto just_set_sens;
2591 iface = ds->interface;
2592 if( !iface )
2593 goto just_set_sens;
2594 if( !iface->readOnly ) {
2595 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2596 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2597 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2599 canDelete = TRUE;
2600 canEdit = TRUE;
2601 canTreeCopy = TRUE;
2603 else if (obj->type == ADDR_ITEM_FOLDER) {
2604 canLookup = TRUE;
2605 ds = addressbook_find_datasource( node );
2606 if( !ds )
2607 goto just_set_sens;
2608 iface = ds->interface;
2609 if( !iface )
2610 goto just_set_sens;
2611 if( !iface->readOnly ) {
2612 canEdit = TRUE;
2613 canDelete = TRUE;
2614 canTreeCut = TRUE;
2615 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2616 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2617 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2619 canTreeCopy = TRUE;
2621 if( iface->externalQuery ) {
2622 /* Enable deletion of LDAP folder */
2623 canDelete = TRUE;
2626 else if (obj->type == ADDR_ITEM_GROUP) {
2627 canLookup = TRUE;
2628 ds = addressbook_find_datasource( node );
2629 if( !ds )
2630 goto just_set_sens;
2631 iface = ds->interface;
2632 if( !iface )
2633 goto just_set_sens;
2634 if( ! iface->readOnly ) {
2635 canEdit = TRUE;
2636 canDelete = TRUE;
2637 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2638 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2642 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2643 canCut = TRUE;
2644 if( ! addrselect_test_empty( _addressSelect_ ) )
2645 canCopy = TRUE;
2646 if( ! addrclip_is_empty( _clipBoard_ ) )
2647 canPaste = TRUE;
2649 /* Forbid write changes when read-only */
2650 if( iface && iface->readOnly ) {
2651 canTreeCut = FALSE;
2652 canTreePaste = FALSE;
2653 canCut = FALSE;
2654 canPaste = FALSE;
2657 just_set_sens:
2658 /* Enable edit */
2659 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2660 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2661 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2662 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2663 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2665 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2666 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2669 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2671 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2672 addrbook.target_compose != NULL);
2674 if( event->button == 3 )
2675 gtk_menu_popup_at_pointer(GTK_MENU(addrbook.tree_popup), NULL);
2677 return FALSE;
2680 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2681 GdkEventButton *event,
2682 gpointer data)
2684 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2685 return FALSE;
2688 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2690 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2691 AddressObject *obj = NULL;
2692 AddressDataSource *ds = NULL;
2693 AddressBookFile *abf = NULL;
2694 ItemFolder *parentFolder = NULL;
2695 ItemFolder *folder = NULL;
2697 if( ! addrbook.treeSelected ) return;
2698 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2699 if( obj == NULL ) return;
2700 ds = addressbook_find_datasource( addrbook.treeSelected );
2701 if( ds == NULL ) return;
2703 if( obj->type == ADDR_DATASOURCE ) {
2704 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2706 else if( obj->type == ADDR_ITEM_FOLDER ) {
2707 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2709 else {
2710 return;
2713 abf = ds->rawDataSource;
2714 if( abf == NULL ) return;
2715 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2716 if( folder ) {
2717 GtkCMCTreeNode *nn;
2718 nn = addressbook_node_add_folder(
2719 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2720 if (nn == NULL) {
2721 g_message("error adding addressbook folder\n");
2723 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2724 if( addrbook.treeSelected == addrbook.opened )
2725 addressbook_set_clist(obj, TRUE);
2729 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2731 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2732 AddressObject *obj = NULL;
2733 AddressDataSource *ds = NULL;
2734 AddressBookFile *abf = NULL;
2735 ItemFolder *parentFolder = NULL;
2736 ItemGroup *group = NULL;
2738 if( ! addrbook.treeSelected ) return;
2739 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2740 if( obj == NULL ) return;
2741 ds = addressbook_find_datasource( addrbook.treeSelected );
2742 if( ds == NULL ) return;
2744 if( obj->type == ADDR_DATASOURCE ) {
2745 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2747 else if( obj->type == ADDR_ITEM_FOLDER ) {
2748 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2750 else {
2751 return;
2754 abf = ds->rawDataSource;
2755 if( abf == NULL ) return;
2756 group = addressbook_edit_group( abf, parentFolder, NULL );
2757 if( group ) {
2758 GtkCMCTreeNode *nn;
2759 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2760 if (nn == NULL) {
2761 g_message("error adding addressbook group\n");
2763 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2764 if( addrbook.treeSelected == addrbook.opened )
2765 addressbook_set_clist(obj, TRUE);
2769 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2771 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2772 gchar *text[1];
2773 guint8 spacing;
2774 GdkPixbuf *pix_cl, *pix_op;
2775 gboolean is_leaf, expanded;
2777 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2778 &pix_cl, &pix_op,
2779 &is_leaf, &expanded);
2780 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2781 pix_cl, pix_op,
2782 is_leaf, expanded);
2786 * Edit data source.
2787 * \param obj Address object to edit.
2788 * \param node Node in tree.
2789 * \return New name of data source.
2791 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2792 gchar *newName = NULL;
2793 AddressDataSource *ds = NULL;
2794 AddressInterface *iface = NULL;
2795 AdapterDSource *ads = NULL;
2797 ds = addressbook_find_datasource( node );
2798 if( ds == NULL ) return NULL;
2799 iface = ds->interface;
2800 if( ! iface->haveLibrary ) return NULL;
2802 /* Read data from data source */
2803 if( addrindex_ds_get_modify_flag( ds ) ) {
2804 addrindex_ds_read_data( ds );
2807 if( ! addrindex_ds_get_read_flag( ds ) ) {
2808 addrindex_ds_read_data( ds );
2811 /* Handle edit */
2812 ads = ADAPTER_DSOURCE(obj);
2813 if( ads->subType == ADDR_BOOK ) {
2814 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2816 else if( ads->subType == ADDR_VCARD ) {
2817 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2819 #ifdef USE_JPILOT
2820 else if( ads->subType == ADDR_JPILOT ) {
2821 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2823 #endif
2824 #ifdef USE_LDAP
2825 else if( ads->subType == ADDR_LDAP ) {
2826 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2828 #endif
2829 else {
2830 return NULL;
2832 newName = obj->name;
2833 return newName;
2837 * Edit an object that is in the address tree area.
2839 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2841 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2842 AddressObject *obj;
2843 AddressDataSource *ds = NULL;
2844 AddressBookFile *abf = NULL;
2845 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2846 gchar *name = NULL;
2848 if( ! addrbook.treeSelected ) return;
2849 node = addrbook.treeSelected;
2850 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2851 obj = gtk_cmctree_node_get_row_data( ctree, node );
2852 if( obj == NULL ) return;
2853 parentNode = GTK_CMCTREE_ROW(node)->parent;
2855 ds = addressbook_find_datasource( node );
2856 if( ds == NULL ) return;
2858 if( obj->type == ADDR_DATASOURCE ) {
2859 name = addressbook_edit_datasource( obj, node );
2860 if( name == NULL ) return;
2862 else {
2863 abf = ds->rawDataSource;
2864 if( abf == NULL ) return;
2865 if( obj->type == ADDR_ITEM_FOLDER ) {
2866 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2867 ItemFolder *item = adapter->itemFolder;
2868 ItemFolder *parentFolder = NULL;
2869 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2870 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2871 name = ADDRITEM_NAME(item);
2873 else if( obj->type == ADDR_ITEM_GROUP ) {
2874 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2875 ItemGroup *item = adapter->itemGroup;
2876 ItemFolder *parentFolder = NULL;
2877 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2878 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2879 name = ADDRITEM_NAME(item);
2882 if( name && parentNode ) {
2883 /* Update node in tree view */
2884 addressbook_change_node_name( node, name );
2885 gtk_sctree_sort_node(ctree, parentNode);
2886 gtk_cmctree_expand( ctree, node );
2887 gtk_sctree_select( GTK_SCTREE( ctree), node );
2891 typedef enum {
2892 ADDRTREE_DEL_NONE,
2893 ADDRTREE_DEL_DATA,
2894 ADDRTREE_DEL_FOLDER_ONLY,
2895 ADDRTREE_DEL_FOLDER_ADDR
2896 } TreeItemDelType ;
2899 * Delete an item from the tree widget.
2900 * \param data Data passed in.
2901 * \param action Action.
2902 * \param widget Widget issuing callback.
2904 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2906 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2907 GtkCMCTreeNode *node = NULL;
2908 AddressObject *obj;
2909 gchar *message;
2910 AlertValue aval;
2911 AddrBookBase *adbase;
2912 AddressCache *cache;
2913 AdapterDSource *ads = NULL;
2914 AddressInterface *iface = NULL;
2915 AddressDataSource *ds = NULL;
2916 gboolean remFlag = FALSE;
2917 TreeItemDelType delType;
2919 if( ! addrbook.treeSelected ) return;
2920 node = addrbook.treeSelected;
2921 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2923 obj = gtk_cmctree_node_get_row_data( ctree, node );
2924 cm_return_if_fail(obj != NULL);
2926 if( obj->type == ADDR_DATASOURCE ) {
2927 ads = ADAPTER_DSOURCE(obj);
2929 ds = ads->dataSource;
2930 if( ds == NULL ) return;
2932 else {
2933 /* Must be folder or something else */
2934 ds = addressbook_find_datasource( node );
2935 if( ds == NULL ) return;
2937 /* Only allow deletion from non-readOnly */
2938 iface = ds->interface;
2939 if( iface->readOnly ) {
2940 /* Allow deletion of query results */
2941 if( ! iface->externalQuery ) return;
2945 /* Confirm deletion */
2946 delType = ADDRTREE_DEL_NONE;
2947 if( obj->type == ADDR_ITEM_FOLDER ) {
2948 if( iface && iface->externalQuery ) {
2949 message = g_strdup_printf( _(
2950 "Do you want to delete the query " \
2951 "results and addresses in '%s'?" ),
2952 obj->name );
2953 aval = alertpanel( _("Delete"), message,
2954 NULL, _("_Cancel"), "edit-delete", _("D_elete"), NULL, NULL,
2955 ALERTFOCUS_SECOND );
2956 g_free(message);
2957 if( aval == G_ALERTALTERNATE ) {
2958 delType = ADDRTREE_DEL_FOLDER_ADDR;
2961 else {
2962 message = g_strdup_printf
2963 ( _( "Do you want to delete '%s'? "
2964 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2965 obj->name );
2966 aval = alertpanel( _("Delete folder"), message,
2967 NULL, _("_Cancel"), "edit-delete", _("Delete _folder only"),
2968 "edit-delete", _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2969 g_free(message);
2970 if( aval == G_ALERTALTERNATE ) {
2971 delType = ADDRTREE_DEL_FOLDER_ONLY;
2973 else if( aval == G_ALERTOTHER ) {
2974 delType = ADDRTREE_DEL_FOLDER_ADDR;
2978 else if( obj->type == ADDR_ITEM_GROUP ) {
2979 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2980 "The addresses it contains will not be lost."), obj->name);
2981 aval = alertpanel(_("Delete"), message, NULL, _("_Cancel"),
2982 "edit-delete", _("D_elete"), NULL, NULL, ALERTFOCUS_SECOND);
2983 g_free(message);
2984 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2985 } else {
2986 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2987 "The addresses it contains will be lost."), obj->name);
2988 aval = alertpanel(_("Delete"), message, NULL, _("_Cancel"),
2989 "edit-delete", _("D_elete"), NULL, NULL, ALERTFOCUS_SECOND);
2990 g_free(message);
2991 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2993 if( delType == ADDRTREE_DEL_NONE ) return;
2995 /* Proceed with deletion */
2996 if( obj->type == ADDR_DATASOURCE ) {
2997 /* Remove node from tree */
2998 gtk_cmctree_remove_node( ctree, node );
3000 if (delType == ADDRTREE_DEL_DATA &&
3001 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3002 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3004 /* Remove data source. */
3005 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3006 addrindex_free_datasource( ds );
3008 return;
3011 /* Get reference to cache */
3012 adbase = ( AddrBookBase * ) ds->rawDataSource;
3013 if( adbase == NULL ) return;
3014 cache = adbase->addressCache;
3016 /* Remove query results folder */
3017 if( iface && iface->externalQuery ) {
3018 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3019 ItemFolder *folder = adapter->itemFolder;
3021 adapter->itemFolder = NULL;
3023 g_print( "remove folder for ::%s::\n", obj->name );
3024 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3025 g_print( "-------------- remove results\n" );
3027 addrindex_remove_results( ds, folder );
3028 /* g_print( "-------------- remove node\n" ); */
3029 gtk_cmctree_remove_node( ctree, node );
3030 return;
3033 /* Code below is valid for regular address book deletion */
3034 if( obj->type == ADDR_ITEM_FOLDER ) {
3035 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3036 ItemFolder *item = adapter->itemFolder;
3038 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3039 /* Remove folder only */
3040 item = addrcache_remove_folder( cache, item );
3041 if( item ) {
3042 addritem_free_item_folder( item );
3043 addressbook_move_nodes_up( ctree, node );
3044 remFlag = TRUE;
3047 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3048 /* Remove folder and addresses */
3049 item = addrcache_remove_folder_delete( cache, item );
3050 if( item ) {
3051 addritem_free_item_folder( item );
3052 remFlag = TRUE;
3056 else if( obj->type == ADDR_ITEM_GROUP ) {
3057 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3058 ItemGroup *item = adapter->itemGroup;
3060 item = addrcache_remove_group( cache, item );
3061 if( item ) {
3062 addritem_free_item_group( item );
3063 remFlag = TRUE;
3067 if( remFlag ) {
3068 /* Remove node. */
3069 gtk_cmctree_remove_node(ctree, node );
3073 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3075 if( person && addrbook.treeSelected == addrbook.opened ) {
3076 person->status = ADD_ENTRY;
3077 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3078 addressbook_folder_refresh_one_person(
3079 GTK_CMCTREE(addrbook.clist), person );
3081 addressbook_address_list_set_focus();
3084 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3086 if( person && addrbook.treeSelected == addrbook.opened) {
3087 person->status = ADD_ENTRY;
3088 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3089 addressbook_set_clist(
3090 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3091 addrbook.opened),
3092 TRUE);
3094 addressbook_address_list_set_focus();
3098 * Label (a format string) that is used to name each folder.
3100 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3103 * Search ctree widget callback function.
3104 * \param pA Pointer to node.
3105 * \param pB Pointer to data item being sought.
3106 * \return Zero (0) if folder found.
3108 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3109 AddressObject *aoA;
3111 aoA = ( AddressObject * ) pA;
3112 if( aoA->type == ADDR_ITEM_FOLDER ) {
3113 ItemFolder *folder, *fld;
3115 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3116 folder = ( ItemFolder * ) pB;
3117 if( fld == folder ) return 0; /* Found folder */
3119 return 1;
3122 static ItemFolder * addressbook_setup_subf(
3123 AddressDataSource *ds, gchar *title,
3124 GtkCMCTreeNode *pNode )
3126 AddrBookBase *adbase;
3127 AddressCache *cache;
3128 ItemFolder *folder;
3129 GtkCMCTree *ctree;
3130 GtkCMCTreeNode *nNode;
3131 gchar *name;
3132 AddressObjectType aoType = ADDR_NONE;
3133 GList *children;
3134 /* Setup a query */
3135 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3137 if( ds && ds->type == ADDR_IF_LDAP ) {
3138 #if USE_LDAP
3139 aoType = ADDR_LDAP_QUERY;
3140 #endif
3142 else {
3143 return NULL;
3146 ctree = GTK_CMCTREE(addrbook.ctree);
3147 /* Get reference to address cache */
3148 adbase = ( AddrBookBase * ) ds->rawDataSource;
3149 cache = adbase->addressCache;
3151 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3152 GList *cur = children;
3153 for (; cur; cur = cur->next) {
3154 ItemFolder *child = (ItemFolder *) cur->data;
3155 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3156 nNode = gtk_cmctree_find_by_row_data_custom(
3157 ctree, NULL, child,
3158 addressbook_treenode_find_folder_cb );
3159 if( nNode ) {
3160 addrindex_remove_results( ds, child );
3161 while( child->listPerson ) {
3162 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3163 item = addrcache_remove_person( cache, item );
3164 if( item ) {
3165 addritem_free_item_person( item );
3166 item = NULL;
3169 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3170 addrbook.treeSelected = nNode;
3172 return child;
3177 /* Create a folder */
3178 folder = addrcache_add_new_folder( cache, NULL );
3179 name = g_strdup_printf( "%s", title );
3180 addritem_folder_set_name( folder, name );
3181 addritem_folder_set_remarks( folder, "" );
3182 g_free( name );
3184 /* Now let's see the folder */
3185 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3186 gtk_cmctree_expand( ctree, pNode );
3187 if( nNode ) {
3188 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3189 addrbook.treeSelected = nNode;
3190 return folder;
3192 return NULL;
3195 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3196 AddressObject *pobj = NULL;
3197 AddressDataSource *ds = NULL;
3198 AddressBookFile *abf = NULL;
3199 debug_print("adding address\n");
3200 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3201 if( pobj == NULL ) {
3202 debug_print("no row data\n");
3203 return;
3205 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3206 if( ds == NULL ) {
3207 debug_print("no datasource\n");
3208 return;
3211 abf = ds->rawDataSource;
3212 if( abf == NULL ) {
3213 g_print("no addressbook file\n");
3214 return;
3217 if( pobj->type == ADDR_DATASOURCE ) {
3218 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3219 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3220 ItemPerson *person;
3221 ItemFolder *folder = NULL;
3222 #ifdef USE_LDAP
3223 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3224 GtkCMCTreeNode *parentNode;
3225 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3226 if( ds == NULL ) return;
3228 /* We must have a datasource that is an external interface */
3229 if( ! ds->interface->haveLibrary ) return;
3230 if( ! ds->interface->externalQuery ) return;
3232 if( pobj->type == ADDR_ITEM_FOLDER ) {
3233 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3235 else {
3236 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3238 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3240 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3241 if (ds)
3242 abf = ds->rawDataSource;
3244 #endif
3245 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3246 addrbook.editaddress_vbox,
3247 addressbook_new_address_from_book_post_cb,
3248 TRUE );
3249 #ifdef USE_LDAP
3250 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3251 LdapServer *server = ds->rawDataSource;
3252 ldapsvr_set_modified(server, TRUE);
3253 ldapsvr_update_book(server, NULL);
3254 if (server->retVal != LDAPRC_SUCCESS) {
3255 alertpanel( _("Add address(es)"),
3256 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3257 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
3258 ALERTFOCUS_FIRST );
3259 server->retVal = LDAPRC_SUCCESS;
3260 return;
3263 #endif
3264 if (prefs_common.addressbook_use_editaddress_dialog)
3265 addressbook_new_address_from_book_post_cb( person );
3268 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3269 /* New address */
3270 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3271 ItemPerson *person;
3272 #ifdef USE_LDAP
3273 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3274 GtkCMCTreeNode *parentNode;
3275 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3276 if( ds == NULL ) return;
3278 /* We must have a datasource that is an external interface */
3279 if( ! ds->interface->haveLibrary ) return;
3280 if( ! ds->interface->externalQuery ) return;
3282 if( pobj->type == ADDR_ITEM_FOLDER ) {
3283 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3285 else {
3286 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3288 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3289 if (!folder)
3290 return;
3292 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3293 if (ds)
3294 abf = ds->rawDataSource;
3296 #endif
3297 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3298 addrbook.editaddress_vbox,
3299 addressbook_new_address_from_folder_post_cb,
3300 TRUE );
3301 #ifdef USE_LDAP
3302 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3303 LdapServer *server = ds->rawDataSource;
3304 ldapsvr_set_modified(server, TRUE);
3305 ldapsvr_update_book(server, NULL);
3306 if (server->retVal != LDAPRC_SUCCESS) {
3307 alertpanel( _("Add address(es)"),
3308 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3309 "window-close", _("_Close"), NULL, NULL, NULL, NULL, ALERTFOCUS_FIRST );
3310 return;
3313 #endif
3314 if (prefs_common.addressbook_use_editaddress_dialog)
3315 addressbook_new_address_from_folder_post_cb( person );
3317 else if( pobj->type == ADDR_ITEM_GROUP ) {
3318 /* New address in group */
3319 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3320 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3321 if (addrbook.treeSelected == addrbook.opened) {
3322 /* Change node name in tree. */
3323 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3324 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3325 addressbook_set_clist(
3326 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3327 addrbook.opened),
3328 TRUE);
3334 * Search for specified child group node in address index tree.
3335 * \param parent Parent node.
3336 * \param group Group to find.
3338 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3339 GtkCMCTreeNode *node = NULL;
3340 GtkCMCTreeRow *currRow;
3342 currRow = GTK_CMCTREE_ROW( parent );
3343 if( currRow ) {
3344 node = currRow->children;
3345 while( node ) {
3346 AddressObject *obj;
3348 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3349 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3350 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3351 if( g == group ) return node;
3353 currRow = GTK_CMCTREE_ROW(node);
3354 node = currRow->sibling;
3357 return NULL;
3360 static AddressBookFile *addressbook_get_book_file() {
3361 AddressBookFile *abf = NULL;
3362 AddressDataSource *ds = NULL;
3364 ds = addressbook_find_datasource( addrbook.treeSelected );
3365 if( ds == NULL ) return NULL;
3366 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3367 return abf;
3370 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3371 GtkCMCTreeNode *node;
3372 GtkCMCTreeRow *row;
3374 /* Remove existing folders and groups */
3375 row = GTK_CMCTREE_ROW( parent );
3376 if( row ) {
3377 while( (node = row->children) ) {
3378 gtk_cmctree_remove_node( ctree, node );
3383 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3384 GtkCMCTreeNode *parent, *child;
3385 GtkCMCTreeRow *currRow;
3386 currRow = GTK_CMCTREE_ROW( node );
3387 if( currRow ) {
3388 parent = currRow->parent;
3389 while( (child = currRow->children) ) {
3390 gtk_cmctree_move( ctree, child, parent, node );
3392 gtk_sctree_sort_node( ctree, parent );
3396 static void addressbook_edit_address_post_cb( ItemPerson *person )
3398 if( person ) {
3399 #ifdef USE_LDAP
3400 AddressBookFile *abf = addressbook_get_book_file();
3402 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3403 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3404 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3406 #endif
3407 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3408 invalidate_address_completion();
3410 addressbook_address_list_set_focus();
3413 void addressbook_address_list_set_focus( void )
3415 if (!prefs_common.addressbook_use_editaddress_dialog) {
3416 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3417 addressbook_list_menu_setup();
3421 void addressbook_address_list_disable_some_actions(void)
3423 /* disable address copy/pasting when editing contact's detail (embedded form) */
3424 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", FALSE );
3425 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", FALSE );
3426 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
3429 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3430 addressbook_edit_address(data, 0, NULL, TRUE);
3433 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3434 gboolean force_focus ) {
3435 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3436 GtkCMCTree *ctree;
3437 AddressObject *obj = NULL, *pobj = NULL;
3438 AddressDataSource *ds = NULL;
3439 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3440 gchar *name = NULL;
3441 AddressBookFile *abf = NULL;
3443 if( addrbook.listSelected == NULL ) return;
3444 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3445 cm_return_if_fail(obj != NULL);
3447 ctree = GTK_CMCTREE( addrbook.ctree );
3448 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3450 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3451 if( ds == NULL ) return;
3453 abf = addressbook_get_book_file();
3455 if( obj->type == ADDR_ITEM_EMAIL ) {
3456 ItemEMail *email = ( ItemEMail * ) obj;
3458 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3459 /* Edit parent group */
3460 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3461 ItemGroup *itemGrp = adapter->itemGroup;
3462 if( abf == NULL ) return;
3463 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3464 name = ADDRITEM_NAME(itemGrp);
3465 node = addrbook.treeSelected;
3466 parentNode = GTK_CMCTREE_ROW(node)->parent;
3468 else {
3469 /* Edit person - email page */
3470 ItemPerson *person;
3471 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3472 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3473 addressbook_edit_address_post_cb,
3474 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3475 != NULL ) {
3476 #ifdef USE_LDAP
3477 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3478 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3479 person->status = UPDATE_ENTRY;
3481 #endif
3482 if (prefs_common.addressbook_use_editaddress_dialog)
3483 addressbook_edit_address_post_cb( person );
3485 return;
3488 else if( obj->type == ADDR_ITEM_PERSON ) {
3489 /* Edit person - basic page */
3490 ItemPerson *person = ( ItemPerson * ) obj;
3491 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3492 addressbook_edit_address_post_cb,
3493 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3494 != NULL ) {
3495 #ifdef USE_LDAP
3496 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3497 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3498 person->status = UPDATE_ENTRY;
3500 #endif
3501 if (prefs_common.addressbook_use_editaddress_dialog)
3502 addressbook_edit_address_post_cb( person );
3504 return;
3506 else if( obj->type == ADDR_ITEM_GROUP ) {
3507 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3508 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3509 parentNode = addrbook.treeSelected;
3510 node = addressbook_find_group_node( parentNode, itemGrp );
3511 name = ADDRITEM_NAME(itemGrp);
3512 invalidate_address_completion();
3514 else {
3515 return;
3518 /* Update tree node with node name */
3519 if( node == NULL ) return;
3520 addressbook_change_node_name( node, name );
3521 gtk_sctree_sort_node( ctree, parentNode );
3522 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3523 addressbook_set_clist(
3524 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3525 addrbook.opened),
3526 TRUE);
3529 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3531 addressbook_del_clicked(NULL, NULL);
3534 static void close_cb(GtkAction *action, gpointer data)
3536 addressbook_close();
3539 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3540 addressbook_export_to_file();
3543 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3544 if( node ) {
3545 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3546 if( person ) addritem_person_set_opened( person, TRUE );
3550 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3551 if( node ) {
3552 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3553 if( person ) addritem_person_set_opened( person, FALSE );
3557 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3558 gchar *str = NULL;
3559 gchar *eMailAlias = ADDRITEM_NAME(email);
3560 if( eMailAlias && *eMailAlias != '\0' ) {
3561 if( person ) {
3562 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3564 else {
3565 str = g_strdup( eMailAlias );
3568 return str;
3571 static gboolean addressbook_match_item(const gchar *name,
3572 const gchar *email_alias,
3573 const gchar *addr,
3574 const gchar *remarks,
3575 const gchar *str)
3577 if (!name)
3578 return FALSE;
3579 if (!str || str[0] == '\0')
3580 return TRUE;
3581 if (strcasestr(name, str))
3582 return TRUE;
3583 else if (email_alias && strcasestr(email_alias, str))
3584 return TRUE;
3585 else if (addr && strcasestr(addr, str))
3586 return TRUE;
3587 else if (remarks && strcasestr(remarks, str))
3588 return TRUE;
3590 return FALSE;
3593 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3594 GList *items = itemGroup->listEMail;
3595 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3596 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3597 for( ; items != NULL; items = g_list_next( items ) ) {
3598 GtkCMCTreeNode *nodeEMail = NULL;
3599 gchar *text[N_LIST_COLS];
3600 ItemEMail *email = items->data;
3601 ItemPerson *person;
3602 gchar *str = NULL;
3604 if( ! email ) continue;
3606 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3608 if( !addressbook_match_item(ADDRITEM_NAME(person),
3609 ADDRITEM_NAME(email),
3610 email->address, email->remarks,
3611 search_str))
3612 continue;
3614 str = addressbook_format_item_clist( person, email );
3615 if( str ) {
3616 text[COL_NAME] = addressbook_set_col_name_guard(str);
3618 else {
3619 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3621 text[COL_ADDRESS] = email->address;
3622 text[COL_REMARKS] = email->remarks;
3623 nodeEMail = gtk_sctree_insert_node(
3624 clist, NULL, NULL,
3625 text, FOLDER_SPACING,
3626 atci->iconXpm,
3627 atci->iconXpmOpen,
3628 FALSE, FALSE );
3629 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3630 g_free( str );
3631 str = NULL;
3635 gchar *addressbook_set_col_name_guard(gchar *value)
3637 gchar *ret = "<not set>";
3638 gchar *tmp = g_strdup(value);
3639 if (tmp) {
3640 g_strstrip(tmp);
3641 if (*tmp != '\0')
3642 ret = value;
3643 g_free(tmp);
3645 return ret;
3648 static void addressbook_folder_load_one_person(
3649 GtkCMCTree *clist, ItemPerson *person,
3650 AddressTypeControlItem *atci,
3651 AddressTypeControlItem *atciMail )
3653 GtkCMCTreeNode *nodePerson = NULL;
3654 GtkCMCTreeNode *nodeEMail = NULL;
3655 gchar *text[N_LIST_COLS];
3656 gboolean flgFirst = TRUE, haveAddr = FALSE;
3657 GList *node;
3658 #ifdef USE_LDAP
3659 AddressBookFile *abf = addressbook_get_book_file();
3660 #endif
3662 if( person == NULL ) return;
3664 text[COL_NAME] = "";
3665 node = person->listEMail;
3666 while( node ) {
3667 ItemEMail *email = node->data;
3668 gchar *eMailAddr = NULL;
3669 node = g_list_next( node );
3671 text[COL_ADDRESS] = email->address;
3672 text[COL_REMARKS] = email->remarks;
3673 eMailAddr = ADDRITEM_NAME(email);
3674 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3675 if( flgFirst ) {
3676 /* First email belongs with person */
3677 gchar *str = addressbook_format_item_clist( person, email );
3678 if( str ) {
3679 text[COL_NAME] = addressbook_set_col_name_guard(str);
3681 #ifdef USE_LDAP
3682 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3683 person && person->nickName ) {
3684 if (person->nickName) {
3685 if (strcmp(person->nickName, "") != 0) {
3686 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3688 else {
3689 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3693 #endif
3694 else {
3695 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3697 nodePerson = gtk_sctree_insert_node(
3698 clist, NULL, NULL,
3699 text, FOLDER_SPACING,
3700 atci->iconXpm,
3701 atci->iconXpmOpen,
3702 FALSE, person->isOpened );
3703 g_free( str );
3704 str = NULL;
3705 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3707 else {
3708 /* Subsequent email is a child node of person */
3709 text[COL_NAME] = ADDRITEM_NAME(email);
3710 nodeEMail = gtk_sctree_insert_node(
3711 clist, nodePerson, NULL,
3712 text, FOLDER_SPACING,
3713 atciMail->iconXpm,
3714 atciMail->iconXpmOpen,
3715 FALSE, TRUE );
3716 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3718 flgFirst = FALSE;
3719 haveAddr = TRUE;
3721 if( ! haveAddr ) {
3722 /* Have name without EMail */
3723 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3724 text[COL_ADDRESS] = "";
3725 text[COL_REMARKS] = "";
3726 nodePerson = gtk_sctree_insert_node(
3727 clist, NULL, NULL,
3728 text, FOLDER_SPACING,
3729 atci->iconXpm,
3730 atci->iconXpmOpen,
3731 FALSE, person->isOpened );
3732 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3734 return;
3737 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3738 GList *items, *cur;
3739 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3740 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3741 const gchar *search_str;
3743 if( atci == NULL ) return;
3744 if( atciMail == NULL ) return;
3746 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3748 /* Load email addresses */
3749 items = addritem_folder_get_person_list( itemFolder );
3750 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3751 ItemPerson *person;
3752 GList *node;
3753 ItemEMail *email;
3755 person = (ItemPerson *)cur->data;
3756 if (!person)
3757 continue;
3758 node = person->listEMail;
3759 if (node && node->data) {
3760 email = node->data;
3761 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3762 continue;
3763 } else {
3764 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3765 continue;
3768 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3770 /* Free up the list */
3771 g_list_free( items );
3774 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3775 addrbook.listSelected = NULL;
3776 gtk_cmctree_remove_node( clist, node );
3777 addressbook_menubar_set_sensitive( FALSE );
3778 addressbook_menuitem_set_sensitive(
3779 gtk_cmctree_node_get_row_data(
3780 GTK_CMCTREE(clist), addrbook.treeSelected ),
3781 addrbook.treeSelected );
3784 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3785 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3786 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3787 GtkCMCTreeNode *node;
3788 if( atci == NULL ) return;
3789 if( atciMail == NULL ) return;
3790 if( person == NULL ) return;
3791 /* unload the person */
3793 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3794 if( node )
3795 addressbook_folder_remove_node( clist, node );
3796 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3797 gtk_sctree_sort_node( clist, NULL );
3798 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3799 if( node ) {
3800 gtk_sctree_select( GTK_SCTREE(clist), node );
3801 if (!gtk_cmctree_node_is_visible( clist, node ) )
3802 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3806 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3807 GtkCMCTreeNode *node;
3809 if( person == NULL ) return;
3810 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3811 if( node ) {
3812 addressbook_folder_remove_node( clist, node );
3816 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3817 GList *items;
3818 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3819 const gchar *search_str;
3821 /* Load any groups */
3822 if( ! atci ) return;
3824 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3826 items = addritem_folder_get_group_list( itemFolder );
3827 for( ; items != NULL; items = g_list_next( items ) ) {
3828 GtkCMCTreeNode *nodeGroup = NULL;
3829 gchar *text[N_LIST_COLS];
3830 ItemGroup *group = items->data;
3831 if( group == NULL ) continue;
3832 if( !addressbook_match_item(ADDRITEM_NAME(group),
3833 NULL, NULL, NULL, search_str) )
3834 continue;
3836 text[COL_NAME] = ADDRITEM_NAME(group);
3837 text[COL_ADDRESS] = "";
3838 text[COL_REMARKS] = "";
3839 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3840 text, FOLDER_SPACING,
3841 atci->iconXpm,
3842 atci->iconXpmOpen,
3843 FALSE, FALSE);
3844 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3845 gtk_sctree_sort_node(clist, NULL);
3847 /* Free up the list */
3848 g_list_free( items );
3852 * Search ctree widget callback function.
3853 * \param pA Pointer to node.
3854 * \param pB Pointer to data item being sought.
3855 * \return Zero (0) if group found.
3857 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3858 AddressObject *aoA;
3860 aoA = ( AddressObject * ) pA;
3861 if( aoA->type == ADDR_ITEM_GROUP ) {
3862 ItemGroup *group, *grp;
3864 grp = ADAPTER_GROUP(aoA)->itemGroup;
3865 group = ( ItemGroup * ) pB;
3866 if( grp == group ) return 0; /* Found group */
3868 return 1;
3872 * Remove folder and group nodes from tree widget for items contained ("cut")
3873 * in clipboard.
3875 static void addressbook_treenode_remove_item( void ) {
3876 GList *node;
3877 AddrSelectItem *cutItem;
3878 AddressCache *cache;
3879 AddrItemObject *aio;
3880 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3881 GtkCMCTreeNode *tn;
3883 node = _clipBoard_->objectList;
3884 while( node ) {
3885 cutItem = node->data;
3886 node = g_list_next( node );
3887 cache = addrindex_get_cache(
3888 _clipBoard_->addressIndex, cutItem->cacheID );
3889 if( cache == NULL ) continue;
3890 aio = addrcache_get_object( cache, cutItem->uid );
3891 if( aio ) {
3892 tn = NULL;
3893 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3894 ItemFolder *folder;
3896 folder = ( ItemFolder * ) aio;
3897 tn = gtk_cmctree_find_by_row_data_custom(
3898 ctree, NULL, folder,
3899 addressbook_treenode_find_folder_cb );
3901 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3902 ItemGroup *group;
3904 group = ( ItemGroup * ) aio;
3905 tn = gtk_cmctree_find_by_row_data_custom(
3906 ctree, NULL, group,
3907 addressbook_treenode_find_group_cb );
3910 if( tn ) {
3911 /* Free up adapter and remove node. */
3912 gtk_cmctree_remove_node( ctree, tn );
3919 * Find parent datasource for specified tree node.
3920 * \param node Node to test.
3921 * \return Data source, or NULL if not found.
3923 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3924 AddressDataSource *ds = NULL;
3925 AddressObject *ao;
3927 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3929 while( node ) {
3930 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3931 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3932 if( ao ) {
3933 /* g_print( "ao->type = %d\n", ao->type ); */
3934 if( ao->type == ADDR_DATASOURCE ) {
3935 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3936 /* g_print( "found it\n" ); */
3937 ds = ads->dataSource;
3938 break;
3941 node = GTK_CMCTREE_ROW(node)->parent;
3943 return ds;
3947 * Load address list widget with children of specified object.
3948 * \param obj Parent object to be loaded.
3950 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3951 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3952 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3953 AddressDataSource *ds = NULL;
3954 AdapterDSource *ads = NULL;
3955 static AddressObject *last_obj = NULL;
3957 if (addrbook.clist == NULL) {
3958 return;
3960 if (obj == last_obj && !refresh)
3961 return;
3963 last_obj = obj;
3964 if( obj == NULL ) {
3965 gtk_cmclist_clear(clist);
3966 return;
3969 if( obj->type == ADDR_INTERFACE ) {
3970 /* g_print( "set_clist: loading datasource...\n" ); */
3971 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3972 return;
3975 gtk_cmclist_freeze(clist);
3976 gtk_cmclist_clear(clist);
3978 if( obj->type == ADDR_DATASOURCE ) {
3979 ads = ADAPTER_DSOURCE(obj);
3980 ds = ads->dataSource;
3981 if( ds ) {
3982 /* Load root folder */
3983 ItemFolder *rootFolder = NULL;
3984 rootFolder = addrindex_ds_get_root_folder( ds );
3985 addressbook_folder_load_person(
3986 ctreelist, rootFolder );
3987 addressbook_folder_load_group(
3988 ctreelist, rootFolder );
3991 else {
3992 if( obj->type == ADDR_ITEM_GROUP ) {
3993 /* Load groups */
3994 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3995 addressbook_load_group( ctreelist, itemGroup );
3997 else if( obj->type == ADDR_ITEM_FOLDER ) {
3998 /* Load folders */
3999 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4000 addressbook_folder_load_person( ctreelist, itemFolder );
4001 addressbook_folder_load_group( ctreelist, itemFolder );
4004 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4005 clist->focus_row = -1;
4006 gtk_cmclist_thaw(clist);
4010 * Call back function to free adaptor. Call back is setup by function
4011 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4012 * called when the address book tree widget node is removed by calling
4013 * function gtk_cmctree_remove_node().
4015 * \param data Tree node's row data.
4017 static void addressbook_free_treenode( gpointer data ) {
4018 AddressObject *ao;
4020 ao = ( AddressObject * ) data;
4021 if( ao == NULL ) return;
4022 if( ao->type == ADDR_INTERFACE ) {
4023 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4024 addrbookctl_free_interface( ai );
4026 else if( ao->type == ADDR_DATASOURCE ) {
4027 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4028 addrbookctl_free_datasource( ads );
4030 else if( ao->type == ADDR_ITEM_FOLDER ) {
4031 AdapterFolder *af = ADAPTER_FOLDER(ao);
4032 addrbookctl_free_folder( af );
4034 else if( ao->type == ADDR_ITEM_GROUP ) {
4035 AdapterGroup *ag = ADAPTER_GROUP(ao);
4036 addrbookctl_free_group( ag );
4041 * Create new adaptor for specified data source.
4043 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4044 AddressObjectType otype, gchar *name )
4046 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4047 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4048 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4049 adapter->dataSource = ds;
4050 adapter->subType = otype;
4051 return adapter;
4054 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4055 ADDRESS_OBJECT_NAME(adapter) =
4056 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4060 * Load tree from address index with the initial data.
4062 static void addressbook_load_tree( void ) {
4063 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4064 GList *nodeIf, *nodeDS;
4065 AdapterInterface *adapter;
4066 AddressInterface *iface;
4067 AddressTypeControlItem *atci;
4068 AddressDataSource *ds;
4069 AdapterDSource *ads;
4070 GtkCMCTreeNode *node, *newNode;
4071 gchar *name;
4073 nodeIf = _addressInterfaceList_;
4074 while( nodeIf ) {
4075 adapter = nodeIf->data;
4076 node = adapter->treeNode;
4077 iface = adapter->interface;
4078 atci = adapter->atci;
4079 if( iface ) {
4080 if( iface->useInterface ) {
4081 /* Load data sources below interface node */
4082 nodeDS = iface->listSource;
4083 while( nodeDS ) {
4084 ds = nodeDS->data;
4085 name = addrindex_ds_get_name( ds );
4086 ads = addressbook_create_ds_adapter(
4087 ds, atci->objectType, name );
4088 newNode = addressbook_add_object(
4089 node, ADDRESS_OBJECT(ads) );
4090 if (newNode == NULL) {
4091 g_message("error adding addressbook object\n");
4093 nodeDS = g_list_next( nodeDS );
4095 gtk_cmctree_expand( ctree, node );
4098 nodeIf = g_list_next( nodeIf );
4103 * Convert the old address book to new format.
4105 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4106 gboolean retVal = FALSE;
4107 gboolean errFlag = TRUE;
4108 gchar *msg = NULL;
4110 /* Read old address book, performing conversion */
4111 debug_print( "Reading and converting old address book...\n" );
4112 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4113 addrindex_read_data( addrIndex );
4114 if( addrIndex->retVal == MGU_NO_FILE ) {
4115 /* We do not have a file - new user */
4116 debug_print( "New user... create new books...\n" );
4117 addrindex_create_new_books( addrIndex );
4118 if( addrIndex->retVal == MGU_SUCCESS ) {
4119 /* Save index file */
4120 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4121 addrindex_save_data( addrIndex );
4122 if( addrIndex->retVal == MGU_SUCCESS ) {
4123 retVal = TRUE;
4124 errFlag = FALSE;
4126 else {
4127 msg = _( "New user, could not save index file." );
4130 else {
4131 msg = _( "New user, could not save address book files." );
4134 else {
4135 /* We have an old file */
4136 if( addrIndex->wasConverted ) {
4137 /* Converted successfully - save address index */
4138 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4139 addrindex_save_data( addrIndex );
4140 if( addrIndex->retVal == MGU_SUCCESS ) {
4141 msg = _( "Old address book converted successfully." );
4142 retVal = TRUE;
4143 errFlag = FALSE;
4145 else {
4146 msg = _("Old address book converted,\n"
4147 "could not save new address index file." );
4150 else {
4151 /* File conversion failed - just create new books */
4152 debug_print( "File conversion failed... just create new books...\n" );
4153 addrindex_create_new_books( addrIndex );
4154 if( addrIndex->retVal == MGU_SUCCESS ) {
4155 /* Save index */
4156 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4157 addrindex_save_data( addrIndex );
4158 if( addrIndex->retVal == MGU_SUCCESS ) {
4159 msg = _("Could not convert address book,\n"
4160 "but created empty new address book files." );
4161 retVal = TRUE;
4162 errFlag = FALSE;
4164 else {
4165 msg = _("Could not convert address book,\n"
4166 "could not save new address index file." );
4169 else {
4170 msg = _("Could not convert address book\n"
4171 "and could not create new address book files." );
4175 if (errFlag) {
4176 debug_print( "Error\n%s\n", msg );
4177 alertpanel_full(_("Addressbook conversion error"), msg,
4178 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
4179 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_ERROR);
4180 } else if (msg) {
4181 debug_print( "Warning\n%s\n", msg );
4182 alertpanel_full(_("Addressbook conversion error"), msg,
4183 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
4184 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING);
4187 return retVal;
4190 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4192 GDir *dp;
4193 const gchar *d;
4194 gboolean failed = FALSE;
4195 GError *error = NULL;
4197 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4198 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4199 error->code, error->message);
4200 g_error_free(error);
4201 return FALSE;
4204 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4205 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4206 continue;
4207 else {
4208 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4209 d, NULL);
4210 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4211 d, NULL);
4212 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4213 failed = TRUE;
4215 g_free(orig_file);
4216 g_free(dest_file);
4217 if (failed) {
4218 break;
4222 g_dir_close( dp );
4224 if (!failed) {
4225 /* all copies succeeded, we can remove source files */
4226 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4227 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4228 error->code, error->message);
4229 g_error_free(error);
4230 return FALSE;
4232 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4233 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4234 continue;
4235 else {
4236 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4237 d, NULL);
4238 claws_unlink(orig_file);
4239 g_free(orig_file);
4242 g_dir_close( dp );
4245 return !failed;
4248 void addressbook_read_file( void ) {
4249 AddressIndex *addrIndex = NULL;
4250 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4252 debug_print( "Reading address index...\n" );
4253 if( _addressIndex_ ) {
4254 debug_print( "address book already read!!!\n" );
4255 g_free(indexdir);
4256 return;
4259 addrIndex = addrindex_create_index();
4260 addrindex_initialize();
4262 /* Use new address book index. */
4264 if ( !is_dir_exist(indexdir) ) {
4265 if ( make_dir(indexdir) < 0 ) {
4266 addrindex_set_file_path( addrIndex, get_rc_dir() );
4267 g_warning("couldn't create dir '%s'", indexdir);
4268 } else {
4269 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4270 remove_dir_recursive(indexdir);
4271 addrindex_set_file_path( addrIndex, get_rc_dir() );
4272 g_error("couldn't migrate dir %s", indexdir);
4273 } else {
4274 addrindex_set_file_path( addrIndex, indexdir);
4277 } else {
4278 addrindex_set_file_path( addrIndex, indexdir);
4280 g_free(indexdir);
4281 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4282 addrindex_read_data( addrIndex );
4283 if( addrIndex->retVal == MGU_NO_FILE ) {
4284 /* Conversion required */
4285 debug_print( "Converting...\n" );
4286 if( addressbook_convert( addrIndex ) ) {
4287 _addressIndex_ = addrIndex;
4290 else if( addrIndex->retVal == MGU_SUCCESS ) {
4291 _addressIndex_ = addrIndex;
4293 else {
4294 /* Error reading address book */
4295 debug_print( "Could not read address index.\n" );
4296 addrindex_print_index( addrIndex, stdout );
4297 alertpanel_full(_("Addressbook Error"),
4298 _("Could not read address index"),
4299 "window-close", _("_Close"), NULL, NULL, NULL, NULL,
4300 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_ERROR);
4302 debug_print( "done.\n" );
4306 * Add object into the address index tree widget.
4307 * Enter: node Parent node.
4308 * obj Object to add.
4309 * Return: Node that was added, or NULL if object not added.
4311 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4312 AddressObject *obj)
4314 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4315 GtkCMCTreeNode *added;
4316 AddressObject *pobj;
4317 AddressObjectType otype;
4318 AddressTypeControlItem *atci = NULL;
4320 cm_return_val_if_fail(node != NULL, NULL);
4321 cm_return_val_if_fail(obj != NULL, NULL);
4323 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4324 cm_return_val_if_fail(pobj != NULL, NULL);
4326 /* Determine object type to be displayed */
4327 if( obj->type == ADDR_DATASOURCE ) {
4328 otype = ADAPTER_DSOURCE(obj)->subType;
4330 else {
4331 otype = obj->type;
4334 /* Handle any special conditions. */
4335 added = node;
4336 atci = addrbookctl_lookup( otype );
4337 if( atci ) {
4338 if( atci->showInTree ) {
4339 /* Add object to tree */
4340 gchar **name;
4341 name = &obj->name;
4342 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4343 atci->iconXpm, atci->iconXpmOpen,
4344 atci->treeLeaf, atci->treeExpand );
4345 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4346 addressbook_free_treenode );
4350 gtk_sctree_sort_node(ctree, node);
4352 return added;
4356 * Add group into the address index tree.
4357 * \param node Parent node.
4358 * \param ds Data source.
4359 * \param itemGroup Group to add.
4360 * \return Inserted node.
4362 static GtkCMCTreeNode *addressbook_node_add_group(
4363 GtkCMCTreeNode *node, AddressDataSource *ds,
4364 ItemGroup *itemGroup )
4366 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4367 GtkCMCTreeNode *newNode;
4368 AdapterGroup *adapter;
4369 AddressTypeControlItem *atci = NULL;
4370 gchar **name;
4372 if( ds == NULL ) return NULL;
4373 if( node == NULL || itemGroup == NULL ) return NULL;
4375 name = &itemGroup->obj.name;
4377 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4379 adapter = g_new0( AdapterGroup, 1 );
4380 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4381 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4382 adapter->itemGroup = itemGroup;
4384 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4385 atci->iconXpm, atci->iconXpm,
4386 atci->treeLeaf, atci->treeExpand );
4387 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4388 addressbook_free_treenode );
4389 gtk_sctree_sort_node( ctree, node );
4390 return newNode;
4394 * Add folder into the address index tree. Only visible folders are loaded into
4395 * the address index tree. Note that the root folder is not inserted into the
4396 * tree.
4398 * \param node Parent node.
4399 * \param ds Data source.
4400 * \param itemFolder Folder to add.
4401 * \param otype Object type to display.
4402 * \return Inserted node for the folder.
4404 static GtkCMCTreeNode *addressbook_node_add_folder(
4405 GtkCMCTreeNode *node, AddressDataSource *ds,
4406 ItemFolder *itemFolder, AddressObjectType otype )
4408 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4409 GtkCMCTreeNode *newNode = NULL;
4410 AddressTypeControlItem *atci = NULL;
4411 GList *listItems = NULL;
4412 gchar *name;
4413 ItemFolder *rootFolder;
4415 /* Only visible folders */
4416 if( itemFolder == NULL || itemFolder->isHidden )
4417 return NULL;
4419 if( ds == NULL )
4420 return NULL;
4421 if( node == NULL || itemFolder == NULL )
4422 return NULL;
4424 /* Determine object type */
4425 atci = addrbookctl_lookup( otype );
4426 if( atci == NULL )
4427 return NULL;
4429 rootFolder = addrindex_ds_get_root_folder( ds );
4430 if( itemFolder == rootFolder ) {
4431 newNode = node;
4433 else {
4434 AdapterFolder *adapter = g_new0( AdapterFolder, 1 );
4435 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4436 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4437 adapter->itemFolder = itemFolder;
4439 name = ADDRITEM_NAME(itemFolder);
4440 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4441 atci->iconXpm, atci->iconXpm,
4442 atci->treeLeaf, atci->treeExpand );
4443 if( newNode ) {
4444 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4445 addressbook_free_treenode );
4446 } else {
4447 addrbookctl_free_folder(adapter);
4451 listItems = itemFolder->listFolder;
4452 while( listItems ) {
4453 ItemFolder *item = listItems->data;
4454 addressbook_node_add_folder( newNode, ds, item, otype );
4455 listItems = g_list_next( listItems );
4457 listItems = itemFolder->listGroup;
4458 while( listItems ) {
4459 ItemGroup *item = listItems->data;
4460 addressbook_node_add_group( newNode, ds, item );
4461 listItems = g_list_next( listItems );
4463 gtk_sctree_sort_node( ctree, node );
4464 return newNode;
4467 void addressbook_export_to_file( void ) {
4468 if( _addressIndex_ ) {
4469 /* Save all new address book data */
4470 debug_print( "Saving address books...\n" );
4471 addrindex_save_all_books( _addressIndex_ );
4473 debug_print( "Exporting addressbook to file...\n" );
4474 addrindex_save_data( _addressIndex_ );
4475 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4476 addrindex_print_index( _addressIndex_, stdout );
4479 /* Notify address completion of new data */
4480 invalidate_address_completion();
4484 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4486 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4487 addressbook_lup_clicked(NULL, NULL);
4488 return FALSE;
4492 * Comparison using cell contents (text in first column). Used for sort
4493 * address index widget.
4495 static gint addressbook_treenode_compare_func(
4496 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4498 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4499 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4500 gchar *name1 = NULL, *name2 = NULL;
4501 if( cell1 ) name1 = cell1->u.text;
4502 if( cell2 ) name2 = cell2->u.text;
4503 if( ! name1 ) return ( name2 != NULL );
4504 if( ! name2 ) return -1;
4505 return g_utf8_collate( name1, name2 );
4508 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4509 AdapterDSource *ads;
4510 AdapterInterface *adapter;
4511 GtkCMCTreeNode *newNode;
4513 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4514 if( adapter == NULL ) return;
4515 ads = addressbook_edit_book( _addressIndex_, NULL );
4516 if( ads ) {
4517 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4518 if( newNode ) {
4519 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4520 addrbook.treeSelected = newNode;
4525 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4526 AdapterDSource *ads;
4527 AdapterInterface *adapter;
4528 GtkCMCTreeNode *newNode;
4530 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4531 if( adapter == NULL ) return;
4532 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4533 if( ads ) {
4534 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4535 if( newNode ) {
4536 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4537 addrbook.treeSelected = newNode;
4542 #ifdef USE_JPILOT
4543 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4544 AdapterDSource *ads;
4545 AdapterInterface *adapter;
4546 AddressInterface *iface;
4547 GtkCMCTreeNode *newNode;
4549 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4550 if( adapter == NULL ) return;
4551 iface = adapter->interface;
4552 if( ! iface->haveLibrary ) return;
4553 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4554 if( ads ) {
4555 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4556 if( newNode ) {
4557 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4558 addrbook.treeSelected = newNode;
4562 #endif
4564 #ifdef USE_LDAP
4565 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4566 AdapterDSource *ads;
4567 AdapterInterface *adapter;
4568 AddressInterface *iface;
4569 GtkCMCTreeNode *newNode;
4571 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4572 if( adapter == NULL ) return;
4573 iface = adapter->interface;
4574 if( ! iface->haveLibrary ) return;
4575 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4576 if( ads ) {
4577 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4578 if( newNode ) {
4579 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4580 addrbook.treeSelected = newNode;
4584 #endif
4587 * Display address search status message.
4588 * \param queryType Query type.
4589 * \param status Status/Error code.
4591 static void addressbook_search_message( gint queryType, gint sts ) {
4592 gchar *desc = NULL;
4593 *addressbook_msgbuf = '\0';
4595 if( sts != MGU_SUCCESS ) {
4596 if( queryType == ADDRQUERY_LDAP ) {
4597 #ifdef USE_LDAP
4598 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4599 #endif
4602 if( desc ) {
4603 g_snprintf( addressbook_msgbuf,
4604 sizeof(addressbook_msgbuf), "%s", desc );
4605 addressbook_status_show( addressbook_msgbuf );
4607 else {
4608 addressbook_status_show( "" );
4613 * Refresh addressbook by forcing refresh of current selected object in
4614 * tree.
4616 static void addressbook_refresh_current( void ) {
4617 AddressObject *obj;
4618 GtkCMCTree *ctree;
4620 ctree = GTK_CMCTREE(addrbook.ctree);
4621 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4622 if( obj == NULL ) return;
4623 addressbook_set_clist( obj, TRUE );
4627 * Message that is displayed whilst a query is executing in a background
4628 * thread.
4630 static gchar *_tempMessage_ = N_( "Busy searching..." );
4633 * Address search idle function. This function is called during UI idle time
4634 * while a search is in progress.
4636 * \param data Idler data.
4638 static void addressbook_search_idle( gpointer data ) {
4640 gint queryID;
4642 queryID = GPOINTER_TO_INT( data );
4643 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4648 * Search completion callback function. This removes the query from the idle
4649 * list.
4651 * \param sender Sender of query.
4652 * \param queryID Query ID of search request.
4653 * \param status Search status.
4654 * \param data Query data.
4656 static void addressbook_search_callback_end(
4657 gpointer sender, gint queryID, gint status, gpointer data )
4659 gpointer ptrQID;
4660 QueryRequest *req;
4661 AddrQueryObject *aqo;
4663 /* Remove idler function */
4664 ptrQID = GINT_TO_POINTER( queryID );
4665 if( ptrQID ) {
4666 g_idle_remove_by_data( ptrQID );
4669 /* Refresh addressbook contents */
4670 addressbook_refresh_current();
4671 req = qrymgr_find_request( queryID );
4672 if( req != NULL ) {
4673 aqo = ( AddrQueryObject * ) req->queryList->data;
4674 addressbook_search_message( aqo->queryType, status );
4677 /* Stop the search */
4678 addrindex_stop_search( queryID );
4682 * Perform search.
4684 * \param ds Data source to search.
4685 * \param searchTerm String to lookup.
4686 * \param pNode Parent data source node.
4688 static void addressbook_perform_search(
4689 AddressDataSource *ds, gchar *searchTerm,
4690 GtkCMCTreeNode *pNode )
4692 ItemFolder *folder;
4693 gchar *name;
4694 gint queryID;
4695 guint idleID;
4697 /* Setup a query */
4698 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4700 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4702 /* Create a folder for the search results */
4703 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4704 folder = addressbook_setup_subf(ds, name, pNode);
4705 g_free( name );
4707 /* Setup the search */
4708 queryID = addrindex_setup_explicit_search(
4709 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4710 if( queryID == 0 ) return;
4712 /* Set up idler function */
4713 idleID = g_idle_add(
4714 (GSourceFunc) addressbook_search_idle,
4715 GINT_TO_POINTER( queryID ) );
4716 if (idleID == 0) {
4717 g_message("error adding addressbook_search_idle\n");
4720 /* Start search, sit back and wait for something to happen */
4721 addrindex_start_search( queryID );
4723 addressbook_status_show( _tempMessage_ );
4727 * Lookup button handler. Address search is only performed against
4728 * address interfaces for external queries.
4730 * \param button Lookup button widget.
4731 * \param data Data object.
4733 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4734 GtkCMCTree *ctree;
4735 AddressObject *obj;
4736 AddressDataSource *ds;
4737 AddressInterface *iface;
4738 gchar *searchTerm;
4739 GtkCMCTreeNode *node, *parentNode;
4740 #ifdef USE_LDAP
4741 LdapServer *ldap_server;
4742 LdapControl *ldap_ctl;
4743 #endif
4745 node = addrbook.treeSelected;
4746 if( ! node ) return;
4747 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4749 ctree = GTK_CMCTREE(addrbook.ctree);
4750 obj = gtk_cmctree_node_get_row_data( ctree, node );
4751 if( obj == NULL ) return;
4753 if (obj->type != ADDR_DATASOURCE ||
4754 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4755 addressbook_set_clist(
4756 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4757 addrbook.treeSelected),
4758 TRUE);
4761 ds = addressbook_find_datasource( node );
4762 if( ds == NULL ) return;
4764 /* We must have a datasource that is an external interface */
4765 iface = ds->interface;
4766 if( ! iface->haveLibrary ) return;
4767 if( ! iface->externalQuery ) return;
4769 #ifdef USE_LDAP
4770 if (iface->type == ADDR_IF_LDAP) {
4771 ldap_server = ds->rawDataSource;
4772 ldap_ctl = ldap_server->control;
4773 if (ldap_ctl != NULL &&
4774 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4775 #ifndef PASSWORD_CRYPTO_OLD
4776 /* LDAP server is password-protected. */
4777 if (primary_passphrase() == NULL) {
4778 /* User did not enter primary passphrase, do not start a search. */
4779 return;
4781 #endif /* PASSWORD_CRYPTO_OLD */
4784 #endif /* USE_LDAP */
4786 searchTerm =
4787 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4788 g_strchomp( searchTerm );
4790 if( obj->type == ADDR_ITEM_FOLDER ) {
4791 parentNode = GTK_CMCTREE_ROW(node)->parent;
4793 else {
4794 parentNode = node;
4796 addressbook_perform_search( ds, searchTerm, parentNode );
4798 gtk_widget_grab_focus( addrbook.entry );
4800 g_free( searchTerm );
4803 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4804 addressbook_close();
4807 #ifdef USE_LDAP
4809 * Browse address entry for highlighted entry.
4811 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4813 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4814 AddressObject *obj;
4815 AddressDataSource *ds;
4816 AddressInterface *iface;
4817 ItemPerson *person;
4818 ItemEMail *email;
4820 if(addrbook.listSelected == NULL)
4821 return;
4823 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4824 if (obj == NULL)
4825 return;
4827 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4828 if(ds == NULL)
4829 return;
4831 iface = ds->interface;
4832 if(!iface || !iface->haveLibrary )
4833 return;
4835 person = NULL;
4836 if (obj->type == ADDR_ITEM_EMAIL) {
4837 email = ( ItemEMail * ) obj;
4839 person = (ItemPerson *) ADDRITEM_PARENT(email);
4841 else if (obj->type == ADDR_ITEM_PERSON) {
4842 person = (ItemPerson *) obj;
4844 else {
4845 /* None of these */
4846 return;
4849 if( iface && iface->type == ADDR_IF_LDAP ) {
4850 browseldap_entry(ds, person->externalID);
4853 #endif
4855 /* **********************************************************************
4856 * Build lookup tables.
4857 * ***********************************************************************
4861 * Remap object types.
4862 * Enter: abType AddressObjectType (used in tree node).
4863 * Return: ItemObjectType (used in address cache data).
4865 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4866 ItemObjectType ioType;
4868 switch( abType ) {
4869 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4870 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4871 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4872 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4873 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4874 default: ioType = ITEMTYPE_NONE; break;
4876 return ioType;
4879 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4880 atci = addrbookctl_lookup(id); \
4881 if (atci) { \
4882 atci->iconXpm = icon; \
4883 atci->iconXpmOpen = iconopen; \
4884 } else { \
4885 g_warning("can't get atci %d", id); \
4890 * Build table that controls the rendering of object types.
4892 static void addrbookctl_build_icons( GtkWidget *window ) {
4893 AddressTypeControlItem *atci;
4895 /* Build icons */
4896 if (interfacexpm)
4897 g_object_unref(interfacexpm);
4898 if (folderxpm)
4899 g_object_unref(folderxpm);
4900 if (folderopenxpm)
4901 g_object_unref(folderopenxpm);
4902 if (groupxpm)
4903 g_object_unref(groupxpm);
4904 if (vcardxpm)
4905 g_object_unref(vcardxpm);
4906 if (bookxpm)
4907 g_object_unref(bookxpm);
4908 if (addressxpm)
4909 g_object_unref(addressxpm);
4910 if (jpilotxpm)
4911 g_object_unref(jpilotxpm);
4912 if (categoryxpm)
4913 g_object_unref(categoryxpm);
4914 if (ldapxpm)
4915 g_object_unref(ldapxpm);
4916 if (addrsearchxpm)
4917 g_object_unref(addrsearchxpm);
4918 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4919 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4920 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4921 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4922 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4923 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4924 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4925 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4930 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4931 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4932 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4933 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4934 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4935 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4936 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4937 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4938 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4939 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4940 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4945 * Build table that controls the rendering of object types.
4947 static void addrbookctl_build_map( GtkWidget *window ) {
4948 AddressTypeControlItem *atci;
4950 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4951 _addressBookTypeList_ = NULL;
4953 /* Interface */
4954 atci = g_new0( AddressTypeControlItem, 1 );
4955 atci->objectType = ADDR_INTERFACE;
4956 atci->interfaceType = ADDR_IF_NONE;
4957 atci->showInTree = TRUE;
4958 atci->treeExpand = TRUE;
4959 atci->treeLeaf = FALSE;
4960 atci->displayName = _( "Interface" );
4961 atci->menuCommand = NULL;
4962 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4963 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4965 /* Address book */
4966 atci = g_new0( AddressTypeControlItem, 1 );
4967 atci->objectType = ADDR_BOOK;
4968 atci->interfaceType = ADDR_IF_BOOK;
4969 atci->showInTree = TRUE;
4970 atci->treeExpand = TRUE;
4971 atci->treeLeaf = FALSE;
4972 atci->displayName = _("Address Books");
4973 atci->menuCommand = "Menu/Book/NewBook";
4974 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4975 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4977 /* Item person */
4978 atci = g_new0( AddressTypeControlItem, 1 );
4979 atci->objectType = ADDR_ITEM_PERSON;
4980 atci->interfaceType = ADDR_IF_NONE;
4981 atci->showInTree = FALSE;
4982 atci->treeExpand = FALSE;
4983 atci->treeLeaf = FALSE;
4984 atci->displayName = _( "Person" );
4985 atci->menuCommand = NULL;
4986 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4987 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4989 /* Item email */
4990 atci = g_new0( AddressTypeControlItem, 1 );
4991 atci->objectType = ADDR_ITEM_EMAIL;
4992 atci->interfaceType = ADDR_IF_NONE;
4993 atci->showInTree = FALSE;
4994 atci->treeExpand = FALSE;
4995 atci->treeLeaf = TRUE;
4996 atci->displayName = _( "Email Address" );
4997 atci->menuCommand = NULL;
4998 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4999 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5001 /* Item group */
5002 atci = g_new0( AddressTypeControlItem, 1 );
5003 atci->objectType = ADDR_ITEM_GROUP;
5004 atci->interfaceType = ADDR_IF_BOOK;
5005 atci->showInTree = TRUE;
5006 atci->treeExpand = FALSE;
5007 atci->treeLeaf = FALSE;
5008 atci->displayName = _( "Group" );
5009 atci->menuCommand = NULL;
5010 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5011 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5013 /* Item folder */
5014 atci = g_new0( AddressTypeControlItem, 1 );
5015 atci->objectType = ADDR_ITEM_FOLDER;
5016 atci->interfaceType = ADDR_IF_BOOK;
5017 atci->showInTree = TRUE;
5018 atci->treeExpand = FALSE;
5019 atci->treeLeaf = FALSE;
5020 atci->displayName = _( "Folder" );
5021 atci->menuCommand = NULL;
5022 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5023 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5025 /* vCard */
5026 atci = g_new0( AddressTypeControlItem, 1 );
5027 atci->objectType = ADDR_VCARD;
5028 atci->interfaceType = ADDR_IF_VCARD;
5029 atci->showInTree = TRUE;
5030 atci->treeExpand = TRUE;
5031 atci->treeLeaf = TRUE;
5032 atci->displayName = _( "vCard" );
5033 atci->menuCommand = "Menu/Book/NewVCard";
5034 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5035 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5037 /* J-Pilot */
5038 atci = g_new0( AddressTypeControlItem, 1 );
5039 atci->objectType = ADDR_JPILOT;
5040 atci->interfaceType = ADDR_IF_JPILOT;
5041 atci->showInTree = TRUE;
5042 atci->treeExpand = TRUE;
5043 atci->treeLeaf = FALSE;
5044 atci->displayName = _( "JPilot" );
5045 atci->menuCommand = "Menu/Book/NewJPilot";
5046 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5047 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5049 /* Category */
5050 atci = g_new0( AddressTypeControlItem, 1 );
5051 atci->objectType = ADDR_CATEGORY;
5052 atci->interfaceType = ADDR_IF_JPILOT;
5053 atci->showInTree = TRUE;
5054 atci->treeExpand = TRUE;
5055 atci->treeLeaf = TRUE;
5056 atci->displayName = _( "JPilot" );
5057 atci->menuCommand = NULL;
5058 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5059 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5061 /* LDAP Server */
5062 atci = g_new0( AddressTypeControlItem, 1 );
5063 atci->objectType = ADDR_LDAP;
5064 atci->interfaceType = ADDR_IF_LDAP;
5065 atci->showInTree = TRUE;
5066 atci->treeExpand = TRUE;
5067 atci->treeLeaf = FALSE;
5068 atci->displayName = _( "LDAP servers" );
5069 atci->menuCommand = "Menu/Book/NewLDAPServer";
5070 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5071 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5073 /* LDAP Query */
5074 atci = g_new0( AddressTypeControlItem, 1 );
5075 atci->objectType = ADDR_LDAP_QUERY;
5076 atci->interfaceType = ADDR_IF_LDAP;
5077 atci->showInTree = TRUE;
5078 atci->treeExpand = FALSE;
5079 atci->treeLeaf = TRUE;
5080 atci->displayName = _( "LDAP Query" );
5081 atci->menuCommand = NULL;
5082 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5083 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5085 addrbookctl_build_icons(window);
5088 void addressbook_reflect_prefs_pixmap_theme(void)
5090 if (addrbook.window)
5091 addrbookctl_build_icons(addrbook.window);
5095 * Search for specified object type.
5097 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5098 gint objType = ot;
5099 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5103 * Search for specified interface type.
5105 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5106 GList *node = _addressBookTypeList_;
5107 while( node ) {
5108 AddressTypeControlItem *atci = node->data;
5109 if( atci->interfaceType == ifType ) return atci;
5110 node = g_list_next( node );
5112 return NULL;
5115 static void addrbookctl_free_address( AddressObject *obj ) {
5116 g_free( obj->name );
5117 obj->type = ADDR_NONE;
5118 obj->name = NULL;
5121 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5122 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5123 adapter->interface = NULL;
5124 adapter->interfaceType = ADDR_IF_NONE;
5125 adapter->atci = NULL;
5126 adapter->enabled = FALSE;
5127 adapter->haveLibrary = FALSE;
5128 adapter->treeNode = NULL;
5129 g_free( adapter );
5132 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5133 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5134 adapter->dataSource = NULL;
5135 adapter->subType = ADDR_NONE;
5136 g_free( adapter );
5139 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5140 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5141 adapter->itemFolder = NULL;
5142 g_free( adapter );
5145 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5146 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5147 adapter->itemGroup = NULL;
5148 g_free( adapter );
5152 * Build GUI interface list.
5154 static void addrbookctl_build_iflist( void ) {
5155 AddressTypeControlItem *atci;
5156 AdapterInterface *adapter;
5157 GList *list = NULL;
5159 if( _addressIndex_ == NULL ) {
5160 _addressIndex_ = addrindex_create_index();
5161 if( _clipBoard_ == NULL ) {
5162 _clipBoard_ = addrclip_create();
5164 addrclip_set_index( _clipBoard_, _addressIndex_ );
5166 _addressInterfaceList_ = NULL;
5167 list = addrindex_get_interface_list( _addressIndex_ );
5168 while( list ) {
5169 AddressInterface *interface = list->data;
5170 atci = addrbookctl_lookup_iface( interface->type );
5171 if( atci ) {
5172 adapter = g_new0( AdapterInterface, 1 );
5173 adapter->interfaceType = interface->type;
5174 adapter->atci = atci;
5175 adapter->interface = interface;
5176 adapter->treeNode = NULL;
5177 adapter->enabled = TRUE;
5178 adapter->haveLibrary = interface->haveLibrary;
5179 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5180 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5181 _addressInterfaceList_ =
5182 g_list_append( _addressInterfaceList_, adapter );
5184 list = g_list_next( list );
5189 * Find GUI interface type specified interface type.
5190 * \param ifType Interface type.
5191 * \return Interface item, or NULL if not found.
5193 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5194 GList *node = _addressInterfaceList_;
5195 while( node ) {
5196 AdapterInterface *adapter = node->data;
5197 if( adapter->interfaceType == ifType ) return adapter;
5198 node = g_list_next( node );
5200 return NULL;
5204 * Build interface list selection.
5206 static void addrbookctl_build_ifselect( void ) {
5207 GList *newList = NULL;
5208 gchar *selectStr;
5209 gchar **splitStr;
5210 gint ifType;
5211 gint i;
5212 gchar *endptr = NULL;
5213 /* gboolean enabled; */
5214 AdapterInterface *adapter;
5216 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5218 /* Parse string */
5219 splitStr = g_strsplit( selectStr, ",", -1 );
5220 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5221 if( splitStr[i] ) {
5222 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5223 ifType = strtol( splitStr[i], &endptr, 10 );
5224 /* enabled = TRUE;
5225 if( *endptr ) {
5226 if( strcmp( endptr, "/n" ) == 0 ) {
5227 enabled = FALSE;
5231 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5232 adapter = addrbookctl_find_interface( ifType );
5233 if( adapter ) {
5234 newList = g_list_append( newList, adapter );
5237 else {
5238 break;
5241 /* g_print( "i=%d\n", i ); */
5242 g_strfreev( splitStr );
5243 g_free( selectStr );
5245 /* Replace existing list */
5246 g_list_free( _addressIFaceSelection_ );
5247 _addressIFaceSelection_ = newList;
5248 newList = NULL;
5251 /* ***********************************************************************
5252 * Add sender to address book.
5253 * ***********************************************************************
5257 * This function is used by the Add sender to address book function.
5259 gboolean addressbook_add_contact(
5260 const gchar *name, const gchar *address, const gchar *remarks,
5261 GdkPixbuf *picture )
5263 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5264 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5265 debug_print( "addressbook_add_contact - added\n" );
5266 addressbook_refresh();
5268 return TRUE;
5271 /* ***********************************************************************
5272 * Book/folder selection.
5273 * ***********************************************************************
5277 * This function is used by the matcher dialog to select a book/folder.
5279 gchar *addressbook_folder_selection( const gchar *folderpath)
5281 AddressBookFile *book = NULL;
5282 ItemFolder *folder = NULL;
5283 gchar *path = NULL;
5285 cm_return_val_if_fail( folderpath != NULL, NULL);
5287 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5288 && book != NULL ) {
5289 if ( folder != NULL) {
5290 gchar *tmp = NULL;
5291 gchar *oldtmp = NULL;
5292 AddrItemObject *obj = NULL;
5294 /* walk thru folder->parent to build the full folder path */
5295 /* TODO: wwp: optimize this */
5296 obj = &folder->obj;
5297 tmp = g_strdup(obj->uid);
5298 while ( obj->parent ) {
5299 obj = obj->parent;
5300 if ( obj->name != NULL ) {
5301 oldtmp = g_strdup(tmp);
5302 g_free(tmp);
5303 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5304 g_free(oldtmp);
5307 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5308 g_free(tmp);
5309 } else {
5310 path = g_strdup_printf("%s", book->fileName);
5312 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5313 return path;
5315 return NULL;
5318 /* ***********************************************************************
5319 * Book/folder checking.
5320 * ***********************************************************************
5323 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5325 FolderInfo *fi = g_new0( FolderInfo, 1 );
5326 fi->book = abf;
5327 fi->folder = folder;
5328 return fi;
5331 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5332 FolderInfo *fiParent, FolderPathMatch *match )
5334 GList *list;
5335 ItemFolder *folder;
5336 gchar *fName;
5337 FolderInfo *fi;
5338 FolderPathMatch *nextmatch = NULL;
5340 if (!parentFolder)
5341 return;
5343 list = parentFolder->listFolder;
5344 while ( list ) {
5345 folder = list->data;
5346 fName = g_strdup( ADDRITEM_NAME(folder) );
5348 /* match folder name, match pointer will be set to NULL if next recursive call
5349 doesn't need to match subfolder name */
5350 if ( match != NULL &&
5351 match->matched == FALSE ) {
5352 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5353 /* folder name matches, prepare next subfolder match */
5354 debug_print("matched folder name '%s'\n", fName);
5355 match->index++;
5356 if ( match->folder_path[match->index] == NULL ) {
5357 /* we've matched all elements */
5358 match->matched = TRUE;
5359 match->folder = folder;
5360 debug_print("book/folder path matched!\n");
5361 } else {
5362 /* keep on matching */
5363 nextmatch = match;
5368 g_free( fName );
5370 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5371 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5372 g_free(fi);
5373 list = g_list_next( list );
5378 * This function is used by to check if a matcher book/folder path corresponds to an
5379 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5380 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5381 if book AND folder are NULL this means that folderpath was empty or Any.
5382 If folderpath is a simple book name (without folder), book will not be NULL and folder
5383 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5386 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5387 AddressDataSource **book,
5388 ItemFolder **folder )
5390 AddressDataSource *ds;
5391 GList *list, *nodeDS;
5392 ItemFolder *rootFolder;
5393 AddressBookFile *abf;
5394 FolderInfo *fi;
5395 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5397 if ( book )
5398 *book = NULL;
5399 if ( folder )
5400 *folder = NULL;
5402 if ( folderpath == NULL )
5403 return FALSE;
5405 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5406 return TRUE;
5408 /* split the folder path we've received, we'll try to match this path, subpath by
5409 subpath against the book/folder structure in order */
5410 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5411 if (!folder_path_match.folder_path)
5412 return FALSE;
5414 list = addrindex_get_interface_list( _addressIndex_ );
5415 while ( list && !folder_path_match.matched ) {
5416 AddressInterface *interface = list->data;
5417 if ( interface && interface->type == ADDR_IF_BOOK ) {
5418 nodeDS = interface->listSource;
5419 while ( nodeDS && !folder_path_match.matched ) {
5420 ds = nodeDS->data;
5422 /* Read address book */
5423 if( ! addrindex_ds_get_read_flag( ds ) ) {
5424 addrindex_ds_read_data( ds );
5427 /* Add node for address book */
5428 abf = ds->rawDataSource;
5430 /* match book name */
5431 if ( abf && abf->fileName &&
5432 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5434 debug_print("matched book name '%s'\n", abf->fileName);
5435 folder_path_match.book = ds;
5437 if ( folder_path_match.folder_path[1] == NULL ) {
5438 /* no folder part to match */
5440 folder_path_match.matched = TRUE;
5441 folder_path_match.folder = NULL;
5442 debug_print("book path matched!\n");
5444 } else {
5445 /* match folder part */
5447 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5448 rootFolder = addrindex_ds_get_root_folder( ds );
5450 /* prepare for recursive call */
5451 folder_path_match.index = 1;
5452 /* this call will set folder_path_match.matched and folder_path_match.folder */
5453 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5454 g_free(fi);
5458 nodeDS = g_list_next( nodeDS );
5461 list = g_list_next( list );
5464 g_strfreev( folder_path_match.folder_path );
5466 if ( book )
5467 *book = folder_path_match.book;
5468 if ( folder )
5469 *folder = folder_path_match.folder;
5470 return folder_path_match.matched;
5474 /* **********************************************************************
5475 * Address Import.
5476 * ***********************************************************************
5480 * Import LDIF file.
5482 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5483 AddressDataSource *ds = NULL;
5484 AdapterDSource *ads = NULL;
5485 AddressBookFile *abf = NULL;
5486 AdapterInterface *adapter;
5487 GtkCMCTreeNode *newNode;
5489 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5490 if( adapter ) {
5491 if( adapter->treeNode ) {
5492 abf = addressbook_imp_ldif( _addressIndex_ );
5493 if( abf ) {
5494 ds = addrindex_index_add_datasource(
5495 _addressIndex_, ADDR_IF_BOOK, abf );
5496 ads = addressbook_create_ds_adapter(
5497 ds, ADDR_BOOK, NULL );
5498 addressbook_ads_set_name(
5499 ads, addrbook_get_name( abf ) );
5500 newNode = addressbook_add_object(
5501 adapter->treeNode,
5502 ADDRESS_OBJECT(ads) );
5503 if( newNode ) {
5504 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5505 newNode );
5506 addrbook.treeSelected = newNode;
5509 /* Notify address completion */
5510 invalidate_address_completion();
5517 * Import MUTT file.
5519 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5520 AddressDataSource *ds = NULL;
5521 AdapterDSource *ads = NULL;
5522 AddressBookFile *abf = NULL;
5523 AdapterInterface *adapter;
5524 GtkCMCTreeNode *newNode;
5526 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5527 if( adapter ) {
5528 if( adapter->treeNode ) {
5529 abf = addressbook_imp_mutt( _addressIndex_ );
5530 if( abf ) {
5531 ds = addrindex_index_add_datasource(
5532 _addressIndex_, ADDR_IF_BOOK, abf );
5533 ads = addressbook_create_ds_adapter(
5534 ds, ADDR_BOOK, NULL );
5535 addressbook_ads_set_name(
5536 ads, addrbook_get_name( abf ) );
5537 newNode = addressbook_add_object(
5538 adapter->treeNode,
5539 ADDRESS_OBJECT(ads) );
5540 if( newNode ) {
5541 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5542 newNode );
5543 addrbook.treeSelected = newNode;
5546 /* Notify address completion */
5547 invalidate_address_completion();
5554 * Import Pine file.
5556 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5557 AddressDataSource *ds = NULL;
5558 AdapterDSource *ads = NULL;
5559 AddressBookFile *abf = NULL;
5560 AdapterInterface *adapter;
5561 GtkCMCTreeNode *newNode;
5563 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5564 if( adapter ) {
5565 if( adapter->treeNode ) {
5566 abf = addressbook_imp_pine( _addressIndex_ );
5567 if( abf ) {
5568 ds = addrindex_index_add_datasource(
5569 _addressIndex_, ADDR_IF_BOOK, abf );
5570 ads = addressbook_create_ds_adapter(
5571 ds, ADDR_BOOK, NULL );
5572 addressbook_ads_set_name(
5573 ads, addrbook_get_name( abf ) );
5574 newNode = addressbook_add_object(
5575 adapter->treeNode,
5576 ADDRESS_OBJECT(ads) );
5577 if( newNode ) {
5578 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5579 newNode );
5580 addrbook.treeSelected = newNode;
5583 /* Notify address completion */
5584 invalidate_address_completion();
5591 * Harvest addresses.
5592 * \param folderItem Folder to import.
5593 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5594 * \param msgList List of message numbers, or NULL to process folder.
5596 void addressbook_harvest(
5597 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5599 AddressDataSource *ds = NULL;
5600 AdapterDSource *ads = NULL;
5601 AddressBookFile *abf = NULL;
5602 AdapterInterface *adapter;
5603 GtkCMCTreeNode *newNode;
5605 abf = addrgather_dlg_execute(
5606 folderItem, _addressIndex_, sourceInd, msgList );
5607 if( abf ) {
5608 ds = addrindex_index_add_datasource(
5609 _addressIndex_, ADDR_IF_BOOK, abf );
5611 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5612 if( adapter ) {
5613 if( adapter->treeNode ) {
5614 ads = addressbook_create_ds_adapter(
5615 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5616 newNode = addressbook_add_object(
5617 adapter->treeNode,
5618 ADDRESS_OBJECT(ads) );
5619 if (newNode == NULL) {
5620 g_message("error adding addressbook object\n");
5625 /* Notify address completion */
5626 invalidate_address_completion();
5631 * Export HTML file.
5633 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5634 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5635 AddressObject *obj;
5636 AddressDataSource *ds = NULL;
5637 AddrBookBase *adbase;
5638 AddressCache *cache;
5639 GtkCMCTreeNode *node = NULL;
5641 if( ! addrbook.treeSelected ) return;
5642 node = addrbook.treeSelected;
5643 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5644 obj = gtk_cmctree_node_get_row_data( ctree, node );
5645 if( obj == NULL ) return;
5647 ds = addressbook_find_datasource( node );
5648 if( ds == NULL ) return;
5649 adbase = ( AddrBookBase * ) ds->rawDataSource;
5650 cache = adbase->addressCache;
5651 addressbook_exp_html( cache );
5655 * Export LDIF file.
5657 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5658 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5659 AddressObject *obj;
5660 AddressDataSource *ds = NULL;
5661 AddrBookBase *adbase;
5662 AddressCache *cache;
5663 GtkCMCTreeNode *node = NULL;
5665 if( ! addrbook.treeSelected ) return;
5666 node = addrbook.treeSelected;
5667 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5668 obj = gtk_cmctree_node_get_row_data( ctree, node );
5669 if( obj == NULL ) return;
5671 ds = addressbook_find_datasource( node );
5672 if( ds == NULL ) return;
5673 adbase = ( AddrBookBase * ) ds->rawDataSource;
5674 cache = adbase->addressCache;
5675 addressbook_exp_ldif( cache );
5678 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5680 addrduplicates_find(GTK_WINDOW(addrbook.window));
5683 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5685 addressbook_custom_attr_edit();
5688 static void addressbook_start_drag(GtkWidget *widget, gint button,
5689 GdkEvent *event,
5690 void *data)
5692 GdkDragContext *context;
5693 if (addressbook_target_list == NULL)
5694 addressbook_target_list = gtk_target_list_new(
5695 addressbook_drag_types, 1);
5696 context = gtk_drag_begin_with_coordinates(widget, addressbook_target_list,
5697 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event,
5698 -1, -1);
5699 gtk_drag_set_icon_default(context);
5702 static void addressbook_drag_data_get(GtkWidget *widget,
5703 GdkDragContext *drag_context,
5704 GtkSelectionData *selection_data,
5705 guint info,
5706 guint time,
5707 void *data)
5709 AddrItemObject *aio = NULL;
5710 AddressObject *pobj = NULL;
5711 AdapterDSource *ads = NULL;
5712 AddressDataSource *ds = NULL;
5713 GList *cur;
5715 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5717 if( pobj == NULL ) return;
5719 if( pobj->type == ADDR_DATASOURCE ) {
5720 ads = ADAPTER_DSOURCE(pobj);
5721 ds = ads->dataSource;
5722 } else if (pobj->type == ADDR_ITEM_GROUP) {
5724 return;
5727 else if( pobj->type != ADDR_INTERFACE ) {
5728 ds = addressbook_find_datasource( addrbook.treeSelected );
5730 if (!ds)
5731 return;
5734 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5735 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5736 GTK_CMCTREE_NODE(cur->data));
5737 while (aio && aio->type != ITEMTYPE_PERSON) {
5738 aio = aio->parent;
5742 if (aio && aio->type == ITEMTYPE_PERSON) {
5743 if( ds && ds->interface && ds->interface->readOnly)
5744 gtk_selection_data_set(selection_data,
5745 gtk_selection_data_get_target(selection_data), 8,
5746 (const guchar *)"Dummy_addr_copy", 15);
5747 else
5748 gtk_selection_data_set(selection_data,
5749 gtk_selection_data_get_target(selection_data), 8,
5750 (const guchar *)"Dummy_addr_move", 15);
5754 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5755 GdkDragContext *context,
5756 gint x,
5757 gint y,
5758 guint time,
5759 void *data)
5761 GtkAllocation allocation;
5762 GtkRequisition requisition;
5763 gint row, column;
5764 GtkCMCTreeNode *node = NULL;
5765 gboolean acceptable = FALSE;
5766 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5767 gint height = allocation.height;
5768 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5769 gint total_height = requisition.height;
5770 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5771 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5772 gfloat vpos = gtk_adjustment_get_value(pos);
5774 if (gtk_cmclist_get_selection_info
5775 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5777 if (y > height - 24 && height + vpos < total_height) {
5778 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5780 if (y < 24 && y > 0) {
5781 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5783 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5785 if (node != NULL) {
5786 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5787 if (obj == NULL)
5788 return FALSE;
5789 if( obj->type == ADDR_ITEM_FOLDER
5790 || obj->type == ADDR_ITEM_GROUP)
5791 acceptable = TRUE;
5792 else {
5793 AdapterDSource *ads = NULL;
5794 AddressDataSource *ds = NULL;
5795 ads = ADAPTER_DSOURCE(obj);
5796 ds = ads->dataSource;
5797 if (ds == NULL ) { return FALSE;}
5799 acceptable = TRUE;
5804 if (acceptable) {
5805 g_signal_handlers_block_by_func
5806 (G_OBJECT(widget),
5807 G_CALLBACK(addressbook_tree_selected), NULL);
5808 gtk_sctree_select( GTK_SCTREE(widget), node);
5809 g_signal_handlers_unblock_by_func
5810 (G_OBJECT(widget),
5811 G_CALLBACK(addressbook_tree_selected), NULL);
5812 gdk_drag_status(context,
5813 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5814 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5815 } else {
5816 gdk_drag_status(context, 0, time);
5818 return acceptable;
5821 static void addressbook_drag_leave_cb(GtkWidget *widget,
5822 GdkDragContext *context,
5823 guint time,
5824 void *data)
5826 if (addrbook.treeSelected) {
5827 g_signal_handlers_block_by_func
5828 (G_OBJECT(widget),
5829 G_CALLBACK(addressbook_tree_selected), NULL);
5830 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5831 g_signal_handlers_unblock_by_func
5832 (G_OBJECT(widget),
5833 G_CALLBACK(addressbook_tree_selected), NULL);
5838 static void addressbook_drag_received_cb(GtkWidget *widget,
5839 GdkDragContext *drag_context,
5840 gint x,
5841 gint y,
5842 GtkSelectionData *data,
5843 guint info,
5844 guint time,
5845 void *pdata)
5847 gint row, column;
5848 GtkCMCTreeNode *node;
5849 GtkCMCTreeNode *lastopened = addrbook.opened;
5851 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5852 if (gtk_cmclist_get_selection_info
5853 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5854 return;
5857 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5858 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5859 return;
5861 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5862 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5863 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5864 addressbook_clip_copy_cb(NULL, NULL);
5865 else
5866 addressbook_clip_cut_cb(NULL, NULL);
5867 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5868 addressbook_clip_paste_cb(NULL,NULL);
5869 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5870 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5871 gtk_drag_finish(drag_context, TRUE, TRUE, time);
5876 * End of Source.