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 51 int fetchLastErrCode; 52 const char *fetchLastErrText; 53 54 /* get URL */ 55 FILE * 56 fetchGetURL(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 */ 80 FILE * 81 fetchPutURL(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 */ 108 url_t * 109 fetchParseURL(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 163 nohost: 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 183 ouch: 184 free(u); 185 return NULL; 186 } 187 188 void 189 fetchFreeURL(url_t *u) 190 { 191 if (u) { 192 if (u->doc) 193 free(u->doc); 194 free(u); 195 } 196 } 197 198 int 199 fetchConnect(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, IPPROTO_TCP)) < 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