b1c76d02a47b0be4cd49d95cc86729c56d52ef90
[claws.git] / src / pgpmime.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2003 Hiroyuki Yamamoto & the Sylpheed-Claws team
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 #ifdef USE_GPGME
25
26 #include "defs.h"
27 #include <glib.h>
28 #include <gpgme.h>
29
30 #include "utils.h"
31 #include "privacy.h"
32 #include "procmime.h"
33 #include "pgpmime.h"
34 #include "sgpgme.h"
35
36 typedef struct _PrivacyDataPGP PrivacyDataPGP;
37
38 struct _PrivacyDataPGP
39 {
40         PrivacyData     data;
41         
42         gboolean        done_sigtest;
43         gboolean        is_signed;
44         GpgmeSigStat    sigstatus;
45         GpgmeCtx        ctx;
46 };
47
48 static PrivacySystem pgpmime_system;
49
50 static PrivacyDataPGP *pgpmime_new_privacydata()
51 {
52         PrivacyDataPGP *data;
53
54         data = g_new0(PrivacyDataPGP, 1);
55         data->data.system = &pgpmime_system;
56         data->done_sigtest = FALSE;
57         data->is_signed = FALSE;
58         data->sigstatus = GPGME_SIG_STAT_NONE;
59         gpgme_new(&data->ctx);
60         
61         return data;
62 }
63
64 static void pgpmime_free_privacydata(PrivacyData *_data)
65 {
66         PrivacyDataPGP *data = (PrivacyDataPGP *) _data;
67         
68         g_free(data);
69 }
70
71 static gboolean pgpmime_is_signed(MimeInfo *mimeinfo)
72 {
73         MimeInfo *parent;
74         MimeInfo *signature;
75         gchar *protocol;
76         PrivacyDataPGP *data = NULL;
77         
78         g_return_val_if_fail(mimeinfo != NULL, FALSE);
79         if (mimeinfo->privacy != NULL) {
80                 data = (PrivacyDataPGP *) mimeinfo->privacy;
81                 if (data->done_sigtest)
82                         return data->is_signed;
83         }
84         
85         /* check parent */
86         parent = procmime_mimeinfo_parent(mimeinfo);
87         if (parent == NULL)
88                 return FALSE;
89         if ((parent->type != MIMETYPE_MULTIPART) ||
90             g_strcasecmp(parent->subtype, "signed"))
91                 return FALSE;
92         protocol = g_hash_table_lookup(parent->parameters, "protocol");
93         if ((protocol == NULL) || g_strcasecmp(protocol, "application/pgp-signature"))
94                 return FALSE;
95
96         /* check if mimeinfo is the first child */
97         if (parent->node->children->data != mimeinfo)
98                 return FALSE;
99
100         /* check signature */
101         signature = parent->node->children->next != NULL ? 
102             (MimeInfo *) parent->node->children->next->data : NULL;
103         if (signature == NULL)
104                 return FALSE;
105         if ((signature->type != MIMETYPE_APPLICATION) ||
106             g_strcasecmp(signature->subtype, "pgp-signature"))
107                 return FALSE;
108
109         if (data == NULL) {
110                 data = pgpmime_new_privacydata();
111                 mimeinfo->privacy = (PrivacyData *) data;
112         }
113         data->done_sigtest = TRUE;
114         data->is_signed = TRUE;
115         
116         return TRUE;
117 }
118
119 static gint pgpmime_check_signature(MimeInfo *mimeinfo)
120 {
121         PrivacyDataPGP *data;
122         MimeInfo *parent, *signature;
123         FILE *fp;
124         gchar buf[BUFFSIZE];
125         gchar *boundary;
126         GString *textstr;
127         gint boundary_len;
128         GpgmeData sigdata, textdata;
129         
130         g_return_val_if_fail(mimeinfo != NULL, -1);
131         g_return_val_if_fail(mimeinfo->privacy != NULL, -1);
132         data = (PrivacyDataPGP *) mimeinfo->privacy;
133         
134         debug_print("Checking PGP/MIME signature\n");
135         parent = procmime_mimeinfo_parent(mimeinfo);
136
137         fp = fopen(parent->filename, "rb");
138         g_return_val_if_fail(fp != NULL, SIGNATURE_INVALID);
139         
140         boundary = g_hash_table_lookup(parent->parameters, "boundary");
141         boundary_len = strlen(boundary);
142         while (fgets(buf, sizeof(buf), fp) != NULL)
143                 if (IS_BOUNDARY(buf, boundary, boundary_len))
144                         break;
145
146         textstr = g_string_new("");
147         while (fgets(buf, sizeof(buf), fp) != NULL) {
148                 gchar *buf2;
149
150                 if (IS_BOUNDARY(buf, boundary, boundary_len))
151                         break;
152                 
153                 buf2 = canonicalize_str(buf);
154                 g_string_append(textstr, buf2);
155                 g_free(buf2);
156         }
157         g_string_truncate(textstr, textstr->len - 2);
158         
159         
160         gpgme_data_new_from_mem(&textdata, textstr->str, textstr->len, 0);
161         signature = (MimeInfo *) mimeinfo->node->next->data;
162         gpgme_data_new_from_filepart(&sigdata,
163                 signature->filename,
164                 NULL,
165                 signature->offset,
166                 signature->length);
167
168         data->sigstatus =
169                 sgpgme_verify_signature (data->ctx, sigdata, textdata);
170         
171         gpgme_data_release(sigdata);
172         gpgme_data_release(textdata);
173         g_string_free(textstr, TRUE);
174         
175         printf("result: %d\n", data->sigstatus);
176         
177         return 0;
178 }
179
180 static SignatureStatus pgpmime_get_sig_status(MimeInfo *mimeinfo)
181 {
182         PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
183         
184         g_return_val_if_fail(data != NULL, SIGNATURE_INVALID);
185
186         return sgpgme_sigstat_gpgme_to_privacy(data->sigstatus);
187 }
188
189 static gchar *pgpmime_get_sig_info_short(MimeInfo *mimeinfo)
190 {
191         PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
192         
193         g_return_val_if_fail(data != NULL, g_strdup("Error"));
194
195         return sgpgme_sigstat_info_short(data->ctx, data->sigstatus);
196 }
197
198 static PrivacySystem pgpmime_system = {
199         "PGP/Mime",                     /* name */
200
201         pgpmime_free_privacydata,       /* free_privacydata */
202
203         pgpmime_is_signed,              /* is_signed(MimeInfo *) */
204         pgpmime_check_signature,        /* check_signature(MimeInfo *) */
205         pgpmime_get_sig_status,         /* get_sig_status(MimeInfo *) */
206         pgpmime_get_sig_info_short,     /* get_sig_info_short(MimeInfo *) */
207         NULL,                           /* get_sig_info_full(MimeInfo *) */
208
209         /* NOT YET */
210         NULL,                           /* is_encrypted(MimeInfo *) */
211         NULL,                           /* decrypt(MimeInfo *) */
212 };
213
214 void pgpmime_init()
215 {
216         privacy_register_system(&pgpmime_system);
217 }
218
219 void pgpmime_done()
220 {
221         privacy_unregister_system(&pgpmime_system);
222 }
223
224 #endif /* USE_GPGME */