* Fixes NB#100026, show new email notifications in order
[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 /* globals */
86 static GObjectClass *parent_class = NULL;
87
88 GType
89 modest_account_protocol_get_type (void)
90 {
91         static GType my_type = 0;
92
93         if (!my_type) {
94                 static const GTypeInfo my_info = {
95                         sizeof(ModestAccountProtocolClass),
96                         NULL,   /* base init */
97                         NULL,   /* base finalize */
98                         (GClassInitFunc) modest_account_protocol_class_init,
99                         NULL,   /* class finalize */
100                         NULL,   /* class data */
101                         sizeof(ModestAccountProtocol),
102                         0,      /* n_preallocs */
103                         (GInstanceInitFunc) modest_account_protocol_instance_init,
104                         NULL
105                 };
106
107                 my_type = g_type_register_static (MODEST_TYPE_PROTOCOL,
108                                                   "ModestAccountProtocol",
109                                                   &my_info, 0);
110         }
111         return my_type;
112 }
113
114 static void
115 modest_account_protocol_class_init (ModestAccountProtocolClass *klass)
116 {
117         GObjectClass *object_class;
118         ModestAccountProtocolClass *account_class;
119
120         object_class = (GObjectClass *) klass;
121         account_class = MODEST_ACCOUNT_PROTOCOL_CLASS (klass);
122         parent_class = g_type_class_peek_parent (klass);
123         object_class->finalize = modest_account_protocol_finalize;
124         object_class->set_property = modest_account_protocol_set_property;
125         object_class->get_property = modest_account_protocol_get_property;
126
127         g_object_class_install_property (object_class,
128                                          PROP_PORT,
129                                          g_param_spec_uint ("port",
130                                                            _("Standard port"),
131                                                            _("The standard port for the protocol"),
132                                                            0, G_MAXINT, 0,
133                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
134
135         g_object_class_install_property (object_class,
136                                          PROP_ALTERNATE_PORT,
137                                          g_param_spec_uint ("alternate-port",
138                                                            _("Alternate port"),
139                                                            _("The alternate port for the protocol (usually used in SSL)"),
140                                                            0, G_MAXINT, 0,
141                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
142
143         g_object_class_install_property (object_class,
144                                          PROP_ACCOUNT_G_TYPE,
145                                          g_param_spec_gtype ("account-g-type",
146                                                              _("Account factory GType"),
147                                                              _("Account factory GType used for creating new instances."),
148                                                              TNY_TYPE_ACCOUNT,
149                                                              G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
150
151         g_type_class_add_private (object_class,
152                                   sizeof(ModestAccountProtocolPrivate));
153
154         /* Virtual methods */
155         account_class->create_account_settings_dialog = 
156                 modest_account_protocol_create_account_settings_dialog_default;
157         account_class->get_easysetupwizard_tabs = 
158                 modest_account_protocol_get_easysetupwizard_tabs_default;
159         account_class->save_settings = 
160                 modest_account_protocol_save_settings_default;
161         account_class->save_wizard_settings = 
162                 modest_account_protocol_save_wizard_settings_default;
163         account_class->create_account =
164                 modest_account_protocol_create_account_default;
165 }
166
167 static void
168 modest_account_protocol_instance_init (ModestAccountProtocol *obj)
169 {
170         ModestAccountProtocolPrivate *priv;
171
172         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (obj);
173
174         priv->port = 0;
175         priv->alternate_port = 0;
176         priv->account_g_type = 0;
177         priv->account_options = tny_simple_list_new ();
178         priv->custom_auth_mechs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
179
180         priv->account_dialogs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
181 }
182
183 static gboolean
184 remove_account (const gchar *account_name, GObject *account, GObject *account_to_remove)
185 {
186         return (account == account_to_remove);
187 }
188
189 static void
190 account_dialog_weak_handler (ModestAccountProtocol *self, GObject *where_the_object_was)
191 {
192         ModestAccountProtocolPrivate *priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
193
194         g_hash_table_foreach_remove (priv->account_dialogs, (GHRFunc) remove_account, where_the_object_was);
195 }
196
197 static gboolean
198 dialogs_remove (const gchar *account_name, GObject *account_dialog, ModestAccountProtocol *self)
199 {
200         g_object_weak_unref (account_dialog, (GWeakNotify) account_dialog_weak_handler, self);
201
202         return TRUE;
203 }
204
205 static void   
206 modest_account_protocol_finalize   (GObject *obj)
207 {
208         ModestAccountProtocol *protocol = MODEST_ACCOUNT_PROTOCOL (obj);
209         ModestAccountProtocolPrivate *priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (protocol);
210
211         if (priv->account_dialogs) {
212                 g_hash_table_foreach_remove (priv->account_dialogs, (GHRFunc) dialogs_remove, obj);
213                 g_hash_table_destroy (priv->account_dialogs);
214         }
215
216         if (priv->account_options)
217                 g_object_unref (priv->account_options);
218         priv->account_options = NULL;
219
220         if (priv->custom_auth_mechs)
221                 g_hash_table_destroy (priv->custom_auth_mechs);
222         priv->custom_auth_mechs = NULL;
223
224         G_OBJECT_CLASS (parent_class)->finalize (obj);
225 }
226
227 static void   
228 modest_account_protocol_get_property (GObject *obj,
229                                       guint property_id,
230                                       GValue *value,
231                                       GParamSpec *pspec)
232 {
233         ModestAccountProtocol *protocol = MODEST_ACCOUNT_PROTOCOL (obj);
234         ModestAccountProtocolPrivate *priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (protocol);
235
236         switch (property_id) {
237         case PROP_PORT:
238                 g_value_set_uint (value, priv->port);
239                 break;
240         case PROP_ALTERNATE_PORT:
241                 g_value_set_uint (value, priv->alternate_port);
242                 break;
243         case PROP_ACCOUNT_G_TYPE:
244                 g_value_set_gtype (value, priv->account_g_type);
245                 break;
246         default:
247                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
248         }
249
250 }
251
252 static void   
253 modest_account_protocol_set_property (GObject *obj,
254                                       guint property_id,
255                                       const GValue *value,
256                                       GParamSpec *pspec)
257 {
258         ModestAccountProtocol *protocol = MODEST_ACCOUNT_PROTOCOL (obj);
259
260         switch (property_id) {
261         case PROP_PORT:
262                 modest_account_protocol_set_port (protocol, g_value_get_uint (value));
263                 break;
264         case PROP_ALTERNATE_PORT:
265                 modest_account_protocol_set_alternate_port (protocol, g_value_get_uint (value));
266                 break;
267         case PROP_ACCOUNT_G_TYPE:
268                 modest_account_protocol_set_account_g_type (protocol, g_value_get_gtype (value));
269                 break;
270         default:
271                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
272         }
273
274 }
275
276
277 ModestProtocol*
278 modest_account_protocol_new (const gchar *name, const gchar *display_name,
279                              guint port, guint alternate_port,
280                              GType account_g_type)
281 {
282         return g_object_new (MODEST_TYPE_ACCOUNT_PROTOCOL, 
283                              "display-name", display_name, "name", name, 
284                              "port", port, "alternate-port", alternate_port,
285                              "account-g-type", account_g_type,
286                              NULL);
287 }
288
289 guint
290 modest_account_protocol_get_port (ModestAccountProtocol *self)
291 {
292         ModestAccountProtocolPrivate *priv;
293
294         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), 0);
295
296         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
297         return priv->port;
298 }
299
300 void         
301 modest_account_protocol_set_port (ModestAccountProtocol *self,
302                                   guint port)
303 {
304         ModestAccountProtocolPrivate *priv;
305
306         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
307
308         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
309         priv->port = port;
310 }
311
312
313 guint
314 modest_account_protocol_get_alternate_port (ModestAccountProtocol *self)
315 {
316         ModestAccountProtocolPrivate *priv;
317
318         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), 0);
319
320         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
321         return priv->alternate_port;
322 }
323
324 void         
325 modest_account_protocol_set_alternate_port (ModestAccountProtocol *self,
326                                             guint alternate_port)
327 {
328         ModestAccountProtocolPrivate *priv;
329
330         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
331
332         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
333         priv->alternate_port = alternate_port;
334 }
335
336 GType
337 modest_account_protocol_get_account_g_type (ModestAccountProtocol *self)
338 {
339         ModestAccountProtocolPrivate *priv;
340
341         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), 0);
342
343         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
344         return priv->account_g_type;
345 }
346
347 TnyList *
348 modest_account_protocol_get_account_options (ModestAccountProtocol *self)
349 {
350         TnyList *result;
351         ModestAccountProtocolPrivate *priv;
352
353         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
354         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
355
356         result = tny_list_copy (priv->account_options);
357
358         return result;
359 }
360
361 void
362 modest_account_protocol_set_account_options (ModestAccountProtocol *self,
363                                              TnyList *list)
364 {
365         ModestAccountProtocolPrivate *priv;
366
367         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
368         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
369
370         if (priv->account_options) {
371                 g_object_unref (priv->account_options);
372                 priv->account_options = NULL;
373         }
374         priv->account_options = tny_list_copy (list);
375 }
376
377 gboolean
378 modest_account_protocol_has_custom_secure_auth_mech (ModestAccountProtocol *self, 
379                                                      ModestProtocolType auth_protocol_type)
380 {
381         ModestAccountProtocolPrivate *priv;
382
383         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), FALSE);
384         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
385
386         return g_hash_table_lookup_extended (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type), NULL, NULL);
387 }
388
389 const gchar *
390 modest_account_protocol_get_custom_secure_auth_mech (ModestAccountProtocol *self, 
391                                                      ModestProtocolType auth_protocol_type)
392 {
393         ModestAccountProtocolPrivate *priv;
394
395         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
396         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
397
398         return (const gchar *) g_hash_table_lookup (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type));
399 }
400
401 void
402 modest_account_protocol_set_custom_secure_auth_mech (ModestAccountProtocol *self, ModestProtocolType auth_protocol_type, const gchar *secure_auth_mech)
403 {
404         ModestAccountProtocolPrivate *priv;
405
406         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
407         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
408
409         g_hash_table_replace (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type), g_strdup (secure_auth_mech));
410 }
411
412 void
413 modest_account_protocol_unset_custom_secure_auth_mech (ModestAccountProtocol *self, ModestProtocolType auth_protocol_type)
414 {
415         ModestAccountProtocolPrivate *priv;
416
417         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
418         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);      
419
420         g_hash_table_remove (priv->custom_auth_mechs, GINT_TO_POINTER (auth_protocol_type));
421 }
422
423
424 void         
425 modest_account_protocol_set_account_g_type (ModestAccountProtocol *self,
426                                             GType account_g_type)
427 {
428         ModestAccountProtocolPrivate *priv;
429
430         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
431
432         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
433         priv->account_g_type = account_g_type;
434 }
435
436 static TnyAccount *
437 modest_account_protocol_create_account_default (ModestAccountProtocol *self)
438 {
439         ModestAccountProtocolPrivate *priv;
440
441         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
442
443         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
444         if (priv->account_g_type > 0) {
445                 return g_object_new (priv->account_g_type, NULL);
446         } else {
447                 return NULL;
448         }
449 }
450
451 TnyAccount *
452 modest_account_protocol_create_account (ModestAccountProtocol *self)
453 {
454         g_return_val_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self), NULL);
455
456         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->create_account (self); 
457 }
458
459 /* This is a template method for getting the account settings
460    dialog. It calls create_account_settings that must be implemented
461    by subclasses and then perform several common operations with the
462    dialog */
463 ModestAccountSettingsDialog *
464 modest_account_protocol_get_account_settings_dialog (ModestAccountProtocol *self,
465                                                      const gchar *account_name)
466 {
467         ModestAccountSettingsDialog *dialog;
468         ModestAccountSettings *settings;
469         ModestAccountProtocolPrivate *priv;
470
471         priv = MODEST_ACCOUNT_PROTOCOL_GET_PRIVATE (self);
472         dialog = g_hash_table_lookup (priv->account_dialogs, account_name);
473
474         if (dialog == NULL) {
475
476                 dialog = MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->create_account_settings_dialog (self);
477         
478                 /* Load settings */
479                 settings = modest_account_mgr_load_account_settings (modest_runtime_get_account_mgr (), 
480                                                                      account_name);
481                 modest_account_settings_dialog_load_settings (dialog, settings);
482         
483                 /* Close dialog on response */
484                 g_signal_connect_swapped (dialog,
485                                           "response",
486                                           G_CALLBACK (gtk_widget_destroy),
487                                           dialog);
488
489                 g_hash_table_insert (priv->account_dialogs, g_strdup (account_name), dialog);
490                 g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) account_dialog_weak_handler, self);
491         }
492
493         return dialog;
494 }
495
496 ModestPairList*
497 modest_account_protocol_get_easysetupwizard_tabs (ModestAccountProtocol *self)
498 {
499         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->get_easysetupwizard_tabs (self);
500 }
501
502
503 void 
504 modest_account_protocol_save_settings (ModestAccountProtocol *self, 
505                                        ModestAccountSettingsDialog *dialog,
506                                        ModestAccountSettings *settings)
507 {
508         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->save_settings (self, dialog, settings);
509 }
510
511 void 
512 modest_account_protocol_save_wizard_settings (ModestAccountProtocol *self, 
513                                               GList *wizard_pages,
514                                               ModestAccountSettings *settings)
515 {
516         return MODEST_ACCOUNT_PROTOCOL_GET_CLASS (self)->save_wizard_settings (self, wizard_pages, settings);
517 }
518
519 /* Default implementations */
520 static ModestAccountSettingsDialog *
521 modest_account_protocol_create_account_settings_dialog_default (ModestAccountProtocol *self)
522 {
523         return modest_default_account_settings_dialog_new ();
524 }
525
526 static ModestPairList*
527 modest_account_protocol_get_easysetupwizard_tabs_default (ModestAccountProtocol *self)
528 {
529         g_warning ("You must implement get_easysetupwizard_tabs");
530         return NULL;
531 }
532
533 static void 
534 modest_account_protocol_save_settings_default (ModestAccountProtocol *self, 
535                                                ModestAccountSettingsDialog *dialog,
536                                                ModestAccountSettings *settings)
537 {
538         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
539         g_return_if_fail (MODEST_IS_ACCOUNT_SETTINGS_DIALOG (dialog));
540         g_return_if_fail (MODEST_IS_ACCOUNT_SETTINGS (settings));
541
542         g_warning ("You must implement save_settings");
543 }
544
545 static void 
546 modest_account_protocol_save_wizard_settings_default (ModestAccountProtocol *self, 
547                                                       GList *wizard_pages,
548                                                       ModestAccountSettings *settings)
549 {
550         g_return_if_fail (MODEST_IS_ACCOUNT_PROTOCOL (self));
551         g_return_if_fail (wizard_pages);
552         g_return_if_fail (MODEST_IS_ACCOUNT_SETTINGS (settings));
553
554         g_warning ("You must implement save_wizard_settings");
555 }