Fix FSF address (Tobias Mueller, #470445)
[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) 2005 Matt Brown.
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 static void filter (CamelMimeFilter *f, char *in, size_t len, size_t prespace,
36                     char **out, size_t *outlen, size_t *outprespace);
37 static void complete (CamelMimeFilter *f, char *in, size_t len,
38                       size_t prespace, char **out, size_t *outlen,
39                       size_t *outprespace);
40 static void reset (CamelMimeFilter *f);
41
42 enum {
43         PGP_PREFACE,
44         PGP_HEADER,
45         PGP_MESSAGE,
46         PGP_FOOTER,
47 };
48
49 static void
50 camel_mime_filter_pgp_class_init (CamelMimeFilterPgpClass *klass)
51 {
52         CamelMimeFilterClass *mime_filter_class = (CamelMimeFilterClass *) klass;
53         
54         mime_filter_class->filter = filter;
55         mime_filter_class->complete = complete;
56         mime_filter_class->reset = reset;
57 }
58
59 CamelType
60 camel_mime_filter_pgp_get_type (void)
61 {
62         static CamelType type = CAMEL_INVALID_TYPE;
63         
64         if (type == CAMEL_INVALID_TYPE) {
65                 type = camel_type_register (camel_mime_filter_get_type (),
66                                             "CamelMimeFilterPgp",
67                                             sizeof (CamelMimeFilterPgp),
68                                             sizeof (CamelMimeFilterPgpClass),
69                                             (CamelObjectClassInitFunc) camel_mime_filter_pgp_class_init,
70                                             NULL,
71                                             NULL,
72                                             NULL);
73         }
74         
75         return type;
76 }
77
78 #define BEGIN_PGP_SIGNED_MESSAGE "-----BEGIN PGP SIGNED MESSAGE-----"
79 #define BEGIN_PGP_SIGNATURE      "-----BEGIN PGP SIGNATURE-----"
80 #define END_PGP_SIGNATURE        "-----END PGP SIGNATURE-----"
81
82 static void
83 filter_run(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace, int last)
84 {
85         CamelMimeFilterPgp *pgp = (CamelMimeFilterPgp *) f;
86         const char *start, *inend = in + len;
87         register const char *inptr = in;
88         register char *o;
89         
90         /* only need as much space as the input, we're stripping chars */
91         camel_mime_filter_set_size (f, len, FALSE);
92         
93         o = f->outbuf;
94         
95         while (inptr < inend) {
96                 start = inptr;
97                 
98                 while (inptr < inend && *inptr != '\n')
99                         inptr++;
100                 
101                 if (inptr == inend) {
102                         if (!last) {
103                                 camel_mime_filter_backup (f, start, inend - start);
104                                 inend = start;
105                         }
106                         break;
107                 }
108                 
109                 inptr++;
110                 
111                 switch (pgp->state) {
112                 case PGP_PREFACE:
113                         /* check for the beginning of the pgp block */
114                         if (!strncmp (start, BEGIN_PGP_SIGNED_MESSAGE, sizeof (BEGIN_PGP_SIGNED_MESSAGE) - 1)) {
115                                 pgp->state++;
116                                 break;
117                         }
118                         
119                         memcpy (o, start, inptr - start);
120                         o += (inptr - start);
121                         break;
122                 case PGP_HEADER:
123                         /* pgp headers (Hash: SHA1, etc) end with a blank (zero-length,
124                            or containing only whitespace) line; see RFC2440 */
125                         if ((inptr - start) == 1 || ((inptr - start) == 2 && *(inptr - 2) == 0x20))
126                                 pgp->state++;
127                         break;
128                 case PGP_MESSAGE:
129                         /* check for beginning of the pgp signature block */
130                         if (!strncmp (start, BEGIN_PGP_SIGNATURE, sizeof (BEGIN_PGP_SIGNATURE) - 1)) {
131                                 pgp->state++;
132                                 break;
133                         }
134                         
135                         /* do dash decoding */
136                         if (!strncmp (start, "- ", 2)) {
137                                 /* Dash encoded line found, skip encoding */
138                                 start += 2;
139                         }
140                         
141                         memcpy (o, start, inptr - start);
142                         o += (inptr - start);
143                         break;
144                 case PGP_FOOTER:
145                         if (!strncmp (start, END_PGP_SIGNATURE, sizeof (END_PGP_SIGNATURE) - 1))
146                                 pgp->state = PGP_PREFACE;
147                         break;
148                 }
149         }
150         
151         *out = f->outbuf;
152         *outlen = o - f->outbuf;
153         *outprespace = f->outpre;
154 }
155
156 static void
157 filter (CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
158 {
159         filter_run (f, in, len, prespace, out, outlen, outprespace, FALSE);
160 }
161
162 static void 
163 complete (CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
164 {
165         filter_run (f, in, len, prespace, out, outlen, outprespace, TRUE);
166 }
167
168 static void
169 reset (CamelMimeFilter *f)
170 {
171         ((CamelMimeFilterPgp *) f)->state = PGP_PREFACE;
172 }
173
174 CamelMimeFilter *
175 camel_mime_filter_pgp_new(void)
176 {
177         return (CamelMimeFilter *) camel_object_new (camel_mime_filter_pgp_get_type ());
178 }