#include <linux/if.h>
#include <linux/route.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>

#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "devices.h"
#include "install.h"
#include "log.h"
#include "newt.h"
#include "net.h"
#include "perror.h"
#include "windows.h"

struct intfconfig_s {
    newtComponent ipLabel, nmLabel, brLabel, naLabel;
    newtComponent ipEntry, nmEntry, brEntry, naEntry;
    char * ip, * nm, * br, * na;
};

struct netconfig_s {
    newtComponent nsLabels[3], gwLabel, hnLabel, dnLabel;
    newtComponent nsEntrys[3], gwEntry, hnEntry, dnEntry;
    char * ns[3], * gw, * hn, * dn;
};

static void ipCallback(newtComponent co, void * data);
static void hnCallback(newtComponent co, void * data);

static int setupNetworkInterface(char * device, struct netInterface * intf,
			         struct driversLoaded ** dl, int justConfig);
static int doBringUpNetworking(struct netInterface * intf, 
			       struct netConfig * netc,
			       struct driversLoaded ** dl, int justConfig);

int addDefaultRoute(struct netConfig netc) {
    int s;
    struct rtentry route;
    struct sockaddr_in addr;

    if (testing) return 0;

    if (!strlen(netc.defaultGateway)) return 0;

    s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0) {
	close(s);
	errorWindow("socket: %s");
	return 1;
    }

    memset(&route, 0, sizeof(route));

    addr.sin_family = AF_INET;
    addr.sin_port = 0;
    inet_aton(netc.defaultGateway, &addr.sin_addr);
    memcpy(&route.rt_gateway, &addr, sizeof(addr));

    addr.sin_addr.s_addr = INADDR_ANY;
    memcpy(&route.rt_dst, &addr, sizeof(addr));
    memcpy(&route.rt_genmask, &addr, sizeof(addr));

    route.rt_flags = RTF_UP | RTF_GATEWAY;
    route.rt_metric = 0;

    if (ioctl(s, SIOCADDRT, &route)) {
	close(s);
	errorWindow("SIOCADDRT: %s");
	return 1;
    }

    return 0;
}

int configureNetDevice(struct netInterface intf) {
    struct ifreq req;
    struct rtentry route;
    int s;
    struct sockaddr_in addr;
    struct in_addr ia;
    char ip[20], nm[20], nw[20], bc[20];

    addr.sin_family = AF_INET;
    addr.sin_port = 0;

    memcpy(&ia, &intf.ip, sizeof(intf.ip));
    strcpy(ip, inet_ntoa(ia));

    memcpy(&ia, &intf.netmask, sizeof(intf.netmask));
    strcpy(nm, inet_ntoa(ia));

    memcpy(&ia, &intf.broadcast, sizeof(intf.broadcast));
    strcpy(bc, inet_ntoa(ia));

    memcpy(&ia, &intf.network, sizeof(intf.network));
    strcpy(nw, inet_ntoa(ia));

    logMessage("configuring %s ip: %s nm: %s nw: %s bc: %s", intf.dev,
		ip, nm, nw, bc);

    if (testing) return 0;
    
    strcpy(req.ifr_name, intf.dev);
    addr.sin_family = AF_INET;
    addr.sin_port = 0;
    memcpy(&addr.sin_addr, &intf.ip, sizeof(intf.ip));

    s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0) {
	errorWindow("socket: %s");
	return 1;
    }

    memcpy(&req.ifr_addr, &addr, sizeof(addr));
    if (ioctl(s, SIOCSIFADDR, &req)) {
	close(s);
	errorWindow("SIOCSIFADDR: %s");
	return 1;
    }

    memcpy(&addr.sin_addr, &intf.broadcast, sizeof(intf.broadcast));
    memcpy(&req.ifr_broadaddr, &addr, sizeof(addr));
    if (ioctl(s, SIOCSIFBRDADDR, &req)) {
	close(s);
	errorWindow("SIOCSIFNETMASK: %s");
	return 1;
    }

    memcpy(&addr.sin_addr, &intf.netmask, sizeof(intf.netmask));
    memcpy(&req.ifr_netmask, &addr, sizeof(addr));
    if (ioctl(s, SIOCSIFNETMASK, &req)) {
	close(s);
	errorWindow("SIOCSIFNETMASK: %s");
	return 1;
    }

    req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
    if (ioctl(s, SIOCSIFFLAGS, &req)) {
	close(s);
	errorWindow("SIOCSIFFLAGS: %s");
	return 1;
    }

    memset(&route, 0, sizeof(route));
    route.rt_dev = intf.dev;
    route.rt_flags = RTF_UP;

    memcpy(&addr.sin_addr, &intf.network, sizeof(intf.netmask));
    memcpy(&route.rt_dst, &addr, sizeof(addr));

    memcpy(&addr.sin_addr, &intf.netmask, sizeof(intf.netmask));
    memcpy(&route.rt_genmask, &addr, sizeof(addr));

    if (ioctl(s, SIOCADDRT, &route)) {
	close(s);
	errorWindow("SIOCADDRT: %s");
	return 1;
    }

    return 0;
}

