summaryrefslogtreecommitdiffabout
path: root/libetpan/src/engine
Unidiff
Diffstat (limited to 'libetpan/src/engine') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/engine/mailengine.c1636
-rw-r--r--libetpan/src/engine/mailengine.h190
-rw-r--r--libetpan/src/engine/mailprivacy.c949
-rw-r--r--libetpan/src/engine/mailprivacy.h117
-rw-r--r--libetpan/src/engine/mailprivacy_gnupg.c2614
-rw-r--r--libetpan/src/engine/mailprivacy_gnupg.h46
-rw-r--r--libetpan/src/engine/mailprivacy_smime.c1755
-rw-r--r--libetpan/src/engine/mailprivacy_smime.h84
-rw-r--r--libetpan/src/engine/mailprivacy_tools.c1283
-rw-r--r--libetpan/src/engine/mailprivacy_tools.h102
-rw-r--r--libetpan/src/engine/mailprivacy_types.h82
11 files changed, 8858 insertions, 0 deletions
diff --git a/libetpan/src/engine/mailengine.c b/libetpan/src/engine/mailengine.c
new file mode 100644
index 0000000..be4df38
--- a/dev/null
+++ b/libetpan/src/engine/mailengine.c
@@ -0,0 +1,1636 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailengine.h"
37
38#ifndef CONFIG_H
39#define CONFIG_H
40#include "config.h"
41#endif
42
43#include "mailfolder.h"
44#include "maildriver.h"
45#include "imapdriver_cached.h"
46#include "mailstorage.h"
47#include "imapdriver_cached_message.h"
48#include <stdlib.h>
49#include "mailprivacy.h"
50#ifdef LIBETPAN_REENTRANT
51#include <pthread.h>
52#endif
53#include <string.h>
54
55/* ************************************************************* */
56/* Message finder */
57
58#if 0
59struct message_folder_finder {
60#ifdef LIBETPAN_REENTRANT
61 pthread_mutex_t lock;
62#endif
63
64 /* msg => folder */
65 chash * message_hash;
66};
67
68static int message_folder_finder_init(struct message_folder_finder * finder)
69{
70 int r;
71
72#ifdef LIBETPAN_REENTRANT
73 r = pthread_mutex_init(&finder->lock, NULL);
74 if (r != 0)
75 return MAIL_ERROR_MEMORY;
76#endif
77
78 finder->message_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
79 if (finder->message_hash == NULL)
80 return MAIL_ERROR_MEMORY;
81
82 return MAIL_NO_ERROR;
83}
84
85static void message_folder_finder_done(struct message_folder_finder * finder)
86{
87 chash_free(finder->message_hash);
88#ifdef LIBETPAN_REENTRANT
89 pthread_mutex_destroy(&finder->lock);
90#endif
91}
92
93static struct mailfolder *
94message_folder_finder_lookup(struct message_folder_finder * finder,
95 mailmessage * msg)
96{
97 int r;
98 chashdatum key;
99 chashdatum data;
100 struct mailfolder * folder;
101
102 key.data = &msg;
103 key.len = sizeof(msg);
104#ifdef LIBETPAN_REENTRANT
105 pthread_mutex_lock(&finder->lock);
106#endif
107 r = chash_get(finder->message_hash, &key, &data);
108#ifdef LIBETPAN_REENTRANT
109 pthread_mutex_unlock(&finder->lock);
110#endif
111 if (r < 0)
112 return NULL;
113
114 folder = data.data;
115
116 return folder;
117}
118
119static inline int
120message_folder_finder_store_no_lock(struct message_folder_finder * finder,
121 mailmessage * msg, struct mailfolder * folder)
122{
123 int r;
124 chashdatum key;
125 chashdatum data;
126
127 key.data = &msg;
128 key.len = sizeof(msg);
129 data.data = folder;
130 data.len = 0;
131 r = chash_set(finder->message_hash, &key, &data, NULL);
132 if (r < 0)
133 return MAIL_ERROR_MEMORY;
134
135 return MAIL_NO_ERROR;
136}
137
138static int
139message_folder_finder_store(struct message_folder_finder * finder,
140 mailmessage * msg, struct mailfolder * folder)
141{
142 int r;
143
144#ifdef LIBETPAN_REENTRANT
145 pthread_mutex_lock(&finder->lock);
146#endif
147 r = message_folder_finder_store_no_lock(finder, msg, folder);
148#ifdef LIBETPAN_REENTRANT
149 pthread_mutex_unlock(&finder->lock);
150#endif
151
152 return r;
153}
154
155static inline void
156message_folder_finder_delete_no_lock(struct message_folder_finder * finder,
157 mailmessage * msg)
158{
159 chashdatum key;
160
161 key.data = &msg;
162 key.len = sizeof(msg);
163 chash_delete(finder->message_hash, &key, NULL);
164}
165
166static void
167message_folder_finder_delete(struct message_folder_finder * finder,
168 mailmessage * msg)
169{
170#ifdef LIBETPAN_REENTRANT
171 pthread_mutex_lock(&finder->lock);
172#endif
173 message_folder_finder_delete_no_lock(finder, msg);
174#ifdef LIBETPAN_REENTRANT
175 pthread_mutex_unlock(&finder->lock);
176#endif
177}
178#endif
179
180/* ************************************************************* */
181/* Message ref info */
182
183struct message_ref_elt {
184 mailmessage * msg;
185 int ref_count;
186 int mime_ref_count;
187 struct mailfolder * folder;
188 int lost;
189};
190
191static struct message_ref_elt *
192message_ref_elt_new(struct mailfolder * folder, mailmessage * msg)
193{
194 struct message_ref_elt * ref;
195
196 ref = malloc(sizeof(* ref));
197 if (ref == NULL)
198 return NULL;
199
200 ref->msg = msg;
201 ref->ref_count = 0;
202 ref->mime_ref_count = 0;
203 ref->folder = folder;
204 ref->lost = 0;
205
206 return ref;
207}
208
209static void message_ref_elt_free(struct message_ref_elt * ref_elt)
210{
211 free(ref_elt);
212}
213
214static inline int message_ref(struct message_ref_elt * ref_elt)
215{
216 ref_elt->ref_count ++;
217
218 return ref_elt->ref_count;
219}
220
221static inline int message_unref(struct message_ref_elt * ref_elt)
222{
223 ref_elt->ref_count --;
224
225 return ref_elt->ref_count;
226}
227
228
229static inline int message_mime_ref(struct mailprivacy * privacy,
230 struct message_ref_elt * ref_elt)
231{
232 int r;
233
234 if (ref_elt->mime_ref_count == 0) {
235 struct mailmime * mime;
236
237 r = mailprivacy_msg_get_bodystructure(privacy, ref_elt->msg, &mime);
238 if (r != MAIL_NO_ERROR)
239 return -r;
240 }
241
242 message_ref(ref_elt);
243
244 ref_elt->mime_ref_count ++;
245
246 return ref_elt->mime_ref_count;
247}
248
249static inline int message_mime_unref(struct mailprivacy * privacy,
250 struct message_ref_elt * ref_elt)
251{
252 message_unref(ref_elt);
253
254 ref_elt->mime_ref_count --;
255
256 if (ref_elt->mime_ref_count == 0)
257 mailprivacy_msg_flush(privacy, ref_elt->msg);
258
259 return ref_elt->mime_ref_count;
260}
261
262
263/* ************************************************************* */
264/* Folder ref info */
265
266struct folder_ref_info {
267 struct mailfolder * folder;
268#if 0
269 struct message_folder_finder * msg_folder_finder;
270#endif
271
272 /* msg => msg_ref_info */
273 chash * msg_hash;
274
275 /* uid => msg */
276 chash * uid_hash;
277
278 int lost_session;
279};
280
281static struct folder_ref_info *
282folder_ref_info_new(struct mailfolder * folder
283 /*, struct message_folder_finder * msg_folder_finder */)
284{
285 struct folder_ref_info * ref_info;
286
287 ref_info = malloc(sizeof(* ref_info));
288 if (ref_info == NULL)
289 goto err;
290
291 ref_info->folder = folder;
292#if 0
293 ref_info->msg_folder_finder = msg_folder_finder;
294#endif
295
296 ref_info->msg_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
297 if (ref_info->msg_hash == NULL)
298 goto free;
299
300 ref_info->uid_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYNONE);
301 if (ref_info->uid_hash == NULL)
302 goto free_msg_hash;
303
304 ref_info->lost_session = 1;
305
306 return ref_info;
307
308 free_msg_hash:
309 chash_free(ref_info->msg_hash);
310 free:
311 free(ref_info);
312 err:
313 return NULL;
314}
315
316static void folder_ref_info_free(struct folder_ref_info * ref_info)
317{
318 chash_free(ref_info->uid_hash);
319 chash_free(ref_info->msg_hash);
320 free(ref_info);
321}
322
323static struct message_ref_elt *
324folder_info_get_msg_ref(struct folder_ref_info * ref_info, mailmessage * msg)
325{
326 chashdatum key;
327 chashdatum data;
328 struct message_ref_elt * ref_elt;
329 int r;
330
331 key.data = &msg;
332 key.len = sizeof(msg);
333 r = chash_get(ref_info->msg_hash, &key, &data);
334 if (r < 0)
335 return NULL;
336
337 ref_elt = data.data;
338
339 return ref_elt;
340}
341
342static mailmessage *
343folder_info_get_msg_by_uid(struct folder_ref_info * ref_info,
344 char * uid)
345{
346 chashdatum key;
347 chashdatum data;
348 mailmessage * msg;
349 int r;
350
351 key.data = uid;
352 key.len = strlen(uid);
353 r = chash_get(ref_info->uid_hash, &key, &data);
354 if (r < 0)
355 return NULL;
356
357 msg = data.data;
358
359 return msg;
360}
361
362static int folder_message_ref(struct folder_ref_info * ref_info,
363 mailmessage * msg)
364{
365 struct message_ref_elt * msg_ref;
366
367 msg_ref = folder_info_get_msg_ref(ref_info, msg);
368 return message_ref(msg_ref);
369}
370
371static void folder_message_remove(struct folder_ref_info * ref_info,
372 mailmessage * msg);
373
374#ifdef DEBUG_ENGINE
375#include "etpan-app.h"
376
377void * engine_app = NULL;
378#endif
379
380static int folder_message_unref(struct folder_ref_info * ref_info,
381 mailmessage * msg)
382{
383 struct message_ref_elt * msg_ref;
384 int count;
385
386 msg_ref = folder_info_get_msg_ref(ref_info, msg);
387
388 if (msg_ref->ref_count == 0) {
389#ifdef ETPAN_APP_DEBUG
390 ETPAN_APP_DEBUG((engine_app, "** BUG detected negative ref count !"));
391#endif
392 }
393
394 count = message_unref(msg_ref);
395 if (count == 0) {
396 folder_message_remove(ref_info, msg);
397 mailmessage_free(msg);
398 }
399
400 return count;
401}
402
403static int folder_message_mime_ref(struct mailprivacy * privacy,
404 struct folder_ref_info * ref_info,
405 mailmessage * msg)
406{
407 struct message_ref_elt * msg_ref;
408
409 msg_ref = folder_info_get_msg_ref(ref_info, msg);
410
411 return message_mime_ref(privacy, msg_ref);
412}
413
414static int folder_message_mime_unref(struct mailprivacy * privacy,
415 struct folder_ref_info * ref_info,
416 mailmessage * msg)
417{
418 struct message_ref_elt * msg_ref;
419
420 msg_ref = folder_info_get_msg_ref(ref_info, msg);
421 return message_mime_unref(privacy, msg_ref);
422}
423
424static int folder_message_add(struct folder_ref_info * ref_info,
425 mailmessage * msg)
426{
427 chashdatum key;
428 chashdatum data;
429 struct message_ref_elt * msg_ref;
430 int r;
431
432 /*
433 r = message_folder_finder_store(ref_info->msg_folder_finder,
434 msg, ref_info->folder);
435 if (r != MAIL_NO_ERROR)
436 goto err;
437 */
438
439 msg_ref = message_ref_elt_new(ref_info->folder, msg);
440 if (msg_ref == NULL)
441 goto msg_folder_remove;
442
443 key.data = &msg;
444 key.len = sizeof(msg);
445 data.data = msg_ref;
446 data.len = 0;
447
448 r = chash_set(ref_info->msg_hash, &key, &data, NULL);
449 if (r < 0)
450 goto free_msg_ref;
451
452 if (msg->msg_uid != NULL) {
453 key.data = msg->msg_uid;
454 key.len = strlen(msg->msg_uid);
455 data.data = msg;
456 data.len = 0;
457
458 r = chash_set(ref_info->uid_hash, &key, &data, NULL);
459 if (r < 0)
460 goto remove_msg_ref;
461 }
462
463 return MAIL_NO_ERROR;
464
465 remove_msg_ref:
466 key.data = &msg;
467 key.len = sizeof(msg);
468 chash_delete(ref_info->msg_hash, &key, NULL);
469 free_msg_ref:
470 message_ref_elt_free(msg_ref);
471 msg_folder_remove:
472 /*
473 message_folder_finder_delete(ref_info->msg_folder_finder, msg);
474 */
475 err:
476 return MAIL_ERROR_MEMORY;
477}
478
479
480static void folder_message_remove(struct folder_ref_info * ref_info,
481 mailmessage * msg)
482{
483 chashdatum key;
484 struct message_ref_elt * msg_ref;
485
486 if (msg->msg_uid != NULL) {
487 key.data = msg->msg_uid;
488 key.len = strlen(msg->msg_uid);
489
490 chash_delete(ref_info->uid_hash, &key, NULL);
491 }
492
493 msg_ref = folder_info_get_msg_ref(ref_info, msg);
494 message_ref_elt_free(msg_ref);
495
496 key.data = &msg;
497 key.len = sizeof(msg);
498
499 chash_delete(ref_info->msg_hash, &key, NULL);
500
501 /*
502 message_folder_finder_delete(ref_info->msg_folder_finder, msg);
503 */
504}
505
506
507static int folder_update_msg_list(struct folder_ref_info * ref_info,
508 struct mailmessage_list ** p_new_msg_list,
509 struct mailmessage_list ** p_lost_msg_list)
510{
511 int r;
512 int res;
513 struct mailmessage_list * new_env_list;
514 unsigned int i;
515 carray * lost_msg_tab;
516 struct mailmessage_list * lost_msg_list;
517 unsigned int free_start_index;
518 chashiter * iter;
519 unsigned int lost_count;
520
521 r = mailfolder_get_messages_list(ref_info->folder, &new_env_list);
522 if (r != MAIL_NO_ERROR) {
523 res = r;
524 goto err;
525 }
526
527 for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ;
528 iter = chash_next(ref_info->msg_hash, iter)) {
529 struct message_ref_elt * msg_ref;
530 chashdatum data;
531
532 chash_value(iter, &data);
533 msg_ref = data.data;
534 msg_ref->lost = 1;
535 }
536
537 lost_count = chash_count(ref_info->msg_hash);
538
539 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
540 mailmessage * msg;
541 mailmessage * old_msg;
542
543 msg = carray_get(new_env_list->msg_tab, i);
544
545 if (msg->msg_uid == NULL)
546 continue;
547
548 old_msg = folder_info_get_msg_by_uid(ref_info, msg->msg_uid);
549 if (old_msg != NULL) {
550 struct message_ref_elt * msg_ref;
551
552 /* replace old message */
553 old_msg->msg_index = msg->msg_index;
554 carray_set(new_env_list->msg_tab, i, old_msg);
555 mailmessage_free(msg);
556
557 msg_ref = folder_info_get_msg_ref(ref_info, old_msg);
558 msg_ref->lost = 0;
559 lost_count --;
560 }
561 else {
562 /* set new message */
563 r = folder_message_add(ref_info, msg);
564 if (r != MAIL_NO_ERROR) {
565 free_start_index = i;
566 res = r;
567 goto free_remaining;
568 }
569 }
570 }
571
572 /* build the table of lost messages */
573 lost_msg_tab = carray_new(lost_count);
574 if (lost_msg_tab == NULL) {
575 res = MAIL_ERROR_MEMORY;
576 goto free_env_list;
577 }
578
579 carray_set_size(lost_msg_tab, lost_count);
580
581 i = 0;
582 for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ;
583 iter = chash_next(ref_info->msg_hash, iter)) {
584 struct message_ref_elt * msg_ref;
585 chashdatum key;
586 chashdatum value;
587 mailmessage * msg;
588
589 chash_key(iter, &key);
590 memcpy(&msg, key.data, sizeof(msg));
591
592 chash_value(iter, &value);
593 msg_ref = value.data;
594 if (msg_ref->lost) {
595 carray_set(lost_msg_tab, i, msg);
596 i ++;
597 }
598 }
599
600 lost_msg_list = mailmessage_list_new(lost_msg_tab);
601 if (lost_msg_list == NULL) {
602 res = MAIL_ERROR_MEMORY;
603 goto free_lost_msg_tab;
604 }
605
606 /* reference messages */
607 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
608 mailmessage * msg;
609
610 msg = carray_get(new_env_list->msg_tab, i);
611 folder_message_ref(ref_info, msg);
612 }
613
614 * p_new_msg_list = new_env_list;
615 * p_lost_msg_list = lost_msg_list;
616
617 return MAIL_NO_ERROR;
618
619 free_lost_msg_tab:
620 carray_free(lost_msg_tab);
621 free_env_list:
622 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
623 mailmessage * msg;
624 struct message_ref_elt * msg_ref;
625
626 msg = carray_get(new_env_list->msg_tab, i);
627 msg_ref = folder_info_get_msg_ref(ref_info, msg);
628 if (msg_ref != NULL) {
629 if (msg_ref->ref_count == 0)
630 folder_message_remove(ref_info, msg);
631 }
632 }
633 carray_set_size(new_env_list->msg_tab, 0);
634 mailmessage_list_free(new_env_list);
635 goto err;
636 free_remaining:
637 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
638 mailmessage * msg;
639 struct message_ref_elt * msg_ref;
640
641 msg = carray_get(new_env_list->msg_tab, i);
642 msg_ref = folder_info_get_msg_ref(ref_info, msg);
643 if (msg_ref != NULL) {
644 if (msg_ref->ref_count == 0)
645 folder_message_remove(ref_info, msg);
646 }
647 }
648 for(i = free_start_index ; i < carray_count(new_env_list->msg_tab) ; i ++) {
649 mailmessage * msg;
650
651 msg = carray_get(new_env_list->msg_tab, i);
652 mailmessage_free(msg);
653 }
654 carray_set_size(new_env_list->msg_tab, 0);
655 mailmessage_list_free(new_env_list);
656 err:
657 return res;
658}
659
660/*
661 folder_fetch_env_list()
662*/
663
664static int folder_fetch_env_list(struct folder_ref_info * ref_info,
665 struct mailmessage_list * msg_list)
666{
667 return mailfolder_get_envelopes_list(ref_info->folder, msg_list);
668}
669
670static void folder_free_msg_list(struct folder_ref_info * ref_info,
671 struct mailmessage_list * env_list)
672{
673 unsigned int i;
674
675 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
676 mailmessage * msg;
677 int count;
678
679 msg = carray_get(env_list->msg_tab, i);
680
681 count = folder_message_unref(ref_info, msg);
682 }
683 carray_set_size(env_list->msg_tab, 0);
684 mailmessage_list_free(env_list);
685}
686
687
688/* ************************************************************* */
689/* Storage ref info */
690
691struct storage_ref_info {
692 struct mailstorage * storage;
693#if 0
694 struct message_folder_finder * msg_folder_finder;
695#endif
696
697#if 0
698 /* msg => folder */
699 chash * msg_ref;
700#endif
701
702 /* folder => folder_ref_info */
703 chash * folder_ref_info;
704};
705
706static struct storage_ref_info *
707storage_ref_info_new(struct mailstorage * storage
708 /*, struct message_folder_finder * msg_folder_finder */)
709{
710 struct storage_ref_info * ref_info;
711
712 ref_info = malloc(sizeof(* ref_info));
713 if (ref_info == NULL)
714 goto err;
715
716 ref_info->storage = storage;
717#if 0
718 ref_info->msg_folder_finder = msg_folder_finder;
719#endif
720
721 ref_info->folder_ref_info = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
722 if (ref_info->folder_ref_info == NULL)
723 goto free;
724
725 return ref_info;
726
727 free:
728 free(ref_info);
729 err:
730 return NULL;
731}
732
733static void storage_ref_info_free(struct storage_ref_info * ref_info)
734{
735#if 0
736 chash_free(ref_info->msg_ref);
737#endif
738 chash_free(ref_info->folder_ref_info);
739 free(ref_info);
740}
741
742
743static struct folder_ref_info *
744storage_get_folder_ref(struct storage_ref_info * ref_info,
745 struct mailfolder * folder)
746{
747 struct folder_ref_info * folder_ref;
748 chashdatum key;
749 chashdatum value;
750 int r;
751
752 key.data = &folder;
753 key.len = sizeof(folder);
754 r = chash_get(ref_info->folder_ref_info, &key, &value);
755 if (r < 0)
756 return NULL;
757
758 folder_ref = value.data;
759
760 return folder_ref;
761}
762
763static struct folder_ref_info *
764storage_folder_add_ref(struct storage_ref_info * ref_info,
765 struct mailfolder * folder)
766{
767 struct folder_ref_info * folder_ref;
768 chashdatum key;
769 chashdatum value;
770 int r;
771
772 folder_ref = folder_ref_info_new(folder /*, ref_info->msg_folder_finder */);
773 if (folder_ref == NULL)
774 goto err;
775
776 key.data = &folder;
777 key.len = sizeof(folder);
778 value.data = folder_ref;
779 value.len = 0;
780 r = chash_set(ref_info->folder_ref_info, &key, &value, NULL);
781 if (r < 0)
782 goto free;
783
784 return folder_ref;
785
786 free:
787 folder_ref_info_free(folder_ref);
788 err:
789 return NULL;
790}
791
792
793static void storage_folder_remove_ref(struct storage_ref_info * ref_info,
794 struct mailfolder * folder)
795{
796 struct folder_ref_info * folder_ref;
797 chashdatum key;
798 chashdatum value;
799 int r;
800
801 key.data = &folder;
802 key.len = sizeof(folder);
803 r = chash_get(ref_info->folder_ref_info, &key, &value);
804 if (r < 0)
805 return;
806
807 folder_ref = value.data;
808
809 if (folder_ref == NULL)
810 return;
811
812 folder_ref_info_free(folder_ref);
813
814 chash_delete(ref_info->folder_ref_info, &key, &value);
815}
816
817static int storage_folder_get_msg_list(struct storage_ref_info * ref_info,
818 struct mailfolder * folder,
819 struct mailmessage_list ** p_new_msg_list,
820 struct mailmessage_list ** p_lost_msg_list)
821{
822 struct folder_ref_info * folder_ref_info;
823
824 folder_ref_info = storage_get_folder_ref(ref_info, folder);
825 if (folder_ref_info == NULL)
826 return MAIL_ERROR_INVAL;
827
828 return folder_update_msg_list(folder_ref_info,
829 p_new_msg_list, p_lost_msg_list);
830}
831
832static int storage_folder_fetch_env_list(struct storage_ref_info * ref_info,
833 struct mailfolder * folder,
834 struct mailmessage_list * msg_list)
835{
836 struct folder_ref_info * folder_ref_info;
837
838 folder_ref_info = storage_get_folder_ref(ref_info, folder);
839 if (folder_ref_info == NULL)
840 return MAIL_ERROR_INVAL;
841
842 return folder_fetch_env_list(folder_ref_info, msg_list);
843}
844
845static void
846storage_folder_free_msg_list(struct storage_ref_info * ref_info,
847 struct mailfolder * folder,
848 struct mailmessage_list * env_list)
849{
850 struct folder_ref_info * folder_ref_info;
851
852 folder_ref_info = storage_get_folder_ref(ref_info, folder);
853
854 folder_free_msg_list(folder_ref_info, env_list);
855}
856
857
858/* connection and disconnection */
859
860static void
861folder_restore_session(struct folder_ref_info * ref_info)
862{
863 chashiter * iter;
864 mailsession * session;
865
866 session = ref_info->folder->fld_session;
867
868 for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ;
869 iter = chash_next(ref_info->msg_hash, iter)) {
870 chashdatum key;
871 mailmessage * msg;
872
873 chash_key(iter, &key);
874 memcpy(&msg, key.data, sizeof(msg));
875 msg->msg_session = session;
876
877 if (msg->msg_driver == imap_cached_message_driver) {
878 struct imap_cached_session_state_data * imap_cached_data;
879 mailmessage * ancestor_msg;
880
881 imap_cached_data = ref_info->folder->fld_session->sess_data;
882 ancestor_msg = msg->msg_data;
883 ancestor_msg->msg_session = imap_cached_data->imap_ancestor;
884 }
885 }
886}
887
888static void
889storage_restore_message_session(struct storage_ref_info * ref_info)
890{
891 chashiter * iter;
892
893 for(iter = chash_begin(ref_info->folder_ref_info) ; iter != NULL ;
894 iter = chash_next(ref_info->folder_ref_info, iter)) {
895 chashdatum data;
896 struct folder_ref_info * folder_ref_info;
897
898 chash_value(iter, &data);
899 folder_ref_info = data.data;
900 if (folder_ref_info->lost_session) {
901 if (folder_ref_info->folder->fld_session != NULL) {
902 /* restore folder session */
903 folder_restore_session(folder_ref_info);
904
905 folder_ref_info->lost_session = 0;
906 }
907 }
908 }
909}
910
911
912static int do_storage_connect(struct storage_ref_info * ref_info)
913{
914 int r;
915
916 r = mailstorage_connect(ref_info->storage);
917 if (r != MAIL_NO_ERROR)
918 return r;
919
920 return MAIL_NO_ERROR;
921}
922
923static void do_storage_disconnect(struct storage_ref_info * ref_info)
924{
925 clistiter * cur;
926
927 /* storage is disconnected, session is lost */
928 for(cur = clist_begin(ref_info->storage->sto_shared_folders) ; cur != NULL ;
929 cur = clist_next(cur)) {
930 struct folder_ref_info * folder_ref_info;
931 struct mailfolder * folder;
932
933 folder = clist_content(cur);
934 /* folder is disconnected (in storage), session is lost */
935
936 folder_ref_info = storage_get_folder_ref(ref_info, folder);
937 folder_ref_info->lost_session = 1;
938 }
939
940 /* storage is disconnected */
941 mailstorage_disconnect(ref_info->storage);
942}
943
944
945
946static int folder_connect(struct storage_ref_info * ref_info,
947 struct mailfolder * folder)
948{
949 int r;
950 struct folder_ref_info * folder_ref_info;
951
952 r = do_storage_connect(ref_info);
953 if (r != MAIL_NO_ERROR)
954 return r;
955
956 r = mailfolder_connect(folder);
957 if (r != MAIL_NO_ERROR)
958 return r;
959
960 folder_ref_info = storage_get_folder_ref(ref_info, folder);
961
962 return MAIL_NO_ERROR;
963}
964
965
966static void folder_disconnect(struct storage_ref_info * ref_info,
967 struct mailfolder * folder)
968{
969 struct folder_ref_info * folder_ref_info;
970
971 folder_ref_info = storage_get_folder_ref(ref_info, folder);
972
973 /* folder is disconnected, session is lost */
974 folder_ref_info->lost_session = 1;
975 mailfolder_disconnect(folder);
976
977 if (folder->fld_shared_session)
978 do_storage_disconnect(ref_info);
979}
980
981
982static int storage_folder_connect(struct storage_ref_info * ref_info,
983 struct mailfolder * folder)
984{
985 int r;
986 int res;
987 struct folder_ref_info * folder_ref_info;
988
989 folder_ref_info = storage_get_folder_ref(ref_info, folder);
990 if (folder_ref_info == NULL) {
991 folder_ref_info = storage_folder_add_ref(ref_info, folder);
992 if (folder_ref_info == NULL)
993 return MAIL_ERROR_MEMORY;
994 }
995
996 /* connect folder */
997
998 r = folder_connect(ref_info, folder);
999 if (r == MAIL_ERROR_STREAM) {
1000 /* properly handles disconnection */
1001
1002 /* reconnect */
1003 folder_disconnect(ref_info, folder);
1004 r = folder_connect(ref_info, folder);
1005 }
1006
1007 if (r != MAIL_NO_ERROR) {
1008 res = r;
1009 goto err;
1010 }
1011
1012 /* test folder connection */
1013 r = mailfolder_noop(folder);
1014 if (r == MAIL_ERROR_STREAM) {
1015 /* reconnect */
1016 folder_disconnect(ref_info, folder);
1017 r = folder_connect(ref_info, folder);
1018 }
1019
1020 if ((r != MAIL_ERROR_NOT_IMPLEMENTED) && (r != MAIL_NO_ERROR)) {
1021 res = r;
1022 goto disconnect;
1023 }
1024
1025 storage_restore_message_session(ref_info);
1026
1027 return MAIL_NO_ERROR;
1028
1029 disconnect:
1030 folder_disconnect(ref_info, folder);
1031 err:
1032 return res;
1033}
1034
1035static void storage_folder_disconnect(struct storage_ref_info * ref_info,
1036 struct mailfolder * folder)
1037{
1038 mailfolder_disconnect(folder);
1039 storage_folder_remove_ref(ref_info, folder);
1040}
1041
1042static int storage_connect(struct storage_ref_info * ref_info)
1043{
1044 int r;
1045 int res;
1046
1047 /* connect storage */
1048
1049 /* properly handles disconnection */
1050 r = do_storage_connect(ref_info);
1051 if (r == MAIL_ERROR_STREAM) {
1052 /* reconnect storage */
1053 do_storage_disconnect(ref_info);
1054 r = do_storage_connect(ref_info);
1055 }
1056
1057 if (r != MAIL_NO_ERROR) {
1058 res = r;
1059 goto disconnect;
1060 }
1061
1062 /* test storage connection */
1063
1064 r = mailsession_noop(ref_info->storage->sto_session);
1065 if ((r != MAIL_ERROR_NOT_IMPLEMENTED) && (r != MAIL_NO_ERROR)) {
1066 /* properly handles disconnection */
1067
1068 /* reconnect storage */
1069 do_storage_disconnect(ref_info);
1070 r = do_storage_connect(ref_info);
1071 }
1072
1073 if (r != MAIL_NO_ERROR) {
1074 res = r;
1075 goto disconnect;
1076 }
1077
1078 storage_restore_message_session(ref_info);
1079
1080 return MAIL_NO_ERROR;
1081
1082 disconnect:
1083 do_storage_disconnect(ref_info);
1084 return res;
1085}
1086
1087
1088static void storage_disconnect(struct storage_ref_info * ref_info)
1089{
1090 chashiter * iter;
1091
1092 /* disconnect folders */
1093 while ((iter = chash_begin(ref_info->folder_ref_info)) != NULL) {
1094 chashdatum key;
1095 struct mailfolder * folder;
1096
1097 chash_key(iter, &key);
1098 memcpy(&folder, key.data, sizeof(folder));
1099
1100 storage_folder_disconnect(ref_info, folder);
1101 }
1102
1103 /* disconnect storage */
1104 do_storage_disconnect(ref_info);
1105}
1106
1107
1108/* ************************************************************* */
1109/* interface for mailengine */
1110
1111struct mailengine {
1112 struct mailprivacy * privacy;
1113
1114#ifdef LIBETPAN_REENTRANT
1115 pthread_mutex_t storage_hash_lock;
1116#endif
1117 /* storage => storage_ref_info */
1118 chash * storage_hash;
1119
1120#if 0
1121 struct message_folder_finder msg_folder_finder;
1122#endif
1123};
1124
1125static struct storage_ref_info *
1126get_storage_ref_info(struct mailengine * engine,
1127 struct mailstorage * storage)
1128{
1129 chashdatum key;
1130 chashdatum data;
1131 int r;
1132 struct storage_ref_info * ref_info;
1133
1134 key.data = &storage;
1135 key.len = sizeof(storage);
1136#ifdef LIBETPAN_REENTRANT
1137 pthread_mutex_lock(&engine->storage_hash_lock);
1138#endif
1139 r = chash_get(engine->storage_hash, &key, &data);
1140#ifdef LIBETPAN_REENTRANT
1141 pthread_mutex_unlock(&engine->storage_hash_lock);
1142#endif
1143 if (r < 0)
1144 return NULL;
1145
1146 ref_info = data.data;
1147
1148 return ref_info;
1149}
1150
1151static struct storage_ref_info *
1152add_storage_ref_info(struct mailengine * engine,
1153 struct mailstorage * storage)
1154{
1155 chashdatum key;
1156 chashdatum data;
1157 int r;
1158 struct storage_ref_info * ref_info;
1159
1160 ref_info = storage_ref_info_new(storage
1161 /* , &engine->msg_folder_finder */);
1162 if (ref_info == NULL)
1163 goto err;
1164
1165 key.data = &storage;
1166 key.len = sizeof(storage);
1167 data.data = ref_info;
1168 data.len = 0;
1169
1170#ifdef LIBETPAN_REENTRANT
1171 pthread_mutex_lock(&engine->storage_hash_lock);
1172#endif
1173 r = chash_set(engine->storage_hash, &key, &data, NULL);
1174#ifdef LIBETPAN_REENTRANT
1175 pthread_mutex_unlock(&engine->storage_hash_lock);
1176#endif
1177 if (r < 0)
1178 goto free;
1179
1180 ref_info = data.data;
1181
1182 return ref_info;
1183
1184 free:
1185 storage_ref_info_free(ref_info);
1186 err:
1187 return NULL;
1188}
1189
1190static void
1191remove_storage_ref_info(struct mailengine * engine,
1192 struct mailstorage * storage)
1193{
1194 chashdatum key;
1195 chashdatum data;
1196 struct storage_ref_info * ref_info;
1197
1198 key.data = &storage;
1199 key.len = sizeof(storage);
1200
1201#ifdef LIBETPAN_REENTRANT
1202 pthread_mutex_lock(&engine->storage_hash_lock);
1203#endif
1204
1205 chash_get(engine->storage_hash, &key, &data);
1206 ref_info = data.data;
1207
1208 if (ref_info != NULL) {
1209 storage_ref_info_free(ref_info);
1210
1211 chash_delete(engine->storage_hash, &key, NULL);
1212 }
1213
1214#ifdef LIBETPAN_REENTRANT
1215 pthread_mutex_unlock(&engine->storage_hash_lock);
1216#endif
1217}
1218
1219struct mailengine *
1220libetpan_engine_new(struct mailprivacy * privacy)
1221{
1222 struct mailengine * engine;
1223 int r;
1224
1225 engine = malloc(sizeof(* engine));
1226 if (engine == NULL)
1227 goto err;
1228
1229 engine->privacy = privacy;
1230
1231#if 0
1232 r = message_folder_finder_init(&engine->msg_folder_finder);
1233 if (r != MAIL_NO_ERROR)
1234 goto free;
1235#endif
1236
1237#ifdef LIBETPAN_REENTRANT
1238 r = pthread_mutex_init(&engine->storage_hash_lock, NULL);
1239 if (r != 0)
1240 goto free;
1241#endif
1242
1243 engine->storage_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
1244 if (engine->storage_hash == NULL)
1245 goto destroy_mutex;
1246
1247 return engine;
1248
1249 destroy_mutex:
1250#ifdef LIBETPAN_REENTRANT
1251 pthread_mutex_destroy(&engine->storage_hash_lock);
1252#endif
1253#if 0
1254 finder_done:
1255 message_folder_finder_done(&engine->msg_folder_finder);
1256#endif
1257 free:
1258 free(engine);
1259 err:
1260 return NULL;
1261}
1262
1263void libetpan_engine_free(struct mailengine * engine)
1264{
1265 chash_free(engine->storage_hash);
1266#ifdef LIBETPAN_REENTRANT
1267 pthread_mutex_destroy(&engine->storage_hash_lock);
1268#endif
1269#if 0
1270 message_folder_finder_done(&engine->msg_folder_finder);
1271#endif
1272 free(engine);
1273}
1274
1275#if 0
1276static struct folder_ref_info *
1277message_get_folder_ref(struct mailengine * engine,
1278 mailmessage * msg)
1279{
1280 struct mailfolder * folder;
1281 struct mailstorage * storage;
1282 struct storage_ref_info * storage_ref_info;
1283 struct folder_ref_info * folder_ref_info;
1284
1285 folder = message_folder_finder_lookup(&engine->msg_folder_finder, msg);
1286 if (folder == NULL)
1287 storage = NULL;
1288 else
1289 storage = folder->fld_storage;
1290
1291 storage_ref_info = get_storage_ref_info(engine, storage);
1292
1293 folder_ref_info = storage_get_folder_ref(storage_ref_info, folder);
1294
1295 return folder_ref_info;
1296}
1297#endif
1298
1299static struct folder_ref_info *
1300message_get_folder_ref(struct mailengine * engine,
1301 mailmessage * msg)
1302{
1303 struct mailfolder * folder;
1304 struct mailstorage * storage;
1305 struct storage_ref_info * storage_ref_info;
1306 struct folder_ref_info * folder_ref_info;
1307
1308 folder = msg->msg_folder;
1309 if (folder == NULL)
1310 storage = NULL;
1311 else
1312 storage = folder->fld_storage;
1313
1314 storage_ref_info = get_storage_ref_info(engine, storage);
1315
1316 folder_ref_info = storage_get_folder_ref(storage_ref_info, folder);
1317
1318 return folder_ref_info;
1319}
1320
1321int libetpan_message_ref(struct mailengine * engine,
1322 mailmessage * msg)
1323{
1324 struct folder_ref_info * ref_info;
1325
1326 ref_info = message_get_folder_ref(engine, msg);
1327
1328 return folder_message_ref(ref_info, msg);
1329}
1330
1331int libetpan_message_unref(struct mailengine * engine,
1332 mailmessage * msg)
1333{
1334 struct folder_ref_info * ref_info;
1335
1336 ref_info = message_get_folder_ref(engine, msg);
1337
1338 return folder_message_unref(ref_info, msg);
1339}
1340
1341
1342int libetpan_message_mime_ref(struct mailengine * engine,
1343 mailmessage * msg)
1344{
1345 struct folder_ref_info * ref_info;
1346
1347 ref_info = message_get_folder_ref(engine, msg);
1348
1349 return folder_message_mime_ref(engine->privacy, ref_info, msg);
1350}
1351
1352int libetpan_message_mime_unref(struct mailengine * engine,
1353 mailmessage * msg)
1354{
1355 struct folder_ref_info * ref_info;
1356
1357 ref_info = message_get_folder_ref(engine, msg);
1358
1359 return folder_message_mime_unref(engine->privacy, ref_info, msg);
1360}
1361
1362int libetpan_folder_get_msg_list(struct mailengine * engine,
1363 struct mailfolder * folder,
1364 struct mailmessage_list ** p_new_msg_list,
1365 struct mailmessage_list ** p_lost_msg_list)
1366{
1367 struct storage_ref_info * ref_info;
1368
1369 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1370
1371 return storage_folder_get_msg_list(ref_info, folder,
1372 p_new_msg_list, p_lost_msg_list);
1373}
1374
1375int libetpan_folder_fetch_env_list(struct mailengine * engine,
1376 struct mailfolder * folder,
1377 struct mailmessage_list * msg_list)
1378{
1379 struct storage_ref_info * ref_info;
1380
1381 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1382
1383 return storage_folder_fetch_env_list(ref_info, folder, msg_list);
1384}
1385
1386void libetpan_folder_free_msg_list(struct mailengine * engine,
1387 struct mailfolder * folder,
1388 struct mailmessage_list * env_list)
1389{
1390 struct storage_ref_info * ref_info;
1391
1392 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1393
1394 storage_folder_free_msg_list(ref_info, folder, env_list);
1395}
1396
1397
1398int libetpan_storage_add(struct mailengine * engine,
1399 struct mailstorage * storage)
1400{
1401 struct storage_ref_info * storage_ref_info;
1402 struct folder_ref_info * folder_ref_info;
1403
1404 storage_ref_info = add_storage_ref_info(engine, storage);
1405 if (storage_ref_info == NULL)
1406 goto err;
1407
1408 if (storage == NULL) {
1409 folder_ref_info = storage_folder_add_ref(storage_ref_info, NULL);
1410 if (folder_ref_info == NULL)
1411 goto remove_storage_ref_info;
1412 }
1413
1414 return MAIL_NO_ERROR;
1415
1416 remove_storage_ref_info:
1417 remove_storage_ref_info(engine, storage);
1418 err:
1419 return MAIL_ERROR_MEMORY;
1420}
1421
1422void libetpan_storage_remove(struct mailengine * engine,
1423 struct mailstorage * storage)
1424{
1425 struct storage_ref_info * storage_ref_info;
1426
1427 storage_ref_info = get_storage_ref_info(engine, storage);
1428 if (storage == NULL) {
1429 storage_folder_remove_ref(storage_ref_info, NULL);
1430 }
1431
1432 remove_storage_ref_info(engine, storage);
1433}
1434
1435int libetpan_storage_connect(struct mailengine * engine,
1436 struct mailstorage * storage)
1437{
1438 struct storage_ref_info * ref_info;
1439
1440 ref_info = get_storage_ref_info(engine, storage);
1441
1442 return storage_connect(ref_info);
1443}
1444
1445
1446void libetpan_storage_disconnect(struct mailengine * engine,
1447 struct mailstorage * storage)
1448{
1449 struct storage_ref_info * ref_info;
1450
1451 ref_info = get_storage_ref_info(engine, storage);
1452
1453 storage_disconnect(ref_info);
1454}
1455
1456int libetpan_storage_used(struct mailengine * engine,
1457 struct mailstorage * storage)
1458{
1459 struct storage_ref_info * ref_info;
1460
1461 ref_info = get_storage_ref_info(engine, storage);
1462
1463 return (chash_count(ref_info->folder_ref_info) != 0);
1464}
1465
1466
1467int libetpan_folder_connect(struct mailengine * engine,
1468 struct mailfolder * folder)
1469{
1470 struct storage_ref_info * ref_info;
1471
1472 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1473
1474 return storage_folder_connect(ref_info, folder);
1475}
1476
1477
1478void libetpan_folder_disconnect(struct mailengine * engine,
1479 struct mailfolder * folder)
1480{
1481 struct storage_ref_info * ref_info;
1482
1483 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1484
1485 storage_folder_disconnect(ref_info, folder);
1486}
1487
1488
1489struct mailfolder *
1490libetpan_message_get_folder(struct mailengine * engine,
1491 mailmessage * msg)
1492{
1493#if 0
1494 return message_folder_finder_lookup(&engine->msg_folder_finder, msg);
1495#endif
1496 return msg->msg_folder;
1497}
1498
1499
1500struct mailstorage *
1501libetpan_message_get_storage(struct mailengine * engine,
1502 mailmessage * msg)
1503{
1504 struct mailfolder * folder;
1505
1506 folder = libetpan_message_get_folder(engine, msg);
1507
1508 if (folder == NULL)
1509 return NULL;
1510 else
1511 return folder->fld_storage;
1512}
1513
1514
1515int libetpan_message_register(struct mailengine * engine,
1516 struct mailfolder * folder,
1517 mailmessage * msg)
1518{
1519 struct storage_ref_info * storage_ref_info;
1520 int r;
1521 int res;
1522 struct folder_ref_info * folder_ref_info;
1523 struct mailstorage * storage;
1524
1525#if 0
1526 r = message_folder_finder_store(&engine->msg_folder_finder, msg, folder);
1527 if (r != MAIL_NO_ERROR) {
1528 res = r;
1529 goto err;
1530 }
1531#endif
1532
1533 if (folder != NULL)
1534 storage = folder->fld_storage;
1535 else
1536 storage = NULL;
1537
1538 storage_ref_info = get_storage_ref_info(engine, storage);
1539
1540 folder_ref_info = storage_get_folder_ref(storage_ref_info, folder);
1541
1542 r = folder_message_add(folder_ref_info, msg);
1543 if (r != MAIL_NO_ERROR) {
1544 res = r;
1545 goto delete;
1546 }
1547
1548 return MAIL_NO_ERROR;
1549
1550 delete:
1551#if 0
1552 message_folder_finder_delete(&engine->msg_folder_finder, msg);
1553#endif
1554 err:
1555 return res;
1556}
1557
1558struct mailprivacy *
1559libetpan_engine_get_privacy(struct mailengine * engine)
1560{
1561 return engine->privacy;
1562}
1563
1564
1565static void folder_debug(struct folder_ref_info * folder_ref_info, FILE * f)
1566{
1567 fprintf(f, "folder debug -- begin\n");
1568 if (folder_ref_info->folder == NULL) {
1569 fprintf(f, "NULL folder\n");
1570 }
1571 else {
1572 if (folder_ref_info->folder->fld_virtual_name != NULL)
1573 fprintf(f, "folder %s\n", folder_ref_info->folder->fld_virtual_name);
1574 else
1575 fprintf(f, "folder [no name]\n");
1576 }
1577
1578 fprintf(f, "message count: %i\n", chash_count(folder_ref_info->msg_hash));
1579 fprintf(f, "UID count: %i\n", chash_count(folder_ref_info->uid_hash));
1580 fprintf(f, "folder debug -- end\n");
1581}
1582
1583static void storage_debug(struct storage_ref_info * storage_ref_info, FILE * f)
1584{
1585 chashiter * iter;
1586
1587 fprintf(f, "storage debug -- begin\n");
1588 if (storage_ref_info->storage == NULL) {
1589 fprintf(f, "NULL storage\n");
1590 }
1591 else {
1592 if (storage_ref_info->storage->sto_id != NULL)
1593 fprintf(f, "storage %s\n", storage_ref_info->storage->sto_id);
1594 else
1595 fprintf(f, "storage [no name]\n");
1596 }
1597 fprintf(f, "folder count: %i\n",
1598 chash_count(storage_ref_info->folder_ref_info));
1599
1600 for(iter = chash_begin(storage_ref_info->folder_ref_info) ; iter != NULL ;
1601 iter = chash_next(storage_ref_info->folder_ref_info, iter)) {
1602 chashdatum data;
1603 struct folder_ref_info * folder_ref_info;
1604
1605 chash_value(iter, &data);
1606 folder_ref_info = data.data;
1607
1608 folder_debug(folder_ref_info, f);
1609 }
1610 fprintf(f, "storage debug -- end\n");
1611}
1612
1613void libetpan_engine_debug(struct mailengine * engine, FILE * f)
1614{
1615 chashiter * iter;
1616
1617 fprintf(f, "mail engine debug -- begin\n");
1618
1619 for(iter = chash_begin(engine->storage_hash) ; iter != NULL ;
1620 iter = chash_next(engine->storage_hash, iter)) {
1621 chashdatum data;
1622 struct storage_ref_info * storage_ref_info;
1623
1624 chash_value(iter, &data);
1625 storage_ref_info = data.data;
1626
1627 storage_debug(storage_ref_info, f);
1628 }
1629
1630#if 0
1631 fprintf(f, "global message references: %i\n",
1632 chash_count(engine->msg_folder_finder.message_hash));
1633#endif
1634 fprintf(f, "mail engine debug -- end\n");
1635}
1636
diff --git a/libetpan/src/engine/mailengine.h b/libetpan/src/engine/mailengine.h
new file mode 100644
index 0000000..acb6a16
--- a/dev/null
+++ b/libetpan/src/engine/mailengine.h
@@ -0,0 +1,190 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#ifndef MAILENGINE_H
37
38#define MAILENGINE_H
39
40#include <libetpan/mailmessage.h>
41#include <libetpan/mailfolder.h>
42#include <libetpan/mailprivacy_types.h>
43
44#ifdef __cplusplus
45extern "C" {
46#endif
47
48/*
49 to run things in thread, you must protect the storage again concurrency.
50*/
51
52
53/*
54 storage data
55*/
56
57struct mailengine *
58libetpan_engine_new(struct mailprivacy * privacy);
59
60void libetpan_engine_free(struct mailengine * engine);
61
62
63struct mailprivacy *
64libetpan_engine_get_privacy(struct mailengine * engine);
65
66
67/*
68 message ref and unref
69*/
70
71/*
72 these function can only take messages returned by get_msg_list()
73 as arguments.
74
75 these functions cannot fail.
76*/
77
78int libetpan_message_ref(struct mailengine * engine,
79 mailmessage * msg);
80
81int libetpan_message_unref(struct mailengine * engine,
82 mailmessage * msg);
83
84
85/*
86 when you want to access the MIME structure of the message
87 with msg->mime, you have to call libetpan_message_mime_ref()
88 and libetpan_message_mime_unref() when you have finished.
89
90 if libetpan_mime_ref() returns a value <= 0, it means this failed.
91 the value is -MAIL_ERROR_XXX
92*/
93
94int libetpan_message_mime_ref(struct mailengine * engine,
95 mailmessage * msg);
96
97int libetpan_message_mime_unref(struct mailengine * engine,
98 mailmessage * msg);
99
100/*
101 message list
102*/
103
104/*
105 libetpan_folder_get_msg_list()
106
107 This function returns two list.
108 - List of lost message (the messages that were previously returned
109 but that does no more exist) (p_lost_msg_list)
110 - List of valid messages (p_new_msg_list).
111
112 These two list can only be freed by libetpan_folder_free_msg_list()
113*/
114
115int libetpan_folder_get_msg_list(struct mailengine * engine,
116 struct mailfolder * folder,
117 struct mailmessage_list ** p_new_msg_list,
118 struct mailmessage_list ** p_lost_msg_list);
119
120int libetpan_folder_fetch_env_list(struct mailengine * engine,
121 struct mailfolder * folder,
122 struct mailmessage_list * msg_list);
123
124void libetpan_folder_free_msg_list(struct mailengine * engine,
125 struct mailfolder * folder,
126 struct mailmessage_list * env_list);
127
128
129/*
130 connect and disconnect storage
131*/
132
133int libetpan_storage_add(struct mailengine * engine,
134 struct mailstorage * storage);
135
136void libetpan_storage_remove(struct mailengine * engine,
137 struct mailstorage * storage);
138
139int libetpan_storage_connect(struct mailengine * engine,
140 struct mailstorage * storage);
141
142void libetpan_storage_disconnect(struct mailengine * engine,
143 struct mailstorage * storage);
144
145int libetpan_storage_used(struct mailengine * engine,
146 struct mailstorage * storage);
147
148
149/*
150 libetpan_folder_connect()
151 libetpan_folder_disconnect()
152
153 You can disconnect the folder only when you have freed all the message
154 you were given.
155*/
156
157int libetpan_folder_connect(struct mailengine * engine,
158 struct mailfolder * folder);
159
160void libetpan_folder_disconnect(struct mailengine * engine,
161 struct mailfolder * folder);
162
163
164struct mailfolder *
165libetpan_message_get_folder(struct mailengine * engine,
166 mailmessage * msg);
167
168struct mailstorage *
169libetpan_message_get_storage(struct mailengine * engine,
170 mailmessage * msg);
171
172
173/*
174 register a message
175*/
176
177int libetpan_message_register(struct mailengine * engine,
178 struct mailfolder * folder,
179 mailmessage * msg);
180
181
182void libetpan_engine_debug(struct mailengine * engine, FILE * f);
183
184extern void * engine_app;
185
186#ifdef __cplusplus
187}
188#endif
189
190#endif
diff --git a/libetpan/src/engine/mailprivacy.c b/libetpan/src/engine/mailprivacy.c
new file mode 100644
index 0000000..99cc50f
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy.c
@@ -0,0 +1,949 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailprivacy.h"
37
38#include <libetpan/libetpan.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <fcntl.h>
42#include <unistd.h>
43#include <sys/mman.h>
44#include <stdlib.h>
45#include <string.h>
46#include "mailprivacy_tools.h"
47
48carray * mailprivacy_get_protocols(struct mailprivacy * privacy)
49{
50 return privacy->protocols;
51}
52
53static int recursive_check_privacy(struct mailprivacy * privacy,
54 mailmessage * msg,
55 struct mailmime * mime);
56
57static int check_tmp_dir(char * tmp_dir)
58{
59 struct stat stat_info;
60 int r;
61
62 r = stat(tmp_dir, &stat_info);
63 if (r < 0)
64 return MAIL_ERROR_FILE;
65
66 /* check if the directory belongs to the user */
67 if (stat_info.st_uid != getuid())
68 return MAIL_ERROR_INVAL;
69
70 if ((stat_info.st_mode & 00777) != 0700) {
71 r = chmod(tmp_dir, 0700);
72 if (r < 0)
73 return MAIL_ERROR_FILE;
74 }
75
76 return MAIL_NO_ERROR;
77}
78
79struct mailprivacy * mailprivacy_new(char * tmp_dir, int make_alternative)
80{
81 struct mailprivacy * privacy;
82 int r;
83
84#if 0
85 r = check_tmp_dir(tmp_dir);
86 if (r != MAIL_NO_ERROR)
87 goto err;
88#endif
89
90 privacy = malloc(sizeof(* privacy));
91 if (privacy == NULL)
92 goto err;
93
94 privacy->tmp_dir = strdup(tmp_dir);
95 if (privacy->tmp_dir == NULL)
96 goto free;
97
98 privacy->msg_ref = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
99 if (privacy->msg_ref == NULL)
100 goto free_tmp_dir;
101
102 privacy->mmapstr = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
103 if (privacy->mmapstr == NULL)
104 goto free_msg_ref;
105
106 privacy->mime_ref = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
107 if (privacy->mime_ref == NULL)
108 goto free_mmapstr;
109
110 privacy->protocols = carray_new(16);
111 if (privacy->protocols == NULL)
112 goto free_mime_ref;
113
114 privacy->make_alternative = make_alternative;
115
116 return privacy;
117
118 free_mime_ref:
119 chash_free(privacy->mime_ref);
120 free_mmapstr:
121 chash_free(privacy->mmapstr);
122 free_msg_ref:
123 chash_free(privacy->msg_ref);
124 free_tmp_dir:
125 free(privacy->tmp_dir);
126 free:
127 free(privacy);
128 err:
129 return NULL;
130}
131
132void mailprivacy_free(struct mailprivacy * privacy)
133{
134 carray_free(privacy->protocols);
135 chash_free(privacy->mime_ref);
136 chash_free(privacy->mmapstr);
137 chash_free(privacy->msg_ref);
138 free(privacy->tmp_dir);
139 free(privacy);
140}
141
142static int msg_is_modified(struct mailprivacy * privacy,
143 mailmessage * msg)
144{
145 chashdatum key;
146 chashdatum data;
147 int r;
148
149 if (privacy == NULL)
150 return 0;
151
152 key.data = &msg;
153 key.len = sizeof(msg);
154
155 r = chash_get(privacy->msg_ref, &key, &data);
156 if (r < 0)
157 return 0;
158 else
159 return 1;
160}
161
162static int register_msg(struct mailprivacy * privacy,
163 mailmessage * msg)
164{
165 chashdatum key;
166 chashdatum data;
167 int r;
168
169 if (privacy == NULL)
170 return MAIL_NO_ERROR;
171
172 key.data = &msg;
173 key.len = sizeof(msg);
174 data.data = msg;
175 data.len = 0;
176
177 r = chash_set(privacy->msg_ref, &key, &data, NULL);
178 if (r < 0)
179 return MAIL_ERROR_MEMORY;
180 else
181 return MAIL_NO_ERROR;
182}
183
184static void unregister_message(struct mailprivacy * privacy,
185 mailmessage * msg)
186{
187 chashdatum key;
188
189 key.data = &msg;
190 key.len = sizeof(msg);
191
192 chash_delete(privacy->msg_ref, &key, NULL);
193}
194
195static int result_is_mmapstr(struct mailprivacy * privacy, char * str)
196{
197 chashdatum key;
198 chashdatum data;
199 int r;
200
201 key.data = &str;
202 key.len = sizeof(str);
203
204 r = chash_get(privacy->mmapstr, &key, &data);
205 if (r < 0)
206 return 0;
207 else
208 return 1;
209}
210
211static int register_result_mmapstr(struct mailprivacy * privacy,
212 char * content)
213{
214 chashdatum key;
215 chashdatum data;
216 int r;
217
218 key.data = &content;
219 key.len = sizeof(content);
220 data.data = content;
221 data.len = 0;
222
223 r = chash_set(privacy->mmapstr, &key, &data, NULL);
224 if (r < 0)
225 return MAIL_ERROR_MEMORY;
226
227 return 0;
228}
229
230static void unregister_result_mmapstr(struct mailprivacy * privacy,
231 char * str)
232{
233 chashdatum key;
234
235 mmap_string_unref(str);
236
237 key.data = &str;
238 key.len = sizeof(str);
239
240 chash_delete(privacy->mmapstr, &key, NULL);
241}
242
243static int register_mime(struct mailprivacy * privacy,
244 struct mailmime * mime)
245{
246 chashdatum key;
247 chashdatum data;
248 int r;
249
250 key.data = &mime;
251 key.len = sizeof(mime);
252 data.data = mime;
253 data.len = 0;
254
255 r = chash_set(privacy->mime_ref, &key, &data, NULL);
256 if (r < 0)
257 return MAIL_ERROR_MEMORY;
258 else
259 return MAIL_NO_ERROR;
260}
261
262static void unregister_mime(struct mailprivacy * privacy,
263 struct mailmime * mime)
264{
265 chashdatum key;
266
267 key.data = &mime;
268 key.len = sizeof(mime);
269
270 chash_delete(privacy->mime_ref, &key, NULL);
271}
272
273static int mime_is_registered(struct mailprivacy * privacy,
274 struct mailmime * mime)
275{
276 chashdatum key;
277 chashdatum data;
278 int r;
279
280 key.data = &mime;
281 key.len = sizeof(mime);
282
283 r = chash_get(privacy->mime_ref, &key, &data);
284 if (r < 0)
285 return 0;
286 else
287 return 1;
288}
289
290static int recursive_register_mime(struct mailprivacy * privacy,
291 struct mailmime * mime)
292{
293 clistiter * cur;
294 int r;
295
296 r = register_mime(privacy, mime);
297 if (r != MAIL_NO_ERROR)
298 return r;
299
300 switch (mime->mm_type) {
301 case MAILMIME_SINGLE:
302 break;
303
304 case MAILMIME_MULTIPLE:
305 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
306 cur != NULL ; cur = clist_next(cur)) {
307 struct mailmime * child;
308
309 child = clist_content(cur);
310
311 r = recursive_register_mime(privacy, child);
312 if (r != MAIL_NO_ERROR)
313 return r;
314 }
315 break;
316
317 case MAILMIME_MESSAGE:
318 if (mime->mm_data.mm_message.mm_msg_mime) {
319 r = recursive_register_mime(privacy,
320 mime->mm_data.mm_message.mm_msg_mime);
321 if (r != MAIL_NO_ERROR)
322 return r;
323 }
324 break;
325 }
326
327 return MAIL_NO_ERROR;
328}
329
330void mailprivacy_recursive_unregister_mime(struct mailprivacy * privacy,
331 struct mailmime * mime)
332{
333 clistiter * cur;
334
335 unregister_mime(privacy, mime);
336
337 switch (mime->mm_type) {
338 case MAILMIME_SINGLE:
339 break;
340
341 case MAILMIME_MULTIPLE:
342 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
343 cur != NULL ; cur = clist_next(cur)) {
344 struct mailmime * child;
345
346 child = clist_content(cur);
347
348 mailprivacy_recursive_unregister_mime(privacy, child);
349 }
350 break;
351
352 case MAILMIME_MESSAGE:
353 if (mime->mm_data.mm_message.mm_msg_mime)
354 mailprivacy_recursive_unregister_mime(privacy,
355 mime->mm_data.mm_message.mm_msg_mime);
356 break;
357 }
358}
359
360static void recursive_clear_registered_mime(struct mailprivacy * privacy,
361 struct mailmime * mime)
362{
363 clistiter * cur;
364 struct mailmime_data * data;
365
366 switch (mime->mm_type) {
367 case MAILMIME_SINGLE:
368 if (mime_is_registered(privacy, mime)) {
369 data = mime->mm_data.mm_single;
370 if (data != NULL) {
371 if (data->dt_type == MAILMIME_DATA_FILE)
372 unlink(data->dt_data.dt_filename);
373 }
374 }
375 break;
376
377 case MAILMIME_MULTIPLE:
378 if (mime_is_registered(privacy, mime)) {
379 data = mime->mm_data.mm_multipart.mm_preamble;
380 if (data != NULL) {
381 if (data->dt_type == MAILMIME_DATA_FILE)
382 unlink(data->dt_data.dt_filename);
383 }
384 data = mime->mm_data.mm_multipart.mm_epilogue;
385 if (data != NULL) {
386 if (data->dt_type == MAILMIME_DATA_FILE)
387 unlink(data->dt_data.dt_filename);
388 }
389 }
390 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
391 cur != NULL ; cur = clist_next(cur)) {
392 struct mailmime * child;
393
394 child = clist_content(cur);
395
396 recursive_clear_registered_mime(privacy, child);
397 }
398 break;
399
400 case MAILMIME_MESSAGE:
401 if (mime->mm_data.mm_message.mm_msg_mime)
402 recursive_clear_registered_mime(privacy,
403 mime->mm_data.mm_message.mm_msg_mime);
404 break;
405 }
406 unregister_mime(privacy, mime);
407}
408
409
410/* **************************************************** */
411/* fetch operations start here */
412
413
414static void recursive_clear_registered_mime(struct mailprivacy * privacy,
415 struct mailmime * mime);
416
417#if 0
418static void display_recursive_part(struct mailmime * mime)
419{
420 clistiter * cur;
421
422 fprintf(stderr, "part %p\n", mime->mm_body);
423 switch (mime->mm_type) {
424 case MAILMIME_SINGLE:
425 fprintf(stderr, "single %p - %i\n", mime->mm_data.mm_single,
426 mime->mm_data.mm_single->dt_type);
427 if (mime->mm_data.mm_single->dt_type == MAILMIME_DATA_TEXT) {
428 fprintf(stderr, "data : %p %i\n",
429 mime->mm_data.mm_single->dt_data.dt_text.dt_data,
430 mime->mm_data.mm_single->dt_data.dt_text.dt_length);
431 }
432 break;
433 case MAILMIME_MESSAGE:
434 fprintf(stderr, "message %p\n", mime->mm_data.mm_message.mm_msg_mime);
435 display_recursive_part(mime->mm_data.mm_message.mm_msg_mime);
436 break;
437 case MAILMIME_MULTIPLE:
438 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ;
439 cur = clist_next(cur)) {
440
441 fprintf(stderr, "multipart\n");
442 display_recursive_part(clist_content(cur));
443 }
444 break;
445 }
446}
447#endif
448
449int mailprivacy_msg_get_bodystructure(struct mailprivacy * privacy,
450 mailmessage * msg_info,
451 struct mailmime ** result)
452{
453 int r;
454 struct mailmime * mime;
455
456 if (msg_info->msg_mime != NULL)
457 return MAIL_NO_ERROR;
458
459 if (msg_is_modified(privacy, msg_info))
460 return MAIL_NO_ERROR;
461
462 r = mailmessage_get_bodystructure(msg_info, &mime);
463 if (r != MAIL_NO_ERROR)
464 return r;
465
466 /* modification on message if necessary */
467 r = recursive_check_privacy(privacy, msg_info, msg_info->msg_mime);
468 if (r != MAIL_NO_ERROR) {
469 * result = msg_info->msg_mime;
470 return MAIL_NO_ERROR;
471 }
472
473 r = register_msg(privacy, msg_info);
474 if (r != MAIL_NO_ERROR) {
475 recursive_clear_registered_mime(privacy, mime);
476 mailmessage_flush(msg_info);
477 return MAIL_ERROR_MEMORY;
478 }
479
480 * result = msg_info->msg_mime;
481
482 return MAIL_NO_ERROR;
483}
484
485void mailprivacy_msg_flush(struct mailprivacy * privacy,
486 mailmessage * msg_info)
487{
488 if (msg_is_modified(privacy, msg_info)) {
489 /* remove all modified parts */
490 if (msg_info->msg_mime != NULL)
491 recursive_clear_registered_mime(privacy, msg_info->msg_mime);
492 unregister_message(privacy, msg_info);
493 }
494
495 mailmessage_flush(msg_info);
496}
497
498static int fetch_registered_part(struct mailprivacy * privacy,
499 int (* fetch_section)(mailmessage *, struct mailmime *,
500 char **, size_t *),
501 struct mailmime * mime,
502 char ** result, size_t * result_len)
503{
504 mailmessage * dummy_msg;
505 int res;
506 char * content;
507 size_t content_len;
508 int r;
509
510 dummy_msg = mime_message_init(NULL);
511 if (dummy_msg == NULL) {
512 res = MAIL_ERROR_MEMORY;
513 goto err;
514 }
515
516 r = mime_message_set_tmpdir(dummy_msg, privacy->tmp_dir);
517 if (r != MAIL_NO_ERROR) {
518 res = MAIL_ERROR_MEMORY;
519 goto free_msg;
520 }
521
522 r = fetch_section(dummy_msg, mime, &content, &content_len);
523 if (r != MAIL_NO_ERROR) {
524 res = r;
525 goto free_msg;
526 }
527
528 r = register_result_mmapstr(privacy, content);
529 if (r != MAIL_NO_ERROR) {
530 res = r;
531 goto free_fetch;
532 }
533
534 mailmessage_free(dummy_msg);
535
536 * result = content;
537 * result_len = content_len;
538
539 return MAIL_NO_ERROR;
540
541 free_fetch:
542 mailmessage_fetch_result_free(dummy_msg, content);
543 free_msg:
544 mailmessage_free(dummy_msg);
545 err:
546 return res;
547}
548
549int mailprivacy_msg_fetch_section(struct mailprivacy * privacy,
550 mailmessage * msg_info,
551 struct mailmime * mime,
552 char ** result, size_t * result_len)
553{
554 if (msg_is_modified(privacy, msg_info) &&
555 mime_is_registered(privacy, mime)) {
556 return fetch_registered_part(privacy, mailmessage_fetch_section,
557 mime, result, result_len);
558 }
559
560 return mailmessage_fetch_section(msg_info, mime, result, result_len);
561}
562
563int mailprivacy_msg_fetch_section_header(struct mailprivacy * privacy,
564 mailmessage * msg_info,
565 struct mailmime * mime,
566 char ** result,
567 size_t * result_len)
568{
569 if (msg_is_modified(privacy, msg_info) &&
570 mime_is_registered(privacy, mime)) {
571 return fetch_registered_part(privacy, mailmessage_fetch_section_header,
572 mime, result, result_len);
573 }
574
575 return mailmessage_fetch_section_header(msg_info, mime, result, result_len);
576}
577
578int mailprivacy_msg_fetch_section_mime(struct mailprivacy * privacy,
579 mailmessage * msg_info,
580 struct mailmime * mime,
581 char ** result,
582 size_t * result_len)
583{
584 if (msg_is_modified(privacy, msg_info) &&
585 mime_is_registered(privacy, mime)) {
586 return fetch_registered_part(privacy, mailmessage_fetch_section_mime,
587 mime, result, result_len);
588 }
589
590 return mailmessage_fetch_section_mime(msg_info, mime, result, result_len);
591}
592
593int mailprivacy_msg_fetch_section_body(struct mailprivacy * privacy,
594 mailmessage * msg_info,
595 struct mailmime * mime,
596 char ** result,
597 size_t * result_len)
598{
599 if (msg_is_modified(privacy, msg_info) &&
600 mime_is_registered(privacy, mime)) {
601 return fetch_registered_part(privacy, mailmessage_fetch_section_body,
602 mime, result, result_len);
603 }
604
605 return mailmessage_fetch_section_body(msg_info, mime, result, result_len);
606}
607
608void mailprivacy_msg_fetch_result_free(struct mailprivacy * privacy,
609 mailmessage * msg_info,
610 char * msg)
611{
612 if (msg == NULL)
613 return;
614
615 if (msg_is_modified(privacy, msg_info)) {
616 if (result_is_mmapstr(privacy, msg)) {
617 unregister_result_mmapstr(privacy, msg);
618 return;
619 }
620 }
621
622 mailmessage_fetch_result_free(msg_info, msg);
623}
624
625int mailprivacy_msg_fetch(struct mailprivacy * privacy,
626 mailmessage * msg_info,
627 char ** result,
628 size_t * result_len)
629{
630 return mailmessage_fetch(msg_info, result, result_len);
631}
632
633int mailprivacy_msg_fetch_header(struct mailprivacy * privacy,
634 mailmessage * msg_info,
635 char ** result,
636 size_t * result_len)
637{
638 return mailmessage_fetch_header(msg_info, result, result_len);
639}
640
641/* end of fetch operations */
642/* **************************************************** */
643
644static int privacy_handler(struct mailprivacy * privacy,
645 mailmessage * msg,
646 struct mailmime * mime, struct mailmime ** result);
647
648
649
650static struct mailmime *
651mime_add_alternative(struct mailprivacy * privacy,
652 mailmessage * msg,
653 struct mailmime * mime,
654 struct mailmime * alternative)
655{
656 struct mailmime * multipart;
657 int r;
658 struct mailmime * mime_copy;
659 char original_filename[PATH_MAX];
660
661 if (mime->mm_parent == NULL)
662 goto err;
663
664 r = mailmime_new_with_content("multipart/alternative", NULL, &multipart);
665 if (r != MAILIMF_NO_ERROR)
666 goto err;
667
668 r = mailmime_smart_add_part(multipart, alternative);
669 if (r != MAILIMF_NO_ERROR) {
670 goto free_multipart;
671 }
672
673 /* get copy of mime part "mime" and set parts */
674
675 r = mailprivacy_fetch_mime_body_to_file(privacy,
676 original_filename, sizeof(original_filename),
677 msg, mime);
678 if (r != MAIL_NO_ERROR)
679 goto detach_alternative;
680
681 r = mailprivacy_get_part_from_file(privacy, 0,
682 original_filename, &mime_copy);
683 unlink(original_filename);
684 if (r != MAIL_NO_ERROR) {
685 goto detach_alternative;
686 }
687
688 r = mailmime_smart_add_part(multipart, mime_copy);
689 if (r != MAILIMF_NO_ERROR) {
690 goto free_mime_copy;
691 }
692
693 r = recursive_register_mime(privacy, multipart);
694 if (r != MAIL_NO_ERROR)
695 goto detach_mime_copy;
696
697 mailmime_substitute(mime, multipart);
698
699 mailmime_free(mime);
700
701 return multipart;
702
703 detach_mime_copy:
704 mailprivacy_recursive_unregister_mime(privacy, multipart);
705 mailmime_remove_part(alternative);
706 free_mime_copy:
707 mailprivacy_mime_clear(mime_copy);
708 mailmime_free(mime_copy);
709 detach_alternative:
710 mailmime_remove_part(alternative);
711 free_multipart:
712 mailmime_free(multipart);
713 err:
714 return NULL;
715}
716
717/*
718 recursive_check_privacy returns MAIL_NO_ERROR if at least one
719 part is using a privacy protocol.
720*/
721
722static int recursive_check_privacy(struct mailprivacy * privacy,
723 mailmessage * msg,
724 struct mailmime * mime)
725{
726 int r;
727 clistiter * cur;
728 struct mailmime * alternative;
729 int res;
730 struct mailmime * multipart;
731
732 if (privacy == NULL)
733 return MAIL_NO_ERROR;
734
735 if (mime_is_registered(privacy, mime))
736 return MAIL_ERROR_INVAL;
737
738 r = privacy_handler(privacy, msg, mime, &alternative);
739 if (r == MAIL_NO_ERROR) {
740 if (privacy->make_alternative) {
741 multipart = mime_add_alternative(privacy, msg, mime, alternative);
742 if (multipart == NULL) {
743 mailprivacy_mime_clear(alternative);
744 mailmime_free(alternative);
745 return MAIL_ERROR_MEMORY;
746 }
747 }
748 else {
749 mailmime_substitute(mime, alternative);
750 mailmime_free(mime);
751 mime = NULL;
752 }
753
754 return MAIL_NO_ERROR;
755 }
756 else {
757 switch (mime->mm_type) {
758 case MAILMIME_SINGLE:
759 return MAIL_ERROR_INVAL;
760
761 case MAILMIME_MULTIPLE:
762 res = MAIL_ERROR_INVAL;
763
764 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
765 cur != NULL ; cur = clist_next(cur)) {
766 struct mailmime * child;
767
768 child = clist_content(cur);
769
770 r = recursive_check_privacy(privacy, msg, child);
771 if (r == MAIL_NO_ERROR)
772 res = MAIL_NO_ERROR;
773 }
774
775 return res;
776
777 case MAILMIME_MESSAGE:
778 if (mime->mm_data.mm_message.mm_msg_mime != NULL)
779 return recursive_check_privacy(privacy, msg,
780 mime->mm_data.mm_message.mm_msg_mime);
781 return MAIL_ERROR_INVAL;
782
783 default:
784 return MAIL_ERROR_INVAL;
785 }
786 }
787}
788
789static int privacy_handler(struct mailprivacy * privacy,
790 mailmessage * msg,
791 struct mailmime * mime, struct mailmime ** result)
792{
793 int r;
794 struct mailmime * alternative_mime;
795 unsigned int i;
796
797 alternative_mime = NULL;
798 for(i = 0 ; i < carray_count(privacy->protocols) ; i ++) {
799 struct mailprivacy_protocol * protocol;
800
801 protocol = carray_get(privacy->protocols, i);
802
803 if (protocol->decrypt != NULL) {
804 r = protocol->decrypt(privacy, msg, mime, &alternative_mime);
805 if (r == MAIL_NO_ERROR) {
806
807 * result = alternative_mime;
808
809 return MAIL_NO_ERROR;
810 }
811 }
812 }
813
814 return MAIL_ERROR_INVAL;
815}
816
817int mailprivacy_register(struct mailprivacy * privacy,
818 struct mailprivacy_protocol * protocol)
819{
820 int r;
821
822 r = carray_add(privacy->protocols, protocol, NULL);
823 if (r < 0)
824 return MAIL_ERROR_MEMORY;
825
826 return MAIL_NO_ERROR;
827}
828
829void mailprivacy_unregister(struct mailprivacy * privacy,
830 struct mailprivacy_protocol * protocol)
831{
832 unsigned int i;
833
834 for(i = 0 ; i < carray_count(privacy->protocols) ; i ++) {
835 if (carray_get(privacy->protocols, i) == protocol) {
836 carray_delete(privacy->protocols, i);
837 return;
838 }
839 }
840}
841
842static struct mailprivacy_protocol *
843get_protocol(struct mailprivacy * privacy, char * privacy_driver)
844{
845 unsigned int i;
846
847 for(i = 0 ; i < carray_count(privacy->protocols) ; i ++) {
848 struct mailprivacy_protocol * protocol;
849
850 protocol = carray_get(privacy->protocols, i);
851 if (strcasecmp(protocol->name, privacy_driver) == 0)
852 return protocol;
853 }
854
855 return NULL;
856}
857
858static struct mailprivacy_encryption *
859get_encryption(struct mailprivacy_protocol * protocol,
860 char * privacy_encryption)
861{
862 int i;
863
864 for(i = 0 ; i < protocol->encryption_count ; i ++) {
865 struct mailprivacy_encryption * encryption;
866
867 encryption = &protocol->encryption_tab[i];
868 if (strcasecmp(encryption->name, privacy_encryption) == 0)
869 return encryption;
870 }
871
872 return NULL;
873}
874
875int mailprivacy_encrypt(struct mailprivacy * privacy,
876 char * privacy_driver, char * privacy_encryption,
877 struct mailmime * mime,
878 struct mailmime ** result)
879{
880 struct mailprivacy_protocol * protocol;
881 struct mailprivacy_encryption * encryption;
882 int r;
883
884 protocol = get_protocol(privacy, privacy_driver);
885 if (protocol == NULL)
886 return MAIL_ERROR_INVAL;
887
888 encryption = get_encryption(protocol, privacy_encryption);
889 if (encryption == NULL)
890 return MAIL_ERROR_INVAL;
891
892 if (encryption->encrypt == NULL)
893 return MAIL_ERROR_NOT_IMPLEMENTED;
894
895 r = encryption->encrypt(privacy, mime, result);
896 if (r != MAIL_NO_ERROR)
897 return r;
898
899 return MAIL_NO_ERROR;
900}
901
902char * mailprivacy_get_encryption_name(struct mailprivacy * privacy,
903 char * privacy_driver, char * privacy_encryption)
904{
905 struct mailprivacy_protocol * protocol;
906 struct mailprivacy_encryption * encryption;
907
908 protocol = get_protocol(privacy, privacy_driver);
909 if (protocol == NULL)
910 return NULL;
911
912 encryption = get_encryption(protocol, privacy_encryption);
913 if (encryption == NULL)
914 return NULL;
915
916 return encryption->description;
917}
918
919int mailprivacy_is_encrypted(struct mailprivacy * privacy,
920 mailmessage * msg,
921 struct mailmime * mime)
922{
923 unsigned int i;
924
925 if (mime_is_registered(privacy, mime))
926 return 0;
927
928 for(i = 0 ; i < carray_count(privacy->protocols) ; i ++) {
929 struct mailprivacy_protocol * protocol;
930
931 protocol = carray_get(privacy->protocols, i);
932
933 if (protocol->is_encrypted != NULL) {
934 if (protocol->is_encrypted(privacy, msg, mime))
935 return 1;
936 }
937 }
938
939 return 0;
940}
941
942void mailprivacy_debug(struct mailprivacy * privacy, FILE * f)
943{
944 fprintf(f, "privacy debug -- begin\n");
945 fprintf(f, "registered message: %i\n", chash_count(privacy->msg_ref));
946 fprintf(f, "registered MMAPStr: %i\n", chash_count(privacy->mmapstr));
947 fprintf(f, "registered mailmime: %i\n", chash_count(privacy->mime_ref));
948 fprintf(f, "privacy debug -- end\n");
949}
diff --git a/libetpan/src/engine/mailprivacy.h b/libetpan/src/engine/mailprivacy.h
new file mode 100644
index 0000000..1f77331
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy.h
@@ -0,0 +1,117 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#ifndef MAILPRIVACY_H
37
38#define MAILPRIVACY_H
39
40#include <libetpan/mailmessage.h>
41#include <libetpan/mailprivacy_types.h>
42#include <libetpan/mailprivacy_tools.h>
43
44struct mailprivacy * mailprivacy_new(char * tmp_dir, int make_alternative);
45
46void mailprivacy_free(struct mailprivacy * privacy);
47
48int mailprivacy_msg_get_bodystructure(struct mailprivacy * privacy,
49 mailmessage * msg_info,
50 struct mailmime ** result);
51
52void mailprivacy_msg_flush(struct mailprivacy * privacy,
53 mailmessage * msg_info);
54
55int mailprivacy_msg_fetch_section(struct mailprivacy * privacy,
56 mailmessage * msg_info,
57 struct mailmime * mime,
58 char ** result, size_t * result_len);
59
60int mailprivacy_msg_fetch_section_header(struct mailprivacy * privacy,
61 mailmessage * msg_info,
62 struct mailmime * mime,
63 char ** result,
64 size_t * result_len);
65
66int mailprivacy_msg_fetch_section_mime(struct mailprivacy * privacy,
67 mailmessage * msg_info,
68 struct mailmime * mime,
69 char ** result,
70 size_t * result_len);
71
72int mailprivacy_msg_fetch_section_body(struct mailprivacy * privacy,
73 mailmessage * msg_info,
74 struct mailmime * mime,
75 char ** result,
76 size_t * result_len);
77
78void mailprivacy_msg_fetch_result_free(struct mailprivacy * privacy,
79 mailmessage * msg_info,
80 char * msg);
81
82int mailprivacy_msg_fetch(struct mailprivacy * privacy,
83 mailmessage * msg_info,
84 char ** result,
85 size_t * result_len);
86
87int mailprivacy_msg_fetch_header(struct mailprivacy * privacy,
88 mailmessage * msg_info,
89 char ** result,
90 size_t * result_len);
91
92int mailprivacy_register(struct mailprivacy * privacy,
93 struct mailprivacy_protocol * protocol);
94
95void mailprivacy_unregister(struct mailprivacy * privacy,
96 struct mailprivacy_protocol * protocol);
97
98char * mailprivacy_get_encryption_name(struct mailprivacy * privacy,
99 char * privacy_driver, char * privacy_encryption);
100
101int mailprivacy_encrypt(struct mailprivacy * privacy,
102 char * privacy_driver, char * privacy_encryption,
103 struct mailmime * mime,
104 struct mailmime ** result);
105
106void mailprivacy_debug(struct mailprivacy * privacy, FILE * f);
107
108carray * mailprivacy_get_protocols(struct mailprivacy * privacy);
109
110int mailprivacy_is_encrypted(struct mailprivacy * privacy,
111 mailmessage * msg,
112 struct mailmime * mime);
113
114void mailprivacy_recursive_unregister_mime(struct mailprivacy * privacy,
115 struct mailmime * mime);
116
117#endif
diff --git a/libetpan/src/engine/mailprivacy_gnupg.c b/libetpan/src/engine/mailprivacy_gnupg.c
new file mode 100644
index 0000000..01dcc80
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_gnupg.c
@@ -0,0 +1,2614 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailprivacy_gnupg.h"
37
38#include "mailprivacy.h"
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <fcntl.h>
42#include <unistd.h>
43#include <sys/mman.h>
44#include <string.h>
45#include <sys/wait.h>
46#include <stdlib.h>
47#include "mailprivacy_tools.h"
48#include <libetpan/mailmime.h>
49#include <libetpan/libetpan-config.h>
50
51static int pgp_is_encrypted(struct mailmime * mime)
52{
53 if (mime->mm_content_type != NULL) {
54 clistiter * cur;
55
56 if (strcasecmp(mime->mm_content_type->ct_subtype, "encrypted") != 0)
57 return 0;
58
59 for(cur = clist_begin(mime->mm_content_type->ct_parameters) ; cur != NULL ;
60 cur = clist_next(cur)) {
61 struct mailmime_parameter * param;
62
63 param = clist_content(cur);
64
65 if ((strcasecmp(param->pa_name, "protocol") == 0) &&
66 (strcasecmp(param->pa_value, "application/pgp-encrypted") == 0))
67 return 1;
68 }
69 }
70
71 return 0;
72}
73
74static int pgp_is_signed(struct mailmime * mime)
75{
76 if (mime->mm_content_type != NULL) {
77 clistiter * cur;
78
79 if (strcasecmp(mime->mm_content_type->ct_subtype, "signed") != 0)
80 return 0;
81
82 for(cur = clist_begin(mime->mm_content_type->ct_parameters) ;
83 cur != NULL ; cur = clist_next(cur)) {
84 struct mailmime_parameter * param;
85
86 param = clist_content(cur);
87
88 if ((strcasecmp(param->pa_name, "protocol") == 0) &&
89 (strcasecmp(param->pa_value, "application/pgp-signature") == 0))
90 return 1;
91 }
92 }
93
94 return 0;
95}
96
97#define PGP_SIGNED "-----BEGIN PGP SIGNED MESSAGE-----"
98
99int pgp_is_clearsigned(char * data, size_t len)
100{
101 if (len >= strlen(PGP_SIGNED))
102 if (strncmp(data, PGP_SIGNED, sizeof(PGP_SIGNED) - 1) == 0)
103 return 1;
104
105 return 0;
106}
107
108#define PGP_CRYPTED "-----BEGIN PGP MESSAGE-----"
109
110int pgp_is_crypted_armor(char * data, size_t len)
111{
112 if (len >= strlen(PGP_CRYPTED))
113 if (strncmp(data, PGP_CRYPTED, sizeof(PGP_CRYPTED) - 1) == 0)
114 return 1;
115
116 return 0;
117}
118
119
120#define BUF_SIZE 1024
121
122enum {
123 NO_ERROR_PGP = 0,
124 ERROR_PGP_CHECK,
125 ERROR_PGP_COMMAND,
126 ERROR_PGP_FILE,
127};
128
129/* write output to a file */
130
131static int get_pgp_output(FILE * dest_f, char * command)
132{
133 FILE * p;
134 char buf[BUF_SIZE];
135 size_t size;
136 int res;
137 int status;
138 char command_redirected[PATH_MAX];
139
140 snprintf(command_redirected, sizeof(command_redirected), "%s 2>&1", command);
141
142 /*
143 flush buffer so that it is not flushed more than once when forking
144 */
145 fflush(dest_f);
146
147 p = popen(command_redirected, "r");
148 if (p == NULL) {
149 res = ERROR_PGP_COMMAND;
150 goto err;
151 }
152
153 while ((size = fread(buf, 1, sizeof(buf), p)) != 0) {
154 size_t written;
155
156 written = fwrite(buf, 1, size, dest_f);
157 if (written != size) {
158 res = ERROR_PGP_FILE;
159 goto close;
160 }
161 }
162 status = pclose(p);
163
164 if (WEXITSTATUS(status) != 0)
165 return ERROR_PGP_CHECK;
166 else
167 return NO_ERROR_PGP;
168
169 close:
170 pclose(p);
171 err:
172 return res;
173}
174
175#define PGP_DECRYPT_DESCRIPTION "PGP encrypted part\r\n"
176#define PGP_DECRYPT_FAILED "PGP decryption FAILED\r\n"
177#define PGP_DECRYPT_SUCCESS "PGP decryption success\r\n"
178
179/* extracted from mailprivacy_smime.c -- begin */
180
181static char * get_first_from_addr(struct mailmime * mime)
182{
183 clistiter * cur;
184 struct mailimf_single_fields single_fields;
185 struct mailimf_fields * fields;
186 struct mailimf_mailbox * mb;
187
188 if (mime->mm_type != MAILMIME_MESSAGE)
189 return NULL;
190
191 fields = mime->mm_data.mm_message.mm_fields;
192 if (fields == NULL)
193 return NULL;
194
195 mailimf_single_fields_init(&single_fields, fields);
196
197 if (single_fields.fld_from == NULL)
198 return NULL;
199
200 cur = clist_begin(single_fields.fld_from->frm_mb_list->mb_list);
201 if (cur == NULL)
202 return NULL;
203
204 mb = clist_content(cur);
205
206 return mb->mb_addr_spec;
207}
208
209/* extracted from mailprivacy_smime.c -- end */
210
211static int pgp_decrypt(struct mailprivacy * privacy,
212 mailmessage * msg,
213 struct mailmime * mime, struct mailmime ** result)
214{
215 char default_key[PATH_MAX];
216 struct mailmime * version_mime;
217 struct mailmime * encrypted_mime;
218 clistiter * cur;
219 char encrypted_filename[PATH_MAX];
220 char description_filename[PATH_MAX];
221 FILE * description_f;
222 char decrypted_filename[PATH_MAX];
223 FILE * decrypted_f;
224 char command[PATH_MAX];
225 struct mailmime * description_mime;
226 struct mailmime * decrypted_mime;
227 int r;
228 int res;
229 int decrypt_ok;
230 char quoted_decrypted_filename[PATH_MAX];
231 char quoted_encrypted_filename[PATH_MAX];
232 struct mailmime * multipart;
233 char * email;
234
235 /* get the two parts of the PGP message */
236
237 cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list);
238 if (cur == NULL) {
239 res = MAIL_ERROR_INVAL;
240 goto err;
241 }
242
243 version_mime = clist_content(cur);
244 cur = clist_next(cur);
245 if (cur == NULL) {
246 res = MAIL_ERROR_INVAL;
247 goto err;
248 }
249
250 encrypted_mime = clist_content(cur);
251
252 /* fetch the second section, that's the useful one */
253
254 r = mailprivacy_fetch_decoded_to_file(privacy,
255 encrypted_filename, sizeof(encrypted_filename),
256 msg, encrypted_mime);
257 if (r != MAIL_NO_ERROR) {
258 res = r;
259 goto err;
260 }
261
262 /* we are in a safe directory */
263
264 decrypted_f = mailprivacy_get_tmp_file(privacy,
265 decrypted_filename,
266 sizeof(decrypted_filename));
267 if (decrypted_f == NULL) {
268 res = MAIL_ERROR_FILE;
269 goto unlink_encrypted;
270 }
271 fclose(decrypted_f);
272
273 /* description */
274
275 description_f = mailprivacy_get_tmp_file(privacy,
276 description_filename,
277 sizeof(description_filename));
278 if (description_f == NULL) {
279 res = MAIL_ERROR_FILE;
280 goto unlink_decrypted;
281 }
282
283 fprintf(description_f, PGP_DECRYPT_DESCRIPTION);
284
285 /* get encryption key */
286
287 * default_key = '\0';
288 email = get_first_from_addr(mime);
289 if (email != NULL)
290 snprintf(default_key, sizeof(default_key),
291 "--default-key %s", email);
292
293 /* run the command */
294
295 r = mail_quote_filename(quoted_encrypted_filename,
296 sizeof(quoted_encrypted_filename), encrypted_filename);
297 if (r < 0) {
298 fclose(description_f);
299 res = MAIL_ERROR_MEMORY;
300 goto unlink_description;
301 }
302
303 r = mail_quote_filename(quoted_decrypted_filename,
304 sizeof(quoted_decrypted_filename), decrypted_filename);
305 if (r < 0) {
306 fclose(description_f);
307 res = MAIL_ERROR_MEMORY;
308 goto unlink_description;
309 }
310
311 decrypt_ok = 0;
312 snprintf(command, sizeof(command),
313 "gpg -q --batch --yes --out %s %s --decrypt %s",
314 quoted_decrypted_filename, default_key, quoted_encrypted_filename);
315
316 r = get_pgp_output(description_f, command);
317 switch (r) {
318 case NO_ERROR_PGP:
319 decrypt_ok = 1;
320 break;
321 case ERROR_PGP_CHECK:
322 decrypt_ok = 0;
323 break;
324 case ERROR_PGP_COMMAND:
325 fclose(description_f);
326 res = MAIL_ERROR_COMMAND;
327 goto unlink_description;
328 case ERROR_PGP_FILE:
329 fclose(description_f);
330 res = MAIL_ERROR_FILE;
331 goto unlink_description;
332 }
333 if (decrypt_ok)
334 fprintf(description_f, PGP_DECRYPT_SUCCESS);
335 else
336 fprintf(description_f, PGP_DECRYPT_FAILED);
337 fclose(description_f);
338
339 /* building multipart */
340
341 r = mailmime_new_with_content("multipart/x-decrypted", NULL, &multipart);
342 if (r != MAILIMF_NO_ERROR) {
343 res = MAIL_ERROR_MEMORY;
344 goto unlink_description;
345 }
346
347 /* building the description part */
348
349 description_mime = mailprivacy_new_file_part(privacy,
350 description_filename,
351 "text/plain", MAILMIME_MECHANISM_8BIT);
352 if (description_mime == NULL) {
353 mailprivacy_mime_clear(multipart);
354 mailmime_free(multipart);
355 res = MAIL_ERROR_MEMORY;
356 goto unlink_description;
357 }
358
359 /* adds the description part */
360
361 r = mailmime_smart_add_part(multipart, description_mime);
362 if (r != MAIL_NO_ERROR) {
363 mailprivacy_mime_clear(description_mime);
364 mailmime_free(description_mime);
365 mailprivacy_mime_clear(multipart);
366 mailmime_free(multipart);
367 res = MAIL_ERROR_MEMORY;
368 goto unlink_description;
369 }
370
371 /* building the decrypted part */
372
373 r = mailprivacy_get_part_from_file(privacy, 1,
374 decrypted_filename, &decrypted_mime);
375 if (r == MAIL_NO_ERROR) {
376 /* adds the decrypted part */
377
378 r = mailmime_smart_add_part(multipart, decrypted_mime);
379 if (r != MAIL_NO_ERROR) {
380 mailprivacy_mime_clear(decrypted_mime);
381 mailmime_free(decrypted_mime);
382 mailprivacy_mime_clear(multipart);
383 mailmime_free(multipart);
384 res = MAIL_ERROR_MEMORY;
385 goto unlink_description;
386 }
387 }
388
389 unlink(description_filename);
390 unlink(decrypted_filename);
391 unlink(encrypted_filename);
392
393 * result = multipart;
394
395 return MAIL_NO_ERROR;
396
397 unlink_description:
398 unlink(description_filename);
399 unlink_decrypted:
400 unlink(decrypted_filename);
401 unlink_encrypted:
402 unlink(encrypted_filename);
403 err:
404 return res;
405}
406
407#define PGP_VERIFY_DESCRIPTION "PGP verify signed message\r\n"
408#define PGP_VERIFY_FAILED "PGP verification FAILED\r\n"
409#define PGP_VERIFY_SUCCESS "PGP verification success\r\n"
410
411static int
412pgp_verify(struct mailprivacy * privacy,
413 mailmessage * msg,
414 struct mailmime * mime, struct mailmime ** result)
415{
416 struct mailmime * signed_mime;
417 struct mailmime * signature_mime;
418 char signed_filename[PATH_MAX];
419 char signature_filename[PATH_MAX];
420 int res;
421 int r;
422 clistiter * cur;
423 char command[PATH_MAX];
424 int sign_ok;
425 struct mailmime * description_mime;
426 FILE * description_f;
427 char description_filename[PATH_MAX];
428 char quoted_signed_filename[PATH_MAX];
429 char quoted_signature_filename[PATH_MAX];
430 struct mailmime * multipart;
431 struct mailmime * signed_msg_mime;
432
433 /* get the two parts of the PGP message */
434
435 cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list);
436 if (cur == NULL) {
437 res = MAIL_ERROR_INVAL;
438 goto err;
439 }
440
441 signed_mime = clist_content(cur);
442 cur = clist_next(cur);
443 if (cur == NULL) {
444 res = MAIL_ERROR_INVAL;
445 goto err;
446 }
447
448 signature_mime = clist_content(cur);
449
450 /* fetch signed part and write it to a file */
451
452 r = mailprivacy_fetch_mime_body_to_file(privacy,
453 signed_filename, sizeof(signed_filename),
454 msg, signed_mime);
455 if (r != MAIL_NO_ERROR) {
456 res = r;
457 goto err;
458 }
459
460 /* fetch signed part and write it to a file */
461
462 r = mailprivacy_fetch_decoded_to_file(privacy,
463 signature_filename, sizeof(signature_filename),
464 msg, signature_mime);
465 if (r != MAIL_NO_ERROR) {
466 res = r;
467 goto unlink_signed;
468 }
469
470 /* description */
471
472 description_f = mailprivacy_get_tmp_file(privacy,
473 description_filename,
474 sizeof(description_filename));
475 if (description_f == NULL) {
476 res = MAIL_ERROR_FILE;
477 goto unlink_signature;
478 }
479
480 fprintf(description_f, PGP_VERIFY_DESCRIPTION);
481
482 /* run the command */
483
484 r = mail_quote_filename(quoted_signature_filename,
485 sizeof(quoted_signature_filename), signature_filename);
486 if (r < 0) {
487 fclose(description_f);
488 res = MAIL_ERROR_MEMORY;
489 goto unlink_description;
490 }
491
492 r = mail_quote_filename(quoted_signed_filename,
493 sizeof(quoted_signed_filename), signed_filename);
494 if (r < 0) {
495 fclose(description_f);
496 res = MAIL_ERROR_MEMORY;
497 goto unlink_description;
498 }
499
500 sign_ok = 0;
501 snprintf(command, sizeof(command), "gpg -q --batch --yes --verify %s %s",
502 quoted_signature_filename, quoted_signed_filename);
503
504 r = get_pgp_output(description_f, command);
505 switch (r) {
506 case NO_ERROR_PGP:
507 sign_ok = 1;
508 break;
509 case ERROR_PGP_CHECK:
510 sign_ok = 0;
511 break;
512 case ERROR_PGP_COMMAND:
513 fclose(description_f);
514 res = MAIL_ERROR_COMMAND;
515 goto unlink_description;
516 case ERROR_PGP_FILE:
517 fclose(description_f);
518 res = MAIL_ERROR_FILE;
519 goto unlink_description;
520 }
521
522 if (sign_ok)
523 fprintf(description_f, PGP_VERIFY_SUCCESS);
524 else
525 fprintf(description_f, PGP_VERIFY_FAILED);
526 fclose(description_f);
527
528 /* building multipart */
529
530 r = mailmime_new_with_content("multipart/x-verified", NULL, &multipart);
531 if (r != MAILIMF_NO_ERROR) {
532 res = MAIL_ERROR_MEMORY;
533 goto unlink_description;
534 }
535
536 /* building the description part */
537
538 description_mime = mailprivacy_new_file_part(privacy,
539 description_filename,
540 "text/plain", MAILMIME_MECHANISM_8BIT);
541 if (description_mime == NULL) {
542 mailprivacy_mime_clear(multipart);
543 mailmime_free(multipart);
544 res = MAIL_ERROR_MEMORY;
545 goto unlink_description;
546 }
547
548 /* adds the description part */
549
550 r = mailmime_smart_add_part(multipart, description_mime);
551 if (r != MAIL_NO_ERROR) {
552 mailprivacy_mime_clear(description_mime);
553 mailmime_free(description_mime);
554 mailprivacy_mime_clear(multipart);
555 mailmime_free(multipart);
556 res = MAIL_ERROR_MEMORY;
557 goto unlink_description;
558 }
559
560 r = mailprivacy_get_part_from_file(privacy, 1,
561 signed_filename, &signed_msg_mime);
562 if (r != MAIL_NO_ERROR) {
563 mailprivacy_mime_clear(multipart);
564 mailmime_free(multipart);
565 res = MAIL_ERROR_MEMORY;
566 goto unlink_description;
567 }
568
569 r = mailmime_smart_add_part(multipart, signed_msg_mime);
570 if (r != MAIL_NO_ERROR) {
571 mailprivacy_mime_clear(signed_msg_mime);
572 mailmime_free(signed_msg_mime);
573 mailprivacy_mime_clear(multipart);
574 mailmime_free(multipart);
575 res = MAIL_ERROR_MEMORY;
576 goto unlink_description;
577 }
578
579 unlink(description_filename);
580 unlink(signature_filename);
581 unlink(signed_filename);
582
583 * result = multipart;
584
585 return MAIL_NO_ERROR;
586
587 unlink_description:
588 unlink(description_filename);
589 unlink_signature:
590 unlink(signature_filename);
591 unlink_signed:
592 unlink(signed_filename);
593 err:
594 return res;
595}
596
597
598#define PGP_CLEAR_VERIFY_DESCRIPTION "PGP verify clear signed message\r\n"
599#define PGP_CLEAR_VERIFY_FAILED "PGP verification FAILED\r\n"
600#define PGP_CLEAR_VERIFY_SUCCESS "PGP verification success\r\n"
601
602static int pgp_verify_clearsigned(struct mailprivacy * privacy,
603 mailmessage * msg,
604 struct mailmime * mime,
605 char * content, size_t content_len, struct mailmime ** result)
606{
607 int r;
608 char command[PATH_MAX];
609 int res;
610 int sign_ok;
611 size_t written;
612 char signed_filename[PATH_MAX];
613 FILE * signed_f;
614 char stripped_filename[PATH_MAX];
615 FILE * stripped_f;
616 char description_filename[PATH_MAX];
617 FILE * description_f;
618 char quoted_signed_filename[PATH_MAX];
619 char quoted_stripped_filename[PATH_MAX];
620 struct mailmime * stripped_mime;
621 struct mailmime * description_mime;
622 struct mailmime * multipart;
623 struct mailmime_content * content_type;
624
625 if (mime->mm_parent == NULL) {
626 res = MAIL_ERROR_INVAL;
627 goto err;
628 }
629
630 if (mime->mm_parent->mm_type == MAILMIME_SINGLE) {
631 res = MAIL_ERROR_INVAL;
632 goto err;
633 }
634
635 signed_f = mailprivacy_get_tmp_file(privacy,
636 signed_filename, sizeof(signed_filename));
637 if (signed_f == NULL) {
638 res = MAIL_ERROR_FILE;
639 goto err;
640 }
641
642 written = fwrite(content, 1, content_len, signed_f);
643 if (written != content_len) {
644 fclose(signed_f);
645 unlink(signed_filename);
646 res = MAIL_ERROR_FILE;
647 goto err;
648 }
649 fclose(signed_f);
650
651 /* XXX - prepare file for PGP, remove trailing WS */
652
653 stripped_f = mailprivacy_get_tmp_file(privacy,
654 stripped_filename, sizeof(stripped_filename));
655 if (stripped_f == NULL) {
656 res = MAIL_ERROR_FILE;
657 goto unlink_signed;
658 }
659 fclose(stripped_f);
660
661 /* description */
662
663 description_f = mailprivacy_get_tmp_file(privacy,
664 description_filename,
665 sizeof(description_filename));
666 if (description_f == NULL) {
667 res = MAIL_ERROR_FILE;
668 goto unlink_stripped;
669 }
670
671 fprintf(description_f, PGP_CLEAR_VERIFY_DESCRIPTION);
672
673 r = mail_quote_filename(quoted_stripped_filename,
674 sizeof(quoted_stripped_filename), stripped_filename);
675 if (r < 0) {
676 fclose(description_f);
677 res = MAIL_ERROR_MEMORY;
678 goto unlink_description;
679 }
680
681 r = mail_quote_filename(quoted_signed_filename,
682 sizeof(quoted_signed_filename), signed_filename);
683 if (r < 0) {
684 fclose(description_f);
685 res = MAIL_ERROR_MEMORY;
686 goto unlink_description;
687 }
688
689 snprintf(command, sizeof(command),
690 "gpg -q --batch --yes --out %s --decrypt %s",
691 quoted_stripped_filename, quoted_signed_filename);
692
693 sign_ok = 0;
694 r = get_pgp_output(description_f, command);
695 switch (r) {
696 case NO_ERROR_PGP:
697 sign_ok = 1;
698 break;
699 case ERROR_PGP_CHECK:
700 sign_ok = 0;
701 break;
702 case ERROR_PGP_COMMAND:
703 res = MAIL_ERROR_COMMAND;
704 fclose(description_f);
705 goto unlink_description;
706 case ERROR_PGP_FILE:
707 res = MAIL_ERROR_FILE;
708 fclose(description_f);
709 goto unlink_description;
710 }
711 if (sign_ok)
712 fprintf(description_f, PGP_CLEAR_VERIFY_SUCCESS);
713 else
714 fprintf(description_f, PGP_CLEAR_VERIFY_FAILED);
715 fclose(description_f);
716
717 /* building multipart */
718
719 r = mailmime_new_with_content("multipart/x-verified", NULL, &multipart);
720 if (r != MAILIMF_NO_ERROR) {
721 res = MAIL_ERROR_MEMORY;
722 goto unlink_description;
723 }
724
725 /* building the description part */
726
727 description_mime = mailprivacy_new_file_part(privacy,
728 description_filename,
729 "text/plain", MAILMIME_MECHANISM_8BIT);
730 if (description_mime == NULL) {
731 mailprivacy_mime_clear(multipart);
732 mailmime_free(multipart);
733 res = MAIL_ERROR_MEMORY;
734 goto unlink_description;
735 }
736
737 /* adds the description part */
738
739 r = mailmime_smart_add_part(multipart, description_mime);
740 if (r != MAIL_NO_ERROR) {
741 mailprivacy_mime_clear(description_mime);
742 mailmime_free(description_mime);
743 mailprivacy_mime_clear(multipart);
744 mailmime_free(multipart);
745 res = MAIL_ERROR_MEMORY;
746 goto unlink_description;
747 }
748
749 /* building the signature stripped part */
750
751 stripped_mime = mailprivacy_new_file_part(privacy,
752 stripped_filename,
753 "application/octet-stream",
754 MAILMIME_MECHANISM_8BIT);
755 if (stripped_mime == NULL) {
756 mailprivacy_mime_clear(multipart);
757 mailmime_free(multipart);
758 res = MAIL_ERROR_MEMORY;
759 goto unlink_description;
760 }
761
762 /* place original content type */
763
764 content_type = mailmime_content_dup(mime->mm_content_type);
765 if (content_type == NULL) {
766 mailprivacy_mime_clear(stripped_mime);
767 mailmime_free(stripped_mime);
768 mailprivacy_mime_clear(multipart);
769 mailmime_free(multipart);
770 res = MAIL_ERROR_MEMORY;
771 goto unlink_description;
772 }
773
774 mailmime_content_free(stripped_mime->mm_content_type);
775 stripped_mime->mm_content_type = content_type;
776
777 /* place original MIME fields */
778
779 if (mime->mm_mime_fields != NULL) {
780 struct mailmime_fields * mime_fields;
781 clistiter * cur;
782
783 mime_fields = mailprivacy_mime_fields_dup(privacy, mime->mm_mime_fields);
784 if (mime_fields == NULL) {
785 mailprivacy_mime_clear(stripped_mime);
786 mailmime_free(stripped_mime);
787 mailprivacy_mime_clear(multipart);
788 mailmime_free(multipart);
789 res = MAIL_ERROR_MEMORY;
790 goto unlink_description;
791 }
792 for(cur = clist_begin(mime_fields->fld_list) ;
793 cur != NULL ; cur = clist_next(cur)) {
794 struct mailmime_field * field;
795
796 field = clist_content(cur);
797 if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) {
798 mailmime_field_free(field);
799 clist_delete(mime_fields->fld_list, cur);
800 break;
801 }
802 }
803 clist_concat(stripped_mime->mm_mime_fields->fld_list,
804 mime_fields->fld_list);
805 mailmime_fields_free(mime_fields);
806 }
807
808 /* adds the stripped part */
809
810 r = mailmime_smart_add_part(multipart, stripped_mime);
811 if (r != MAIL_NO_ERROR) {
812 mailprivacy_mime_clear(stripped_mime);
813 mailmime_free(stripped_mime);
814 mailprivacy_mime_clear(multipart);
815 mailmime_free(multipart);
816 res = MAIL_ERROR_MEMORY;
817 goto unlink_description;
818 }
819
820 unlink(description_filename);
821 unlink(stripped_filename);
822 unlink(signed_filename);
823
824 * result = multipart;
825
826 return MAIL_NO_ERROR;
827
828 unlink_description:
829 unlink(description_filename);
830 unlink_stripped:
831 unlink(stripped_filename);
832 unlink_signed:
833 unlink(signed_filename);
834 err:
835 return res;
836}
837
838
839#define PGP_DECRYPT_ARMOR_DESCRIPTION "PGP ASCII armor encrypted part\r\n"
840#define PGP_DECRYPT_ARMOR_FAILED "PGP ASCII armor decryption FAILED\r\n"
841#define PGP_DECRYPT_ARMOR_SUCCESS "PGP ASCII armor decryption success\r\n"
842
843static int pgp_decrypt_armor(struct mailprivacy * privacy,
844 mailmessage * msg,
845 struct mailmime * mime,
846 char * content, size_t content_len, struct mailmime ** result)
847{
848 char default_key[PATH_MAX];
849 FILE * encrypted_f;
850 char encrypted_filename[PATH_MAX];
851 char description_filename[PATH_MAX];
852 FILE * description_f;
853 char decrypted_filename[PATH_MAX];
854 FILE * decrypted_f;
855 size_t written;
856 char command[PATH_MAX];
857 struct mailmime * description_mime;
858 struct mailmime * decrypted_mime;
859 struct mailmime * multipart;
860 int r;
861 int res;
862 int sign_ok;
863 char quoted_decrypted_filename[PATH_MAX];
864 char quoted_encrypted_filename[PATH_MAX];
865 char * email;
866
867 if (mime->mm_parent == NULL) {
868 res = MAIL_ERROR_INVAL;
869 goto err;
870 }
871
872 if (mime->mm_parent->mm_type == MAILMIME_SINGLE) {
873 res = MAIL_ERROR_INVAL;
874 goto err;
875 }
876
877 encrypted_f = mailprivacy_get_tmp_file(privacy,
878 encrypted_filename,
879 sizeof(encrypted_filename));
880 if (encrypted_f == NULL) {
881 res = MAIL_ERROR_FILE;
882 goto err;
883 }
884
885 written = fwrite(content, 1, content_len, encrypted_f);
886 if (written != content_len) {
887 fclose(encrypted_f);
888 unlink(encrypted_filename);
889 res = MAIL_ERROR_FILE;
890 goto err;
891 }
892
893 fclose(encrypted_f);
894
895 /* we are in a safe directory */
896
897 decrypted_f = mailprivacy_get_tmp_file(privacy,
898 decrypted_filename,
899 sizeof(decrypted_filename));
900 if (decrypted_f == NULL) {
901 res = MAIL_ERROR_FILE;
902 goto unlink_encrypted;
903 }
904 fclose(decrypted_f);
905
906 /* description */
907
908 description_f = mailprivacy_get_tmp_file(privacy,
909 description_filename,
910 sizeof(description_filename));
911 if (description_f == NULL) {
912 res = MAIL_ERROR_FILE;
913 goto unlink_decrypted;
914 }
915
916 fprintf(description_f, PGP_DECRYPT_ARMOR_DESCRIPTION);
917
918 /* get encryption key */
919
920 * default_key = '\0';
921 email = get_first_from_addr(mime);
922 if (email != NULL)
923 snprintf(default_key, sizeof(default_key),
924 "--default-key %s", email);
925
926 /* run the command */
927
928 r = mail_quote_filename(quoted_encrypted_filename,
929 sizeof(quoted_encrypted_filename), encrypted_filename);
930 if (r < 0) {
931 fclose(description_f);
932 res = MAIL_ERROR_MEMORY;
933 goto unlink_description;
934 }
935
936 r = mail_quote_filename(quoted_decrypted_filename,
937 sizeof(quoted_decrypted_filename), decrypted_filename);
938 if (r < 0) {
939 fclose(description_f);
940 res = MAIL_ERROR_MEMORY;
941 goto unlink_description;
942 }
943
944 sign_ok = 0;
945 snprintf(command, sizeof(command),
946 "gpg -q --batch --yes --out %s %s --decrypt %s",
947 quoted_decrypted_filename, default_key, quoted_encrypted_filename);
948
949 r = get_pgp_output(description_f, command);
950 switch (r) {
951 case NO_ERROR_PGP:
952 sign_ok = 1;
953 break;
954 case ERROR_PGP_CHECK:
955 sign_ok = 0;
956 break;
957 case ERROR_PGP_COMMAND:
958 fclose(description_f);
959 res = MAIL_ERROR_COMMAND;
960 goto unlink_description;
961 case ERROR_PGP_FILE:
962 fclose(description_f);
963 res = MAIL_ERROR_FILE;
964 goto unlink_description;
965 }
966 if (sign_ok)
967 fprintf(description_f, PGP_DECRYPT_ARMOR_SUCCESS);
968 else
969 fprintf(description_f, PGP_DECRYPT_ARMOR_FAILED);
970 fclose(description_f);
971
972 /* building multipart */
973
974 r = mailmime_new_with_content("multipart/x-decrypted", NULL, &multipart);
975 if (r != MAILIMF_NO_ERROR) {
976 res = MAIL_ERROR_MEMORY;
977 goto unlink_description;
978 }
979
980 /* building the description part */
981
982 description_mime = mailprivacy_new_file_part(privacy,
983 description_filename,
984 "text/plain", MAILMIME_MECHANISM_8BIT);
985 if (description_mime == NULL) {
986 mailprivacy_mime_clear(multipart);
987 mailmime_free(multipart);
988 res = MAIL_ERROR_MEMORY;
989 goto unlink_description;
990 }
991
992 /* adds the description part */
993
994 r = mailmime_smart_add_part(multipart, description_mime);
995 if (r != MAIL_NO_ERROR) {
996 mailprivacy_mime_clear(description_mime);
997 mailmime_free(description_mime);
998 mailprivacy_mime_clear(multipart);
999 mailmime_free(multipart);
1000 res = MAIL_ERROR_MEMORY;
1001 goto unlink_description;
1002 }
1003
1004 /* building the decrypted part */
1005
1006 r = mailprivacy_get_part_from_file(privacy, 1,
1007 decrypted_filename, &decrypted_mime);
1008 if (r != MAIL_NO_ERROR) {
1009 mailprivacy_mime_clear(multipart);
1010 mailmime_free(multipart);
1011 res = r;
1012 goto unlink_description;
1013 }
1014
1015 /* adds the decrypted part */
1016
1017 r = mailmime_smart_add_part(multipart, decrypted_mime);
1018 if (r != MAIL_NO_ERROR) {
1019 mailprivacy_mime_clear(decrypted_mime);
1020 mailmime_free(decrypted_mime);
1021 mailprivacy_mime_clear(multipart);
1022 mailmime_free(multipart);
1023 res = MAIL_ERROR_MEMORY;
1024 goto unlink_description;
1025 }
1026
1027 unlink(description_filename);
1028 unlink(decrypted_filename);
1029 unlink(encrypted_filename);
1030
1031 * result = multipart;
1032
1033 return MAIL_NO_ERROR;
1034
1035 unlink_description:
1036 unlink(description_filename);
1037 unlink_decrypted:
1038 unlink(decrypted_filename);
1039 unlink_encrypted:
1040 unlink(encrypted_filename);
1041 err:
1042 return res;
1043}
1044
1045
1046static int mime_is_text(struct mailmime * build_info)
1047{
1048 if (build_info->mm_type == MAILMIME_SINGLE) {
1049 if (build_info->mm_content_type != NULL) {
1050 if (build_info->mm_content_type->ct_type->tp_type ==
1051 MAILMIME_TYPE_DISCRETE_TYPE) {
1052 if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type ==
1053 MAILMIME_DISCRETE_TYPE_TEXT)
1054 return 1;
1055 }
1056 }
1057 else
1058 return 1;
1059 }
1060
1061 return 0;
1062}
1063
1064
1065static int pgp_test_encrypted(struct mailprivacy * privacy,
1066 mailmessage * msg, struct mailmime * mime)
1067{
1068 int r;
1069 int res;
1070
1071 switch (mime->mm_type) {
1072 case MAILMIME_MULTIPLE:
1073 return (pgp_is_encrypted(mime) || pgp_is_signed(mime));
1074
1075 case MAILMIME_SINGLE:
1076 /* clear sign or ASCII armor encryption */
1077 if (mime_is_text(mime)) {
1078 char * content;
1079 size_t content_len;
1080 char * parsed_content;
1081 size_t parsed_content_len;
1082 size_t cur_token;
1083 int encoding;
1084 struct mailmime_single_fields single_fields;
1085
1086 r = mailprivacy_msg_fetch_section(privacy, msg, mime,
1087 &content, &content_len);
1088 if (r != MAIL_NO_ERROR)
1089 return 0;
1090
1091 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
1092 mime->mm_content_type);
1093 if (single_fields.fld_encoding != NULL)
1094 encoding = single_fields.fld_encoding->enc_type;
1095 else
1096 encoding = MAILMIME_MECHANISM_8BIT;
1097
1098 cur_token = 0;
1099 r = mailmime_part_parse(content, content_len, &cur_token,
1100 encoding, &parsed_content, &parsed_content_len);
1101 mailprivacy_msg_fetch_result_free(privacy, msg, content);
1102
1103 if (r != MAILIMF_NO_ERROR)
1104 return 0;
1105
1106 res = 0;
1107
1108 if (pgp_is_clearsigned(parsed_content, parsed_content_len))
1109 res = 1;
1110 else if (pgp_is_crypted_armor(parsed_content, parsed_content_len))
1111 res = 1;
1112
1113 mmap_string_unref(parsed_content);
1114
1115 return res;
1116 }
1117 break;
1118 }
1119
1120 return 0;
1121}
1122
1123static int pgp_handler(struct mailprivacy * privacy,
1124 mailmessage * msg,
1125 struct mailmime * mime, struct mailmime ** result)
1126{
1127 int r;
1128 struct mailmime * alternative_mime;
1129
1130 alternative_mime = NULL;
1131 switch (mime->mm_type) {
1132 case MAILMIME_MULTIPLE:
1133 r = MAIL_ERROR_INVAL;
1134 if (pgp_is_encrypted(mime)) {
1135 r = pgp_decrypt(privacy, msg, mime, &alternative_mime);
1136 }
1137 else if (pgp_is_signed(mime)) {
1138 r = pgp_verify(privacy, msg, mime, &alternative_mime);
1139 }
1140
1141 if (r != MAIL_NO_ERROR)
1142 return r;
1143
1144 * result = alternative_mime;
1145
1146 return MAIL_NO_ERROR;
1147
1148 case MAILMIME_SINGLE:
1149 /* clear sign or ASCII armor encryption */
1150 if (mime_is_text(mime)) {
1151 char * content;
1152 size_t content_len;
1153 char * parsed_content;
1154 size_t parsed_content_len;
1155 size_t cur_token;
1156 int encoding;
1157 struct mailmime_single_fields single_fields;
1158
1159 r = mailprivacy_msg_fetch_section(privacy, msg, mime,
1160 &content, &content_len);
1161 if (r != MAIL_NO_ERROR)
1162 return MAIL_ERROR_FETCH;
1163
1164 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
1165 mime->mm_content_type);
1166 if (single_fields.fld_encoding != NULL)
1167 encoding = single_fields.fld_encoding->enc_type;
1168 else
1169 encoding = MAILMIME_MECHANISM_8BIT;
1170
1171 cur_token = 0;
1172 r = mailmime_part_parse(content, content_len, &cur_token,
1173 encoding, &parsed_content, &parsed_content_len);
1174 mailprivacy_msg_fetch_result_free(privacy, msg, content);
1175
1176 if (r != MAILIMF_NO_ERROR)
1177 return MAIL_ERROR_PARSE;
1178
1179 r = MAIL_ERROR_INVAL;
1180 if (pgp_is_clearsigned(parsed_content,
1181 parsed_content_len)) {
1182 r = pgp_verify_clearsigned(privacy,
1183 msg, mime, parsed_content, parsed_content_len, &alternative_mime);
1184 }
1185 else if (pgp_is_crypted_armor(parsed_content,
1186 parsed_content_len)) {
1187 r = pgp_decrypt_armor(privacy,
1188 msg, mime, parsed_content, parsed_content_len, &alternative_mime);
1189 }
1190
1191 mmap_string_unref(parsed_content);
1192
1193 if (r != MAIL_NO_ERROR)
1194 return r;
1195
1196 * result = alternative_mime;
1197
1198 return MAIL_NO_ERROR;
1199 }
1200 break;
1201 }
1202
1203 return MAIL_ERROR_INVAL;
1204}
1205
1206
1207#if 0
1208static void prepare_mime_single(struct mailmime * mime)
1209{
1210 struct mailmime_single_fields single_fields;
1211 int encoding;
1212 int r;
1213
1214 if (mime->mime_fields != NULL) {
1215 mailmime_single_fields_init(&single_fields, mime->mime_fields,
1216 mime->content_type);
1217 if (single_fields.encoding != NULL) {
1218 encoding = single_fields.encoding->type;
1219 switch (encoding) {
1220 case MAILMIME_MECHANISM_8BIT:
1221 case MAILMIME_MECHANISM_7BIT:
1222 case MAILMIME_MECHANISM_BINARY:
1223 single_fields.encoding->type = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
1224 break;
1225 }
1226 }
1227 else {
1228 struct mailmime_mechanism * mechanism;
1229 struct mailmime_field * field;
1230
1231 mechanism =
1232 mailmime_mechanism_new(MAILMIME_MECHANISM_QUOTED_PRINTABLE, NULL);
1233 if (mechanism == NULL)
1234 return;
1235
1236 field = mailmime_field_new(MAILMIME_FIELD_TRANSFER_ENCODING,
1237 NULL, mechanism, NULL, NULL, 0, NULL, NULL);
1238 if (field == NULL) {
1239 mailmime_mechanism_free(mechanism);
1240 return;
1241 }
1242
1243 r = clist_append(mime->mime_fields->list, field);
1244 if (r < 0) {
1245 mailmime_field_free(field);
1246 return;
1247 }
1248 }
1249 }
1250
1251 switch (mime->body->encoding) {
1252 case MAILMIME_MECHANISM_8BIT:
1253 case MAILMIME_MECHANISM_7BIT:
1254 case MAILMIME_MECHANISM_BINARY:
1255 mime->body->encoding = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
1256 mime->body->encoded = 0;
1257 break;
1258 }
1259}
1260
1261/*
1262 prepare_mime()
1263
1264 we assume we built ourself the message.
1265*/
1266
1267static void prepare_mime(struct mailmime * mime)
1268{
1269 clistiter * cur;
1270
1271 switch (mime->type) {
1272 case MAILMIME_SINGLE:
1273 if (mime->body != NULL) {
1274 prepare_mime_single(mime);
1275 }
1276 break;
1277
1278 case MAILMIME_MULTIPLE:
1279 for(cur = clist_begin(mime->list) ; cur != NULL ; cur = clist_next(cur)) {
1280 struct mailmime * child;
1281
1282 child = cur->data;
1283
1284 prepare_mime(child);
1285 }
1286 break;
1287
1288 case MAILMIME_MESSAGE:
1289 if (mime->msg_mime) {
1290 prepare_mime(mime->msg_mime);
1291 }
1292 break;
1293 }
1294}
1295#endif
1296
1297static int pgp_sign_mime(struct mailprivacy * privacy,
1298 struct mailmime * mime, struct mailmime ** result)
1299{
1300 char signed_filename[PATH_MAX];
1301 FILE * signed_f;
1302 int res;
1303 int r;
1304 int col;
1305 char signature_filename[PATH_MAX];
1306 FILE * signature_f;
1307 char command[PATH_MAX];
1308 char quoted_signature_filename[PATH_MAX];
1309 char quoted_signed_filename[PATH_MAX];
1310 char default_key[PATH_MAX];
1311 struct mailmime * signature_mime;
1312 struct mailmime * multipart;
1313 struct mailmime_content * content;
1314 struct mailmime_parameter * param;
1315 struct mailmime * signed_msg_mime;
1316 char * dup_signature_filename;
1317 char * email;
1318
1319 /* get signing key */
1320
1321 * default_key = '\0';
1322 email = get_first_from_addr(mime);
1323 if (email != NULL)
1324 snprintf(default_key, sizeof(default_key),
1325 "--default-key %s", email);
1326
1327 /* part to sign */
1328
1329 /* encode quoted printable all text parts */
1330
1331 mailprivacy_prepare_mime(mime);
1332
1333 signed_f = mailprivacy_get_tmp_file(privacy,
1334 signed_filename, sizeof(signed_filename));
1335 if (signed_f == NULL) {
1336 res = MAIL_ERROR_FILE;
1337 goto err;
1338 }
1339
1340 col = 0;
1341 r = mailmime_write(signed_f, &col, mime);
1342 if (r != MAILIMF_NO_ERROR) {
1343 fclose(signed_f);
1344 res = MAIL_ERROR_FILE;
1345 goto unlink_signed;
1346 }
1347
1348 fclose(signed_f);
1349
1350 /* prepare destination file for signature */
1351
1352 signature_f = mailprivacy_get_tmp_file(privacy,
1353 signature_filename,
1354 sizeof(signature_filename));
1355 if (signature_f == NULL) {
1356 res = MAIL_ERROR_FILE;
1357 goto unlink_signed;
1358 }
1359 fclose(signature_f);
1360
1361 r = mail_quote_filename(quoted_signed_filename,
1362 sizeof(quoted_signed_filename), signed_filename);
1363 if (r < 0) {
1364 res = MAIL_ERROR_MEMORY;
1365 goto unlink_signature;
1366 }
1367
1368 r = mail_quote_filename(quoted_signature_filename,
1369 sizeof(quoted_signature_filename), signature_filename);
1370 if (r < 0) {
1371 res = MAIL_ERROR_MEMORY;
1372 goto unlink_signature;
1373 }
1374
1375 snprintf(command, sizeof(command),
1376 "gpg -q -a --batch --yes --digest-algo sha1 --out %s %s -b %s 2>/dev/null",
1377 quoted_signature_filename, default_key, quoted_signed_filename);
1378
1379 r = system(command);
1380 if (WEXITSTATUS(r) != 0) {
1381 res = MAIL_ERROR_COMMAND;
1382 goto unlink_signature;
1383 }
1384
1385 /* multipart */
1386
1387 multipart = mailprivacy_new_file_part(privacy, NULL,
1388 "multipart/signed", -1);
1389
1390 content = multipart->mm_content_type;
1391
1392 param = mailmime_param_new_with_data("micalg", "pgp-sha1");
1393 if (param == NULL) {
1394 mailmime_free(multipart);
1395 res = MAIL_ERROR_MEMORY;
1396 goto unlink_signature;
1397 }
1398
1399 r = clist_append(content->ct_parameters, param);
1400 if (r < 0) {
1401 mailmime_parameter_free(param);
1402 mailmime_free(multipart);
1403 res = MAIL_ERROR_MEMORY;
1404 goto unlink_signature;
1405 }
1406
1407 param = mailmime_param_new_with_data("protocol",
1408 "application/pgp-signature");
1409 if (param == NULL) {
1410 mailmime_free(multipart);
1411 res = MAIL_ERROR_MEMORY;
1412 goto unlink_signature;
1413 }
1414
1415 r = clist_append(content->ct_parameters, param);
1416 if (r < 0) {
1417 mailmime_parameter_free(param);
1418 mailmime_free(multipart);
1419 res = MAIL_ERROR_MEMORY;
1420 goto unlink_signature;
1421 }
1422
1423 /* signed part */
1424
1425 r = mailprivacy_get_part_from_file(privacy, 1,
1426 signed_filename, &signed_msg_mime);
1427 if (r != MAIL_NO_ERROR) {
1428 mailprivacy_mime_clear(multipart);
1429 mailmime_free(multipart);
1430 res = r;
1431 goto unlink_signature;
1432 }
1433
1434 mailprivacy_prepare_mime(signed_msg_mime);
1435
1436 r = mailmime_smart_add_part(multipart, signed_msg_mime);
1437 if (r != MAIL_NO_ERROR) {
1438 mailprivacy_mime_clear(signed_msg_mime);
1439 mailmime_free(signed_msg_mime);
1440 mailprivacy_mime_clear(multipart);
1441 mailmime_free(multipart);
1442 res = MAIL_ERROR_MEMORY;
1443 goto unlink_signature;
1444 }
1445
1446 /* signature part */
1447
1448 /* reencode the signature file with CRLF */
1449 dup_signature_filename = mailprivacy_dup_imf_file(privacy,
1450 signature_filename);
1451 if (dup_signature_filename == NULL) {
1452 mailprivacy_mime_clear(multipart);
1453 mailmime_free(multipart);
1454 res = MAIL_ERROR_FILE;
1455 goto unlink_signature;
1456 }
1457
1458 /* replace the signature file */
1459 unlink(signature_filename);
1460 strncpy(signature_filename,
1461 dup_signature_filename, sizeof(signature_filename));
1462 signature_filename[sizeof(signature_filename) - 1] = '\0';
1463
1464 signature_mime = mailprivacy_new_file_part(privacy,
1465 signature_filename,
1466 "application/pgp-signature",
1467 MAILMIME_MECHANISM_8BIT);
1468 if (signature_mime == NULL) {
1469 mailprivacy_mime_clear(multipart);
1470 mailmime_free(multipart);
1471 res = MAIL_ERROR_MEMORY;
1472 goto unlink_signature;
1473 }
1474
1475 r = mailmime_smart_add_part(multipart, signature_mime);
1476 if (r != MAIL_NO_ERROR) {
1477 mailprivacy_mime_clear(signature_mime);
1478 mailmime_free(signature_mime);
1479 mailprivacy_mime_clear(multipart);
1480 mailmime_free(multipart);
1481 res = MAIL_ERROR_MEMORY;
1482 goto unlink_signature;
1483 }
1484
1485 unlink(signature_filename);
1486 unlink(signed_filename);
1487
1488 * result = multipart;
1489
1490 return MAIL_NO_ERROR;
1491
1492 unlink_signature:
1493 unlink(signature_filename);
1494 unlink_signed:
1495 unlink(signed_filename);
1496 err:
1497 return res;
1498}
1499
1500
1501/* ********************************************************************* */
1502/* find GPG recipient */
1503
1504static int recipient_add_mb(char * recipient, size_t * len,
1505 struct mailimf_mailbox * mb)
1506{
1507 char buffer[PATH_MAX];
1508 size_t buflen;
1509
1510 if (mb->mb_addr_spec != NULL) {
1511 snprintf(buffer, sizeof(buffer), "-r %s ", mb->mb_addr_spec);
1512 buflen = strlen(buffer);
1513 if (buflen >= * len)
1514 return MAIL_ERROR_MEMORY;
1515
1516 strncat(recipient, buffer, * len);
1517 (* len) -= buflen;
1518 }
1519
1520 return MAIL_NO_ERROR;
1521}
1522
1523static int recipient_add_mb_list(char * recipient, size_t * len,
1524 struct mailimf_mailbox_list * mb_list)
1525{
1526 clistiter * cur;
1527 int r;
1528
1529 for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
1530 cur = clist_next(cur)) {
1531 struct mailimf_mailbox * mb;
1532
1533 mb = clist_content(cur);
1534
1535 r = recipient_add_mb(recipient, len, mb);
1536 if (r != MAIL_NO_ERROR)
1537 return r;
1538 }
1539
1540 return MAIL_NO_ERROR;
1541}
1542
1543static int recipient_add_group(char * recipient, size_t * len,
1544 struct mailimf_group * group)
1545{
1546 return recipient_add_mb_list(recipient, len, group->grp_mb_list);
1547}
1548
1549static int recipient_add_addr(char * recipient, size_t * len,
1550 struct mailimf_address * addr)
1551{
1552 int r;
1553
1554 switch (addr->ad_type) {
1555 case MAILIMF_ADDRESS_MAILBOX:
1556 r = recipient_add_mb(recipient, len, addr->ad_data.ad_mailbox);
1557 break;
1558 case MAILIMF_ADDRESS_GROUP:
1559 r = recipient_add_group(recipient, len, addr->ad_data.ad_group);
1560 break;
1561 default:
1562 r = MAIL_ERROR_INVAL;
1563 }
1564
1565 return r;
1566}
1567
1568static int recipient_add_addr_list(char * recipient, size_t * len,
1569 struct mailimf_address_list * addr_list)
1570{
1571 clistiter * cur;
1572 int r;
1573
1574 for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
1575 cur = clist_next(cur)) {
1576 struct mailimf_address * addr;
1577
1578 addr = clist_content(cur);
1579
1580 r = recipient_add_addr(recipient, len, addr);
1581 if (r != MAIL_NO_ERROR)
1582 return r;
1583 }
1584
1585 return MAIL_NO_ERROR;
1586}
1587
1588
1589static int collect_recipient(char * recipient, size_t size,
1590 struct mailimf_fields * fields)
1591{
1592 struct mailimf_single_fields single_fields;
1593 int r;
1594 size_t remaining;
1595 int res;
1596
1597 * recipient = '\0';
1598 remaining = size;
1599
1600 if (fields != NULL)
1601 mailimf_single_fields_init(&single_fields, fields);
1602
1603 if (single_fields.fld_to != NULL) {
1604 r = recipient_add_addr_list(recipient, &remaining,
1605 single_fields.fld_to->to_addr_list);
1606 if (r != MAIL_NO_ERROR) {
1607 res = r;
1608 goto err;
1609 }
1610 }
1611
1612 if (single_fields.fld_cc != NULL) {
1613 r = recipient_add_addr_list(recipient, &remaining,
1614 single_fields.fld_cc->cc_addr_list);
1615 if (r != MAIL_NO_ERROR) {
1616 res = r;
1617 goto err;
1618 }
1619 }
1620
1621 if (single_fields.fld_bcc != NULL) {
1622 if (single_fields.fld_bcc->bcc_addr_list != NULL) {
1623 r = recipient_add_addr_list(recipient, &remaining,
1624 single_fields.fld_bcc->bcc_addr_list);
1625 if (r != MAIL_NO_ERROR) {
1626 res = r;
1627 goto err;
1628 }
1629 }
1630 }
1631
1632 return MAIL_NO_ERROR;
1633
1634 err:
1635 return res;
1636}
1637
1638
1639#define PGP_VERSION "Version: 1\r\n"
1640
1641static int pgp_sign_encrypt_mime(struct mailprivacy * privacy,
1642 struct mailmime * mime, struct mailmime ** result)
1643{
1644 char original_filename[PATH_MAX];
1645 FILE * original_f;
1646 int res;
1647 int r;
1648 int col;
1649 char encrypted_filename[PATH_MAX];
1650 FILE * encrypted_f;
1651 char version_filename[PATH_MAX];
1652 FILE * version_f;
1653 char command[PATH_MAX];
1654 char quoted_original_filename[PATH_MAX];
1655 char quoted_encrypted_filename[PATH_MAX];
1656 char default_key[PATH_MAX];
1657 struct mailmime * version_mime;
1658 struct mailmime * multipart;
1659 struct mailmime_content * content;
1660 struct mailmime_parameter * param;
1661 struct mailmime * encrypted_mime;
1662 char recipient[PATH_MAX];
1663 struct mailimf_fields * fields;
1664 struct mailmime * root;
1665 size_t written;
1666 char * email;
1667
1668 root = mime;
1669 while (root->mm_parent != NULL)
1670 root = root->mm_parent;
1671
1672 fields = NULL;
1673 if (root->mm_type == MAILMIME_MESSAGE)
1674 fields = root->mm_data.mm_message.mm_fields;
1675
1676 /* recipient */
1677
1678 collect_recipient(recipient, sizeof(recipient), fields);
1679
1680 /* get signing key */
1681
1682 * default_key = '\0';
1683 email = get_first_from_addr(mime);
1684 if (email != NULL)
1685 snprintf(default_key, sizeof(default_key),
1686 "--default-key %s", email);
1687
1688 /* part to encrypt */
1689
1690 /* encode quoted printable all text parts */
1691
1692 mailprivacy_prepare_mime(mime);
1693
1694 original_f = mailprivacy_get_tmp_file(privacy, original_filename,
1695 sizeof(original_filename));
1696 if (original_f == NULL) {
1697 res = MAIL_ERROR_FILE;
1698 goto err;
1699 }
1700
1701 col = 0;
1702 r = mailmime_write(original_f, &col, mime);
1703 if (r != MAILIMF_NO_ERROR) {
1704 fclose(original_f);
1705 res = MAIL_ERROR_FILE;
1706 goto unlink_original;
1707 }
1708
1709 fclose(original_f);
1710
1711 /* prepare destination file for encryption */
1712
1713 encrypted_f = mailprivacy_get_tmp_file(privacy,
1714 encrypted_filename,
1715 sizeof(encrypted_filename));
1716 if (encrypted_f == NULL) {
1717 res = MAIL_ERROR_FILE;
1718 goto unlink_original;
1719 }
1720 fclose(encrypted_f);
1721
1722 r = mail_quote_filename(quoted_original_filename,
1723 sizeof(quoted_original_filename), original_filename);
1724 if (r < 0) {
1725 res = MAIL_ERROR_MEMORY;
1726 goto unlink_encrypted;
1727 }
1728
1729 r = mail_quote_filename(quoted_encrypted_filename,
1730 sizeof(quoted_encrypted_filename), encrypted_filename);
1731 if (r < 0) {
1732 res = MAIL_ERROR_MEMORY;
1733 goto unlink_encrypted;
1734 }
1735
1736 snprintf(command, sizeof(command),
1737 "gpg -q %s -a --batch --yes --digest-algo sha1 --out %s -s %s -e %s 2>/dev/null",
1738 recipient, quoted_encrypted_filename, default_key,
1739 quoted_original_filename);
1740
1741 r = system(command);
1742 if (WEXITSTATUS(r) != 0) {
1743 res = MAIL_ERROR_COMMAND;
1744 goto unlink_encrypted;
1745 }
1746
1747 /* multipart */
1748
1749 multipart = mailprivacy_new_file_part(privacy, NULL,
1750 "multipart/encrypted", -1);
1751
1752 content = multipart->mm_content_type;
1753
1754 param = mailmime_param_new_with_data("protocol",
1755 "application/pgp-encrypted");
1756 if (param == NULL) {
1757 mailmime_free(multipart);
1758 res = MAIL_ERROR_MEMORY;
1759 goto unlink_encrypted;
1760 }
1761
1762 r = clist_append(content->ct_parameters, param);
1763 if (r < 0) {
1764 mailmime_parameter_free(param);
1765 mailmime_free(multipart);
1766 res = MAIL_ERROR_MEMORY;
1767 goto unlink_encrypted;
1768 }
1769
1770 /* version part */
1771
1772 version_f = mailprivacy_get_tmp_file(privacy,
1773 version_filename,
1774 sizeof(version_filename));
1775 if (version_f == NULL) {
1776 mailprivacy_mime_clear(multipart);
1777 mailmime_free(multipart);
1778 res = MAIL_ERROR_FILE;
1779 goto unlink_encrypted;
1780 }
1781 written = fwrite(PGP_VERSION, 1, sizeof(PGP_VERSION) - 1, version_f);
1782 if (written != sizeof(PGP_VERSION) - 1) {
1783 fclose(version_f);
1784 mailprivacy_mime_clear(multipart);
1785 mailmime_free(multipart);
1786 res = MAIL_ERROR_FILE;
1787 goto unlink_encrypted;
1788 }
1789 fclose(version_f);
1790
1791 version_mime = mailprivacy_new_file_part(privacy,
1792 version_filename,
1793 "application/pgp-encrypted",
1794 MAILMIME_MECHANISM_8BIT);
1795 if (r != MAIL_NO_ERROR) {
1796 mailprivacy_mime_clear(multipart);
1797 mailmime_free(multipart);
1798 res = r;
1799 goto unlink_version;
1800 }
1801
1802 r = mailmime_smart_add_part(multipart, version_mime);
1803 if (r != MAIL_NO_ERROR) {
1804 mailprivacy_mime_clear(version_mime);
1805 mailmime_free(version_mime);
1806 mailprivacy_mime_clear(multipart);
1807 mailmime_free(multipart);
1808 res = MAIL_ERROR_MEMORY;
1809 goto unlink_version;
1810 }
1811
1812 /* encrypted part */
1813
1814 encrypted_mime = mailprivacy_new_file_part(privacy,
1815 encrypted_filename,
1816 "application/octet-stream",
1817 MAILMIME_MECHANISM_8BIT);
1818 if (r != MAIL_NO_ERROR) {
1819 mailprivacy_mime_clear(multipart);
1820 mailmime_free(multipart);
1821 res = r;
1822 goto unlink_version;
1823 }
1824
1825 r = mailmime_smart_add_part(multipart, encrypted_mime);
1826 if (r != MAIL_NO_ERROR) {
1827 mailprivacy_mime_clear(encrypted_mime);
1828 mailmime_free(encrypted_mime);
1829 mailprivacy_mime_clear(multipart);
1830 mailmime_free(multipart);
1831 res = MAIL_ERROR_MEMORY;
1832 goto unlink_version;
1833 }
1834
1835 unlink(version_filename);
1836 unlink(encrypted_filename);
1837 unlink(original_filename);
1838
1839 * result = multipart;
1840
1841 return MAIL_NO_ERROR;
1842
1843 unlink_version:
1844 unlink(version_filename);
1845 unlink_encrypted:
1846 unlink(encrypted_filename);
1847 unlink_original:
1848 unlink(original_filename);
1849 err:
1850 return res;
1851}
1852
1853
1854static int pgp_encrypt_mime(struct mailprivacy * privacy,
1855 struct mailmime * mime, struct mailmime ** result)
1856{
1857 char original_filename[PATH_MAX];
1858 FILE * original_f;
1859 int res;
1860 int r;
1861 int col;
1862 char encrypted_filename[PATH_MAX];
1863 FILE * encrypted_f;
1864 char version_filename[PATH_MAX];
1865 FILE * version_f;
1866 char command[PATH_MAX];
1867 char quoted_original_filename[PATH_MAX];
1868 char quoted_encrypted_filename[PATH_MAX];
1869 struct mailmime * version_mime;
1870 struct mailmime * multipart;
1871 struct mailmime_content * content;
1872 struct mailmime_parameter * param;
1873 struct mailmime * encrypted_mime;
1874 char recipient[PATH_MAX];
1875 struct mailimf_fields * fields;
1876 struct mailmime * root;
1877 size_t written;
1878
1879 root = mime;
1880 while (root->mm_parent != NULL)
1881 root = root->mm_parent;
1882
1883 fields = NULL;
1884 if (root->mm_type == MAILMIME_MESSAGE)
1885 fields = root->mm_data.mm_message.mm_fields;
1886
1887 /* recipient */
1888
1889 collect_recipient(recipient, sizeof(recipient), fields);
1890
1891 /* part to encrypt */
1892
1893 /* encode quoted printable all text parts */
1894
1895 mailprivacy_prepare_mime(mime);
1896
1897 original_f = mailprivacy_get_tmp_file(privacy,
1898 original_filename, sizeof(original_filename));
1899 if (original_f == NULL) {
1900 res = MAIL_ERROR_FILE;
1901 goto err;
1902 }
1903
1904 col = 0;
1905 r = mailmime_write(original_f, &col, mime);
1906 if (r != MAILIMF_NO_ERROR) {
1907 fclose(original_f);
1908 res = MAIL_ERROR_FILE;
1909 goto unlink_original;
1910 }
1911
1912 fclose(original_f);
1913
1914 /* prepare destination file for encryption */
1915
1916 encrypted_f = mailprivacy_get_tmp_file(privacy,
1917 encrypted_filename,
1918 sizeof(encrypted_filename));
1919 if (encrypted_f == NULL) {
1920 res = MAIL_ERROR_FILE;
1921 goto unlink_original;
1922 }
1923 fclose(encrypted_f);
1924
1925 r = mail_quote_filename(quoted_original_filename,
1926 sizeof(quoted_original_filename), original_filename);
1927 if (r < 0) {
1928 res = MAIL_ERROR_MEMORY;
1929 goto unlink_encrypted;
1930 }
1931
1932 r = mail_quote_filename(quoted_encrypted_filename,
1933 sizeof(quoted_encrypted_filename), encrypted_filename);
1934 if (r < 0) {
1935 res = MAIL_ERROR_MEMORY;
1936 goto unlink_encrypted;
1937 }
1938
1939 snprintf(command, sizeof(command),
1940 "gpg -q %s -a --batch --yes --out %s -e %s 2>/dev/null",
1941 recipient, quoted_encrypted_filename, quoted_original_filename);
1942
1943 r = system(command);
1944 if (WEXITSTATUS(r) != 0) {
1945 res = MAIL_ERROR_COMMAND;
1946 goto unlink_encrypted;
1947 }
1948
1949 /* multipart */
1950
1951 multipart = mailprivacy_new_file_part(privacy, NULL,
1952 "multipart/encrypted", -1);
1953
1954 content = multipart->mm_content_type;
1955
1956 param = mailmime_param_new_with_data("protocol",
1957 "application/pgp-encrypted");
1958 if (param == NULL) {
1959 mailmime_free(multipart);
1960 res = MAIL_ERROR_MEMORY;
1961 goto unlink_encrypted;
1962 }
1963
1964 r = clist_append(content->ct_parameters, param);
1965 if (r < 0) {
1966 mailmime_parameter_free(param);
1967 mailmime_free(multipart);
1968 res = MAIL_ERROR_MEMORY;
1969 goto unlink_encrypted;
1970 }
1971
1972 /* version part */
1973
1974 version_f = mailprivacy_get_tmp_file(privacy,
1975 version_filename, sizeof(version_filename));
1976 if (version_f == NULL) {
1977 mailprivacy_mime_clear(multipart);
1978 mailmime_free(multipart);
1979 res = MAIL_ERROR_FILE;
1980 goto unlink_encrypted;
1981 }
1982 written = fwrite(PGP_VERSION, 1, sizeof(PGP_VERSION) - 1, version_f);
1983 if (written != sizeof(PGP_VERSION) - 1) {
1984 fclose(version_f);
1985 mailprivacy_mime_clear(multipart);
1986 mailmime_free(multipart);
1987 res = MAIL_ERROR_FILE;
1988 goto unlink_encrypted;
1989 }
1990 fclose(version_f);
1991
1992 version_mime = mailprivacy_new_file_part(privacy,
1993 version_filename,
1994 "application/pgp-encrypted",
1995 MAILMIME_MECHANISM_8BIT);
1996 if (r != MAIL_NO_ERROR) {
1997 mailprivacy_mime_clear(multipart);
1998 mailmime_free(multipart);
1999 res = r;
2000 goto unlink_version;
2001 }
2002
2003 r = mailmime_smart_add_part(multipart, version_mime);
2004 if (r != MAIL_NO_ERROR) {
2005 mailprivacy_mime_clear(version_mime);
2006 mailmime_free(version_mime);
2007 mailprivacy_mime_clear(multipart);
2008 mailmime_free(multipart);
2009 res = MAIL_ERROR_MEMORY;
2010 goto unlink_version;
2011 }
2012
2013 /* encrypted part */
2014
2015 encrypted_mime = mailprivacy_new_file_part(privacy,
2016 encrypted_filename,
2017 "application/octet-stream",
2018 MAILMIME_MECHANISM_8BIT);
2019 if (r != MAIL_NO_ERROR) {
2020 mailprivacy_mime_clear(multipart);
2021 mailmime_free(multipart);
2022 res = r;
2023 goto unlink_version;
2024 }
2025
2026 r = mailmime_smart_add_part(multipart, encrypted_mime);
2027 if (r != MAIL_NO_ERROR) {
2028 mailprivacy_mime_clear(encrypted_mime);
2029 mailmime_free(encrypted_mime);
2030 mailprivacy_mime_clear(multipart);
2031 mailmime_free(multipart);
2032 res = MAIL_ERROR_MEMORY;
2033 goto unlink_version;
2034 }
2035
2036 unlink(version_filename);
2037 unlink(encrypted_filename);
2038 unlink(original_filename);
2039
2040 * result = multipart;
2041
2042 return MAIL_NO_ERROR;
2043
2044 unlink_version:
2045 unlink(version_filename);
2046 unlink_encrypted:
2047 unlink(encrypted_filename);
2048 unlink_original:
2049 unlink(original_filename);
2050 err:
2051 return res;
2052}
2053
2054static int pgp_clear_sign(struct mailprivacy * privacy,
2055 struct mailmime * mime, struct mailmime ** result)
2056{
2057 char default_key[PATH_MAX];
2058 char original_filename[PATH_MAX];
2059 FILE * original_f;
2060 char signed_filename[PATH_MAX];
2061 FILE * signed_f;
2062 char quoted_original_filename[PATH_MAX];
2063 char quoted_signed_filename[PATH_MAX];
2064 int col;
2065 struct mailmime * signed_mime;
2066 int res;
2067 int r;
2068 char command[PATH_MAX];
2069 struct mailmime_content * content_type;
2070 char * email;
2071
2072 if (mime->mm_type != MAILMIME_SINGLE) {
2073 res = MAIL_ERROR_INVAL;
2074 goto err;
2075 }
2076
2077 if (mime->mm_data.mm_single == NULL) {
2078 res = MAIL_ERROR_INVAL;
2079 goto err;
2080 }
2081
2082 /* get signing key */
2083
2084 * default_key = '\0';
2085 email = get_first_from_addr(mime);
2086 if (email != NULL)
2087 snprintf(default_key, sizeof(default_key),
2088 "--default-key %s", email);
2089
2090 /* get part to sign */
2091
2092 original_f = mailprivacy_get_tmp_file(privacy,
2093 original_filename,
2094 sizeof(original_filename));
2095 if (original_f == NULL) {
2096 res = MAIL_ERROR_FILE;
2097 goto err;
2098 }
2099
2100 col = 0;
2101 r = mailmime_data_write(original_f, &col, mime->mm_data.mm_single, 1);
2102 if (r != MAILIMF_NO_ERROR) {
2103 fclose(original_f);
2104 res = MAIL_ERROR_FILE;
2105 goto unlink_original;
2106 }
2107 fclose(original_f);
2108
2109 signed_f = mailprivacy_get_tmp_file(privacy,
2110 signed_filename,
2111 sizeof(signed_filename));
2112 if (signed_f == NULL) {
2113 res = MAIL_ERROR_FILE;
2114 goto unlink_original;
2115 }
2116 fclose(signed_f);
2117
2118 r = mail_quote_filename(quoted_original_filename,
2119 sizeof(quoted_original_filename), original_filename);
2120 if (r < 0) {
2121 res = MAIL_ERROR_MEMORY;
2122 goto unlink_signed;
2123 }
2124
2125 r = mail_quote_filename(quoted_signed_filename,
2126 sizeof(quoted_signed_filename), signed_filename);
2127 if (r < 0) {
2128 res = MAIL_ERROR_MEMORY;
2129 goto unlink_signed;
2130 }
2131
2132 snprintf(command, sizeof(command),
2133 "gpg -q --batch --yes --digest-algo sha1 --out %s %s --clearsign %s 2>/dev/null",
2134 quoted_signed_filename, default_key, quoted_original_filename);
2135
2136 r = system(command);
2137 if (WEXITSTATUS(r) != 0) {
2138 res = MAIL_ERROR_COMMAND;
2139 goto unlink_signed;
2140 }
2141
2142 /* building the signed part */
2143
2144 signed_mime = mailprivacy_new_file_part(privacy, signed_filename,
2145 NULL, MAILMIME_MECHANISM_8BIT);
2146 if (signed_mime == NULL) {
2147 res = MAIL_ERROR_MEMORY;
2148 goto unlink_signed;
2149 }
2150
2151 /* place original content type */
2152
2153 content_type = mailmime_content_dup(mime->mm_content_type);
2154 if (content_type == NULL) {
2155 mailprivacy_mime_clear(signed_mime);
2156 mailmime_free(signed_mime);
2157 res = MAIL_ERROR_MEMORY;
2158 goto unlink_signed;
2159 }
2160
2161 mailmime_content_free(signed_mime->mm_content_type);
2162 signed_mime->mm_content_type = content_type;
2163
2164 /* place original MIME fields */
2165
2166 if (mime->mm_mime_fields != NULL) {
2167 struct mailmime_fields * mime_fields;
2168 clistiter * cur;
2169
2170 mime_fields = mailprivacy_mime_fields_dup(privacy,
2171 mime->mm_mime_fields);
2172 if (mime_fields == NULL) {
2173 mailprivacy_mime_clear(signed_mime);
2174 mailmime_free(signed_mime);
2175 res = MAIL_ERROR_MEMORY;
2176 goto unlink_signed;
2177 }
2178 for(cur = clist_begin(mime_fields->fld_list) ;
2179 cur != NULL ; cur = clist_next(cur)) {
2180 struct mailmime_field * field;
2181
2182 field = clist_content(cur);
2183 if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) {
2184 mailmime_field_free(field);
2185 clist_delete(mime_fields->fld_list, cur);
2186 break;
2187 }
2188 }
2189 clist_concat(signed_mime->mm_mime_fields->fld_list,
2190 mime_fields->fld_list);
2191 mailmime_fields_free(mime_fields);
2192 }
2193
2194 unlink(signed_filename);
2195 unlink(original_filename);
2196
2197 * result = signed_mime;
2198
2199 return MAIL_NO_ERROR;
2200
2201 unlink_signed:
2202 unlink(signed_filename);
2203 unlink_original:
2204 unlink(original_filename);
2205 err:
2206 return res;
2207}
2208
2209
2210static int pgp_armor_encrypt(struct mailprivacy * privacy,
2211 struct mailmime * mime, struct mailmime ** result)
2212{
2213 char original_filename[PATH_MAX];
2214 FILE * original_f;
2215 char encrypted_filename[PATH_MAX];
2216 FILE * encrypted_f;
2217 char quoted_original_filename[PATH_MAX];
2218 char quoted_encrypted_filename[PATH_MAX];
2219 int col;
2220 struct mailmime * encrypted_mime;
2221 int res;
2222 int r;
2223 char command[PATH_MAX];
2224 struct mailmime_content * content_type;
2225 struct mailmime * root;
2226 struct mailimf_fields * fields;
2227 char recipient[PATH_MAX];
2228
2229 if (mime->mm_type != MAILMIME_SINGLE) {
2230 res = MAIL_ERROR_INVAL;
2231 goto err;
2232 }
2233
2234 if (mime->mm_data.mm_single == NULL) {
2235 res = MAIL_ERROR_INVAL;
2236 goto err;
2237 }
2238
2239 root = mime;
2240 while (root->mm_parent != NULL)
2241 root = root->mm_parent;
2242
2243 fields = NULL;
2244 if (root->mm_type == MAILMIME_MESSAGE)
2245 fields = root->mm_data.mm_message.mm_fields;
2246
2247 /* recipient */
2248
2249 collect_recipient(recipient, sizeof(recipient), fields);
2250
2251 /* get part to encrypt */
2252
2253 original_f = mailprivacy_get_tmp_file(privacy, original_filename,
2254 sizeof(original_filename));
2255 if (original_f == NULL) {
2256 res = MAIL_ERROR_FILE;
2257 goto err;
2258 }
2259
2260 col = 0;
2261 r = mailmime_data_write(original_f, &col, mime->mm_data.mm_single, 1);
2262 if (r != MAILIMF_NO_ERROR) {
2263 fclose(original_f);
2264 res = MAIL_ERROR_FILE;
2265 goto unlink_original;
2266 }
2267 fclose(original_f);
2268
2269 encrypted_f = mailprivacy_get_tmp_file(privacy,
2270 encrypted_filename,
2271 sizeof(encrypted_filename));
2272 if (encrypted_f == NULL) {
2273 res = MAIL_ERROR_FILE;
2274 goto unlink_original;
2275 }
2276 fclose(encrypted_f);
2277
2278 r = mail_quote_filename(quoted_original_filename,
2279 sizeof(quoted_original_filename), original_filename);
2280 if (r < 0) {
2281 res = MAIL_ERROR_MEMORY;
2282 goto unlink_encrypted;
2283 }
2284
2285 r = mail_quote_filename(quoted_encrypted_filename,
2286 sizeof(quoted_encrypted_filename), encrypted_filename);
2287 if (r < 0) {
2288 res = MAIL_ERROR_MEMORY;
2289 goto unlink_encrypted;
2290 }
2291
2292 snprintf(command, sizeof(command),
2293 "gpg -q %s --batch --yes --out %s -e --armor %s 2>/dev/null",
2294 recipient, quoted_encrypted_filename, quoted_original_filename);
2295
2296 r = system(command);
2297 if (WEXITSTATUS(r) != 0) {
2298 res = MAIL_ERROR_COMMAND;
2299 goto unlink_encrypted;
2300 }
2301
2302 /* building the encrypted part */
2303
2304 encrypted_mime = mailprivacy_new_file_part(privacy,
2305 encrypted_filename,
2306 "application/octet-stream",
2307 MAILMIME_MECHANISM_8BIT);
2308 if (encrypted_mime == NULL) {
2309 res = MAIL_ERROR_MEMORY;
2310 goto unlink_encrypted;
2311 }
2312
2313 /* place original content type */
2314
2315 content_type = mailmime_content_dup(mime->mm_content_type);
2316 if (content_type == NULL) {
2317 mailprivacy_mime_clear(encrypted_mime);
2318 mailmime_free(encrypted_mime);
2319 res = MAIL_ERROR_MEMORY;
2320 goto unlink_encrypted;
2321 }
2322
2323 mailmime_content_free(encrypted_mime->mm_content_type);
2324 encrypted_mime->mm_content_type = content_type;
2325
2326 /* place original MIME fields */
2327
2328 if (mime->mm_mime_fields != NULL) {
2329 struct mailmime_fields * mime_fields;
2330 clistiter * cur;
2331
2332 mime_fields = mailprivacy_mime_fields_dup(privacy, mime->mm_mime_fields);
2333 if (mime_fields == NULL) {
2334 mailprivacy_mime_clear(encrypted_mime);
2335 mailmime_free(encrypted_mime);
2336 res = MAIL_ERROR_MEMORY;
2337 goto unlink_encrypted;
2338 }
2339 for(cur = clist_begin(mime_fields->fld_list) ;
2340 cur != NULL ; cur = clist_next(cur)) {
2341 struct mailmime_field * field;
2342
2343 field = clist_content(cur);
2344 if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) {
2345 mailmime_field_free(field);
2346 clist_delete(mime_fields->fld_list, cur);
2347 break;
2348 }
2349 }
2350 clist_concat(encrypted_mime->mm_mime_fields->fld_list,
2351 mime_fields->fld_list);
2352 mailmime_fields_free(mime_fields);
2353 }
2354
2355 unlink(encrypted_filename);
2356 unlink(original_filename);
2357
2358 * result = encrypted_mime;
2359
2360 return MAIL_NO_ERROR;
2361
2362 unlink_encrypted:
2363 unlink(encrypted_filename);
2364 unlink_original:
2365 unlink(original_filename);
2366 err:
2367 return res;
2368}
2369
2370
2371static int pgp_armor_sign_encrypt(struct mailprivacy * privacy,
2372 struct mailmime * mime, struct mailmime ** result)
2373{
2374 char default_key[PATH_MAX];
2375 char original_filename[PATH_MAX];
2376 FILE * original_f;
2377 char encrypted_filename[PATH_MAX];
2378 FILE * encrypted_f;
2379 char quoted_original_filename[PATH_MAX];
2380 char quoted_encrypted_filename[PATH_MAX];
2381 int col;
2382 struct mailmime * encrypted_mime;
2383 int res;
2384 int r;
2385 char command[PATH_MAX];
2386 struct mailmime_content * content_type;
2387 struct mailmime * root;
2388 struct mailimf_fields * fields;
2389 char recipient[PATH_MAX];
2390 char * email;
2391
2392 if (mime->mm_type != MAILMIME_SINGLE) {
2393 res = MAIL_ERROR_INVAL;
2394 goto err;
2395 }
2396
2397 if (mime->mm_data.mm_single == NULL) {
2398 res = MAIL_ERROR_INVAL;
2399 goto err;
2400 }
2401
2402 /* get signing key */
2403
2404 * default_key = '\0';
2405 email = get_first_from_addr(mime);
2406 if (email != NULL)
2407 snprintf(default_key, sizeof(default_key),
2408 "--default-key %s", email);
2409
2410 root = mime;
2411 while (root->mm_parent != NULL)
2412 root = root->mm_parent;
2413
2414 fields = NULL;
2415 if (root->mm_type == MAILMIME_MESSAGE)
2416 fields = root->mm_data.mm_message.mm_fields;
2417
2418 /* recipient */
2419
2420 collect_recipient(recipient, sizeof(recipient), fields);
2421
2422 /* get part to encrypt */
2423
2424 original_f = mailprivacy_get_tmp_file(privacy,
2425 original_filename,
2426 sizeof(original_filename));
2427 if (original_f == NULL) {
2428 res = MAIL_ERROR_FILE;
2429 goto err;
2430 }
2431
2432 col = 0;
2433 r = mailmime_data_write(original_f, &col, mime->mm_data.mm_single, 1);
2434 if (r != MAILIMF_NO_ERROR) {
2435 fclose(original_f);
2436 res = MAIL_ERROR_FILE;
2437 goto unlink_original;
2438 }
2439 fclose(original_f);
2440
2441 encrypted_f = mailprivacy_get_tmp_file(privacy,
2442 encrypted_filename,
2443 sizeof(encrypted_filename));
2444 if (encrypted_f == NULL) {
2445 res = MAIL_ERROR_FILE;
2446 goto unlink_original;
2447 }
2448 fclose(encrypted_f);
2449
2450 r = mail_quote_filename(quoted_original_filename,
2451 sizeof(quoted_original_filename), original_filename);
2452 if (r < 0) {
2453 res = MAIL_ERROR_MEMORY;
2454 goto unlink_encrypted;
2455 }
2456
2457 r = mail_quote_filename(quoted_encrypted_filename,
2458 sizeof(quoted_encrypted_filename), encrypted_filename);
2459 if (r < 0) {
2460 res = MAIL_ERROR_MEMORY;
2461 goto unlink_encrypted;
2462 }
2463
2464 snprintf(command, sizeof(command),
2465 "gpg -q %s --batch --yes --digest-algo sha1 "
2466 "--out %s %s -e -s -a %s 2>/dev/null",
2467 recipient, encrypted_filename, default_key, original_filename);
2468
2469 r = system(command);
2470 if (WEXITSTATUS(r) != 0) {
2471 res = MAIL_ERROR_COMMAND;
2472 goto unlink_encrypted;
2473 }
2474
2475 /* building the encrypted part */
2476
2477 encrypted_mime = mailprivacy_new_file_part(privacy,
2478 encrypted_filename,
2479 "application/octet-stream",
2480 MAILMIME_MECHANISM_8BIT);
2481 if (encrypted_mime == NULL) {
2482 res = MAIL_ERROR_MEMORY;
2483 goto unlink_encrypted;
2484 }
2485
2486 /* place original content type */
2487
2488 content_type = mailmime_content_dup(mime->mm_content_type);
2489 if (content_type == NULL) {
2490 mailprivacy_mime_clear(encrypted_mime);
2491 mailmime_free(encrypted_mime);
2492 res = MAIL_ERROR_MEMORY;
2493 goto unlink_encrypted;
2494 }
2495
2496 mailmime_content_free(encrypted_mime->mm_content_type);
2497 encrypted_mime->mm_content_type = content_type;
2498
2499 /* place original MIME fields */
2500
2501 if (mime->mm_mime_fields != NULL) {
2502 struct mailmime_fields * mime_fields;
2503 clistiter * cur;
2504
2505 mime_fields = mailprivacy_mime_fields_dup(privacy, mime->mm_mime_fields);
2506 if (mime_fields == NULL) {
2507 mailprivacy_mime_clear(encrypted_mime);
2508 mailmime_free(encrypted_mime);
2509 res = MAIL_ERROR_MEMORY;
2510 goto unlink_encrypted;
2511 }
2512 for(cur = clist_begin(mime_fields->fld_list) ;
2513 cur != NULL ; cur = clist_next(cur)) {
2514 struct mailmime_field * field;
2515
2516 field = clist_content(cur);
2517 if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) {
2518 mailmime_field_free(field);
2519 clist_delete(mime_fields->fld_list, cur);
2520 break;
2521 }
2522 }
2523 clist_concat(encrypted_mime->mm_mime_fields->fld_list,
2524 mime_fields->fld_list);
2525 mailmime_fields_free(mime_fields);
2526 }
2527
2528 unlink(encrypted_filename);
2529 unlink(original_filename);
2530
2531 * result = encrypted_mime;
2532
2533 return MAIL_NO_ERROR;
2534
2535 unlink_encrypted:
2536 unlink(encrypted_filename);
2537 unlink_original:
2538 unlink(original_filename);
2539 err:
2540 return res;
2541}
2542
2543
2544static struct mailprivacy_encryption pgp_encryption_tab[] = {
2545 /* PGP signed part */
2546 {
2547 .name = "signed",
2548 .description = "PGP signed part",
2549 .encrypt = pgp_sign_mime,
2550 },
2551
2552 /* PGP encrypted part */
2553
2554 {
2555 .name = "encrypted",
2556 .description = "PGP encrypted part",
2557 .encrypt = pgp_encrypt_mime,
2558 },
2559
2560 /* PGP signed & encrypted part */
2561
2562 {
2563 .name = "signed-encrypted",
2564 .description = "PGP signed & encrypted part",
2565 .encrypt = pgp_sign_encrypt_mime,
2566 },
2567
2568 /* PGP clear signed part */
2569
2570 {
2571 .name = "clear-signed",
2572 .description = "PGP clear signed part",
2573 .encrypt = pgp_clear_sign,
2574 },
2575
2576 /* PGP armor encrypted part */
2577
2578 {
2579 .name = "encrypted-armor",
2580 .description = "PGP ASCII armor encrypted part",
2581 .encrypt = pgp_armor_encrypt,
2582 },
2583
2584 /* PGP armor signed & encrypted part */
2585
2586 {
2587 .name = "signed-encrypted-armor",
2588 .description = "PGP ASCII armor signed & encrypted part",
2589 .encrypt = pgp_armor_sign_encrypt,
2590 },
2591};
2592
2593static struct mailprivacy_protocol pgp_protocol = {
2594 .name = "pgp",
2595 .description = "OpenPGP",
2596
2597 .is_encrypted = pgp_test_encrypted,
2598 .decrypt = pgp_handler,
2599
2600 .encryption_count =
2601 (sizeof(pgp_encryption_tab) / sizeof(pgp_encryption_tab[0])),
2602
2603 .encryption_tab = pgp_encryption_tab,
2604};
2605
2606int mailprivacy_gnupg_init(struct mailprivacy * privacy)
2607{
2608 return mailprivacy_register(privacy, &pgp_protocol);
2609}
2610
2611void mailprivacy_gnupg_done(struct mailprivacy * privacy)
2612{
2613 mailprivacy_unregister(privacy, &pgp_protocol);
2614}
diff --git a/libetpan/src/engine/mailprivacy_gnupg.h b/libetpan/src/engine/mailprivacy_gnupg.h
new file mode 100644
index 0000000..013c8a4
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_gnupg.h
@@ -0,0 +1,46 @@
1/*
2 * etPan! -- a mail user agent
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#ifndef MAIL_PRIVACY_GNUPG_H
37
38#define MAIL_PRIVACY_GNUPG_H
39
40#include <libetpan/mailprivacy_types.h>
41
42int mailprivacy_gnupg_init(struct mailprivacy * privacy);
43
44void mailprivacy_gnupg_done(struct mailprivacy * privacy);
45
46#endif
diff --git a/libetpan/src/engine/mailprivacy_smime.c b/libetpan/src/engine/mailprivacy_smime.c
new file mode 100644
index 0000000..43eb69f
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_smime.c
@@ -0,0 +1,1755 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailprivacy_smime.h"
37#include <string.h>
38#include <sys/wait.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <fcntl.h>
42#include <unistd.h>
43#include <sys/mman.h>
44#include "mailprivacy_tools.h"
45#include "mailprivacy.h"
46#include <stdlib.h>
47#include <dirent.h>
48#include <stdio.h>
49#include <ctype.h>
50#include <libetpan/libetpan-config.h>
51
52/*
53 global variable
54
55 TODO : instance of privacy drivers
56*/
57
58static char cert_dir[PATH_MAX] = "";
59static chash * certificates = NULL;
60static chash * private_keys = NULL;
61static char CAcert_dir[PATH_MAX] = "";
62static char * CAfile = NULL;
63static int CA_check = 1;
64static int store_cert = 0;
65static char private_keys_dir[PATH_MAX] = "";
66
67static char * get_cert_file(char * email);
68
69static char * get_private_key_file(char * email);
70
71
72static int smime_is_signed(struct mailmime * mime)
73{
74 if (mime->mm_content_type != NULL) {
75 clistiter * cur;
76
77 for(cur = clist_begin(mime->mm_content_type->ct_parameters) ; cur != NULL ;
78 cur = clist_next(cur)) {
79 struct mailmime_parameter * param;
80
81 param = cur->data;
82
83 if ((strcasecmp(param->pa_name, "protocol") == 0) &&
84 ((strcasecmp(param->pa_value, "application/x-pkcs7-signature") == 0) ||
85 (strcasecmp(param->pa_value, "application/pkcs7-signature") == 0)))
86 return 1;
87 }
88 }
89
90 return 0;
91}
92
93static int smime_is_encrypted(struct mailmime * mime)
94{
95 if (mime->mm_content_type != NULL) {
96 if ((strcasecmp(mime->mm_content_type->ct_subtype, "x-pkcs7-mime") == 0) ||
97 (strcasecmp(mime->mm_content_type->ct_subtype, "pkcs7-mime") == 0))
98 return 1;
99 }
100
101 return 0;
102}
103
104#define BUF_SIZE 1024
105
106enum {
107 NO_ERROR_SMIME = 0,
108 ERROR_SMIME_CHECK,
109 ERROR_SMIME_COMMAND,
110 ERROR_SMIME_FILE,
111};
112
113/* write output to a file */
114
115static int get_smime_output(FILE * dest_f, char * command)
116{
117 FILE * p;
118 char buf[BUF_SIZE];
119 size_t size;
120 int res;
121 int status;
122 char command_redirected[PATH_MAX];
123
124 snprintf(command_redirected, sizeof(command_redirected), "%s 2>&1", command);
125
126 /*
127 flush buffer so that it is not flushed more than once when forking
128 */
129 fflush(dest_f);
130
131 p = popen(command_redirected, "r");
132 if (p == NULL) {
133 res = ERROR_SMIME_COMMAND;
134 goto err;
135 }
136
137 while ((size = fread(buf, 1, sizeof(buf), p)) != 0) {
138 size_t written;
139
140 written = fwrite(buf, 1, size, dest_f);
141 if (written != size) {
142 res = ERROR_SMIME_FILE;
143 goto close;
144 }
145 }
146 status = pclose(p);
147
148 if (WEXITSTATUS(status) != 0)
149 return ERROR_SMIME_CHECK;
150 else
151 return NO_ERROR_SMIME;
152
153 close:
154 pclose(p);
155 err:
156 return res;
157}
158
159static char * get_first_from_addr(struct mailmime * mime)
160{
161 clistiter * cur;
162 struct mailimf_single_fields single_fields;
163 struct mailimf_fields * fields;
164 struct mailimf_mailbox * mb;
165
166 while (mime->mm_parent != NULL)
167 mime = mime->mm_parent;
168
169 if (mime->mm_type != MAILMIME_MESSAGE)
170 return NULL;
171
172 fields = mime->mm_data.mm_message.mm_fields;
173 if (fields == NULL)
174 return NULL;
175
176 mailimf_single_fields_init(&single_fields, fields);
177
178 if (single_fields.fld_from == NULL)
179 return NULL;
180
181 cur = clist_begin(single_fields.fld_from->frm_mb_list->mb_list);
182 if (cur == NULL)
183 return NULL;
184
185 mb = clist_content(cur);
186
187 return mb->mb_addr_spec;
188}
189
190#define SMIME_DECRYPT_DESCRIPTION "S/MIME encrypted part\r\n"
191#define SMIME_DECRYPT_FAILED "S/MIME decryption FAILED\r\n"
192#define SMIME_DECRYPT_SUCCESS "S/MIME decryption success\r\n"
193
194static int smime_decrypt(struct mailprivacy * privacy,
195 mailmessage * msg,
196 struct mailmime * mime, struct mailmime ** result)
197{
198 char smime_filename[PATH_MAX];
199 char quoted_smime_filename[PATH_MAX];
200 char description_filename[PATH_MAX];
201 FILE * description_f;
202 char decrypted_filename[PATH_MAX];
203 FILE * decrypted_f;
204 char command[PATH_MAX];
205 struct mailmime * description_mime;
206 struct mailmime * decrypted_mime;
207 int r;
208 int res;
209 int sign_ok;
210 char quoted_decrypted_filename[PATH_MAX];
211 struct mailmime * multipart;
212 char * smime_cert;
213 char * smime_key;
214 char quoted_smime_cert[PATH_MAX];
215 char quoted_smime_key[PATH_MAX];
216 char * email;
217 chashiter * iter;
218
219 /* fetch the whole multipart and write it to a file */
220
221 r = mailprivacy_fetch_mime_body_to_file(privacy,
222 smime_filename, sizeof(smime_filename),
223 msg, mime);
224 if (r != MAIL_NO_ERROR) {
225 res = r;
226 goto err;
227 }
228
229 /* we are in a safe directory */
230
231 decrypted_f = mailprivacy_get_tmp_file(privacy,
232 decrypted_filename,
233 sizeof(decrypted_filename));
234 if (decrypted_f == NULL) {
235 res = MAIL_ERROR_FILE;
236 goto unlink_smime;
237 }
238 fclose(decrypted_f);
239
240 sign_ok = 0;
241 for(iter = chash_begin(private_keys) ; iter != NULL ;
242 iter = chash_next(private_keys, iter)) {
243 chashdatum key;
244 char email_buf[BUF_SIZE];
245
246 chash_key(iter, &key);
247
248 if (key.len >= sizeof(email_buf))
249 continue;
250
251 strncpy(email_buf, key.data, key.len);
252 email_buf[key.len] = '\0';
253 email = email_buf;
254
255 /* description */
256
257 description_f = mailprivacy_get_tmp_file(privacy,
258 description_filename,
259 sizeof(description_filename));
260 if (description_f == NULL) {
261 res = MAIL_ERROR_FILE;
262 goto unlink_decrypted;
263 }
264
265 fprintf(description_f, SMIME_DECRYPT_DESCRIPTION);
266
267 /* get encryption key */
268
269#if 0
270 email = get_first_from_addr(mime);
271 if (email == NULL) {
272 fclose(description_f);
273 res = MAIL_ERROR_INVAL;
274 goto unlink_description;
275 }
276#endif
277
278 smime_key = get_private_key_file(email);
279 smime_cert = get_cert_file(email);
280 if ((smime_cert == NULL) || (smime_key == NULL)) {
281 fclose(description_f);
282 res = MAIL_ERROR_INVAL;
283 goto unlink_description;
284 }
285
286 r = mail_quote_filename(quoted_smime_cert, sizeof(quoted_smime_cert),
287 smime_cert);
288 if (r < 0) {
289 fclose(description_f);
290 res = MAIL_ERROR_MEMORY;
291 goto unlink_description;
292 }
293
294 r = mail_quote_filename(quoted_smime_key, sizeof(quoted_smime_key),
295 smime_key);
296 if (r < 0) {
297 fclose(description_f);
298 res = MAIL_ERROR_MEMORY;
299 goto unlink_description;
300 }
301
302 /* run the command */
303
304 r = mail_quote_filename(quoted_smime_filename,
305 sizeof(quoted_smime_filename), smime_filename);
306 if (r < 0) {
307 fclose(description_f);
308 res = MAIL_ERROR_MEMORY;
309 goto unlink_description;
310 }
311
312 r = mail_quote_filename(quoted_decrypted_filename,
313 sizeof(quoted_decrypted_filename), decrypted_filename);
314 if (r < 0) {
315 fclose(description_f);
316 res = MAIL_ERROR_MEMORY;
317 goto unlink_description;
318 }
319
320 sign_ok = 0;
321 snprintf(command, PATH_MAX,
322 "openssl smime -decrypt -in %s -out %s -inkey %s -recip %s",
323 quoted_smime_filename, quoted_decrypted_filename,
324 quoted_smime_key, quoted_smime_cert);
325
326 r = get_smime_output(description_f, command);
327 switch (r) {
328 case NO_ERROR_SMIME:
329 sign_ok = 1;
330 break;
331 case ERROR_SMIME_CHECK:
332 sign_ok = 0;
333 break;
334 case ERROR_SMIME_COMMAND:
335 fclose(description_f);
336 res = MAIL_ERROR_COMMAND;
337 goto unlink_description;
338 case ERROR_SMIME_FILE:
339 fclose(description_f);
340 res = MAIL_ERROR_FILE;
341 goto unlink_description;
342 }
343
344 if (sign_ok) {
345 fprintf(description_f, SMIME_DECRYPT_SUCCESS);
346 fclose(description_f);
347 break;
348 }
349 else {
350 fclose(description_f);
351 unlink(description_filename);
352 }
353 }
354
355 if (!sign_ok) {
356 description_f = mailprivacy_get_tmp_file(privacy,
357 description_filename,
358 sizeof(description_filename));
359 if (description_f == NULL) {
360 res = MAIL_ERROR_FILE;
361 goto unlink_decrypted;
362 }
363
364 fprintf(description_f, SMIME_DECRYPT_DESCRIPTION);
365 fprintf(description_f, SMIME_DECRYPT_FAILED);
366 fclose(description_f);
367 }
368
369 /* building multipart */
370
371 r = mailmime_new_with_content("multipart/x-decrypted", NULL, &multipart);
372 if (r != MAILIMF_NO_ERROR) {
373 res = MAIL_ERROR_MEMORY;
374 goto unlink_description;
375 }
376
377 /* building the description part */
378
379 description_mime = mailprivacy_new_file_part(privacy,
380 description_filename,
381 "text/plain", MAILMIME_MECHANISM_8BIT);
382 if (description_mime == NULL) {
383 mailprivacy_mime_clear(multipart);
384 mailmime_free(multipart);
385 res = MAIL_ERROR_MEMORY;
386 goto unlink_description;
387 }
388
389 /* adds the description part */
390
391 r = mailmime_smart_add_part(multipart, description_mime);
392 if (r != MAIL_NO_ERROR) {
393 mailprivacy_mime_clear(description_mime);
394 mailmime_free(description_mime);
395 mailprivacy_mime_clear(multipart);
396 mailmime_free(multipart);
397 res = MAIL_ERROR_MEMORY;
398 goto unlink_description;
399 }
400
401 /* building the decrypted part */
402
403 r = mailprivacy_get_part_from_file(privacy, 1,
404 decrypted_filename, &decrypted_mime);
405 if (r == MAIL_NO_ERROR) {
406 /* adds the decrypted part */
407
408 r = mailmime_smart_add_part(multipart, decrypted_mime);
409 if (r != MAIL_NO_ERROR) {
410 mailprivacy_mime_clear(decrypted_mime);
411 mailmime_free(decrypted_mime);
412 mailprivacy_mime_clear(multipart);
413 mailmime_free(multipart);
414 res = MAIL_ERROR_MEMORY;
415 goto unlink_description;
416 }
417 }
418
419 unlink(description_filename);
420 unlink(decrypted_filename);
421 unlink(smime_filename);
422
423 * result = multipart;
424
425 return MAIL_NO_ERROR;
426
427 unlink_description:
428 unlink(description_filename);
429 unlink_decrypted:
430 unlink(decrypted_filename);
431 unlink_smime:
432 unlink(smime_filename);
433 err:
434 return res;
435}
436
437
438static int get_cert_from_sig(struct mailprivacy * privacy,
439 mailmessage * msg,
440 struct mailmime * mime);
441
442#define SMIME_VERIFY_DESCRIPTION "S/MIME verify signed message\r\n"
443#define SMIME_VERIFY_FAILED "S/MIME verification FAILED\r\n"
444#define SMIME_VERIFY_SUCCESS "S/MIME verification success\r\n"
445
446static int
447smime_verify(struct mailprivacy * privacy,
448 mailmessage * msg,
449 struct mailmime * mime, struct mailmime ** result)
450{
451 char smime_filename[PATH_MAX];
452 char quoted_smime_filename[PATH_MAX];
453 int res;
454 int r;
455 char command[PATH_MAX];
456 int sign_ok;
457 struct mailmime * description_mime;
458 FILE * description_f;
459 char description_filename[PATH_MAX];
460 struct mailmime * multipart;
461 char stripped_filename[PATH_MAX];
462 struct mailmime * stripped_mime;
463 char quoted_stripped_filename[PATH_MAX];
464 FILE * stripped_f;
465 char check_CA[PATH_MAX];
466 char quoted_CAfile[PATH_MAX];
467 char noverify[PATH_MAX];
468
469 if (store_cert)
470 get_cert_from_sig(privacy, msg, mime);
471
472 * check_CA = '\0';
473 if (CAfile != NULL) {
474 r = mail_quote_filename(quoted_CAfile, sizeof(quoted_CAfile), CAfile);
475 if (r < 0) {
476 res = MAIL_ERROR_MEMORY;
477 goto err;
478 }
479
480 snprintf(check_CA, sizeof(check_CA), "-CAfile %s", quoted_CAfile);
481 }
482
483 * noverify = '\0';
484 if (!CA_check) {
485 snprintf(noverify, sizeof(noverify), "-noverify");
486 }
487
488 /* fetch the whole multipart and write it to a file */
489
490 r = mailprivacy_fetch_mime_body_to_file(privacy,
491 smime_filename, sizeof(smime_filename),
492 msg, mime);
493 if (r != MAIL_NO_ERROR) {
494 res = r;
495 goto err;
496 }
497
498 stripped_f = mailprivacy_get_tmp_file(privacy,
499 stripped_filename,
500 sizeof(stripped_filename));
501 if (stripped_f == NULL) {
502 res = MAIL_ERROR_FILE;
503 goto unlink_smime;
504 }
505 fclose(stripped_f);
506
507 /* description */
508
509 description_f = mailprivacy_get_tmp_file(privacy,
510 description_filename,
511 sizeof(description_filename));
512 if (description_f == NULL) {
513 res = MAIL_ERROR_FILE;
514 goto unlink_stripped;
515 }
516
517 fprintf(description_f, SMIME_VERIFY_DESCRIPTION);
518
519 /* run the command */
520
521 r = mail_quote_filename(quoted_smime_filename,
522 sizeof(quoted_smime_filename), smime_filename);
523 if (r < 0) {
524 fclose(description_f);
525 res = MAIL_ERROR_MEMORY;
526 goto unlink_description;
527 }
528
529 r = mail_quote_filename(quoted_stripped_filename,
530 sizeof(quoted_stripped_filename), stripped_filename);
531 if (r < 0) {
532 fclose(description_f);
533 res = MAIL_ERROR_MEMORY;
534 goto unlink_description;
535 }
536
537 sign_ok = 0;
538 snprintf(command, PATH_MAX, "openssl smime -verify -in %s -out %s %s %s",
539 quoted_smime_filename, quoted_stripped_filename, check_CA, noverify);
540
541 r = get_smime_output(description_f, command);
542 switch (r) {
543 case NO_ERROR_SMIME:
544 sign_ok = 1;
545 break;
546 case ERROR_SMIME_CHECK:
547 sign_ok = 0;
548 break;
549 case ERROR_SMIME_COMMAND:
550 fclose(description_f);
551 res = MAIL_ERROR_COMMAND;
552 goto unlink_description;
553 case ERROR_SMIME_FILE:
554 fclose(description_f);
555 res = MAIL_ERROR_FILE;
556 goto unlink_description;
557 }
558 if (sign_ok)
559 fprintf(description_f, SMIME_VERIFY_SUCCESS);
560 else
561 fprintf(description_f, SMIME_VERIFY_FAILED);
562 fclose(description_f);
563
564 /* building multipart */
565
566 r = mailmime_new_with_content("multipart/x-verified", NULL, &multipart);
567 if (r != MAILIMF_NO_ERROR) {
568 res = MAIL_ERROR_MEMORY;
569 goto unlink_description;
570 }
571
572 /* building the description part */
573
574 description_mime = mailprivacy_new_file_part(privacy,
575 description_filename,
576 "text/plain", MAILMIME_MECHANISM_8BIT);
577 if (description_mime == NULL) {
578 mailprivacy_mime_clear(multipart);
579 mailmime_free(multipart);
580 res = MAIL_ERROR_MEMORY;
581 goto unlink_description;
582 }
583
584 /* adds the description part */
585
586 r = mailmime_smart_add_part(multipart, description_mime);
587 if (r != MAIL_NO_ERROR) {
588 mailprivacy_mime_clear(description_mime);
589 mailmime_free(description_mime);
590 mailprivacy_mime_clear(multipart);
591 mailmime_free(multipart);
592 res = MAIL_ERROR_MEMORY;
593 goto unlink_description;
594 }
595
596 r = mailprivacy_get_part_from_file(privacy, 1,
597 stripped_filename, &stripped_mime);
598 if (r != MAIL_NO_ERROR) {
599 mailprivacy_mime_clear(multipart);
600 mailmime_free(multipart);
601 res = r;
602 goto unlink_description;
603 }
604
605 r = mailmime_smart_add_part(multipart, stripped_mime);
606 if (r != MAIL_NO_ERROR) {
607 mailprivacy_mime_clear(stripped_mime);
608 mailmime_free(stripped_mime);
609 mailprivacy_mime_clear(multipart);
610 mailmime_free(multipart);
611 res = MAIL_ERROR_MEMORY;
612 goto unlink_description;
613 }
614
615 unlink(description_filename);
616 unlink(stripped_filename);
617 unlink(smime_filename);
618
619 * result = multipart;
620
621 return MAIL_NO_ERROR;
622
623 unlink_description:
624 unlink(description_filename);
625 unlink_stripped:
626 unlink(stripped_filename);
627 unlink_smime:
628 unlink(smime_filename);
629 err:
630 return res;
631}
632
633static int smime_test_encrypted(struct mailprivacy * privacy,
634 mailmessage * msg,
635 struct mailmime * mime)
636{
637 switch (mime->mm_type) {
638 case MAILMIME_MULTIPLE:
639 return smime_is_signed(mime);
640
641 case MAILMIME_SINGLE:
642 return smime_is_encrypted(mime);
643 }
644
645 return 0;
646}
647
648static int smime_handler(struct mailprivacy * privacy,
649 mailmessage * msg,
650 struct mailmime * mime, struct mailmime ** result)
651{
652 int r;
653 struct mailmime * alternative_mime;
654
655 alternative_mime = NULL;
656 switch (mime->mm_type) {
657 case MAILMIME_MULTIPLE:
658 r = MAIL_ERROR_INVAL;
659 if (smime_is_signed(mime))
660 r = smime_verify(privacy, msg, mime, &alternative_mime);
661
662 if (r != MAIL_NO_ERROR)
663 return r;
664
665 * result = alternative_mime;
666
667 return MAIL_NO_ERROR;
668
669 case MAILMIME_SINGLE:
670 r = MAIL_ERROR_INVAL;
671 if (smime_is_encrypted(mime))
672 r = smime_decrypt(privacy, msg, mime, &alternative_mime);
673
674 if (r != MAIL_NO_ERROR)
675 return r;
676
677 * result = alternative_mime;
678
679 return MAIL_NO_ERROR;
680 }
681
682 return MAIL_ERROR_INVAL;
683}
684
685
686
687
688static void strip_mime_headers(struct mailmime * mime)
689{
690 struct mailmime_fields * fields;
691 clistiter * cur;
692
693 fields = mime->mm_mime_fields;
694
695 if (fields == NULL)
696 return;
697
698 for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
699 cur = clist_next(cur)) {
700 struct mailmime_field * field;
701
702 field = clist_content(cur);
703
704 if (field->fld_type == MAILMIME_FIELD_VERSION) {
705 mailmime_field_free(field);
706 clist_delete(fields->fld_list, cur);
707 break;
708 }
709 }
710}
711
712static int smime_sign(struct mailprivacy * privacy,
713 struct mailmime * mime, struct mailmime ** result)
714{
715 char signed_filename[PATH_MAX];
716 FILE * signed_f;
717 int res;
718 int r;
719 int col;
720 char signature_filename[PATH_MAX];
721 FILE * signature_f;
722 char command[PATH_MAX];
723 char quoted_signature_filename[PATH_MAX];
724 char quoted_signed_filename[PATH_MAX];
725 struct mailmime * signed_mime;
726 char * smime_cert;
727 char * smime_key;
728 char quoted_smime_cert[PATH_MAX];
729 char quoted_smime_key[PATH_MAX];
730 char * email;
731
732 /* get signing key */
733
734 email = get_first_from_addr(mime);
735 if (email == NULL) {
736 res = MAIL_ERROR_INVAL;
737 goto err;
738 }
739
740 smime_key = get_private_key_file(email);
741 smime_cert = get_cert_file(email);
742 if ((smime_cert == NULL) || (smime_key == NULL)) {
743 res = MAIL_ERROR_INVAL;
744 goto err;
745 }
746
747 /* part to sign */
748
749 /* encode quoted printable all text parts */
750
751 mailprivacy_prepare_mime(mime);
752
753 signed_f = mailprivacy_get_tmp_file(privacy,
754 signed_filename, sizeof(signed_filename));
755 if (signed_f == NULL) {
756 res = MAIL_ERROR_FILE;
757 goto err;
758 }
759
760 col = 0;
761 r = mailmime_write(signed_f, &col, mime);
762 if (r != MAILIMF_NO_ERROR) {
763 fclose(signed_f);
764 res = MAIL_ERROR_FILE;
765 goto unlink_signed;
766 }
767
768 fclose(signed_f);
769
770 /* prepare destination file for signature */
771
772 signature_f = mailprivacy_get_tmp_file(privacy,
773 signature_filename,
774 sizeof(signature_filename));
775 if (signature_f == NULL) {
776 res = MAIL_ERROR_FILE;
777 goto unlink_signed;
778 }
779 fclose(signature_f);
780
781 r = mail_quote_filename(quoted_signed_filename,
782 sizeof(quoted_signed_filename), signed_filename);
783 if (r < 0) {
784 res = MAIL_ERROR_MEMORY;
785 goto unlink_signature;
786 }
787
788 r = mail_quote_filename(quoted_signature_filename,
789 sizeof(quoted_signature_filename), signature_filename);
790 if (r < 0) {
791 res = MAIL_ERROR_MEMORY;
792 goto unlink_signature;
793 }
794
795 r = mail_quote_filename(quoted_smime_key,
796 sizeof(quoted_smime_key), smime_key);
797 if (r < 0) {
798 res = MAIL_ERROR_MEMORY;
799 goto unlink_signature;
800 }
801
802 r = mail_quote_filename(quoted_smime_cert,
803 sizeof(quoted_smime_cert), smime_cert);
804 if (r < 0) {
805 res = MAIL_ERROR_MEMORY;
806 goto unlink_signature;
807 }
808
809 snprintf(command, sizeof(command),
810 "openssl smime -sign -in %s -out %s -signer %s -inkey %s 2>/dev/null",
811 quoted_signed_filename, quoted_signature_filename,
812 quoted_smime_cert, quoted_smime_key);
813
814 r = system(command);
815 if (WEXITSTATUS(r) != 0) {
816 res = MAIL_ERROR_COMMAND;
817 goto unlink_signature;
818 }
819
820 /* signature part */
821
822 r = mailprivacy_get_part_from_file(privacy, 0,
823 signature_filename, &signed_mime);
824 if (r != MAIL_NO_ERROR) {
825 res = r;
826 goto unlink_signature;
827 }
828 strip_mime_headers(signed_mime);
829
830 unlink(signature_filename);
831 unlink(signed_filename);
832
833 * result = signed_mime;
834
835 return MAIL_NO_ERROR;
836
837 unlink_signature:
838 unlink(signature_filename);
839 unlink_signed:
840 unlink(signed_filename);
841 err:
842 return res;
843}
844
845
846/* ********************************************************************* */
847/* find S/MIME recipient */
848
849static int recipient_add_mb(char * recipient, size_t * len,
850 struct mailimf_mailbox * mb)
851{
852 char * filename;
853 char quoted_filename[PATH_MAX];
854 size_t buflen;
855 int r;
856
857 if (mb->mb_addr_spec == NULL)
858 return MAIL_NO_ERROR;
859
860 filename = get_cert_file(mb->mb_addr_spec);
861 if (filename == NULL)
862 return MAIL_ERROR_INVAL;
863
864 r = mail_quote_filename(quoted_filename, sizeof(quoted_filename),
865 filename);
866 if (r < 0)
867 return MAIL_ERROR_MEMORY;
868
869 buflen = strlen(quoted_filename + 1);
870 if (buflen >= * len)
871 return MAIL_ERROR_MEMORY;
872
873 strncat(recipient, quoted_filename, * len);
874 (* len) -= buflen;
875 strncat(recipient, " ", * len);
876 (* len) --;
877
878 return MAIL_NO_ERROR;
879}
880
881static int recipient_add_mb_list(char * recipient, size_t * len,
882 struct mailimf_mailbox_list * mb_list)
883{
884 clistiter * cur;
885 int r;
886
887 for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
888 cur = clist_next(cur)) {
889 struct mailimf_mailbox * mb;
890
891 mb = clist_content(cur);
892
893 r = recipient_add_mb(recipient, len, mb);
894 if (r != MAIL_NO_ERROR)
895 return r;
896 }
897
898 return MAIL_NO_ERROR;
899}
900
901static int recipient_add_group(char * recipient, size_t * len,
902 struct mailimf_group * group)
903{
904 return recipient_add_mb_list(recipient, len, group->grp_mb_list);
905}
906
907static int recipient_add_addr(char * recipient, size_t * len,
908 struct mailimf_address * addr)
909{
910 int r;
911
912 switch (addr->ad_type) {
913 case MAILIMF_ADDRESS_MAILBOX:
914 r = recipient_add_mb(recipient, len, addr->ad_data.ad_mailbox);
915 break;
916 case MAILIMF_ADDRESS_GROUP:
917 r = recipient_add_group(recipient, len, addr->ad_data.ad_group);
918 break;
919 default:
920 r = MAIL_ERROR_INVAL;
921 }
922
923 return r;
924}
925
926static int recipient_add_addr_list(char * recipient, size_t * len,
927 struct mailimf_address_list * addr_list)
928{
929 clistiter * cur;
930 int r;
931
932 for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
933 cur = clist_next(cur)) {
934 struct mailimf_address * addr;
935
936 addr = clist_content(cur);
937
938 r = recipient_add_addr(recipient, len, addr);
939 if (r != MAIL_NO_ERROR)
940 return r;
941 }
942
943 return MAIL_NO_ERROR;
944}
945
946static int collect_smime_cert(char * recipient, size_t size,
947 struct mailimf_fields * fields)
948{
949 struct mailimf_single_fields single_fields;
950 int r;
951 size_t remaining;
952 int res;
953
954 * recipient = '\0';
955 remaining = size;
956
957 if (fields != NULL)
958 mailimf_single_fields_init(&single_fields, fields);
959
960 if (single_fields.fld_to != NULL) {
961 r = recipient_add_addr_list(recipient, &remaining,
962 single_fields.fld_to->to_addr_list);
963 if (r != MAIL_NO_ERROR) {
964 res = r;
965 goto err;
966 }
967 }
968
969 if (single_fields.fld_cc != NULL) {
970 r = recipient_add_addr_list(recipient, &remaining,
971 single_fields.fld_cc->cc_addr_list);
972 if (r != MAIL_NO_ERROR) {
973 res = r;
974 goto err;
975 }
976 }
977
978 if (single_fields.fld_bcc != NULL) {
979 if (single_fields.fld_bcc->bcc_addr_list != NULL) {
980 r = recipient_add_addr_list(recipient, &remaining,
981 single_fields.fld_bcc->bcc_addr_list);
982 if (r < 0) {
983 res = r;
984 goto err;
985 }
986 }
987 }
988
989 return MAIL_NO_ERROR;
990
991 err:
992 return res;
993}
994
995
996
997static int smime_encrypt(struct mailprivacy * privacy,
998 struct mailmime * mime, struct mailmime ** result)
999{
1000 char encrypted_filename[PATH_MAX];
1001 FILE * encrypted_f;
1002 int res;
1003 int r;
1004 int col;
1005 char decrypted_filename[PATH_MAX];
1006 FILE * decrypted_f;
1007 char command[PATH_MAX];
1008 char quoted_decrypted_filename[PATH_MAX];
1009 char quoted_encrypted_filename[PATH_MAX];
1010 struct mailmime * encrypted_mime;
1011 struct mailmime * root;
1012 struct mailimf_fields * fields;
1013 char recipient[PATH_MAX];
1014
1015 root = mime;
1016 while (root->mm_parent != NULL)
1017 root = root->mm_parent;
1018
1019 fields = NULL;
1020 if (root->mm_type == MAILMIME_MESSAGE)
1021 fields = root->mm_data.mm_message.mm_fields;
1022
1023 /* recipient */
1024 r = collect_smime_cert(recipient, sizeof(recipient), fields);
1025 if (r != MAIL_NO_ERROR) {
1026 res = r;
1027 goto err;
1028 }
1029
1030 /* part to encrypt */
1031
1032 /* encode quoted printable all text parts */
1033
1034 mailprivacy_prepare_mime(mime);
1035
1036 decrypted_f = mailprivacy_get_tmp_file(privacy,
1037 decrypted_filename,
1038 sizeof(decrypted_filename));
1039 if (decrypted_f == NULL) {
1040 res = MAIL_ERROR_FILE;
1041 goto err;
1042 }
1043
1044 col = 0;
1045 r = mailmime_write(decrypted_f, &col, mime);
1046 if (r != MAILIMF_NO_ERROR) {
1047 fclose(decrypted_f);
1048 res = MAIL_ERROR_FILE;
1049 goto unlink_decrypted;
1050 }
1051
1052 fclose(decrypted_f);
1053
1054 /* prepare destination file for encryption */
1055
1056 encrypted_f = mailprivacy_get_tmp_file(privacy,
1057 encrypted_filename,
1058 sizeof(encrypted_filename));
1059 if (encrypted_f == NULL) {
1060 res = MAIL_ERROR_FILE;
1061 goto unlink_decrypted;
1062 }
1063 fclose(encrypted_f);
1064
1065 r = mail_quote_filename(quoted_decrypted_filename,
1066 sizeof(quoted_decrypted_filename), decrypted_filename);
1067 if (r < 0) {
1068 res = MAIL_ERROR_MEMORY;
1069 goto unlink_encrypted;
1070 }
1071
1072 r = mail_quote_filename(quoted_encrypted_filename,
1073 sizeof(quoted_encrypted_filename), encrypted_filename);
1074 if (r < 0) {
1075 res = MAIL_ERROR_MEMORY;
1076 goto unlink_encrypted;
1077 }
1078
1079 snprintf(command, sizeof(command),
1080 "openssl smime -encrypt -in %s -out %s %s 2>/dev/null",
1081 quoted_decrypted_filename, quoted_encrypted_filename, recipient);
1082
1083 r = system(command);
1084 if (WEXITSTATUS(r) != 0) {
1085 res = MAIL_ERROR_COMMAND;
1086 goto unlink_encrypted;
1087 }
1088
1089 /* encrypted part */
1090
1091 r = mailprivacy_get_part_from_file(privacy, 0,
1092 encrypted_filename, &encrypted_mime);
1093 if (r != MAIL_NO_ERROR) {
1094 res = r;
1095 goto unlink_encrypted;
1096 }
1097 strip_mime_headers(encrypted_mime);
1098
1099 unlink(encrypted_filename);
1100 unlink(decrypted_filename);
1101
1102 * result = encrypted_mime;
1103
1104 return MAIL_NO_ERROR;
1105
1106 unlink_encrypted:
1107 unlink(encrypted_filename);
1108 unlink_decrypted:
1109 unlink(decrypted_filename);
1110 err:
1111 return res;
1112}
1113
1114
1115static int smime_sign_encrypt(struct mailprivacy * privacy,
1116 struct mailmime * mime, struct mailmime ** result)
1117{
1118 char encrypted_filename[PATH_MAX];
1119 FILE * encrypted_f;
1120 int res;
1121 int r;
1122 int col;
1123 char signature_filename[PATH_MAX];
1124 FILE * signature_f;
1125 char decrypted_filename[PATH_MAX];
1126 FILE * decrypted_f;
1127 char command[PATH_MAX];
1128 char quoted_decrypted_filename[PATH_MAX];
1129 char quoted_encrypted_filename[PATH_MAX];
1130 char quoted_signature_filename[PATH_MAX];
1131 struct mailmime * encrypted_mime;
1132 struct mailmime * root;
1133 struct mailimf_fields * fields;
1134 char recipient[PATH_MAX];
1135 char * smime_cert;
1136 char * smime_key;
1137 char quoted_smime_cert[PATH_MAX];
1138 char quoted_smime_key[PATH_MAX];
1139 char * email;
1140
1141 root = mime;
1142 while (root->mm_parent != NULL)
1143 root = root->mm_parent;
1144
1145 fields = NULL;
1146 if (root->mm_type == MAILMIME_MESSAGE)
1147 fields = root->mm_data.mm_message.mm_fields;
1148
1149 /* recipient */
1150 r = collect_smime_cert(recipient, sizeof(recipient), fields);
1151 if (r != MAIL_NO_ERROR) {
1152 res = r;
1153 goto err;
1154 }
1155
1156 /* get signing key */
1157
1158 email = get_first_from_addr(mime);
1159 if (email == NULL) {
1160 res = MAIL_ERROR_INVAL;
1161 goto err;
1162 }
1163
1164 smime_key = get_private_key_file(email);
1165 smime_cert = get_cert_file(email);
1166 if ((smime_cert == NULL) || (smime_key == NULL)) {
1167 res = MAIL_ERROR_INVAL;
1168 goto err;
1169 }
1170
1171 /* part to encrypt */
1172
1173 /* encode quoted printable all text parts */
1174
1175 mailprivacy_prepare_mime(mime);
1176
1177 decrypted_f = mailprivacy_get_tmp_file(privacy,
1178 decrypted_filename, sizeof(decrypted_filename));
1179 if (decrypted_f == NULL) {
1180 res = MAIL_ERROR_FILE;
1181 goto err;
1182 }
1183
1184 col = 0;
1185 r = mailmime_write(decrypted_f, &col, mime);
1186 if (r != MAILIMF_NO_ERROR) {
1187 fclose(decrypted_f);
1188 res = MAIL_ERROR_FILE;
1189 goto unlink_decrypted;
1190 }
1191
1192 fclose(decrypted_f);
1193
1194 /* prepare destination file for signature */
1195
1196 signature_f = mailprivacy_get_tmp_file(privacy,
1197 signature_filename,
1198 sizeof(signature_filename));
1199 if (signature_f == NULL) {
1200 res = MAIL_ERROR_FILE;
1201 goto unlink_decrypted;
1202 }
1203 fclose(signature_f);
1204
1205 r = mail_quote_filename(quoted_decrypted_filename,
1206 sizeof(quoted_decrypted_filename), decrypted_filename);
1207 if (r < 0) {
1208 res = MAIL_ERROR_MEMORY;
1209 goto unlink_signature;
1210 }
1211
1212 r = mail_quote_filename(quoted_signature_filename,
1213 sizeof(quoted_signature_filename), signature_filename);
1214 if (r < 0) {
1215 res = MAIL_ERROR_MEMORY;
1216 goto unlink_signature;
1217 }
1218
1219 r = mail_quote_filename(quoted_smime_key,
1220 sizeof(quoted_smime_key), smime_key);
1221 if (r < 0) {
1222 res = MAIL_ERROR_MEMORY;
1223 goto unlink_signature;
1224 }
1225
1226 r = mail_quote_filename(quoted_smime_cert,
1227 sizeof(quoted_smime_cert), smime_cert);
1228 if (r < 0) {
1229 res = MAIL_ERROR_MEMORY;
1230 goto unlink_signature;
1231 }
1232
1233 snprintf(command, sizeof(command),
1234 "openssl smime -sign -in %s -out %s -signer %s -inkey %s 2>/dev/null",
1235 quoted_decrypted_filename, quoted_signature_filename,
1236 quoted_smime_cert, quoted_smime_key);
1237
1238 r = system(command);
1239 if (WEXITSTATUS(r) != 0) {
1240 res = MAIL_ERROR_COMMAND;
1241 goto unlink_signature;
1242 }
1243
1244
1245 /* prepare destination file for encryption */
1246
1247 encrypted_f = mailprivacy_get_tmp_file(privacy,
1248 encrypted_filename,
1249 sizeof(encrypted_filename));
1250 if (encrypted_f == NULL) {
1251 res = MAIL_ERROR_FILE;
1252 goto unlink_signature;
1253 }
1254 fclose(encrypted_f);
1255
1256 r = mail_quote_filename(quoted_encrypted_filename,
1257 sizeof(quoted_encrypted_filename), encrypted_filename);
1258 if (r < 0) {
1259 res = MAIL_ERROR_MEMORY;
1260 goto unlink_encrypted;
1261 }
1262
1263 snprintf(command, sizeof(command),
1264 "openssl smime -encrypt -in %s -out %s %s 2>/dev/null",
1265 quoted_signature_filename, quoted_encrypted_filename, recipient);
1266
1267 r = system(command);
1268 if (WEXITSTATUS(r) != 0) {
1269 res = MAIL_ERROR_COMMAND;
1270 goto unlink_encrypted;
1271 }
1272
1273 /* encrypted part */
1274
1275 r = mailprivacy_get_part_from_file(privacy, 0,
1276 encrypted_filename, &encrypted_mime);
1277 if (r != MAIL_NO_ERROR) {
1278 res = r;
1279 goto unlink_encrypted;
1280 }
1281 strip_mime_headers(encrypted_mime);
1282
1283 unlink(encrypted_filename);
1284 unlink(signature_filename);
1285 unlink(decrypted_filename);
1286
1287 * result = encrypted_mime;
1288
1289 return MAIL_NO_ERROR;
1290
1291 unlink_encrypted:
1292 unlink(encrypted_filename);
1293 unlink_signature:
1294 unlink(signature_filename);
1295 unlink_decrypted:
1296 unlink(decrypted_filename);
1297 err:
1298 return res;
1299}
1300
1301
1302
1303static struct mailprivacy_encryption smime_encryption_tab[] = {
1304 /* S/MIME signed part */
1305 {
1306 .name = "signed",
1307 .description = "S/MIME signed part",
1308 .encrypt = smime_sign,
1309 },
1310
1311 /* S/MIME encrypted part */
1312
1313 {
1314 .name = "encrypted",
1315 .description = "S/MIME encrypted part",
1316 .encrypt = smime_encrypt,
1317 },
1318
1319 /* S/MIME signed & encrypted part */
1320
1321 {
1322 .name = "signed-encrypted",
1323 .description = "S/MIME signed & encrypted part",
1324 .encrypt = smime_sign_encrypt,
1325 },
1326};
1327
1328static struct mailprivacy_protocol smime_protocol = {
1329 .name = "smime",
1330 .description = "S/MIME",
1331
1332 .is_encrypted = smime_test_encrypted,
1333 .decrypt = smime_handler,
1334
1335 .encryption_count =
1336 (sizeof(smime_encryption_tab) / sizeof(smime_encryption_tab[0])),
1337
1338 .encryption_tab = smime_encryption_tab,
1339};
1340
1341int mailprivacy_smime_init(struct mailprivacy * privacy)
1342{
1343 certificates = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
1344 if (certificates == NULL)
1345 goto err;
1346
1347 private_keys = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
1348 if (private_keys == NULL)
1349 goto free_cert;
1350
1351 CAcert_dir[0] = '\0';
1352
1353 return mailprivacy_register(privacy, &smime_protocol);
1354
1355 free_cert:
1356 chash_free(certificates);
1357 err:
1358 return MAIL_ERROR_MEMORY;
1359}
1360
1361void mailprivacy_smime_done(struct mailprivacy * privacy)
1362{
1363 mailprivacy_unregister(privacy, &smime_protocol);
1364 chash_free(private_keys);
1365 private_keys = NULL;
1366 chash_free(certificates);
1367 certificates = NULL;
1368 if (CAfile != NULL) {
1369 unlink(CAfile);
1370 free(CAfile);
1371 }
1372 CAfile = NULL;
1373 CAcert_dir[0] = '\0';
1374}
1375
1376
1377static void strip_string(char * str)
1378{
1379 char * p;
1380 size_t len;
1381
1382 p = strchr(str, '\r');
1383 if (p != NULL)
1384 * p = 0;
1385
1386 p = strchr(str, '\n');
1387 if (p != NULL)
1388 * p = 0;
1389
1390 p = str;
1391 while ((* p == ' ') || (* p == '\t')) {
1392 p ++;
1393 }
1394
1395 len = strlen(p);
1396 memmove(str, p, len);
1397 str[len] = 0;
1398
1399 if (len == 0)
1400 return;
1401
1402 p = str;
1403 len = len - 1;
1404 while ((p[len] == ' ') || (p[len] == '\t')) {
1405 p[len] = '\0';
1406
1407 if (len == 0)
1408 break;
1409
1410 len --;
1411 }
1412}
1413
1414
1415
1416#define MAX_EMAIL_SIZE 1024
1417
1418static void set_file(chash * hash, char * email, char * filename)
1419{
1420 char * n;
1421 char buf[MAX_EMAIL_SIZE];
1422 chashdatum key;
1423 chashdatum data;
1424
1425 strncpy(buf, email, sizeof(buf));
1426 buf[sizeof(buf) - 1] = '\0';
1427 for(n = buf ; * n != '\0' ; n ++)
1428 * n = toupper((unsigned char) * n);
1429 strip_string(buf);
1430
1431 key.data = buf;
1432 key.len = strlen(buf);
1433 data.data = filename;
1434 data.len = strlen(filename) + 1;
1435
1436 chash_set(hash, &key, &data, NULL);
1437}
1438
1439static char * get_file(chash * hash, char * email)
1440{
1441 chashdatum key;
1442 chashdatum data;
1443 char buf[MAX_EMAIL_SIZE];
1444 char * n;
1445 int r;
1446
1447 strncpy(buf, email, sizeof(buf));
1448 buf[sizeof(buf) - 1] = '\0';
1449 for(n = buf ; * n != '\0' ; n ++)
1450 * n = toupper((unsigned char) * n);
1451
1452 strip_string(buf);
1453 key.data = buf;
1454 key.len = strlen(buf);
1455 r = chash_get(hash, &key, &data);
1456 if (r < 0)
1457 return NULL;
1458
1459 return data.data;
1460}
1461
1462void mailprivacy_smime_set_cert_dir(struct mailprivacy * privacy,
1463 char * directory)
1464{
1465 DIR * dir;
1466 struct dirent * ent;
1467
1468 chash_clear(certificates);
1469
1470 if (directory == NULL)
1471 return;
1472
1473 if (* directory == '\0')
1474 return;
1475
1476 strncpy(cert_dir, directory, sizeof(cert_dir));
1477 cert_dir[sizeof(cert_dir) - 1] = '\0';
1478
1479 dir = opendir(directory);
1480 if (dir == NULL)
1481 return;
1482
1483 while ((ent = readdir(dir)) != NULL) {
1484 char filename[PATH_MAX];
1485 char command[PATH_MAX];
1486 char buf[MAX_EMAIL_SIZE];
1487 FILE * p;
1488
1489 snprintf(filename, sizeof(filename),
1490 "%s/%s", directory, ent->d_name);
1491
1492 snprintf(command, sizeof(command),
1493 "openssl x509 -email -noout -in %s 2>/dev/null", filename);
1494
1495 p = popen(command, "r");
1496 if (p == NULL)
1497 continue;
1498
1499 while (fgets(buf, sizeof(buf), p) != NULL)
1500 set_file(certificates, buf, filename);
1501
1502 pclose(p);
1503 }
1504 closedir(dir);
1505}
1506
1507static char * get_cert_file(char * email)
1508{
1509 return get_file(certificates, email);
1510}
1511
1512static char * get_private_key_file(char * email)
1513{
1514 return get_file(private_keys, email);
1515}
1516
1517void mail_private_smime_clear_private_keys(struct mailprivacy * privacy)
1518{
1519 chash_clear(private_keys);
1520}
1521
1522#define MAX_BUF 1024
1523
1524void mailprivacy_smime_set_CA_dir(struct mailprivacy * privacy,
1525 char * directory)
1526{
1527 DIR * dir;
1528 struct dirent * ent;
1529 FILE * f_CA;
1530 char CA_filename[PATH_MAX];
1531
1532 if (directory == NULL)
1533 return;
1534
1535 if (* directory == '\0')
1536 return;
1537
1538 /* make a temporary file that contains all the CAs */
1539
1540 if (CAfile != NULL) {
1541 unlink(CAfile);
1542 free(CAfile);
1543 CAfile = NULL;
1544 }
1545
1546 f_CA = mailprivacy_get_tmp_file(privacy, CA_filename, sizeof(CA_filename));
1547 if (f_CA == NULL)
1548 return;
1549
1550 strncpy(CAcert_dir, directory, sizeof(CAcert_dir));
1551 CAcert_dir[sizeof(CAcert_dir) - 1] = '\0';
1552
1553 dir = opendir(directory);
1554 if (dir == NULL) {
1555 fclose(f_CA);
1556 goto unlink_CA;
1557 }
1558
1559 while ((ent = readdir(dir)) != NULL) {
1560 char filename[PATH_MAX];
1561 char command[PATH_MAX];
1562 char buf[MAX_BUF];
1563 FILE * f;
1564
1565 snprintf(filename, sizeof(filename),
1566 "%s/%s", directory, ent->d_name);
1567
1568 f = fopen(filename, "r");
1569 if (f == NULL)
1570 continue;
1571
1572 while (fgets(buf, sizeof(buf), f) != NULL)
1573 fputs(buf, f_CA);
1574
1575 fclose(f);
1576 }
1577
1578 closedir(dir);
1579
1580 fclose(f_CA);
1581
1582 CAfile = strdup(CA_filename);
1583 if (CAfile == NULL)
1584 goto unlink_CA;
1585
1586 return;
1587
1588 unlink_CA:
1589 unlink(CA_filename);
1590}
1591
1592void mailprivacy_smime_set_CA_check(struct mailprivacy * privacy,
1593 int enabled)
1594{
1595 CA_check = enabled;
1596}
1597
1598void mailprivacy_smime_set_store_cert(struct mailprivacy * privacy,
1599 int enabled)
1600{
1601 store_cert = enabled;
1602}
1603
1604static int get_cert_from_sig(struct mailprivacy * privacy,
1605 mailmessage * msg,
1606 struct mailmime * mime)
1607{
1608 clistiter * cur;
1609 struct mailmime * signed_mime;
1610 struct mailmime * signature_mime;
1611 int res;
1612 char signature_filename[PATH_MAX];
1613 char quoted_signature_filename[PATH_MAX];
1614 char * email;
1615 char * cert_file;
1616 char store_cert_filename[PATH_MAX];
1617 char quoted_store_cert_filename[PATH_MAX];
1618 int r;
1619 char command[PATH_MAX];
1620
1621 if (* cert_dir == '\0')
1622 return MAIL_ERROR_INVAL;
1623
1624 if (mime->mm_type != MAILMIME_MULTIPLE)
1625 return MAIL_ERROR_INVAL;
1626
1627 email = get_first_from_addr(mime);
1628 if (email == NULL)
1629 return MAIL_ERROR_INVAL;
1630
1631 cert_file = get_cert_file(email);
1632 if (cert_file != NULL)
1633 return MAIL_NO_ERROR;
1634
1635 /* get the two parts of the S/MIME message */
1636
1637 cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list);
1638 if (cur == NULL) {
1639 res = MAIL_ERROR_INVAL;
1640 goto err;
1641 }
1642
1643 signed_mime = cur->data;
1644 cur = clist_next(cur);
1645 if (cur == NULL) {
1646 res = MAIL_ERROR_INVAL;
1647 goto err;
1648 }
1649
1650 signature_mime = cur->data;
1651
1652 r = mailprivacy_fetch_decoded_to_file(privacy,
1653 signature_filename, sizeof(signature_filename),
1654 msg, signature_mime);
1655 if (r != MAILIMF_NO_ERROR) {
1656 res = r;
1657 goto err;
1658 }
1659
1660 r = mail_quote_filename(quoted_signature_filename,
1661 sizeof(quoted_signature_filename), signature_filename);
1662 if (r < 0) {
1663 res = MAIL_ERROR_MEMORY;
1664 goto unlink_signature;
1665 }
1666
1667 snprintf(store_cert_filename, sizeof(store_cert_filename),
1668 "%s/%s-cert.pem", cert_dir, email);
1669
1670 r = mail_quote_filename(quoted_store_cert_filename,
1671 sizeof(quoted_store_cert_filename), store_cert_filename);
1672 if (r < 0) {
1673 res = MAIL_ERROR_MEMORY;
1674 goto unlink_signature;
1675 }
1676
1677 snprintf(command, sizeof(command),
1678 "openssl pkcs7 -inform DER -in %s -out %s -print_certs 2>/dev/null",
1679 quoted_signature_filename, quoted_store_cert_filename);
1680
1681 r = system(command);
1682 if (WEXITSTATUS(r) != 0) {
1683 res = MAIL_ERROR_COMMAND;
1684 goto unlink_signature;
1685 }
1686
1687 unlink(signature_filename);
1688
1689 set_file(certificates, email, store_cert_filename);
1690
1691 return MAIL_NO_ERROR;
1692
1693 unlink_signature:
1694 unlink(signature_filename);
1695 err:
1696 return res;
1697}
1698
1699
1700static void set_private_key(struct mailprivacy * privacy,
1701 char * email, char * file)
1702{
1703 set_file(private_keys, email, file);
1704}
1705
1706#define PRIVATE_KEY_SUFFIX "-private-key.pem"
1707
1708void mailprivacy_smime_set_private_keys_dir(struct mailprivacy * privacy,
1709 char * directory)
1710{
1711 DIR * dir;
1712 struct dirent * ent;
1713
1714 chash_clear(private_keys);
1715
1716 if (directory == NULL)
1717 return;
1718
1719 if (* directory == '\0')
1720 return;
1721
1722 strncpy(private_keys_dir, directory, sizeof(private_keys_dir));
1723 private_keys_dir[sizeof(private_keys_dir) - 1] = '\0';
1724
1725 dir = opendir(directory);
1726 if (dir == NULL)
1727 return;
1728
1729 while ((ent = readdir(dir)) != NULL) {
1730 char filename[PATH_MAX];
1731 char email[PATH_MAX];
1732 char * p;
1733
1734 snprintf(filename, sizeof(filename),
1735 "%s/%s", directory, ent->d_name);
1736
1737 strncpy(email, ent->d_name, sizeof(email));
1738 email[sizeof(email) - 1] = '\0';
1739
1740 p = strstr(email, PRIVATE_KEY_SUFFIX);
1741 if (p == NULL)
1742 continue;
1743
1744 if (strlen(p) != sizeof(PRIVATE_KEY_SUFFIX) - 1)
1745 continue;
1746
1747 * p = 0;
1748
1749 if (* email == '\0')
1750 continue;
1751
1752 set_private_key(privacy, email, filename);
1753 }
1754 closedir(dir);
1755}
diff --git a/libetpan/src/engine/mailprivacy_smime.h b/libetpan/src/engine/mailprivacy_smime.h
new file mode 100644
index 0000000..85d9e40
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_smime.h
@@ -0,0 +1,84 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#ifndef MAILPRIVACY_SMIME_H
37
38#define MAILPRIVACY_SMIME_H
39
40#include <libetpan/mailprivacy_types.h>
41
42int mailprivacy_smime_init(struct mailprivacy * privacy);
43
44void mailprivacy_smime_done(struct mailprivacy * privacy);
45
46void mailprivacy_smime_set_cert_dir(struct mailprivacy * privacy,
47 char * directory);
48
49
50/*
51 set directory where certificates of authority certifications are
52 stored.
53*/
54
55void mailprivacy_smime_set_CA_dir(struct mailprivacy * privacy,
56 char * directory);
57
58
59/*
60 to disable the verification of signers certificates of a
61 signed message.
62*/
63
64void mailprivacy_smime_set_CA_check(struct mailprivacy * privacy,
65 int enabled);
66
67
68/*
69 to store certificates of signed messages
70*/
71
72void mailprivacy_smime_set_store_cert(struct mailprivacy * privacy,
73 int enabled);
74
75/*
76 set directory where private keys are stored.
77 name of the files in that directory must be in form :
78 [email-address]-private-key.pem
79*/
80
81void mailprivacy_smime_set_private_keys_dir(struct mailprivacy * privacy,
82 char * directory);
83
84#endif
diff --git a/libetpan/src/engine/mailprivacy_tools.c b/libetpan/src/engine/mailprivacy_tools.c
new file mode 100644
index 0000000..cae2ef8
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_tools.c
@@ -0,0 +1,1283 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailprivacy_tools.h"
37
38#include <stdlib.h>
39#include <string.h>
40#include <libgen.h>
41#include <unistd.h>
42#include <sys/mman.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <fcntl.h>
46#include <libetpan/mailmessage.h>
47#include <ctype.h>
48#include "mailprivacy.h"
49#include <libetpan/libetpan-config.h>
50#include <libetpan/data_message_driver.h>
51
52void mailprivacy_mime_clear(struct mailmime * mime)
53{
54 struct mailmime_data * data;
55 clistiter * cur;
56
57 switch (mime->mm_type) {
58 case MAILMIME_SINGLE:
59 data = mime->mm_data.mm_single;
60 if (data != NULL) {
61 if (data->dt_type == MAILMIME_DATA_FILE)
62 unlink(data->dt_data.dt_filename);
63 }
64 break;
65
66 case MAILMIME_MULTIPLE:
67 data = mime->mm_data.mm_multipart.mm_preamble;
68 if (data != NULL) {
69 if (data->dt_type == MAILMIME_DATA_FILE)
70 unlink(data->dt_data.dt_filename);
71 }
72 data = mime->mm_data.mm_multipart.mm_epilogue;
73 if (data != NULL) {
74 if (data->dt_type == MAILMIME_DATA_FILE)
75 unlink(data->dt_data.dt_filename);
76 }
77
78 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
79 cur != NULL ; cur = clist_next(cur)) {
80 struct mailmime * submime;
81
82 submime = clist_content(cur);
83
84 mailprivacy_mime_clear(submime);
85 }
86 break;
87
88 case MAILMIME_MESSAGE:
89 if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
90 mailprivacy_mime_clear(mime->mm_data.mm_message.mm_msg_mime);
91 }
92 break;
93 }
94}
95
96
97static FILE * get_tmp_file(char * filename)
98{
99 int fd;
100 mode_t old_mask;
101 FILE * f;
102
103 old_mask = umask(0077);
104 fd = mkstemp(filename);
105 umask(old_mask);
106 if (fd == -1)
107 return NULL;
108
109 f = fdopen(fd, "r+");
110 if (f == NULL) {
111 close(fd);
112 unlink(filename);
113 }
114
115 return f;
116}
117
118FILE * mailprivacy_get_tmp_file(struct mailprivacy * privacy,
119 char * filename, size_t size)
120{
121 snprintf(filename, size, "%s/libetpan-privacy-XXXXXX", privacy->tmp_dir);
122 return get_tmp_file(filename);
123}
124
125
126static char * dup_file(struct mailprivacy * privacy,
127 char * source_filename)
128{
129 char filename[PATH_MAX];
130 FILE * dest_f;
131 int r;
132 struct stat stat_info;
133 char * dest_filename;
134 char * mapping;
135 size_t written;
136 int fd;
137
138 dest_f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename));
139 if (dest_f == NULL)
140 goto err;
141
142 dest_filename = strdup(filename);
143 if (dest_filename == NULL)
144 goto close_dest;
145
146 fd = open(source_filename, O_RDONLY);
147 if (fd < 0)
148 goto free_dest;
149
150 r = fstat(fd, &stat_info);
151 if (r < 0)
152 goto close_src;
153
154 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
155 if (mapping == MAP_FAILED)
156 goto close_src;
157
158 written = fwrite(mapping, 1, stat_info.st_size, dest_f);
159 if (written != (size_t) stat_info.st_size)
160 goto unmap;
161
162 munmap(mapping, stat_info.st_size);
163 close(fd);
164 fclose(dest_f);
165
166 return dest_filename;
167
168 unmap:
169 munmap(mapping, stat_info.st_size);
170 close_src:
171 close(fd);
172 free_dest:
173 free(dest_filename);
174 close_dest:
175 fclose(dest_f);
176 err:
177 return NULL;
178}
179
180
181/*
182 mime_data_replace()
183
184 write a mime part to a file and change the reference of mailmime_data
185 to the file.
186*/
187
188static int mime_data_replace(struct mailprivacy * privacy,
189 int encoding_type,
190 struct mailmime_data * data)
191{
192 char filename[PATH_MAX];
193 FILE * f;
194 size_t written;
195 char * dup_filename;
196 int res;
197 int r;
198 int decoded;
199
200 if (data->dt_type != MAILMIME_DATA_TEXT) {
201 res = MAIL_NO_ERROR;
202 goto err;
203 }
204
205 f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename));
206 if (f == NULL) {
207 res = MAIL_ERROR_FILE;
208 goto err;
209 }
210
211 decoded = 0;
212 if (encoding_type != -1) {
213 char * content;
214 size_t content_len;
215 size_t cur_token;
216
217 cur_token = 0;
218 r = mailmime_part_parse(data->dt_data.dt_text.dt_data,
219 data->dt_data.dt_text.dt_length,
220 &cur_token, encoding_type, &content, &content_len);
221
222 if (r == MAILIMF_NO_ERROR) {
223 /* write decoded */
224 written = fwrite(content, 1, content_len, f);
225 if (written != content_len) {
226 fclose(f);
227 unlink(filename);
228 res = MAIL_ERROR_FILE;
229 goto err;
230 }
231 mmap_string_unref(content);
232
233 decoded = 1;
234 data->dt_encoded = 0;
235 }
236 }
237
238 if (!decoded) {
239 written = fwrite(data->dt_data.dt_text.dt_data, 1,
240 data->dt_data.dt_text.dt_length, f);
241 if (written != data->dt_data.dt_text.dt_length) {
242 fclose(f);
243 unlink(filename);
244 res = MAIL_ERROR_FILE;
245 goto err;
246 }
247 }
248
249 fclose(f);
250
251 dup_filename = strdup(filename);
252 if (dup_filename == NULL) {
253 unlink(filename);
254 res = MAIL_ERROR_MEMORY;
255 goto err;
256 }
257
258 data->dt_type = MAILMIME_DATA_FILE;
259 data->dt_data.dt_filename = dup_filename;
260
261 return MAIL_NO_ERROR;
262
263 err:
264 return res;
265}
266
267
268/*
269 recursive_replace_single_parts()
270
271 write all parts of the given mime part to file.
272*/
273
274static int recursive_replace_single_parts(struct mailprivacy * privacy,
275 struct mailmime * mime)
276{
277 int r;
278 int res;
279 clistiter * cur;
280
281 mime->mm_mime_start = NULL;
282
283 switch(mime->mm_type) {
284 case MAILMIME_SINGLE:
285 if (mime->mm_data.mm_single != NULL) {
286 int encoding_type;
287 struct mailmime_single_fields single_fields;
288
289 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
290 mime->mm_content_type);
291
292 if (single_fields.fld_encoding != NULL)
293 encoding_type = single_fields.fld_encoding->enc_type;
294 else
295 encoding_type = -1;
296
297 r = mime_data_replace(privacy, encoding_type, mime->mm_data.mm_single);
298 if (r != MAIL_NO_ERROR) {
299 res = r;
300 goto err;
301 }
302 }
303 break;
304
305 case MAILMIME_MULTIPLE:
306 if (mime->mm_data.mm_multipart.mm_preamble != NULL) {
307 r = mime_data_replace(privacy, -1,
308 mime->mm_data.mm_multipart.mm_preamble);
309 if (r != MAIL_NO_ERROR) {
310 res = r;
311 goto err;
312 }
313 }
314
315 if (mime->mm_data.mm_multipart.mm_epilogue != NULL) {
316 r = mime_data_replace(privacy, -1,
317 mime->mm_data.mm_multipart.mm_epilogue);
318 if (r != MAIL_NO_ERROR) {
319 res = r;
320 goto err;
321 }
322 }
323
324 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
325 cur != NULL ; cur = clist_next(cur)) {
326 struct mailmime * child;
327
328 child = clist_content(cur);
329
330 r = recursive_replace_single_parts(privacy, child);
331 if (r != MAIL_NO_ERROR) {
332 res = r;
333 goto err;
334 }
335 }
336
337 break;
338
339 case MAILMIME_MESSAGE:
340 if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
341 r = recursive_replace_single_parts(privacy,
342 mime->mm_data.mm_message.mm_msg_mime);
343 if (r != MAIL_NO_ERROR) {
344 res = r;
345 goto err;
346 }
347 }
348 break;
349 }
350
351 return MAIL_NO_ERROR;
352
353 err:
354 return res;
355}
356
357/*
358 mailprivacy_get_mime()
359
360 parse the message in MIME structure,
361 all single MIME parts are stored in files.
362
363 privacy can be set to NULL to disable privacy check.
364*/
365
366int mailprivacy_get_mime(struct mailprivacy * privacy,
367 int check_privacy,
368 char * content, size_t content_len,
369 struct mailmime ** result_mime)
370{
371 struct mailmime * mime;
372 mailmessage * msg;
373 int r;
374 int res;
375
376#if 0
377 int check_privacy;
378
379 check_privacy = (privacy != NULL);
380#endif
381
382 /*
383 use message data driver, get bodystructure and
384 convert all the data part in MAILMIME_SINGLE to files.
385 */
386
387 msg = data_message_init(content, content_len);
388 if (msg == NULL) {
389 res = MAIL_ERROR_MEMORY;
390 goto err;
391 }
392
393#if 0
394 if (msg->mime == NULL) {
395 if (check_privacy) {
396 r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime);
397 }
398 else {
399 /*
400 don't use etpan_msg_get_bodystructure because it is not useful
401 and to avoid loops due to security part
402 */
403 r = mailmessage_get_bodystructure(msg, &mime);
404 }
405 }
406 else {
407 mime = msg->mime;
408 }
409#endif
410
411 if (check_privacy)
412 r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime);
413 else
414 r = mailmessage_get_bodystructure(msg, &mime);
415 if (r != MAIL_NO_ERROR) {
416 res = r;
417 goto free_msg;
418 }
419
420 /*
421 should be done so that the MIME structure need not to be unregistered.
422 */
423 mailprivacy_recursive_unregister_mime(privacy, mime);
424
425 r = recursive_replace_single_parts(privacy, mime);
426 if (r != MAIL_NO_ERROR) {
427 res = r;
428 goto clear_mime;
429 }
430
431 data_message_detach_mime(msg);
432#if 0
433 if (check_privacy)
434 mailprivacy_msg_flush(privacy, msg);
435 else
436 mailmessage_flush(msg);
437#endif
438 mailprivacy_msg_flush(privacy, msg);
439 mailmessage_free(msg);
440
441 * result_mime = mime;
442
443 return MAIL_NO_ERROR;
444
445 clear_mime:
446 mailprivacy_mime_clear(mime);
447 mailprivacy_msg_flush(privacy, msg);
448 free_msg:
449 mailmessage_free(msg);
450 err:
451 return res;
452}
453
454#ifndef LIBETPAN_SYSTEM_BASENAME
455static char * libetpan_basename(char * filename)
456{
457 char * next;
458 char * p;
459
460 p = filename;
461 next = strchr(p, '/');
462
463 while (next != NULL) {
464 p = next;
465 next = strchr(p + 1, '/');
466 }
467
468 if (p == filename)
469 return filename;
470 else
471 return p + 1;
472}
473#else
474#define libetpan_basename(a) basename(a)
475#endif
476
477struct mailmime *
478mailprivacy_new_file_part(struct mailprivacy * privacy,
479 char * filename,
480 char * default_content_type, int default_encoding)
481{
482 char basename_buf[PATH_MAX];
483 char * name;
484 struct mailmime_mechanism * encoding;
485 struct mailmime_content * content;
486 struct mailmime * mime;
487 int r;
488 char * dup_filename;
489 struct mailmime_fields * mime_fields;
490 int encoding_type;
491 char * content_type_str;
492 int do_encoding;
493
494 if (filename != NULL) {
495 strncpy(basename_buf, filename, PATH_MAX);
496 name = libetpan_basename(basename_buf);
497 }
498 else {
499 name = NULL;
500 }
501
502 encoding = NULL;
503
504 /* default content-type */
505 if (default_content_type == NULL)
506 content_type_str = "application/octet-stream";
507 else
508 content_type_str = default_content_type;
509
510 content = mailmime_content_new_with_str(content_type_str);
511 if (content == NULL) {
512 goto free_content;
513 }
514
515 do_encoding = 1;
516 if (content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE) {
517 struct mailmime_composite_type * composite;
518
519 composite = content->ct_type->tp_data.tp_composite_type;
520
521 switch (composite->ct_type) {
522 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
523 if (strcasecmp(content->ct_subtype, "rfc822") == 0)
524 do_encoding = 0;
525 break;
526
527 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
528 do_encoding = 0;
529 break;
530 }
531 }
532
533 if (do_encoding) {
534 if (default_encoding == -1)
535 encoding_type = MAILMIME_MECHANISM_BASE64;
536 else
537 encoding_type = default_encoding;
538
539 /* default Content-Transfer-Encoding */
540 encoding = mailmime_mechanism_new(encoding_type, NULL);
541 if (encoding == NULL) {
542 goto free_content;
543 }
544 }
545
546 mime_fields = mailmime_fields_new_with_data(encoding,
547 NULL, NULL, NULL, NULL);
548 if (mime_fields == NULL) {
549 goto free_content;
550 }
551
552 mime = mailmime_new_empty(content, mime_fields);
553 if (mime == NULL) {
554 goto free_mime_fields;
555 }
556
557 if ((filename != NULL) && (mime->mm_type == MAILMIME_SINGLE)) {
558 /*
559 duplicates the file so that the file can be deleted when
560 the MIME part is done
561 */
562 dup_filename = dup_file(privacy, filename);
563 if (dup_filename == NULL) {
564 goto free_mime;
565 }
566
567 r = mailmime_set_body_file(mime, dup_filename);
568 if (r != MAILIMF_NO_ERROR) {
569 free(dup_filename);
570 goto free_mime;
571 }
572 }
573
574 return mime;
575
576 free_mime:
577 mailmime_free(mime);
578 goto err;
579 free_mime_fields:
580 mailmime_fields_free(mime_fields);
581 mailmime_content_free(content);
582 goto err;
583 free_content:
584 if (encoding != NULL)
585 mailmime_mechanism_free(encoding);
586 if (content != NULL)
587 mailmime_content_free(content);
588 err:
589 return NULL;
590}
591
592
593int mailmime_substitute(struct mailmime * old_mime,
594 struct mailmime * new_mime)
595{
596 struct mailmime * parent;
597
598 parent = old_mime->mm_parent;
599 if (parent == NULL)
600 return MAIL_ERROR_INVAL;
601
602 if (old_mime->mm_parent_type == MAILMIME_MESSAGE)
603 parent->mm_data.mm_message.mm_msg_mime = new_mime;
604 else /* MAILMIME_MULTIPLE */
605 old_mime->mm_multipart_pos->data = new_mime;
606 new_mime->mm_parent = parent;
607 new_mime->mm_parent_type = old_mime->mm_parent_type;
608
609 /* detach old_mime */
610 old_mime->mm_parent = NULL;
611 old_mime->mm_parent_type = MAILMIME_NONE;
612
613 return MAIL_NO_ERROR;
614}
615
616
617
618/* write mime headers and body to a file, CR LF fixed */
619
620int mailprivacy_fetch_mime_body_to_file(struct mailprivacy * privacy,
621 char * filename, size_t size,
622 mailmessage * msg, struct mailmime * mime)
623{
624 int r;
625 int res;
626 FILE * f;
627 char * content;
628 size_t content_len;
629 int col;
630
631 if (mime->mm_parent_type == MAILMIME_NONE) {
632 res = MAIL_ERROR_INVAL;
633 goto err;
634 }
635
636 f = mailprivacy_get_tmp_file(privacy, filename, size);
637 if (f == NULL) {
638 res = MAIL_ERROR_FETCH;
639 goto err;
640 }
641
642 r = mailprivacy_msg_fetch_section_mime(privacy, msg, mime,
643 &content, &content_len);
644 if (r != MAIL_NO_ERROR) {
645 res = MAIL_ERROR_FETCH;
646 goto close;
647 }
648
649 col = 0;
650 r = mailimf_string_write(f, &col, content, content_len);
651 mailprivacy_msg_fetch_result_free(privacy, msg, content);
652 if (r != MAILIMF_NO_ERROR) {
653 res = r;
654 goto close;
655 }
656
657 r = mailprivacy_msg_fetch_section(privacy, msg, mime,
658 &content, &content_len);
659 if (r != MAIL_NO_ERROR) {
660 res = MAIL_ERROR_FETCH;
661 goto close;
662 }
663
664 r = mailimf_string_write(f, &col, content, content_len);
665 mailprivacy_msg_fetch_result_free(privacy, msg, content);
666 if (r != MAILIMF_NO_ERROR) {
667 res = r;
668 goto close;
669 }
670
671 fclose(f);
672
673 return MAIL_NO_ERROR;
674
675 close:
676 fclose(f);
677 unlink(filename);
678 err:
679 return res;
680}
681
682
683int mailprivacy_get_part_from_file(struct mailprivacy * privacy,
684 int check_security, char * filename,
685 struct mailmime ** result_mime)
686{
687 int fd;
688 struct mailmime * mime;
689 int r;
690 struct stat stat_info;
691 int res;
692 char * mapping;
693
694 fd = open(filename, O_RDONLY);
695 if (fd < 0) {
696 res = MAIL_ERROR_FILE;
697 goto err;
698 }
699
700 r = fstat(fd, &stat_info);
701 if (r < 0) {
702 res = MAIL_ERROR_FILE;
703 goto close;
704 }
705
706 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
707 if (mapping == MAP_FAILED) {
708 res = MAIL_ERROR_FILE;
709 goto close;
710 }
711
712 /* check recursive parts if privacy is set */
713 r = mailprivacy_get_mime(privacy, check_security,
714 mapping, stat_info.st_size, &mime);
715 if (r != MAIL_NO_ERROR) {
716 res = r;
717 goto unmap;
718 }
719
720 if (mime->mm_type == MAILMIME_MESSAGE) {
721 struct mailmime * submime;
722
723 submime = mime->mm_data.mm_message.mm_msg_mime;
724 if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
725 mailmime_remove_part(submime);
726 mailmime_free(mime);
727
728 mime = submime;
729 }
730 }
731
732 munmap(mapping, stat_info.st_size);
733
734 close(fd);
735
736 * result_mime = mime;
737
738 return MAIL_NO_ERROR;
739
740 unmap:
741 munmap(mapping, stat_info.st_size);
742 close:
743 close(fd);
744 err:
745 return res;
746}
747
748int mail_quote_filename(char * result, size_t size, char * path)
749{
750 char * p;
751 char * result_p;
752 size_t remaining;
753
754 result_p = result;
755 remaining = size;
756
757 for(p = path ; * p != '\0' ; p ++) {
758
759 if (isalpha(* p) || isdigit(* p) || (* p == '/')) {
760 if (remaining > 0) {
761 * result_p = * p;
762 result_p ++;
763 remaining --;
764 }
765 else {
766 result[size - 1] = '\0';
767 return -1;
768 }
769 }
770 else {
771 if (remaining >= 2) {
772 * result_p = '\\';
773 result_p ++;
774 * result_p = * p;
775 result_p ++;
776 remaining -= 2;
777 }
778 else {
779 result[size - 1] = '\0';
780 return -1;
781 }
782 }
783 }
784 if (remaining > 0) {
785 * result_p = '\0';
786 }
787 else {
788 result[size - 1] = '\0';
789 return -1;
790 }
791
792 return 0;
793}
794
795
796static void prepare_mime_single(struct mailmime * mime)
797{
798 struct mailmime_single_fields single_fields;
799 int encoding;
800 int r;
801
802 if (mime->mm_mime_fields != NULL) {
803 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
804 mime->mm_content_type);
805 if (single_fields.fld_encoding != NULL) {
806 encoding = single_fields.fld_encoding->enc_type;
807 switch (encoding) {
808 case MAILMIME_MECHANISM_8BIT:
809 case MAILMIME_MECHANISM_7BIT:
810 case MAILMIME_MECHANISM_BINARY:
811 single_fields.fld_encoding->enc_type =
812 MAILMIME_MECHANISM_QUOTED_PRINTABLE;
813 break;
814 }
815 }
816 else {
817 struct mailmime_mechanism * mechanism;
818 struct mailmime_field * field;
819
820 mechanism =
821 mailmime_mechanism_new(MAILMIME_MECHANISM_QUOTED_PRINTABLE, NULL);
822 if (mechanism == NULL)
823 return;
824
825 field = mailmime_field_new(MAILMIME_FIELD_TRANSFER_ENCODING,
826 NULL, mechanism, NULL, NULL, 0, NULL, NULL);
827 if (field == NULL) {
828 mailmime_mechanism_free(mechanism);
829 return;
830 }
831
832 r = clist_append(mime->mm_mime_fields->fld_list, field);
833 if (r < 0) {
834 mailmime_field_free(field);
835 return;
836 }
837 }
838 }
839
840 if (mime->mm_type == MAILMIME_SINGLE) {
841 switch (mime->mm_data.mm_single->dt_encoding) {
842 case MAILMIME_MECHANISM_8BIT:
843 case MAILMIME_MECHANISM_7BIT:
844 case MAILMIME_MECHANISM_BINARY:
845 mime->mm_data.mm_single->dt_encoding =
846 MAILMIME_MECHANISM_QUOTED_PRINTABLE;
847 mime->mm_data.mm_single->dt_encoded = 0;
848 break;
849 }
850 }
851}
852
853/*
854 mailprivacy_prepare_mime()
855
856 we assume we built ourself the message.
857*/
858
859void mailprivacy_prepare_mime(struct mailmime * mime)
860{
861 clistiter * cur;
862
863 switch (mime->mm_type) {
864 case MAILMIME_SINGLE:
865 if (mime->mm_data.mm_single != NULL) {
866 prepare_mime_single(mime);
867 }
868 break;
869
870 case MAILMIME_MULTIPLE:
871 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
872 cur != NULL ; cur = clist_next(cur)) {
873 struct mailmime * child;
874
875 child = clist_content(cur);
876
877 mailprivacy_prepare_mime(child);
878 }
879 break;
880
881 case MAILMIME_MESSAGE:
882 if (mime->mm_data.mm_message.mm_msg_mime) {
883 mailprivacy_prepare_mime(mime->mm_data.mm_message.mm_msg_mime);
884 }
885 break;
886 }
887}
888
889
890char * mailprivacy_dup_imf_file(struct mailprivacy * privacy,
891 char * source_filename)
892{
893 char filename[PATH_MAX];
894 FILE * dest_f;
895 int r;
896 struct stat stat_info;
897 char * dest_filename;
898 char * mapping;
899 int fd;
900 int col;
901
902 dest_f = mailprivacy_get_tmp_file(privacy,
903 filename, sizeof(filename));
904 if (dest_f == NULL)
905 goto err;
906
907 dest_filename = strdup(filename);
908 if (dest_filename == NULL)
909 goto close_dest;
910
911 fd = open(source_filename, O_RDONLY);
912 if (fd < 0)
913 goto free_dest;
914
915 r = fstat(fd, &stat_info);
916 if (r < 0)
917 goto close_src;
918
919 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
920 if (mapping == MAP_FAILED)
921 goto close_src;
922
923 col = 0;
924 r = mailimf_string_write(dest_f, &col, mapping, stat_info.st_size);
925 if (r != MAILIMF_NO_ERROR)
926 goto unmap;
927
928 munmap(mapping, stat_info.st_size);
929 close(fd);
930 fclose(dest_f);
931
932 return dest_filename;
933
934 unmap:
935 munmap(mapping, stat_info.st_size);
936 close_src:
937 close(fd);
938 free_dest:
939 free(dest_filename);
940 close_dest:
941 fclose(dest_f);
942 err:
943 return NULL;
944}
945
946/* TODO : better function to duplicate mime fields, currenly such inelegant */
947
948struct mailmime_fields *
949mailprivacy_mime_fields_dup(struct mailprivacy * privacy,
950 struct mailmime_fields * mime_fields)
951{
952 FILE * f;
953 char tmp_file[PATH_MAX];
954 int col;
955 int r;
956 struct mailmime_fields * dup_mime_fields;
957 int fd;
958 char * mapping;
959 struct stat stat_info;
960 struct mailimf_fields * fields;
961 size_t cur_token;
962
963 f = mailprivacy_get_tmp_file(privacy, tmp_file, sizeof(tmp_file));
964 if (f == NULL)
965 goto err;
966
967 col = 0;
968 r = mailmime_fields_write(f, &col, mime_fields);
969 if (r != MAILIMF_NO_ERROR)
970 goto unlink;
971
972 fflush(f);
973
974 fd = fileno(f);
975 if (fd == -1)
976 goto unlink;
977
978 r = fstat(fd, &stat_info);
979 if (r < 0)
980 goto unlink;
981
982 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
983 if (mapping == MAP_FAILED)
984 goto unlink;
985
986 cur_token = 0;
987 r = mailimf_optional_fields_parse(mapping, stat_info.st_size,
988 &cur_token, &fields);
989 if (r != MAILIMF_NO_ERROR)
990 goto unmap;
991
992 r = mailmime_fields_parse(fields, &dup_mime_fields);
993 mailimf_fields_free(fields);
994 if (r != MAILIMF_NO_ERROR)
995 goto unmap;
996
997 munmap(mapping, stat_info.st_size);
998 fclose(f);
999 unlink(tmp_file);
1000
1001 return dup_mime_fields;
1002
1003 unmap:
1004 munmap(mapping, stat_info.st_size);
1005 unlink:
1006 fclose(f);
1007 unlink(tmp_file);
1008 err:
1009 return NULL;
1010}
1011
1012
1013
1014struct mailmime_parameter *
1015mailmime_parameter_dup(struct mailmime_parameter * param)
1016{
1017 char * name;
1018 char * value;
1019 struct mailmime_parameter * dup_param;
1020
1021 name = strdup(param->pa_name);
1022 if (name == NULL)
1023 goto err;
1024
1025 value = strdup(param->pa_value);
1026 if (value == NULL)
1027 goto free_name;
1028
1029 dup_param = mailmime_parameter_new(name, value);
1030 if (dup_param == NULL)
1031 goto free_value;
1032
1033 return dup_param;
1034
1035 free_value:
1036 free(value);
1037 free_name:
1038 free(name);
1039 err:
1040 return NULL;
1041}
1042
1043struct mailmime_composite_type *
1044mailmime_composite_type_dup(struct mailmime_composite_type * composite_type)
1045{
1046 struct mailmime_composite_type * dup_composite;
1047 char * token;
1048
1049 token = NULL;
1050 if (composite_type->ct_token != NULL) {
1051 token = strdup(composite_type->ct_token);
1052 if (token == NULL)
1053 goto err;
1054 }
1055
1056 dup_composite = mailmime_composite_type_new(composite_type->ct_type, token);
1057 if (dup_composite == NULL)
1058 goto free_token;
1059
1060 return dup_composite;
1061
1062 free_token:
1063 if (token != NULL)
1064 free(token);
1065 err:
1066 return NULL;
1067}
1068
1069struct mailmime_discrete_type *
1070mailmime_discrete_type_dup(struct mailmime_discrete_type * discrete_type)
1071{
1072 struct mailmime_discrete_type * dup_discrete;
1073 char * extension;
1074
1075 extension = NULL;
1076 if (discrete_type->dt_extension != NULL) {
1077 extension = strdup(discrete_type->dt_extension);
1078 if (extension == NULL)
1079 goto err;
1080 }
1081
1082 dup_discrete = mailmime_discrete_type_new(discrete_type->dt_type, extension);
1083 if (dup_discrete == NULL)
1084 goto free_extension;
1085
1086 return dup_discrete;
1087
1088 free_extension:
1089 if (extension != NULL)
1090 free(extension);
1091 err:
1092 return NULL;
1093}
1094
1095struct mailmime_type * mailmime_type_dup(struct mailmime_type * type)
1096{
1097 struct mailmime_type * dup_type;
1098 struct mailmime_discrete_type * discrete_type;
1099 struct mailmime_composite_type * composite_type;
1100
1101 discrete_type = NULL;
1102 composite_type = NULL;
1103 switch (type->tp_type) {
1104 case MAILMIME_TYPE_DISCRETE_TYPE:
1105 discrete_type =
1106 mailmime_discrete_type_dup(type->tp_data.tp_discrete_type);
1107 if (discrete_type == NULL)
1108 goto err;
1109 break;
1110
1111 composite_type =
1112 mailmime_composite_type_dup(type->tp_data.tp_composite_type);
1113 if (composite_type == NULL)
1114 goto free_discrete;
1115 }
1116
1117 dup_type = mailmime_type_new(type->tp_type, discrete_type, composite_type);
1118 if (dup_type == NULL)
1119 goto free_composite;
1120
1121 return dup_type;
1122
1123 free_composite:
1124 if (composite_type != NULL)
1125 mailmime_composite_type_free(composite_type);
1126 free_discrete:
1127 if (discrete_type != NULL)
1128 mailmime_discrete_type_free(discrete_type);
1129 err:
1130 return NULL;
1131}
1132
1133struct mailmime_content *
1134mailmime_content_dup(struct mailmime_content * content)
1135{
1136 clist * list;
1137 struct mailmime_type * type;
1138 int r;
1139 struct mailmime_content * dup_content;
1140 char * subtype;
1141
1142 type = mailmime_type_dup(content->ct_type);
1143 if (type == NULL)
1144 goto err;
1145
1146 subtype = strdup(content->ct_subtype);
1147 if (subtype == NULL)
1148 goto free_type;
1149
1150 list = clist_new();
1151 if (list == NULL)
1152 goto free_subtype;
1153
1154 if (content->ct_parameters != NULL) {
1155 clistiter * cur;
1156
1157 for(cur = clist_begin(content->ct_parameters) ;
1158 cur != NULL ; cur = clist_next(cur)) {
1159 struct mailmime_parameter * param;
1160
1161 param = mailmime_parameter_dup(clist_content(cur));
1162 if (param == NULL)
1163 goto free_list;
1164
1165 r = clist_append(list, param);
1166 if (r < 0) {
1167 mailmime_parameter_free(param);
1168 goto free_list;
1169 }
1170 }
1171 }
1172
1173 dup_content = mailmime_content_new(type, subtype, list);
1174 if (dup_content == NULL)
1175 goto free_list;
1176
1177 return dup_content;
1178
1179 free_list:
1180 clist_foreach(list, (clist_func) mailmime_parameter_free, NULL);
1181 free_subtype:
1182 free(subtype);
1183 free_type:
1184 mailmime_type_free(type);
1185 err:
1186 return NULL;
1187}
1188
1189
1190struct mailmime_parameter *
1191mailmime_param_new_with_data(char * name, char * value)
1192{
1193 char * param_name;
1194 char * param_value;
1195 struct mailmime_parameter * param;
1196
1197 param_name = strdup(name);
1198 if (param_name == NULL)
1199 goto err;
1200
1201 param_value = strdup(value);
1202 if (param_value == NULL)
1203 goto free_name;
1204
1205 param = mailmime_parameter_new(param_name, param_value);
1206 if (param == NULL)
1207 goto free_value;
1208
1209 return param;
1210
1211 free_value:
1212 free(param_value);
1213 free_name:
1214 free(param_name);
1215 err:
1216 return NULL;
1217}
1218
1219
1220int mailprivacy_fetch_decoded_to_file(struct mailprivacy * privacy,
1221 char * filename, size_t size,
1222 mailmessage * msg, struct mailmime * mime)
1223{
1224 int r;
1225 int res;
1226 FILE * f;
1227 char * content;
1228 size_t content_len;
1229 size_t written;
1230 struct mailmime_single_fields single_fields;
1231 int encoding;
1232 size_t cur_token;
1233 char * parsed_content;
1234 size_t parsed_content_len;
1235
1236 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
1237 mime->mm_content_type);
1238 if (single_fields.fld_encoding != NULL)
1239 encoding = single_fields.fld_encoding->enc_type;
1240 else
1241 encoding = MAILMIME_MECHANISM_8BIT;
1242
1243 r = mailprivacy_msg_fetch_section(privacy, msg, mime,
1244 &content, &content_len);
1245 if (r != MAIL_NO_ERROR) {
1246 res = MAIL_ERROR_FETCH;
1247 goto err;
1248 }
1249
1250 cur_token = 0;
1251 r = mailmime_part_parse(content, content_len, &cur_token,
1252 encoding, &parsed_content, &parsed_content_len);
1253 mailprivacy_msg_fetch_result_free(privacy, msg, content);
1254 if (r != MAILIMF_NO_ERROR) {
1255 res = MAIL_ERROR_PARSE;
1256 goto err;
1257 }
1258
1259 f = mailprivacy_get_tmp_file(privacy, filename, size);
1260 if (f == NULL) {
1261 res = MAIL_ERROR_FETCH;
1262 goto free_fetch;
1263 }
1264 written = fwrite(parsed_content, 1, parsed_content_len, f);
1265 if (written != parsed_content_len) {
1266 res = MAIL_ERROR_FILE;
1267 goto close;
1268 }
1269 fclose(f);
1270
1271 mmap_string_unref(parsed_content);
1272
1273 return MAIL_NO_ERROR;
1274
1275 close:
1276 fclose(f);
1277 unlink(filename);
1278 free_fetch:
1279 mmap_string_unref(parsed_content);
1280 err:
1281 return res;
1282}
1283
diff --git a/libetpan/src/engine/mailprivacy_tools.h b/libetpan/src/engine/mailprivacy_tools.h
new file mode 100644
index 0000000..1bf27c4
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_tools.h
@@ -0,0 +1,102 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#ifndef MAIL_PRIVACY_TOOLS_H
37
38#define MAIL_PRIVACY_TOOLS_H
39
40#include <libetpan/mailmessage.h>
41#include <libetpan/mailprivacy_types.h>
42
43void mailprivacy_mime_clear(struct mailmime * mime);
44
45FILE * mailprivacy_get_tmp_file(struct mailprivacy * privacy,
46 char * filename, size_t size);
47
48int mailprivacy_get_mime(struct mailprivacy * privacy,
49 int check_privacy,
50 char * content, size_t content_len,
51 struct mailmime ** result_mime);
52
53struct mailmime *
54mailprivacy_new_file_part(struct mailprivacy * privacy,
55 char * filename,
56 char * default_content_type, int default_encoding);
57
58int mailmime_substitute(struct mailmime * old_mime,
59 struct mailmime * new_mime);
60
61int mailprivacy_fetch_mime_body_to_file(struct mailprivacy * privacy,
62 char * filename, size_t size,
63 mailmessage * msg, struct mailmime * mime);
64
65int mailprivacy_get_part_from_file(struct mailprivacy * privacy,
66 int check_privacy,
67 char * filename,
68 struct mailmime ** result_mime);
69
70int mail_quote_filename(char * result, size_t size, char * path);
71
72void mailprivacy_prepare_mime(struct mailmime * mime);
73
74char * mailprivacy_dup_imf_file(struct mailprivacy * privacy,
75 char * source_filename);
76
77struct mailmime_fields *
78mailprivacy_mime_fields_dup(struct mailprivacy * privacy,
79 struct mailmime_fields * mime_fields);
80
81struct mailmime_parameter *
82mailmime_parameter_dup(struct mailmime_parameter * param);
83
84struct mailmime_composite_type *
85mailmime_composite_type_dup(struct mailmime_composite_type * composite_type);
86
87struct mailmime_discrete_type *
88mailmime_discrete_type_dup(struct mailmime_discrete_type * discrete_type);
89
90struct mailmime_type * mailmime_type_dup(struct mailmime_type * type);
91
92struct mailmime_content *
93mailmime_content_dup(struct mailmime_content * content);
94
95struct mailmime_parameter *
96mailmime_param_new_with_data(char * name, char * value);
97
98int mailprivacy_fetch_decoded_to_file(struct mailprivacy * privacy,
99 char * filename, size_t size,
100 mailmessage * msg, struct mailmime * mime);
101
102#endif
diff --git a/libetpan/src/engine/mailprivacy_types.h b/libetpan/src/engine/mailprivacy_types.h
new file mode 100644
index 0000000..e53f226
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_types.h
@@ -0,0 +1,82 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#ifndef MAIL_PRIVACY_TYPES_H
37
38#define MAIL_PRIVACY_TYPES_H
39
40#include <libetpan/chash.h>
41#include <libetpan/carray.h>
42#include <libetpan/mailmessage.h>
43#include <libetpan/mailmime.h>
44
45struct mailprivacy {
46 char * tmp_dir; /* working tmp directory */
47 chash * msg_ref; /* mailmessage => present or not */
48 chash * mmapstr; /* mmapstring => present or not present */
49 chash * mime_ref; /* mime => present or not */
50 carray * protocols;
51 int make_alternative;
52 /* if make_alternative is 0, replaces the part with decrypted
53 part, if 1, adds a multipart/alternative and put the decrypted
54 and encrypted part as subparts.
55 */
56};
57
58struct mailprivacy_encryption {
59 char * name;
60 char * description;
61
62 int (* encrypt)(struct mailprivacy *,
63 struct mailmime *, struct mailmime **);
64};
65
66struct mailprivacy_protocol {
67 char * name;
68 char * description;
69
70 /* introduce to easy the port to sylpheed */
71 int (* is_encrypted)(struct mailprivacy *,
72 mailmessage *, struct mailmime *);
73
74 int (* decrypt)(struct mailprivacy *,
75 mailmessage *, struct mailmime *,
76 struct mailmime **);
77
78 int encryption_count;
79 struct mailprivacy_encryption * encryption_tab;
80};
81
82#endif