correct changelog entry
[claws.git] / src / enriched.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999,2000 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <glib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
24
25 #include "enriched.h"
26 #include "codeconv.h"
27 #include "utils.h"
28
29 #define ERTFBUFSIZE     8192
30
31
32 static ERTFState ertf_read_line         (ERTFParser     *parser);
33 static void ertf_append_char            (ERTFParser     *parser,
34                                          gchar           ch);
35
36 static ERTFState ertf_parse_tag         (ERTFParser     *parser);
37 static void ertf_get_parenthesis        (ERTFParser     *parser, 
38                                          gchar          *buf, 
39                                          gint            len);
40
41 ERTFParser *ertf_parser_new(FILE *fp, CodeConverter *conv)
42 {
43         ERTFParser *parser;
44
45         g_return_val_if_fail(fp   != NULL, NULL);
46         g_return_val_if_fail(conv != NULL, NULL);
47
48         parser             = g_new0(ERTFParser, 1);
49         parser->fp         = fp;
50         parser->conv       = conv;
51         parser->str        = g_string_new(NULL);
52         parser->buf        = g_string_new(NULL);
53         parser->bufp       = parser->buf->str;
54         parser->newline    = TRUE;
55         parser->empty_line = TRUE;
56         parser->space      = FALSE;
57         parser->pre        = FALSE;
58
59         return parser;
60 }
61
62 void ertf_parser_destroy(ERTFParser *parser)
63 {
64         g_string_free(parser->str, TRUE);
65         g_string_free(parser->buf, TRUE);
66         g_free(parser);
67 }
68
69 gchar *ertf_parse(ERTFParser *parser)
70 {
71         parser->state = ERTF_NORMAL;
72         g_string_truncate(parser->str, 0);
73
74         if (*parser->bufp == '\0') {
75                 g_string_truncate(parser->buf, 0);
76                 parser->bufp = parser->buf->str;
77                 if (ertf_read_line(parser) == ERTF_EOF)
78                         return NULL;
79         }
80         
81         while (*parser->bufp != '\0') {
82                 switch (*parser->bufp) {
83                         case '<':
84                                 if (parser->str->len == 0)
85                                         ertf_parse_tag(parser);
86                                 else
87                                         return parser->str->str;
88                                 break;
89                         case '\n':
90                         case '\r':      
91                                 if (parser->bufp[0] == '\r' && parser->bufp[1] == '\n') 
92                                                 parser->bufp++;
93
94                                 if (!parser->pre) {
95                                         /* When not pre (not <nofill>), 1 CRLF = SPACE, N>1 CRLF = N-1 CRLF*/
96                                         if (!parser->newline) {
97                                                 parser->newline = TRUE;
98                                                 parser->space = TRUE;
99                                         parser->bufp++;
100                                         break;
101                                         }
102
103                                 }
104                         default:
105                                 ertf_append_char(parser, *parser->bufp++);
106                 }
107         }
108         
109         return parser->str->str;
110 }
111
112 static ERTFState ertf_read_line(ERTFParser *parser)
113 {
114         gchar buf[ERTFBUFSIZE];
115         gchar buf2[ERTFBUFSIZE];
116         gint index;
117
118         if (fgets(buf, sizeof(buf), parser->fp) == NULL) {
119                 parser->state = ERTF_EOF;
120                 return ERTF_EOF;
121         }
122
123         if (conv_convert(parser->conv, buf2, sizeof(buf2), buf) < 0) {
124                 g_warning("ertf_read_line(): code conversion failed\n");
125
126                 index = parser->bufp - parser->buf->str;
127
128                 g_string_append(parser->buf, buf);
129
130                 parser->bufp = parser->buf->str + index;
131
132                 return ERTF_ERR;
133         }
134
135         index = parser->bufp - parser->buf->str;
136
137         g_string_append(parser->buf, buf2);
138
139         parser->bufp = parser->buf->str + index;
140
141         return ERTF_NORMAL;
142 }
143
144 static void ertf_append_char(ERTFParser *parser, gchar ch)
145 {
146         GString *str = parser->str;
147
148         if (!parser->pre && parser->space) {
149                 if (ch != '\n')
150                         g_string_append_c(str, ' ');
151                 parser->space = FALSE;
152         }
153
154         g_string_append_c(str, ch);
155
156         parser->empty_line = FALSE;
157         if (ch == '\n') {
158                 if (parser->newline)
159                         parser->empty_line = TRUE;
160                 else
161                         parser->newline = TRUE;
162         } else
163                 parser->newline = FALSE;
164 }
165
166 static ERTFState ertf_parse_tag(ERTFParser *parser)
167 {
168         gchar buf[ERTFBUFSIZE];
169         gchar *p;
170         
171         ertf_get_parenthesis (parser, buf, sizeof(buf));
172         
173         for (p = buf; *p != '\0'; p++) {
174                 if (isspace (*p)) {
175                         *p = '\0';
176                         break;
177                 }
178         }
179
180         parser->state = ERTF_UNKNOWN;
181         if (buf[0] == '\0') return parser->state;
182
183         g_strdown (buf);
184
185         if (!strcmp(buf, "nofill")) {
186                 parser->pre   = TRUE;
187                 parser->state = ERTF_NOFILL;
188         }
189         else if (!strcmp(buf, "/nofill")) {
190                 parser->pre   = FALSE;
191                 parser->state = ERTF_NORMAL;
192         }
193         
194         return parser->state;
195 }
196                 
197 static void ertf_get_parenthesis(ERTFParser *parser, gchar *buf, gint len)
198 {
199         gchar *p;
200
201         buf[0] = '\0';
202         g_return_if_fail(*parser->bufp == '<');
203
204         /* ignore params */
205         if (!g_strncasecmp(parser->bufp, "<param>", 4)) {
206                 parser->bufp += 7;
207                 while ((p = strstr(parser->bufp, "</param>")) == NULL)
208                         if (ertf_read_line(parser) == ERTF_EOF) return;
209                 parser->bufp = p + 8;
210                 return;
211         }
212         parser->bufp++;
213         while ((p = strchr(parser->bufp, '>')) == NULL)
214                 if (ertf_read_line(parser) == ERTF_EOF) return;
215
216         strncpy2(buf, parser->bufp, MIN(p - parser->bufp + 1, len));
217         parser->bufp = p + 1;
218 }
219