int netDeviceAvailable(char * device) {
    struct ifreq req;
    int s;
    
    s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0) {
	close(s);
	errorWindow("socket: %s");
	return 1;
    }

    strcpy(req.ifr_name, device);

    if (ioctl(s, SIOCGIFFLAGS, &req)) {
	/* if we can't get the flags, the networking device isn't available */
	close(s);
	return 0;
    }
  
    return 1;
}

static int setupNetworkInterface(char * device, struct netInterface * intf,
			         struct driversLoaded ** dl, int justConfig) {
    newtComponent okay, cancel, f, answer;
    int top = 3;
    struct intfconfig_s c;
    struct in_addr addr;
    int rc;

    if (!netDeviceAvailable(device)) {
	if ((rc = loadDeviceDriver(DRIVER_ETHERNET, dl)))
	    return rc;
    }

    newtOpenWindow(17, 4, 45, 15, "Configure TCP/IP");

    c.ipLabel = newtLabel(1, top    , "IP address:");
    c.nmLabel = newtLabel(1, top + 1, "Netmask:");
    c.naLabel = newtLabel(1, top + 2, "Network address:");
    c.brLabel = newtLabel(1, top + 3, "Broadcast address:");
   
    if (!intf->isConfigured){
	c.ipEntry = newtEntry(20, top    , "", 16, &c.ip, 0);
	c.nmEntry = newtEntry(20, top + 1, "", 16, &c.nm, 0);
	c.naEntry = newtEntry(20, top + 2, "", 16, &c.na, 0);
	c.brEntry = newtEntry(20, top + 3, "", 16, &c.br, 0);
    } else {
	memcpy(&addr, &intf->ip, sizeof(intf->ip));
	c.ipEntry = newtEntry(20, top    , inet_ntoa(addr), 16, &c.ip, 0);
	memcpy(&addr, &intf->netmask, sizeof(intf->netmask));
	c.nmEntry = newtEntry(20, top + 1, inet_ntoa(addr), 16, &c.nm, 0);
	memcpy(&addr, &intf->network, sizeof(intf->network));
	c.naEntry = newtEntry(20, top + 2, inet_ntoa(addr), 16, &c.na, 0);
	memcpy(&addr, &intf->broadcast, sizeof(intf->broadcast));
	c.brEntry = newtEntry(20, top + 3, inet_ntoa(addr), 16, &c.br, 0);
    }
   
    f = newtForm(NULL, NULL, 0);
    newtFormAddComponents(f, c.ipLabel, c.nmLabel, c.naLabel, c.brLabel, 
			     c.ipEntry, c.nmEntry, c.naEntry, c.brEntry, NULL);

    newtComponentAddCallback(c.ipEntry, ipCallback, &c);
    newtComponentAddCallback(c.nmEntry, ipCallback, &c);

    okay = newtButton(8, 10, "Ok");
    cancel = newtButton(28, 10, "Cancel");

    newtFormAddComponents(f, okay, cancel, NULL);

    answer = newtRunForm(f);

    if (answer == cancel) {
	newtFormDestroy(f);
	newtPopWindow();

	return INST_CANCEL;
    }

    strcpy(intf->dev, device);
    inet_aton(c.ip, (struct in_addr *) &intf->ip);
    inet_aton(c.nm, (struct in_addr *) &intf->netmask);
    inet_aton(c.br, (struct in_addr *) &intf->broadcast);
    inet_aton(c.na, (struct in_addr *) &intf->network);

    intf->isConfigured = 1;

    if (!justConfig) 
	if (configureNetDevice(*intf)) return INST_ERROR;

    newtFormDestroy(f);
    newtPopWindow();

    return 0;
} 

