Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[platform/upstream/evolution-data-server.git] / camel / camel-mime-filter-pgp.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  *
5  * Authors: Matt Brown <matt@mattb.net.nz>
6  *          Jeffrey Stedfast <fejj@novell.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /* Strips PGP message headers from the input stream and also performs
24  * pgp decoding as described in section 7.1 of RFC2440 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <ctype.h>
31 #include <string.h>
32
33 #include "camel-mime-filter-pgp.h"
34
35 #define CAMEL_MIME_FILTER_PGP_GET_PRIVATE(obj) \
36         (G_TYPE_INSTANCE_GET_PRIVATE \
37         ((obj), CAMEL_TYPE_MIME_FILTER_PGP, CamelMimeFilterPgpPrivate))
38
39 #define BEGIN_PGP_SIGNED_MESSAGE "-----BEGIN PGP SIGNED MESSAGE-----"
40 #define BEGIN_PGP_SIGNATURE      "-----BEGIN PGP SIGNATURE-----"
41 #define END_PGP_SIGNATURE        "-----END PGP SIGNATURE-----"
42
43 #define BEGIN_PGP_SIGNED_MESSAGE_LEN (sizeof (BEGIN_PGP_SIGNED_MESSAGE) - 1)
44 #define BEGIN_PGP_SIGNATURE_LEN      (sizeof (BEGIN_PGP_SIGNATURE) - 1)
45 #define END_PGP_SIGNATURE_LEN        (sizeof (END_PGP_SIGNATURE) - 1)
46
47 struct _CamelMimeFilterPgpPrivate {
48         gint state;
49 };
50
51 enum {
52         PGP_PREFACE,
53         PGP_HEADER,
54         PGP_MESSAGE,
55         PGP_FOOTER
56 };
57
58 G_DEFINE_TYPE (CamelMimeFilterPgp, camel_mime_filter_pgp, CAMEL_TYPE_MIME_FILTER)
59
60 static void
61 mime_filter_pgp_run (CamelMimeFilter *mime_filter,
62                      const gchar *in,
63                      gsize inlen,
64                      gsize prespace,
65                      gchar **out,
66                      gsize *outlen,
67                      gsize *outprespace,
68                      gint last)
69 {
70         CamelMimeFilterPgpPrivate *priv;
71         const gchar *start, *inend = in + inlen;
72         register const gchar *inptr = in;
73         register gchar *o;
74         gboolean blank;
75         gsize len;
76
77         priv = CAMEL_MIME_FILTER_PGP_GET_PRIVATE (mime_filter);
78
79         /* only need as much space as the input, we're stripping chars */
80         camel_mime_filter_set_size (mime_filter, inlen, FALSE);
81
82         o = mime_filter->outbuf;
83
84         while (inptr < inend) {
85                 start = inptr;
86
87                 blank = TRUE;
88                 while (inptr < inend && *inptr != '\n') {
89                         if (blank && !strchr (" \t\r", *inptr))
90                                 blank = FALSE;
91                         inptr++;
92                 }
93
94                 if (inptr == inend) {
95                         if (!last) {
96                                 camel_mime_filter_backup (mime_filter, start, inend - start);
97                                 inend = start;
98                         }
99                         break;
100                 }
101
102                 len = inptr - start;
103                 if (len > 0 && inptr[-1] == '\r')
104                         len--;
105
106                 inptr++;
107
108                 switch (priv->state) {
109                 case PGP_PREFACE:
110                         /* check for the beginning of the pgp block */
111                         if (len == BEGIN_PGP_SIGNED_MESSAGE_LEN && !strncmp (start, BEGIN_PGP_SIGNED_MESSAGE, len)) {
112                                 priv->state++;
113                                 break;
114                         }
115
116                         memcpy (o, start, inptr - start);
117                         o += (inptr - start);
118                         break;
119                 case PGP_HEADER:
120                         /* pgp headers (Hash: SHA1, etc) end with a blank (zero-length,
121                          * or containing only whitespace) line; see RFC2440 */
122                         if (blank)
123                                 priv->state++;
124                         break;
125                 case PGP_MESSAGE:
126                         /* check for beginning of the pgp signature block */
127                         if (len == BEGIN_PGP_SIGNATURE_LEN && !strncmp (start, BEGIN_PGP_SIGNATURE, len)) {
128                                 priv->state++;
129                                 break;
130                         }
131
132                         /* do dash decoding */
133                         if (!strncmp (start, "- ", 2)) {
134                                 /* Dash encoded line found, skip encoding */
135                                 start += 2;
136                         }
137
138                         memcpy (o, start, inptr - start);
139                         o += (inptr - start);
140                         break;
141                 case PGP_FOOTER:
142                         if (len == END_PGP_SIGNATURE_LEN && !strncmp (start, END_PGP_SIGNATURE, len))
143                                 priv->state = PGP_PREFACE;
144                         break;
145                 }
146         }
147
148         *out = mime_filter->outbuf;
149         *outlen = o - mime_filter->outbuf;
150         *outprespace = mime_filter->outpre;
151 }
152
153 static void
154 mime_filter_pgp_filter (CamelMimeFilter *mime_filter,
155                         const gchar *in,
156                         gsize len,
157                         gsize prespace,
158                         gchar **out,
159                         gsize *outlen,
160                         gsize *outprespace)
161 {
162         mime_filter_pgp_run (
163                 mime_filter, in, len, prespace,
164                 out, outlen, outprespace, FALSE);
165 }
166
167 static void
168 mime_filter_pgp_complete (CamelMimeFilter *mime_filter,
169                           const gchar *in,
170                           gsize len,
171                           gsize prespace,
172                           gchar **out,
173                           gsize *outlen,
174                           gsize *outprespace)
175 {
176         mime_filter_pgp_run (
177                 mime_filter, in, len, prespace,
178                 out, outlen, outprespace, TRUE);
179 }
180
181 static void
182 mime_filter_pgp_reset (CamelMimeFilter *mime_filter)
183 {
184         CamelMimeFilterPgpPrivate *priv;
185
186         priv = CAMEL_MIME_FILTER_PGP_GET_PRIVATE (mime_filter);
187
188         priv->state = PGP_PREFACE;
189 }
190
191 static void
192 camel_mime_filter_pgp_class_init (CamelMimeFilterPgpClass *class)
193 {
194         CamelMimeFilterClass *mime_filter_class;
195
196         g_type_class_add_private (class, sizeof (CamelMimeFilterPgpPrivate));
197
198         mime_filter_class = CAMEL_MIME_FILTER_CLASS (class);
199         mime_filter_class->filter = mime_filter_pgp_filter;
200         mime_filter_class->complete = mime_filter_pgp_complete;
201         mime_filter_class->reset = mime_filter_pgp_reset;
202 }
203
204 static void
205 camel_mime_filter_pgp_init (CamelMimeFilterPgp *filter)
206 {
207         filter->priv = CAMEL_MIME_FILTER_PGP_GET_PRIVATE (filter);
208 }
209
210 CamelMimeFilter *
211 camel_mime_filter_pgp_new (void)
212 {
213         return g_object_new (CAMEL_TYPE_MIME_FILTER_PGP, NULL);
214 }