/*
** 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