static void hnCallback(newtComponent co, void * dptr) {
    char * buf;
    struct netconfig_s * data = dptr;

    if (strlen(data->hn)) return;
    if (!strlen(data->dn)) return;

    buf = alloca(strlen(data->dn) + 5);
    strcpy(buf, ".");
    strcat(buf, data->dn);
    
    newtEntrySet(data->hnEntry, buf, 0);
}

static void ipCallback(newtComponent co, void * dptr) {
    struct intfconfig_s * data = dptr;
    struct in_addr ipaddr, nmaddr, addr;
    char * ascii;

    if (co == data->ipEntry) {
	if (strlen(data->ip) && !strlen(data->nm)) {
	    if (inet_aton(data->ip, &ipaddr)) {
		ipaddr.s_addr = ntohl(ipaddr.s_addr);
		if (((ipaddr.s_addr & 0xFF000000) >> 24) <= 127)
		    ascii = "255.0.0.0";
		else if (((ipaddr.s_addr & 0xFF000000) >> 24) <= 191)
		    ascii = "255.255.0.0";
		else 
		    ascii = "255.255.255.0";
		newtEntrySet(data->nmEntry, ascii, 1);
	    }
	}
    } else if (co == data->nmEntry) {
	if (!strlen(data->ip) || !strlen(data->nm)) return;
	if (!inet_aton(data->ip, &ipaddr)) return;
	if (!inet_aton(data->nm, &nmaddr)) return;

	if (!strlen(data->na)) {
	    addr.s_addr = ipaddr.s_addr & nmaddr.s_addr;
	    ascii = inet_ntoa(addr);
	    newtEntrySet(data->naEntry, ascii, 1);
	}
	if (!strlen(data->br)) {
	    addr.s_addr = (ipaddr.s_addr & nmaddr.s_addr) | (~nmaddr.s_addr);
	    ascii = inet_ntoa(addr);
	    newtEntrySet(data->brEntry, ascii, 1);
	}
    }
}

int writeNetConfig(char * prefix, struct netConfig * netc, 
		   struct netInterface * gwdev, int verbose) {
    char filename[100];
    FILE * f;

    if (testing) return 0;

    sprintf(filename, "%s/network", prefix);

    f = fopen(filename, "w");
    if (!f) {
	errorWindow("cannot create network config file: %s");
	return INST_ERROR;
    }

    fprintf(f, "NETWORKING=yes\n");

    logMessage("writing network information to %s", filename);

    if (netc->isConfigured) {
	logMessage("\tnetwork is configured, writing complete information");
	fprintf(f, "HOSTNAME=%s\n", netc->hostname);
	fprintf(f, "DOMAINNAME=%s\n", netc->domainname);

	if (gwdev && strlen(netc->defaultGateway)) {
	    fprintf(f, "GATEWAY=%s\n", netc->defaultGateway);
	    fprintf(f, "GATEWAYDEV=%s\n", gwdev->dev);
	}

	if (verbose) {
	    if (netc->nameserver[0])
		fprintf(f, "NS1=%s\n", netc->nameserver[0]);
	    
	    if (netc->nameserver[1])
		fprintf(f, "NS2=%s\n", netc->nameserver[1]);
	    
	    if (netc->nameserver[2])
		fprintf(f, "NS3=%s\n", netc->nameserver[2]);
	}
    } else {
	logMessage("\tnetwork is not configured");
	fprintf(f, "HOSTNAME=localhost\n");
    }

    fclose(f);

    return 0;
}

