ascii-armored pgp messages: make decryption and signature verification work again
[claws.git] / src / pgptext.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001 Jens Jahnke <jan0sch@gmx.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #if USE_GPGME
25
26 #include "defs.h"
27
28 #include <glib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <locale.h>
32 #include <ctype.h>
33 #include <fcntl.h>      /* FIXME */
34
35 #include <gpgme.h>
36
37 #include "intl.h"
38 #include "procmime.h"
39 #include "procheader.h"
40 #include "base64.h"
41 #include "uuencode.h"
42 #include "unmime.h"
43 #include "codeconv.h"
44 #include "utils.h"
45 #include "prefs_common.h"
46 #include "passphrase.h"
47 #include "select-keys.h"
48 #include "sigstatus.h"
49 #include "rfc2015.h"
50
51 #include "pgptext.h"
52
53 #define DIM(v)     (sizeof(v)/sizeof((v)[0]))
54
55 static char *content_names[] = {
56     "Content-Type",
57     "Content-Disposition",
58     "Content-Transfer-Encoding",
59     NULL
60 };
61
62 static char *mime_version_name[] = {
63     "Mime-Version",
64     NULL
65 };
66
67
68 struct passphrase_cb_info_s {
69     GpgmeCtx c;
70     int did_it;
71 };
72
73 static const gchar *
74 sig_status_to_string (GpgmeSigStat status)
75 {
76     const gchar *result;
77
78     switch (status) {
79       case GPGME_SIG_STAT_NONE:
80         result = _("Oops: Signature not verified");
81         break;
82       case GPGME_SIG_STAT_NOSIG:
83         result = _("No signature found");
84         break;
85       case GPGME_SIG_STAT_GOOD:
86         result = _("Good signature");
87         break;
88       case GPGME_SIG_STAT_BAD:
89         result = _("BAD signature");
90         break;
91       case GPGME_SIG_STAT_NOKEY:
92         result = _("No public key to verify the signature");
93         break;
94       case GPGME_SIG_STAT_ERROR:
95         result = _("Error verifying the signature");
96         break;
97       case GPGME_SIG_STAT_DIFF:
98         result = _("Different results for signatures");
99         break;
100       default:
101         result = _("Error: Unknown status");
102         break;
103     }
104
105     return result;
106 }
107
108 static const gchar *
109 sig_status_with_name (GpgmeSigStat status)
110 {
111     const gchar *result;
112
113     switch (status) {
114       case GPGME_SIG_STAT_NONE:
115         result = _("Oops: Signature not verified");
116         break;
117       case GPGME_SIG_STAT_NOSIG:
118         result = _("No signature found");
119         break;
120       case GPGME_SIG_STAT_GOOD:
121         result = _("Good signature from \"%s\"");
122         break;
123       case GPGME_SIG_STAT_BAD:
124         result = _("BAD signature  from \"%s\"");
125         break;
126       case GPGME_SIG_STAT_NOKEY:
127         result = _("No public key to verify the signature");
128         break;
129       case GPGME_SIG_STAT_ERROR:
130         result = _("Error verifying the signature");
131         break;
132       case GPGME_SIG_STAT_DIFF:
133         result = _("Different results for signatures");
134         break;
135       default:
136         result = _("Error: Unknown status");
137         break;
138     }
139
140     return result;
141 }
142
143 static void
144 sig_status_for_key(GString *str, GpgmeCtx ctx, GpgmeSigStat status, 
145                    GpgmeKey key, const gchar *fpr)
146 {
147         gint idx = 0;
148         const char *uid;
149
150         uid = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, NULL, idx);
151         if (uid == NULL) {
152                 g_string_sprintfa (str, "%s\n",
153                                    sig_status_to_string (status));
154                 if ((fpr != NULL) && (*fpr != '\0'))
155                         g_string_sprintfa (str, "Key fingerprint: %s\n", fpr);
156                 g_string_append (str, _("Cannot find user ID for this key."));
157                 return;
158         }
159         g_string_sprintfa (str, sig_status_with_name (status), uid);
160         g_string_append (str, "\n");
161
162         while (1) {
163                 uid = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID,
164                                                  NULL, ++idx);
165                 if (uid == NULL)
166                         break;
167                 g_string_sprintfa (str, _("                aka \"%s\"\n"),
168                                    uid);
169         }
170 }
171
172 static gchar *
173 sig_status_full (GpgmeCtx ctx)
174 {
175         GString *str;
176         gint sig_idx = 0;
177         GpgmeError err;
178         GpgmeSigStat status;
179         GpgmeKey key;
180         const char *fpr;
181         time_t created;
182         struct tm *ctime_val;
183         char ctime_str[80];
184         gchar *retval;
185
186         str = g_string_new ("");
187
188         fpr = gpgme_get_sig_status (ctx, sig_idx, &status, &created);
189         while (fpr != NULL) {
190                 if (created != 0) {
191                         ctime_val = localtime (&created);
192                         strftime (ctime_str, sizeof (ctime_str), "%c", 
193                                   ctime_val);
194                         g_string_sprintfa (str,
195                                            _("Signature made %s\n"),
196                                            ctime_str);
197                 }
198                 err = gpgme_get_sig_key (ctx, sig_idx, &key);
199                 if (err != 0) {
200                         g_string_sprintfa (str, "%s\n",
201                                            sig_status_to_string (status));
202                         if ((fpr != NULL) && (*fpr != '\0'))
203                                 g_string_sprintfa (str,
204                                                    _("Key fingerprint: %s\n"),
205                                                    fpr);
206                 } else {
207                         sig_status_for_key (str, ctx, status, key, fpr);
208                         gpgme_key_unref (key);
209                 }
210                 g_string_append (str, "\n\n");
211
212                 fpr = gpgme_get_sig_status (ctx, ++sig_idx, &status, &created);
213         }
214
215         retval = str->str;
216         g_string_free (str, FALSE);
217         return retval;
218 }
219
220 static void dump_part ( MimeInfo *mimeinfo, FILE *fp )
221 {
222     unsigned int size = mimeinfo->size;
223     int c;
224
225     if (fseek (fp, mimeinfo->fpos, SEEK_SET)) {
226         g_warning ("dump_part: fseek error");
227         return;
228     }
229
230     debug_print ("** --- begin dump_part ----");
231     while (size-- && (c = getc (fp)) != EOF)
232         putc (c, stderr);
233     if (ferror (fp))
234         g_warning ("dump_part: read error");
235     debug_print ("** --- end dump_part ----");
236 }
237
238 static void pgptext_fine_check_signature (MimeInfo *mimeinfo, FILE *fp)
239 {
240     GpgmeCtx ctx = NULL;
241     GpgmeError err;
242     GpgmeData text = NULL;
243     GpgmeSigStat status = GPGME_SIG_STAT_NONE;
244     GpgmegtkSigStatus statuswindow = NULL;
245     const char *result = NULL;
246
247         /* As this is the most simple solution, I prefer it. :-) */
248         statuswindow = gpgmegtk_sig_status_create ();
249
250     err = gpgme_new (&ctx);
251     if (err) {
252         g_warning ("gpgme_new failed: %s", gpgme_strerror (err));
253         goto leave;
254     }
255
256     err = gpgme_data_new_from_filepart (&text, NULL, fp,
257                                         mimeinfo->fpos, mimeinfo->size);
258
259     if (err) {
260         debug_print ("gpgme_data_new_from_filepart failed: %s",
261                    gpgme_strerror (err));
262         goto leave;
263     }
264
265         /* Just pass the text to gpgme_op_verify to enable plain text stuff. */
266     err = gpgme_op_verify (ctx, text, NULL, &status);
267     if (err)
268         debug_print ("gpgme_op_verify failed: %s", gpgme_strerror (err));
269
270     /* FIXME: check what the heck this sig_status_full stuff is.
271      * it should better go into sigstatus.c */
272     g_free (mimeinfo->sigstatus_full);
273     mimeinfo->sigstatus_full = sig_status_full (ctx);
274
275 leave:
276     result = gpgmegtk_sig_status_to_string(status);
277     debug_print("verification status: %s\n", result);
278     gpgmegtk_sig_status_update (statuswindow,ctx);
279
280     g_assert (!err); /* FIXME: Hey: this may indeed happen */
281     g_free (mimeinfo->sigstatus);
282     mimeinfo->sigstatus = g_strdup (result);
283
284     gpgme_data_release (text);
285     gpgme_release (ctx);
286     gpgmegtk_sig_status_destroy (statuswindow);
287 }
288
289 /* stolen from rfc2015.c */
290 static int
291 gpg_name_cmp(const char *a, const char *b)
292 {
293     for( ; *a && *b; a++, b++) {
294         if(*a != *b
295            && toupper(*(unsigned char *)a) != toupper(*(unsigned char *)b))
296             return 1;
297     }
298
299     return *a != *b;
300 }
301
302 static const char *
303 passphrase_cb (void *opaque, const char *desc, void *r_hd)
304 {
305     struct passphrase_cb_info_s *info = opaque;
306     GpgmeCtx ctx = info ? info->c : NULL;
307     const char *pass;
308
309     if (!desc) {
310         /* FIXME: cleanup by looking at *r_hd */
311         return NULL;
312     }
313
314     gpgmegtk_set_passphrase_grab (prefs_common.passphrase_grab);
315     debug_print ("requesting passphrase for `%s': ", desc);
316     pass = gpgmegtk_passphrase_mbox (desc);
317     if (!pass) {
318         debug_print ("cancel passphrase entry\n");
319         gpgme_cancel (ctx);
320     }
321     else
322         debug_print ("sending passphrase\n");
323
324     return pass;
325 }
326
327 static GpgmeData
328 pgptext_decrypt (MimeInfo *partinfo, FILE *fp)
329 {
330     GpgmeCtx ctx = NULL;
331     GpgmeError err;
332     GpgmeData cipher = NULL, plain = NULL;
333     struct passphrase_cb_info_s info;
334
335     memset (&info, 0, sizeof info);
336
337     err = gpgme_new (&ctx);
338     if (err) {
339         debug_print ("gpgme_new failed: %s\n", gpgme_strerror (err));
340         goto leave;
341     }
342
343     err = gpgme_data_new_from_filepart (&cipher, NULL, fp,
344                                         partinfo->fpos, partinfo->size);
345     if (err) {
346         debug_print ("gpgme_data_new_from_filepart failed: %s\n",
347                      gpgme_strerror (err));
348         goto leave;
349     }
350
351     err = gpgme_data_new (&plain);
352     if (err) {
353         debug_print ("gpgme_new failed: %s\n", gpgme_strerror (err));
354         goto leave;
355     }
356
357     if (!getenv("GPG_AGENT_INFO")) {
358         info.c = ctx;
359         gpgme_set_passphrase_cb (ctx, passphrase_cb, &info);
360     } 
361
362     err = gpgme_op_decrypt (ctx, cipher, plain);
363
364 leave:
365     gpgme_data_release (cipher);
366     if (err) {
367         debug_print ("decryption failed: %s\n", gpgme_strerror (err));
368         gpgme_data_release (plain);
369         plain = NULL;
370     }
371     else
372         debug_print ("decryption succeeded\n");
373
374     gpgme_release (ctx);
375     return plain;
376 }
377
378 static int
379 headerp(char *p, char **names)
380 {
381     int i, c;
382     char *p2;
383
384     p2 = strchr(p, ':');
385     if(!p2 || p == p2) {
386         return 0;
387     }
388     if(p2[-1] == ' ' || p2[-1] == '\t') {
389         return 0;
390     }
391
392     if(!names[0])
393         return 1;
394
395     c = *p2;
396     *p2 = 0;
397     for(i = 0 ; names[i] != NULL; i++) {
398         if(!gpg_name_cmp (names[i], p))
399             break;
400     }
401     *p2 = c;
402
403     return names[i] != NULL;
404 }
405
406 gboolean pgptext_has_signature (MsgInfo *msginfo, MimeInfo *mimeinfo)
407 {
408         FILE *fp;
409         gchar *file = NULL, *tmpchk, *tmpln, *tmpln_1;
410         gchar buf[BUFFSIZE];
411         gboolean has_begin_pgp_signed_msg = FALSE;
412         gboolean has_begin_pgp_sig = FALSE;
413         gboolean has_end_pgp_sig = FALSE;
414         gchar *check_begin_pgp_signed_msg = "-----BEGIN PGP SIGNED MESSAGE-----\n";
415         gchar *check_begin_pgp_signed_msg_1 = "-----BEGIN PGP SIGNED MESSAGE-----\r\n";
416         gchar *check_begin_pgp_sig = "-----BEGIN PGP SIGNATURE-----\n";
417         gchar *check_begin_pgp_sig_1 = "-----BEGIN PGP SIGNATURE-----\r\n";
418         gchar *check_end_pgp_sig = "-----END PGP SIGNATURE-----\n";
419         gchar *check_end_pgp_sig_1 = "-----END PGP SIGNATURE-----\r\n";
420
421         if ((!mimeinfo) || (!msginfo))
422                 return FALSE;
423         
424         file = g_strdup_printf("%s", procmsg_get_message_file_path(msginfo));
425         
426         if (mimeinfo->mime_type != MIME_TEXT) {
427                 if ((fp = fopen(file, "r")) == NULL) {
428                         FILE_OP_ERROR(file, "fopen");
429                         return;
430                 }
431                 /* skip headers */
432                 if (mimeinfo->mime_type == MIME_MULTIPART) {
433                         if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
434                         perror("fseek");
435                         while (fgets(buf, sizeof(buf), fp) != NULL)
436                                 if (buf[0] == '\r' || buf[0] == '\n') break;
437                 }
438                 /* now check for a pgptext signed message
439                  * the strlen check catches quoted signatures */
440                 while (fgets(buf, sizeof(buf), fp) != NULL) {
441                         tmpchk = g_strnfill(sizeof(buf), '\n');
442                         memmove(tmpchk, &buf, sizeof(buf));
443                         
444                         tmpln = strstr(tmpchk, check_begin_pgp_signed_msg);
445                         tmpln_1 = strstr(tmpchk, check_begin_pgp_signed_msg_1);
446                         if (((tmpln != NULL) || (tmpln_1 != NULL)) && ((strlen(tmpchk) ==
447                               strlen(tmpln)) || (strlen(tmpchk) == strlen(tmpln_1))) )
448                                 has_begin_pgp_signed_msg = TRUE;
449                         
450                         tmpln = strstr(tmpchk, check_begin_pgp_sig);
451                         tmpln_1 = strstr(tmpchk, check_begin_pgp_sig_1);
452                         if (((tmpln != NULL) || (tmpln_1 != NULL)) && ((strlen(tmpchk) ==
453                               strlen(tmpln)) || (strlen(tmpchk) == strlen(tmpln_1))) )
454                                 has_begin_pgp_sig = TRUE;
455                         
456                         tmpln = strstr(tmpchk, check_end_pgp_sig);
457                         tmpln_1 = strstr(tmpchk, check_end_pgp_sig_1);
458                         if (((tmpln != NULL) || (tmpln_1 != NULL)) && ((strlen(tmpchk) ==
459                               strlen(tmpln)) || (strlen(tmpchk) == strlen(tmpln_1))) )
460                                 has_end_pgp_sig = TRUE;
461                         
462                         g_free(tmpchk);
463                 }
464                 fclose(fp);
465         } else {
466                 if ((fp = fopen(file, "r")) == NULL) {
467                         FILE_OP_ERROR(file, "fopen");
468                         return;
469                 }
470                 /* skip headers */
471                 if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
472                 perror("fseek");
473                 while (fgets(buf, sizeof(buf), fp) != NULL)
474                         if (buf[0] == '\r' || buf[0] == '\n') break;
475                 
476                 /* now check for a pgptext encrypted message */
477                 while (fgets(buf, sizeof(buf), fp) != NULL) {
478                         tmpchk = g_strnfill(sizeof(buf), '\n');
479                         memmove(tmpchk, &buf, sizeof(buf));
480
481                         if (strstr(tmpchk, check_begin_pgp_signed_msg) != NULL ||
482                                         strstr(tmpchk, check_begin_pgp_signed_msg_1) != NULL)
483                                 has_begin_pgp_signed_msg = TRUE;
484                         if (strstr(tmpchk, check_begin_pgp_sig) != NULL ||
485                                         strstr(tmpchk, check_begin_pgp_sig_1) != NULL)
486                                 has_begin_pgp_sig = TRUE;
487                         if (strstr(tmpchk, check_end_pgp_sig) != NULL ||
488                                         strstr(tmpchk, check_end_pgp_sig_1) != NULL)
489                                 has_end_pgp_sig = TRUE;
490
491                         g_free(tmpchk);
492                 }
493                 fclose(fp);
494         }
495         
496         g_free(file);
497         
498         /* do we have a proper message? */
499         if (has_begin_pgp_signed_msg && has_begin_pgp_sig && has_end_pgp_sig) {
500                 debug_print ("** pgptext signed message encountered\n");
501                 return TRUE;
502         } else
503                 return FALSE;
504 }
505
506 void pgptext_check_signature (MimeInfo *mimeinfo, FILE *fp)
507 {
508         gchar *file, *tmpchk;
509         gchar buf[BUFFSIZE];
510         gboolean has_begin_pgp_signed_msg = FALSE;
511         gboolean has_begin_pgp_sig = FALSE;
512         gboolean has_end_pgp_sig = FALSE;
513         gchar *check_begin_pgp_signed_msg = "-----BEGIN PGP SIGNED MESSAGE-----\n";
514         gchar *check_begin_pgp_signed_msg_1 = "-----BEGIN PGP SIGNED
515 MESSAGE-----\r\n";
516         gchar *check_begin_pgp_sig = "-----BEGIN PGP SIGNATURE-----\n";
517         gchar *check_begin_pgp_sig_1 = "-----BEGIN PGP SIGNATURE-----\r\n";
518         gchar *check_end_pgp_sig = "-----END PGP SIGNATURE-----\n";
519         gchar *check_end_pgp_sig_1 = "-----END PGP SIGNATURE-----\r\n";
520
521     if (!mimeinfo)
522         return;
523         
524         /* now we have to set fpos and size correctly */
525         /* skip headers */
526         /* FIXME: we should check for the correct mime type
527          * f.e. mime/text, application/pgp and so on...*/
528 /*      if (mimeinfo->mime_type == MIME_TEXT) {*/
529                 if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
530                 perror("fseek");
531                 while (fgets(buf, sizeof(buf), fp) != NULL) {
532                         mimeinfo->fpos = mimeinfo->fpos + strlen(buf);
533                         if (buf[0] == '\r' || buf[0] == '\n') break;
534                 }
535 /*      }*/
536
537         /* now check for fpos and size of the pgptext signed message */
538         mimeinfo->size = 0;     /* init */
539         while (fgets(buf, sizeof(buf), fp) != NULL) {
540                 tmpchk = g_strnfill(sizeof(buf), '\n');
541                 memmove(tmpchk, &buf, sizeof(buf));
542
543                 if (has_begin_pgp_signed_msg)
544                         /* get the size */
545                         mimeinfo->size = mimeinfo->size + strlen(tmpchk);
546
547                 if (strstr(tmpchk, check_begin_pgp_signed_msg) != NULL ||
548                                 strstr(tmpchk, check_begin_pgp_signed_msg_1) != NULL)
549                         has_begin_pgp_signed_msg = TRUE;
550                 else if (!has_begin_pgp_signed_msg)
551                         /* set the beginning of the pgptext signed message */
552                         mimeinfo->fpos = mimeinfo->fpos + strlen(tmpchk);
553
554                 if (strstr(tmpchk, check_begin_pgp_sig) != NULL ||
555                                 strstr(tmpchk, check_begin_pgp_sig_1) != NULL)
556                         has_begin_pgp_sig = TRUE;
557
558                 if (strstr(tmpchk, check_end_pgp_sig) != NULL ||
559                                 strstr(tmpchk, check_end_pgp_sig_1) != NULL) {
560                         has_end_pgp_sig = TRUE;
561                         /* FIXME: Find out why the hell there are always 6[+1] 
562                          * chars less in our counter!*/
563                         mimeinfo->size = mimeinfo->size + strlen(tmpchk) + 7;
564                         break;
565                 }
566
567                 g_free(tmpchk);
568         }
569         
570 #if 0
571         debug_print ("** pgptext sig check...");
572         debug_print ("\tmimeinfo->fpos: %lu\tmimeinfo->size: %lu\n",
573                         mimeinfo->fpos, mimeinfo->size);
574         dump_part (mimeinfo, fp);
575 #endif
576
577         pgptext_fine_check_signature (mimeinfo, fp);
578 }
579
580 int pgptext_is_encrypted (MimeInfo *mimeinfo, MsgInfo *msginfo)
581 {
582         FILE *fp;
583         gchar *file, *tmpchk;
584         gchar buf[BUFFSIZE];
585         gboolean has_begin_pgp_msg = FALSE;
586         gboolean has_end_pgp_msg = FALSE;
587         gchar *check_begin_pgp_msg = "-----BEGIN PGP MESSAGE-----\n";
588         gchar *check_begin_pgp_msg_1 = "-----BEGIN PGP MESSAGE-----\r\n";
589         gchar *check_end_pgp_msg = "-----END PGP MESSAGE-----\n";
590         gchar *check_end_pgp_msg_1 = "-----END PGP MESSAGE-----\r\n";
591         
592         g_return_if_fail(msginfo != NULL);
593         
594         if (!mimeinfo)
595                 return 0;
596
597         if ((fp = procmsg_open_message(msginfo)) == NULL) return;
598         mimeinfo = procmime_scan_mime_header(fp);
599         fclose(fp);
600         if (!mimeinfo) return;
601
602         file = procmsg_get_message_file_path(msginfo);
603         g_return_if_fail(file != NULL);
604
605         if (mimeinfo->mime_type != MIME_TEXT) {
606                 if ((fp = fopen(file, "r")) == NULL) {
607                         FILE_OP_ERROR(file, "fopen");
608                         return;
609                 }
610                 /* skip headers */
611                 if (mimeinfo->mime_type == MIME_MULTIPART) {
612                         if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
613                         perror("fseek");
614                         while (fgets(buf, sizeof(buf), fp) != NULL)
615                                 if (buf[0] == '\r' || buf[0] == '\n') break;
616                 }
617                 /* now check for a pgptext encrypted message */
618                 while (fgets(buf, sizeof(buf), fp) != NULL) {
619                         tmpchk = g_strnfill(sizeof(buf), '\n');
620                         memmove(tmpchk, &buf, sizeof(buf));
621                         
622                         if (strstr(tmpchk, check_begin_pgp_msg) != NULL || 
623                             strstr(tmpchk, check_begin_pgp_msg_1) != NULL)
624                                 has_begin_pgp_msg = TRUE;
625                         if (strstr(tmpchk, check_end_pgp_msg) != NULL || 
626                             strstr(tmpchk, check_end_pgp_msg_1) != NULL)
627                                 has_end_pgp_msg = TRUE;
628
629                         g_free(tmpchk);
630                 }
631                 fclose(fp);
632         } else {
633                 if ((fp = fopen(file, "r")) == NULL) {
634                         FILE_OP_ERROR(file, "fopen");
635                         return;
636                 }
637                 /* skip headers */
638                 if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
639                 perror("fseek");
640                 while (fgets(buf, sizeof(buf), fp) != NULL)
641                         if (buf[0] == '\r' || buf[0] == '\n') break;
642                 
643                 /* now check for a pgptext encrypted message */
644                 while (fgets(buf, sizeof(buf), fp) != NULL) {
645                         tmpchk = g_strnfill(sizeof(buf), '\n');
646                         memmove(tmpchk, &buf, sizeof(buf));
647                         
648                         if (strstr(tmpchk, check_begin_pgp_msg) != NULL || 
649                             strstr(tmpchk, check_begin_pgp_msg_1) != NULL)
650                                 has_begin_pgp_msg = TRUE;
651                         if (strstr(tmpchk, check_end_pgp_msg) != NULL || 
652                             strstr(tmpchk, check_end_pgp_msg_1) != NULL)
653                                 has_end_pgp_msg = TRUE;
654
655                         g_free(tmpchk);
656                 }
657                 fclose(fp);
658         }
659         
660         g_free(file);
661         
662         /* do we have a proper message? */
663         if (has_begin_pgp_msg && has_end_pgp_msg)
664                 return 1;
665         else
666                 return 0;
667 }
668
669 void pgptext_decrypt_message (MsgInfo *msginfo, MimeInfo *mimeinfo, FILE *fp)
670 {
671     static int id;
672     MimeInfo *partinfo;
673     int n, found;
674     int ver_okay=0;
675     char *fname;
676     GpgmeData plain;
677     FILE *dstfp;
678     size_t nread;
679     char buf[BUFFSIZE];
680     GpgmeError err;
681
682     g_return_if_fail (mimeinfo->mime_type == MIME_TEXT);
683
684     debug_print ("text/plain with pgptext encountered\n");
685
686     partinfo = procmime_scan_message(msginfo);
687                 
688     /* skip headers */
689     if (fseek(fp, partinfo->fpos, SEEK_SET) < 0)
690         perror("fseek");
691     while (fgets(buf, sizeof(buf), fp) != NULL) {
692                                 partinfo->fpos = partinfo->fpos + strlen(buf);
693         if (buf[0] == '\r' || buf[0] == '\n') break;
694                 }
695     /* get size */
696     while (fgets(buf, sizeof(buf), fp) != NULL)
697                                 partinfo->size = partinfo->size + strlen(buf);
698                 
699     plain = pgptext_decrypt (partinfo, fp);
700     if (!plain) {
701         msginfo->decryption_failed = 1;
702         return;
703     }
704     
705     fname = g_strdup_printf("%s%cplaintext.%08x",
706                             get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);
707
708     if ((dstfp = fopen(fname, "w")) == NULL) {
709         FILE_OP_ERROR(fname, "fopen");
710         g_free(fname);
711         msginfo->decryption_failed = 1;
712         return;
713     }
714
715     /* write the orginal header to the new file */
716     if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
717         perror("fseek");
718
719     while (fgets(buf, sizeof(buf), fp)) {
720         if (headerp (buf, content_names))
721             continue;
722         if (buf[0] == '\r' || buf[0] == '\n')
723             break;
724         fputs (buf, dstfp);
725     }
726                 
727     err = gpgme_data_rewind (plain);
728     if (err)
729         debug_print ("gpgme_data_rewind failed: %s\n", gpgme_strerror (err));
730
731                 /* insert blank line to avoid some trouble... */
732                 fputs ("\n", dstfp);
733                 
734     while (!(err = gpgme_data_read (plain, buf, sizeof(buf), &nread))) {
735         fwrite (buf, nread, 1, dstfp);
736     }
737
738     if (err != GPGME_EOF) {
739         debug_print ("gpgme_data_read failed: %s\n", gpgme_strerror (err));
740     }
741
742     fclose (dstfp);
743
744     msginfo->plaintext_file = fname;
745     msginfo->decryption_failed = 0;
746
747 }
748
749 /* int pgptext_encrypt (const char *file, GSList *recp_list)
750 {
751 }
752
753 int pgptext_sign (const char *file, PrefsAccount *ac)
754 {
755 } */
756
757 #endif  /* USE_GPGME */
758