notmuch reply: Add (incomplete) reply command
[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 "gmime-filter-reply.h"
20
21 /**
22  * SECTION: gmime-filter-reply
23  * @title: GMimeFilterReply
24  * @short_description: Add/remove reply markers
25  *
26  * A #GMimeFilter for adding or removing reply markers
27  **/
28
29
30 static void g_mime_filter_reply_class_init (GMimeFilterReplyClass *klass);
31 static void g_mime_filter_reply_init (GMimeFilterReply *filter, GMimeFilterReplyClass *klass);
32 static void g_mime_filter_reply_finalize (GObject *object);
33
34 static GMimeFilter *filter_copy (GMimeFilter *filter);
35 static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
36                            char **out, size_t *outlen, size_t *outprespace);
37 static void filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
38                              char **out, size_t *outlen, size_t *outprespace);
39 static void filter_reset (GMimeFilter *filter);
40
41
42 static GMimeFilterClass *parent_class = NULL;
43
44 GType
45 g_mime_filter_reply_get_type (void)
46 {
47         static GType type = 0;
48
49         if (!type) {
50                 static const GTypeInfo info = {
51                         sizeof (GMimeFilterReplyClass),
52                         NULL, /* base_class_init */
53                         NULL, /* base_class_finalize */
54                         (GClassInitFunc) g_mime_filter_reply_class_init,
55                         NULL, /* class_finalize */
56                         NULL, /* class_data */
57                         sizeof (GMimeFilterReply),
58                         0,    /* n_preallocs */
59                         (GInstanceInitFunc) g_mime_filter_reply_init,
60                         NULL    /* value_table */
61                 };
62
63                 type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterReply", &info, (GTypeFlags) 0);
64         }
65
66         return type;
67 }
68
69
70 static void
71 g_mime_filter_reply_class_init (GMimeFilterReplyClass *klass)
72 {
73         GObjectClass *object_class = G_OBJECT_CLASS (klass);
74         GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
75
76         parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER);
77
78         object_class->finalize = g_mime_filter_reply_finalize;
79
80         filter_class->copy = filter_copy;
81         filter_class->filter = filter_filter;
82         filter_class->complete = filter_complete;
83         filter_class->reset = filter_reset;
84 }
85
86 static void
87 g_mime_filter_reply_init (GMimeFilterReply *filter, GMimeFilterReplyClass *klass)
88 {
89         (void) klass;
90         filter->saw_nl = TRUE;
91         filter->saw_angle = FALSE;
92 }
93
94 static void
95 g_mime_filter_reply_finalize (GObject *object)
96 {
97         G_OBJECT_CLASS (parent_class)->finalize (object);
98 }
99
100
101 static GMimeFilter *
102 filter_copy (GMimeFilter *filter)
103 {
104         GMimeFilterReply *reply = (GMimeFilterReply *) filter;
105
106         return g_mime_filter_reply_new (reply->encode);
107 }
108
109 static void
110 filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
111                char **outbuf, size_t *outlen, size_t *outprespace)
112 {
113         GMimeFilterReply *reply = (GMimeFilterReply *) filter;
114         register const char *inptr = inbuf;
115         const char *inend = inbuf + inlen;
116         char *outptr;
117
118         (void) prespace;
119         if (reply->encode) {
120                 g_mime_filter_set_size (filter, 3 * inlen, FALSE);
121
122                 outptr = filter->outbuf;
123                 while (inptr < inend) {
124                         if (reply->saw_nl) {
125                                 *outptr++ = '>';
126                                 *outptr++ = ' ';
127                                 reply->saw_nl = FALSE;
128                         }
129                         if (*inptr == '\n')
130                                 reply->saw_nl = TRUE;
131                         else
132                                 reply->saw_nl = FALSE;
133
134                         *outptr++ = *inptr++;
135                 }
136         } else {
137                 g_mime_filter_set_size (filter, inlen + 1, FALSE);
138
139                 outptr = filter->outbuf;
140                 while (inptr < inend) {
141                         if (reply->saw_nl) {
142                                 if (*inptr == '>')
143                                         reply->saw_angle = TRUE;
144                                 else
145                                         *outptr++ = *inptr;
146                                 reply->saw_nl = FALSE;
147                         } else if (reply->saw_angle) {
148                                 if (*inptr == ' ')
149                                         ;
150                                 else
151                                         *outptr++ = *inptr;
152                                 reply->saw_angle = FALSE;
153                         } else {
154                                 if (*inptr == '\n')
155                                         reply->saw_nl = TRUE;
156                                 *outptr++ = *inptr;
157                         }
158
159                         inptr++;
160                 }
161         }
162
163         *outlen = outptr - filter->outbuf;
164         *outprespace = filter->outpre;
165         *outbuf = filter->outbuf;
166 }
167
168 static void
169 filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
170                  char **outbuf, size_t *outlen, size_t *outprespace)
171 {
172         if (inbuf && inlen)
173                 filter_filter (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace);
174 }
175
176 static void
177 filter_reset (GMimeFilter *filter)
178 {
179         GMimeFilterReply *reply = (GMimeFilterReply *) filter;
180
181         reply->saw_nl = TRUE;
182         reply->saw_angle = FALSE;
183 }
184
185
186 /**
187  * g_mime_filter_reply_new:
188  * @encode: %TRUE if the filter should encode or %FALSE otherwise
189  * @dots: encode/decode dots (as for SMTP)
190  *
191  * Creates a new #GMimeFilterReply filter.
192  *
193  * If @encode is %TRUE, then all lines will be prefixed by "> ",
194  * otherwise any lines starting with "> " will have that removed
195  *
196  * Returns: a new #GMimeFilterReply filter.
197  **/
198 GMimeFilter *
199 g_mime_filter_reply_new (gboolean encode)
200 {
201         GMimeFilterReply *new_reply;
202
203         new_reply = (GMimeFilterReply *) g_object_newv (GMIME_TYPE_FILTER_REPLY, 0, NULL);
204         new_reply->encode = encode;
205
206         return (GMimeFilter *) new_reply;
207 }
208