Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-filter-crlf.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 "gmime-filter-crlf.h"
27
28
29 /**
30  * SECTION: gmime-filter-crlf
31  * @title: GMimeFilterCRLF
32  * @short_description: Convert line-endings from LF to CRLF or vise versa
33  *
34  * A #GMimeFilter for converting between DOS and UNIX line-endings.
35  **/
36
37
38 static void g_mime_filter_crlf_class_init (GMimeFilterCRLFClass *klass);
39 static void g_mime_filter_crlf_init (GMimeFilterCRLF *filter, GMimeFilterCRLFClass *klass);
40 static void g_mime_filter_crlf_finalize (GObject *object);
41
42 static GMimeFilter *filter_copy (GMimeFilter *filter);
43 static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
44                            char **out, size_t *outlen, size_t *outprespace);
45 static void filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
46                              char **out, size_t *outlen, size_t *outprespace);
47 static void filter_reset (GMimeFilter *filter);
48
49
50 static GMimeFilterClass *parent_class = NULL;
51
52
53 GType
54 g_mime_filter_crlf_get_type (void)
55 {
56         static GType type = 0;
57         
58         if (!type) {
59                 static const GTypeInfo info = {
60                         sizeof (GMimeFilterCRLFClass),
61                         NULL, /* base_class_init */
62                         NULL, /* base_class_finalize */
63                         (GClassInitFunc) g_mime_filter_crlf_class_init,
64                         NULL, /* class_finalize */
65                         NULL, /* class_data */
66                         sizeof (GMimeFilterCRLF),
67                         0,    /* n_preallocs */
68                         (GInstanceInitFunc) g_mime_filter_crlf_init,
69                 };
70                 
71                 type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterCRLF", &info, 0);
72         }
73         
74         return type;
75 }
76
77
78 static void
79 g_mime_filter_crlf_class_init (GMimeFilterCRLFClass *klass)
80 {
81         GObjectClass *object_class = G_OBJECT_CLASS (klass);
82         GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
83         
84         parent_class = g_type_class_ref (GMIME_TYPE_FILTER);
85         
86         object_class->finalize = g_mime_filter_crlf_finalize;
87         
88         filter_class->copy = filter_copy;
89         filter_class->filter = filter_filter;
90         filter_class->complete = filter_complete;
91         filter_class->reset = filter_reset;
92 }
93
94 static void
95 g_mime_filter_crlf_init (GMimeFilterCRLF *filter, GMimeFilterCRLFClass *klass)
96 {
97         filter->saw_cr = FALSE;
98         filter->saw_lf = FALSE;
99         filter->saw_dot = FALSE;
100 }
101
102 static void
103 g_mime_filter_crlf_finalize (GObject *object)
104 {
105         G_OBJECT_CLASS (parent_class)->finalize (object);
106 }
107
108
109 static GMimeFilter *
110 filter_copy (GMimeFilter *filter)
111 {
112         GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter;
113         
114         return g_mime_filter_crlf_new (crlf->encode, crlf->dots);
115 }
116
117 static void
118 filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
119                char **outbuf, size_t *outlen, size_t *outprespace)
120 {
121         GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter;
122         register const char *inptr = inbuf;
123         const char *inend = inbuf + inlen;
124         char *outptr;
125         
126         if (crlf->encode) {
127                 g_mime_filter_set_size (filter, 3 * inlen, FALSE);
128                 
129                 outptr = filter->outbuf;
130                 while (inptr < inend) {
131                         if (*inptr == '\r') {
132                                 crlf->saw_cr = TRUE;
133                         } else if (*inptr == '\n') {
134                                 crlf->saw_lf = TRUE;
135                                 if (!crlf->saw_cr)
136                                         *outptr++ = '\r';
137                                 crlf->saw_cr = FALSE;
138                         } else {
139                                 if (crlf->dots && *inptr == '.' && crlf->saw_lf)
140                                         *outptr++ = '.';
141                                 
142                                 crlf->saw_cr = FALSE;
143                                 crlf->saw_lf = FALSE;
144                         }
145                         
146                         *outptr++ = *inptr++;
147                 }
148         } else {
149                 g_mime_filter_set_size (filter, inlen + 1, FALSE);
150                 
151                 outptr = filter->outbuf;
152                 while (inptr < inend) {
153                         if (*inptr == '\r') {
154                                 crlf->saw_dot = FALSE;
155                                 crlf->saw_cr = TRUE;
156                         } else {
157                                 if (crlf->saw_cr) {
158                                         crlf->saw_cr = FALSE;
159                                         
160                                         if (*inptr == '\n') {
161                                                 crlf->saw_lf = TRUE;
162                                                 *outptr++ = *inptr++;
163                                                 continue;
164                                         } else
165                                                 *outptr++ = '\r';
166                                 }
167                                 
168                                 if (!(crlf->dots && crlf->saw_dot && *inptr == '.'))
169                                         *outptr++ = *inptr;
170                         }
171                         
172                         if (crlf->dots && *inptr == '.') {
173                                 if (crlf->saw_lf) {
174                                         crlf->saw_dot = TRUE;
175                                 } else if (crlf->saw_dot) {
176                                         crlf->saw_dot = FALSE;
177                                 }
178                         }
179                         
180                         crlf->saw_lf = FALSE;
181                         
182                         inptr++;
183                 }
184         }
185         
186         *outlen = outptr - filter->outbuf;
187         *outprespace = filter->outpre;
188         *outbuf = filter->outbuf;
189 }
190
191 static void 
192 filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
193                  char **outbuf, size_t *outlen, size_t *outprespace)
194 {
195         if (inbuf && inlen)
196                 filter_filter (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace);
197 }
198
199 static void
200 filter_reset (GMimeFilter *filter)
201 {
202         GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter;
203         
204         crlf->saw_cr = FALSE;
205         crlf->saw_lf = TRUE;
206         crlf->saw_dot = FALSE;
207 }
208
209
210 /**
211  * g_mime_filter_crlf_new:
212  * @encode: %TRUE if the filter should encode or %FALSE otherwise
213  * @dots: encode/decode dots (as for SMTP)
214  *
215  * Creates a new #GMimeFilterCRLF filter.
216  *
217  * If @encode is %TRUE, then lone line-feeds ('\n') will be 'encoded'
218  * into the canonical CRLF end-of-line sequence ("\r\n") otherwise
219  * CRLF sequences will be 'decoded' into the UNIX line-ending form
220  * ('\n').
221  *
222  * The @dots parameter tells the filter whether or not it should
223  * encode or decode lines beginning with a dot ('.'). If both @encode
224  * and @dots are %TRUE, then a '.' at the beginning of a line will be
225  * 'encoded' into "..". If @encode is %FALSE, then ".." at the
226  * beginning of a line will be decoded into a single '.'.
227  *
228  * Returns: a new #GMimeFilterCRLF filter.
229  **/
230 GMimeFilter *
231 g_mime_filter_crlf_new (gboolean encode, gboolean dots)
232 {
233         GMimeFilterCRLF *new;
234         
235         new = g_object_newv (GMIME_TYPE_FILTER_CRLF, 0, NULL);
236         new->encode = encode;
237         new->dots = dots;
238         
239         return (GMimeFilter *) new;
240 }