Fix bug #3574: Template addressing
[claws.git] / src / addressbook.c
blob403b556c9501aeaeb40e8195004eb30f530462bf
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 void addressbook_entry_activated (GtkWidget *widget,
214 gpointer data);
216 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
217 GdkEventButton *event,
218 gpointer data);
219 static gboolean addressbook_list_button_released(GtkWidget *widget,
220 GdkEventButton *event,
221 gpointer data);
222 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
223 GdkEventButton *event,
224 gpointer data);
225 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
226 GdkEventButton *event,
227 gpointer data);
229 static void addressbook_new_folder_cb (GtkAction *action,
230 gpointer data);
231 static void addressbook_new_group_cb (GtkAction *action,
232 gpointer data);
233 static void addressbook_treenode_edit_cb (GtkAction *action,
234 gpointer data);
235 static void addressbook_treenode_delete_cb (GtkAction *action,
236 gpointer data);
238 static void addressbook_change_node_name (GtkCMCTreeNode *node,
239 const gchar *name);
241 static void addressbook_new_address_cb (GtkAction *action,
242 gpointer data);
243 static void addressbook_edit_address_cb (GtkAction *action,
244 gpointer data);
245 static void addressbook_delete_address_cb (GtkAction *action,
246 gpointer data);
248 static void close_cb (GtkAction *action,
249 gpointer data);
250 static void addressbook_file_save_cb (GtkAction *action,
251 gpointer data);
253 /* Data source edit stuff */
254 static void addressbook_new_book_cb (GtkAction *action,
255 gpointer data);
256 static void addressbook_new_vcard_cb (GtkAction *action,
257 gpointer data);
259 #ifdef USE_JPILOT
260 static void addressbook_new_jpilot_cb (GtkAction *action,
261 gpointer data);
262 #endif
264 #ifdef USE_LDAP
265 static void addressbook_new_ldap_cb (GtkAction *action,
266 gpointer data);
267 #endif
269 static void addressbook_set_clist (AddressObject *obj,
270 gboolean refresh);
272 static void addressbook_load_tree (void);
273 void addressbook_read_file (void);
275 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
276 AddressObject *obj);
277 static void addressbook_treenode_remove_item ( void );
279 static AddressDataSource *addressbook_find_datasource
280 (GtkCMCTreeNode *node );
282 static AddressBookFile *addressbook_get_book_file(void);
284 static GtkCMCTreeNode *addressbook_node_add_folder
285 (GtkCMCTreeNode *node,
286 AddressDataSource *ds,
287 ItemFolder *itemFolder,
288 AddressObjectType otype);
289 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
290 AddressDataSource *ds,
291 ItemGroup *itemGroup);
292 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
293 GtkCMCTreeNode *parent);
294 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
295 GtkCMCTreeNode *node);
296 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
297 ItemGroup *group);
298 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
299 GdkEventKey *event,
300 gpointer data);
301 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
302 gconstpointer ptr1,
303 gconstpointer ptr2);
304 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
305 ItemPerson *person,
306 AddressTypeControlItem *atci,
307 AddressTypeControlItem *atciMail);
308 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
309 ItemPerson *person);
310 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
311 ItemPerson *person);
312 static void addressbook_folder_remove_node (GtkCMCTree *clist,
313 GtkCMCTreeNode *node);
315 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
316 gboolean force_focus );
318 /* LUT's and IF stuff */
319 static void addressbook_free_treenode ( gpointer data );
320 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
321 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
323 static void addrbookctl_build_map (GtkWidget *window);
324 static void addrbookctl_build_iflist (void);
325 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
326 static void addrbookctl_build_ifselect (void);
328 static void addrbookctl_free_interface (AdapterInterface *adapter);
329 static void addrbookctl_free_datasource (AdapterDSource *adapter);
330 static void addrbookctl_free_folder (AdapterFolder *adapter);
331 static void addrbookctl_free_group (AdapterGroup *adapter);
333 static void addressbook_list_select_clear ( void );
334 static void addressbook_list_select_add ( AddrItemObject *aio,
335 AddressDataSource *ds );
336 static void addressbook_list_select_remove ( AddrItemObject *aio );
338 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
339 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
340 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
342 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
344 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
345 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
348 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
351 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
353 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
355 #ifdef USE_LDAP
356 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
357 #endif
358 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
360 static void addressbook_start_drag(GtkWidget *widget, gint button,
361 GdkEvent *event,
362 void *data);
363 static void addressbook_drag_data_get(GtkWidget *widget,
364 GdkDragContext *drag_context,
365 GtkSelectionData *selection_data,
366 guint info,
367 guint time,
368 void *data);
369 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
370 GdkDragContext *context,
371 gint x,
372 gint y,
373 guint time,
374 void *data);
375 static void addressbook_drag_leave_cb(GtkWidget *widget,
376 GdkDragContext *context,
377 guint time,
378 void *data);
379 static void addressbook_drag_received_cb(GtkWidget *widget,
380 GdkDragContext *drag_context,
381 gint x,
382 gint y,
383 GtkSelectionData *data,
384 guint info,
385 guint time,
386 void *pdata);
387 static void addressbook_list_menu_setup( void );
389 static GtkTargetEntry addressbook_drag_types[] =
391 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
394 static GtkTargetList *addressbook_target_list = NULL;
396 static void about_show_cb(GtkAction *action, gpointer data)
398 about_show();
401 static GtkActionEntry addressbook_entries[] =
403 {"Menu", NULL, "Menu" },
404 /* menus */
405 {"Book", NULL, N_("_Book") },
406 {"Address", NULL, N_("_Edit") },
407 {"Tools", NULL, N_("_Tools") },
408 {"Help", NULL, N_("_Help") },
410 /* Book menu */
411 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
412 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
413 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
416 #ifdef USE_JPILOT
417 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
418 #endif
419 #ifdef USE_LDAP
420 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
421 #endif
422 {"Book/---", NULL, "---", NULL, NULL, NULL },
424 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
425 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
426 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
427 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
428 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
430 /* Adress menu */
431 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
432 {"Address/---", NULL, "---", NULL, NULL, NULL },
433 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
434 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
435 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
438 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
439 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
440 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
441 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
442 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
443 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
446 /* Tools menu */
447 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
448 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
449 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
450 {"Tools/---", NULL, "---", NULL, NULL, NULL },
451 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
452 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
453 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
454 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
455 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
457 /* Help menu */
458 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
462 static GtkActionEntry addressbook_tree_popup_entries[] =
464 {"ABTreePopup", NULL, "ABTreePopup" },
465 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
466 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
467 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
468 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
469 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
470 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
471 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
472 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
473 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
474 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
477 static GtkActionEntry addressbook_list_popup_entries[] =
479 {"ABListPopup", NULL, "ABListPopup" },
480 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
481 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
482 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
483 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
484 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
485 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
486 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
489 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
490 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
491 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
492 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
493 #ifdef USE_LDAP
494 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
495 #endif
499 * Structure of error message table.
501 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
502 struct _ErrMsgTableEntry {
503 gint code;
504 gchar *description;
507 static gchar *_errMsgUnknown_ = N_( "Unknown" );
510 * Lookup table of error messages for general errors. Note that a NULL
511 * description signifies the end of the table.
513 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
514 { MGU_SUCCESS, N_("Success") },
515 { MGU_BAD_ARGS, N_("Bad arguments") },
516 { MGU_NO_FILE, N_("File not specified") },
517 { MGU_OPEN_FILE, N_("Error opening file") },
518 { MGU_ERROR_READ, N_("Error reading file") },
519 { MGU_EOF, N_("End of file encountered") },
520 { MGU_OO_MEMORY, N_("Error allocating memory") },
521 { MGU_BAD_FORMAT, N_("Bad file format") },
522 { MGU_ERROR_WRITE, N_("Error writing to file") },
523 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
524 { MGU_NO_PATH, N_("No path specified") },
525 { 0, NULL }
528 #ifdef USE_LDAP
530 * Lookup table of error messages for LDAP errors.
532 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
533 { LDAPRC_SUCCESS, N_("Success") },
534 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
535 { LDAPRC_INIT, N_("Error initializing LDAP") },
536 { LDAPRC_BIND, N_("Error binding to LDAP server") },
537 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
538 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
539 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
540 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
541 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
542 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
543 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
544 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
545 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
546 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
547 { 0, NULL }
549 #endif
552 * Lookup message for specified error code.
553 * \param lut Lookup table.
554 * \param code Code to lookup.
555 * \return Description associated to code.
557 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
558 gchar *desc = NULL;
559 ErrMsgTableEntry entry;
560 gint i;
562 for( i = 0; ; i++ ) {
563 entry = lut[ i ];
564 if( entry.description == NULL ) break;
565 if( entry.code == code ) {
566 desc = entry.description;
567 break;
570 if( ! desc ) {
571 desc = _errMsgUnknown_;
573 return desc;
576 static gboolean lastCanLookup = FALSE;
578 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
580 if (add_and_delete) {
581 gtk_widget_show(addrbook.edit_btn);
582 gtk_widget_show(addrbook.del_btn);
583 gtk_widget_show(addrbook.reg_btn);
584 } else {
585 gtk_widget_hide(addrbook.edit_btn);
586 gtk_widget_hide(addrbook.del_btn);
587 gtk_widget_hide(addrbook.reg_btn);
590 if (lookup) {
591 gtk_widget_show(addrbook.lup_btn);
592 gtk_widget_show(addrbook.entry);
593 gtk_widget_show(addrbook.label);
594 } else {
595 gtk_widget_hide(addrbook.lup_btn);
596 gtk_widget_hide(addrbook.entry);
597 gtk_widget_hide(addrbook.label);
600 lastCanLookup = lookup;
602 if (mail_ops) {
603 gtk_widget_show(addrbook.to_btn);
604 gtk_widget_show(addrbook.cc_btn);
605 gtk_widget_show(addrbook.bcc_btn);
606 } else {
607 gtk_widget_hide(addrbook.to_btn);
608 gtk_widget_hide(addrbook.cc_btn);
609 gtk_widget_hide(addrbook.bcc_btn);
613 void addressbook_open(Compose *target)
615 /* Initialize all static members */
616 if( _clipBoard_ == NULL ) {
617 _clipBoard_ = addrclip_create();
619 if( _addressIndex_ != NULL ) {
620 addrclip_set_index( _clipBoard_, _addressIndex_ );
622 if( _addressSelect_ == NULL ) {
623 _addressSelect_ = addrselect_list_create();
625 if (!addrbook.window) {
626 addressbook_read_file();
627 addressbook_create();
628 addressbook_load_tree();
629 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
630 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
632 else {
633 gtk_widget_hide(addrbook.window);
636 gtk_widget_show_all(addrbook.window);
638 if (!prefs_common.addressbook_use_editaddress_dialog)
639 addressbook_edit_person_widgetset_hide();
641 address_completion_start(addrbook.window);
643 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
644 addressbook_set_target_compose(target);
648 * Destroy addressbook.
650 void addressbook_destroy( void ) {
651 /* Free up address stuff */
652 if( _addressSelect_ != NULL ) {
653 addrselect_list_free( _addressSelect_ );
655 if( _clipBoard_ != NULL ) {
656 addrclip_free( _clipBoard_ );
658 if( _addressIndex_ != NULL ) {
659 addrindex_free_index( _addressIndex_ );
660 addrindex_teardown();
662 _addressSelect_ = NULL;
663 _clipBoard_ = NULL;
664 _addressIndex_ = NULL;
667 void addressbook_set_target_compose(Compose *target)
669 addrbook.target_compose = target;
672 Compose *addressbook_get_target_compose(void)
674 return addrbook.target_compose;
678 * Refresh addressbook and save to file(s).
680 void addressbook_refresh( void )
682 if (addrbook.window) {
683 if (addrbook.treeSelected) {
684 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
685 addrbook.treeSelected);
686 addressbook_set_clist(
687 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
688 addrbook.treeSelected),
689 TRUE);
693 addressbook_export_to_file();
696 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
698 if (event && event->keyval == GDK_KEY_Escape)
699 addressbook_close();
700 else if (event && event->keyval == GDK_KEY_Delete) {
701 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
702 if ( /* address_index_has_focus || */ address_list_has_focus )
703 addressbook_del_clicked(NULL, NULL);
705 return FALSE;
709 *\brief Save Gtk object size to prefs dataset
711 static void addressbook_size_allocate_cb(GtkWidget *widget,
712 GtkAllocation *allocation)
714 cm_return_if_fail(allocation != NULL);
716 prefs_common.addressbookwin_width = allocation->width;
717 prefs_common.addressbookwin_height = allocation->height;
720 static gint sort_column_number = 0;
721 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
723 static gint list_case_sort(
724 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
726 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
727 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
728 gchar *name1 = NULL, *name2 = NULL;
729 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
730 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
732 if( aio1->type == aio2->type ) {
733 if( row1 )
734 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
735 if( row2 )
736 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
737 if( ! name1 ) return ( name2 != NULL );
738 if( ! name2 ) return -1;
739 return g_utf8_collate( name1, name2 );
740 } else {
741 /* Order groups before person */
742 if( aio1->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
744 } else if( aio2->type == ITEMTYPE_GROUP ) {
745 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
747 return 0;
751 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
752 const GtkSortType sort_type)
754 gint pos;
755 GtkWidget *hbox, *label, *arrow;
757 sort_column_number = col;
758 sort_column_type = sort_type;
759 gtk_cmclist_set_compare_func(clist, list_case_sort);
760 gtk_cmclist_set_sort_type(clist, sort_type);
761 gtk_cmclist_set_sort_column(clist, col);
763 gtk_cmclist_freeze(clist);
764 gtk_cmclist_sort(clist);
766 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
767 hbox = gtk_hbox_new(FALSE, 4);
768 label = gtk_label_new(gettext(list_titles[pos]));
769 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
771 if(pos == col) {
772 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
773 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
774 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
777 gtk_widget_show_all(hbox);
778 gtk_cmclist_set_column_widget(clist, pos, hbox);
781 gtk_cmclist_thaw(clist);
784 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
786 static GtkSortType sort_type = GTK_SORT_ASCENDING;
788 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
789 GTK_SORT_ASCENDING;
790 addressbook_sort_list(clist, COL_NAME, sort_type);
793 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
795 static GtkSortType sort_type = GTK_SORT_ASCENDING;
797 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
798 GTK_SORT_ASCENDING;
799 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
802 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
804 static GtkSortType sort_type = GTK_SORT_ASCENDING;
806 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
807 GTK_SORT_ASCENDING;
808 addressbook_sort_list(clist, COL_REMARKS, sort_type);
811 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
812 gpointer data)
814 address_index_has_focus = TRUE;
815 return FALSE;
818 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
819 gpointer data)
821 address_index_has_focus = FALSE;
822 if (!prefs_common.addressbook_use_editaddress_dialog
823 && !address_list_has_focus)
824 addressbook_address_list_disable_some_actions();
825 return FALSE;
828 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
829 gpointer data)
831 address_list_has_focus = TRUE;
832 return FALSE;
835 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
836 gpointer data)
838 address_list_has_focus = FALSE;
839 if (!prefs_common.addressbook_use_editaddress_dialog
840 && !address_index_has_focus)
841 addressbook_address_list_disable_some_actions();
842 return FALSE;
845 /* save hpane and vpane's handle position when it moves */
846 static void addressbook_pane_save_position(void)
848 if (addrbook.hpaned)
849 prefs_common.addressbook_hpaned_pos =
850 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
851 if (addrbook.vpaned)
852 prefs_common.addressbook_vpaned_pos =
853 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
857 * Create the address book widgets. The address book contains two CTree widgets: the
858 * address index tree on the left and the address list on the right.
860 * The address index tree displays a hierarchy of interfaces and groups. Each node in
861 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
862 * data sources and folder objects.
864 * The address list displays group, person and email objects. These items are linked
865 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
866 * sources.
868 * In the tradition of MVC architecture, the data stores have been separated from the
869 * GUI components. The addrindex.c file provides the interface to all data stores.
871 static void addressbook_create(void)
873 GtkWidget *window;
874 GtkWidget *vbox;
875 GtkWidget *menubar;
876 GtkWidget *vbox2;
877 GtkWidget *ctree_swin;
878 GtkWidget *ctree;
879 GtkWidget *editaddress_vbox;
880 GtkWidget *clist_vbox;
881 GtkWidget *clist_swin;
882 GtkWidget *clist;
883 GtkWidget *hpaned;
884 GtkWidget *vpaned;
885 GtkWidget *hbox;
886 GtkWidget *label;
887 GtkWidget *entry;
888 GtkWidget *statusbar;
889 GtkWidget *hbbox;
890 GtkWidget *hsbox;
891 GtkWidget *help_btn;
892 GtkWidget *del_btn;
893 GtkWidget *edit_btn;
894 GtkWidget *reg_btn;
895 GtkWidget *lup_btn;
896 GtkWidget *to_btn;
897 GtkWidget *cc_btn;
898 GtkWidget *bcc_btn;
899 GtkWidget *close_btn;
900 GtkWidget *tree_popup;
901 GtkWidget *list_popup;
902 GList *nodeIf;
903 GtkUIManager *ui_manager;
904 GtkActionGroup *action_group;
905 gchar *index_titles[N_INDEX_COLS];
906 gchar *text;
907 gint i;
909 static GdkGeometry geometry;
911 debug_print("Creating addressbook window...\n");
913 index_titles[COL_SOURCES] = _("Sources");
915 /* Address book window */
916 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
917 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
918 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
919 gtk_widget_realize(window);
921 g_signal_connect(G_OBJECT(window), "delete_event",
922 G_CALLBACK(addressbook_close), NULL);
923 g_signal_connect(G_OBJECT(window), "size_allocate",
924 G_CALLBACK(addressbook_size_allocate_cb), NULL);
925 g_signal_connect(G_OBJECT(window), "key_press_event",
926 G_CALLBACK(key_pressed), NULL);
927 MANAGE_WINDOW_SIGNALS_CONNECT(window);
929 vbox = gtk_vbox_new(FALSE, 0);
930 gtk_container_add(GTK_CONTAINER(window), vbox);
932 /* Menu bar */
933 ui_manager = gtk_ui_manager_new();
934 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
935 G_N_ELEMENTS(addressbook_entries), NULL);
936 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
937 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
938 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
939 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
948 /* Book menu */
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
952 #ifdef USE_JPILOT
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
954 #endif
955 #ifdef USE_LDAP
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
957 #endif
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
965 /* Address menu */
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
980 /* Tools menu */
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
991 /* Help menu */
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
994 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
996 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
998 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
999 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1000 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1002 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1003 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1004 GTK_POLICY_AUTOMATIC,
1005 GTK_POLICY_AUTOMATIC);
1006 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1008 /* Address index */
1009 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1010 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1012 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1013 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1014 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1015 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1016 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1017 GTK_CMCTREE_EXPANDER_TRIANGLE);
1018 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1019 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1020 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1021 addressbook_treenode_compare_func);
1023 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1024 G_CALLBACK(addressbook_tree_selected), NULL);
1025 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1026 G_CALLBACK(addressbook_tree_button_pressed),
1027 NULL);
1028 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1029 G_CALLBACK(addressbook_tree_button_released),
1030 NULL);
1031 /* TEMPORARY */
1032 g_signal_connect(G_OBJECT(ctree), "select_row",
1033 G_CALLBACK(addressbook_select_row_tree), NULL);
1035 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1036 addressbook_drag_types, 1,
1037 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1038 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1039 G_CALLBACK(addressbook_drag_motion_cb),
1040 ctree);
1041 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1042 G_CALLBACK(addressbook_drag_leave_cb),
1043 ctree);
1044 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1045 G_CALLBACK(addressbook_drag_received_cb),
1046 ctree);
1047 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1048 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1049 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1050 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1052 clist_vbox = gtk_vbox_new(FALSE, 4);
1054 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1055 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1056 GTK_POLICY_AUTOMATIC,
1057 GTK_POLICY_AUTOMATIC);
1058 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1060 /* Address list */
1061 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1062 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1063 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1064 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1065 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1066 GTK_CMCTREE_EXPANDER_TRIANGLE);
1067 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1068 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1069 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1070 COL_NAME_WIDTH);
1071 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1072 COL_ADDRESS_WIDTH);
1073 gtk_widget_set_size_request(clist, -1, 80);
1075 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1076 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1077 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1078 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1079 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1080 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1081 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1082 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1083 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1084 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1085 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1087 for (i = 0; i < N_LIST_COLS; i++)
1088 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1089 FALSE);
1091 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1092 G_CALLBACK(addressbook_list_row_selected), NULL);
1093 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1094 G_CALLBACK(addressbook_list_row_unselected), NULL);
1095 g_signal_connect(G_OBJECT(clist), "button_press_event",
1096 G_CALLBACK(addressbook_list_button_pressed),
1097 NULL);
1098 g_signal_connect(G_OBJECT(clist), "button_release_event",
1099 G_CALLBACK(addressbook_list_button_released),
1100 NULL);
1101 g_signal_connect(G_OBJECT(clist), "tree_expand",
1102 G_CALLBACK(addressbook_person_expand_node), NULL );
1103 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1104 G_CALLBACK(addressbook_person_collapse_node), NULL );
1105 g_signal_connect(G_OBJECT(clist), "start_drag",
1106 G_CALLBACK(addressbook_start_drag), NULL);
1107 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1108 G_CALLBACK(addressbook_drag_data_get), NULL);
1109 hbox = gtk_hbox_new(FALSE, 4);
1110 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1112 label = gtk_label_new(_("Search"));
1113 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1115 entry = gtk_entry_new();
1116 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1118 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1120 g_signal_connect(G_OBJECT(entry), "key_press_event",
1121 G_CALLBACK(addressbook_entry_key_pressed),
1122 NULL);
1123 g_signal_connect(G_OBJECT(entry), "activate",
1124 G_CALLBACK(addressbook_entry_activated), NULL);
1126 if (!prefs_common.addressbook_use_editaddress_dialog) {
1127 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1128 vpaned = gtk_vpaned_new();
1129 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1130 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1131 } else {
1132 vpaned = NULL;
1133 editaddress_vbox = NULL;
1135 hpaned = gtk_hpaned_new();
1136 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1137 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1138 if (prefs_common.addressbook_use_editaddress_dialog)
1139 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1140 else
1141 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1143 /* Status bar */
1144 hsbox = gtk_hbox_new(FALSE, 0);
1145 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1146 statusbar = gtk_statusbar_new();
1147 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1149 /* Button panel */
1150 hbbox = gtk_hbutton_box_new();
1151 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1152 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1153 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1154 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1156 gtkut_stock_button_add_help(hbbox, &help_btn);
1158 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1159 gtkut_widget_set_can_default(edit_btn, TRUE);
1160 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1161 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1162 gtkut_widget_set_can_default(del_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1164 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1165 gtkut_widget_set_can_default(reg_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1169 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1170 gtkut_widget_set_can_default(lup_btn, TRUE);
1171 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1173 g_signal_connect(G_OBJECT(help_btn), "clicked",
1174 G_CALLBACK(manual_open_with_anchor_cb),
1175 MANUAL_ANCHOR_ADDRBOOK);
1177 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1178 G_CALLBACK(addressbook_edit_clicked), NULL);
1179 g_signal_connect(G_OBJECT(del_btn), "clicked",
1180 G_CALLBACK(addressbook_del_clicked), NULL);
1181 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1182 G_CALLBACK(addressbook_reg_clicked), NULL);
1183 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1184 G_CALLBACK(addressbook_lup_clicked), NULL);
1186 to_btn = gtk_button_new_with_label
1187 (prefs_common_translated_header_name("To:"));
1188 gtkut_widget_set_can_default(to_btn, TRUE);
1189 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1190 cc_btn = gtk_button_new_with_label
1191 (prefs_common_translated_header_name("Cc:"));
1192 gtkut_widget_set_can_default(cc_btn, TRUE);
1193 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1194 bcc_btn = gtk_button_new_with_label
1195 (prefs_common_translated_header_name("Bcc:"));
1196 gtkut_widget_set_can_default(bcc_btn, TRUE);
1197 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1199 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1200 gtkut_widget_set_can_default(close_btn, TRUE);
1201 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1203 g_signal_connect(G_OBJECT(to_btn), "clicked",
1204 G_CALLBACK(addressbook_to_clicked),
1205 GINT_TO_POINTER(COMPOSE_TO));
1206 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1207 G_CALLBACK(addressbook_to_clicked),
1208 GINT_TO_POINTER(COMPOSE_CC));
1209 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1210 G_CALLBACK(addressbook_to_clicked),
1211 GINT_TO_POINTER(COMPOSE_BCC));
1212 g_signal_connect(G_OBJECT(close_btn), "clicked",
1213 G_CALLBACK(addressbook_close_clicked), NULL);
1215 /* Build icons for interface */
1217 /* Build control tables */
1218 addrbookctl_build_map(window);
1219 addrbookctl_build_iflist();
1220 addrbookctl_build_ifselect();
1222 addrbook.clist = NULL;
1224 /* Add each interface into the tree as a root level folder */
1225 nodeIf = _addressInterfaceList_;
1226 while( nodeIf ) {
1227 AdapterInterface *adapter = nodeIf->data;
1228 AddressInterface *iface = adapter->interface;
1229 nodeIf = g_list_next(nodeIf);
1231 if(iface->useInterface) {
1232 AddressTypeControlItem *atci = adapter->atci;
1233 text = atci->displayName;
1234 adapter->treeNode =
1235 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1236 NULL, NULL, &text, FOLDER_SPACING,
1237 interfacexpm,
1238 interfacexpm,
1239 FALSE, FALSE );
1240 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1241 gtk_cmctree_node_set_row_data_full(
1242 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1243 addressbook_free_treenode );
1247 /* Popup menu */
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1262 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1263 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1279 #ifdef USE_LDAP
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1281 #endif
1282 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1283 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1285 addrbook.window = window;
1286 addrbook.hpaned = hpaned;
1287 addrbook.vpaned = vpaned;
1288 addrbook.menubar = menubar;
1289 addrbook.ctree = ctree;
1290 addrbook.ctree_swin
1291 = ctree_swin;
1292 addrbook.editaddress_vbox = editaddress_vbox;
1293 addrbook.clist = clist;
1294 addrbook.label = label;
1295 addrbook.entry = entry;
1296 addrbook.statusbar = statusbar;
1297 addrbook.status_cid = gtk_statusbar_get_context_id(
1298 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1300 addrbook.help_btn = help_btn;
1301 addrbook.edit_btn = edit_btn;
1302 addrbook.del_btn = del_btn;
1303 addrbook.reg_btn = reg_btn;
1304 addrbook.lup_btn = lup_btn;
1305 addrbook.to_btn = to_btn;
1306 addrbook.cc_btn = cc_btn;
1307 addrbook.bcc_btn = bcc_btn;
1309 addrbook.tree_popup = tree_popup;
1310 addrbook.list_popup = list_popup;
1311 addrbook.ui_manager = ui_manager;
1313 addrbook.listSelected = NULL;
1315 if (!geometry.min_height) {
1316 geometry.min_width = ADDRESSBOOK_WIDTH;
1317 geometry.min_height = ADDRESSBOOK_HEIGHT;
1320 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1321 GDK_HINT_MIN_SIZE);
1322 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1323 prefs_common.addressbookwin_height);
1324 #ifdef G_OS_WIN32
1325 gtk_window_move(GTK_WINDOW(window), 48, 48);
1326 #endif
1328 if (!prefs_common.addressbook_use_editaddress_dialog) {
1329 if (prefs_common.addressbook_vpaned_pos > 0)
1330 gtk_paned_set_position(GTK_PANED(vpaned),
1331 prefs_common.addressbook_vpaned_pos);
1333 if (prefs_common.addressbook_hpaned_pos > 0)
1334 gtk_paned_set_position(GTK_PANED(hpaned),
1335 prefs_common.addressbook_hpaned_pos);
1338 gtk_widget_show_all(window);
1342 * Close address book window and save to file(s).
1344 static gint addressbook_close( void ) {
1345 address_completion_end(addrbook.window);
1346 if (!prefs_common.addressbook_use_editaddress_dialog)
1347 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1349 addressbook_pane_save_position();
1351 gtk_widget_hide(addrbook.window);
1352 addressbook_export_to_file();
1353 return TRUE;
1357 * Display message in status line.
1358 * \param msg Message to display.
1360 static void addressbook_status_show( gchar *msg ) {
1361 if( addrbook.statusbar != NULL ) {
1362 gtk_statusbar_pop(
1363 GTK_STATUSBAR(addrbook.statusbar),
1364 addrbook.status_cid );
1365 if( msg ) {
1366 gtk_statusbar_push(
1367 GTK_STATUSBAR(addrbook.statusbar),
1368 addrbook.status_cid, msg );
1373 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1374 gint retVal;
1375 gchar *name;
1376 gchar *desc;
1377 *addressbook_msgbuf = '\0';
1378 if( ds ) {
1379 name = addrindex_ds_get_name( ds );
1380 retVal = addrindex_ds_get_status_code( ds );
1381 if( retVal == MGU_SUCCESS ) {
1382 g_snprintf( addressbook_msgbuf,
1383 sizeof(addressbook_msgbuf), "%s", name );
1385 else {
1386 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1387 g_snprintf( addressbook_msgbuf,
1388 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1391 addressbook_status_show( addressbook_msgbuf );
1394 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1396 addressbook_edit_address_cb(NULL, NULL);
1399 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1401 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1405 * Delete one or more objects from address list.
1407 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1409 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1410 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1411 AddressObject *pobj;
1412 AdapterDSource *ads = NULL;
1413 GtkCMCTreeNode *nodeList;
1414 gboolean procFlag;
1415 AlertValue aval;
1416 AddressBookFile *abf = NULL;
1417 AddressDataSource *ds = NULL;
1418 AddressInterface *iface;
1419 AddrItemObject *aio;
1420 AddrSelectItem *item;
1421 GList *list, *node;
1422 gboolean refreshList = FALSE;
1424 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1425 cm_return_if_fail(pobj != NULL);
1427 /* Test whether anything selected for deletion */
1428 nodeList = addrbook.listSelected;
1430 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1431 if( aio == NULL) return;
1432 ds = addressbook_find_datasource( addrbook.treeSelected );
1433 if( ds == NULL ) return;
1435 /* Test for read only */
1436 iface = ds->interface;
1437 if( iface->readOnly ) {
1438 alertpanel( _("Delete address(es)"),
1439 _("This address data is readonly and cannot be deleted."),
1440 GTK_STOCK_CLOSE, NULL, NULL );
1441 return;
1444 /* Test whether Ok to proceed */
1445 procFlag = FALSE;
1446 if( pobj->type == ADDR_DATASOURCE ) {
1447 ads = ADAPTER_DSOURCE(pobj);
1448 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1450 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1451 procFlag = TRUE;
1453 else if( pobj->type == ADDR_ITEM_GROUP ) {
1454 procFlag = TRUE;
1456 if( ! procFlag ) return;
1457 abf = ds->rawDataSource;
1458 if( abf == NULL ) return;
1460 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1461 g_signal_handlers_block_by_func
1462 (G_OBJECT(addrbook.clist),
1463 G_CALLBACK(addressbook_list_row_unselected), NULL);
1465 /* Process deletions */
1466 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1467 GList *groups = NULL, *persons = NULL, *emails = NULL;
1468 gboolean group_delete = TRUE;
1469 /* Items inside folders */
1470 list = addrselect_get_list( _addressSelect_ );
1471 /* Confirm deletion */
1472 node = list;
1473 while( node ) {
1474 item = node->data;
1475 node = g_list_next( node );
1476 aio = ( AddrItemObject * ) item->addressItem;
1477 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1478 group_delete = FALSE;
1479 break;
1482 if (group_delete) {
1483 aval = alertpanel( _("Delete group"),
1484 _("Really delete the group(s)?\n"
1485 "The addresses it contains will not be lost."),
1486 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1487 if( aval != G_ALERTALTERNATE ) {
1488 goto thaw_ret;
1490 } else {
1491 aval = alertpanel( _("Delete address(es)"),
1492 _("Really delete the address(es)?"),
1493 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1494 if( aval != G_ALERTALTERNATE ) {
1495 goto thaw_ret;
1499 /* first, set lists of groups and persons to remove */
1500 node = list;
1501 while( node ) {
1502 item = node->data;
1503 node = g_list_next( node );
1504 aio = ( AddrItemObject * ) item->addressItem;
1505 if (!aio)
1506 continue;
1507 if( aio->type == ITEMTYPE_GROUP ) {
1508 groups = g_list_prepend(groups, item);
1510 else if( aio->type == ITEMTYPE_PERSON ) {
1511 persons = g_list_prepend(persons, item);
1514 /* then set list of emails to remove *if* they're not children of
1515 * persons to remove */
1516 node = list;
1517 while( node ) {
1518 item = node->data;
1519 node = g_list_next( node );
1520 aio = ( AddrItemObject * ) item->addressItem;
1521 if (!aio)
1522 continue;
1523 if( aio->type == ITEMTYPE_EMAIL ) {
1524 ItemEMail *sitem = ( ItemEMail * ) aio;
1525 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1526 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1527 emails = g_list_prepend(emails, item);
1529 /* else, the email will be removed via the parent person */
1532 /* then delete groups */
1533 node = groups;
1534 while( node ) {
1535 item = node->data;
1536 node = g_list_next( node );
1537 aio = ( AddrItemObject * ) item->addressItem;
1538 if (!aio)
1539 continue;
1540 if( aio->type == ITEMTYPE_GROUP ) {
1541 ItemGroup *item = ( ItemGroup * ) aio;
1542 GtkCMCTreeNode *nd = NULL;
1543 nd = addressbook_find_group_node( addrbook.opened, item );
1544 item = addrbook_remove_group( abf, item );
1545 if( item ) {
1546 addritem_free_item_group( item );
1548 /* Remove group from parent node */
1549 gtk_cmctree_remove_node( ctree, nd );
1550 refreshList = TRUE;
1553 /* then delete persons */
1554 node = persons;
1555 while( node ) {
1556 item = node->data;
1557 node = g_list_next( node );
1558 aio = ( AddrItemObject * ) item->addressItem;
1559 if (!aio)
1560 continue;
1561 if( aio->type == ITEMTYPE_PERSON ) {
1562 ItemPerson *item = ( ItemPerson * ) aio;
1563 item->status = DELETE_ENTRY;
1564 addressbook_folder_remove_one_person( clist, item );
1565 if (pobj->type == ADDR_ITEM_FOLDER)
1566 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1567 item = addrbook_remove_person( abf, item );
1568 #ifdef USE_LDAP
1569 if (ds && ds->type == ADDR_IF_LDAP) {
1570 LdapServer *server = ds->rawDataSource;
1571 ldapsvr_set_modified(server, TRUE);
1572 ldapsvr_update_book(server, item);
1574 #endif
1575 if( item ) {
1576 gchar *filename = addritem_person_get_picture(item);
1577 if (filename && is_file_exist(filename))
1578 claws_unlink(filename);
1579 g_free(filename);
1580 addritem_free_item_person( item );
1584 /* then delete emails */
1585 node = emails;
1586 while( node ) {
1587 item = node->data;
1588 node = g_list_next( node );
1589 aio = ( AddrItemObject * ) item->addressItem;
1590 if (!aio)
1591 continue;
1593 if( aio->type == ITEMTYPE_EMAIL ) {
1594 ItemEMail *sitem = ( ItemEMail * ) aio;
1595 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1596 sitem = addrbook_person_remove_email( abf, person, sitem );
1597 if( sitem ) {
1598 addrcache_remove_email(abf->addressCache, sitem);
1599 addritem_free_item_email( sitem );
1601 addressbook_folder_refresh_one_person( clist, person );
1604 g_list_free( groups );
1605 g_list_free( persons );
1606 g_list_free( emails );
1607 g_list_free( list );
1608 addressbook_list_select_clear();
1609 if( refreshList ) {
1610 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1611 addressbook_set_clist(
1612 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1613 addrbook.opened),
1614 TRUE);
1616 addrbook_set_dirty(abf, TRUE);
1617 addressbook_export_to_file();
1618 addressbook_list_menu_setup();
1619 goto thaw_ret;
1621 else if( pobj->type == ADDR_ITEM_GROUP ) {
1622 /* Items inside groups */
1623 list = addrselect_get_list( _addressSelect_ );
1624 node = list;
1625 while( node ) {
1626 item = node->data;
1627 node = g_list_next( node );
1628 aio = ( AddrItemObject * ) item->addressItem;
1629 if( aio->type == ITEMTYPE_EMAIL ) {
1630 ItemEMail *item = ( ItemEMail * ) aio;
1631 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1632 item = addrbook_person_remove_email( abf, person, item );
1633 if( item ) {
1634 addritem_free_item_email( item );
1638 g_list_free( list );
1639 addressbook_list_select_clear();
1640 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1641 addressbook_set_clist(
1642 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1643 addrbook.opened),
1644 TRUE);
1646 addrbook_set_dirty(abf, TRUE);
1647 addressbook_export_to_file();
1648 addressbook_list_menu_setup();
1649 goto thaw_ret;
1652 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1653 gtk_cmctree_remove_node( clist, nodeList );
1654 thaw_ret:
1655 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1656 g_signal_handlers_unblock_by_func
1657 (G_OBJECT(addrbook.clist),
1658 G_CALLBACK(addressbook_list_row_unselected), NULL);
1661 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1663 addressbook_new_address_cb( NULL, NULL );
1666 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1667 gchar *buf = NULL;
1668 gchar *name = NULL;
1669 gchar *address = NULL;
1671 if( aio->type == ITEMTYPE_EMAIL ) {
1672 ItemPerson *person = NULL;
1673 ItemEMail *email = ( ItemEMail * ) aio;
1675 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1676 if( email->address ) {
1677 if( ADDRITEM_NAME(email) ) {
1678 name = ADDRITEM_NAME(email);
1679 if( *name == '\0' ) {
1680 name = ADDRITEM_NAME(person);
1683 else if( ADDRITEM_NAME(person) ) {
1684 name = ADDRITEM_NAME(person);
1686 else {
1687 buf = g_strdup( email->address );
1689 address = email->address;
1692 else if( aio->type == ITEMTYPE_PERSON ) {
1693 ItemPerson *person = ( ItemPerson * ) aio;
1694 GList *node = person->listEMail;
1696 name = ADDRITEM_NAME(person);
1697 if( node ) {
1698 ItemEMail *email = ( ItemEMail * ) node->data;
1699 address = email->address;
1702 if( address ) {
1703 if( name && name[0] != '\0' ) {
1704 if( strchr_with_skip_quote( name, '"', ',' ) )
1705 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1706 else
1707 buf = g_strdup_printf( "%s <%s>", name, address );
1709 else {
1710 buf = g_strdup( address );
1714 return buf;
1717 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1719 GList *list, *node;
1720 Compose *compose;
1721 AddrSelectItem *item;
1722 AddrItemObject *aio;
1723 gchar *addr;
1725 compose = addrbook.target_compose;
1726 if( ! compose ) return;
1728 /* Nothing selected, but maybe there is something in text entry */
1729 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1730 if ( addr ) {
1731 compose_entry_append(
1732 compose, addr, (ComposeEntryType)data , PREF_NONE);
1735 /* Select from address list */
1736 list = addrselect_get_list( _addressSelect_ );
1737 node = list;
1738 if (node) {
1739 while( node ) {
1740 item = node->data;
1741 node = g_list_next( node );
1742 aio = item->addressItem;
1743 if( aio->type == ITEMTYPE_PERSON ||
1744 aio->type == ITEMTYPE_EMAIL ) {
1745 addr = addressbook_format_address( aio );
1746 compose_entry_append(
1747 compose, addr, (ComposeEntryType) data, PREF_NONE );
1748 g_free( addr );
1750 else if( aio->type == ITEMTYPE_GROUP ) {
1751 ItemGroup *group = ( ItemGroup * ) aio;
1752 GList *nodeMail = group->listEMail;
1753 while( nodeMail ) {
1754 ItemEMail *email = nodeMail->data;
1756 addr = addressbook_format_address(
1757 ( AddrItemObject * ) email );
1758 compose_entry_append(
1759 compose, addr, (ComposeEntryType) data, PREF_NONE );
1760 g_free( addr );
1761 nodeMail = g_list_next( nodeMail );
1765 } else {
1766 AddressObject *obj = NULL;
1768 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1770 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1771 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1772 GList *nodeMail = itemGroup->listEMail;
1773 while( nodeMail ) {
1774 ItemEMail *email = nodeMail->data;
1776 addr = addressbook_format_address(
1777 ( AddrItemObject * ) email );
1778 compose_entry_append(
1779 compose, addr, (ComposeEntryType) data, PREF_NONE );
1780 g_free( addr );
1781 nodeMail = g_list_next( nodeMail );
1785 g_list_free( list );
1788 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1801 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1802 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1805 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1806 gboolean canEdit = FALSE;
1807 gboolean canDelete = TRUE;
1808 gboolean canAdd = FALSE;
1809 gboolean canEditTr = TRUE;
1810 gboolean editAddress = FALSE;
1811 gboolean canExport = TRUE;
1812 AddressTypeControlItem *atci = NULL;
1813 AddressDataSource *ds = NULL;
1814 AddressInterface *iface = NULL;
1816 if( obj == NULL ) return;
1817 if( obj->type == ADDR_INTERFACE ) {
1818 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1819 iface = adapter->interface;
1820 if( iface ) {
1821 if( iface->haveLibrary ) {
1822 /* Enable appropriate File / New command */
1823 atci = adapter->atci;
1824 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1827 canEditTr = canExport = FALSE;
1829 else if( obj->type == ADDR_DATASOURCE ) {
1830 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1831 ds = ads->dataSource;
1832 iface = ds->interface;
1833 if( ! iface->readOnly ) {
1834 canAdd = canEdit = editAddress = canDelete = TRUE;
1836 if( ! iface->haveLibrary ) {
1837 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1840 else if( obj->type == ADDR_ITEM_FOLDER ) {
1841 ds = addressbook_find_datasource( addrbook.treeSelected );
1842 if( ds ) {
1843 iface = ds->interface;
1844 if( iface->readOnly ) {
1845 canEditTr = FALSE;
1846 canDelete = FALSE;
1848 else {
1849 canAdd = editAddress = TRUE;
1853 else if( obj->type == ADDR_ITEM_GROUP ) {
1854 ds = addressbook_find_datasource( addrbook.treeSelected );
1855 if( ds ) {
1856 iface = ds->interface;
1857 if( ! iface->readOnly ) {
1858 editAddress = TRUE;
1863 if( addrbook.listSelected == NULL )
1864 canEdit = FALSE;
1866 /* Enable add */
1867 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1868 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1870 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1872 /* Enable edit */
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1875 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1876 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1881 /* Export data */
1882 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1887 * Address book tree callback function that responds to selection of tree
1888 * items.
1890 * \param ctree Tree widget.
1891 * \param node Node that was selected.
1892 * \param column Column number where selected occurred.
1893 * \param data Pointer to user data.
1895 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1896 gint column, gpointer data)
1898 AddressObject *obj = NULL;
1899 AdapterDSource *ads = NULL;
1900 AddressDataSource *ds = NULL;
1901 ItemFolder *rootFolder = NULL;
1902 AddressObjectType aot;
1904 addrbook.treeSelected = node;
1905 addrbook.listSelected = NULL;
1906 addressbook_status_show( "" );
1907 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1909 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1910 if( obj == NULL ) {
1911 addressbook_set_clist(NULL, TRUE);
1912 return;
1914 addrbook.opened = node;
1916 if( obj->type == ADDR_DATASOURCE ) {
1917 /* Read from file */
1918 static gboolean tVal = TRUE;
1920 ads = ADAPTER_DSOURCE(obj);
1922 ds = ads->dataSource;
1923 if( ds == NULL ) return;
1925 if( addrindex_ds_get_modify_flag( ds ) ) {
1926 addrindex_ds_read_data( ds );
1929 if( ! addrindex_ds_get_read_flag( ds ) ) {
1930 addrindex_ds_read_data( ds );
1932 addressbook_ds_show_message( ds );
1934 if( ! addrindex_ds_get_access_flag( ds ) ) {
1935 /* Remove existing folders and groups */
1936 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1937 addressbook_tree_remove_children( ctree, node );
1938 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1940 /* Load folders into the tree */
1941 rootFolder = addrindex_ds_get_root_folder( ds );
1942 if( ds && ds->type == ADDR_IF_JPILOT ) {
1943 aot = ADDR_CATEGORY;
1945 else if( ds && ds->type == ADDR_IF_LDAP ) {
1946 aot = ADDR_LDAP_QUERY;
1948 else {
1949 aot = ADDR_ITEM_FOLDER;
1951 addressbook_node_add_folder( node, ds, rootFolder, aot );
1952 addrindex_ds_set_access_flag( ds, &tVal );
1953 gtk_cmctree_expand( ctree, node );
1955 } else {
1956 addressbook_set_clist(NULL, TRUE);
1959 /* Update address list */
1960 g_signal_handlers_block_by_func
1961 (G_OBJECT(ctree),
1962 G_CALLBACK(addressbook_tree_selected), NULL);
1963 addressbook_set_clist( obj, FALSE );
1964 g_signal_handlers_unblock_by_func
1965 (G_OBJECT(ctree),
1966 G_CALLBACK(addressbook_tree_selected), NULL);
1967 if (!prefs_common.addressbook_use_editaddress_dialog)
1968 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1970 /* Setup main menu selections */
1971 addressbook_menubar_set_sensitive( FALSE );
1972 addressbook_menuitem_set_sensitive( obj, node );
1973 addressbook_list_select_clear();
1974 addressbook_list_menu_setup();
1975 return;
1979 * Setup address list popup menu items. Items are enabled or disabled as
1980 * required.
1982 static void addressbook_list_menu_setup( void ) {
1983 GtkCMCTree *clist = NULL;
1984 AddressObject *pobj = NULL;
1985 AddressObject *obj = NULL;
1986 AdapterDSource *ads = NULL;
1987 AddressInterface *iface = NULL;
1988 AddressDataSource *ds = NULL;
1989 gboolean canEdit = FALSE;
1990 gboolean canDelete = FALSE;
1991 gboolean canCut = FALSE;
1992 gboolean canCopy = FALSE;
1993 gboolean canPaste = FALSE;
1994 gboolean canBrowse = FALSE;
1996 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1997 if( pobj == NULL ) return;
1999 clist = GTK_CMCTREE(addrbook.clist);
2000 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2001 if( obj == NULL ) canEdit = FALSE;
2003 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2004 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2006 if( pobj->type == ADDR_DATASOURCE ) {
2007 /* Parent object is a data source */
2008 ads = ADAPTER_DSOURCE(pobj);
2009 ds = ads->dataSource;
2010 if (!ds)
2011 return;
2012 iface = ds->interface;
2013 if (!iface)
2014 return;
2015 if( ! iface->readOnly ) {
2016 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2017 if (iface->type != ADDR_IF_LDAP)
2018 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2019 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2020 if( obj )
2021 canEdit = TRUE;
2022 canDelete = canEdit;
2025 else if( pobj->type != ADDR_INTERFACE ) {
2026 /* Parent object is not an interface */
2027 ds = addressbook_find_datasource( addrbook.treeSelected );
2028 if (!ds)
2029 return;
2030 iface = ds->interface;
2031 if (!iface)
2032 return;
2033 if( ! iface->readOnly ) {
2034 /* Folder or group */
2035 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2036 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2037 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2038 if( obj ) canEdit = TRUE;
2040 /* Folder */
2041 if( pobj->type == ADDR_ITEM_FOLDER ) {
2042 if (iface->type != ADDR_IF_LDAP)
2043 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2044 if( obj ) canEdit = TRUE;
2046 canDelete = canEdit;
2048 if( iface->type == ADDR_IF_LDAP ) {
2049 if( obj ) canBrowse = TRUE;
2050 canEdit = TRUE;
2051 canDelete = TRUE;
2055 if( iface ) {
2056 /* Enable cut and paste */
2057 if( ! addrclip_is_empty( _clipBoard_ ) )
2058 canPaste = TRUE;
2059 if( ! addrselect_test_empty( _addressSelect_ ) )
2060 canCut = TRUE;
2061 /* Enable copy if something is selected */
2062 if( ! addrselect_test_empty( _addressSelect_ ) )
2063 canCopy = TRUE;
2066 /* Disable edit or browse if more than one row selected */
2067 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2068 canEdit = FALSE;
2069 canBrowse = FALSE;
2072 /* Forbid write changes when read-only */
2073 if( iface && iface->readOnly ) {
2074 canCut = FALSE;
2075 canDelete = FALSE;
2076 canPaste = FALSE;
2079 /* Now go finalize menu items */
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2081 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2083 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2084 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2085 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2087 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2091 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2094 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2097 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2098 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2100 if (addrbook.target_compose) {
2101 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2102 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2103 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2105 #ifdef USE_LDAP
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2107 #endif
2110 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2111 GtkCMCTreeNode *node,
2112 gint column,
2113 gpointer data)
2118 * Add list of items into tree node below specified tree node.
2119 * \param treeNode Tree node.
2120 * \param ds Data source.
2121 * \param listItems List of items.
2123 static void addressbook_treenode_add_list(
2124 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2126 GList *node;
2128 node = listItems;
2129 while( node ) {
2130 AddrItemObject *aio;
2131 GtkCMCTreeNode *nn;
2133 aio = node->data;
2134 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2135 ItemGroup *group;
2137 group = ( ItemGroup * ) aio;
2138 nn = addressbook_node_add_group( treeNode, ds, group );
2139 if (nn == NULL) {
2140 g_message("error adding addressbook group\n");
2143 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2144 ItemFolder *folder;
2146 folder = ( ItemFolder * ) aio;
2147 nn = addressbook_node_add_folder(
2148 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2149 if (nn == NULL) {
2150 g_message("error adding addressbook folder\n");
2153 node = g_list_next( node );
2157 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2158 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2162 * Cut from address list widget.
2164 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2165 _clipBoard_->cutFlag = TRUE;
2166 addrclip_clear( _clipBoard_ );
2167 addrclip_add( _clipBoard_, _addressSelect_ );
2168 /* addrclip_list_show( _clipBoard_, stdout ); */
2172 * Copy from address list widget.
2174 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2175 _clipBoard_->cutFlag = FALSE;
2176 addrclip_clear( _clipBoard_ );
2177 addrclip_add( _clipBoard_, _addressSelect_ );
2178 /* addrclip_list_show( _clipBoard_, stdout ); */
2182 * Paste clipboard into address list widget.
2184 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2185 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2186 AddressObject *pobj = NULL;
2187 AddressDataSource *ds = NULL;
2188 AddressBookFile *abf = NULL;
2189 ItemFolder *folder = NULL;
2190 GList *folderGroup = NULL;
2192 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2193 if( ds == NULL ) return;
2194 if( addrindex_ds_get_readonly( ds ) ) {
2195 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2196 return;
2199 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2200 if( pobj ) {
2201 if( pobj->type == ADDR_ITEM_FOLDER ) {
2202 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2204 else if( pobj->type == ADDR_ITEM_GROUP ) {
2205 alertpanel_error( _("Cannot paste into an address group.") );
2206 return;
2210 /* Get an address book */
2211 abf = addressbook_get_book_file();
2212 if( abf == NULL ) return;
2214 if( _clipBoard_->cutFlag ) {
2215 /* Paste/Cut */
2216 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2218 /* Remove all groups and folders in clipboard from tree node */
2219 addressbook_treenode_remove_item();
2221 /* Remove all "cut" items */
2222 addrclip_delete_item( _clipBoard_ );
2224 /* Clear clipboard - cut items??? */
2225 addrclip_clear( _clipBoard_ );
2227 else {
2228 /* Paste/Copy */
2229 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2232 /* addrclip_list_show( _clipBoard_, stdout ); */
2233 if( folderGroup ) {
2234 /* Update tree by inserting node for each folder or group */
2235 addressbook_treenode_add_list(
2236 addrbook.treeSelected, ds, folderGroup );
2237 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2238 g_list_free( folderGroup );
2239 folderGroup = NULL;
2242 /* Display items pasted */
2243 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2244 addressbook_set_clist(
2245 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2246 addrbook.opened),
2247 TRUE);
2253 * Add current treenode object to clipboard. Note that widget only allows
2254 * one entry from the tree list to be selected.
2256 static void addressbook_treenode_to_clipboard( void ) {
2257 AddressObject *obj = NULL;
2258 AddressDataSource *ds = NULL;
2259 AddrSelectItem *item;
2260 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2261 GtkCMCTreeNode *node;
2263 node = addrbook.treeSelected;
2264 if( node == NULL ) return;
2265 obj = gtk_cmctree_node_get_row_data( ctree, node );
2266 if( obj == NULL ) return;
2268 ds = addressbook_find_datasource( node );
2269 if( ds == NULL ) return;
2271 item = NULL;
2272 if( obj->type == ADDR_ITEM_FOLDER ) {
2273 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2274 ItemFolder *folder = adapter->itemFolder;
2276 item = addrselect_create_node( obj );
2277 item->uid = g_strdup( ADDRITEM_ID(folder) );
2279 else if( obj->type == ADDR_ITEM_GROUP ) {
2280 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2281 ItemGroup *group = adapter->itemGroup;
2283 item = addrselect_create_node( obj );
2284 item->uid = g_strdup( ADDRITEM_ID(group) );
2286 else if( obj->type == ADDR_DATASOURCE ) {
2287 /* Data source */
2288 item = addrselect_create_node( obj );
2289 item->uid = NULL;
2292 if( item ) {
2293 /* Clear existing list and add item into list */
2294 gchar *cacheID;
2296 addressbook_list_select_clear();
2297 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2298 addrselect_list_add( _addressSelect_, item, cacheID );
2299 g_free( cacheID );
2304 * Cut from tree widget.
2306 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2307 _clipBoard_->cutFlag = TRUE;
2308 addressbook_treenode_to_clipboard();
2309 addrclip_clear( _clipBoard_ );
2310 addrclip_add( _clipBoard_, _addressSelect_ );
2311 /* addrclip_list_show( _clipBoard_, stdout ); */
2315 * Copy from tree widget.
2317 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2318 _clipBoard_->cutFlag = FALSE;
2319 addressbook_treenode_to_clipboard();
2320 addrclip_clear( _clipBoard_ );
2321 addrclip_add( _clipBoard_, _addressSelect_ );
2322 /* addrclip_list_show( _clipBoard_, stdout ); */
2326 * Paste clipboard into address tree widget.
2328 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2329 addressbook_clip_paste_cb(NULL,NULL);
2333 * Clear selected entries in clipboard.
2335 static void addressbook_list_select_clear( void ) {
2336 addrselect_list_clear( _addressSelect_ );
2340 * Add specified address item to selected address list.
2341 * \param aio Address item object.
2342 * \param ds Datasource.
2344 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2345 gchar *cacheID;
2347 if( ds == NULL ) return;
2348 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2349 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2350 g_free( cacheID );
2354 * Remove specified address item from selected address list.
2355 * \param aio Address item object.
2357 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2358 addrselect_list_remove( _addressSelect_, aio );
2362 * Invoke EMail compose window with addresses in selected address list.
2364 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2365 GList *listAddress;
2367 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2368 listAddress = addrselect_build_list( _addressSelect_ );
2369 compose_new_with_list( NULL, listAddress );
2370 mgu_free_dlist( listAddress );
2371 listAddress = NULL;
2375 static void addressbook_list_row_selected( GtkCMCTree *clist,
2376 GtkCMCTreeNode *node,
2377 gint column,
2378 gpointer data )
2380 AddrItemObject *aio = NULL;
2381 AddressObject *pobj = NULL;
2382 AdapterDSource *ads = NULL;
2383 AddressDataSource *ds = NULL;
2385 addrbook.listSelected = node;
2387 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2388 if( pobj == NULL ) return;
2390 if( pobj->type == ADDR_DATASOURCE ) {
2391 ads = ADAPTER_DSOURCE(pobj);
2392 ds = ads->dataSource;
2394 else if( pobj->type != ADDR_INTERFACE ) {
2395 ds = addressbook_find_datasource( addrbook.treeSelected );
2398 aio = gtk_cmctree_node_get_row_data( clist, node );
2399 if( aio ) {
2400 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2401 addressbook_list_select_add( aio, ds );
2404 addressbook_list_menu_setup();
2406 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2407 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2409 if (obj && obj->type != ADDR_ITEM_GROUP)
2410 addressbook_edit_address(NULL, 0, NULL, FALSE);
2414 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2415 GtkCMCTreeNode *node,
2416 gint column,
2417 gpointer data )
2419 AddrItemObject *aio;
2421 aio = gtk_cmctree_node_get_row_data( ctree, node );
2422 if( aio != NULL ) {
2423 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2424 addressbook_list_select_remove( aio );
2427 if (!prefs_common.addressbook_use_editaddress_dialog)
2428 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2431 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2433 addressbook_lup_clicked(NULL, NULL);
2436 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2437 GdkEventButton *event,
2438 gpointer data)
2440 if( ! event ) return FALSE;
2442 addressbook_list_menu_setup();
2444 if( event->button == 3 ) {
2445 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2446 event->button, event->time );
2447 } else if (event->button == 1) {
2448 if (event->type == GDK_2BUTTON_PRESS) {
2449 if (prefs_common.add_address_by_click &&
2450 addrbook.target_compose)
2451 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2452 else
2453 if (prefs_common.addressbook_use_editaddress_dialog)
2454 addressbook_edit_address_cb(NULL, NULL);
2455 else {
2456 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2457 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2458 if( obj && obj->type == ADDR_ITEM_GROUP )
2459 addressbook_edit_address_cb(NULL, NULL);
2464 return FALSE;
2467 static gboolean addressbook_list_button_released(GtkWidget *widget,
2468 GdkEventButton *event,
2469 gpointer data)
2471 return FALSE;
2474 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2475 GdkEventButton *event,
2476 gpointer data)
2478 GtkCMCList *clist = GTK_CMCLIST(ctree);
2479 gint row, column;
2480 AddressObject *obj = NULL;
2481 AdapterDSource *ads = NULL;
2482 AddressInterface *iface = NULL;
2483 AddressDataSource *ds = NULL;
2484 gboolean canEdit = FALSE;
2485 gboolean canDelete = FALSE;
2486 gboolean canCut = FALSE;
2487 gboolean canCopy = FALSE;
2488 gboolean canPaste = FALSE;
2489 gboolean canTreeCut = FALSE;
2490 gboolean canTreeCopy = FALSE;
2491 gboolean canTreePaste = FALSE;
2492 gboolean canLookup = FALSE;
2493 GtkCMCTreeNode *node = NULL;
2495 if( ! event ) return FALSE;
2496 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2498 if (event->button == 1) {
2499 if (event->type == GDK_2BUTTON_PRESS) {
2500 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2501 gtkut_clist_set_focus_row(clist, row);
2502 obj = gtk_cmclist_get_row_data( clist, row );
2504 if( obj == NULL )
2505 return FALSE;
2507 if (obj->type == ADDR_ITEM_GROUP ||
2508 obj->type == ADDR_DATASOURCE) {
2509 /* edit group */
2510 addressbook_treenode_edit_cb(NULL, NULL);
2511 } else {
2512 /* expand pr collapse */
2513 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2514 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2516 return FALSE;
2520 addressbook_menubar_set_sensitive( FALSE );
2522 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2523 gtkut_clist_set_focus_row(clist, row);
2524 obj = gtk_cmclist_get_row_data( clist, row );
2527 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2529 if( obj == NULL )
2530 return FALSE;
2531 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2533 if( ! addrclip_is_empty( _clipBoard_ ) )
2534 canTreePaste = TRUE;
2536 if (obj->type == ADDR_INTERFACE) {
2537 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2538 iface = adapter->interface;
2539 if( !iface )
2540 goto just_set_sens;
2541 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2542 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2544 if( iface->externalQuery )
2545 canLookup = TRUE;
2547 if (obj->type == ADDR_DATASOURCE) {
2548 canLookup = TRUE;
2549 ads = ADAPTER_DSOURCE(obj);
2550 ds = ads->dataSource;
2551 if( !ds )
2552 goto just_set_sens;
2553 iface = ds->interface;
2554 if( !iface )
2555 goto just_set_sens;
2556 if( !iface->readOnly ) {
2557 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2558 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2559 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2561 canDelete = TRUE;
2562 canEdit = TRUE;
2563 canTreeCopy = TRUE;
2565 else if (obj->type == ADDR_ITEM_FOLDER) {
2566 canLookup = TRUE;
2567 ds = addressbook_find_datasource( node );
2568 if( !ds )
2569 goto just_set_sens;
2570 iface = ds->interface;
2571 if( !iface )
2572 goto just_set_sens;
2573 if( !iface->readOnly ) {
2574 canEdit = TRUE;
2575 canDelete = TRUE;
2576 canTreeCut = TRUE;
2577 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2578 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2579 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2581 canTreeCopy = TRUE;
2583 if( iface->externalQuery ) {
2584 /* Enable deletion of LDAP folder */
2585 canDelete = TRUE;
2588 else if (obj->type == ADDR_ITEM_GROUP) {
2589 canLookup = TRUE;
2590 ds = addressbook_find_datasource( node );
2591 if( !ds )
2592 goto just_set_sens;
2593 iface = ds->interface;
2594 if( !iface )
2595 goto just_set_sens;
2596 if( ! iface->readOnly ) {
2597 canEdit = TRUE;
2598 canDelete = TRUE;
2599 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2600 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2604 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2605 canCut = TRUE;
2606 if( ! addrselect_test_empty( _addressSelect_ ) )
2607 canCopy = TRUE;
2608 if( ! addrclip_is_empty( _clipBoard_ ) )
2609 canPaste = TRUE;
2611 /* Forbid write changes when read-only */
2612 if( iface && iface->readOnly ) {
2613 canTreeCut = FALSE;
2614 canTreePaste = FALSE;
2615 canCut = FALSE;
2616 canPaste = FALSE;
2619 just_set_sens:
2620 /* Enable edit */
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2627 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2633 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2634 addrbook.target_compose != NULL);
2636 if( event->button == 3 )
2637 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2638 event->button, event->time);
2640 return FALSE;
2643 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2644 GdkEventButton *event,
2645 gpointer data)
2647 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2648 return FALSE;
2651 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2653 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2654 AddressObject *obj = NULL;
2655 AddressDataSource *ds = NULL;
2656 AddressBookFile *abf = NULL;
2657 ItemFolder *parentFolder = NULL;
2658 ItemFolder *folder = NULL;
2660 if( ! addrbook.treeSelected ) return;
2661 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2662 if( obj == NULL ) return;
2663 ds = addressbook_find_datasource( addrbook.treeSelected );
2664 if( ds == NULL ) return;
2666 if( obj->type == ADDR_DATASOURCE ) {
2667 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2669 else if( obj->type == ADDR_ITEM_FOLDER ) {
2670 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2672 else {
2673 return;
2676 abf = ds->rawDataSource;
2677 if( abf == NULL ) return;
2678 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2679 if( folder ) {
2680 GtkCMCTreeNode *nn;
2681 nn = addressbook_node_add_folder(
2682 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2683 if (nn == NULL) {
2684 g_message("error adding addressbook folder\n");
2686 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2687 if( addrbook.treeSelected == addrbook.opened )
2688 addressbook_set_clist(obj, TRUE);
2692 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2694 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2695 AddressObject *obj = NULL;
2696 AddressDataSource *ds = NULL;
2697 AddressBookFile *abf = NULL;
2698 ItemFolder *parentFolder = NULL;
2699 ItemGroup *group = NULL;
2701 if( ! addrbook.treeSelected ) return;
2702 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2703 if( obj == NULL ) return;
2704 ds = addressbook_find_datasource( addrbook.treeSelected );
2705 if( ds == NULL ) return;
2707 if( obj->type == ADDR_DATASOURCE ) {
2708 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2710 else if( obj->type == ADDR_ITEM_FOLDER ) {
2711 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2713 else {
2714 return;
2717 abf = ds->rawDataSource;
2718 if( abf == NULL ) return;
2719 group = addressbook_edit_group( abf, parentFolder, NULL );
2720 if( group ) {
2721 GtkCMCTreeNode *nn;
2722 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2723 if (nn == NULL) {
2724 g_message("error adding addressbook group\n");
2726 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2727 if( addrbook.treeSelected == addrbook.opened )
2728 addressbook_set_clist(obj, TRUE);
2732 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2734 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2735 gchar *text[1];
2736 guint8 spacing;
2737 GdkPixbuf *pix_cl, *pix_op;
2738 gboolean is_leaf, expanded;
2740 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2741 &pix_cl, &pix_op,
2742 &is_leaf, &expanded);
2743 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2744 pix_cl, pix_op,
2745 is_leaf, expanded);
2749 * Edit data source.
2750 * \param obj Address object to edit.
2751 * \param node Node in tree.
2752 * \return New name of data source.
2754 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2755 gchar *newName = NULL;
2756 AddressDataSource *ds = NULL;
2757 AddressInterface *iface = NULL;
2758 AdapterDSource *ads = NULL;
2760 ds = addressbook_find_datasource( node );
2761 if( ds == NULL ) return NULL;
2762 iface = ds->interface;
2763 if( ! iface->haveLibrary ) return NULL;
2765 /* Read data from data source */
2766 if( addrindex_ds_get_modify_flag( ds ) ) {
2767 addrindex_ds_read_data( ds );
2770 if( ! addrindex_ds_get_read_flag( ds ) ) {
2771 addrindex_ds_read_data( ds );
2774 /* Handle edit */
2775 ads = ADAPTER_DSOURCE(obj);
2776 if( ads->subType == ADDR_BOOK ) {
2777 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2779 else if( ads->subType == ADDR_VCARD ) {
2780 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2782 #ifdef USE_JPILOT
2783 else if( ads->subType == ADDR_JPILOT ) {
2784 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2786 #endif
2787 #ifdef USE_LDAP
2788 else if( ads->subType == ADDR_LDAP ) {
2789 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2791 #endif
2792 else {
2793 return NULL;
2795 newName = obj->name;
2796 return newName;
2800 * Edit an object that is in the address tree area.
2802 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2804 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2805 AddressObject *obj;
2806 AddressDataSource *ds = NULL;
2807 AddressBookFile *abf = NULL;
2808 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2809 gchar *name = NULL;
2811 if( ! addrbook.treeSelected ) return;
2812 node = addrbook.treeSelected;
2813 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2814 obj = gtk_cmctree_node_get_row_data( ctree, node );
2815 if( obj == NULL ) return;
2816 parentNode = GTK_CMCTREE_ROW(node)->parent;
2818 ds = addressbook_find_datasource( node );
2819 if( ds == NULL ) return;
2821 if( obj->type == ADDR_DATASOURCE ) {
2822 name = addressbook_edit_datasource( obj, node );
2823 if( name == NULL ) return;
2825 else {
2826 abf = ds->rawDataSource;
2827 if( abf == NULL ) return;
2828 if( obj->type == ADDR_ITEM_FOLDER ) {
2829 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2830 ItemFolder *item = adapter->itemFolder;
2831 ItemFolder *parentFolder = NULL;
2832 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2833 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2834 name = ADDRITEM_NAME(item);
2836 else if( obj->type == ADDR_ITEM_GROUP ) {
2837 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2838 ItemGroup *item = adapter->itemGroup;
2839 ItemFolder *parentFolder = NULL;
2840 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2841 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2842 name = ADDRITEM_NAME(item);
2845 if( name && parentNode ) {
2846 /* Update node in tree view */
2847 addressbook_change_node_name( node, name );
2848 gtk_sctree_sort_node(ctree, parentNode);
2849 gtk_cmctree_expand( ctree, node );
2850 gtk_sctree_select( GTK_SCTREE( ctree), node );
2854 typedef enum {
2855 ADDRTREE_DEL_NONE,
2856 ADDRTREE_DEL_DATA,
2857 ADDRTREE_DEL_FOLDER_ONLY,
2858 ADDRTREE_DEL_FOLDER_ADDR
2859 } TreeItemDelType ;
2862 * Delete an item from the tree widget.
2863 * \param data Data passed in.
2864 * \param action Action.
2865 * \param widget Widget issuing callback.
2867 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2869 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2870 GtkCMCTreeNode *node = NULL;
2871 AddressObject *obj;
2872 gchar *message;
2873 AlertValue aval;
2874 AddrBookBase *adbase;
2875 AddressCache *cache;
2876 AdapterDSource *ads = NULL;
2877 AddressInterface *iface = NULL;
2878 AddressDataSource *ds = NULL;
2879 gboolean remFlag = FALSE;
2880 TreeItemDelType delType;
2882 if( ! addrbook.treeSelected ) return;
2883 node = addrbook.treeSelected;
2884 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2886 obj = gtk_cmctree_node_get_row_data( ctree, node );
2887 cm_return_if_fail(obj != NULL);
2889 if( obj->type == ADDR_DATASOURCE ) {
2890 ads = ADAPTER_DSOURCE(obj);
2892 ds = ads->dataSource;
2893 if( ds == NULL ) return;
2895 else {
2896 /* Must be folder or something else */
2897 ds = addressbook_find_datasource( node );
2898 if( ds == NULL ) return;
2900 /* Only allow deletion from non-readOnly */
2901 iface = ds->interface;
2902 if( iface->readOnly ) {
2903 /* Allow deletion of query results */
2904 if( ! iface->externalQuery ) return;
2908 /* Confirm deletion */
2909 delType = ADDRTREE_DEL_NONE;
2910 if( obj->type == ADDR_ITEM_FOLDER ) {
2911 if( iface && iface->externalQuery ) {
2912 message = g_strdup_printf( _(
2913 "Do you want to delete the query " \
2914 "results and addresses in '%s'?" ),
2915 obj->name );
2916 aval = alertpanel( _("Delete"), message,
2917 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2918 g_free(message);
2919 if( aval == G_ALERTALTERNATE ) {
2920 delType = ADDRTREE_DEL_FOLDER_ADDR;
2923 else {
2924 message = g_strdup_printf
2925 ( _( "Do you want to delete '%s'? "
2926 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2927 obj->name );
2928 aval = alertpanel( _("Delete folder"), message,
2929 GTK_STOCK_CANCEL, g_strconcat("+",_("Delete _folder only"), NULL), _("Delete folder and _addresses"));
2930 g_free(message);
2931 if( aval == G_ALERTALTERNATE ) {
2932 delType = ADDRTREE_DEL_FOLDER_ONLY;
2934 else if( aval == G_ALERTOTHER ) {
2935 delType = ADDRTREE_DEL_FOLDER_ADDR;
2939 else if( obj->type == ADDR_ITEM_GROUP ) {
2940 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2941 "The addresses it contains will not 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_FOLDER_ONLY;
2946 } else {
2947 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2948 "The addresses it contains will be lost."), obj->name);
2949 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2950 "+" GTK_STOCK_DELETE, NULL);
2951 g_free(message);
2952 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2954 if( delType == ADDRTREE_DEL_NONE ) return;
2956 /* Proceed with deletion */
2957 if( obj->type == ADDR_DATASOURCE ) {
2958 /* Remove node from tree */
2959 gtk_cmctree_remove_node( ctree, node );
2961 if (delType == ADDRTREE_DEL_DATA &&
2962 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2963 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2965 /* Remove data source. */
2966 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2967 addrindex_free_datasource( ds );
2969 return;
2972 /* Get reference to cache */
2973 adbase = ( AddrBookBase * ) ds->rawDataSource;
2974 if( adbase == NULL ) return;
2975 cache = adbase->addressCache;
2977 /* Remove query results folder */
2978 if( iface && iface->externalQuery ) {
2979 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2980 ItemFolder *folder = adapter->itemFolder;
2982 adapter->itemFolder = NULL;
2984 g_print( "remove folder for ::%s::\n", obj->name );
2985 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2986 g_print( "-------------- remove results\n" );
2988 addrindex_remove_results( ds, folder );
2989 /* g_print( "-------------- remove node\n" ); */
2990 gtk_cmctree_remove_node( ctree, node );
2991 return;
2994 /* Code below is valid for regular address book deletion */
2995 if( obj->type == ADDR_ITEM_FOLDER ) {
2996 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2997 ItemFolder *item = adapter->itemFolder;
2999 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3000 /* Remove folder only */
3001 item = addrcache_remove_folder( cache, item );
3002 if( item ) {
3003 addritem_free_item_folder( item );
3004 addressbook_move_nodes_up( ctree, node );
3005 remFlag = TRUE;
3008 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3009 /* Remove folder and addresses */
3010 item = addrcache_remove_folder_delete( cache, item );
3011 if( item ) {
3012 addritem_free_item_folder( item );
3013 remFlag = TRUE;
3017 else if( obj->type == ADDR_ITEM_GROUP ) {
3018 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3019 ItemGroup *item = adapter->itemGroup;
3021 item = addrcache_remove_group( cache, item );
3022 if( item ) {
3023 addritem_free_item_group( item );
3024 remFlag = TRUE;
3028 if( remFlag ) {
3029 /* Remove node. */
3030 gtk_cmctree_remove_node(ctree, node );
3034 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3036 if( person && addrbook.treeSelected == addrbook.opened ) {
3037 person->status = ADD_ENTRY;
3038 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3039 addressbook_folder_refresh_one_person(
3040 GTK_CMCTREE(addrbook.clist), person );
3042 addressbook_address_list_set_focus();
3045 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3047 if( person && addrbook.treeSelected == addrbook.opened) {
3048 person->status = ADD_ENTRY;
3049 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3050 addressbook_set_clist(
3051 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3052 addrbook.opened),
3053 TRUE);
3055 addressbook_address_list_set_focus();
3059 * Label (a format string) that is used to name each folder.
3061 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3064 * Search ctree widget callback function.
3065 * \param pA Pointer to node.
3066 * \param pB Pointer to data item being sought.
3067 * \return Zero (0) if folder found.
3069 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3070 AddressObject *aoA;
3072 aoA = ( AddressObject * ) pA;
3073 if( aoA->type == ADDR_ITEM_FOLDER ) {
3074 ItemFolder *folder, *fld;
3076 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3077 folder = ( ItemFolder * ) pB;
3078 if( fld == folder ) return 0; /* Found folder */
3080 return 1;
3083 static ItemFolder * addressbook_setup_subf(
3084 AddressDataSource *ds, gchar *title,
3085 GtkCMCTreeNode *pNode )
3087 AddrBookBase *adbase;
3088 AddressCache *cache;
3089 ItemFolder *folder;
3090 GtkCMCTree *ctree;
3091 GtkCMCTreeNode *nNode;
3092 gchar *name;
3093 AddressObjectType aoType = ADDR_NONE;
3094 GList *children;
3095 /* Setup a query */
3096 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3098 if( ds && ds->type == ADDR_IF_LDAP ) {
3099 #if USE_LDAP
3100 aoType = ADDR_LDAP_QUERY;
3101 #endif
3103 else {
3104 return NULL;
3107 ctree = GTK_CMCTREE(addrbook.ctree);
3108 /* Get reference to address cache */
3109 adbase = ( AddrBookBase * ) ds->rawDataSource;
3110 cache = adbase->addressCache;
3112 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3113 GList *cur = children;
3114 for (; cur; cur = cur->next) {
3115 ItemFolder *child = (ItemFolder *) cur->data;
3116 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3117 nNode = gtk_cmctree_find_by_row_data_custom(
3118 ctree, NULL, child,
3119 addressbook_treenode_find_folder_cb );
3120 if( nNode ) {
3121 addrindex_remove_results( ds, child );
3122 while( child->listPerson ) {
3123 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3124 item = addrcache_remove_person( cache, item );
3125 if( item ) {
3126 addritem_free_item_person( item );
3127 item = NULL;
3130 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3131 addrbook.treeSelected = nNode;
3133 return child;
3138 /* Create a folder */
3139 folder = addrcache_add_new_folder( cache, NULL );
3140 name = g_strdup_printf( "%s", title );
3141 addritem_folder_set_name( folder, name );
3142 addritem_folder_set_remarks( folder, "" );
3143 g_free( name );
3145 /* Now let's see the folder */
3146 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3147 gtk_cmctree_expand( ctree, pNode );
3148 if( nNode ) {
3149 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3150 addrbook.treeSelected = nNode;
3151 return folder;
3153 return NULL;
3156 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3157 AddressObject *pobj = NULL;
3158 AddressDataSource *ds = NULL;
3159 AddressBookFile *abf = NULL;
3160 debug_print("adding address\n");
3161 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3162 if( pobj == NULL ) {
3163 debug_print("no row data\n");
3164 return;
3166 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3167 if( ds == NULL ) {
3168 debug_print("no datasource\n");
3169 return;
3172 abf = ds->rawDataSource;
3173 if( abf == NULL ) {
3174 g_print("no addressbook file\n");
3175 return;
3178 if( pobj->type == ADDR_DATASOURCE ) {
3179 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3180 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3181 ItemPerson *person;
3182 ItemFolder *folder = NULL;
3183 #ifdef USE_LDAP
3184 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3185 GtkCMCTreeNode *parentNode;
3186 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3187 if( ds == NULL ) return;
3189 /* We must have a datasource that is an external interface */
3190 if( ! ds->interface->haveLibrary ) return;
3191 if( ! ds->interface->externalQuery ) return;
3193 if( pobj->type == ADDR_ITEM_FOLDER ) {
3194 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3196 else {
3197 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3199 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3201 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3202 if (ds)
3203 abf = ds->rawDataSource;
3205 #endif
3206 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3207 addrbook.editaddress_vbox,
3208 addressbook_new_address_from_book_post_cb,
3209 TRUE );
3210 #ifdef USE_LDAP
3211 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3212 LdapServer *server = ds->rawDataSource;
3213 ldapsvr_set_modified(server, TRUE);
3214 ldapsvr_update_book(server, NULL);
3215 if (server->retVal != LDAPRC_SUCCESS) {
3216 alertpanel( _("Add address(es)"),
3217 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3218 GTK_STOCK_CLOSE, NULL, NULL );
3219 server->retVal = LDAPRC_SUCCESS;
3220 return;
3223 #endif
3224 if (prefs_common.addressbook_use_editaddress_dialog)
3225 addressbook_new_address_from_book_post_cb( person );
3228 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3229 /* New address */
3230 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3231 ItemPerson *person;
3232 #ifdef USE_LDAP
3233 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3234 GtkCMCTreeNode *parentNode;
3235 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3236 if( ds == NULL ) return;
3238 /* We must have a datasource that is an external interface */
3239 if( ! ds->interface->haveLibrary ) return;
3240 if( ! ds->interface->externalQuery ) return;
3242 if( pobj->type == ADDR_ITEM_FOLDER ) {
3243 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3245 else {
3246 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3248 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3249 if (!folder)
3250 return;
3252 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3253 if (ds)
3254 abf = ds->rawDataSource;
3256 #endif
3257 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3258 addrbook.editaddress_vbox,
3259 addressbook_new_address_from_folder_post_cb,
3260 TRUE );
3261 #ifdef USE_LDAP
3262 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3263 LdapServer *server = ds->rawDataSource;
3264 ldapsvr_set_modified(server, TRUE);
3265 ldapsvr_update_book(server, NULL);
3266 if (server->retVal != LDAPRC_SUCCESS) {
3267 alertpanel( _("Add address(es)"),
3268 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3269 GTK_STOCK_CLOSE, NULL, NULL );
3270 return;
3273 #endif
3274 if (prefs_common.addressbook_use_editaddress_dialog)
3275 addressbook_new_address_from_folder_post_cb( person );
3277 else if( pobj->type == ADDR_ITEM_GROUP ) {
3278 /* New address in group */
3279 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3280 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3281 if (addrbook.treeSelected == addrbook.opened) {
3282 /* Change node name in tree. */
3283 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3284 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3285 addressbook_set_clist(
3286 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3287 addrbook.opened),
3288 TRUE);
3294 * Search for specified child group node in address index tree.
3295 * \param parent Parent node.
3296 * \param group Group to find.
3298 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3299 GtkCMCTreeNode *node = NULL;
3300 GtkCMCTreeRow *currRow;
3302 currRow = GTK_CMCTREE_ROW( parent );
3303 if( currRow ) {
3304 node = currRow->children;
3305 while( node ) {
3306 AddressObject *obj;
3308 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3309 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3310 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3311 if( g == group ) return node;
3313 currRow = GTK_CMCTREE_ROW(node);
3314 node = currRow->sibling;
3317 return NULL;
3320 static AddressBookFile *addressbook_get_book_file() {
3321 AddressBookFile *abf = NULL;
3322 AddressDataSource *ds = NULL;
3324 ds = addressbook_find_datasource( addrbook.treeSelected );
3325 if( ds == NULL ) return NULL;
3326 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3327 return abf;
3330 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3331 GtkCMCTreeNode *node;
3332 GtkCMCTreeRow *row;
3334 /* Remove existing folders and groups */
3335 row = GTK_CMCTREE_ROW( parent );
3336 if( row ) {
3337 while( (node = row->children) ) {
3338 gtk_cmctree_remove_node( ctree, node );
3343 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3344 GtkCMCTreeNode *parent, *child;
3345 GtkCMCTreeRow *currRow;
3346 currRow = GTK_CMCTREE_ROW( node );
3347 if( currRow ) {
3348 parent = currRow->parent;
3349 while( (child = currRow->children) ) {
3350 gtk_cmctree_move( ctree, child, parent, node );
3352 gtk_sctree_sort_node( ctree, parent );
3356 static void addressbook_edit_address_post_cb( ItemPerson *person )
3358 if( person ) {
3359 #ifdef USE_LDAP
3360 AddressBookFile *abf = addressbook_get_book_file();
3362 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3363 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3364 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3366 #endif
3367 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3368 invalidate_address_completion();
3370 addressbook_address_list_set_focus();
3373 void addressbook_address_list_set_focus( void )
3375 if (!prefs_common.addressbook_use_editaddress_dialog) {
3376 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3377 addressbook_list_menu_setup();
3381 void addressbook_address_list_disable_some_actions(void)
3383 /* disable address copy/pasting when editing contact's detail (embedded form) */
3384 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3385 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3386 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3389 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3390 addressbook_edit_address(data, 0, NULL, TRUE);
3393 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3394 gboolean force_focus ) {
3395 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3396 GtkCMCTree *ctree;
3397 AddressObject *obj = NULL, *pobj = NULL;
3398 AddressDataSource *ds = NULL;
3399 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3400 gchar *name = NULL;
3401 AddressBookFile *abf = NULL;
3403 if( addrbook.listSelected == NULL ) return;
3404 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3405 cm_return_if_fail(obj != NULL);
3407 ctree = GTK_CMCTREE( addrbook.ctree );
3408 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3410 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3411 if( ds == NULL ) return;
3413 abf = addressbook_get_book_file();
3415 if( obj->type == ADDR_ITEM_EMAIL ) {
3416 ItemEMail *email = ( ItemEMail * ) obj;
3418 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3419 /* Edit parent group */
3420 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3421 ItemGroup *itemGrp = adapter->itemGroup;
3422 if( abf == NULL ) return;
3423 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3424 name = ADDRITEM_NAME(itemGrp);
3425 node = addrbook.treeSelected;
3426 parentNode = GTK_CMCTREE_ROW(node)->parent;
3428 else {
3429 /* Edit person - email page */
3430 ItemPerson *person;
3431 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3432 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3433 addressbook_edit_address_post_cb,
3434 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3435 != NULL ) {
3436 #ifdef USE_LDAP
3437 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3438 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3439 person->status = UPDATE_ENTRY;
3441 #endif
3442 if (prefs_common.addressbook_use_editaddress_dialog)
3443 addressbook_edit_address_post_cb( person );
3445 return;
3448 else if( obj->type == ADDR_ITEM_PERSON ) {
3449 /* Edit person - basic page */
3450 ItemPerson *person = ( ItemPerson * ) obj;
3451 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3452 addressbook_edit_address_post_cb,
3453 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3454 != NULL ) {
3455 #ifdef USE_LDAP
3456 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3457 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3458 person->status = UPDATE_ENTRY;
3460 #endif
3461 if (prefs_common.addressbook_use_editaddress_dialog)
3462 addressbook_edit_address_post_cb( person );
3464 return;
3466 else if( obj->type == ADDR_ITEM_GROUP ) {
3467 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3468 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3469 parentNode = addrbook.treeSelected;
3470 node = addressbook_find_group_node( parentNode, itemGrp );
3471 name = ADDRITEM_NAME(itemGrp);
3472 invalidate_address_completion();
3474 else {
3475 return;
3478 /* Update tree node with node name */
3479 if( node == NULL ) return;
3480 addressbook_change_node_name( node, name );
3481 gtk_sctree_sort_node( ctree, parentNode );
3482 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3483 addressbook_set_clist(
3484 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3485 addrbook.opened),
3486 TRUE);
3489 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3491 addressbook_del_clicked(NULL, NULL);
3494 static void close_cb(GtkAction *action, gpointer data)
3496 addressbook_close();
3499 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3500 addressbook_export_to_file();
3503 static void addressbook_person_expand_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, TRUE );
3510 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3511 if( node ) {
3512 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3513 if( person ) addritem_person_set_opened( person, FALSE );
3517 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3518 gchar *str = NULL;
3519 gchar *eMailAlias = ADDRITEM_NAME(email);
3520 if( eMailAlias && *eMailAlias != '\0' ) {
3521 if( person ) {
3522 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3524 else {
3525 str = g_strdup( eMailAlias );
3528 return str;
3531 static gboolean addressbook_match_item(const gchar *name,
3532 const gchar *email_alias,
3533 const gchar *addr,
3534 const gchar *remarks,
3535 const gchar *str)
3537 if (!name)
3538 return FALSE;
3539 if (!str || str[0] == '\0')
3540 return TRUE;
3541 if (strcasestr(name, str))
3542 return TRUE;
3543 else if (email_alias && strcasestr(email_alias, str))
3544 return TRUE;
3545 else if (addr && strcasestr(addr, str))
3546 return TRUE;
3547 else if (remarks && strcasestr(remarks, str))
3548 return TRUE;
3550 return FALSE;
3553 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3554 GList *items = itemGroup->listEMail;
3555 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3556 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3557 for( ; items != NULL; items = g_list_next( items ) ) {
3558 GtkCMCTreeNode *nodeEMail = NULL;
3559 gchar *text[N_LIST_COLS];
3560 ItemEMail *email = items->data;
3561 ItemPerson *person;
3562 gchar *str = NULL;
3564 if( ! email ) continue;
3566 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3568 if( !addressbook_match_item(ADDRITEM_NAME(person),
3569 ADDRITEM_NAME(email),
3570 email->address, email->remarks,
3571 search_str))
3572 continue;
3574 str = addressbook_format_item_clist( person, email );
3575 if( str ) {
3576 text[COL_NAME] = addressbook_set_col_name_guard(str);
3578 else {
3579 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3581 text[COL_ADDRESS] = email->address;
3582 text[COL_REMARKS] = email->remarks;
3583 nodeEMail = gtk_sctree_insert_node(
3584 clist, NULL, NULL,
3585 text, FOLDER_SPACING,
3586 atci->iconXpm,
3587 atci->iconXpmOpen,
3588 FALSE, FALSE );
3589 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3590 g_free( str );
3591 str = NULL;
3595 gchar *addressbook_set_col_name_guard(gchar *value)
3597 gchar *ret = "<not set>";
3598 gchar *tmp = g_strdup(value);
3599 g_strstrip(tmp);
3600 if (tmp !=NULL && *tmp != '\0')
3601 ret = value;
3602 g_free(tmp);
3603 return ret;
3606 static void addressbook_folder_load_one_person(
3607 GtkCMCTree *clist, ItemPerson *person,
3608 AddressTypeControlItem *atci,
3609 AddressTypeControlItem *atciMail )
3611 GtkCMCTreeNode *nodePerson = NULL;
3612 GtkCMCTreeNode *nodeEMail = NULL;
3613 gchar *text[N_LIST_COLS];
3614 gboolean flgFirst = TRUE, haveAddr = FALSE;
3615 GList *node;
3616 #ifdef USE_LDAP
3617 AddressBookFile *abf = addressbook_get_book_file();
3618 #endif
3620 if( person == NULL ) return;
3622 text[COL_NAME] = "";
3623 node = person->listEMail;
3624 while( node ) {
3625 ItemEMail *email = node->data;
3626 gchar *eMailAddr = NULL;
3627 node = g_list_next( node );
3629 text[COL_ADDRESS] = email->address;
3630 text[COL_REMARKS] = email->remarks;
3631 eMailAddr = ADDRITEM_NAME(email);
3632 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3633 if( flgFirst ) {
3634 /* First email belongs with person */
3635 gchar *str = addressbook_format_item_clist( person, email );
3636 if( str ) {
3637 text[COL_NAME] = addressbook_set_col_name_guard(str);
3639 #ifdef USE_LDAP
3640 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3641 person && person->nickName ) {
3642 if (person->nickName) {
3643 if (strcmp(person->nickName, "") != 0) {
3644 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3646 else {
3647 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3651 #endif
3652 else {
3653 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3655 nodePerson = gtk_sctree_insert_node(
3656 clist, NULL, NULL,
3657 text, FOLDER_SPACING,
3658 atci->iconXpm,
3659 atci->iconXpmOpen,
3660 FALSE, person->isOpened );
3661 g_free( str );
3662 str = NULL;
3663 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3665 else {
3666 /* Subsequent email is a child node of person */
3667 text[COL_NAME] = ADDRITEM_NAME(email);
3668 nodeEMail = gtk_sctree_insert_node(
3669 clist, nodePerson, NULL,
3670 text, FOLDER_SPACING,
3671 atciMail->iconXpm,
3672 atciMail->iconXpmOpen,
3673 FALSE, TRUE );
3674 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3676 flgFirst = FALSE;
3677 haveAddr = TRUE;
3679 if( ! haveAddr ) {
3680 /* Have name without EMail */
3681 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3682 text[COL_ADDRESS] = "";
3683 text[COL_REMARKS] = "";
3684 nodePerson = gtk_sctree_insert_node(
3685 clist, NULL, NULL,
3686 text, FOLDER_SPACING,
3687 atci->iconXpm,
3688 atci->iconXpmOpen,
3689 FALSE, person->isOpened );
3690 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3692 return;
3695 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3696 GList *items;
3697 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3698 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3699 const gchar *search_str;
3701 if( atci == NULL ) return;
3702 if( atciMail == NULL ) return;
3704 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3706 /* Load email addresses */
3707 items = addritem_folder_get_person_list( itemFolder );
3708 for( ; items != NULL; items = g_list_next( items ) ) {
3709 ItemPerson *person;
3710 GList *node;
3711 ItemEMail *email;
3713 person = (ItemPerson *)items->data;
3714 if (!person)
3715 continue;
3716 node = person->listEMail;
3717 if (node && node->data) {
3718 email = node->data;
3719 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3720 continue;
3721 } else {
3722 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3723 continue;
3726 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3728 /* Free up the list */
3729 mgu_clear_list( items );
3730 g_list_free( items );
3733 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3734 addrbook.listSelected = NULL;
3735 gtk_cmctree_remove_node( clist, node );
3736 addressbook_menubar_set_sensitive( FALSE );
3737 addressbook_menuitem_set_sensitive(
3738 gtk_cmctree_node_get_row_data(
3739 GTK_CMCTREE(clist), addrbook.treeSelected ),
3740 addrbook.treeSelected );
3743 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3744 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3745 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3746 GtkCMCTreeNode *node;
3747 if( atci == NULL ) return;
3748 if( atciMail == NULL ) return;
3749 if( person == NULL ) return;
3750 /* unload the person */
3752 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3753 if( node )
3754 addressbook_folder_remove_node( clist, node );
3755 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3756 gtk_sctree_sort_node( clist, NULL );
3757 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3758 if( node ) {
3759 gtk_sctree_select( GTK_SCTREE(clist), node );
3760 if (!gtk_cmctree_node_is_visible( clist, node ) )
3761 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3765 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3766 GtkCMCTreeNode *node;
3768 if( person == NULL ) return;
3769 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3770 if( node ) {
3771 addressbook_folder_remove_node( clist, node );
3775 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3776 GList *items;
3777 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3778 const gchar *search_str;
3780 /* Load any groups */
3781 if( ! atci ) return;
3783 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3785 items = addritem_folder_get_group_list( itemFolder );
3786 for( ; items != NULL; items = g_list_next( items ) ) {
3787 GtkCMCTreeNode *nodeGroup = NULL;
3788 gchar *text[N_LIST_COLS];
3789 ItemGroup *group = items->data;
3790 if( group == NULL ) continue;
3791 if( !addressbook_match_item(ADDRITEM_NAME(group),
3792 NULL, NULL, NULL, search_str) )
3793 continue;
3795 text[COL_NAME] = ADDRITEM_NAME(group);
3796 text[COL_ADDRESS] = "";
3797 text[COL_REMARKS] = "";
3798 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3799 text, FOLDER_SPACING,
3800 atci->iconXpm,
3801 atci->iconXpmOpen,
3802 FALSE, FALSE);
3803 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3804 gtk_sctree_sort_node(clist, NULL);
3806 /* Free up the list */
3807 mgu_clear_list( items );
3808 g_list_free( items );
3812 * Search ctree widget callback function.
3813 * \param pA Pointer to node.
3814 * \param pB Pointer to data item being sought.
3815 * \return Zero (0) if group found.
3817 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3818 AddressObject *aoA;
3820 aoA = ( AddressObject * ) pA;
3821 if( aoA->type == ADDR_ITEM_GROUP ) {
3822 ItemGroup *group, *grp;
3824 grp = ADAPTER_GROUP(aoA)->itemGroup;
3825 group = ( ItemGroup * ) pB;
3826 if( grp == group ) return 0; /* Found group */
3828 return 1;
3832 * Remove folder and group nodes from tree widget for items contained ("cut")
3833 * in clipboard.
3835 static void addressbook_treenode_remove_item( void ) {
3836 GList *node;
3837 AddrSelectItem *cutItem;
3838 AddressCache *cache;
3839 AddrItemObject *aio;
3840 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3841 GtkCMCTreeNode *tn;
3843 node = _clipBoard_->objectList;
3844 while( node ) {
3845 cutItem = node->data;
3846 node = g_list_next( node );
3847 cache = addrindex_get_cache(
3848 _clipBoard_->addressIndex, cutItem->cacheID );
3849 if( cache == NULL ) continue;
3850 aio = addrcache_get_object( cache, cutItem->uid );
3851 if( aio ) {
3852 tn = NULL;
3853 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3854 ItemFolder *folder;
3856 folder = ( ItemFolder * ) aio;
3857 tn = gtk_cmctree_find_by_row_data_custom(
3858 ctree, NULL, folder,
3859 addressbook_treenode_find_folder_cb );
3861 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3862 ItemGroup *group;
3864 group = ( ItemGroup * ) aio;
3865 tn = gtk_cmctree_find_by_row_data_custom(
3866 ctree, NULL, group,
3867 addressbook_treenode_find_group_cb );
3870 if( tn ) {
3871 /* Free up adapter and remove node. */
3872 gtk_cmctree_remove_node( ctree, tn );
3879 * Find parent datasource for specified tree node.
3880 * \param node Node to test.
3881 * \return Data source, or NULL if not found.
3883 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3884 AddressDataSource *ds = NULL;
3885 AddressObject *ao;
3887 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3889 while( node ) {
3890 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3891 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3892 if( ao ) {
3893 /* g_print( "ao->type = %d\n", ao->type ); */
3894 if( ao->type == ADDR_DATASOURCE ) {
3895 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3896 /* g_print( "found it\n" ); */
3897 ds = ads->dataSource;
3898 break;
3901 node = GTK_CMCTREE_ROW(node)->parent;
3903 return ds;
3907 * Load address list widget with children of specified object.
3908 * \param obj Parent object to be loaded.
3910 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3911 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3912 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3913 AddressDataSource *ds = NULL;
3914 AdapterDSource *ads = NULL;
3915 static AddressObject *last_obj = NULL;
3917 if (addrbook.clist == NULL) {
3918 return;
3920 if (obj == last_obj && !refresh)
3921 return;
3923 last_obj = obj;
3924 if( obj == NULL ) {
3925 gtk_cmclist_clear(clist);
3926 return;
3929 if( obj->type == ADDR_INTERFACE ) {
3930 /* g_print( "set_clist: loading datasource...\n" ); */
3931 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3932 return;
3935 gtk_cmclist_freeze(clist);
3936 gtk_cmclist_clear(clist);
3938 if( obj->type == ADDR_DATASOURCE ) {
3939 ads = ADAPTER_DSOURCE(obj);
3940 ds = ads->dataSource;
3941 if( ds ) {
3942 /* Load root folder */
3943 ItemFolder *rootFolder = NULL;
3944 rootFolder = addrindex_ds_get_root_folder( ds );
3945 addressbook_folder_load_person(
3946 ctreelist, rootFolder );
3947 addressbook_folder_load_group(
3948 ctreelist, rootFolder );
3951 else {
3952 if( obj->type == ADDR_ITEM_GROUP ) {
3953 /* Load groups */
3954 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3955 addressbook_load_group( ctreelist, itemGroup );
3957 else if( obj->type == ADDR_ITEM_FOLDER ) {
3958 /* Load folders */
3959 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3960 addressbook_folder_load_person( ctreelist, itemFolder );
3961 addressbook_folder_load_group( ctreelist, itemFolder );
3964 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3965 clist->focus_row = -1;
3966 gtk_cmclist_thaw(clist);
3970 * Call back function to free adaptor. Call back is setup by function
3971 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3972 * called when the address book tree widget node is removed by calling
3973 * function gtk_cmctree_remove_node().
3975 * \param data Tree node's row data.
3977 static void addressbook_free_treenode( gpointer data ) {
3978 AddressObject *ao;
3980 ao = ( AddressObject * ) data;
3981 if( ao == NULL ) return;
3982 if( ao->type == ADDR_INTERFACE ) {
3983 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3984 addrbookctl_free_interface( ai );
3986 else if( ao->type == ADDR_DATASOURCE ) {
3987 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3988 addrbookctl_free_datasource( ads );
3990 else if( ao->type == ADDR_ITEM_FOLDER ) {
3991 AdapterFolder *af = ADAPTER_FOLDER(ao);
3992 addrbookctl_free_folder( af );
3994 else if( ao->type == ADDR_ITEM_GROUP ) {
3995 AdapterGroup *ag = ADAPTER_GROUP(ao);
3996 addrbookctl_free_group( ag );
4001 * Create new adaptor for specified data source.
4003 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4004 AddressObjectType otype, gchar *name )
4006 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4007 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4008 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4009 adapter->dataSource = ds;
4010 adapter->subType = otype;
4011 return adapter;
4014 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4015 ADDRESS_OBJECT_NAME(adapter) =
4016 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4020 * Load tree from address index with the initial data.
4022 static void addressbook_load_tree( void ) {
4023 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4024 GList *nodeIf, *nodeDS;
4025 AdapterInterface *adapter;
4026 AddressInterface *iface;
4027 AddressTypeControlItem *atci;
4028 AddressDataSource *ds;
4029 AdapterDSource *ads;
4030 GtkCMCTreeNode *node, *newNode;
4031 gchar *name;
4033 nodeIf = _addressInterfaceList_;
4034 while( nodeIf ) {
4035 adapter = nodeIf->data;
4036 node = adapter->treeNode;
4037 iface = adapter->interface;
4038 atci = adapter->atci;
4039 if( iface ) {
4040 if( iface->useInterface ) {
4041 /* Load data sources below interface node */
4042 nodeDS = iface->listSource;
4043 while( nodeDS ) {
4044 ds = nodeDS->data;
4045 name = addrindex_ds_get_name( ds );
4046 ads = addressbook_create_ds_adapter(
4047 ds, atci->objectType, name );
4048 newNode = addressbook_add_object(
4049 node, ADDRESS_OBJECT(ads) );
4050 if (newNode == NULL) {
4051 g_message("error adding addressbook object\n");
4053 nodeDS = g_list_next( nodeDS );
4055 gtk_cmctree_expand( ctree, node );
4058 nodeIf = g_list_next( nodeIf );
4063 * Convert the old address book to new format.
4065 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4066 gboolean retVal = FALSE;
4067 gboolean errFlag = TRUE;
4068 gchar *msg = NULL;
4070 /* Read old address book, performing conversion */
4071 debug_print( "Reading and converting old address book...\n" );
4072 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4073 addrindex_read_data( addrIndex );
4074 if( addrIndex->retVal == MGU_NO_FILE ) {
4075 /* We do not have a file - new user */
4076 debug_print( "New user... create new books...\n" );
4077 addrindex_create_new_books( addrIndex );
4078 if( addrIndex->retVal == MGU_SUCCESS ) {
4079 /* Save index file */
4080 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4081 addrindex_save_data( addrIndex );
4082 if( addrIndex->retVal == MGU_SUCCESS ) {
4083 retVal = TRUE;
4084 errFlag = FALSE;
4086 else {
4087 msg = _( "New user, could not save index file." );
4090 else {
4091 msg = _( "New user, could not save address book files." );
4094 else {
4095 /* We have an old file */
4096 if( addrIndex->wasConverted ) {
4097 /* Converted successfully - save address index */
4098 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4099 addrindex_save_data( addrIndex );
4100 if( addrIndex->retVal == MGU_SUCCESS ) {
4101 msg = _( "Old address book converted successfully." );
4102 retVal = TRUE;
4103 errFlag = FALSE;
4105 else {
4106 msg = _("Old address book converted,\n"
4107 "could not save new address index file." );
4110 else {
4111 /* File conversion failed - just create new books */
4112 debug_print( "File conversion failed... just create new books...\n" );
4113 addrindex_create_new_books( addrIndex );
4114 if( addrIndex->retVal == MGU_SUCCESS ) {
4115 /* Save index */
4116 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4117 addrindex_save_data( addrIndex );
4118 if( addrIndex->retVal == MGU_SUCCESS ) {
4119 msg = _("Could not convert address book,\n"
4120 "but created empty new address book files." );
4121 retVal = TRUE;
4122 errFlag = FALSE;
4124 else {
4125 msg = _("Could not convert address book,\n"
4126 "could not save new address index file." );
4129 else {
4130 msg = _("Could not convert address book\n"
4131 "and could not create new address book files." );
4135 if( errFlag ) {
4136 debug_print( "Error\n%s\n", msg );
4137 alertpanel_full(_("Addressbook conversion error"), msg,
4138 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4139 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4141 else if( msg ) {
4142 debug_print( "Warning\n%s\n", msg );
4143 alertpanel_full(_("Addressbook conversion error"), msg,
4144 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4145 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4148 return retVal;
4151 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4153 GDir *dp;
4154 const gchar *d;
4155 gboolean failed = FALSE;
4156 GError *error = NULL;
4158 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4159 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4160 error->code, error->message);
4161 g_error_free(error);
4162 return FALSE;
4165 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4166 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4167 continue;
4168 else {
4169 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4170 d, NULL);
4171 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4172 d, NULL);
4173 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4174 failed = TRUE;
4176 g_free(orig_file);
4177 g_free(dest_file);
4178 if (failed) {
4179 break;
4183 g_dir_close( dp );
4185 if (!failed) {
4186 /* all copies succeeded, we can remove source files */
4187 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4188 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4189 error->code, error->message);
4190 g_error_free(error);
4191 return FALSE;
4193 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4194 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4195 continue;
4196 else {
4197 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4198 d, NULL);
4199 claws_unlink(orig_file);
4200 g_free(orig_file);
4203 g_dir_close( dp );
4206 return !failed;
4209 void addressbook_read_file( void ) {
4210 AddressIndex *addrIndex = NULL;
4211 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4213 debug_print( "Reading address index...\n" );
4214 if( _addressIndex_ ) {
4215 debug_print( "address book already read!!!\n" );
4216 return;
4219 addrIndex = addrindex_create_index();
4220 addrindex_initialize();
4222 /* Use new address book index. */
4224 if ( !is_dir_exist(indexdir) ) {
4225 if ( make_dir(indexdir) < 0 ) {
4226 addrindex_set_file_path( addrIndex, get_rc_dir() );
4227 g_warning( "couldn't create dir '%s'", indexdir);
4228 } else {
4229 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4230 remove_dir_recursive(indexdir);
4231 addrindex_set_file_path( addrIndex, get_rc_dir() );
4232 g_error("couldn't migrate dir %s", indexdir);
4233 } else {
4234 addrindex_set_file_path( addrIndex, indexdir);
4237 } else {
4238 addrindex_set_file_path( addrIndex, indexdir);
4240 g_free(indexdir);
4241 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4242 addrindex_read_data( addrIndex );
4243 if( addrIndex->retVal == MGU_NO_FILE ) {
4244 /* Conversion required */
4245 debug_print( "Converting...\n" );
4246 if( addressbook_convert( addrIndex ) ) {
4247 _addressIndex_ = addrIndex;
4250 else if( addrIndex->retVal == MGU_SUCCESS ) {
4251 _addressIndex_ = addrIndex;
4253 else {
4254 /* Error reading address book */
4255 debug_print( "Could not read address index.\n" );
4256 addrindex_print_index( addrIndex, stdout );
4257 alertpanel_full(_("Addressbook Error"),
4258 _("Could not read address index"),
4259 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4260 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4262 debug_print( "done.\n" );
4266 * Add object into the address index tree widget.
4267 * Enter: node Parent node.
4268 * obj Object to add.
4269 * Return: Node that was added, or NULL if object not added.
4271 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4272 AddressObject *obj)
4274 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4275 GtkCMCTreeNode *added;
4276 AddressObject *pobj;
4277 AddressObjectType otype;
4278 AddressTypeControlItem *atci = NULL;
4280 cm_return_val_if_fail(node != NULL, NULL);
4281 cm_return_val_if_fail(obj != NULL, NULL);
4283 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4284 cm_return_val_if_fail(pobj != NULL, NULL);
4286 /* Determine object type to be displayed */
4287 if( obj->type == ADDR_DATASOURCE ) {
4288 otype = ADAPTER_DSOURCE(obj)->subType;
4290 else {
4291 otype = obj->type;
4294 /* Handle any special conditions. */
4295 added = node;
4296 atci = addrbookctl_lookup( otype );
4297 if( atci ) {
4298 if( atci->showInTree ) {
4299 /* Add object to tree */
4300 gchar **name;
4301 name = &obj->name;
4302 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4303 atci->iconXpm, atci->iconXpmOpen,
4304 atci->treeLeaf, atci->treeExpand );
4305 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4306 addressbook_free_treenode );
4310 gtk_sctree_sort_node(ctree, node);
4312 return added;
4316 * Add group into the address index tree.
4317 * \param node Parent node.
4318 * \param ds Data source.
4319 * \param itemGroup Group to add.
4320 * \return Inserted node.
4322 static GtkCMCTreeNode *addressbook_node_add_group(
4323 GtkCMCTreeNode *node, AddressDataSource *ds,
4324 ItemGroup *itemGroup )
4326 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4327 GtkCMCTreeNode *newNode;
4328 AdapterGroup *adapter;
4329 AddressTypeControlItem *atci = NULL;
4330 gchar **name;
4332 if( ds == NULL ) return NULL;
4333 if( node == NULL || itemGroup == NULL ) return NULL;
4335 name = &itemGroup->obj.name;
4337 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4339 adapter = g_new0( AdapterGroup, 1 );
4340 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4341 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4342 adapter->itemGroup = itemGroup;
4344 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4345 atci->iconXpm, atci->iconXpm,
4346 atci->treeLeaf, atci->treeExpand );
4347 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4348 addressbook_free_treenode );
4349 gtk_sctree_sort_node( ctree, node );
4350 return newNode;
4354 * Add folder into the address index tree. Only visible folders are loaded into
4355 * the address index tree. Note that the root folder is not inserted into the
4356 * tree.
4358 * \param node Parent node.
4359 * \param ds Data source.
4360 * \param itemFolder Folder to add.
4361 * \param otype Object type to display.
4362 * \return Inserted node for the folder.
4364 static GtkCMCTreeNode *addressbook_node_add_folder(
4365 GtkCMCTreeNode *node, AddressDataSource *ds,
4366 ItemFolder *itemFolder, AddressObjectType otype )
4368 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4369 GtkCMCTreeNode *newNode = NULL;
4370 AdapterFolder *adapter;
4371 AddressTypeControlItem *atci = NULL;
4372 GList *listItems = NULL;
4373 gchar *name;
4374 ItemFolder *rootFolder;
4376 /* Only visible folders */
4377 if( itemFolder == NULL || itemFolder->isHidden )
4378 return NULL;
4380 if( ds == NULL )
4381 return NULL;
4382 if( node == NULL || itemFolder == NULL )
4383 return NULL;
4385 /* Determine object type */
4386 atci = addrbookctl_lookup( otype );
4387 if( atci == NULL )
4388 return NULL;
4390 rootFolder = addrindex_ds_get_root_folder( ds );
4391 if( itemFolder == rootFolder ) {
4392 newNode = node;
4394 else {
4395 adapter = g_new0( AdapterFolder, 1 );
4396 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4397 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4398 adapter->itemFolder = itemFolder;
4400 name = ADDRITEM_NAME(itemFolder);
4401 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4402 atci->iconXpm, atci->iconXpm,
4403 atci->treeLeaf, atci->treeExpand );
4404 if( newNode ) {
4405 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4406 addressbook_free_treenode );
4410 listItems = itemFolder->listFolder;
4411 while( listItems ) {
4412 ItemFolder *item = listItems->data;
4413 addressbook_node_add_folder( newNode, ds, item, otype );
4414 listItems = g_list_next( listItems );
4416 listItems = itemFolder->listGroup;
4417 while( listItems ) {
4418 ItemGroup *item = listItems->data;
4419 addressbook_node_add_group( newNode, ds, item );
4420 listItems = g_list_next( listItems );
4422 gtk_sctree_sort_node( ctree, node );
4423 return newNode;
4426 void addressbook_export_to_file( void ) {
4427 if( _addressIndex_ ) {
4428 /* Save all new address book data */
4429 debug_print( "Saving address books...\n" );
4430 addrindex_save_all_books( _addressIndex_ );
4432 debug_print( "Exporting addressbook to file...\n" );
4433 addrindex_save_data( _addressIndex_ );
4434 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4435 addrindex_print_index( _addressIndex_, stdout );
4438 /* Notify address completion of new data */
4439 invalidate_address_completion();
4443 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4445 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4446 addressbook_lup_clicked(NULL, NULL);
4447 return FALSE;
4451 * Comparison using cell contents (text in first column). Used for sort
4452 * address index widget.
4454 static gint addressbook_treenode_compare_func(
4455 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4457 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4458 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4459 gchar *name1 = NULL, *name2 = NULL;
4460 if( cell1 ) name1 = cell1->u.text;
4461 if( cell2 ) name2 = cell2->u.text;
4462 if( ! name1 ) return ( name2 != NULL );
4463 if( ! name2 ) return -1;
4464 return g_utf8_collate( name1, name2 );
4467 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4468 AdapterDSource *ads;
4469 AdapterInterface *adapter;
4470 GtkCMCTreeNode *newNode;
4472 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4473 if( adapter == NULL ) return;
4474 ads = addressbook_edit_book( _addressIndex_, NULL );
4475 if( ads ) {
4476 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4477 if( newNode ) {
4478 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4479 addrbook.treeSelected = newNode;
4484 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4485 AdapterDSource *ads;
4486 AdapterInterface *adapter;
4487 GtkCMCTreeNode *newNode;
4489 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4490 if( adapter == NULL ) return;
4491 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4492 if( ads ) {
4493 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4494 if( newNode ) {
4495 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4496 addrbook.treeSelected = newNode;
4501 #ifdef USE_JPILOT
4502 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4503 AdapterDSource *ads;
4504 AdapterInterface *adapter;
4505 AddressInterface *iface;
4506 GtkCMCTreeNode *newNode;
4508 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4509 if( adapter == NULL ) return;
4510 iface = adapter->interface;
4511 if( ! iface->haveLibrary ) return;
4512 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4513 if( ads ) {
4514 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4515 if( newNode ) {
4516 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4517 addrbook.treeSelected = newNode;
4521 #endif
4523 #ifdef USE_LDAP
4524 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4525 AdapterDSource *ads;
4526 AdapterInterface *adapter;
4527 AddressInterface *iface;
4528 GtkCMCTreeNode *newNode;
4530 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4531 if( adapter == NULL ) return;
4532 iface = adapter->interface;
4533 if( ! iface->haveLibrary ) return;
4534 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4535 if( ads ) {
4536 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4537 if( newNode ) {
4538 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4539 addrbook.treeSelected = newNode;
4543 #endif
4546 * Display address search status message.
4547 * \param queryType Query type.
4548 * \param status Status/Error code.
4550 static void addressbook_search_message( gint queryType, gint sts ) {
4551 gchar *desc = NULL;
4552 *addressbook_msgbuf = '\0';
4554 if( sts != MGU_SUCCESS ) {
4555 if( queryType == ADDRQUERY_LDAP ) {
4556 #ifdef USE_LDAP
4557 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4558 #endif
4561 if( desc ) {
4562 g_snprintf( addressbook_msgbuf,
4563 sizeof(addressbook_msgbuf), "%s", desc );
4564 addressbook_status_show( addressbook_msgbuf );
4566 else {
4567 addressbook_status_show( "" );
4572 * Refresh addressbook by forcing refresh of current selected object in
4573 * tree.
4575 static void addressbook_refresh_current( void ) {
4576 AddressObject *obj;
4577 GtkCMCTree *ctree;
4579 ctree = GTK_CMCTREE(addrbook.ctree);
4580 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4581 if( obj == NULL ) return;
4582 addressbook_set_clist( obj, TRUE );
4586 * Message that is displayed whilst a query is executing in a background
4587 * thread.
4589 static gchar *_tempMessage_ = N_( "Busy searching..." );
4592 * Address search idle function. This function is called during UI idle time
4593 * while a search is in progress.
4595 * \param data Idler data.
4597 static void addressbook_search_idle( gpointer data ) {
4599 gint queryID;
4601 queryID = GPOINTER_TO_INT( data );
4602 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4607 * Search completion callback function. This removes the query from the idle
4608 * list.
4610 * \param sender Sender of query.
4611 * \param queryID Query ID of search request.
4612 * \param status Search status.
4613 * \param data Query data.
4615 static void addressbook_search_callback_end(
4616 gpointer sender, gint queryID, gint status, gpointer data )
4618 gpointer ptrQID;
4619 QueryRequest *req;
4620 AddrQueryObject *aqo;
4622 /* Remove idler function */
4623 ptrQID = GINT_TO_POINTER( queryID );
4624 if( ptrQID ) {
4625 g_idle_remove_by_data( ptrQID );
4628 /* Refresh addressbook contents */
4629 addressbook_refresh_current();
4630 req = qrymgr_find_request( queryID );
4631 if( req != NULL ) {
4632 aqo = ( AddrQueryObject * ) req->queryList->data;
4633 addressbook_search_message( aqo->queryType, status );
4636 /* Stop the search */
4637 addrindex_stop_search( queryID );
4641 * Perform search.
4643 * \param ds Data source to search.
4644 * \param searchTerm String to lookup.
4645 * \param pNode Parent data source node.
4647 static void addressbook_perform_search(
4648 AddressDataSource *ds, gchar *searchTerm,
4649 GtkCMCTreeNode *pNode )
4651 ItemFolder *folder;
4652 gchar *name;
4653 gint queryID;
4654 guint idleID;
4656 /* Setup a query */
4657 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4659 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4661 /* Create a folder for the search results */
4662 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4663 folder = addressbook_setup_subf(ds, name, pNode);
4664 g_free( name );
4666 /* Setup the search */
4667 queryID = addrindex_setup_explicit_search(
4668 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4669 if( queryID == 0 ) return;
4671 /* Set up idler function */
4672 idleID = g_idle_add(
4673 (GSourceFunc) addressbook_search_idle,
4674 GINT_TO_POINTER( queryID ) );
4675 if (idleID == 0) {
4676 g_message("error adding addressbook_search_idle\n");
4679 /* Start search, sit back and wait for something to happen */
4680 addrindex_start_search( queryID );
4682 addressbook_status_show( _tempMessage_ );
4686 * Lookup button handler. Address search is only performed against
4687 * address interfaces for external queries.
4689 * \param button Lookup button widget.
4690 * \param data Data object.
4692 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4693 GtkCMCTree *ctree;
4694 AddressObject *obj;
4695 AddressDataSource *ds;
4696 AddressInterface *iface;
4697 gchar *searchTerm;
4698 GtkCMCTreeNode *node, *parentNode;
4700 node = addrbook.treeSelected;
4701 if( ! node ) return;
4702 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4704 ctree = GTK_CMCTREE(addrbook.ctree);
4705 obj = gtk_cmctree_node_get_row_data( ctree, node );
4706 if( obj == NULL ) return;
4708 if (obj->type != ADDR_DATASOURCE ||
4709 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4710 addressbook_set_clist(
4711 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4712 addrbook.treeSelected),
4713 TRUE);
4716 ds = addressbook_find_datasource( node );
4717 if( ds == NULL ) return;
4719 /* We must have a datasource that is an external interface */
4720 iface = ds->interface;
4721 if( ! iface->haveLibrary ) return;
4722 if( ! iface->externalQuery ) return;
4724 searchTerm =
4725 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4726 g_strchomp( searchTerm );
4728 if( obj->type == ADDR_ITEM_FOLDER ) {
4729 parentNode = GTK_CMCTREE_ROW(node)->parent;
4731 else {
4732 parentNode = node;
4734 addressbook_perform_search( ds, searchTerm, parentNode );
4736 gtk_widget_grab_focus( addrbook.entry );
4738 g_free( searchTerm );
4741 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4742 addressbook_close();
4745 #ifdef USE_LDAP
4747 * Browse address entry for highlighted entry.
4749 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4751 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4752 AddressObject *obj;
4753 AddressDataSource *ds;
4754 AddressInterface *iface;
4755 ItemPerson *person;
4756 ItemEMail *email;
4758 if(addrbook.listSelected == NULL)
4759 return;
4761 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4762 if (obj == NULL)
4763 return;
4765 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4766 if(ds == NULL)
4767 return;
4769 iface = ds->interface;
4770 if(!iface || !iface->haveLibrary )
4771 return;
4773 person = NULL;
4774 if (obj->type == ADDR_ITEM_EMAIL) {
4775 email = ( ItemEMail * ) obj;
4777 person = (ItemPerson *) ADDRITEM_PARENT(email);
4779 else if (obj->type == ADDR_ITEM_PERSON) {
4780 person = (ItemPerson *) obj;
4782 else {
4783 /* None of these */
4784 return;
4787 if( iface && iface->type == ADDR_IF_LDAP ) {
4788 browseldap_entry(ds, person->externalID);
4791 #endif
4793 /* **********************************************************************
4794 * Build lookup tables.
4795 * ***********************************************************************
4799 * Remap object types.
4800 * Enter: abType AddressObjectType (used in tree node).
4801 * Return: ItemObjectType (used in address cache data).
4803 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4804 ItemObjectType ioType;
4806 switch( abType ) {
4807 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4808 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4809 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4810 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4811 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4812 default: ioType = ITEMTYPE_NONE; break;
4814 return ioType;
4817 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4818 atci = addrbookctl_lookup(id); \
4819 if (atci) { \
4820 atci->iconXpm = icon; \
4821 atci->iconXpmOpen = iconopen; \
4822 } else { \
4823 g_warning("can't get atci %d", id); \
4828 * Build table that controls the rendering of object types.
4830 static void addrbookctl_build_icons( GtkWidget *window ) {
4831 AddressTypeControlItem *atci;
4833 /* Build icons */
4834 if (interfacexpm)
4835 g_object_unref(interfacexpm);
4836 if (folderxpm)
4837 g_object_unref(folderxpm);
4838 if (folderopenxpm)
4839 g_object_unref(folderopenxpm);
4840 if (groupxpm)
4841 g_object_unref(groupxpm);
4842 if (vcardxpm)
4843 g_object_unref(vcardxpm);
4844 if (bookxpm)
4845 g_object_unref(bookxpm);
4846 if (addressxpm)
4847 g_object_unref(addressxpm);
4848 if (jpilotxpm)
4849 g_object_unref(jpilotxpm);
4850 if (categoryxpm)
4851 g_object_unref(categoryxpm);
4852 if (ldapxpm)
4853 g_object_unref(ldapxpm);
4854 if (addrsearchxpm)
4855 g_object_unref(addrsearchxpm);
4856 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4857 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4858 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4859 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4860 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4861 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4862 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4863 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4864 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4865 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4866 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4868 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4869 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4870 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4871 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4872 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4873 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4874 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4875 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4876 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4877 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4878 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4883 * Build table that controls the rendering of object types.
4885 static void addrbookctl_build_map( GtkWidget *window ) {
4886 AddressTypeControlItem *atci;
4888 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4889 _addressBookTypeList_ = NULL;
4891 /* Interface */
4892 atci = g_new0( AddressTypeControlItem, 1 );
4893 atci->objectType = ADDR_INTERFACE;
4894 atci->interfaceType = ADDR_IF_NONE;
4895 atci->showInTree = TRUE;
4896 atci->treeExpand = TRUE;
4897 atci->treeLeaf = FALSE;
4898 atci->displayName = _( "Interface" );
4899 atci->menuCommand = NULL;
4900 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4901 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4903 /* Address book */
4904 atci = g_new0( AddressTypeControlItem, 1 );
4905 atci->objectType = ADDR_BOOK;
4906 atci->interfaceType = ADDR_IF_BOOK;
4907 atci->showInTree = TRUE;
4908 atci->treeExpand = TRUE;
4909 atci->treeLeaf = FALSE;
4910 atci->displayName = _("Address Books");
4911 atci->menuCommand = "Menu/Book/NewBook";
4912 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4913 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4915 /* Item person */
4916 atci = g_new0( AddressTypeControlItem, 1 );
4917 atci->objectType = ADDR_ITEM_PERSON;
4918 atci->interfaceType = ADDR_IF_NONE;
4919 atci->showInTree = FALSE;
4920 atci->treeExpand = FALSE;
4921 atci->treeLeaf = FALSE;
4922 atci->displayName = _( "Person" );
4923 atci->menuCommand = NULL;
4924 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4925 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4927 /* Item email */
4928 atci = g_new0( AddressTypeControlItem, 1 );
4929 atci->objectType = ADDR_ITEM_EMAIL;
4930 atci->interfaceType = ADDR_IF_NONE;
4931 atci->showInTree = FALSE;
4932 atci->treeExpand = FALSE;
4933 atci->treeLeaf = TRUE;
4934 atci->displayName = _( "Email Address" );
4935 atci->menuCommand = NULL;
4936 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4937 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4939 /* Item group */
4940 atci = g_new0( AddressTypeControlItem, 1 );
4941 atci->objectType = ADDR_ITEM_GROUP;
4942 atci->interfaceType = ADDR_IF_BOOK;
4943 atci->showInTree = TRUE;
4944 atci->treeExpand = FALSE;
4945 atci->treeLeaf = FALSE;
4946 atci->displayName = _( "Group" );
4947 atci->menuCommand = NULL;
4948 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4949 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4951 /* Item folder */
4952 atci = g_new0( AddressTypeControlItem, 1 );
4953 atci->objectType = ADDR_ITEM_FOLDER;
4954 atci->interfaceType = ADDR_IF_BOOK;
4955 atci->showInTree = TRUE;
4956 atci->treeExpand = FALSE;
4957 atci->treeLeaf = FALSE;
4958 atci->displayName = _( "Folder" );
4959 atci->menuCommand = NULL;
4960 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4961 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4963 /* vCard */
4964 atci = g_new0( AddressTypeControlItem, 1 );
4965 atci->objectType = ADDR_VCARD;
4966 atci->interfaceType = ADDR_IF_VCARD;
4967 atci->showInTree = TRUE;
4968 atci->treeExpand = TRUE;
4969 atci->treeLeaf = TRUE;
4970 atci->displayName = _( "vCard" );
4971 atci->menuCommand = "Menu/Book/NewVCard";
4972 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4973 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4975 /* J-Pilot */
4976 atci = g_new0( AddressTypeControlItem, 1 );
4977 atci->objectType = ADDR_JPILOT;
4978 atci->interfaceType = ADDR_IF_JPILOT;
4979 atci->showInTree = TRUE;
4980 atci->treeExpand = TRUE;
4981 atci->treeLeaf = FALSE;
4982 atci->displayName = _( "JPilot" );
4983 atci->menuCommand = "Menu/Book/NewJPilot";
4984 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4985 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4987 /* Category */
4988 atci = g_new0( AddressTypeControlItem, 1 );
4989 atci->objectType = ADDR_CATEGORY;
4990 atci->interfaceType = ADDR_IF_JPILOT;
4991 atci->showInTree = TRUE;
4992 atci->treeExpand = TRUE;
4993 atci->treeLeaf = TRUE;
4994 atci->displayName = _( "JPilot" );
4995 atci->menuCommand = NULL;
4996 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4997 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4999 /* LDAP Server */
5000 atci = g_new0( AddressTypeControlItem, 1 );
5001 atci->objectType = ADDR_LDAP;
5002 atci->interfaceType = ADDR_IF_LDAP;
5003 atci->showInTree = TRUE;
5004 atci->treeExpand = TRUE;
5005 atci->treeLeaf = FALSE;
5006 atci->displayName = _( "LDAP servers" );
5007 atci->menuCommand = "Menu/Book/NewLDAPServer";
5008 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5009 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5011 /* LDAP Query */
5012 atci = g_new0( AddressTypeControlItem, 1 );
5013 atci->objectType = ADDR_LDAP_QUERY;
5014 atci->interfaceType = ADDR_IF_LDAP;
5015 atci->showInTree = TRUE;
5016 atci->treeExpand = FALSE;
5017 atci->treeLeaf = TRUE;
5018 atci->displayName = _( "LDAP Query" );
5019 atci->menuCommand = NULL;
5020 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5021 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5023 addrbookctl_build_icons(window);
5026 void addressbook_reflect_prefs_pixmap_theme(void)
5028 if (addrbook.window)
5029 addrbookctl_build_icons(addrbook.window);
5033 * Search for specified object type.
5035 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5036 gint objType = ot;
5037 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5041 * Search for specified interface type.
5043 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5044 GList *node = _addressBookTypeList_;
5045 while( node ) {
5046 AddressTypeControlItem *atci = node->data;
5047 if( atci->interfaceType == ifType ) return atci;
5048 node = g_list_next( node );
5050 return NULL;
5053 static void addrbookctl_free_address( AddressObject *obj ) {
5054 g_free( obj->name );
5055 obj->type = ADDR_NONE;
5056 obj->name = NULL;
5059 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5060 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5061 adapter->interface = NULL;
5062 adapter->interfaceType = ADDR_IF_NONE;
5063 adapter->atci = NULL;
5064 adapter->enabled = FALSE;
5065 adapter->haveLibrary = FALSE;
5066 adapter->treeNode = NULL;
5067 g_free( adapter );
5070 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5071 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5072 adapter->dataSource = NULL;
5073 adapter->subType = ADDR_NONE;
5074 g_free( adapter );
5077 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5078 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5079 adapter->itemFolder = NULL;
5080 g_free( adapter );
5083 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5084 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5085 adapter->itemGroup = NULL;
5086 g_free( adapter );
5090 * Build GUI interface list.
5092 static void addrbookctl_build_iflist( void ) {
5093 AddressTypeControlItem *atci;
5094 AdapterInterface *adapter;
5095 GList *list = NULL;
5097 if( _addressIndex_ == NULL ) {
5098 _addressIndex_ = addrindex_create_index();
5099 if( _clipBoard_ == NULL ) {
5100 _clipBoard_ = addrclip_create();
5102 addrclip_set_index( _clipBoard_, _addressIndex_ );
5104 _addressInterfaceList_ = NULL;
5105 list = addrindex_get_interface_list( _addressIndex_ );
5106 while( list ) {
5107 AddressInterface *interface = list->data;
5108 atci = addrbookctl_lookup_iface( interface->type );
5109 if( atci ) {
5110 adapter = g_new0( AdapterInterface, 1 );
5111 adapter->interfaceType = interface->type;
5112 adapter->atci = atci;
5113 adapter->interface = interface;
5114 adapter->treeNode = NULL;
5115 adapter->enabled = TRUE;
5116 adapter->haveLibrary = interface->haveLibrary;
5117 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5118 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5119 _addressInterfaceList_ =
5120 g_list_append( _addressInterfaceList_, adapter );
5122 list = g_list_next( list );
5127 * Find GUI interface type specified interface type.
5128 * \param ifType Interface type.
5129 * \return Interface item, or NULL if not found.
5131 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5132 GList *node = _addressInterfaceList_;
5133 while( node ) {
5134 AdapterInterface *adapter = node->data;
5135 if( adapter->interfaceType == ifType ) return adapter;
5136 node = g_list_next( node );
5138 return NULL;
5142 * Build interface list selection.
5144 static void addrbookctl_build_ifselect( void ) {
5145 GList *newList = NULL;
5146 gchar *selectStr;
5147 gchar **splitStr;
5148 gint ifType;
5149 gint i;
5150 gchar *endptr = NULL;
5151 /* gboolean enabled; */
5152 AdapterInterface *adapter;
5154 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5156 /* Parse string */
5157 splitStr = g_strsplit( selectStr, ",", -1 );
5158 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5159 if( splitStr[i] ) {
5160 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5161 ifType = strtol( splitStr[i], &endptr, 10 );
5162 /* enabled = TRUE;
5163 if( *endptr ) {
5164 if( strcmp( endptr, "/n" ) == 0 ) {
5165 enabled = FALSE;
5169 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5170 adapter = addrbookctl_find_interface( ifType );
5171 if( adapter ) {
5172 newList = g_list_append( newList, adapter );
5175 else {
5176 break;
5179 /* g_print( "i=%d\n", i ); */
5180 g_strfreev( splitStr );
5181 g_free( selectStr );
5183 /* Replace existing list */
5184 mgu_clear_list( _addressIFaceSelection_ );
5185 g_list_free( _addressIFaceSelection_ );
5186 _addressIFaceSelection_ = newList;
5187 newList = NULL;
5190 /* ***********************************************************************
5191 * Add sender to address book.
5192 * ***********************************************************************
5196 * This function is used by the Add sender to address book function.
5198 gboolean addressbook_add_contact(
5199 const gchar *name, const gchar *address, const gchar *remarks,
5200 GdkPixbuf *picture )
5202 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5203 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5204 debug_print( "addressbook_add_contact - added\n" );
5205 addressbook_refresh();
5207 return TRUE;
5210 /* ***********************************************************************
5211 * Book/folder selection.
5212 * ***********************************************************************
5216 * This function is used by the matcher dialog to select a book/folder.
5218 gchar *addressbook_folder_selection( const gchar *folderpath)
5220 AddressBookFile *book = NULL;
5221 ItemFolder *folder = NULL;
5222 gchar *path = NULL;
5224 cm_return_val_if_fail( folderpath != NULL, NULL);
5226 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5227 && book != NULL ) {
5228 if ( folder != NULL) {
5229 gchar *tmp = NULL;
5230 gchar *oldtmp = NULL;
5231 AddrItemObject *obj = NULL;
5233 /* walk thru folder->parent to build the full folder path */
5234 /* TODO: wwp: optimize this */
5235 obj = &folder->obj;
5236 tmp = g_strdup(obj->uid);
5237 while ( obj->parent ) {
5238 obj = obj->parent;
5239 if ( obj->name != NULL ) {
5240 oldtmp = g_strdup(tmp);
5241 g_free(tmp);
5242 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5243 g_free(oldtmp);
5246 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5247 g_free(tmp);
5248 } else {
5249 path = g_strdup_printf("%s", book->fileName);
5251 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5252 return path;
5254 return NULL;
5257 /* ***********************************************************************
5258 * Book/folder checking.
5259 * ***********************************************************************
5262 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5264 FolderInfo *fi = g_new0( FolderInfo, 1 );
5265 fi->book = abf;
5266 fi->folder = folder;
5267 return fi;
5270 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5271 FolderInfo *fiParent, FolderPathMatch *match )
5273 GList *list;
5274 ItemFolder *folder;
5275 gchar *fName;
5276 FolderInfo *fi;
5277 FolderPathMatch *nextmatch = NULL;
5279 if (!parentFolder)
5280 return;
5282 list = parentFolder->listFolder;
5283 while ( list ) {
5284 folder = list->data;
5285 fName = g_strdup( ADDRITEM_NAME(folder) );
5287 /* match folder name, match pointer will be set to NULL if next recursive call
5288 doesn't need to match subfolder name */
5289 if ( match != NULL &&
5290 match->matched == FALSE ) {
5291 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5292 /* folder name matches, prepare next subfolder match */
5293 debug_print("matched folder name '%s'\n", fName);
5294 match->index++;
5295 if ( match->folder_path[match->index] == NULL ) {
5296 /* we've matched all elements */
5297 match->matched = TRUE;
5298 match->folder = folder;
5299 debug_print("book/folder path matched!\n");
5300 } else {
5301 /* keep on matching */
5302 nextmatch = match;
5307 g_free( fName );
5309 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5310 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5311 g_free(fi);
5312 list = g_list_next( list );
5317 * This function is used by to check if a matcher book/folder path corresponds to an
5318 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5319 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5320 if book AND folder are NULL this means that folderpath was empty or Any.
5321 If folderpath is a simple book name (without folder), book will not be NULL and folder
5322 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5325 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5326 AddressDataSource **book,
5327 ItemFolder **folder )
5329 AddressDataSource *ds;
5330 GList *list, *nodeDS;
5331 ItemFolder *rootFolder;
5332 AddressBookFile *abf;
5333 FolderInfo *fi;
5334 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5336 if ( book )
5337 *book = NULL;
5338 if ( folder )
5339 *folder = NULL;
5341 if ( folderpath == NULL )
5342 return FALSE;
5344 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5345 return TRUE;
5347 /* split the folder path we've received, we'll try to match this path, subpath by
5348 subpath against the book/folder structure in order */
5349 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5350 if (!folder_path_match.folder_path)
5351 return FALSE;
5353 list = addrindex_get_interface_list( _addressIndex_ );
5354 while ( list && !folder_path_match.matched ) {
5355 AddressInterface *interface = list->data;
5356 if ( interface && interface->type == ADDR_IF_BOOK ) {
5357 nodeDS = interface->listSource;
5358 while ( nodeDS && !folder_path_match.matched ) {
5359 ds = nodeDS->data;
5361 /* Read address book */
5362 if( ! addrindex_ds_get_read_flag( ds ) ) {
5363 addrindex_ds_read_data( ds );
5366 /* Add node for address book */
5367 abf = ds->rawDataSource;
5369 /* match book name */
5370 if ( abf && abf->fileName &&
5371 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5373 debug_print("matched book name '%s'\n", abf->fileName);
5374 folder_path_match.book = ds;
5376 if ( folder_path_match.folder_path[1] == NULL ) {
5377 /* no folder part to match */
5379 folder_path_match.matched = TRUE;
5380 folder_path_match.folder = NULL;
5381 debug_print("book path matched!\n");
5383 } else {
5384 /* match folder part */
5386 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5387 rootFolder = addrindex_ds_get_root_folder( ds );
5389 /* prepare for recursive call */
5390 folder_path_match.index = 1;
5391 /* this call will set folder_path_match.matched and folder_path_match.folder */
5392 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5393 g_free(fi);
5397 nodeDS = g_list_next( nodeDS );
5400 list = g_list_next( list );
5403 g_strfreev( folder_path_match.folder_path );
5405 if ( book )
5406 *book = folder_path_match.book;
5407 if ( folder )
5408 *folder = folder_path_match.folder;
5409 return folder_path_match.matched;
5413 /* **********************************************************************
5414 * Address Import.
5415 * ***********************************************************************
5419 * Import LDIF file.
5421 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5422 AddressDataSource *ds = NULL;
5423 AdapterDSource *ads = NULL;
5424 AddressBookFile *abf = NULL;
5425 AdapterInterface *adapter;
5426 GtkCMCTreeNode *newNode;
5428 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5429 if( adapter ) {
5430 if( adapter->treeNode ) {
5431 abf = addressbook_imp_ldif( _addressIndex_ );
5432 if( abf ) {
5433 ds = addrindex_index_add_datasource(
5434 _addressIndex_, ADDR_IF_BOOK, abf );
5435 ads = addressbook_create_ds_adapter(
5436 ds, ADDR_BOOK, NULL );
5437 addressbook_ads_set_name(
5438 ads, addrbook_get_name( abf ) );
5439 newNode = addressbook_add_object(
5440 adapter->treeNode,
5441 ADDRESS_OBJECT(ads) );
5442 if( newNode ) {
5443 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5444 newNode );
5445 addrbook.treeSelected = newNode;
5448 /* Notify address completion */
5449 invalidate_address_completion();
5456 * Import MUTT file.
5458 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5459 AddressDataSource *ds = NULL;
5460 AdapterDSource *ads = NULL;
5461 AddressBookFile *abf = NULL;
5462 AdapterInterface *adapter;
5463 GtkCMCTreeNode *newNode;
5465 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5466 if( adapter ) {
5467 if( adapter->treeNode ) {
5468 abf = addressbook_imp_mutt( _addressIndex_ );
5469 if( abf ) {
5470 ds = addrindex_index_add_datasource(
5471 _addressIndex_, ADDR_IF_BOOK, abf );
5472 ads = addressbook_create_ds_adapter(
5473 ds, ADDR_BOOK, NULL );
5474 addressbook_ads_set_name(
5475 ads, addrbook_get_name( abf ) );
5476 newNode = addressbook_add_object(
5477 adapter->treeNode,
5478 ADDRESS_OBJECT(ads) );
5479 if( newNode ) {
5480 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5481 newNode );
5482 addrbook.treeSelected = newNode;
5485 /* Notify address completion */
5486 invalidate_address_completion();
5493 * Import Pine file.
5495 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5496 AddressDataSource *ds = NULL;
5497 AdapterDSource *ads = NULL;
5498 AddressBookFile *abf = NULL;
5499 AdapterInterface *adapter;
5500 GtkCMCTreeNode *newNode;
5502 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5503 if( adapter ) {
5504 if( adapter->treeNode ) {
5505 abf = addressbook_imp_pine( _addressIndex_ );
5506 if( abf ) {
5507 ds = addrindex_index_add_datasource(
5508 _addressIndex_, ADDR_IF_BOOK, abf );
5509 ads = addressbook_create_ds_adapter(
5510 ds, ADDR_BOOK, NULL );
5511 addressbook_ads_set_name(
5512 ads, addrbook_get_name( abf ) );
5513 newNode = addressbook_add_object(
5514 adapter->treeNode,
5515 ADDRESS_OBJECT(ads) );
5516 if( newNode ) {
5517 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5518 newNode );
5519 addrbook.treeSelected = newNode;
5522 /* Notify address completion */
5523 invalidate_address_completion();
5530 * Harvest addresses.
5531 * \param folderItem Folder to import.
5532 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5533 * \param msgList List of message numbers, or NULL to process folder.
5535 void addressbook_harvest(
5536 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5538 AddressDataSource *ds = NULL;
5539 AdapterDSource *ads = NULL;
5540 AddressBookFile *abf = NULL;
5541 AdapterInterface *adapter;
5542 GtkCMCTreeNode *newNode;
5544 abf = addrgather_dlg_execute(
5545 folderItem, _addressIndex_, sourceInd, msgList );
5546 if( abf ) {
5547 ds = addrindex_index_add_datasource(
5548 _addressIndex_, ADDR_IF_BOOK, abf );
5550 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5551 if( adapter ) {
5552 if( adapter->treeNode ) {
5553 ads = addressbook_create_ds_adapter(
5554 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5555 newNode = addressbook_add_object(
5556 adapter->treeNode,
5557 ADDRESS_OBJECT(ads) );
5558 if (newNode == NULL) {
5559 g_message("error adding addressbook object\n");
5564 /* Notify address completion */
5565 invalidate_address_completion();
5570 * Export HTML file.
5572 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5573 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5574 AddressObject *obj;
5575 AddressDataSource *ds = NULL;
5576 AddrBookBase *adbase;
5577 AddressCache *cache;
5578 GtkCMCTreeNode *node = NULL;
5580 if( ! addrbook.treeSelected ) return;
5581 node = addrbook.treeSelected;
5582 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5583 obj = gtk_cmctree_node_get_row_data( ctree, node );
5584 if( obj == NULL ) return;
5586 ds = addressbook_find_datasource( node );
5587 if( ds == NULL ) return;
5588 adbase = ( AddrBookBase * ) ds->rawDataSource;
5589 cache = adbase->addressCache;
5590 addressbook_exp_html( cache );
5594 * Export LDIF file.
5596 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5597 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5598 AddressObject *obj;
5599 AddressDataSource *ds = NULL;
5600 AddrBookBase *adbase;
5601 AddressCache *cache;
5602 GtkCMCTreeNode *node = NULL;
5604 if( ! addrbook.treeSelected ) return;
5605 node = addrbook.treeSelected;
5606 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5607 obj = gtk_cmctree_node_get_row_data( ctree, node );
5608 if( obj == NULL ) return;
5610 ds = addressbook_find_datasource( node );
5611 if( ds == NULL ) return;
5612 adbase = ( AddrBookBase * ) ds->rawDataSource;
5613 cache = adbase->addressCache;
5614 addressbook_exp_ldif( cache );
5617 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5619 addrduplicates_find(GTK_WINDOW(addrbook.window));
5622 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5624 addressbook_custom_attr_edit();
5627 static void addressbook_start_drag(GtkWidget *widget, gint button,
5628 GdkEvent *event,
5629 void *data)
5631 GdkDragContext *context;
5632 if (addressbook_target_list == NULL)
5633 addressbook_target_list = gtk_target_list_new(
5634 addressbook_drag_types, 1);
5635 context = gtk_drag_begin(widget, addressbook_target_list,
5636 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5637 gtk_drag_set_icon_default(context);
5640 static void addressbook_drag_data_get(GtkWidget *widget,
5641 GdkDragContext *drag_context,
5642 GtkSelectionData *selection_data,
5643 guint info,
5644 guint time,
5645 void *data)
5647 AddrItemObject *aio = NULL;
5648 AddressObject *pobj = NULL;
5649 AdapterDSource *ads = NULL;
5650 AddressDataSource *ds = NULL;
5651 GList *cur;
5653 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5655 if( pobj == NULL ) return;
5657 if( pobj->type == ADDR_DATASOURCE ) {
5658 ads = ADAPTER_DSOURCE(pobj);
5659 ds = ads->dataSource;
5660 } else if (pobj->type == ADDR_ITEM_GROUP) {
5662 return;
5665 else if( pobj->type != ADDR_INTERFACE ) {
5666 ds = addressbook_find_datasource( addrbook.treeSelected );
5668 if (!ds)
5669 return;
5672 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5673 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5674 GTK_CMCTREE_NODE(cur->data));
5675 while (aio && aio->type != ITEMTYPE_PERSON) {
5676 aio = aio->parent;
5680 if (aio && aio->type == ITEMTYPE_PERSON) {
5681 if( ds && ds->interface && ds->interface->readOnly)
5682 gtk_selection_data_set(selection_data,
5683 gtk_selection_data_get_target(selection_data), 8,
5684 (const guchar *)"Dummy_addr_copy", 15);
5685 else
5686 gtk_selection_data_set(selection_data,
5687 gtk_selection_data_get_target(selection_data), 8,
5688 (const guchar *)"Dummy_addr_move", 15);
5692 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5693 GdkDragContext *context,
5694 gint x,
5695 gint y,
5696 guint time,
5697 void *data)
5699 GtkAllocation allocation;
5700 GtkRequisition requisition;
5701 gint row, column;
5702 GtkCMCTreeNode *node = NULL;
5703 gboolean acceptable = FALSE;
5704 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5705 gint height = allocation.height;
5706 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5707 gint total_height = requisition.height;
5708 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5709 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5710 gfloat vpos = gtk_adjustment_get_value(pos);
5712 if (gtk_cmclist_get_selection_info
5713 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5715 if (y > height - 24 && height + vpos < total_height) {
5716 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5717 gtk_adjustment_changed(pos);
5719 if (y < 24 && y > 0) {
5720 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5721 gtk_adjustment_changed(pos);
5723 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5725 if (node != NULL) {
5726 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5727 if( obj->type == ADDR_ITEM_FOLDER
5728 || obj->type == ADDR_ITEM_GROUP)
5729 acceptable = TRUE;
5730 else {
5731 AdapterDSource *ads = NULL;
5732 AddressDataSource *ds = NULL;
5733 ads = ADAPTER_DSOURCE(obj);
5734 if (ads == NULL ){ return FALSE;}
5735 ds = ads->dataSource;
5736 if (ds == NULL ) { return FALSE;}
5738 acceptable = TRUE;
5743 if (acceptable) {
5744 g_signal_handlers_block_by_func
5745 (G_OBJECT(widget),
5746 G_CALLBACK(addressbook_tree_selected), NULL);
5747 gtk_sctree_select( GTK_SCTREE(widget), node);
5748 g_signal_handlers_unblock_by_func
5749 (G_OBJECT(widget),
5750 G_CALLBACK(addressbook_tree_selected), NULL);
5751 gdk_drag_status(context,
5752 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5753 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5754 } else {
5755 gdk_drag_status(context, 0, time);
5757 return acceptable;
5760 static void addressbook_drag_leave_cb(GtkWidget *widget,
5761 GdkDragContext *context,
5762 guint time,
5763 void *data)
5765 if (addrbook.treeSelected) {
5766 g_signal_handlers_block_by_func
5767 (G_OBJECT(widget),
5768 G_CALLBACK(addressbook_tree_selected), NULL);
5769 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5770 g_signal_handlers_unblock_by_func
5771 (G_OBJECT(widget),
5772 G_CALLBACK(addressbook_tree_selected), NULL);
5777 static void addressbook_drag_received_cb(GtkWidget *widget,
5778 GdkDragContext *drag_context,
5779 gint x,
5780 gint y,
5781 GtkSelectionData *data,
5782 guint info,
5783 guint time,
5784 void *pdata)
5786 gint row, column;
5787 GtkCMCTreeNode *node;
5788 GtkCMCTreeNode *lastopened = addrbook.opened;
5790 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5791 if (gtk_cmclist_get_selection_info
5792 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5793 return;
5796 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5797 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5798 return;
5800 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5801 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5802 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5803 addressbook_clip_copy_cb(NULL, NULL);
5804 else
5805 addressbook_clip_cut_cb(NULL, NULL);
5806 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5807 addressbook_clip_paste_cb(NULL,NULL);
5808 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5809 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5810 gtk_drag_finish(drag_context, TRUE, TRUE, time);
5815 * End of Source.