3d9f1c53f5d039cc9624dee3c4d759a74e293057
[claws.git] / src / plugins / rssyl / strutils.c
1 /*
2  * Claws-Mail-- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2005 Andrej Kacian <andrej@kacian.sk>
4  *
5  * - a strreplace function (something like sed's s/foo/bar/g)
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 /* Global includes */
27 #include <glib.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30
31 /* Claws Mail includes */
32 #include <common/utils.h>
33
34 /* Local includes */
35 /* (shouldn't be any) */
36
37 gchar *rssyl_strreplace(gchar *source, gchar *pattern,
38                 gchar *replacement)
39 {
40         gchar *new, *w_new = NULL, *c;
41         guint count = 0, final_length;
42         size_t len_pattern, len_replacement;
43
44         /*
45         debug_print("RSSyl: ======= strreplace: '%s': '%s'->'%s'\n", source, pattern,
46                         replacement);
47         */
48
49         if( source == NULL || pattern == NULL ) {
50                 debug_print("RSSyl: source or pattern is NULL!!!\n");
51                 return source;
52         }
53
54         if( !g_utf8_validate(source, -1, NULL) ) {
55                 debug_print("RSSyl: source is not an UTF-8 encoded text\n");
56                 return source;
57         }
58
59         if( !g_utf8_validate(pattern, -1, NULL) ) {
60                 debug_print("RSSyl: pattern is not an UTF-8 encoded text\n");
61                 return source;
62         }
63
64         len_pattern = strlen(pattern);
65         len_replacement = strlen(replacement);
66
67         c = source;
68         while( ( c = g_strstr_len(c, strlen(c), pattern) ) ) {
69                 count++;
70                 c += len_pattern;
71         }
72
73         /*
74         debug_print("RSSyl: ==== count = %d\n", count);
75         */
76
77         final_length = strlen(source)
78                 - ( count * len_pattern )
79                 + ( count * len_replacement );
80
81         new = malloc(final_length + 1);
82         w_new = new;
83         memset(new, '\0', final_length + 1);
84
85         c = source;
86
87         while( *c != '\0' ) {
88                 if( !memcmp(c, pattern, len_pattern) ) {
89                         gboolean break_after_rep = FALSE;
90                         int i;
91                         if (*(c + len_pattern) == '\0')
92                                 break_after_rep = TRUE;
93                         for (i = 0; i < len_replacement; i++) {
94                                 *w_new = replacement[i];
95                                 w_new++;
96                         }
97                         if (break_after_rep)
98                                 break;
99                         c = c + len_pattern;
100                 } else {
101                         *w_new = *c;
102                         w_new++;
103                         c++;
104                 }
105         }
106         return new;
107 }
108
109 typedef struct _RSSyl_HTMLSymbol RSSyl_HTMLSymbol;
110 struct _RSSyl_HTMLSymbol
111 {
112         gchar *const key;
113         gchar *const val;
114 };
115
116 static RSSyl_HTMLSymbol symbol_list[] = {
117         { "&lt;", "<" },
118         { "&gt;", ">" },
119         { "&amp;", "&" },
120         { "&quot;", "\"" },
121         { "&lsquo;",  "'" },
122         { "&rsquo;",  "'" },
123         { "&ldquo;",  "\"" },
124         { "&rdquo;",  "\"" },
125         { "&nbsp;", " " },
126         { "&trade;", "(TM)" },
127         { "&#153;", "(TM)" },
128         { "&#39;", "'" },
129         { "&hellip;", "..." },
130         { "&#8230;", "..." },
131         { "&mdash;", "-" },
132         { NULL, NULL }
133 };
134
135 static RSSyl_HTMLSymbol tag_list[] = {
136         { "<cite>", "\"" },
137         { "</cite>", "\"" },
138         { "<i>", "" },
139         { "</i>", "" },
140         { "<em>", "" },
141         { "</em>", "" },
142         { "<b>", "" },
143         { "</b>", "" },
144         { "<nobr>", "" },
145         { "</nobr>", "" },
146         { "<wbr>", "" },
147         { NULL, NULL }
148 };
149
150 gchar *rssyl_replace_html_stuff(gchar *text,
151                 gboolean symbols, gboolean tags)
152 {
153         gchar *tmp = NULL, *wtext = NULL;
154         gint i;
155
156         g_return_val_if_fail(text != NULL, NULL);
157
158         wtext = g_strdup(text);
159
160         /* Ugly, needlessly traverses the string again and again. Probably
161          * could use a rewrite. */
162         if( symbols ) {
163                 for( i = 0; symbol_list[i].key != NULL; i++ ) {
164                         if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
165                                 tmp = rssyl_strreplace(wtext, symbol_list[i].key, symbol_list[i].val);
166                                 wtext = g_strdup(tmp);
167                                 g_free(tmp);
168                         }
169                 }
170         }
171
172         if( tags ) {
173                 for( i = 0; tag_list[i].key != NULL; i++ ) {
174                         if( g_strstr_len(text, strlen(text), symbol_list[i].key) ) {
175                                 tmp = rssyl_strreplace(wtext, tag_list[i].key, tag_list[i].val);
176                                 wtext = g_strdup(tmp);
177                                 g_free(tmp);
178                         }
179                 }
180         }
181
182         return wtext;
183 }
184
185 static gchar *rssyl_sanitize_string(gchar *str, gboolean strip_nl)
186 {
187         gchar *new = NULL, *c = str, *n = NULL;
188
189         if( str == NULL )
190                 return NULL;
191
192         n = new = malloc(strlen(str) + 1);
193         memset(new, '\0', strlen(str) + 1);
194
195         while( *c != '\0' ) {
196                 if( !isspace(*c) || *c == ' ' || (!strip_nl && *c == '\n') ) {
197                         *n = *c;
198                         n++;
199                 }
200                 c++;
201         }
202
203         return new;
204 }
205
206 /* rssyl_format_string()
207  * - return value needs to be freed
208  */
209 gchar *rssyl_format_string(gchar *str, gboolean replace_html,
210                 gboolean strip_nl)
211 {
212         gchar *res = NULL, *tmp = NULL;
213
214         g_return_val_if_fail(str != NULL, NULL);
215
216         if (replace_html)
217                 tmp = rssyl_replace_html_stuff(str, TRUE, TRUE);
218         else
219                 tmp = g_strdup(str);
220
221         res = rssyl_sanitize_string(tmp, strip_nl);
222         g_free(tmp);
223
224         g_strstrip(res);
225
226         return res;
227 }
228
229 /* this functions splits a string into an array of string, by 
230  * returning an array of pointers to positions of the delimiter
231  * in the original string and replacing this delimiter with a
232  * NULL. It does not duplicate memory, hence you should only
233  * free the array and not its elements, and you should not
234  * free the original string before you're done with the array.
235  * maybe could be part of the core (utils.c).
236  */
237 gchar **strsplit_no_copy(gchar *str, char delimiter)
238 {
239         gchar **array = g_new(gchar *, 1);
240         int i = 0;
241         gchar *cur = str, *next;
242         
243         array[i] = cur;
244         i++;
245         while ((next = strchr(cur, delimiter)) != NULL) {
246                 *(next) = '\0';
247                 array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
248                 array[i] = next + 1;
249                 cur = next + 1;
250                 i++;
251         }
252         array = g_realloc(array, (sizeof(gchar *)) * (i + 1));
253         array[i] = NULL;
254         return array;
255 }
256
257 /* This is a very dumb function - it just strips <, > and everything between
258  * them. */
259 void strip_html(gchar *str)
260 {
261         gchar *p = str;
262         gboolean intag = FALSE;
263
264         while (*p) {
265                 if (*p == '<')
266                         intag = TRUE;
267                 else if (*p == '>')
268                         intag = FALSE;
269
270                 if (*p == '<' || *p == '>' || intag)
271                         memmove(p, p + 1, strlen(p));
272                 else
273                         p++;
274         }
275 }
276
277 gchar *my_normalize_url(const gchar *url)
278 {
279         gchar *myurl = NULL;
280
281         if (!strncmp(url, "feed://", 7))
282                 myurl = g_strdup(url+7);
283         else if (!strncmp(url, "feed:", 5))
284                 myurl = g_strdup(url+5);
285         else
286                 myurl = g_strdup(url);
287
288         return myurl;
289 }