int writeHosts(char * prefix, struct netConfig * netc, 
	       struct netInterface * intf) {
    char filename[100];
    FILE * f;
    struct in_addr * addrptr;
    char * nickname;
    int i;

    if (testing) return 1;

    sprintf(filename, "%s/hosts", prefix);

    f = fopen(filename, "w");
    if (!f) {
	errorWindow("cannot create /etc/hosts: %s");
	return INST_ERROR;
    }

    logMessage("writing host information to %s", filename);

    fprintf(f, "127.0.0.1\t\tlocalhost\n");
    if (netc->isConfigured) {
	addrptr = (struct in_addr *) &intf->ip;
	i = strlen(netc->hostname) - strlen(netc->domainname);
	if (i > 1 && !strcmp(netc->hostname + i, netc->domainname)
	    && netc->hostname[i - 1] == '.') {
	    nickname = strdup(netc->hostname);
	    nickname[i - 1] = '\0';
	    fprintf(f, "%s\t\t%s %s\n", inet_ntoa(*addrptr),
			netc->hostname, nickname);
	    free(nickname);
	} else {
	    fprintf(f, "%s\t\t%s\n", inet_ntoa(*addrptr),
			netc->hostname);
	}

	sethostname(netc->hostname, strlen(netc->hostname));
    }

    fclose(f);

    return 0;
}

int writeResolvConf(char * prefix, struct netConfig * netc) {
    char filename[100];
    FILE * f;

    if (testing) return 1;
    if (!netc->isConfigured) {
	logMessage("networking is not configured - not writing resolv.conf");
	return 0;
    }

    sprintf(filename, "%s/resolv.conf", prefix);

    f = fopen(filename, "w");
    if (!f) {
	errorWindow("cannot create resolv.conf: %s");
	return INST_ERROR;
    }

    logMessage("writing nameservices information to %s", filename);

    fprintf(f, "search %s\n", netc->domainname);

    if (netc->nameserver[0])
	fprintf(f, "nameserver %s\n", netc->nameserver[0]);
    
    if (netc->nameserver[1])
	fprintf(f, "nameserver %s\n", netc->nameserver[1]);
    
    if (netc->nameserver[2])
	fprintf(f, "nameserver %s\n", netc->nameserver[2]);

    fclose(f);

    return 0;
}

int writeNetInterfaceConfig(char * prefix, struct netInterface * intf) {
    char filename[100];
    FILE * f;
    struct in_addr * addrptr;

    if (testing) return 0;

    if (!intf->isConfigured) {
	logMessage("network interface is not configured - not creating "
		   "ifcfg-*");
	return(0);
    }

    sprintf(filename, "%s/ifcfg-%s", prefix, intf->dev);

    f = fopen(filename, "w");
    if (!f) {
	errorWindow("cannot create network device config file: %s");
	return INST_ERROR;
    }

    logMessage("writing network information to %s", filename);
    
    fprintf(f, "DEVICE=%s\n", intf->dev);

    addrptr = (struct in_addr *) &intf->ip;
    fprintf(f, "IPADDR=%s\n", inet_ntoa(*addrptr));

    addrptr = (struct in_addr *) &intf->netmask;
    fprintf(f, "NETMASK=%s\n", inet_ntoa(*addrptr));

    addrptr = (struct in_addr *) &intf->network;
    fprintf(f, "NETWORK=%s\n", inet_ntoa(*addrptr));

    addrptr = (struct in_addr *) &intf->broadcast;
    fprintf(f, "BROADCAST=%s\n", inet_ntoa(*addrptr));

    fprintf(f, "ONBOOT=yes\n");

    fclose(f);

    return 0;
}

