2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2022 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/>.
20 * Add address to address book dialog.
25 #include "claws-features.h"
31 #include <glib/gi18n.h>
32 #include <gdk/gdkkeysyms.h>
36 #include "stock_pixmap.h"
37 #include "prefs_common.h"
38 #include "prefs_gtk.h"
39 #include "addressadd.h"
40 #ifndef USE_ALT_ADDRBOOK
43 #include "addrindex.h"
44 #include "ldapserver.h"
45 #include "ldapupdate.h"
47 #include "addressbook-dbus.h"
49 #include "manage_window.h"
50 #include "alertpanel.h"
52 #ifndef USE_ALT_ADDRBOOK
54 AddressBookFile
*book
;
63 static struct _AddressAdd_dlg
{
66 GtkWidget
*entry_name
;
67 GtkWidget
*label_address
;
68 GtkWidget
*entry_remarks
;
69 GtkWidget
*tree_folder
;
71 GtkWidget
*cancel_btn
;
72 FolderInfo
*fiSelected
;
75 static GdkPixbuf
*folderXpm
;
76 static GdkPixbuf
*bookXpm
;
78 static gboolean addressadd_cancelled
;
87 #ifndef USE_ALT_ADDRBOOK
88 static FolderInfo
*addressadd_create_folderinfo( AddressBookFile
*abf
, ItemFolder
*folder
)
90 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
96 static FolderInfo
*addressadd_create_folderinfo(gchar
* book
) {
97 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
103 #ifndef USE_ALT_ADDRBOOK
104 static void addressadd_free_folderinfo( FolderInfo
*fi
) {
110 static void addressadd_free_folderinfo( FolderInfo
*fi
) {
116 static gint
addressadd_delete_event( GtkWidget
*widget
, GdkEventAny
*event
, gboolean
*cancelled
) {
117 addressadd_cancelled
= TRUE
;
122 static gboolean
addressadd_key_pressed( GtkWidget
*widget
, GdkEventKey
*event
, gboolean
*cancelled
) {
123 if (event
&& event
->keyval
== GDK_KEY_Escape
) {
124 addressadd_cancelled
= TRUE
;
130 /* Points addressadd_dlg.fiSelected to the selected item */
131 static void set_selected_ptr()
133 addressadd_dlg
.fiSelected
= gtkut_tree_view_get_selected_pointer(
134 GTK_TREE_VIEW(addressadd_dlg
.tree_folder
), ADDRADD_COL_PTR
,
138 static void addressadd_ok( GtkWidget
*widget
, gboolean
*cancelled
) {
140 addressadd_cancelled
= FALSE
;
144 static void addressadd_cancel( GtkWidget
*widget
, gboolean
*cancelled
) {
146 addressadd_cancelled
= TRUE
;
150 static void addressadd_tree_row_activated(GtkTreeView
*view
,
151 GtkTreePath
*path
, GtkTreeViewColumn
*col
,
154 addressadd_ok(NULL
, NULL
);
157 static void addressadd_size_allocate_cb(GtkWidget
*widget
,
158 GtkAllocation
*allocation
)
160 cm_return_if_fail(allocation
!= NULL
);
162 gtk_window_get_size(GTK_WINDOW(widget
),
163 &prefs_common
.addressaddwin_width
, &prefs_common
.addressaddwin_height
);
166 static void addressadd_create( void ) {
168 GtkWidget
*vbox
, *hbox
;
173 GtkWidget
*entry_name
;
174 GtkWidget
*label_addr
;
175 GtkWidget
*entry_rems
;
176 GtkWidget
*tree_folder
;
181 GtkWidget
*cancel_btn
;
182 static GdkGeometry geometry
;
184 GtkTreeViewColumn
*col
;
185 GtkCellRenderer
*rdr
;
186 GtkTreeSelection
*sel
;
188 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "addressadd");
189 gtk_container_set_border_width( GTK_CONTAINER(window
), VBOX_BORDER
);
190 gtk_window_set_title( GTK_WINDOW(window
), _("Add to address book") );
191 gtk_window_set_position( GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
192 gtk_window_set_type_hint(GTK_WINDOW(window
), GDK_WINDOW_TYPE_HINT_DIALOG
);
193 g_signal_connect( G_OBJECT(window
), "delete_event",
194 G_CALLBACK(addressadd_delete_event
), NULL
);
195 g_signal_connect( G_OBJECT(window
), "key_press_event",
196 G_CALLBACK(addressadd_key_pressed
), NULL
);
197 g_signal_connect(G_OBJECT(window
), "size_allocate",
198 G_CALLBACK(addressadd_size_allocate_cb
), NULL
);
200 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 10);
201 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 4);
202 vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 8);
203 gtk_container_add(GTK_CONTAINER(window
), vbox
);
205 picture
= gtk_image_new();
206 gtk_box_pack_start(GTK_BOX(hbox
), picture
, FALSE
, FALSE
, 0);
208 table
= gtk_grid_new();
209 gtk_box_pack_start(GTK_BOX(hbox
), table
, TRUE
, TRUE
, 0);
210 gtk_grid_set_row_spacing(GTK_GRID(table
), VSPACING_NARROW
);
211 gtk_grid_set_column_spacing(GTK_GRID(table
), HSPACING_NARROW
);
213 frame
= gtk_frame_new(_("Contact"));
214 gtk_frame_set_label_align(GTK_FRAME(frame
), 0.01, 0.5);
215 gtk_container_add(GTK_CONTAINER(frame
), hbox
);
216 gtk_container_set_border_width( GTK_CONTAINER(frame
), 4);
217 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 0);
220 label
= gtk_label_new(_("Name"));
221 gtk_grid_attach(GTK_GRID(table
), label
, 0, 0, 1, 1);
222 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
224 entry_name
= gtk_entry_new();
225 gtk_widget_set_size_request(entry_name
, 150, -1);
226 gtk_entry_set_text (GTK_ENTRY(entry_name
),"");
228 gtk_grid_attach(GTK_GRID(table
), entry_name
, 1, 0, 1, 1);
229 gtk_widget_set_hexpand(entry_name
, TRUE
);
230 gtk_widget_set_halign(entry_name
, GTK_ALIGN_FILL
);
233 label
= gtk_label_new(_("Address"));
234 gtk_grid_attach(GTK_GRID(table
), label
, 0, 1, 1, 1);
235 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
237 label_addr
= gtk_label_new("");
238 gtk_widget_set_size_request(label_addr
, 150, -1);
239 gtk_grid_attach(GTK_GRID(table
), label_addr
, 1, 1, 1, 1);
240 gtk_label_set_xalign(GTK_LABEL(label_addr
), 0.0);
243 label
= gtk_label_new(_("Remarks"));
244 gtk_grid_attach(GTK_GRID(table
), label
, 0, 2, 1, 1);
245 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
247 entry_rems
= gtk_entry_new();
248 gtk_widget_set_size_request(entry_rems
, 150, -1);
249 gtk_grid_attach(GTK_GRID(table
), entry_rems
, 1, 2, 1, 1);
250 gtk_widget_set_hexpand(entry_rems
, TRUE
);
251 gtk_widget_set_halign(entry_rems
, GTK_ALIGN_FILL
);
253 /* Address book/folder tree */
254 vlbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, VBOX_BORDER
);
255 gtk_box_pack_start(GTK_BOX(vbox
), vlbox
, TRUE
, TRUE
, 0);
256 gtk_container_set_border_width( GTK_CONTAINER(vlbox
), 4);
258 tree_win
= gtk_scrolled_window_new( NULL
, NULL
);
259 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win
),
260 GTK_POLICY_AUTOMATIC
,
261 GTK_POLICY_AUTOMATIC
);
262 gtk_box_pack_start( GTK_BOX(vlbox
), tree_win
, TRUE
, TRUE
, 0 );
264 store
= gtk_tree_store_new(N_ADDRADD_COLS
,
265 GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_POINTER
);
267 tree_folder
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
268 g_object_unref(store
);
269 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store
), ADDRADD_COL_NAME
, GTK_SORT_ASCENDING
);
270 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_folder
), prefs_common
.use_stripes_everywhere
);
271 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_folder
), TRUE
);
272 gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(tree_folder
), FALSE
);
273 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree_folder
),
276 /* Column with addressbook/folder icon and name. It has two
277 * renderers, so we create it a bit differently. */
278 col
= gtk_tree_view_column_new();
279 rdr
= gtk_cell_renderer_pixbuf_new();
280 gtk_cell_renderer_set_padding(rdr
, 0, 0);
281 gtk_tree_view_column_pack_start(col
, rdr
, FALSE
);
282 gtk_tree_view_column_set_attributes(col
, rdr
,
283 "pixbuf", ADDRADD_COL_ICON
, NULL
);
284 rdr
= gtk_cell_renderer_text_new();
285 gtk_tree_view_column_pack_start(col
, rdr
, TRUE
);
286 gtk_tree_view_column_set_attributes(col
, rdr
,
287 "markup", ADDRADD_COL_NAME
, NULL
);
288 gtk_tree_view_column_set_title(col
, _("Select Address Book Folder"));
289 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_folder
), col
);
291 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_folder
));
292 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_BROWSE
);
294 gtk_container_add( GTK_CONTAINER(tree_win
), tree_folder
);
296 g_signal_connect(G_OBJECT(tree_folder
), "row-activated",
297 G_CALLBACK(addressadd_tree_row_activated
), NULL
);
300 gtkut_stock_button_set_create(&hbbox
, &cancel_btn
, NULL
, _("_Cancel"),
301 &ok_btn
, NULL
, _("_OK"),
303 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
304 gtk_container_set_border_width( GTK_CONTAINER(hbbox
), HSPACING_NARROW
);
305 gtk_widget_grab_default(ok_btn
);
307 g_signal_connect(G_OBJECT(ok_btn
), "clicked",
308 G_CALLBACK(addressadd_ok
), NULL
);
309 g_signal_connect(G_OBJECT(cancel_btn
), "clicked",
310 G_CALLBACK(addressadd_cancel
), NULL
);
312 if (!geometry
.min_height
) {
313 geometry
.min_width
= 300;
314 geometry
.min_height
= 350;
317 gtk_window_set_geometry_hints(GTK_WINDOW(window
), NULL
, &geometry
,
319 gtk_window_set_default_size(GTK_WINDOW(window
),
320 prefs_common
.addressaddwin_width
,
321 prefs_common
.addressaddwin_height
);
323 addressadd_dlg
.window
= window
;
324 addressadd_dlg
.picture
= picture
;
325 addressadd_dlg
.entry_name
= entry_name
;
326 addressadd_dlg
.label_address
= label_addr
;
327 addressadd_dlg
.entry_remarks
= entry_rems
;
328 addressadd_dlg
.tree_folder
= tree_folder
;
329 addressadd_dlg
.ok_btn
= ok_btn
;
330 addressadd_dlg
.cancel_btn
= cancel_btn
;
332 gtk_widget_show_all( window
);
334 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK
, &bookXpm
);
335 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderXpm
);
338 /* Helper function used by addressadd_tree_clear(). */
339 static gboolean
close_dialog_foreach_func(GtkTreeModel
*model
,
346 gtk_tree_model_get(model
, iter
, ADDRADD_COL_PTR
, &fi
, -1);
348 addressadd_free_folderinfo(fi
);
350 gtk_tree_store_set(GTK_TREE_STORE(model
), iter
, ADDRADD_COL_PTR
, NULL
, -1);
354 /* Function to remove all rows from the tree view, and free the
355 * FolderInfo pointers in them in pointer column. */
356 static void addressadd_tree_clear()
358 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
359 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
361 gtk_tree_model_foreach(model
, close_dialog_foreach_func
, NULL
);
362 gtk_tree_store_clear(GTK_TREE_STORE(model
));
365 #ifndef USE_ALT_ADDRBOOK
366 static void addressadd_load_folder( GtkTreeIter
*parent_iter
,
367 ItemFolder
*parentFolder
, FolderInfo
*fiParent
)
369 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
371 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
377 list
= parentFolder
!= NULL
? parentFolder
->listFolder
: NULL
;
380 name
= g_strdup( ADDRITEM_NAME(folder
) );
381 fi
= addressadd_create_folderinfo( fiParent
->book
, folder
);
383 gtk_tree_store_append(GTK_TREE_STORE(model
), &iter
, parent_iter
);
384 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
,
385 ADDRADD_COL_ICON
, folderXpm
,
386 ADDRADD_COL_NAME
, name
,
391 addressadd_load_folder( parent_iter
, folder
, fi
);
393 list
= g_list_next( list
);
397 static void addressadd_load_data( AddressIndex
*addrIndex
) {
398 AddressDataSource
*ds
;
399 GList
*list
, *nodeDS
;
401 ItemFolder
*rootFolder
;
402 AddressBookFile
*abf
;
404 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
406 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
407 GtkTreeSelection
*sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(view
));
409 addressadd_tree_clear();
411 list
= addrindex_get_interface_list( addrIndex
);
413 AddressInterface
*ainterface
= list
->data
;
414 if( ainterface
->type
== ADDR_IF_BOOK
||
415 ainterface
->type
== ADDR_IF_LDAP
) {
416 nodeDS
= ainterface
->listSource
;
419 name
= g_strdup( addrindex_ds_get_name( ds
) );
421 /* Read address book */
422 if( ! addrindex_ds_get_read_flag( ds
) ) {
423 addrindex_ds_read_data( ds
);
426 /* Add node for address book */
427 abf
= ds
->rawDataSource
;
428 fi
= addressadd_create_folderinfo( abf
, NULL
);
430 gtk_tree_store_append(GTK_TREE_STORE(model
), &iter
, NULL
);
431 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
,
432 ADDRADD_COL_ICON
, bookXpm
,
433 ADDRADD_COL_NAME
, name
,
438 rootFolder
= addrindex_ds_get_root_folder( ds
);
439 addressadd_load_folder( &iter
, rootFolder
, fi
);
441 nodeDS
= g_list_next( nodeDS
);
444 list
= g_list_next( list
);
447 if (gtk_tree_model_get_iter_first(model
, &iter
))
448 gtk_tree_selection_select_iter(sel
, &iter
);
451 static void addressadd_load_data() {
453 FolderInfo
*fi
= NULL
;
454 GError
* error
= NULL
;
455 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
457 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
458 GtkTreeSelection
*sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(view
));
461 addressadd_tree_clear();
463 list
= addressbook_dbus_get_books(&error
);
464 for (; list
; list
= g_slist_next(list
)) {
465 name
= (gchar
*) list
->data
;
466 fi
= addressadd_create_folderinfo(name
);
467 gtk_tree_store_append(GTK_TREE_STORE(model
), &iter
, NULL
);
468 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
,
469 ADDRADD_COL_ICON
, bookXpm
,ADDRADD_COL_NAME
, (gchar
*)list
->data
,
474 if (gtk_tree_model_get_iter_first(model
, &iter
))
475 gtk_tree_selection_select_iter(sel
, &iter
);
479 #ifndef USE_ALT_ADDRBOOK
480 gboolean
addressadd_selection( AddressIndex
*addrIndex
, const gchar
*name
,
481 const gchar
*address
, const gchar
*remarks
, GdkPixbuf
*picture
) {
483 gboolean
addressadd_selection(const gchar
*name
, const gchar
*address
,
484 const gchar
*remarks
, GdkPixbuf
*picture
) {
486 gboolean retVal
= FALSE
;
487 #ifndef USE_ALT_ADDRBOOK
488 ItemPerson
*person
= NULL
;
490 FolderInfo
*fi
= NULL
;
491 addressadd_cancelled
= FALSE
;
493 if( ! addressadd_dlg
.window
) addressadd_create();
495 addressadd_dlg
.fiSelected
= NULL
;
496 #ifndef USE_ALT_ADDRBOOK
497 addressadd_load_data( addrIndex
);
499 addressadd_load_data();
501 gtk_widget_show(addressadd_dlg
.window
);
502 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), TRUE
);
503 gtk_widget_grab_focus(addressadd_dlg
.ok_btn
);
505 manage_window_set_transient(GTK_WINDOW(addressadd_dlg
.window
));
507 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), "" );
508 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), "" );
509 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), "" );
511 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), name
);
513 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), address
);
515 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), remarks
);
517 gtk_image_set_from_pixbuf(GTK_IMAGE(addressadd_dlg
.picture
), picture
);
518 gtk_widget_show(GTK_WIDGET(addressadd_dlg
.picture
));
520 gtk_widget_hide(GTK_WIDGET(addressadd_dlg
.picture
));
523 gtk_widget_hide( addressadd_dlg
.window
);
524 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), FALSE
);
525 if( ! addressadd_cancelled
) {
526 if( addressadd_dlg
.fiSelected
) {
527 gchar
*returned_name
;
528 gchar
*returned_remarks
;
529 returned_name
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_name
), 0, -1 );
530 returned_remarks
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_remarks
), 0, -1 );
532 fi
= addressadd_dlg
.fiSelected
;
534 #ifndef USE_ALT_ADDRBOOK
535 person
= addrbook_add_contact( fi
->book
, fi
->folder
,
540 if (person
!= NULL
) {
541 person
->status
= ADD_ENTRY
;
544 GError
*error
= NULL
;
545 gchar
*name
= g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S
, ADDRBOOK_DIR
, G_DIR_SEPARATOR_S
,
546 ADDRITEM_ID(person
), ".png", NULL
);
547 gdk_pixbuf_save(picture
, name
, "png", &error
, NULL
);
549 g_warning("failed to save image: %s", error
->message
);
552 addritem_person_set_picture( person
, ADDRITEM_ID(person
) ) ;
557 ContactData
* contact
= g_new0(ContactData
, 1);
558 GError
* error
= NULL
;
561 contact
->cn
= g_strdup(returned_name
);
563 contact
->cn
= g_strdup(address
);
565 contact
->name
= g_strdup(returned_name
);
566 contact
->email
= g_strdup(address
);
567 contact
->remarks
= g_strdup(returned_remarks
);
568 contact
->book
= g_strdup(fi
->book
);
569 contact
->picture
= picture
;
571 if (addressbook_dbus_add_contact(contact
, &error
) == 0) {
572 debug_print("Added to addressbook:\n%s\n%s\n%s\n%s\n",
573 returned_name
, address
, returned_remarks
, fi
->book
);
579 GtkWidget
* dialog
= gtk_message_dialog_new (
580 GTK_WINDOW(addressadd_dlg
.window
),
581 GTK_DIALOG_DESTROY_WITH_PARENT
,
584 "%s", error
->message
);
585 gtk_dialog_run (GTK_DIALOG (dialog
));
586 gtk_widget_destroy (dialog
);
590 contact_data_free(&contact
);
593 if (person
!= NULL
&& fi
->book
->type
== ADBOOKTYPE_LDAP
) {
594 LdapServer
*server
= (LdapServer
*) fi
->book
;
595 ldapsvr_set_modified(server
, TRUE
);
596 ldapsvr_update_book(server
, person
);
597 if (server
->retVal
!= LDAPRC_SUCCESS
) {
598 alertpanel( _("Add address(es)"),
599 _("Can't add the specified address"),
600 "window-close", _("_Close"), NULL
, NULL
,
601 NULL
, NULL
, ALERTFOCUS_FIRST
);
602 return server
->retVal
;
606 g_free(returned_name
);
607 g_free(returned_remarks
);
608 #ifndef USE_ALT_ADDRBOOK
609 if( person
) retVal
= TRUE
;
614 addressadd_tree_clear();