Add capability to account protocol to override wizard response
[modest] / src / modest-account-protocol.c
1 /* Copyright (c) 2008, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <tny-simple-list.h>
31 #include "modest-account-protocol.h"
32 #include "modest-account-mgr-helpers.h"
33 #include "widgets/modest-default-account-settings-dialog.h"
34 #include "modest-runtime.h"
35
36 enum {
37         PROP_0,
38         PROP_PORT,
39         PROP_ALTERNATE_PORT,
40         PROP_ACCOUNT_G_TYPE,
41 };
42
43 typedef struct _ModestAccountProtocolPrivate ModestAccountProtocolPrivate;
44 struct _ModestAccountProtocolPrivate {
45         guint port;
46         guint alternate_port;
47         TnyList *account_options;
48         GHashTable *custom_auth_mechs;
49         GType account_g_type;
50
51         GHashTable *account_dialogs;
52 };
53
54 /* 'private'/'protected' functions */
55 static void   modest_account_protocol_class_init (ModestAccountProtocolClass *klass);
56 static void   modest_account_protocol_finalize   (GObject *obj);
57 static void   modest_account_protocol_get_property (GObject *obj,
58                                             guint property_id,
59                                             GValue *value,
60                                             GParamSpec *pspec);
61 static void   modest_account_protocol_set_property (GObject *obj,
62                                             guint property_id,
63                                             const GValue *value,
64                                             GParamSpec *pspec);
65 static void   modest_account_protocol_instance_init (ModestAccountProtocol *obj);
66
67 #define MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
68                                                                                  MODEST_TYPE_ACCOUNT_PROTOCOL, \
69                                                                                  ModestAccountProtocolPrivate))
70
71 static TnyAccount *modest_account_protocol_create_account_default (ModestAccountProtocol *self);
72
73 static ModestAccountSettingsDialog *modest_account_protocol_create_account_settings_dialog_default (ModestAccountProtocol *self);
74
75 static ModestPairList* modest_account_protocol_get_easysetupwizard_tabs_default (ModestAccountProtocol *self);
76
77 static void modest_account_protocol_save_settings_default (ModestAccountProtocol *self, 
78                                                            ModestAccountSettingsDialog *dialog,
79                                                            ModestAccountSettings *settings);
80
81 static void modest_account_protocol_save_wizard_settings_default (ModestAccountProtocol *self, 
82                                                                   GList *wizard_pages,
83                                                                   ModestAccountSettings *settings);
84
85 static ModestWizardDialogResponseOverrideFunc 
86 modest_account_protocol_get_wizard_response_override_default (ModestAccountProtocol *self);
87
88 /* globals */
89 static GObjectClass *parent_class = NULL;
90
91 GType
92 modest_account_protocol_get_type (void)
93 {
94         static GType my_type = 0;
95
96         if (!my_type) {
97                 static const GTypeInfo my_info = {
98                         sizeof(ModestAccountProtocolClass),
99                         NULL,   /* base init */
100                         NULL,   /* base finalize */
101                         (GClassInitFunc) modest_account_protocol_class_init,
102                         NULL,   /* class finalize */
103                         NULL,   /* class data */
104                         sizeof(ModestAccountProtocol),
105                         0,      /* n_preallocs */
106                         (GInstanceInitFunc) modest_account_protocol_instance_init,
107                         NULL
108                 };
109
110                 my_type = g_type_register_static (MODEST_TYPE_PROTOCOL,
111                                                   "ModestAccountProtocol",
112                                                   &my_info, 0);
113         }
114         return my_type;
115 }
116
117 static void
118 modest_account_protocol_class_init (ModestAccountProtocolClass *klass)
119 {
120         GObjectClass *object_class;
121         ModestAccountProtocolClass *account_class;
122
123         object_class = (GObjectClass *) klass;
124         account_class = MODEST_ACCOUNT_PROTOCOL_CLASS (klass);
125         parent_class = g_type_class_peek_parent (klass);
126         object_class->finalize = modest_account_protocol_finalize;
127         object_class->set_property = modest_account_protocol_set_property;
128         object_class->get_property = modest_account_protocol_get_property;
129
130         g_object_class_install_property (object_class,
131                                          PROP_PORT,
132                                          g_param_spec_uint ("port",
133                                                            _("Standard port"),
134                                                            _("The standard port for the protocol"),
135                                                            0, G_MAXINT, 0,
136                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
137
138         g_object_class_install_property (object_class,
139                                          PROP_ALTERNATE_PORT,
140                                          g_param_spec_uint ("alternate-port",
141                                                            _("Alternate port"),
142                                                            _("The alternate port for the protocol (usually used in SSL)"),
143                                                            0, G_MAXINT, 0,
144                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
145
146         g_object_class_install_property (object_class,
147                                          PROP_ACCOUNT_G_TYPE,
148                                          g_param_spec_gtype ("account-g-type",
149                                                              _("Account factory GType"),
150                                                              _("Account factory GType used for creating new instances."),
151                                                              TNY_TYPE_ACCOUNT,
152                                                              G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
153
154         g_type_class_add_private (object_class,
155                                   sizeof(ModestAccountProtocolPrivate));
156
157         /* Virtual methods */
158         account_class->create_account_settings_dialog = 
159                 modest_account_protocol_create_account_settings_dialog_default;
160         account_class->get_easysetupwizard_tabs = 
161                 modest_account_protocol_get_easysetupwizard_tabs_default;
162         account_class->save_settings = 
163                 modest_account_protocol_save_settings_default;
164         account_class->save_wizard_settings = 
165                 modest_account_protocol_save_wizard_settings_default;
166         account_class->create_account =
167                 modest_account_protocol_create_account_default;
168         account_class->get_wizard_response_override =
169                 modest_account_protocol_get_wizard_response_override_default;
170 }
171
172 static void
173 modest_account_protocol_instance_init (ModestAccountProtocol *obj)
174 {
175         ModestAccountProtocolPrivate *priv;
176
177         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (obj);
178
179         priv->port = 0;
180         priv->alternate_port = 0;
181         priv->account_g_type = 0;
182         priv->account_options = tny_simple_list_new ();
183         priv->custom_auth_mechs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
184
185         priv->account_dialogs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
186 }
187
188 static gboolean
189 remove_account (const gchar *account_name, GObject *account, GObject *account_to_remove)
190 {
191         return (account == account_to_remove);
192 }
193
194 static void
195 account_dialog_weak_handler (ModestAccountProtocol *self, GObject *where_the_object_was)
196 {
197         ModestAccountProtocolPrivate *priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
198
199         g_hash_table_foreach_remove (priv->account_dialogs, (GHRFunc) remove_account, where_the_object_was);
200 }
201
202 static gboolean
203 dialogs_remove (const gchar *account_name, GObject *account_dialog, ModestAccountProtocol *self)
204 {
205         g_object_weak_unref (account_dialog, (GWeakNotify) account_dialog_weak_handler, self);
206
207         return TRUE;
208 }
209
210 static void   
211 modest_account_protocol_finalize   (GObject *obj)
212 {
213         ModestAccountProtocol *protocol = MODEST_ACCOUNT_PROTOCOL (obj);
214         ModestAccountProtocolPrivate *priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (protocol);
215
216         if (priv->account_dialogs) {
217                 g_hash_table_foreach_remove (priv->account_dialogs, (GHRFunc) dialogs_remove, obj);
218                 g_hash_table_destroy (priv->account_dialogs);
219         }
220
221         if (priv->account_options)
222                 g_object_unref (priv->account_options);
223         priv->account_options = NULL;
224
225         if (priv->custom_auth_mechs)
226                 g_hash_table_destroy (priv->custom_auth_mechs);
227         priv->custom_auth_mechs = NULL;
228
229         G_OBJECT_CLASS (parent_class)->finalize (obj);
230 }
231
232 static void   
233 modest_account_protocol_get_property (GObject *obj,
234                                       guint property_id,
235                                       GValue *value,
236                                       GParamSpec *pspec)
237 {
238         ModestAccountProtocol *protocol = MODEST_ACCOUNT_PROTOCOL (obj);
239         ModestAccountProtocolPrivate *priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (protocol);
240
241         switch (property_id) {
242         case PROP_PORT:
243                 g_value_set_uint (value, priv->port);
244                 break;
245         case PROP_ALTERNATE_PORT:
246                 g_value_set_uint (value, priv->alternate_port);
247                 break;
248         case PROP_ACCOUNT_G_TYPE:
249                 g_value_set_gtype (value, priv->account_g_type);
250                 break;
251         default:
252                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
253         }
254
255 }
256
257 static void   
258 modest_account_protocol_set_property (GObject *obj,
259                                       guint property_id,
260                                       const GValue *value,
261                                       GParamSpec *pspec)
262 {
263         ModestAccountProtocol *protocol = MODEST_ACCOUNT_PROTOCOL (obj);
264
265         switch (property_id) {
266         case PROP_PORT:
267                 modest_account_protocol_set_port (protocol, g_value_get_uint (value));
268                 break;
269         case PROP_ALTERNATE_PORT:
270                 modest_account_protocol_set_alternate_port (protocol, g_value_get_uint (value));
271                 break;
272         case PROP_ACCOUNT_G_TYPE:
273                 modest_account_protocol_set_account_g_type (protocol, g_value_get_gtype (value));
274                 break;
275         default:
276                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
277         }
278
279 }
280
281
282 ModestProtocol*
283 modest_account_protocol_new (const gchar *name, const gchar *display_name,
284                              guint port, guint alternate_port,
285                              GType account_g_type)
286 {
287         return g_object_new (MODEST_TYPE_ACCOUNT_PROTOCOL, 
288                              "display-name", display_name, "name", name, 
289                              "port", port, "alternate-port", alternate_port,
290                              "account-g-type", account_g_type,
291                              NULL);
292 }
293
294 guint
295 modest_account_protocol_get_port (ModestAccountProtocol *self)
296 {
297         ModestAccountProtocolPrivate *priv;
298
299         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), 0);
300
301         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
302         return priv->port;
303 }
304
305 void         
306 modest_account_protocol_set_port (ModestAccountProtocol *self,
307                                   guint port)
308 {
309         ModestAccountProtocolPrivate *priv;
310
311         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
312
313         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
314         priv->port = port;
315 }
316
317
318 guint
319 modest_account_protocol_get_alternate_port (ModestAccountProtocol *self)
320 {
321         ModestAccountProtocolPrivate *priv;
322
323         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), 0);
324
325         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
326         return priv->alternate_port;
327 }
328
329 void         
330 modest_account_protocol_set_alternate_port (ModestAccountProtocol *self,
331                                             guint alternate_port)
332 {
333         ModestAccountProtocolPrivate *priv;
334
335         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
336
337         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
338         priv->alternate_port = alternate_port;
339 }
340
341 GType
342 modest_account_protocol_get_account_g_type (ModestAccountProtocol *self)
343 {
344         ModestAccountProtocolPrivate *priv;
345
346         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), 0);
347
348         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
349         return priv->account_g_type;
350 }
351
352 TnyList *
353 modest_account_protocol_get_account_options (ModestAccountProtocol *self)
354 {
355         TnyList *result;
356         ModestAccountProtocolPrivate *priv;
357
358         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
359         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
360
361         result = tny_list_copy (priv->account_options);
362
363         return result;
364 }
365
366 void
367 modest_account_protocol_set_account_options (ModestAccountProtocol *self,
368                                              TnyList *list)
369 {
370         ModestAccountProtocolPrivate *priv;
371
372         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
373         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
374
375         if (priv->account_options) {
376                 g_object_unref (priv->account_options);
377                 priv->account_options = NULL;
378         }
379         priv->account_options = tny_list_copy (list);
380 }
381
382 gboolean
383 modest_account_protocol_has_custom_secure_auth_mech (ModestAccountProtocol *self, 
384                                                      ModestProtocolType auth_protocol_type)
385 {
386         ModestAccountProtocolPrivate *priv;
387
388         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), FALSE);
389         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
390
391         return g_hash_table_lookup_extended (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type), NULL, NULL);
392 }
393
394 const gchar *
395 modest_account_protocol_get_custom_secure_auth_mech (ModestAccountProtocol *self, 
396                                                      ModestProtocolType auth_protocol_type)
397 {
398         ModestAccountProtocolPrivate *priv;
399
400         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
401         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
402
403         return (const gchar *) g_hash_table_lookup (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type));
404 }
405
406 void
407 modest_account_protocol_set_custom_secure_auth_mech (ModestAccountProtocol *self, ModestProtocolType auth_protocol_type, const gchar *secure_auth_mech)
408 {
409         ModestAccountProtocolPrivate *priv;
410
411         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
412         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
413
414         g_hash_table_replace (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type), g_strdup (secure_auth_mech));
415 }
416
417 void
418 modest_account_protocol_unset_custom_secure_auth_mech (ModestAccountProtocol *self, ModestProtocolType auth_protocol_type)
419 {
420         ModestAccountProtocolPrivate *priv;
421
422         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
423         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
424
425         g_hash_table_remove (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type));
426 }
427
428
429 void         
430 modest_account_protocol_set_account_g_type (ModestAccountProtocol *self,
431                                             GType account_g_type)
432 {
433         ModestAccountProtocolPrivate *priv;
434
435         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
436
437         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
438         priv->account_g_type = account_g_type;
439 }
440
441 static TnyAccount *
442 modest_account_protocol_create_account_default (ModestAccountProtocol *self)
443 {
444         ModestAccountProtocolPrivate *priv;
445
446         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
447
448         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
449         if (priv->account_g_type > 0) {
450                 return g_object_new (priv->account_g_type, NULL);
451         } else {
452                 return NULL;
453         }
454 }
455
456 TnyAccount *
457 modest_account_protocol_create_account (ModestAccountProtocol *self)
458 {
459         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
460
461         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->create_account (self); 
462 }
463
464 /* This is a template method for getting the account settings
465    dialog. It calls create_account_settings that must be implemented
466    by subclasses and then perform several common operations with the
467    dialog */
468 ModestAccountSettingsDialog *
469 modest_account_protocol_get_account_settings_dialog (ModestAccountProtocol *self,
470                                                      const gchar *account_name)
471 {
472         ModestAccountSettingsDialog *dialog;
473         ModestAccountSettings *settings;
474         ModestAccountProtocolPrivate *priv;
475
476         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
477         dialog = g_hash_table_lookup (priv->account_dialogs, account_name);
478
479         if (dialog == NULL) {
480
481                 dialog = MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->create_account_settings_dialog (self);
482         
483                 /* Load settings */
484                 settings = modest_account_mgr_load_account_settings (modest_runtime_get_account_mgr (), 
485                                                                      account_name);
486                 modest_account_settings_dialog_load_settings (dialog, settings);
487         
488                 /* Close dialog on response */
489                 g_signal_connect_swapped (dialog,
490                                           "response",
491                                           G_CALLBACK (gtk_widget_destroy),
492                                           dialog);
493
494                 g_hash_table_insert (priv->account_dialogs, g_strdup (account_name), dialog);
495                 g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) account_dialog_weak_handler, self);
496         }
497
498         return dialog;
499 }
500
501 ModestPairList*
502 modest_account_protocol_get_easysetupwizard_tabs (ModestAccountProtocol *self)
503 {
504         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->get_easysetupwizard_tabs (self);
505 }
506
507
508 void 
509 modest_account_protocol_save_settings (ModestAccountProtocol *self, 
510                                        ModestAccountSettingsDialog *dialog,
511                                        ModestAccountSettings *settings)
512 {
513         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->save_settings (self, dialog, settings);
514 }
515
516 void 
517 modest_account_protocol_save_wizard_settings (ModestAccountProtocol *self, 
518                                               GList *wizard_pages,
519                                               ModestAccountSettings *settings)
520 {
521         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->save_wizard_settings (self, wizard_pages, settings);
522 }
523
524 /* Default implementations */
525 static ModestAccountSettingsDialog *
526 modest_account_protocol_create_account_settings_dialog_default (ModestAccountProtocol *self)
527 {
528         return modest_default_account_settings_dialog_new ();
529 }
530
531 static ModestPairList*
532 modest_account_protocol_get_easysetupwizard_tabs_default (ModestAccountProtocol *self)
533 {
534         g_warning ("You must implement get_easysetupwizard_tabs");
535         return NULL;
536 }
537
538 static void 
539 modest_account_protocol_save_settings_default (ModestAccountProtocol *self, 
540                                                ModestAccountSettingsDialog *dialog,
541                                                ModestAccountSettings *settings)
542 {
543         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
544         g_return_if_fail (MODEST_IS_ACCOUNT_SETTINGS_DIALOG (dialog));
545         g_return_if_fail (MODEST_IS_ACCOUNT_SETTINGS (settings));
546
547         g_warning ("You must implement save_settings");
548 }
549
550 static void 
551 modest_account_protocol_save_wizard_settings_default (ModestAccountProtocol *self, 
552                                                       GList *wizard_pages,
553                                                       ModestAccountSettings *settings)
554 {
555         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
556         g_return_if_fail (wizard_pages);
557         g_return_if_fail (MODEST_IS_ACCOUNT_SETTINGS (settings));
558
559         g_warning ("You must implement save_wizard_settings");
560 }
561
562 static ModestWizardDialogResponseOverrideFunc
563 modest_account_protocol_get_wizard_response_override_default (ModestAccountProtocol *self)
564 {
565         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
566
567         return NULL;
568 }
569
570 ModestWizardDialogResponseOverrideFunc
571 modest_account_protocol_get_wizard_response_override (ModestAccountProtocol *self)
572 {
573         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
574
575         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->get_wizard_response_override (self);   
576 }
577