1 /*
2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2020 the Claws Mail team and Hiroyuki Yamamoto
4 *
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.
9 *
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.
14 *
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/>.
17 *
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #include "claws-features.h"
23 #endif
24
25 #include "defs.h"
26
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>
35
36 #include "main.h"
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
42 #include "menu.h"
43 #include "stock_pixmap.h"
44 #include "xml.h"
45 #include "prefs_gtk.h"
46 #include "procmime.h"
47 #include "file-utils.h"
48 #include "utils.h"
49 #include "gtkutils.h"
50 #include "codeconv.h"
51 #include "about.h"
52 #include "addr_compl.h"
53 #include "password.h"
54
55 #include "mgutils.h"
56 #include "addressitem.h"
57 #include "addritem.h"
58 #include "addrcache.h"
59 #include "addrbook.h"
60 #include "addrindex.h"
61 #include "addrmerge.h"
62 #include "addressadd.h"
63 #include "addrduplicates.h"
64 #include "addressbook_foldersel.h"
65 #include "vcard.h"
66 #include "editvcard.h"
67 #include "editgroup.h"
68 #include "editaddress.h"
69 #include "editbook.h"
70 #include "importldif.h"
71 #include "importmutt.h"
72 #include "importpine.h"
73 #include "manual.h"
74
75 #ifdef USE_JPILOT
76 #include "jpilot.h"
77 #include "editjpilot.h"
78 #endif
79
80 #ifdef USE_LDAP
81 #include <pthread.h>
82 #include "ldapserver.h"
83 #include "editldap.h"
84 #include "ldapupdate.h"
85
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
87 #endif
88
89 #include "addrquery.h"
90 #include "addrselect.h"
91 #include "addrclip.h"
92 #include "addrgather.h"
93 #include "adbookbase.h"
94 #include "exphtmldlg.h"
95 #include "expldifdlg.h"
96 #include "browseldap.h"
97 #include "addrcustomattr.h"
98 #ifdef G_OS_WIN32
99 #undef interface
100 #endif
101 typedef enum
102 {
103 COL_SOURCES = 0,
104 N_INDEX_COLS = 1
105 } AddressIndexColumns;
106
107 typedef enum
108 {
109 COL_NAME = 0,
110 COL_ADDRESS = 1,
111 COL_REMARKS = 2,
112 N_LIST_COLS = 3
113 } AddressListColumns;
114
115 typedef struct {
116 AddressBookFile *book;
117 ItemFolder *folder;
118 } FolderInfo;
119
120 typedef struct {
121 gchar **folder_path;
122 gboolean matched;
123 gint index;
124 AddressDataSource *book;
125 ItemFolder *folder;
126 } FolderPathMatch;
127
128 static gchar *list_titles[] = { N_("Name"),
129 N_("Email Address"),
130 N_("Remarks") };
131
132 #define COL_NAME_WIDTH 164
133 #define COL_ADDRESS_WIDTH 156
134
135 #define COL_FOLDER_WIDTH 170
136 #define ADDRESSBOOK_WIDTH 640
137 #define ADDRESSBOOK_HEIGHT 360
138
139 #define ADDRESSBOOK_MSGBUF_SIZE 2048
140
141 static GdkPixbuf *folderxpm = NULL;
142 static GdkPixbuf *folderopenxpm = NULL;
143 static GdkPixbuf *groupxpm = NULL;
144 static GdkPixbuf *interfacexpm = NULL;
145 static GdkPixbuf *bookxpm = NULL;
146 static GdkPixbuf *addressxpm = NULL;
147 static GdkPixbuf *vcardxpm = NULL;
148 static GdkPixbuf *jpilotxpm = NULL;
149 static GdkPixbuf *categoryxpm = NULL;
150 static GdkPixbuf *ldapxpm = NULL;
151 static GdkPixbuf *addrsearchxpm = NULL;
152
153 /* Message buffer */
154 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
155
156 /* Address list selection */
157 static AddrSelectList *_addressSelect_ = NULL;
158 static AddressClipboard *_clipBoard_ = NULL;
159
160 /* Address index file and interfaces */
161 static AddressIndex *_addressIndex_ = NULL;
162 static GList *_addressInterfaceList_ = NULL;
163 static GList *_addressIFaceSelection_ = NULL;
164 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
165
166 static AddressBook_win addrbook;
167
168 static GHashTable *_addressBookTypeHash_ = NULL;
169 static GList *_addressBookTypeList_ = NULL;
170
171 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
172 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
173 static void addressbook_edit_address_post_cb( ItemPerson *person );
174
175 static void addressbook_create (void);
176 static gint addressbook_close (void);
177
178 static gboolean address_index_has_focus = FALSE;
179 static gboolean address_list_has_focus = FALSE;
180
181 /* callback functions */
182 static void addressbook_del_clicked (GtkButton *button,
183 gpointer data);
184 static void addressbook_reg_clicked (GtkButton *button,
185 gpointer data);
186 static void addressbook_to_clicked (GtkButton *button,
187 gpointer data);
188 static void addressbook_lup_clicked (GtkButton *button,
189 gpointer data);
190 static void addressbook_close_clicked (GtkButton *button,
191 gpointer data);
192
193 static void addressbook_tree_selected (GtkCMCTree *ctree,
194 GtkCMCTreeNode *node,
195 gint column,
196 gpointer data);
197 static void addressbook_select_row_tree (GtkCMCTree *ctree,
198 GtkCMCTreeNode *node,
199 gint column,
200 gpointer data);
201 static void addressbook_list_row_selected (GtkCMCTree *clist,
202 GtkCMCTreeNode *node,
203 gint column,
204 gpointer data);
205 static void addressbook_list_row_unselected (GtkCMCTree *clist,
206 GtkCMCTreeNode *node,
207 gint column,
208 gpointer data);
209 static void addressbook_person_expand_node (GtkCMCTree *ctree,
210 GList *node,
211 gpointer *data );
212 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
213 GList *node,
214 gpointer *data );
215
216 static void addressbook_entry_activated (GtkWidget *widget,
217 gpointer data);
218
219 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
220 GdkEventButton *event,
221 gpointer data);
222 static gboolean addressbook_list_button_released(GtkWidget *widget,
223 GdkEventButton *event,
224 gpointer data);
225 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
226 GdkEventButton *event,
227 gpointer data);
228 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
229 GdkEventButton *event,
230 gpointer data);
231
232 static void addressbook_new_folder_cb (GtkAction *action,
233 gpointer data);
234 static void addressbook_new_group_cb (GtkAction *action,
235 gpointer data);
236 static void addressbook_treenode_edit_cb (GtkAction *action,
237 gpointer data);
238 static void addressbook_treenode_delete_cb (GtkAction *action,
239 gpointer data);
240
241 static void addressbook_change_node_name (GtkCMCTreeNode *node,
242 const gchar *name);
243
244 static void addressbook_new_address_cb (GtkAction *action,
245 gpointer data);
246 static void addressbook_edit_address_cb (GtkAction *action,
247 gpointer data);
248 static void addressbook_delete_address_cb (GtkAction *action,
249 gpointer data);
250
251 static void close_cb (GtkAction *action,
252 gpointer data);
253 static void addressbook_file_save_cb (GtkAction *action,
254 gpointer data);
255
256 /* Data source edit stuff */
257 static void addressbook_new_book_cb (GtkAction *action,
258 gpointer data);
259 static void addressbook_new_vcard_cb (GtkAction *action,
260 gpointer data);
261
262 #ifdef USE_JPILOT
263 static void addressbook_new_jpilot_cb (GtkAction *action,
264 gpointer data);
265 #endif
266
267 #ifdef USE_LDAP
268 static void addressbook_new_ldap_cb (GtkAction *action,
269 gpointer data);
270 #endif
271
272 static void addressbook_set_clist (AddressObject *obj,
273 gboolean refresh);
274
275 static void addressbook_load_tree (void);
276 void addressbook_read_file (void);
277
278 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
279 AddressObject *obj);
280 static void addressbook_treenode_remove_item ( void );
281
282 static AddressDataSource *addressbook_find_datasource
283 (GtkCMCTreeNode *node );
284
285 static AddressBookFile *addressbook_get_book_file(void);
286
287 static GtkCMCTreeNode *addressbook_node_add_folder
288 (GtkCMCTreeNode *node,
289 AddressDataSource *ds,
290 ItemFolder *itemFolder,
291 AddressObjectType otype);
292 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
293 AddressDataSource *ds,
294 ItemGroup *itemGroup);
295 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
296 GtkCMCTreeNode *parent);
297 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
298 GtkCMCTreeNode *node);
299 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
300 ItemGroup *group);
301 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
302 GdkEventKey *event,
303 gpointer data);
304 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
305 gconstpointer ptr1,
306 gconstpointer ptr2);
307 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
308 ItemPerson *person,
309 AddressTypeControlItem *atci,
310 AddressTypeControlItem *atciMail);
311 static void addressbook_folder_remove_node (GtkCMCTree *clist,
312 GtkCMCTreeNode *node);
313
314 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
315 gboolean force_focus );
316
317 /* LUT's and IF stuff */
318 static void addressbook_free_treenode ( gpointer data );
319 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
320 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
321
322 static void addrbookctl_build_map (GtkWidget *window);
323 static void addrbookctl_build_iflist (void);
324 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
325 static void addrbookctl_build_ifselect (void);
326
327 static void addrbookctl_free_interface (AdapterInterface *adapter);
328 static void addrbookctl_free_datasource (AdapterDSource *adapter);
329 static void addrbookctl_free_folder (AdapterFolder *adapter);
330 static void addrbookctl_free_group (AdapterGroup *adapter);
331
332 static void addressbook_list_select_clear ( void );
333 static void addressbook_list_select_add ( AddrItemObject *aio,
334 AddressDataSource *ds );
335 static void addressbook_list_select_remove ( AddrItemObject *aio );
336
337 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
338 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
339 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
340 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
342 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
344 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
351
352 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
353 static void addressbook_merge_cb ( GtkAction *action, gpointer data );
354
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);
359
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 );
388
389 static GtkTargetEntry addressbook_drag_types[] =
390 {
391 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
392 };
393
394 static GtkTargetList *addressbook_target_list = NULL;
395
about_show_cb(GtkAction * action,gpointer data)396 static void about_show_cb(GtkAction *action, gpointer data)
397 {
398 about_show();
399 }
400
401 static GtkActionEntry addressbook_entries[] =
402 {
403 {"Menu", NULL, "Menu", NULL, NULL, NULL },
404 /* menus */
405 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
406 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
407 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
408
409 /* Book menu */
410 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
411 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
412 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
413
414
415 #ifdef USE_JPILOT
416 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
417 #endif
418 #ifdef USE_LDAP
419 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
420 #endif
421 {"Book/---", NULL, "---", NULL, NULL, NULL },
422
423 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
424 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
425 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
426 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
427 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
428
429 /* Adress menu */
430 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
431 {"Address/---", NULL, "---", NULL, NULL, NULL },
432 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
433 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
434 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
435 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
436 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
437 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
438 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
439 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
440 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
441 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
442 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
443 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
444
445
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) },
456 };
457
458 static GtkActionEntry addressbook_tree_popup_entries[] =
459 {
460 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
461 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
462 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
463 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
464 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
465 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
466 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
467 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
468 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
469 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
470 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
471 };
472
473 static GtkActionEntry addressbook_list_popup_entries[] =
474 {
475 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
476 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
477 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
478 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
479 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
480 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
481 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
482 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
483 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
484 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
485 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
486 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
489 #ifdef USE_LDAP
490 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
491 #endif
492 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
493 };
494
495 /**
496 * Structure of error message table.
497 */
498 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
499 struct _ErrMsgTableEntry {
500 gint code;
501 gchar *description;
502 };
503
504 static gchar *_errMsgUnknown_ = N_( "Unknown" );
505
506 /**
507 * Lookup table of error messages for general errors. Note that a NULL
508 * description signifies the end of the table.
509 */
510 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
511 { MGU_SUCCESS, N_("Success") },
512 { MGU_BAD_ARGS, N_("Bad arguments") },
513 { MGU_NO_FILE, N_("File not specified") },
514 { MGU_OPEN_FILE, N_("Error opening file") },
515 { MGU_ERROR_READ, N_("Error reading file") },
516 { MGU_EOF, N_("End of file encountered") },
517 { MGU_OO_MEMORY, N_("Error allocating memory") },
518 { MGU_BAD_FORMAT, N_("Bad file format") },
519 { MGU_ERROR_WRITE, N_("Error writing to file") },
520 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
521 { MGU_NO_PATH, N_("No path specified") },
522 { 0, NULL }
523 };
524
525 #ifdef USE_LDAP
526 /**
527 * Lookup table of error messages for LDAP errors.
528 */
529 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
530 { LDAPRC_SUCCESS, N_("Success") },
531 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
532 { LDAPRC_INIT, N_("Error initializing LDAP") },
533 { LDAPRC_BIND, N_("Error binding to LDAP server") },
534 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
535 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
536 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
537 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
538 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
539 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
540 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
541 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
542 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
543 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
544 { 0, NULL }
545 };
546 #endif
547
548 /**
549 * Lookup message for specified error code.
550 * \param lut Lookup table.
551 * \param code Code to lookup.
552 * \return Description associated to code.
553 */
addressbook_err2string(ErrMsgTableEntry lut[],gint code)554 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
555 gchar *desc = NULL;
556 ErrMsgTableEntry entry;
557 gint i;
558
559 for( i = 0; ; i++ ) {
560 entry = lut[ i ];
561 if( entry.description == NULL ) break;
562 if( entry.code == code ) {
563 desc = entry.description;
564 break;
565 }
566 }
567 if( ! desc ) {
568 desc = _errMsgUnknown_;
569 }
570 return desc;
571 }
572
573 static gboolean lastCanLookup = FALSE;
574
addressbook_show_buttons(gboolean add_and_delete,gboolean lookup,gboolean mail_ops)575 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
576 {
577 if (add_and_delete) {
578 gtk_widget_show(addrbook.edit_btn);
579 gtk_widget_show(addrbook.del_btn);
580 gtk_widget_show(addrbook.reg_btn);
581 } else {
582 gtk_widget_hide(addrbook.edit_btn);
583 gtk_widget_hide(addrbook.del_btn);
584 gtk_widget_hide(addrbook.reg_btn);
585 }
586
587 if (lookup) {
588 gtk_widget_show(addrbook.lup_btn);
589 gtk_widget_show(addrbook.entry);
590 gtk_widget_show(addrbook.label);
591 } else {
592 gtk_widget_hide(addrbook.lup_btn);
593 gtk_widget_hide(addrbook.entry);
594 gtk_widget_hide(addrbook.label);
595 }
596
597 lastCanLookup = lookup;
598
599 if (mail_ops) {
600 gtk_widget_show(addrbook.to_btn);
601 gtk_widget_show(addrbook.cc_btn);
602 gtk_widget_show(addrbook.bcc_btn);
603 } else {
604 gtk_widget_hide(addrbook.to_btn);
605 gtk_widget_hide(addrbook.cc_btn);
606 gtk_widget_hide(addrbook.bcc_btn);
607 }
608 }
609
addressbook_open(Compose * target)610 void addressbook_open(Compose *target)
611 {
612 /* Initialize all static members */
613 if( _clipBoard_ == NULL ) {
614 _clipBoard_ = addrclip_create();
615 }
616 if( _addressIndex_ != NULL ) {
617 addrclip_set_index( _clipBoard_, _addressIndex_ );
618 }
619 if( _addressSelect_ == NULL ) {
620 _addressSelect_ = addrselect_list_create();
621 }
622 if (!addrbook.window) {
623 addressbook_read_file();
624 addressbook_create();
625 addressbook_load_tree();
626 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
627 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
628 }
629 else {
630 gtk_widget_hide(addrbook.window);
631 }
632
633 gtk_widget_show_all(addrbook.window);
634
635 if (!prefs_common.addressbook_use_editaddress_dialog)
636 addressbook_edit_person_widgetset_hide();
637
638 address_completion_start(addrbook.window);
639
640 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
641 addressbook_set_target_compose(target);
642 }
643
644 /**
645 * Destroy addressbook.
646 */
addressbook_destroy(void)647 void addressbook_destroy( void ) {
648 /* Free up address stuff */
649 if( _addressSelect_ != NULL ) {
650 addrselect_list_free( _addressSelect_ );
651 }
652 if( _clipBoard_ != NULL ) {
653 addrclip_free( _clipBoard_ );
654 _clipBoard_ = NULL;
655 }
656 if( _addressIndex_ != NULL ) {
657 addrindex_free_index( _addressIndex_ );
658 addrindex_teardown();
659 }
660 _addressSelect_ = NULL;
661 _clipBoard_ = NULL;
662 _addressIndex_ = NULL;
663 }
664
addressbook_set_target_compose(Compose * target)665 void addressbook_set_target_compose(Compose *target)
666 {
667 addrbook.target_compose = target;
668 }
669
addressbook_get_target_compose(void)670 Compose *addressbook_get_target_compose(void)
671 {
672 return addrbook.target_compose;
673 }
674
675 /**
676 * Refresh addressbook and save to file(s).
677 */
addressbook_refresh(void)678 void addressbook_refresh( void )
679 {
680 if (addrbook.window) {
681 if (addrbook.treeSelected) {
682 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
683 addrbook.treeSelected);
684 addressbook_set_clist(
685 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
686 addrbook.treeSelected),
687 TRUE);
688
689 }
690 }
691 addressbook_export_to_file();
692 }
693
key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer data)694 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
695 {
696 if (event && event->keyval == GDK_KEY_Escape)
697 addressbook_close();
698 else if (event && event->keyval == GDK_KEY_Delete) {
699 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
700 if ( /* address_index_has_focus || */ address_list_has_focus )
701 addressbook_del_clicked(NULL, NULL);
702 }
703 return FALSE;
704 }
705
706 /*!
707 *\brief Save Gtk object size to prefs dataset
708 */
addressbook_size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation)709 static void addressbook_size_allocate_cb(GtkWidget *widget,
710 GtkAllocation *allocation)
711 {
712 cm_return_if_fail(allocation != NULL);
713
714 prefs_common.addressbookwin_width = allocation->width;
715 prefs_common.addressbookwin_height = allocation->height;
716 }
717
718 static gint sort_column_number = 0;
719 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
720
list_case_sort(GtkCMCList * clist,gconstpointer ptr1,gconstpointer ptr2)721 static gint list_case_sort(
722 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
723 {
724 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
725 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
726 gchar *name1 = NULL, *name2 = NULL;
727 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
728 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
729
730 if( aio1->type == aio2->type ) {
731 if( row1 )
732 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
733 if( row2 )
734 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
735 if( ! name1 ) return ( name2 != NULL );
736 if( ! name2 ) return -1;
737 return g_utf8_collate( name1, name2 );
738 } else {
739 /* Order groups before person */
740 if( aio1->type == ITEMTYPE_GROUP ) {
741 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
742 } else if( aio2->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
744 }
745 return 0;
746 }
747 }
748
addressbook_sort_list(GtkCMCList * clist,const gint col,const GtkSortType sort_type)749 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
750 const GtkSortType sort_type)
751 {
752 gint pos;
753 GtkWidget *hbox, *label, *arrow;
754
755 sort_column_number = col;
756 sort_column_type = sort_type;
757 gtk_cmclist_set_compare_func(clist, list_case_sort);
758 gtk_cmclist_set_sort_type(clist, sort_type);
759 gtk_cmclist_set_sort_column(clist, col);
760
761 gtk_cmclist_freeze(clist);
762 gtk_cmclist_sort(clist);
763
764 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
765 hbox = gtk_hbox_new(FALSE, 4);
766 label = gtk_label_new(gettext(list_titles[pos]));
767 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
768
769 if(pos == col) {
770 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
771 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
772 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
773 }
774
775 gtk_widget_show_all(hbox);
776 gtk_cmclist_set_column_widget(clist, pos, hbox);
777 }
778
779 gtk_cmclist_thaw(clist);
780 }
781
addressbook_name_clicked(GtkWidget * button,GtkCMCList * clist)782 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
783 {
784 static GtkSortType sort_type = GTK_SORT_ASCENDING;
785
786 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
787 GTK_SORT_ASCENDING;
788 addressbook_sort_list(clist, COL_NAME, sort_type);
789 }
790
addressbook_address_clicked(GtkWidget * button,GtkCMCList * clist)791 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
792 {
793 static GtkSortType sort_type = GTK_SORT_ASCENDING;
794
795 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
796 GTK_SORT_ASCENDING;
797 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
798 }
799
addressbook_remarks_clicked(GtkWidget * button,GtkCMCList * clist)800 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
801 {
802 static GtkSortType sort_type = GTK_SORT_ASCENDING;
803
804 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
805 GTK_SORT_ASCENDING;
806 addressbook_sort_list(clist, COL_REMARKS, sort_type);
807 }
808
addressbook_address_index_focus_evt_in(GtkWidget * widget,GdkEventFocus * event,gpointer data)809 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
810 gpointer data)
811 {
812 address_index_has_focus = TRUE;
813 return FALSE;
814 }
815
addressbook_address_index_focus_evt_out(GtkWidget * widget,GdkEventFocus * event,gpointer data)816 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
817 gpointer data)
818 {
819 address_index_has_focus = FALSE;
820 if (!prefs_common.addressbook_use_editaddress_dialog
821 && !address_list_has_focus)
822 addressbook_address_list_disable_some_actions();
823 return FALSE;
824 }
825
addressbook_address_list_focus_evt_in(GtkWidget * widget,GdkEventFocus * event,gpointer data)826 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
827 gpointer data)
828 {
829 address_list_has_focus = TRUE;
830 return FALSE;
831 }
832
addressbook_address_list_focus_evt_out(GtkWidget * widget,GdkEventFocus * event,gpointer data)833 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
834 gpointer data)
835 {
836 address_list_has_focus = FALSE;
837 if (!prefs_common.addressbook_use_editaddress_dialog
838 && !address_index_has_focus)
839 addressbook_address_list_disable_some_actions();
840 return FALSE;
841 }
842
843 /* save hpane and vpane's handle position when it moves */
addressbook_pane_save_position(void)844 static void addressbook_pane_save_position(void)
845 {
846 if (addrbook.hpaned)
847 prefs_common.addressbook_hpaned_pos =
848 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
849 if (addrbook.vpaned)
850 prefs_common.addressbook_vpaned_pos =
851 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
852 }
853
854 /*
855 * Create the address book widgets. The address book contains two CTree widgets: the
856 * address index tree on the left and the address list on the right.
857 *
858 * The address index tree displays a hierarchy of interfaces and groups. Each node in
859 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
860 * data sources and folder objects.
861 *
862 * The address list displays group, person and email objects. These items are linked
863 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
864 * sources.
865 *
866 * In the tradition of MVC architecture, the data stores have been separated from the
867 * GUI components. The addrindex.c file provides the interface to all data stores.
868 */
addressbook_create(void)869 static void addressbook_create(void)
870 {
871 GtkWidget *window;
872 GtkWidget *vbox;
873 GtkWidget *menubar;
874 GtkWidget *vbox2;
875 GtkWidget *ctree_swin;
876 GtkWidget *ctree;
877 GtkWidget *editaddress_vbox;
878 GtkWidget *clist_vbox;
879 GtkWidget *clist_swin;
880 GtkWidget *clist;
881 GtkWidget *hpaned;
882 GtkWidget *vpaned;
883 GtkWidget *hbox;
884 GtkWidget *label;
885 GtkWidget *entry;
886 GtkWidget *statusbar;
887 GtkWidget *hbbox;
888 GtkWidget *hsbox;
889 GtkWidget *help_btn;
890 GtkWidget *del_btn;
891 GtkWidget *edit_btn;
892 GtkWidget *reg_btn;
893 GtkWidget *lup_btn;
894 GtkWidget *to_btn;
895 GtkWidget *cc_btn;
896 GtkWidget *bcc_btn;
897 GtkWidget *close_btn;
898 GtkWidget *tree_popup;
899 GtkWidget *list_popup;
900 GList *nodeIf;
901 GtkUIManager *ui_manager;
902 GtkActionGroup *action_group;
903 gchar *index_titles[N_INDEX_COLS];
904 gchar *text;
905 gint i;
906
907 static GdkGeometry geometry;
908
909 debug_print("Creating addressbook window...\n");
910
911 index_titles[COL_SOURCES] = _("Sources");
912
913 /* Address book window */
914 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
915 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
916 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
917 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
918 gtk_widget_realize(window);
919
920 g_signal_connect(G_OBJECT(window), "delete_event",
921 G_CALLBACK(addressbook_close), NULL);
922 g_signal_connect(G_OBJECT(window), "size_allocate",
923 G_CALLBACK(addressbook_size_allocate_cb), NULL);
924 g_signal_connect(G_OBJECT(window), "key_press_event",
925 G_CALLBACK(key_pressed), NULL);
926 MANAGE_WINDOW_SIGNALS_CONNECT(window);
927
928 vbox = gtk_vbox_new(FALSE, 0);
929 gtk_container_add(GTK_CONTAINER(window), vbox);
930
931 /* Menu bar */
932 ui_manager = gtk_ui_manager_new();
933 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
934 G_N_ELEMENTS(addressbook_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
936 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
937 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
938 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
939
940 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
941
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
945
946 /* Book menu */
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
950 #ifdef USE_JPILOT
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
952 #endif
953 #ifdef USE_LDAP
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
955 #endif
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
962
963 /* Address menu */
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
978
979 /* Tools menu */
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
989
990 gtk_window_add_accel_group(GTK_WINDOW(window),
991 gtk_ui_manager_get_accel_group(ui_manager));
992
993 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
994
995 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
996
997 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
998 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
999 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1000
1001 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1002 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1003 GTK_POLICY_AUTOMATIC,
1004 GTK_POLICY_AUTOMATIC);
1005 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1006
1007 /* Address index */
1008 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1009 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1010
1011 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1012 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1013 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1014 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1015 GTK_CMCTREE_EXPANDER_TRIANGLE);
1016 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1017 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1018 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1019 addressbook_treenode_compare_func);
1020
1021 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1022 G_CALLBACK(addressbook_tree_selected), NULL);
1023 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1024 G_CALLBACK(addressbook_tree_button_pressed),
1025 NULL);
1026 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1027 G_CALLBACK(addressbook_tree_button_released),
1028 NULL);
1029 /* TEMPORARY */
1030 g_signal_connect(G_OBJECT(ctree), "select_row",
1031 G_CALLBACK(addressbook_select_row_tree), NULL);
1032
1033 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1034 addressbook_drag_types, 1,
1035 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1036 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1037 G_CALLBACK(addressbook_drag_motion_cb),
1038 ctree);
1039 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1040 G_CALLBACK(addressbook_drag_leave_cb),
1041 ctree);
1042 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1043 G_CALLBACK(addressbook_drag_received_cb),
1044 ctree);
1045 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1046 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1047 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1048 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1049
1050 clist_vbox = gtk_vbox_new(FALSE, 4);
1051
1052 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1053 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1054 GTK_POLICY_AUTOMATIC,
1055 GTK_POLICY_AUTOMATIC);
1056 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1057
1058 /* Address list */
1059 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1060 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1061 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1062 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1063 GTK_CMCTREE_EXPANDER_TRIANGLE);
1064 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1065 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1066 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1067 COL_NAME_WIDTH);
1068 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1069 COL_ADDRESS_WIDTH);
1070 gtk_widget_set_size_request(clist, -1, 80);
1071
1072 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1073 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1074 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1075 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1076 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1077 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1078 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1079 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1080 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1081 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1082 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1083
1084 for (i = 0; i < N_LIST_COLS; i++)
1085 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1086 FALSE);
1087
1088 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1089 G_CALLBACK(addressbook_list_row_selected), NULL);
1090 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1091 G_CALLBACK(addressbook_list_row_unselected), NULL);
1092 g_signal_connect(G_OBJECT(clist), "button_press_event",
1093 G_CALLBACK(addressbook_list_button_pressed),
1094 NULL);
1095 g_signal_connect(G_OBJECT(clist), "button_release_event",
1096 G_CALLBACK(addressbook_list_button_released),
1097 NULL);
1098 g_signal_connect(G_OBJECT(clist), "tree_expand",
1099 G_CALLBACK(addressbook_person_expand_node), NULL );
1100 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1101 G_CALLBACK(addressbook_person_collapse_node), NULL );
1102 g_signal_connect(G_OBJECT(clist), "start_drag",
1103 G_CALLBACK(addressbook_start_drag), NULL);
1104 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1105 G_CALLBACK(addressbook_drag_data_get), NULL);
1106 hbox = gtk_hbox_new(FALSE, 4);
1107 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1108
1109 label = gtk_label_new(_("Search"));
1110 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1111
1112 entry = gtk_entry_new();
1113 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1114
1115 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1116
1117 g_signal_connect(G_OBJECT(entry), "key_press_event",
1118 G_CALLBACK(addressbook_entry_key_pressed),
1119 NULL);
1120 g_signal_connect(G_OBJECT(entry), "activate",
1121 G_CALLBACK(addressbook_entry_activated), NULL);
1122
1123 if (!prefs_common.addressbook_use_editaddress_dialog) {
1124 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1125 vpaned = gtk_vpaned_new();
1126 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1127 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1128 } else {
1129 vpaned = NULL;
1130 editaddress_vbox = NULL;
1131 }
1132 hpaned = gtk_hpaned_new();
1133 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1134 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1135 if (prefs_common.addressbook_use_editaddress_dialog)
1136 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1137 else
1138 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1139
1140 /* Status bar */
1141 hsbox = gtk_hbox_new(FALSE, 0);
1142 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1143 statusbar = gtk_statusbar_new();
1144 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1145
1146 /* Button panel */
1147 hbbox = gtk_hbutton_box_new();
1148 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1149 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1150 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1151 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1152
1153 gtkut_stock_button_add_help(hbbox, &help_btn);
1154
1155 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1156 gtk_widget_set_can_default(edit_btn, TRUE);
1157 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1158 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1159 gtk_widget_set_can_default(del_btn, TRUE);
1160 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1161 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1162 gtk_widget_set_can_default(reg_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1164
1165
1166 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1167 gtk_widget_set_can_default(lup_btn, TRUE);
1168 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1169
1170 g_signal_connect(G_OBJECT(help_btn), "clicked",
1171 G_CALLBACK(manual_open_with_anchor_cb),
1172 MANUAL_ANCHOR_ADDRBOOK);
1173
1174 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1175 G_CALLBACK(addressbook_edit_clicked), NULL);
1176 g_signal_connect(G_OBJECT(del_btn), "clicked",
1177 G_CALLBACK(addressbook_del_clicked), NULL);
1178 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1179 G_CALLBACK(addressbook_reg_clicked), NULL);
1180 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1181 G_CALLBACK(addressbook_lup_clicked), NULL);
1182
1183 to_btn = gtk_button_new_with_label
1184 (prefs_common_translated_header_name("To:"));
1185 gtk_widget_set_can_default(to_btn, TRUE);
1186 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1187 cc_btn = gtk_button_new_with_label
1188 (prefs_common_translated_header_name("Cc:"));
1189 gtk_widget_set_can_default(cc_btn, TRUE);
1190 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1191 bcc_btn = gtk_button_new_with_label
1192 (prefs_common_translated_header_name("Bcc:"));
1193 gtk_widget_set_can_default(bcc_btn, TRUE);
1194 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1195
1196 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1197 gtk_widget_set_can_default(close_btn, TRUE);
1198 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1199
1200 g_signal_connect(G_OBJECT(to_btn), "clicked",
1201 G_CALLBACK(addressbook_to_clicked),
1202 GINT_TO_POINTER(COMPOSE_TO));
1203 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1204 G_CALLBACK(addressbook_to_clicked),
1205 GINT_TO_POINTER(COMPOSE_CC));
1206 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1207 G_CALLBACK(addressbook_to_clicked),
1208 GINT_TO_POINTER(COMPOSE_BCC));
1209 g_signal_connect(G_OBJECT(close_btn), "clicked",
1210 G_CALLBACK(addressbook_close_clicked), NULL);
1211
1212 /* Build icons for interface */
1213
1214 /* Build control tables */
1215 addrbookctl_build_map(window);
1216 addrbookctl_build_iflist();
1217 addrbookctl_build_ifselect();
1218
1219 addrbook.clist = NULL;
1220
1221 /* Add each interface into the tree as a root level folder */
1222 nodeIf = _addressInterfaceList_;
1223 while( nodeIf ) {
1224 AdapterInterface *adapter = nodeIf->data;
1225 AddressInterface *iface = adapter->interface;
1226 nodeIf = g_list_next(nodeIf);
1227
1228 if(iface->useInterface) {
1229 AddressTypeControlItem *atci = adapter->atci;
1230 text = atci->displayName;
1231 adapter->treeNode =
1232 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1233 NULL, NULL, &text, FOLDER_SPACING,
1234 interfacexpm,
1235 interfacexpm,
1236 FALSE, FALSE );
1237 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1238 gtk_cmctree_node_set_row_data_full(
1239 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1240 addressbook_free_treenode );
1241 }
1242 }
1243
1244 /* Popup menu */
1245
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1258
1259 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1260 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1261
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1276 #ifdef USE_LDAP
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1278 #endif
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1280 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1281 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1282
1283 addrbook.window = window;
1284 addrbook.hpaned = hpaned;
1285 addrbook.vpaned = vpaned;
1286 addrbook.menubar = menubar;
1287 addrbook.ctree = ctree;
1288 addrbook.ctree_swin
1289 = ctree_swin;
1290 addrbook.editaddress_vbox = editaddress_vbox;
1291 addrbook.clist = clist;
1292 addrbook.label = label;
1293 addrbook.entry = entry;
1294 addrbook.statusbar = statusbar;
1295 addrbook.status_cid = gtk_statusbar_get_context_id(
1296 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1297
1298 addrbook.help_btn = help_btn;
1299 addrbook.edit_btn = edit_btn;
1300 addrbook.del_btn = del_btn;
1301 addrbook.reg_btn = reg_btn;
1302 addrbook.lup_btn = lup_btn;
1303 addrbook.to_btn = to_btn;
1304 addrbook.cc_btn = cc_btn;
1305 addrbook.bcc_btn = bcc_btn;
1306
1307 addrbook.tree_popup = tree_popup;
1308 addrbook.list_popup = list_popup;
1309 addrbook.ui_manager = ui_manager;
1310
1311 addrbook.listSelected = NULL;
1312
1313 if (!geometry.min_height) {
1314 geometry.min_width = ADDRESSBOOK_WIDTH;
1315 geometry.min_height = ADDRESSBOOK_HEIGHT;
1316 }
1317
1318 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1319 GDK_HINT_MIN_SIZE);
1320 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1321 prefs_common.addressbookwin_height);
1322 #ifdef G_OS_WIN32
1323 gtk_window_move(GTK_WINDOW(window), 48, 48);
1324 #endif
1325
1326 if (!prefs_common.addressbook_use_editaddress_dialog) {
1327 if (prefs_common.addressbook_vpaned_pos > 0)
1328 gtk_paned_set_position(GTK_PANED(vpaned),
1329 prefs_common.addressbook_vpaned_pos);
1330 }
1331 if (prefs_common.addressbook_hpaned_pos > 0)
1332 gtk_paned_set_position(GTK_PANED(hpaned),
1333 prefs_common.addressbook_hpaned_pos);
1334
1335
1336 gtk_widget_show_all(window);
1337 }
1338
1339 /**
1340 * Close address book window and save to file(s).
1341 */
addressbook_close(void)1342 static gint addressbook_close( void ) {
1343 address_completion_end(addrbook.window);
1344 if (!prefs_common.addressbook_use_editaddress_dialog)
1345 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1346
1347 addressbook_pane_save_position();
1348
1349 gtk_widget_hide(addrbook.window);
1350 addressbook_export_to_file();
1351 return TRUE;
1352 }
1353
1354 /**
1355 * Display message in status line.
1356 * \param msg Message to display.
1357 */
addressbook_status_show(gchar * msg)1358 static void addressbook_status_show( gchar *msg ) {
1359 if( addrbook.statusbar != NULL ) {
1360 gtk_statusbar_pop(
1361 GTK_STATUSBAR(addrbook.statusbar),
1362 addrbook.status_cid );
1363 if( msg ) {
1364 gtk_statusbar_push(
1365 GTK_STATUSBAR(addrbook.statusbar),
1366 addrbook.status_cid, msg );
1367 }
1368 }
1369 }
1370
addressbook_ds_show_message(AddressDataSource * ds)1371 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1372 gint retVal;
1373 gchar *name;
1374 gchar *desc;
1375 *addressbook_msgbuf = '\0';
1376 if( ds ) {
1377 name = addrindex_ds_get_name( ds );
1378 retVal = addrindex_ds_get_status_code( ds );
1379 if( retVal == MGU_SUCCESS ) {
1380 g_snprintf( addressbook_msgbuf,
1381 sizeof(addressbook_msgbuf), "%s", name );
1382 }
1383 else {
1384 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1385 g_snprintf( addressbook_msgbuf,
1386 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1387 }
1388 }
1389 addressbook_status_show( addressbook_msgbuf );
1390 }
1391
addressbook_edit_clicked(GtkButton * button,gpointer data)1392 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1393 {
1394 addressbook_edit_address_cb(NULL, NULL);
1395 }
1396
find_person(AddrSelectItem * item_a,ItemPerson * person)1397 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1398 {
1399 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1400 }
1401
1402 /*
1403 * Delete one or more objects from address list.
1404 */
addressbook_del_clicked(GtkButton * button,gpointer data)1405 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1406 {
1407 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1408 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1409 AddressObject *pobj;
1410 AdapterDSource *ads = NULL;
1411 GtkCMCTreeNode *nodeList;
1412 gboolean procFlag;
1413 AlertValue aval;
1414 AddressBookFile *abf = NULL;
1415 AddressDataSource *ds = NULL;
1416 AddressInterface *iface;
1417 AddrItemObject *aio;
1418 AddrSelectItem *item;
1419 GList *list, *node;
1420 gboolean refreshList = FALSE;
1421
1422 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1423 cm_return_if_fail(pobj != NULL);
1424
1425 /* Test whether anything selected for deletion */
1426 nodeList = addrbook.listSelected;
1427
1428 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1429 if( aio == NULL) return;
1430 ds = addressbook_find_datasource( addrbook.treeSelected );
1431 if( ds == NULL ) return;
1432
1433 /* Test for read only */
1434 iface = ds->interface;
1435 if( iface->readOnly ) {
1436 alertpanel( _("Delete address(es)"),
1437 _("This address data is readonly and cannot be deleted."),
1438 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1439 return;
1440 }
1441
1442 /* Test whether Ok to proceed */
1443 procFlag = FALSE;
1444 if( pobj->type == ADDR_DATASOURCE ) {
1445 ads = ADAPTER_DSOURCE(pobj);
1446 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1447 }
1448 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1449 procFlag = TRUE;
1450 }
1451 else if( pobj->type == ADDR_ITEM_GROUP ) {
1452 procFlag = TRUE;
1453 }
1454 if( ! procFlag ) return;
1455 abf = ds->rawDataSource;
1456 if( abf == NULL ) return;
1457
1458 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1459 g_signal_handlers_block_by_func
1460 (G_OBJECT(addrbook.clist),
1461 G_CALLBACK(addressbook_list_row_unselected), NULL);
1462
1463 /* Process deletions */
1464 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1465 GList *groups = NULL, *persons = NULL, *emails = NULL;
1466 gboolean group_delete = TRUE;
1467 /* Items inside folders */
1468 list = addrselect_get_list( _addressSelect_ );
1469 /* Confirm deletion */
1470 node = list;
1471 while( node ) {
1472 item = node->data;
1473 node = g_list_next( node );
1474 aio = ( AddrItemObject * ) item->addressItem;
1475 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1476 group_delete = FALSE;
1477 break;
1478 }
1479 }
1480 if (group_delete) {
1481 aval = alertpanel( _("Delete group"),
1482 _("Really delete the group(s)?\n"
1483 "The addresses it contains will not be lost."),
1484 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1485 if( aval != G_ALERTALTERNATE ) {
1486 goto thaw_ret;
1487 }
1488 } else {
1489 aval = alertpanel( _("Delete address(es)"),
1490 _("Really delete the address(es)?"),
1491 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1492 if( aval != G_ALERTALTERNATE ) {
1493 goto thaw_ret;
1494 }
1495 }
1496
1497 /* first, set lists of groups and persons to remove */
1498 node = list;
1499 while( node ) {
1500 item = node->data;
1501 node = g_list_next( node );
1502 aio = ( AddrItemObject * ) item->addressItem;
1503 if (!aio)
1504 continue;
1505 if( aio->type == ITEMTYPE_GROUP ) {
1506 groups = g_list_prepend(groups, item);
1507 }
1508 else if( aio->type == ITEMTYPE_PERSON ) {
1509 persons = g_list_prepend(persons, item);
1510 }
1511 }
1512 /* then set list of emails to remove *if* they're not children of
1513 * persons to remove */
1514 node = list;
1515 while( node ) {
1516 item = node->data;
1517 node = g_list_next( node );
1518 aio = ( AddrItemObject * ) item->addressItem;
1519 if (!aio)
1520 continue;
1521 if( aio->type == ITEMTYPE_EMAIL ) {
1522 ItemEMail *sitem = ( ItemEMail * ) aio;
1523 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1524 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1525 emails = g_list_prepend(emails, item);
1526 }
1527 /* else, the email will be removed via the parent person */
1528 }
1529 }
1530 /* then delete groups */
1531 node = groups;
1532 while( node ) {
1533 item = node->data;
1534 node = g_list_next( node );
1535 aio = ( AddrItemObject * ) item->addressItem;
1536 if (!aio)
1537 continue;
1538 if( aio->type == ITEMTYPE_GROUP ) {
1539 ItemGroup *item = ( ItemGroup * ) aio;
1540 GtkCMCTreeNode *nd = NULL;
1541 nd = addressbook_find_group_node( addrbook.opened, item );
1542 item = addrbook_remove_group( abf, item );
1543 if( item ) {
1544 addritem_free_item_group( item );
1545 }
1546 /* Remove group from parent node */
1547 gtk_cmctree_remove_node( ctree, nd );
1548 refreshList = TRUE;
1549 }
1550 }
1551 /* then delete persons */
1552 node = persons;
1553 while( node ) {
1554 item = node->data;
1555 node = g_list_next( node );
1556 aio = ( AddrItemObject * ) item->addressItem;
1557 if (!aio)
1558 continue;
1559 if( aio->type == ITEMTYPE_PERSON ) {
1560 ItemPerson *item = ( ItemPerson * ) aio;
1561 item->status = DELETE_ENTRY;
1562 addressbook_folder_remove_one_person( clist, item );
1563 if (pobj->type == ADDR_ITEM_FOLDER)
1564 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1565 item = addrbook_remove_person( abf, item );
1566 #ifdef USE_LDAP
1567 if (ds && ds->type == ADDR_IF_LDAP) {
1568 LdapServer *server = ds->rawDataSource;
1569 ldapsvr_set_modified(server, TRUE);
1570 ldapsvr_update_book(server, item);
1571 }
1572 #endif
1573 if( item ) {
1574 addritem_person_remove_picture(item);
1575 addritem_free_item_person( item );
1576 }
1577 }
1578 }
1579 /* then delete emails */
1580 node = emails;
1581 while( node ) {
1582 item = node->data;
1583 node = g_list_next( node );
1584 aio = ( AddrItemObject * ) item->addressItem;
1585 if (!aio)
1586 continue;
1587
1588 if( aio->type == ITEMTYPE_EMAIL ) {
1589 ItemEMail *sitem = ( ItemEMail * ) aio;
1590 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1591 sitem = addrbook_person_remove_email( abf, person, sitem );
1592 if( sitem ) {
1593 addrcache_remove_email(abf->addressCache, sitem);
1594 addritem_free_item_email( sitem );
1595 }
1596 addressbook_folder_refresh_one_person( clist, person );
1597 }
1598 }
1599 g_list_free( groups );
1600 g_list_free( persons );
1601 g_list_free( emails );
1602 g_list_free( list );
1603 addressbook_list_select_clear();
1604 if( refreshList ) {
1605 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1606 addressbook_set_clist(
1607 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1608 addrbook.opened),
1609 TRUE);
1610 }
1611 addrbook_set_dirty(abf, TRUE);
1612 addressbook_export_to_file();
1613 addressbook_list_menu_setup();
1614 goto thaw_ret;
1615 }
1616 else if( pobj->type == ADDR_ITEM_GROUP ) {
1617 /* Items inside groups */
1618 list = addrselect_get_list( _addressSelect_ );
1619 node = list;
1620 while( node ) {
1621 item = node->data;
1622 node = g_list_next( node );
1623 aio = ( AddrItemObject * ) item->addressItem;
1624 if( aio->type == ITEMTYPE_EMAIL ) {
1625 ItemEMail *item = ( ItemEMail * ) aio;
1626 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1627 item = addrbook_person_remove_email( abf, person, item );
1628 if( item ) {
1629 addritem_free_item_email( item );
1630 }
1631 }
1632 }
1633 g_list_free( list );
1634 addressbook_list_select_clear();
1635 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1636 addressbook_set_clist(
1637 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1638 addrbook.opened),
1639 TRUE);
1640
1641 addrbook_set_dirty(abf, TRUE);
1642 addressbook_export_to_file();
1643 addressbook_list_menu_setup();
1644 goto thaw_ret;
1645 }
1646
1647 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1648 gtk_cmctree_remove_node( clist, nodeList );
1649 thaw_ret:
1650 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1651 g_signal_handlers_unblock_by_func
1652 (G_OBJECT(addrbook.clist),
1653 G_CALLBACK(addressbook_list_row_unselected), NULL);
1654 }
1655
addressbook_reg_clicked(GtkButton * button,gpointer data)1656 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1657 {
1658 addressbook_new_address_cb( NULL, NULL );
1659 }
1660
addressbook_format_address(AddrItemObject * aio)1661 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1662 gchar *buf = NULL;
1663 gchar *name = NULL;
1664 gchar *address = NULL;
1665
1666 if( aio->type == ITEMTYPE_EMAIL ) {
1667 ItemPerson *person = NULL;
1668 ItemEMail *email = ( ItemEMail * ) aio;
1669
1670 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1671 if( email->address ) {
1672 if( ADDRITEM_NAME(email) ) {
1673 name = ADDRITEM_NAME(email);
1674 if( *name == '\0' ) {
1675 name = ADDRITEM_NAME(person);
1676 }
1677 }
1678 else if( ADDRITEM_NAME(person) ) {
1679 name = ADDRITEM_NAME(person);
1680 }
1681 else {
1682 buf = g_strdup( email->address );
1683 }
1684 address = email->address;
1685 }
1686 }
1687 else if( aio->type == ITEMTYPE_PERSON ) {
1688 ItemPerson *person = ( ItemPerson * ) aio;
1689 GList *node = person->listEMail;
1690
1691 name = ADDRITEM_NAME(person);
1692 if( node ) {
1693 ItemEMail *email = ( ItemEMail * ) node->data;
1694 address = email->address;
1695 }
1696 }
1697 if( address ) {
1698 if( name && name[0] != '\0' ) {
1699 if( strchr_with_skip_quote( name, '"', ',' ) )
1700 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1701 else
1702 buf = g_strdup_printf( "%s <%s>", name, address );
1703 }
1704 else {
1705 buf = g_strdup( address );
1706 }
1707 }
1708
1709 return buf;
1710 }
1711
addressbook_to_clicked(GtkButton * button,gpointer data)1712 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1713 {
1714 GList *list, *node;
1715 Compose *compose;
1716 AddrSelectItem *item;
1717 AddrItemObject *aio;
1718 gchar *addr;
1719
1720 compose = addrbook.target_compose;
1721 if( ! compose ) return;
1722
1723 /* Nothing selected, but maybe there is something in text entry */
1724 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1725 if ( addr ) {
1726 compose_entry_append(
1727 compose, addr, (ComposeEntryType)data , PREF_NONE);
1728 }
1729
1730 /* Select from address list */
1731 list = addrselect_get_list( _addressSelect_ );
1732 node = list;
1733 if (node) {
1734 while( node ) {
1735 item = node->data;
1736 node = g_list_next( node );
1737 aio = item->addressItem;
1738 if( aio->type == ITEMTYPE_PERSON ||
1739 aio->type == ITEMTYPE_EMAIL ) {
1740 addr = addressbook_format_address( aio );
1741 compose_entry_append(
1742 compose, addr, (ComposeEntryType) data, PREF_NONE );
1743 g_free( addr );
1744 }
1745 else if( aio->type == ITEMTYPE_GROUP ) {
1746 ItemGroup *group = ( ItemGroup * ) aio;
1747 GList *nodeMail = group->listEMail;
1748 while( nodeMail ) {
1749 ItemEMail *email = nodeMail->data;
1750
1751 addr = addressbook_format_address(
1752 ( AddrItemObject * ) email );
1753 compose_entry_append(
1754 compose, addr, (ComposeEntryType) data, PREF_NONE );
1755 g_free( addr );
1756 nodeMail = g_list_next( nodeMail );
1757 }
1758 }
1759 }
1760 } else {
1761 AddressObject *obj = NULL;
1762
1763 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1764
1765 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1766 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1767 GList *nodeMail = itemGroup->listEMail;
1768 while( nodeMail ) {
1769 ItemEMail *email = nodeMail->data;
1770
1771 addr = addressbook_format_address(
1772 ( AddrItemObject * ) email );
1773 compose_entry_append(
1774 compose, addr, (ComposeEntryType) data, PREF_NONE );
1775 g_free( addr );
1776 nodeMail = g_list_next( nodeMail );
1777 }
1778 }
1779 }
1780 g_list_free( list );
1781 }
1782
addressbook_menubar_set_sensitive(gboolean sensitive)1783 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1787
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1792
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1797 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1798 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1799 }
1800
addressbook_menuitem_set_sensitive(AddressObject * obj,GtkCMCTreeNode * node)1801 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1802 gboolean canEdit = FALSE;
1803 gboolean canDelete = TRUE;
1804 gboolean canAdd = FALSE;
1805 gboolean canEditTr = TRUE;
1806 gboolean editAddress = FALSE;
1807 gboolean canExport = TRUE;
1808 AddressTypeControlItem *atci = NULL;
1809 AddressDataSource *ds = NULL;
1810 AddressInterface *iface = NULL;
1811
1812 if( obj == NULL ) return;
1813 if( obj->type == ADDR_INTERFACE ) {
1814 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1815 iface = adapter->interface;
1816 if( iface ) {
1817 if( iface->haveLibrary ) {
1818 /* Enable appropriate File / New command */
1819 atci = adapter->atci;
1820 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1821 }
1822 }
1823 canEditTr = canExport = FALSE;
1824 }
1825 else if( obj->type == ADDR_DATASOURCE ) {
1826 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1827 ds = ads->dataSource;
1828 iface = ds->interface;
1829 if( ! iface->readOnly ) {
1830 canAdd = canEdit = editAddress = canDelete = TRUE;
1831 }
1832 if( ! iface->haveLibrary ) {
1833 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1834 }
1835 }
1836 else if( obj->type == ADDR_ITEM_FOLDER ) {
1837 ds = addressbook_find_datasource( addrbook.treeSelected );
1838 if( ds ) {
1839 iface = ds->interface;
1840 if( iface->readOnly ) {
1841 canEditTr = FALSE;
1842 canDelete = FALSE;
1843 }
1844 else {
1845 canAdd = editAddress = TRUE;
1846 }
1847 }
1848 }
1849 else if( obj->type == ADDR_ITEM_GROUP ) {
1850 ds = addressbook_find_datasource( addrbook.treeSelected );
1851 if( ds ) {
1852 iface = ds->interface;
1853 if( ! iface->readOnly ) {
1854 editAddress = TRUE;
1855 }
1856 }
1857 }
1858
1859 if( addrbook.listSelected == NULL )
1860 canEdit = FALSE;
1861
1862 /* Enable add */
1863 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1865 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1866 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1867
1868 /* Enable edit */
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1871 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1872 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1873
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1876
1877 /* Export data */
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1880 }
1881
1882 /**
1883 * Address book tree callback function that responds to selection of tree
1884 * items.
1885 *
1886 * \param ctree Tree widget.
1887 * \param node Node that was selected.
1888 * \param column Column number where selected occurred.
1889 * \param data Pointer to user data.
1890 */
addressbook_tree_selected(GtkCMCTree * ctree,GtkCMCTreeNode * node,gint column,gpointer data)1891 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1892 gint column, gpointer data)
1893 {
1894 AddressObject *obj = NULL;
1895 AdapterDSource *ads = NULL;
1896 AddressDataSource *ds = NULL;
1897 ItemFolder *rootFolder = NULL;
1898 AddressObjectType aot;
1899
1900 addrbook.treeSelected = node;
1901 addrbook.listSelected = NULL;
1902 addressbook_status_show( "" );
1903 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1904
1905 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1906 if( obj == NULL ) {
1907 addressbook_set_clist(NULL, TRUE);
1908 return;
1909 }
1910 addrbook.opened = node;
1911
1912 if( obj->type == ADDR_DATASOURCE ) {
1913 /* Read from file */
1914 static gboolean tVal = TRUE;
1915
1916 ads = ADAPTER_DSOURCE(obj);
1917
1918 ds = ads->dataSource;
1919 if( ds == NULL ) return;
1920
1921 if( addrindex_ds_get_modify_flag( ds ) ) {
1922 addrindex_ds_read_data( ds );
1923 }
1924
1925 if( ! addrindex_ds_get_read_flag( ds ) ) {
1926 addrindex_ds_read_data( ds );
1927 }
1928 addressbook_ds_show_message( ds );
1929
1930 if( ! addrindex_ds_get_access_flag( ds ) ) {
1931 /* Remove existing folders and groups */
1932 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1933 addressbook_tree_remove_children( ctree, node );
1934 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1935
1936 /* Load folders into the tree */
1937 rootFolder = addrindex_ds_get_root_folder( ds );
1938 if( ds && ds->type == ADDR_IF_JPILOT ) {
1939 aot = ADDR_CATEGORY;
1940 }
1941 else if( ds && ds->type == ADDR_IF_LDAP ) {
1942 aot = ADDR_LDAP_QUERY;
1943 }
1944 else {
1945 aot = ADDR_ITEM_FOLDER;
1946 }
1947 addressbook_node_add_folder( node, ds, rootFolder, aot );
1948 addrindex_ds_set_access_flag( ds, &tVal );
1949 gtk_cmctree_expand( ctree, node );
1950 }
1951 } else {
1952 addressbook_set_clist(NULL, TRUE);
1953 }
1954
1955 /* Update address list */
1956 g_signal_handlers_block_by_func
1957 (G_OBJECT(ctree),
1958 G_CALLBACK(addressbook_tree_selected), NULL);
1959 addressbook_set_clist( obj, FALSE );
1960 g_signal_handlers_unblock_by_func
1961 (G_OBJECT(ctree),
1962 G_CALLBACK(addressbook_tree_selected), NULL);
1963 if (!prefs_common.addressbook_use_editaddress_dialog)
1964 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1965
1966 /* Setup main menu selections */
1967 addressbook_menubar_set_sensitive( FALSE );
1968 addressbook_menuitem_set_sensitive( obj, node );
1969 addressbook_list_select_clear();
1970 addressbook_list_menu_setup();
1971 return;
1972 }
1973
1974 /**
1975 * Setup address list popup menu items. Items are enabled or disabled as
1976 * required.
1977 */
addressbook_list_menu_setup(void)1978 static void addressbook_list_menu_setup( void ) {
1979 GtkCMCTree *clist = NULL;
1980 AddressObject *pobj = NULL;
1981 AddressObject *obj = NULL;
1982 AdapterDSource *ads = NULL;
1983 AddressInterface *iface = NULL;
1984 AddressDataSource *ds = NULL;
1985 GList *list;
1986 AddrItemObject *aio;
1987 AddrSelectItem *item;
1988 gboolean canEdit = FALSE;
1989 gboolean canDelete = FALSE;
1990 gboolean canCut = FALSE;
1991 gboolean canCopy = FALSE;
1992 gboolean canPaste = FALSE;
1993 gboolean canBrowse = FALSE;
1994 gboolean canMerge = FALSE;
1995
1996 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1997 if( pobj == NULL ) return;
1998
1999 clist = GTK_CMCTREE(addrbook.clist);
2000 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2001 if( obj == NULL ) canEdit = FALSE;
2002
2003 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2004 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2005
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;
2023 }
2024 }
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;
2039 }
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;
2045 }
2046 canDelete = canEdit;
2047 }
2048 if( iface->type == ADDR_IF_LDAP ) {
2049 if( obj ) canBrowse = TRUE;
2050 canEdit = TRUE;
2051 canDelete = TRUE;
2052 }
2053 }
2054
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;
2064 }
2065
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;
2070 }
2071
2072 /* Allow merging persons or emails are selected */
2073 list = _addressSelect_->listSelect;
2074 if (list && list->next ) {
2075 item = list->data;
2076 aio = ( AddrItemObject * ) item->addressItem;
2077 if( aio->type == ITEMTYPE_EMAIL ||
2078 aio->type == ITEMTYPE_PERSON ) {
2079 canMerge = TRUE;
2080 }
2081 }
2082
2083 /* Forbid write changes when read-only */
2084 if( iface && iface->readOnly ) {
2085 canCut = FALSE;
2086 canDelete = FALSE;
2087 canPaste = FALSE;
2088 canMerge = FALSE;
2089 }
2090
2091 /* Now go finalize menu items */
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2094
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2098
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2101
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2105
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2110
2111 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2112 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2113
2114 if (addrbook.target_compose) {
2115 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2116 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2117 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2118 }
2119 #ifdef USE_LDAP
2120 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2121 #endif
2122 }
2123
addressbook_select_row_tree(GtkCMCTree * ctree,GtkCMCTreeNode * node,gint column,gpointer data)2124 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2125 GtkCMCTreeNode *node,
2126 gint column,
2127 gpointer data)
2128 {
2129 }
2130
2131 /**
2132 * Add list of items into tree node below specified tree node.
2133 * \param treeNode Tree node.
2134 * \param ds Data source.
2135 * \param listItems List of items.
2136 */
addressbook_treenode_add_list(GtkCMCTreeNode * treeNode,AddressDataSource * ds,GList * listItems)2137 static void addressbook_treenode_add_list(
2138 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2139 {
2140 GList *node;
2141
2142 node = listItems;
2143 while( node ) {
2144 AddrItemObject *aio;
2145 GtkCMCTreeNode *nn;
2146
2147 aio = node->data;
2148 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2149 ItemGroup *group;
2150
2151 group = ( ItemGroup * ) aio;
2152 nn = addressbook_node_add_group( treeNode, ds, group );
2153 if (nn == NULL) {
2154 g_message("error adding addressbook group\n");
2155 }
2156 }
2157 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2158 ItemFolder *folder;
2159
2160 folder = ( ItemFolder * ) aio;
2161 nn = addressbook_node_add_folder(
2162 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2163 if (nn == NULL) {
2164 g_message("error adding addressbook folder\n");
2165 }
2166 }
2167 node = g_list_next( node );
2168 }
2169 }
2170
addressbook_select_all_cb(GtkAction * action,gpointer data)2171 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2172 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2173 }
2174
2175 /**
2176 * Cut from address list widget.
2177 */
addressbook_clip_cut_cb(GtkAction * action,gpointer data)2178 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2179 _clipBoard_->cutFlag = TRUE;
2180 addrclip_clear( _clipBoard_ );
2181 addrclip_add( _clipBoard_, _addressSelect_ );
2182 /* addrclip_list_show( _clipBoard_, stdout ); */
2183 }
2184
2185 /**
2186 * Copy from address list widget.
2187 */
addressbook_clip_copy_cb(GtkAction * action,gpointer data)2188 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2189 _clipBoard_->cutFlag = FALSE;
2190 addrclip_clear( _clipBoard_ );
2191 addrclip_add( _clipBoard_, _addressSelect_ );
2192 /* addrclip_list_show( _clipBoard_, stdout ); */
2193 }
2194
2195 /**
2196 * Paste clipboard into address list widget.
2197 */
addressbook_clip_paste_cb(GtkAction * action,gpointer data)2198 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2199 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2200 AddressObject *pobj = NULL;
2201 AddressDataSource *ds = NULL;
2202 AddressBookFile *abf = NULL;
2203 ItemFolder *folder = NULL;
2204 GList *folderGroup = NULL;
2205
2206 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2207 if( ds == NULL ) return;
2208 if( addrindex_ds_get_readonly( ds ) ) {
2209 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2210 return;
2211 }
2212
2213 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2214 if( pobj ) {
2215 if( pobj->type == ADDR_ITEM_FOLDER ) {
2216 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2217 }
2218 else if( pobj->type == ADDR_ITEM_GROUP ) {
2219 alertpanel_error( _("Cannot paste into an address group.") );
2220 return;
2221 }
2222 }
2223
2224 /* Get an address book */
2225 abf = addressbook_get_book_file();
2226 if( abf == NULL ) return;
2227
2228 if( _clipBoard_->cutFlag ) {
2229 /* Paste/Cut */
2230 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2231
2232 /* Remove all groups and folders in clipboard from tree node */
2233 addressbook_treenode_remove_item();
2234
2235 /* Remove all "cut" items */
2236 addrclip_delete_item( _clipBoard_ );
2237
2238 /* Clear clipboard - cut items??? */
2239 addrclip_clear( _clipBoard_ );
2240 }
2241 else {
2242 /* Paste/Copy */
2243 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2244 }
2245
2246 /* addrclip_list_show( _clipBoard_, stdout ); */
2247 if( folderGroup ) {
2248 /* Update tree by inserting node for each folder or group */
2249 addressbook_treenode_add_list(
2250 addrbook.treeSelected, ds, folderGroup );
2251 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2252 g_list_free( folderGroup );
2253 folderGroup = NULL;
2254 }
2255
2256 /* Display items pasted */
2257 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2258 addressbook_set_clist(
2259 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2260 addrbook.opened),
2261 TRUE);
2262
2263
2264 }
2265
2266 /**
2267 * Add current treenode object to clipboard. Note that widget only allows
2268 * one entry from the tree list to be selected.
2269 */
addressbook_treenode_to_clipboard(void)2270 static void addressbook_treenode_to_clipboard( void ) {
2271 AddressObject *obj = NULL;
2272 AddressDataSource *ds = NULL;
2273 AddrSelectItem *item;
2274 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2275 GtkCMCTreeNode *node;
2276
2277 node = addrbook.treeSelected;
2278 if( node == NULL ) return;
2279 obj = gtk_cmctree_node_get_row_data( ctree, node );
2280 if( obj == NULL ) return;
2281
2282 ds = addressbook_find_datasource( node );
2283 if( ds == NULL ) return;
2284
2285 item = NULL;
2286 if( obj->type == ADDR_ITEM_FOLDER ) {
2287 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2288 ItemFolder *folder = adapter->itemFolder;
2289
2290 item = addrselect_create_node( obj );
2291 item->uid = g_strdup( ADDRITEM_ID(folder) );
2292 }
2293 else if( obj->type == ADDR_ITEM_GROUP ) {
2294 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2295 ItemGroup *group = adapter->itemGroup;
2296
2297 item = addrselect_create_node( obj );
2298 item->uid = g_strdup( ADDRITEM_ID(group) );
2299 }
2300 else if( obj->type == ADDR_DATASOURCE ) {
2301 /* Data source */
2302 item = addrselect_create_node( obj );
2303 item->uid = NULL;
2304 }
2305
2306 if( item ) {
2307 /* Clear existing list and add item into list */
2308 gchar *cacheID;
2309
2310 addressbook_list_select_clear();
2311 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2312 addrselect_list_add( _addressSelect_, item, cacheID );
2313 g_free( cacheID );
2314 }
2315 }
2316
2317 /**
2318 * Cut from tree widget.
2319 */
addressbook_treenode_cut_cb(GtkAction * action,gpointer data)2320 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2321 _clipBoard_->cutFlag = TRUE;
2322 addressbook_treenode_to_clipboard();
2323 addrclip_clear( _clipBoard_ );
2324 addrclip_add( _clipBoard_, _addressSelect_ );
2325 /* addrclip_list_show( _clipBoard_, stdout ); */
2326 }
2327
2328 /**
2329 * Copy from tree widget.
2330 */
addressbook_treenode_copy_cb(GtkAction * action,gpointer data)2331 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2332 _clipBoard_->cutFlag = FALSE;
2333 addressbook_treenode_to_clipboard();
2334 addrclip_clear( _clipBoard_ );
2335 addrclip_add( _clipBoard_, _addressSelect_ );
2336 /* addrclip_list_show( _clipBoard_, stdout ); */
2337 }
2338
2339 /**
2340 * Paste clipboard into address tree widget.
2341 */
addressbook_treenode_paste_cb(GtkAction * action,gpointer data)2342 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2343 addressbook_clip_paste_cb(NULL,NULL);
2344 }
2345
2346 /**
2347 * Clear selected entries in clipboard.
2348 */
addressbook_list_select_clear(void)2349 static void addressbook_list_select_clear( void ) {
2350 addrselect_list_clear( _addressSelect_ );
2351 }
2352
2353 /**
2354 * Add specified address item to selected address list.
2355 * \param aio Address item object.
2356 * \param ds Datasource.
2357 */
addressbook_list_select_add(AddrItemObject * aio,AddressDataSource * ds)2358 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2359 gchar *cacheID;
2360
2361 if( ds == NULL ) return;
2362 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2363 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2364 g_free( cacheID );
2365 }
2366
2367 /**
2368 * Remove specified address item from selected address list.
2369 * \param aio Address item object.
2370 */
addressbook_list_select_remove(AddrItemObject * aio)2371 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2372 addrselect_list_remove( _addressSelect_, aio );
2373 }
2374
2375 /**
2376 * Invoke EMail compose window with addresses in selected address list.
2377 */
addressbook_mail_to_cb(GtkAction * action,gpointer data)2378 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2379 GList *listAddress;
2380
2381 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2382 listAddress = addrselect_build_list( _addressSelect_ );
2383 compose_new_with_list( NULL, listAddress );
2384 g_list_free_full( listAddress, g_free );
2385 listAddress = NULL;
2386 }
2387 }
2388
addressbook_merge_list(AddrSelectList * list)2389 static void addressbook_merge_list( AddrSelectList *list ) {
2390 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2391 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2392 AddressObject *pobj;
2393 AddressDataSource *ds = NULL;
2394
2395 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2396 cm_return_if_fail(pobj != NULL);
2397
2398 ds = addressbook_find_datasource( addrbook.treeSelected );
2399 if( ds == NULL ) return;
2400
2401 addrmerge_merge(clist, pobj, ds, list);
2402 }
2403
2404 /**
2405 * Merge selected entries in the address list
2406 */
addressbook_merge_cb(GtkAction * action,gpointer data)2407 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2408 if( addrselect_test_empty( _addressSelect_ ) )
2409 return;
2410
2411 addressbook_merge_list( _addressSelect_ );
2412 }
2413
addressbook_list_row_selected(GtkCMCTree * clist,GtkCMCTreeNode * node,gint column,gpointer data)2414 static void addressbook_list_row_selected( GtkCMCTree *clist,
2415 GtkCMCTreeNode *node,
2416 gint column,
2417 gpointer data )
2418 {
2419 AddrItemObject *aio = NULL;
2420 AddressObject *pobj = NULL;
2421 AdapterDSource *ads = NULL;
2422 AddressDataSource *ds = NULL;
2423
2424 addrbook.listSelected = node;
2425
2426 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2427 if( pobj == NULL ) return;
2428
2429 if( pobj->type == ADDR_DATASOURCE ) {
2430 ads = ADAPTER_DSOURCE(pobj);
2431 ds = ads->dataSource;
2432 }
2433 else if( pobj->type != ADDR_INTERFACE ) {
2434 ds = addressbook_find_datasource( addrbook.treeSelected );
2435 }
2436
2437 aio = gtk_cmctree_node_get_row_data( clist, node );
2438 if( aio ) {
2439 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2440 addressbook_list_select_add( aio, ds );
2441 }
2442
2443 addressbook_list_menu_setup();
2444
2445 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2446 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2447
2448 if (obj && obj->type != ADDR_ITEM_GROUP)
2449 addressbook_edit_address(NULL, 0, NULL, FALSE);
2450 }
2451 }
2452
addressbook_list_row_unselected(GtkCMCTree * ctree,GtkCMCTreeNode * node,gint column,gpointer data)2453 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2454 GtkCMCTreeNode *node,
2455 gint column,
2456 gpointer data )
2457 {
2458 AddrItemObject *aio;
2459
2460 aio = gtk_cmctree_node_get_row_data( ctree, node );
2461 if( aio != NULL ) {
2462 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2463 addressbook_list_select_remove( aio );
2464 }
2465
2466 if (!prefs_common.addressbook_use_editaddress_dialog)
2467 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2468 }
2469
addressbook_entry_activated(GtkWidget * widget,gpointer data)2470 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2471 {
2472 addressbook_lup_clicked(NULL, NULL);
2473 }
2474
addressbook_list_button_pressed(GtkWidget * widget,GdkEventButton * event,gpointer data)2475 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2476 GdkEventButton *event,
2477 gpointer data)
2478 {
2479 if( ! event ) return FALSE;
2480 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2481
2482 addressbook_list_menu_setup();
2483
2484 if( event->button == 3 ) {
2485 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2486 event->button, event->time );
2487 } else if (event->button == 1) {
2488 if (event->type == GDK_2BUTTON_PRESS) {
2489 if (prefs_common.add_address_by_click &&
2490 addrbook.target_compose)
2491 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2492 else
2493 if (prefs_common.addressbook_use_editaddress_dialog)
2494 addressbook_edit_address_cb(NULL, NULL);
2495 else {
2496 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2497 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2498 if( obj && obj->type == ADDR_ITEM_GROUP )
2499 addressbook_edit_address_cb(NULL, NULL);
2500 }
2501 }
2502 }
2503
2504 return FALSE;
2505 }
2506
addressbook_list_button_released(GtkWidget * widget,GdkEventButton * event,gpointer data)2507 static gboolean addressbook_list_button_released(GtkWidget *widget,
2508 GdkEventButton *event,
2509 gpointer data)
2510 {
2511 return FALSE;
2512 }
2513
addressbook_tree_button_pressed(GtkWidget * ctree,GdkEventButton * event,gpointer data)2514 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2515 GdkEventButton *event,
2516 gpointer data)
2517 {
2518 GtkCMCList *clist = GTK_CMCLIST(ctree);
2519 gint row, column;
2520 AddressObject *obj = NULL;
2521 AdapterDSource *ads = NULL;
2522 AddressInterface *iface = NULL;
2523 AddressDataSource *ds = NULL;
2524 gboolean canEdit = FALSE;
2525 gboolean canDelete = FALSE;
2526 gboolean canCut = FALSE;
2527 gboolean canCopy = FALSE;
2528 gboolean canPaste = FALSE;
2529 gboolean canTreeCut = FALSE;
2530 gboolean canTreeCopy = FALSE;
2531 gboolean canTreePaste = FALSE;
2532 gboolean canLookup = FALSE;
2533 GtkCMCTreeNode *node = NULL;
2534
2535 if( ! event ) return FALSE;
2536 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2537
2538 if( event->window != clist->clist_window )
2539 return FALSE;
2540
2541 if (event->button == 1) {
2542 if (event->type == GDK_2BUTTON_PRESS) {
2543 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2544 gtkut_clist_set_focus_row(clist, row);
2545 obj = gtk_cmclist_get_row_data( clist, row );
2546 }
2547 if( obj == NULL )
2548 return FALSE;
2549
2550 if (obj->type == ADDR_ITEM_GROUP ||
2551 obj->type == ADDR_DATASOURCE) {
2552 /* edit group */
2553 addressbook_treenode_edit_cb(NULL, NULL);
2554 } else {
2555 /* expand pr collapse */
2556 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2557 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2558 }
2559 return FALSE;
2560 }
2561 }
2562
2563 addressbook_menubar_set_sensitive( FALSE );
2564
2565 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2566 gtkut_clist_set_focus_row(clist, row);
2567 obj = gtk_cmclist_get_row_data( clist, row );
2568 }
2569
2570 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2571
2572 if( obj == NULL )
2573 return FALSE;
2574 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2575
2576 if( ! addrclip_is_empty( _clipBoard_ ) )
2577 canTreePaste = TRUE;
2578
2579 if (obj->type == ADDR_INTERFACE) {
2580 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2581 iface = adapter->interface;
2582 if( !iface )
2583 goto just_set_sens;
2584 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2585 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2586 }
2587 if( iface->externalQuery )
2588 canLookup = TRUE;
2589 }
2590 if (obj->type == ADDR_DATASOURCE) {
2591 canLookup = TRUE;
2592 ads = ADAPTER_DSOURCE(obj);
2593 ds = ads->dataSource;
2594 if( !ds )
2595 goto just_set_sens;
2596 iface = ds->interface;
2597 if( !iface )
2598 goto just_set_sens;
2599 if( !iface->readOnly ) {
2600 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2601 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2602 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2603 }
2604 canDelete = TRUE;
2605 canEdit = TRUE;
2606 canTreeCopy = TRUE;
2607 }
2608 else if (obj->type == ADDR_ITEM_FOLDER) {
2609 canLookup = TRUE;
2610 ds = addressbook_find_datasource( node );
2611 if( !ds )
2612 goto just_set_sens;
2613 iface = ds->interface;
2614 if( !iface )
2615 goto just_set_sens;
2616 if( !iface->readOnly ) {
2617 canEdit = TRUE;
2618 canDelete = TRUE;
2619 canTreeCut = TRUE;
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2622 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2623 }
2624 canTreeCopy = TRUE;
2625
2626 if( iface->externalQuery ) {
2627 /* Enable deletion of LDAP folder */
2628 canDelete = TRUE;
2629 }
2630 }
2631 else if (obj->type == ADDR_ITEM_GROUP) {
2632 canLookup = TRUE;
2633 ds = addressbook_find_datasource( node );
2634 if( !ds )
2635 goto just_set_sens;
2636 iface = ds->interface;
2637 if( !iface )
2638 goto just_set_sens;
2639 if( ! iface->readOnly ) {
2640 canEdit = TRUE;
2641 canDelete = TRUE;
2642 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2643 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2644 }
2645 }
2646
2647 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2648 canCut = TRUE;
2649 if( ! addrselect_test_empty( _addressSelect_ ) )
2650 canCopy = TRUE;
2651 if( ! addrclip_is_empty( _clipBoard_ ) )
2652 canPaste = TRUE;
2653
2654 /* Forbid write changes when read-only */
2655 if( iface && iface->readOnly ) {
2656 canTreeCut = FALSE;
2657 canTreePaste = FALSE;
2658 canCut = FALSE;
2659 canPaste = FALSE;
2660 }
2661
2662 just_set_sens:
2663 /* Enable edit */
2664 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2665 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2666 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2669
2670 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2671 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2672 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2675
2676 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2677 addrbook.target_compose != NULL);
2678
2679 if( event->button == 3 )
2680 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2681 event->button, event->time);
2682
2683 return FALSE;
2684 }
2685
addressbook_tree_button_released(GtkWidget * ctree,GdkEventButton * event,gpointer data)2686 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2687 GdkEventButton *event,
2688 gpointer data)
2689 {
2690 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2691 return FALSE;
2692 }
2693
addressbook_new_folder_cb(GtkAction * action,gpointer data)2694 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2695 {
2696 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2697 AddressObject *obj = NULL;
2698 AddressDataSource *ds = NULL;
2699 AddressBookFile *abf = NULL;
2700 ItemFolder *parentFolder = NULL;
2701 ItemFolder *folder = NULL;
2702
2703 if( ! addrbook.treeSelected ) return;
2704 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2705 if( obj == NULL ) return;
2706 ds = addressbook_find_datasource( addrbook.treeSelected );
2707 if( ds == NULL ) return;
2708
2709 if( obj->type == ADDR_DATASOURCE ) {
2710 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2711 }
2712 else if( obj->type == ADDR_ITEM_FOLDER ) {
2713 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2714 }
2715 else {
2716 return;
2717 }
2718
2719 abf = ds->rawDataSource;
2720 if( abf == NULL ) return;
2721 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2722 if( folder ) {
2723 GtkCMCTreeNode *nn;
2724 nn = addressbook_node_add_folder(
2725 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2726 if (nn == NULL) {
2727 g_message("error adding addressbook folder\n");
2728 }
2729 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2730 if( addrbook.treeSelected == addrbook.opened )
2731 addressbook_set_clist(obj, TRUE);
2732 }
2733 }
2734
addressbook_new_group_cb(GtkAction * action,gpointer data)2735 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2736 {
2737 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2738 AddressObject *obj = NULL;
2739 AddressDataSource *ds = NULL;
2740 AddressBookFile *abf = NULL;
2741 ItemFolder *parentFolder = NULL;
2742 ItemGroup *group = NULL;
2743
2744 if( ! addrbook.treeSelected ) return;
2745 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2746 if( obj == NULL ) return;
2747 ds = addressbook_find_datasource( addrbook.treeSelected );
2748 if( ds == NULL ) return;
2749
2750 if( obj->type == ADDR_DATASOURCE ) {
2751 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2752 }
2753 else if( obj->type == ADDR_ITEM_FOLDER ) {
2754 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2755 }
2756 else {
2757 return;
2758 }
2759
2760 abf = ds->rawDataSource;
2761 if( abf == NULL ) return;
2762 group = addressbook_edit_group( abf, parentFolder, NULL );
2763 if( group ) {
2764 GtkCMCTreeNode *nn;
2765 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2766 if (nn == NULL) {
2767 g_message("error adding addressbook group\n");
2768 }
2769 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2770 if( addrbook.treeSelected == addrbook.opened )
2771 addressbook_set_clist(obj, TRUE);
2772 }
2773 }
2774
addressbook_change_node_name(GtkCMCTreeNode * node,const gchar * name)2775 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2776 {
2777 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2778 gchar *text[1];
2779 guint8 spacing;
2780 GdkPixbuf *pix_cl, *pix_op;
2781 gboolean is_leaf, expanded;
2782
2783 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2784 &pix_cl, &pix_op,
2785 &is_leaf, &expanded);
2786 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2787 pix_cl, pix_op,
2788 is_leaf, expanded);
2789 }
2790
2791 /**
2792 * Edit data source.
2793 * \param obj Address object to edit.
2794 * \param node Node in tree.
2795 * \return New name of data source.
2796 */
addressbook_edit_datasource(AddressObject * obj,GtkCMCTreeNode * node)2797 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2798 gchar *newName = NULL;
2799 AddressDataSource *ds = NULL;
2800 AddressInterface *iface = NULL;
2801 AdapterDSource *ads = NULL;
2802
2803 ds = addressbook_find_datasource( node );
2804 if( ds == NULL ) return NULL;
2805 iface = ds->interface;
2806 if( ! iface->haveLibrary ) return NULL;
2807
2808 /* Read data from data source */
2809 if( addrindex_ds_get_modify_flag( ds ) ) {
2810 addrindex_ds_read_data( ds );
2811 }
2812
2813 if( ! addrindex_ds_get_read_flag( ds ) ) {
2814 addrindex_ds_read_data( ds );
2815 }
2816
2817 /* Handle edit */
2818 ads = ADAPTER_DSOURCE(obj);
2819 if( ads->subType == ADDR_BOOK ) {
2820 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2821 }
2822 else if( ads->subType == ADDR_VCARD ) {
2823 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2824 }
2825 #ifdef USE_JPILOT
2826 else if( ads->subType == ADDR_JPILOT ) {
2827 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2828 }
2829 #endif
2830 #ifdef USE_LDAP
2831 else if( ads->subType == ADDR_LDAP ) {
2832 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2833 }
2834 #endif
2835 else {
2836 return NULL;
2837 }
2838 newName = obj->name;
2839 return newName;
2840 }
2841
2842 /*
2843 * Edit an object that is in the address tree area.
2844 */
addressbook_treenode_edit_cb(GtkAction * action,gpointer data)2845 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2846 {
2847 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2848 AddressObject *obj;
2849 AddressDataSource *ds = NULL;
2850 AddressBookFile *abf = NULL;
2851 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2852 gchar *name = NULL;
2853
2854 if( ! addrbook.treeSelected ) return;
2855 node = addrbook.treeSelected;
2856 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2857 obj = gtk_cmctree_node_get_row_data( ctree, node );
2858 if( obj == NULL ) return;
2859 parentNode = GTK_CMCTREE_ROW(node)->parent;
2860
2861 ds = addressbook_find_datasource( node );
2862 if( ds == NULL ) return;
2863
2864 if( obj->type == ADDR_DATASOURCE ) {
2865 name = addressbook_edit_datasource( obj, node );
2866 if( name == NULL ) return;
2867 }
2868 else {
2869 abf = ds->rawDataSource;
2870 if( abf == NULL ) return;
2871 if( obj->type == ADDR_ITEM_FOLDER ) {
2872 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2873 ItemFolder *item = adapter->itemFolder;
2874 ItemFolder *parentFolder = NULL;
2875 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2876 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2877 name = ADDRITEM_NAME(item);
2878 }
2879 else if( obj->type == ADDR_ITEM_GROUP ) {
2880 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2881 ItemGroup *item = adapter->itemGroup;
2882 ItemFolder *parentFolder = NULL;
2883 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2884 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2885 name = ADDRITEM_NAME(item);
2886 }
2887 }
2888 if( name && parentNode ) {
2889 /* Update node in tree view */
2890 addressbook_change_node_name( node, name );
2891 gtk_sctree_sort_node(ctree, parentNode);
2892 gtk_cmctree_expand( ctree, node );
2893 gtk_sctree_select( GTK_SCTREE( ctree), node );
2894 }
2895 }
2896
2897 typedef enum {
2898 ADDRTREE_DEL_NONE,
2899 ADDRTREE_DEL_DATA,
2900 ADDRTREE_DEL_FOLDER_ONLY,
2901 ADDRTREE_DEL_FOLDER_ADDR
2902 } TreeItemDelType ;
2903
2904 /**
2905 * Delete an item from the tree widget.
2906 * \param data Data passed in.
2907 * \param action Action.
2908 * \param widget Widget issuing callback.
2909 */
addressbook_treenode_delete_cb(GtkAction * action,gpointer data)2910 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2911 {
2912 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2913 GtkCMCTreeNode *node = NULL;
2914 AddressObject *obj;
2915 gchar *message;
2916 AlertValue aval;
2917 AddrBookBase *adbase;
2918 AddressCache *cache;
2919 AdapterDSource *ads = NULL;
2920 AddressInterface *iface = NULL;
2921 AddressDataSource *ds = NULL;
2922 gboolean remFlag = FALSE;
2923 TreeItemDelType delType;
2924
2925 if( ! addrbook.treeSelected ) return;
2926 node = addrbook.treeSelected;
2927 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2928
2929 obj = gtk_cmctree_node_get_row_data( ctree, node );
2930 cm_return_if_fail(obj != NULL);
2931
2932 if( obj->type == ADDR_DATASOURCE ) {
2933 ads = ADAPTER_DSOURCE(obj);
2934
2935 ds = ads->dataSource;
2936 if( ds == NULL ) return;
2937 }
2938 else {
2939 /* Must be folder or something else */
2940 ds = addressbook_find_datasource( node );
2941 if( ds == NULL ) return;
2942
2943 /* Only allow deletion from non-readOnly */
2944 iface = ds->interface;
2945 if( iface->readOnly ) {
2946 /* Allow deletion of query results */
2947 if( ! iface->externalQuery ) return;
2948 }
2949 }
2950
2951 /* Confirm deletion */
2952 delType = ADDRTREE_DEL_NONE;
2953 if( obj->type == ADDR_ITEM_FOLDER ) {
2954 if( iface && iface->externalQuery ) {
2955 message = g_strdup_printf( _(
2956 "Do you want to delete the query " \
2957 "results and addresses in '%s'?" ),
2958 obj->name );
2959 aval = alertpanel( _("Delete"), message,
2960 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2961 g_free(message);
2962 if( aval == G_ALERTALTERNATE ) {
2963 delType = ADDRTREE_DEL_FOLDER_ADDR;
2964 }
2965 }
2966 else {
2967 message = g_strdup_printf
2968 ( _( "Do you want to delete '%s'? "
2969 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2970 obj->name );
2971 aval = alertpanel( _("Delete folder"), message,
2972 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2973 g_free(message);
2974 if( aval == G_ALERTALTERNATE ) {
2975 delType = ADDRTREE_DEL_FOLDER_ONLY;
2976 }
2977 else if( aval == G_ALERTOTHER ) {
2978 delType = ADDRTREE_DEL_FOLDER_ADDR;
2979 }
2980 }
2981 }
2982 else if( obj->type == ADDR_ITEM_GROUP ) {
2983 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2984 "The addresses it contains will not be lost."), obj->name);
2985 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2986 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2987 g_free(message);
2988 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2989 } else {
2990 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2991 "The addresses it contains will be lost."), obj->name);
2992 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2993 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2994 g_free(message);
2995 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2996 }
2997 if( delType == ADDRTREE_DEL_NONE ) return;
2998
2999 /* Proceed with deletion */
3000 if( obj->type == ADDR_DATASOURCE ) {
3001 /* Remove node from tree */
3002 gtk_cmctree_remove_node( ctree, node );
3003
3004 if (delType == ADDRTREE_DEL_DATA &&
3005 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3006 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3007
3008 /* Remove data source. */
3009 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3010 addrindex_free_datasource( ds );
3011 }
3012 return;
3013 }
3014
3015 /* Get reference to cache */
3016 adbase = ( AddrBookBase * ) ds->rawDataSource;
3017 if( adbase == NULL ) return;
3018 cache = adbase->addressCache;
3019
3020 /* Remove query results folder */
3021 if( iface && iface->externalQuery ) {
3022 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3023 ItemFolder *folder = adapter->itemFolder;
3024
3025 adapter->itemFolder = NULL;
3026 /*
3027 g_print( "remove folder for ::%s::\n", obj->name );
3028 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3029 g_print( "-------------- remove results\n" );
3030 */
3031 addrindex_remove_results( ds, folder );
3032 /* g_print( "-------------- remove node\n" ); */
3033 gtk_cmctree_remove_node( ctree, node );
3034 return;
3035 }
3036
3037 /* Code below is valid for regular address book deletion */
3038 if( obj->type == ADDR_ITEM_FOLDER ) {
3039 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3040 ItemFolder *item = adapter->itemFolder;
3041
3042 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3043 /* Remove folder only */
3044 item = addrcache_remove_folder( cache, item );
3045 if( item ) {
3046 addritem_free_item_folder( item );
3047 addressbook_move_nodes_up( ctree, node );
3048 remFlag = TRUE;
3049 }
3050 }
3051 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3052 /* Remove folder and addresses */
3053 item = addrcache_remove_folder_delete( cache, item );
3054 if( item ) {
3055 addritem_free_item_folder( item );
3056 remFlag = TRUE;
3057 }
3058 }
3059 }
3060 else if( obj->type == ADDR_ITEM_GROUP ) {
3061 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3062 ItemGroup *item = adapter->itemGroup;
3063
3064 item = addrcache_remove_group( cache, item );
3065 if( item ) {
3066 addritem_free_item_group( item );
3067 remFlag = TRUE;
3068 }
3069 }
3070
3071 if( remFlag ) {
3072 /* Remove node. */
3073 gtk_cmctree_remove_node(ctree, node );
3074 }
3075 }
3076
addressbook_new_address_from_book_post_cb(ItemPerson * person)3077 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3078 {
3079 if( person && addrbook.treeSelected == addrbook.opened ) {
3080 person->status = ADD_ENTRY;
3081 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3082 addressbook_folder_refresh_one_person(
3083 GTK_CMCTREE(addrbook.clist), person );
3084 }
3085 addressbook_address_list_set_focus();
3086 }
3087
addressbook_new_address_from_folder_post_cb(ItemPerson * person)3088 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3089 {
3090 if( person && addrbook.treeSelected == addrbook.opened) {
3091 person->status = ADD_ENTRY;
3092 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3093 addressbook_set_clist(
3094 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3095 addrbook.opened),
3096 TRUE);
3097 }
3098 addressbook_address_list_set_focus();
3099 }
3100
3101 /**
3102 * Label (a format string) that is used to name each folder.
3103 */
3104 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3105
3106 /**
3107 * Search ctree widget callback function.
3108 * \param pA Pointer to node.
3109 * \param pB Pointer to data item being sought.
3110 * \return Zero (0) if folder found.
3111 */
addressbook_treenode_find_folder_cb(gconstpointer pA,gconstpointer pB)3112 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3113 AddressObject *aoA;
3114
3115 aoA = ( AddressObject * ) pA;
3116 if( aoA->type == ADDR_ITEM_FOLDER ) {
3117 ItemFolder *folder, *fld;
3118
3119 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3120 folder = ( ItemFolder * ) pB;
3121 if( fld == folder ) return 0; /* Found folder */
3122 }
3123 return 1;
3124 }
3125
addressbook_setup_subf(AddressDataSource * ds,gchar * title,GtkCMCTreeNode * pNode)3126 static ItemFolder * addressbook_setup_subf(
3127 AddressDataSource *ds, gchar *title,
3128 GtkCMCTreeNode *pNode )
3129 {
3130 AddrBookBase *adbase;
3131 AddressCache *cache;
3132 ItemFolder *folder;
3133 GtkCMCTree *ctree;
3134 GtkCMCTreeNode *nNode;
3135 gchar *name;
3136 AddressObjectType aoType = ADDR_NONE;
3137 GList *children;
3138 /* Setup a query */
3139 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3140
3141 if( ds && ds->type == ADDR_IF_LDAP ) {
3142 #if USE_LDAP
3143 aoType = ADDR_LDAP_QUERY;
3144 #endif
3145 }
3146 else {
3147 return NULL;
3148 }
3149
3150 ctree = GTK_CMCTREE(addrbook.ctree);
3151 /* Get reference to address cache */
3152 adbase = ( AddrBookBase * ) ds->rawDataSource;
3153 cache = adbase->addressCache;
3154
3155 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3156 GList *cur = children;
3157 for (; cur; cur = cur->next) {
3158 ItemFolder *child = (ItemFolder *) cur->data;
3159 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3160 nNode = gtk_cmctree_find_by_row_data_custom(
3161 ctree, NULL, child,
3162 addressbook_treenode_find_folder_cb );
3163 if( nNode ) {
3164 addrindex_remove_results( ds, child );
3165 while( child->listPerson ) {
3166 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3167 item = addrcache_remove_person( cache, item );
3168 if( item ) {
3169 addritem_free_item_person( item );
3170 item = NULL;
3171 }
3172 }
3173 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3174 addrbook.treeSelected = nNode;
3175 }
3176 return child;
3177 }
3178 }
3179 }
3180
3181 /* Create a folder */
3182 folder = addrcache_add_new_folder( cache, NULL );
3183 name = g_strdup_printf( "%s", title );
3184 addritem_folder_set_name( folder, name );
3185 addritem_folder_set_remarks( folder, "" );
3186 g_free( name );
3187
3188 /* Now let's see the folder */
3189 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3190 gtk_cmctree_expand( ctree, pNode );
3191 if( nNode ) {
3192 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3193 addrbook.treeSelected = nNode;
3194 return folder;
3195 }
3196 return NULL;
3197 }
3198
addressbook_new_address_cb(GtkAction * action,gpointer data)3199 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3200 AddressObject *pobj = NULL;
3201 AddressDataSource *ds = NULL;
3202 AddressBookFile *abf = NULL;
3203 debug_print("adding address\n");
3204 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3205 if( pobj == NULL ) {
3206 debug_print("no row data\n");
3207 return;
3208 }
3209 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3210 if( ds == NULL ) {
3211 debug_print("no datasource\n");
3212 return;
3213 }
3214
3215 abf = ds->rawDataSource;
3216 if( abf == NULL ) {
3217 g_print("no addressbook file\n");
3218 return;
3219 }
3220
3221 if( pobj->type == ADDR_DATASOURCE ) {
3222 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3223 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3224 ItemPerson *person;
3225 ItemFolder *folder = NULL;
3226 #ifdef USE_LDAP
3227 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3228 GtkCMCTreeNode *parentNode;
3229 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3230 if( ds == NULL ) return;
3231
3232 /* We must have a datasource that is an external interface */
3233 if( ! ds->interface->haveLibrary ) return;
3234 if( ! ds->interface->externalQuery ) return;
3235
3236 if( pobj->type == ADDR_ITEM_FOLDER ) {
3237 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3238 }
3239 else {
3240 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3241 }
3242 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3243
3244 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3245 if (ds)
3246 abf = ds->rawDataSource;
3247 }
3248 #endif
3249 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3250 addrbook.editaddress_vbox,
3251 addressbook_new_address_from_book_post_cb,
3252 TRUE );
3253 #ifdef USE_LDAP
3254 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3255 LdapServer *server = ds->rawDataSource;
3256 ldapsvr_set_modified(server, TRUE);
3257 ldapsvr_update_book(server, NULL);
3258 if (server->retVal != LDAPRC_SUCCESS) {
3259 alertpanel( _("Add address(es)"),
3260 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3261 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3262 server->retVal = LDAPRC_SUCCESS;
3263 return;
3264 }
3265 }
3266 #endif
3267 if (prefs_common.addressbook_use_editaddress_dialog)
3268 addressbook_new_address_from_book_post_cb( person );
3269 }
3270 }
3271 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3272 /* New address */
3273 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3274 ItemPerson *person;
3275 #ifdef USE_LDAP
3276 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3277 GtkCMCTreeNode *parentNode;
3278 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3279 if( ds == NULL ) return;
3280
3281 /* We must have a datasource that is an external interface */
3282 if( ! ds->interface->haveLibrary ) return;
3283 if( ! ds->interface->externalQuery ) return;
3284
3285 if( pobj->type == ADDR_ITEM_FOLDER ) {
3286 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3287 }
3288 else {
3289 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3290 }
3291 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3292 if (!folder)
3293 return;
3294
3295 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3296 if (ds)
3297 abf = ds->rawDataSource;
3298 }
3299 #endif
3300 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3301 addrbook.editaddress_vbox,
3302 addressbook_new_address_from_folder_post_cb,
3303 TRUE );
3304 #ifdef USE_LDAP
3305 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3306 LdapServer *server = ds->rawDataSource;
3307 ldapsvr_set_modified(server, TRUE);
3308 ldapsvr_update_book(server, NULL);
3309 if (server->retVal != LDAPRC_SUCCESS) {
3310 alertpanel( _("Add address(es)"),
3311 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3312 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3313 return;
3314 }
3315 }
3316 #endif
3317 if (prefs_common.addressbook_use_editaddress_dialog)
3318 addressbook_new_address_from_folder_post_cb( person );
3319 }
3320 else if( pobj->type == ADDR_ITEM_GROUP ) {
3321 /* New address in group */
3322 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3323 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3324 if (addrbook.treeSelected == addrbook.opened) {
3325 /* Change node name in tree. */
3326 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3327 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3328 addressbook_set_clist(
3329 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3330 addrbook.opened),
3331 TRUE);
3332 }
3333 }
3334 }
3335
3336 /**
3337 * Search for specified child group node in address index tree.
3338 * \param parent Parent node.
3339 * \param group Group to find.
3340 */
addressbook_find_group_node(GtkCMCTreeNode * parent,ItemGroup * group)3341 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3342 GtkCMCTreeNode *node = NULL;
3343 GtkCMCTreeRow *currRow;
3344
3345 currRow = GTK_CMCTREE_ROW( parent );
3346 if( currRow ) {
3347 node = currRow->children;
3348 while( node ) {
3349 AddressObject *obj;
3350
3351 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3352 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3353 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3354 if( g == group ) return node;
3355 }
3356 currRow = GTK_CMCTREE_ROW(node);
3357 node = currRow->sibling;
3358 }
3359 }
3360 return NULL;
3361 }
3362
addressbook_get_book_file()3363 static AddressBookFile *addressbook_get_book_file() {
3364 AddressBookFile *abf = NULL;
3365 AddressDataSource *ds = NULL;
3366
3367 ds = addressbook_find_datasource( addrbook.treeSelected );
3368 if( ds == NULL ) return NULL;
3369 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3370 return abf;
3371 }
3372
addressbook_tree_remove_children(GtkCMCTree * ctree,GtkCMCTreeNode * parent)3373 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3374 GtkCMCTreeNode *node;
3375 GtkCMCTreeRow *row;
3376
3377 /* Remove existing folders and groups */
3378 row = GTK_CMCTREE_ROW( parent );
3379 if( row ) {
3380 while( (node = row->children) ) {
3381 gtk_cmctree_remove_node( ctree, node );
3382 }
3383 }
3384 }
3385
addressbook_move_nodes_up(GtkCMCTree * ctree,GtkCMCTreeNode * node)3386 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3387 GtkCMCTreeNode *parent, *child;
3388 GtkCMCTreeRow *currRow;
3389 currRow = GTK_CMCTREE_ROW( node );
3390 if( currRow ) {
3391 parent = currRow->parent;
3392 while( (child = currRow->children) ) {
3393 gtk_cmctree_move( ctree, child, parent, node );
3394 }
3395 gtk_sctree_sort_node( ctree, parent );
3396 }
3397 }
3398
addressbook_edit_address_post_cb(ItemPerson * person)3399 static void addressbook_edit_address_post_cb( ItemPerson *person )
3400 {
3401 if( person ) {
3402 #ifdef USE_LDAP
3403 AddressBookFile *abf = addressbook_get_book_file();
3404
3405 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3406 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3407 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3408 }
3409 #endif
3410 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3411 invalidate_address_completion();
3412 }
3413 addressbook_address_list_set_focus();
3414 }
3415
addressbook_address_list_set_focus(void)3416 void addressbook_address_list_set_focus( void )
3417 {
3418 if (!prefs_common.addressbook_use_editaddress_dialog) {
3419 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3420 addressbook_list_menu_setup();
3421 }
3422 }
3423
addressbook_address_list_disable_some_actions(void)3424 void addressbook_address_list_disable_some_actions(void)
3425 {
3426 /* disable address copy/pasting when editing contact's detail (embedded form) */
3427 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", FALSE );
3428 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", FALSE );
3429 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
3430 }
3431
addressbook_edit_address_cb(GtkAction * action,gpointer data)3432 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3433 addressbook_edit_address(data, 0, NULL, TRUE);
3434 }
3435
addressbook_edit_address(gpointer data,guint action,GtkWidget * widget,gboolean force_focus)3436 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3437 gboolean force_focus ) {
3438 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3439 GtkCMCTree *ctree;
3440 AddressObject *obj = NULL, *pobj = NULL;
3441 AddressDataSource *ds = NULL;
3442 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3443 gchar *name = NULL;
3444 AddressBookFile *abf = NULL;
3445
3446 if( addrbook.listSelected == NULL ) return;
3447 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3448 cm_return_if_fail(obj != NULL);
3449
3450 ctree = GTK_CMCTREE( addrbook.ctree );
3451 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3452
3453 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3454 if( ds == NULL ) return;
3455
3456 abf = addressbook_get_book_file();
3457
3458 if( obj->type == ADDR_ITEM_EMAIL ) {
3459 ItemEMail *email = ( ItemEMail * ) obj;
3460
3461 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3462 /* Edit parent group */
3463 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3464 ItemGroup *itemGrp = adapter->itemGroup;
3465 if( abf == NULL ) return;
3466 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3467 name = ADDRITEM_NAME(itemGrp);
3468 node = addrbook.treeSelected;
3469 parentNode = GTK_CMCTREE_ROW(node)->parent;
3470 }
3471 else {
3472 /* Edit person - email page */
3473 ItemPerson *person;
3474 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3475 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3476 addressbook_edit_address_post_cb,
3477 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3478 != NULL ) {
3479 #ifdef USE_LDAP
3480 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3481 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3482 person->status = UPDATE_ENTRY;
3483 }
3484 #endif
3485 if (prefs_common.addressbook_use_editaddress_dialog)
3486 addressbook_edit_address_post_cb( person );
3487 }
3488 return;
3489 }
3490 }
3491 else if( obj->type == ADDR_ITEM_PERSON ) {
3492 /* Edit person - basic page */
3493 ItemPerson *person = ( ItemPerson * ) obj;
3494 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3495 addressbook_edit_address_post_cb,
3496 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3497 != NULL ) {
3498 #ifdef USE_LDAP
3499 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3500 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3501 person->status = UPDATE_ENTRY;
3502 }
3503 #endif
3504 if (prefs_common.addressbook_use_editaddress_dialog)
3505 addressbook_edit_address_post_cb( person );
3506 }
3507 return;
3508 }
3509 else if( obj->type == ADDR_ITEM_GROUP ) {
3510 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3511 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3512 parentNode = addrbook.treeSelected;
3513 node = addressbook_find_group_node( parentNode, itemGrp );
3514 name = ADDRITEM_NAME(itemGrp);
3515 invalidate_address_completion();
3516 }
3517 else {
3518 return;
3519 }
3520
3521 /* Update tree node with node name */
3522 if( node == NULL ) return;
3523 addressbook_change_node_name( node, name );
3524 gtk_sctree_sort_node( ctree, parentNode );
3525 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3526 addressbook_set_clist(
3527 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3528 addrbook.opened),
3529 TRUE);
3530 }
3531
addressbook_delete_address_cb(GtkAction * action,gpointer data)3532 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3533 {
3534 addressbook_del_clicked(NULL, NULL);
3535 }
3536
close_cb(GtkAction * action,gpointer data)3537 static void close_cb(GtkAction *action, gpointer data)
3538 {
3539 addressbook_close();
3540 }
3541
addressbook_file_save_cb(GtkAction * action,gpointer data)3542 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3543 addressbook_export_to_file();
3544 }
3545
addressbook_person_expand_node(GtkCMCTree * ctree,GList * node,gpointer * data)3546 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3547 if( node ) {
3548 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3549 if( person ) addritem_person_set_opened( person, TRUE );
3550 }
3551 }
3552
addressbook_person_collapse_node(GtkCMCTree * ctree,GList * node,gpointer * data)3553 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3554 if( node ) {
3555 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3556 if( person ) addritem_person_set_opened( person, FALSE );
3557 }
3558 }
3559
addressbook_format_item_clist(ItemPerson * person,ItemEMail * email)3560 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3561 gchar *str = NULL;
3562 gchar *eMailAlias = ADDRITEM_NAME(email);
3563 if( eMailAlias && *eMailAlias != '\0' ) {
3564 if( person ) {
3565 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3566 }
3567 else {
3568 str = g_strdup( eMailAlias );
3569 }
3570 }
3571 return str;
3572 }
3573
addressbook_match_item(const gchar * name,const gchar * email_alias,const gchar * addr,const gchar * remarks,const gchar * str)3574 static gboolean addressbook_match_item(const gchar *name,
3575 const gchar *email_alias,
3576 const gchar *addr,
3577 const gchar *remarks,
3578 const gchar *str)
3579 {
3580 if (!name)
3581 return FALSE;
3582 if (!str || str[0] == '\0')
3583 return TRUE;
3584 if (strcasestr(name, str))
3585 return TRUE;
3586 else if (email_alias && strcasestr(email_alias, str))
3587 return TRUE;
3588 else if (addr && strcasestr(addr, str))
3589 return TRUE;
3590 else if (remarks && strcasestr(remarks, str))
3591 return TRUE;
3592
3593 return FALSE;
3594 }
3595
addressbook_load_group(GtkCMCTree * clist,ItemGroup * itemGroup)3596 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3597 GList *items = itemGroup->listEMail;
3598 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3599 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3600 for( ; items != NULL; items = g_list_next( items ) ) {
3601 GtkCMCTreeNode *nodeEMail = NULL;
3602 gchar *text[N_LIST_COLS];
3603 ItemEMail *email = items->data;
3604 ItemPerson *person;
3605 gchar *str = NULL;
3606
3607 if( ! email ) continue;
3608
3609 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3610
3611 if( !addressbook_match_item(ADDRITEM_NAME(person),
3612 ADDRITEM_NAME(email),
3613 email->address, email->remarks,
3614 search_str))
3615 continue;
3616
3617 str = addressbook_format_item_clist( person, email );
3618 if( str ) {
3619 text[COL_NAME] = addressbook_set_col_name_guard(str);
3620 }
3621 else {
3622 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3623 }
3624 text[COL_ADDRESS] = email->address;
3625 text[COL_REMARKS] = email->remarks;
3626 nodeEMail = gtk_sctree_insert_node(
3627 clist, NULL, NULL,
3628 text, FOLDER_SPACING,
3629 atci->iconXpm,
3630 atci->iconXpmOpen,
3631 FALSE, FALSE );
3632 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3633 g_free( str );
3634 str = NULL;
3635 }
3636 }
3637
addressbook_set_col_name_guard(gchar * value)3638 gchar *addressbook_set_col_name_guard(gchar *value)
3639 {
3640 gchar *ret = "<not set>";
3641 gchar *tmp = g_strdup(value);
3642 g_strstrip(tmp);
3643 if (tmp !=NULL && *tmp != '\0')
3644 ret = value;
3645 g_free(tmp);
3646 return ret;
3647 }
3648
addressbook_folder_load_one_person(GtkCMCTree * clist,ItemPerson * person,AddressTypeControlItem * atci,AddressTypeControlItem * atciMail)3649 static void addressbook_folder_load_one_person(
3650 GtkCMCTree *clist, ItemPerson *person,
3651 AddressTypeControlItem *atci,
3652 AddressTypeControlItem *atciMail )
3653 {
3654 GtkCMCTreeNode *nodePerson = NULL;
3655 GtkCMCTreeNode *nodeEMail = NULL;
3656 gchar *text[N_LIST_COLS];
3657 gboolean flgFirst = TRUE, haveAddr = FALSE;
3658 GList *node;
3659 #ifdef USE_LDAP
3660 AddressBookFile *abf = addressbook_get_book_file();
3661 #endif
3662
3663 if( person == NULL ) return;
3664
3665 text[COL_NAME] = "";
3666 node = person->listEMail;
3667 while( node ) {
3668 ItemEMail *email = node->data;
3669 gchar *eMailAddr = NULL;
3670 node = g_list_next( node );
3671
3672 text[COL_ADDRESS] = email->address;
3673 text[COL_REMARKS] = email->remarks;
3674 eMailAddr = ADDRITEM_NAME(email);
3675 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3676 if( flgFirst ) {
3677 /* First email belongs with person */
3678 gchar *str = addressbook_format_item_clist( person, email );
3679 if( str ) {
3680 text[COL_NAME] = addressbook_set_col_name_guard(str);
3681 }
3682 #ifdef USE_LDAP
3683 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3684 person && person->nickName ) {
3685 if (person->nickName) {
3686 if (strcmp(person->nickName, "") != 0) {
3687 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3688 }
3689 else {
3690 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3691 }
3692 }
3693 }
3694 #endif
3695 else {
3696 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3697 }
3698 nodePerson = gtk_sctree_insert_node(
3699 clist, NULL, NULL,
3700 text, FOLDER_SPACING,
3701 atci->iconXpm,
3702 atci->iconXpmOpen,
3703 FALSE, person->isOpened );
3704 g_free( str );
3705 str = NULL;
3706 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3707 }
3708 else {
3709 /* Subsequent email is a child node of person */
3710 text[COL_NAME] = ADDRITEM_NAME(email);
3711 nodeEMail = gtk_sctree_insert_node(
3712 clist, nodePerson, NULL,
3713 text, FOLDER_SPACING,
3714 atciMail->iconXpm,
3715 atciMail->iconXpmOpen,
3716 FALSE, TRUE );
3717 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3718 }
3719 flgFirst = FALSE;
3720 haveAddr = TRUE;
3721 }
3722 if( ! haveAddr ) {
3723 /* Have name without EMail */
3724 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3725 text[COL_ADDRESS] = "";
3726 text[COL_REMARKS] = "";
3727 nodePerson = gtk_sctree_insert_node(
3728 clist, NULL, NULL,
3729 text, FOLDER_SPACING,
3730 atci->iconXpm,
3731 atci->iconXpmOpen,
3732 FALSE, person->isOpened );
3733 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3734 }
3735 return;
3736 }
3737
addressbook_folder_load_person(GtkCMCTree * clist,ItemFolder * itemFolder)3738 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3739 GList *items, *cur;
3740 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3741 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3742 const gchar *search_str;
3743
3744 if( atci == NULL ) return;
3745 if( atciMail == NULL ) return;
3746
3747 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3748
3749 /* Load email addresses */
3750 items = addritem_folder_get_person_list( itemFolder );
3751 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3752 ItemPerson *person;
3753 GList *node;
3754 ItemEMail *email;
3755
3756 person = (ItemPerson *)cur->data;
3757 if (!person)
3758 continue;
3759 node = person->listEMail;
3760 if (node && node->data) {
3761 email = node->data;
3762 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3763 continue;
3764 } else {
3765 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3766 continue;
3767 }
3768
3769 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3770 }
3771 /* Free up the list */
3772 g_list_free( items );
3773 }
3774
addressbook_folder_remove_node(GtkCMCTree * clist,GtkCMCTreeNode * node)3775 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3776 addrbook.listSelected = NULL;
3777 gtk_cmctree_remove_node( clist, node );
3778 addressbook_menubar_set_sensitive( FALSE );
3779 addressbook_menuitem_set_sensitive(
3780 gtk_cmctree_node_get_row_data(
3781 GTK_CMCTREE(clist), addrbook.treeSelected ),
3782 addrbook.treeSelected );
3783 }
3784
addressbook_folder_refresh_one_person(GtkCMCTree * clist,ItemPerson * person)3785 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3786 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3787 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3788 GtkCMCTreeNode *node;
3789 if( atci == NULL ) return;
3790 if( atciMail == NULL ) return;
3791 if( person == NULL ) return;
3792 /* unload the person */
3793
3794 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3795 if( node )
3796 addressbook_folder_remove_node( clist, node );
3797 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3798 gtk_sctree_sort_node( clist, NULL );
3799 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3800 if( node ) {
3801 gtk_sctree_select( GTK_SCTREE(clist), node );
3802 if (!gtk_cmctree_node_is_visible( clist, node ) )
3803 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3804 }
3805 }
3806
addressbook_folder_remove_one_person(GtkCMCTree * clist,ItemPerson * person)3807 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3808 GtkCMCTreeNode *node;
3809
3810 if( person == NULL ) return;
3811 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3812 if( node ) {
3813 addressbook_folder_remove_node( clist, node );
3814 }
3815 }
3816
addressbook_folder_load_group(GtkCMCTree * clist,ItemFolder * itemFolder)3817 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3818 GList *items;
3819 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3820 const gchar *search_str;
3821
3822 /* Load any groups */
3823 if( ! atci ) return;
3824
3825 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3826
3827 items = addritem_folder_get_group_list( itemFolder );
3828 for( ; items != NULL; items = g_list_next( items ) ) {
3829 GtkCMCTreeNode *nodeGroup = NULL;
3830 gchar *text[N_LIST_COLS];
3831 ItemGroup *group = items->data;
3832 if( group == NULL ) continue;
3833 if( !addressbook_match_item(ADDRITEM_NAME(group),
3834 NULL, NULL, NULL, search_str) )
3835 continue;
3836
3837 text[COL_NAME] = ADDRITEM_NAME(group);
3838 text[COL_ADDRESS] = "";
3839 text[COL_REMARKS] = "";
3840 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3841 text, FOLDER_SPACING,
3842 atci->iconXpm,
3843 atci->iconXpmOpen,
3844 FALSE, FALSE);
3845 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3846 gtk_sctree_sort_node(clist, NULL);
3847 }
3848 /* Free up the list */
3849 g_list_free( items );
3850 }
3851
3852 /**
3853 * Search ctree widget callback function.
3854 * \param pA Pointer to node.
3855 * \param pB Pointer to data item being sought.
3856 * \return Zero (0) if group found.
3857 */
addressbook_treenode_find_group_cb(gconstpointer pA,gconstpointer pB)3858 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3859 AddressObject *aoA;
3860
3861 aoA = ( AddressObject * ) pA;
3862 if( aoA->type == ADDR_ITEM_GROUP ) {
3863 ItemGroup *group, *grp;
3864
3865 grp = ADAPTER_GROUP(aoA)->itemGroup;
3866 group = ( ItemGroup * ) pB;
3867 if( grp == group ) return 0; /* Found group */
3868 }
3869 return 1;
3870 }
3871
3872 /*
3873 * Remove folder and group nodes from tree widget for items contained ("cut")
3874 * in clipboard.
3875 */
addressbook_treenode_remove_item(void)3876 static void addressbook_treenode_remove_item( void ) {
3877 GList *node;
3878 AddrSelectItem *cutItem;
3879 AddressCache *cache;
3880 AddrItemObject *aio;
3881 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3882 GtkCMCTreeNode *tn;
3883
3884 node = _clipBoard_->objectList;
3885 while( node ) {
3886 cutItem = node->data;
3887 node = g_list_next( node );
3888 cache = addrindex_get_cache(
3889 _clipBoard_->addressIndex, cutItem->cacheID );
3890 if( cache == NULL ) continue;
3891 aio = addrcache_get_object( cache, cutItem->uid );
3892 if( aio ) {
3893 tn = NULL;
3894 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3895 ItemFolder *folder;
3896
3897 folder = ( ItemFolder * ) aio;
3898 tn = gtk_cmctree_find_by_row_data_custom(
3899 ctree, NULL, folder,
3900 addressbook_treenode_find_folder_cb );
3901 }
3902 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3903 ItemGroup *group;
3904
3905 group = ( ItemGroup * ) aio;
3906 tn = gtk_cmctree_find_by_row_data_custom(
3907 ctree, NULL, group,
3908 addressbook_treenode_find_group_cb );
3909 }
3910
3911 if( tn ) {
3912 /* Free up adapter and remove node. */
3913 gtk_cmctree_remove_node( ctree, tn );
3914 }
3915 }
3916 }
3917 }
3918
3919 /**
3920 * Find parent datasource for specified tree node.
3921 * \param node Node to test.
3922 * \return Data source, or NULL if not found.
3923 */
addressbook_find_datasource(GtkCMCTreeNode * node)3924 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3925 AddressDataSource *ds = NULL;
3926 AddressObject *ao;
3927
3928 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3929
3930 while( node ) {
3931 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3932 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3933 if( ao ) {
3934 /* g_print( "ao->type = %d\n", ao->type ); */
3935 if( ao->type == ADDR_DATASOURCE ) {
3936 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3937 /* g_print( "found it\n" ); */
3938 ds = ads->dataSource;
3939 break;
3940 }
3941 }
3942 node = GTK_CMCTREE_ROW(node)->parent;
3943 }
3944 return ds;
3945 }
3946
3947 /**
3948 * Load address list widget with children of specified object.
3949 * \param obj Parent object to be loaded.
3950 */
addressbook_set_clist(AddressObject * obj,gboolean refresh)3951 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3952 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3953 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3954 AddressDataSource *ds = NULL;
3955 AdapterDSource *ads = NULL;
3956 static AddressObject *last_obj = NULL;
3957
3958 if (addrbook.clist == NULL) {
3959 return;
3960 }
3961 if (obj == last_obj && !refresh)
3962 return;
3963
3964 last_obj = obj;
3965 if( obj == NULL ) {
3966 gtk_cmclist_clear(clist);
3967 return;
3968 }
3969
3970 if( obj->type == ADDR_INTERFACE ) {
3971 /* g_print( "set_clist: loading datasource...\n" ); */
3972 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3973 return;
3974 }
3975
3976 gtk_cmclist_freeze(clist);
3977 gtk_cmclist_clear(clist);
3978
3979 if( obj->type == ADDR_DATASOURCE ) {
3980 ads = ADAPTER_DSOURCE(obj);
3981 ds = ads->dataSource;
3982 if( ds ) {
3983 /* Load root folder */
3984 ItemFolder *rootFolder = NULL;
3985 rootFolder = addrindex_ds_get_root_folder( ds );
3986 addressbook_folder_load_person(
3987 ctreelist, rootFolder );
3988 addressbook_folder_load_group(
3989 ctreelist, rootFolder );
3990 }
3991 }
3992 else {
3993 if( obj->type == ADDR_ITEM_GROUP ) {
3994 /* Load groups */
3995 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3996 addressbook_load_group( ctreelist, itemGroup );
3997 }
3998 else if( obj->type == ADDR_ITEM_FOLDER ) {
3999 /* Load folders */
4000 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4001 addressbook_folder_load_person( ctreelist, itemFolder );
4002 addressbook_folder_load_group( ctreelist, itemFolder );
4003 }
4004 }
4005 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4006 clist->focus_row = -1;
4007 gtk_cmclist_thaw(clist);
4008 }
4009
4010 /**
4011 * Call back function to free adaptor. Call back is setup by function
4012 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4013 * called when the address book tree widget node is removed by calling
4014 * function gtk_cmctree_remove_node().
4015 *
4016 * \param data Tree node's row data.
4017 */
addressbook_free_treenode(gpointer data)4018 static void addressbook_free_treenode( gpointer data ) {
4019 AddressObject *ao;
4020
4021 ao = ( AddressObject * ) data;
4022 if( ao == NULL ) return;
4023 if( ao->type == ADDR_INTERFACE ) {
4024 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4025 addrbookctl_free_interface( ai );
4026 }
4027 else if( ao->type == ADDR_DATASOURCE ) {
4028 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4029 addrbookctl_free_datasource( ads );
4030 }
4031 else if( ao->type == ADDR_ITEM_FOLDER ) {
4032 AdapterFolder *af = ADAPTER_FOLDER(ao);
4033 addrbookctl_free_folder( af );
4034 }
4035 else if( ao->type == ADDR_ITEM_GROUP ) {
4036 AdapterGroup *ag = ADAPTER_GROUP(ao);
4037 addrbookctl_free_group( ag );
4038 }
4039 }
4040
4041 /*
4042 * Create new adaptor for specified data source.
4043 */
addressbook_create_ds_adapter(AddressDataSource * ds,AddressObjectType otype,gchar * name)4044 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4045 AddressObjectType otype, gchar *name )
4046 {
4047 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4048 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4049 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4050 adapter->dataSource = ds;
4051 adapter->subType = otype;
4052 return adapter;
4053 }
4054
addressbook_ads_set_name(AdapterDSource * adapter,gchar * value)4055 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4056 ADDRESS_OBJECT_NAME(adapter) =
4057 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4058 }
4059
4060 /*
4061 * Load tree from address index with the initial data.
4062 */
addressbook_load_tree(void)4063 static void addressbook_load_tree( void ) {
4064 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4065 GList *nodeIf, *nodeDS;
4066 AdapterInterface *adapter;
4067 AddressInterface *iface;
4068 AddressTypeControlItem *atci;
4069 AddressDataSource *ds;
4070 AdapterDSource *ads;
4071 GtkCMCTreeNode *node, *newNode;
4072 gchar *name;
4073
4074 nodeIf = _addressInterfaceList_;
4075 while( nodeIf ) {
4076 adapter = nodeIf->data;
4077 node = adapter->treeNode;
4078 iface = adapter->interface;
4079 atci = adapter->atci;
4080 if( iface ) {
4081 if( iface->useInterface ) {
4082 /* Load data sources below interface node */
4083 nodeDS = iface->listSource;
4084 while( nodeDS ) {
4085 ds = nodeDS->data;
4086 name = addrindex_ds_get_name( ds );
4087 ads = addressbook_create_ds_adapter(
4088 ds, atci->objectType, name );
4089 newNode = addressbook_add_object(
4090 node, ADDRESS_OBJECT(ads) );
4091 if (newNode == NULL) {
4092 g_message("error adding addressbook object\n");
4093 }
4094 nodeDS = g_list_next( nodeDS );
4095 }
4096 gtk_cmctree_expand( ctree, node );
4097 }
4098 }
4099 nodeIf = g_list_next( nodeIf );
4100 }
4101 }
4102
4103 /*
4104 * Convert the old address book to new format.
4105 */
addressbook_convert(AddressIndex * addrIndex)4106 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4107 gboolean retVal = FALSE;
4108 gboolean errFlag = TRUE;
4109 gchar *msg = NULL;
4110
4111 /* Read old address book, performing conversion */
4112 debug_print( "Reading and converting old address book...\n" );
4113 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4114 addrindex_read_data( addrIndex );
4115 if( addrIndex->retVal == MGU_NO_FILE ) {
4116 /* We do not have a file - new user */
4117 debug_print( "New user... create new books...\n" );
4118 addrindex_create_new_books( addrIndex );
4119 if( addrIndex->retVal == MGU_SUCCESS ) {
4120 /* Save index file */
4121 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4122 addrindex_save_data( addrIndex );
4123 if( addrIndex->retVal == MGU_SUCCESS ) {
4124 retVal = TRUE;
4125 errFlag = FALSE;
4126 }
4127 else {
4128 msg = _( "New user, could not save index file." );
4129 }
4130 }
4131 else {
4132 msg = _( "New user, could not save address book files." );
4133 }
4134 }
4135 else {
4136 /* We have an old file */
4137 if( addrIndex->wasConverted ) {
4138 /* Converted successfully - save address index */
4139 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4140 addrindex_save_data( addrIndex );
4141 if( addrIndex->retVal == MGU_SUCCESS ) {
4142 msg = _( "Old address book converted successfully." );
4143 retVal = TRUE;
4144 errFlag = FALSE;
4145 }
4146 else {
4147 msg = _("Old address book converted,\n"
4148 "could not save new address index file." );
4149 }
4150 }
4151 else {
4152 /* File conversion failed - just create new books */
4153 debug_print( "File conversion failed... just create new books...\n" );
4154 addrindex_create_new_books( addrIndex );
4155 if( addrIndex->retVal == MGU_SUCCESS ) {
4156 /* Save index */
4157 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4158 addrindex_save_data( addrIndex );
4159 if( addrIndex->retVal == MGU_SUCCESS ) {
4160 msg = _("Could not convert address book,\n"
4161 "but created empty new address book files." );
4162 retVal = TRUE;
4163 errFlag = FALSE;
4164 }
4165 else {
4166 msg = _("Could not convert address book,\n"
4167 "could not save new address index file." );
4168 }
4169 }
4170 else {
4171 msg = _("Could not convert address book\n"
4172 "and could not create new address book files." );
4173 }
4174 }
4175 }
4176 if( errFlag ) {
4177 debug_print( "Error\n%s\n", msg );
4178 alertpanel_full(_("Addressbook conversion error"), msg,
4179 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4180 NULL, ALERT_ERROR);
4181 }
4182 else if( msg ) {
4183 debug_print( "Warning\n%s\n", msg );
4184 alertpanel_full(_("Addressbook conversion error"), msg,
4185 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4186 NULL, ALERT_WARNING);
4187 }
4188
4189 return retVal;
4190 }
4191
migrate_addrbook(const gchar * origdir,const gchar * destdir)4192 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4193 {
4194 GDir *dp;
4195 const gchar *d;
4196 gboolean failed = FALSE;
4197 GError *error = NULL;
4198
4199 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4200 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4201 error->code, error->message);
4202 g_error_free(error);
4203 return FALSE;
4204 }
4205
4206 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4207 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4208 continue;
4209 else {
4210 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4211 d, NULL);
4212 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4213 d, NULL);
4214 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4215 failed = TRUE;
4216 }
4217 g_free(orig_file);
4218 g_free(dest_file);
4219 if (failed) {
4220 break;
4221 }
4222 }
4223 }
4224 g_dir_close( dp );
4225
4226 if (!failed) {
4227 /* all copies succeeded, we can remove source files */
4228 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4229 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4230 error->code, error->message);
4231 g_error_free(error);
4232 return FALSE;
4233 }
4234 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4235 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4236 continue;
4237 else {
4238 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4239 d, NULL);
4240 claws_unlink(orig_file);
4241 g_free(orig_file);
4242 }
4243 }
4244 g_dir_close( dp );
4245 }
4246
4247 return !failed;
4248 }
4249
addressbook_read_file(void)4250 void addressbook_read_file( void ) {
4251 AddressIndex *addrIndex = NULL;
4252 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4253
4254 debug_print( "Reading address index...\n" );
4255 if( _addressIndex_ ) {
4256 debug_print( "address book already read!!!\n" );
4257 g_free(indexdir);
4258 return;
4259 }
4260
4261 addrIndex = addrindex_create_index();
4262 addrindex_initialize();
4263
4264 /* Use new address book index. */
4265
4266 if ( !is_dir_exist(indexdir) ) {
4267 if ( make_dir(indexdir) < 0 ) {
4268 addrindex_set_file_path( addrIndex, get_rc_dir() );
4269 g_warning( "couldn't create dir '%s'", indexdir);
4270 } else {
4271 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4272 remove_dir_recursive(indexdir);
4273 addrindex_set_file_path( addrIndex, get_rc_dir() );
4274 g_error("couldn't migrate dir %s", indexdir);
4275 } else {
4276 addrindex_set_file_path( addrIndex, indexdir);
4277 }
4278 }
4279 } else {
4280 addrindex_set_file_path( addrIndex, indexdir);
4281 }
4282 g_free(indexdir);
4283 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4284 addrindex_read_data( addrIndex );
4285 if( addrIndex->retVal == MGU_NO_FILE ) {
4286 /* Conversion required */
4287 debug_print( "Converting...\n" );
4288 if( addressbook_convert( addrIndex ) ) {
4289 _addressIndex_ = addrIndex;
4290 }
4291 }
4292 else if( addrIndex->retVal == MGU_SUCCESS ) {
4293 _addressIndex_ = addrIndex;
4294 }
4295 else {
4296 /* Error reading address book */
4297 debug_print( "Could not read address index.\n" );
4298 addrindex_print_index( addrIndex, stdout );
4299 alertpanel_full(_("Addressbook Error"),
4300 _("Could not read address index"),
4301 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4302 NULL, ALERT_ERROR);
4303 }
4304 debug_print( "done.\n" );
4305 }
4306
4307 /*
4308 * Add object into the address index tree widget.
4309 * Enter: node Parent node.
4310 * obj Object to add.
4311 * Return: Node that was added, or NULL if object not added.
4312 */
addressbook_add_object(GtkCMCTreeNode * node,AddressObject * obj)4313 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4314 AddressObject *obj)
4315 {
4316 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4317 GtkCMCTreeNode *added;
4318 AddressObject *pobj;
4319 AddressObjectType otype;
4320 AddressTypeControlItem *atci = NULL;
4321
4322 cm_return_val_if_fail(node != NULL, NULL);
4323 cm_return_val_if_fail(obj != NULL, NULL);
4324
4325 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4326 cm_return_val_if_fail(pobj != NULL, NULL);
4327
4328 /* Determine object type to be displayed */
4329 if( obj->type == ADDR_DATASOURCE ) {
4330 otype = ADAPTER_DSOURCE(obj)->subType;
4331 }
4332 else {
4333 otype = obj->type;
4334 }
4335
4336 /* Handle any special conditions. */
4337 added = node;
4338 atci = addrbookctl_lookup( otype );
4339 if( atci ) {
4340 if( atci->showInTree ) {
4341 /* Add object to tree */
4342 gchar **name;
4343 name = &obj->name;
4344 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4345 atci->iconXpm, atci->iconXpmOpen,
4346 atci->treeLeaf, atci->treeExpand );
4347 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4348 addressbook_free_treenode );
4349 }
4350 }
4351
4352 gtk_sctree_sort_node(ctree, node);
4353
4354 return added;
4355 }
4356
4357 /**
4358 * Add group into the address index tree.
4359 * \param node Parent node.
4360 * \param ds Data source.
4361 * \param itemGroup Group to add.
4362 * \return Inserted node.
4363 */
addressbook_node_add_group(GtkCMCTreeNode * node,AddressDataSource * ds,ItemGroup * itemGroup)4364 static GtkCMCTreeNode *addressbook_node_add_group(
4365 GtkCMCTreeNode *node, AddressDataSource *ds,
4366 ItemGroup *itemGroup )
4367 {
4368 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4369 GtkCMCTreeNode *newNode;
4370 AdapterGroup *adapter;
4371 AddressTypeControlItem *atci = NULL;
4372 gchar **name;
4373
4374 if( ds == NULL ) return NULL;
4375 if( node == NULL || itemGroup == NULL ) return NULL;
4376
4377 name = &itemGroup->obj.name;
4378
4379 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4380
4381 adapter = g_new0( AdapterGroup, 1 );
4382 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4383 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4384 adapter->itemGroup = itemGroup;
4385
4386 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4387 atci->iconXpm, atci->iconXpm,
4388 atci->treeLeaf, atci->treeExpand );
4389 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4390 addressbook_free_treenode );
4391 gtk_sctree_sort_node( ctree, node );
4392 return newNode;
4393 }
4394
4395 /**
4396 * Add folder into the address index tree. Only visible folders are loaded into
4397 * the address index tree. Note that the root folder is not inserted into the
4398 * tree.
4399 *
4400 * \param node Parent node.
4401 * \param ds Data source.
4402 * \param itemFolder Folder to add.
4403 * \param otype Object type to display.
4404 * \return Inserted node for the folder.
4405 */
addressbook_node_add_folder(GtkCMCTreeNode * node,AddressDataSource * ds,ItemFolder * itemFolder,AddressObjectType otype)4406 static GtkCMCTreeNode *addressbook_node_add_folder(
4407 GtkCMCTreeNode *node, AddressDataSource *ds,
4408 ItemFolder *itemFolder, AddressObjectType otype )
4409 {
4410 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4411 GtkCMCTreeNode *newNode = NULL;
4412 AdapterFolder *adapter;
4413 AddressTypeControlItem *atci = NULL;
4414 GList *listItems = NULL;
4415 gchar *name;
4416 ItemFolder *rootFolder;
4417
4418 /* Only visible folders */
4419 if( itemFolder == NULL || itemFolder->isHidden )
4420 return NULL;
4421
4422 if( ds == NULL )
4423 return NULL;
4424 if( node == NULL || itemFolder == NULL )
4425 return NULL;
4426
4427 /* Determine object type */
4428 atci = addrbookctl_lookup( otype );
4429 if( atci == NULL )
4430 return NULL;
4431
4432 rootFolder = addrindex_ds_get_root_folder( ds );
4433 if( itemFolder == rootFolder ) {
4434 newNode = node;
4435 }
4436 else {
4437 adapter = g_new0( AdapterFolder, 1 );
4438 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4439 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4440 adapter->itemFolder = itemFolder;
4441
4442 name = ADDRITEM_NAME(itemFolder);
4443 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4444 atci->iconXpm, atci->iconXpm,
4445 atci->treeLeaf, atci->treeExpand );
4446 if( newNode ) {
4447 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4448 addressbook_free_treenode );
4449 }
4450 }
4451
4452 listItems = itemFolder->listFolder;
4453 while( listItems ) {
4454 ItemFolder *item = listItems->data;
4455 addressbook_node_add_folder( newNode, ds, item, otype );
4456 listItems = g_list_next( listItems );
4457 }
4458 listItems = itemFolder->listGroup;
4459 while( listItems ) {
4460 ItemGroup *item = listItems->data;
4461 addressbook_node_add_group( newNode, ds, item );
4462 listItems = g_list_next( listItems );
4463 }
4464 gtk_sctree_sort_node( ctree, node );
4465 return newNode;
4466 }
4467
addressbook_export_to_file(void)4468 void addressbook_export_to_file( void ) {
4469 if( _addressIndex_ ) {
4470 /* Save all new address book data */
4471 debug_print( "Saving address books...\n" );
4472 addrindex_save_all_books( _addressIndex_ );
4473
4474 debug_print( "Exporting addressbook to file...\n" );
4475 addrindex_save_data( _addressIndex_ );
4476 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4477 addrindex_print_index( _addressIndex_, stdout );
4478 }
4479
4480 /* Notify address completion of new data */
4481 invalidate_address_completion();
4482 }
4483 }
4484
addressbook_entry_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer data)4485 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4486 {
4487 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4488 addressbook_lup_clicked(NULL, NULL);
4489 return FALSE;
4490 }
4491
4492 /*
4493 * Comparison using cell contents (text in first column). Used for sort
4494 * address index widget.
4495 */
addressbook_treenode_compare_func(GtkCMCList * clist,gconstpointer ptr1,gconstpointer ptr2)4496 static gint addressbook_treenode_compare_func(
4497 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4498 {
4499 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4500 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4501 gchar *name1 = NULL, *name2 = NULL;
4502 if( cell1 ) name1 = cell1->u.text;
4503 if( cell2 ) name2 = cell2->u.text;
4504 if( ! name1 ) return ( name2 != NULL );
4505 if( ! name2 ) return -1;
4506 return g_utf8_collate( name1, name2 );
4507 }
4508
addressbook_new_book_cb(GtkAction * action,gpointer data)4509 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4510 AdapterDSource *ads;
4511 AdapterInterface *adapter;
4512 GtkCMCTreeNode *newNode;
4513
4514 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4515 if( adapter == NULL ) return;
4516 ads = addressbook_edit_book( _addressIndex_, NULL );
4517 if( ads ) {
4518 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4519 if( newNode ) {
4520 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4521 addrbook.treeSelected = newNode;
4522 }
4523 }
4524 }
4525
addressbook_new_vcard_cb(GtkAction * action,gpointer data)4526 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4527 AdapterDSource *ads;
4528 AdapterInterface *adapter;
4529 GtkCMCTreeNode *newNode;
4530
4531 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4532 if( adapter == NULL ) return;
4533 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4534 if( ads ) {
4535 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4536 if( newNode ) {
4537 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4538 addrbook.treeSelected = newNode;
4539 }
4540 }
4541 }
4542
4543 #ifdef USE_JPILOT
addressbook_new_jpilot_cb(GtkAction * action,gpointer data)4544 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4545 AdapterDSource *ads;
4546 AdapterInterface *adapter;
4547 AddressInterface *iface;
4548 GtkCMCTreeNode *newNode;
4549
4550 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4551 if( adapter == NULL ) return;
4552 iface = adapter->interface;
4553 if( ! iface->haveLibrary ) return;
4554 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4555 if( ads ) {
4556 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4557 if( newNode ) {
4558 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4559 addrbook.treeSelected = newNode;
4560 }
4561 }
4562 }
4563 #endif
4564
4565 #ifdef USE_LDAP
addressbook_new_ldap_cb(GtkAction * action,gpointer data)4566 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4567 AdapterDSource *ads;
4568 AdapterInterface *adapter;
4569 AddressInterface *iface;
4570 GtkCMCTreeNode *newNode;
4571
4572 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4573 if( adapter == NULL ) return;
4574 iface = adapter->interface;
4575 if( ! iface->haveLibrary ) return;
4576 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4577 if( ads ) {
4578 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4579 if( newNode ) {
4580 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4581 addrbook.treeSelected = newNode;
4582 }
4583 }
4584 }
4585 #endif
4586
4587 /**
4588 * Display address search status message.
4589 * \param queryType Query type.
4590 * \param status Status/Error code.
4591 */
addressbook_search_message(gint queryType,gint sts)4592 static void addressbook_search_message( gint queryType, gint sts ) {
4593 gchar *desc = NULL;
4594 *addressbook_msgbuf = '\0';
4595
4596 if( sts != MGU_SUCCESS ) {
4597 if( queryType == ADDRQUERY_LDAP ) {
4598 #ifdef USE_LDAP
4599 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4600 #endif
4601 }
4602 }
4603 if( desc ) {
4604 g_snprintf( addressbook_msgbuf,
4605 sizeof(addressbook_msgbuf), "%s", desc );
4606 addressbook_status_show( addressbook_msgbuf );
4607 }
4608 else {
4609 addressbook_status_show( "" );
4610 }
4611 }
4612
4613 /**
4614 * Refresh addressbook by forcing refresh of current selected object in
4615 * tree.
4616 */
addressbook_refresh_current(void)4617 static void addressbook_refresh_current( void ) {
4618 AddressObject *obj;
4619 GtkCMCTree *ctree;
4620
4621 ctree = GTK_CMCTREE(addrbook.ctree);
4622 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4623 if( obj == NULL ) return;
4624 addressbook_set_clist( obj, TRUE );
4625 }
4626
4627 /**
4628 * Message that is displayed whilst a query is executing in a background
4629 * thread.
4630 */
4631 static gchar *_tempMessage_ = N_( "Busy searching..." );
4632
4633 /**
4634 * Address search idle function. This function is called during UI idle time
4635 * while a search is in progress.
4636 *
4637 * \param data Idler data.
4638 */
addressbook_search_idle(gpointer data)4639 static void addressbook_search_idle( gpointer data ) {
4640 /*
4641 gint queryID;
4642
4643 queryID = GPOINTER_TO_INT( data );
4644 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4645 */
4646 }
4647
4648 /**
4649 * Search completion callback function. This removes the query from the idle
4650 * list.
4651 *
4652 * \param sender Sender of query.
4653 * \param queryID Query ID of search request.
4654 * \param status Search status.
4655 * \param data Query data.
4656 */
addressbook_search_callback_end(gpointer sender,gint queryID,gint status,gpointer data)4657 static void addressbook_search_callback_end(
4658 gpointer sender, gint queryID, gint status, gpointer data )
4659 {
4660 gpointer ptrQID;
4661 QueryRequest *req;
4662 AddrQueryObject *aqo;
4663
4664 /* Remove idler function */
4665 ptrQID = GINT_TO_POINTER( queryID );
4666 if( ptrQID ) {
4667 g_idle_remove_by_data( ptrQID );
4668 }
4669
4670 /* Refresh addressbook contents */
4671 addressbook_refresh_current();
4672 req = qrymgr_find_request( queryID );
4673 if( req != NULL ) {
4674 aqo = ( AddrQueryObject * ) req->queryList->data;
4675 addressbook_search_message( aqo->queryType, status );
4676 }
4677
4678 /* Stop the search */
4679 addrindex_stop_search( queryID );
4680 }
4681
4682 /**
4683 * Perform search.
4684 *
4685 * \param ds Data source to search.
4686 * \param searchTerm String to lookup.
4687 * \param pNode Parent data source node.
4688 */
addressbook_perform_search(AddressDataSource * ds,gchar * searchTerm,GtkCMCTreeNode * pNode)4689 static void addressbook_perform_search(
4690 AddressDataSource *ds, gchar *searchTerm,
4691 GtkCMCTreeNode *pNode )
4692 {
4693 ItemFolder *folder;
4694 gchar *name;
4695 gint queryID;
4696 guint idleID;
4697
4698 /* Setup a query */
4699 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4700
4701 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4702
4703 /* Create a folder for the search results */
4704 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4705 folder = addressbook_setup_subf(ds, name, pNode);
4706 g_free( name );
4707
4708 /* Setup the search */
4709 queryID = addrindex_setup_explicit_search(
4710 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4711 if( queryID == 0 ) return;
4712
4713 /* Set up idler function */
4714 idleID = g_idle_add(
4715 (GSourceFunc) addressbook_search_idle,
4716 GINT_TO_POINTER( queryID ) );
4717 if (idleID == 0) {
4718 g_message("error adding addressbook_search_idle\n");
4719 }
4720
4721 /* Start search, sit back and wait for something to happen */
4722 addrindex_start_search( queryID );
4723
4724 addressbook_status_show( _tempMessage_ );
4725 }
4726
4727 /**
4728 * Lookup button handler. Address search is only performed against
4729 * address interfaces for external queries.
4730 *
4731 * \param button Lookup button widget.
4732 * \param data Data object.
4733 */
addressbook_lup_clicked(GtkButton * button,gpointer data)4734 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4735 GtkCMCTree *ctree;
4736 AddressObject *obj;
4737 AddressDataSource *ds;
4738 AddressInterface *iface;
4739 gchar *searchTerm;
4740 GtkCMCTreeNode *node, *parentNode;
4741 #ifdef USE_LDAP
4742 LdapServer *ldap_server;
4743 LdapControl *ldap_ctl;
4744 #endif
4745
4746 node = addrbook.treeSelected;
4747 if( ! node ) return;
4748 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4749
4750 ctree = GTK_CMCTREE(addrbook.ctree);
4751 obj = gtk_cmctree_node_get_row_data( ctree, node );
4752 if( obj == NULL ) return;
4753
4754 if (obj->type != ADDR_DATASOURCE ||
4755 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4756 addressbook_set_clist(
4757 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4758 addrbook.treeSelected),
4759 TRUE);
4760 }
4761
4762 ds = addressbook_find_datasource( node );
4763 if( ds == NULL ) return;
4764
4765 /* We must have a datasource that is an external interface */
4766 iface = ds->interface;
4767 if( ! iface->haveLibrary ) return;
4768 if( ! iface->externalQuery ) return;
4769
4770 #ifdef USE_LDAP
4771 if (iface->type == ADDR_IF_LDAP) {
4772 ldap_server = ds->rawDataSource;
4773 ldap_ctl = ldap_server->control;
4774 if (ldap_ctl != NULL &&
4775 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4776 #ifndef PASSWORD_CRYPTO_OLD
4777 /* LDAP server is password-protected. */
4778 if (master_passphrase() == NULL) {
4779 /* User did not enter master passphrase, do not start a search. */
4780 return;
4781 }
4782 #endif /* PASSWORD_CRYPTO_OLD */
4783 }
4784 }
4785 #endif /* USE_LDAP */
4786
4787 searchTerm =
4788 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4789 g_strchomp( searchTerm );
4790
4791 if( obj->type == ADDR_ITEM_FOLDER ) {
4792 parentNode = GTK_CMCTREE_ROW(node)->parent;
4793 }
4794 else {
4795 parentNode = node;
4796 }
4797 addressbook_perform_search( ds, searchTerm, parentNode );
4798
4799 gtk_widget_grab_focus( addrbook.entry );
4800
4801 g_free( searchTerm );
4802 }
4803
addressbook_close_clicked(GtkButton * button,gpointer data)4804 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4805 addressbook_close();
4806 }
4807
4808 #ifdef USE_LDAP
4809 /**
4810 * Browse address entry for highlighted entry.
4811 */
addressbook_browse_entry_cb(GtkAction * action,gpointer data)4812 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4813 {
4814 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4815 AddressObject *obj;
4816 AddressDataSource *ds;
4817 AddressInterface *iface;
4818 ItemPerson *person;
4819 ItemEMail *email;
4820
4821 if(addrbook.listSelected == NULL)
4822 return;
4823
4824 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4825 if (obj == NULL)
4826 return;
4827
4828 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4829 if(ds == NULL)
4830 return;
4831
4832 iface = ds->interface;
4833 if(!iface || !iface->haveLibrary )
4834 return;
4835
4836 person = NULL;
4837 if (obj->type == ADDR_ITEM_EMAIL) {
4838 email = ( ItemEMail * ) obj;
4839
4840 person = (ItemPerson *) ADDRITEM_PARENT(email);
4841 }
4842 else if (obj->type == ADDR_ITEM_PERSON) {
4843 person = (ItemPerson *) obj;
4844 }
4845 else {
4846 /* None of these */
4847 return;
4848 }
4849
4850 if( iface && iface->type == ADDR_IF_LDAP ) {
4851 browseldap_entry(ds, person->externalID);
4852 }
4853 }
4854 #endif
4855
4856 /* **********************************************************************
4857 * Build lookup tables.
4858 * ***********************************************************************
4859 */
4860
4861 /*
4862 * Remap object types.
4863 * Enter: abType AddressObjectType (used in tree node).
4864 * Return: ItemObjectType (used in address cache data).
4865 */
addressbook_type2item(AddressObjectType abType)4866 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4867 ItemObjectType ioType;
4868
4869 switch( abType ) {
4870 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4871 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4872 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4873 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4874 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4875 default: ioType = ITEMTYPE_NONE; break;
4876 }
4877 return ioType;
4878 }
4879
4880 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4881 atci = addrbookctl_lookup(id); \
4882 if (atci) { \
4883 atci->iconXpm = icon; \
4884 atci->iconXpmOpen = iconopen; \
4885 } else { \
4886 g_warning("can't get atci %d", id); \
4887 } \
4888 }
4889
4890 /*
4891 * Build table that controls the rendering of object types.
4892 */
addrbookctl_build_icons(GtkWidget * window)4893 static void addrbookctl_build_icons( GtkWidget *window ) {
4894 AddressTypeControlItem *atci;
4895
4896 /* Build icons */
4897 if (interfacexpm)
4898 g_object_unref(interfacexpm);
4899 if (folderxpm)
4900 g_object_unref(folderxpm);
4901 if (folderopenxpm)
4902 g_object_unref(folderopenxpm);
4903 if (groupxpm)
4904 g_object_unref(groupxpm);
4905 if (vcardxpm)
4906 g_object_unref(vcardxpm);
4907 if (bookxpm)
4908 g_object_unref(bookxpm);
4909 if (addressxpm)
4910 g_object_unref(addressxpm);
4911 if (jpilotxpm)
4912 g_object_unref(jpilotxpm);
4913 if (categoryxpm)
4914 g_object_unref(categoryxpm);
4915 if (ldapxpm)
4916 g_object_unref(ldapxpm);
4917 if (addrsearchxpm)
4918 g_object_unref(addrsearchxpm);
4919 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4920 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4921 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4922 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4923 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4924 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4925 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4930
4931 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4932 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4933 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4934 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4935 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4936 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4937 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4938 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4939 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4940 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4941 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4942
4943 }
4944
4945 /*
4946 * Build table that controls the rendering of object types.
4947 */
addrbookctl_build_map(GtkWidget * window)4948 static void addrbookctl_build_map( GtkWidget *window ) {
4949 AddressTypeControlItem *atci;
4950
4951 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4952 _addressBookTypeList_ = NULL;
4953
4954 /* Interface */
4955 atci = g_new0( AddressTypeControlItem, 1 );
4956 atci->objectType = ADDR_INTERFACE;
4957 atci->interfaceType = ADDR_IF_NONE;
4958 atci->showInTree = TRUE;
4959 atci->treeExpand = TRUE;
4960 atci->treeLeaf = FALSE;
4961 atci->displayName = _( "Interface" );
4962 atci->menuCommand = NULL;
4963 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4964 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4965
4966 /* Address book */
4967 atci = g_new0( AddressTypeControlItem, 1 );
4968 atci->objectType = ADDR_BOOK;
4969 atci->interfaceType = ADDR_IF_BOOK;
4970 atci->showInTree = TRUE;
4971 atci->treeExpand = TRUE;
4972 atci->treeLeaf = FALSE;
4973 atci->displayName = _("Address Books");
4974 atci->menuCommand = "Menu/Book/NewBook";
4975 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4976 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4977
4978 /* Item person */
4979 atci = g_new0( AddressTypeControlItem, 1 );
4980 atci->objectType = ADDR_ITEM_PERSON;
4981 atci->interfaceType = ADDR_IF_NONE;
4982 atci->showInTree = FALSE;
4983 atci->treeExpand = FALSE;
4984 atci->treeLeaf = FALSE;
4985 atci->displayName = _( "Person" );
4986 atci->menuCommand = NULL;
4987 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4988 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4989
4990 /* Item email */
4991 atci = g_new0( AddressTypeControlItem, 1 );
4992 atci->objectType = ADDR_ITEM_EMAIL;
4993 atci->interfaceType = ADDR_IF_NONE;
4994 atci->showInTree = FALSE;
4995 atci->treeExpand = FALSE;
4996 atci->treeLeaf = TRUE;
4997 atci->displayName = _( "Email Address" );
4998 atci->menuCommand = NULL;
4999 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5000 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5001
5002 /* Item group */
5003 atci = g_new0( AddressTypeControlItem, 1 );
5004 atci->objectType = ADDR_ITEM_GROUP;
5005 atci->interfaceType = ADDR_IF_BOOK;
5006 atci->showInTree = TRUE;
5007 atci->treeExpand = FALSE;
5008 atci->treeLeaf = FALSE;
5009 atci->displayName = _( "Group" );
5010 atci->menuCommand = NULL;
5011 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5012 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5013
5014 /* Item folder */
5015 atci = g_new0( AddressTypeControlItem, 1 );
5016 atci->objectType = ADDR_ITEM_FOLDER;
5017 atci->interfaceType = ADDR_IF_BOOK;
5018 atci->showInTree = TRUE;
5019 atci->treeExpand = FALSE;
5020 atci->treeLeaf = FALSE;
5021 atci->displayName = _( "Folder" );
5022 atci->menuCommand = NULL;
5023 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5024 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5025
5026 /* vCard */
5027 atci = g_new0( AddressTypeControlItem, 1 );
5028 atci->objectType = ADDR_VCARD;
5029 atci->interfaceType = ADDR_IF_VCARD;
5030 atci->showInTree = TRUE;
5031 atci->treeExpand = TRUE;
5032 atci->treeLeaf = TRUE;
5033 atci->displayName = _( "vCard" );
5034 atci->menuCommand = "Menu/Book/NewVCard";
5035 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5036 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5037
5038 /* J-Pilot */
5039 atci = g_new0( AddressTypeControlItem, 1 );
5040 atci->objectType = ADDR_JPILOT;
5041 atci->interfaceType = ADDR_IF_JPILOT;
5042 atci->showInTree = TRUE;
5043 atci->treeExpand = TRUE;
5044 atci->treeLeaf = FALSE;
5045 atci->displayName = _( "JPilot" );
5046 atci->menuCommand = "Menu/Book/NewJPilot";
5047 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5048 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5049
5050 /* Category */
5051 atci = g_new0( AddressTypeControlItem, 1 );
5052 atci->objectType = ADDR_CATEGORY;
5053 atci->interfaceType = ADDR_IF_JPILOT;
5054 atci->showInTree = TRUE;
5055 atci->treeExpand = TRUE;
5056 atci->treeLeaf = TRUE;
5057 atci->displayName = _( "JPilot" );
5058 atci->menuCommand = NULL;
5059 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5060 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5061
5062 /* LDAP Server */
5063 atci = g_new0( AddressTypeControlItem, 1 );
5064 atci->objectType = ADDR_LDAP;
5065 atci->interfaceType = ADDR_IF_LDAP;
5066 atci->showInTree = TRUE;
5067 atci->treeExpand = TRUE;
5068 atci->treeLeaf = FALSE;
5069 atci->displayName = _( "LDAP servers" );
5070 atci->menuCommand = "Menu/Book/NewLDAPServer";
5071 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5072 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5073
5074 /* LDAP Query */
5075 atci = g_new0( AddressTypeControlItem, 1 );
5076 atci->objectType = ADDR_LDAP_QUERY;
5077 atci->interfaceType = ADDR_IF_LDAP;
5078 atci->showInTree = TRUE;
5079 atci->treeExpand = FALSE;
5080 atci->treeLeaf = TRUE;
5081 atci->displayName = _( "LDAP Query" );
5082 atci->menuCommand = NULL;
5083 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5084 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5085
5086 addrbookctl_build_icons(window);
5087 }
5088
addressbook_reflect_prefs_pixmap_theme(void)5089 void addressbook_reflect_prefs_pixmap_theme(void)
5090 {
5091 if (addrbook.window)
5092 addrbookctl_build_icons(addrbook.window);
5093 }
5094
5095 /*
5096 * Search for specified object type.
5097 */
addrbookctl_lookup(gint ot)5098 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5099 gint objType = ot;
5100 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5101 }
5102
5103 /*
5104 * Search for specified interface type.
5105 */
addrbookctl_lookup_iface(AddressIfType ifType)5106 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5107 GList *node = _addressBookTypeList_;
5108 while( node ) {
5109 AddressTypeControlItem *atci = node->data;
5110 if( atci->interfaceType == ifType ) return atci;
5111 node = g_list_next( node );
5112 }
5113 return NULL;
5114 }
5115
addrbookctl_free_address(AddressObject * obj)5116 static void addrbookctl_free_address( AddressObject *obj ) {
5117 g_free( obj->name );
5118 obj->type = ADDR_NONE;
5119 obj->name = NULL;
5120 }
5121
addrbookctl_free_interface(AdapterInterface * adapter)5122 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5123 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5124 adapter->interface = NULL;
5125 adapter->interfaceType = ADDR_IF_NONE;
5126 adapter->atci = NULL;
5127 adapter->enabled = FALSE;
5128 adapter->haveLibrary = FALSE;
5129 adapter->treeNode = NULL;
5130 g_free( adapter );
5131 }
5132
addrbookctl_free_datasource(AdapterDSource * adapter)5133 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5134 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5135 adapter->dataSource = NULL;
5136 adapter->subType = ADDR_NONE;
5137 g_free( adapter );
5138 }
5139
addrbookctl_free_folder(AdapterFolder * adapter)5140 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5141 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5142 adapter->itemFolder = NULL;
5143 g_free( adapter );
5144 }
5145
addrbookctl_free_group(AdapterGroup * adapter)5146 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5147 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5148 adapter->itemGroup = NULL;
5149 g_free( adapter );
5150 }
5151
5152 /**
5153 * Build GUI interface list.
5154 */
addrbookctl_build_iflist(void)5155 static void addrbookctl_build_iflist( void ) {
5156 AddressTypeControlItem *atci;
5157 AdapterInterface *adapter;
5158 GList *list = NULL;
5159
5160 if( _addressIndex_ == NULL ) {
5161 _addressIndex_ = addrindex_create_index();
5162 if( _clipBoard_ == NULL ) {
5163 _clipBoard_ = addrclip_create();
5164 }
5165 addrclip_set_index( _clipBoard_, _addressIndex_ );
5166 }
5167 _addressInterfaceList_ = NULL;
5168 list = addrindex_get_interface_list( _addressIndex_ );
5169 while( list ) {
5170 AddressInterface *interface = list->data;
5171 atci = addrbookctl_lookup_iface( interface->type );
5172 if( atci ) {
5173 adapter = g_new0( AdapterInterface, 1 );
5174 adapter->interfaceType = interface->type;
5175 adapter->atci = atci;
5176 adapter->interface = interface;
5177 adapter->treeNode = NULL;
5178 adapter->enabled = TRUE;
5179 adapter->haveLibrary = interface->haveLibrary;
5180 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5181 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5182 _addressInterfaceList_ =
5183 g_list_append( _addressInterfaceList_, adapter );
5184 }
5185 list = g_list_next( list );
5186 }
5187 }
5188
5189 /**
5190 * Find GUI interface type specified interface type.
5191 * \param ifType Interface type.
5192 * \return Interface item, or NULL if not found.
5193 */
addrbookctl_find_interface(AddressIfType ifType)5194 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5195 GList *node = _addressInterfaceList_;
5196 while( node ) {
5197 AdapterInterface *adapter = node->data;
5198 if( adapter->interfaceType == ifType ) return adapter;
5199 node = g_list_next( node );
5200 }
5201 return NULL;
5202 }
5203
5204 /**
5205 * Build interface list selection.
5206 */
addrbookctl_build_ifselect(void)5207 static void addrbookctl_build_ifselect( void ) {
5208 GList *newList = NULL;
5209 gchar *selectStr;
5210 gchar **splitStr;
5211 gint ifType;
5212 gint i;
5213 gchar *endptr = NULL;
5214 /* gboolean enabled; */
5215 AdapterInterface *adapter;
5216
5217 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5218
5219 /* Parse string */
5220 splitStr = g_strsplit( selectStr, ",", -1 );
5221 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5222 if( splitStr[i] ) {
5223 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5224 ifType = strtol( splitStr[i], &endptr, 10 );
5225 /* enabled = TRUE;
5226 if( *endptr ) {
5227 if( strcmp( endptr, "/n" ) == 0 ) {
5228 enabled = FALSE;
5229 }
5230 }
5231 */
5232 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5233 adapter = addrbookctl_find_interface( ifType );
5234 if( adapter ) {
5235 newList = g_list_append( newList, adapter );
5236 }
5237 }
5238 else {
5239 break;
5240 }
5241 }
5242 /* g_print( "i=%d\n", i ); */
5243 g_strfreev( splitStr );
5244 g_free( selectStr );
5245
5246 /* Replace existing list */
5247 g_list_free( _addressIFaceSelection_ );
5248 _addressIFaceSelection_ = newList;
5249 newList = NULL;
5250 }
5251
5252 /* ***********************************************************************
5253 * Add sender to address book.
5254 * ***********************************************************************
5255 */
5256
5257 /*
5258 * This function is used by the Add sender to address book function.
5259 */
addressbook_add_contact(const gchar * name,const gchar * address,const gchar * remarks,GdkPixbuf * picture)5260 gboolean addressbook_add_contact(
5261 const gchar *name, const gchar *address, const gchar *remarks,
5262 GdkPixbuf *picture )
5263 {
5264 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5265 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5266 debug_print( "addressbook_add_contact - added\n" );
5267 addressbook_refresh();
5268 }
5269 return TRUE;
5270 }
5271
5272 /* ***********************************************************************
5273 * Book/folder selection.
5274 * ***********************************************************************
5275 */
5276
5277 /*
5278 * This function is used by the matcher dialog to select a book/folder.
5279 */
addressbook_folder_selection(const gchar * folderpath)5280 gchar *addressbook_folder_selection( const gchar *folderpath)
5281 {
5282 AddressBookFile *book = NULL;
5283 ItemFolder *folder = NULL;
5284 gchar *path = NULL;
5285
5286 cm_return_val_if_fail( folderpath != NULL, NULL);
5287
5288 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5289 && book != NULL ) {
5290 if ( folder != NULL) {
5291 gchar *tmp = NULL;
5292 gchar *oldtmp = NULL;
5293 AddrItemObject *obj = NULL;
5294
5295 /* walk thru folder->parent to build the full folder path */
5296 /* TODO: wwp: optimize this */
5297 obj = &folder->obj;
5298 tmp = g_strdup(obj->uid);
5299 while ( obj->parent ) {
5300 obj = obj->parent;
5301 if ( obj->name != NULL ) {
5302 oldtmp = g_strdup(tmp);
5303 g_free(tmp);
5304 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5305 g_free(oldtmp);
5306 }
5307 }
5308 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5309 g_free(tmp);
5310 } else {
5311 path = g_strdup_printf("%s", book->fileName);
5312 }
5313 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5314 return path;
5315 }
5316 return NULL;
5317 }
5318
5319 /* ***********************************************************************
5320 * Book/folder checking.
5321 * ***********************************************************************
5322 */
5323
addressbook_peek_subfolder_exists_create_folderinfo(AddressBookFile * abf,ItemFolder * folder)5324 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5325 {
5326 FolderInfo *fi = g_new0( FolderInfo, 1 );
5327 fi->book = abf;
5328 fi->folder = folder;
5329 return fi;
5330 }
5331
addressbook_peek_subfolder_exists_load_folder(ItemFolder * parentFolder,FolderInfo * fiParent,FolderPathMatch * match)5332 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5333 FolderInfo *fiParent, FolderPathMatch *match )
5334 {
5335 GList *list;
5336 ItemFolder *folder;
5337 gchar *fName;
5338 FolderInfo *fi;
5339 FolderPathMatch *nextmatch = NULL;
5340
5341 if (!parentFolder)
5342 return;
5343
5344 list = parentFolder->listFolder;
5345 while ( list ) {
5346 folder = list->data;
5347 fName = g_strdup( ADDRITEM_NAME(folder) );
5348
5349 /* match folder name, match pointer will be set to NULL if next recursive call
5350 doesn't need to match subfolder name */
5351 if ( match != NULL &&
5352 match->matched == FALSE ) {
5353 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5354 /* folder name matches, prepare next subfolder match */
5355 debug_print("matched folder name '%s'\n", fName);
5356 match->index++;
5357 if ( match->folder_path[match->index] == NULL ) {
5358 /* we've matched all elements */
5359 match->matched = TRUE;
5360 match->folder = folder;
5361 debug_print("book/folder path matched!\n");
5362 } else {
5363 /* keep on matching */
5364 nextmatch = match;
5365 }
5366 }
5367 }
5368
5369 g_free( fName );
5370
5371 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5372 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5373 g_free(fi);
5374 list = g_list_next( list );
5375 }
5376 }
5377
5378 /*
5379 * This function is used by to check if a matcher book/folder path corresponds to an
5380 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5381 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5382 if book AND folder are NULL this means that folderpath was empty or Any.
5383 If folderpath is a simple book name (without folder), book will not be NULL and folder
5384 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5385 */
5386
addressbook_peek_folder_exists(gchar * folderpath,AddressDataSource ** book,ItemFolder ** folder)5387 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5388 AddressDataSource **book,
5389 ItemFolder **folder )
5390 {
5391 AddressDataSource *ds;
5392 GList *list, *nodeDS;
5393 ItemFolder *rootFolder;
5394 AddressBookFile *abf;
5395 FolderInfo *fi;
5396 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5397
5398 if ( book )
5399 *book = NULL;
5400 if ( folder )
5401 *folder = NULL;
5402
5403 if ( folderpath == NULL )
5404 return FALSE;
5405
5406 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5407 return TRUE;
5408
5409 /* split the folder path we've received, we'll try to match this path, subpath by
5410 subpath against the book/folder structure in order */
5411 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5412 if (!folder_path_match.folder_path)
5413 return FALSE;
5414
5415 list = addrindex_get_interface_list( _addressIndex_ );
5416 while ( list && !folder_path_match.matched ) {
5417 AddressInterface *interface = list->data;
5418 if ( interface && interface->type == ADDR_IF_BOOK ) {
5419 nodeDS = interface->listSource;
5420 while ( nodeDS && !folder_path_match.matched ) {
5421 ds = nodeDS->data;
5422
5423 /* Read address book */
5424 if( ! addrindex_ds_get_read_flag( ds ) ) {
5425 addrindex_ds_read_data( ds );
5426 }
5427
5428 /* Add node for address book */
5429 abf = ds->rawDataSource;
5430
5431 /* match book name */
5432 if ( abf && abf->fileName &&
5433 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5434
5435 debug_print("matched book name '%s'\n", abf->fileName);
5436 folder_path_match.book = ds;
5437
5438 if ( folder_path_match.folder_path[1] == NULL ) {
5439 /* no folder part to match */
5440
5441 folder_path_match.matched = TRUE;
5442 folder_path_match.folder = NULL;
5443 debug_print("book path matched!\n");
5444
5445 } else {
5446 /* match folder part */
5447
5448 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5449 rootFolder = addrindex_ds_get_root_folder( ds );
5450
5451 /* prepare for recursive call */
5452 folder_path_match.index = 1;
5453 /* this call will set folder_path_match.matched and folder_path_match.folder */
5454 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5455 g_free(fi);
5456 }
5457 }
5458
5459 nodeDS = g_list_next( nodeDS );
5460 }
5461 }
5462 list = g_list_next( list );
5463 }
5464
5465 g_strfreev( folder_path_match.folder_path );
5466
5467 if ( book )
5468 *book = folder_path_match.book;
5469 if ( folder )
5470 *folder = folder_path_match.folder;
5471 return folder_path_match.matched;
5472 }
5473
5474
5475 /* **********************************************************************
5476 * Address Import.
5477 * ***********************************************************************
5478 */
5479
5480 /**
5481 * Import LDIF file.
5482 */
addressbook_import_ldif_cb(GtkAction * action,gpointer data)5483 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5484 AddressDataSource *ds = NULL;
5485 AdapterDSource *ads = NULL;
5486 AddressBookFile *abf = NULL;
5487 AdapterInterface *adapter;
5488 GtkCMCTreeNode *newNode;
5489
5490 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5491 if( adapter ) {
5492 if( adapter->treeNode ) {
5493 abf = addressbook_imp_ldif( _addressIndex_ );
5494 if( abf ) {
5495 ds = addrindex_index_add_datasource(
5496 _addressIndex_, ADDR_IF_BOOK, abf );
5497 ads = addressbook_create_ds_adapter(
5498 ds, ADDR_BOOK, NULL );
5499 addressbook_ads_set_name(
5500 ads, addrbook_get_name( abf ) );
5501 newNode = addressbook_add_object(
5502 adapter->treeNode,
5503 ADDRESS_OBJECT(ads) );
5504 if( newNode ) {
5505 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5506 newNode );
5507 addrbook.treeSelected = newNode;
5508 }
5509
5510 /* Notify address completion */
5511 invalidate_address_completion();
5512 }
5513 }
5514 }
5515 }
5516
5517 /**
5518 * Import MUTT file.
5519 */
addressbook_import_mutt_cb(GtkAction * action,gpointer data)5520 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5521 AddressDataSource *ds = NULL;
5522 AdapterDSource *ads = NULL;
5523 AddressBookFile *abf = NULL;
5524 AdapterInterface *adapter;
5525 GtkCMCTreeNode *newNode;
5526
5527 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5528 if( adapter ) {
5529 if( adapter->treeNode ) {
5530 abf = addressbook_imp_mutt( _addressIndex_ );
5531 if( abf ) {
5532 ds = addrindex_index_add_datasource(
5533 _addressIndex_, ADDR_IF_BOOK, abf );
5534 ads = addressbook_create_ds_adapter(
5535 ds, ADDR_BOOK, NULL );
5536 addressbook_ads_set_name(
5537 ads, addrbook_get_name( abf ) );
5538 newNode = addressbook_add_object(
5539 adapter->treeNode,
5540 ADDRESS_OBJECT(ads) );
5541 if( newNode ) {
5542 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5543 newNode );
5544 addrbook.treeSelected = newNode;
5545 }
5546
5547 /* Notify address completion */
5548 invalidate_address_completion();
5549 }
5550 }
5551 }
5552 }
5553
5554 /**
5555 * Import Pine file.
5556 */
addressbook_import_pine_cb(GtkAction * action,gpointer data)5557 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5558 AddressDataSource *ds = NULL;
5559 AdapterDSource *ads = NULL;
5560 AddressBookFile *abf = NULL;
5561 AdapterInterface *adapter;
5562 GtkCMCTreeNode *newNode;
5563
5564 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5565 if( adapter ) {
5566 if( adapter->treeNode ) {
5567 abf = addressbook_imp_pine( _addressIndex_ );
5568 if( abf ) {
5569 ds = addrindex_index_add_datasource(
5570 _addressIndex_, ADDR_IF_BOOK, abf );
5571 ads = addressbook_create_ds_adapter(
5572 ds, ADDR_BOOK, NULL );
5573 addressbook_ads_set_name(
5574 ads, addrbook_get_name( abf ) );
5575 newNode = addressbook_add_object(
5576 adapter->treeNode,
5577 ADDRESS_OBJECT(ads) );
5578 if( newNode ) {
5579 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5580 newNode );
5581 addrbook.treeSelected = newNode;
5582 }
5583
5584 /* Notify address completion */
5585 invalidate_address_completion();
5586 }
5587 }
5588 }
5589 }
5590
5591 /**
5592 * Harvest addresses.
5593 * \param folderItem Folder to import.
5594 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5595 * \param msgList List of message numbers, or NULL to process folder.
5596 */
addressbook_harvest(FolderItem * folderItem,gboolean sourceInd,GList * msgList)5597 void addressbook_harvest(
5598 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5599 {
5600 AddressDataSource *ds = NULL;
5601 AdapterDSource *ads = NULL;
5602 AddressBookFile *abf = NULL;
5603 AdapterInterface *adapter;
5604 GtkCMCTreeNode *newNode;
5605
5606 abf = addrgather_dlg_execute(
5607 folderItem, _addressIndex_, sourceInd, msgList );
5608 if( abf ) {
5609 ds = addrindex_index_add_datasource(
5610 _addressIndex_, ADDR_IF_BOOK, abf );
5611
5612 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5613 if( adapter ) {
5614 if( adapter->treeNode ) {
5615 ads = addressbook_create_ds_adapter(
5616 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5617 newNode = addressbook_add_object(
5618 adapter->treeNode,
5619 ADDRESS_OBJECT(ads) );
5620 if (newNode == NULL) {
5621 g_message("error adding addressbook object\n");
5622 }
5623 }
5624 }
5625
5626 /* Notify address completion */
5627 invalidate_address_completion();
5628 }
5629 }
5630
5631 /**
5632 * Export HTML file.
5633 */
addressbook_export_html_cb(GtkAction * action,gpointer data)5634 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5635 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5636 AddressObject *obj;
5637 AddressDataSource *ds = NULL;
5638 AddrBookBase *adbase;
5639 AddressCache *cache;
5640 GtkCMCTreeNode *node = NULL;
5641
5642 if( ! addrbook.treeSelected ) return;
5643 node = addrbook.treeSelected;
5644 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5645 obj = gtk_cmctree_node_get_row_data( ctree, node );
5646 if( obj == NULL ) return;
5647
5648 ds = addressbook_find_datasource( node );
5649 if( ds == NULL ) return;
5650 adbase = ( AddrBookBase * ) ds->rawDataSource;
5651 cache = adbase->addressCache;
5652 addressbook_exp_html( cache );
5653 }
5654
5655 /**
5656 * Export LDIF file.
5657 */
addressbook_export_ldif_cb(GtkAction * action,gpointer data)5658 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5659 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5660 AddressObject *obj;
5661 AddressDataSource *ds = NULL;
5662 AddrBookBase *adbase;
5663 AddressCache *cache;
5664 GtkCMCTreeNode *node = NULL;
5665
5666 if( ! addrbook.treeSelected ) return;
5667 node = addrbook.treeSelected;
5668 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5669 obj = gtk_cmctree_node_get_row_data( ctree, node );
5670 if( obj == NULL ) return;
5671
5672 ds = addressbook_find_datasource( node );
5673 if( ds == NULL ) return;
5674 adbase = ( AddrBookBase * ) ds->rawDataSource;
5675 cache = adbase->addressCache;
5676 addressbook_exp_ldif( cache );
5677 }
5678
addressbook_find_duplicates_cb(GtkAction * action,gpointer data)5679 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5680 {
5681 addrduplicates_find(GTK_WINDOW(addrbook.window));
5682 }
5683
addressbook_edit_custom_attr_cb(GtkAction * action,gpointer data)5684 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5685 {
5686 addressbook_custom_attr_edit();
5687 }
5688
addressbook_start_drag(GtkWidget * widget,gint button,GdkEvent * event,void * data)5689 static void addressbook_start_drag(GtkWidget *widget, gint button,
5690 GdkEvent *event,
5691 void *data)
5692 {
5693 GdkDragContext *context;
5694 if (addressbook_target_list == NULL)
5695 addressbook_target_list = gtk_target_list_new(
5696 addressbook_drag_types, 1);
5697 context = gtk_drag_begin(widget, addressbook_target_list,
5698 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5699 gtk_drag_set_icon_default(context);
5700 }
5701
addressbook_drag_data_get(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * selection_data,guint info,guint time,void * data)5702 static void addressbook_drag_data_get(GtkWidget *widget,
5703 GdkDragContext *drag_context,
5704 GtkSelectionData *selection_data,
5705 guint info,
5706 guint time,
5707 void *data)
5708 {
5709 AddrItemObject *aio = NULL;
5710 AddressObject *pobj = NULL;
5711 AdapterDSource *ads = NULL;
5712 AddressDataSource *ds = NULL;
5713 GList *cur;
5714
5715 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5716
5717 if( pobj == NULL ) return;
5718
5719 if( pobj->type == ADDR_DATASOURCE ) {
5720 ads = ADAPTER_DSOURCE(pobj);
5721 ds = ads->dataSource;
5722 } else if (pobj->type == ADDR_ITEM_GROUP) {
5723
5724 return;
5725 }
5726
5727 else if( pobj->type != ADDR_INTERFACE ) {
5728 ds = addressbook_find_datasource( addrbook.treeSelected );
5729
5730 if (!ds)
5731 return;
5732 }
5733
5734 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5735 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5736 GTK_CMCTREE_NODE(cur->data));
5737 while (aio && aio->type != ITEMTYPE_PERSON) {
5738 aio = aio->parent;
5739 }
5740 }
5741
5742 if (aio && aio->type == ITEMTYPE_PERSON) {
5743 if( ds && ds->interface && ds->interface->readOnly)
5744 gtk_selection_data_set(selection_data,
5745 gtk_selection_data_get_target(selection_data), 8,
5746 (const guchar *)"Dummy_addr_copy", 15);
5747 else
5748 gtk_selection_data_set(selection_data,
5749 gtk_selection_data_get_target(selection_data), 8,
5750 (const guchar *)"Dummy_addr_move", 15);
5751 }
5752 }
5753
addressbook_drag_motion_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,void * data)5754 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5755 GdkDragContext *context,
5756 gint x,
5757 gint y,
5758 guint time,
5759 void *data)
5760 {
5761 GtkAllocation allocation;
5762 GtkRequisition requisition;
5763 gint row, column;
5764 GtkCMCTreeNode *node = NULL;
5765 gboolean acceptable = FALSE;
5766 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5767 gint height = allocation.height;
5768 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5769 gint total_height = requisition.height;
5770 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5771 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5772 gfloat vpos = gtk_adjustment_get_value(pos);
5773
5774 if (gtk_cmclist_get_selection_info
5775 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5776
5777 if (y > height - 24 && height + vpos < total_height) {
5778 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5779 gtk_adjustment_changed(pos);
5780 }
5781 if (y < 24 && y > 0) {
5782 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5783 gtk_adjustment_changed(pos);
5784 }
5785 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5786
5787 if (node != NULL) {
5788 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5789 if( obj->type == ADDR_ITEM_FOLDER
5790 || obj->type == ADDR_ITEM_GROUP)
5791 acceptable = TRUE;
5792 else {
5793 AdapterDSource *ads = NULL;
5794 AddressDataSource *ds = NULL;
5795 ads = ADAPTER_DSOURCE(obj);
5796 if (ads == NULL ){ return FALSE;}
5797 ds = ads->dataSource;
5798 if (ds == NULL ) { return FALSE;}
5799
5800 acceptable = TRUE;
5801 }
5802 }
5803 }
5804
5805 if (acceptable) {
5806 g_signal_handlers_block_by_func
5807 (G_OBJECT(widget),
5808 G_CALLBACK(addressbook_tree_selected), NULL);
5809 gtk_sctree_select( GTK_SCTREE(widget), node);
5810 g_signal_handlers_unblock_by_func
5811 (G_OBJECT(widget),
5812 G_CALLBACK(addressbook_tree_selected), NULL);
5813 gdk_drag_status(context,
5814 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5815 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5816 } else {
5817 gdk_drag_status(context, 0, time);
5818 }
5819 return acceptable;
5820 }
5821
addressbook_drag_leave_cb(GtkWidget * widget,GdkDragContext * context,guint time,void * data)5822 static void addressbook_drag_leave_cb(GtkWidget *widget,
5823 GdkDragContext *context,
5824 guint time,
5825 void *data)
5826 {
5827 if (addrbook.treeSelected) {
5828 g_signal_handlers_block_by_func
5829 (G_OBJECT(widget),
5830 G_CALLBACK(addressbook_tree_selected), NULL);
5831 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5832 g_signal_handlers_unblock_by_func
5833 (G_OBJECT(widget),
5834 G_CALLBACK(addressbook_tree_selected), NULL);
5835 }
5836
5837 }
5838
addressbook_drag_received_cb(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,GtkSelectionData * data,guint info,guint time,void * pdata)5839 static void addressbook_drag_received_cb(GtkWidget *widget,
5840 GdkDragContext *drag_context,
5841 gint x,
5842 gint y,
5843 GtkSelectionData *data,
5844 guint info,
5845 guint time,
5846 void *pdata)
5847 {
5848 gint row, column;
5849 GtkCMCTreeNode *node;
5850 GtkCMCTreeNode *lastopened = addrbook.opened;
5851
5852 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5853 if (gtk_cmclist_get_selection_info
5854 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5855 return;
5856 }
5857
5858 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5859 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5860 return;
5861
5862 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5863 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5864 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5865 addressbook_clip_copy_cb(NULL, NULL);
5866 else
5867 addressbook_clip_cut_cb(NULL, NULL);
5868 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5869 addressbook_clip_paste_cb(NULL,NULL);
5870 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5871 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5872 gtk_drag_finish(drag_context, TRUE, TRUE, time);
5873 }
5874 }
5875
5876 /*
5877 * End of Source.
5878 */
5879