186883Smatusita/*
286883Smatusita * Copyright (c) 1999
386883Smatusita *	Philipp Mergenthaler <philipp.mergenthaler@stud.uni-karlsruhe.de>
486883Smatusita * All rights reserved.
586883Smatusita *
686883Smatusita * Redistribution and use in source and binary forms, with or without
786883Smatusita * modification, are permitted provided that the following conditions
886883Smatusita * are met:
986883Smatusita * 1. Redistributions of source code must retain the above copyright
1086883Smatusita *    notice, this list of conditions and the following disclaimer.
1186883Smatusita * 2. Redistributions in binary form must reproduce the above copyright
1286883Smatusita *    notice, this list of conditions and the following disclaimer in the
1386883Smatusita *    documentation and/or other materials provided with the distribution.
1486883Smatusita *
1586883Smatusita * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1686883Smatusita * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1786883Smatusita * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1886883Smatusita * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1986883Smatusita * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2086883Smatusita * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2186883Smatusita * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
2286883Smatusita * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2386883Smatusita * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2486883Smatusita * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2586883Smatusita * SUCH DAMAGE.
2686883Smatusita *
2786883Smatusita * $FreeBSD$
2886883Smatusita */
2986883Smatusita
3055393Sjkh#include "sysinstall.h"
3155393Sjkh#include <sys/socket.h>
3255393Sjkh#include <netinet/in.h>
3355393Sjkh#include <arpa/inet.h>
3455393Sjkh#include <sys/param.h>
3555393Sjkh#include <netdb.h>
3655393Sjkh
3769647Sjkhextern const char *ftp_dirs[]; /* defined in ftp.c */
3869647Sjkh
39248313SdteskeBoolean
40248313SdteskecheckAccess(Boolean connectCheckOnly, Boolean isProxy)
4155393Sjkh{
4263118Sume    int rv, s, af;
4366369Sjkh    bool el, found=FALSE;		    /* end of header line */
4469647Sjkh    char *cp, buf[PATH_MAX], req[BUFSIZ];
4563118Sume    struct addrinfo hints, *res, *res0;
4655393Sjkh
4763118Sume    af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
4863118Sume    memset(&hints, 0, sizeof(hints));
4963118Sume    hints.ai_family = af;
5063118Sume    hints.ai_socktype = SOCK_STREAM;
5163118Sume    hints.ai_protocol = 0;
5263118Sume    if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST),
5363118Sume			  variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) {
5463118Sume	msgConfirm("%s", gai_strerror(rv));
5569647Sjkh	variable_unset(VAR_HTTP_HOST);
5656573Sjkh	return FALSE;
5755393Sjkh    }
5863118Sume    s = -1;
5963118Sume    for (res = res0; res; res = res->ai_next) {
6063118Sume	if ((s = socket(res->ai_family, res->ai_socktype,
6163118Sume			res->ai_protocol)) < 0)
6263118Sume	    continue;
6363118Sume	if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
6463118Sume	    break;
6563118Sume	close(s);
6663118Sume	s = -1;
6755393Sjkh    }
6863118Sume    freeaddrinfo(res0);
6963118Sume    if (s == -1) {
70248313Sdteske	if (isProxy) {
71248313Sdteske		msgConfirm("Couldn't connect to proxy %s:%s",
72248313Sdteske			    variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
73248313Sdteske	} else {
74248313Sdteske		msgConfirm("Couldn't connect to server http://%s:%s/",
75248313Sdteske			    variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
76248313Sdteske	}
7769647Sjkh	variable_unset(VAR_HTTP_HOST);
7856573Sjkh	return FALSE;
7955393Sjkh    }
80248313Sdteske    if (connectCheckOnly) {
8169647Sjkh       close(s);
8269647Sjkh       return TRUE;
8366369Sjkh    }
8455393Sjkh
8566369Sjkh    msgNotify("Checking access to\n %s", variable_get(VAR_HTTP_PATH));
86248313Sdteske    if (isProxy)
87248313Sdteske	sprintf(req,"GET %s/ HTTP/1.0\r\n\r\n", variable_get(VAR_HTTP_PATH));
88248313Sdteske    else
89248313Sdteske	sprintf(req,"GET /%s/ HTTP/1.0\r\n\r\n", variable_get(VAR_HTTP_PATH));
9055393Sjkh    write(s,req,strlen(req));
9155393Sjkh/*
9255393Sjkh *  scan the headers of the response
9355393Sjkh *  this is extremely quick'n dirty
9455393Sjkh *
9555393Sjkh */
9669647Sjkh    bzero(buf, PATH_MAX);
9755393Sjkh    cp=buf;
9855393Sjkh    el=FALSE;
9955393Sjkh    rv=read(s,cp,1);
10055393Sjkh    variable_set2(VAR_HTTP_FTP_MODE,"",0);
10155393Sjkh    while (rv>0) {
10256573Sjkh	if ((*cp == '\012') && el) {
10356573Sjkh	    /* reached end of a header line */
10466369Sjkh	    if (!strncmp(buf,"HTTP",4)) {
10566369Sjkh		if (strtol((char *)(buf+9),0,0) == 200) {
10666369Sjkh		    found = TRUE;
10766369Sjkh		}
10866369Sjkh	    }
10966369Sjkh
110248313Sdteske	    /*
111248313Sdteske	     * Some proxies fetch files with certain extensions in "ascii mode"
112248313Sdteske	     * instead of "binary mode" for FTP. The FTP server then translates
113248313Sdteske	     * all LF to CRLF.
114248313Sdteske	     *
115248313Sdteske	     * You can force Squid to use binary mode by appending ";type=i" to
116248313Sdteske	     * the URL, which is what I do here. For other proxies, the
117248313Sdteske	     * LF->CRLF substitution is reverted in distExtract().
118248313Sdteske	     */
119248313Sdteske	    if (isProxy && !strncmp(buf,"Server: ",8)) {
12056573Sjkh		if (!strncmp(buf,"Server: Squid",13)) {
12156573Sjkh		    variable_set2(VAR_HTTP_FTP_MODE,";type=i",0);
12256573Sjkh		} else {
12356573Sjkh		    variable_set2(VAR_HTTP_FTP_MODE,"",0);
12456573Sjkh		}
12556573Sjkh	    }
12656573Sjkh	    /* ignore other headers */
12756573Sjkh	    /* check for "\015\012" at beginning of line, i.e. end of headers */
12856573Sjkh	    if ((cp-buf) == 1)
12956573Sjkh		break;
13056573Sjkh	    cp=buf;
13156573Sjkh	    rv=read(s,cp,1);
13256573Sjkh	} else {
13356573Sjkh	    el=FALSE;
13456573Sjkh	    if (*cp == '\015')
13556573Sjkh		el=TRUE;
13656573Sjkh	    cp++;
13756573Sjkh	    rv=read(s,cp,1);
13856573Sjkh	}
13955393Sjkh    }
14055393Sjkh    close(s);
14169647Sjkh    return found;
14269647Sjkh}
14369647Sjkh
14469647SjkhBoolean
14569647SjkhmediaInitHTTP(Device *dev)
14669647Sjkh{
14769647Sjkh    bool found=FALSE;		    /* end of header line */
14869647Sjkh    char *rel, req[BUFSIZ];
14969647Sjkh    int fdir;
15069647Sjkh
15169647Sjkh    /*
15269647Sjkh     * First verify the proxy access
15369647Sjkh     */
154248313Sdteske    checkAccess(TRUE, TRUE);
15569647Sjkh    while (variable_get(VAR_HTTP_HOST) == NULL) {
15669647Sjkh        if (DITEM_STATUS(mediaSetHTTP(NULL)) == DITEM_FAILURE)
15769647Sjkh            return FALSE;
158248313Sdteske        checkAccess(TRUE, TRUE);
15969647Sjkh    }
16069647Sjkhagain:
16169647Sjkh    /* If the release is specified as "__RELEASE" or "any", then just
16269647Sjkh     * assume that the path the user gave is ok.
16369647Sjkh     */
16469647Sjkh    rel = variable_get(VAR_RELNAME);
16569647Sjkh    /*
16669647Sjkh    msgConfirm("rel: -%s-", rel);
16769647Sjkh    */
16869647Sjkh
16969647Sjkh    if (strcmp(rel, "__RELEASE") && strcmp(rel, "any"))  {
17069647Sjkh        for (fdir = 0; ftp_dirs[fdir]; fdir++) {
17169647Sjkh            sprintf(req, "%s/%s/%s", variable_get(VAR_FTP_PATH),
17269647Sjkh                ftp_dirs[fdir], rel);
17369647Sjkh            variable_set2(VAR_HTTP_PATH, req, 0);
174248313Sdteske            if (checkAccess(FALSE, TRUE)) {
17569647Sjkh                found = TRUE;
17669647Sjkh                break;
17769647Sjkh            }
17869647Sjkh        }
17969647Sjkh    } else {
18069647Sjkh        variable_set2(VAR_HTTP_PATH, variable_get(VAR_FTP_PATH), 0);
181248313Sdteske        found = checkAccess(FALSE, TRUE);
18269647Sjkh    }
18369647Sjkh    if (!found) {
18466369Sjkh    	msgConfirm("No such directory: %s\n"
18566369Sjkh		   "please check the URL and try again.", variable_get(VAR_HTTP_PATH));
18669647Sjkh        variable_unset(VAR_HTTP_PATH);
18769647Sjkh        dialog_clear_norefresh();
18869647Sjkh        clear();
18969647Sjkh        if (DITEM_STATUS(mediaSetHTTP(NULL)) != DITEM_FAILURE) goto again;
19069647Sjkh    }
19166369Sjkh    return found;
19269647Sjkh}
19355393Sjkh
19455393SjkhFILE *
19555393SjkhmediaGetHTTP(Device *dev, char *file, Boolean probe)
19655393Sjkh{
19755393Sjkh    FILE *fp;
19863118Sume    int rv, s, af;
19955393Sjkh    bool el;			/* end of header line */
20056573Sjkh    char *cp, buf[PATH_MAX], req[BUFSIZ];
20163118Sume    struct addrinfo hints, *res, *res0;
20255393Sjkh
20363118Sume    af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
20463118Sume    memset(&hints, 0, sizeof(hints));
20563118Sume    hints.ai_family = af;
20663118Sume    hints.ai_socktype = SOCK_STREAM;
20763118Sume    hints.ai_protocol = 0;
20863118Sume    if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST),
20963118Sume			  variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) {
21063118Sume	msgConfirm("%s", gai_strerror(rv));
21156573Sjkh	return NULL;
21255393Sjkh    }
21363118Sume    s = -1;
21463118Sume    for (res = res0; res; res = res->ai_next) {
21563118Sume	if ((s = socket(res->ai_family, res->ai_socktype,
21663118Sume			res->ai_protocol)) < 0)
21763118Sume	    continue;
21863118Sume	if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
21963118Sume	    break;
22063118Sume	close(s);
22163118Sume	s = -1;
22263118Sume    }
22363118Sume    freeaddrinfo(res0);
22463118Sume    if (s == -1) {
22556573Sjkh	msgConfirm("Couldn't connect to proxy %s:%s",
22663118Sume		    variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
22756573Sjkh	return NULL;
22855393Sjkh    }
22956573Sjkh
23066369Sjkh    sprintf(req,"GET %s/%s%s HTTP/1.0\r\n\r\n",
23166369Sjkh	    variable_get(VAR_HTTP_PATH), file, variable_get(VAR_HTTP_FTP_MODE));
23256573Sjkh
23356573Sjkh    if (isDebug()) {
234106279Skuriyama	msgDebug("sending http request: %s\n",req);
23556573Sjkh    }
23655393Sjkh    write(s,req,strlen(req));
23755393Sjkh
23855393Sjkh/*
23955393Sjkh *  scan the headers of the response
24055393Sjkh *  this is extremely quick'n dirty
24155393Sjkh *
24255393Sjkh */
24355393Sjkh    cp=buf;
24455393Sjkh    el=FALSE;
24555393Sjkh    rv=read(s,cp,1);
24655393Sjkh    while (rv>0) {
24756573Sjkh	if ((*cp == '\012') && el) {
24856573Sjkh  	    /* reached end of a header line */
24956573Sjkh  	    if (!strncmp(buf,"HTTP",4)) {
25056573Sjkh		rv=strtol((char *)(buf+9),0,0);
25156573Sjkh		*(cp-1)='\0';		/* chop the CRLF off */
25256573Sjkh		if (probe && (rv != 200)) {
25356573Sjkh		    return NULL;
25456573Sjkh		} else if (rv >= 500) {
25556573Sjkh		    msgConfirm("Server error %s when sending %s, you could try an other server",buf, req);
25656573Sjkh		    return NULL;
25756573Sjkh		} else if (rv == 404) {
25856573Sjkh		    msgConfirm("%s was not found, maybe directory or release-version are wrong?",req);
25956573Sjkh		    return NULL;
26056573Sjkh		} else if (rv >= 400) {
26156573Sjkh		    msgConfirm("Client error %s, you could try an other server",buf);
26256573Sjkh		    return NULL;
26356573Sjkh		} else if (rv >= 300) {
264244676Sdteske		    msgConfirm("Error %s",buf);
26556573Sjkh		    return NULL;
26656573Sjkh		} else if (rv != 200) {
26756573Sjkh		    msgConfirm("Error %s when sending %s, you could try an other server",buf, req);
26856573Sjkh		    return NULL;
26956573Sjkh		}
27056573Sjkh	    }
27156573Sjkh	    /* ignore other headers */
27256573Sjkh	    /* check for "\015\012" at beginning of line, i.e. end of headers */
27356573Sjkh	    if ((cp-buf) == 1)
27456573Sjkh		break;
27556573Sjkh	    cp=buf;
27656573Sjkh	    rv=read(s,cp,1);
27756573Sjkh	} else {
27856573Sjkh	    el=FALSE;
27956573Sjkh	    if (*cp == '\015')
28056573Sjkh		el=TRUE;
28156573Sjkh	    cp++;
28256573Sjkh	    rv=read(s,cp,1);
28356573Sjkh	}
28455393Sjkh    }
28555393Sjkh    fp=fdopen(s,"r");
28655393Sjkh    return fp;
28755393Sjkh}
288