/*
**  Copyright 2000-2004 University of Illinois Board of Trustees
**  Copyright 2000-2004 Mark D. Roth
**  All rights reserved.
**
**  url.c - FTP URL parsing code
**
**  Mark D. Roth <roth@feep.net>
*/

#include <internal.h>

#include <stdio.h>
#include <errno.h>

#ifdef STDC_HEADERS
# include <string.h>
#endif


/* decode "%xx" hex encodings in string and write the decoded version to buf */
static int
_url_decode(char *string, char *buf, size_t bufsize)
{
	char cbuf[] = "x";
	char *cp;
	unsigned int c;

	buf[0] = '\0';

	while ((cp = strchr(string, '%')) != NULL)
	{
		*cp++ = '\0';
		if (sscanf(cp, "%2x", &c) != 1)
		{
			errno = EINVAL;
			return -1;
		}
		if (strlcat(buf, string, bufsize) > bufsize)
		{
			errno = ENAMETOOLONG;
			return -1;
		}
		cbuf[0] = c;
		if (strlcat(buf, cbuf, bufsize) > bufsize)
		{
			errno = ENAMETOOLONG;
			return -1;
		}
		string = cp + 2;
	}

	if (strlcat(buf, string, bufsize) > bufsize)
	{
		errno = ENAMETOOLONG;
		return -1;
	}

	return 0;
}


/* parse RFC-1738 style URL and fill in caller-supplied fields */
int
ftp_url_parse(char *url, struct ftp_url *ftpurl)
{
	char newurl[sizeof(struct ftp_url)];
	char *cp, *fieldp, *nextp;
	size_t sz;

	ftpurl->fu_hostname[0] = '\0';
	ftpurl->fu_login[0] = '\0';
	ftpurl->fu_passwd[0] = '\0';
	ftpurl->fu_path[0] = '\0';

	if (strlcpy(newurl, url, sizeof(newurl)) > sizeof(newurl))
	{
		errno = ENAMETOOLONG;
		return -1;
	}

	nextp = newurl;
	if (strncmp("ftp://", newurl, 6) == 0)
		nextp += 6;

	fieldp = nextp;

	/* save type if present */
	if ((cp = strrchr(fieldp, ';')) != NULL
	    && strncmp(cp + 1, "type=", 5) == 0)
	{
		*cp++ = '\0';
		switch (cp[5])
		{
		case 'a':
		case 'i':
		case 'd':
			ftpurl->fu_type = cp[5];
			break;
		default:
			errno = EINVAL;
			return -1;
		}
	}
	else
		ftpurl->fu_type = '?';

	/* save path if present */
	if ((nextp = strchr(fieldp, '/')) != NULL)
		*nextp++ = '\0';
	if (nextp != NULL && *nextp != '\0')
	{
		if (_url_decode(nextp, ftpurl->fu_path,
				sizeof(ftpurl->fu_path)) == -1)
			return -1;
		sz = strlen(ftpurl->fu_path) - 1;
		if (sz > 0
		    && ftpurl->fu_path[sz] == '/')
			ftpurl->fu_path[sz] = '\0';
	}
	else
	{
		if (strlcat(ftpurl->fu_path, ".",
			    sizeof(ftpurl->fu_path)) > sizeof(ftpurl->fu_path))
		{
			errno = ENAMETOOLONG;
			return -1;
		}
	}

	/* parse "user:pass@" if present */
	if ((nextp = strchr(fieldp, '@')) != NULL
	    && nextp != fieldp)
	{
		*nextp++ = '\0';
		if ((cp = strchr(fieldp, ':')) != NULL)
		{
			*cp++ = '\0';
			if (_url_decode(cp, ftpurl->fu_passwd,
					sizeof(ftpurl->fu_passwd)) == -1)
				return -1;
		}
		if (_url_decode(fieldp, ftpurl->fu_login,
				sizeof(ftpurl->fu_login)) == -1)
			return -1;
		fieldp = nextp;
	}

	/* what's left is the hostname */
	if (_url_decode(fieldp, ftpurl->fu_hostname,
			sizeof(ftpurl->fu_hostname)) == -1)
		return -1;

	return 0;
}




syntax highlighted by Code2HTML, v. 0.9.1