add user specified stylesheet option
[claws.git] / src / addressbook.c
blob4cbfc421b597455af6515fb266f11bf810fd6e4b
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
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 "utils.h"
48 #include "gtkutils.h"
49 #include "codeconv.h"
50 #include "about.h"
51 #include "addr_compl.h"
53 #include "mgutils.h"
54 #include "addressitem.h"
55 #include "addritem.h"
56 #include "addrcache.h"
57 #include "addrbook.h"
58 #include "addrindex.h"
59 #include "addressadd.h"
60 #include "addrduplicates.h"
61 #include "addressbook_foldersel.h"
62 #include "vcard.h"
63 #include "editvcard.h"
64 #include "editgroup.h"
65 #include "editaddress.h"
66 #include "editbook.h"
67 #include "importldif.h"
68 #include "importmutt.h"
69 #include "importpine.h"
70 #include "manual.h"
72 #ifdef USE_JPILOT
73 #include "jpilot.h"
74 #include "editjpilot.h"
75 #endif
77 #ifdef USE_LDAP
78 #include <pthread.h>
79 #include "ldapserver.h"
80 #include "editldap.h"
81 #include "ldapupdate.h"
83 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
84 #endif
86 #include "addrquery.h"
87 #include "addrselect.h"
88 #include "addrclip.h"
89 #include "addrgather.h"
90 #include "adbookbase.h"
91 #include "exphtmldlg.h"
92 #include "expldifdlg.h"
93 #include "browseldap.h"
94 #include "addrcustomattr.h"
95 #ifdef G_OS_WIN32
96 #undef interface
97 #endif
98 typedef enum
100 COL_SOURCES = 0,
101 N_INDEX_COLS = 1
102 } AddressIndexColumns;
104 typedef enum
106 COL_NAME = 0,
107 COL_ADDRESS = 1,
108 COL_REMARKS = 2,
109 N_LIST_COLS = 3
110 } AddressListColumns;
112 typedef struct {
113 AddressBookFile *book;
114 ItemFolder *folder;
115 } FolderInfo;
117 typedef struct {
118 gchar **folder_path;
119 gboolean matched;
120 gint index;
121 AddressDataSource *book;
122 ItemFolder *folder;
123 } FolderPathMatch;
125 static gchar *list_titles[] = { N_("Name"),
126 N_("Email Address"),
127 N_("Remarks") };
129 #define COL_NAME_WIDTH 164
130 #define COL_ADDRESS_WIDTH 156
132 #define COL_FOLDER_WIDTH 170
133 #define ADDRESSBOOK_WIDTH 640
134 #define ADDRESSBOOK_HEIGHT 360
136 #define ADDRESSBOOK_MSGBUF_SIZE 2048
138 static GdkPixbuf *folderxpm = NULL;
139 static GdkPixbuf *folderopenxpm = NULL;
140 static GdkPixbuf *groupxpm = NULL;
141 static GdkPixbuf *interfacexpm = NULL;
142 static GdkPixbuf *bookxpm = NULL;
143 static GdkPixbuf *addressxpm = NULL;
144 static GdkPixbuf *vcardxpm = NULL;
145 static GdkPixbuf *jpilotxpm = NULL;
146 static GdkPixbuf *categoryxpm = NULL;
147 static GdkPixbuf *ldapxpm = NULL;
148 static GdkPixbuf *addrsearchxpm = NULL;
150 /* Message buffer */
151 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
153 /* Address list selection */
154 static AddrSelectList *_addressSelect_ = NULL;
155 static AddressClipboard *_clipBoard_ = NULL;
157 /* Address index file and interfaces */
158 static AddressIndex *_addressIndex_ = NULL;
159 static GList *_addressInterfaceList_ = NULL;
160 static GList *_addressIFaceSelection_ = NULL;
161 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
163 static AddressBook_win addrbook;
165 static GHashTable *_addressBookTypeHash_ = NULL;
166 static GList *_addressBookTypeList_ = NULL;
168 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
169 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
170 static void addressbook_edit_address_post_cb( ItemPerson *person );
172 static void addressbook_create (void);
173 static gint addressbook_close (void);
175 static gboolean address_index_has_focus = FALSE;
176 static gboolean address_list_has_focus = FALSE;
178 /* callback functions */
179 static void addressbook_del_clicked (GtkButton *button,
180 gpointer data);
181 static void addressbook_reg_clicked (GtkButton *button,
182 gpointer data);
183 static void addressbook_to_clicked (GtkButton *button,
184 gpointer data);
185 static void addressbook_lup_clicked (GtkButton *button,
186 gpointer data);
187 static void addressbook_close_clicked (GtkButton *button,
188 gpointer data);
190 static void addressbook_tree_selected (GtkCMCTree *ctree,
191 GtkCMCTreeNode *node,
192 gint column,
193 gpointer data);
194 static void addressbook_select_row_tree (GtkCMCTree *ctree,
195 GtkCMCTreeNode *node,
196 gint column,
197 gpointer data);
198 static void addressbook_list_row_selected (GtkCMCTree *clist,
199 GtkCMCTreeNode *node,
200 gint column,
201 gpointer data);
202 static void addressbook_list_row_unselected (GtkCMCTree *clist,
203 GtkCMCTreeNode *node,
204 gint column,
205 gpointer data);
206 static void addressbook_person_expand_node (GtkCMCTree *ctree,
207 GList *node,
208 gpointer *data );
209 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
210 GList *node,
211 gpointer *data );
213 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
214 GdkEventButton *event,
215 gpointer data);
216 static gboolean addressbook_list_button_released(GtkWidget *widget,
217 GdkEventButton *event,
218 gpointer data);
219 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
220 GdkEventButton *event,
221 gpointer data);
222 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
223 GdkEventButton *event,
224 gpointer data);
226 static void addressbook_new_folder_cb (GtkAction *action,
227 gpointer data);
228 static void addressbook_new_group_cb (GtkAction *action,
229 gpointer data);
230 static void addressbook_treenode_edit_cb (GtkAction *action,
231 gpointer data);
232 static void addressbook_treenode_delete_cb (GtkAction *action,
233 gpointer data);
235 static void addressbook_change_node_name (GtkCMCTreeNode *node,
236 const gchar *name);
238 static void addressbook_new_address_cb (GtkAction *action,
239 gpointer data);
240 static void addressbook_edit_address_cb (GtkAction *action,
241 gpointer data);
242 static void addressbook_delete_address_cb (GtkAction *action,
243 gpointer data);
245 static void close_cb (GtkAction *action,
246 gpointer data);
247 static void addressbook_file_save_cb (GtkAction *action,
248 gpointer data);
250 /* Data source edit stuff */
251 static void addressbook_new_book_cb (GtkAction *action,
252 gpointer data);
253 static void addressbook_new_vcard_cb (GtkAction *action,
254 gpointer data);
256 #ifdef USE_JPILOT
257 static void addressbook_new_jpilot_cb (GtkAction *action,
258 gpointer data);
259 #endif
261 #ifdef USE_LDAP
262 static void addressbook_new_ldap_cb (GtkAction *action,
263 gpointer data);
264 #endif
266 static void addressbook_set_clist (AddressObject *obj,
267 gboolean refresh);
269 static void addressbook_load_tree (void);
270 void addressbook_read_file (void);
272 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
273 AddressObject *obj);
274 static void addressbook_treenode_remove_item ( void );
276 static AddressDataSource *addressbook_find_datasource
277 (GtkCMCTreeNode *node );
279 static AddressBookFile *addressbook_get_book_file(void);
281 static GtkCMCTreeNode *addressbook_node_add_folder
282 (GtkCMCTreeNode *node,
283 AddressDataSource *ds,
284 ItemFolder *itemFolder,
285 AddressObjectType otype);
286 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
287 AddressDataSource *ds,
288 ItemGroup *itemGroup);
289 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
290 GtkCMCTreeNode *parent);
291 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
292 GtkCMCTreeNode *node);
293 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
294 ItemGroup *group);
295 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
296 GdkEventKey *event,
297 gpointer data);
298 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
299 gconstpointer ptr1,
300 gconstpointer ptr2);
301 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
302 ItemPerson *person,
303 AddressTypeControlItem *atci,
304 AddressTypeControlItem *atciMail);
305 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
306 ItemPerson *person);
307 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
308 ItemPerson *person);
309 static void addressbook_folder_remove_node (GtkCMCTree *clist,
310 GtkCMCTreeNode *node);
312 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
313 gboolean force_focus );
315 /* LUT's and IF stuff */
316 static void addressbook_free_treenode ( gpointer data );
317 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
318 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
320 static void addrbookctl_build_map (GtkWidget *window);
321 static void addrbookctl_build_iflist (void);
322 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
323 static void addrbookctl_build_ifselect (void);
325 static void addrbookctl_free_interface (AdapterInterface *adapter);
326 static void addrbookctl_free_datasource (AdapterDSource *adapter);
327 static void addrbookctl_free_folder (AdapterFolder *adapter);
328 static void addrbookctl_free_group (AdapterGroup *adapter);
330 static void addressbook_list_select_clear ( void );
331 static void addressbook_list_select_add ( AddrItemObject *aio,
332 AddressDataSource *ds );
333 static void addressbook_list_select_remove ( AddrItemObject *aio );
335 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
336 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
337 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
338 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
339 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
340 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
341 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
342 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
343 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
344 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
346 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
347 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
350 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
352 #ifdef USE_LDAP
353 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
354 #endif
355 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
357 static void addressbook_start_drag(GtkWidget *widget, gint button,
358 GdkEvent *event,
359 void *data);
360 static void addressbook_drag_data_get(GtkWidget *widget,
361 GdkDragContext *drag_context,
362 GtkSelectionData *selection_data,
363 guint info,
364 guint time,
365 void *data);
366 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
367 GdkDragContext *context,
368 gint x,
369 gint y,
370 guint time,
371 void *data);
372 static void addressbook_drag_leave_cb(GtkWidget *widget,
373 GdkDragContext *context,
374 guint time,
375 void *data);
376 static void addressbook_drag_received_cb(GtkWidget *widget,
377 GdkDragContext *drag_context,
378 gint x,
379 gint y,
380 GtkSelectionData *data,
381 guint info,
382 guint time,
383 void *pdata);
384 static void addressbook_list_menu_setup( void );
386 static GtkTargetEntry addressbook_drag_types[] =
388 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
391 static GtkTargetList *addressbook_target_list = NULL;
393 static void about_show_cb(GtkAction *action, gpointer data)
395 about_show();
398 static GtkActionEntry addressbook_entries[] =
400 {"Menu", NULL, "Menu" },
401 /* menus */
402 {"Book", NULL, N_("_Book") },
403 {"Address", NULL, N_("_Edit") },
404 {"Tools", NULL, N_("_Tools") },
405 {"Help", NULL, N_("_Help") },
407 /* Book menu */
408 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
409 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
410 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
413 #ifdef USE_JPILOT
414 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
415 #endif
416 #ifdef USE_LDAP
417 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
418 #endif
419 {"Book/---", NULL, "---", NULL, NULL, NULL },
421 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
422 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
423 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
424 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
425 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
427 /* Adress menu */
428 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
429 {"Address/---", NULL, "---", NULL, NULL, NULL },
430 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
431 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
432 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
433 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
434 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
435 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
438 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
439 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
440 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
443 /* Tools menu */
444 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
445 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
446 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
447 {"Tools/---", NULL, "---", NULL, NULL, NULL },
448 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
449 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
450 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
451 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
452 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
454 /* Help menu */
455 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
459 static GtkActionEntry addressbook_tree_popup_entries[] =
461 {"ABTreePopup", NULL, "ABTreePopup" },
462 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
463 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
464 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
465 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
466 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
467 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
468 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
469 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
470 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
471 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
474 static GtkActionEntry addressbook_list_popup_entries[] =
476 {"ABListPopup", NULL, "ABListPopup" },
477 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
478 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
479 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
480 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
481 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
482 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
483 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
484 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
485 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
486 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
487 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
488 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
489 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
490 #ifdef USE_LDAP
491 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
492 #endif
496 * Structure of error message table.
498 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
499 struct _ErrMsgTableEntry {
500 gint code;
501 gchar *description;
504 static gchar *_errMsgUnknown_ = N_( "Unknown" );
507 * Lookup table of error messages for general errors. Note that a NULL
508 * description signifies the end of the table.
510 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
511 { MGU_SUCCESS, N_("Success") },
512 { MGU_BAD_ARGS, N_("Bad arguments") },
513 { MGU_NO_FILE, N_("File not specified") },
514 { MGU_OPEN_FILE, N_("Error opening file") },
515 { MGU_ERROR_READ, N_("Error reading file") },
516 { MGU_EOF, N_("End of file encountered") },
517 { MGU_OO_MEMORY, N_("Error allocating memory") },
518 { MGU_BAD_FORMAT, N_("Bad file format") },
519 { MGU_ERROR_WRITE, N_("Error writing to file") },
520 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
521 { MGU_NO_PATH, N_("No path specified") },
522 { 0, NULL }
525 #ifdef USE_LDAP
527 * Lookup table of error messages for LDAP errors.
529 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
530 { LDAPRC_SUCCESS, N_("Success") },
531 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
532 { LDAPRC_INIT, N_("Error initializing LDAP") },
533 { LDAPRC_BIND, N_("Error binding to LDAP server") },
534 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
535 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
536 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
537 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
538 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
539 { LDAPRC_TLS, N_("Error starting TLS connection") },
540 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
541 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
542 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
543 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
544 { 0, NULL }
546 #endif
549 * Lookup message for specified error code.
550 * \param lut Lookup table.
551 * \param code Code to lookup.
552 * \return Description associated to code.
554 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
555 gchar *desc = NULL;
556 ErrMsgTableEntry entry;
557 gint i;
559 for( i = 0; ; i++ ) {
560 entry = lut[ i ];
561 if( entry.description == NULL ) break;
562 if( entry.code == code ) {
563 desc = entry.description;
564 break;
567 if( ! desc ) {
568 desc = _errMsgUnknown_;
570 return desc;
573 static gboolean lastCanLookup = FALSE;
575 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
577 if (add_and_delete) {
578 gtk_widget_show(addrbook.edit_btn);
579 gtk_widget_show(addrbook.del_btn);
580 gtk_widget_show(addrbook.reg_btn);
581 } else {
582 gtk_widget_hide(addrbook.edit_btn);
583 gtk_widget_hide(addrbook.del_btn);
584 gtk_widget_hide(addrbook.reg_btn);
587 if (lookup) {
588 gtk_widget_show(addrbook.lup_btn);
589 gtk_widget_show(addrbook.entry);
590 gtk_widget_show(addrbook.label);
591 } else {
592 gtk_widget_hide(addrbook.lup_btn);
593 gtk_widget_hide(addrbook.entry);
594 gtk_widget_hide(addrbook.label);
597 lastCanLookup = lookup;
599 if (mail_ops) {
600 gtk_widget_show(addrbook.to_btn);
601 gtk_widget_show(addrbook.cc_btn);
602 gtk_widget_show(addrbook.bcc_btn);
603 } else {
604 gtk_widget_hide(addrbook.to_btn);
605 gtk_widget_hide(addrbook.cc_btn);
606 gtk_widget_hide(addrbook.bcc_btn);
610 void addressbook_open(Compose *target)
612 /* Initialize all static members */
613 if( _clipBoard_ == NULL ) {
614 _clipBoard_ = addrclip_create();
616 if( _addressIndex_ != NULL ) {
617 addrclip_set_index( _clipBoard_, _addressIndex_ );
619 if( _addressSelect_ == NULL ) {
620 _addressSelect_ = addrselect_list_create();
622 if (!addrbook.window) {
623 addressbook_read_file();
624 addressbook_create();
625 addressbook_load_tree();
626 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
627 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
629 else {
630 gtk_widget_hide(addrbook.window);
633 gtk_widget_show_all(addrbook.window);
635 if (!prefs_common.addressbook_use_editaddress_dialog)
636 addressbook_edit_person_widgetset_hide();
638 address_completion_start(addrbook.window);
640 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
641 addressbook_set_target_compose(target);
645 * Destroy addressbook.
647 void addressbook_destroy( void ) {
648 /* Free up address stuff */
649 if( _addressSelect_ != NULL ) {
650 addrselect_list_free( _addressSelect_ );
652 if( _clipBoard_ != NULL ) {
653 addrclip_free( _clipBoard_ );
655 if( _addressIndex_ != NULL ) {
656 addrindex_free_index( _addressIndex_ );
657 addrindex_teardown();
659 _addressSelect_ = NULL;
660 _clipBoard_ = NULL;
661 _addressIndex_ = NULL;
664 void addressbook_set_target_compose(Compose *target)
666 addrbook.target_compose = target;
669 Compose *addressbook_get_target_compose(void)
671 return addrbook.target_compose;
675 * Refresh addressbook and save to file(s).
677 void addressbook_refresh( void )
679 if (addrbook.window) {
680 if (addrbook.treeSelected) {
681 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
682 addrbook.treeSelected);
683 addressbook_set_clist(
684 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
685 addrbook.treeSelected),
686 TRUE);
690 addressbook_export_to_file();
693 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
695 if (event && event->keyval == GDK_KEY_Escape)
696 addressbook_close();
697 else if (event && event->keyval == GDK_KEY_Delete) {
698 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
699 if ( /* address_index_has_focus || */ address_list_has_focus )
700 addressbook_del_clicked(NULL, NULL);
702 return FALSE;
706 *\brief Save Gtk object size to prefs dataset
708 static void addressbook_size_allocate_cb(GtkWidget *widget,
709 GtkAllocation *allocation)
711 cm_return_if_fail(allocation != NULL);
713 prefs_common.addressbookwin_width = allocation->width;
714 prefs_common.addressbookwin_height = allocation->height;
717 static gint sort_column_number = 0;
718 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
720 static gint list_case_sort(
721 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
723 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
724 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
725 gchar *name1 = NULL, *name2 = NULL;
726 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
727 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
729 if( aio1->type == aio2->type ) {
730 if( row1 )
731 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
732 if( row2 )
733 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
734 if( ! name1 ) return ( name2 != NULL );
735 if( ! name2 ) return -1;
736 return g_utf8_collate( name1, name2 );
737 } else {
738 /* Order groups before person */
739 if( aio1->type == ITEMTYPE_GROUP ) {
740 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
741 } else if( aio2->type == ITEMTYPE_GROUP ) {
742 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
744 return 0;
748 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
749 const GtkSortType sort_type)
751 gint pos;
752 GtkWidget *hbox, *label, *arrow;
754 sort_column_number = col;
755 sort_column_type = sort_type;
756 gtk_cmclist_set_compare_func(clist, list_case_sort);
757 gtk_cmclist_set_sort_type(clist, sort_type);
758 gtk_cmclist_set_sort_column(clist, col);
760 gtk_cmclist_freeze(clist);
761 gtk_cmclist_sort(clist);
763 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
764 hbox = gtk_hbox_new(FALSE, 4);
765 label = gtk_label_new(gettext(list_titles[pos]));
766 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
768 if(pos == col) {
769 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
770 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
771 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
774 gtk_widget_show_all(hbox);
775 gtk_cmclist_set_column_widget(clist, pos, hbox);
778 gtk_cmclist_thaw(clist);
781 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
783 static GtkSortType sort_type = GTK_SORT_ASCENDING;
785 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
786 GTK_SORT_ASCENDING;
787 addressbook_sort_list(clist, COL_NAME, sort_type);
790 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
792 static GtkSortType sort_type = GTK_SORT_ASCENDING;
794 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
795 GTK_SORT_ASCENDING;
796 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
799 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
801 static GtkSortType sort_type = GTK_SORT_ASCENDING;
803 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
804 GTK_SORT_ASCENDING;
805 addressbook_sort_list(clist, COL_REMARKS, sort_type);
808 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
809 gpointer data)
811 address_index_has_focus = TRUE;
812 return FALSE;
815 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
816 gpointer data)
818 address_index_has_focus = FALSE;
819 if (!prefs_common.addressbook_use_editaddress_dialog
820 && !address_list_has_focus)
821 addressbook_address_list_disable_some_actions();
822 return FALSE;
825 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
826 gpointer data)
828 address_list_has_focus = TRUE;
829 return FALSE;
832 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
833 gpointer data)
835 address_list_has_focus = FALSE;
836 if (!prefs_common.addressbook_use_editaddress_dialog
837 && !address_index_has_focus)
838 addressbook_address_list_disable_some_actions();
839 return FALSE;
842 /* save hpane and vpane's handle position when it moves */
843 static void addressbook_pane_save_position(void)
845 if (addrbook.hpaned)
846 prefs_common.addressbook_hpaned_pos =
847 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
848 if (addrbook.vpaned)
849 prefs_common.addressbook_vpaned_pos =
850 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
854 * Create the address book widgets. The address book contains two CTree widgets: the
855 * address index tree on the left and the address list on the right.
857 * The address index tree displays a hierarchy of interfaces and groups. Each node in
858 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
859 * data sources and folder objects.
861 * The address list displays group, person and email objects. These items are linked
862 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
863 * sources.
865 * In the tradition of MVC architecture, the data stores have been separated from the
866 * GUI components. The addrindex.c file provides the interface to all data stores.
868 static void addressbook_create(void)
870 GtkWidget *window;
871 GtkWidget *vbox;
872 GtkWidget *menubar;
873 GtkWidget *vbox2;
874 GtkWidget *ctree_swin;
875 GtkWidget *ctree;
876 GtkWidget *editaddress_vbox;
877 GtkWidget *clist_vbox;
878 GtkWidget *clist_swin;
879 GtkWidget *clist;
880 GtkWidget *hpaned;
881 GtkWidget *vpaned;
882 GtkWidget *hbox;
883 GtkWidget *label;
884 GtkWidget *entry;
885 GtkWidget *statusbar;
886 GtkWidget *hbbox;
887 GtkWidget *hsbox;
888 GtkWidget *help_btn;
889 GtkWidget *del_btn;
890 GtkWidget *edit_btn;
891 GtkWidget *reg_btn;
892 GtkWidget *lup_btn;
893 GtkWidget *to_btn;
894 GtkWidget *cc_btn;
895 GtkWidget *bcc_btn;
896 GtkWidget *close_btn;
897 GtkWidget *tree_popup;
898 GtkWidget *list_popup;
899 GList *nodeIf;
900 GtkUIManager *ui_manager;
901 GtkActionGroup *action_group;
902 gchar *index_titles[N_INDEX_COLS];
903 gchar *text;
904 gint i;
906 static GdkGeometry geometry;
908 debug_print("Creating addressbook window...\n");
910 index_titles[COL_SOURCES] = _("Sources");
912 /* Address book window */
913 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
914 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
915 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
916 gtk_widget_realize(window);
918 g_signal_connect(G_OBJECT(window), "delete_event",
919 G_CALLBACK(addressbook_close), NULL);
920 g_signal_connect(G_OBJECT(window), "size_allocate",
921 G_CALLBACK(addressbook_size_allocate_cb), NULL);
922 g_signal_connect(G_OBJECT(window), "key_press_event",
923 G_CALLBACK(key_pressed), NULL);
924 MANAGE_WINDOW_SIGNALS_CONNECT(window);
926 vbox = gtk_vbox_new(FALSE, 0);
927 gtk_container_add(GTK_CONTAINER(window), vbox);
929 /* Menu bar */
930 ui_manager = gtk_ui_manager_new();
931 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
932 G_N_ELEMENTS(addressbook_entries), NULL);
933 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
934 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
936 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
938 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
940 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
945 /* Book menu */
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
949 #ifdef USE_JPILOT
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
951 #endif
952 #ifdef USE_LDAP
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
954 #endif
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
962 /* Address menu */
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
977 /* Tools menu */
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
988 /* Help menu */
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
991 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
993 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
995 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
996 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
997 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
999 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1000 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1001 GTK_POLICY_AUTOMATIC,
1002 GTK_POLICY_AUTOMATIC);
1003 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1005 /* Address index */
1006 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1007 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1009 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1010 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1011 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1012 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1013 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1014 GTK_CMCTREE_EXPANDER_TRIANGLE);
1015 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1016 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1017 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1018 addressbook_treenode_compare_func);
1020 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1021 G_CALLBACK(addressbook_tree_selected), NULL);
1022 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1023 G_CALLBACK(addressbook_tree_button_pressed),
1024 NULL);
1025 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1026 G_CALLBACK(addressbook_tree_button_released),
1027 NULL);
1028 /* TEMPORARY */
1029 g_signal_connect(G_OBJECT(ctree), "select_row",
1030 G_CALLBACK(addressbook_select_row_tree), NULL);
1032 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1033 addressbook_drag_types, 1,
1034 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1035 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1036 G_CALLBACK(addressbook_drag_motion_cb),
1037 ctree);
1038 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1039 G_CALLBACK(addressbook_drag_leave_cb),
1040 ctree);
1041 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1042 G_CALLBACK(addressbook_drag_received_cb),
1043 ctree);
1044 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1045 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1046 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1047 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1049 clist_vbox = gtk_vbox_new(FALSE, 4);
1051 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1052 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1053 GTK_POLICY_AUTOMATIC,
1054 GTK_POLICY_AUTOMATIC);
1055 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1057 /* Address list */
1058 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1059 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1060 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1061 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1062 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1063 GTK_CMCTREE_EXPANDER_TRIANGLE);
1064 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1065 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1066 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1067 COL_NAME_WIDTH);
1068 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1069 COL_ADDRESS_WIDTH);
1070 gtk_widget_set_size_request(clist, -1, 80);
1072 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1073 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1074 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1075 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1076 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1077 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1078 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1079 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1080 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1081 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1082 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1084 for (i = 0; i < N_LIST_COLS; i++)
1085 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1086 FALSE);
1088 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1089 G_CALLBACK(addressbook_list_row_selected), NULL);
1090 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1091 G_CALLBACK(addressbook_list_row_unselected), NULL);
1092 g_signal_connect(G_OBJECT(clist), "button_press_event",
1093 G_CALLBACK(addressbook_list_button_pressed),
1094 NULL);
1095 g_signal_connect(G_OBJECT(clist), "button_release_event",
1096 G_CALLBACK(addressbook_list_button_released),
1097 NULL);
1098 g_signal_connect(G_OBJECT(clist), "tree_expand",
1099 G_CALLBACK(addressbook_person_expand_node), NULL );
1100 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1101 G_CALLBACK(addressbook_person_collapse_node), NULL );
1102 g_signal_connect(G_OBJECT(clist), "start_drag",
1103 G_CALLBACK(addressbook_start_drag), NULL);
1104 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1105 G_CALLBACK(addressbook_drag_data_get), NULL);
1106 hbox = gtk_hbox_new(FALSE, 4);
1107 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1109 label = gtk_label_new(_("Lookup name:"));
1110 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1112 entry = gtk_entry_new();
1113 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1115 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1117 g_signal_connect(G_OBJECT(entry), "key_press_event",
1118 G_CALLBACK(addressbook_entry_key_pressed),
1119 NULL);
1121 if (!prefs_common.addressbook_use_editaddress_dialog) {
1122 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1123 vpaned = gtk_vpaned_new();
1124 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1125 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1126 } else {
1127 vpaned = NULL;
1128 editaddress_vbox = NULL;
1130 hpaned = gtk_hpaned_new();
1131 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1132 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1133 if (prefs_common.addressbook_use_editaddress_dialog)
1134 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1135 else
1136 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1138 /* Status bar */
1139 hsbox = gtk_hbox_new(FALSE, 0);
1140 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1141 statusbar = gtk_statusbar_new();
1142 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1144 /* Button panel */
1145 hbbox = gtk_hbutton_box_new();
1146 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1147 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1148 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1149 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1151 gtkut_stock_button_add_help(hbbox, &help_btn);
1153 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1154 gtkut_widget_set_can_default(edit_btn, TRUE);
1155 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1156 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1157 gtkut_widget_set_can_default(del_btn, TRUE);
1158 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1159 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1160 gtkut_widget_set_can_default(reg_btn, TRUE);
1161 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1164 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1165 gtkut_widget_set_can_default(lup_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1168 g_signal_connect(G_OBJECT(help_btn), "clicked",
1169 G_CALLBACK(manual_open_with_anchor_cb),
1170 MANUAL_ANCHOR_ADDRBOOK);
1172 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1173 G_CALLBACK(addressbook_edit_clicked), NULL);
1174 g_signal_connect(G_OBJECT(del_btn), "clicked",
1175 G_CALLBACK(addressbook_del_clicked), NULL);
1176 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1177 G_CALLBACK(addressbook_reg_clicked), NULL);
1178 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1179 G_CALLBACK(addressbook_lup_clicked), NULL);
1181 to_btn = gtk_button_new_with_label
1182 (prefs_common_translated_header_name("To:"));
1183 gtkut_widget_set_can_default(to_btn, TRUE);
1184 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1185 cc_btn = gtk_button_new_with_label
1186 (prefs_common_translated_header_name("Cc:"));
1187 gtkut_widget_set_can_default(cc_btn, TRUE);
1188 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1189 bcc_btn = gtk_button_new_with_label
1190 (prefs_common_translated_header_name("Bcc:"));
1191 gtkut_widget_set_can_default(bcc_btn, TRUE);
1192 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1194 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1195 gtkut_widget_set_can_default(close_btn, TRUE);
1196 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1198 g_signal_connect(G_OBJECT(to_btn), "clicked",
1199 G_CALLBACK(addressbook_to_clicked),
1200 GINT_TO_POINTER(COMPOSE_TO));
1201 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1202 G_CALLBACK(addressbook_to_clicked),
1203 GINT_TO_POINTER(COMPOSE_CC));
1204 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1205 G_CALLBACK(addressbook_to_clicked),
1206 GINT_TO_POINTER(COMPOSE_BCC));
1207 g_signal_connect(G_OBJECT(close_btn), "clicked",
1208 G_CALLBACK(addressbook_close_clicked), NULL);
1210 /* Build icons for interface */
1212 /* Build control tables */
1213 addrbookctl_build_map(window);
1214 addrbookctl_build_iflist();
1215 addrbookctl_build_ifselect();
1217 addrbook.clist = NULL;
1219 /* Add each interface into the tree as a root level folder */
1220 nodeIf = _addressInterfaceList_;
1221 while( nodeIf ) {
1222 AdapterInterface *adapter = nodeIf->data;
1223 AddressInterface *iface = adapter->interface;
1224 nodeIf = g_list_next(nodeIf);
1226 if(iface->useInterface) {
1227 AddressTypeControlItem *atci = adapter->atci;
1228 text = atci->displayName;
1229 adapter->treeNode =
1230 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1231 NULL, NULL, &text, FOLDER_SPACING,
1232 interfacexpm,
1233 interfacexpm,
1234 FALSE, FALSE );
1235 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1236 gtk_cmctree_node_set_row_data_full(
1237 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1238 addressbook_free_treenode );
1242 /* Popup menu */
1244 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1245 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1257 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1258 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1274 #ifdef USE_LDAP
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1276 #endif
1277 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1278 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1280 addrbook.window = window;
1281 addrbook.hpaned = hpaned;
1282 addrbook.vpaned = vpaned;
1283 addrbook.menubar = menubar;
1284 addrbook.ctree = ctree;
1285 addrbook.ctree_swin
1286 = ctree_swin;
1287 addrbook.editaddress_vbox = editaddress_vbox;
1288 addrbook.clist = clist;
1289 addrbook.label = label;
1290 addrbook.entry = entry;
1291 addrbook.statusbar = statusbar;
1292 addrbook.status_cid = gtk_statusbar_get_context_id(
1293 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1295 addrbook.help_btn = help_btn;
1296 addrbook.edit_btn = edit_btn;
1297 addrbook.del_btn = del_btn;
1298 addrbook.reg_btn = reg_btn;
1299 addrbook.lup_btn = lup_btn;
1300 addrbook.to_btn = to_btn;
1301 addrbook.cc_btn = cc_btn;
1302 addrbook.bcc_btn = bcc_btn;
1304 addrbook.tree_popup = tree_popup;
1305 addrbook.list_popup = list_popup;
1306 addrbook.ui_manager = ui_manager;
1308 addrbook.listSelected = NULL;
1310 if (!geometry.min_height) {
1311 geometry.min_width = ADDRESSBOOK_WIDTH;
1312 geometry.min_height = ADDRESSBOOK_HEIGHT;
1315 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1316 GDK_HINT_MIN_SIZE);
1317 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1318 prefs_common.addressbookwin_height);
1319 #ifdef G_OS_WIN32
1320 gtk_window_move(GTK_WINDOW(window), 48, 48);
1321 #endif
1323 if (!prefs_common.addressbook_use_editaddress_dialog) {
1324 if (prefs_common.addressbook_vpaned_pos > 0)
1325 gtk_paned_set_position(GTK_PANED(vpaned),
1326 prefs_common.addressbook_vpaned_pos);
1328 if (prefs_common.addressbook_hpaned_pos > 0)
1329 gtk_paned_set_position(GTK_PANED(hpaned),
1330 prefs_common.addressbook_hpaned_pos);
1333 gtk_widget_show_all(window);
1337 * Close address book window and save to file(s).
1339 static gint addressbook_close( void ) {
1340 address_completion_end(addrbook.window);
1341 if (!prefs_common.addressbook_use_editaddress_dialog)
1342 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1344 addressbook_pane_save_position();
1346 gtk_widget_hide(addrbook.window);
1347 addressbook_export_to_file();
1348 return TRUE;
1352 * Display message in status line.
1353 * \param msg Message to display.
1355 static void addressbook_status_show( gchar *msg ) {
1356 if( addrbook.statusbar != NULL ) {
1357 gtk_statusbar_pop(
1358 GTK_STATUSBAR(addrbook.statusbar),
1359 addrbook.status_cid );
1360 if( msg ) {
1361 gtk_statusbar_push(
1362 GTK_STATUSBAR(addrbook.statusbar),
1363 addrbook.status_cid, msg );
1368 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1369 gint retVal;
1370 gchar *name;
1371 gchar *desc;
1372 *addressbook_msgbuf = '\0';
1373 if( ds ) {
1374 name = addrindex_ds_get_name( ds );
1375 retVal = addrindex_ds_get_status_code( ds );
1376 if( retVal == MGU_SUCCESS ) {
1377 g_snprintf( addressbook_msgbuf,
1378 sizeof(addressbook_msgbuf), "%s", name );
1380 else {
1381 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1382 g_snprintf( addressbook_msgbuf,
1383 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1386 addressbook_status_show( addressbook_msgbuf );
1389 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1391 addressbook_edit_address_cb(NULL, NULL);
1394 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1396 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1400 * Delete one or more objects from address list.
1402 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1404 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1405 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1406 AddressObject *pobj;
1407 AdapterDSource *ads = NULL;
1408 GtkCMCTreeNode *nodeList;
1409 gboolean procFlag;
1410 AlertValue aval;
1411 AddressBookFile *abf = NULL;
1412 AddressDataSource *ds = NULL;
1413 AddressInterface *iface;
1414 AddrItemObject *aio;
1415 AddrSelectItem *item;
1416 GList *list, *node;
1417 gboolean refreshList = FALSE;
1419 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1420 cm_return_if_fail(pobj != NULL);
1422 /* Test whether anything selected for deletion */
1423 nodeList = addrbook.listSelected;
1425 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1426 if( aio == NULL) return;
1427 ds = addressbook_find_datasource( addrbook.treeSelected );
1428 if( ds == NULL ) return;
1430 /* Test for read only */
1431 iface = ds->interface;
1432 if( iface->readOnly ) {
1433 alertpanel( _("Delete address(es)"),
1434 _("This address data is readonly and cannot be deleted."),
1435 GTK_STOCK_CLOSE, NULL, NULL );
1436 return;
1439 /* Test whether Ok to proceed */
1440 procFlag = FALSE;
1441 if( pobj->type == ADDR_DATASOURCE ) {
1442 ads = ADAPTER_DSOURCE(pobj);
1443 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1445 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1446 procFlag = TRUE;
1448 else if( pobj->type == ADDR_ITEM_GROUP ) {
1449 procFlag = TRUE;
1451 if( ! procFlag ) return;
1452 abf = ds->rawDataSource;
1453 if( abf == NULL ) return;
1455 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1456 g_signal_handlers_block_by_func
1457 (G_OBJECT(addrbook.clist),
1458 G_CALLBACK(addressbook_list_row_unselected), NULL);
1460 /* Process deletions */
1461 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1462 GList *groups = NULL, *persons = NULL, *emails = NULL;
1463 gboolean group_delete = TRUE;
1464 /* Items inside folders */
1465 list = addrselect_get_list( _addressSelect_ );
1466 /* Confirm deletion */
1467 node = list;
1468 while( node ) {
1469 item = node->data;
1470 node = g_list_next( node );
1471 aio = ( AddrItemObject * ) item->addressItem;
1472 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1473 group_delete = FALSE;
1474 break;
1477 if (group_delete) {
1478 aval = alertpanel( _("Delete group"),
1479 _("Really delete the group(s)?\n"
1480 "The addresses it contains will not be lost."),
1481 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1482 if( aval != G_ALERTALTERNATE ) {
1483 goto thaw_ret;
1485 } else {
1486 aval = alertpanel( _("Delete address(es)"),
1487 _("Really delete the address(es)?"),
1488 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1489 if( aval != G_ALERTALTERNATE ) {
1490 goto thaw_ret;
1494 /* first, set lists of groups and persons to remove */
1495 node = list;
1496 while( node ) {
1497 item = node->data;
1498 node = g_list_next( node );
1499 aio = ( AddrItemObject * ) item->addressItem;
1500 if (!aio)
1501 continue;
1502 if( aio->type == ITEMTYPE_GROUP ) {
1503 groups = g_list_prepend(groups, item);
1505 else if( aio->type == ITEMTYPE_PERSON ) {
1506 persons = g_list_prepend(persons, item);
1509 /* then set list of emails to remove *if* they're not children of
1510 * persons to remove */
1511 node = list;
1512 while( node ) {
1513 item = node->data;
1514 node = g_list_next( node );
1515 aio = ( AddrItemObject * ) item->addressItem;
1516 if (!aio)
1517 continue;
1518 if( aio->type == ITEMTYPE_EMAIL ) {
1519 ItemEMail *sitem = ( ItemEMail * ) aio;
1520 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1521 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1522 emails = g_list_prepend(emails, item);
1524 /* else, the email will be removed via the parent person */
1527 /* then delete groups */
1528 node = groups;
1529 while( node ) {
1530 item = node->data;
1531 node = g_list_next( node );
1532 aio = ( AddrItemObject * ) item->addressItem;
1533 if (!aio)
1534 continue;
1535 if( aio->type == ITEMTYPE_GROUP ) {
1536 ItemGroup *item = ( ItemGroup * ) aio;
1537 GtkCMCTreeNode *nd = NULL;
1538 nd = addressbook_find_group_node( addrbook.opened, item );
1539 item = addrbook_remove_group( abf, item );
1540 if( item ) {
1541 addritem_free_item_group( item );
1543 /* Remove group from parent node */
1544 gtk_cmctree_remove_node( ctree, nd );
1545 refreshList = TRUE;
1548 /* then delete persons */
1549 node = persons;
1550 while( node ) {
1551 item = node->data;
1552 node = g_list_next( node );
1553 aio = ( AddrItemObject * ) item->addressItem;
1554 if (!aio)
1555 continue;
1556 if( aio->type == ITEMTYPE_PERSON ) {
1557 ItemPerson *item = ( ItemPerson * ) aio;
1558 item->status = DELETE_ENTRY;
1559 addressbook_folder_remove_one_person( clist, item );
1560 if (pobj->type == ADDR_ITEM_FOLDER)
1561 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1562 item = addrbook_remove_person( abf, item );
1563 #ifdef USE_LDAP
1564 if (ds && ds->type == ADDR_IF_LDAP) {
1565 LdapServer *server = ds->rawDataSource;
1566 ldapsvr_set_modified(server, TRUE);
1567 ldapsvr_update_book(server, item);
1569 #endif
1570 if( item ) {
1571 gchar *filename = addritem_person_get_picture(item);
1572 if (filename && is_file_exist(filename))
1573 claws_unlink(filename);
1574 g_free(filename);
1575 addritem_free_item_person( item );
1579 /* then delete emails */
1580 node = emails;
1581 while( node ) {
1582 item = node->data;
1583 node = g_list_next( node );
1584 aio = ( AddrItemObject * ) item->addressItem;
1585 if (!aio)
1586 continue;
1588 if( aio->type == ITEMTYPE_EMAIL ) {
1589 ItemEMail *sitem = ( ItemEMail * ) aio;
1590 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1591 sitem = addrbook_person_remove_email( abf, person, sitem );
1592 if( sitem ) {
1593 addrcache_remove_email(abf->addressCache, sitem);
1594 addritem_free_item_email( sitem );
1596 addressbook_folder_refresh_one_person( clist, person );
1599 g_list_free( groups );
1600 g_list_free( persons );
1601 g_list_free( emails );
1602 g_list_free( list );
1603 addressbook_list_select_clear();
1604 if( refreshList ) {
1605 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1606 addressbook_set_clist(
1607 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1608 addrbook.opened),
1609 TRUE);
1611 addrbook_set_dirty(abf, TRUE);
1612 addressbook_export_to_file();
1613 addressbook_list_menu_setup();
1614 goto thaw_ret;
1616 else if( pobj->type == ADDR_ITEM_GROUP ) {
1617 /* Items inside groups */
1618 list = addrselect_get_list( _addressSelect_ );
1619 node = list;
1620 while( node ) {
1621 item = node->data;
1622 node = g_list_next( node );
1623 aio = ( AddrItemObject * ) item->addressItem;
1624 if( aio->type == ITEMTYPE_EMAIL ) {
1625 ItemEMail *item = ( ItemEMail * ) aio;
1626 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1627 item = addrbook_person_remove_email( abf, person, item );
1628 if( item ) {
1629 addritem_free_item_email( item );
1633 g_list_free( list );
1634 addressbook_list_select_clear();
1635 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1636 addressbook_set_clist(
1637 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1638 addrbook.opened),
1639 TRUE);
1641 addrbook_set_dirty(abf, TRUE);
1642 addressbook_export_to_file();
1643 addressbook_list_menu_setup();
1644 goto thaw_ret;
1647 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1648 gtk_cmctree_remove_node( clist, nodeList );
1649 thaw_ret:
1650 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1651 g_signal_handlers_unblock_by_func
1652 (G_OBJECT(addrbook.clist),
1653 G_CALLBACK(addressbook_list_row_unselected), NULL);
1656 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1658 addressbook_new_address_cb( NULL, NULL );
1661 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1662 gchar *buf = NULL;
1663 gchar *name = NULL;
1664 gchar *address = NULL;
1666 if( aio->type == ITEMTYPE_EMAIL ) {
1667 ItemPerson *person = NULL;
1668 ItemEMail *email = ( ItemEMail * ) aio;
1670 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1671 if( email->address ) {
1672 if( ADDRITEM_NAME(email) ) {
1673 name = ADDRITEM_NAME(email);
1674 if( *name == '\0' ) {
1675 name = ADDRITEM_NAME(person);
1678 else if( ADDRITEM_NAME(person) ) {
1679 name = ADDRITEM_NAME(person);
1681 else {
1682 buf = g_strdup( email->address );
1684 address = email->address;
1687 else if( aio->type == ITEMTYPE_PERSON ) {
1688 ItemPerson *person = ( ItemPerson * ) aio;
1689 GList *node = person->listEMail;
1691 name = ADDRITEM_NAME(person);
1692 if( node ) {
1693 ItemEMail *email = ( ItemEMail * ) node->data;
1694 address = email->address;
1697 if( address ) {
1698 if( name && name[0] != '\0' ) {
1699 if( strchr_with_skip_quote( name, '"', ',' ) )
1700 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1701 else
1702 buf = g_strdup_printf( "%s <%s>", name, address );
1704 else {
1705 buf = g_strdup( address );
1709 return buf;
1712 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1714 GList *list, *node;
1715 Compose *compose;
1716 AddrSelectItem *item;
1717 AddrItemObject *aio;
1718 gchar *addr;
1720 compose = addrbook.target_compose;
1721 if( ! compose ) return;
1723 /* Nothing selected, but maybe there is something in text entry */
1724 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1725 if ( addr ) {
1726 compose_entry_append(
1727 compose, addr, (ComposeEntryType)data , PREF_NONE);
1730 /* Select from address list */
1731 list = addrselect_get_list( _addressSelect_ );
1732 node = list;
1733 if (node) {
1734 while( node ) {
1735 item = node->data;
1736 node = g_list_next( node );
1737 aio = item->addressItem;
1738 if( aio->type == ITEMTYPE_PERSON ||
1739 aio->type == ITEMTYPE_EMAIL ) {
1740 addr = addressbook_format_address( aio );
1741 compose_entry_append(
1742 compose, addr, (ComposeEntryType) data, PREF_NONE );
1743 g_free( addr );
1745 else if( aio->type == ITEMTYPE_GROUP ) {
1746 ItemGroup *group = ( ItemGroup * ) aio;
1747 GList *nodeMail = group->listEMail;
1748 while( nodeMail ) {
1749 ItemEMail *email = nodeMail->data;
1751 addr = addressbook_format_address(
1752 ( AddrItemObject * ) email );
1753 compose_entry_append(
1754 compose, addr, (ComposeEntryType) data, PREF_NONE );
1755 g_free( addr );
1756 nodeMail = g_list_next( nodeMail );
1760 } else {
1761 AddressObject *obj = NULL;
1763 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1765 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1766 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1767 GList *nodeMail = itemGroup->listEMail;
1768 while( nodeMail ) {
1769 ItemEMail *email = nodeMail->data;
1771 addr = addressbook_format_address(
1772 ( AddrItemObject * ) email );
1773 compose_entry_append(
1774 compose, addr, (ComposeEntryType) data, PREF_NONE );
1775 g_free( addr );
1776 nodeMail = g_list_next( nodeMail );
1780 g_list_free( list );
1783 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1796 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1797 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1800 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1801 gboolean canEdit = FALSE;
1802 gboolean canDelete = TRUE;
1803 gboolean canAdd = FALSE;
1804 gboolean canEditTr = TRUE;
1805 gboolean editAddress = FALSE;
1806 gboolean canExport = TRUE;
1807 AddressTypeControlItem *atci = NULL;
1808 AddressDataSource *ds = NULL;
1809 AddressInterface *iface = NULL;
1811 if( obj == NULL ) return;
1812 if( obj->type == ADDR_INTERFACE ) {
1813 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1814 iface = adapter->interface;
1815 if( iface ) {
1816 if( iface->haveLibrary ) {
1817 /* Enable appropriate File / New command */
1818 atci = adapter->atci;
1819 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1822 canEditTr = canExport = FALSE;
1824 else if( obj->type == ADDR_DATASOURCE ) {
1825 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1826 ds = ads->dataSource;
1827 iface = ds->interface;
1828 if( ! iface->readOnly ) {
1829 canAdd = canEdit = editAddress = canDelete = TRUE;
1831 if( ! iface->haveLibrary ) {
1832 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1835 else if( obj->type == ADDR_ITEM_FOLDER ) {
1836 ds = addressbook_find_datasource( addrbook.treeSelected );
1837 if( ds ) {
1838 iface = ds->interface;
1839 if( iface->readOnly ) {
1840 canEditTr = FALSE;
1841 canDelete = FALSE;
1843 else {
1844 canAdd = editAddress = TRUE;
1848 else if( obj->type == ADDR_ITEM_GROUP ) {
1849 ds = addressbook_find_datasource( addrbook.treeSelected );
1850 if( ds ) {
1851 iface = ds->interface;
1852 if( ! iface->readOnly ) {
1853 editAddress = TRUE;
1858 if( addrbook.listSelected == NULL )
1859 canEdit = FALSE;
1861 /* Enable add */
1862 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1863 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1865 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1867 /* Enable edit */
1868 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1870 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1871 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1876 /* Export data */
1877 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1882 * Address book tree callback function that responds to selection of tree
1883 * items.
1885 * \param ctree Tree widget.
1886 * \param node Node that was selected.
1887 * \param column Column number where selected occurred.
1888 * \param data Pointer to user data.
1890 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1891 gint column, gpointer data)
1893 AddressObject *obj = NULL;
1894 AdapterDSource *ads = NULL;
1895 AddressDataSource *ds = NULL;
1896 ItemFolder *rootFolder = NULL;
1897 AddressObjectType aot;
1899 addrbook.treeSelected = node;
1900 addrbook.listSelected = NULL;
1901 addressbook_status_show( "" );
1902 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1904 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1905 if( obj == NULL ) {
1906 addressbook_set_clist(NULL, TRUE);
1907 return;
1909 addrbook.opened = node;
1911 if( obj->type == ADDR_DATASOURCE ) {
1912 /* Read from file */
1913 static gboolean tVal = TRUE;
1915 ads = ADAPTER_DSOURCE(obj);
1917 ds = ads->dataSource;
1918 if( ds == NULL ) return;
1920 if( addrindex_ds_get_modify_flag( ds ) ) {
1921 addrindex_ds_read_data( ds );
1924 if( ! addrindex_ds_get_read_flag( ds ) ) {
1925 addrindex_ds_read_data( ds );
1927 addressbook_ds_show_message( ds );
1929 if( ! addrindex_ds_get_access_flag( ds ) ) {
1930 /* Remove existing folders and groups */
1931 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1932 addressbook_tree_remove_children( ctree, node );
1933 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1935 /* Load folders into the tree */
1936 rootFolder = addrindex_ds_get_root_folder( ds );
1937 if( ds && ds->type == ADDR_IF_JPILOT ) {
1938 aot = ADDR_CATEGORY;
1940 else if( ds && ds->type == ADDR_IF_LDAP ) {
1941 aot = ADDR_LDAP_QUERY;
1943 else {
1944 aot = ADDR_ITEM_FOLDER;
1946 addressbook_node_add_folder( node, ds, rootFolder, aot );
1947 addrindex_ds_set_access_flag( ds, &tVal );
1948 gtk_cmctree_expand( ctree, node );
1950 } else {
1951 addressbook_set_clist(NULL, TRUE);
1954 /* Update address list */
1955 g_signal_handlers_block_by_func
1956 (G_OBJECT(ctree),
1957 G_CALLBACK(addressbook_tree_selected), NULL);
1958 addressbook_set_clist( obj, FALSE );
1959 g_signal_handlers_unblock_by_func
1960 (G_OBJECT(ctree),
1961 G_CALLBACK(addressbook_tree_selected), NULL);
1962 if (!prefs_common.addressbook_use_editaddress_dialog)
1963 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1965 /* Setup main menu selections */
1966 addressbook_menubar_set_sensitive( FALSE );
1967 addressbook_menuitem_set_sensitive( obj, node );
1968 addressbook_list_select_clear();
1969 addressbook_list_menu_setup();
1970 return;
1974 * Setup address list popup menu items. Items are enabled or disabled as
1975 * required.
1977 static void addressbook_list_menu_setup( void ) {
1978 GtkCMCTree *clist = NULL;
1979 AddressObject *pobj = NULL;
1980 AddressObject *obj = NULL;
1981 AdapterDSource *ads = NULL;
1982 AddressInterface *iface = NULL;
1983 AddressDataSource *ds = NULL;
1984 gboolean canEdit = FALSE;
1985 gboolean canDelete = FALSE;
1986 gboolean canCut = FALSE;
1987 gboolean canCopy = FALSE;
1988 gboolean canPaste = FALSE;
1989 gboolean canBrowse = FALSE;
1991 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1992 if( pobj == NULL ) return;
1994 clist = GTK_CMCTREE(addrbook.clist);
1995 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
1996 if( obj == NULL ) canEdit = FALSE;
1998 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1999 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2001 if( pobj->type == ADDR_DATASOURCE ) {
2002 /* Parent object is a data source */
2003 ads = ADAPTER_DSOURCE(pobj);
2004 ds = ads->dataSource;
2005 if (!ds)
2006 return;
2007 iface = ds->interface;
2008 if (!iface)
2009 return;
2010 if( ! iface->readOnly ) {
2011 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2012 if (iface->type != ADDR_IF_LDAP)
2013 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2014 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2015 if( obj )
2016 canEdit = TRUE;
2017 canDelete = canEdit;
2020 else if( pobj->type != ADDR_INTERFACE ) {
2021 /* Parent object is not an interface */
2022 ds = addressbook_find_datasource( addrbook.treeSelected );
2023 if (!ds)
2024 return;
2025 iface = ds->interface;
2026 if (!iface)
2027 return;
2028 if( ! iface->readOnly ) {
2029 /* Folder or group */
2030 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2031 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2032 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2033 if( obj ) canEdit = TRUE;
2035 /* Folder */
2036 if( pobj->type == ADDR_ITEM_FOLDER ) {
2037 if (iface->type != ADDR_IF_LDAP)
2038 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2039 if( obj ) canEdit = TRUE;
2041 canDelete = canEdit;
2043 if( iface->type == ADDR_IF_LDAP ) {
2044 if( obj ) canBrowse = TRUE;
2045 canEdit = TRUE;
2046 canDelete = TRUE;
2050 if( iface ) {
2051 /* Enable cut and paste */
2052 if( ! addrclip_is_empty( _clipBoard_ ) )
2053 canPaste = TRUE;
2054 if( ! addrselect_test_empty( _addressSelect_ ) )
2055 canCut = TRUE;
2056 /* Enable copy if something is selected */
2057 if( ! addrselect_test_empty( _addressSelect_ ) )
2058 canCopy = TRUE;
2061 /* Disable edit or browse if more than one row selected */
2062 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2063 canEdit = FALSE;
2064 canBrowse = FALSE;
2067 /* Forbid write changes when read-only */
2068 if( iface && iface->readOnly ) {
2069 canCut = FALSE;
2070 canDelete = FALSE;
2071 canPaste = FALSE;
2074 /* Now go finalize menu items */
2075 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2076 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2078 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2079 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2082 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2084 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2085 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2086 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2088 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2092 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2093 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2095 if (addrbook.target_compose) {
2096 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2097 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2098 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2100 #ifdef USE_LDAP
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2102 #endif
2105 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2106 GtkCMCTreeNode *node,
2107 gint column,
2108 gpointer data)
2113 * Add list of items into tree node below specified tree node.
2114 * \param treeNode Tree node.
2115 * \param ds Data source.
2116 * \param listItems List of items.
2118 static void addressbook_treenode_add_list(
2119 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2121 GList *node;
2123 node = listItems;
2124 while( node ) {
2125 AddrItemObject *aio;
2126 GtkCMCTreeNode *nn;
2128 aio = node->data;
2129 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2130 ItemGroup *group;
2132 group = ( ItemGroup * ) aio;
2133 nn = addressbook_node_add_group( treeNode, ds, group );
2134 if (nn == NULL) {
2135 g_message("error adding addressbook group\n");
2138 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2139 ItemFolder *folder;
2141 folder = ( ItemFolder * ) aio;
2142 nn = addressbook_node_add_folder(
2143 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2144 if (nn == NULL) {
2145 g_message("error adding addressbook folder\n");
2148 node = g_list_next( node );
2152 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2153 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2157 * Cut from address list widget.
2159 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2160 _clipBoard_->cutFlag = TRUE;
2161 addrclip_clear( _clipBoard_ );
2162 addrclip_add( _clipBoard_, _addressSelect_ );
2163 /* addrclip_list_show( _clipBoard_, stdout ); */
2167 * Copy from address list widget.
2169 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2170 _clipBoard_->cutFlag = FALSE;
2171 addrclip_clear( _clipBoard_ );
2172 addrclip_add( _clipBoard_, _addressSelect_ );
2173 /* addrclip_list_show( _clipBoard_, stdout ); */
2177 * Paste clipboard into address list widget.
2179 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2180 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2181 AddressObject *pobj = NULL;
2182 AddressDataSource *ds = NULL;
2183 AddressBookFile *abf = NULL;
2184 ItemFolder *folder = NULL;
2185 GList *folderGroup = NULL;
2187 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2188 if( ds == NULL ) return;
2189 if( addrindex_ds_get_readonly( ds ) ) {
2190 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2191 return;
2194 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2195 if( pobj ) {
2196 if( pobj->type == ADDR_ITEM_FOLDER ) {
2197 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2199 else if( pobj->type == ADDR_ITEM_GROUP ) {
2200 alertpanel_error( _("Cannot paste into an address group.") );
2201 return;
2205 /* Get an address book */
2206 abf = addressbook_get_book_file();
2207 if( abf == NULL ) return;
2209 if( _clipBoard_->cutFlag ) {
2210 /* Paste/Cut */
2211 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2213 /* Remove all groups and folders in clipboard from tree node */
2214 addressbook_treenode_remove_item();
2216 /* Remove all "cut" items */
2217 addrclip_delete_item( _clipBoard_ );
2219 /* Clear clipboard - cut items??? */
2220 addrclip_clear( _clipBoard_ );
2222 else {
2223 /* Paste/Copy */
2224 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2227 /* addrclip_list_show( _clipBoard_, stdout ); */
2228 if( folderGroup ) {
2229 /* Update tree by inserting node for each folder or group */
2230 addressbook_treenode_add_list(
2231 addrbook.treeSelected, ds, folderGroup );
2232 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2233 g_list_free( folderGroup );
2234 folderGroup = NULL;
2237 /* Display items pasted */
2238 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2239 addressbook_set_clist(
2240 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2241 addrbook.opened),
2242 TRUE);
2248 * Add current treenode object to clipboard. Note that widget only allows
2249 * one entry from the tree list to be selected.
2251 static void addressbook_treenode_to_clipboard( void ) {
2252 AddressObject *obj = NULL;
2253 AddressDataSource *ds = NULL;
2254 AddrSelectItem *item;
2255 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2256 GtkCMCTreeNode *node;
2258 node = addrbook.treeSelected;
2259 if( node == NULL ) return;
2260 obj = gtk_cmctree_node_get_row_data( ctree, node );
2261 if( obj == NULL ) return;
2263 ds = addressbook_find_datasource( node );
2264 if( ds == NULL ) return;
2266 item = NULL;
2267 if( obj->type == ADDR_ITEM_FOLDER ) {
2268 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2269 ItemFolder *folder = adapter->itemFolder;
2271 item = addrselect_create_node( obj );
2272 item->uid = g_strdup( ADDRITEM_ID(folder) );
2274 else if( obj->type == ADDR_ITEM_GROUP ) {
2275 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2276 ItemGroup *group = adapter->itemGroup;
2278 item = addrselect_create_node( obj );
2279 item->uid = g_strdup( ADDRITEM_ID(group) );
2281 else if( obj->type == ADDR_DATASOURCE ) {
2282 /* Data source */
2283 item = addrselect_create_node( obj );
2284 item->uid = NULL;
2287 if( item ) {
2288 /* Clear existing list and add item into list */
2289 gchar *cacheID;
2291 addressbook_list_select_clear();
2292 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2293 addrselect_list_add( _addressSelect_, item, cacheID );
2294 g_free( cacheID );
2299 * Cut from tree widget.
2301 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2302 _clipBoard_->cutFlag = TRUE;
2303 addressbook_treenode_to_clipboard();
2304 addrclip_clear( _clipBoard_ );
2305 addrclip_add( _clipBoard_, _addressSelect_ );
2306 /* addrclip_list_show( _clipBoard_, stdout ); */
2310 * Copy from tree widget.
2312 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2313 _clipBoard_->cutFlag = FALSE;
2314 addressbook_treenode_to_clipboard();
2315 addrclip_clear( _clipBoard_ );
2316 addrclip_add( _clipBoard_, _addressSelect_ );
2317 /* addrclip_list_show( _clipBoard_, stdout ); */
2321 * Paste clipboard into address tree widget.
2323 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2324 addressbook_clip_paste_cb(NULL,NULL);
2328 * Clear selected entries in clipboard.
2330 static void addressbook_list_select_clear( void ) {
2331 addrselect_list_clear( _addressSelect_ );
2335 * Add specified address item to selected address list.
2336 * \param aio Address item object.
2337 * \param ds Datasource.
2339 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2340 gchar *cacheID;
2342 if( ds == NULL ) return;
2343 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2344 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2345 g_free( cacheID );
2349 * Remove specified address item from selected address list.
2350 * \param aio Address item object.
2352 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2353 addrselect_list_remove( _addressSelect_, aio );
2357 * Invoke EMail compose window with addresses in selected address list.
2359 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2360 GList *listAddress;
2362 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2363 listAddress = addrselect_build_list( _addressSelect_ );
2364 compose_new_with_list( NULL, listAddress );
2365 mgu_free_dlist( listAddress );
2366 listAddress = NULL;
2370 static void addressbook_list_row_selected( GtkCMCTree *clist,
2371 GtkCMCTreeNode *node,
2372 gint column,
2373 gpointer data )
2375 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2376 AddrItemObject *aio = NULL;
2377 AddressObject *pobj = NULL;
2378 AdapterDSource *ads = NULL;
2379 AddressDataSource *ds = NULL;
2381 gtk_entry_set_text( entry, "" );
2382 addrbook.listSelected = node;
2384 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2385 if( pobj == NULL ) return;
2387 if( pobj->type == ADDR_DATASOURCE ) {
2388 ads = ADAPTER_DSOURCE(pobj);
2389 ds = ads->dataSource;
2391 else if( pobj->type != ADDR_INTERFACE ) {
2392 ds = addressbook_find_datasource( addrbook.treeSelected );
2395 aio = gtk_cmctree_node_get_row_data( clist, node );
2396 if( aio ) {
2397 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2398 addressbook_list_select_add( aio, ds );
2401 addressbook_list_menu_setup();
2403 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2404 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2406 if (obj && obj->type != ADDR_ITEM_GROUP)
2407 addressbook_edit_address(NULL, 0, NULL, FALSE);
2411 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2412 GtkCMCTreeNode *node,
2413 gint column,
2414 gpointer data )
2416 AddrItemObject *aio;
2418 aio = gtk_cmctree_node_get_row_data( ctree, node );
2419 if( aio != NULL ) {
2420 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2421 addressbook_list_select_remove( aio );
2424 if (!prefs_common.addressbook_use_editaddress_dialog)
2425 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2428 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2429 GdkEventButton *event,
2430 gpointer data)
2432 if( ! event ) return FALSE;
2434 addressbook_list_menu_setup();
2436 if( event->button == 3 ) {
2437 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2438 event->button, event->time );
2439 } else if (event->button == 1) {
2440 if (event->type == GDK_2BUTTON_PRESS) {
2441 if (prefs_common.add_address_by_click &&
2442 addrbook.target_compose)
2443 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2444 else
2445 if (prefs_common.addressbook_use_editaddress_dialog)
2446 addressbook_edit_address_cb(NULL, NULL);
2447 else {
2448 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2449 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2450 if( obj && obj->type == ADDR_ITEM_GROUP )
2451 addressbook_edit_address_cb(NULL, NULL);
2456 return FALSE;
2459 static gboolean addressbook_list_button_released(GtkWidget *widget,
2460 GdkEventButton *event,
2461 gpointer data)
2463 return FALSE;
2466 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2467 GdkEventButton *event,
2468 gpointer data)
2470 GtkCMCList *clist = GTK_CMCLIST(ctree);
2471 gint row, column;
2472 AddressObject *obj = NULL;
2473 AdapterDSource *ads = NULL;
2474 AddressInterface *iface = NULL;
2475 AddressDataSource *ds = NULL;
2476 gboolean canEdit = FALSE;
2477 gboolean canDelete = FALSE;
2478 gboolean canCut = FALSE;
2479 gboolean canCopy = FALSE;
2480 gboolean canPaste = FALSE;
2481 gboolean canTreeCut = FALSE;
2482 gboolean canTreeCopy = FALSE;
2483 gboolean canTreePaste = FALSE;
2484 gboolean canLookup = FALSE;
2485 GtkCMCTreeNode *node = NULL;
2487 if( ! event ) return FALSE;
2488 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2490 if (event->button == 1) {
2491 if (event->type == GDK_2BUTTON_PRESS) {
2492 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2493 gtkut_clist_set_focus_row(clist, row);
2494 obj = gtk_cmclist_get_row_data( clist, row );
2496 if( obj == NULL )
2497 return FALSE;
2499 if (obj->type == ADDR_ITEM_GROUP) {
2500 /* edit group */
2501 addressbook_treenode_edit_cb(NULL, NULL);
2502 } else {
2503 /* expand pr collapse */
2504 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2505 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2507 return FALSE;
2511 addressbook_menubar_set_sensitive( FALSE );
2513 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2514 gtkut_clist_set_focus_row(clist, row);
2515 obj = gtk_cmclist_get_row_data( clist, row );
2518 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2520 if( obj == NULL )
2521 return FALSE;
2522 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2524 if( ! addrclip_is_empty( _clipBoard_ ) )
2525 canTreePaste = TRUE;
2527 if (obj->type == ADDR_INTERFACE) {
2528 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2529 iface = adapter->interface;
2530 if( !iface )
2531 goto just_set_sens;
2532 if( !iface->readOnly ) {
2533 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2534 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2536 if( iface->externalQuery )
2537 canLookup = TRUE;
2539 if (obj->type == ADDR_DATASOURCE) {
2540 ads = ADAPTER_DSOURCE(obj);
2541 ds = ads->dataSource;
2542 if( !ds )
2543 goto just_set_sens;
2544 iface = ds->interface;
2545 if( !iface )
2546 goto just_set_sens;
2547 if( !iface->readOnly ) {
2548 canDelete = TRUE;
2549 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2550 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2551 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2553 canEdit = TRUE;
2554 canTreeCopy = TRUE;
2555 if( iface->externalQuery )
2556 canLookup = TRUE;
2558 else if (obj->type == ADDR_ITEM_FOLDER) {
2559 ds = addressbook_find_datasource( node );
2560 if( !ds )
2561 goto just_set_sens;
2562 iface = ds->interface;
2563 if( !iface )
2564 goto just_set_sens;
2565 if( !iface->readOnly ) {
2566 canEdit = TRUE;
2567 canDelete = TRUE;
2568 canTreeCut = TRUE;
2569 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2570 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2571 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2573 canTreeCopy = TRUE;
2575 if( iface->externalQuery ) {
2576 /* Enable deletion of LDAP folder */
2577 canLookup = TRUE;
2578 canDelete = TRUE;
2581 else if (obj->type == ADDR_ITEM_GROUP) {
2582 ds = addressbook_find_datasource( node );
2583 if( !ds )
2584 goto just_set_sens;
2585 iface = ds->interface;
2586 if( !iface )
2587 goto just_set_sens;
2588 if( ! iface->readOnly ) {
2589 canEdit = TRUE;
2590 canDelete = TRUE;
2591 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2592 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2596 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2597 canCut = TRUE;
2598 if( ! addrselect_test_empty( _addressSelect_ ) )
2599 canCopy = TRUE;
2600 if( ! addrclip_is_empty( _clipBoard_ ) )
2601 canPaste = TRUE;
2603 /* Forbid write changes when read-only */
2604 if( iface && iface->readOnly ) {
2605 canTreeCut = FALSE;
2606 canTreePaste = FALSE;
2607 canCut = FALSE;
2608 canDelete = FALSE;
2609 canPaste = FALSE;
2612 just_set_sens:
2613 /* Enable edit */
2614 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2615 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2616 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2617 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2618 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2626 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2627 addrbook.target_compose != NULL);
2629 if( event->button == 3 )
2630 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2631 event->button, event->time);
2633 return FALSE;
2636 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2637 GdkEventButton *event,
2638 gpointer data)
2640 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2641 return FALSE;
2644 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2646 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2647 AddressObject *obj = NULL;
2648 AddressDataSource *ds = NULL;
2649 AddressBookFile *abf = NULL;
2650 ItemFolder *parentFolder = NULL;
2651 ItemFolder *folder = NULL;
2653 if( ! addrbook.treeSelected ) return;
2654 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2655 if( obj == NULL ) return;
2656 ds = addressbook_find_datasource( addrbook.treeSelected );
2657 if( ds == NULL ) return;
2659 if( obj->type == ADDR_DATASOURCE ) {
2660 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2662 else if( obj->type == ADDR_ITEM_FOLDER ) {
2663 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2665 else {
2666 return;
2669 abf = ds->rawDataSource;
2670 if( abf == NULL ) return;
2671 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2672 if( folder ) {
2673 GtkCMCTreeNode *nn;
2674 nn = addressbook_node_add_folder(
2675 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2676 if (nn == NULL) {
2677 g_message("error adding addressbook folder\n");
2679 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2680 if( addrbook.treeSelected == addrbook.opened )
2681 addressbook_set_clist(obj, TRUE);
2685 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2687 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2688 AddressObject *obj = NULL;
2689 AddressDataSource *ds = NULL;
2690 AddressBookFile *abf = NULL;
2691 ItemFolder *parentFolder = NULL;
2692 ItemGroup *group = NULL;
2694 if( ! addrbook.treeSelected ) return;
2695 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2696 if( obj == NULL ) return;
2697 ds = addressbook_find_datasource( addrbook.treeSelected );
2698 if( ds == NULL ) return;
2700 if( obj->type == ADDR_DATASOURCE ) {
2701 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2703 else if( obj->type == ADDR_ITEM_FOLDER ) {
2704 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2706 else {
2707 return;
2710 abf = ds->rawDataSource;
2711 if( abf == NULL ) return;
2712 group = addressbook_edit_group( abf, parentFolder, NULL );
2713 if( group ) {
2714 GtkCMCTreeNode *nn;
2715 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2716 if (nn == NULL) {
2717 g_message("error adding addressbook group\n");
2719 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2720 if( addrbook.treeSelected == addrbook.opened )
2721 addressbook_set_clist(obj, TRUE);
2725 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2727 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2728 gchar *text[1];
2729 guint8 spacing;
2730 GdkPixbuf *pix_cl, *pix_op;
2731 gboolean is_leaf, expanded;
2733 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2734 &pix_cl, &pix_op,
2735 &is_leaf, &expanded);
2736 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2737 pix_cl, pix_op,
2738 is_leaf, expanded);
2742 * Edit data source.
2743 * \param obj Address object to edit.
2744 * \param node Node in tree.
2745 * \return New name of data source.
2747 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2748 gchar *newName = NULL;
2749 AddressDataSource *ds = NULL;
2750 AddressInterface *iface = NULL;
2751 AdapterDSource *ads = NULL;
2753 ds = addressbook_find_datasource( node );
2754 if( ds == NULL ) return NULL;
2755 iface = ds->interface;
2756 if( ! iface->haveLibrary ) return NULL;
2758 /* Read data from data source */
2759 if( addrindex_ds_get_modify_flag( ds ) ) {
2760 addrindex_ds_read_data( ds );
2763 if( ! addrindex_ds_get_read_flag( ds ) ) {
2764 addrindex_ds_read_data( ds );
2767 /* Handle edit */
2768 ads = ADAPTER_DSOURCE(obj);
2769 if( ads->subType == ADDR_BOOK ) {
2770 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2772 else if( ads->subType == ADDR_VCARD ) {
2773 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2775 #ifdef USE_JPILOT
2776 else if( ads->subType == ADDR_JPILOT ) {
2777 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2779 #endif
2780 #ifdef USE_LDAP
2781 else if( ads->subType == ADDR_LDAP ) {
2782 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2784 #endif
2785 else {
2786 return NULL;
2788 newName = obj->name;
2789 return newName;
2793 * Edit an object that is in the address tree area.
2795 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2797 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2798 AddressObject *obj;
2799 AddressDataSource *ds = NULL;
2800 AddressBookFile *abf = NULL;
2801 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2802 gchar *name = NULL;
2804 if( ! addrbook.treeSelected ) return;
2805 node = addrbook.treeSelected;
2806 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2807 obj = gtk_cmctree_node_get_row_data( ctree, node );
2808 if( obj == NULL ) return;
2809 parentNode = GTK_CMCTREE_ROW(node)->parent;
2811 ds = addressbook_find_datasource( node );
2812 if( ds == NULL ) return;
2814 if( obj->type == ADDR_DATASOURCE ) {
2815 name = addressbook_edit_datasource( obj, node );
2816 if( name == NULL ) return;
2818 else {
2819 abf = ds->rawDataSource;
2820 if( abf == NULL ) return;
2821 if( obj->type == ADDR_ITEM_FOLDER ) {
2822 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2823 ItemFolder *item = adapter->itemFolder;
2824 ItemFolder *parentFolder = NULL;
2825 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2826 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2827 name = ADDRITEM_NAME(item);
2829 else if( obj->type == ADDR_ITEM_GROUP ) {
2830 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2831 ItemGroup *item = adapter->itemGroup;
2832 ItemFolder *parentFolder = NULL;
2833 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2834 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2835 name = ADDRITEM_NAME(item);
2838 if( name && parentNode ) {
2839 /* Update node in tree view */
2840 addressbook_change_node_name( node, name );
2841 gtk_sctree_sort_node(ctree, parentNode);
2842 gtk_cmctree_expand( ctree, node );
2843 gtk_sctree_select( GTK_SCTREE( ctree), node );
2847 typedef enum {
2848 ADDRTREE_DEL_NONE,
2849 ADDRTREE_DEL_DATA,
2850 ADDRTREE_DEL_FOLDER_ONLY,
2851 ADDRTREE_DEL_FOLDER_ADDR
2852 } TreeItemDelType ;
2855 * Delete an item from the tree widget.
2856 * \param data Data passed in.
2857 * \param action Action.
2858 * \param widget Widget issuing callback.
2860 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2862 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2863 GtkCMCTreeNode *node = NULL;
2864 AddressObject *obj;
2865 gchar *message;
2866 AlertValue aval;
2867 AddrBookBase *adbase;
2868 AddressCache *cache;
2869 AdapterDSource *ads = NULL;
2870 AddressInterface *iface = NULL;
2871 AddressDataSource *ds = NULL;
2872 gboolean remFlag = FALSE;
2873 TreeItemDelType delType;
2875 if( ! addrbook.treeSelected ) return;
2876 node = addrbook.treeSelected;
2877 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2879 obj = gtk_cmctree_node_get_row_data( ctree, node );
2880 cm_return_if_fail(obj != NULL);
2882 if( obj->type == ADDR_DATASOURCE ) {
2883 ads = ADAPTER_DSOURCE(obj);
2885 ds = ads->dataSource;
2886 if( ds == NULL ) return;
2888 else {
2889 /* Must be folder or something else */
2890 ds = addressbook_find_datasource( node );
2891 if( ds == NULL ) return;
2893 /* Only allow deletion from non-readOnly */
2894 iface = ds->interface;
2895 if( iface->readOnly ) {
2896 /* Allow deletion of query results */
2897 if( ! iface->externalQuery ) return;
2901 /* Confirm deletion */
2902 delType = ADDRTREE_DEL_NONE;
2903 if( obj->type == ADDR_ITEM_FOLDER ) {
2904 if( iface && iface->externalQuery ) {
2905 message = g_strdup_printf( _(
2906 "Do you want to delete the query " \
2907 "results and addresses in '%s'?" ),
2908 obj->name );
2909 aval = alertpanel( _("Delete"), message,
2910 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2911 g_free(message);
2912 if( aval == G_ALERTALTERNATE ) {
2913 delType = ADDRTREE_DEL_FOLDER_ADDR;
2916 else {
2917 message = g_strdup_printf
2918 ( _( "Do you want to delete '%s'? "
2919 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2920 obj->name );
2921 aval = alertpanel( _("Delete folder"), message,
2922 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2923 g_free(message);
2924 if( aval == G_ALERTALTERNATE ) {
2925 delType = ADDRTREE_DEL_FOLDER_ONLY;
2927 else if( aval == G_ALERTOTHER ) {
2928 delType = ADDRTREE_DEL_FOLDER_ADDR;
2932 else if( obj->type == ADDR_ITEM_GROUP ) {
2933 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2934 "The addresses it contains will not be lost."), obj->name);
2935 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2936 "+" GTK_STOCK_DELETE, NULL);
2937 g_free(message);
2938 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2939 } else {
2940 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2941 "The addresses it contains will be lost."), obj->name);
2942 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2943 "+" GTK_STOCK_DELETE, NULL);
2944 g_free(message);
2945 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2947 if( delType == ADDRTREE_DEL_NONE ) return;
2949 /* Proceed with deletion */
2950 if( obj->type == ADDR_DATASOURCE ) {
2951 /* Remove node from tree */
2952 gtk_cmctree_remove_node( ctree, node );
2954 if (delType == ADDRTREE_DEL_DATA &&
2955 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2956 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2958 /* Remove data source. */
2959 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2960 addrindex_free_datasource( ds );
2962 return;
2965 /* Get reference to cache */
2966 adbase = ( AddrBookBase * ) ds->rawDataSource;
2967 if( adbase == NULL ) return;
2968 cache = adbase->addressCache;
2970 /* Remove query results folder */
2971 if( iface && iface->externalQuery ) {
2972 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2973 ItemFolder *folder = adapter->itemFolder;
2975 adapter->itemFolder = NULL;
2977 g_print( "remove folder for ::%s::\n", obj->name );
2978 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2979 g_print( "-------------- remove results\n" );
2981 addrindex_remove_results( ds, folder );
2982 /* g_print( "-------------- remove node\n" ); */
2983 gtk_cmctree_remove_node( ctree, node );
2984 return;
2987 /* Code below is valid for regular address book deletion */
2988 if( obj->type == ADDR_ITEM_FOLDER ) {
2989 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2990 ItemFolder *item = adapter->itemFolder;
2992 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2993 /* Remove folder only */
2994 item = addrcache_remove_folder( cache, item );
2995 if( item ) {
2996 addritem_free_item_folder( item );
2997 addressbook_move_nodes_up( ctree, node );
2998 remFlag = TRUE;
3001 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3002 /* Remove folder and addresses */
3003 item = addrcache_remove_folder_delete( cache, item );
3004 if( item ) {
3005 addritem_free_item_folder( item );
3006 remFlag = TRUE;
3010 else if( obj->type == ADDR_ITEM_GROUP ) {
3011 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3012 ItemGroup *item = adapter->itemGroup;
3014 item = addrcache_remove_group( cache, item );
3015 if( item ) {
3016 addritem_free_item_group( item );
3017 remFlag = TRUE;
3021 if( remFlag ) {
3022 /* Remove node. */
3023 gtk_cmctree_remove_node(ctree, node );
3027 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3029 if( person && addrbook.treeSelected == addrbook.opened ) {
3030 person->status = ADD_ENTRY;
3031 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3032 addressbook_folder_refresh_one_person(
3033 GTK_CMCTREE(addrbook.clist), person );
3035 addressbook_address_list_set_focus();
3038 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3040 if( person && addrbook.treeSelected == addrbook.opened) {
3041 person->status = ADD_ENTRY;
3042 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3043 addressbook_set_clist(
3044 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3045 addrbook.opened),
3046 TRUE);
3048 addressbook_address_list_set_focus();
3052 * Label (a format string) that is used to name each folder.
3054 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3057 * Search ctree widget callback function.
3058 * \param pA Pointer to node.
3059 * \param pB Pointer to data item being sought.
3060 * \return Zero (0) if folder found.
3062 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3063 AddressObject *aoA;
3065 aoA = ( AddressObject * ) pA;
3066 if( aoA->type == ADDR_ITEM_FOLDER ) {
3067 ItemFolder *folder, *fld;
3069 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3070 folder = ( ItemFolder * ) pB;
3071 if( fld == folder ) return 0; /* Found folder */
3073 return 1;
3076 static ItemFolder * addressbook_setup_subf(
3077 AddressDataSource *ds, gchar *title,
3078 GtkCMCTreeNode *pNode )
3080 AddrBookBase *adbase;
3081 AddressCache *cache;
3082 ItemFolder *folder;
3083 GtkCMCTree *ctree;
3084 GtkCMCTreeNode *nNode;
3085 gchar *name;
3086 AddressObjectType aoType = ADDR_NONE;
3087 GList *children;
3088 /* Setup a query */
3089 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3091 if( ds && ds->type == ADDR_IF_LDAP ) {
3092 #if USE_LDAP
3093 aoType = ADDR_LDAP_QUERY;
3094 #endif
3096 else {
3097 return NULL;
3100 ctree = GTK_CMCTREE(addrbook.ctree);
3101 /* Get reference to address cache */
3102 adbase = ( AddrBookBase * ) ds->rawDataSource;
3103 cache = adbase->addressCache;
3105 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3106 GList *cur = children;
3107 for (; cur; cur = cur->next) {
3108 ItemFolder *child = (ItemFolder *) cur->data;
3109 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3110 nNode = gtk_cmctree_find_by_row_data_custom(
3111 ctree, NULL, child,
3112 addressbook_treenode_find_folder_cb );
3113 if( nNode ) {
3114 addrindex_remove_results( ds, child );
3115 while( child->listPerson ) {
3116 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3117 item = addrcache_remove_person( cache, item );
3118 if( item ) {
3119 addritem_free_item_person( item );
3120 item = NULL;
3123 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3124 addrbook.treeSelected = nNode;
3126 return child;
3131 /* Create a folder */
3132 folder = addrcache_add_new_folder( cache, NULL );
3133 name = g_strdup_printf( "%s", title );
3134 addritem_folder_set_name( folder, name );
3135 addritem_folder_set_remarks( folder, "" );
3136 g_free( name );
3138 /* Now let's see the folder */
3139 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3140 gtk_cmctree_expand( ctree, pNode );
3141 if( nNode ) {
3142 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3143 addrbook.treeSelected = nNode;
3144 return folder;
3146 return NULL;
3149 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3150 AddressObject *pobj = NULL;
3151 AddressDataSource *ds = NULL;
3152 AddressBookFile *abf = NULL;
3153 debug_print("adding address\n");
3154 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3155 if( pobj == NULL ) {
3156 debug_print("no row data\n");
3157 return;
3159 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3160 if( ds == NULL ) {
3161 debug_print("no datasource\n");
3162 return;
3165 abf = ds->rawDataSource;
3166 if( abf == NULL ) {
3167 g_print("no addressbook file\n");
3168 return;
3171 if( pobj->type == ADDR_DATASOURCE ) {
3172 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3173 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3174 ItemPerson *person;
3175 ItemFolder *folder = NULL;
3176 #ifdef USE_LDAP
3177 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3178 GtkCMCTreeNode *parentNode;
3179 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3180 if( ds == NULL ) return;
3182 /* We must have a datasource that is an external interface */
3183 if( ! ds->interface->haveLibrary ) return;
3184 if( ! ds->interface->externalQuery ) return;
3186 if( pobj->type == ADDR_ITEM_FOLDER ) {
3187 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3189 else {
3190 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3192 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3194 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3195 if (ds)
3196 abf = ds->rawDataSource;
3198 #endif
3199 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3200 addrbook.editaddress_vbox,
3201 addressbook_new_address_from_book_post_cb,
3202 TRUE );
3203 #ifdef USE_LDAP
3204 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3205 LdapServer *server = ds->rawDataSource;
3206 ldapsvr_set_modified(server, TRUE);
3207 ldapsvr_update_book(server, NULL);
3208 if (server->retVal != LDAPRC_SUCCESS) {
3209 alertpanel( _("Add address(es)"),
3210 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3211 GTK_STOCK_CLOSE, NULL, NULL );
3212 server->retVal = LDAPRC_SUCCESS;
3213 return;
3216 #endif
3217 if (prefs_common.addressbook_use_editaddress_dialog)
3218 addressbook_new_address_from_book_post_cb( person );
3221 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3222 /* New address */
3223 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3224 ItemPerson *person;
3225 #ifdef USE_LDAP
3226 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3227 GtkCMCTreeNode *parentNode;
3228 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3229 if( ds == NULL ) return;
3231 /* We must have a datasource that is an external interface */
3232 if( ! ds->interface->haveLibrary ) return;
3233 if( ! ds->interface->externalQuery ) return;
3235 if( pobj->type == ADDR_ITEM_FOLDER ) {
3236 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3238 else {
3239 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3241 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3242 if (!folder)
3243 return;
3245 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3246 if (ds)
3247 abf = ds->rawDataSource;
3249 #endif
3250 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3251 addrbook.editaddress_vbox,
3252 addressbook_new_address_from_folder_post_cb,
3253 TRUE );
3254 #ifdef USE_LDAP
3255 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3256 LdapServer *server = ds->rawDataSource;
3257 ldapsvr_set_modified(server, TRUE);
3258 ldapsvr_update_book(server, NULL);
3259 if (server->retVal != LDAPRC_SUCCESS) {
3260 alertpanel( _("Add address(es)"),
3261 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3262 GTK_STOCK_CLOSE, NULL, NULL );
3263 return;
3266 #endif
3267 if (prefs_common.addressbook_use_editaddress_dialog)
3268 addressbook_new_address_from_folder_post_cb( person );
3270 else if( pobj->type == ADDR_ITEM_GROUP ) {
3271 /* New address in group */
3272 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3273 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3274 if (addrbook.treeSelected == addrbook.opened) {
3275 /* Change node name in tree. */
3276 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3277 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3278 addressbook_set_clist(
3279 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3280 addrbook.opened),
3281 TRUE);
3287 * Search for specified child group node in address index tree.
3288 * \param parent Parent node.
3289 * \param group Group to find.
3291 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3292 GtkCMCTreeNode *node = NULL;
3293 GtkCMCTreeRow *currRow;
3295 currRow = GTK_CMCTREE_ROW( parent );
3296 if( currRow ) {
3297 node = currRow->children;
3298 while( node ) {
3299 AddressObject *obj;
3301 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3302 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3303 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3304 if( g == group ) return node;
3306 currRow = GTK_CMCTREE_ROW(node);
3307 node = currRow->sibling;
3310 return NULL;
3313 static AddressBookFile *addressbook_get_book_file() {
3314 AddressBookFile *abf = NULL;
3315 AddressDataSource *ds = NULL;
3317 ds = addressbook_find_datasource( addrbook.treeSelected );
3318 if( ds == NULL ) return NULL;
3319 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3320 return abf;
3323 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3324 GtkCMCTreeNode *node;
3325 GtkCMCTreeRow *row;
3327 /* Remove existing folders and groups */
3328 row = GTK_CMCTREE_ROW( parent );
3329 if( row ) {
3330 while( (node = row->children) ) {
3331 gtk_cmctree_remove_node( ctree, node );
3336 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3337 GtkCMCTreeNode *parent, *child;
3338 GtkCMCTreeRow *currRow;
3339 currRow = GTK_CMCTREE_ROW( node );
3340 if( currRow ) {
3341 parent = currRow->parent;
3342 while( (child = currRow->children) ) {
3343 gtk_cmctree_move( ctree, child, parent, node );
3345 gtk_sctree_sort_node( ctree, parent );
3349 static void addressbook_edit_address_post_cb( ItemPerson *person )
3351 if( person ) {
3352 #ifdef USE_LDAP
3353 AddressBookFile *abf = addressbook_get_book_file();
3355 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3356 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3357 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3359 #endif
3360 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3361 invalidate_address_completion();
3363 addressbook_address_list_set_focus();
3366 void addressbook_address_list_set_focus( void )
3368 if (!prefs_common.addressbook_use_editaddress_dialog) {
3369 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3370 addressbook_list_menu_setup();
3374 void addressbook_address_list_disable_some_actions(void)
3376 /* disable address copy/pasting when editing contact's detail (embedded form) */
3377 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3378 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3379 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3382 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3383 addressbook_edit_address(data, 0, NULL, TRUE);
3386 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3387 gboolean force_focus ) {
3388 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3389 GtkCMCTree *ctree;
3390 AddressObject *obj = NULL, *pobj = NULL;
3391 AddressDataSource *ds = NULL;
3392 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3393 gchar *name = NULL;
3394 AddressBookFile *abf = NULL;
3396 if( addrbook.listSelected == NULL ) return;
3397 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3398 cm_return_if_fail(obj != NULL);
3400 ctree = GTK_CMCTREE( addrbook.ctree );
3401 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3403 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3404 if( ds == NULL ) return;
3406 abf = addressbook_get_book_file();
3408 if( obj->type == ADDR_ITEM_EMAIL ) {
3409 ItemEMail *email = ( ItemEMail * ) obj;
3411 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3412 /* Edit parent group */
3413 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3414 ItemGroup *itemGrp = adapter->itemGroup;
3415 if( abf == NULL ) return;
3416 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3417 name = ADDRITEM_NAME(itemGrp);
3418 node = addrbook.treeSelected;
3419 parentNode = GTK_CMCTREE_ROW(node)->parent;
3421 else {
3422 /* Edit person - email page */
3423 ItemPerson *person;
3424 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3425 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3426 addressbook_edit_address_post_cb,
3427 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3428 != NULL ) {
3429 #ifdef USE_LDAP
3430 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3431 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3432 person->status = UPDATE_ENTRY;
3434 #endif
3435 if (prefs_common.addressbook_use_editaddress_dialog)
3436 addressbook_edit_address_post_cb( person );
3438 return;
3441 else if( obj->type == ADDR_ITEM_PERSON ) {
3442 /* Edit person - basic page */
3443 ItemPerson *person = ( ItemPerson * ) obj;
3444 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3445 addressbook_edit_address_post_cb,
3446 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3447 != NULL ) {
3448 #ifdef USE_LDAP
3449 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3450 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3451 person->status = UPDATE_ENTRY;
3453 #endif
3454 if (prefs_common.addressbook_use_editaddress_dialog)
3455 addressbook_edit_address_post_cb( person );
3457 return;
3459 else if( obj->type == ADDR_ITEM_GROUP ) {
3460 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3461 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3462 parentNode = addrbook.treeSelected;
3463 node = addressbook_find_group_node( parentNode, itemGrp );
3464 name = ADDRITEM_NAME(itemGrp);
3465 invalidate_address_completion();
3467 else {
3468 return;
3471 /* Update tree node with node name */
3472 if( node == NULL ) return;
3473 addressbook_change_node_name( node, name );
3474 gtk_sctree_sort_node( ctree, parentNode );
3475 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3476 addressbook_set_clist(
3477 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3478 addrbook.opened),
3479 TRUE);
3482 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3484 addressbook_del_clicked(NULL, NULL);
3487 static void close_cb(GtkAction *action, gpointer data)
3489 addressbook_close();
3492 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3493 addressbook_export_to_file();
3496 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3497 if( node ) {
3498 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3499 if( person ) addritem_person_set_opened( person, TRUE );
3503 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3504 if( node ) {
3505 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3506 if( person ) addritem_person_set_opened( person, FALSE );
3510 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3511 gchar *str = NULL;
3512 gchar *eMailAlias = ADDRITEM_NAME(email);
3513 if( eMailAlias && *eMailAlias != '\0' ) {
3514 if( person ) {
3515 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3517 else {
3518 str = g_strdup( eMailAlias );
3521 return str;
3524 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3525 GList *items = itemGroup->listEMail;
3526 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3527 for( ; items != NULL; items = g_list_next( items ) ) {
3528 GtkCMCTreeNode *nodeEMail = NULL;
3529 gchar *text[N_LIST_COLS];
3530 ItemEMail *email = items->data;
3531 ItemPerson *person;
3532 gchar *str = NULL;
3534 if( ! email ) continue;
3536 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3537 str = addressbook_format_item_clist( person, email );
3538 if( str ) {
3539 text[COL_NAME] = addressbook_set_col_name_guard(str);
3541 else {
3542 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3544 text[COL_ADDRESS] = email->address;
3545 text[COL_REMARKS] = email->remarks;
3546 nodeEMail = gtk_sctree_insert_node(
3547 clist, NULL, NULL,
3548 text, FOLDER_SPACING,
3549 atci->iconXpm,
3550 atci->iconXpmOpen,
3551 FALSE, FALSE );
3552 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3553 g_free( str );
3554 str = NULL;
3558 gchar *addressbook_set_col_name_guard(gchar *value)
3560 gchar *ret = "<not set>";
3561 gchar *tmp = g_strdup(value);
3562 g_strstrip(tmp);
3563 if (tmp !=NULL && *tmp != '\0')
3564 ret = value;
3565 g_free(tmp);
3566 return ret;
3569 static void addressbook_folder_load_one_person(
3570 GtkCMCTree *clist, ItemPerson *person,
3571 AddressTypeControlItem *atci,
3572 AddressTypeControlItem *atciMail )
3574 GtkCMCTreeNode *nodePerson = NULL;
3575 GtkCMCTreeNode *nodeEMail = NULL;
3576 gchar *text[N_LIST_COLS];
3577 gboolean flgFirst = TRUE, haveAddr = FALSE;
3578 GList *node;
3579 #ifdef USE_LDAP
3580 AddressBookFile *abf = addressbook_get_book_file();
3581 #endif
3583 if( person == NULL ) return;
3585 text[COL_NAME] = "";
3586 node = person->listEMail;
3587 while( node ) {
3588 ItemEMail *email = node->data;
3589 gchar *eMailAddr = NULL;
3590 node = g_list_next( node );
3592 text[COL_ADDRESS] = email->address;
3593 text[COL_REMARKS] = email->remarks;
3594 eMailAddr = ADDRITEM_NAME(email);
3595 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3596 if( flgFirst ) {
3597 /* First email belongs with person */
3598 gchar *str = addressbook_format_item_clist( person, email );
3599 if( str ) {
3600 text[COL_NAME] = addressbook_set_col_name_guard(str);
3602 #ifdef USE_LDAP
3603 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3604 person && person->nickName ) {
3605 if (person->nickName) {
3606 if (strcmp(person->nickName, "") != 0) {
3607 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3609 else {
3610 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3614 #endif
3615 else {
3616 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3618 nodePerson = gtk_sctree_insert_node(
3619 clist, NULL, NULL,
3620 text, FOLDER_SPACING,
3621 atci->iconXpm,
3622 atci->iconXpmOpen,
3623 FALSE, person->isOpened );
3624 g_free( str );
3625 str = NULL;
3626 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3628 else {
3629 /* Subsequent email is a child node of person */
3630 text[COL_NAME] = ADDRITEM_NAME(email);
3631 nodeEMail = gtk_sctree_insert_node(
3632 clist, nodePerson, NULL,
3633 text, FOLDER_SPACING,
3634 atciMail->iconXpm,
3635 atciMail->iconXpmOpen,
3636 FALSE, TRUE );
3637 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3639 flgFirst = FALSE;
3640 haveAddr = TRUE;
3642 if( ! haveAddr ) {
3643 /* Have name without EMail */
3644 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3645 text[COL_ADDRESS] = "";
3646 text[COL_REMARKS] = "";
3647 nodePerson = gtk_sctree_insert_node(
3648 clist, NULL, NULL,
3649 text, FOLDER_SPACING,
3650 atci->iconXpm,
3651 atci->iconXpmOpen,
3652 FALSE, person->isOpened );
3653 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3655 return;
3658 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3659 GList *items;
3660 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3661 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3663 if( atci == NULL ) return;
3664 if( atciMail == NULL ) return;
3666 /* Load email addresses */
3667 items = addritem_folder_get_person_list( itemFolder );
3668 for( ; items != NULL; items = g_list_next( items ) ) {
3669 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3671 /* Free up the list */
3672 mgu_clear_list( items );
3673 g_list_free( items );
3676 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3677 addrbook.listSelected = NULL;
3678 gtk_cmctree_remove_node( clist, node );
3679 addressbook_menubar_set_sensitive( FALSE );
3680 addressbook_menuitem_set_sensitive(
3681 gtk_cmctree_node_get_row_data(
3682 GTK_CMCTREE(clist), addrbook.treeSelected ),
3683 addrbook.treeSelected );
3686 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3687 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3688 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3689 GtkCMCTreeNode *node;
3690 if( atci == NULL ) return;
3691 if( atciMail == NULL ) return;
3692 if( person == NULL ) return;
3693 /* unload the person */
3695 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3696 if( node )
3697 addressbook_folder_remove_node( clist, node );
3698 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3699 gtk_sctree_sort_node( clist, NULL );
3700 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3701 if( node ) {
3702 gtk_sctree_select( GTK_SCTREE(clist), node );
3703 if (!gtk_cmctree_node_is_visible( clist, node ) )
3704 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3708 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3709 GtkCMCTreeNode *node;
3711 if( person == NULL ) return;
3712 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3713 if( node ) {
3714 addressbook_folder_remove_node( clist, node );
3718 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3719 GList *items;
3720 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3722 /* Load any groups */
3723 if( ! atci ) return;
3724 items = addritem_folder_get_group_list( itemFolder );
3725 for( ; items != NULL; items = g_list_next( items ) ) {
3726 GtkCMCTreeNode *nodeGroup = NULL;
3727 gchar *text[N_LIST_COLS];
3728 ItemGroup *group = items->data;
3729 if( group == NULL ) continue;
3730 text[COL_NAME] = ADDRITEM_NAME(group);
3731 text[COL_ADDRESS] = "";
3732 text[COL_REMARKS] = "";
3733 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3734 text, FOLDER_SPACING,
3735 atci->iconXpm,
3736 atci->iconXpmOpen,
3737 FALSE, FALSE);
3738 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3739 gtk_sctree_sort_node(clist, NULL);
3741 /* Free up the list */
3742 mgu_clear_list( items );
3743 g_list_free( items );
3747 * Search ctree widget callback function.
3748 * \param pA Pointer to node.
3749 * \param pB Pointer to data item being sought.
3750 * \return Zero (0) if group found.
3752 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3753 AddressObject *aoA;
3755 aoA = ( AddressObject * ) pA;
3756 if( aoA->type == ADDR_ITEM_GROUP ) {
3757 ItemGroup *group, *grp;
3759 grp = ADAPTER_GROUP(aoA)->itemGroup;
3760 group = ( ItemGroup * ) pB;
3761 if( grp == group ) return 0; /* Found group */
3763 return 1;
3767 * Remove folder and group nodes from tree widget for items contained ("cut")
3768 * in clipboard.
3770 static void addressbook_treenode_remove_item( void ) {
3771 GList *node;
3772 AddrSelectItem *cutItem;
3773 AddressCache *cache;
3774 AddrItemObject *aio;
3775 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3776 GtkCMCTreeNode *tn;
3778 node = _clipBoard_->objectList;
3779 while( node ) {
3780 cutItem = node->data;
3781 node = g_list_next( node );
3782 cache = addrindex_get_cache(
3783 _clipBoard_->addressIndex, cutItem->cacheID );
3784 if( cache == NULL ) continue;
3785 aio = addrcache_get_object( cache, cutItem->uid );
3786 if( aio ) {
3787 tn = NULL;
3788 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3789 ItemFolder *folder;
3791 folder = ( ItemFolder * ) aio;
3792 tn = gtk_cmctree_find_by_row_data_custom(
3793 ctree, NULL, folder,
3794 addressbook_treenode_find_folder_cb );
3796 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3797 ItemGroup *group;
3799 group = ( ItemGroup * ) aio;
3800 tn = gtk_cmctree_find_by_row_data_custom(
3801 ctree, NULL, group,
3802 addressbook_treenode_find_group_cb );
3805 if( tn ) {
3806 /* Free up adapter and remove node. */
3807 gtk_cmctree_remove_node( ctree, tn );
3814 * Find parent datasource for specified tree node.
3815 * \param node Node to test.
3816 * \return Data source, or NULL if not found.
3818 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3819 AddressDataSource *ds = NULL;
3820 AddressObject *ao;
3822 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3824 while( node ) {
3825 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3826 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3827 if( ao ) {
3828 /* g_print( "ao->type = %d\n", ao->type ); */
3829 if( ao->type == ADDR_DATASOURCE ) {
3830 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3831 /* g_print( "found it\n" ); */
3832 ds = ads->dataSource;
3833 break;
3836 node = GTK_CMCTREE_ROW(node)->parent;
3838 return ds;
3842 * Load address list widget with children of specified object.
3843 * \param obj Parent object to be loaded.
3845 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3846 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3847 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3848 AddressDataSource *ds = NULL;
3849 AdapterDSource *ads = NULL;
3850 static AddressObject *last_obj = NULL;
3852 if (addrbook.clist == NULL) {
3853 return;
3855 if (obj == last_obj && !refresh)
3856 return;
3858 last_obj = obj;
3859 if( obj == NULL ) {
3860 gtk_cmclist_clear(clist);
3861 return;
3864 if( obj->type == ADDR_INTERFACE ) {
3865 /* g_print( "set_clist: loading datasource...\n" ); */
3866 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3867 return;
3870 gtk_cmclist_freeze(clist);
3871 gtk_cmclist_clear(clist);
3873 if( obj->type == ADDR_DATASOURCE ) {
3874 ads = ADAPTER_DSOURCE(obj);
3875 ds = ads->dataSource;
3876 if( ds ) {
3877 /* Load root folder */
3878 ItemFolder *rootFolder = NULL;
3879 rootFolder = addrindex_ds_get_root_folder( ds );
3880 addressbook_folder_load_person(
3881 ctreelist, rootFolder );
3882 addressbook_folder_load_group(
3883 ctreelist, rootFolder );
3886 else {
3887 if( obj->type == ADDR_ITEM_GROUP ) {
3888 /* Load groups */
3889 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3890 addressbook_load_group( ctreelist, itemGroup );
3892 else if( obj->type == ADDR_ITEM_FOLDER ) {
3893 /* Load folders */
3894 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3895 addressbook_folder_load_person( ctreelist, itemFolder );
3896 addressbook_folder_load_group( ctreelist, itemFolder );
3899 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3900 clist->focus_row = -1;
3901 gtk_cmclist_thaw(clist);
3905 * Call back function to free adaptor. Call back is setup by function
3906 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3907 * called when the address book tree widget node is removed by calling
3908 * function gtk_cmctree_remove_node().
3910 * \param data Tree node's row data.
3912 static void addressbook_free_treenode( gpointer data ) {
3913 AddressObject *ao;
3915 ao = ( AddressObject * ) data;
3916 if( ao == NULL ) return;
3917 if( ao->type == ADDR_INTERFACE ) {
3918 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3919 addrbookctl_free_interface( ai );
3921 else if( ao->type == ADDR_DATASOURCE ) {
3922 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3923 addrbookctl_free_datasource( ads );
3925 else if( ao->type == ADDR_ITEM_FOLDER ) {
3926 AdapterFolder *af = ADAPTER_FOLDER(ao);
3927 addrbookctl_free_folder( af );
3929 else if( ao->type == ADDR_ITEM_GROUP ) {
3930 AdapterGroup *ag = ADAPTER_GROUP(ao);
3931 addrbookctl_free_group( ag );
3936 * Create new adaptor for specified data source.
3938 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3939 AddressObjectType otype, gchar *name )
3941 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3942 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3943 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3944 adapter->dataSource = ds;
3945 adapter->subType = otype;
3946 return adapter;
3949 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3950 ADDRESS_OBJECT_NAME(adapter) =
3951 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3955 * Load tree from address index with the initial data.
3957 static void addressbook_load_tree( void ) {
3958 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3959 GList *nodeIf, *nodeDS;
3960 AdapterInterface *adapter;
3961 AddressInterface *iface;
3962 AddressTypeControlItem *atci;
3963 AddressDataSource *ds;
3964 AdapterDSource *ads;
3965 GtkCMCTreeNode *node, *newNode;
3966 gchar *name;
3968 nodeIf = _addressInterfaceList_;
3969 while( nodeIf ) {
3970 adapter = nodeIf->data;
3971 node = adapter->treeNode;
3972 iface = adapter->interface;
3973 atci = adapter->atci;
3974 if( iface ) {
3975 if( iface->useInterface ) {
3976 /* Load data sources below interface node */
3977 nodeDS = iface->listSource;
3978 while( nodeDS ) {
3979 ds = nodeDS->data;
3980 name = addrindex_ds_get_name( ds );
3981 ads = addressbook_create_ds_adapter(
3982 ds, atci->objectType, name );
3983 newNode = addressbook_add_object(
3984 node, ADDRESS_OBJECT(ads) );
3985 if (newNode == NULL) {
3986 g_message("error adding addressbook object\n");
3988 nodeDS = g_list_next( nodeDS );
3990 gtk_cmctree_expand( ctree, node );
3993 nodeIf = g_list_next( nodeIf );
3998 * Convert the old address book to new format.
4000 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4001 gboolean retVal = FALSE;
4002 gboolean errFlag = TRUE;
4003 gchar *msg = NULL;
4005 /* Read old address book, performing conversion */
4006 debug_print( "Reading and converting old address book...\n" );
4007 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4008 addrindex_read_data( addrIndex );
4009 if( addrIndex->retVal == MGU_NO_FILE ) {
4010 /* We do not have a file - new user */
4011 debug_print( "New user... create new books...\n" );
4012 addrindex_create_new_books( addrIndex );
4013 if( addrIndex->retVal == MGU_SUCCESS ) {
4014 /* Save index file */
4015 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4016 addrindex_save_data( addrIndex );
4017 if( addrIndex->retVal == MGU_SUCCESS ) {
4018 retVal = TRUE;
4019 errFlag = FALSE;
4021 else {
4022 msg = _( "New user, could not save index file." );
4025 else {
4026 msg = _( "New user, could not save address book files." );
4029 else {
4030 /* We have an old file */
4031 if( addrIndex->wasConverted ) {
4032 /* Converted successfully - save address index */
4033 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4034 addrindex_save_data( addrIndex );
4035 if( addrIndex->retVal == MGU_SUCCESS ) {
4036 msg = _( "Old address book converted successfully." );
4037 retVal = TRUE;
4038 errFlag = FALSE;
4040 else {
4041 msg = _("Old address book converted,\n"
4042 "could not save new address index file." );
4045 else {
4046 /* File conversion failed - just create new books */
4047 debug_print( "File conversion failed... just create new books...\n" );
4048 addrindex_create_new_books( addrIndex );
4049 if( addrIndex->retVal == MGU_SUCCESS ) {
4050 /* Save index */
4051 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4052 addrindex_save_data( addrIndex );
4053 if( addrIndex->retVal == MGU_SUCCESS ) {
4054 msg = _("Could not convert address book,\n"
4055 "but created empty new address book files." );
4056 retVal = TRUE;
4057 errFlag = FALSE;
4059 else {
4060 msg = _("Could not convert address book,\n"
4061 "could not save new address index file." );
4064 else {
4065 msg = _("Could not convert address book\n"
4066 "and could not create new address book files." );
4070 if( errFlag ) {
4071 debug_print( "Error\n%s\n", msg );
4072 alertpanel_full(_("Addressbook conversion error"), msg,
4073 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4074 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4076 else if( msg ) {
4077 debug_print( "Warning\n%s\n", msg );
4078 alertpanel_full(_("Addressbook conversion error"), msg,
4079 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4080 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4083 return retVal;
4086 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4088 DIR *dp;
4089 struct dirent *d;
4090 gboolean failed = FALSE;
4092 if( ( dp = opendir( origdir ) ) == NULL ) {
4093 return FALSE;
4096 while( ( d = readdir( dp ) ) != NULL ) {
4097 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4098 continue;
4099 else {
4100 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4101 d->d_name, NULL);
4102 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4103 d->d_name, NULL);
4104 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4105 failed = TRUE;
4107 g_free(orig_file);
4108 g_free(dest_file);
4109 if (failed) {
4110 break;
4115 closedir( dp );
4116 if (!failed) {
4117 /* all copies succeeded, we can remove source files */
4118 if( ( dp = opendir( origdir ) ) == NULL ) {
4119 return FALSE;
4121 while( ( d = readdir( dp ) ) != NULL ) {
4122 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4123 continue;
4124 else {
4125 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4126 d->d_name, NULL);
4127 claws_unlink(orig_file);
4128 g_free(orig_file);
4131 closedir( dp );
4134 return !failed;
4137 void addressbook_read_file( void ) {
4138 AddressIndex *addrIndex = NULL;
4139 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4141 debug_print( "Reading address index...\n" );
4142 if( _addressIndex_ ) {
4143 debug_print( "address book already read!!!\n" );
4144 return;
4147 addrIndex = addrindex_create_index();
4148 addrindex_initialize();
4150 /* Use new address book index. */
4152 if ( !is_dir_exist(indexdir) ) {
4153 if ( make_dir(indexdir) < 0 ) {
4154 addrindex_set_file_path( addrIndex, get_rc_dir() );
4155 g_warning( "couldn't create dir %s\n", indexdir);
4156 } else {
4157 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4158 remove_dir_recursive(indexdir);
4159 addrindex_set_file_path( addrIndex, get_rc_dir() );
4160 g_error("couldn't migrate dir %s", indexdir);
4161 } else {
4162 addrindex_set_file_path( addrIndex, indexdir);
4165 } else {
4166 addrindex_set_file_path( addrIndex, indexdir);
4168 g_free(indexdir);
4169 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4170 addrindex_read_data( addrIndex );
4171 if( addrIndex->retVal == MGU_NO_FILE ) {
4172 /* Conversion required */
4173 debug_print( "Converting...\n" );
4174 if( addressbook_convert( addrIndex ) ) {
4175 _addressIndex_ = addrIndex;
4178 else if( addrIndex->retVal == MGU_SUCCESS ) {
4179 _addressIndex_ = addrIndex;
4181 else {
4182 /* Error reading address book */
4183 debug_print( "Could not read address index.\n" );
4184 addrindex_print_index( addrIndex, stdout );
4185 alertpanel_full(_("Addressbook Error"),
4186 _("Could not read address index"),
4187 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4188 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4190 debug_print( "done.\n" );
4194 * Add object into the address index tree widget.
4195 * Enter: node Parent node.
4196 * obj Object to add.
4197 * Return: Node that was added, or NULL if object not added.
4199 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4200 AddressObject *obj)
4202 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4203 GtkCMCTreeNode *added;
4204 AddressObject *pobj;
4205 AddressObjectType otype;
4206 AddressTypeControlItem *atci = NULL;
4208 cm_return_val_if_fail(node != NULL, NULL);
4209 cm_return_val_if_fail(obj != NULL, NULL);
4211 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4212 cm_return_val_if_fail(pobj != NULL, NULL);
4214 /* Determine object type to be displayed */
4215 if( obj->type == ADDR_DATASOURCE ) {
4216 otype = ADAPTER_DSOURCE(obj)->subType;
4218 else {
4219 otype = obj->type;
4222 /* Handle any special conditions. */
4223 added = node;
4224 atci = addrbookctl_lookup( otype );
4225 if( atci ) {
4226 if( atci->showInTree ) {
4227 /* Add object to tree */
4228 gchar **name;
4229 name = &obj->name;
4230 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4231 atci->iconXpm, atci->iconXpmOpen,
4232 atci->treeLeaf, atci->treeExpand );
4233 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4234 addressbook_free_treenode );
4238 gtk_sctree_sort_node(ctree, node);
4240 return added;
4244 * Add group into the address index tree.
4245 * \param node Parent node.
4246 * \param ds Data source.
4247 * \param itemGroup Group to add.
4248 * \return Inserted node.
4250 static GtkCMCTreeNode *addressbook_node_add_group(
4251 GtkCMCTreeNode *node, AddressDataSource *ds,
4252 ItemGroup *itemGroup )
4254 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4255 GtkCMCTreeNode *newNode;
4256 AdapterGroup *adapter;
4257 AddressTypeControlItem *atci = NULL;
4258 gchar **name;
4260 if( ds == NULL ) return NULL;
4261 if( node == NULL || itemGroup == NULL ) return NULL;
4263 name = &itemGroup->obj.name;
4265 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4267 adapter = g_new0( AdapterGroup, 1 );
4268 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4269 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4270 adapter->itemGroup = itemGroup;
4272 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4273 atci->iconXpm, atci->iconXpm,
4274 atci->treeLeaf, atci->treeExpand );
4275 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4276 addressbook_free_treenode );
4277 gtk_sctree_sort_node( ctree, node );
4278 return newNode;
4282 * Add folder into the address index tree. Only visible folders are loaded into
4283 * the address index tree. Note that the root folder is not inserted into the
4284 * tree.
4286 * \param node Parent node.
4287 * \param ds Data source.
4288 * \param itemFolder Folder to add.
4289 * \param otype Object type to display.
4290 * \return Inserted node for the folder.
4292 static GtkCMCTreeNode *addressbook_node_add_folder(
4293 GtkCMCTreeNode *node, AddressDataSource *ds,
4294 ItemFolder *itemFolder, AddressObjectType otype )
4296 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4297 GtkCMCTreeNode *newNode = NULL;
4298 AdapterFolder *adapter;
4299 AddressTypeControlItem *atci = NULL;
4300 GList *listItems = NULL;
4301 gchar *name;
4302 ItemFolder *rootFolder;
4304 /* Only visible folders */
4305 if( itemFolder == NULL || itemFolder->isHidden )
4306 return NULL;
4308 if( ds == NULL )
4309 return NULL;
4310 if( node == NULL || itemFolder == NULL )
4311 return NULL;
4313 /* Determine object type */
4314 atci = addrbookctl_lookup( otype );
4315 if( atci == NULL )
4316 return NULL;
4318 rootFolder = addrindex_ds_get_root_folder( ds );
4319 if( itemFolder == rootFolder ) {
4320 newNode = node;
4322 else {
4323 adapter = g_new0( AdapterFolder, 1 );
4324 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4325 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4326 adapter->itemFolder = itemFolder;
4328 name = ADDRITEM_NAME(itemFolder);
4329 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4330 atci->iconXpm, atci->iconXpm,
4331 atci->treeLeaf, atci->treeExpand );
4332 if( newNode ) {
4333 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4334 addressbook_free_treenode );
4338 listItems = itemFolder->listFolder;
4339 while( listItems ) {
4340 ItemFolder *item = listItems->data;
4341 addressbook_node_add_folder( newNode, ds, item, otype );
4342 listItems = g_list_next( listItems );
4344 listItems = itemFolder->listGroup;
4345 while( listItems ) {
4346 ItemGroup *item = listItems->data;
4347 addressbook_node_add_group( newNode, ds, item );
4348 listItems = g_list_next( listItems );
4350 gtk_sctree_sort_node( ctree, node );
4351 return newNode;
4354 void addressbook_export_to_file( void ) {
4355 if( _addressIndex_ ) {
4356 /* Save all new address book data */
4357 debug_print( "Saving address books...\n" );
4358 addrindex_save_all_books( _addressIndex_ );
4360 debug_print( "Exporting addressbook to file...\n" );
4361 addrindex_save_data( _addressIndex_ );
4362 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4363 addrindex_print_index( _addressIndex_, stdout );
4366 /* Notify address completion of new data */
4367 invalidate_address_completion();
4371 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4373 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4374 addressbook_lup_clicked(NULL, NULL);
4375 return FALSE;
4379 * Comparison using cell contents (text in first column). Used for sort
4380 * address index widget.
4382 static gint addressbook_treenode_compare_func(
4383 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4385 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4386 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4387 gchar *name1 = NULL, *name2 = NULL;
4388 if( cell1 ) name1 = cell1->u.text;
4389 if( cell2 ) name2 = cell2->u.text;
4390 if( ! name1 ) return ( name2 != NULL );
4391 if( ! name2 ) return -1;
4392 return g_utf8_collate( name1, name2 );
4395 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4396 AdapterDSource *ads;
4397 AdapterInterface *adapter;
4398 GtkCMCTreeNode *newNode;
4400 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4401 if( adapter == NULL ) return;
4402 ads = addressbook_edit_book( _addressIndex_, NULL );
4403 if( ads ) {
4404 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4405 if( newNode ) {
4406 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4407 addrbook.treeSelected = newNode;
4412 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4413 AdapterDSource *ads;
4414 AdapterInterface *adapter;
4415 GtkCMCTreeNode *newNode;
4417 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4418 if( adapter == NULL ) return;
4419 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4420 if( ads ) {
4421 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4422 if( newNode ) {
4423 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4424 addrbook.treeSelected = newNode;
4429 #ifdef USE_JPILOT
4430 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4431 AdapterDSource *ads;
4432 AdapterInterface *adapter;
4433 AddressInterface *iface;
4434 GtkCMCTreeNode *newNode;
4436 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4437 if( adapter == NULL ) return;
4438 iface = adapter->interface;
4439 if( ! iface->haveLibrary ) return;
4440 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4441 if( ads ) {
4442 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4443 if( newNode ) {
4444 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4445 addrbook.treeSelected = newNode;
4449 #endif
4451 #ifdef USE_LDAP
4452 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4453 AdapterDSource *ads;
4454 AdapterInterface *adapter;
4455 AddressInterface *iface;
4456 GtkCMCTreeNode *newNode;
4458 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4459 if( adapter == NULL ) return;
4460 iface = adapter->interface;
4461 if( ! iface->haveLibrary ) return;
4462 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4463 if( ads ) {
4464 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4465 if( newNode ) {
4466 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4467 addrbook.treeSelected = newNode;
4471 #endif
4474 * Display address search status message.
4475 * \param queryType Query type.
4476 * \param status Status/Error code.
4478 static void addressbook_search_message( gint queryType, gint sts ) {
4479 gchar *desc = NULL;
4480 *addressbook_msgbuf = '\0';
4482 if( sts != MGU_SUCCESS ) {
4483 if( queryType == ADDRQUERY_LDAP ) {
4484 #ifdef USE_LDAP
4485 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4486 #endif
4489 if( desc ) {
4490 g_snprintf( addressbook_msgbuf,
4491 sizeof(addressbook_msgbuf), "%s", desc );
4492 addressbook_status_show( addressbook_msgbuf );
4494 else {
4495 addressbook_status_show( "" );
4500 * Refresh addressbook by forcing refresh of current selected object in
4501 * tree.
4503 static void addressbook_refresh_current( void ) {
4504 AddressObject *obj;
4505 GtkCMCTree *ctree;
4507 ctree = GTK_CMCTREE(addrbook.ctree);
4508 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4509 if( obj == NULL ) return;
4510 addressbook_set_clist( obj, TRUE );
4514 * Message that is displayed whilst a query is executing in a background
4515 * thread.
4517 static gchar *_tempMessage_ = N_( "Busy searching..." );
4520 * Address search idle function. This function is called during UI idle time
4521 * while a search is in progress.
4523 * \param data Idler data.
4525 static void addressbook_search_idle( gpointer data ) {
4527 gint queryID;
4529 queryID = GPOINTER_TO_INT( data );
4530 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4535 * Search completion callback function. This removes the query from the idle
4536 * list.
4538 * \param sender Sender of query.
4539 * \param queryID Query ID of search request.
4540 * \param status Search status.
4541 * \param data Query data.
4543 static void addressbook_search_callback_end(
4544 gpointer sender, gint queryID, gint status, gpointer data )
4546 gpointer ptrQID;
4547 QueryRequest *req;
4548 AddrQueryObject *aqo;
4550 /* Remove idler function */
4551 ptrQID = GINT_TO_POINTER( queryID );
4552 if( ptrQID ) {
4553 g_idle_remove_by_data( ptrQID );
4556 /* Refresh addressbook contents */
4557 addressbook_refresh_current();
4558 req = qrymgr_find_request( queryID );
4559 if( req != NULL ) {
4560 aqo = ( AddrQueryObject * ) req->queryList->data;
4561 addressbook_search_message( aqo->queryType, status );
4564 /* Stop the search */
4565 addrindex_stop_search( queryID );
4569 * Perform search.
4571 * \param ds Data source to search.
4572 * \param searchTerm String to lookup.
4573 * \param pNode Parent data source node.
4575 static void addressbook_perform_search(
4576 AddressDataSource *ds, gchar *searchTerm,
4577 GtkCMCTreeNode *pNode )
4579 ItemFolder *folder;
4580 gchar *name;
4581 gint queryID;
4582 guint idleID;
4584 /* Setup a query */
4585 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4587 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4589 /* Create a folder for the search results */
4590 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4591 folder = addressbook_setup_subf(ds, name, pNode);
4592 g_free( name );
4594 /* Setup the search */
4595 queryID = addrindex_setup_explicit_search(
4596 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4597 if( queryID == 0 ) return;
4599 /* Set up idler function */
4600 idleID = g_idle_add(
4601 (GSourceFunc) addressbook_search_idle,
4602 GINT_TO_POINTER( queryID ) );
4603 if (idleID == 0) {
4604 g_message("error adding addressbook_search_idle\n");
4607 /* Start search, sit back and wait for something to happen */
4608 addrindex_start_search( queryID );
4610 addressbook_status_show( _tempMessage_ );
4614 * Lookup button handler. Address search is only performed against
4615 * address interfaces for external queries.
4617 * \param button Lookup button widget.
4618 * \param data Data object.
4620 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4621 GtkCMCTree *ctree;
4622 AddressObject *obj;
4623 AddressDataSource *ds;
4624 AddressInterface *iface;
4625 gchar *searchTerm;
4626 GtkCMCTreeNode *node, *parentNode;
4628 node = addrbook.treeSelected;
4629 if( ! node ) return;
4630 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4632 ctree = GTK_CMCTREE(addrbook.ctree);
4633 obj = gtk_cmctree_node_get_row_data( ctree, node );
4634 if( obj == NULL ) return;
4636 ds = addressbook_find_datasource( node );
4637 if( ds == NULL ) return;
4639 /* We must have a datasource that is an external interface */
4640 iface = ds->interface;
4641 if( ! iface->haveLibrary ) return;
4642 if( ! iface->externalQuery ) return;
4644 searchTerm =
4645 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4646 g_strchomp( searchTerm );
4648 if( obj->type == ADDR_ITEM_FOLDER ) {
4649 parentNode = GTK_CMCTREE_ROW(node)->parent;
4651 else {
4652 parentNode = node;
4654 addressbook_perform_search( ds, searchTerm, parentNode );
4656 gtk_widget_grab_focus( addrbook.entry );
4658 g_free( searchTerm );
4661 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4662 addressbook_close();
4665 #ifdef USE_LDAP
4667 * Browse address entry for highlighted entry.
4669 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4671 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4672 AddressObject *obj;
4673 AddressDataSource *ds;
4674 AddressInterface *iface;
4675 ItemPerson *person;
4676 ItemEMail *email;
4678 if(addrbook.listSelected == NULL)
4679 return;
4681 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4682 if (obj == NULL)
4683 return;
4685 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4686 if(ds == NULL)
4687 return;
4689 iface = ds->interface;
4690 if(!iface || !iface->haveLibrary )
4691 return;
4693 person = NULL;
4694 if (obj->type == ADDR_ITEM_EMAIL) {
4695 email = ( ItemEMail * ) obj;
4697 person = (ItemPerson *) ADDRITEM_PARENT(email);
4699 else if (obj->type == ADDR_ITEM_PERSON) {
4700 person = (ItemPerson *) obj;
4702 else {
4703 /* None of these */
4704 return;
4707 if( iface && iface->type == ADDR_IF_LDAP ) {
4708 browseldap_entry(ds, person->externalID);
4711 #endif
4713 /* **********************************************************************
4714 * Build lookup tables.
4715 * ***********************************************************************
4719 * Remap object types.
4720 * Enter: abType AddressObjectType (used in tree node).
4721 * Return: ItemObjectType (used in address cache data).
4723 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4724 ItemObjectType ioType;
4726 switch( abType ) {
4727 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4728 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4729 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4730 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4731 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4732 default: ioType = ITEMTYPE_NONE; break;
4734 return ioType;
4737 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4738 atci = addrbookctl_lookup(id); \
4739 if (atci) { \
4740 atci->iconXpm = icon; \
4741 atci->iconXpmOpen = iconopen; \
4742 } else { \
4743 g_warning("can't get atci %d\n", id); \
4748 * Build table that controls the rendering of object types.
4750 static void addrbookctl_build_icons( GtkWidget *window ) {
4751 AddressTypeControlItem *atci;
4753 /* Build icons */
4754 if (interfacexpm)
4755 g_object_unref(interfacexpm);
4756 if (folderxpm)
4757 g_object_unref(folderxpm);
4758 if (folderopenxpm)
4759 g_object_unref(folderopenxpm);
4760 if (groupxpm)
4761 g_object_unref(groupxpm);
4762 if (vcardxpm)
4763 g_object_unref(vcardxpm);
4764 if (bookxpm)
4765 g_object_unref(bookxpm);
4766 if (addressxpm)
4767 g_object_unref(addressxpm);
4768 if (jpilotxpm)
4769 g_object_unref(jpilotxpm);
4770 if (categoryxpm)
4771 g_object_unref(categoryxpm);
4772 if (ldapxpm)
4773 g_object_unref(ldapxpm);
4774 if (addrsearchxpm)
4775 g_object_unref(addrsearchxpm);
4776 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4777 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4778 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4779 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4780 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4781 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4782 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4783 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4784 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4785 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4786 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4788 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4789 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4790 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4791 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4792 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4793 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4794 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4795 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4796 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4797 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4798 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4803 * Build table that controls the rendering of object types.
4805 static void addrbookctl_build_map( GtkWidget *window ) {
4806 AddressTypeControlItem *atci;
4808 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4809 _addressBookTypeList_ = NULL;
4811 /* Interface */
4812 atci = g_new0( AddressTypeControlItem, 1 );
4813 atci->objectType = ADDR_INTERFACE;
4814 atci->interfaceType = ADDR_IF_NONE;
4815 atci->showInTree = TRUE;
4816 atci->treeExpand = TRUE;
4817 atci->treeLeaf = FALSE;
4818 atci->displayName = _( "Interface" );
4819 atci->menuCommand = NULL;
4820 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4821 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4823 /* Address book */
4824 atci = g_new0( AddressTypeControlItem, 1 );
4825 atci->objectType = ADDR_BOOK;
4826 atci->interfaceType = ADDR_IF_BOOK;
4827 atci->showInTree = TRUE;
4828 atci->treeExpand = TRUE;
4829 atci->treeLeaf = FALSE;
4830 atci->displayName = _( "Address Book" );
4831 atci->menuCommand = "Menu/Book/NewBook";
4832 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4833 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4835 /* Item person */
4836 atci = g_new0( AddressTypeControlItem, 1 );
4837 atci->objectType = ADDR_ITEM_PERSON;
4838 atci->interfaceType = ADDR_IF_NONE;
4839 atci->showInTree = FALSE;
4840 atci->treeExpand = FALSE;
4841 atci->treeLeaf = FALSE;
4842 atci->displayName = _( "Person" );
4843 atci->menuCommand = NULL;
4844 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4845 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4847 /* Item email */
4848 atci = g_new0( AddressTypeControlItem, 1 );
4849 atci->objectType = ADDR_ITEM_EMAIL;
4850 atci->interfaceType = ADDR_IF_NONE;
4851 atci->showInTree = FALSE;
4852 atci->treeExpand = FALSE;
4853 atci->treeLeaf = TRUE;
4854 atci->displayName = _( "Email Address" );
4855 atci->menuCommand = NULL;
4856 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4857 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4859 /* Item group */
4860 atci = g_new0( AddressTypeControlItem, 1 );
4861 atci->objectType = ADDR_ITEM_GROUP;
4862 atci->interfaceType = ADDR_IF_BOOK;
4863 atci->showInTree = TRUE;
4864 atci->treeExpand = FALSE;
4865 atci->treeLeaf = FALSE;
4866 atci->displayName = _( "Group" );
4867 atci->menuCommand = NULL;
4868 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4869 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4871 /* Item folder */
4872 atci = g_new0( AddressTypeControlItem, 1 );
4873 atci->objectType = ADDR_ITEM_FOLDER;
4874 atci->interfaceType = ADDR_IF_BOOK;
4875 atci->showInTree = TRUE;
4876 atci->treeExpand = FALSE;
4877 atci->treeLeaf = FALSE;
4878 atci->displayName = _( "Folder" );
4879 atci->menuCommand = NULL;
4880 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4881 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4883 /* vCard */
4884 atci = g_new0( AddressTypeControlItem, 1 );
4885 atci->objectType = ADDR_VCARD;
4886 atci->interfaceType = ADDR_IF_VCARD;
4887 atci->showInTree = TRUE;
4888 atci->treeExpand = TRUE;
4889 atci->treeLeaf = TRUE;
4890 atci->displayName = _( "vCard" );
4891 atci->menuCommand = "Menu/Book/NewVCard";
4892 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4893 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4895 /* J-Pilot */
4896 atci = g_new0( AddressTypeControlItem, 1 );
4897 atci->objectType = ADDR_JPILOT;
4898 atci->interfaceType = ADDR_IF_JPILOT;
4899 atci->showInTree = TRUE;
4900 atci->treeExpand = TRUE;
4901 atci->treeLeaf = FALSE;
4902 atci->displayName = _( "JPilot" );
4903 atci->menuCommand = "Menu/Book/NewJPilot";
4904 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4905 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4907 /* Category */
4908 atci = g_new0( AddressTypeControlItem, 1 );
4909 atci->objectType = ADDR_CATEGORY;
4910 atci->interfaceType = ADDR_IF_JPILOT;
4911 atci->showInTree = TRUE;
4912 atci->treeExpand = TRUE;
4913 atci->treeLeaf = TRUE;
4914 atci->displayName = _( "JPilot" );
4915 atci->menuCommand = NULL;
4916 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4917 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4919 /* LDAP Server */
4920 atci = g_new0( AddressTypeControlItem, 1 );
4921 atci->objectType = ADDR_LDAP;
4922 atci->interfaceType = ADDR_IF_LDAP;
4923 atci->showInTree = TRUE;
4924 atci->treeExpand = TRUE;
4925 atci->treeLeaf = FALSE;
4926 atci->displayName = _( "LDAP servers" );
4927 atci->menuCommand = "Menu/Book/NewLDAPServer";
4928 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4929 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4931 /* LDAP Query */
4932 atci = g_new0( AddressTypeControlItem, 1 );
4933 atci->objectType = ADDR_LDAP_QUERY;
4934 atci->interfaceType = ADDR_IF_LDAP;
4935 atci->showInTree = TRUE;
4936 atci->treeExpand = FALSE;
4937 atci->treeLeaf = TRUE;
4938 atci->displayName = _( "LDAP Query" );
4939 atci->menuCommand = NULL;
4940 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4941 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4943 addrbookctl_build_icons(window);
4946 void addressbook_reflect_prefs_pixmap_theme(void)
4948 if (addrbook.window)
4949 addrbookctl_build_icons(addrbook.window);
4953 * Search for specified object type.
4955 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4956 gint objType = ot;
4957 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4961 * Search for specified interface type.
4963 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4964 GList *node = _addressBookTypeList_;
4965 while( node ) {
4966 AddressTypeControlItem *atci = node->data;
4967 if( atci->interfaceType == ifType ) return atci;
4968 node = g_list_next( node );
4970 return NULL;
4973 static void addrbookctl_free_address( AddressObject *obj ) {
4974 g_free( obj->name );
4975 obj->type = ADDR_NONE;
4976 obj->name = NULL;
4979 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4980 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4981 adapter->interface = NULL;
4982 adapter->interfaceType = ADDR_IF_NONE;
4983 adapter->atci = NULL;
4984 adapter->enabled = FALSE;
4985 adapter->haveLibrary = FALSE;
4986 adapter->treeNode = NULL;
4987 g_free( adapter );
4990 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4991 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4992 adapter->dataSource = NULL;
4993 adapter->subType = ADDR_NONE;
4994 g_free( adapter );
4997 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4998 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4999 adapter->itemFolder = NULL;
5000 g_free( adapter );
5003 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5004 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5005 adapter->itemGroup = NULL;
5006 g_free( adapter );
5010 * Build GUI interface list.
5012 static void addrbookctl_build_iflist( void ) {
5013 AddressTypeControlItem *atci;
5014 AdapterInterface *adapter;
5015 GList *list = NULL;
5017 if( _addressIndex_ == NULL ) {
5018 _addressIndex_ = addrindex_create_index();
5019 if( _clipBoard_ == NULL ) {
5020 _clipBoard_ = addrclip_create();
5022 addrclip_set_index( _clipBoard_, _addressIndex_ );
5024 _addressInterfaceList_ = NULL;
5025 list = addrindex_get_interface_list( _addressIndex_ );
5026 while( list ) {
5027 AddressInterface *interface = list->data;
5028 atci = addrbookctl_lookup_iface( interface->type );
5029 if( atci ) {
5030 adapter = g_new0( AdapterInterface, 1 );
5031 adapter->interfaceType = interface->type;
5032 adapter->atci = atci;
5033 adapter->interface = interface;
5034 adapter->treeNode = NULL;
5035 adapter->enabled = TRUE;
5036 adapter->haveLibrary = interface->haveLibrary;
5037 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5038 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5039 _addressInterfaceList_ =
5040 g_list_append( _addressInterfaceList_, adapter );
5042 list = g_list_next( list );
5047 * Find GUI interface type specified interface type.
5048 * \param ifType Interface type.
5049 * \return Interface item, or NULL if not found.
5051 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5052 GList *node = _addressInterfaceList_;
5053 while( node ) {
5054 AdapterInterface *adapter = node->data;
5055 if( adapter->interfaceType == ifType ) return adapter;
5056 node = g_list_next( node );
5058 return NULL;
5062 * Build interface list selection.
5064 static void addrbookctl_build_ifselect( void ) {
5065 GList *newList = NULL;
5066 gchar *selectStr;
5067 gchar **splitStr;
5068 gint ifType;
5069 gint i;
5070 gchar *endptr = NULL;
5071 /* gboolean enabled; */
5072 AdapterInterface *adapter;
5074 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5076 /* Parse string */
5077 splitStr = g_strsplit( selectStr, ",", -1 );
5078 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5079 if( splitStr[i] ) {
5080 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5081 ifType = strtol( splitStr[i], &endptr, 10 );
5082 /* enabled = TRUE;
5083 if( *endptr ) {
5084 if( strcmp( endptr, "/n" ) == 0 ) {
5085 enabled = FALSE;
5089 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5090 adapter = addrbookctl_find_interface( ifType );
5091 if( adapter ) {
5092 newList = g_list_append( newList, adapter );
5095 else {
5096 break;
5099 /* g_print( "i=%d\n", i ); */
5100 g_strfreev( splitStr );
5101 g_free( selectStr );
5103 /* Replace existing list */
5104 mgu_clear_list( _addressIFaceSelection_ );
5105 g_list_free( _addressIFaceSelection_ );
5106 _addressIFaceSelection_ = newList;
5107 newList = NULL;
5110 /* ***********************************************************************
5111 * Add sender to address book.
5112 * ***********************************************************************
5116 * This function is used by the Add sender to address book function.
5118 gboolean addressbook_add_contact(
5119 const gchar *name, const gchar *address, const gchar *remarks,
5120 GdkPixbuf *picture )
5122 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5123 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5124 debug_print( "addressbook_add_contact - added\n" );
5125 addressbook_refresh();
5127 return TRUE;
5130 /* ***********************************************************************
5131 * Book/folder selection.
5132 * ***********************************************************************
5136 * This function is used by the matcher dialog to select a book/folder.
5138 gchar *addressbook_folder_selection( const gchar *folderpath)
5140 AddressBookFile *book = NULL;
5141 ItemFolder *folder = NULL;
5142 gchar *path = NULL;
5144 cm_return_val_if_fail( folderpath != NULL, NULL);
5146 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5147 && book != NULL ) {
5148 if ( folder != NULL) {
5149 gchar *tmp = NULL;
5150 gchar *oldtmp = NULL;
5151 AddrItemObject *obj = NULL;
5153 /* walk thru folder->parent to build the full folder path */
5154 /* TODO: wwp: optimize this */
5155 obj = &folder->obj;
5156 tmp = g_strdup(obj->uid);
5157 while ( obj->parent ) {
5158 obj = obj->parent;
5159 if ( obj->name != NULL ) {
5160 oldtmp = g_strdup(tmp);
5161 g_free(tmp);
5162 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5163 g_free(oldtmp);
5166 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5167 g_free(tmp);
5168 } else {
5169 path = g_strdup_printf("%s", book->fileName);
5171 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5172 return path;
5174 return NULL;
5177 /* ***********************************************************************
5178 * Book/folder checking.
5179 * ***********************************************************************
5182 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5184 FolderInfo *fi = g_new0( FolderInfo, 1 );
5185 fi->book = abf;
5186 fi->folder = folder;
5187 return fi;
5190 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5191 FolderInfo *fiParent, FolderPathMatch *match )
5193 GList *list;
5194 ItemFolder *folder;
5195 gchar *fName;
5196 FolderInfo *fi;
5197 FolderPathMatch *nextmatch = NULL;
5199 if (!parentFolder)
5200 return;
5202 list = parentFolder->listFolder;
5203 while ( list ) {
5204 folder = list->data;
5205 fName = g_strdup( ADDRITEM_NAME(folder) );
5207 /* match folder name, match pointer will be set to NULL if next recursive call
5208 doesn't need to match subfolder name */
5209 if ( match != NULL &&
5210 match->matched == FALSE ) {
5211 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5212 /* folder name matches, prepare next subfolder match */
5213 debug_print("matched folder name '%s'\n", fName);
5214 match->index++;
5215 if ( match->folder_path[match->index] == NULL ) {
5216 /* we've matched all elements */
5217 match->matched = TRUE;
5218 match->folder = folder;
5219 debug_print("book/folder path matched!\n");
5220 } else {
5221 /* keep on matching */
5222 nextmatch = match;
5227 g_free( fName );
5229 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5230 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5231 g_free(fi);
5232 list = g_list_next( list );
5237 * This function is used by to check if a matcher book/folder path corresponds to an
5238 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5239 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5240 if book AND folder are NULL this means that folderpath was empty or Any.
5241 If folderpath is a simple book name (without folder), book will not be NULL and folder
5242 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5245 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5246 AddressDataSource **book,
5247 ItemFolder **folder )
5249 AddressDataSource *ds;
5250 GList *list, *nodeDS;
5251 ItemFolder *rootFolder;
5252 AddressBookFile *abf;
5253 FolderInfo *fi;
5254 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5256 if ( book )
5257 *book = NULL;
5258 if ( folder )
5259 *folder = NULL;
5261 if ( folderpath == NULL )
5262 return FALSE;
5264 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5265 return TRUE;
5267 /* split the folder path we've received, we'll try to match this path, subpath by
5268 subpath against the book/folder structure in order */
5269 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5270 if (!folder_path_match.folder_path)
5271 return FALSE;
5273 list = addrindex_get_interface_list( _addressIndex_ );
5274 while ( list && !folder_path_match.matched ) {
5275 AddressInterface *interface = list->data;
5276 if ( interface && interface->type == ADDR_IF_BOOK ) {
5277 nodeDS = interface->listSource;
5278 while ( nodeDS && !folder_path_match.matched ) {
5279 ds = nodeDS->data;
5281 /* Read address book */
5282 if( ! addrindex_ds_get_read_flag( ds ) ) {
5283 addrindex_ds_read_data( ds );
5286 /* Add node for address book */
5287 abf = ds->rawDataSource;
5289 /* match book name */
5290 if ( abf && abf->fileName &&
5291 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5293 debug_print("matched book name '%s'\n", abf->fileName);
5294 folder_path_match.book = ds;
5296 if ( folder_path_match.folder_path[1] == NULL ) {
5297 /* no folder part to match */
5299 folder_path_match.matched = TRUE;
5300 folder_path_match.folder = NULL;
5301 debug_print("book path matched!\n");
5303 } else {
5304 /* match folder part */
5306 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5307 rootFolder = addrindex_ds_get_root_folder( ds );
5309 /* prepare for recursive call */
5310 folder_path_match.index = 1;
5311 /* this call will set folder_path_match.matched and folder_path_match.folder */
5312 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5313 g_free(fi);
5317 nodeDS = g_list_next( nodeDS );
5320 list = g_list_next( list );
5323 g_strfreev( folder_path_match.folder_path );
5325 if ( book )
5326 *book = folder_path_match.book;
5327 if ( folder )
5328 *folder = folder_path_match.folder;
5329 return folder_path_match.matched;
5333 /* **********************************************************************
5334 * Address Import.
5335 * ***********************************************************************
5339 * Import LDIF file.
5341 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5342 AddressDataSource *ds = NULL;
5343 AdapterDSource *ads = NULL;
5344 AddressBookFile *abf = NULL;
5345 AdapterInterface *adapter;
5346 GtkCMCTreeNode *newNode;
5348 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5349 if( adapter ) {
5350 if( adapter->treeNode ) {
5351 abf = addressbook_imp_ldif( _addressIndex_ );
5352 if( abf ) {
5353 ds = addrindex_index_add_datasource(
5354 _addressIndex_, ADDR_IF_BOOK, abf );
5355 ads = addressbook_create_ds_adapter(
5356 ds, ADDR_BOOK, NULL );
5357 addressbook_ads_set_name(
5358 ads, addrbook_get_name( abf ) );
5359 newNode = addressbook_add_object(
5360 adapter->treeNode,
5361 ADDRESS_OBJECT(ads) );
5362 if( newNode ) {
5363 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5364 newNode );
5365 addrbook.treeSelected = newNode;
5368 /* Notify address completion */
5369 invalidate_address_completion();
5376 * Import MUTT file.
5378 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5379 AddressDataSource *ds = NULL;
5380 AdapterDSource *ads = NULL;
5381 AddressBookFile *abf = NULL;
5382 AdapterInterface *adapter;
5383 GtkCMCTreeNode *newNode;
5385 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5386 if( adapter ) {
5387 if( adapter->treeNode ) {
5388 abf = addressbook_imp_mutt( _addressIndex_ );
5389 if( abf ) {
5390 ds = addrindex_index_add_datasource(
5391 _addressIndex_, ADDR_IF_BOOK, abf );
5392 ads = addressbook_create_ds_adapter(
5393 ds, ADDR_BOOK, NULL );
5394 addressbook_ads_set_name(
5395 ads, addrbook_get_name( abf ) );
5396 newNode = addressbook_add_object(
5397 adapter->treeNode,
5398 ADDRESS_OBJECT(ads) );
5399 if( newNode ) {
5400 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5401 newNode );
5402 addrbook.treeSelected = newNode;
5405 /* Notify address completion */
5406 invalidate_address_completion();
5413 * Import Pine file.
5415 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5416 AddressDataSource *ds = NULL;
5417 AdapterDSource *ads = NULL;
5418 AddressBookFile *abf = NULL;
5419 AdapterInterface *adapter;
5420 GtkCMCTreeNode *newNode;
5422 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5423 if( adapter ) {
5424 if( adapter->treeNode ) {
5425 abf = addressbook_imp_pine( _addressIndex_ );
5426 if( abf ) {
5427 ds = addrindex_index_add_datasource(
5428 _addressIndex_, ADDR_IF_BOOK, abf );
5429 ads = addressbook_create_ds_adapter(
5430 ds, ADDR_BOOK, NULL );
5431 addressbook_ads_set_name(
5432 ads, addrbook_get_name( abf ) );
5433 newNode = addressbook_add_object(
5434 adapter->treeNode,
5435 ADDRESS_OBJECT(ads) );
5436 if( newNode ) {
5437 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5438 newNode );
5439 addrbook.treeSelected = newNode;
5442 /* Notify address completion */
5443 invalidate_address_completion();
5450 * Harvest addresses.
5451 * \param folderItem Folder to import.
5452 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5453 * \param msgList List of message numbers, or NULL to process folder.
5455 void addressbook_harvest(
5456 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5458 AddressDataSource *ds = NULL;
5459 AdapterDSource *ads = NULL;
5460 AddressBookFile *abf = NULL;
5461 AdapterInterface *adapter;
5462 GtkCMCTreeNode *newNode;
5464 abf = addrgather_dlg_execute(
5465 folderItem, _addressIndex_, sourceInd, msgList );
5466 if( abf ) {
5467 ds = addrindex_index_add_datasource(
5468 _addressIndex_, ADDR_IF_BOOK, abf );
5470 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5471 if( adapter ) {
5472 if( adapter->treeNode ) {
5473 ads = addressbook_create_ds_adapter(
5474 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5475 newNode = addressbook_add_object(
5476 adapter->treeNode,
5477 ADDRESS_OBJECT(ads) );
5478 if (newNode == NULL) {
5479 g_message("error adding addressbook object\n");
5484 /* Notify address completion */
5485 invalidate_address_completion();
5490 * Export HTML file.
5492 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5493 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5494 AddressObject *obj;
5495 AddressDataSource *ds = NULL;
5496 AddrBookBase *adbase;
5497 AddressCache *cache;
5498 GtkCMCTreeNode *node = NULL;
5500 if( ! addrbook.treeSelected ) return;
5501 node = addrbook.treeSelected;
5502 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5503 obj = gtk_cmctree_node_get_row_data( ctree, node );
5504 if( obj == NULL ) return;
5506 ds = addressbook_find_datasource( node );
5507 if( ds == NULL ) return;
5508 adbase = ( AddrBookBase * ) ds->rawDataSource;
5509 cache = adbase->addressCache;
5510 addressbook_exp_html( cache );
5514 * Export LDIF file.
5516 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5517 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5518 AddressObject *obj;
5519 AddressDataSource *ds = NULL;
5520 AddrBookBase *adbase;
5521 AddressCache *cache;
5522 GtkCMCTreeNode *node = NULL;
5524 if( ! addrbook.treeSelected ) return;
5525 node = addrbook.treeSelected;
5526 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5527 obj = gtk_cmctree_node_get_row_data( ctree, node );
5528 if( obj == NULL ) return;
5530 ds = addressbook_find_datasource( node );
5531 if( ds == NULL ) return;
5532 adbase = ( AddrBookBase * ) ds->rawDataSource;
5533 cache = adbase->addressCache;
5534 addressbook_exp_ldif( cache );
5537 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5539 addrduplicates_find(GTK_WINDOW(addrbook.window));
5542 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5544 addressbook_custom_attr_edit();
5547 static void addressbook_start_drag(GtkWidget *widget, gint button,
5548 GdkEvent *event,
5549 void *data)
5551 GdkDragContext *context;
5552 if (addressbook_target_list == NULL)
5553 addressbook_target_list = gtk_target_list_new(
5554 addressbook_drag_types, 1);
5555 context = gtk_drag_begin(widget, addressbook_target_list,
5556 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5557 gtk_drag_set_icon_default(context);
5560 static void addressbook_drag_data_get(GtkWidget *widget,
5561 GdkDragContext *drag_context,
5562 GtkSelectionData *selection_data,
5563 guint info,
5564 guint time,
5565 void *data)
5567 AddrItemObject *aio = NULL;
5568 AddressObject *pobj = NULL;
5569 AdapterDSource *ads = NULL;
5570 AddressDataSource *ds = NULL;
5571 GList *cur;
5573 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5575 if( pobj == NULL ) return;
5577 if( pobj->type == ADDR_DATASOURCE ) {
5578 ads = ADAPTER_DSOURCE(pobj);
5579 ds = ads->dataSource;
5580 } else if (pobj->type == ADDR_ITEM_GROUP) {
5582 return;
5585 else if( pobj->type != ADDR_INTERFACE ) {
5586 ds = addressbook_find_datasource( addrbook.treeSelected );
5588 if (!ds)
5589 return;
5592 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5593 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5594 GTK_CMCTREE_NODE(cur->data));
5595 while (aio && aio->type != ITEMTYPE_PERSON) {
5596 aio = aio->parent;
5600 if (aio && aio->type == ITEMTYPE_PERSON) {
5601 if( ds && ds->interface && ds->interface->readOnly)
5602 gtk_selection_data_set(selection_data,
5603 gtk_selection_data_get_target(selection_data), 8,
5604 (const guchar *)"Dummy_addr_copy", 15);
5605 else
5606 gtk_selection_data_set(selection_data,
5607 gtk_selection_data_get_target(selection_data), 8,
5608 (const guchar *)"Dummy_addr_move", 15);
5612 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5613 GdkDragContext *context,
5614 gint x,
5615 gint y,
5616 guint time,
5617 void *data)
5619 GtkAllocation allocation;
5620 GtkRequisition requisition;
5621 gint row, column;
5622 GtkCMCTreeNode *node = NULL;
5623 gboolean acceptable = FALSE;
5624 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5625 gint height = allocation.height;
5626 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5627 gint total_height = requisition.height;
5628 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5629 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5630 gfloat vpos = gtk_adjustment_get_value(pos);
5632 if (gtk_cmclist_get_selection_info
5633 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5635 if (y > height - 24 && height + vpos < total_height) {
5636 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5637 gtk_adjustment_changed(pos);
5639 if (y < 24 && y > 0) {
5640 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5641 gtk_adjustment_changed(pos);
5643 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5645 if (node != NULL) {
5646 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5647 if( obj->type == ADDR_ITEM_FOLDER
5648 || obj->type == ADDR_ITEM_GROUP)
5649 acceptable = TRUE;
5650 else {
5651 AdapterDSource *ads = NULL;
5652 AddressDataSource *ds = NULL;
5653 ads = ADAPTER_DSOURCE(obj);
5654 if (ads == NULL ){ return FALSE;}
5655 ds = ads->dataSource;
5656 if (ds == NULL ) { return FALSE;}
5658 acceptable = TRUE;
5663 if (acceptable) {
5664 g_signal_handlers_block_by_func
5665 (G_OBJECT(widget),
5666 G_CALLBACK(addressbook_tree_selected), NULL);
5667 gtk_sctree_select( GTK_SCTREE(widget), node);
5668 g_signal_handlers_unblock_by_func
5669 (G_OBJECT(widget),
5670 G_CALLBACK(addressbook_tree_selected), NULL);
5671 gdk_drag_status(context,
5672 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5673 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5674 } else {
5675 gdk_drag_status(context, 0, time);
5677 return acceptable;
5680 static void addressbook_drag_leave_cb(GtkWidget *widget,
5681 GdkDragContext *context,
5682 guint time,
5683 void *data)
5685 if (addrbook.treeSelected) {
5686 g_signal_handlers_block_by_func
5687 (G_OBJECT(widget),
5688 G_CALLBACK(addressbook_tree_selected), NULL);
5689 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5690 g_signal_handlers_unblock_by_func
5691 (G_OBJECT(widget),
5692 G_CALLBACK(addressbook_tree_selected), NULL);
5697 static void addressbook_drag_received_cb(GtkWidget *widget,
5698 GdkDragContext *drag_context,
5699 gint x,
5700 gint y,
5701 GtkSelectionData *data,
5702 guint info,
5703 guint time,
5704 void *pdata)
5706 gint row, column;
5707 GtkCMCTreeNode *node;
5708 GtkCMCTreeNode *lastopened = addrbook.opened;
5710 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5711 if (gtk_cmclist_get_selection_info
5712 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5713 return;
5716 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5717 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5718 return;
5720 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5721 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5722 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5723 addressbook_clip_copy_cb(NULL, NULL);
5724 else
5725 addressbook_clip_cut_cb(NULL, NULL);
5726 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5727 addressbook_clip_paste_cb(NULL,NULL);
5728 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5729 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5730 gtk_drag_finish(drag_context, TRUE, TRUE, time);
5735 * End of Source.