/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xchat.h"
#include "cfgfiles.h"
#include "fe.h"
#include "tree.h"
#include "url.h"
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif

void *url_tree = NULL;


static int
url_free (char *url, void *data)
{
	free (url);
	return TRUE;
}

void
url_clear (void)
{
	tree_foreach (url_tree, (tree_traverse_func *)url_free, NULL);
	tree_destroy (url_tree);
	url_tree = NULL;
}

static int
url_save_cb (char *url, FILE *fd)
{
	fprintf (fd, "%s\n", url);
	return TRUE;
}

void
url_save (const char *fname, const char *mode)
{
	FILE *fd;

	fd = fopen (fname, mode);
	if (fd == NULL)
		return;

	tree_foreach (url_tree, (tree_traverse_func *)url_save_cb, fd);
	fclose (fd);
}

void
url_autosave (void)
{
	char *buf;

	buf = malloc (512);
	snprintf (buf, 512, "%s/url.save", get_xdir_fs ());
	url_save (buf, "a");
	free (buf);
}

static int
url_find (char *urltext)
{
	int pos;

	if (tree_find (url_tree, urltext, (tree_cmp_func *)strcasecmp, NULL, &pos))
		return 1;
	return 0;
}

static void
url_add (char *urltext, int len)
{
	char *data = malloc (len + 1);
	if (!data)
		return;
	memcpy (data, urltext, len);
	data[len] = 0;

	if (data[len - 1] == '.')	/* chop trailing dot */
	{
		len--;
		data[len] = 0;
	}
	if (data[len - 1] == ')')	/* chop trailing ) */
		data[len - 1] = 0;

	if (url_find (data))
	{
		free (data);
		return;
	}

	if (!url_tree)
		url_tree = tree_new ((tree_cmp_func *)strcasecmp, NULL);

	tree_insert (url_tree, data);
	fe_url_add (data);
}

/* check if a word is clickable. This is called on mouse motion events, so
   keep it FAST! This new version was found to be almost 3x faster than
   2.4.4 release. */

int
url_check_word (char *word, int len)
{
	char *at, *dot;
	int i, dots;
	char temp[4];
	guint32 pre;

	if ((word[0] == '@' || word[0] == '+' || word[0] == '^' || word[0] == '%' || word[0] == '*' ) && word[1] == '#')
		return WORD_CHANNEL;

	if ((word[0] == '#' || word[0] == '&') && word[1] != '#' && word[1] != 0)
		return WORD_CHANNEL;

	if (len > 4 && word[4] != '.')
	{
		temp[0] = tolower (word[0]);
		temp[1] = tolower (word[1]);
		temp[2] = tolower (word[2]);
		temp[3] = tolower (word[3]);

		pre = *((guint32 *)temp);

		if (CMPL (pre, 'i','r','c','.'))
			return WORD_URL;
		if (CMPL (pre, 'f','t','p','.'))
			return WORD_URL;
		if (CMPL (pre, 'w','w','w','.'))
			return WORD_URL;

		if (len > 7 && word[4] == '/' && word[5] == '/')
		{
			if (CMPL (pre, 'i','r','c',':'))	/* irc:// */
				return WORD_URL;
			if (CMPL (pre, 'f','t','p',':'))	/* ftp:// */
				return WORD_URL;
		}

		/* check for ABCD://... */
		if (len > 8 && word[4] == ':' && word[5] == '/' && word[6] == '/')
		{
			if (CMPL (pre, 'h','t','t','p'))		/* http:// */
				return WORD_URL;
			if (CMPL (pre, 'f','i','l','e'))		/* file:// */
				return WORD_URL;
			if (CMPL (pre, 'r','t','s','p'))		/* rtsp:// */
				return WORD_URL;
		}

		/* check for https:// */
		if (len > 9 && word[5] == ':' && word[6] == '/' && word[7] == '/')
		{
			if (CMPL (pre, 'h','t','t','p') && (word[4] == 's' || word[4] == 'S'))
				return WORD_URL;
		}

		/* check for gopher:// */
		if (len > 10 && word[6] == ':' && word[7] == '/' && word[8] == '/')
		{
			if (CMPL (pre, 'g','o','p','h'))
				if (CMPW (word + 4, 'e','r') || CMPW (word + 4, 'E','R'))
					return WORD_URL;
		}
	}

	at = strchr (word, '@');	  /* check for email addy */
	dot = strrchr (word, '.');
	if (at && dot)
	{
		if (at < dot)
		{
			if (strchr (word, '*'))
				return WORD_HOST;
			else
				return WORD_EMAIL;
		}
	}
 
	/* check if it's an IP number */
	dots = 0;
	for (i = 0; i < len; i++)
	{
		if (word[i] == '.' && i > 1)
			dots++;	/* allow 127.0.0.1:80 */
		else if (!isdigit (word[i]) && word[i] != ':')
		{
			dots = 0;
			break;
		}
	}
	if (dots == 3)
		return WORD_HOST;

	if (len > 5)
	{
		/* create a lowercase version of the last 4 letters */
		temp[0] = tolower (word[len - 4]);
		temp[1] = tolower (word[len - 3]);
		temp[2] = tolower (word[len - 2]);
		temp[3] = tolower (word[len - 1]);

		pre = *((guint32 *)temp);

		if (word[len - 5] == '.')
		{
			if (CMPL (pre, 'h','t','m','l'))
				return WORD_HOST;
			if (CMPL (pre, 'i','n','f','o'))
				return WORD_HOST;
			if (CMPL (pre, 'n','a','m','e'))
				return WORD_HOST;
		}

		if (CMPL (pre, '.','o','r','g'))
			return WORD_HOST;
		if (CMPL (pre, '.','n','e','t'))
			return WORD_HOST;
		if (CMPL (pre, '.','c','o','m'))
			return WORD_HOST;
		if (CMPL (pre, '.','e','d','u'))
			return WORD_HOST;

		if (word[len - 3] == '.' &&
			 isalpha (word[len - 2]) && isalpha (word[len - 1]))
			return WORD_HOST;
	}

	return 0;
}

void
url_check_line (char *buf, int len)
{
	char *po = buf;
	char *start;
	int wlen;

	if (buf[0] == ':' && buf[1] != 0)
		po++;

	start = po;

	/* check each "word" (space separated) */
	while (1)
	{
		switch (po[0])
		{
		case 0:
		case ' ':
			wlen = po - start;
			if (wlen > 1)
			{
				if (url_check_word (start, wlen) == WORD_URL)
				{
					url_add (start, wlen);
				}
			}
			if (po[0] == 0)
				return;
			po++;
			start = po;
			break;

		default:
			po++;
		}
	}
}