int readNetInterfaceConfig(char * prefix, char * device, 
				  struct netInterface * intf) {
    FILE * f;
    char * start, * end;
    char buf[250];
    int line = 0;

    intf->isConfigured = 0;

    if (testing) {
	return 0;
    }

    sprintf(buf, "%s/ifcfg-%s", prefix, device);

    f = fopen(buf, "r");
    if (!f) {
	if (errno != ENOENT) {
	    errorWindow("cannot open file: %s");
	    return INST_ERROR;
	} else {
	    intf->ip = 0;
	    return 0;
	}
    }

    while (fgets(buf, sizeof(buf) - 1, f)) {
	line++;

	start = buf;

	/* skipping leading spaces */
	while (*start && isspace(*start)) start++;
	if (!*start) continue;

	/* skip comments */
	if (*start == '#') continue;

	/* cut off trailing spaces and \n */
	end = start + strlen(start) - 2;
	while (isspace(*end)) end--;
	end++;
	*end = '\0';	
	end--;
	
	if (!strncmp("IPADDR=", start, 7)) {
	    start += 7;
	    inet_aton(start, (struct in_addr *) &intf->ip);
	} else if (!strncmp("NETMASK=", start, 8)) {
	    start += 8;
	    inet_aton(start, (struct in_addr *) &intf->netmask);
	} else if (!strncmp("NETWORK=", start, 8)) {
	    start += 8;
	    inet_aton(start, (struct in_addr *) &intf->network);
	} else if (!strncmp("BROADCAST=", start, 10)) {
	    start += 10;
	    inet_aton(start, (struct in_addr *) &intf->broadcast);
	}
    }

    fclose(f);

    strcpy(intf->dev, device);
    intf->useBootp = 0;

    intf->isConfigured = 1;

    return 0;
}

int configureNetwork(struct netConfig * netc, 
		     const struct netInterface * intf) {
    struct netconfig_s n;
    int top = 3;
    newtComponent f, okay, cancel, answer;
    struct in_addr ia;
    int32 ipnum;
    char * chptr;
    int i;

    newtOpenWindow(15, 4, 50, 15, "Configure Network");

    n.dnLabel = newtLabel(1, top    , "Domain name:");
    n.hnLabel = newtLabel(1, top + 1, "Host name:");
    n.gwLabel = newtLabel(1, top + 2, "Default gateway (IP):");
    n.nsLabels[0] = newtLabel(1, top + 3, "Primary nameserver (IP):");
    n.nsLabels[1] = newtLabel(1, top + 4, "Secondary nameserver (IP):");
    n.nsLabels[2] = newtLabel(1, top + 5, "Tertiary nameserver (IP):");

    n.dnEntry = newtEntry(28, top    , "", 20, &n.dn, NEWT_ENTRY_SCROLL);
    n.hnEntry = newtEntry(28, top + 1, "", 20, &n.hn, NEWT_ENTRY_SCROLL);
    n.gwEntry = newtEntry(28, top + 2, "", 20, &n.gw, NEWT_ENTRY_SCROLL);
    n.nsEntrys[0] = newtEntry(28, top + 3, "", 20, &n.ns[0], NEWT_ENTRY_SCROLL);
    n.nsEntrys[1] = newtEntry(28, top + 4, "", 20, &n.ns[1], NEWT_ENTRY_SCROLL);
    n.nsEntrys[2] = newtEntry(28, top + 5, "", 20, &n.ns[2], NEWT_ENTRY_SCROLL);

    if (netc->isConfigured) {
	newtEntrySet(n.hnEntry, netc->hostname, 0);
	newtEntrySet(n.dnEntry, netc->domainname, 0);
	newtEntrySet(n.gwEntry, netc->defaultGateway, 0);
	if (netc->nameserver[0])
	    newtEntrySet(n.nsEntrys[0], netc->nameserver[0], 0);
	if (netc->nameserver[1])
	    newtEntrySet(n.nsEntrys[1], netc->nameserver[1], 0);
	if (netc->nameserver[2])
	    newtEntrySet(n.nsEntrys[2], netc->nameserver[2], 0);
    } else if (intf->isConfigured) {
	ipnum = htonl(ntohl(intf->broadcast) - 1);
	memcpy(&ia, &ipnum, sizeof(ipnum));
	newtEntrySet(n.gwEntry, inet_ntoa(ia), 1);

	ipnum = htonl(ntohl(intf->network) + 1);
	memcpy(&ia, &ipnum, sizeof(ipnum));
	newtEntrySet(n.nsEntrys[0], inet_ntoa(ia), 1);
    }

    newtComponentAddCallback(n.dnEntry, hnCallback, &n);

    f = newtForm(NULL, NULL, 0);
    newtFormAddComponents(f, n.dnLabel, n.hnLabel, n.gwLabel, n.nsLabels[0],
			  n.nsLabels[1], n.nsLabels[2], NULL);
    newtFormAddComponents(f, n.dnEntry, n.hnEntry, n.gwEntry, n.nsEntrys[0],
			  n.nsEntrys[1], n.nsEntrys[2], NULL);

    okay = newtButton(11, 11, "Ok");
    cancel = newtButton(30, 11, "Cancel");

    newtFormAddComponents(f, okay, cancel, NULL);

    answer = newtRunForm(f);

    strcpy(netc->hostname, n.hn);
    strcpy(netc->domainname, n.dn);

    chptr = n.gw;
    while (isspace(*chptr) && *chptr) chptr++;
    if (!isspace(*chptr) || *chptr)
	strcpy(netc->defaultGateway, n.gw);
    else
	strcpy(netc->defaultGateway, "");

    for (i = 0; i < 3; i++) {
	if (netc->isConfigured && netc->nameserver[i]) 
	    free(netc->nameserver[i]);
	netc->nameserver[i] = *n.ns[i] ? strdup(n.ns[i]) : NULL;
    }

    newtFormDestroy(f);
    newtPopWindow();

    if (answer == cancel) return INST_CANCEL;

    netc->isConfigured = 1;

    return 0;
}

