1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2017 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 2 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 
24 #include "defs.h"
25 
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtk.h>
30 #include <string.h>
31 #include <setjmp.h>
32 
33 #include "main.h"
34 #include "addressbook.h"
35 #include "manage_window.h"
36 #include "prefs_common.h"
37 #include "alertpanel.h"
38 #include "inputdialog.h"
39 #include "menu.h"
40 #include "stock_pixmap.h"
41 #include "xml.h"
42 #include "prefs.h"
43 #include "procmime.h"
44 #include "utils.h"
45 #include "gtkutils.h"
46 #include "codeconv.h"
47 #include "about.h"
48 #include "addr_compl.h"
49 
50 #include "mgutils.h"
51 #include "addressitem.h"
52 #include "addritem.h"
53 #include "addrcache.h"
54 #include "addrbook.h"
55 #include "addrindex.h"
56 #include "addressadd.h"
57 #include "vcard.h"
58 #include "editvcard.h"
59 #include "editgroup.h"
60 #include "editaddress.h"
61 #include "editbook.h"
62 #include "ldif.h"
63 #include "importldif.h"
64 #include "importcsv.h"
65 #include "exportcsv.h"
66 
67 #ifdef USE_JPILOT
68 #include "jpilot.h"
69 #include "editjpilot.h"
70 #endif
71 
72 #ifdef USE_LDAP
73 #include <pthread.h>
74 #include "syldap.h"
75 #include "editldap.h"
76 
77 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
78 #endif
79 
80 typedef enum
81 {
82 	COL_FOLDER_NAME,
83 	COL_OBJ,
84 	COL_PIXBUF,
85 	COL_PIXBUF_OPEN,
86 
87 	N_TREE_COLS
88 } AddressBookTreeColumnPos;
89 
90 typedef enum
91 {
92 	COL_NAME,
93 	COL_ADDRESS,
94 	COL_NICKNAME,
95 	COL_REMARKS,
96 	COL_L_OBJ,
97 	COL_L_PIXBUF,
98 
99 	N_LIST_COLS
100 } AddressBookListColumnPos;
101 
102 enum
103 {
104 	DRAG_TYPE_OBJ,
105 
106 	N_DRAG_TYPES
107 };
108 
109 #define COL_NAME_WIDTH		164
110 #define COL_ADDRESS_WIDTH	156
111 
112 #define COL_FOLDER_WIDTH	170
113 
114 #define ADDRESSBOOK_MSGBUF_SIZE 2048
115 
116 static GdkPixbuf *folderpix;
117 static GdkPixbuf *folderopenpix;
118 static GdkPixbuf *grouppix;
119 static GdkPixbuf *interfacepix;
120 static GdkPixbuf *bookpix;
121 static GdkPixbuf *personpix;
122 static GdkPixbuf *addresspix;
123 static GdkPixbuf *vcardpix;
124 static GdkPixbuf *jpilotpix;
125 static GdkPixbuf *categorypix;
126 static GdkPixbuf *ldappix;
127 
128 /* Address list selection */
129 static GList *_addressListSelection_ = NULL;
130 
131 static gboolean can_toggle_list_selection = TRUE;
132 static gboolean list_on_drag = FALSE;
133 
134 /* Address index file and interfaces */
135 static AddressIndex *_addressIndex_ = NULL;
136 static GList *_addressInterfaceList_ = NULL;
137 static GList *_addressIFaceSelection_ = NULL;
138 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
139 
140 /* Address clipboard */
141 static GList *_clipObjectList_ = NULL;
142 
143 static AddressBook_win addrbook;
144 
145 static GHashTable *_addressBookTypeHash_ = NULL;
146 static GList *_addressBookTypeList_ = NULL;
147 
148 static void addressbook_refresh			(void);
149 static void addressbook_reopen			(void);
150 
151 static void addressbook_create			(void);
152 static gint addressbook_close			(void);
153 
154 static void addressbook_menuitem_set_sensitive	(void);
155 
156 /* callback functions */
157 static void addressbook_del_clicked		(GtkButton	*button,
158 						 gpointer	 data);
159 static void addressbook_reg_clicked		(GtkButton	*button,
160 						 gpointer	 data);
161 static void addressbook_to_clicked		(GtkButton	*button,
162 						 gpointer	 data);
163 static void addressbook_lup_clicked		(GtkButton	*button,
164 						 gpointer	data);
165 static void addressbook_close_clicked		(GtkButton	*button,
166 						 gpointer	data);
167 
168 static void addressbook_tree_selection_changed	(GtkTreeSelection *selection,
169 						 gpointer	 data);
170 static void addressbook_list_selection_changed	(GtkTreeSelection *selection,
171 						 gpointer	 data);
172 static void addressbook_person_expand_node	(GtkTreeView	*treeview,
173 						 GtkTreeIter	*iter,
174 						 GtkTreePath	*path,
175 						 gpointer	*data);
176 static void addressbook_person_collapse_node	(GtkTreeView	*treeview,
177 						 GtkTreeIter	*iter,
178 						 GtkTreePath	*path,
179 						 gpointer	*data);
180 
181 static void addressbook_drag_begin		(GtkWidget	*widget,
182 						 GdkDragContext	*drag_context,
183 						 gpointer	 data);
184 static void addressbook_drag_end		(GtkWidget	*widget,
185 						 GdkDragContext	*drag_context,
186 						 gpointer	 data);
187 static void addressbook_drag_data_get		(GtkWidget	*widget,
188 						 GdkDragContext	*drag_context,
189 						 GtkSelectionData *selection_data,
190 						 guint		 info,
191 						 guint		 time,
192 						 gpointer	 data);
193 
194 #if 0
195 static void addressbook_entry_changed		(GtkWidget	*widget);
196 #endif
197 static void addressbook_entry_activated		(GtkWidget	*widget,
198 						 gpointer	 data);
199 
200 static gboolean addressbook_list_button_pressed	(GtkWidget	*widget,
201 						 GdkEventButton	*event,
202 						 gpointer	 data);
203 static gboolean addressbook_list_button_released(GtkWidget	*widget,
204 						 GdkEventButton	*event,
205 						 gpointer	 data);
206 static gboolean addressbook_tree_button_pressed	(GtkWidget	*ctree,
207 						 GdkEventButton	*event,
208 						 gpointer	 data);
209 static gboolean addressbook_tree_button_released(GtkWidget	*ctree,
210 						 GdkEventButton	*event,
211 						 gpointer	 data);
212 
213 static gboolean addressbook_drag_motion		(GtkWidget	*widget,
214 						 GdkDragContext	*context,
215 						 gint		 x,
216 						 gint		 y,
217 						 guint		 time,
218 						 gpointer	 data);
219 static void addressbook_drag_leave		(GtkWidget	*widget,
220 						 GdkDragContext	*context,
221 						 guint		 time,
222 						 gpointer	 data);
223 static void addressbook_drag_received		(GtkWidget	*widget,
224 						 GdkDragContext	*context,
225 						 gint		 x,
226 						 gint		 y,
227 						 GtkSelectionData *data,
228 						 guint		 info,
229 						 guint		 time,
230 						 gpointer	 user_data);
231 
232 static void addressbook_folder_resized		(GtkWidget	*widget,
233 						 GtkAllocation	*allocation,
234 						 gpointer	 data);
235 static void addressbook_col_resized		(GtkWidget	*widget,
236 						 GtkAllocation	*allocation,
237 						 gpointer	 data);
238 
239 static void addressbook_popup_close		(GtkMenuShell	*menu_shell,
240 						 gpointer	 data);
241 
242 static void addressbook_new_folder_cb		(gpointer	 data,
243 						 guint		 action,
244 						 GtkWidget	*widget);
245 static void addressbook_new_group_cb		(gpointer	 data,
246 						 guint		 action,
247 						 GtkWidget	*widget);
248 static void addressbook_treenode_edit_cb	(gpointer	 data,
249 						 guint		 action,
250 						 GtkWidget	*widget);
251 static void addressbook_treenode_delete_cb	(gpointer	 data,
252 						 guint		 action,
253 						 GtkWidget	*widget);
254 
255 static void addressbook_change_node_name	(GtkTreeIter	*iter,
256 						 const gchar	*name);
257 
258 static void addressbook_new_address_cb		(gpointer	 data,
259 						 guint		 action,
260 						 GtkWidget	*widget);
261 static void addressbook_compose_to_cb		(gpointer	 data,
262 						 guint		 action,
263 						 GtkWidget	*widget);
264 static void addressbook_edit_address_cb		(gpointer	 data,
265 						 guint		 action,
266 						 GtkWidget	*widget);
267 static void addressbook_delete_address_cb	(gpointer	 data,
268 						 guint		 action,
269 						 GtkWidget	*widget);
270 static void addressbook_copy_address_cb		(gpointer	 data,
271 						 guint		 action,
272 						 GtkWidget	*widget);
273 static void addressbook_paste_address_cb	(gpointer	 data,
274 						 guint		 action,
275 						 GtkWidget	*widget);
276 
277 static void close_cb				(gpointer	 data,
278 						 guint		 action,
279 						 GtkWidget	*widget);
280 static void addressbook_file_save_cb		(gpointer	 data,
281 						 guint		 action,
282 						 GtkWidget	*widget);
283 
284 /* Data source edit stuff */
285 static void addressbook_new_book_cb		(gpointer	 data,
286 	       					 guint		 action,
287 						 GtkWidget	*widget);
288 static void addressbook_new_vcard_cb		(gpointer	 data,
289 	       					 guint		 action,
290 						 GtkWidget	*widget);
291 
292 #ifdef USE_JPILOT
293 static void addressbook_new_jpilot_cb		(gpointer	 data,
294 	       					 guint		 action,
295 						 GtkWidget	*widget);
296 #endif
297 
298 #ifdef USE_LDAP
299 static void addressbook_new_ldap_cb		(gpointer	 data,
300 	       					 guint		 action,
301 						 GtkWidget	*widget);
302 #endif
303 
304 static void addressbook_set_list		(AddressObject	*obj);
305 
306 static void addressbook_load_tree		(void);
307 void addressbook_read_file			(void);
308 
309 static gboolean addressbook_add_object		(GtkTreeIter	*iter,
310 						 GtkTreeIter	*new_iter,
311 						 AddressObject	*obj);
312 static AddressDataSource *addressbook_find_datasource
313 						(GtkTreeIter	*iter);
314 
315 static AddressBookFile *addressbook_get_book_file();
316 
317 static gboolean addressbook_node_add_folder	(GtkTreeIter	*iter,
318 						 AddressDataSource *ds,
319 						 ItemFolder	*itemFolder,
320 						 AddressObjectType otype,
321 						 GtkTreeIter	*new_iter);
322 static gboolean addressbook_node_add_group	(GtkTreeIter	*iter,
323 						 AddressDataSource *ds,
324 						 ItemGroup	*itemGroup,
325 						 GtkTreeIter	*new_iter);
326 static void addressbook_tree_remove_children	(GtkTreeModel	*model,
327 						 GtkTreeIter	*parent);
328 static void addressbook_move_nodes_up		(GtkTreeIter	*iter);
329 static gboolean addressbook_find_group_node	(GtkTreeIter	*parent,
330 						 GtkTreeIter	*iter,
331 						 ItemGroup	*group);
332 
333 /* static void addressbook_delete_object	(AddressObject	*obj); */
334 
335 static gboolean key_pressed			(GtkWidget	*widget,
336 						 GdkEventKey	*event,
337 						 gpointer	 data);
338 static void size_allocated			(GtkWidget	*widget,
339 						 GtkAllocation	*allocation,
340 						 gpointer	 data);
341 
342 static gint addressbook_tree_compare		(GtkTreeModel	*model,
343 						 GtkTreeIter	*a,
344 						 GtkTreeIter	*b,
345 						 gpointer	 data);
346 static gint addressbook_list_name_compare	(GtkTreeModel	*model,
347 						 GtkTreeIter	*a,
348 						 GtkTreeIter	*b,
349 						 gpointer	 data);
350 static gint addressbook_list_address_compare	(GtkTreeModel	*model,
351 						 GtkTreeIter	*a,
352 						 GtkTreeIter	*b,
353 						 gpointer	 data);
354 static gint addressbook_list_nickname_compare	(GtkTreeModel	*model,
355 						 GtkTreeIter	*a,
356 						 GtkTreeIter	*b,
357 						 gpointer	 data);
358 static gint addressbook_list_remarks_compare	(GtkTreeModel	*model,
359 						 GtkTreeIter	*a,
360 						 GtkTreeIter	*b,
361 						 gpointer	 data);
362 
363 static gboolean addressbook_list_select_func	(GtkTreeSelection *selection,
364 						 GtkTreeModel *model,
365 						 GtkTreePath *path,
366 						 gboolean cur_selected,
367 						 gpointer data);
368 
369 /* static void addressbook_book_show_message	(AddressBookFile *book); */
370 /* static void addressbook_vcard_show_message	(VCardFile *vcf); */
371 #ifdef USE_JPILOT
372 /* static void addressbook_jpilot_show_message	(JPilotFile *jpf); */
373 #endif
374 #ifdef USE_LDAP
375 static void addressbook_ldap_show_message	(SyldapServer *server);
376 #endif
377 
378 /* LUT's and IF stuff */
379 static void addressbook_free_adapter		(GtkTreeIter	*iter);
380 static void addressbook_free_child_adapters	(GtkTreeIter	*iter);
381 AddressTypeControlItem *addrbookctl_lookup	(gint		 ot);
382 AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType	 ifType);
383 
384 void addrbookctl_build_map			(GtkWidget	*window);
385 void addrbookctl_build_iflist			(void);
386 AdapterInterface *addrbookctl_find_interface	(AddressIfType	 ifType);
387 void addrbookctl_build_ifselect			(void);
388 
389 static void addrbookctl_free_interface		(AdapterInterface *adapter);
390 static void addrbookctl_free_datasource		(AdapterDSource	  *adapter);
391 static void addrbookctl_free_folder		(AdapterFolder	  *adapter);
392 static void addrbookctl_free_group		(AdapterGroup	  *adapter);
393 
394 static void addressbook_list_select_clear	(void);
395 static void addressbook_list_select_remove	(AddressObject	*obj);
396 static void addressbook_list_select_set		(GList		*row_list);
397 
398 static void addressbook_import_ldif_cb		(void);
399 static void addressbook_import_csv_cb		(void);
400 
401 static void addressbook_export_csv_cb		(void);
402 
403 static void addressbook_modified		(void);
404 
405 
406 static GtkTargetEntry addressbook_drag_types[] =
407 {
408 	{"application/octet-stream", GTK_TARGET_SAME_APP, DRAG_TYPE_OBJ}
409 };
410 
411 static GtkItemFactoryEntry addressbook_entries[] =
412 {
413 	{N_("/_File"),			NULL,	NULL, 0, "<Branch>"},
414 	{N_("/_File/New _Book"),	NULL,	addressbook_new_book_cb,        0, NULL},
415 	{N_("/_File/New _vCard"),	NULL,	addressbook_new_vcard_cb,       0, NULL},
416 #ifdef USE_JPILOT
417 	{N_("/_File/New _JPilot"),	NULL,	addressbook_new_jpilot_cb,      0, NULL},
418 #endif
419 #ifdef USE_LDAP
420 	{N_("/_File/New _LDAP Server"),	NULL,	addressbook_new_ldap_cb,        0, NULL},
421 #endif
422 	{N_("/_File/---"),		NULL,		NULL, 0, "<Separator>"},
423 	{N_("/_File/_Edit"),		NULL,		addressbook_treenode_edit_cb,   0, NULL},
424 	{N_("/_File/_Delete"),		NULL,		addressbook_treenode_delete_cb, 0, NULL},
425 	{N_("/_File/---"),		NULL,		NULL, 0, "<Separator>"},
426 	{N_("/_File/_Save"),		"<control>S",	addressbook_file_save_cb,       0, NULL},
427 	{N_("/_File/_Close"),		"<control>W",	close_cb, 0, NULL},
428 
429 	{N_("/_Edit"),			NULL,		NULL, 0, "<Branch>"},
430 	{N_("/_Edit/_Copy"),		"<control>C",	addressbook_copy_address_cb,    0, NULL},
431 	{N_("/_Edit/_Paste"),		"<control>V",	addressbook_paste_address_cb,    0, NULL},
432 
433 	{N_("/_Address"),		NULL,		NULL, 0, "<Branch>"},
434 	{N_("/_Address/New _Address"),	"<control>N",	addressbook_new_address_cb,     0, NULL},
435 	{N_("/_Address/New _Group"),	"<control>G",	addressbook_new_group_cb,       0, NULL},
436 	{N_("/_Address/New _Folder"),	"<control>F",	addressbook_new_folder_cb,      0, NULL},
437 	{N_("/_Address/---"),		NULL,		NULL, 0, "<Separator>"},
438 	{N_("/_Address/Add _to recipient"),
439 					"<control>M",	addressbook_compose_to_cb, COMPOSE_ENTRY_TO, NULL},
440 	{N_("/_Address/Add to _Cc"),
441 					NULL,		addressbook_compose_to_cb, COMPOSE_ENTRY_CC, NULL},
442 	{N_("/_Address/Add to _Bcc"),
443 					NULL,		addressbook_compose_to_cb, COMPOSE_ENTRY_BCC, NULL},
444 	{N_("/_Address/---"),		NULL,		NULL, 0, "<Separator>"},
445 	{N_("/_Address/_Edit"),		"<control>Return",	addressbook_edit_address_cb,    0, NULL},
446 	{N_("/_Address/_Delete"),	"Delete",	addressbook_delete_address_cb,  0, NULL},
447 
448 	{N_("/_Tools"),			NULL,		NULL, 0, "<Branch>"},
449 	{N_("/_Tools/Import _LDIF file"), NULL,		addressbook_import_ldif_cb,	0, NULL},
450 	{N_("/_Tools/Import _CSV file"), NULL,		addressbook_import_csv_cb,	0, NULL},
451 	{N_("/_Tools/---"),		NULL,		NULL, 0, "<Separator>"},
452 	{N_("/_Tools/Export to C_SV file"), NULL,	addressbook_export_csv_cb,	0, NULL},
453 	{N_("/_Help"),			NULL,		NULL, 0, "<Branch>"},
454 	{N_("/_Help/_About"),		NULL,		about_show, 0, NULL}
455 };
456 
457 /* New options to be added. */
458 /*
459 	{N_("/_Edit"),			NULL,		NULL, 0, "<Branch>"},
460 	{N_("/_Edit/C_ut"),		"<control>X",	NULL,				0, NULL},
461 	{N_("/_Tools"),			NULL,		NULL, 0, "<Branch>"},
462 	{N_("/_Tools/Import _Mozilla"),	NULL,           NULL,				0, NULL},
463 	{N_("/_Tools/Import _vCard"),	NULL,           NULL,				0, NULL},
464 	{N_("/_Tools/---"),		NULL,		NULL, 0, "<Separator>"},
465 	{N_("/_Tools/Export _LDIF file"), NULL,		NULL,				0, NULL},
466 	{N_("/_Tools/Export v_Card"),	NULL,           NULL,				0, NULL},
467 */
468 
469 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
470 {
471 	{N_("/New _Address"),	NULL, addressbook_new_address_cb, 0, NULL},
472 	{N_("/New _Group"),	NULL, addressbook_new_group_cb,   0, NULL},
473 	{N_("/New _Folder"),	NULL, addressbook_new_folder_cb,  0, NULL},
474 	{N_("/---"),		NULL, NULL, 0, "<Separator>"},
475 	{N_("/_Edit"),		NULL, addressbook_treenode_edit_cb,   0, NULL},
476 	{N_("/_Delete"),	NULL, addressbook_treenode_delete_cb, 0, NULL}
477 };
478 
479 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
480 {
481 	{N_("/New _Address"),	NULL, addressbook_new_address_cb,  0, NULL},
482 	{N_("/New _Group"),	NULL, addressbook_new_group_cb,    0, NULL},
483 	{N_("/New _Folder"),	NULL, addressbook_new_folder_cb,   0, NULL},
484 	{N_("/---"),		NULL, NULL, 0, "<Separator>"},
485 	{N_("/Add _to recipient"),
486 				NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_TO, NULL},
487 	{N_("/Add t_o Cc"),
488 				NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_CC, NULL},
489 	{N_("/Add to _Bcc"),
490 				NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_BCC, NULL},
491 	{N_("/---"),		NULL, NULL, 0, "<Separator>"},
492 	{N_("/_Edit"),		NULL, addressbook_edit_address_cb,   0, NULL},
493 	{N_("/_Delete"),	NULL, addressbook_delete_address_cb, 0, NULL},
494 	{N_("/---"),		NULL, NULL, 0, "<Separator>"},
495 	{N_("/_Copy"),		NULL, addressbook_copy_address_cb,  0, NULL},
496 	{N_("/_Paste"),		NULL, addressbook_paste_address_cb, 0, NULL}
497 };
498 
499 
addressbook_open(Compose * target)500 void addressbook_open(Compose *target)
501 {
502 	if (!addrbook.window) {
503 		GtkTreeView *treeview;
504 		GtkTreeModel *model;
505 		GtkTreeIter iter;
506 		GtkTreePath *path;
507 
508 		addressbook_read_file();
509 		addressbook_create();
510 		addressbook_load_tree();
511 		treeview = GTK_TREE_VIEW(addrbook.treeview);
512 		model = gtk_tree_view_get_model(treeview);
513 		if (gtk_tree_model_get_iter_first(model, &iter)) {
514 			path = gtk_tree_model_get_path(model, &iter);
515 			gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
516 			gtk_tree_path_free(path);
517 		}
518 		addressbook_menuitem_set_sensitive();
519 		gtk_widget_show(addrbook.window);
520 	}
521 
522 	gtk_window_present(GTK_WINDOW(addrbook.window));
523 
524 	addressbook_set_target_compose(target);
525 }
526 
addressbook_set_target_compose(Compose * target)527 void addressbook_set_target_compose(Compose *target)
528 {
529 	addrbook.target_compose = target;
530 }
531 
addressbook_get_target_compose(void)532 Compose *addressbook_get_target_compose(void)
533 {
534 	return addrbook.target_compose;
535 }
536 
addressbook_refresh(void)537 static void addressbook_refresh(void)
538 {
539 	if (addrbook.window) {
540 		if (addrbook.tree_opened) {
541 			addressbook_reopen();
542 		}
543 	}
544 	addressbook_export_to_file();
545 }
546 
addressbook_reopen(void)547 static void addressbook_reopen(void)
548 {
549 	GtkTreePath *path;
550 
551 	if (addrbook.tree_selected) {
552 		gtk_tree_row_reference_free(addrbook.tree_selected);
553 		addrbook.tree_selected = NULL;
554 	}
555 	if (addrbook.tree_opened) {
556 		path = gtk_tree_row_reference_get_path(addrbook.tree_opened);
557 		gtk_tree_view_set_cursor(GTK_TREE_VIEW(addrbook.treeview), path, NULL, FALSE);
558 		gtk_tree_path_free(path);
559 	}
560 }
561 
562 /*
563 * Create the address book widgets. The address book contains two CTree widgets: the
564 * address index tree on the left and the address list on the right.
565 *
566 * The address index tree displays a hierarchy of interfaces and groups. Each node in
567 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
568 * data sources and folder objects.
569 *
570 * The address list displays group, person and email objects. These items are linked
571 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
572 * sources.
573 *
574 * In the tradition of MVC architecture, the data stores have been separated from the
575 * GUI components. The addrindex.c file provides the interface to all data stores.
576 */
addressbook_create(void)577 static void addressbook_create(void)
578 {
579 	GtkWidget *window;
580 	GtkWidget *vbox;
581 	GtkWidget *menubar;
582 	GtkWidget *spc_hbox;
583 	GtkWidget *vbox2;
584 	GtkWidget *tree_swin;
585 	GtkWidget *treeview;
586 	GtkTreeStore *tree_store;
587 	GtkTreeSelection *selection;
588 	GtkTreeViewColumn *column;
589 	GtkCellRenderer *renderer;
590 	GtkWidget *list_vbox;
591 	GtkWidget *list_swin;
592 	GtkWidget *listview;
593 	GtkTreeStore *list_store;
594 	GtkWidget *paned;
595 	GtkWidget *hbox;
596 	GtkWidget *label;
597 	GtkWidget *entry;
598 	GtkWidget *statusbar;
599 	GtkWidget *hbbox;
600 	GtkWidget *hbbox1;
601 	GtkWidget *hbbox2;
602 	GtkWidget *hsbox;
603 	GtkWidget *to_btn;
604 	GtkWidget *cc_btn;
605 	GtkWidget *bcc_btn;
606 	GtkWidget *del_btn;
607 	GtkWidget *reg_btn;
608 	GtkWidget *lup_btn;
609 	GtkWidget *close_btn;
610 	GtkWidget *tree_popup;
611 	GtkWidget *list_popup;
612 	GtkItemFactory *tree_factory;
613 	GtkItemFactory *list_factory;
614 	GtkItemFactory *menu_factory;
615 	gint n_entries;
616 	GList *nodeIf;
617 
618 	debug_print("Creating addressbook window...\n");
619 
620 	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
621 	gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
622 	gtk_window_set_wmclass(GTK_WINDOW(window), "addressbook", "Sylpheed");
623 	gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
624 	gtk_widget_set_size_request(window, 620 * gtkut_get_dpi_multiplier(), 360 * gtkut_get_dpi_multiplier());
625 	gtk_window_set_default_size(GTK_WINDOW(window),
626 				    prefs_common.addressbook_width,
627 				    prefs_common.addressbook_height);
628 	gtkut_window_move(GTK_WINDOW(window), prefs_common.addressbook_x,
629 			  prefs_common.addressbook_y);
630 	gtk_widget_realize(window);
631 
632 	g_signal_connect(G_OBJECT(window), "delete_event",
633 			 G_CALLBACK(addressbook_close), NULL);
634 	g_signal_connect(G_OBJECT(window), "key_press_event",
635 			 G_CALLBACK(key_pressed), NULL);
636 	g_signal_connect(G_OBJECT(window), "size_allocate",
637 			 G_CALLBACK(size_allocated), NULL);
638 	MANAGE_WINDOW_SIGNALS_CONNECT(window);
639 
640 	vbox = gtk_vbox_new(FALSE, 0);
641 	gtk_container_add(GTK_CONTAINER(window), vbox);
642 
643 	n_entries = sizeof(addressbook_entries) /
644 		sizeof(addressbook_entries[0]);
645 	menubar = menubar_create(window, addressbook_entries, n_entries,
646 				 "<AddressBook>", NULL);
647 	gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
648 	menu_factory = gtk_item_factory_from_widget(menubar);
649 
650 	spc_hbox = gtk_hbox_new(FALSE, 0);
651 	gtk_widget_set_size_request(spc_hbox, -1, BORDER_WIDTH);
652 	gtk_box_pack_start(GTK_BOX(vbox), spc_hbox, FALSE, FALSE, 0);
653 
654 	vbox2 = gtk_vbox_new(FALSE, 4);
655 	gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
656 
657 	tree_swin = gtk_scrolled_window_new(NULL, NULL);
658 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tree_swin),
659 				       GTK_POLICY_AUTOMATIC,
660 				       GTK_POLICY_AUTOMATIC);
661 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_swin),
662 					    GTK_SHADOW_IN);
663 	gtk_widget_set_size_request(tree_swin, prefs_common.addressbook_folder_width, -1);
664 
665 	/* Address index */
666 	tree_store = gtk_tree_store_new(N_TREE_COLS, G_TYPE_STRING,
667 					G_TYPE_POINTER, GDK_TYPE_PIXBUF,
668 					GDK_TYPE_PIXBUF);
669 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(tree_store),
670 					COL_FOLDER_NAME,
671 					addressbook_tree_compare,
672 					NULL, NULL);
673 
674 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store));
675 	g_object_unref(G_OBJECT(tree_store));
676 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
677 	gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
678 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
679 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), FALSE);
680 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview),
681 					COL_FOLDER_NAME);
682 	gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), FALSE);
683 
684 	gtk_container_add(GTK_CONTAINER(tree_swin), treeview);
685 
686 	column = gtk_tree_view_column_new();
687 	gtk_tree_view_column_set_spacing(column, 1);
688 	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
689 	gtk_tree_view_column_set_resizable(column, TRUE);
690 
691 	renderer = gtk_cell_renderer_pixbuf_new();
692 	g_object_set(renderer, "ypad", 0, NULL);
693 	gtk_tree_view_column_pack_start(column, renderer, FALSE);
694 	gtk_tree_view_column_set_title(column, _("Folder"));
695 	gtk_tree_view_column_set_attributes
696 		(column, renderer, "pixbuf", COL_PIXBUF,
697 		 "pixbuf-expander-open", COL_PIXBUF_OPEN,
698 		 "pixbuf-expander-closed", COL_PIXBUF, NULL);
699 
700 	renderer = gtk_cell_renderer_text_new();
701 	g_object_set(renderer,
702 #if GTK_CHECK_VERSION(2, 6, 0)
703 		     "ellipsize", PANGO_ELLIPSIZE_END,
704 #endif
705 		     "ypad", 0, NULL);
706 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
707 	gtk_tree_view_column_set_attributes(column, renderer,
708 					    "text", COL_FOLDER_NAME, NULL);
709 
710 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
711 	gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
712 
713 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(tree_store),
714 					     COL_FOLDER_NAME,
715 					     GTK_SORT_ASCENDING);
716 
717 	g_signal_connect(G_OBJECT(tree_swin), "size-allocate",
718 			 G_CALLBACK(addressbook_folder_resized), NULL);
719 
720 	g_signal_connect(G_OBJECT(selection), "changed",
721 			 G_CALLBACK(addressbook_tree_selection_changed), NULL);
722 	g_signal_connect(G_OBJECT(treeview), "button_press_event",
723 			 G_CALLBACK(addressbook_tree_button_pressed),
724 			 NULL);
725 	g_signal_connect(G_OBJECT(treeview), "button_release_event",
726 			 G_CALLBACK(addressbook_tree_button_released),
727 			 NULL);
728 
729 	gtk_drag_dest_set(treeview, GTK_DEST_DEFAULT_ALL,
730 			  addressbook_drag_types, N_DRAG_TYPES,
731 			  GDK_ACTION_MOVE | GDK_ACTION_COPY);
732 	g_signal_connect(G_OBJECT(treeview), "drag-motion",
733 			 G_CALLBACK(addressbook_drag_motion), NULL);
734 	g_signal_connect(G_OBJECT(treeview), "drag-leave",
735 			 G_CALLBACK(addressbook_drag_leave), NULL);
736 	g_signal_connect(G_OBJECT(treeview), "drag-data-received",
737 			 G_CALLBACK(addressbook_drag_received), NULL);
738 
739 	list_vbox = gtk_vbox_new(FALSE, 4);
740 
741 	list_swin = gtk_scrolled_window_new(NULL, NULL);
742 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(list_swin),
743 				       GTK_POLICY_AUTOMATIC,
744 				       GTK_POLICY_AUTOMATIC);
745 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(list_swin),
746 					    GTK_SHADOW_IN);
747 	gtk_box_pack_start(GTK_BOX(list_vbox), list_swin, TRUE, TRUE, 0);
748 
749 	/* Address list */
750 	list_store = gtk_tree_store_new(N_LIST_COLS, G_TYPE_STRING,
751 					G_TYPE_STRING, G_TYPE_STRING,
752 					G_TYPE_STRING, G_TYPE_POINTER,
753 					GDK_TYPE_PIXBUF);
754 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store),
755 					COL_NAME,
756 					addressbook_list_name_compare,
757 					NULL, NULL);
758 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store),
759 					COL_ADDRESS,
760 					addressbook_list_address_compare,
761 					NULL, NULL);
762 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store),
763 					COL_NICKNAME,
764 					addressbook_list_nickname_compare,
765 					NULL, NULL);
766 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store),
767 					COL_REMARKS,
768 					addressbook_list_remarks_compare,
769 					NULL, NULL);
770 
771 	listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
772 	g_object_unref(G_OBJECT(list_store));
773 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview));
774 	gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
775 	gtk_tree_selection_set_select_function
776 		(selection, addressbook_list_select_func, NULL, NULL);
777 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(listview), TRUE);
778 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(listview), COL_NAME);
779 	gtk_tree_view_set_reorderable(GTK_TREE_VIEW(listview), FALSE);
780 	gtk_container_add(GTK_CONTAINER(list_swin), listview);
781 
782 	column = gtk_tree_view_column_new();
783 	gtk_tree_view_column_set_spacing(column, 1);
784 	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
785 	gtk_tree_view_column_set_fixed_width
786 		(column, prefs_common.addressbook_col_name);
787 	gtk_tree_view_column_set_resizable(column, TRUE);
788 	gtk_tree_view_column_set_title(column, _("Name"));
789 #if GTK_CHECK_VERSION(2, 14, 0)
790 	/* gtk_tree_view_column_set_expand(column, TRUE); */
791 #endif
792 
793 	renderer = gtk_cell_renderer_pixbuf_new();
794 	g_object_set(renderer, "ypad", 0, NULL);
795 	gtk_tree_view_column_pack_start(column, renderer, FALSE);
796 	gtk_tree_view_column_set_attributes(column, renderer,
797 					    "pixbuf", COL_L_PIXBUF, NULL);
798 
799 	renderer = gtk_cell_renderer_text_new();
800 	g_object_set(renderer,
801 #if GTK_CHECK_VERSION(2, 6, 0)
802 		     "ellipsize", PANGO_ELLIPSIZE_END,
803 #endif
804 		     "ypad", 0, NULL);
805 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
806 	gtk_tree_view_column_set_attributes(column, renderer,
807 					    "text", COL_NAME, NULL);
808 
809 	gtk_tree_view_column_set_sort_column_id(column, COL_NAME);
810 	gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
811 	gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
812 	g_signal_connect(G_OBJECT(column->button), "size-allocate",
813 			 G_CALLBACK(addressbook_col_resized),
814 			 GINT_TO_POINTER(COL_NAME));
815 
816 	renderer = gtk_cell_renderer_text_new();
817 	g_object_set(renderer,
818 #if GTK_CHECK_VERSION(2, 6, 0)
819 		     "ellipsize", PANGO_ELLIPSIZE_END,
820 #endif
821 		     "ypad", 0, NULL);
822 	column = gtk_tree_view_column_new_with_attributes
823 		(_("E-Mail address"), renderer, "text", COL_ADDRESS, NULL);
824 	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
825 	gtk_tree_view_column_set_fixed_width
826 		(column, prefs_common.addressbook_col_addr);
827 	gtk_tree_view_column_set_resizable(column, TRUE);
828 #if GTK_CHECK_VERSION(2, 14, 0)
829 	/* gtk_tree_view_column_set_expand(column, TRUE); */
830 #endif
831 	gtk_tree_view_column_set_sort_column_id(column, COL_ADDRESS);
832 	gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
833 	g_signal_connect(G_OBJECT(column->button), "size-allocate",
834 			 G_CALLBACK(addressbook_col_resized),
835 			 GINT_TO_POINTER(COL_ADDRESS));
836 
837 	renderer = gtk_cell_renderer_text_new();
838 	g_object_set(renderer,
839 #if GTK_CHECK_VERSION(2, 6, 0)
840 		     "ellipsize", PANGO_ELLIPSIZE_END,
841 #endif
842 		     "ypad", 0, NULL);
843 	column = gtk_tree_view_column_new_with_attributes
844 		(_("Nick Name"), renderer, "text", COL_NICKNAME, NULL);
845 	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
846 	gtk_tree_view_column_set_fixed_width
847 		(column, prefs_common.addressbook_col_nickname);
848 	gtk_tree_view_column_set_resizable(column, TRUE);
849 #if GTK_CHECK_VERSION(2, 14, 0)
850 	/* gtk_tree_view_column_set_expand(column, TRUE); */
851 #endif
852 	gtk_tree_view_column_set_sort_column_id(column, COL_NICKNAME);
853 	gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
854 	g_signal_connect(G_OBJECT(column->button), "size-allocate",
855 			 G_CALLBACK(addressbook_col_resized),
856 			 GINT_TO_POINTER(COL_NICKNAME));
857 
858 	renderer = gtk_cell_renderer_text_new();
859 	g_object_set(renderer,
860 #if GTK_CHECK_VERSION(2, 6, 0)
861 		     "ellipsize", PANGO_ELLIPSIZE_END,
862 #endif
863 		     "ypad", 0, NULL);
864 	column = gtk_tree_view_column_new_with_attributes
865 		(_("Remarks"), renderer, "text", COL_REMARKS, NULL);
866 	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
867 	gtk_tree_view_column_set_resizable(column, TRUE);
868 #if GTK_CHECK_VERSION(2, 14, 0)
869 	/* gtk_tree_view_column_set_expand(column, TRUE); */
870 #endif
871 	gtk_tree_view_column_set_sort_column_id(column, COL_REMARKS);
872 	gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
873 	g_signal_connect(G_OBJECT(column->button), "size-allocate",
874 			 G_CALLBACK(addressbook_col_resized),
875 			 GINT_TO_POINTER(COL_REMARKS));
876 
877 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(list_store),
878 					     COL_NAME, GTK_SORT_ASCENDING);
879 
880 	g_signal_connect(G_OBJECT(selection), "changed",
881 			 G_CALLBACK(addressbook_list_selection_changed), NULL);
882 	g_signal_connect(G_OBJECT(listview), "button_press_event",
883 			 G_CALLBACK(addressbook_list_button_pressed),
884 			 NULL);
885 	g_signal_connect(G_OBJECT(listview), "button_release_event",
886 			 G_CALLBACK(addressbook_list_button_released),
887 			 NULL);
888 	g_signal_connect(G_OBJECT(listview), "row_expanded",
889 			 G_CALLBACK(addressbook_person_expand_node), NULL);
890 	g_signal_connect(G_OBJECT(listview), "row_collapsed",
891 			 G_CALLBACK(addressbook_person_collapse_node), NULL);
892 
893 	gtk_tree_view_enable_model_drag_source
894 		(GTK_TREE_VIEW(listview), GDK_BUTTON1_MASK,
895 		 addressbook_drag_types, N_DRAG_TYPES,
896 		 GDK_ACTION_MOVE | GDK_ACTION_COPY);
897 
898 	g_signal_connect_after(G_OBJECT(listview), "drag-begin",
899 			       G_CALLBACK(addressbook_drag_begin), NULL);
900 	g_signal_connect_after(G_OBJECT(listview), "drag-end",
901 			       G_CALLBACK(addressbook_drag_end), NULL);
902 	g_signal_connect(G_OBJECT(listview), "drag-data-get",
903 			 G_CALLBACK(addressbook_drag_data_get), NULL);
904 
905 	hbox = gtk_hbox_new(FALSE, 4);
906 	gtk_box_pack_start(GTK_BOX(list_vbox), hbox, FALSE, FALSE, 0);
907 
908 	label = gtk_label_new(_("Search:"));
909 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
910 
911 	entry = gtk_entry_new();
912 	gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
913 
914 	address_completion_register_entry(GTK_ENTRY(entry));
915 
916 #if 0
917 	g_signal_connect(G_OBJECT(entry), "changed",
918 			 G_CALLBACK(addressbook_entry_changed), NULL);
919 #endif
920 	g_signal_connect(G_OBJECT(entry), "activate",
921 			 G_CALLBACK(addressbook_entry_activated), NULL);
922 
923 	paned = gtk_hpaned_new();
924 	gtk_box_pack_start(GTK_BOX(vbox2), paned, TRUE, TRUE, 0);
925 	gtk_paned_add1(GTK_PANED(paned), tree_swin);
926 	gtk_paned_add2(GTK_PANED(paned), list_vbox);
927 
928 	/* Status bar */
929 	hsbox = gtk_hbox_new(FALSE, 0);
930 	gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, 0);
931 	statusbar = gtk_statusbar_new();
932 	gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, 0);
933 
934 	hbbox = gtk_hbox_new(FALSE, 4);
935 	gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
936 
937 	/* Button panel */
938 	hbbox1 = gtk_hbutton_box_new();
939 	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox1), GTK_BUTTONBOX_END);
940 	gtk_box_set_spacing(GTK_BOX(hbbox1), 4);
941 	gtk_container_set_border_width(GTK_CONTAINER(hbbox1), 4);
942 	gtk_button_box_set_child_size(GTK_BUTTON_BOX(hbbox1), 64, -1);
943 	gtk_box_pack_end(GTK_BOX(hbbox), hbbox1, FALSE, FALSE, 0);
944 
945 	to_btn = gtk_button_new_with_label
946 		(prefs_common.trans_hdr ? _("To:") : "To:");
947 	GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
948 	gtk_box_pack_start(GTK_BOX(hbbox1), to_btn, TRUE, TRUE, 0);
949 	cc_btn = gtk_button_new_with_label
950 		(prefs_common.trans_hdr ? _("Cc:") : "Cc:");
951 	GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
952 	gtk_box_pack_start(GTK_BOX(hbbox1), cc_btn, TRUE, TRUE, 0);
953 	bcc_btn = gtk_button_new_with_label
954 		(prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
955 	GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
956 	gtk_box_pack_start(GTK_BOX(hbbox1), bcc_btn, TRUE, TRUE, 0);
957 
958 	g_signal_connect(G_OBJECT(to_btn), "clicked",
959 			 G_CALLBACK(addressbook_to_clicked),
960 			 GINT_TO_POINTER(COMPOSE_ENTRY_TO));
961 	g_signal_connect(G_OBJECT(cc_btn), "clicked",
962 			 G_CALLBACK(addressbook_to_clicked),
963 			 GINT_TO_POINTER(COMPOSE_ENTRY_CC));
964 	g_signal_connect(G_OBJECT(bcc_btn), "clicked",
965 			 G_CALLBACK(addressbook_to_clicked),
966 			 GINT_TO_POINTER(COMPOSE_ENTRY_BCC));
967 
968 	hbbox2 = gtk_hbutton_box_new();
969 	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox2), GTK_BUTTONBOX_END);
970 	gtk_box_set_spacing(GTK_BOX(hbbox2), 4);
971 	gtk_container_set_border_width(GTK_CONTAINER(hbbox2), 4);
972 	gtk_button_box_set_child_size(GTK_BUTTON_BOX(hbbox2), 64, -1);
973 	gtk_box_pack_end(GTK_BOX(hbbox), hbbox2, TRUE, TRUE, 0);
974 
975 	del_btn = gtk_button_new_with_label(_("Delete"));
976 	GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
977 	gtk_box_pack_start(GTK_BOX(hbbox2), del_btn, TRUE, TRUE, 0);
978 	reg_btn = gtk_button_new_with_label(_("Add"));
979 	GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
980 	gtk_box_pack_start(GTK_BOX(hbbox2), reg_btn, TRUE, TRUE, 0);
981 	lup_btn = gtk_button_new_with_label(_("Search"));
982 	GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
983 	gtk_box_pack_start(GTK_BOX(hbbox2), lup_btn, TRUE, TRUE, 0);
984 	close_btn = gtk_button_new_with_mnemonic(_("_Close"));
985 	GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
986 	gtk_box_pack_start(GTK_BOX(hbbox2), close_btn, TRUE, TRUE, 0);
987 	gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(hbbox2), close_btn,
988 					   TRUE);
989 
990 	g_signal_connect(G_OBJECT(del_btn), "clicked",
991 			 G_CALLBACK(addressbook_del_clicked), NULL);
992 	g_signal_connect(G_OBJECT(reg_btn), "clicked",
993 			 G_CALLBACK(addressbook_reg_clicked), NULL);
994 	g_signal_connect(G_OBJECT(lup_btn), "clicked",
995 			 G_CALLBACK(addressbook_lup_clicked), NULL);
996 	g_signal_connect(G_OBJECT(close_btn), "clicked",
997 			 G_CALLBACK(addressbook_close_clicked), NULL);
998 
999 	/* Build icons for interface */
1000 	stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacepix);
1001 	/* Build control tables */
1002 	addrbookctl_build_map(window);
1003 	addrbookctl_build_iflist();
1004 	addrbookctl_build_ifselect();
1005 
1006 	/* Add each interface into the tree as a root level folder */
1007 	nodeIf = _addressInterfaceList_;
1008 	while( nodeIf ) {
1009 		AdapterInterface *adapter = nodeIf->data;
1010 		AddressInterface *iface = adapter->iface;
1011 
1012 		nodeIf = g_list_next(nodeIf);
1013 
1014 		if(iface->useInterface) {
1015 			AddressTypeControlItem *atci = adapter->atci;
1016 			gchar *text = atci->displayName;
1017 			GtkTreeIter iter;
1018 			GtkTreePath *path;
1019 
1020 			debug_print("addressbook_create: adapter: %s\n", text);
1021 			gtk_tree_store_append(tree_store, &iter, NULL);
1022 			gtk_tree_store_set(tree_store, &iter,
1023 					   COL_FOLDER_NAME, text,
1024 					   COL_OBJ, adapter,
1025 					   COL_PIXBUF, interfacepix,
1026 					   COL_PIXBUF_OPEN, interfacepix, -1);
1027 			path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store), &iter);
1028 			adapter->tree_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(tree_store), path);
1029 			gtk_tree_path_free(path);
1030 		}
1031 	}
1032 
1033 	/* Popup menu */
1034 	n_entries = sizeof(addressbook_tree_popup_entries) /
1035 		sizeof(addressbook_tree_popup_entries[0]);
1036 	tree_popup = menu_create_items(addressbook_tree_popup_entries,
1037 				       n_entries,
1038 				       "<AddressBookTree>", &tree_factory,
1039 				       NULL);
1040 	g_signal_connect(G_OBJECT(tree_popup), "selection_done",
1041 			 G_CALLBACK(addressbook_popup_close), NULL);
1042 	n_entries = sizeof(addressbook_list_popup_entries) /
1043 		sizeof(addressbook_list_popup_entries[0]);
1044 	list_popup = menu_create_items(addressbook_list_popup_entries,
1045 				       n_entries,
1046 				       "<AddressBookList>", &list_factory,
1047 				       NULL);
1048 
1049 	addrbook.window     = window;
1050 	addrbook.menubar    = menubar;
1051 	addrbook.treeview   = treeview;
1052 	addrbook.listview   = listview;
1053 	addrbook.entry      = entry;
1054 	addrbook.statusbar  = statusbar;
1055 	addrbook.status_cid = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "Address Book Window");
1056 
1057 	addrbook.to_btn  = to_btn;
1058 	addrbook.cc_btn  = cc_btn;
1059 	addrbook.bcc_btn = bcc_btn;
1060 	addrbook.del_btn = del_btn;
1061 	addrbook.reg_btn = reg_btn;
1062 	addrbook.lup_btn = lup_btn;
1063 	addrbook.close_btn = close_btn;
1064 
1065 	addrbook.tree_popup   = tree_popup;
1066 	addrbook.list_popup   = list_popup;
1067 	addrbook.tree_factory = tree_factory;
1068 	addrbook.list_factory = list_factory;
1069 	addrbook.menu_factory = menu_factory;
1070 
1071 	addrbook.tree_selected = NULL;
1072 	addrbook.list_selected = NULL;
1073 	address_completion_start(window);
1074 	gtk_widget_show_all(window);
1075 }
1076 
addressbook_close(void)1077 static gint addressbook_close(void)
1078 {
1079 	gtkut_widget_get_uposition(addrbook.window,
1080 				   &prefs_common.addressbook_x,
1081 				   &prefs_common.addressbook_y);
1082 	gtk_widget_hide(addrbook.window);
1083 	addressbook_export_to_file();
1084 	return TRUE;
1085 }
1086 
addressbook_status_show(const gchar * msg)1087 static void addressbook_status_show(const gchar *msg)
1088 {
1089 	if (addrbook.statusbar != NULL) {
1090 		gtk_statusbar_pop(GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid);
1091 		if (msg) {
1092 			gtk_statusbar_push(GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid, msg);
1093 		}
1094 	}
1095 }
1096 
addressbook_ds_show_message(AddressDataSource * ds)1097 static void addressbook_ds_show_message(AddressDataSource *ds)
1098 {
1099 	gint retVal;
1100 	gchar *name;
1101 	gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = "";
1102 
1103 	if (ds) {
1104 		name = addrindex_ds_get_name(ds);
1105 		if (ds->type == ADDR_IF_BOOK && name &&
1106 		    !strcmp(name, ADDR_DS_AUTOREG))
1107 			name = _("Auto-registered address");
1108 		retVal = addrindex_ds_get_status_code(ds);
1109 		if (retVal == MGU_SUCCESS) {
1110 			g_snprintf(msgbuf, sizeof(msgbuf), "%s", name);
1111 		} else {
1112 			g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s",
1113 				   name, mgu_error2string(retVal));
1114 		}
1115 	}
1116 
1117 	addressbook_status_show(msgbuf);
1118 }
1119 
1120 /*
1121 * Delete one or more objects from address list.
1122 */
addressbook_del_clicked(GtkButton * button,gpointer data)1123 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1124 {
1125 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
1126 	GtkTreeSelection *selection;
1127 	GtkTreeModel *model;
1128 	GtkTreeIter iter;
1129 	GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview);
1130 	GtkTreeModel *lmodel;
1131 	GtkTreeIter list_sel;
1132 	AddressObject *pobj = NULL;
1133 	AddressObject *obj = NULL;
1134 	AdapterDSource *ads = NULL;
1135 	gboolean procFlag;
1136 	AlertValue aval;
1137 	AddressBookFile *abf = NULL;
1138 	AddressDataSource *ds = NULL;
1139 
1140 	if (!addrbook.tree_opened)
1141 		return;
1142 
1143 	model = gtk_tree_view_get_model(treeview);
1144 	lmodel = gtk_tree_view_get_model(listview);
1145 	selection = gtk_tree_view_get_selection(treeview);
1146 
1147 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter);
1148 	gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1);
1149 	g_return_if_fail(pobj != NULL);
1150 
1151 	gtkut_tree_row_reference_get_iter(lmodel, addrbook.list_selected,
1152 					  &list_sel);
1153 	gtk_tree_model_get(lmodel, &list_sel, COL_L_OBJ, &obj, -1);
1154 	if (obj == NULL)
1155 		return;
1156 	if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
1157 		return;
1158 	ds = addressbook_find_datasource(&iter);
1159 	if (ds == NULL)
1160 		return;
1161 
1162 	procFlag = FALSE;
1163 	if (pobj->type == ADDR_DATASOURCE) {
1164 		ads = ADAPTER_DSOURCE(pobj);
1165 		if(ads->subType == ADDR_BOOK)
1166 			procFlag = TRUE;
1167 	}
1168 	else if (pobj->type == ADDR_ITEM_FOLDER) {
1169 		procFlag = TRUE;
1170 	} else if (pobj->type == ADDR_ITEM_GROUP) {
1171 		procFlag = TRUE;
1172 	}
1173 	if (!procFlag)
1174 		return;
1175 	abf = ds->rawDataSource;
1176 	if (abf == NULL)
1177 		return;
1178 
1179 	/* Confirm deletion */
1180 	aval = alertpanel(_("Delete address(es)"),
1181 			  _("Really delete the address(es)?"),
1182 			  GTK_STOCK_YES, GTK_STOCK_NO, NULL);
1183 	if (aval != G_ALERTDEFAULT)
1184 		return;
1185 
1186 	/* Process deletions */
1187 	if (pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER) {
1188 		/* Items inside folders */
1189 		GList *node;
1190 
1191 		node = _addressListSelection_;
1192 		while (node) {
1193 			AddrItemObject *aio = node->data;
1194 			node = g_list_next(node);
1195 			if (aio->type == ADDR_ITEM_GROUP) {
1196 				ItemGroup *item = (ItemGroup *)aio;
1197 				GtkTreeIter giter;
1198 
1199 				addressbook_find_group_node(&iter, &giter, item);
1200 				item = addrbook_remove_group(abf, item);
1201 				if (item) {
1202 					addritem_free_item_group(item);
1203 					item = NULL;
1204 				}
1205 				/* Remove group from parent node */
1206 				gtk_tree_store_remove(GTK_TREE_STORE(model), &giter);
1207 			} else if (aio->type == ADDR_ITEM_PERSON) {
1208 				ItemPerson *item = (ItemPerson *)aio;
1209 
1210 				if (_clipObjectList_) {
1211 					_clipObjectList_ = g_list_remove(_clipObjectList_, item);
1212 				}
1213 				item = addrbook_remove_person(abf, item);
1214 				if (item) {
1215 					addritem_free_item_person(item);
1216 					item = NULL;
1217 				}
1218 			} else if (aio->type == ADDR_ITEM_EMAIL) {
1219 				ItemEMail *item = (ItemEMail *)aio;
1220 				ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(item);
1221 
1222 				item = addrbook_person_remove_email(abf, person, item);
1223 				if (item) {
1224 					addritem_free_item_email(item);
1225 					item = NULL;
1226 				}
1227 			}
1228 		}
1229 		addressbook_list_select_clear();
1230 		addressbook_reopen();
1231 		addressbook_modified();
1232 		return;
1233 	} else if (pobj->type == ADDR_ITEM_GROUP) {
1234 		/* Items inside groups */
1235 		GList *node;
1236 		ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
1237 
1238 		node = _addressListSelection_;
1239 		while (node) {
1240 			AddrItemObject *aio = node->data;
1241 			node = g_list_next(node);
1242 			if (aio->type == ADDR_ITEM_EMAIL) {
1243 				ItemEMail *item = (ItemEMail *)aio;
1244 				item = addrbook_group_remove_email(abf, group, item);
1245 			}
1246 		}
1247 		addressbook_list_select_clear();
1248 		addressbook_reopen();
1249 		return;
1250 	}
1251 
1252 	gtk_tree_store_remove(GTK_TREE_STORE(lmodel), &list_sel);
1253 	addressbook_list_select_remove(obj);
1254 }
1255 
addressbook_reg_clicked(GtkButton * button,gpointer data)1256 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1257 {
1258 	addressbook_new_address_cb(NULL, 0, NULL);
1259 }
1260 
addressbook_format_address(AddressObject * obj)1261 gchar *addressbook_format_address(AddressObject *obj)
1262 {
1263 	gchar *buf = NULL;
1264 	gchar *name = NULL;
1265 	gchar *address = NULL;
1266 
1267 	if( obj->type == ADDR_ITEM_EMAIL ) {
1268 		ItemPerson *person = NULL;
1269 		ItemEMail *email = ( ItemEMail * ) obj;
1270 
1271 		person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1272 		if( email->address ) {
1273 			if( ADDRITEM_NAME(email) ) {
1274 				name = ADDRITEM_NAME(email);
1275 				if( *name == '\0' ) {
1276 					name = ADDRITEM_NAME(person);
1277 				}
1278 			}
1279 			else if( person && ADDRITEM_NAME(person) ) {
1280 				name = ADDRITEM_NAME(person);
1281 			}
1282 			else {
1283 				buf = g_strdup( email->address );
1284 			}
1285 			address = email->address;
1286 		}
1287 	}
1288 	else if( obj->type == ADDR_ITEM_PERSON ) {
1289 		ItemPerson *person = ( ItemPerson * ) obj;
1290 		GList *node = person->listEMail;
1291 
1292 		name = ADDRITEM_NAME(person);
1293 		if( node ) {
1294 			ItemEMail *email = ( ItemEMail * ) node->data;
1295 			address = email->address;
1296 		}
1297 	}
1298 	if( address ) {
1299 		if( !prefs_common.always_add_address_only &&
1300 		    name && name[0] != '\0' ) {
1301 			if( name[0] != '"' && strpbrk( name, ",.[]<>" ) != NULL )
1302 				buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1303 			else
1304 				buf = g_strdup_printf( "%s <%s>", name, address );
1305 		}
1306 		else {
1307 			buf = g_strdup( address );
1308 		}
1309 	}
1310 
1311 	return buf;
1312 }
1313 
addressbook_to_clicked(GtkButton * button,gpointer data)1314 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1315 {
1316 	GList *node = _addressListSelection_;
1317 	gboolean new_compose = FALSE;
1318 
1319 	if (!addrbook.target_compose) {
1320 		new_compose = TRUE;
1321 		addrbook.target_compose = compose_new(NULL, NULL, NULL, NULL);
1322 		if (!addrbook.target_compose)
1323 			return;
1324 	}
1325 
1326 	if (new_compose)
1327 		compose_block_modified(addrbook.target_compose);
1328 
1329 	while( node ) {
1330 		AddressObject *obj = node->data;
1331 		Compose *compose = addrbook.target_compose;
1332 
1333 		node = g_list_next( node );
1334 		if( obj->type == ADDR_ITEM_PERSON || obj->type == ADDR_ITEM_EMAIL ) {
1335 			gchar *addr = addressbook_format_address( obj );
1336 			compose_entry_append( compose, addr, (ComposeEntryType) data );
1337 			g_free( addr );
1338 			addr = NULL;
1339 		}
1340 		else if( obj->type == ADDR_ITEM_GROUP ) {
1341 			ItemGroup *group = ( ItemGroup * ) obj;
1342 			GList *nodeMail = group->listEMail;
1343 			while( nodeMail ) {
1344 				ItemEMail *email = nodeMail->data;
1345 				gchar *addr = addressbook_format_address( ( AddressObject * ) email );
1346 				compose_entry_append( compose, addr, (ComposeEntryType) data );
1347 				g_free( addr );
1348 				nodeMail = g_list_next( nodeMail );
1349 			}
1350 		}
1351 	}
1352 
1353 	if (new_compose)
1354 		compose_unblock_modified(addrbook.target_compose);
1355 }
1356 
addressbook_menuitem_set_sensitive(void)1357 static void addressbook_menuitem_set_sensitive(void)
1358 {
1359 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
1360 	GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview);
1361 	GtkTreeSelection *selection;
1362 	GtkTreeSelection *lselection;
1363 	GtkTreeModel *model;
1364 	GtkTreeModel *lmodel;
1365 	GtkTreeIter iter;
1366 	GtkTreeIter liter;
1367 	gboolean canAdd = FALSE;
1368 	gboolean canEditTree = TRUE;
1369 	gboolean canEditAddress = FALSE;
1370 	gboolean canDelete = FALSE;
1371 	gboolean canLookup = FALSE;
1372 	gboolean canCopy = FALSE;
1373 	gboolean canPaste = FALSE;
1374 	gboolean hasListSelection = _addressListSelection_ != NULL;
1375 	AddressTypeControlItem *atci = NULL;
1376 	AddressDataSource *ds = NULL;
1377 	AddressInterface *iface = NULL;
1378 	AddressObject *pobj = NULL;
1379 	AddressObject *obj = NULL;
1380 
1381 	menu_set_sensitive(addrbook.menu_factory, "/File/New Book", FALSE);
1382 	menu_set_sensitive(addrbook.menu_factory, "/File/New vCard", FALSE);
1383 #ifdef USE_JPILOT
1384 	menu_set_sensitive(addrbook.menu_factory, "/File/New JPilot", FALSE);
1385 #endif
1386 #ifdef USE_LDAP
1387 	menu_set_sensitive(addrbook.menu_factory, "/File/New LDAP Server", FALSE);
1388 #endif
1389 	menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
1390 	menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.list_popup));
1391 
1392 	selection = gtk_tree_view_get_selection(treeview);
1393 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1394 		return;
1395 
1396 	gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1);
1397 	if (pobj == NULL)
1398 		return;
1399 
1400 	lmodel = gtk_tree_view_get_model(listview);
1401 	lselection = gtk_tree_view_get_selection(listview);
1402 
1403 	if (addrbook.list_selected) {
1404 		if (gtkut_tree_row_reference_get_iter(lmodel, addrbook.list_selected, &liter))
1405 			gtk_tree_model_get(lmodel, &liter, COL_L_OBJ, &obj, -1);
1406 	}
1407 
1408 	if (pobj->type == ADDR_INTERFACE) {
1409 		AdapterInterface *adapter = ADAPTER_INTERFACE(pobj);
1410 
1411 		iface = adapter->iface;
1412 		if (iface && iface->haveLibrary) {
1413 			/* Enable appropriate File / New command */
1414 			atci = adapter->atci;
1415 			menu_set_sensitive(addrbook.menu_factory, atci->menuCommand, TRUE);
1416 		}
1417 		canEditTree = FALSE;
1418 	} else if (pobj->type == ADDR_DATASOURCE) {
1419 		AdapterDSource *ads = ADAPTER_DSOURCE(pobj);
1420 
1421 		ds = ads->dataSource;
1422 		iface = ds->iface;
1423 		if (!iface->readOnly) {
1424 			canAdd = canEditAddress = TRUE;
1425 		}
1426 		if (!iface->haveLibrary) {
1427 			canAdd = canEditAddress = FALSE;
1428 		}
1429 #ifdef USE_LDAP
1430 		if (ads->subType == ADDR_LDAP) {
1431 			if (iface->haveLibrary && ds->rawDataSource)
1432 				canLookup = TRUE;
1433 		} else
1434 #endif
1435 			canLookup = TRUE;
1436 		if (ads->subType == ADDR_BOOK && pobj->name &&
1437 		    !strcmp(pobj->name, ADDR_DS_AUTOREG))
1438 			canEditTree = FALSE;
1439 	} else if (pobj->type == ADDR_ITEM_FOLDER) {
1440 		ds = addressbook_find_datasource(&iter);
1441 		if (ds) {
1442 			iface = ds->iface;
1443 			if (!iface->readOnly) {
1444 				canAdd = canEditAddress = TRUE;
1445 			}
1446 			canLookup = TRUE;
1447 		}
1448 	} else if (pobj->type == ADDR_ITEM_GROUP) {
1449 		ds = addressbook_find_datasource(&iter);
1450 		if (ds) {
1451 			iface = ds->iface;
1452 			if (!iface->readOnly) {
1453 				canEditAddress = TRUE;
1454 			}
1455 			canLookup = TRUE;
1456 		}
1457 	}
1458 
1459 	if (obj == NULL)
1460 		canEditAddress = FALSE;
1461 	canDelete = canEditAddress;
1462 	if (gtk_tree_selection_count_selected_rows(lselection) > 1)
1463 		canEditAddress = FALSE;
1464 	if (_addressListSelection_) {
1465 		GList *cur;
1466 		AddressObject *item;
1467 
1468 		for (cur = _addressListSelection_; cur != NULL; cur = cur->next) {
1469 			item = cur->data;
1470 			if (item->type == ADDR_ITEM_PERSON) {
1471 				canCopy = TRUE;
1472 				break;
1473 			}
1474 		}
1475 	}
1476 	if (_clipObjectList_ && canAdd)
1477 		canPaste = TRUE;
1478 
1479 	/* Enable add */
1480 	menu_set_sensitive(addrbook.menu_factory, "/Address/New Address", canAdd);
1481 	menu_set_sensitive(addrbook.menu_factory, "/Address/New Folder", canAdd);
1482 	menu_set_sensitive(addrbook.menu_factory, "/Address/New Group", canAdd);
1483 
1484 	menu_set_sensitive(addrbook.menu_factory, "/Address/Add to recipient", hasListSelection);
1485 	menu_set_sensitive(addrbook.menu_factory, "/Address/Add to Cc", hasListSelection);
1486 	menu_set_sensitive(addrbook.menu_factory, "/Address/Add to Bcc", hasListSelection);
1487 
1488 	/* Enable edit */
1489 	menu_set_sensitive(addrbook.menu_factory, "/Address/Edit", canEditAddress);
1490 	menu_set_sensitive(addrbook.menu_factory, "/Address/Delete", canDelete);
1491 
1492 	menu_set_sensitive(addrbook.menu_factory, "/File/Edit", canEditTree);
1493 	menu_set_sensitive(addrbook.menu_factory, "/File/Delete", canEditTree);
1494 
1495 	menu_set_sensitive(addrbook.menu_factory, "/Edit/Copy",   canCopy);
1496 	menu_set_sensitive(addrbook.menu_factory, "/Edit/Paste",  canPaste);
1497 
1498 	menu_set_sensitive(addrbook.menu_factory, "/Tools/Export to CSV file", canEditTree);
1499 
1500 	/* Popup menu */
1501 	menu_set_sensitive(addrbook.tree_factory, "/New Address", canAdd);
1502 	menu_set_sensitive(addrbook.tree_factory, "/New Folder", canAdd);
1503 	menu_set_sensitive(addrbook.tree_factory, "/New Group", canAdd);
1504 	menu_set_sensitive(addrbook.tree_factory, "/Edit", canEditTree);
1505 	menu_set_sensitive(addrbook.tree_factory, "/Delete", canEditTree);
1506 
1507 	menu_set_sensitive(addrbook.list_factory, "/New Address", canAdd);
1508 	menu_set_sensitive(addrbook.list_factory, "/New Folder", canAdd);
1509 	menu_set_sensitive(addrbook.list_factory, "/New Group", canAdd);
1510 	menu_set_sensitive(addrbook.list_factory, "/Add to recipient", hasListSelection);
1511 	menu_set_sensitive(addrbook.list_factory, "/Add to Cc", hasListSelection);
1512 	menu_set_sensitive(addrbook.list_factory, "/Add to Bcc", hasListSelection);
1513 	menu_set_sensitive(addrbook.list_factory, "/Edit", canEditAddress);
1514 	menu_set_sensitive(addrbook.list_factory, "/Delete", canDelete);
1515 	menu_set_sensitive(addrbook.list_factory, "/Copy", canCopy);
1516 	menu_set_sensitive(addrbook.list_factory, "/Paste", canPaste);
1517 
1518 	/* Buttons */
1519 	gtk_widget_set_sensitive(addrbook.to_btn, hasListSelection);
1520 	gtk_widget_set_sensitive(addrbook.cc_btn, hasListSelection);
1521 	gtk_widget_set_sensitive(addrbook.bcc_btn, hasListSelection);
1522 	gtk_widget_set_sensitive(addrbook.reg_btn, canAdd);
1523 	gtk_widget_set_sensitive(addrbook.del_btn, canDelete);
1524 	gtk_widget_set_sensitive(addrbook.lup_btn, canLookup);
1525 }
1526 
addressbook_tree_selection_changed(GtkTreeSelection * selection,gpointer data)1527 static void addressbook_tree_selection_changed(GtkTreeSelection *selection,
1528 					       gpointer data)
1529 {
1530 	GtkTreeModel *model;
1531 	GtkTreeModel *lmodel;
1532 	GtkTreeIter iter;
1533 	GtkTreePath *path;
1534 	AddressObject *obj = NULL;
1535 	AdapterDSource *ads = NULL;
1536 	AddressDataSource *ds = NULL;
1537 	ItemFolder *rootFolder = NULL;
1538 
1539 	debug_print("addressbook_tree_selection_changed\n");
1540 
1541 	if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
1542 		debug_print("addressbook_tree_selection_changed: no selection\n");
1543 		gtk_tree_row_reference_free(addrbook.tree_selected);
1544 		addrbook.tree_selected = NULL;
1545 		gtk_tree_row_reference_free(addrbook.tree_opened);
1546 		addrbook.tree_opened = NULL;
1547 		addressbook_status_show("");
1548 		if (addrbook.entry)
1549 			gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1550 		if (addrbook.listview) {
1551 			lmodel = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.listview));
1552 			gtk_tree_store_clear(GTK_TREE_STORE(lmodel));
1553 		}
1554 		return;
1555 	}
1556 
1557 	path = gtk_tree_model_get_path(model, &iter);
1558 	gtk_tree_row_reference_free(addrbook.tree_selected);
1559 	addrbook.tree_selected = gtk_tree_row_reference_new(model, path);
1560 	gtk_tree_row_reference_free(addrbook.list_selected);
1561 	addrbook.list_selected = NULL;
1562 	addressbook_status_show("");
1563 	if (addrbook.entry)
1564 		gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1565 	if (addrbook.listview) {
1566 		lmodel = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.listview));
1567 		gtk_tree_store_clear(GTK_TREE_STORE(lmodel));
1568 	}
1569 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
1570 	if (obj == NULL) {
1571 		gtk_tree_path_free(path);
1572 		return;
1573 	}
1574 
1575 	gtk_tree_row_reference_free(addrbook.tree_opened);
1576 	addrbook.tree_opened = gtk_tree_row_reference_new(model, path);
1577 
1578 	if (obj->type == ADDR_DATASOURCE) {
1579 		/* Read from file */
1580 		static gboolean tVal = TRUE;
1581 
1582 		ads = ADAPTER_DSOURCE(obj);
1583 		if (ads == NULL) return;
1584 		ds = ads->dataSource;
1585 		if (ds == NULL) return;
1586 
1587 		if (addrindex_ds_get_modify_flag(ds)) {
1588 			addrindex_ds_read_data(ds);
1589 		}
1590 
1591 		if (!addrindex_ds_get_read_flag(ds)) {
1592 			addrindex_ds_read_data(ds);
1593 		}
1594 		addressbook_ds_show_message(ds);
1595 
1596 		if (!addrindex_ds_get_access_flag(ds)) {
1597 			/* Remove existing folders and groups */
1598 			addressbook_tree_remove_children(model, &iter);
1599 
1600 			/* Load folders into the tree */
1601 			rootFolder = addrindex_ds_get_root_folder(ds);
1602 			if (ds->type == ADDR_IF_JPILOT) {
1603 				addressbook_node_add_folder(&iter, ds, rootFolder, ADDR_CATEGORY, NULL);
1604 			} else {
1605 				addressbook_node_add_folder(&iter, ds, rootFolder, ADDR_ITEM_FOLDER, NULL);
1606 			}
1607 			addrindex_ds_set_access_flag(ds, &tVal);
1608 			gtk_tree_view_expand_row(GTK_TREE_VIEW(addrbook.treeview), path, TRUE);
1609 		}
1610 	}
1611 
1612 	gtk_tree_path_free(path);
1613 
1614 	/* Update address list */
1615 	addressbook_set_list(obj);
1616 	addressbook_menuitem_set_sensitive();
1617 	addressbook_list_select_clear();
1618 }
1619 
addressbook_list_selection_changed(GtkTreeSelection * selection,gpointer data)1620 static void addressbook_list_selection_changed(GtkTreeSelection *selection,
1621 					       gpointer data)
1622 {
1623 	GtkTreeModel *lmodel;
1624 	GtkTreePath *path;
1625 	GList *selected;
1626 
1627 	debug_print("addressbook_list_selection_changed\n");
1628 
1629 	selected = gtk_tree_selection_get_selected_rows(selection, &lmodel);
1630 	addressbook_list_select_set(selected);
1631 	gtk_tree_row_reference_free(addrbook.list_selected);
1632 	if (selected) {
1633 		path = (GtkTreePath *)selected->data;
1634 		addrbook.list_selected = gtk_tree_row_reference_new(lmodel, path);
1635 		g_list_foreach(selected, (GFunc)gtk_tree_path_free, NULL);
1636 		g_list_free(selected);
1637 	} else
1638 		addrbook.list_selected = NULL;
1639 
1640 	addressbook_menuitem_set_sensitive();
1641 }
1642 
addressbook_list_select_clear(void)1643 static void addressbook_list_select_clear(void)
1644 {
1645 	if (_addressListSelection_) {
1646 		g_list_free(_addressListSelection_);
1647 	}
1648 	_addressListSelection_ = NULL;
1649 }
1650 
addressbook_list_select_remove(AddressObject * obj)1651 static void addressbook_list_select_remove(AddressObject *obj)
1652 {
1653 	if (!obj)
1654 		return;
1655 	if (_addressListSelection_) {
1656 		_addressListSelection_ = g_list_remove(_addressListSelection_, obj);
1657 	}
1658 }
1659 
addressbook_list_select_set(GList * row_list)1660 static void addressbook_list_select_set(GList *row_list)
1661 {
1662 	GtkTreeModel *model;
1663 	GtkTreeIter iter;
1664 	GList *cur;
1665 	AddressObject *obj;
1666 
1667 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.listview));
1668 
1669 	addressbook_list_select_clear();
1670 	for (cur = row_list; cur != NULL; cur = cur->next) {
1671 		obj = NULL;
1672 		gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
1673 		gtk_tree_model_get(model, &iter, COL_L_OBJ, &obj, -1);
1674 		if (obj && (obj->type == ADDR_ITEM_PERSON ||
1675 			    obj->type == ADDR_ITEM_EMAIL ||
1676 			    obj->type == ADDR_ITEM_GROUP)) {
1677 			_addressListSelection_ = g_list_prepend(_addressListSelection_, obj);
1678 		}
1679 	}
1680 	_addressListSelection_ = g_list_reverse(_addressListSelection_);
1681 }
1682 
addressbook_entry_activated(GtkWidget * widget,gpointer data)1683 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
1684 {
1685 	addressbook_lup_clicked(NULL, NULL);
1686 }
1687 
addressbook_list_button_pressed(GtkWidget * widget,GdkEventButton * event,gpointer data)1688 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
1689 						GdkEventButton *event,
1690 						gpointer data)
1691 {
1692 	GtkTreePath *path = NULL;
1693 	GtkTreeSelection *selection;
1694 	gboolean is_selected = FALSE;
1695 	gboolean mod_pressed = FALSE;
1696 
1697 	if (!event)
1698 		return FALSE;
1699 
1700 	gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), event->x, event->y,
1701 				      &path, NULL, NULL, NULL);
1702 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
1703 	if (path)
1704 		is_selected = gtk_tree_selection_path_is_selected
1705 			(selection, path);
1706 	mod_pressed = ((event->state &
1707 			(GDK_SHIFT_MASK|GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0);
1708 
1709 	if (event->button == 1) {
1710 		if (is_selected && !mod_pressed) {
1711 			can_toggle_list_selection = FALSE;
1712 		}
1713 
1714 		if (is_selected && event->type == GDK_2BUTTON_PRESS) {
1715 			debug_print("addressbook_list_button_pressed: GDK_2BUTTON_PRESS\n");
1716 			/* Handle double click */
1717 			if (prefs_common.add_address_by_click &&
1718 			    addrbook.target_compose)
1719 				addressbook_to_clicked
1720 					(NULL, GINT_TO_POINTER(COMPOSE_ENTRY_TO));
1721 			else
1722 				addressbook_edit_address_cb(NULL, 0, NULL);
1723 			return TRUE;
1724 		}
1725 	} else if (event->button == 3) {
1726 		gtk_menu_popup(GTK_MENU(addrbook.list_popup), NULL, NULL,
1727 			       NULL, NULL, event->button, event->time);
1728 		gtk_tree_path_free(path);
1729 		if (is_selected)
1730 			return TRUE;
1731 	}
1732 
1733 	return FALSE;
1734 }
1735 
addressbook_list_button_released(GtkWidget * widget,GdkEventButton * event,gpointer data)1736 static gboolean addressbook_list_button_released(GtkWidget *widget,
1737 						 GdkEventButton *event,
1738 						 gpointer data)
1739 {
1740 	if (!can_toggle_list_selection && !list_on_drag) {
1741 		GtkTreePath *path;
1742 
1743 		if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), event->x, event->y, &path, NULL, NULL, NULL)) {
1744 			can_toggle_list_selection = TRUE;
1745 			gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), path, NULL, FALSE);
1746 			gtk_tree_path_free(path);
1747 		}
1748 	}
1749 	can_toggle_list_selection = TRUE;
1750 	list_on_drag = FALSE;
1751 	return FALSE;
1752 }
1753 
addressbook_tree_button_pressed(GtkWidget * widget,GdkEventButton * event,gpointer data)1754 static gboolean addressbook_tree_button_pressed(GtkWidget *widget,
1755 						GdkEventButton *event,
1756 						gpointer data)
1757 {
1758 	GtkTreeView *treeview = GTK_TREE_VIEW(widget);
1759 	GtkTreeSelection *selection;
1760 	GtkTreePath *path;
1761 
1762 	if (!event)
1763 		return FALSE;
1764 
1765 	if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
1766 					   &path, NULL, NULL, NULL))
1767 		return TRUE;
1768 	selection = gtk_tree_view_get_selection(treeview);
1769 
1770 	addressbook_menuitem_set_sensitive();
1771 
1772 	if (event->button == 3) {
1773 		gtk_tree_selection_select_path(selection, path);
1774 		gtk_menu_popup(GTK_MENU(addrbook.tree_popup),
1775 			       NULL, NULL, NULL, NULL,
1776 			       event->button, event->time);
1777 	} else if (event->type == GDK_2BUTTON_PRESS) {
1778 		gtk_tree_view_expand_row(treeview, path, FALSE);
1779 	}
1780 
1781 	gtk_tree_path_free(path);
1782 	return FALSE;
1783 }
1784 
addressbook_tree_button_released(GtkWidget * widget,GdkEventButton * event,gpointer data)1785 static gboolean addressbook_tree_button_released(GtkWidget *widget,
1786 						 GdkEventButton *event,
1787 						 gpointer data)
1788 {
1789 	return FALSE;
1790 }
1791 
addressbook_obj_is_droppable(GtkTreeModel * model,AddressObject * obj)1792 static gboolean addressbook_obj_is_droppable(GtkTreeModel *model,
1793 					     AddressObject *obj)
1794 {
1795 	gboolean acceptable = FALSE;
1796 
1797 	if (!model || !obj)
1798 		return FALSE;
1799 	if (!_addressListSelection_)
1800 		return FALSE;
1801 
1802 	if (obj->type == ADDR_DATASOURCE) {
1803 		AdapterDSource *ads;
1804 		AddressDataSource *ds;
1805 		AddressInterface *iface;
1806 
1807 		ads = ADAPTER_DSOURCE(obj);
1808 		ds = ads ? ads->dataSource : NULL;
1809 		iface = ds ? ds->iface : NULL;
1810 		if (ads && ads->subType == ADDR_BOOK &&
1811 		    iface && !iface->readOnly)
1812 			acceptable = TRUE;
1813 	} else if (obj->type == ADDR_ITEM_FOLDER) {
1814 		acceptable = TRUE;
1815 	}
1816 
1817 	if (acceptable && addrbook.tree_opened) {
1818 		AddressObject *open_obj;
1819 		GtkTreeIter opened;
1820 
1821 		gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened,
1822 						  &opened);
1823 		gtk_tree_model_get(model, &opened, COL_OBJ, &open_obj, -1);
1824 		if (open_obj == obj)
1825 			acceptable = FALSE;
1826 	}
1827 
1828 	if (acceptable) {
1829 		GList *node;
1830 		for (node = _addressListSelection_; node != NULL; node = node->next) {
1831 			AddressObject *obj = node->data;
1832 			if (obj && obj->type == ADDR_ITEM_PERSON)
1833 				break;
1834 		}
1835 		if (!node)
1836 			acceptable = FALSE;
1837 	}
1838 
1839 	return acceptable;
1840 }
1841 
addressbook_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,gpointer data)1842 static gboolean addressbook_drag_motion(GtkWidget *widget,
1843 					GdkDragContext *context,
1844 					gint x, gint y,
1845 					guint time, gpointer data)
1846 {
1847 	GtkTreeModel *model;
1848 	GtkTreePath *path = NULL;
1849 	GtkTreeIter iter;
1850 	AddressObject *obj, *src_obj;
1851 	AddressDataSource *src_ds;
1852 	AddressBookFile *src_abf;
1853 	gboolean acceptable;
1854 
1855 	if (!gtk_tree_view_get_dest_row_at_pos
1856 		(GTK_TREE_VIEW(widget), x, y, &path, NULL)) {
1857 		gtk_tree_view_set_drag_dest_row
1858 			(GTK_TREE_VIEW(widget), NULL,
1859 			 GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1860 		gdk_drag_status(context, 0, time);
1861 		return FALSE;
1862 	}
1863 
1864 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1865 	gtk_tree_model_get_iter(model, &iter, path);
1866 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
1867 	g_return_val_if_fail(obj != NULL, FALSE);
1868 
1869 	/* source */
1870 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter);
1871 	gtk_tree_model_get(model, &iter, COL_OBJ, &src_obj, -1);
1872 	g_return_val_if_fail(src_obj != NULL, FALSE);
1873 	src_ds = addressbook_find_datasource(&iter);
1874 	g_return_val_if_fail(src_ds != NULL, FALSE);
1875 	src_abf = src_ds->rawDataSource;
1876 	g_return_val_if_fail(src_abf != NULL, FALSE);
1877 
1878 #ifdef G_OS_WIN32
1879 	{
1880 		GdkModifierType state = 0;
1881 
1882 		gdk_window_get_pointer(widget->window, NULL, NULL, &state);
1883 		if ((state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) == 0)
1884 			context->actions = GDK_ACTION_MOVE | GDK_ACTION_COPY;
1885 	}
1886 #endif
1887 
1888 	if (!src_ds->iface ||
1889 	    (src_ds->iface->readOnly || !src_ds->iface->haveLibrary))
1890 		context->actions &= ~GDK_ACTION_MOVE;
1891 
1892 	acceptable = addressbook_obj_is_droppable(model, obj);
1893 	if ((context->actions & (GDK_ACTION_MOVE | GDK_ACTION_COPY)) == 0)
1894 		acceptable = FALSE;
1895 
1896 	if (!acceptable) {
1897 		gtk_tree_view_set_drag_dest_row
1898 			(GTK_TREE_VIEW(widget), NULL,
1899 			 GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1900 		gdk_drag_status(context, 0, time);
1901 	} else {
1902 		GdkDragAction action = 0;
1903 
1904 		if ((context->actions & GDK_ACTION_MOVE) != 0)
1905 			action = GDK_ACTION_MOVE;
1906 		else if ((context->actions & GDK_ACTION_COPY) != 0)
1907 			action = GDK_ACTION_COPY;
1908 		gtk_tree_view_set_drag_dest_row
1909 			(GTK_TREE_VIEW(widget), path,
1910 			 GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1911 		gdk_drag_status(context, action, time);
1912 	}
1913 
1914 	gtk_tree_path_free(path);
1915 
1916 	return TRUE;
1917 }
1918 
addressbook_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time,gpointer data)1919 static void addressbook_drag_leave(GtkWidget *widget, GdkDragContext *context,
1920 				   guint time, gpointer data)
1921 {
1922 	gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), NULL,
1923 					GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1924 }
1925 
addressbook_drag_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,gpointer user_data)1926 static void addressbook_drag_received(GtkWidget	*widget,
1927 				      GdkDragContext *context,
1928 				      gint x, gint y,
1929 				      GtkSelectionData *data,
1930 				      guint info, guint time,
1931 				      gpointer user_data)
1932 {
1933 	GtkTreeModel *model;
1934 	GtkTreePath *path = NULL;
1935 	GtkTreeIter iter;
1936 	AddressObject *obj, *pobj, *src_obj;
1937 	AddressDataSource *ds, *src_ds;
1938 	AddressBookFile *abf, *src_abf;
1939 	gboolean acceptable;
1940 	gboolean is_move;
1941 	GList *node;
1942 	ItemFolder *folder = NULL;
1943 	ItemPerson *person, *new_person;
1944 
1945 	if (!gtk_tree_view_get_dest_row_at_pos
1946 		(GTK_TREE_VIEW(widget), x, y, &path, NULL))
1947 		return;
1948 
1949 	debug_print("addressbook_drag_received_cb: received data\n");
1950 
1951 	/* dest */
1952 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1953 	gtk_tree_model_get_iter(model, &iter, path);
1954 	gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1);
1955 	g_return_if_fail(pobj != NULL);
1956 	ds = addressbook_find_datasource(&iter);
1957 	g_return_if_fail(ds != NULL);
1958 
1959 	/* source */
1960 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter);
1961 	gtk_tree_model_get(model, &iter, COL_OBJ, &src_obj, -1);
1962 	g_return_if_fail(src_obj != NULL);
1963 	src_ds = addressbook_find_datasource(&iter);
1964 	g_return_if_fail(src_ds != NULL);
1965 	src_abf = src_ds->rawDataSource;
1966 	g_return_if_fail(src_abf != NULL);
1967 
1968 	acceptable = addressbook_obj_is_droppable(model, pobj);
1969 	abf = ds->rawDataSource;
1970 	if (!abf)
1971 		acceptable = FALSE;
1972 
1973 	if ((context->actions & (GDK_ACTION_MOVE | GDK_ACTION_COPY)) == 0)
1974 		acceptable = FALSE;
1975 	is_move = (context->actions & GDK_ACTION_MOVE) != 0;
1976 
1977 	if (!src_ds->iface ||
1978 	    (src_ds->iface->readOnly || !src_ds->iface->haveLibrary))
1979 		is_move = FALSE;
1980 
1981 	if (!_addressListSelection_ || !acceptable) {
1982 		context->action = 0;
1983 		gtk_drag_finish(context, FALSE, FALSE, time);
1984 		gtk_tree_path_free(path);
1985 		return;
1986 	}
1987 
1988 	if (pobj->type == ADDR_ITEM_FOLDER)
1989 		folder = ADAPTER_FOLDER(pobj)->itemFolder;
1990 
1991 	node = _addressListSelection_;
1992 	while (node) {
1993 		GList *cur;
1994 
1995 		obj = node->data;
1996 		node = g_list_next(node);
1997 		if (obj->type != ADDR_ITEM_PERSON)
1998 			continue;
1999 
2000 		person = (ItemPerson *)obj;
2001 		new_person = addrbook_add_address_list(abf, folder, NULL);
2002 		ADDRITEM_NAME(new_person) = g_strdup(ADDRITEM_NAME(person));
2003 		new_person->firstName = g_strdup(person->firstName);
2004                 new_person->lastName = g_strdup(person->lastName);
2005                 new_person->nickName = g_strdup(person->nickName);
2006 		for (cur = person->listEMail; cur != NULL; cur = cur->next) {
2007 			ItemEMail *email = cur->data;
2008 			addritem_person_add_email(new_person, addritem_copy_item_email(email));
2009 		}
2010 		for (cur = person->listAttrib; cur != NULL; cur = cur->next) {
2011 			UserAttribute *attr = cur->data;
2012 			addritem_person_add_attribute(new_person, addritem_copy_attribute(attr));
2013 		}
2014 
2015 		if (is_move) {
2016 			if (_clipObjectList_)
2017 				_clipObjectList_ = g_list_remove(_clipObjectList_, person);
2018 			person = addrbook_remove_person(src_abf, person);
2019 			if (person)
2020 				addritem_free_item_person(person);
2021 		}
2022 	}
2023 
2024 	if (is_move) {
2025 		addressbook_list_select_clear();
2026 		addressbook_reopen();
2027 	}
2028 
2029 	context->action = 0;
2030 	gtk_drag_finish(context, TRUE, FALSE, time);
2031 
2032 	gtk_tree_path_free(path);
2033 
2034 	addressbook_modified();
2035 }
2036 
addressbook_folder_resized(GtkWidget * widget,GtkAllocation * allocation,gpointer data)2037 static void addressbook_folder_resized(GtkWidget *widget,
2038 				       GtkAllocation *allocation,
2039 				       gpointer data)
2040 {
2041 	gint width = allocation->width;
2042 
2043 	if (width < 8)
2044 		return;
2045 
2046 	prefs_common.addressbook_folder_width = width;
2047 }
2048 
addressbook_col_resized(GtkWidget * widget,GtkAllocation * allocation,gpointer data)2049 static void addressbook_col_resized(GtkWidget *widget,
2050 				    GtkAllocation *allocation, gpointer data)
2051 {
2052 	AddressBookListColumnPos type = (gint)data;
2053 	gint width = allocation->width;
2054 
2055 	if (width < 8)
2056 		return;
2057 
2058 	switch (type) {
2059 	case COL_NAME:
2060 		prefs_common.addressbook_col_name = width;
2061 		break;
2062 	case COL_ADDRESS:
2063 		prefs_common.addressbook_col_addr = width;
2064 		break;
2065 	case COL_NICKNAME:
2066 		prefs_common.addressbook_col_nickname = width;
2067 		break;
2068 	case COL_REMARKS:
2069 		prefs_common.addressbook_col_rem = width;
2070 		break;
2071 	default:
2072 		break;
2073 	}
2074 }
2075 
addressbook_popup_close(GtkMenuShell * menu_shell,gpointer data)2076 static void addressbook_popup_close(GtkMenuShell *menu_shell, gpointer data)
2077 {
2078 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2079 	GtkTreeSelection *selection;
2080 	GtkTreePath *path;
2081 
2082 	if (!addrbook.tree_opened)
2083 		return;
2084 
2085 	selection = gtk_tree_view_get_selection(treeview);
2086 	path = gtk_tree_row_reference_get_path(addrbook.tree_opened);
2087 	if (path) {
2088 		gtk_tree_selection_select_path(selection, path);
2089 		gtk_tree_path_free(path);
2090 	}
2091 }
2092 
addressbook_new_folder_cb(gpointer data,guint action,GtkWidget * widget)2093 static void addressbook_new_folder_cb(gpointer data, guint action,
2094 				      GtkWidget *widget)
2095 {
2096 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2097 	GtkTreeSelection *selection;
2098 	GtkTreeModel *model;
2099 	GtkTreeIter iter;
2100 	AddressObject *obj = NULL;
2101 	AddressDataSource *ds = NULL;
2102 	AddressBookFile *abf = NULL;
2103 	ItemFolder *parentFolder = NULL;
2104 	ItemFolder *folder = NULL;
2105 
2106 	selection = gtk_tree_view_get_selection(treeview);
2107 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2108 		return;
2109 
2110 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
2111 	if (obj == NULL)
2112 		return;
2113 	ds = addressbook_find_datasource(&iter);
2114 	if (ds == NULL)
2115 		return;
2116 
2117 	if (obj->type == ADDR_DATASOURCE) {
2118 		if (ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK) return;
2119 	} else if (obj->type == ADDR_ITEM_FOLDER) {
2120 		parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2121 	} else {
2122 		return;
2123 	}
2124 
2125 	abf = ds->rawDataSource;
2126 	if (abf == NULL) return;
2127 	folder = addressbook_edit_folder(abf, parentFolder, NULL);
2128 	if (folder) {
2129 		GtkTreeIter new_iter;
2130 		GtkTreePath *path;
2131 		addressbook_node_add_folder(&iter, ds, folder, ADDR_ITEM_FOLDER, &new_iter);
2132 		path = gtk_tree_model_get_path(model, &iter);
2133 		gtk_tree_view_expand_row(treeview, path, TRUE);
2134 		gtk_tree_path_free(path);
2135 		if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened))
2136 			addressbook_set_list(obj);
2137 	}
2138 
2139 }
2140 
addressbook_new_group_cb(gpointer data,guint action,GtkWidget * widget)2141 static void addressbook_new_group_cb(gpointer data, guint action,
2142 				     GtkWidget *widget)
2143 {
2144 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2145 	GtkTreeSelection *selection;
2146 	GtkTreeModel *model;
2147 	GtkTreeIter iter;
2148 	AddressObject *obj = NULL;
2149 	AddressDataSource *ds = NULL;
2150 	AddressBookFile *abf = NULL;
2151 	ItemFolder *parentFolder = NULL;
2152 	ItemGroup *group = NULL;
2153 
2154 	selection = gtk_tree_view_get_selection(treeview);
2155 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2156 		return;
2157 
2158 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
2159 	if (obj == NULL)
2160 		return;
2161 	ds = addressbook_find_datasource(&iter);
2162 	if (ds == NULL)
2163 		return;
2164 
2165 	if (obj->type == ADDR_DATASOURCE) {
2166 		if (ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK) return;
2167 	} else if (obj->type == ADDR_ITEM_FOLDER) {
2168 		parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2169 	} else {
2170 		return;
2171 	}
2172 
2173 	abf = ds->rawDataSource;
2174 	if (abf == NULL) return;
2175 	group = addressbook_edit_group(abf, parentFolder, NULL);
2176 	if (group) {
2177 		GtkTreeIter new_iter;
2178 		GtkTreePath *path;
2179 		addressbook_node_add_group(&iter, ds, group, &new_iter);
2180 		path = gtk_tree_model_get_path(model, &iter);
2181 		gtk_tree_view_expand_row(treeview, path, TRUE);
2182 		gtk_tree_path_free(path);
2183 		if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened))
2184 			addressbook_set_list(obj);
2185 	}
2186 
2187 }
2188 
addressbook_change_node_name(GtkTreeIter * iter,const gchar * name)2189 static void addressbook_change_node_name(GtkTreeIter *iter, const gchar *name)
2190 {
2191 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2192 	GtkTreeStore *store;
2193 
2194 	store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2195 	gtk_tree_store_set(store, iter, COL_FOLDER_NAME, name, -1);
2196 }
2197 
2198 /*
2199 * Edit data source.
2200 * Enter: obj   Address object to edit.
2201 *        node  Node in tree.
2202 * Return: New name of data source.
2203 */
addressbook_edit_datasource(AddressObject * obj,GtkTreeIter * iter)2204 static gchar *addressbook_edit_datasource(AddressObject *obj, GtkTreeIter *iter)
2205 {
2206 	gchar *newName = NULL;
2207 	AddressDataSource *ds = NULL;
2208 	AddressInterface *iface = NULL;
2209 	AdapterDSource *ads = NULL;
2210 
2211 	ds = addressbook_find_datasource(iter);
2212 	if (ds == NULL)
2213 		return NULL;
2214 	iface = ds->iface;
2215 	if (!iface->haveLibrary)
2216 		return NULL;
2217 
2218 	/* Read data from data source */
2219 	if (!addrindex_ds_get_read_flag(ds)) {
2220 		addrindex_ds_read_data(ds);
2221 	}
2222 
2223 	/* Handle edit */
2224 	ads = ADAPTER_DSOURCE(obj);
2225 	if (ads->subType == ADDR_BOOK) {
2226                 if (addressbook_edit_book(_addressIndex_, ads) == NULL)
2227 			return NULL;
2228 	} else if (ads->subType == ADDR_VCARD) {
2229        	        if (addressbook_edit_vcard(_addressIndex_, ads) == NULL)
2230 			return NULL;
2231 #ifdef USE_JPILOT
2232 	} else if (ads->subType == ADDR_JPILOT) {
2233                 if (addressbook_edit_jpilot(_addressIndex_, ads) == NULL)
2234 			return NULL;
2235 #endif
2236 #ifdef USE_LDAP
2237 	} else if (ads->subType == ADDR_LDAP) {
2238 		if (addressbook_edit_ldap(_addressIndex_, ads) == NULL)
2239 			return NULL;
2240 #endif
2241 	} else {
2242 		return NULL;
2243 	}
2244 	newName = obj->name;
2245 	return newName;
2246 }
2247 
2248 /*
2249 * Edit an object that is in the address tree area.
2250 */
addressbook_treenode_edit_cb(gpointer data,guint action,GtkWidget * widget)2251 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2252 					 GtkWidget *widget)
2253 {
2254 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2255 	GtkTreeSelection *selection;
2256 	GtkTreeModel *model;
2257 	GtkTreeIter iter, parent;
2258 	AddressObject *obj = NULL;
2259 	AddressDataSource *ds = NULL;
2260 	AddressBookFile *abf = NULL;
2261 	gchar *name = NULL;
2262 
2263 	selection = gtk_tree_view_get_selection(treeview);
2264 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2265 		return;
2266 
2267 	if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0)
2268 		return;
2269 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
2270 	if (obj == NULL)
2271 		return;
2272 	if (!gtk_tree_model_iter_parent(model, &parent, &iter))
2273 		return;
2274 
2275 	ds = addressbook_find_datasource(&iter);
2276 	if (ds == NULL)
2277 		return;
2278 
2279 	if (obj->type == ADDR_DATASOURCE) {
2280 		name = addressbook_edit_datasource(obj, &iter);
2281 		if (name == NULL)
2282 			return;
2283 	} else {
2284 		abf = ds->rawDataSource;
2285 		if (abf == NULL)
2286 			return;
2287 		if (obj->type == ADDR_ITEM_FOLDER) {
2288 			AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2289 			ItemFolder *item = adapter->itemFolder;
2290 			ItemFolder *parentFolder = NULL;
2291 			parentFolder = (ItemFolder *)ADDRITEM_PARENT(item);
2292 			if (addressbook_edit_folder(abf, parentFolder, item) == NULL)
2293 				return;
2294 			name = ADDRITEM_NAME(item);
2295 		} else if (obj->type == ADDR_ITEM_GROUP) {
2296 			AdapterGroup *adapter = ADAPTER_GROUP(obj);
2297 			ItemGroup *item = adapter->itemGroup;
2298 			ItemFolder *parentFolder = NULL;
2299 			parentFolder = (ItemFolder *)ADDRITEM_PARENT(item);
2300 			if (addressbook_edit_group(abf, parentFolder, item) == NULL)
2301 				return;
2302 			name = ADDRITEM_NAME(item);
2303 		}
2304 	}
2305 
2306 	if (name) {
2307 		GtkTreePath *path;
2308 
2309 		/* Update node in tree view */
2310 		addressbook_change_node_name(&iter, name);
2311 		path = gtk_tree_model_get_path(model, &iter);
2312 		gtk_tree_view_expand_row(treeview, path, TRUE);
2313 		gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
2314 		gtk_tree_path_free(path);
2315 	}
2316 }
2317 
2318 /*
2319 * Delete an item from the tree widget.
2320 */
addressbook_treenode_delete_cb(gpointer data,guint action,GtkWidget * widget)2321 static void addressbook_treenode_delete_cb(gpointer data, guint action,
2322 					 GtkWidget *widget)
2323 {
2324 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2325 	GtkTreeSelection *selection;
2326 	GtkTreeModel *model;
2327 	GtkTreeIter iter, parent;
2328 	AddressObject *obj;
2329 	gchar *message;
2330 	AlertValue aval;
2331 	AddressBookFile *abf = NULL;
2332 	AdapterDSource *ads = NULL;
2333 	AddressInterface *iface = NULL;
2334 	AddressDataSource *ds = NULL;
2335 	gboolean remFlag = FALSE;
2336 
2337 	selection = gtk_tree_view_get_selection(treeview);
2338 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2339 		return;
2340 
2341 	if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0)
2342 		return;
2343 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
2344 	g_return_if_fail(obj != NULL);
2345 
2346 	if (obj->type == ADDR_DATASOURCE) {
2347 		ads = ADAPTER_DSOURCE(obj);
2348 		if (ads == NULL)
2349 			return;
2350 		ds = ads->dataSource;
2351 		if (ds == NULL)
2352 			return;
2353 	} else {
2354 		/* Must be folder or something else */
2355 		ds = addressbook_find_datasource(&iter);
2356 		if (ds == NULL)
2357 			return;
2358 
2359 		/* Only allow deletion from non-readOnly data sources */
2360 		iface = ds->iface;
2361 		if (iface->readOnly)
2362 			return;
2363 	}
2364 
2365 	/* Confirm deletion */
2366 	if (obj->type == ADDR_ITEM_FOLDER) {
2367 		message = g_strdup_printf
2368 			(_("Do you want to delete the folder AND all addresses in `%s' ?\n"
2369 			   "If deleting the folder only, addresses will be moved into parent folder."),
2370 			 obj->name);
2371 		aval = alertpanel(_("Delete folder"), message, _("_Folder only"), _("Folder and _addresses"), GTK_STOCK_CANCEL);
2372 		g_free(message);
2373 		if (aval != G_ALERTDEFAULT && aval != G_ALERTALTERNATE)
2374 			return;
2375 	} else {
2376 		message = g_strdup_printf(_("Really delete `%s' ?"), obj->name);
2377 		aval = alertpanel(_("Delete"), message, GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2378 		g_free(message);
2379 		if (aval != G_ALERTDEFAULT)
2380 			return;
2381 	}
2382 
2383 	/* Proceed with deletion */
2384 	if (obj->type == ADDR_DATASOURCE) {
2385 		/* Remove data source. */
2386 		if (addrindex_index_remove_datasource(_addressIndex_, ds)) {
2387 			addressbook_free_child_adapters(&iter);
2388 			abf = addressbook_get_book_file();
2389 			if (abf) {
2390 				gchar *bookFile;
2391 				bookFile = g_strconcat(abf->path, G_DIR_SEPARATOR_S, abf->fileName, NULL);
2392 				debug_print("removing %s\n", bookFile);
2393 				g_unlink(bookFile);
2394 				g_free(bookFile);
2395 			}
2396 			remFlag = TRUE;
2397 		}
2398 	} else {
2399 		abf = addressbook_get_book_file();
2400 		if (abf == NULL)
2401 			return;
2402 	}
2403 
2404 	if (obj->type == ADDR_ITEM_FOLDER) {
2405 		AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2406 		ItemFolder *item = adapter->itemFolder;
2407 
2408 		if (aval == G_ALERTDEFAULT) {
2409 			/* Remove folder only */
2410 			item = addrbook_remove_folder(abf, item);
2411 			if (item) {
2412 				addritem_free_item_folder(item);
2413 				addressbook_move_nodes_up(&iter);
2414 				remFlag = TRUE;
2415 			}
2416 		} else if (aval == G_ALERTALTERNATE) {
2417 			/* Remove folder and addresses */
2418 			item = addrbook_remove_folder_delete(abf, item);
2419 			if (item) {
2420 				addritem_free_item_folder(item);
2421 				addressbook_free_child_adapters(&iter);
2422 				remFlag = TRUE;
2423 			}
2424 		}
2425 	} else if (obj->type == ADDR_ITEM_GROUP) {
2426 		AdapterGroup *adapter = ADAPTER_GROUP(obj);
2427 		ItemGroup *item = adapter->itemGroup;
2428 
2429 		item = addrbook_remove_group(abf, item);
2430 		if (item) {
2431 			addritem_free_item_group(item);
2432 			remFlag = TRUE;
2433 		}
2434 	}
2435 
2436 	if (remFlag) {
2437 		/* Free up adapter and remove node. */
2438 		addressbook_free_adapter(&iter);
2439 		gtk_tree_model_iter_parent(model, &parent, &iter);
2440 		gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2441 		gtk_tree_selection_select_iter(selection, &parent);
2442 	}
2443 }
2444 
addressbook_new_address_cb(gpointer data,guint action,GtkWidget * widget)2445 static void addressbook_new_address_cb(gpointer data, guint action, GtkWidget *widget)
2446 {
2447 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2448 	GtkTreeSelection *selection;
2449 	GtkTreeModel *model;
2450 	GtkTreeIter iter;
2451 	AddressObject *pobj = NULL;
2452 	AddressDataSource *ds = NULL;
2453 	AddressBookFile *abf = NULL;
2454 
2455 	selection = gtk_tree_view_get_selection(treeview);
2456 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2457 		return;
2458 
2459 	gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1);
2460 	if (pobj == NULL)
2461 		return;
2462 	ds = addressbook_find_datasource(&iter);
2463 	if (ds == NULL)
2464 		return;
2465 
2466 	abf = ds->rawDataSource;
2467 	if (abf == NULL)
2468 		return;
2469 
2470 	if (pobj->type == ADDR_DATASOURCE) {
2471 		if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK) {
2472 			/* New address */
2473 			ItemPerson *person = addressbook_edit_person(abf, NULL, NULL, FALSE);
2474 			if (person) {
2475 				if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) {
2476 					addressbook_reopen();
2477 				}
2478 				addressbook_modified();
2479 			}
2480 		}
2481 	}
2482 	else if( pobj->type == ADDR_ITEM_FOLDER ) {
2483 		/* New address */
2484 		ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
2485 		ItemPerson *person = addressbook_edit_person(abf, folder, NULL, FALSE);
2486 		if (person) {
2487 			if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) {
2488 				addressbook_reopen();
2489 			}
2490 			addressbook_modified();
2491 		}
2492 	}
2493 	else if( pobj->type == ADDR_ITEM_GROUP ) {
2494 		/* New address in group */
2495 		ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
2496 
2497 		if (addressbook_edit_group(abf, NULL, group) == NULL)
2498 			return;
2499 		if (gtkut_tree_row_reference_equal
2500 			(addrbook.tree_selected, addrbook.tree_opened)) {
2501 			/* Change node name in tree. */
2502 			addressbook_change_node_name(&iter, ADDRITEM_NAME(group));
2503 			addressbook_reopen();
2504 		}
2505 	}
2506 }
2507 
addressbook_compose_to_cb(gpointer data,guint action,GtkWidget * widget)2508 static void addressbook_compose_to_cb(gpointer data, guint action, GtkWidget *widget)
2509 {
2510 	addressbook_to_clicked(NULL, GINT_TO_POINTER(action));
2511 }
2512 
2513 /*
2514 * Search for specified group in address index tree.
2515 */
addressbook_find_group_node(GtkTreeIter * parent,GtkTreeIter * iter,ItemGroup * group)2516 static gboolean addressbook_find_group_node(GtkTreeIter *parent, GtkTreeIter *iter, ItemGroup *group)
2517 {
2518 	GtkTreeModel *model;
2519 	GtkTreeIter iter_;
2520 	gboolean valid = TRUE;
2521 
2522 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
2523 	valid = gtk_tree_model_iter_children(model, &iter_, parent);
2524 	while (valid) {
2525 		AddressObject *obj = NULL;
2526 
2527 		gtk_tree_model_get(model, &iter_, COL_OBJ, &obj, -1);
2528 		if (obj && obj->type == ADDR_ITEM_GROUP) {
2529 			ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
2530 			if (g == group) {
2531 				*iter = iter_;
2532 				return TRUE;
2533 			}
2534 		}
2535 		valid = gtk_tree_model_iter_next(model, &iter_);
2536 	}
2537 
2538 	return FALSE;
2539 }
2540 
addressbook_get_book_file(void)2541 static AddressBookFile *addressbook_get_book_file(void)
2542 {
2543 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2544 	GtkTreeSelection *selection;
2545 	GtkTreeIter iter;
2546 	AddressBookFile *abf = NULL;
2547 	AddressDataSource *ds = NULL;
2548 
2549 	selection = gtk_tree_view_get_selection(treeview);
2550 	if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
2551 		return NULL;
2552 	ds = addressbook_find_datasource(&iter);
2553 	if (ds == NULL)
2554 		return NULL;
2555 	if (ds->type == ADDR_IF_BOOK)
2556 		abf = ds->rawDataSource;
2557 	return abf;
2558 }
2559 
addressbook_tree_remove_children(GtkTreeModel * model,GtkTreeIter * parent)2560 static void addressbook_tree_remove_children(GtkTreeModel *model,
2561 					     GtkTreeIter *parent)
2562 {
2563 	GtkTreeIter iter;
2564 
2565 	/* Remove existing folders and groups */
2566 	while (gtk_tree_model_iter_children(model, &iter, parent)) {
2567 		gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2568 	}
2569 }
2570 
addressbook_move_nodes_recursive(GtkTreeIter * iter,GtkTreeIter * parent)2571 static void addressbook_move_nodes_recursive(GtkTreeIter *iter,
2572 					     GtkTreeIter *parent)
2573 {
2574 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2575 	GtkTreeModel *model;
2576 	GtkTreeIter child, new_iter;
2577 	gboolean valid;
2578 
2579 	model = gtk_tree_view_get_model(treeview);
2580 
2581 	valid = gtk_tree_model_iter_children(model, &child, iter);
2582 	while (valid) {
2583 		gchar *name = NULL;
2584 		AddressObject *obj = NULL;
2585 		GdkPixbuf *pixbuf = NULL;
2586 		GdkPixbuf *pixbuf_open = NULL;
2587 
2588 		gtk_tree_model_get(model, &child, COL_FOLDER_NAME, &name,
2589 				   COL_OBJ, &obj, COL_PIXBUF, &pixbuf,
2590 				   COL_PIXBUF_OPEN, &pixbuf_open, -1);
2591 		gtk_tree_store_append(GTK_TREE_STORE(model), &new_iter, parent);
2592 		gtk_tree_store_set(GTK_TREE_STORE(model), &new_iter,
2593 				   COL_FOLDER_NAME, name,
2594 				   COL_OBJ, obj,
2595 				   COL_PIXBUF, pixbuf,
2596 				   COL_PIXBUF_OPEN, pixbuf_open, -1);
2597 		g_free(name);
2598 		addressbook_move_nodes_recursive(&child, &new_iter);
2599 		valid = gtk_tree_model_iter_next(model, &child);
2600 	}
2601 }
2602 
addressbook_move_nodes_up(GtkTreeIter * iter)2603 static void addressbook_move_nodes_up(GtkTreeIter *iter)
2604 {
2605 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2606 	GtkTreeModel *model;
2607 	GtkTreeIter parent;
2608 
2609 	model = gtk_tree_view_get_model(treeview);
2610 	if (!gtk_tree_model_iter_parent(model, &parent, iter))
2611 		return;
2612 
2613 	addressbook_move_nodes_recursive(iter, &parent);
2614 }
2615 
addressbook_edit_address_cb(gpointer data,guint action,GtkWidget * widget)2616 static void addressbook_edit_address_cb(gpointer data, guint action, GtkWidget *widget)
2617 {
2618 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2619 	GtkTreeSelection *selection;
2620 	GtkTreeModel *model;
2621 	GtkTreeIter liter, iter, node, parent;
2622 	gboolean node_found;
2623 	gboolean parent_found = FALSE;
2624 	GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview);
2625 	GtkTreeModel *lmodel;
2626 	AddressObject *obj = NULL, *pobj = NULL;
2627 	AddressDataSource *ds = NULL;
2628 	gchar *name = NULL;
2629 	AddressBookFile *abf = NULL;
2630 
2631 	if (addrbook.list_selected == NULL)
2632 		return;
2633 
2634 	lmodel = gtk_tree_view_get_model(listview);
2635 	if (!gtkut_tree_row_reference_get_iter(lmodel, addrbook.list_selected,
2636 					       &liter))
2637 		return;
2638 	gtk_tree_model_get(lmodel, &liter, COL_L_OBJ, &obj, -1);
2639 	g_return_if_fail(obj != NULL);
2640 
2641 	selection = gtk_tree_view_get_selection(treeview);
2642 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2643 		return;
2644 	gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1);
2645 	node_found = gtkut_tree_model_find_by_column_data
2646 		(model, &node, &iter, COL_OBJ, obj);
2647 
2648 	ds = addressbook_find_datasource(&iter);
2649 	if (ds == NULL)
2650 		return;
2651 
2652 	abf = addressbook_get_book_file();
2653 	if (abf == NULL)
2654 		return;
2655 
2656 	if (obj->type == ADDR_ITEM_EMAIL) {
2657 		ItemEMail *email = (ItemEMail *)obj;
2658 		ItemPerson *person;
2659 
2660 		if (email == NULL)
2661 			return;
2662 		if (pobj && pobj->type == ADDR_ITEM_GROUP) {
2663 			/* Edit parent group */
2664 			AdapterGroup *adapter = ADAPTER_GROUP(pobj);
2665 			ItemGroup *itemGrp = adapter->itemGroup;
2666 
2667 			if (addressbook_edit_group(abf, NULL, itemGrp) == NULL)
2668 				return;
2669 			name = ADDRITEM_NAME(itemGrp);
2670 			node = iter;
2671 			node_found = TRUE;
2672 			parent_found = gtk_tree_model_iter_parent(model, &parent, &node);
2673 		} else {
2674 			/* Edit person - email page */
2675 			person = (ItemPerson *)ADDRITEM_PARENT(email);
2676 			if (addressbook_edit_person(abf, NULL, person, TRUE) == NULL)
2677 				return;
2678 			addressbook_reopen();
2679 			addressbook_modified();
2680 			return;
2681 		}
2682 	} else if (obj->type == ADDR_ITEM_PERSON) {
2683 		/* Edit person - basic page */
2684 		ItemPerson *person = (ItemPerson *)obj;
2685 
2686 		if (addressbook_edit_person(abf, NULL, person, FALSE) == NULL)
2687 			return;
2688 		addressbook_reopen();
2689 		addressbook_modified();
2690 		return;
2691 	} else if (obj->type == ADDR_ITEM_GROUP) {
2692 		ItemGroup *itemGrp = (ItemGroup *)obj;
2693 
2694 		if (addressbook_edit_group(abf, NULL, itemGrp) == NULL)
2695 			return;
2696 		parent = iter;
2697 		parent_found = TRUE;
2698 		node_found = addressbook_find_group_node(&parent, &node, itemGrp);
2699 		name = ADDRITEM_NAME(itemGrp);
2700 	} else {
2701 		return;
2702 	}
2703 
2704 	/* Update tree node with node name */
2705 	if (node_found) {
2706 		addressbook_change_node_name(&node, name);
2707 		addressbook_reopen();
2708 	}
2709 }
2710 
addressbook_delete_address_cb(gpointer data,guint action,GtkWidget * widget)2711 static void addressbook_delete_address_cb(gpointer data, guint action,
2712 					  GtkWidget *widget)
2713 {
2714 	addressbook_del_clicked(NULL, NULL);
2715 }
2716 
addressbook_copy_address_cb(gpointer data,guint action,GtkWidget * widget)2717 static void addressbook_copy_address_cb(gpointer data, guint action,
2718 					GtkWidget *widget)
2719 {
2720 	AddressObject *obj;
2721 	GList *node;
2722 
2723 	if (_addressListSelection_ == NULL)
2724 		return;
2725 
2726 	g_list_free(_clipObjectList_);
2727 	_clipObjectList_ = NULL;
2728 
2729 	node = _addressListSelection_;
2730 	while (node) {
2731 		obj = node->data;
2732 		if (obj->type == ADDR_ITEM_PERSON) {
2733 			_clipObjectList_ = g_list_append(_clipObjectList_, obj);
2734 		}
2735 		node = g_list_next(node);
2736 	}
2737 
2738 	addressbook_menuitem_set_sensitive();
2739 }
2740 
addressbook_paste_address_cb(gpointer data,guint action,GtkWidget * widget)2741 static void addressbook_paste_address_cb(gpointer data, guint action,
2742 					 GtkWidget *widget)
2743 {
2744 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
2745 	GtkTreeSelection *selection;
2746 	GtkTreeModel *model;
2747 	GtkTreeIter iter;
2748 	AddressObject *obj = NULL, *pobj = NULL;
2749 	AddressDataSource *ds = NULL;
2750 	AddressBookFile *abf = NULL;
2751 	ItemFolder *folder = NULL;
2752 	ItemPerson *clipPerson, *person;
2753 	GList *cur;
2754 	GList *node;
2755 
2756 	if (!_clipObjectList_)
2757 		return;
2758 
2759 	selection = gtk_tree_view_get_selection(treeview);
2760 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
2761 		return;
2762 	gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1);
2763 	if (pobj->type == ADDR_ITEM_FOLDER)
2764 		folder = ADAPTER_FOLDER(pobj)->itemFolder;
2765 	else if (pobj->type == ADDR_DATASOURCE)
2766 		folder = NULL;
2767 	else
2768 		return;
2769 
2770 	ds = addressbook_find_datasource(&iter);
2771 	if (ds == NULL)
2772 		return;
2773 
2774 	abf = ds->rawDataSource;
2775 	if (abf == NULL)
2776 		return;
2777 
2778 	node = _clipObjectList_;
2779 	while (node) {
2780 		obj = node->data;
2781 		node = g_list_next(node);
2782 		if (obj->type != ADDR_ITEM_PERSON)
2783 			continue;
2784 		clipPerson = (ItemPerson *)obj;
2785 
2786 		person = addrbook_add_address_list(abf, folder, NULL);
2787 		ADDRITEM_NAME(person) = g_strdup(ADDRITEM_NAME(clipPerson));
2788 		person->firstName = g_strdup(clipPerson->firstName);
2789 		person->lastName = g_strdup(clipPerson->lastName);
2790 		person->nickName = g_strdup(clipPerson->nickName);
2791 		for (cur = clipPerson->listEMail; cur != NULL; cur = cur->next) {
2792 			ItemEMail *email = cur->data;
2793 			addritem_person_add_email(person, addritem_copy_item_email(email));
2794 		}
2795 		for (cur = clipPerson->listAttrib; cur != NULL; cur = cur->next) {
2796 			UserAttribute *attr = cur->data;
2797 			addritem_person_add_attribute(person, addritem_copy_attribute(attr));
2798 		}
2799 	}
2800 
2801 	if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened))
2802 		addressbook_reopen();
2803 	addressbook_modified();
2804 }
2805 
close_cb(gpointer data,guint action,GtkWidget * widget)2806 static void close_cb(gpointer data, guint action, GtkWidget *widget)
2807 {
2808 	addressbook_close();
2809 }
2810 
addressbook_file_save_cb(gpointer data,guint action,GtkWidget * widget)2811 static void addressbook_file_save_cb(gpointer data, guint action, GtkWidget *widget)
2812 {
2813 	addressbook_export_to_file();
2814 }
2815 
addressbook_person_expand_node(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,gpointer * data)2816 static void addressbook_person_expand_node(GtkTreeView *treeview,
2817 					   GtkTreeIter *iter, GtkTreePath *path,
2818 					   gpointer *data)
2819 {
2820 	GtkTreeModel *model;
2821 	ItemPerson *person = NULL;
2822 
2823 	model = gtk_tree_view_get_model(treeview);
2824 	gtk_tree_model_get(model, iter, COL_L_OBJ, &person, -1);
2825 	if (person)
2826 		addritem_person_set_opened(person, TRUE);
2827 }
2828 
addressbook_person_collapse_node(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,gpointer * data)2829 static void addressbook_person_collapse_node(GtkTreeView *treeview,
2830 					     GtkTreeIter *iter,
2831 					     GtkTreePath *path, gpointer *data)
2832 {
2833 	GtkTreeModel *model;
2834 	ItemPerson *person = NULL;
2835 
2836 	model = gtk_tree_view_get_model(treeview);
2837 	gtk_tree_model_get(model, iter, COL_L_OBJ, &person, -1);
2838 	if (person)
2839 		addritem_person_set_opened(person, FALSE);
2840 }
2841 
addressbook_drag_begin(GtkWidget * widget,GdkDragContext * drag_context,gpointer data)2842 static void addressbook_drag_begin(GtkWidget *widget,
2843 				   GdkDragContext *drag_context, gpointer data)
2844 {
2845 	list_on_drag = TRUE;
2846 	/* gtk_drag_set_icon_default(drag_context); */
2847 }
2848 
addressbook_drag_end(GtkWidget * widget,GdkDragContext * drag_context,gpointer data)2849 static void addressbook_drag_end(GtkWidget *widget,
2850 				 GdkDragContext *drag_context, gpointer data)
2851 {
2852 }
2853 
addressbook_drag_data_get(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * selection_data,guint info,guint time,gpointer data)2854 static void addressbook_drag_data_get(GtkWidget *widget,
2855 				      GdkDragContext *drag_context,
2856 				      GtkSelectionData *selection_data,
2857 				      guint info, guint time, gpointer data)
2858 {
2859 	if (info == DRAG_TYPE_OBJ) {
2860 		gtk_selection_data_set(selection_data, selection_data->target,
2861 				       8, (guchar *)"drag-from-list", 14);
2862 	}
2863 }
2864 
addressbook_format_item_list(ItemPerson * person,ItemEMail * email)2865 static gchar *addressbook_format_item_list(ItemPerson *person, ItemEMail *email)
2866 {
2867 	gchar *str = NULL;
2868 	gchar *eMailAlias = ADDRITEM_NAME(email);
2869 
2870 	if (eMailAlias && *eMailAlias != '\0') {
2871 		if (person) {
2872 			str = g_strdup_printf("%s - %s", ADDRITEM_NAME(person), eMailAlias);
2873 		} else {
2874 			str = g_strdup(eMailAlias);
2875 		}
2876 	}
2877 	return str;
2878 }
2879 
addressbook_match_item(const gchar * name,const gchar * email_alias,const gchar * addr,const gchar * remarks,const gchar * str)2880 static gboolean addressbook_match_item(const gchar *name,
2881 				       const gchar *email_alias,
2882 				       const gchar *addr,
2883 				       const gchar *remarks,
2884 				       const gchar *str)
2885 {
2886 	if (!name)
2887 		return FALSE;
2888 	if (!str || str[0] == '\0')
2889 		return TRUE;
2890 	if (strcasestr(name, str))
2891 		return TRUE;
2892 	else if (email_alias && strcasestr(email_alias, str))
2893 		return TRUE;
2894 	else if (addr && strcasestr(addr, str))
2895 		return TRUE;
2896 	else if (remarks && strcasestr(remarks, str))
2897 		return TRUE;
2898 
2899 	return FALSE;
2900 }
2901 
addressbook_load_group(ItemGroup * itemGroup)2902 static void addressbook_load_group(ItemGroup *itemGroup)
2903 {
2904 	GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview);
2905 	GtkTreeModel *model;
2906 	GtkTreeIter iter;
2907 	GList *items = itemGroup->listEMail;
2908 	AddressTypeControlItem *atci = addrbookctl_lookup(ADDR_ITEM_EMAIL);
2909 	const gchar *search_str;
2910 
2911 	model = gtk_tree_view_get_model(listview);
2912 	search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
2913 
2914 	for (; items != NULL; items = g_list_next(items)) {
2915 		ItemEMail *email = items->data;
2916 		ItemPerson *person;
2917 		const gchar *name;
2918 		gchar *str;
2919 
2920 		if (!email) continue;
2921 
2922 		person = (ItemPerson *)ADDRITEM_PARENT(email);
2923 		if (!person) {
2924 			g_warning("email %p (%s) don't have parent\n", email, email->address);
2925 			continue;
2926 		}
2927 		if (!addressbook_match_item(ADDRITEM_NAME(person),
2928 					    ADDRITEM_NAME(email),
2929 					    email->address, email->remarks,
2930 					    search_str))
2931 			continue;
2932 
2933 		str = addressbook_format_item_list(person, email);
2934 		if (str) {
2935 			name = str;
2936 		} else {
2937 			name = ADDRITEM_NAME(person);
2938 		}
2939 		gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
2940 		gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
2941 				   COL_NAME, name,
2942 				   COL_ADDRESS, email->address ? email->address : "",
2943 				   COL_NICKNAME, person->nickName ? person->nickName : "",
2944 				   COL_REMARKS, email->remarks ? email->remarks : "",
2945 				   COL_L_OBJ, email,
2946 				   COL_L_PIXBUF, atci->icon_pixbuf,
2947 				   -1);
2948 		g_free(str);
2949 	}
2950 }
2951 
addressbook_folder_load_person(ItemFolder * itemFolder)2952 static void addressbook_folder_load_person(ItemFolder *itemFolder)
2953 {
2954 	GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview);
2955 	GtkTreeModel *model;
2956 	GList *items;
2957 	AddressTypeControlItem *atci = addrbookctl_lookup(ADDR_ITEM_PERSON);
2958 	AddressTypeControlItem *atciMail = addrbookctl_lookup(ADDR_ITEM_EMAIL);
2959 	const gchar *search_str;
2960 
2961 	if (atci == NULL)
2962 		return;
2963 	if (atciMail == NULL)
2964 		return;
2965 
2966 	model = gtk_tree_view_get_model(listview);
2967 	search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
2968 
2969 	/* Load email addresses */
2970 	items = addritem_folder_get_person_list(itemFolder);
2971 	for (; items != NULL; items = g_list_next(items)) {
2972 		GtkTreeIter iperson, iemail;
2973 		gboolean flgFirst = TRUE, haveAddr = FALSE;
2974 		ItemPerson *person;
2975 		ItemEMail *email;
2976 		GList *node;
2977 
2978 		person = (ItemPerson *)items->data;
2979 		if (!person)
2980 			continue;
2981 
2982 		node = person->listEMail;
2983 		if (node && node->data) {
2984 			email = node->data;
2985 			if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
2986 				continue;
2987 		} else {
2988 			if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
2989 				continue;
2990 		}
2991 
2992 		while (node) {
2993 			const gchar *name;
2994 
2995 			email = node->data;
2996 			node = g_list_next(node);
2997 
2998 			if (flgFirst) {
2999 				/* First email belongs with person */
3000 				gchar *str = addressbook_format_item_list(person, email);
3001 				if (str) {
3002 					name = str;
3003 				} else {
3004 					name = ADDRITEM_NAME(person);
3005 				}
3006 
3007 				gtk_tree_store_append(GTK_TREE_STORE(model),
3008 						      &iperson, NULL);
3009 				gtk_tree_store_set(GTK_TREE_STORE(model),
3010 						   &iperson,
3011 						   COL_NAME, name,
3012 						   COL_ADDRESS, email->address ? email->address : "",
3013 						   COL_NICKNAME, person->nickName ? person->nickName : "",
3014 						   COL_REMARKS, email->remarks ? email->remarks : "",
3015 						   COL_L_OBJ, person,
3016 						   COL_L_PIXBUF, atci->icon_pixbuf,
3017 						   -1);
3018 				g_free(str);
3019 			} else {
3020 				/* Subsequent email is a child node of person */
3021 				name = ADDRITEM_NAME(email);
3022 				gtk_tree_store_append(GTK_TREE_STORE(model),
3023 						      &iemail, &iperson);
3024 				gtk_tree_store_set(GTK_TREE_STORE(model),
3025 						   &iemail,
3026 						   COL_NAME, name,
3027 						   COL_ADDRESS, email->address ? email->address : "",
3028 						   COL_NICKNAME, "",
3029 						   COL_REMARKS, email->remarks ? email->remarks : "",
3030 						   COL_L_OBJ, email,
3031 						   COL_L_PIXBUF, atciMail->icon_pixbuf,
3032 						   -1);
3033 			}
3034 			flgFirst = FALSE;
3035 			haveAddr = TRUE;
3036 		}
3037 		if (!haveAddr) {
3038 			/* Have name without EMail */
3039 			gtk_tree_store_append(GTK_TREE_STORE(model),
3040 					      &iperson, NULL);
3041 			gtk_tree_store_set(GTK_TREE_STORE(model),
3042 					   &iperson,
3043 					   COL_NAME, ADDRITEM_NAME(person),
3044 					   COL_ADDRESS, "",
3045 					   COL_NICKNAME, person->nickName ? person->nickName : "",
3046 					   COL_REMARKS, "",
3047 					   COL_L_OBJ, person,
3048 					   COL_L_PIXBUF, atci->icon_pixbuf,
3049 					   -1);
3050 		}
3051 		if (person->isOpened) {
3052 			GtkTreePath *path;
3053 			path = gtk_tree_model_get_path(model, &iperson);
3054 			gtk_tree_view_expand_row(listview, path, TRUE);
3055 			gtk_tree_path_free(path);
3056 		}
3057 	}
3058 
3059 	/* Free up the list */
3060 	mgu_clear_list(items);
3061 	g_list_free(items);
3062 }
3063 
addressbook_folder_load_group(ItemFolder * itemFolder)3064 static void addressbook_folder_load_group(ItemFolder *itemFolder)
3065 {
3066 	GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview);
3067 	GtkTreeModel *model;
3068 	GList *items;
3069 	AddressTypeControlItem *atci = addrbookctl_lookup(ADDR_ITEM_GROUP);
3070 	const gchar *search_str;
3071 
3072 	if (!atci)
3073 		return;
3074 
3075 	model = gtk_tree_view_get_model(listview);
3076 	search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3077 
3078 	/* Load any groups */
3079 	items = addritem_folder_get_group_list(itemFolder);
3080 	for (; items != NULL; items = g_list_next(items)) {
3081 		GtkTreeIter iter;
3082 		ItemGroup *group = items->data;
3083 
3084 		if (!group)
3085 			continue;
3086 		if (!addressbook_match_item(ADDRITEM_NAME(group),
3087 					    NULL, NULL, NULL, search_str))
3088 			continue;
3089 
3090 		gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
3091 		gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
3092 				   COL_NAME, ADDRITEM_NAME(group),
3093 				   COL_ADDRESS, "",
3094 				   COL_NICKNAME, "",
3095 				   COL_REMARKS, "",
3096 				   COL_L_OBJ, group,
3097 				   COL_L_PIXBUF, atci->icon_pixbuf,
3098 				   -1);
3099 	}
3100 
3101 	/* Free up the list */
3102 	mgu_clear_list(items);
3103 	g_list_free(items);
3104 }
3105 
addressbook_find_datasource(GtkTreeIter * iter)3106 static AddressDataSource *addressbook_find_datasource(GtkTreeIter *iter)
3107 {
3108 	GtkTreeModel *model;
3109 	GtkTreeIter iter_, parent;
3110 	AddressDataSource *ds = NULL;
3111 	AddressObject *ao;
3112 
3113 	g_return_val_if_fail(addrbook.treeview != NULL, NULL);
3114 
3115 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
3116 	parent = *iter;
3117 
3118 	do {
3119 		iter_ = parent;
3120 		if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter_) < 1)
3121 			return NULL;
3122 		ao = NULL;
3123 		gtk_tree_model_get(model, &iter_, COL_OBJ, &ao, -1);
3124 		if (ao) {
3125 			/* g_print("ao->type = %d\n", ao->type); */
3126 			if (ao->type == ADDR_DATASOURCE) {
3127 				AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3128 				/* g_print("found it\n"); */
3129 				ds = ads->dataSource;
3130 				break;
3131 			}
3132 		}
3133 	} while (gtk_tree_model_iter_parent(model, &parent, &iter_));
3134 
3135 	return ds;
3136 }
3137 
3138 /*
3139 * Load address list widget with children of specified object.
3140 * Enter: obj	Parent object to be loaded.
3141 */
addressbook_set_list(AddressObject * obj)3142 static void addressbook_set_list(AddressObject *obj)
3143 {
3144 	GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview);
3145 	GtkTreeModel *model;
3146 	AddressDataSource *ds = NULL;
3147 	AdapterDSource *ads = NULL;
3148 	gboolean sorted;
3149 	gint address_list_sort_id = COL_NAME;
3150 	GtkSortType order = GTK_SORT_ASCENDING;
3151 
3152 	debug_print("addressbook_set_list\n");
3153 
3154 	model = gtk_tree_view_get_model(listview);
3155 
3156 	if (obj == NULL) {
3157 		gtk_tree_store_clear(GTK_TREE_STORE(model));
3158 		return;
3159 	}
3160 
3161 	if (obj->type == ADDR_INTERFACE) {
3162 		return;
3163 	}
3164 
3165 	gtk_tree_store_clear(GTK_TREE_STORE(model));
3166 	sorted = gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(model),
3167 						      &address_list_sort_id,
3168 						      &order);
3169 	if (!sorted) {
3170 		address_list_sort_id = COL_NAME;
3171 		order = GTK_SORT_ASCENDING;
3172 	}
3173 	gtkut_tree_sortable_unset_sort_column_id(GTK_TREE_SORTABLE(model));
3174 
3175 	if (obj->type == ADDR_DATASOURCE) {
3176 		ads = ADAPTER_DSOURCE(obj);
3177 		ds = ADAPTER_DSOURCE(obj)->dataSource;
3178 		if (ds) {
3179 			/* Load root folder */
3180 			ItemFolder *rootFolder = NULL;
3181 			rootFolder = addrindex_ds_get_root_folder(ds);
3182 			addressbook_folder_load_person(addrindex_ds_get_root_folder(ds));
3183 			addressbook_folder_load_group(addrindex_ds_get_root_folder(ds));
3184 		}
3185 	} else if (obj->type == ADDR_ITEM_GROUP) {
3186 		/* Load groups */
3187 		ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3188 		addressbook_load_group(itemGroup);
3189 	} else if (obj->type == ADDR_ITEM_FOLDER) {
3190 		/* Load folders */
3191 		ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3192 		addressbook_folder_load_person(itemFolder);
3193 		addressbook_folder_load_group(itemFolder);
3194 	}
3195 
3196 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
3197 					     address_list_sort_id, order);
3198 }
3199 
3200 /*
3201 * Free adaptor for specified node.
3202 */
addressbook_free_adapter(GtkTreeIter * iter)3203 static void addressbook_free_adapter(GtkTreeIter *iter)
3204 {
3205 	GtkTreeModel *model;
3206 	AddressObject *ao = NULL;
3207 
3208 	g_return_if_fail(addrbook.treeview != NULL);
3209 	g_return_if_fail(iter != NULL);
3210 
3211 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
3212 	if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), iter) < 1)
3213 		return;
3214 	gtk_tree_model_get(model, iter, COL_OBJ, &ao, -1);
3215 	if (ao == NULL)
3216 		return;
3217 
3218 	if (ao->type == ADDR_INTERFACE) {
3219 		AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3220 		addrbookctl_free_interface(ai);
3221 	} else if (ao->type == ADDR_DATASOURCE) {
3222 		AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3223 		addrbookctl_free_datasource(ads);
3224 	} else if (ao->type == ADDR_ITEM_FOLDER) {
3225 		AdapterFolder *af = ADAPTER_FOLDER(ao);
3226 		addrbookctl_free_folder(af);
3227 	} else if (ao->type == ADDR_ITEM_GROUP) {
3228 		AdapterGroup *ag = ADAPTER_GROUP(ao);
3229 		addrbookctl_free_group(ag);
3230 	}
3231 
3232 	gtk_tree_store_set(GTK_TREE_STORE(model), iter, COL_OBJ, NULL, -1);
3233 }
3234 
3235 /*
3236 * Free all children adapters.
3237 */
addressbook_free_child_adapters(GtkTreeIter * iter)3238 static void addressbook_free_child_adapters(GtkTreeIter *iter)
3239 {
3240 	GtkTreeModel *model;
3241 	GtkTreeIter child;
3242 	gboolean valid;
3243 
3244 	g_return_if_fail(iter != NULL);
3245 
3246 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
3247 	valid = gtk_tree_model_iter_children(model, &child, iter);
3248 	while (valid) {
3249 		addressbook_free_child_adapters(&child);
3250 		addressbook_free_adapter(&child);
3251 		valid = gtk_tree_model_iter_next(model, &child);
3252 	}
3253 }
3254 
addressbook_create_ds_adapter(AddressDataSource * ds,AddressObjectType otype,gchar * name)3255 AdapterDSource *addressbook_create_ds_adapter(AddressDataSource *ds,
3256 					      AddressObjectType otype,
3257 					      gchar *name)
3258 {
3259 	AdapterDSource *adapter = g_new0(AdapterDSource, 1);
3260 	ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3261 	ADDRESS_OBJECT_NAME(adapter) = g_strdup(name);
3262 	adapter->dataSource = ds;
3263 	adapter->subType = otype;
3264 	return adapter;
3265 }
3266 
addressbook_ads_set_name(AdapterDSource * adapter,gchar * value)3267 void addressbook_ads_set_name(AdapterDSource *adapter, gchar *value)
3268 {
3269 	ADDRESS_OBJECT_NAME(adapter) =
3270 		mgu_replace_string(ADDRESS_OBJECT_NAME(adapter), value);
3271 }
3272 
3273 /*
3274  * Load tree from address index with the initial data.
3275  */
addressbook_load_tree(void)3276 static void addressbook_load_tree(void)
3277 {
3278 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
3279 	GtkTreeModel *model;
3280 	GtkTreeIter iter, new_iter;
3281 	GtkTreePath *path;
3282 	GList *nodeIf, *nodeDS;
3283 	AdapterInterface *adapter;
3284 	AddressInterface *iface;
3285 	AddressTypeControlItem *atci;
3286 	AddressDataSource *ds;
3287 	AdapterDSource *ads;
3288 	gchar *name;
3289 
3290 	model = gtk_tree_view_get_model(treeview);
3291 
3292 	nodeIf = _addressInterfaceList_;
3293 	while (nodeIf) {
3294 		adapter = nodeIf->data;
3295 		gtkut_tree_row_reference_get_iter(model, adapter->tree_row, &iter);
3296 		iface = adapter->iface;
3297 		atci = adapter->atci;
3298 		if (iface) {
3299 			if (iface->useInterface) {
3300 				/* Load data sources below interface node */
3301 				nodeDS = iface->listSource;
3302 				while (nodeDS) {
3303 					ds = nodeDS->data;
3304 					name = addrindex_ds_get_name(ds);
3305 					ads = addressbook_create_ds_adapter(ds, atci->objectType, name);
3306 					addressbook_add_object(&iter, &new_iter, ADDRESS_OBJECT(ads));
3307 					nodeDS = g_list_next( nodeDS );
3308 				}
3309 				path = gtk_tree_model_get_path(model, &iter);
3310 				gtk_tree_view_expand_row(treeview, path, TRUE);
3311 				gtk_tree_path_free(path);
3312 			}
3313 		}
3314 		nodeIf = g_list_next(nodeIf);
3315 	}
3316 }
3317 
3318 /*
3319  * Convert the old address book to new format.
3320  */
addressbook_convert(AddressIndex * addrIndex)3321 static gboolean addressbook_convert(AddressIndex *addrIndex)
3322 {
3323 	gboolean retVal = FALSE;
3324 	gboolean errFlag = TRUE;
3325 	gchar *msg = NULL;
3326 
3327 	/* Read old address book, performing conversion */
3328 	debug_print( "Reading and converting old address book...\n" );
3329 	addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3330 	addrindex_read_data( addrIndex );
3331 	if( addrIndex->retVal == MGU_NO_FILE ) {
3332 		/* We do not have a file - new user */
3333 		debug_print( "New user... create new books...\n" );
3334 		addrindex_create_new_books( addrIndex );
3335 		if( addrIndex->retVal == MGU_SUCCESS ) {
3336 			/* Save index file */
3337 			addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3338 			addrindex_save_data( addrIndex );
3339 			if( addrIndex->retVal == MGU_SUCCESS ) {
3340 				retVal = TRUE;
3341 				errFlag = FALSE;
3342 			}
3343 			else {
3344 				msg = _( "New user, could not save index file." );
3345 			}
3346 		}
3347 		else {
3348 			msg = _( "New user, could not save address book files." );
3349 		}
3350 	}
3351 	else {
3352 		/* We have an old file */
3353 		if( addrIndex->wasConverted ) {
3354 			/* Converted successfully - save address index */
3355 			addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3356 			addrindex_save_data( addrIndex );
3357 			if( addrIndex->retVal == MGU_SUCCESS ) {
3358 				msg = _( "Old address book converted successfully." );
3359 				retVal = TRUE;
3360 				errFlag = FALSE;
3361 			}
3362 			else {
3363 				msg = _("Old address book converted,\n"
3364 					"could not save new address index file" );
3365 			}
3366 		}
3367 		else {
3368 			/* File conversion failed - just create new books */
3369 			debug_print( "File conversion failed... just create new books...\n" );
3370 			addrindex_create_new_books( addrIndex );
3371 			if( addrIndex->retVal == MGU_SUCCESS ) {
3372 				/* Save index */
3373 				addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3374 				addrindex_save_data( addrIndex );
3375 				if( addrIndex->retVal == MGU_SUCCESS ) {
3376 					msg = _("Could not convert address book,\n"
3377 						"but created empty new address book files." );
3378 					retVal = TRUE;
3379 					errFlag = FALSE;
3380 				}
3381 				else {
3382 					msg = _("Could not convert address book,\n"
3383 						"could not create new address book files." );
3384 				}
3385 			}
3386 			else {
3387 				msg = _("Could not convert address book\n"
3388 					"and could not create new address book files." );
3389 			}
3390 		}
3391 	}
3392 	if( errFlag ) {
3393 		debug_print( "Error\n%s\n", msg );
3394 		alertpanel( _( "Address book conversion error" ), msg, GTK_STOCK_CLOSE, NULL, NULL );
3395 	}
3396 	else if( msg ) {
3397 		debug_print( "Warning\n%s\n", msg );
3398 		alertpanel( _( "Address book conversion" ), msg, GTK_STOCK_CLOSE, NULL, NULL );
3399 	}
3400 
3401 	return retVal;
3402 }
3403 
addressbook_read_file(void)3404 void addressbook_read_file(void)
3405 {
3406 	AddressIndex *addrIndex = NULL;
3407 
3408 	debug_print( "Reading address index...\n" );
3409 	if (_addressIndex_) {
3410 		debug_print("address book already read!\n");
3411 		return;
3412 	}
3413 
3414 	addrIndex = addrindex_create_index();
3415 
3416 	/* Use new address book index. */
3417 	addrindex_set_file_path(addrIndex, get_rc_dir());
3418 	addrindex_set_file_name(addrIndex, ADDRESSBOOK_INDEX_FILE);
3419 	addrindex_read_data(addrIndex);
3420 	if (addrIndex->retVal == MGU_NO_FILE) {
3421 		/* Conversion required */
3422 		debug_print("Converting...\n");
3423 		if (addressbook_convert(addrIndex)) {
3424 			addrindex_create_extra_books(addrIndex);
3425 			_addressIndex_ = addrIndex;
3426 		}
3427 	} else if (addrIndex->retVal == MGU_SUCCESS) {
3428 		addrindex_create_extra_books(addrIndex);
3429 		_addressIndex_ = addrIndex;
3430 	} else {
3431 		gchar msg[1024];
3432 
3433 		/* Error reading address book */
3434 		debug_print("Could not read address index.\n");
3435 		addrindex_print_index(addrIndex, stdout);
3436 		g_snprintf(msg, sizeof(msg),
3437 			   _("Could not read address index:\n\n%s%c%s"),
3438 			   addrIndex->filePath, G_DIR_SEPARATOR,
3439 			   addrIndex->fileName);
3440 		alertpanel_message(_("Address Book Error"), msg, ALERT_ERROR);
3441 	}
3442 	debug_print( "done.\n" );
3443 }
3444 
3445 #if 0
3446 void addressbook_read_file_old( void ) {
3447 	AddressIndex *addrIndex = NULL;
3448 	gboolean errFlag = TRUE;
3449 	gchar *msg = NULL;
3450 
3451 	if( _addressIndex_ ) {
3452 		debug_print( "address book already read!!!\n" );
3453 		return;
3454 	}
3455 
3456 	addrIndex = addrindex_create_index();
3457 
3458 	/* Use use new address book. */
3459 	/* addrindex_set_file_path( addrIndex, "/home/match/tmp/empty-dir" ); */
3460 	addrindex_set_file_path( addrIndex, get_rc_dir() );
3461 	addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3462 
3463 	debug_print( "Reading address index...\n" );
3464 	addrindex_read_data( addrIndex );
3465 	if( addrIndex->retVal == MGU_NO_FILE ) {
3466 		/* Read old address book, performing conversion */
3467 		debug_print( "Reading and converting old address book...\n" );
3468 		addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3469 		addrindex_read_data( addrIndex );
3470 		if( addrIndex->retVal == MGU_NO_FILE ) {
3471 			/* We do not have a file - new user */
3472 			debug_print( "New user... create new books...\n" );
3473 			addrindex_create_new_books( addrIndex );
3474 			if( addrIndex->retVal == MGU_SUCCESS ) {
3475 				/* Save index file */
3476 				addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3477 				addrindex_save_data( addrIndex );
3478 				if( addrIndex->retVal == MGU_SUCCESS ) {
3479 					errFlag = FALSE;
3480 				}
3481 				else {
3482 					msg = g_strdup( _( "New user, could not save index file." ) );
3483 				}
3484 			}
3485 			else {
3486 				msg = g_strdup( _( "New user, could not save address book files." ) );
3487 			}
3488 		}
3489 		else {
3490 			/* We have an old file */
3491 			if( addrIndex->wasConverted ) {
3492 				/* Converted successfully - save address index */
3493 				addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3494 				addrindex_save_data( addrIndex );
3495 				if( addrIndex->retVal == MGU_SUCCESS ) {
3496 					msg = g_strdup( _( "Old address book converted successfully." ) );
3497 					errFlag = FALSE;
3498 				}
3499 				else {
3500 					msg = g_strdup( _(
3501 						"Old address book converted, " \
3502 						"could not save new address index file" ) );
3503 				}
3504 			}
3505 			else {
3506 				/* File conversion failed - just create new books */
3507 				debug_print( "File conversion failed... just create new books...\n" );
3508 				addrindex_create_new_books( addrIndex );
3509 				if( addrIndex->retVal == MGU_SUCCESS ) {
3510 					/* Save index */
3511 					addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3512 					addrindex_save_data( addrIndex );
3513 					if( addrIndex->retVal == MGU_SUCCESS ) {
3514 						msg = g_strdup( _(
3515 							"Could not convert address book, " \
3516 							"but created empty new address book files." ) );
3517 						errFlag = FALSE;
3518 					}
3519 					else {
3520 						msg = g_strdup( _(
3521 							"Could not convert address book, " \
3522 							"could not create new address book files." ) );
3523 					}
3524 				}
3525 				else {
3526 					msg = g_strdup( _(
3527 						"Could not convert address book " \
3528 						"and could not create new address book files." ) );
3529 				}
3530 			}
3531 		}
3532 	}
3533 	else if( addrIndex->retVal == MGU_SUCCESS ) {
3534 		errFlag = FALSE;
3535 	}
3536 	else {
3537 		debug_print( "Could not read address index.\n" );
3538 		addrindex_print_index( addrIndex, stdout );
3539 		msg = g_strdup( _( "Could not read address index" ) );
3540 	}
3541 	_addressIndex_ = addrIndex;
3542 
3543 	if( errFlag ) {
3544 		debug_print( "Error\n%s\n", msg );
3545 		alertpanel( _( "Address Book Conversion Error" ), msg,
3546 			    GTK_STOCK_CLOSE, NULL, NULL );
3547 	}
3548 	else {
3549 		if( msg ) {
3550 			debug_print( "Warning\n%s\n", msg );
3551 			alertpanel( _( "Address Book Conversion" ), msg,
3552 				    GTK_STOCK_CLOSE, NULL, NULL );
3553 		}
3554 	}
3555 	if( msg ) g_free( msg );
3556 	debug_print( "done.\n" );
3557 }
3558 #endif
3559 
3560 /*
3561 * Add object into the address index tree widget.
3562 * Enter: node	Parent node.
3563 *        obj	Object to add.
3564 * Return: Node that was added, or NULL if object not added.
3565 */
addressbook_add_object(GtkTreeIter * iter,GtkTreeIter * new_iter,AddressObject * obj)3566 static gboolean addressbook_add_object(GtkTreeIter *iter, GtkTreeIter *new_iter,
3567 				       AddressObject *obj)
3568 {
3569 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
3570 	GtkTreeModel *model;
3571 	GtkTreeIter added;
3572 	AddressObject *pobj;
3573 	AddressObjectType otype;
3574 	AddressTypeControlItem *atci = NULL;
3575 	const gchar *name;
3576 
3577 	g_return_val_if_fail(iter != NULL, FALSE);
3578 	g_return_val_if_fail(obj  != NULL, FALSE);
3579 
3580 	model = gtk_tree_view_get_model(treeview);
3581 	gtk_tree_model_get(model, iter, COL_OBJ, &pobj, -1);
3582 	g_return_val_if_fail(pobj != NULL, FALSE);
3583 
3584 	/* Determine object type to be displayed */
3585 	if (obj->type == ADDR_DATASOURCE) {
3586 		otype = ADAPTER_DSOURCE(obj)->subType;
3587 	} else {
3588 		otype = obj->type;
3589 	}
3590 
3591 	/* Handle any special conditions. */
3592 	atci = addrbookctl_lookup(otype);
3593 	if (atci && atci->showInTree) {
3594 		/* Add object to tree */
3595 		debug_print("addressbook_add_object: obj: %s\n", obj->name);
3596 		if (otype == ADDR_BOOK && obj->name &&
3597 		    !strcmp(obj->name, ADDR_DS_AUTOREG))
3598 			name = _("Auto-registered address");
3599 		else
3600 			name = obj->name;
3601 		gtk_tree_store_append(GTK_TREE_STORE(model), &added, iter);
3602 		gtk_tree_store_set(GTK_TREE_STORE(model), &added,
3603 				   COL_FOLDER_NAME, name,
3604 				   COL_OBJ, obj,
3605 				   COL_PIXBUF, atci->icon_pixbuf,
3606 				   COL_PIXBUF_OPEN, atci->icon_open_pixbuf,
3607 				   -1);
3608 		if (new_iter)
3609 			*new_iter = added;
3610 		return TRUE;
3611 	}
3612 
3613 	return FALSE;
3614 }
3615 
3616 /*
3617 * Add group into the address index tree.
3618 * Enter: node	   Parent node.
3619 *        ds        Data source.
3620 *        itemGroup Group to add.
3621 * Return: Inserted node.
3622 */
addressbook_node_add_group(GtkTreeIter * iter,AddressDataSource * ds,ItemGroup * itemGroup,GtkTreeIter * new_iter)3623 static gboolean addressbook_node_add_group(GtkTreeIter *iter, AddressDataSource *ds, ItemGroup *itemGroup, GtkTreeIter *new_iter)
3624 {
3625 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
3626 	GtkTreeStore *store;
3627 	GtkTreeIter new_iter_;
3628 	AdapterGroup *adapter;
3629 	AddressTypeControlItem *atci = NULL;
3630 	gchar *name;
3631 
3632 	if(ds == NULL) return FALSE;
3633 	if(iter == NULL || itemGroup == NULL) return FALSE;
3634 
3635 	name = itemGroup->obj.name;
3636 
3637 	atci = addrbookctl_lookup(ADDR_ITEM_GROUP);
3638 
3639 	adapter = g_new0(AdapterGroup, 1);
3640 	ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
3641 	ADDRESS_OBJECT_NAME(adapter) = g_strdup(ADDRITEM_NAME(itemGroup));
3642 	adapter->itemGroup = itemGroup;
3643 
3644 	debug_print("addressbook_node_add_group: name: %s\n", name);
3645 	store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
3646 	gtk_tree_store_append(store, &new_iter_, iter);
3647 	gtk_tree_store_set(store, &new_iter_,
3648 			   COL_FOLDER_NAME, name,
3649 			   COL_OBJ, adapter,
3650 			   COL_PIXBUF, atci->icon_pixbuf,
3651 			   COL_PIXBUF_OPEN, atci->icon_open_pixbuf,
3652 			   -1);
3653 	if (new_iter)
3654 		*new_iter = new_iter_;
3655 	return TRUE;
3656 }
3657 
3658 /*
3659 * Add folder into the address index tree.
3660 * Enter: iter	    Parent node.
3661 *        ds         Data source.
3662 *        itemFolder Folder to add.
3663 *        otype      Object type to display.
3664 *        new_iter   Inserted node.
3665 * Return: TRUE if inserted.
3666 */
addressbook_node_add_folder(GtkTreeIter * iter,AddressDataSource * ds,ItemFolder * itemFolder,AddressObjectType otype,GtkTreeIter * new_iter)3667 static gboolean addressbook_node_add_folder(GtkTreeIter *iter, AddressDataSource *ds, ItemFolder *itemFolder, AddressObjectType otype, GtkTreeIter *new_iter)
3668 {
3669 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
3670 	GtkTreeStore *store;
3671 	GtkTreeIter new_iter_;
3672 	AdapterFolder *adapter;
3673 	AddressTypeControlItem *atci = NULL;
3674 	GList *listItems = NULL;
3675 	gchar *name;
3676 	ItemFolder *rootFolder;
3677 
3678 	if (ds == NULL)
3679 		return FALSE;
3680 	if (iter == NULL || itemFolder == NULL)
3681 		return FALSE;
3682 
3683 	/* Determine object type */
3684 	atci = addrbookctl_lookup(otype);
3685 	if (atci == NULL)
3686 		return FALSE;
3687 
3688 	store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
3689 
3690 	rootFolder = addrindex_ds_get_root_folder(ds);
3691 	if (itemFolder == rootFolder) {
3692 		new_iter_ = *iter;
3693 	} else {
3694 		name = itemFolder->obj.name;
3695 
3696 		adapter = g_new0(AdapterFolder, 1);
3697 		ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
3698 		ADDRESS_OBJECT_NAME(adapter) = g_strdup(ADDRITEM_NAME(itemFolder));
3699 		adapter->itemFolder = itemFolder;
3700 
3701 		debug_print("addressbook_node_add_folder: name: %s\n", name);
3702 		gtk_tree_store_append(store, &new_iter_, iter);
3703 		gtk_tree_store_set(store, &new_iter_,
3704 				   COL_FOLDER_NAME, name,
3705 				   COL_OBJ, adapter,
3706 				   COL_PIXBUF, atci->icon_pixbuf,
3707 				   COL_PIXBUF_OPEN, atci->icon_open_pixbuf,
3708 				   -1);
3709 	}
3710 
3711 	listItems = itemFolder->listFolder;
3712 	while (listItems) {
3713 		ItemFolder *item = listItems->data;
3714 		addressbook_node_add_folder(&new_iter_, ds, item, otype, NULL);
3715 		listItems = g_list_next(listItems);
3716 	}
3717 	listItems = itemFolder->listGroup;
3718 	while (listItems) {
3719 		ItemGroup *item = listItems->data;
3720 		addressbook_node_add_group(&new_iter_, ds, item, NULL);
3721 		listItems = g_list_next(listItems);
3722 	}
3723 	if (new_iter)
3724 		*new_iter = new_iter_;
3725 	return TRUE;
3726 }
3727 
3728 #if 0
3729 static void addressbook_delete_object(AddressObject *obj) {
3730 	AdapterDSource *ads = NULL;
3731 	AddressDataSource *ds = NULL;
3732 	if (!obj) return;
3733 
3734 	/* Remove data source. */
3735 	/* printf( "Delete obj type : %d\n", obj->type ); */
3736 
3737 	ads = ADAPTER_DSOURCE(obj);
3738 	if( ads == NULL ) return;
3739 	ds = ads->dataSource;
3740 	if( ds == NULL ) return;
3741 
3742 	/* Remove data source */
3743 	if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3744 		addrindex_free_datasource( _addressIndex_, ds );
3745 	}
3746 	/* Free up Adapter object */
3747 	g_free( ADAPTER_DSOURCE(obj) );
3748 }
3749 #endif
3750 
addressbook_export_to_file(void)3751 void addressbook_export_to_file( void ) {
3752 	if( _addressIndex_ ) {
3753 		/* Save all new address book data */
3754 		debug_print( "Saving address books...\n" );
3755 		addrindex_save_all_books( _addressIndex_ );
3756 
3757 		debug_print( "Exporting addressbook to file...\n" );
3758 		addrindex_save_data( _addressIndex_ );
3759 		if( _addressIndex_->retVal != MGU_SUCCESS ) {
3760 			addrindex_print_index( _addressIndex_, stdout );
3761 		}
3762 
3763 		/* Notify address completion of new data */
3764 		addressbook_modified();
3765 	}
3766 }
3767 
key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer data)3768 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
3769 			    gpointer data)
3770 {
3771 	if (event && event->keyval == GDK_Escape)
3772 		addressbook_close();
3773 	return FALSE;
3774 }
3775 
size_allocated(GtkWidget * widget,GtkAllocation * allocation,gpointer data)3776 static void size_allocated(GtkWidget *widget, GtkAllocation *allocation,
3777 			   gpointer data)
3778 {
3779 	if (allocation->width <= 1 || allocation->height <= 1)
3780 		return;
3781 
3782 	prefs_common.addressbook_width = allocation->width;
3783 	prefs_common.addressbook_height = allocation->height;
3784 }
3785 
3786 /*
3787 * Comparison using cell contents (text in first column).
3788 */
addressbook_tree_compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)3789 static gint addressbook_tree_compare(GtkTreeModel *model, GtkTreeIter *a,
3790 				     GtkTreeIter *b, gpointer data)
3791 {
3792 	gchar *name1 = NULL, *name2 = NULL;
3793 	AddressObject *obj1 = NULL, *obj2 = NULL;
3794 	gint ret;
3795 
3796 	gtk_tree_model_get(model, a, COL_FOLDER_NAME, &name1, COL_OBJ, &obj1,
3797 			   -1);
3798 	gtk_tree_model_get(model, b, COL_FOLDER_NAME, &name2, COL_OBJ, &obj2,
3799 			   -1);
3800 
3801 	/* Do not sort toplevel row */
3802 	if (obj1 && obj1->type == ADDR_INTERFACE)
3803 		return 0;
3804 
3805 	if (!name1 || !name2) {
3806 		if (!name1)
3807 			ret = (name2 != NULL);
3808 		else
3809 			ret = -1;
3810 		g_free(name2);
3811 		g_free(name1);
3812 		return ret;
3813 	}
3814 	ret = g_ascii_strcasecmp(name1, name2);
3815 	g_free(name2);
3816 	g_free(name1);
3817 	return ret;
3818 }
3819 
addressbook_list_col_compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gint col)3820 static gint addressbook_list_col_compare(GtkTreeModel *model, GtkTreeIter *a,
3821 					 GtkTreeIter *b, gint col)
3822 {
3823 	gchar *name1 = NULL, *name2 = NULL;
3824 	gint ret;
3825 
3826 	gtk_tree_model_get(model, a, col, &name1, -1);
3827 	gtk_tree_model_get(model, b, col, &name2, -1);
3828 
3829 	if (!name1)
3830 		name1 = g_strdup("");
3831 	if (!name2)
3832 		name2 = g_strdup("");
3833 	ret = g_ascii_strcasecmp(name1, name2);
3834 	g_free(name2);
3835 	g_free(name1);
3836 	return ret;
3837 }
3838 
addressbook_list_name_compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)3839 static gint addressbook_list_name_compare(GtkTreeModel *model, GtkTreeIter *a,
3840 					  GtkTreeIter *b, gpointer data)
3841 {
3842 	gint ret;
3843 
3844 	ret = addressbook_list_col_compare(model, a, b, COL_NAME);
3845 	if (ret == 0)
3846 		ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME);
3847 	if (ret == 0)
3848 		ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS);
3849 	if (ret == 0)
3850 		ret = addressbook_list_col_compare(model, a, b, COL_REMARKS);
3851 
3852 	return ret;
3853 }
3854 
addressbook_list_address_compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)3855 static gint addressbook_list_address_compare(GtkTreeModel *model,
3856 					     GtkTreeIter *a, GtkTreeIter *b,
3857 					     gpointer data)
3858 {
3859 	gint ret;
3860 
3861 	ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS);
3862 	if (ret == 0)
3863 		ret = addressbook_list_col_compare(model, a, b, COL_NAME);
3864 	if (ret == 0)
3865 		ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME);
3866 	if (ret == 0)
3867 		ret = addressbook_list_col_compare(model, a, b, COL_REMARKS);
3868 
3869 	return ret;
3870 }
3871 
addressbook_list_nickname_compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)3872 static gint addressbook_list_nickname_compare(GtkTreeModel *model,
3873 					      GtkTreeIter *a, GtkTreeIter *b,
3874 					      gpointer data)
3875 {
3876 	gint ret;
3877 
3878 	ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME);
3879 	if (ret == 0)
3880 		ret = addressbook_list_col_compare(model, a, b, COL_NAME);
3881 	if (ret == 0)
3882 		ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS);
3883 	if (ret == 0)
3884 		ret = addressbook_list_col_compare(model, a, b, COL_REMARKS);
3885 
3886 	return ret;
3887 }
3888 
addressbook_list_remarks_compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)3889 static gint addressbook_list_remarks_compare(GtkTreeModel *model,
3890 					     GtkTreeIter *a, GtkTreeIter *b,
3891 					     gpointer data)
3892 {
3893 	gint ret;
3894 
3895 	ret = addressbook_list_col_compare(model, a, b, COL_REMARKS);
3896 	if (ret == 0)
3897 		ret = addressbook_list_col_compare(model, a, b, COL_NAME);
3898 	if (ret == 0)
3899 		ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME);
3900 	if (ret == 0)
3901 		ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS);
3902 
3903 	return ret;
3904 }
3905 
addressbook_list_select_func(GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean cur_selected,gpointer data)3906 static gboolean addressbook_list_select_func(GtkTreeSelection *selection,
3907 					     GtkTreeModel *model,
3908 					     GtkTreePath *path,
3909 					     gboolean cur_selected,
3910 					     gpointer data)
3911 {
3912 	return can_toggle_list_selection;
3913 }
3914 
3915 /* static */
addressbook_obj_name_compare(gconstpointer a,gconstpointer b)3916 gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b)
3917 {
3918 	const AddressObject *obj = a;
3919 	const gchar *name = b;
3920 	AddressTypeControlItem *atci = NULL;
3921 
3922 	if (!obj || !name) return -1;
3923 
3924 	atci = addrbookctl_lookup( obj->type );
3925 	if( ! atci ) return -1;
3926 	if( ! obj->name ) return -1;
3927 	return g_ascii_strcasecmp(obj->name, name);
3928 }
3929 
3930 #if 0
3931 static void addressbook_book_show_message( AddressBookFile *abf ) {
3932 	gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = "";
3933 
3934 	if (abf) {
3935 		if (abf->retVal == MGU_SUCCESS) {
3936 			g_snprintf(msgbuf, sizeof(msgbuf), "%s", abf->name);
3937 		} else {
3938 			g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", abf->name, mgu_error2string(abf->retVal));
3939 		}
3940 	}
3941 	addressbook_status_show(msgbuf);
3942 }
3943 #endif
3944 
addressbook_new_book_cb(gpointer data,guint action,GtkWidget * widget)3945 static void addressbook_new_book_cb(gpointer data, guint action, GtkWidget *widget)
3946 {
3947 	GtkTreeModel *model;
3948 	GtkTreeIter iter;
3949 	AdapterDSource *ads;
3950 	AdapterInterface *adapter;
3951 
3952 	adapter = addrbookctl_find_interface(ADDR_IF_BOOK);
3953 	if (adapter == NULL)
3954 		return;
3955 	if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row))
3956 		return;
3957 
3958 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
3959 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter);
3960 
3961 	ads = addressbook_edit_book(_addressIndex_, NULL);
3962 	if (ads) {
3963 		addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads));
3964 		if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) {
3965 			addressbook_reopen();
3966 		}
3967 	}
3968 }
3969 
addressbook_new_vcard_cb(gpointer data,guint action,GtkWidget * widget)3970 static void addressbook_new_vcard_cb(gpointer data, guint action, GtkWidget *widget)
3971 {
3972 	GtkTreeModel *model;
3973 	GtkTreeIter iter;
3974 	AdapterDSource *ads;
3975 	AdapterInterface *adapter;
3976 
3977 	adapter = addrbookctl_find_interface(ADDR_IF_VCARD);
3978 	if (adapter == NULL)
3979 		return;
3980 	if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row))
3981 		return;
3982 
3983 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
3984 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter);
3985 
3986 	ads = addressbook_edit_vcard(_addressIndex_, NULL);
3987 	if (ads) {
3988 		addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads));
3989 		if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) {
3990 			addressbook_reopen();
3991 		}
3992 		addressbook_modified();
3993 	}
3994 }
3995 
3996 #if 0
3997 static void addressbook_vcard_show_message( VCardFile *vcf ) {
3998 	gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = "";
3999 
4000 	if (vcf) {
4001 		if (vcf->retVal == MGU_SUCCESS) {
4002 			g_snprintf(msgbuf, sizeof(msgbuf), "%s", vcf->name);
4003 		} else {
4004 			g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", vcf->name, mgu_error2string(vcf->retVal));
4005 		}
4006 	}
4007 	addressbook_status_show(msgbuf);
4008 }
4009 #endif
4010 
4011 #ifdef USE_JPILOT
addressbook_new_jpilot_cb(gpointer data,guint action,GtkWidget * widget)4012 static void addressbook_new_jpilot_cb(gpointer data, guint action, GtkWidget *widget)
4013 {
4014 	GtkTreeModel *model;
4015 	GtkTreeIter iter;
4016 	AdapterDSource *ads;
4017 	AdapterInterface *adapter;
4018 	AddressInterface *iface;
4019 
4020 	adapter = addrbookctl_find_interface(ADDR_IF_JPILOT);
4021 	if (adapter == NULL)
4022 		return;
4023 	if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row))
4024 		return;
4025 	iface = adapter->iface;
4026 	if (!iface->haveLibrary)
4027 		return;
4028 
4029 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
4030 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter);
4031 
4032 	ads = addressbook_edit_jpilot(_addressIndex_, NULL);
4033 	if (ads) {
4034 		addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads));
4035 		if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) {
4036 			addressbook_reopen();
4037 		}
4038 	}
4039 }
4040 
4041 #if 0
4042 static void addressbook_jpilot_show_message( JPilotFile *jpf ) {
4043 	gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = "";
4044 
4045 	if (jpf) {
4046 		if (jpf->retVal == MGU_SUCCESS) {
4047 			g_snprintf(msgbuf, sizeof(msgbuf), "%s", jpf->name);
4048 		} else {
4049 			g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", jpf->name, mgu_error2string(jpf->retVal));
4050 		}
4051 	}
4052 	addressbook_status_show(msgbuf);
4053 }
4054 #endif
4055 #endif /* USE_JPILOT */
4056 
4057 #ifdef USE_LDAP
addressbook_new_ldap_cb(gpointer data,guint action,GtkWidget * widget)4058 static void addressbook_new_ldap_cb(gpointer data, guint action, GtkWidget *widget)
4059 {
4060 	GtkTreeModel *model;
4061 	GtkTreeIter iter;
4062 	AdapterDSource *ads;
4063 	AdapterInterface *adapter;
4064 	AddressInterface *iface;
4065 
4066 	adapter = addrbookctl_find_interface(ADDR_IF_LDAP);
4067 	if (adapter == NULL)
4068 		return;
4069 	if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row))
4070 		return;
4071 	iface = adapter->iface;
4072 	if (!iface->haveLibrary)
4073 		return;
4074 
4075 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview));
4076 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter);
4077 
4078 	ads = addressbook_edit_ldap(_addressIndex_, NULL);
4079 	if( ads ) {
4080 		addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads));
4081 		if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) {
4082 			addressbook_reopen();
4083 		}
4084 	}
4085 }
4086 
addressbook_ldap_show_message(SyldapServer * svr)4087 static void addressbook_ldap_show_message(SyldapServer *svr)
4088 {
4089 	gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = "";
4090 
4091 	if (svr) {
4092 		if (svr->busyFlag) {
4093 			g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", svr->name, ADDRESSBOOK_LDAP_BUSYMSG);
4094 		} else {
4095 			if (svr->retVal == MGU_SUCCESS) {
4096 				g_snprintf(msgbuf, sizeof(msgbuf), "%s", svr->name);
4097 			} else {
4098 				g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", svr->name, mgu_error2string(svr->retVal));
4099 			}
4100 		}
4101 	}
4102 	addressbook_status_show(msgbuf);
4103 }
4104 
ldapsearch_callback(SyldapServer * sls)4105 static void ldapsearch_callback(SyldapServer *sls)
4106 {
4107 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
4108 	GtkTreeSelection *selection;
4109 	GtkTreeModel *model;
4110 	GtkTreeIter iter;
4111 	AddressObject *obj;
4112 	AdapterDSource *ads = NULL;
4113 	AddressDataSource *ds = NULL;
4114 	AddressInterface *iface = NULL;
4115 
4116 	if (sls == NULL)
4117 		return;
4118 
4119 	selection = gtk_tree_view_get_selection(treeview);
4120 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
4121 		return;
4122 	if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0)
4123 		return;
4124 
4125 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
4126 	if (obj == NULL)
4127 		return;
4128 	if (obj->type == ADDR_DATASOURCE) {
4129 		ads = ADAPTER_DSOURCE(obj);
4130 		if (ads->subType == ADDR_LDAP) {
4131 			SyldapServer *server;
4132 
4133 			ds = ads->dataSource;
4134 			if (ds == NULL)
4135 				return;
4136 			iface = ds->iface;
4137 			if (!iface->haveLibrary)
4138 				return;
4139 			server = ds->rawDataSource;
4140 			if (server == sls) {
4141 				/* Read from cache */
4142 				gtk_widget_show(addrbook.window);
4143 				addressbook_set_list(obj);
4144 				addressbook_ldap_show_message(sls);
4145 				gtk_widget_show(addrbook.window);
4146 				gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
4147 			}
4148 		}
4149 	}
4150 }
4151 #endif
4152 
4153 /*
4154  * Lookup button handler.
4155  */
addressbook_lup_clicked(GtkButton * button,gpointer data)4156 static void addressbook_lup_clicked(GtkButton *button, gpointer data)
4157 {
4158 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
4159 	GtkTreeSelection *selection;
4160 	GtkTreeModel *model;
4161 	GtkTreeIter iter;
4162 	AddressObject *obj;
4163 	AdapterDSource *ads = NULL;
4164 #ifdef USE_LDAP
4165 	AddressDataSource *ds = NULL;
4166 	AddressInterface *iface = NULL;
4167 #endif /* USE_LDAP */
4168 	gchar *sLookup;
4169 
4170 	selection = gtk_tree_view_get_selection(treeview);
4171 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
4172 		return;
4173 	if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0)
4174 		return;
4175 
4176 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
4177 	if (obj == NULL)
4178 		return;
4179 
4180 	sLookup = gtk_editable_get_chars(GTK_EDITABLE(addrbook.entry), 0, -1);
4181 	g_strstrip(sLookup);
4182 
4183 	if (obj->type == ADDR_DATASOURCE) {
4184 		ads = ADAPTER_DSOURCE(obj);
4185 #ifdef USE_LDAP
4186 		if (ads->subType == ADDR_LDAP) {
4187 			SyldapServer *server;
4188 
4189 			ds = ads->dataSource;
4190 			if (ds == NULL)
4191 				return;
4192 			iface = ds->iface;
4193 			if (!iface->haveLibrary)
4194 				return;
4195 			server = ds->rawDataSource;
4196 			if (server) {
4197 				syldap_cancel_read(server);
4198 				if (*sLookup == '\0' || strlen(sLookup) < 1 )
4199 					return;
4200 				syldap_set_search_value(server, sLookup);
4201 				syldap_set_callback(server, ldapsearch_callback);
4202 				syldap_read_data_th(server);
4203 				addressbook_ldap_show_message(server);
4204 			}
4205 		} else
4206 #endif /* USE_LDAP */
4207 			addressbook_set_list(obj);
4208 	} else {
4209 		addressbook_set_list(obj);
4210 	}
4211 
4212 	g_free(sLookup);
4213 }
4214 
addressbook_close_clicked(GtkButton * button,gpointer data)4215 static void addressbook_close_clicked(GtkButton	*button, gpointer data)
4216 {
4217 	addressbook_close();
4218 }
4219 
4220 /* **********************************************************************
4221 * Build lookup tables.
4222 * ***********************************************************************
4223 */
4224 
4225 /*
4226 * Build table that controls the rendering of object types.
4227 */
addrbookctl_build_map(GtkWidget * window)4228 void addrbookctl_build_map(GtkWidget *window)
4229 {
4230 	AddressTypeControlItem *atci;
4231 
4232 	/* Build icons */
4233 	stock_pixbuf_gdk(window, STOCK_PIXMAP_FOLDER_CLOSE, &folderpix);
4234 	stock_pixbuf_gdk(window, STOCK_PIXMAP_FOLDER_OPEN, &folderopenpix);
4235 	stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &grouppix);
4236 	stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardpix);
4237 	stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookpix);
4238 	stock_pixbuf_gdk(window, STOCK_PIXMAP_PERSON, &personpix);
4239 	stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addresspix);
4240 	stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotpix);
4241 	stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categorypix);
4242 	stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldappix);
4243 
4244 	_addressBookTypeHash_ = g_hash_table_new(g_int_hash, g_int_equal);
4245 	_addressBookTypeList_ = NULL;
4246 
4247 	/* Interface */
4248 	atci = g_new0(AddressTypeControlItem, 1);
4249 	atci->objectType = ADDR_INTERFACE;
4250 	atci->interfaceType = ADDR_IF_NONE;
4251 	atci->showInTree = TRUE;
4252 	atci->treeExpand = TRUE;
4253 	atci->treeLeaf = FALSE;
4254 	atci->displayName = _("Interface");
4255 	atci->icon_pixbuf = folderpix;
4256 	atci->icon_open_pixbuf = folderopenpix;
4257 	atci->menuCommand = NULL;
4258 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4259 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4260 
4261 	/* Address book */
4262 	atci = g_new0(AddressTypeControlItem, 1);
4263 	atci->objectType = ADDR_BOOK;
4264 	atci->interfaceType = ADDR_IF_BOOK;
4265 	atci->showInTree = TRUE;
4266 	atci->treeExpand = TRUE;
4267 	atci->treeLeaf = FALSE;
4268 	atci->displayName = _("Address Book");
4269 	atci->icon_pixbuf = bookpix;
4270 	atci->icon_open_pixbuf = bookpix;
4271 	atci->menuCommand = "/File/New Book";
4272 	g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4273 	_addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4274 
4275 	/* Item person */
4276 	atci = g_new0(AddressTypeControlItem, 1);
4277 	atci->objectType = ADDR_ITEM_PERSON;
4278 	atci->interfaceType = ADDR_IF_NONE;
4279 	atci->showInTree = FALSE;
4280 	atci->treeExpand = FALSE;
4281 	atci->treeLeaf = FALSE;
4282 	atci->displayName = _("Person");
4283 	atci->icon_pixbuf = personpix;
4284 	atci->icon_open_pixbuf = personpix;
4285 	atci->menuCommand = NULL;
4286 	g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4287 	_addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4288 
4289 	/* Item email */
4290 	atci = g_new0(AddressTypeControlItem, 1);
4291 	atci->objectType = ADDR_ITEM_EMAIL;
4292 	atci->interfaceType = ADDR_IF_NONE;
4293 	atci->showInTree = FALSE;
4294 	atci->treeExpand = FALSE;
4295 	atci->treeLeaf = TRUE;
4296 	atci->displayName = _("EMail Address");
4297 	atci->icon_pixbuf = addresspix;
4298 	atci->icon_open_pixbuf = addresspix;
4299 	atci->menuCommand = NULL;
4300 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4301 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4302 
4303 	/* Item group */
4304 	atci = g_new0(AddressTypeControlItem, 1);
4305 	atci->objectType = ADDR_ITEM_GROUP;
4306 	atci->interfaceType = ADDR_IF_BOOK;
4307 	atci->showInTree = TRUE;
4308 	atci->treeExpand = FALSE;
4309 	atci->treeLeaf = FALSE;
4310 	atci->displayName = _("Group");
4311 	atci->icon_pixbuf = grouppix;
4312 	atci->icon_open_pixbuf = grouppix;
4313 	atci->menuCommand = NULL;
4314 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4315 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4316 
4317 	/* Item folder */
4318 	atci = g_new0(AddressTypeControlItem, 1);
4319 	atci->objectType = ADDR_ITEM_FOLDER;
4320 	atci->interfaceType = ADDR_IF_BOOK;
4321 	atci->showInTree = TRUE;
4322 	atci->treeExpand = FALSE;
4323 	atci->treeLeaf = FALSE;
4324 	atci->displayName = _("Folder");
4325 	atci->icon_pixbuf = folderpix;
4326 	atci->icon_open_pixbuf = folderopenpix;
4327 	atci->menuCommand = NULL;
4328 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4329 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4330 
4331 	/* vCard */
4332 	atci = g_new0(AddressTypeControlItem, 1);
4333 	atci->objectType = ADDR_VCARD;
4334 	atci->interfaceType = ADDR_IF_VCARD;
4335 	atci->showInTree = TRUE;
4336 	atci->treeExpand = TRUE;
4337 	atci->treeLeaf = TRUE;
4338 	atci->displayName = _("vCard");
4339 	atci->icon_pixbuf = vcardpix;
4340 	atci->icon_open_pixbuf = vcardpix;
4341 	atci->menuCommand = "/File/New vCard";
4342 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4343 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4344 
4345 	/* JPilot */
4346 	atci = g_new0(AddressTypeControlItem, 1);
4347 	atci->objectType = ADDR_JPILOT;
4348 	atci->interfaceType = ADDR_IF_JPILOT;
4349 	atci->showInTree = TRUE;
4350 	atci->treeExpand = TRUE;
4351 	atci->treeLeaf = FALSE;
4352 	atci->displayName = _("JPilot");
4353 	atci->icon_pixbuf = jpilotpix;
4354 	atci->icon_open_pixbuf = jpilotpix;
4355 	atci->menuCommand = "/File/New JPilot";
4356 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4357 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4358 
4359 	/* Category */
4360 	atci = g_new0(AddressTypeControlItem, 1);
4361 	atci->objectType = ADDR_CATEGORY;
4362 	atci->interfaceType = ADDR_IF_JPILOT;
4363 	atci->showInTree = TRUE;
4364 	atci->treeExpand = TRUE;
4365 	atci->treeLeaf = TRUE;
4366 	atci->displayName = _("JPilot");
4367 	atci->icon_pixbuf = categorypix;
4368 	atci->icon_open_pixbuf = categorypix;
4369 	atci->menuCommand = NULL;
4370 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4371 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4372 
4373 	/* LDAP Server */
4374 	atci = g_new0(AddressTypeControlItem, 1);
4375 	atci->objectType = ADDR_LDAP;
4376 	atci->interfaceType = ADDR_IF_LDAP;
4377 	atci->showInTree = TRUE;
4378 	atci->treeExpand = TRUE;
4379 	atci->treeLeaf = TRUE;
4380 	atci->displayName = _("LDAP Server");
4381 	atci->icon_pixbuf = ldappix;
4382 	atci->icon_open_pixbuf = ldappix;
4383 	atci->menuCommand = "/File/New LDAP Server";
4384 	g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci);
4385 	_addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci);
4386 }
4387 
4388 /*
4389 * Search for specified object type.
4390 */
addrbookctl_lookup(gint ot)4391 AddressTypeControlItem *addrbookctl_lookup(gint ot)
4392 {
4393 	gint objType = ot;
4394 	return (AddressTypeControlItem *)g_hash_table_lookup(_addressBookTypeHash_, &objType);
4395 }
4396 
4397 /*
4398 * Search for specified interface type.
4399 */
addrbookctl_lookup_iface(AddressIfType ifType)4400 AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4401 	GList *node = _addressBookTypeList_;
4402 	while( node ) {
4403 		AddressTypeControlItem *atci = node->data;
4404 		if( atci->interfaceType == ifType ) return atci;
4405 		node = g_list_next( node );
4406 	}
4407 	return NULL;
4408 }
4409 
addrbookctl_free_address(AddressObject * obj)4410 static void addrbookctl_free_address( AddressObject *obj ) {
4411 	g_free( obj->name );
4412 	obj->type = ADDR_NONE;
4413 	obj->name = NULL;
4414 }
4415 
addrbookctl_free_interface(AdapterInterface * adapter)4416 static void addrbookctl_free_interface(AdapterInterface *adapter)
4417 {
4418 	addrbookctl_free_address(ADDRESS_OBJECT(adapter));
4419 	adapter->iface = NULL;
4420 	adapter->interfaceType = ADDR_IF_NONE;
4421 	adapter->atci = NULL;
4422 	adapter->enabled = FALSE;
4423 	adapter->haveLibrary = FALSE;
4424 	if (adapter->tree_row) {
4425 		gtk_tree_row_reference_free(adapter->tree_row);
4426 		adapter->tree_row = NULL;
4427 	}
4428 	g_free(adapter);
4429 }
4430 
addrbookctl_free_datasource(AdapterDSource * adapter)4431 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4432 	addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4433 	adapter->dataSource = NULL;
4434 	adapter->subType = ADDR_NONE;
4435 	g_free( adapter );
4436 }
4437 
addrbookctl_free_folder(AdapterFolder * adapter)4438 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4439 	addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4440 	adapter->itemFolder = NULL;
4441 	g_free( adapter );
4442 }
4443 
addrbookctl_free_group(AdapterGroup * adapter)4444 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4445 	addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4446 	adapter->itemGroup = NULL;
4447 	g_free( adapter );
4448 }
4449 
4450 /*
4451  * Build GUI interface list.
4452  */
addrbookctl_build_iflist(void)4453 void addrbookctl_build_iflist(void)
4454 {
4455 	AddressTypeControlItem *atci;
4456 	AdapterInterface *adapter;
4457 	GList *list = NULL;
4458 
4459 	if(_addressIndex_ == NULL) {
4460 		_addressIndex_ = addrindex_create_index();
4461 	}
4462 	_addressInterfaceList_ = NULL;
4463 	list = addrindex_get_interface_list(_addressIndex_);
4464 	while (list) {
4465 		AddressInterface *iface = list->data;
4466 		atci = addrbookctl_lookup_iface(iface->type);
4467 		if (atci) {
4468 			adapter = g_new0(AdapterInterface, 1);
4469 			adapter->interfaceType = iface->type;
4470 			adapter->atci = atci;
4471 			adapter->iface = iface;
4472 			adapter->tree_row = NULL;
4473 			adapter->enabled = TRUE;
4474 			adapter->haveLibrary = iface->haveLibrary;
4475 			ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4476 			ADDRESS_OBJECT_NAME(adapter) = g_strdup(atci->displayName);
4477 			_addressInterfaceList_ = g_list_append(_addressInterfaceList_, adapter);
4478 		}
4479 		list = g_list_next(list);
4480 	}
4481 }
4482 
addrbookctl_free_selection(GList * list)4483 void addrbookctl_free_selection( GList *list ) {
4484 	GList *node = list;
4485 	while( node ) {
4486 		AdapterInterface *adapter = node->data;
4487 		adapter = NULL;
4488 		node = g_list_next( node );
4489 	}
4490 	g_list_free( list );
4491 }
4492 
4493 /*
4494 * Find GUI interface type specified interface type.
4495 * Return: Interface item, or NULL if not found.
4496 */
addrbookctl_find_interface(AddressIfType ifType)4497 AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4498 	GList *node = _addressInterfaceList_;
4499 	while( node ) {
4500 		AdapterInterface *adapter = node->data;
4501 		if( adapter->interfaceType == ifType ) return adapter;
4502 		node = g_list_next( node );
4503 	}
4504 	return NULL;
4505 }
4506 
4507 /*
4508 * Build interface list selection.
4509 */
addrbookctl_build_ifselect(void)4510 void addrbookctl_build_ifselect(void)
4511 {
4512 	GList *newList = NULL;
4513 	gchar *selectStr;
4514 	gchar **splitStr;
4515 	gint ifType;
4516 	gint i;
4517 	gchar *endptr = NULL;
4518 	gboolean enabled;
4519 	AdapterInterface *adapter;
4520 	/* GList *node; */
4521 
4522 	selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4523 
4524 	/* Parse string */
4525 	splitStr = g_strsplit( selectStr, ",", -1 );
4526 	for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4527 		if( splitStr[i] ) {
4528 			/* printf( "%d : %s\n", i, splitStr[i] ); */
4529 			ifType = strtol( splitStr[i], &endptr, 10 );
4530 			enabled = TRUE;
4531 			if( *endptr ) {
4532 				if( strcmp( endptr, "/n" ) == 0 ) {
4533 					enabled = FALSE;
4534 				}
4535 			}
4536 			/* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4537 			adapter = addrbookctl_find_interface( ifType );
4538 			if( adapter ) {
4539 				newList = g_list_append( newList, adapter );
4540 			}
4541 		}
4542 		else {
4543 			break;
4544 		}
4545 	}
4546 	/* printf( "i=%d\n", i ); */
4547 	g_strfreev( splitStr );
4548 	g_free( selectStr );
4549 
4550 	/* Replace existing list */
4551 	mgu_clear_list( _addressIFaceSelection_ );
4552 	g_list_free( _addressIFaceSelection_ );
4553 	_addressIFaceSelection_ = newList;
4554 	newList = NULL;
4555 
4556 }
4557 
4558 /* **********************************************************************
4559 * Add sender to address book.
4560 * ***********************************************************************
4561 */
4562 
4563 /*
4564  * This function is used by the Add sender to address book function.
4565  */
addressbook_add_contact(const gchar * name,const gchar * address,const gchar * remarks)4566 gboolean addressbook_add_contact(const gchar *name, const gchar *address, const gchar *remarks)
4567 {
4568 	debug_print("addressbook_add_contact: name/address: %s <%s>\n", name ? name : "", address);
4569 	if (addressadd_selection(_addressIndex_, name, address, remarks)) {
4570 		debug_print("addressbook_add_contact - added\n");
4571 		addressbook_refresh();
4572 	}
4573 	return TRUE;
4574 }
4575 
4576 /*
4577  * This function is used by the automatic address registration.
4578  */
addressbook_add_contact_autoreg(const gchar * name,const gchar * address,const gchar * remarks)4579 gboolean addressbook_add_contact_autoreg(const gchar *name, const gchar *address, const gchar *remarks)
4580 {
4581 	debug_print("addressbook_add_contact_autoreg: name/address: %s <%s>\n", name ? name : "", address);
4582 	if (addressadd_autoreg(_addressIndex_, name, address, remarks)) {
4583 		addressbook_refresh();
4584 	}
4585 	return TRUE;
4586 }
4587 
4588 /* **********************************************************************
4589 * Address completion support.
4590 * ***********************************************************************
4591 */
4592 
4593 /*
4594 * This function is used by the address completion function to load
4595 * addresses.
4596 * Enter: callBackFunc Function to be called when an address is
4597 *                     to be loaded.
4598 * Return: TRUE if data loaded, FALSE if address index not loaded.
4599 */
addressbook_load_completion_full(AddressBookCompletionFunc func)4600 gboolean addressbook_load_completion_full(AddressBookCompletionFunc func)
4601 {
4602 	/* AddressInterface *interface; */
4603 	AddressDataSource *ds;
4604 	GList *nodeIf, *nodeDS;
4605 	GList *listP, *nodeP;
4606 	GList *nodeM;
4607 	gchar *sName, *sAddress, *sAlias, *sNickName;
4608 	gchar *sFirstName, *sLastName;
4609 
4610 	debug_print( "addressbook_load_completion\n" );
4611 
4612 	if( _addressIndex_ == NULL ) return FALSE;
4613 
4614 	nodeIf = addrindex_get_interface_list( _addressIndex_ );
4615 	while( nodeIf ) {
4616 		AddressInterface *iface = nodeIf->data;
4617 		nodeDS = iface->listSource;
4618 		while( nodeDS ) {
4619 			ds = nodeDS->data;
4620 
4621 			/* Read address book */
4622 			if( ! addrindex_ds_get_read_flag( ds ) ) {
4623 				addrindex_ds_read_data( ds );
4624 			}
4625 
4626 			/* Get all persons */
4627 			listP = addrindex_ds_get_all_persons( ds );
4628 			nodeP = listP;
4629 			while( nodeP ) {
4630 				ItemPerson *person = nodeP->data;
4631 				nodeM = person->listEMail;
4632 
4633 				/* Figure out name to use */
4634 				sName = ADDRITEM_NAME(person);
4635 				sNickName = person->nickName;
4636 				if( sName == NULL || *sName == '\0' ) {
4637 					if (sNickName)
4638 						sName = sNickName;
4639 				}
4640 				sFirstName = person->firstName;
4641 				sLastName = person->lastName;
4642 
4643 				/* Process each E-Mail address */
4644 				while( nodeM ) {
4645 					ItemEMail *email = nodeM->data;
4646 					/* Have mail */
4647 					sAddress = email->address;
4648 					if( sAddress && *sAddress != '\0' ) {
4649 						sAlias = ADDRITEM_NAME(email);
4650 						if( sAlias && *sAlias != '\0' ) {
4651 							func( sName, sFirstName, sLastName, sAlias, sAddress );
4652 						} else {
4653 							func( sName, sFirstName, sLastName, sNickName, sAddress );
4654 						}
4655 					}
4656 					nodeM = g_list_next( nodeM );
4657 				}
4658 				nodeP = g_list_next( nodeP );
4659 			}
4660 			/* Free up the list */
4661 			g_list_free( listP );
4662 
4663 			nodeDS = g_list_next( nodeDS );
4664 		}
4665 		nodeIf = g_list_next( nodeIf );
4666 	}
4667 	debug_print( "addressbook_load_completion... done\n" );
4668 
4669 	return TRUE;
4670 }
4671 
4672 static gint (*real_func)(const gchar *, const gchar *, const gchar *);
4673 
wrapper_func(const gchar * name,const gchar * firstname,const gchar * lastname,const gchar * nickname,const gchar * address)4674 static gint wrapper_func(const gchar *name, const gchar *firstname, const gchar *lastname, const gchar *nickname, const gchar *address)
4675 {
4676 	return real_func(name, address, nickname);
4677 }
4678 
addressbook_load_completion(gint (* callBackFunc)(const gchar *,const gchar *,const gchar *))4679 gboolean addressbook_load_completion(gint (*callBackFunc)(const gchar *, const gchar *, const gchar *))
4680 {
4681 	gboolean ret;
4682 
4683 	real_func = callBackFunc;
4684 	ret = addressbook_load_completion_full(wrapper_func);
4685 	real_func = NULL;
4686 
4687 	return ret;
4688 }
4689 
4690 /* **********************************************************************
4691 * Address Import.
4692 * ***********************************************************************
4693 */
4694 
4695 /*
4696 * Import LDIF file.
4697 */
addressbook_import_ldif_cb(void)4698 static void addressbook_import_ldif_cb(void)
4699 {
4700 	AddressDataSource *ds = NULL;
4701 	AdapterDSource *ads = NULL;
4702 	AddressBookFile *abf = NULL;
4703 	AdapterInterface *adapter;
4704 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
4705 	GtkTreeModel *model;
4706 	GtkTreeIter iter, new_iter;
4707 	GtkTreePath *path;
4708 
4709 	adapter = addrbookctl_find_interface(ADDR_IF_BOOK);
4710 	if (!adapter || !adapter->tree_row)
4711 		return;
4712 
4713 	abf = addressbook_imp_ldif(_addressIndex_);
4714 	gtk_window_present(GTK_WINDOW(addrbook.window));
4715 	if (!abf)
4716 		return;
4717 
4718 	ds = addrindex_index_add_datasource(_addressIndex_, ADDR_IF_BOOK, abf);
4719 	ads = addressbook_create_ds_adapter(ds, ADDR_BOOK, NULL);
4720 	addressbook_ads_set_name(ads, abf->name);
4721 
4722 	model = gtk_tree_view_get_model(treeview);
4723 	gtkut_tree_row_reference_get_iter(model, adapter->tree_row, &iter);
4724 
4725 	if (addressbook_add_object(&iter, &new_iter, ADDRESS_OBJECT(ads))) {
4726 		path = gtk_tree_model_get_path(model, &new_iter);
4727 		gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
4728 		gtk_tree_path_free(path);
4729 	}
4730 
4731 	/* Notify address completion */
4732 	addressbook_modified();
4733 }
4734 
addressbook_import_ldif_file(const gchar * file,const gchar * book_name)4735 gboolean addressbook_import_ldif_file(const gchar *file, const gchar *book_name)
4736 {
4737 	AddressBookFile *abf;
4738 
4739 	g_return_val_if_fail(file != NULL, FALSE);
4740 	g_return_val_if_fail(book_name != NULL, FALSE);
4741 
4742 	abf = addressbook_imp_ldif_file(_addressIndex_, file, book_name);
4743 	if (!abf)
4744 		return FALSE;
4745 
4746 	addrindex_index_add_datasource(_addressIndex_, ADDR_IF_BOOK, abf);
4747 	addrindex_save_data(_addressIndex_);
4748 	addressbook_modified();
4749 
4750 	return TRUE;
4751 }
4752 
4753 /*
4754 * Import CSV file.
4755 */
addressbook_import_csv_cb(void)4756 static void addressbook_import_csv_cb(void)
4757 {
4758 	AddressDataSource *ds = NULL;
4759 	AdapterDSource *ads = NULL;
4760 	AddressBookFile *abf = NULL;
4761 	AdapterInterface *adapter;
4762 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
4763 	GtkTreeModel *model;
4764 	GtkTreeIter iter, new_iter;
4765 	GtkTreePath *path;
4766 
4767 	adapter = addrbookctl_find_interface(ADDR_IF_BOOK);
4768 	if (!adapter || !adapter->tree_row)
4769 		return;
4770 
4771 	abf = addressbook_imp_csv(_addressIndex_);
4772 	gtk_window_present(GTK_WINDOW(addrbook.window));
4773 	if (!abf)
4774 		return;
4775 
4776 	ds = addrindex_index_add_datasource(_addressIndex_, ADDR_IF_BOOK, abf);
4777 	ads = addressbook_create_ds_adapter(ds, ADDR_BOOK, NULL);
4778 	addressbook_ads_set_name(ads, abf->name);
4779 
4780 	model = gtk_tree_view_get_model(treeview);
4781 	gtkut_tree_row_reference_get_iter(model, adapter->tree_row, &iter);
4782 
4783 	if (addressbook_add_object(&iter, &new_iter, ADDRESS_OBJECT(ads))) {
4784 		path = gtk_tree_model_get_path(model, &new_iter);
4785 		gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
4786 		gtk_tree_path_free(path);
4787 	}
4788 
4789 	/* Notify address completion */
4790 	addressbook_modified();
4791 }
4792 
4793 /*
4794 * Export CSV file.
4795 */
addressbook_export_csv_cb(void)4796 static void addressbook_export_csv_cb(void)
4797 {
4798 	GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview);
4799 	GtkTreeModel *model;
4800 	GtkTreeIter iter;
4801 	GtkTreePath *path;
4802 	AddressObject *obj;
4803 	ItemFolder *itemFolder = NULL;
4804 	ItemGroup *itemGroup = NULL;
4805 	GList *items;
4806 	GList *cur;
4807 	gchar delim = ',';
4808 
4809 	if (!addrbook.tree_opened) {
4810 		return;
4811 	}
4812 
4813 	model = gtk_tree_view_get_model(treeview);
4814 	gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter);
4815 	gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1);
4816 	g_return_if_fail(obj != NULL);
4817 
4818 	if (obj->type == ADDR_INTERFACE) {
4819 		return;
4820 	}
4821 
4822 	addressbook_exp_csv(obj);
4823 }
4824 
4825 /* **********************************************************************
4826 * Address Book Fast Search.
4827 * ***********************************************************************
4828 */
4829 
4830 static GHashTable *addr_table;
4831 
4832 #if USE_THREADS
4833 G_LOCK_DEFINE_STATIC(addr_table);
4834 #define S_LOCK(name)	G_LOCK(name)
4835 #define S_UNLOCK(name)	G_UNLOCK(name)
4836 #else
4837 #define S_LOCK(name)
4838 #define S_UNLOCK(name)
4839 #endif
4840 
load_address(const gchar * name,const gchar * address,const gchar * nickname)4841 static gint load_address(const gchar *name, const gchar *address,
4842 			 const gchar *nickname)
4843 {
4844 	gchar *addr;
4845 
4846 	if (!address)
4847 		return -1;
4848 
4849 	addr = g_ascii_strdown(address, -1);
4850 
4851 	if (g_hash_table_lookup(addr_table, addr) == NULL)
4852 		g_hash_table_insert(addr_table, addr, addr);
4853 	else
4854 		g_free(addr);
4855 
4856 	return 0;
4857 }
4858 
addressbook_modified(void)4859 static void addressbook_modified(void)
4860 {
4861 	S_LOCK(addr_table);
4862 
4863 	if (addr_table) {
4864 		hash_free_strings(addr_table);
4865 		g_hash_table_destroy(addr_table);
4866 		addr_table = NULL;
4867 	}
4868 
4869 	S_UNLOCK(addr_table);
4870 
4871 	invalidate_address_completion();
4872 }
4873 
addressbook_has_address(const gchar * address)4874 gboolean addressbook_has_address(const gchar *address)
4875 {
4876 	GSList *list, *cur;
4877 	gchar *addr;
4878 	gboolean found = FALSE;
4879 
4880 	if (!address)
4881 		return FALSE;
4882 
4883 	/* debug_print("addressbook_has_address: check if addressbook has address: %s\n", address); */
4884 
4885 	list = address_list_append(NULL, address);
4886 	if (!list)
4887 		return FALSE;
4888 
4889 	S_LOCK(addr_table);
4890 
4891 	if (!addr_table) {
4892 		addr_table = g_hash_table_new(g_str_hash, g_str_equal);
4893 		addressbook_load_completion(load_address);
4894 	}
4895 
4896 	for (cur = list; cur != NULL; cur = cur->next) {
4897 		addr = g_ascii_strdown((gchar *)cur->data, -1);
4898 
4899 		if (g_hash_table_lookup(addr_table, addr)) {
4900 			found = TRUE;
4901 			/* debug_print("<%s> is in addressbook\n", addr); */
4902 		} else {
4903 			found = FALSE;
4904 			g_free(addr);
4905 			break;
4906 		}
4907 		g_free(addr);
4908 	}
4909 
4910 	S_UNLOCK(addr_table);
4911 
4912 	slist_free_strings(list);
4913 
4914 	return found;
4915 }
4916 
4917 /*
4918 * End of Source.
4919 */
4920