Fix bug 4325 "Following redirects when retrieving image"
[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 3 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, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #include "claws-features.h"
23 #endif
24
25 #include <glib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #include "enriched.h"
31 #include "utils.h"
32 #include "file-utils.h"
33
34 #define ERTFBUFSIZE     8192
35
36
37 static ERTFState ertf_read_line         (ERTFParser     *parser);
38 static void ertf_append_char            (ERTFParser     *parser,
39                                          gchar           ch);
40
41 static ERTFState ertf_parse_tag         (ERTFParser     *parser);
42 static void ertf_get_parenthesis        (ERTFParser     *parser, 
43                                          gchar          *buf, 
44                                          gint            len);
45
46 ERTFParser *ertf_parser_new(FILE *fp, CodeConverter *conv)
47 {
48         ERTFParser *parser;
49
50         cm_return_val_if_fail(fp   != NULL, NULL);
51         cm_return_val_if_fail(conv != NULL, NULL);
52
53         parser             = g_new0(ERTFParser, 1);
54         parser->fp         = fp;
55         parser->conv       = conv;
56         parser->str        = g_string_new(NULL);
57         parser->buf        = g_string_new(NULL);
58         parser->bufp       = parser->buf->str;
59         parser->newline    = TRUE;
60         parser->empty_line = TRUE;
61         parser->space      = FALSE;
62         parser->pre        = FALSE;
63
64         return parser;
65 }
66
67 void ertf_parser_destroy(ERTFParser *parser)
68 {
69         g_string_free(parser->str, TRUE);
70         g_string_free(parser->buf, TRUE);
71         g_free(parser);
72 }
73
74 gchar *ertf_parse(ERTFParser *parser)
75 {
76         parser->state = ERTF_NORMAL;
77         g_string_truncate(parser->str, 0);
78
79         if (*parser->bufp == '\0') {
80                 g_string_truncate(parser->buf, 0);
81                 parser->bufp = parser->buf->str;
82                 if (ertf_read_line(parser) == ERTF_EOF)
83                         return NULL;
84         }
85         
86         while (*parser->bufp != '\0') {
87                 switch (*parser->bufp) {
88                         case '<':
89                                 if (parser->str->len == 0)
90                                         ertf_parse_tag(parser);
91                                 else
92                                         return parser->str->str;
93                                 break;
94                         case '\n':
95                         case '\r':      
96                                 if (parser->bufp[0] == '\r' && parser->bufp[1] == '\n') 
97                                                 parser->bufp++;
98
99                                 if (!parser->pre) {
100                                         /* When not pre (not <nofill>), 1 CRLF = SPACE, N>1 CRLF = N-1 CRLF*/
101                                         if (!parser->newline) {
102                                                 parser->newline = TRUE;
103                                                 parser->space = TRUE;
104                                         parser->bufp++;
105                                         break;
106                                         }
107
108                                 }
109                         default:
110                                 ertf_append_char(parser, *parser->bufp++);
111                 }
112         }
113         
114         return parser->str->str;
115 }
116
117 static ERTFState ertf_read_line(ERTFParser *parser)
118 {
119         gchar buf[ERTFBUFSIZE];
120         gchar buf2[ERTFBUFSIZE];
121         gint index;
122
123         if (claws_fgets(buf, sizeof(buf), parser->fp) == NULL) {
124                 parser->state = ERTF_EOF;
125                 return ERTF_EOF;
126         }
127
128         if (conv_convert(parser->conv, buf2, sizeof(buf2), buf) < 0) {
129                 g_warning("ertf_read_line(): code conversion failed");
130
131                 index = parser->bufp - parser->buf->str;
132
133                 g_string_append(parser->buf, buf);
134
135                 parser->bufp = parser->buf->str + index;
136
137                 return ERTF_ERR;
138         }
139
140         index = parser->bufp - parser->buf->str;
141
142         g_string_append(parser->buf, buf2);
143
144         parser->bufp = parser->buf->str + index;
145
146         return ERTF_NORMAL;
147 }
148
149 static void ertf_append_char(ERTFParser *parser, gchar ch)
150 {
151         GString *str = parser->str;
152
153         if (!parser->pre && parser->space) {
154                 if (ch != '\n')
155                         g_string_append_c(str, ' ');
156                 parser->space = FALSE;
157         }
158
159         g_string_append_c(str, ch);
160
161         parser->empty_line = FALSE;
162         if (ch == '\n') {
163                 if (parser->newline)
164                         parser->empty_line = TRUE;
165                 else
166                         parser->newline = TRUE;
167         } else
168                 parser->newline = FALSE;
169 }
170
171 static ERTFState ertf_parse_tag(ERTFParser *parser)
172 {
173         gchar buf[ERTFBUFSIZE];
174         gchar *p;
175         gchar *down;
176         
177         ertf_get_parenthesis (parser, buf, sizeof(buf));
178         
179         for (p = buf; *p != '\0'; p++) {
180                 if (isspace (*(guchar *)p)) {
181                         *p = '\0';
182                         break;
183                 }
184         }
185
186         parser->state = ERTF_UNKNOWN;
187         if (buf[0] == '\0') return parser->state;
188
189         down = g_utf8_strdown (buf, -1);
190
191         if (!strcmp(down, "nofill")) {
192                 parser->pre   = TRUE;
193                 parser->state = ERTF_NOFILL;
194         }
195         else if (!strcmp(down, "/nofill")) {
196                 parser->pre   = FALSE;
197                 parser->state = ERTF_NORMAL;
198         }
199         g_free(down);
200         return parser->state;
201 }
202                 
203 static void ertf_get_parenthesis(ERTFParser *parser, gchar *buf, gint len)
204 {
205         gchar *p;
206
207         buf[0] = '\0';
208         cm_return_if_fail(*parser->bufp == '<');
209
210         /* ignore params */
211         if (!g_ascii_strncasecmp(parser->bufp, "<param>", 4)) {
212                 parser->bufp += 7;
213                 while ((p = strstr(parser->bufp, "</param>")) == NULL)
214                         if (ertf_read_line(parser) == ERTF_EOF) return;
215                 parser->bufp = p + 8;
216                 return;
217         }
218         parser->bufp++;
219         while ((p = strchr(parser->bufp, '>')) == NULL)
220                 if (ertf_read_line(parser) == ERTF_EOF) return;
221
222         strncpy2(buf, parser->bufp, MIN(p - parser->bufp + 1, len));
223         parser->bufp = p + 1;
224 }
225