fetch.c revision 37571
1/*-
2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 *	$Id: fetch.c,v 1.1.1.1 1998/07/09 16:52:42 des Exp $
29 */
30
31#include <sys/param.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <netinet/in.h>
35
36#include <ctype.h>
37#include <netdb.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include "fetch.h"
44
45#ifndef NDEBUG
46#define DEBUG(x) do x; while (0)
47#else
48#define DEBUG(x) do { } while (0)
49#endif
50
51int fetchLastErrCode;
52const char *fetchLastErrText;
53
54/* get URL */
55FILE *
56fetchGetURL(char *URL, char *flags)
57{
58    url_t *u;
59    FILE *f;
60
61    /* parse URL */
62    if ((u = fetchParseURL(URL)) == NULL)
63	return NULL;
64
65    /* select appropriate function */
66    if (strcasecmp(u->scheme, "file") == 0)
67	f = fetchGetFile(u, flags);
68    else if (strcasecmp(u->scheme, "http") == 0)
69	f = fetchGetHTTP(u, flags);
70    else if (strcasecmp(u->scheme, "ftp") == 0)
71	f = fetchGetFTP(u, flags);
72    else f = NULL;
73
74    fetchFreeURL(u);
75    return f;
76}
77
78
79/* put URL */
80FILE *
81fetchPutURL(char *URL, char *flags)
82{
83    url_t *u;
84    FILE *f;
85
86    /* parse URL */
87    if ((u = fetchParseURL(URL)) == NULL)
88	return NULL;
89
90    /* select appropriate function */
91    if (strcasecmp(u->scheme, "file") == 0)
92	f = fetchPutFile(u, flags);
93    else if (strcasecmp(u->scheme, "http") == 0)
94	f = fetchPutHTTP(u, flags);
95    else if (strcasecmp(u->scheme, "ftp") == 0)
96	f = fetchPutFTP(u, flags);
97    else f = NULL;
98
99    fetchFreeURL(u);
100    return f;
101}
102
103/*
104 * Split an URL into components. URL syntax is:
105 * method:[//[user[:pwd]@]host[:port]]/[document]
106 * This almost, but not quite, RFC1738 URL syntax.
107 */
108url_t *
109fetchParseURL(char *URL)
110{
111    char *p, *q;
112    url_t *u;
113    int i;
114
115    /* allocate url_t */
116    if ((u = calloc(1, sizeof(url_t))) == NULL)
117	return NULL;
118
119    /* scheme name */
120    for (i = 0; *URL && (*URL != ':'); URL++)
121	if (i < URL_SCHEMELEN)
122	    u->scheme[i++] = *URL;
123    if (!URL[0] || (URL[1] != '/'))
124	goto ouch;
125    else URL++;
126    if (URL[1] != '/') {
127	p = URL;
128	goto nohost;
129    }
130    else URL += 2;
131
132    p = strpbrk(URL, "/@");
133    if (*p == '@') {
134	/* username */
135	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
136	    if (i < URL_USERLEN)
137		u->user[i++] = *q;
138
139	/* password */
140	if (*q == ':')
141	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
142		if (i < URL_PWDLEN)
143		    u->pwd[i++] = *q;
144
145	p++;
146    } else p = URL;
147
148    /* hostname */
149    for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
150	if (i < MAXHOSTNAMELEN)
151	    u->host[i++] = *p;
152
153    /* port */
154    if (*p == ':') {
155	for (q = ++p; *q && (*q != '/'); q++)
156	    if (isdigit(*q))
157		u->port = u->port * 10 + (*q - '0');
158	    else return 0; /* invalid port */
159	while (*p && (*p != '/'))
160	    p++;
161    }
162
163nohost:
164    /* document */
165    if (*p)
166	u->doc = strdup(p);
167    u->doc = strdup(*p ? p : "/");
168    if (!u->doc)
169	goto ouch;
170
171    DEBUG(fprintf(stderr,
172		  "scheme:   [\033[1m%s\033[m]\n"
173		  "user:     [\033[1m%s\033[m]\n"
174		  "password: [\033[1m%s\033[m]\n"
175		  "host:     [\033[1m%s\033[m]\n"
176		  "port:     [\033[1m%d\033[m]\n"
177		  "document: [\033[1m%s\033[m]\n",
178		  u->scheme, u->user, u->pwd,
179		  u->host, u->port, u->doc));
180
181    return u;
182
183ouch:
184    free(u);
185    return NULL;
186}
187
188void
189fetchFreeURL(url_t *u)
190{
191    if (u) {
192	if (u->doc)
193	    free(u->doc);
194	free(u);
195    }
196}
197
198int
199fetchConnect(char *host, int port)
200{
201    struct sockaddr_in sin;
202    struct hostent *he;
203    int sd;
204
205    /* look up host name */
206    if ((he = gethostbyname(host)) == NULL)
207	return -1;
208
209    /* set up socket address structure */
210    bzero(&sin, sizeof(sin));
211    bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
212    sin.sin_family = he->h_addrtype;
213    sin.sin_port = htons(port);
214
215    /* try to connect */
216    if ((sd = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
217	return -1;
218    if (connect(sd, (struct sockaddr *)&sin, sizeof sin) < 0) {
219	close(sd);
220	return -1;
221    }
222
223    return sd;
224}
225