Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[platform/upstream/evolution-data-server.git] / camel / camel-cipher-context.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6  *
7  * This program 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 program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28
29 #include <glib/gi18n-lib.h>
30
31 #include "camel-cipher-context.h"
32 #include "camel-debug.h"
33 #include "camel-session.h"
34 #include "camel-stream.h"
35 #include "camel-operation.h"
36
37 #include "camel-mime-utils.h"
38 #include "camel-medium.h"
39 #include "camel-multipart.h"
40 #include "camel-multipart-encrypted.h"
41 #include "camel-multipart-signed.h"
42 #include "camel-mime-message.h"
43 #include "camel-mime-filter-canon.h"
44 #include "camel-stream-filter.h"
45
46 #define CAMEL_CIPHER_CONTEXT_GET_PRIVATE(obj) \
47         (G_TYPE_INSTANCE_GET_PRIVATE \
48         ((obj), CAMEL_TYPE_CIPHER_CONTEXT, CamelCipherContextPrivate))
49
50 #define CIPHER_LOCK(ctx) \
51         g_mutex_lock (&((CamelCipherContext *) ctx)->priv->lock)
52 #define CIPHER_UNLOCK(ctx) \
53         g_mutex_unlock (&((CamelCipherContext *) ctx)->priv->lock);
54
55 #define d(x)
56
57 typedef struct _AsyncContext AsyncContext;
58
59 struct _CamelCipherContextPrivate {
60         CamelSession *session;
61         GMutex lock;
62 };
63
64 struct _AsyncContext {
65         /* arguments */
66         CamelCipherHash hash;
67         CamelMimePart *ipart;
68         CamelMimePart *opart;
69         CamelStream *stream;
70         GPtrArray *strings;
71         gchar *userid;
72
73         /* results */
74         CamelCipherValidity *validity;
75 };
76
77 enum {
78         PROP_0,
79         PROP_SESSION
80 };
81
82 G_DEFINE_TYPE (CamelCipherContext, camel_cipher_context, CAMEL_TYPE_OBJECT)
83
84 static void
85 async_context_free (AsyncContext *async_context)
86 {
87         if (async_context->ipart != NULL)
88                 g_object_unref (async_context->ipart);
89
90         if (async_context->opart != NULL)
91                 g_object_unref (async_context->opart);
92
93         if (async_context->stream != NULL)
94                 g_object_unref (async_context->stream);
95
96         if (async_context->strings != NULL) {
97                 g_ptr_array_foreach (
98                         async_context->strings, (GFunc) g_free, NULL);
99                 g_ptr_array_free (async_context->strings, TRUE);
100         }
101
102         if (async_context->validity != NULL)
103                 camel_cipher_validity_free (async_context->validity);
104
105         g_free (async_context->userid);
106
107         g_slice_free (AsyncContext, async_context);
108 }
109
110 static void
111 cipher_context_set_session (CamelCipherContext *context,
112                             CamelSession *session)
113 {
114         g_return_if_fail (CAMEL_IS_SESSION (session));
115         g_return_if_fail (context->priv->session == NULL);
116
117         context->priv->session = g_object_ref (session);
118 }
119
120 static void
121 cipher_context_set_property (GObject *object,
122                              guint property_id,
123                              const GValue *value,
124                              GParamSpec *pspec)
125 {
126         switch (property_id) {
127                 case PROP_SESSION:
128                         cipher_context_set_session (
129                                 CAMEL_CIPHER_CONTEXT (object),
130                                 g_value_get_object (value));
131                         return;
132         }
133
134         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
135 }
136
137 static void
138 cipher_context_get_property (GObject *object,
139                              guint property_id,
140                              GValue *value,
141                              GParamSpec *pspec)
142 {
143         switch (property_id) {
144                 case PROP_SESSION:
145                         g_value_set_object (
146                                 value, camel_cipher_context_get_session (
147                                 CAMEL_CIPHER_CONTEXT (object)));
148                         return;
149         }
150
151         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
152 }
153
154 static void
155 cipher_context_dispose (GObject *object)
156 {
157         CamelCipherContextPrivate *priv;
158
159         priv = CAMEL_CIPHER_CONTEXT_GET_PRIVATE (object);
160
161         if (priv->session != NULL) {
162                 g_object_unref (priv->session);
163                 priv->session = NULL;
164         }
165
166         /* Chain up to parent's dispose () method. */
167         G_OBJECT_CLASS (camel_cipher_context_parent_class)->dispose (object);
168 }
169
170 static void
171 cipher_context_finalize (GObject *object)
172 {
173         CamelCipherContextPrivate *priv;
174
175         priv = CAMEL_CIPHER_CONTEXT_GET_PRIVATE (object);
176
177         g_mutex_clear (&priv->lock);
178
179         /* Chain up to parent's finalize () method. */
180         G_OBJECT_CLASS (camel_cipher_context_parent_class)->finalize (object);
181 }
182
183 static const gchar *
184 cipher_context_hash_to_id (CamelCipherContext *context,
185                            CamelCipherHash hash)
186 {
187         return NULL;
188 }
189
190 static CamelCipherHash
191 cipher_context_id_to_hash (CamelCipherContext *context,
192                            const gchar *id)
193 {
194         return CAMEL_CIPHER_HASH_DEFAULT;
195 }
196
197 static gboolean
198 cipher_context_sign_sync (CamelCipherContext *ctx,
199                           const gchar *userid,
200                           CamelCipherHash hash,
201                           CamelMimePart *ipart,
202                           CamelMimePart *opart,
203                           GCancellable *cancellable,
204                           GError **error)
205 {
206         g_set_error (
207                 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
208                 _("Signing is not supported by this cipher"));
209
210         return FALSE;
211 }
212
213 static CamelCipherValidity *
214 cipher_context_verify_sync (CamelCipherContext *context,
215                             CamelMimePart *sigpart,
216                             GCancellable *cancellable,
217                             GError **error)
218 {
219         g_set_error (
220                 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
221                 _("Verifying is not supported by this cipher"));
222
223         return NULL;
224 }
225
226 static gboolean
227 cipher_context_encrypt_sync (CamelCipherContext *context,
228                              const gchar *userid,
229                              GPtrArray *recipients,
230                              CamelMimePart *ipart,
231                              CamelMimePart *opart,
232                              GCancellable *cancellable,
233                              GError **error)
234 {
235         g_set_error (
236                 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
237                 _("Encryption is not supported by this cipher"));
238
239         return FALSE;
240 }
241
242 static CamelCipherValidity *
243 cipher_context_decrypt_sync (CamelCipherContext *context,
244                              CamelMimePart *ipart,
245                              CamelMimePart *opart,
246                              GCancellable *cancellable,
247                              GError **error)
248 {
249         g_set_error (
250                 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
251                 _("Decryption is not supported by this cipher"));
252
253         return NULL;
254 }
255
256 static gboolean
257 cipher_context_import_keys_sync (CamelCipherContext *context,
258                                  CamelStream *istream,
259                                  GCancellable *cancellable,
260                                  GError **error)
261 {
262         g_set_error (
263                 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
264                 _("You may not import keys with this cipher"));
265
266         return FALSE;
267 }
268
269 static gint
270 cipher_context_export_keys_sync (CamelCipherContext *context,
271                                  GPtrArray *keys,
272                                  CamelStream *ostream,
273                                  GCancellable *cancellable,
274                                  GError **error)
275 {
276         g_set_error (
277                 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
278                 _("You may not export keys with this cipher"));
279
280         return FALSE;
281 }
282
283 static void
284 cipher_context_sign_thread (GSimpleAsyncResult *simple,
285                             GObject *object,
286                             GCancellable *cancellable)
287 {
288         AsyncContext *async_context;
289         GError *error = NULL;
290
291         async_context = g_simple_async_result_get_op_res_gpointer (simple);
292
293         camel_cipher_context_sign_sync (
294                 CAMEL_CIPHER_CONTEXT (object),
295                 async_context->userid, async_context->hash,
296                 async_context->ipart, async_context->opart,
297                 cancellable, &error);
298
299         if (error != NULL)
300                 g_simple_async_result_take_error (simple, error);
301 }
302
303 static void
304 cipher_context_sign (CamelCipherContext *context,
305                      const gchar *userid,
306                      CamelCipherHash hash,
307                      CamelMimePart *ipart,
308                      CamelMimePart *opart,
309                      gint io_priority,
310                      GCancellable *cancellable,
311                      GAsyncReadyCallback callback,
312                      gpointer user_data)
313 {
314         GSimpleAsyncResult *simple;
315         AsyncContext *async_context;
316
317         async_context = g_slice_new0 (AsyncContext);
318         async_context->userid = g_strdup (userid);
319         async_context->hash = hash;
320         async_context->ipart = g_object_ref (ipart);
321         async_context->opart = g_object_ref (opart);
322
323         simple = g_simple_async_result_new (
324                 G_OBJECT (context), callback, user_data, cipher_context_sign);
325
326         g_simple_async_result_set_check_cancellable (simple, cancellable);
327
328         g_simple_async_result_set_op_res_gpointer (
329                 simple, async_context, (GDestroyNotify) async_context_free);
330
331         g_simple_async_result_run_in_thread (
332                 simple, cipher_context_sign_thread, io_priority, cancellable);
333
334         g_object_unref (simple);
335 }
336
337 static gboolean
338 cipher_context_sign_finish (CamelCipherContext *context,
339                             GAsyncResult *result,
340                             GError **error)
341 {
342         GSimpleAsyncResult *simple;
343
344         g_return_val_if_fail (
345                 g_simple_async_result_is_valid (
346                 result, G_OBJECT (context), cipher_context_sign), FALSE);
347
348         simple = G_SIMPLE_ASYNC_RESULT (result);
349
350         /* Assume success unless a GError is set. */
351         return !g_simple_async_result_propagate_error (simple, error);
352 }
353
354 static void
355 cipher_context_verify_thread (GSimpleAsyncResult *simple,
356                               GObject *object,
357                               GCancellable *cancellable)
358 {
359         AsyncContext *async_context;
360         GError *error = NULL;
361
362         async_context = g_simple_async_result_get_op_res_gpointer (simple);
363
364         async_context->validity = camel_cipher_context_verify_sync (
365                 CAMEL_CIPHER_CONTEXT (object), async_context->ipart,
366                 cancellable, &error);
367
368         if (error != NULL)
369                 g_simple_async_result_take_error (simple, error);
370 }
371
372 static void
373 cipher_context_verify (CamelCipherContext *context,
374                        CamelMimePart *ipart,
375                        gint io_priority,
376                        GCancellable *cancellable,
377                        GAsyncReadyCallback callback,
378                        gpointer user_data)
379 {
380         GSimpleAsyncResult *simple;
381         AsyncContext *async_context;
382
383         async_context = g_slice_new0 (AsyncContext);
384         async_context->ipart = g_object_ref (ipart);
385
386         simple = g_simple_async_result_new (
387                 G_OBJECT (context), callback,
388                 user_data, cipher_context_verify);
389
390         g_simple_async_result_set_check_cancellable (simple, cancellable);
391
392         g_simple_async_result_set_op_res_gpointer (
393                 simple, async_context, (GDestroyNotify) async_context_free);
394
395         g_simple_async_result_run_in_thread (
396                 simple, cipher_context_verify_thread,
397                 io_priority, cancellable);
398
399         g_object_unref (simple);
400 }
401
402 static CamelCipherValidity *
403 cipher_context_verify_finish (CamelCipherContext *context,
404                               GAsyncResult *result,
405                               GError **error)
406 {
407         GSimpleAsyncResult *simple;
408         AsyncContext *async_context;
409         CamelCipherValidity *validity;
410
411         g_return_val_if_fail (
412                 g_simple_async_result_is_valid (
413                 result, G_OBJECT (context), cipher_context_verify), NULL);
414
415         simple = G_SIMPLE_ASYNC_RESULT (result);
416         async_context = g_simple_async_result_get_op_res_gpointer (simple);
417
418         if (g_simple_async_result_propagate_error (simple, error))
419                 return NULL;
420
421         validity = async_context->validity;
422         async_context->validity = NULL;
423
424         return validity;
425 }
426
427 static void
428 cipher_context_encrypt_thread (GSimpleAsyncResult *simple,
429                                GObject *object,
430                                GCancellable *cancellable)
431 {
432         AsyncContext *async_context;
433         GError *error = NULL;
434
435         async_context = g_simple_async_result_get_op_res_gpointer (simple);
436
437         camel_cipher_context_encrypt_sync (
438                 CAMEL_CIPHER_CONTEXT (object),
439                 async_context->userid, async_context->strings,
440                 async_context->ipart, async_context->opart,
441                 cancellable, &error);
442
443         if (error != NULL)
444                 g_simple_async_result_take_error (simple, error);
445 }
446
447 static void
448 cipher_context_encrypt (CamelCipherContext *context,
449                         const gchar *userid,
450                         GPtrArray *recipients,
451                         CamelMimePart *ipart,
452                         CamelMimePart *opart,
453                         gint io_priority,
454                         GCancellable *cancellable,
455                         GAsyncReadyCallback callback,
456                         gpointer user_data)
457 {
458         GSimpleAsyncResult *simple;
459         AsyncContext *async_context;
460         guint ii;
461
462         async_context = g_slice_new0 (AsyncContext);
463         async_context->userid = g_strdup (userid);
464         async_context->strings = g_ptr_array_new ();
465         async_context->ipart = g_object_ref (ipart);
466         async_context->opart = g_object_ref (opart);
467
468         for (ii = 0; ii < recipients->len; ii++)
469                 g_ptr_array_add (
470                         async_context->strings,
471                         g_strdup (recipients->pdata[ii]));
472
473         simple = g_simple_async_result_new (
474                 G_OBJECT (context), callback,
475                 user_data, cipher_context_encrypt);
476
477         g_simple_async_result_set_check_cancellable (simple, cancellable);
478
479         g_simple_async_result_set_op_res_gpointer (
480                 simple, async_context, (GDestroyNotify) async_context_free);
481
482         g_simple_async_result_run_in_thread (
483                 simple, cipher_context_encrypt_thread,
484                 io_priority, cancellable);
485
486         g_object_unref (simple);
487 }
488
489 static gboolean
490 cipher_context_encrypt_finish (CamelCipherContext *context,
491                                GAsyncResult *result,
492                                GError **error)
493 {
494         GSimpleAsyncResult *simple;
495
496         g_return_val_if_fail (
497                 g_simple_async_result_is_valid (
498                 result, G_OBJECT (context), cipher_context_encrypt), FALSE);
499
500         simple = G_SIMPLE_ASYNC_RESULT (result);
501
502         /* Assume success unless a GError is set. */
503         return !g_simple_async_result_propagate_error (simple, error);
504 }
505
506 static void
507 cipher_context_decrypt_thread (GSimpleAsyncResult *simple,
508                                GObject *object,
509                                GCancellable *cancellable)
510 {
511         AsyncContext *async_context;
512         GError *error = NULL;
513
514         async_context = g_simple_async_result_get_op_res_gpointer (simple);
515
516         async_context->validity = camel_cipher_context_decrypt_sync (
517                 CAMEL_CIPHER_CONTEXT (object), async_context->ipart,
518                 async_context->opart, cancellable, &error);
519
520         if (error != NULL)
521                 g_simple_async_result_take_error (simple, error);
522 }
523
524 static void
525 cipher_context_decrypt (CamelCipherContext *context,
526                         CamelMimePart *ipart,
527                         CamelMimePart *opart,
528                         gint io_priority,
529                         GCancellable *cancellable,
530                         GAsyncReadyCallback callback,
531                         gpointer user_data)
532 {
533         GSimpleAsyncResult *simple;
534         AsyncContext *async_context;
535
536         async_context = g_slice_new0 (AsyncContext);
537         async_context->ipart = g_object_ref (ipart);
538         async_context->opart = g_object_ref (opart);
539
540         simple = g_simple_async_result_new (
541                 G_OBJECT (context), callback,
542                 user_data, cipher_context_decrypt);
543
544         g_simple_async_result_set_check_cancellable (simple, cancellable);
545
546         g_simple_async_result_set_op_res_gpointer (
547                 simple, async_context, (GDestroyNotify) async_context_free);
548
549         g_simple_async_result_run_in_thread (
550                 simple, cipher_context_decrypt_thread,
551                 io_priority, cancellable);
552
553         g_object_unref (simple);
554 }
555
556 static CamelCipherValidity *
557 cipher_context_decrypt_finish (CamelCipherContext *context,
558                                GAsyncResult *result,
559                                GError **error)
560 {
561         GSimpleAsyncResult *simple;
562         AsyncContext *async_context;
563         CamelCipherValidity *validity;
564
565         g_return_val_if_fail (
566                 g_simple_async_result_is_valid (
567                 result, G_OBJECT (context), cipher_context_decrypt), NULL);
568
569         simple = G_SIMPLE_ASYNC_RESULT (result);
570         async_context = g_simple_async_result_get_op_res_gpointer (simple);
571
572         if (g_simple_async_result_propagate_error (simple, error))
573                 return NULL;
574
575         validity = async_context->validity;
576         async_context->validity = NULL;
577
578         return validity;
579 }
580
581 static void
582 cipher_context_import_keys_thread (GSimpleAsyncResult *simple,
583                                    GObject *object,
584                                    GCancellable *cancellable)
585 {
586         AsyncContext *async_context;
587         GError *error = NULL;
588
589         async_context = g_simple_async_result_get_op_res_gpointer (simple);
590
591         camel_cipher_context_import_keys_sync (
592                 CAMEL_CIPHER_CONTEXT (object), async_context->stream,
593                 cancellable, &error);
594
595         if (error != NULL)
596                 g_simple_async_result_take_error (simple, error);
597 }
598
599 static void
600 cipher_context_import_keys (CamelCipherContext *context,
601                             CamelStream *istream,
602                             gint io_priority,
603                             GCancellable *cancellable,
604                             GAsyncReadyCallback callback,
605                             gpointer user_data)
606 {
607         GSimpleAsyncResult *simple;
608         AsyncContext *async_context;
609
610         async_context = g_slice_new0 (AsyncContext);
611         async_context->stream = g_object_ref (istream);
612
613         simple = g_simple_async_result_new (
614                 G_OBJECT (context), callback,
615                 user_data, cipher_context_import_keys);
616
617         g_simple_async_result_set_check_cancellable (simple, cancellable);
618
619         g_simple_async_result_set_op_res_gpointer (
620                 simple, async_context, (GDestroyNotify) async_context_free);
621
622         g_simple_async_result_run_in_thread (
623                 simple, cipher_context_import_keys_thread,
624                 io_priority, cancellable);
625
626         g_object_unref (simple);
627 }
628
629 static gboolean
630 cipher_context_import_keys_finish (CamelCipherContext *context,
631                                    GAsyncResult *result,
632                                    GError **error)
633 {
634         GSimpleAsyncResult *simple;
635
636         g_return_val_if_fail (
637                 g_simple_async_result_is_valid (
638                 result, G_OBJECT (context),
639                 cipher_context_import_keys), FALSE);
640
641         simple = G_SIMPLE_ASYNC_RESULT (result);
642
643         /* Assume success unless a GError is set. */
644         return !g_simple_async_result_propagate_error (simple, error);
645 }
646
647 static void
648 cipher_context_export_keys_thread (GSimpleAsyncResult *simple,
649                                    GObject *object,
650                                    GCancellable *cancellable)
651 {
652         AsyncContext *async_context;
653         GError *error = NULL;
654
655         async_context = g_simple_async_result_get_op_res_gpointer (simple);
656
657         camel_cipher_context_export_keys_sync (
658                 CAMEL_CIPHER_CONTEXT (object), async_context->strings,
659                 async_context->stream, cancellable, &error);
660
661         if (error != NULL)
662                 g_simple_async_result_take_error (simple, error);
663 }
664
665 static void
666 cipher_context_export_keys (CamelCipherContext *context,
667                             GPtrArray *keys,
668                             CamelStream *ostream,
669                             gint io_priority,
670                             GCancellable *cancellable,
671                             GAsyncReadyCallback callback,
672                             gpointer user_data)
673 {
674         GSimpleAsyncResult *simple;
675         AsyncContext *async_context;
676         guint ii;
677
678         async_context = g_slice_new0 (AsyncContext);
679         async_context->strings = g_ptr_array_new ();
680         async_context->stream = g_object_ref (ostream);
681
682         for (ii = 0; ii < keys->len; ii++)
683                 g_ptr_array_add (
684                         async_context->strings,
685                         g_strdup (keys->pdata[ii]));
686
687         simple = g_simple_async_result_new (
688                 G_OBJECT (context), callback,
689                 user_data, cipher_context_export_keys);
690
691         g_simple_async_result_set_check_cancellable (simple, cancellable);
692
693         g_simple_async_result_set_op_res_gpointer (
694                 simple, async_context, (GDestroyNotify) async_context_free);
695
696         g_simple_async_result_run_in_thread (
697                 simple, cipher_context_export_keys_thread,
698                 io_priority, cancellable);
699
700         g_object_unref (simple);
701 }
702
703 static gboolean
704 cipher_context_export_keys_finish (CamelCipherContext *context,
705                                    GAsyncResult *result,
706                                    GError **error)
707 {
708         GSimpleAsyncResult *simple;
709
710         g_return_val_if_fail (
711                 g_simple_async_result_is_valid (
712                 result, G_OBJECT (context),
713                 cipher_context_export_keys), FALSE);
714
715         simple = G_SIMPLE_ASYNC_RESULT (result);
716
717         /* Assume success unless a GError is set. */
718         return !g_simple_async_result_propagate_error (simple, error);
719 }
720
721 static void
722 camel_cipher_context_class_init (CamelCipherContextClass *class)
723 {
724         GObjectClass *object_class;
725
726         g_type_class_add_private (class, sizeof (CamelCipherContextPrivate));
727
728         object_class = G_OBJECT_CLASS (class);
729         object_class->set_property = cipher_context_set_property;
730         object_class->get_property = cipher_context_get_property;
731         object_class->dispose = cipher_context_dispose;
732         object_class->finalize = cipher_context_finalize;
733
734         class->hash_to_id = cipher_context_hash_to_id;
735         class->id_to_hash = cipher_context_id_to_hash;
736
737         class->sign_sync = cipher_context_sign_sync;
738         class->verify_sync = cipher_context_verify_sync;
739         class->encrypt_sync = cipher_context_encrypt_sync;
740         class->decrypt_sync = cipher_context_decrypt_sync;
741         class->import_keys_sync = cipher_context_import_keys_sync;
742         class->export_keys_sync = cipher_context_export_keys_sync;
743
744         class->sign = cipher_context_sign;
745         class->sign_finish = cipher_context_sign_finish;
746         class->verify = cipher_context_verify;
747         class->verify_finish = cipher_context_verify_finish;
748         class->encrypt = cipher_context_encrypt;
749         class->encrypt_finish = cipher_context_encrypt_finish;
750         class->decrypt = cipher_context_decrypt;
751         class->decrypt_finish = cipher_context_decrypt_finish;
752         class->import_keys = cipher_context_import_keys;
753         class->import_keys_finish = cipher_context_import_keys_finish;
754         class->export_keys = cipher_context_export_keys;
755         class->export_keys_finish = cipher_context_export_keys_finish;
756
757         g_object_class_install_property (
758                 object_class,
759                 PROP_SESSION,
760                 g_param_spec_object (
761                         "session",
762                         "Session",
763                         NULL,
764                         CAMEL_TYPE_SESSION,
765                         G_PARAM_READWRITE |
766                         G_PARAM_CONSTRUCT_ONLY));
767 }
768
769 static void
770 camel_cipher_context_init (CamelCipherContext *context)
771 {
772         context->priv = CAMEL_CIPHER_CONTEXT_GET_PRIVATE (context);
773         g_mutex_init (&context->priv->lock);
774 }
775
776 /**
777  * camel_cipher_context_sign_sync:
778  * @context: a #CamelCipherContext
779  * @userid: a private key to use to sign the stream
780  * @hash: preferred Message-Integrity-Check hash algorithm
781  * @ipart: input #CamelMimePart
782  * @opart: output #CamelMimePart
783  * @cancellable: optional #GCancellable object, or %NULL
784  * @error: return location for a #GError, or %NULL
785  *
786  * Converts the (unsigned) part @ipart into a new self-contained MIME
787  * part @opart.  This may be a multipart/signed part, or a simple part
788  * for enveloped types.
789  *
790  * Returns: %TRUE on success, %FALSE on error
791  *
792  * Since: 3.0
793  **/
794 gboolean
795 camel_cipher_context_sign_sync (CamelCipherContext *context,
796                                 const gchar *userid,
797                                 CamelCipherHash hash,
798                                 CamelMimePart *ipart,
799                                 CamelMimePart *opart,
800                                 GCancellable *cancellable,
801                                 GError **error)
802 {
803         CamelCipherContextClass *class;
804         gboolean success;
805
806         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
807
808         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
809         g_return_val_if_fail (class->sign_sync != NULL, FALSE);
810
811         CIPHER_LOCK (context);
812
813         /* Check for cancellation after locking. */
814         if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
815                 CIPHER_UNLOCK (context);
816                 return FALSE;
817         }
818
819         camel_operation_push_message (cancellable, _("Signing message"));
820
821         success = class->sign_sync (
822                 context, userid, hash, ipart, opart, cancellable, error);
823         CAMEL_CHECK_GERROR (context, sign_sync, success, error);
824
825         camel_operation_pop_message (cancellable);
826
827         CIPHER_UNLOCK (context);
828
829         return success;
830 }
831
832 /**
833  * camel_cipher_context_sign:
834  * @context: a #CamelCipherContext
835  * @userid: a private key to use to sign the stream
836  * @hash: preferred Message-Integrity-Check hash algorithm
837  * @ipart: input #CamelMimePart
838  * @opart: output #CamelMimePart
839  * @io_priority: the I/O priority of the request
840  * @cancellable: optional #GCancellable object, or %NULL
841  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
842  * @user_data: data to pass to the callback function
843  *
844  * Asynchronously converts the (unsigned) part @ipart into a new
845  * self-contained MIME part @opart.  This may be a multipart/signed part,
846  * or a simple part for enveloped types.
847  *
848  * When the operation is finished, @callback will be called.  You can then
849  * call camel_cipher_context_sign_finish() to get the result of the operation.
850  *
851  * Since: 3.0
852  **/
853 void
854 camel_cipher_context_sign (CamelCipherContext *context,
855                            const gchar *userid,
856                            CamelCipherHash hash,
857                            CamelMimePart *ipart,
858                            CamelMimePart *opart,
859                            gint io_priority,
860                            GCancellable *cancellable,
861                            GAsyncReadyCallback callback,
862                            gpointer user_data)
863 {
864         CamelCipherContextClass *class;
865
866         g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
867
868         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
869         g_return_if_fail (class->sign != NULL);
870
871         class->sign (
872                 context, userid, hash, ipart, opart, io_priority,
873                 cancellable, callback, user_data);
874 }
875
876 /**
877  * camel_cipher_context_sign_finish:
878  * @context: a #CamelCipherContext
879  * @result: a #GAsyncResult
880  * @error: return location for a #GError, or %NULL
881  *
882  * Finishes the operation started with camel_cipher_context_sign().
883  *
884  * Returns: %TRUE on success, %FALSE on error
885  *
886  * Since: 3.0
887  **/
888 gboolean
889 camel_cipher_context_sign_finish (CamelCipherContext *context,
890                                   GAsyncResult *result,
891                                   GError **error)
892 {
893         CamelCipherContextClass *class;
894
895         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
896         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
897
898         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
899         g_return_val_if_fail (class->sign_finish != NULL, FALSE);
900
901         return class->sign_finish (context, result, error);
902 }
903
904 /**
905  * camel_cipher_context_verify_sync:
906  * @context: a #CamelCipherContext
907  * @ipart: the #CamelMimePart to verify
908  * @cancellable: optional #GCancellable object, or %NULL
909  * @error: return location for a #GError, or %NULL
910  *
911  * Verifies the signature.
912  *
913  * Returns: a #CamelCipherValidity structure containing information
914  * about the integrity of the input stream, or %NULL on failure to
915  * execute at all
916  **/
917 CamelCipherValidity *
918 camel_cipher_context_verify_sync (CamelCipherContext *context,
919                                   CamelMimePart *ipart,
920                                   GCancellable *cancellable,
921                                   GError **error)
922 {
923         CamelCipherContextClass *class;
924         CamelCipherValidity *valid;
925
926         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
927         g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), NULL);
928
929         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
930         g_return_val_if_fail (class->verify_sync != NULL, NULL);
931
932         CIPHER_LOCK (context);
933
934         /* Check for cancellation after locking. */
935         if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
936                 CIPHER_UNLOCK (context);
937                 return NULL;
938         }
939
940         valid = class->verify_sync (context, ipart, cancellable, error);
941         CAMEL_CHECK_GERROR (context, verify_sync, valid != NULL, error);
942
943         CIPHER_UNLOCK (context);
944
945         return valid;
946 }
947
948 /**
949  * camel_cipher_context_verify:
950  * @context: a #CamelCipherContext
951  * @ipart: the #CamelMimePart to verify
952  * @io_priority: the I/O priority of the request
953  * @cancellable: optional #GCancellable object, or %NULL
954  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
955  * @user_data: data to pass to the callback function
956  *
957  * Asynchronously verifies the signature.
958  *
959  * When the operation is finished, @callback will be called.  You can
960  * then call camel_cipher_context_verify_finish() to get the result of
961  * the operation.
962  *
963  * Since: 3.0
964  **/
965 void
966 camel_cipher_context_verify (CamelCipherContext *context,
967                              CamelMimePart *ipart,
968                              gint io_priority,
969                              GCancellable *cancellable,
970                              GAsyncReadyCallback callback,
971                              gpointer user_data)
972 {
973         CamelCipherContextClass *class;
974
975         g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
976         g_return_if_fail (CAMEL_IS_MIME_PART (ipart));
977
978         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
979         g_return_if_fail (class->verify != NULL);
980
981         class->verify (
982                 context, ipart, io_priority,
983                 cancellable, callback, user_data);
984 }
985
986 /**
987  * camel_cipher_context_verify_finish:
988  * @context: a #CamelCipherContext
989  * @result: a #GAsyncResult
990  * @error: return location for a #GError, or %NULL
991  *
992  * Finishes the operation started with camel_cipher_context_verify().
993  *
994  * Returns: a #CamelCipherValidity structure containing information
995  * about the integrity of the input stream, or %NULL on failure to
996  * execute at all
997  *
998  * Since: 3.0
999  **/
1000 CamelCipherValidity *
1001 camel_cipher_context_verify_finish (CamelCipherContext *context,
1002                                     GAsyncResult *result,
1003                                     GError **error)
1004 {
1005         CamelCipherContextClass *class;
1006
1007         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
1008         g_return_val_if_fail (G_IS_ASYNC_RESULT (context), NULL);
1009
1010         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1011         g_return_val_if_fail (class->verify_finish != NULL, NULL);
1012
1013         return class->verify_finish (context, result, error);
1014 }
1015
1016 /**
1017  * camel_cipher_context_encrypt_sync:
1018  * @context: a #CamelCipherContext
1019  * @userid: key ID (or email address) to use when signing, or %NULL to not sign
1020  * @recipients: an array of recipient key IDs and/or email addresses
1021  * @ipart: clear-text #CamelMimePart
1022  * @opart: cipher-text #CamelMimePart
1023  * @cancellable: optional #GCancellable object, or %NULL
1024  * @error: return location for a #GError, or %NULL
1025  *
1026  * Encrypts (and optionally signs) the clear-text @ipart and writes the
1027  * resulting cipher-text to @opart.
1028  *
1029  * Returns: %TRUE on success, %FALSE on error
1030  *
1031  * Since: 3.0
1032  **/
1033 gboolean
1034 camel_cipher_context_encrypt_sync (CamelCipherContext *context,
1035                                    const gchar *userid,
1036                                    GPtrArray *recipients,
1037                                    CamelMimePart *ipart,
1038                                    CamelMimePart *opart,
1039                                    GCancellable *cancellable,
1040                                    GError **error)
1041 {
1042         CamelCipherContextClass *class;
1043         gboolean success;
1044
1045         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
1046         g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), FALSE);
1047         g_return_val_if_fail (CAMEL_IS_MIME_PART (opart), FALSE);
1048
1049         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1050         g_return_val_if_fail (class->encrypt_sync != NULL, FALSE);
1051
1052         CIPHER_LOCK (context);
1053
1054         /* Check for cancellation after locking. */
1055         if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
1056                 CIPHER_UNLOCK (context);
1057                 return FALSE;
1058         }
1059
1060         camel_operation_push_message (cancellable, _("Encrypting message"));
1061
1062         success = class->encrypt_sync (
1063                 context, userid, recipients,
1064                 ipart, opart, cancellable, error);
1065         CAMEL_CHECK_GERROR (context, encrypt_sync, success, error);
1066
1067         camel_operation_pop_message (cancellable);
1068
1069         CIPHER_UNLOCK (context);
1070
1071         return success;
1072 }
1073
1074 /**
1075  * camel_cipher_context_encrypt:
1076  * @context: a #CamelCipherContext
1077  * @userid: key id (or email address) to use when signing, or %NULL to not sign
1078  * @recipients: an array of recipient key IDs and/or email addresses
1079  * @ipart: clear-text #CamelMimePart
1080  * @opart: cipher-text #CamelMimePart
1081  * @io_priority: the I/O priority of the request
1082  * @cancellable: optional #GCancellable object, or %NULL
1083  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1084  * @user_data: data to pass to the callback function
1085  *
1086  * Asynchronously encrypts (and optionally signs) the clear-text @ipart and
1087  * writes the resulting cipher-text to @opart.
1088  *
1089  * When the operation is finished, @callback will be called.  You can
1090  * then call camel_cipher_context_encrypt_finish() to get the result of
1091  * the operation.
1092  *
1093  * Since: 3.0
1094  **/
1095 void
1096 camel_cipher_context_encrypt (CamelCipherContext *context,
1097                               const gchar *userid,
1098                               GPtrArray *recipients,
1099                               CamelMimePart *ipart,
1100                               CamelMimePart *opart,
1101                               gint io_priority,
1102                               GCancellable *cancellable,
1103                               GAsyncReadyCallback callback,
1104                               gpointer user_data)
1105 {
1106         CamelCipherContextClass *class;
1107
1108         g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
1109         g_return_if_fail (CAMEL_IS_MIME_PART (ipart));
1110         g_return_if_fail (CAMEL_IS_MIME_PART (opart));
1111
1112         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1113         g_return_if_fail (class->encrypt != NULL);
1114
1115         class->encrypt (
1116                 context, userid, recipients, ipart, opart,
1117                 io_priority, cancellable, callback, user_data);
1118 }
1119
1120 /**
1121  * camel_cipher_context_encrypt_finish:
1122  * @context: a #CamelCipherContext
1123  * @result: a #GAsyncResult
1124  * @error: return location for a #GError, or %NULL
1125  *
1126  * Finishes the operation started with camel_cipher_context_encrypt().
1127  *
1128  * Returns: %TRUE on success, %FALSE on error
1129  *
1130  * Since: 3.0
1131  **/
1132 gboolean
1133 camel_cipher_context_encrypt_finish (CamelCipherContext *context,
1134                                      GAsyncResult *result,
1135                                      GError **error)
1136 {
1137         CamelCipherContextClass *class;
1138
1139         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
1140         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
1141
1142         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1143         g_return_val_if_fail (class->encrypt_finish != NULL, FALSE);
1144
1145         return class->encrypt_finish (context, result, error);
1146 }
1147
1148 /**
1149  * camel_cipher_context_decrypt_sync:
1150  * @context: a #CamelCipherContext
1151  * @ipart: cipher-text #CamelMimePart
1152  * @opart: clear-text #CamelMimePart
1153  * @cancellable: optional #GCancellable object, or %NULL
1154  * @error: return location for a #GError, or %NULL
1155  *
1156  * Decrypts @ipart into @opart.
1157  *
1158  * Returns: a validity/encryption status, or %NULL on error
1159  *
1160  * Since: 3.0
1161  **/
1162 CamelCipherValidity *
1163 camel_cipher_context_decrypt_sync (CamelCipherContext *context,
1164                                    CamelMimePart *ipart,
1165                                    CamelMimePart *opart,
1166                                    GCancellable *cancellable,
1167                                    GError **error)
1168 {
1169         CamelCipherContextClass *class;
1170         CamelCipherValidity *valid;
1171
1172         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
1173         g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), NULL);
1174         g_return_val_if_fail (CAMEL_IS_MIME_PART (opart), NULL);
1175
1176         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1177         g_return_val_if_fail (class->decrypt_sync != NULL, NULL);
1178
1179         CIPHER_LOCK (context);
1180
1181         /* Check for cancellation after locking. */
1182         if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
1183                 CIPHER_UNLOCK (context);
1184                 return NULL;
1185         }
1186
1187         camel_operation_push_message (cancellable, _("Decrypting message"));
1188
1189         valid = class->decrypt_sync (
1190                 context, ipart, opart, cancellable, error);
1191         CAMEL_CHECK_GERROR (context, decrypt_sync, valid != NULL, error);
1192
1193         camel_operation_pop_message (cancellable);
1194
1195         CIPHER_UNLOCK (context);
1196
1197         return valid;
1198 }
1199
1200 /**
1201  * camel_cipher_context_decrypt:
1202  * @context: a #CamelCipherContext
1203  * @ipart: cipher-text #CamelMimePart
1204  * @opart: clear-text #CamelMimePart
1205  * @io_priority: the I/O priority of the request
1206  * @cancellable: optional #GCancellable object, or %NULL
1207  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1208  * @user_data: data to pass to the callback function
1209  *
1210  * Asynchronously decrypts @ipart into @opart.
1211  *
1212  * When the operation is finished, @callback will be called.  You can
1213  * then call camel_cipher_context_decrypt_finish() to get the result of
1214  * the operation.
1215  *
1216  * Since: 3.0
1217  **/
1218 void
1219 camel_cipher_context_decrypt (CamelCipherContext *context,
1220                               CamelMimePart *ipart,
1221                               CamelMimePart *opart,
1222                               gint io_priority,
1223                               GCancellable *cancellable,
1224                               GAsyncReadyCallback callback,
1225                               gpointer user_data)
1226 {
1227         CamelCipherContextClass *class;
1228
1229         g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
1230         g_return_if_fail (CAMEL_IS_MIME_PART (ipart));
1231         g_return_if_fail (CAMEL_IS_MIME_PART (opart));
1232
1233         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1234         g_return_if_fail (class->decrypt != NULL);
1235
1236         class->decrypt (
1237                 context, ipart, opart, io_priority,
1238                 cancellable, callback, user_data);
1239 }
1240
1241 /**
1242  * camel_cipher_context_decrypt_finish:
1243  * @context: a #CamelCipherContext
1244  * @result: a #GAsyncResult
1245  * @error: return location for a #GError, or %NULL
1246  *
1247  * Finishes the operation started with camel_cipher_context_decrypt().
1248  *
1249  * Returns: a validity/encryption status, or %NULL on error
1250  *
1251  * Since: 3.0
1252  **/
1253 CamelCipherValidity *
1254 camel_cipher_context_decrypt_finish (CamelCipherContext *context,
1255                                      GAsyncResult *result,
1256                                      GError **error)
1257 {
1258         CamelCipherContextClass *class;
1259
1260         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
1261         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1262
1263         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1264         g_return_val_if_fail (class->decrypt_finish != NULL, NULL);
1265
1266         return class->decrypt_finish (context, result, error);
1267 }
1268
1269 /**
1270  * camel_cipher_context_import_keys_sync:
1271  * @context: a #CamelCipherContext
1272  * @istream: an input stream containing keys
1273  * @cancellable: optional #GCancellable object, or %NULL
1274  * @error: return location for a #GError, or %NULL
1275  *
1276  * Imports a stream of keys/certificates contained within @istream
1277  * into the key/certificate database controlled by @context.
1278  *
1279  * Returns: %TRUE on success, %FALSE on error
1280  *
1281  * Since: 3.0
1282  **/
1283 gboolean
1284 camel_cipher_context_import_keys_sync (CamelCipherContext *context,
1285                                        CamelStream *istream,
1286                                        GCancellable *cancellable,
1287                                        GError **error)
1288 {
1289         CamelCipherContextClass *class;
1290         gboolean success;
1291
1292         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
1293         g_return_val_if_fail (CAMEL_IS_STREAM (istream), FALSE);
1294
1295         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1296         g_return_val_if_fail (class->import_keys_sync != NULL, FALSE);
1297
1298         success = class->import_keys_sync (
1299                 context, istream, cancellable, error);
1300         CAMEL_CHECK_GERROR (context, import_keys_sync, success, error);
1301
1302         return success;
1303 }
1304
1305 /**
1306  * camel_cipher_context_import_keys:
1307  * @context: a #CamelCipherContext
1308  * @istream: an input stream containing keys
1309  * @io_priority: the I/O priority of the request
1310  * @cancellable: optional #GCancellable object, or %NULL
1311  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1312  * @user_data: data to pass to the callback function
1313  *
1314  * Asynchronously imports a stream of keys/certificates contained within
1315  * @istream into the key/certificate database controlled by @context.
1316  *
1317  * When the operation is finished, @callback will be called.  You can
1318  * then call camel_cipher_context_import_keys_finish() to get the result
1319  * of the operation.
1320  *
1321  * Since: 3.0
1322  **/
1323 void
1324 camel_cipher_context_import_keys (CamelCipherContext *context,
1325                                   CamelStream *istream,
1326                                   gint io_priority,
1327                                   GCancellable *cancellable,
1328                                   GAsyncReadyCallback callback,
1329                                   gpointer user_data)
1330 {
1331         CamelCipherContextClass *class;
1332
1333         g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
1334         g_return_if_fail (CAMEL_IS_STREAM (istream));
1335
1336         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1337         g_return_if_fail (class->import_keys != NULL);
1338
1339         class->import_keys (
1340                 context, istream, io_priority,
1341                 cancellable, callback, user_data);
1342 }
1343
1344 /**
1345  * camel_cipher_context_import_keys_finish:
1346  * @context: a #CamelCipherContext
1347  * @result: a #GAsyncResult
1348  * @error: return location for a #GError, or %NULL
1349  *
1350  * Finishes the operation started with camel_cipher_context_import_keys().
1351  *
1352  * Returns: %TRUE on success, %FALSE on error
1353  *
1354  * Since: 3.0
1355  **/
1356 gboolean
1357 camel_cipher_context_import_keys_finish (CamelCipherContext *context,
1358                                          GAsyncResult *result,
1359                                          GError **error)
1360 {
1361         CamelCipherContextClass *class;
1362
1363         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
1364         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
1365
1366         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1367         g_return_val_if_fail (class->import_keys_finish != NULL, FALSE);
1368
1369         return class->import_keys_finish (context, result, error);
1370 }
1371
1372 /**
1373  * camel_cipher_context_export_keys_sync:
1374  * @context: a #CamelCipherContext
1375  * @keys: an array of key IDs
1376  * @ostream: an output stream
1377  * @cancellable: optional #GCancellable object, or %NULL
1378  * @error: return location for a #GError, or %NULL
1379  *
1380  * Exports the keys/certificates in @keys to the stream @ostream from
1381  * the key/certificate database controlled by @context.
1382  *
1383  * Returns: %TRUE on success, %FALSE on error
1384  *
1385  * Since: 3.0
1386  **/
1387 gboolean
1388 camel_cipher_context_export_keys_sync (CamelCipherContext *context,
1389                                        GPtrArray *keys,
1390                                        CamelStream *ostream,
1391                                        GCancellable *cancellable,
1392                                        GError **error)
1393 {
1394         CamelCipherContextClass *class;
1395         gboolean success;
1396
1397         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
1398         g_return_val_if_fail (keys != NULL, FALSE);
1399         g_return_val_if_fail (CAMEL_IS_STREAM (ostream), FALSE);
1400
1401         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1402         g_return_val_if_fail (class->export_keys_sync != NULL, FALSE);
1403
1404         success = class->export_keys_sync (
1405                 context, keys, ostream, cancellable, error);
1406         CAMEL_CHECK_GERROR (context, export_keys_sync, success, error);
1407
1408         return success;
1409 }
1410
1411 /**
1412  * camel_cipher_context_export_keys:
1413  * @context: a #CamelCipherContext
1414  * @keys: an array of key IDs
1415  * @ostream: an output stream
1416  * @io_priority: the I/O priority of the request
1417  * @cancellable: optional #GCancellable object, or %NULL
1418  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1419  * @user_data: data to pass to the callback function
1420  *
1421  * Asynchronously exports the keys/certificates in @keys to the stream
1422  * @ostream from the key/certificate database controlled by @context.
1423  *
1424  * When the operation is finished, @callback will be called.  You can then
1425  * call camel_cipher_context_export_keys_finish() to get the result of the
1426  * operation.
1427  *
1428  * Since: 3.0
1429  **/
1430 void
1431 camel_cipher_context_export_keys (CamelCipherContext *context,
1432                                   GPtrArray *keys,
1433                                   CamelStream *ostream,
1434                                   gint io_priority,
1435                                   GCancellable *cancellable,
1436                                   GAsyncReadyCallback callback,
1437                                   gpointer user_data)
1438 {
1439         CamelCipherContextClass *class;
1440
1441         g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
1442         g_return_if_fail (keys != NULL);
1443         g_return_if_fail (CAMEL_IS_STREAM (ostream));
1444
1445         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1446         g_return_if_fail (class->export_keys != NULL);
1447
1448         class->export_keys (
1449                 context, keys, ostream, io_priority,
1450                 cancellable, callback, user_data);
1451 }
1452
1453 /**
1454  * camel_cipher_context_export_keys_finish:
1455  * @context: a #CamelCipherContext
1456  * @result: a #GAsyncResult
1457  * @error: return location for a #GError, or %NULL
1458  *
1459  * Finishes the operation started with camel_cipher_context_export_keys().
1460  *
1461  * Returns: %TRUE on success, %FALSE on error
1462  *
1463  * Since: 3.0
1464  **/
1465 gboolean
1466 camel_cipher_context_export_keys_finish (CamelCipherContext *context,
1467                                          GAsyncResult *result,
1468                                          GError **error)
1469 {
1470         CamelCipherContextClass *class;
1471
1472         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
1473         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
1474
1475         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1476         g_return_val_if_fail (class->export_keys_finish != NULL, FALSE);
1477
1478         return class->export_keys_finish (context, result, error);
1479 }
1480
1481 /* a couple of util functions */
1482 CamelCipherHash
1483 camel_cipher_context_id_to_hash (CamelCipherContext *context,
1484                                  const gchar *id)
1485 {
1486         CamelCipherContextClass *class;
1487
1488         g_return_val_if_fail (
1489                 CAMEL_IS_CIPHER_CONTEXT (context),
1490                 CAMEL_CIPHER_HASH_DEFAULT);
1491
1492         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1493         g_return_val_if_fail (
1494                 class->id_to_hash != NULL, CAMEL_CIPHER_HASH_DEFAULT);
1495
1496         return class->id_to_hash (context, id);
1497 }
1498
1499 const gchar *
1500 camel_cipher_context_hash_to_id (CamelCipherContext *context,
1501                                  CamelCipherHash hash)
1502 {
1503         CamelCipherContextClass *class;
1504
1505         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
1506
1507         class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1508         g_return_val_if_fail (class->hash_to_id != NULL, NULL);
1509
1510         return class->hash_to_id (context, hash);
1511 }
1512
1513 /* Cipher Validity stuff */
1514 static void
1515 ccv_certinfo_free (CamelCipherCertInfo *info)
1516 {
1517         g_return_if_fail (info != NULL);
1518
1519         g_free (info->name);
1520         g_free (info->email);
1521
1522         if (info->cert_data && info->cert_data_free)
1523                 info->cert_data_free (info->cert_data);
1524
1525         g_free (info);
1526 }
1527
1528 CamelCipherValidity *
1529 camel_cipher_validity_new (void)
1530 {
1531         CamelCipherValidity *validity;
1532
1533         validity = g_malloc (sizeof (*validity));
1534         camel_cipher_validity_init (validity);
1535
1536         return validity;
1537 }
1538
1539 void
1540 camel_cipher_validity_init (CamelCipherValidity *validity)
1541 {
1542         g_return_if_fail (validity != NULL);
1543
1544         memset (validity, 0, sizeof (*validity));
1545         g_queue_init (&validity->children);
1546         g_queue_init (&validity->sign.signers);
1547         g_queue_init (&validity->encrypt.encrypters);
1548 }
1549
1550 gboolean
1551 camel_cipher_validity_get_valid (CamelCipherValidity *validity)
1552 {
1553         return validity != NULL
1554                 && validity->sign.status == CAMEL_CIPHER_VALIDITY_SIGN_GOOD;
1555 }
1556
1557 void
1558 camel_cipher_validity_set_valid (CamelCipherValidity *validity,
1559                                  gboolean valid)
1560 {
1561         g_return_if_fail (validity != NULL);
1562
1563         validity->sign.status = valid ? CAMEL_CIPHER_VALIDITY_SIGN_GOOD : CAMEL_CIPHER_VALIDITY_SIGN_BAD;
1564 }
1565
1566 gchar *
1567 camel_cipher_validity_get_description (CamelCipherValidity *validity)
1568 {
1569         g_return_val_if_fail (validity != NULL, NULL);
1570
1571         return validity->sign.description;
1572 }
1573
1574 void
1575 camel_cipher_validity_set_description (CamelCipherValidity *validity,
1576                                        const gchar *description)
1577 {
1578         g_return_if_fail (validity != NULL);
1579
1580         g_free (validity->sign.description);
1581         validity->sign.description = g_strdup (description);
1582 }
1583
1584 void
1585 camel_cipher_validity_clear (CamelCipherValidity *validity)
1586 {
1587         g_return_if_fail (validity != NULL);
1588
1589         /* TODO: this doesn't free children/clear key lists */
1590         g_free (validity->sign.description);
1591         g_free (validity->encrypt.description);
1592         camel_cipher_validity_init (validity);
1593 }
1594
1595 CamelCipherValidity *
1596 camel_cipher_validity_clone (CamelCipherValidity *vin)
1597 {
1598         CamelCipherValidity *vo;
1599         GList *head, *link;
1600
1601         g_return_val_if_fail (vin != NULL, NULL);
1602
1603         vo = camel_cipher_validity_new ();
1604         vo->sign.status = vin->sign.status;
1605         vo->sign.description = g_strdup (vin->sign.description);
1606         vo->encrypt.status = vin->encrypt.status;
1607         vo->encrypt.description = g_strdup (vin->encrypt.description);
1608
1609         head = g_queue_peek_head_link (&vin->sign.signers);
1610         for (link = head; link != NULL; link = g_list_next (link)) {
1611                 CamelCipherCertInfo *info = link->data;
1612
1613                 if (info->cert_data && info->cert_data_clone && info->cert_data_free)
1614                         camel_cipher_validity_add_certinfo_ex (vo, CAMEL_CIPHER_VALIDITY_SIGN, info->name, info->email, info->cert_data_clone (info->cert_data), info->cert_data_free, info->cert_data_clone);
1615                 else
1616                         camel_cipher_validity_add_certinfo (vo, CAMEL_CIPHER_VALIDITY_SIGN, info->name, info->email);
1617         }
1618
1619         head = g_queue_peek_head_link (&vin->encrypt.encrypters);
1620         for (link = head; link != NULL; link = g_list_next (link)) {
1621                 CamelCipherCertInfo *info = link->data;
1622
1623                 if (info->cert_data && info->cert_data_clone && info->cert_data_free)
1624                         camel_cipher_validity_add_certinfo_ex (vo, CAMEL_CIPHER_VALIDITY_SIGN, info->name, info->email, info->cert_data_clone (info->cert_data), info->cert_data_free, info->cert_data_clone);
1625                 else
1626                         camel_cipher_validity_add_certinfo (vo, CAMEL_CIPHER_VALIDITY_ENCRYPT, info->name, info->email);
1627         }
1628
1629         return vo;
1630 }
1631
1632 /**
1633  * camel_cipher_validity_add_certinfo:
1634  * @vin:
1635  * @mode:
1636  * @name:
1637  * @email:
1638  *
1639  * Add a cert info to the signer or encrypter info.
1640  **/
1641 void
1642 camel_cipher_validity_add_certinfo (CamelCipherValidity *vin,
1643                                     enum _camel_cipher_validity_mode_t mode,
1644                                     const gchar *name,
1645                                     const gchar *email)
1646 {
1647         camel_cipher_validity_add_certinfo_ex (vin, mode, name, email, NULL, NULL, NULL);
1648 }
1649
1650 /**
1651  * camel_cipher_validity_add_certinfo_ex:
1652  *
1653  * Add a cert info to the signer or encrypter info, with extended data set.
1654  *
1655  * Since: 2.30
1656  **/
1657 void
1658 camel_cipher_validity_add_certinfo_ex (CamelCipherValidity *vin,
1659                                        camel_cipher_validity_mode_t mode,
1660                                        const gchar *name,
1661                                        const gchar *email,
1662                                        gpointer cert_data,
1663                                        void (*cert_data_free)(gpointer cert_data),
1664                                        gpointer (*cert_data_clone)(gpointer cert_data))
1665 {
1666         CamelCipherCertInfo *info;
1667
1668         g_return_if_fail (vin != NULL);
1669         if (cert_data) {
1670                 g_return_if_fail (cert_data_free != NULL);
1671                 g_return_if_fail (cert_data_clone != NULL);
1672         }
1673
1674         info = g_malloc0 (sizeof (*info));
1675         info->name = g_strdup (name);
1676         info->email = g_strdup (email);
1677         if (cert_data) {
1678                 info->cert_data = cert_data;
1679                 info->cert_data_free = cert_data_free;
1680                 info->cert_data_clone = cert_data_clone;
1681         }
1682
1683         if (mode == CAMEL_CIPHER_VALIDITY_SIGN)
1684                 g_queue_push_tail (&vin->sign.signers, info);
1685         else
1686                 g_queue_push_tail (&vin->encrypt.encrypters, info);
1687 }
1688
1689 /**
1690  * camel_cipher_validity_envelope:
1691  * @parent:
1692  * @valid:
1693  *
1694  * Calculate a conglomerate validity based on wrapping one secure part inside
1695  * another one.
1696  **/
1697 void
1698 camel_cipher_validity_envelope (CamelCipherValidity *parent,
1699                                 CamelCipherValidity *valid)
1700 {
1701
1702         g_return_if_fail (parent != NULL);
1703         g_return_if_fail (valid != NULL);
1704
1705         if (parent->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE
1706             && parent->encrypt.status == CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
1707             && valid->sign.status == CAMEL_CIPHER_VALIDITY_SIGN_NONE
1708             && valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
1709                 GList *head, *link;
1710
1711                 /* case 1: only signed inside only encrypted -> merge both */
1712                 parent->encrypt.status = valid->encrypt.status;
1713                 parent->encrypt.description = g_strdup (valid->encrypt.description);
1714
1715                 head = g_queue_peek_head_link (&valid->encrypt.encrypters);
1716                 for (link = head; link != NULL; link = g_list_next (link)) {
1717                         CamelCipherCertInfo *info = link->data;
1718                         camel_cipher_validity_add_certinfo (
1719                                 parent, CAMEL_CIPHER_VALIDITY_ENCRYPT,
1720                                 info->name, info->email);
1721                 }
1722         } else if (parent->sign.status == CAMEL_CIPHER_VALIDITY_SIGN_NONE
1723                    && parent->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
1724                    && valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE
1725                    && valid->encrypt.status == CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
1726                 GList *head, *link;
1727
1728                 /* case 2: only encrypted inside only signed */
1729                 parent->sign.status = valid->sign.status;
1730                 parent->sign.description = g_strdup (valid->sign.description);
1731
1732                 head = g_queue_peek_head_link (&valid->sign.signers);
1733                 for (link = head; link != NULL; link = g_list_next (link)) {
1734                         CamelCipherCertInfo *info = link->data;
1735                         camel_cipher_validity_add_certinfo (
1736                                 parent, CAMEL_CIPHER_VALIDITY_SIGN,
1737                                 info->name, info->email);
1738                 }
1739         }
1740         /* Otherwise, I dunno - what do you do? */
1741 }
1742
1743 void
1744 camel_cipher_validity_free (CamelCipherValidity *validity)
1745 {
1746         CamelCipherValidity *child;
1747         CamelCipherCertInfo *info;
1748         GQueue *queue;
1749
1750         if (validity == NULL)
1751                 return;
1752
1753         queue = &validity->children;
1754         while ((child = g_queue_pop_head (queue)) != NULL)
1755                 camel_cipher_validity_free (child);
1756
1757         queue = &validity->sign.signers;
1758         while ((info = g_queue_pop_head (queue)) != NULL)
1759                 ccv_certinfo_free (info);
1760
1761         queue = &validity->encrypt.encrypters;
1762         while ((info = g_queue_pop_head (queue)) != NULL)
1763                 ccv_certinfo_free (info);
1764
1765         camel_cipher_validity_clear (validity);
1766         g_free (validity);
1767 }
1768
1769 /* ********************************************************************** */
1770
1771 /**
1772  * camel_cipher_context_new:
1773  * @session: a #CamelSession
1774  *
1775  * This creates a new CamelCipherContext object which is used to sign,
1776  * verify, encrypt and decrypt streams.
1777  *
1778  * Returns: the new CamelCipherContext
1779  **/
1780 CamelCipherContext *
1781 camel_cipher_context_new (CamelSession *session)
1782 {
1783         g_return_val_if_fail (session != NULL, NULL);
1784
1785         return g_object_new (
1786                 CAMEL_TYPE_CIPHER_CONTEXT,
1787                 "session", session, NULL);
1788 }
1789
1790 /**
1791  * camel_cipher_context_get_session:
1792  * @context: a #CamelCipherContext
1793  *
1794  * Since: 2.32
1795  **/
1796 CamelSession *
1797 camel_cipher_context_get_session (CamelCipherContext *context)
1798 {
1799         g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
1800
1801         return context->priv->session;
1802 }
1803
1804 /* See rfc3156, section 2 and others */
1805 /* We do this simply: Anything not base64 must be qp
1806  * This is so that we can safely translate any occurance of "From "
1807  * into the quoted-printable escaped version safely. */
1808 static void
1809 cc_prepare_sign (CamelMimePart *part)
1810 {
1811         CamelDataWrapper *dw;
1812         CamelTransferEncoding encoding;
1813         gint parts, i;
1814
1815         dw = camel_medium_get_content ((CamelMedium *) part);
1816         if (!dw)
1817                 return;
1818
1819         /* should not change encoding for these, they have the right encoding set already */
1820         if (CAMEL_IS_MULTIPART_SIGNED (dw) || CAMEL_IS_MULTIPART_ENCRYPTED (dw))
1821                 return;
1822
1823         if (CAMEL_IS_MULTIPART (dw)) {
1824                 parts = camel_multipart_get_number ((CamelMultipart *) dw);
1825                 for (i = 0; i < parts; i++)
1826                         cc_prepare_sign (camel_multipart_get_part ((CamelMultipart *) dw, i));
1827         } else if (CAMEL_IS_MIME_MESSAGE (dw)) {
1828                 cc_prepare_sign ((CamelMimePart *) dw);
1829         } else {
1830                 encoding = camel_mime_part_get_encoding (part);
1831
1832                 if (encoding != CAMEL_TRANSFER_ENCODING_BASE64
1833                     && encoding != CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE) {
1834                         camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
1835                 }
1836         }
1837 }
1838
1839 /**
1840  * camel_cipher_canonical_to_stream:
1841  * @part: Part to write.
1842  * @flags: flags for the canonicalisation filter (CamelMimeFilterCanon)
1843  * @ostream: stream to write canonicalised output to.
1844  * @cancellable: optional #GCancellable object, or %NULL
1845  * @error: return location for a #GError, or %NULL
1846  *
1847  * Writes a part to a stream in a canonicalised format, suitable for signing/encrypting.
1848  *
1849  * The transfer encoding paramaters for the part may be changed by this function.
1850  *
1851  * Returns: -1 on error;
1852  **/
1853 gint
1854 camel_cipher_canonical_to_stream (CamelMimePart *part,
1855                                   guint32 flags,
1856                                   CamelStream *ostream,
1857                                   GCancellable *cancellable,
1858                                   GError **error)
1859 {
1860         CamelStream *filter;
1861         CamelMimeFilter *canon;
1862         gint res = -1;
1863
1864         g_return_val_if_fail (CAMEL_IS_MIME_PART (part), -1);
1865         g_return_val_if_fail (CAMEL_IS_STREAM (ostream), -1);
1866
1867         if (flags & (CAMEL_MIME_FILTER_CANON_FROM | CAMEL_MIME_FILTER_CANON_STRIP))
1868                 cc_prepare_sign (part);
1869
1870         filter = camel_stream_filter_new (ostream);
1871         canon = camel_mime_filter_canon_new (flags);
1872         camel_stream_filter_add (CAMEL_STREAM_FILTER (filter), canon);
1873         g_object_unref (canon);
1874
1875         if (camel_data_wrapper_write_to_stream_sync (
1876                 CAMEL_DATA_WRAPPER (part), filter, cancellable, error) != -1
1877             && camel_stream_flush (filter, cancellable, error) != -1)
1878                 res = 0;
1879
1880         g_object_unref (filter);
1881
1882         /* Reset stream position to beginning. */
1883         if (G_IS_SEEKABLE (ostream))
1884                 g_seekable_seek (
1885                         G_SEEKABLE (ostream), 0,
1886                         G_SEEK_SET, NULL, NULL);
1887
1888         return res;
1889 }