configure: add stuff for spell checking
[rofl0r-ixchat.git] / src / common / url.c
blobb83732d1b9480a9fe4ae4eac2e4d22932800bbb0
1 /* X-Chat
2 * Copyright (C) 1998 Peter Zelezny.
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 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include "xchat.h"
24 #include "xchatc.h"
25 #include "cfgfiles.h"
26 #include "fe.h"
27 #include "tree.h"
28 #include "url.h"
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
33 void *url_tree = NULL;
36 static int
37 url_free (char *url, void *data)
39 free (url);
40 return TRUE;
43 void
44 url_clear (void)
46 tree_foreach (url_tree, (tree_traverse_func *)url_free, NULL);
47 tree_destroy (url_tree);
48 url_tree = NULL;
51 static int
52 url_save_cb (char *url, FILE *fd)
54 fprintf (fd, "%s\n", url);
55 return TRUE;
58 void
59 url_save (const char *fname, const char *mode, gboolean fullpath)
61 FILE *fd;
63 if (fullpath)
64 fd = xchat_fopen_file (fname, mode, XOF_FULLPATH);
65 else
66 fd = xchat_fopen_file (fname, mode, 0);
67 if (fd == NULL)
68 return;
70 tree_foreach (url_tree, (tree_traverse_func *)url_save_cb, fd);
71 fclose (fd);
74 void
75 url_autosave (void)
77 url_save ("url.save", "a", FALSE);
80 static int
81 url_find (char *urltext)
83 int pos;
85 if (tree_find (url_tree, urltext, (tree_cmp_func *)strcasecmp, NULL, &pos))
86 return 1;
87 return 0;
90 static void
91 url_add (char *urltext, int len)
93 char *data;
94 int size;
96 if (!prefs.url_grabber)
97 return;
99 data = malloc (len + 1);
100 if (!data)
101 return;
102 memcpy (data, urltext, len);
103 data[len] = 0;
105 if (data[len - 1] == '.') /* chop trailing dot */
107 len--;
108 data[len] = 0;
110 if (data[len - 1] == ')') /* chop trailing ) */
111 data[len - 1] = 0;
113 if (url_find (data))
115 free (data);
116 return;
119 if (!url_tree)
120 url_tree = tree_new ((tree_cmp_func *)strcasecmp, NULL);
122 size = tree_size (url_tree);
123 /* 0 is unlimited */
124 if (prefs.url_grabber_limit > 0 && size >= prefs.url_grabber_limit)
126 /* the loop is necessary to handle having the limit lowered while
127 xchat is running */
128 size -= prefs.url_grabber_limit;
129 for(; size > 0; size--)
130 tree_remove_at_pos (url_tree, 0);
133 tree_append (url_tree, data);
134 fe_url_add (data);
137 /* check if a word is clickable. This is called on mouse motion events, so
138 keep it FAST! This new version was found to be almost 3x faster than
139 2.4.4 release. */
142 url_check_word (char *word, int len)
144 #define D(x) (x), ((sizeof (x)) - 1)
145 static const struct {
146 const char *s;
147 int len;
149 prefix[] = {
150 { D("irc.") },
151 { D("ftp.") },
152 { D("www.") },
153 { D("irc://") },
154 { D("ftp://") },
155 { D("http://") },
156 { D("https://") },
157 { D("file://") },
158 { D("rtsp://") },
159 { D("ut2004://") },
161 suffix[] = {
162 { D(".org") },
163 { D(".net") },
164 { D(".com") },
165 { D(".edu") },
166 { D(".html") },
167 { D(".info") },
168 { D(".name") },
170 #undef D
171 const char *at, *dot;
172 int i, dots;
174 if (len > 1 && word[1] == '#' && strchr("@+^%*#", word[0]))
175 return WORD_CHANNEL;
177 if ((word[0] == '#' || word[0] == '&') && word[1] != '#' && word[1] != 0)
178 return WORD_CHANNEL;
180 for (i = 0; i < G_N_ELEMENTS(prefix); i++)
182 int l;
184 l = prefix[i].len;
185 if (len > l)
187 int j;
189 /* This is pretty much strncasecmp(). */
190 for (j = 0; j < l; j++)
192 unsigned char c = word[j];
193 if (tolower(c) != prefix[i].s[j])
194 break;
196 if (j == l)
197 return WORD_URL;
201 at = strchr (word, '@'); /* check for email addy */
202 dot = strrchr (word, '.');
203 if (at && dot)
205 if (at < dot)
207 if (strchr (word, '*'))
208 return WORD_HOST;
209 else
210 return WORD_EMAIL;
214 /* check if it's an IP number */
215 dots = 0;
216 for (i = 0; i < len; i++)
218 if (word[i] == '.' && i > 0)
219 dots++; /* allow 127.0.0.1:80 */
220 else if (!isdigit ((unsigned char) word[i]) && word[i] != ':')
222 dots = 0;
223 break;
226 if (dots == 3)
227 return WORD_HOST;
229 if (len > 5)
231 for (i = 0; i < G_N_ELEMENTS(suffix); i++)
233 int l;
235 l = suffix[i].len;
236 if (len > l)
238 const unsigned char *p = &word[len - l];
239 int j;
241 /* This is pretty much strncasecmp(). */
242 for (j = 0; j < l; j++)
244 if (tolower(p[j]) != suffix[i].s[j])
245 break;
247 if (j == l)
248 return WORD_HOST;
252 if (word[len - 3] == '.' &&
253 isalpha ((unsigned char) word[len - 2]) &&
254 isalpha ((unsigned char) word[len - 1]))
255 return WORD_HOST;
258 return 0;
261 void
262 url_check_line (char *buf, int len)
264 char *po = buf;
265 char *start;
266 int wlen;
268 if (buf[0] == ':' && buf[1] != 0)
269 po++;
271 start = po;
273 /* check each "word" (space separated) */
274 while (1)
276 switch (po[0])
278 case 0:
279 case ' ':
281 wlen = po - start;
282 if (wlen > 2)
284 /* HACK! :( */
285 /* This is to work around not being able to detect URLs that are at
286 the start of messages. */
287 if (start[0] == ':')
289 start++;
290 wlen--;
292 if (start[0] == '+' || start[0] == '-')
294 start++;
295 wlen--;
298 if (wlen > 2 && url_check_word (start, wlen) == WORD_URL)
300 url_add (start, wlen);
303 if (po[0] == 0)
304 return;
305 po++;
306 start = po;
307 break;
309 default:
310 po++;