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_ALT_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_ALT_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_ALT_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_ALT_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(STOCK_PIXMAP_BOOK
, &bookXpm
);
309 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderXpm
);
312 #ifndef USE_ALT_ADDRBOOK
313 static void addressadd_load_folder( GtkCMCTreeNode
*parentNode
, ItemFolder
*parentFolder
,
314 FolderInfo
*fiParent
)
316 GtkCMCTree
*tree
= GTK_CMCTREE( addressadd_dlg
.tree_folder
);
321 GtkCMCTreeNode
*node
;
324 list
= parentFolder
->listFolder
;
327 fName
= g_strdup( ADDRITEM_NAME(folder
) );
329 node
= gtk_sctree_insert_node( tree
, parentNode
, NULL
, name
, FOLDER_SPACING
,
330 folderXpm
, folderXpm
,
333 fi
= addressadd_create_folderinfo( fiParent
->book
, folder
);
334 gtk_cmctree_node_set_row_data_full( tree
, node
, fi
,
335 ( GDestroyNotify
) addressadd_free_folderinfo
);
336 addressadd_load_folder( node
, folder
, fi
);
337 list
= g_list_next( list
);
341 static void addressadd_load_data( AddressIndex
*addrIndex
) {
342 AddressDataSource
*ds
;
343 GList
*list
, *nodeDS
;
346 ItemFolder
*rootFolder
;
347 AddressBookFile
*abf
;
349 GtkCMCTree
*tree
= GTK_CMCTREE( addressadd_dlg
.tree_folder
);
350 GtkCMCTreeNode
*node
;
352 gtk_cmclist_clear( GTK_CMCLIST( tree
) );
353 list
= addrindex_get_interface_list( addrIndex
);
355 AddressInterface
*ainterface
= list
->data
;
356 if( ainterface
->type
== ADDR_IF_BOOK
||
357 ainterface
->type
== ADDR_IF_LDAP
) {
358 nodeDS
= ainterface
->listSource
;
361 dsName
= g_strdup( addrindex_ds_get_name( ds
) );
363 /* Read address book */
364 if( ! addrindex_ds_get_read_flag( ds
) ) {
365 addrindex_ds_read_data( ds
);
368 /* Add node for address book */
369 abf
= ds
->rawDataSource
;
371 node
= gtk_cmctree_insert_node( tree
, NULL
, NULL
,
372 name
, FOLDER_SPACING
, bookXpm
,
377 fi
= addressadd_create_folderinfo( abf
, NULL
);
378 gtk_cmctree_node_set_row_data_full( tree
, node
, fi
,
379 ( GDestroyNotify
) addressadd_free_folderinfo
);
381 rootFolder
= addrindex_ds_get_root_folder( ds
);
382 addressadd_load_folder( node
, rootFolder
, fi
);
384 nodeDS
= g_list_next( nodeDS
);
387 list
= g_list_next( list
);
391 static void addressadd_load_data() {
394 GtkCMCTree
*tree
= GTK_CMCTREE(addressadd_dlg
.tree_folder
);
395 GtkCMCTreeNode
*node
;
396 FolderInfo
*fi
= NULL
;
397 GError
* error
= NULL
;
399 gtk_cmclist_clear(GTK_CMCLIST(tree
));
400 list
= addressbook_dbus_get_books(&error
);
401 for (; list
; list
= g_slist_next(list
)) {
402 name
= (gchar
*) list
->data
;
403 node
= gtk_cmctree_insert_node(tree
, NULL
, NULL
,
404 &name
, FOLDER_SPACING
, bookXpm
,
405 bookXpm
, FALSE
, TRUE
);
406 fi
= addressadd_create_folderinfo(name
);
407 gtk_cmctree_node_set_row_data_full(tree
, node
, fi
,
408 ( GDestroyNotify
) addressadd_free_folderinfo
);
413 #ifndef USE_ALT_ADDRBOOK
414 gboolean
addressadd_selection( AddressIndex
*addrIndex
, const gchar
*name
,
415 const gchar
*address
, const gchar
*remarks
, GdkPixbuf
*picture
) {
417 gboolean
addressadd_selection(const gchar
*name
, const gchar
*address
,
418 const gchar
*remarks
, GdkPixbuf
*picture
) {
420 gboolean retVal
= FALSE
;
421 #ifndef USE_ALT_ADDRBOOK
422 ItemPerson
*person
= NULL
;
424 FolderInfo
*fi
= NULL
;
425 addressadd_cancelled
= FALSE
;
427 if( ! addressadd_dlg
.window
) addressadd_create();
429 addressadd_dlg
.fiSelected
= NULL
;
430 #ifndef USE_ALT_ADDRBOOK
431 addressadd_load_data( addrIndex
);
433 addressadd_load_data();
435 gtk_cmclist_select_row( GTK_CMCLIST( addressadd_dlg
.tree_folder
), 0, 0 );
436 gtk_widget_show(addressadd_dlg
.window
);
437 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), TRUE
);
438 gtk_widget_grab_focus(addressadd_dlg
.ok_btn
);
440 manage_window_set_transient(GTK_WINDOW(addressadd_dlg
.window
));
442 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), "" );
443 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), "" );
444 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), "" );
446 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), name
);
448 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), address
);
450 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), remarks
);
452 gtk_image_set_from_pixbuf(GTK_IMAGE(addressadd_dlg
.picture
), picture
);
453 gtk_widget_show(GTK_WIDGET(addressadd_dlg
.picture
));
455 gtk_widget_hide(GTK_WIDGET(addressadd_dlg
.picture
));
458 gtk_widget_hide( addressadd_dlg
.window
);
459 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), FALSE
);
460 if( ! addressadd_cancelled
) {
461 if( addressadd_dlg
.fiSelected
) {
462 gchar
*returned_name
;
463 gchar
*returned_remarks
;
464 returned_name
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_name
), 0, -1 );
465 returned_remarks
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_remarks
), 0, -1 );
467 fi
= addressadd_dlg
.fiSelected
;
469 #ifndef USE_ALT_ADDRBOOK
470 person
= addrbook_add_contact( fi
->book
, fi
->folder
,
475 if (person
!= NULL
) {
476 person
->status
= ADD_ENTRY
;
479 GError
*error
= NULL
;
480 gchar
*name
= g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S
, ADDRBOOK_DIR
, G_DIR_SEPARATOR_S
,
481 ADDRITEM_ID(person
), ".png", NULL
);
482 gdk_pixbuf_save(picture
, name
, "png", &error
, NULL
);
484 g_warning("Failed to save image: %s",
488 addritem_person_set_picture( person
, ADDRITEM_ID(person
) ) ;
493 ContactData
* contact
= g_new0(ContactData
, 1);
494 GError
* error
= NULL
;
497 contact
->cn
= g_strdup(returned_name
);
499 contact
->cn
= g_strdup(address
);
501 contact
->name
= g_strdup(returned_name
);
502 contact
->email
= g_strdup(address
);
503 contact
->remarks
= g_strdup(returned_remarks
);
504 contact
->book
= g_strdup(fi
->book
);
505 contact
->picture
= picture
;
507 if (addressbook_dbus_add_contact(contact
, &error
) == 0) {
508 debug_print("Added to addressbook:\n%s\n%s\n%s\n%s\n",
509 returned_name
, address
, returned_remarks
, fi
->book
);
515 GtkWidget
* dialog
= gtk_message_dialog_new (
516 GTK_WINDOW(addressadd_dlg
.window
),
517 GTK_DIALOG_DESTROY_WITH_PARENT
,
520 "%s", error
->message
);
521 gtk_dialog_run (GTK_DIALOG (dialog
));
522 gtk_widget_destroy (dialog
);
526 contact_data_free(&contact
);
529 if (person
!= NULL
&& fi
->book
->type
== ADBOOKTYPE_LDAP
) {
530 LdapServer
*server
= (LdapServer
*) fi
->book
;
531 ldapsvr_set_modified(server
, TRUE
);
532 ldapsvr_update_book(server
, person
);
533 if (server
->retVal
!= LDAPRC_SUCCESS
) {
534 alertpanel( _("Add address(es)"),
535 _("Can't add the specified address"),
536 GTK_STOCK_CLOSE
, NULL
, NULL
);
537 return server
->retVal
;
541 g_free(returned_name
);
542 g_free(returned_remarks
);
543 #ifndef USE_ALT_ADDRBOOK
544 if( person
) retVal
= TRUE
;
549 gtk_cmclist_clear( GTK_CMCLIST( addressadd_dlg
.tree_folder
) );