allow quote / reply date & time format to be set using %D{format}.
[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
34 #include <gpgme.h>
35
36 #include "intl.h"
37 #include "procmime.h"
38 #include "procheader.h"
39 #include "base64.h"
40 #include "uuencode.h"
41 #include "unmime.h"
42 #include "codeconv.h"
43 #include "utils.h"
44 #include "prefs_common.h"
45 #include "passphrase.h"
46 #include "select-keys.h"
47 #include "sigstatus.h"
48 #include "rfc2015.h"
49
50 #include "pgptext.h"
51
52 #define DIM(v)     (sizeof(v)/sizeof((v)[0]))
53
54 static char *content_names[] = {
55     "Content-Type",
56     "Content-Disposition",
57     "Content-Transfer-Encoding",
58     NULL
59 };
60
61 static char *mime_version_name[] = {
62     "Mime-Version",
63     NULL
64 };
65
66 /* stolen from rfc2015.c */
67 static int
68 gpg_name_cmp(const char *a, const char *b)
69 {
70     for( ; *a && *b; a++, b++) {
71         if(*a != *b
72            && toupper(*(unsigned char *)a) != toupper(*(unsigned char *)b))
73             return 1;
74     }
75
76     return *a != *b;
77 }
78
79 static GpgmeData
80 pgptext_decrypt (MimeInfo *partinfo, FILE *fp)
81 {
82     GpgmeCtx ctx = NULL;
83     GpgmeError err;
84     GpgmeData cipher = NULL, plain = NULL;
85     struct passphrase_cb_info_s info;
86
87     memset (&info, 0, sizeof info);
88
89     err = gpgme_new (&ctx);
90     if (err) {
91         debug_print ("gpgme_new failed: %s\n", gpgme_strerror (err));
92         goto leave;
93     }
94
95     err = gpgme_data_new_from_filepart (&cipher, NULL, fp,
96                                         partinfo->fpos, partinfo->size);
97     if (err) {
98         debug_print ("gpgme_data_new_from_filepart failed: %s\n",
99                      gpgme_strerror (err));
100         goto leave;
101     }
102
103     err = gpgme_data_new (&plain);
104     if (err) {
105         debug_print ("gpgme_new failed: %s\n", gpgme_strerror (err));
106         goto leave;
107     }
108
109     if (!getenv("GPG_AGENT_INFO")) {
110         info.c = ctx;
111         gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
112     } 
113
114     err = gpgme_op_decrypt (ctx, cipher, plain);
115
116 leave:
117     gpgme_data_release (cipher);
118     if (err) {
119         gpgmegtk_free_passphrase();
120         debug_print ("decryption failed: %s\n", gpgme_strerror (err));
121         gpgme_data_release (plain);
122         plain = NULL;
123     }
124     else
125         debug_print ("decryption succeeded\n");
126
127     gpgme_release (ctx);
128     return plain;
129 }
130
131 static int
132 headerp(char *p, char **names)
133 {
134     int i, c;
135     char *p2;
136
137     p2 = strchr(p, ':');
138     if(!p2 || p == p2) {
139         return 0;
140     }
141     if(p2[-1] == ' ' || p2[-1] == '\t') {
142         return 0;
143     }
144
145     if(!names[0])
146         return 1;  
147
148     c = *p2;
149     *p2 = 0;
150     for(i = 0 ; names[i] != NULL; i++) {
151         if(!gpg_name_cmp (names[i], p))
152             break;
153     }
154     *p2 = c;
155
156     return names[i] != NULL;
157 }
158
159 MimeInfo * pgptext_find_signature (MimeInfo *mimeinfo)
160 {
161 }
162
163 gboolean pgptext_has_signature (MimeInfo *mimeinfo)
164 {
165         /*
166          * check for the following strings:
167          *   -----BEGIN PGP SIGNED MESSAGE-----
168          *   ----- ????
169          *   -----BEGIN PGP SIGNATURE-----
170          *   -----END PGP SIGNATURE-----
171          */
172         
173         return 0;
174 }
175
176 void pgptext_check_signature (MimeInfo *mimeinfo, FILE *fp)
177 {
178 }
179
180 int pgptext_is_encrypted (MimeInfo *mimeinfo, MsgInfo *msginfo)
181 {
182         FILE *fp;
183         gchar *file, *tmpchk;
184         gchar buf[BUFFSIZE];
185         gboolean has_begin_pgp_msg = FALSE;
186         gboolean has_end_pgp_msg = FALSE;
187         gchar *check_begin_pgp_msg = "-----BEGIN PGP MESSAGE-----\n";
188         gchar *check_end_pgp_msg = "-----END PGP MESSAGE-----\n";
189         
190         g_return_if_fail(msginfo != NULL);
191         
192         if (!mimeinfo)
193                 return 0;
194         
195         if ((fp = procmsg_open_message(msginfo)) == NULL) return;
196         mimeinfo = procmime_scan_mime_header(fp);
197         fclose(fp);
198         if (!mimeinfo) return;
199
200         file = procmsg_get_message_file_path(msginfo);
201         g_return_if_fail(file != NULL);
202
203         if (mimeinfo->mime_type != MIME_TEXT) {
204                 if ((fp = fopen(file, "rb")) == NULL) {
205                         FILE_OP_ERROR(file, "fopen");
206                         return;
207                 }
208                 /* skip headers */
209                 if (mimeinfo->mime_type == MIME_MULTIPART) {
210                         if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
211                         perror("fseek");
212                         while (fgets(buf, sizeof(buf), fp) != NULL)
213                                 if (buf[0] == '\r' || buf[0] == '\n') break;
214                 }
215                 /* now check for a pgptext encrypted message */
216                 while (fgets(buf, sizeof(buf), fp) != NULL) {
217                         tmpchk = g_strnfill(sizeof(buf), '\n');
218                         memmove(tmpchk, &buf, sizeof(buf));
219                         
220                         if (strstr(tmpchk, check_begin_pgp_msg) != NULL)
221                                 has_begin_pgp_msg = TRUE;
222                         if (strstr(tmpchk, check_end_pgp_msg) != NULL)
223                                 has_end_pgp_msg = TRUE;
224                         
225                         g_free(tmpchk);
226                 }
227                 fclose(fp);
228         } else {
229                 if ((fp = fopen(file, "rb")) == NULL) {
230                         FILE_OP_ERROR(file, "fopen");
231                         return;
232                 }
233                 /* skip headers */
234                 if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
235                 perror("fseek");
236                 while (fgets(buf, sizeof(buf), fp) != NULL)
237                         if (buf[0] == '\r' || buf[0] == '\n') break;
238                 
239                 /* now check for a pgptext encrypted message */
240                 while (fgets(buf, sizeof(buf), fp) != NULL) {
241                         tmpchk = g_strnfill(sizeof(buf), '\n');
242                         memmove(tmpchk, &buf, sizeof(buf));
243                         
244                         if (strstr(tmpchk, check_begin_pgp_msg) != NULL)
245                                 has_begin_pgp_msg = TRUE;
246                         if (strstr(tmpchk, check_end_pgp_msg) != NULL)
247                                 has_end_pgp_msg = TRUE;
248                         
249                         g_free(tmpchk);
250                 }
251                 fclose(fp);
252         }
253         
254         g_free(file);   
255         
256         /* do we have a proper message? */
257         if (has_begin_pgp_msg && has_end_pgp_msg)
258                 return 1;
259         else
260                 return 0;
261 }
262
263 void pgptext_decrypt_message (MsgInfo *msginfo, MimeInfo *mimeinfo, FILE *fp)
264 {
265     static int id;
266     MimeInfo *partinfo;
267     int n, found;
268     int ver_okay=0;
269     char *fname;
270     GpgmeData plain;
271     FILE *dstfp;
272     size_t nread;
273     char buf[BUFFSIZE];
274     GpgmeError err;
275
276     g_return_if_fail (mimeinfo->mime_type == MIME_TEXT);
277
278     debug_print ("text/plain with pgptext encountered\n");
279
280     partinfo = procmime_scan_message(msginfo);
281                 
282     /* skip headers */
283     if (fseek(fp, partinfo->fpos, SEEK_SET) < 0)
284         perror("fseek");
285     while (fgets(buf, sizeof(buf), fp) != NULL) {
286                                 partinfo->fpos = partinfo->fpos + strlen(buf);
287         if (buf[0] == '\r' || buf[0] == '\n') break;
288                 }
289     /* get size */
290     while (fgets(buf, sizeof(buf), fp) != NULL)
291                                 partinfo->size = partinfo->size + strlen(buf);
292                 
293     plain = pgptext_decrypt (partinfo, fp);
294     if (!plain) {
295         msginfo->decryption_failed = 1;
296         return;
297     }
298     
299     fname = g_strdup_printf("%s%cplaintext.%08x",
300                             get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);
301
302     if ((dstfp = fopen(fname, "wb")) == NULL) {
303         FILE_OP_ERROR(fname, "fopen");
304         g_free(fname);
305         msginfo->decryption_failed = 1;
306         return;
307     }
308
309     /* write the orginal header to the new file */
310     if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
311         perror("fseek");
312
313     while (fgets(buf, sizeof(buf), fp)) {
314         if (headerp (buf, content_names))
315             continue;
316         if (buf[0] == '\r' || buf[0] == '\n')
317             break;
318         fputs (buf, dstfp);
319     }
320                 
321     err = gpgme_data_rewind (plain);
322     if (err)
323         debug_print ("gpgme_data_rewind failed: %s\n", gpgme_strerror (err));
324
325                 /* insert blank line to avoid some trouble... */
326                 fputs ("\n", dstfp);
327                 
328     while (!(err = gpgme_data_read (plain, buf, sizeof(buf), &nread))) {
329         fwrite (buf, nread, 1, dstfp);
330     }
331
332     if (err != GPGME_EOF) {
333         debug_print ("gpgme_data_read failed: %s\n", gpgme_strerror (err));
334     }
335
336     fclose (dstfp);
337
338     msginfo->plaintext_file = fname;
339     msginfo->decryption_failed = 0;
340
341 }
342
343 int pgptext_encrypt (const char *file, GSList *recp_list)
344 {
345 }
346
347 int pgptext_sign (const char *file, PrefsAccount *ac)
348 {
349 }
350
351 #endif  /* USE_GPGME */
352