Import notmuch_0.27.orig.tar.gz
[notmuch] / gmime-filter-reply.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <stdbool.h>
20
21 #include "gmime-filter-reply.h"
22
23 /**
24  * SECTION: gmime-filter-reply
25  * @title: GMimeFilterReply
26  * @short_description: Add/remove reply markers
27  *
28  * A #GMimeFilter for adding or removing reply markers
29  **/
30
31
32 static void g_mime_filter_reply_class_init (GMimeFilterReplyClass *klass);
33 static void g_mime_filter_reply_init (GMimeFilterReply *filter, GMimeFilterReplyClass *klass);
34 static void g_mime_filter_reply_finalize (GObject *object);
35
36 static GMimeFilter *filter_copy (GMimeFilter *filter);
37 static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
38                            char **out, size_t *outlen, size_t *outprespace);
39 static void filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
40                              char **out, size_t *outlen, size_t *outprespace);
41 static void filter_reset (GMimeFilter *filter);
42
43
44 static GMimeFilterClass *parent_class = NULL;
45
46 GType
47 g_mime_filter_reply_get_type (void)
48 {
49         static GType type = 0;
50
51         if (!type) {
52                 static const GTypeInfo info = {
53                         sizeof (GMimeFilterReplyClass),
54                         NULL, /* base_class_init */
55                         NULL, /* base_class_finalize */
56                         (GClassInitFunc) g_mime_filter_reply_class_init,
57                         NULL, /* class_finalize */
58                         NULL, /* class_data */
59                         sizeof (GMimeFilterReply),
60                         0,    /* n_preallocs */
61                         (GInstanceInitFunc) g_mime_filter_reply_init,
62                         NULL    /* value_table */
63                 };
64
65                 type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterReply", &info, (GTypeFlags) 0);
66         }
67
68         return type;
69 }
70
71
72 static void
73 g_mime_filter_reply_class_init (GMimeFilterReplyClass *klass)
74 {
75         GObjectClass *object_class = G_OBJECT_CLASS (klass);
76         GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
77
78         parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER);
79
80         object_class->finalize = g_mime_filter_reply_finalize;
81
82         filter_class->copy = filter_copy;
83         filter_class->filter = filter_filter;
84         filter_class->complete = filter_complete;
85         filter_class->reset = filter_reset;
86 }
87
88 static void
89 g_mime_filter_reply_init (GMimeFilterReply *filter, GMimeFilterReplyClass *klass)
90 {
91         (void) klass;
92         filter->saw_nl = true;
93         filter->saw_angle = false;
94 }
95
96 static void
97 g_mime_filter_reply_finalize (GObject *object)
98 {
99         G_OBJECT_CLASS (parent_class)->finalize (object);
100 }
101
102
103 static GMimeFilter *
104 filter_copy (GMimeFilter *filter)
105 {
106         GMimeFilterReply *reply = (GMimeFilterReply *) filter;
107
108         return g_mime_filter_reply_new (reply->encode);
109 }
110
111 static void
112 filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
113                char **outbuf, size_t *outlen, size_t *outprespace)
114 {
115         GMimeFilterReply *reply = (GMimeFilterReply *) filter;
116         const char *inptr = inbuf;
117         const char *inend = inbuf + inlen;
118         char *outptr;
119
120         (void) prespace;
121         if (reply->encode) {
122                 g_mime_filter_set_size (filter, 3 * inlen, false);
123
124                 outptr = filter->outbuf;
125                 while (inptr < inend) {
126                         if (reply->saw_nl) {
127                                 *outptr++ = '>';
128                                 *outptr++ = ' ';
129                                 reply->saw_nl = false;
130                         }
131                         if (*inptr == '\n')
132                                 reply->saw_nl = true;
133                         else
134                                 reply->saw_nl = false;
135                         if (*inptr != '\r')
136                                 *outptr++ = *inptr;
137                         inptr++;
138                 }
139         } else {
140                 g_mime_filter_set_size (filter, inlen + 1, false);
141
142                 outptr = filter->outbuf;
143                 while (inptr < inend) {
144                         if (reply->saw_nl) {
145                                 if (*inptr == '>')
146                                         reply->saw_angle = true;
147                                 else
148                                         *outptr++ = *inptr;
149                                 reply->saw_nl = false;
150                         } else if (reply->saw_angle) {
151                                 if (*inptr == ' ')
152                                         ;
153                                 else
154                                         *outptr++ = *inptr;
155                                 reply->saw_angle = false;
156                         } else if (*inptr != '\r') {
157                                 if (*inptr == '\n')
158                                         reply->saw_nl = true;
159                                 *outptr++ = *inptr;
160                         }
161
162                         inptr++;
163                 }
164         }
165
166         *outlen = outptr - filter->outbuf;
167         *outprespace = filter->outpre;
168         *outbuf = filter->outbuf;
169 }
170
171 static void
172 filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
173                  char **outbuf, size_t *outlen, size_t *outprespace)
174 {
175         if (inbuf && inlen)
176                 filter_filter (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace);
177 }
178
179 static void
180 filter_reset (GMimeFilter *filter)
181 {
182         GMimeFilterReply *reply = (GMimeFilterReply *) filter;
183
184         reply->saw_nl = true;
185         reply->saw_angle = false;
186 }
187
188
189 /**
190  * g_mime_filter_reply_new:
191  * @encode: %true if the filter should encode or %false otherwise
192  * @dots: encode/decode dots (as for SMTP)
193  *
194  * Creates a new #GMimeFilterReply filter.
195  *
196  * If @encode is %true, then all lines will be prefixed by "> ",
197  * otherwise any lines starting with "> " will have that removed
198  *
199  * Returns: a new #GMimeFilterReply filter.
200  **/
201 GMimeFilter *
202 g_mime_filter_reply_new (gboolean encode)
203 {
204         GMimeFilterReply *new_reply;
205
206         new_reply = (GMimeFilterReply *) g_object_new (GMIME_TYPE_FILTER_REPLY, NULL);
207         new_reply->encode = encode;
208
209         return (GMimeFilter *) new_reply;
210 }
211