-rw-r--r-- | libetpan/src/engine/mailengine.c | 1636 | ||||
-rw-r--r-- | libetpan/src/engine/mailengine.h | 190 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy.c | 949 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy.h | 117 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy_gnupg.c | 2614 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy_gnupg.h | 46 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy_smime.c | 1755 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy_smime.h | 84 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy_tools.c | 1283 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy_tools.h | 102 | ||||
-rw-r--r-- | libetpan/src/engine/mailprivacy_types.h | 82 |
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 | ||
59 | struct message_folder_finder { | ||
60 | #ifdef LIBETPAN_REENTRANT | ||
61 | pthread_mutex_t lock; | ||
62 | #endif | ||
63 | |||
64 | /* msg => folder */ | ||
65 | chash * message_hash; | ||
66 | }; | ||
67 | |||
68 | static 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 | |||
85 | static 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 | |||
93 | static struct mailfolder * | ||
94 | message_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 | |||
119 | static inline int | ||
120 | message_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 | |||
138 | static int | ||
139 | message_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 | |||
155 | static inline void | ||
156 | message_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 | |||
166 | static void | ||
167 | message_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 | |||
183 | struct message_ref_elt { | ||
184 | mailmessage * msg; | ||
185 | int ref_count; | ||
186 | int mime_ref_count; | ||
187 | struct mailfolder * folder; | ||
188 | int lost; | ||
189 | }; | ||
190 | |||
191 | static struct message_ref_elt * | ||
192 | message_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 | |||
209 | static void message_ref_elt_free(struct message_ref_elt * ref_elt) | ||
210 | { | ||
211 | free(ref_elt); | ||
212 | } | ||
213 | |||
214 | static 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 | |||
221 | static 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 | |||
229 | static 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 | |||
249 | static 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 | |||
266 | struct 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 | |||
281 | static struct folder_ref_info * | ||
282 | folder_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 | |||
316 | static 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 | |||
323 | static struct message_ref_elt * | ||
324 | folder_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 | |||
342 | static mailmessage * | ||
343 | folder_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 | |||
362 | static 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 | |||
371 | static void folder_message_remove(struct folder_ref_info * ref_info, | ||
372 | mailmessage * msg); | ||
373 | |||
374 | #ifdef DEBUG_ENGINE | ||
375 | #include "etpan-app.h" | ||
376 | |||
377 | void * engine_app = NULL; | ||
378 | #endif | ||
379 | |||
380 | static 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 | |||
403 | static 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 | |||
414 | static 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 | |||
424 | static 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 | |||
480 | static 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 | |||
507 | static 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 | |||
664 | static 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 | |||
670 | static 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 | |||
691 | struct 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 | |||
706 | static struct storage_ref_info * | ||
707 | storage_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 | |||
733 | static 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 | |||
743 | static struct folder_ref_info * | ||
744 | storage_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 | |||
763 | static struct folder_ref_info * | ||
764 | storage_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 | |||
793 | static 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 | |||
817 | static 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 | |||
832 | static 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 | |||
845 | static void | ||
846 | storage_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 | |||
860 | static void | ||
861 | folder_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 | |||
888 | static void | ||
889 | storage_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 | |||
912 | static 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 | |||
923 | static 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 | |||
946 | static 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 | |||
966 | static 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 | |||
982 | static 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 | |||
1035 | static 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 | |||
1042 | static 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 | |||
1088 | static 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 | |||
1111 | struct 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 | |||
1125 | static struct storage_ref_info * | ||
1126 | get_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 | |||
1151 | static struct storage_ref_info * | ||
1152 | add_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 | |||
1190 | static void | ||
1191 | remove_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 | |||
1219 | struct mailengine * | ||
1220 | libetpan_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 | |||
1263 | void 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 | ||
1276 | static struct folder_ref_info * | ||
1277 | message_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 | |||
1299 | static struct folder_ref_info * | ||
1300 | message_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 | |||
1321 | int 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 | |||
1331 | int 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 | |||
1342 | int 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 | |||
1352 | int 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 | |||
1362 | int 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 | |||
1375 | int 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 | |||
1386 | void 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 | |||
1398 | int 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 | |||
1422 | void 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 | |||
1435 | int 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 | |||
1446 | void 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 | |||
1456 | int 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 | |||
1467 | int 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 | |||
1478 | void 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 | |||
1489 | struct mailfolder * | ||
1490 | libetpan_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 | |||
1500 | struct mailstorage * | ||
1501 | libetpan_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 | |||
1515 | int 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 | |||
1558 | struct mailprivacy * | ||
1559 | libetpan_engine_get_privacy(struct mailengine * engine) | ||
1560 | { | ||
1561 | return engine->privacy; | ||
1562 | } | ||
1563 | |||
1564 | |||
1565 | static 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 | |||
1583 | static 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 | |||
1613 | void 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 | ||
45 | extern "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 | |||
57 | struct mailengine * | ||
58 | libetpan_engine_new(struct mailprivacy * privacy); | ||
59 | |||
60 | void libetpan_engine_free(struct mailengine * engine); | ||
61 | |||
62 | |||
63 | struct mailprivacy * | ||
64 | libetpan_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 | |||
78 | int libetpan_message_ref(struct mailengine * engine, | ||
79 | mailmessage * msg); | ||
80 | |||
81 | int 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 | |||
94 | int libetpan_message_mime_ref(struct mailengine * engine, | ||
95 | mailmessage * msg); | ||
96 | |||
97 | int 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 | |||
115 | int 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 | |||
120 | int libetpan_folder_fetch_env_list(struct mailengine * engine, | ||
121 | struct mailfolder * folder, | ||
122 | struct mailmessage_list * msg_list); | ||
123 | |||
124 | void 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 | |||
133 | int libetpan_storage_add(struct mailengine * engine, | ||
134 | struct mailstorage * storage); | ||
135 | |||
136 | void libetpan_storage_remove(struct mailengine * engine, | ||
137 | struct mailstorage * storage); | ||
138 | |||
139 | int libetpan_storage_connect(struct mailengine * engine, | ||
140 | struct mailstorage * storage); | ||
141 | |||
142 | void libetpan_storage_disconnect(struct mailengine * engine, | ||
143 | struct mailstorage * storage); | ||
144 | |||
145 | int 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 | |||
157 | int libetpan_folder_connect(struct mailengine * engine, | ||
158 | struct mailfolder * folder); | ||
159 | |||
160 | void libetpan_folder_disconnect(struct mailengine * engine, | ||
161 | struct mailfolder * folder); | ||
162 | |||
163 | |||
164 | struct mailfolder * | ||
165 | libetpan_message_get_folder(struct mailengine * engine, | ||
166 | mailmessage * msg); | ||
167 | |||
168 | struct mailstorage * | ||
169 | libetpan_message_get_storage(struct mailengine * engine, | ||
170 | mailmessage * msg); | ||
171 | |||
172 | |||
173 | /* | ||
174 | register a message | ||
175 | */ | ||
176 | |||
177 | int libetpan_message_register(struct mailengine * engine, | ||
178 | struct mailfolder * folder, | ||
179 | mailmessage * msg); | ||
180 | |||
181 | |||
182 | void libetpan_engine_debug(struct mailengine * engine, FILE * f); | ||
183 | |||
184 | extern 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 | |||
48 | carray * mailprivacy_get_protocols(struct mailprivacy * privacy) | ||
49 | { | ||
50 | return privacy->protocols; | ||
51 | } | ||
52 | |||
53 | static int recursive_check_privacy(struct mailprivacy * privacy, | ||
54 | mailmessage * msg, | ||
55 | struct mailmime * mime); | ||
56 | |||
57 | static 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 | |||
79 | struct 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 | |||
132 | void 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 | |||
142 | static 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 | |||
162 | static 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 | |||
184 | static 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 | |||
195 | static 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 | |||
211 | static 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 | |||
230 | static 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 | |||
243 | static 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 | |||
262 | static 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 | |||
273 | static 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 | |||
290 | static 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 | |||
330 | void 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 | |||
360 | static 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 | |||
414 | static void recursive_clear_registered_mime(struct mailprivacy * privacy, | ||
415 | struct mailmime * mime); | ||
416 | |||
417 | #if 0 | ||
418 | static 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 | |||
449 | int 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 | |||
485 | void 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 | |||
498 | static 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 | |||
549 | int 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 | |||
563 | int 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 | |||
578 | int 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 | |||
593 | int 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 | |||
608 | void 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 | |||
625 | int 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 | |||
633 | int 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 | |||
644 | static int privacy_handler(struct mailprivacy * privacy, | ||
645 | mailmessage * msg, | ||
646 | struct mailmime * mime, struct mailmime ** result); | ||
647 | |||
648 | |||
649 | |||
650 | static struct mailmime * | ||
651 | mime_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 | |||
722 | static 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 | |||
789 | static 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 | |||
817 | int 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 | |||
829 | void 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 | |||
842 | static struct mailprivacy_protocol * | ||
843 | get_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 | |||
858 | static struct mailprivacy_encryption * | ||
859 | get_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 | |||
875 | int 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 | |||
902 | char * 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 | |||
919 | int 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 | |||
942 | void 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 | |||
44 | struct mailprivacy * mailprivacy_new(char * tmp_dir, int make_alternative); | ||
45 | |||
46 | void mailprivacy_free(struct mailprivacy * privacy); | ||
47 | |||
48 | int mailprivacy_msg_get_bodystructure(struct mailprivacy * privacy, | ||
49 | mailmessage * msg_info, | ||
50 | struct mailmime ** result); | ||
51 | |||
52 | void mailprivacy_msg_flush(struct mailprivacy * privacy, | ||
53 | mailmessage * msg_info); | ||
54 | |||
55 | int mailprivacy_msg_fetch_section(struct mailprivacy * privacy, | ||
56 | mailmessage * msg_info, | ||
57 | struct mailmime * mime, | ||
58 | char ** result, size_t * result_len); | ||
59 | |||
60 | int 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 | |||
66 | int 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 | |||
72 | int 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 | |||
78 | void mailprivacy_msg_fetch_result_free(struct mailprivacy * privacy, | ||
79 | mailmessage * msg_info, | ||
80 | char * msg); | ||
81 | |||
82 | int mailprivacy_msg_fetch(struct mailprivacy * privacy, | ||
83 | mailmessage * msg_info, | ||
84 | char ** result, | ||
85 | size_t * result_len); | ||
86 | |||
87 | int mailprivacy_msg_fetch_header(struct mailprivacy * privacy, | ||
88 | mailmessage * msg_info, | ||
89 | char ** result, | ||
90 | size_t * result_len); | ||
91 | |||
92 | int mailprivacy_register(struct mailprivacy * privacy, | ||
93 | struct mailprivacy_protocol * protocol); | ||
94 | |||
95 | void mailprivacy_unregister(struct mailprivacy * privacy, | ||
96 | struct mailprivacy_protocol * protocol); | ||
97 | |||
98 | char * mailprivacy_get_encryption_name(struct mailprivacy * privacy, | ||
99 | char * privacy_driver, char * privacy_encryption); | ||
100 | |||
101 | int mailprivacy_encrypt(struct mailprivacy * privacy, | ||
102 | char * privacy_driver, char * privacy_encryption, | ||
103 | struct mailmime * mime, | ||
104 | struct mailmime ** result); | ||
105 | |||
106 | void mailprivacy_debug(struct mailprivacy * privacy, FILE * f); | ||
107 | |||
108 | carray * mailprivacy_get_protocols(struct mailprivacy * privacy); | ||
109 | |||
110 | int mailprivacy_is_encrypted(struct mailprivacy * privacy, | ||
111 | mailmessage * msg, | ||
112 | struct mailmime * mime); | ||
113 | |||
114 | void 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 | |||
51 | static 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 | |||
74 | static 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 | |||
99 | int 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 | |||
110 | int 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 | |||
122 | enum { | ||
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 | |||
131 | static 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 | |||
181 | static 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 | |||
211 | static 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 | |||
411 | static int | ||
412 | pgp_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 | |||
602 | static 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 | |||
843 | static 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 | |||
1046 | static 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 | |||
1065 | static 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 | |||
1123 | static 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 | ||
1208 | static 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 | |||
1267 | static 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 | |||
1297 | static 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 | |||
1504 | static 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 | |||
1523 | static 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 | |||
1543 | static 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 | |||
1549 | static 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 | |||
1568 | static 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 | |||
1589 | static 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 | |||
1641 | static 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 | |||
1854 | static 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 | |||
2054 | static 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 | |||
2210 | static 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 | |||
2371 | static 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 | |||
2544 | static 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 | |||
2593 | static 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 | |||
2606 | int mailprivacy_gnupg_init(struct mailprivacy * privacy) | ||
2607 | { | ||
2608 | return mailprivacy_register(privacy, &pgp_protocol); | ||
2609 | } | ||
2610 | |||
2611 | void 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 | |||
42 | int mailprivacy_gnupg_init(struct mailprivacy * privacy); | ||
43 | |||
44 | void 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 | |||
58 | static char cert_dir[PATH_MAX] = ""; | ||
59 | static chash * certificates = NULL; | ||
60 | static chash * private_keys = NULL; | ||
61 | static char CAcert_dir[PATH_MAX] = ""; | ||
62 | static char * CAfile = NULL; | ||
63 | static int CA_check = 1; | ||
64 | static int store_cert = 0; | ||
65 | static char private_keys_dir[PATH_MAX] = ""; | ||
66 | |||
67 | static char * get_cert_file(char * email); | ||
68 | |||
69 | static char * get_private_key_file(char * email); | ||
70 | |||
71 | |||
72 | static 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 | |||
93 | static 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 | |||
106 | enum { | ||
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 | |||
115 | static 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 | |||
159 | static 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 | |||
194 | static 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 | |||
438 | static 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 | |||
446 | static int | ||
447 | smime_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 | |||
633 | static 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 | |||
648 | static 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 | |||
688 | static 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 | |||
712 | static 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 | |||
849 | static 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 | |||
881 | static 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 | |||
901 | static 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 | |||
907 | static 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 | |||
926 | static 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 | |||
946 | static 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 | |||
997 | static 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 | |||
1115 | static 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 | |||
1303 | static 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 | |||
1328 | static 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 | |||
1341 | int 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 | |||
1361 | void 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 | |||
1377 | static 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 | |||
1418 | static 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 | |||
1439 | static 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 | |||
1462 | void 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 | |||
1507 | static char * get_cert_file(char * email) | ||
1508 | { | ||
1509 | return get_file(certificates, email); | ||
1510 | } | ||
1511 | |||
1512 | static char * get_private_key_file(char * email) | ||
1513 | { | ||
1514 | return get_file(private_keys, email); | ||
1515 | } | ||
1516 | |||
1517 | void mail_private_smime_clear_private_keys(struct mailprivacy * privacy) | ||
1518 | { | ||
1519 | chash_clear(private_keys); | ||
1520 | } | ||
1521 | |||
1522 | #define MAX_BUF 1024 | ||
1523 | |||
1524 | void 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 | |||
1592 | void mailprivacy_smime_set_CA_check(struct mailprivacy * privacy, | ||
1593 | int enabled) | ||
1594 | { | ||
1595 | CA_check = enabled; | ||
1596 | } | ||
1597 | |||
1598 | void mailprivacy_smime_set_store_cert(struct mailprivacy * privacy, | ||
1599 | int enabled) | ||
1600 | { | ||
1601 | store_cert = enabled; | ||
1602 | } | ||
1603 | |||
1604 | static 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 | |||
1700 | static 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 | |||
1708 | void 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 | |||
42 | int mailprivacy_smime_init(struct mailprivacy * privacy); | ||
43 | |||
44 | void mailprivacy_smime_done(struct mailprivacy * privacy); | ||
45 | |||
46 | void 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 | |||
55 | void 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 | |||
64 | void mailprivacy_smime_set_CA_check(struct mailprivacy * privacy, | ||
65 | int enabled); | ||
66 | |||
67 | |||
68 | /* | ||
69 | to store certificates of signed messages | ||
70 | */ | ||
71 | |||
72 | void 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 | |||
81 | void 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 | |||
52 | void 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 | |||
97 | static 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 | |||
118 | FILE * 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 | |||
126 | static 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 | |||
188 | static 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 | |||
274 | static 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 | |||
366 | int 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 | ||
455 | static 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 | |||
477 | struct mailmime * | ||
478 | mailprivacy_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 | |||
593 | int 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 | |||
620 | int 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 | |||
683 | int 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 | |||
748 | int 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 | |||
796 | static 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 | |||
859 | void 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 | |||
890 | char * 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 | |||
948 | struct mailmime_fields * | ||
949 | mailprivacy_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 | |||
1014 | struct mailmime_parameter * | ||
1015 | mailmime_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 | |||
1043 | struct mailmime_composite_type * | ||
1044 | mailmime_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 | |||
1069 | struct mailmime_discrete_type * | ||
1070 | mailmime_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 | |||
1095 | struct 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 | |||
1133 | struct mailmime_content * | ||
1134 | mailmime_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 | |||
1190 | struct mailmime_parameter * | ||
1191 | mailmime_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 | |||
1220 | int 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 | |||
43 | void mailprivacy_mime_clear(struct mailmime * mime); | ||
44 | |||
45 | FILE * mailprivacy_get_tmp_file(struct mailprivacy * privacy, | ||
46 | char * filename, size_t size); | ||
47 | |||
48 | int mailprivacy_get_mime(struct mailprivacy * privacy, | ||
49 | int check_privacy, | ||
50 | char * content, size_t content_len, | ||
51 | struct mailmime ** result_mime); | ||
52 | |||
53 | struct mailmime * | ||
54 | mailprivacy_new_file_part(struct mailprivacy * privacy, | ||
55 | char * filename, | ||
56 | char * default_content_type, int default_encoding); | ||
57 | |||
58 | int mailmime_substitute(struct mailmime * old_mime, | ||
59 | struct mailmime * new_mime); | ||
60 | |||
61 | int mailprivacy_fetch_mime_body_to_file(struct mailprivacy * privacy, | ||
62 | char * filename, size_t size, | ||
63 | mailmessage * msg, struct mailmime * mime); | ||
64 | |||
65 | int mailprivacy_get_part_from_file(struct mailprivacy * privacy, | ||
66 | int check_privacy, | ||
67 | char * filename, | ||
68 | struct mailmime ** result_mime); | ||
69 | |||
70 | int mail_quote_filename(char * result, size_t size, char * path); | ||
71 | |||
72 | void mailprivacy_prepare_mime(struct mailmime * mime); | ||
73 | |||
74 | char * mailprivacy_dup_imf_file(struct mailprivacy * privacy, | ||
75 | char * source_filename); | ||
76 | |||
77 | struct mailmime_fields * | ||
78 | mailprivacy_mime_fields_dup(struct mailprivacy * privacy, | ||
79 | struct mailmime_fields * mime_fields); | ||
80 | |||
81 | struct mailmime_parameter * | ||
82 | mailmime_parameter_dup(struct mailmime_parameter * param); | ||
83 | |||
84 | struct mailmime_composite_type * | ||
85 | mailmime_composite_type_dup(struct mailmime_composite_type * composite_type); | ||
86 | |||
87 | struct mailmime_discrete_type * | ||
88 | mailmime_discrete_type_dup(struct mailmime_discrete_type * discrete_type); | ||
89 | |||
90 | struct mailmime_type * mailmime_type_dup(struct mailmime_type * type); | ||
91 | |||
92 | struct mailmime_content * | ||
93 | mailmime_content_dup(struct mailmime_content * content); | ||
94 | |||
95 | struct mailmime_parameter * | ||
96 | mailmime_param_new_with_data(char * name, char * value); | ||
97 | |||
98 | int 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 | |||
45 | struct 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 | |||
58 | struct mailprivacy_encryption { | ||
59 | char * name; | ||
60 | char * description; | ||
61 | |||
62 | int (* encrypt)(struct mailprivacy *, | ||
63 | struct mailmime *, struct mailmime **); | ||
64 | }; | ||
65 | |||
66 | struct 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 | ||