/* vi:ts=4:sw=4
*
* url.c
* open URL
*
* code contributions By: Atsushi Nakamura anaka@mrit.mei.co.jp
*/
#ifdef MDOMAIN
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
#include "ops.h"
#ifdef JP
# include "jp.h"
#endif
#include <fcntl.h>
#if !defined(pyr) && !defined(NOT_BOTH_TIME)
# include <time.h> /* on some systems time.h should not be
included together with sys/time.h */
#endif
#ifndef M_XENIX
# include <sys/types.h>
#endif
#ifdef SYSV_UNIX
# if defined(__sgi) || defined(UTS2) || defined(UTS4) || defined(AUX3)
# include <sys/time.h>
# endif
# if defined(M_XENIX) || defined(SCO)
# include <stropts.h>
# endif
# if defined(M_XENIX) || defined(SCO) || defined(UNICOS) || defined(AIX31)
# include <sys/select.h>
# else
# if !defined(AUX3)
# include <poll.h>
# endif
# endif
# if defined(SCO) || defined(ISC)
# include <sys/stream.h>
# include <sys/ptem.h>
# endif
# if defined(M_UNIX) && !defined(SCO)
# include <sys/time.h>
# endif /* M_UNIX */
#else /* SYSV_UNIX */
# include <sys/time.h>
#endif /* !SYSV_UNIX */
#if defined(FD_ZERO) && defined(SYSV_UNIX)
# undef FD_ZERO
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#ifdef _POSIX_VERSION
#include <sys/utsname.h>
#endif
#include <pwd.h>
#ifdef JP
extern char *UAJVersion;
#else
extern char *UAVersion;
#endif
extern gettimeofday();
#define BUFSIZE 100
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 64
#endif
#ifndef MAXPATHLEN
# define MAXPATHLEN 1024
#endif
#define MAXPROTO 20
#define MAXPORT 20
#define MAXURL (MAXHOSTNAMELEN + MAXPORT + MAXPATHLEN)
static char *dow[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
static char *moy[12]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static char hostname[MAXHOSTNAMELEN + 1] = "";
static char loginname[MAXHOSTNAMELEN + 1] = "";
static int uid, pid, count = 0;
static char domainname[MAXHOSTNAMELEN + 1] = MDOMAIN;
static char curl[MAXURL + 1] = "";
static int parse_url(), read_line(), send_line(), fd_wait();
static void const_url(), pinfo_init();
int
is_url(url)
char *url;
{
char proto[MAXPROTO];
proto[0] = NUL;
parse_url(url, proto, NULL, NULL, NULL);
if ( !strcmp(proto, "http")
|| ( *p_proxy && !strcmp(proto, "ftp")) )
return 1;
return 0;
}
void
url_init(url)
char *url;
{
p_curl = curl;
if (! *curl)
const_url(curl, "http", "localhost", "", "");
if (!url)
return;
if (is_url(url))
{
strncpy(curl, url, MAXURL);
curl[MAXURL] = NUL;
}
}
enum e_proto { PROTO_HTTP, PROTO_FTP, PROTO_ERROR };
int url_open(url, mode, total)
char *url;
int mode, *total;
{
char proto[MAXPROTO + 1];
char host[MAXHOSTNAMELEN + 1];
char port[MAXPORT + 1];
char path[MAXPATHLEN + 1], lpath[MAXPATHLEN + 1];
char furl[MAXURL + 1];
char cbuf[MAXURL + 11];
char temp[20], status[20], type[20];
char *cp, *cp2;
int size;
int fd;
struct sockaddr_in dest;
struct hostent *hostinfo;
struct servent *servinfo;
struct tm *tm;
time_t now;
enum e_proto protocol;
if (mode != O_RDONLY && mode != O_WRONLY)
return -1;
if (!*curl)
url_init(NULL);
if (!loginname[0])
pinfo_init();
parse_url(url, NULL, NULL, NULL, lpath);
parse_url(curl, proto, host, port, path);
if (parse_url(url, proto, host, port, path))
return -1;
const_url(furl, proto, host, port, path);
if (*p_proxy)
{
/* parse proxy server */
cp = p_proxy;
cp2 = host;
while(*cp && *cp != ':')
*cp2 ++ = *cp ++;
*cp2 = NUL;
if (*cp == ':')
strcpy(port, cp + 1);
strcpy(proto, "http");
}
if (! strcmp(proto, "http") )
protocol = PROTO_HTTP;
else if (! strcmp(proto, "ftp") )
protocol = PROTO_FTP;
else
protocol = PROTO_ERROR;
smsg("Resolving %s", host);
if (! (hostinfo = gethostbyname(host)))
{
emsg2("Host %s unknown.", host);
return -1;
}
msg("");
memset((void *)&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(atoi(port));
if (!dest.sin_port)
{
if (*port)
{
if (! (servinfo = getservbyname(port, NULL)) )
{
emsg2("Service '%s' unknown.", port);
return -1;
}
dest.sin_port = servinfo -> s_port;
}
else if ((servinfo = getservbyname(proto, NULL)))
dest.sin_port = servinfo -> s_port;
else
switch(protocol)
{
case PROTO_HTTP:
dest.sin_port = htons(80);
break;
case PROTO_FTP:
dest.sin_port = htons(21);
break;
default:
emsg2("Default Service for '%s' unknown.", proto);
return -1;
}
}
memcpy(&dest.sin_addr, hostinfo->h_addr, hostinfo->h_length);
if((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
emsg("Socket allocation error.");
return -1;
}
smsg("Connecting to %s", host);
fflush(stderr);
if(connect(fd, (struct sockaddr *)&dest, sizeof(dest)) == -1)
{
switch(errno)
{
case EACCES:
emsg("Search permission denied.");
break;
case EADDRNOTAVAIL:
emsg("Address not available.");
break;
case ECONNREFUSED:
emsg("Connection rejected.");
break;
case ENETUNREACH:
emsg("Network unreachable.");
break;
case ETIMEDOUT:
emsg("Connection timed out.");
break;
}
return -1;
}
switch(protocol)
{
case PROTO_HTTP:
/* header request */
smsg("sending request to %s.", host);
if (p_ntr)
fprintf(stderr, "\n");
if (mode == O_WRONLY)
sprintf(cbuf, "PUT %s HTTP/1.0", *p_proxy ? furl : path);
else
sprintf(cbuf, "GET %s HTTP/1.0", *p_proxy ? furl : path);
if (send_line(fd, cbuf))
goto fail;
/* general header*/
/* send date and time in RFC1123 format */
now = time(NULL);
tm = gmtime(&now);
sprintf(cbuf, "DATE: %s, %02d %s %4d %02d:%02d:%02d GMT",
dow[tm->tm_wday], tm->tm_mday, moy[tm->tm_mon],
1900 + tm->tm_year,
tm->tm_hour, tm->tm_min, tm->tm_sec);
if (send_line(fd, cbuf))
goto fail;
/* send message ID in RFC822 format */
sprintf(cbuf, "Message-ID: <%04X%x.%s@%s.%s>",
pid, count++ , loginname, hostname, domainname);
if (send_line(fd, cbuf))
goto fail;
/* send MIME Version*/
if (send_line(fd, "MIME-Version: 1.0"))
goto fail;
/* request header*/
/* send Accept */
if (send_line(fd, "Accept: */*"))
goto fail;
/* send Accept Character set */
if (send_line(fd, "Accept-Charset: ISO-2022-JP"))
goto fail;
/* send Accept Encoding */
if (send_line(fd, "Accept-Encoding: *"))
goto fail;
/* send user agent */
#ifdef JP
sprintf(cbuf, "User-Agent: %s", UAJVersion);
#else
sprintf(cbuf, "User-Agent: %s", UAVersion);
#endif
if (send_line(fd, cbuf))
goto fail;
/* send from */
sprintf(cbuf, "From: %s@%s.%s", loginname, hostname, domainname);
if (send_line(fd, cbuf))
goto fail;
/* end of header */
if (send_line(fd, ""))
goto fail;
if(mode == O_WRONLY && fd_wait(fd, 15) <= 0)
goto fail;
/* read response line */
smsg("waiting response from %s", host);
if (p_ntr)
fprintf(stderr, "\n");
if ((size = read_line(fd, cbuf)) < 0)
goto fail;
sscanf(cbuf, "%s %s", temp, status);
if (status[0] != '2')
{
/* show all error messages */
smsg("%s\n", cbuf);
while((size = read_line(fd, cbuf)))
if (size < 0)
break;
close(fd);
goto fail;
}
/* read response header */
*total = -1;
type[0] = NUL;
while((size = read_line(fd, cbuf)))
{
char *cp;
if (size < 0)
goto fail;
for(cp = cbuf; *cp && *cp != ':'; cp++)
if ('A' <= *cp && *cp <= 'Z')
*cp -= 'A' - 'a';
if (!strncmp("content-length", cbuf, 14))
sscanf(cbuf, "%[^:]: %d", temp, total);
else if (!strncmp("content-type", cbuf, 12))
sscanf(cbuf, "%[^:]: %s", temp, type);
/*
not implemented yet.
*/
}
if (p_ntr)
{
wait_return();
updateScreen(CLEAR);
}
smsg("%d bytes %s", *total, type);
/* if (strncmp(type, "text", 4))
{
emsg2("File format(%s) is not text.", type);
close(fd);
goto fail;
}
*/
break;
case PROTO_FTP:
default:
/*
Not implemented yet.
*/
break;
}
/*
strcpy(curl, furl);
p_curl = curl;
*/
return fd;
fail:
if (p_ntr)
{
fprintf(stderr, "Error....\n");
wait_return();
}
return -1;
}
static int
fd_wait(fd, sec)
int fd;
int sec;
{
#ifdef UNIX
#if defined(SYSV_UNIX) && !defined(M_XENIX) && !defined(UNICOS) && !defined(AUX3)
struct pollfd fds[2];
fds[0].fd = 0;
fds[1].fd = fd;
fds[0].events =
fds[1].events = POLLIN;
if (!poll(fds, 2, sec * 1000))
return 0;
if ((fds[0].revents & (POLLIN | POLLERR | POLLHUP))
||(fds[1].revents & (POLLERR | POLLHUP)))
return -1;
# else
extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(fd, &fds);
FD_SET(0, &fds);
timeout.tv_sec = sec;
timeout.tv_usec = 0;
if (select(32, &fds, NULL, NULL, &timeout) <= 0)
return 0;
if (!FD_ISSET(fd, &fds))
return -1;
# endif
return 1;
#else
return 1;
#endif
}
static void
const_url(url, proto, host, port, path)
char *url, *proto, *host, *port, *path;
{
sprintf(url, "%s://%s", proto, host);
if (*port)
sprintf(url + strlen(url), ":%s", port);
strcat(url, path);
}
static int
parse_url(url, proto, host, port, path)
char *url, *proto, *host, *port, *path;
{
char *cp;
char *orgpath;
/* protocol */
for(cp = url; *cp && *cp != ':'; cp++);
if (*cp)
{
if (cp - url > MAXPROTO)
return -1;
if (proto)
{
if (port && strncmp(proto, url, strlen(proto)))
*port = NUL;
while(url != cp)
*proto++ = *url++;
*proto = NUL;
}
url = cp = cp + 1;
}
else
cp = url;
/* host address & port number */
if (*cp == '/' && *(cp + 1) == '/')
{
url = cp = cp + 2;
for(; *cp && *cp != ':' && *cp != '/' ; cp++);
if (cp - url > MAXHOSTNAMELEN)
return -1;
if (host)
{
while(url != cp)
*host++ = *url++;
*host = NUL;
}
if (*cp == ':')
{
for(url = cp = cp + 1; *cp && *cp != '/'; cp++);
if (cp - url > MAXPROTO)
return -1;
if (port)
while(url != cp)
*port++ = *url++;
}
if (port)
*port = NUL;
}
/* path */
if (!path)
return 0;
if (*cp)
{
orgpath = path;
if (*cp != '/')
{
for(;*path; path++);
for(;*path != '/' && path != orgpath; path--);
}
if ((int)strlen(cp) + (path - orgpath) > MAXPATHLEN)
return -1;
if (*cp != '/')
*path++ = '/';
while(*cp)
*path++ = *cp++;
}
*path = NUL;
return 0;
}
static int
send_line(fd, line)
int fd;
char *line;
{
if (p_ntr)
fprintf(stderr, "< %s\n", line);
if (write(fd, line, strlen(line)) >= 0
&& write(fd, "\r\n", 2) >= 0 )
return 0;
close(fd);
return -1;
}
static int
read_line(fd, line)
int fd;
char *line;
{
char c, *top;
int i, size;
switch(fd_wait(fd, p_nto))
{
case 0:
emsg("Timed out.");
close(fd);
return -1;
case -1:
emsg("Interrupted.");
close(fd);
return -1;
default:
break;
}
top = line;
for(size = 0; 1; size++, line++)
{
i = read(fd, &c, 1);
if (i == 0)
{
close(fd);
return -1;
}
if (c == '\r')
{
read(fd, &c, 1);
break;
}
if (c == '\n')
break;
*line = c;
}
*line = NUL;
if (p_ntr)
fprintf(stderr, "> %s\n", top);
return size;
}
static void
pinfo_init()
{
char *cp, *cp2;
#ifdef _POSIX_VERSION
struct utsname uts;
uname(&uts);
cp = uts.nodename;
cp2 = hostname;
while(*cp && cp2 - hostname < MAXHOSTNAMELEN)
*cp2 ++ = *cp ++;
*cp2 = NUL;
#else
gethostname(hostname, MAXHOSTNAMELEN);
#endif
if ((cp2 = strchr(hostname, '.')) != NULL)
*cp2 = NUL;
uid = getuid();
cp = getpwuid(uid)->pw_name;
cp2 = loginname;
while(*cp && cp2 - loginname < MAXHOSTNAMELEN)
*cp2 ++ = *cp ++;
pid = getpid();
if ((cp = getenv("DOMAINNAME")))
{
if ((int)strlen(cp) < MAXHOSTNAMELEN)
strcpy(domainname, cp);
else
emsg("Environment variable DOMAINNAME too long.");
}
else if (!strcmp(domainname, "localhost"))
emsg("Recompile this program setting MDOMAIN....");
}
int
do_nget(args)
char *args;
{
char *url, *file;
char *cp;
int rfd, wfd;
int i, size, total;
/* int bps; */
url = args;
file = "";
for(cp = args; *cp && *cp != ' ' && *cp != '\t'; cp++);
if (args == cp)
{
emsg("URL and filename are required.");
return -1;
}
else if (*cp)
{ /* 2 parameters are specified */
*cp++ = NUL;
for(; *cp && (*cp == ' ' || *cp == '\t'); cp++);
file = cp;
for(; *cp && *cp != ' ' && *cp != '\t'; cp++);
/* more than 2 parameters */
if (*cp)
{
emsg("Only URL and filename are required.");
return -1;
}
}
if (! *file)
{ /* if file is not specified */
for(cp = url; *cp; cp++);
if (* (cp - 1) == '/')
{
emsg("Filename is required.");
return -1;
}
for(;cp != url && *cp != '/' && *cp != ':'; cp--);
if (*cp == '/' || *cp == ':')
cp++;
file = cp;
}
if (!is_url(url))
{
emsg2("%s is not URL.", url);
return -1;
}
if ((rfd = url_open(url, O_RDONLY, &total)) < 0)
return -1;
if ((wfd = open(file, O_WRONLY | O_CREAT | O_EXCL, 0744)) < 0)
{
emsg2("file '%s' cannot open for writing.", file);
return -1;
}
size = 0;
while((i = read(rfd, IObuff, IOSIZE)))
{
write(wfd, IObuff, i);
size += i;
/* bps = speed(i); */
if (size > 1024)
smsg("%d/%d Kbytes", size >> 10, total >> 10);
else
smsg("%d/%d bytes", size, total);
}
smsg("%d bytes transferred", size);
close(rfd);
close(wfd);
return 0;
}
/*
static int
speed(size)
int size;
{
static struct timeval tprev = { 0, 0 };
struct timeval now, diff;
int rate;
gettimeofday(&now, NULL);
rate = 0;
if (tprev.tv_sec || tprev.tv_usec)
{
diff.tv_sec = now.tv_sec - tprev.tv_sec;
diff.tv_usec = now.tv_usec - tprev.tv_usec;
if (diff.tv_usec < 0)
{
diff.tv_sec --;
diff.tv_usec += 1000000;
}
size <<= 8;
diff.tv_sec <<= 8;
diff.tv_usec <<= 8;
diff.tv_sec += (diff.tv_usec / 1000000);
if (diff.tv_sec)
rate = size / diff.tv_sec;
else
rate = -1;
}
tprev = now;
return rate;
}
*/
#endif /* MDOMAIN */
syntax highlighted by Code2HTML, v. 0.9.1