Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / libedataserverui / e-book-auth-util.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* e-book-auth-util.c - Lame helper to load addressbooks with authentication.
4  *
5  * Copyright (C) 2005 Novell, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * Authors: Hans Petter Jansson <hpj@novell.com>
22  *
23  * Mostly taken from Evolution's addressbook/gui/component/addressbook.c
24  */
25
26 #include <config.h>
27 #include <string.h>
28 #include <gtk/gtkmessagedialog.h>
29 #include <glib/gi18n-lib.h>
30 #include <libebook/e-book.h>
31 #include <libedataserverui/e-passwords.h>
32 #include "libedataserver/e-url.h"
33 #include "e-book-auth-util.h"
34
35 static void addressbook_authenticate (EBook *book, gboolean previous_failure,
36                                       ESource *source, EBookCallback cb, gpointer closure);
37 static void auth_required_cb (EBook *book, gpointer data);
38 typedef struct {
39         ESource       *source;
40         EBook         *book;
41
42         EBookCallback  open_func;
43         gpointer       open_func_data;
44 } LoadSourceData;
45
46 static void
47 free_load_source_data (LoadSourceData *data)
48 {
49         if (data->source)
50                 g_object_unref (data->source);
51         if (data->book) {
52                 g_signal_handlers_disconnect_by_func (data->book, auth_required_cb, NULL);
53                 g_object_unref (data->book);
54         }
55         g_free (data);
56 }
57
58 static gchar *
59 remove_parameters_from_uri (const gchar *uri)
60 {
61         char *euri_str;
62         EUri *euri;
63
64         euri = e_uri_new (uri);
65         euri_str = e_uri_to_string (euri, FALSE);
66         e_uri_free (euri);
67         return euri_str;
68 }
69
70 static void
71 load_source_auth_cb (EBook *book, EBookStatus status, gpointer closure)
72 {
73         LoadSourceData *data = closure;
74
75         if (status != E_BOOK_ERROR_OK) {
76                 /* the user clicked cancel in the password dialog */
77                 if (status == E_BOOK_ERROR_CANCELLED) {
78                         if (e_book_check_static_capability (book, "anon-access")) {
79                                 GtkWidget *dialog;
80
81                                 /* XXX "LDAP" has to be removed from the folowing message
82                                    so that it wil valid for other servers which provide 
83                                    anonymous access*/
84
85                                 dialog = gtk_message_dialog_new (NULL,
86                                                                  0,
87                                                                  GTK_MESSAGE_WARNING,
88                                                                  GTK_BUTTONS_OK,
89                                                                  _("Accessing LDAP Server anonymously"));
90                                 g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
91                                 gtk_widget_show (dialog);
92                                 if (data->open_func)
93                                         data->open_func (book, E_BOOK_ERROR_OK, data->open_func_data);
94                                 free_load_source_data (data);
95                                 return;
96                         }
97                 } else if (status == E_BOOK_ERROR_INVALID_SERVER_VERSION) {
98 #if 0
99                         e_error_run (NULL, "addressbook:server-version", NULL);
100 #endif
101                         status = E_BOOK_ERROR_OK;
102                         if (data->open_func)
103                                 data->open_func (book, status, data->open_func_data);
104                         free_load_source_data (data);
105                         return;
106                 } else {
107                         const gchar *uri = e_book_get_uri (book);
108                         gchar *stripped_uri = remove_parameters_from_uri (uri);
109                         const gchar *auth_domain = e_source_get_property (data->source, "auth-domain");
110                         const gchar *component_name;
111
112                         component_name = auth_domain ? auth_domain : "Addressbook";
113
114                         e_passwords_forget_password (component_name, stripped_uri);
115                         addressbook_authenticate (book, TRUE, data->source, load_source_auth_cb, closure);
116
117                         g_free (stripped_uri);
118                        
119                         return;
120                 }
121         }
122
123         if (data->open_func)
124                 data->open_func (book, status, data->open_func_data);
125
126         free_load_source_data (data);
127 }
128
129 static gboolean
130 get_remember_password (ESource *source)
131 {
132         const gchar *value;
133
134         value = e_source_get_property (source, "remember_password");
135         if (value && !g_ascii_strcasecmp (value, "true"))
136                 return TRUE;
137
138         return FALSE;
139 }
140
141 static void
142 set_remember_password (ESource *source, gboolean value)
143 {
144         e_source_set_property (source, "remember_password",
145                                value ? "true" : "false");
146 }
147
148 static void
149 addressbook_authenticate (EBook *book, gboolean previous_failure, ESource *source,
150                           EBookCallback cb, gpointer closure)
151 {
152         const gchar *auth;
153         const gchar *user;
154         const gchar *component_name;
155         const char *password     = NULL;
156         char *pass_dup           = NULL;
157         const gchar *uri               = e_book_get_uri (book);
158         gchar *stripped_uri      = remove_parameters_from_uri (uri);
159         const gchar *auth_domain = e_source_get_property (source, "auth-domain");
160                         
161         component_name = auth_domain ? auth_domain : "Addressbook";
162         uri = stripped_uri;
163
164         password = e_passwords_get_password (component_name, uri);
165
166         auth = e_source_get_property (source, "auth");
167
168         if (auth && !strcmp ("ldap/simple-binddn", auth)) {
169                 user = e_source_get_property (source, "binddn");
170         }
171         else if (auth && !strcmp ("plain/password", auth)) {
172                 user = e_source_get_property (source, "user");
173                 if (!user) {
174                         user = e_source_get_property (source, "username");
175                 }
176         }
177         else {
178                 user = e_source_get_property (source, "email_addr");
179         }
180         if (!user)
181                 user = "";
182
183         if (!password) {
184                 char *prompt;
185                 char *password_prompt;
186                 gboolean remember;
187                 char *failed_auth;
188                 guint32 flags = E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET|E_PASSWORDS_ONLINE;
189
190                 if (previous_failure) {
191                         failed_auth = _("Failed to authenticate.\n");
192                         flags |= E_PASSWORDS_REPROMPT;
193                 }
194                 else {
195                         failed_auth = "";
196                 }
197
198                 password_prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
199                                                    e_source_peek_name (source), user);
200
201                 prompt = g_strconcat (failed_auth, password_prompt, NULL);
202                 g_free (password_prompt);
203
204                 remember = get_remember_password (source);
205                 pass_dup = e_passwords_ask_password (prompt, component_name, uri, prompt,
206                                                      flags, &remember,
207                                                      NULL);
208                 if (remember != get_remember_password (source))
209                         set_remember_password (source, remember);
210
211                 g_free (prompt);
212         }
213
214         if (password || pass_dup) {
215                 e_book_async_authenticate_user (book, user, password ? password : pass_dup,
216                                                 e_source_get_property (source, "auth"),
217                                                 cb, closure);
218                 g_free (pass_dup);
219         }
220         else {
221                 /* they hit cancel */
222                 cb (book, E_BOOK_ERROR_CANCELLED, closure);
223         }
224
225         g_free (stripped_uri);
226 }
227
228 static void
229 auth_required_cb (EBook *book, gpointer data)
230 {
231         LoadSourceData *load_source_data = g_new0 (LoadSourceData, 1);
232         
233         load_source_data->source = g_object_ref (g_object_ref (e_book_get_source (book)));
234
235         addressbook_authenticate (book, FALSE, load_source_data->source,
236                                   load_source_auth_cb, load_source_data);
237 }
238
239 static void
240 load_source_cb (EBook *book, EBookStatus status, gpointer closure)
241 {
242         LoadSourceData *load_source_data = closure;
243
244         if (status == E_BOOK_ERROR_OK && book != NULL) {
245                 const gchar *auth;
246
247                 auth = e_source_get_property (load_source_data->source, "auth");
248                 if (auth && strcmp (auth, "none")) {
249                         g_signal_connect (book, "auth_required", (GCallback) auth_required_cb, NULL);
250                         
251                         if (e_book_is_online (book)) {
252                                 addressbook_authenticate (book, FALSE, load_source_data->source,
253                                                           load_source_auth_cb, closure);
254                                 return;
255                         }
256                 }
257         }
258
259         if (load_source_data->open_func)
260                 load_source_data->open_func (book, status, load_source_data->open_func_data);
261
262         free_load_source_data (load_source_data);
263 }
264
265 /**
266  * e_load_book_source:
267  * @source: an #ESource
268  * @open_func: a function to call when the operation finishes, or %NULL
269  * @user_data: data to pass to callback function
270  *
271  * Creates a new #EBook specified by @source, and starts a non-blocking
272  * open operation on it. If the book requires authorization, presents
273  * a window asking the user for such.
274  *
275  * When the operation finishes, calls the callback function indicating
276  * if it succeeded or not. If you don't care, you can pass %NULL for
277  * @open_func, and no action will be taken on completion.
278  *
279  * Return value: A new #EBook that is being opened.
280  **/
281 EBook *
282 e_load_book_source (ESource *source, EBookCallback open_func, gpointer user_data)
283 {
284         EBook          *book;
285         LoadSourceData *load_source_data = g_new0 (LoadSourceData, 1);
286
287         load_source_data->source = g_object_ref (source);
288         load_source_data->open_func = open_func;
289         load_source_data->open_func_data = user_data;
290
291         book = e_book_new (source, NULL);
292         if (!book)
293                 return NULL;
294
295         load_source_data->book = book;
296         g_object_ref (book);
297         e_book_async_open (book, FALSE, load_source_cb, load_source_data);
298         return book;
299 }