#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
#endif
#include <ctype.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <errno.h>
#include <assert.h>
#include "wget.h"
#include "utils.h"
#include "url.h"
#include "host.h"
#include "html.h"
#ifndef errno
extern int errno;
#endif
#define DEFAULT_HTTP_PORT 80
#define DEFAULT_FTP_PORT 21
#define URL_SEPARATOR "!\"#'(),>`{}|<>"
#ifndef WINDOWS
# define URL_UNSAFE " <>\"#%{}|\\^~[]`@:\033"
#else
# define URL_UNSAFE " <>\"%{}|\\^[]`\033"
#endif
#define URL_CLEANSE(s) do \
{ \
if (contains_unsafe (s)) \
{ \
char *uc_tmp = encode_string (s); \
free (s); \
(s) = uc_tmp; \
} \
} while (0)
#define DOTP(x) ((*(x) == '.') && (!*(x + 1)))
#define DDOTP(x) ((*(x) == '.') && (*(x + 1) == '.') && (!*(x + 2)))
static char *protostrings[] =
{
"cid:",
"clsid:",
"file:",
"finger:",
"ftp:",
"gopher:",
"hdl:",
"http:",
"https:",
"ilu:",
"ior:",
"irc:",
"java:",
"javascript:",
"lifn:",
"mailto:",
"mid:",
"news:",
"nntp:",
"path:",
"prospero:",
"rlogin:",
"service:",
"shttp:",
"snews:",
"stanf:",
"telnet:",
"tn3270:",
"wais:",
"whois++:",
NULL
};
struct proto
{
char *name;
uerr_t ind;
unsigned short port;
};
static struct proto sup_protos[] =
{
{ "http://", URLHTTP, DEFAULT_HTTP_PORT },
{ "ftp://", URLFTP, DEFAULT_FTP_PORT },
};
static void parse_dir PARAMS ((const char *, char **, char **));
static uerr_t parse_uname PARAMS ((const char *, char **, char **));
static char *construct PARAMS ((const char *, const char *, int , int));
static char *construct_relative PARAMS ((const char *, const char *));
static char process_ftp_type PARAMS ((char *));
int
skip_url (const char *url)
{
int i;
if (toupper (url[0]) == 'U'
&& toupper (url[1]) == 'R'
&& toupper (url[2]) == 'L'
&& url[3] == ':')
{
for (i = 4; url[i] && ISSPACE (url[i]); i++);
return i;
}
else
return 0;
}
int
contains_unsafe (const char *s)
{
for (; *s; s++)
if (strchr (URL_UNSAFE, *s))
return 1;
return 0;
}
static void
decode_string (char *s)
{
char *p = s;
for (; *s; s++, p++)
{
if (*s != '%')
*p = *s;
else
{
if (!*(s + 1) || !*(s + 2)
|| !(ISXDIGIT (*(s + 1)) && ISXDIGIT (*(s + 2))))
{
*p = *s;
continue;
}
*p = (ASC2HEXD (*(s + 1)) << 4) + ASC2HEXD (*(s + 2));
s += 2;
}
}
*p = '\0';
}
char *
encode_string (const char *s)
{
const char *b;
char *p, *res;
int i;
b = s;
for (i = 0; *s; s++, i++)
if (strchr (URL_UNSAFE, *s))
i += 2;
res = (char *)xmalloc (i + 1);
s = b;
for (p = res; *s; s++)
if (strchr (URL_UNSAFE, *s))
{
const unsigned char c = *s;
*p++ = '%';
*p++ = HEXD2ASC (c >> 4);
*p++ = HEXD2ASC (c & 0xf);
}
else
*p++ = *s;
*p = '\0';
return res;
}
uerr_t
urlproto (const char *url)
{
int i;
url += skip_url (url);
for (i = 0; i < ARRAY_SIZE (sup_protos); i++)
if (!strncasecmp (url, sup_protos[i].name, strlen (sup_protos[i].name)))
return sup_protos[i].ind;
for (i = 0; url[i] && url[i] != ':' && url[i] != '/'; i++);
if (url[i] == ':')
{
for (++i; url[i] && url[i] != '/'; i++)
if (!ISDIGIT (url[i]))
return URLBADPORT;
if (url[i - 1] == ':')
return URLFTP;
else
return URLHTTP;
}
else
return URLHTTP;
}
int
skip_proto (const char *url)
{
char **s;
int l;
for (s = protostrings; *s; s++)
if (!strncasecmp (*s, url, strlen (*s)))
break;
if (!*s)
return 0;
l = strlen (*s);
if (!strcmp (*s, "http:") || !strcmp (*s, "ftp:"))
l += 2;
return l;
}
static int
has_proto (const char *url)
{
char **s;
url += skip_url (url);
for (s = protostrings; *s; s++)
if (strncasecmp (url, *s, strlen (*s)) == 0)
return 1;
return 0;
}
int
skip_uname (const char *url)
{
const char *p;
for (p = url; *p && *p != '/'; p++)
if (*p == '@')
break;
if (*p == '@')
return p - url + 1;
else
return 0;
}
struct urlinfo *
newurl (void)
{
struct urlinfo *u;
u = (struct urlinfo *)xmalloc (sizeof (struct urlinfo));
memset (u, 0, sizeof (*u));
u->proto = URLUNKNOWN;
return u;
}
void
freeurl (struct urlinfo *u, int complete)
{
assert (u != NULL);
FREE_MAYBE (u->url);
FREE_MAYBE (u->host);
FREE_MAYBE (u->path);
FREE_MAYBE (u->file);
FREE_MAYBE (u->dir);
FREE_MAYBE (u->user);
FREE_MAYBE (u->passwd);
FREE_MAYBE (u->local);
FREE_MAYBE (u->referer);
if (u->proxy)
freeurl (u->proxy, 1);
if (complete)
free (u);
return;
}
uerr_t
parseurl (const char *url, struct urlinfo *u, int strict)
{
int i, l, abs_ftp;
int recognizable;
uerr_t type;
DEBUGP (("parseurl (\"%s\") -> ", url));
url += skip_url (url);
recognizable = has_proto (url);
if (strict && !recognizable)
return URLUNKNOWN;
for (i = 0, l = 0; i < ARRAY_SIZE (sup_protos); i++)
{
l = strlen (sup_protos[i].name);
if (!strncasecmp (sup_protos[i].name, url, l))
break;
}
if (recognizable && !sup_protos[i].name)
return URLUNKNOWN;
else if (i == ARRAY_SIZE (sup_protos))
type = URLUNKNOWN;
else
u->proto = type = sup_protos[i].ind;
if (type == URLUNKNOWN)
l = 0;
if (recognizable)
l += skip_uname (url + l);
for (i = l; url[i] && url[i] != ':' && url[i] != '/'; i++);
if (i == l)
return URLBADHOST;
u->host = strdupdelim (url + l, url + i);
DEBUGP (("host %s -> ", u->host));
u->port = 0;
if (url[i] == ':')
{
if (ISDIGIT (url[++i]))
{
if (type == URLUNKNOWN)
u->proto = type = URLHTTP;
for (; url[i] && url[i] != '/'; i++)
if (ISDIGIT (url[i]))
u->port = 10 * u->port + (url[i] - '0');
else
return URLBADPORT;
if (!u->port)
return URLBADPORT;
DEBUGP (("port %hu -> ", u->port));
}
else if (type == URLUNKNOWN)
u->proto = type = URLFTP;
else
return URLBADPORT;
}
else if (type == URLUNKNOWN)
u->proto = type = URLHTTP;
if (!u->port)
{
int i;
for (i = 0; i < ARRAY_SIZE (sup_protos); i++)
if (sup_protos[i].ind == type)
break;
if (i == ARRAY_SIZE (sup_protos))
return URLUNKNOWN;
u->port = sup_protos[i].port;
}
if (url[i] == '/' && url[i - 1] != ':')
++i;
if (type == URLHTTP)
while (url[i] && url[i] == '/')
++i;
u->path = (char *)xmalloc (strlen (url + i) + 8);
strcpy (u->path, url + i);
if (type == URLFTP)
{
u->ftp_type = process_ftp_type (u->path);
if (!u->ftp_type || toupper (u->ftp_type) == 'D')
u->ftp_type = 'I';
}
DEBUGP (("opath %s -> ", u->path));
parse_uname (url, &u->user, &u->passwd);
decode_string (u->host);
decode_string (u->path);
if (u->user)
decode_string (u->user);
if (u->passwd)
decode_string (u->passwd);
parse_dir (u->path, &u->dir, &u->file);
DEBUGP (("dir %s -> file %s -> ", u->dir, u->file));
path_simplify (u->dir);
if (type == URLHTTP && *u->dir == '/')
strcpy (u->dir, u->dir + 1);
DEBUGP (("ndir %s\n", u->dir));
l = strlen (u->dir);
if (l && u->dir[l - 1] == '/')
u->dir[l - 1] = '\0';
abs_ftp = (u->proto == URLFTP && *u->dir == '/');
strcpy (u->path, abs_ftp ? "%2F" : "/");
strcat (u->path, abs_ftp ? (u->dir + 1) : u->dir);
strcat (u->path, *u->dir ? "/" : "");
strcat (u->path, u->file);
URL_CLEANSE (u->path);
u->url = str_url (u, 0);
return URLOK;
}
static void
parse_dir (const char *path, char **dir, char **file)
{
int i, l;
for (i = l = strlen (path); i && path[i] != '/'; i--);
if (!i && *path != '/')
{
if (DOTP (path) || DDOTP (path))
{
*dir = xstrdup (path);
*file = xstrdup ("");
}
else
{
*dir = xstrdup ("");
*file = xstrdup (path);
}
}
else if (!i)
{
if (DOTP (path + 1) || DDOTP (path + 1))
{
*dir = xstrdup (path);
*file = xstrdup ("");
}
else
{
*dir = xstrdup ("/");
*file = xstrdup (path + 1);
}
}
else
{
if (DOTP (path + i + 1) || DDOTP (path + i + 1))
{
*dir = xstrdup (path);
*file = xstrdup ("");
}
else
{
*dir = strdupdelim (path, path + i);
*file = strdupdelim (path + i + 1, path + l + 1);
}
}
}
static uerr_t
parse_uname (const char *url, char **user, char **passwd)
{
int l;
const char *p, *col;
char **where;
*user = NULL;
*passwd = NULL;
url += skip_url (url);
l = skip_proto (url);
if (!l)
return URLUNKNOWN;
url += l;
for (p = url; *p && *p != '/'; p++)
if (*p == '@')
break;
if (*p != '@')
return URLOK;
for (p = col = url; *p != '@'; p++)
{
if (*p == ':' && !*user)
{
*user = (char *)xmalloc (p - url + 1);
memcpy (*user, url, p - url);
(*user)[p - url] = '\0';
col = p + 1;
}
}
where = *user ? passwd : user;
*where = (char *)xmalloc (p - col + 1);
memcpy (*where, col, p - col);
(*where)[p - col] = '\0';
return URLOK;
}
static char
process_ftp_type (char *path)
{
int len = strlen (path);
if (len >= 7
&& !memcmp (path + len - 7, ";type=", 6))
{
path[len - 7] = '\0';
return path[len - 1];
}
else
return '\0';
}
char *
str_url (const struct urlinfo *u, int hide)
{
char *res, *host, *user, *passwd, *proto_name, *dir, *file;
int i, l, ln, lu, lh, lp, lf, ld;
for (i = 0; i < ARRAY_SIZE (sup_protos); i++)
if (sup_protos[i].ind == u->proto)
break;
if (i == ARRAY_SIZE (sup_protos))
return NULL;
proto_name = sup_protos[i].name;
host = CLEANDUP (u->host);
dir = CLEANDUP (u->dir);
file = CLEANDUP (u->file);
user = passwd = NULL;
if (u->user)
user = CLEANDUP (u->user);
if (u->passwd)
{
int i;
passwd = CLEANDUP (u->passwd);
if (hide)
for (i = 0; passwd[i]; i++)
passwd[i] = 'x';
}
if (u->proto == URLFTP && *dir == '/')
{
char *tmp = (char *)xmalloc (strlen (dir) + 3);
*tmp = '%';
tmp[1] = '2';
tmp[2] = 'F';
strcpy (tmp + 3, dir + 1);
free (dir);
dir = tmp;
}
ln = strlen (proto_name);
lu = user ? strlen (user) : 0;
lp = passwd ? strlen (passwd) : 0;
lh = strlen (host);
ld = strlen (dir);
lf = strlen (file);
res = (char *)xmalloc (ln + lu + lp + lh + ld + lf + 20);
l = 0;
memcpy (res, proto_name, ln);
l += ln;
if (user)
{
memcpy (res + l, user, lu);
l += lu;
if (passwd)
{
res[l++] = ':';
memcpy (res + l, passwd, lp);
l += lp;
}
res[l++] = '@';
}
memcpy (res + l, host, lh);
l += lh;
res[l++] = ':';
long_to_string (res + l, (long)u->port);
l += numdigit (u->port);
res[l++] = '/';
memcpy (res + l, dir, ld);
l += ld;
if (*dir)
res[l++] = '/';
strcpy (res + l, file);
free (host);
free (dir);
free (file);
FREE_MAYBE (user);
FREE_MAYBE (passwd);
return res;
}
int
url_equal (const char *url1, const char *url2)
{
struct urlinfo *u1, *u2;
uerr_t err;
int res;
u1 = newurl ();
err = parseurl (url1, u1, 0);
if (err != URLOK)
{
freeurl (u1, 1);
return 0;
}
u2 = newurl ();
err = parseurl (url2, u2, 0);
if (err != URLOK)
{
freeurl (u2, 1);
return 0;
}
res = !strcmp (u1->url, u2->url);
freeurl (u1, 1);
freeurl (u2, 1);
return res;
}
static const char *
findurl (const char *buf, int howmuch, int *count)
{
char **prot;
const char *s1, *s2;
for (s1 = buf; howmuch; s1++, howmuch--)
for (prot = protostrings; *prot; prot++)
if (howmuch <= strlen (*prot))
continue;
else if (!strncasecmp (*prot, s1, strlen (*prot)))
{
for (s2 = s1, *count = 0;
howmuch && *s2 && *s2 >= 32 && *s2 < 127 && !ISSPACE (*s2) &&
!strchr (URL_SEPARATOR, *s2);
s2++, (*count)++, howmuch--);
return s1;
}
return NULL;
}
urlpos *
get_urls_file (const char *file)
{
long nread;
FILE *fp;
char *buf;
const char *pbuf;
int size;
urlpos *first, *current, *old;
if (file && !HYPHENP (file))
{
fp = fopen (file, "rb");
if (!fp)
{
logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
return NULL;
}
}
else
fp = stdin;
load_file (fp, &buf, &nread);
if (file && !HYPHENP (file))
fclose (fp);
DEBUGP (("Loaded %s (size %ld).\n", file, nread));
first = current = NULL;
for (pbuf = buf; (pbuf = findurl (pbuf, nread - (pbuf - buf), &size));
pbuf += size)
{
old = current;
current = (urlpos *)xmalloc (sizeof (urlpos));
if (old)
old->next = current;
memset (current, 0, sizeof (*current));
current->next = NULL;
current->url = (char *)xmalloc (size + 1);
memcpy (current->url, pbuf, size);
current->url[size] = '\0';
if (!first)
first = current;
}
free (buf);
return first;
}
urlpos *
get_urls_html (const char *file, const char *this_url, int silent)
{
long nread;
FILE *fp;
char *orig_buf;
const char *buf;
int step, first_time;
urlpos *first, *current, *old;
if (file && !HYPHENP (file))
{
fp = fopen (file, "rb");
if (!fp)
{
logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
return NULL;
}
}
else
fp = stdin;
load_file (fp, &orig_buf, &nread);
if (file && !HYPHENP (file))
fclose (fp);
DEBUGP (("Loaded HTML file %s (size %ld).\n", file, nread));
first = current = NULL;
first_time = 1;
for (buf = orig_buf;
(buf = htmlfindurl (buf, nread - (buf - orig_buf), &step, first_time));
buf += step)
{
int i, no_proto;
int size = step;
const char *pbuf = buf;
char *constr, *base;
const char *cbase;
first_time = 0;
while ((pbuf < buf + step) && ISSPACE (*pbuf))
{
++pbuf;
--size;
}
while (size && ISSPACE (pbuf[size - 1]))
--size;
if (!size)
break;
for (i = 0; protostrings[i]; i++)
{
if (!strncasecmp (protostrings[i], pbuf,
MINVAL (strlen (protostrings[i]), size)))
break;
}
if (protostrings[i]
&& !(strncasecmp (pbuf, "http:", 5) == 0
&& strncasecmp (pbuf, "http://", 7) != 0))
{
no_proto = 0;
}
else
{
no_proto = 1;
if ((size > 5) && !strncasecmp ("http:", pbuf, 5))
pbuf += 5, size -= 5;
}
if (!no_proto)
{
for (i = 0; i < ARRAY_SIZE (sup_protos); i++)
{
if (!strncasecmp (sup_protos[i].name, pbuf,
MINVAL (strlen (sup_protos[i].name), size)))
break;
}
if (i == ARRAY_SIZE (sup_protos))
continue;
}
if (no_proto)
{
cbase = html_base ();
if (!cbase)
cbase = this_url;
if (!cbase)
cbase = opt.base_href;
if (!cbase)
{
if (!opt.quiet && !silent)
{
char *temp = (char *)malloc (size + 1);
strncpy (temp, pbuf, size);
temp[size] = '\0';
logprintf (LOG_NOTQUIET,
_("Error (%s): Link %s without a base provided.\n"),
file, temp);
free (temp);
}
continue;
}
if (this_url)
base = construct (this_url, cbase, strlen (cbase),
!has_proto (cbase));
else
{
if (!has_proto (cbase))
{
logprintf (LOG_NOTQUIET, _("\
Error (%s): Base %s relative, without referer URL.\n"),
file, cbase);
continue;
}
base = xstrdup (cbase);
}
constr = construct (base, pbuf, size, no_proto);
free (base);
}
else
{
constr = (char *)xmalloc (size + 1);
strncpy (constr, pbuf, size);
constr[size] = '\0';
}
#ifdef DEBUG
if (opt.debug)
{
char *tmp;
const char *tmp2;
tmp2 = html_base ();
tmp = (char *)xmalloc (size + 1);
strncpy (tmp, pbuf, size);
tmp[size] = '\0';
logprintf (LOG_ALWAYS,
"file %s; this_url %s; base %s\nlink: %s; constr: %s\n",
file, this_url ? this_url : "(null)",
tmp2 ? tmp2 : "(null)", tmp, constr);
free (tmp);
}
#endif
old = current;
current = (urlpos *)xmalloc (sizeof (urlpos));
if (old)
old->next = current;
if (!first)
first = current;
memset (current, 0, sizeof (*current));
current->next = NULL;
current->url = constr;
current->size = size;
current->pos = pbuf - orig_buf;
if (no_proto && *pbuf != '/')
current->flags |= (URELATIVE | UNOPROTO);
else if (no_proto)
current->flags |= UNOPROTO;
}
free (orig_buf);
return first;
}
void
free_urlpos (urlpos *l)
{
while (l)
{
urlpos *next = l->next;
free (l->url);
FREE_MAYBE (l->local_name);
free (l);
l = next;
}
}
void
rotate_backups(const char *fname)
{
int maxlen = strlen (fname) + 1 + numdigit (opt.backups) + 1;
char *from = (char *)alloca (maxlen);
char *to = (char *)alloca (maxlen);
struct stat sb;
int i;
if (stat (fname, &sb) == 0)
if (S_ISREG (sb.st_mode) == 0)
return;
for (i = opt.backups; i > 1; i--)
{
sprintf (from, "%s.%d", fname, i - 1);
sprintf (to, "%s.%d", fname, i);
rename (from, to);
}
sprintf (to, "%s.%d", fname, 1);
rename(fname, to);
}
int
mkalldirs (const char *path)
{
const char *p;
char *t;
struct stat st;
int res;
p = path + strlen (path);
for (; *p != '/' && p != path; p--);
if ((p == path) && (*p != '/'))
return 0;
t = strdupdelim (path, p);
if ((stat (t, &st) == 0))
{
if (S_ISDIR (st.st_mode))
{
free (t);
return 0;
}
else
{
DEBUGP (("Removing %s because of directory danger!\n", t));
unlink (t);
}
}
res = make_directory (t);
if (res != 0)
logprintf (LOG_NOTQUIET, "%s: %s", t, strerror (errno));
free (t);
return res;
}
static int
count_slashes (const char *s)
{
int i = 0;
while (*s)
if (*s++ == '/')
++i;
return i;
}
static char *
mkstruct (const struct urlinfo *u)
{
char *host, *dir, *file, *res, *dirpref;
int l;
assert (u->dir != NULL);
assert (u->host != NULL);
if (opt.cut_dirs)
{
char *ptr = u->dir + (*u->dir == '/');
int slash_count = 1 + count_slashes (ptr);
int cut = MINVAL (opt.cut_dirs, slash_count);
for (; cut && *ptr; ptr++)
if (*ptr == '/')
--cut;
STRDUP_ALLOCA (dir, ptr);
}
else
dir = u->dir + (*u->dir == '/');
host = xstrdup (u->host);
if (opt.add_hostdir && !opt.simple_check)
{
char *nhost = realhost (host);
free (host);
host = nhost;
}
if (opt.add_hostdir)
{
if (!DOTP (opt.dir_prefix))
{
dirpref = (char *)alloca (strlen (opt.dir_prefix) + 1
+ strlen (host) + 1);
sprintf (dirpref, "%s/%s", opt.dir_prefix, host);
}
else
STRDUP_ALLOCA (dirpref, host);
}
else
{
if (!DOTP (opt.dir_prefix))
dirpref = opt.dir_prefix;
else
dirpref = "";
}
free (host);
if (*dirpref)
{
char *newdir = (char *)alloca (strlen (dirpref) + 1 + strlen (dir) + 2);
sprintf (newdir, "%s%s%s", dirpref, *dir == '/' ? "" : "/", dir);
dir = newdir;
}
dir = xstrdup (dir);
URL_CLEANSE (dir);
l = strlen (dir);
if (l && dir[l - 1] == '/')
dir[l - 1] = '\0';
if (!*u->file)
file = "index.html";
else
file = u->file;
res = (char *)xmalloc (strlen (dir) + 1 + strlen (file) + 1);
sprintf (res, "%s%s%s", dir, *dir ? "/" : "", file);
free (dir);
return res;
}
char *
url_filename (const struct urlinfo *u)
{
char *file, *name;
int have_prefix = 0;
if (opt.dirstruct)
{
file = mkstruct (u);
have_prefix = 1;
}
else
{
if (!*u->file)
file = xstrdup ("index.html");
else
file = xstrdup (u->file);
}
if (!have_prefix)
{
if (!DOTP (opt.dir_prefix))
{
char *nfile = (char *)xmalloc (strlen (opt.dir_prefix)
+ 1 + strlen (file) + 1);
sprintf (nfile, "%s/%s", opt.dir_prefix, file);
free (file);
file = nfile;
}
}
#ifdef WINDOWS
{
char *p = file;
for (p = file; *p; p++)
if (*p == '%')
*p = '@';
}
#endif
if ((opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct)
&& !(file_exists_p (file) && !file_non_directory_p (file)))
return file;
name = unique_name (file);
free (file);
return name;
}
static char *
construct (const char *url, const char *sub, int subsize, int no_proto)
{
char *constr;
if (no_proto)
{
int i;
if (*sub != '/')
{
for (i = strlen (url); i && url[i] != '/'; i--);
if (!i || (url[i] == url[i - 1]))
{
int l = strlen (url);
char *t = (char *)alloca (l + 2);
strcpy (t, url);
t[l] = '/';
t[l + 1] = '\0';
url = t;
i = l;
}
constr = (char *)xmalloc (i + 1 + subsize + 1);
strncpy (constr, url, i + 1);
constr[i + 1] = '\0';
strncat (constr, sub, subsize);
}
else
{
int fl;
i = 0;
do
{
for (; url[i] && url[i] != '/'; i++);
if (!url[i])
break;
fl = (url[i] == url[i + 1] && url[i + 1] == '/');
if (fl)
i += 2;
}
while (fl);
if (!url[i])
{
int l = strlen (url);
char *t = (char *)alloca (l + 2);
strcpy (t, url);
t[l] = '/';
t[l + 1] = '\0';
url = t;
}
constr = (char *)xmalloc (i + 1 + subsize + 1);
strncpy (constr, url, i);
constr[i] = '\0';
strncat (constr + i, sub, subsize);
constr[i + subsize] = '\0';
}
}
else
{
constr = (char *)xmalloc (subsize + 1);
strncpy (constr, sub, subsize);
constr[subsize] = '\0';
}
return constr;
}
void
opt_url (struct urlinfo *u)
{
char *host = realhost (u->host);
free (u->host);
u->host = host;
assert (u->dir != NULL);
free (u->url);
u->url = str_url (u, 0);
}
char *
getproxy (uerr_t proto)
{
if (proto == URLHTTP)
return opt.http_proxy ? opt.http_proxy : getenv ("http_proxy");
else if (proto == URLFTP)
return opt.ftp_proxy ? opt.ftp_proxy : getenv ("ftp_proxy");
else
return NULL;
}
int
no_proxy_match (const char *host, const char **no_proxy)
{
if (!no_proxy)
return 1;
else
return !sufmatch (no_proxy, host);
}
void
convert_links (const char *file, urlpos *l)
{
FILE *fp;
char *buf, *p, *p2;
long size;
logprintf (LOG_VERBOSE, _("Converting %s... "), file);
fp = fopen (file, "rb");
if (!fp)
{
logprintf (LOG_NOTQUIET, _("Cannot convert links in %s: %s\n"),
file, strerror (errno));
return;
}
load_file (fp, &buf, &size);
fclose (fp);
fp = fopen (file, "wb");
if (!fp)
{
logprintf (LOG_NOTQUIET, _("Cannot convert links in %s: %s\n"),
file, strerror (errno));
free (buf);
return;
}
for (p = buf; l; l = l->next)
{
if (l->pos >= size)
{
DEBUGP (("Something strange is going on. Please investigate."));
break;
}
if ((l->flags & URELATIVE) || !(l->flags & UABS2REL))
{
DEBUGP (("Skipping %s at position %d (flags %d).\n", l->url,
l->pos, l->flags));
continue;
}
for (p2 = buf + l->pos; p < p2; p++)
putc (*p, fp);
if (l->flags & UABS2REL)
{
char *newname = construct_relative (file, l->local_name);
fprintf (fp, "%s", newname);
DEBUGP (("ABS2REL: %s to %s at position %d in %s.\n",
l->url, newname, l->pos, file));
free (newname);
}
p += l->size;
}
if (p - buf < size)
{
for (p2 = buf + size; p < p2; p++)
putc (*p, fp);
}
fclose (fp);
free (buf);
logputs (LOG_VERBOSE, _("done.\n"));
}
static char *
construct_relative (const char *s1, const char *s2)
{
int i, cnt, sepdirs1;
char *res;
if (*s2 == '/')
return xstrdup (s2);
assert (*s1 != '/');
i = cnt = 0;
while (1)
{
while (s1[i] && s2[i]
&& (s1[i] == s2[i])
&& (s1[i] != '/')
&& (s2[i] != '/'))
++i;
if (s1[i] == '/' && s2[i] == '/')
cnt = ++i;
else
break;
}
for (sepdirs1 = 0; s1[i]; i++)
if (s1[i] == '/')
++sepdirs1;
res = (char *)xmalloc (3 * sepdirs1 + strlen (s2 + cnt) + 1);
for (i = 0; i < sepdirs1; i++)
memcpy (res + 3 * i, "../", 3);
strcpy (res + 3 * i, s2 + cnt);
return res;
}
urlpos *
add_url (urlpos *l, const char *url, const char *file)
{
urlpos *t;
t = (urlpos *)xmalloc (sizeof (urlpos));
memset (t, 0, sizeof (*t));
t->url = xstrdup (url);
t->local_name = xstrdup (file);
t->next = l;
return t;
}