int readNetConfig(char * prefix, struct netConfig * netc) {
    FILE * f;
    char * start, * end;
    char buf[250];
    int line = 0;

    netc->isConfigured = 0;

    if (testing) {
	return 0;
    }

    sprintf(buf, "%s/network", prefix);

    f = fopen(buf, "r");
    if (!f) {
	if (errno != ENOENT) {
	    errorWindow("cannot open file: %s");
	    return INST_ERROR;
	} else {
	    netc->hostname[0] = '\0';
	    return 0;
	}
    }

    memset(netc, 0, sizeof(*netc));

    while (fgets(buf, sizeof(buf) - 1, f)) {
	line++;

	start = buf;

	/* skipping leading spaces */
	while (*start && isspace(*start)) start++;
	if (!*start) continue;

	/* skip comments */
	if (*start == '#') continue;

	/* cut off trailing spaces and \n */
	end = start + strlen(start) - 2;
	while (isspace(*end)) end--;
	end++;
	*end = '\0';	
	end--;
	
	if (!strncmp("HOSTNAME=", start, 9)) {
	    start += 9;
	    strcpy(netc->hostname, start);
	} else if (!strncmp("DOMAINNAME=", start, 11)) {
	    start += 11;
	    strcpy(netc->domainname, start);
	} else if (!strncmp("GATEWAY=", start, 8)) {
	    start += 8;
	    strcpy(netc->defaultGateway, start);
	} else if (!strncmp("NS1=", start, 4)) {
	    start += 4;
	    netc->nameserver[0] = strdup(start);
	} else if (!strncmp("NS2=", start, 4)) {
	    start += 4;
	    netc->nameserver[1] = strdup(start);
	} else if (!strncmp("NS3=", start, 4)) {
	    start += 4;
	    netc->nameserver[2] = strdup(start);
	}
    }

    fclose(f);

    netc->isConfigured = 1;

    return 0;
}


int bringUpNetworking(struct netInterface * intf, struct netConfig * netc,
		      struct driversLoaded ** dl) {
    return doBringUpNetworking(intf, netc, dl, 0);
}

#define BRINGUP_NET 	1
#define BRINGUP_CONF	2
#define BRINGUP_ROUTE	3
#define BRINGUP_DONE	4

