Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-filter-from.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*  GMime
3  *  Copyright (C) 2000-2012 Jeffrey Stedfast
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public License
7  *  as published by the Free Software Foundation; either version 2.1
8  *  of the License, or (at your option) any later version.
9  *
10  *  This library 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 GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free
17  *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
18  *  02110-1301, USA.
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include "gmime-filter-from.h"
29
30
31 /**
32  * SECTION: gmime-filter-from
33  * @title: GMimeFilterFrom
34  * @short_description: Escape MBox From_ lines
35  * @see_also: #GMimeFilter
36  *
37  * A #GMimeFilter used for escaping MBox From_ lines using either the
38  * traditional ">From " or quoted-printable encoding.
39  **/
40
41
42 static void g_mime_filter_from_class_init (GMimeFilterFromClass *klass);
43 static void g_mime_filter_from_init (GMimeFilterFrom *filter, GMimeFilterFromClass *klass);
44 static void g_mime_filter_from_finalize (GObject *object);
45
46 static GMimeFilter *filter_copy (GMimeFilter *filter);
47 static void filter_filter (GMimeFilter *filter, char *in, size_t len, 
48                            size_t prespace, char **out, 
49                            size_t *outlen, size_t *outprespace);
50 static void filter_complete (GMimeFilter *filter, char *in, size_t len, 
51                              size_t prespace, char **out, 
52                              size_t *outlen, size_t *outprespace);
53 static void filter_reset (GMimeFilter *filter);
54
55
56 static GMimeFilterClass *parent_class = NULL;
57
58
59 GType
60 g_mime_filter_from_get_type (void)
61 {
62         static GType type = 0;
63         
64         if (!type) {
65                 static const GTypeInfo info = {
66                         sizeof (GMimeFilterFromClass),
67                         NULL, /* base_class_init */
68                         NULL, /* base_class_finalize */
69                         (GClassInitFunc) g_mime_filter_from_class_init,
70                         NULL, /* class_finalize */
71                         NULL, /* class_data */
72                         sizeof (GMimeFilterFrom),
73                         0,    /* n_preallocs */
74                         (GInstanceInitFunc) g_mime_filter_from_init,
75                 };
76                 
77                 type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterFrom", &info, 0);
78         }
79         
80         return type;
81 }
82
83
84 static void
85 g_mime_filter_from_class_init (GMimeFilterFromClass *klass)
86 {
87         GObjectClass *object_class = G_OBJECT_CLASS (klass);
88         GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
89         
90         parent_class = g_type_class_ref (GMIME_TYPE_FILTER);
91         
92         object_class->finalize = g_mime_filter_from_finalize;
93         
94         filter_class->copy = filter_copy;
95         filter_class->filter = filter_filter;
96         filter_class->complete = filter_complete;
97         filter_class->reset = filter_reset;
98 }
99
100 static void
101 g_mime_filter_from_init (GMimeFilterFrom *filter, GMimeFilterFromClass *klass)
102 {
103         filter->midline = FALSE;
104 }
105
106 static void
107 g_mime_filter_from_finalize (GObject *object)
108 {
109         G_OBJECT_CLASS (parent_class)->finalize (object);
110 }
111
112
113 static GMimeFilter *
114 filter_copy (GMimeFilter *filter)
115 {
116         GMimeFilterFrom *from = (GMimeFilterFrom *) filter;
117         
118         return g_mime_filter_from_new (from->mode);
119 }
120
121 struct fromnode {
122         struct fromnode *next;
123         char *pointer;
124 };
125
126 static void
127 filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
128                char **out, size_t *outlen, size_t *outprespace)
129 {
130         GMimeFilterFrom *from = (GMimeFilterFrom *) filter;
131         struct fromnode *head = NULL, *tail = (struct fromnode *) &head, *node;
132         register char *inptr, *inend;
133         int fromcount = 0;
134         char *outptr;
135         size_t left;
136         
137         inptr = in;
138         inend = inptr + len;
139         
140         while (inptr < inend) {
141                 register int c = -1;
142                 
143                 if (from->midline) {
144                         while (inptr < inend && (c = *inptr++) != '\n')
145                                 ;
146                 }
147                 
148                 if (c == '\n' || !from->midline) {
149                         left = (size_t) (inend - inptr);
150                         if (left > 0) {
151                                 from->midline = TRUE;
152                                 if (left < 5) {
153                                         if (*inptr == 'F') {
154                                                 g_mime_filter_backup (filter, inptr, left);
155                                                 from->midline = FALSE;
156                                                 inend = inptr;
157                                                 break;
158                                         }
159                                 } else {
160                                         if (!strncmp (inptr, "From ", 5)) {
161                                                 fromcount++;
162                                                 
163                                                 node = g_alloca (sizeof (struct fromnode));
164                                                 node->pointer = inptr;
165                                                 node->next = NULL;
166                                                 tail->next = node;
167                                                 tail = node;
168                                                 
169                                                 inptr += 5;
170                                         }
171                                 }
172                         } else {
173                                 from->midline = FALSE;
174                         }
175                 }
176         }
177         
178         if (fromcount > 0) {
179                 if (from->mode == GMIME_FILTER_FROM_MODE_ARMOR)
180                         len += (fromcount * 2);
181                 else
182                         len += fromcount;
183                 
184                 g_mime_filter_set_size (filter, len, FALSE);
185                 
186                 node = head;
187                 inptr = in;
188                 outptr = filter->outbuf;
189                 while (node) {
190                         memcpy (outptr, inptr, (unsigned) (node->pointer - inptr));
191                         outptr += node->pointer - inptr;
192                         if (from->mode == GMIME_FILTER_FROM_MODE_ARMOR) {
193                                 *outptr++ = '=';
194                                 *outptr++ = '4';
195                                 *outptr++ = '6';
196                                 inptr = node->pointer + 1;
197                         } else {
198                                 *outptr++ = '>';
199                                 inptr = node->pointer;
200                         }
201                         
202                         node = node->next;
203                 }
204                 
205                 memcpy (outptr, inptr, (size_t) (inend - inptr));
206                 outptr += inend - inptr;
207                 *out = filter->outbuf;
208                 *outlen = (size_t) (outptr - filter->outbuf);
209                 *outprespace = filter->outbuf - filter->outreal;
210         } else {
211                 *out = in;
212                 *outlen = (size_t) (inend - in);
213                 *outprespace = prespace;
214         }
215 }
216
217 static void 
218 filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
219                  char **out, size_t *outlen, size_t *outprespace)
220 {
221         filter_filter (filter, in, len, prespace, out, outlen, outprespace);
222 }
223
224 static void
225 filter_reset (GMimeFilter *filter)
226 {
227         GMimeFilterFrom *from = (GMimeFilterFrom *) filter;
228         
229         from->midline = FALSE;
230 }
231
232
233 /**
234  * g_mime_filter_from_new:
235  * @mode: filter mode
236  *
237  * Creates a new GMimeFilterFrom filter. If @mode is
238  * #GMIME_FILTER_FROM_MODE_ARMOR, the from-filter will encode from
239  * lines using the quoted-printable encoding resulting in "=46rom ".
240  * Using the #GMIME_FILTER_FROM_MODE_DEFAULT or
241  * #GMIME_FILTER_FROM_MODE_ESCAPE mode (they are the same), from lines
242  * will be escaped to ">From ".
243  *
244  * Note: If you plan on using a from-filter in mode ARMOR, you should
245  * remember to also use a #GMimeFilterBasic filter with an encoding of
246  * #GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE.
247  *
248  * Returns: a new from filter with mode @mode.
249  **/
250 GMimeFilter *
251 g_mime_filter_from_new (GMimeFilterFromMode mode)
252 {
253         GMimeFilterFrom *new;
254         
255         new = g_object_newv (GMIME_TYPE_FILTER_FROM, 0, NULL);
256         new->midline = FALSE;
257         switch (mode) {
258         case GMIME_FILTER_FROM_MODE_ARMOR:
259                 new->mode = mode;
260                 break;
261         case GMIME_FILTER_FROM_MODE_ESCAPE:
262         default:
263                 new->mode = GMIME_FILTER_FROM_MODE_ESCAPE;
264                 break;
265         }
266         
267         return (GMimeFilter *) new;
268 }