2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2012 Match Grun and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * Add address to address book dialog.
26 #include "claws-features.h"
32 #include <glib/gi18n.h>
33 #include <gdk/gdkkeysyms.h>
37 #include "stock_pixmap.h"
38 #include "prefs_common.h"
39 #include "prefs_gtk.h"
40 #include "addressadd.h"
41 #ifndef USE_NEW_ADDRBOOK
44 #include "addrindex.h"
45 #include "ldapserver.h"
46 #include "ldapupdate.h"
48 #include "addressbook-dbus.h"
50 #include "manage_window.h"
51 #include "alertpanel.h"
53 #ifndef USE_NEW_ADDRBOOK
55 AddressBookFile
*book
;
64 static struct _AddressAdd_dlg
{
67 GtkWidget
*entry_name
;
68 GtkWidget
*label_address
;
69 GtkWidget
*entry_remarks
;
70 GtkWidget
*tree_folder
;
72 GtkWidget
*cancel_btn
;
73 FolderInfo
*fiSelected
;
76 static GdkPixbuf
*folderXpm
;
77 static GdkPixbuf
*bookXpm
;
79 static gboolean addressadd_cancelled
;
81 #ifndef USE_NEW_ADDRBOOK
82 static FolderInfo
*addressadd_create_folderinfo( AddressBookFile
*abf
, ItemFolder
*folder
)
84 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
90 static FolderInfo
*addressadd_create_folderinfo(gchar
* book
) {
91 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
97 #ifndef USE_NEW_ADDRBOOK
98 static void addressadd_free_folderinfo( FolderInfo
*fi
) {
104 static void addressadd_free_folderinfo( FolderInfo
*fi
) {
110 static gint
addressadd_delete_event( GtkWidget
*widget
, GdkEventAny
*event
, gboolean
*cancelled
) {
111 addressadd_cancelled
= TRUE
;
116 static gboolean
addressadd_key_pressed( GtkWidget
*widget
, GdkEventKey
*event
, gboolean
*cancelled
) {
117 if (event
&& event
->keyval
== GDK_KEY_Escape
) {
118 addressadd_cancelled
= TRUE
;
124 static void addressadd_ok( GtkWidget
*widget
, gboolean
*cancelled
) {
125 addressadd_cancelled
= FALSE
;
129 static void addressadd_cancel( GtkWidget
*widget
, gboolean
*cancelled
) {
130 addressadd_cancelled
= TRUE
;
134 static void addressadd_folder_select( GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
135 gint column
, gpointer data
)
137 addressadd_dlg
.fiSelected
= gtk_cmctree_node_get_row_data( ctree
, node
);
140 static gboolean
addressadd_tree_button( GtkCMCTree
*ctree
, GdkEventButton
*event
, gpointer data
) {
143 if( event
->button
== 1 ) {
144 /* Handle double click */
145 if( event
->type
== GDK_2BUTTON_PRESS
) {
146 addressadd_cancelled
= FALSE
;
154 static void addressadd_size_allocate_cb(GtkWidget
*widget
,
155 GtkAllocation
*allocation
)
157 cm_return_if_fail(allocation
!= NULL
);
159 prefs_common
.addressaddwin_width
= allocation
->width
;
160 prefs_common
.addressaddwin_height
= allocation
->height
;
163 static void addressadd_create( void ) {
165 GtkWidget
*vbox
, *hbox
;
170 GtkWidget
*entry_name
;
171 GtkWidget
*label_addr
;
172 GtkWidget
*entry_rems
;
173 GtkWidget
*tree_folder
;
178 GtkWidget
*cancel_btn
;
180 static GdkGeometry geometry
;
183 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "addressadd");
184 gtk_container_set_border_width( GTK_CONTAINER(window
), VBOX_BORDER
);
185 gtk_window_set_title( GTK_WINDOW(window
), _("Add to address book") );
186 gtk_window_set_position( GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
187 g_signal_connect( G_OBJECT(window
), "delete_event",
188 G_CALLBACK(addressadd_delete_event
), NULL
);
189 g_signal_connect( G_OBJECT(window
), "key_press_event",
190 G_CALLBACK(addressadd_key_pressed
), NULL
);
191 g_signal_connect(G_OBJECT(window
), "size_allocate",
192 G_CALLBACK(addressadd_size_allocate_cb
), NULL
);
194 hbox
= gtk_hbox_new(FALSE
, 10);
195 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 4);
196 vbox
= gtk_vbox_new(FALSE
, 8);
197 gtk_container_add(GTK_CONTAINER(window
), vbox
);
199 picture
= gtk_image_new();
200 gtk_box_pack_start(GTK_BOX(hbox
), picture
, FALSE
, FALSE
, 0);
202 table
= gtk_table_new(3, 2, FALSE
);
203 gtk_box_pack_start(GTK_BOX(hbox
), table
, TRUE
, TRUE
, 0);
204 gtk_table_set_row_spacings(GTK_TABLE(table
), VSPACING_NARROW
);
205 gtk_table_set_col_spacings(GTK_TABLE(table
), HSPACING_NARROW
);
207 frame
= gtk_frame_new(_("Contact"));
208 gtk_frame_set_label_align(GTK_FRAME(frame
), 0.01, 0.5);
209 gtk_container_add(GTK_CONTAINER(frame
), hbox
);
210 gtk_container_set_border_width( GTK_CONTAINER(frame
), 4);
211 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 0);
215 label
= gtk_label_new(_("Name"));
216 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
217 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
219 entry_name
= gtk_entry_new();
220 gtk_widget_set_size_request(entry_name
, 150, -1);
221 gtk_entry_set_text (GTK_ENTRY(entry_name
),"");
223 gtk_table_attach(GTK_TABLE(table
), entry_name
, 1, 2, top
, (top
+ 1), GTK_FILL
| GTK_EXPAND
, 0, 0, 0);
227 label
= gtk_label_new(_("Address"));
228 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
229 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
231 label_addr
= gtk_label_new("");
232 gtk_widget_set_size_request(label_addr
, 150, -1);
233 gtk_table_attach(GTK_TABLE(table
), label_addr
, 1, 2, top
, (top
+ 1), GTK_FILL
| GTK_EXPAND
, 0, 0, 0);
234 gtk_misc_set_alignment(GTK_MISC(label_addr
), 0, 0.5);
238 label
= gtk_label_new(_("Remarks"));
239 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
240 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
242 entry_rems
= gtk_entry_new();
243 gtk_widget_set_size_request(entry_rems
, 150, -1);
244 gtk_table_attach(GTK_TABLE(table
), entry_rems
, 1, 2, top
, (top
+ 1), GTK_FILL
| GTK_EXPAND
, 0, 0, 0);
246 /* Address book/folder tree */
247 vlbox
= gtk_vbox_new(FALSE
, VBOX_BORDER
);
248 gtk_box_pack_start(GTK_BOX(vbox
), vlbox
, TRUE
, TRUE
, 0);
249 gtk_container_set_border_width( GTK_CONTAINER(vlbox
), 4);
251 tree_win
= gtk_scrolled_window_new( NULL
, NULL
);
252 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win
),
253 GTK_POLICY_AUTOMATIC
,
254 GTK_POLICY_AUTOMATIC
);
255 gtk_box_pack_start( GTK_BOX(vlbox
), tree_win
, TRUE
, TRUE
, 0 );
257 titles
[0] = _( "Select Address Book Folder") ;
259 tree_folder
= gtk_sctree_new_with_titles( 1, 0, titles
);
260 gtk_container_add( GTK_CONTAINER(tree_win
), tree_folder
);
261 gtk_cmclist_column_titles_show( GTK_CMCLIST(tree_folder
) );
262 gtk_cmctree_set_line_style(GTK_CMCTREE(tree_folder
), GTK_CMCTREE_LINES_NONE
);
263 gtk_cmctree_set_expander_style(GTK_CMCTREE(tree_folder
),
264 GTK_CMCTREE_EXPANDER_TRIANGLE
);
265 gtk_sctree_set_stripes(GTK_SCTREE(tree_folder
), prefs_common
.use_stripes_everywhere
);
266 gtk_cmclist_set_selection_mode( GTK_CMCLIST(tree_folder
), GTK_SELECTION_BROWSE
);
267 gtk_cmctree_set_indent( GTK_CMCTREE(tree_folder
), CTREE_INDENT
);
268 gtk_cmclist_set_auto_sort( GTK_CMCLIST(tree_folder
), TRUE
);
271 gtkut_stock_button_set_create(&hbbox
, &cancel_btn
, GTK_STOCK_CANCEL
,
272 &ok_btn
, GTK_STOCK_OK
,
274 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
275 gtk_container_set_border_width( GTK_CONTAINER(hbbox
), HSPACING_NARROW
);
276 gtk_widget_grab_default(ok_btn
);
278 g_signal_connect(G_OBJECT(ok_btn
), "clicked",
279 G_CALLBACK(addressadd_ok
), NULL
);
280 g_signal_connect(G_OBJECT(cancel_btn
), "clicked",
281 G_CALLBACK(addressadd_cancel
), NULL
);
282 g_signal_connect(G_OBJECT(tree_folder
), "tree_select_row",
283 G_CALLBACK(addressadd_folder_select
), NULL
);
284 g_signal_connect(G_OBJECT(tree_folder
), "button_press_event",
285 G_CALLBACK(addressadd_tree_button
), NULL
);
287 if (!geometry
.min_height
) {
288 geometry
.min_width
= 300;
289 geometry
.min_height
= 350;
292 gtk_window_set_geometry_hints(GTK_WINDOW(window
), NULL
, &geometry
,
294 gtk_widget_set_size_request(window
, prefs_common
.addressaddwin_width
,
295 prefs_common
.addressaddwin_height
);
297 addressadd_dlg
.window
= window
;
298 addressadd_dlg
.picture
= picture
;
299 addressadd_dlg
.entry_name
= entry_name
;
300 addressadd_dlg
.label_address
= label_addr
;
301 addressadd_dlg
.entry_remarks
= entry_rems
;
302 addressadd_dlg
.tree_folder
= tree_folder
;
303 addressadd_dlg
.ok_btn
= ok_btn
;
304 addressadd_dlg
.cancel_btn
= cancel_btn
;
306 gtk_widget_show_all( window
);
308 stock_pixbuf_gdk( window
, STOCK_PIXMAP_BOOK
, &bookXpm
);
309 stock_pixbuf_gdk( window
, STOCK_PIXMAP_DIR_OPEN
,
313 #ifndef USE_NEW_ADDRBOOK
314 static void addressadd_load_folder( GtkCMCTreeNode
*parentNode
, ItemFolder
*parentFolder
,
315 FolderInfo
*fiParent
)
317 GtkCMCTree
*tree
= GTK_CMCTREE( addressadd_dlg
.tree_folder
);
322 GtkCMCTreeNode
*node
;
325 list
= parentFolder
->listFolder
;
328 fName
= g_strdup( ADDRITEM_NAME(folder
) );
330 node
= gtk_sctree_insert_node( tree
, parentNode
, NULL
, name
, FOLDER_SPACING
,
331 folderXpm
, folderXpm
,
334 fi
= addressadd_create_folderinfo( fiParent
->book
, folder
);
335 gtk_cmctree_node_set_row_data_full( tree
, node
, fi
,
336 ( GDestroyNotify
) addressadd_free_folderinfo
);
337 addressadd_load_folder( node
, folder
, fi
);
338 list
= g_list_next( list
);
342 static void addressadd_load_data( AddressIndex
*addrIndex
) {
343 AddressDataSource
*ds
;
344 GList
*list
, *nodeDS
;
347 ItemFolder
*rootFolder
;
348 AddressBookFile
*abf
;
350 GtkCMCTree
*tree
= GTK_CMCTREE( addressadd_dlg
.tree_folder
);
351 GtkCMCTreeNode
*node
;
353 gtk_cmclist_clear( GTK_CMCLIST( tree
) );
354 list
= addrindex_get_interface_list( addrIndex
);
356 AddressInterface
*ainterface
= list
->data
;
357 if( ainterface
->type
== ADDR_IF_BOOK
||
358 ainterface
->type
== ADDR_IF_LDAP
) {
359 nodeDS
= ainterface
->listSource
;
362 dsName
= g_strdup( addrindex_ds_get_name( ds
) );
364 /* Read address book */
365 if( ! addrindex_ds_get_read_flag( ds
) ) {
366 addrindex_ds_read_data( ds
);
369 /* Add node for address book */
370 abf
= ds
->rawDataSource
;
372 node
= gtk_cmctree_insert_node( tree
, NULL
, NULL
,
373 name
, FOLDER_SPACING
, bookXpm
,
378 fi
= addressadd_create_folderinfo( abf
, NULL
);
379 gtk_cmctree_node_set_row_data_full( tree
, node
, fi
,
380 ( GDestroyNotify
) addressadd_free_folderinfo
);
382 rootFolder
= addrindex_ds_get_root_folder( ds
);
383 addressadd_load_folder( node
, rootFolder
, fi
);
385 nodeDS
= g_list_next( nodeDS
);
388 list
= g_list_next( list
);
392 static void addressadd_load_data() {
395 GtkCMCTree
*tree
= GTK_CMCTREE(addressadd_dlg
.tree_folder
);
396 GtkCMCTreeNode
*node
;
397 FolderInfo
*fi
= NULL
;
398 GError
* error
= NULL
;
400 gtk_cmclist_clear(GTK_CMCLIST(tree
));
401 list
= addressbook_dbus_get_books(&error
);
402 for (; list
; list
= g_slist_next(list
)) {
403 name
= (gchar
*) list
->data
;
404 node
= gtk_cmctree_insert_node(tree
, NULL
, NULL
,
405 &name
, FOLDER_SPACING
, bookXpm
,
406 bookXpm
, FALSE
, TRUE
);
407 fi
= addressadd_create_folderinfo(name
);
408 gtk_cmctree_node_set_row_data_full(tree
, node
, fi
,
409 ( GDestroyNotify
) addressadd_free_folderinfo
);
414 #ifndef USE_NEW_ADDRBOOK
415 gboolean
addressadd_selection( AddressIndex
*addrIndex
, const gchar
*name
,
416 const gchar
*address
, const gchar
*remarks
, GdkPixbuf
*picture
) {
418 gboolean
addressadd_selection(const gchar
*name
, const gchar
*address
,
419 const gchar
*remarks
, GdkPixbuf
*picture
) {
421 gboolean retVal
= FALSE
;
422 #ifndef USE_NEW_ADDRBOOK
423 ItemPerson
*person
= NULL
;
425 FolderInfo
*fi
= NULL
;
426 addressadd_cancelled
= FALSE
;
428 if( ! addressadd_dlg
.window
) addressadd_create();
430 addressadd_dlg
.fiSelected
= NULL
;
431 #ifndef USE_NEW_ADDRBOOK
432 addressadd_load_data( addrIndex
);
434 addressadd_load_data();
436 gtk_cmclist_select_row( GTK_CMCLIST( addressadd_dlg
.tree_folder
), 0, 0 );
437 gtk_widget_show(addressadd_dlg
.window
);
438 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), TRUE
);
439 gtk_widget_grab_focus(addressadd_dlg
.ok_btn
);
441 manage_window_set_transient(GTK_WINDOW(addressadd_dlg
.window
));
443 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), "" );
444 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), "" );
445 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), "" );
447 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), name
);
449 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), address
);
451 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), remarks
);
453 gtk_image_set_from_pixbuf(GTK_IMAGE(addressadd_dlg
.picture
), picture
);
454 gtk_widget_show(GTK_WIDGET(addressadd_dlg
.picture
));
456 gtk_widget_hide(GTK_WIDGET(addressadd_dlg
.picture
));
459 gtk_widget_hide( addressadd_dlg
.window
);
460 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), FALSE
);
461 if( ! addressadd_cancelled
) {
462 if( addressadd_dlg
.fiSelected
) {
463 gchar
*returned_name
;
464 gchar
*returned_remarks
;
465 returned_name
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_name
), 0, -1 );
466 returned_remarks
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_remarks
), 0, -1 );
468 fi
= addressadd_dlg
.fiSelected
;
470 #ifndef USE_NEW_ADDRBOOK
471 person
= addrbook_add_contact( fi
->book
, fi
->folder
,
476 if (person
!= NULL
) {
477 person
->status
= ADD_ENTRY
;
480 GError
*error
= NULL
;
481 gchar
*name
= g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S
, ADDRBOOK_DIR
, G_DIR_SEPARATOR_S
,
482 ADDRITEM_ID(person
), ".png", NULL
);
483 gdk_pixbuf_save(picture
, name
, "png", &error
, NULL
);
485 g_warning(_("Failed to save image: \n%s"),
489 addritem_person_set_picture( person
, ADDRITEM_ID(person
) ) ;
494 ContactData
* contact
= g_new0(ContactData
, 1);
495 GError
* error
= NULL
;
498 contact
->cn
= g_strdup(returned_name
);
500 contact
->cn
= g_strdup(address
);
502 contact
->name
= g_strdup(returned_name
);
503 contact
->email
= g_strdup(address
);
504 contact
->remarks
= g_strdup(returned_remarks
);
505 contact
->book
= g_strdup(fi
->book
);
506 contact
->picture
= picture
;
508 if (addressbook_dbus_add_contact(contact
, &error
) == 0) {
509 debug_print("Added to addressbook:\n%s\n%s\n%s\n%s\n",
510 returned_name
, address
, returned_remarks
, fi
->book
);
516 GtkWidget
* dialog
= gtk_message_dialog_new (
517 GTK_WINDOW(addressadd_dlg
.window
),
518 GTK_DIALOG_DESTROY_WITH_PARENT
,
521 "%s", error
->message
);
522 gtk_dialog_run (GTK_DIALOG (dialog
));
523 gtk_widget_destroy (dialog
);
527 contact_data_free(&contact
);
530 if (person
!= NULL
&& fi
->book
->type
== ADBOOKTYPE_LDAP
) {
531 LdapServer
*server
= (LdapServer
*) fi
->book
;
532 ldapsvr_set_modified(server
, TRUE
);
533 ldapsvr_update_book(server
, person
);
534 if (server
->retVal
!= LDAPRC_SUCCESS
) {
535 alertpanel( _("Add address(es)"),
536 _("Can't add the specified address"),
537 GTK_STOCK_CLOSE
, NULL
, NULL
);
538 return server
->retVal
;
542 g_free(returned_name
);
543 g_free(returned_remarks
);
544 #ifndef USE_NEW_ADDRBOOK
545 if( person
) retVal
= TRUE
;
550 gtk_cmclist_clear( GTK_CMCLIST( addressadd_dlg
.tree_folder
) );