static int doBringUpNetworking(struct netInterface * intf, 
			       struct netConfig * netc,
			       struct driversLoaded ** dl, int justConfig) {
    int where = BRINGUP_NET;
    int rc;

    while (where != BRINGUP_DONE) {
	switch (where) {
	  case BRINGUP_NET:
	    rc = setupNetworkInterface("eth0", intf, dl, justConfig);
	    if (rc) return rc;
	    where = BRINGUP_CONF;
	    break;

	  case BRINGUP_CONF:
	    rc = configureNetwork(netc, intf);
	    if (rc == INST_CANCEL)
		where = BRINGUP_NET;
	    else if (rc)
		return INST_ERROR;
	    else
		where = BRINGUP_ROUTE;
	    break;

	  case BRINGUP_ROUTE:
	    if (justConfig)
		rc = 0;
	    else
		rc = addDefaultRoute(*netc);

	    if (rc) return rc;
	    where = BRINGUP_DONE;
	    break;
	}
    }

    /* write out the /etc/resolv.conf, as we'll need that to use name services
       properly */
    writeResolvConf("/etc", netc);

    return 0;
}

#define CHECKNET_CONFIG		1
#define CHECKNET_KEEP		2
#define CHECKNET_NONE		3

static int checkNetConfigPanel(int isConfigured, int * choice) {
    newtComponent text, okay, cancel;
    newtComponent f, answer, yes, no, listbox;
    int which;

    if (isConfigured) {
	newtOpenWindow(18, 5, 42, 12, "Network Configuration");
	text = newtTextbox(1, 1, 40, 2, NEWT_TEXTBOX_WRAP);
	newtTextboxSetText(text,
		"LAN networking has already been configured. Do you "
		"want to:");

	listbox = newtListbox(8, 4, 0, NEWT_LISTBOX_RETURNEXIT);
	newtListboxAddEntry(listbox, "Keep this setup", (void *) 1);
	newtListboxAddEntry(listbox, "Reconfigure network", (void *) 2);
	newtListboxAddEntry(listbox, "Don't setup networking", (void *) 3);

	okay = newtButton(6, 8, "Ok");
	cancel = newtButton(23, 8, "Cancel");

	f = newtForm(NULL, NULL, 0);

	newtFormAddComponents(f, text, listbox, okay, cancel, NULL);

	answer = newtRunForm(f);
	if (answer == cancel) {
	    newtPopWindow();
	    newtFormDestroy(f);

	    return INST_CANCEL;
	}

	which = (int) newtListboxGetCurrent(listbox);

	newtPopWindow();
	newtFormDestroy(f);

	if (which == 1)
	    *choice = CHECKNET_KEEP;
	else if (which == 3)
	    *choice = CHECKNET_NONE;
	else
	    *choice = CHECKNET_CONFIG;
    } else {
	newtOpenWindow(18, 6, 42, 10, "Network Configuration");

	text = newtTextbox(1, 1, 40, 3, NEWT_TEXTBOX_WRAP);
	newtTextboxSetText(text,
		"Do you want to configure LAN (not dialup) networking "
		"for your installed system?");

	yes = newtButton(3, 6, " Yes ");
	no = newtButton(16, 6, "  No  ");
	cancel = newtButton(29, 6, "Cancel");

	f = newtForm(NULL, NULL, 0);
	newtFormAddComponents(f, text, yes, no, cancel, NULL);

	answer = newtRunForm(f);
	if (answer == f) 
	    answer = newtFormGetCurrent(f);

	newtPopWindow();
	newtFormDestroy(f);

	if (answer == yes) {
	    *choice = CHECKNET_CONFIG;
	} else if (answer == cancel) {
	    return INST_CANCEL;
	} else {
	    *choice = CHECKNET_NONE;
	}
    }

    return 0;
}

int checkNetConfig(struct netInterface * intf, struct netConfig * netc,
		   struct driversLoaded ** dl) {
    int choice, rc;

    /* this doesn't handle cancel very well as the dl makes it difficult :-( */

    do {
	rc = checkNetConfigPanel(netc->isConfigured && intf->isConfigured,
				 &choice);
	if (rc) return rc;

	switch (choice) {
	  case CHECKNET_CONFIG:
	    rc = doBringUpNetworking(intf, netc, dl, 1);
	    if (rc == INST_ERROR) return rc;
	    break;

	  case CHECKNET_NONE:
	    intf->isConfigured = netc->isConfigured = 0;
	    rc = 0;
	    break;
	}
    } while (rc);

    return 0;
}
