This commit was manufactured by cvs2svn to create tag 'LAST_STABLE'.
[claws.git] / src / pgptext.c
blobfd46b6551ff0b16c11a41400068e7799404e0577
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001 Jens Jahnke <jan0sch@gmx.net>
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.
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.
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.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
24 #if USE_GPGME
26 #include "defs.h"
28 #include <glib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <locale.h>
32 #include <ctype.h>
34 #include <gpgme.h>
36 #include "intl.h"
37 #include "utils.h"
38 #include "passphrase.h"
39 #include "rfc2015.h"
41 #include "pgptext.h"
43 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
45 static char *content_names[] = {
46 "Content-Type",
47 "Content-Disposition",
48 "Content-Transfer-Encoding",
49 NULL
52 /* stolen from rfc2015.c */
53 static int
54 gpg_name_cmp(const char *a, const char *b)
56 for( ; *a && *b; a++, b++) {
57 if(*a != *b
58 && toupper(*(unsigned char *)a) != toupper(*(unsigned char *)b))
59 return 1;
62 return *a != *b;
65 static GpgmeData
66 pgptext_decrypt (MimeInfo *partinfo, FILE *fp)
68 GpgmeCtx ctx = NULL;
69 GpgmeError err;
70 GpgmeData cipher = NULL, plain = NULL;
71 struct passphrase_cb_info_s info;
73 memset (&info, 0, sizeof info);
75 err = gpgme_new (&ctx);
76 if (err) {
77 debug_print ("gpgme_new failed: %s\n", gpgme_strerror (err));
78 goto leave;
81 err = gpgme_data_new_from_filepart (&cipher, NULL, fp,
82 partinfo->fpos, partinfo->size);
83 if (err) {
84 debug_print ("gpgme_data_new_from_filepart failed: %s\n",
85 gpgme_strerror (err));
86 goto leave;
89 err = gpgme_data_new (&plain);
90 if (err) {
91 debug_print ("gpgme_new failed: %s\n", gpgme_strerror (err));
92 goto leave;
95 if (!getenv("GPG_AGENT_INFO")) {
96 info.c = ctx;
97 gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, (void *)&info);
100 err = gpgme_op_decrypt (ctx, cipher, plain);
102 leave:
103 gpgme_data_release (cipher);
104 if (err) {
105 gpgmegtk_free_passphrase();
106 debug_print ("decryption failed: %s\n", gpgme_strerror (err));
107 gpgme_data_release (plain);
108 plain = NULL;
110 else
111 debug_print ("decryption succeeded\n");
113 gpgme_release (ctx);
114 return plain;
117 static int
118 headerp(char *p, char **names)
120 int i, c;
121 char *p2;
123 p2 = strchr(p, ':');
124 if(!p2 || p == p2) {
125 return 0;
127 if(p2[-1] == ' ' || p2[-1] == '\t') {
128 return 0;
131 if(!names[0])
132 return 1;
134 c = *p2;
135 *p2 = 0;
136 for(i = 0 ; names[i] != NULL; i++) {
137 if(!gpg_name_cmp (names[i], p))
138 break;
140 *p2 = c;
142 return names[i] != NULL;
145 MimeInfo * pgptext_find_signature (MimeInfo *mimeinfo)
147 return NULL;
150 gboolean pgptext_has_signature (MimeInfo *mimeinfo)
153 * check for the following strings:
154 * -----BEGIN PGP SIGNED MESSAGE-----
155 * ----- ????
156 * -----BEGIN PGP SIGNATURE-----
157 * -----END PGP SIGNATURE-----
160 return 0;
163 void pgptext_check_signature (MimeInfo *mimeinfo, FILE *fp)
167 int pgptext_is_encrypted (MimeInfo *mimeinfo, MsgInfo *msginfo)
169 FILE *fp;
170 gchar *file, *tmpchk;
171 gchar buf[BUFFSIZE];
172 gboolean has_begin_pgp_msg = FALSE;
173 gboolean has_end_pgp_msg = FALSE;
174 gchar *check_begin_pgp_msg = "-----BEGIN PGP MESSAGE-----\n";
175 gchar *check_end_pgp_msg = "-----END PGP MESSAGE-----\n";
177 g_return_val_if_fail(msginfo != NULL, 0);
179 if (!mimeinfo)
180 return 0;
182 if ((fp = procmsg_open_message(msginfo)) == NULL) return 0;
183 mimeinfo = procmime_scan_mime_header(fp);
184 fclose(fp);
185 if (!mimeinfo) return 0;
187 file = procmsg_get_message_file_path(msginfo);
188 g_return_val_if_fail(file != NULL, 0);
190 if (mimeinfo->mime_type != MIME_TEXT) {
191 if ((fp = fopen(file, "rb")) == NULL) {
192 FILE_OP_ERROR(file, "fopen");
193 g_free(file);
194 return 0;
196 /* skip headers */
197 if (mimeinfo->mime_type == MIME_MULTIPART) {
198 if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
199 perror("fseek");
200 while (fgets(buf, sizeof(buf), fp) != NULL)
201 if (buf[0] == '\r' || buf[0] == '\n') break;
203 /* now check for a pgptext encrypted message */
204 while (fgets(buf, sizeof(buf), fp) != NULL) {
205 tmpchk = g_strnfill(sizeof(buf), '\n');
206 memmove(tmpchk, &buf, sizeof(buf));
208 if (strstr(tmpchk, check_begin_pgp_msg) != NULL)
209 has_begin_pgp_msg = TRUE;
210 if (strstr(tmpchk, check_end_pgp_msg) != NULL)
211 has_end_pgp_msg = TRUE;
213 g_free(tmpchk);
215 fclose(fp);
216 } else {
217 if ((fp = fopen(file, "rb")) == NULL) {
218 FILE_OP_ERROR(file, "fopen");
219 g_free(file);
220 return 0;
222 /* skip headers */
223 if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
224 perror("fseek");
225 while (fgets(buf, sizeof(buf), fp) != NULL)
226 if (buf[0] == '\r' || buf[0] == '\n') break;
228 /* now check for a pgptext encrypted message */
229 while (fgets(buf, sizeof(buf), fp) != NULL) {
230 tmpchk = g_strnfill(sizeof(buf), '\n');
231 memmove(tmpchk, &buf, sizeof(buf));
233 if (strstr(tmpchk, check_begin_pgp_msg) != NULL)
234 has_begin_pgp_msg = TRUE;
235 if (strstr(tmpchk, check_end_pgp_msg) != NULL)
236 has_end_pgp_msg = TRUE;
238 g_free(tmpchk);
240 fclose(fp);
243 g_free(file);
245 /* do we have a proper message? */
246 if (has_begin_pgp_msg && has_end_pgp_msg)
247 return 1;
248 else
249 return 0;
252 void pgptext_decrypt_message (MsgInfo *msginfo, MimeInfo *mimeinfo, FILE *fp)
254 static int id;
255 MimeInfo *partinfo;
256 char *fname;
257 GpgmeData plain;
258 FILE *dstfp;
259 size_t nread;
260 char buf[BUFFSIZE];
261 GpgmeError err;
263 g_return_if_fail (mimeinfo->mime_type == MIME_TEXT);
265 debug_print ("text/plain with pgptext encountered\n");
267 partinfo = procmime_scan_message(msginfo);
269 /* skip headers */
270 if (fseek(fp, partinfo->fpos, SEEK_SET) < 0)
271 perror("fseek");
272 while (fgets(buf, sizeof(buf), fp) != NULL) {
273 partinfo->fpos = partinfo->fpos + strlen(buf);
274 if (buf[0] == '\r' || buf[0] == '\n') break;
276 /* get size */
277 while (fgets(buf, sizeof(buf), fp) != NULL)
278 partinfo->size = partinfo->size + strlen(buf);
280 plain = pgptext_decrypt (partinfo, fp);
281 if (!plain) {
282 msginfo->decryption_failed = 1;
283 return;
286 fname = g_strdup_printf("%s%cplaintext.%08x",
287 get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);
289 if ((dstfp = fopen(fname, "wb")) == NULL) {
290 FILE_OP_ERROR(fname, "fopen");
291 g_free(fname);
292 msginfo->decryption_failed = 1;
293 return;
296 /* write the orginal header to the new file */
297 if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
298 perror("fseek");
300 while (fgets(buf, sizeof(buf), fp)) {
301 if (headerp (buf, content_names))
302 continue;
303 if (buf[0] == '\r' || buf[0] == '\n')
304 break;
305 fputs (buf, dstfp);
308 err = gpgme_data_rewind (plain);
309 if (err)
310 debug_print ("gpgme_data_rewind failed: %s\n", gpgme_strerror (err));
312 /* insert blank line to avoid some trouble... */
313 fputs ("\n", dstfp);
315 while (!(err = gpgme_data_read (plain, buf, sizeof(buf), &nread))) {
316 fwrite (buf, nread, 1, dstfp);
319 if (err != GPGME_EOF) {
320 debug_print ("gpgme_data_read failed: %s\n", gpgme_strerror (err));
323 fclose (dstfp);
325 msginfo->plaintext_file = fname;
326 msginfo->decryption_failed = 0;
330 int pgptext_encrypt (const char *file, GSList *recp_list)
332 return 0;
335 int pgptext_sign (const char *file, PrefsAccount *ac)
337 return 0;
340 #endif /* USE_GPGME */