/*
 * Copyright 1999-2001 Red Hat, Inc.
 * 
 * All Rights Reserved.
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * Except as contained in this notice, the name of Red Hat shall not be
 * used in advertising or otherwise to promote the sale, use or other dealings
 * in this Software without prior written authorization from Red Hat.
 *
 */

#include <arpa/inet.h>
#include <errno.h>
#include <popt.h>
#include <resolv.h>
#include <net/if.h>
#include <newt.h>
#include <stdlib.h>
#include <string.h>

#include <netdb.h>
#ifdef __STANDALONE__
#include <libintl.h>
#include <locale.h>

#define _(String) gettext((String))
#define N_(String) String

#define LOADER_BACK 2
#define LOADER_OK 0
#define LOADER_ERROR -1;

#include "net.h"
#include "pump.h"

#else

# include "isys/dns.h"

#include "kickstart.h"
#include "lang.h"
#include "loader.h"
#include "log.h"
#include "net.h"
#include "windows.h"
#include "misc.h"

#endif /* __STANDALONE__ */

#ifndef __STANDALONE__
char *netServerPrompt = \
    N_("Please enter the following information:\n"
       "\n"
       "    o the name or IP number of your %s server\n" 
       "    o the directory on that server containing\n" 
       "      %s for your architecture\n");
#endif

struct intfconfig_s {
    newtComponent ipEntry, nmEntry, gwEntry, nsEntry;
    char * ip, * nm, * gw, * ns;
};

typedef int int32;

#ifdef __STANDALONE__
static FILE * logfile = NULL;

#define FL_TESTING(foo) 1

void logMessage(const char * s, ...) {
	va_list args;
	
	if (!logfile) return;
	va_start(args, s);

	fprintf(logfile, "* ");
	vfprintf(logfile, s, args);
	fprintf(logfile, "\n");
	fflush(logfile);

	va_end(args);

	return;
}

/* yawn. This really should be in newt. */
void winStatus(int width, int height, char * title,
	                       char * text, ...) {
	newtComponent t, f;
	char * buf = NULL;
	int size = 0;
	int i = 0;
	va_list args;
	
	va_start(args, text);
	
	do {
		size += 1000;
		if (buf) free(buf);
		buf = malloc(size);
		i = vsnprintf(buf, size, text, args);
	} while (i == size);
	
	va_end(args);
	
	newtCenteredWindow(width, height, title);
	
	t = newtTextbox(1, 1, width - 2, height - 2, NEWT_TEXTBOX_WRAP);
	newtTextboxSetText(t, buf);
	f = newtForm(NULL, NULL, 0);
	
	free(buf);
	
	newtFormAddComponent(f, t);
	
	newtDrawForm(f);
	newtRefresh();
	newtFormDestroy(f);
}

#endif

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

    if (co == data->ipEntry) {
	if (strlen(data->ip) && !strlen(data->nm)) {
	    if (inet_aton(data->ip, &ipaddr)) {
		ipaddr.s_addr = ntohl(ipaddr.s_addr);
		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;

        network = ipaddr.s_addr & nmaddr.s_addr;
	broadcast = (ipaddr.s_addr & nmaddr.s_addr) | (~nmaddr.s_addr);

	if (!strlen(data->gw)) {
	    addr.s_addr = htonl(ntohl(broadcast) - 1);
	    newtEntrySet(data->gwEntry, inet_ntoa(addr), 1);
	}

	if (!strlen(data->ns)) {
	    addr.s_addr = htonl(ntohl(network) + 1);
	    newtEntrySet(data->nsEntry, inet_ntoa(addr), 1);
	}
    }
}

#ifndef __STANDALONE__
int nfsGetSetup(char ** hostptr, char ** dirptr) {
    struct newtWinEntry entries[3];
    char * buf;
    char * newServer = *hostptr ? strdup(*hostptr) : NULL;
    char * newDir = *dirptr ? strdup(*dirptr) : NULL;
    int rc;

    entries[0].text = _("NFS server name:");
    entries[0].value = &newServer;
    entries[0].flags = NEWT_FLAG_SCROLL;
    entries[1].text = _("Red Hat directory:");
    entries[1].value = &newDir;
    entries[1].flags = NEWT_FLAG_SCROLL;
    entries[2].text = NULL;
    entries[2].value = NULL;
    buf = sdupprintf(_(netServerPrompt), "NFS", PRODUCTNAME);
    rc = newtWinEntries(_("NFS Setup"), buf, 60, 5, 15,
			24, entries, _("OK"), _("Back"), NULL);
    free(buf);

    if (rc == 2) {
	if (newServer) free(newServer);
	if (newDir) free(newDir);
	return LOADER_BACK;
    }

    if (*hostptr) free(*hostptr);
    if (*dirptr) free(*dirptr);
    *hostptr = newServer;
    *dirptr = newDir;

    return 0;
}
#endif

static void fillInIpInfo(struct networkDeviceConfig * cfg) {
    int32 * i;
    char * nm;
   
    if (!(cfg->dev.set & PUMP_INTFINFO_HAS_NETMASK)) {
	i = (int32 *) &cfg->dev.ip;

	nm = "255.255.255.0";

	inet_aton(nm, &cfg->dev.netmask);
	cfg->dev.set |= PUMP_INTFINFO_HAS_NETMASK;
    }

    if (!(cfg->dev.set & PUMP_INTFINFO_HAS_BROADCAST)) {
	*((int32 *) &cfg->dev.broadcast) = (*((int32 *) &cfg->dev.ip) & 
			   *((int32 *) &cfg->dev.netmask)) | 
			   ~(*((int32 *) &cfg->dev.netmask));
	cfg->dev.set |= PUMP_INTFINFO_HAS_BROADCAST;
    }

    if (!(cfg->dev.set & PUMP_INTFINFO_HAS_NETWORK)) {
	*((int32 *) &cfg->dev.network) = 
		*((int32 *) &cfg->dev.ip) &
		*((int32 *) &cfg->dev.netmask);
	cfg->dev.set |= PUMP_INTFINFO_HAS_NETWORK;
    }
}

#ifndef __STANDALONE__
void initLoopback(void) {
    struct pumpNetIntf dev;

    strcpy(dev.device, "lo");
    inet_aton("127.0.0.1", &dev.ip);
    inet_aton("255.0.0.0", &dev.netmask);
    inet_aton("127.0.0.0", &dev.network);
    dev.set = PUMP_INTFINFO_HAS_NETMASK | PUMP_INTFINFO_HAS_IP
		| PUMP_INTFINFO_HAS_NETWORK;

    pumpSetupInterface(&dev);
}
#endif

static void dhcpBoxCallback(newtComponent co, void * ptr) {
    struct intfconfig_s * c = ptr;

    newtEntrySetFlags(c->ipEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
    newtEntrySetFlags(c->gwEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
    newtEntrySetFlags(c->nmEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
    newtEntrySetFlags(c->nsEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
}

static int getDnsServers(struct networkDeviceConfig * cfg) {
    int rc;
    char * ns = "";
    struct newtWinEntry entry[] = { { N_("Nameserver IP"), &ns, 0 },
				      { NULL, NULL, 0 } };

    do {
	rc = newtWinEntries(_("Nameserver"), 
		_("Your dynamic IP request returned IP configuration "
		  "information, but it did not include a DNS nameserver. "
		  "If you know what your nameserver is, please enter it "
		  "now. If you don't have this information, you can leave "
		  "this field blank and the install will continue."),
		40, 5, 10, 25, entry, _("OK"), _("Back"), NULL);

	if (rc == 2) return LOADER_BACK;

	if (ns && *ns && !inet_aton(ns, &cfg->dev.dnsServers[0])) {
	    newtWinMessage(_("Invalid IP Information"), _("Retry"),
			_("You entered an invalid IP address."));
	    rc = 2;
	} 

    } while (rc == 2);

    cfg->dev.set |= PUMP_NETINFO_HAS_DNS;
    cfg->dev.numDns = 1;

    return LOADER_OK;
}

int readNetConfig(char * device, struct networkDeviceConfig * cfg, int flags) {
    newtComponent text, f, okay, back, answer, dhcpCheckbox;
    newtGrid grid, subgrid, buttons;
    struct networkDeviceConfig newCfg;
    struct intfconfig_s c;
    int i;
    struct in_addr addr;
    char dhcpChoice;
    char * chptr;

#if !defined(__s390__) && !defined(__s390x__)
    text = newtTextboxReflowed(-1, -1, 
		_("Please enter the IP configuration for this machine. Each "
		  "item should be entered as an IP address in dotted-decimal "
		  "notation (for example, 1.2.3.4)."), 50, 5, 10, 0);

    subgrid = newtCreateGrid(2, 4);
    newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
		     newtLabel(-1, -1, _("IP address:")),
		     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
    newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT,
    		     newtLabel(-1, -1, _("Netmask:")),
		     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
    newtGridSetField(subgrid, 0, 2, NEWT_GRID_COMPONENT,
    		     newtLabel(-1, -1, _("Default gateway (IP):")),
		     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
    newtGridSetField(subgrid, 0, 3, NEWT_GRID_COMPONENT,
    		     newtLabel(-1, -1, _("Primary nameserver:")),
		     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);

    c.ipEntry = newtEntry(-1, -1, NULL, 16, &c.ip, 0);
    c.nmEntry = newtEntry(-1, -1, NULL, 16, &c.nm, 0);
    c.gwEntry = newtEntry(-1, -1, NULL, 16, &c.gw, 0);
    c.nsEntry = newtEntry(-1, -1, NULL, 16, &c.ns, 0);

    if (!cfg->isDynamic) {
	if (cfg->dev.set & PUMP_INTFINFO_HAS_IP)
	    newtEntrySet(c.ipEntry, inet_ntoa(cfg->dev.ip), 1);

	if (cfg->dev.set & PUMP_INTFINFO_HAS_NETMASK)
	    newtEntrySet(c.nmEntry, inet_ntoa(cfg->dev.netmask), 1);

	if (cfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)
	    newtEntrySet(c.gwEntry, inet_ntoa(cfg->dev.gateway), 1);

	if (cfg->dev.numDns)
	    newtEntrySet(c.nsEntry, inet_ntoa(cfg->dev.dnsServers[0]), 1);

    	dhcpChoice = ' ';
    } else {
    	dhcpChoice = '*';
    }

    dhcpCheckbox = newtCheckbox(-1, -1, 
    		_("Use dynamic IP configuration (BOOTP/DHCP)"),
		dhcpChoice, NULL, &dhcpChoice);
    newtComponentAddCallback(dhcpCheckbox, dhcpBoxCallback, &c);
    if (dhcpChoice == '*') dhcpBoxCallback(dhcpCheckbox, &c);

    newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, c.ipEntry,
		     1, 0, 0, 0, 0, 0);
    newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT, c.nmEntry,
		     1, 0, 0, 0, 0, 0);
    newtGridSetField(subgrid, 1, 2, NEWT_GRID_COMPONENT, c.gwEntry,
		     1, 0, 0, 0, 0, 0);
    newtGridSetField(subgrid, 1, 3, NEWT_GRID_COMPONENT, c.nsEntry,
		     1, 0, 0, 0, 0, 0);

    buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);

    grid = newtCreateGrid(1, 4);
    newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
		     0, 0, 0, 1, 0, 0);
    newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, dhcpCheckbox,
		     0, 0, 0, 1, 0, 0);
    newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, subgrid,
		     0, 0, 0, 1, 0, 0);
    newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
		     0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);

    f = newtForm(NULL, NULL, 0);
    newtGridAddComponentsToForm(grid, f, 1);
    newtGridWrappedWindow(grid, _("Configure TCP/IP"));
    newtGridFree(grid, 1);
   
    newtComponentAddCallback(c.ipEntry, ipCallback, &c);
    newtComponentAddCallback(c.nmEntry, ipCallback, &c);
    
    do {
	answer = newtRunForm(f);

	if (answer == back) {
	    newtFormDestroy(f);
	    newtPopWindow();
	    return LOADER_BACK;
	} 

	if (dhcpChoice == ' ') {
	    i = 0;
	    memset(&newCfg, 0, sizeof(newCfg));
	    if (*c.ip && inet_aton(c.ip, &addr)) {
		i++;
		newCfg.dev.ip = addr;
		newCfg.dev.set |= PUMP_INTFINFO_HAS_IP;
	    }

	    if (*c.nm && inet_aton(c.nm, &addr)) {
		i++;
		newCfg.dev.netmask = addr;
		newCfg.dev.set |= PUMP_INTFINFO_HAS_NETMASK;
	    }

	    if (i != 2) {
		newtWinMessage(_("Missing Information"), _("Retry"),
			    _("You must enter both a valid IP address and a "
			      "netmask."));
	    }

	    strcpy(newCfg.dev.device, device);
	    newCfg.isDynamic = 0;
	} else {
	    if (!FL_TESTING(flags)) {
		winStatus(50, 3, _("Dynamic IP"), 
			  _("Sending request for IP information..."),
			    0);
		chptr = pumpDhcpRun(device, 0, 0, NULL, &newCfg.dev, NULL);
		newtPopWindow();
	    } else {
	    	chptr = NULL;
	    }

	    if (!chptr) {
		newCfg.isDynamic = 1;
#ifdef __STANDALONE__
		i = 2;
#else		    
		if (!(newCfg.dev.set & PUMP_NETINFO_HAS_DNS)) {
		    logMessage("pump worked, but didn't return a DNS server");
		    i = getDnsServers(&newCfg);
		    i = i ? 0 : 2;
		} else {
		    i = 2; 
		}
#endif		    
	    } else {
		logMessage("pump told us: %s", chptr);
		i = 0;
	    }
	}
    } while (i != 2);

#else /* s390 now */
   char * env;
   /* quick and dirty hack by opaukstadt@millenux.com for s390 */
   /* ctc stores remoteip in broadcast-field until pump.h is changed */
   memset(&newCfg, 0, sizeof(newCfg));
   strcpy(newCfg.dev.device, device);
   newCfg.isDynamic = 0;
   env = getenv("IPADDR");
   if (env && *env) {
     if(inet_aton(env, &newCfg.dev.ip))
      newCfg.dev.set |= PUMP_INTFINFO_HAS_IP;
   }
   env = getenv("NETMASK");
   if (env && *env) {
     if(inet_aton(env, &newCfg.dev.netmask))
      newCfg.dev.set |= PUMP_INTFINFO_HAS_NETMASK;
   }
   env = getenv("GATEWAY");
   if (env && *env) {
     if(inet_aton(env, &newCfg.dev.gateway))
      newCfg.dev.set |= PUMP_NETINFO_HAS_GATEWAY;
   }
   env = getenv("NETWORK");
   if (env && *env) {
     if(inet_aton(env, &newCfg.dev.network))
      newCfg.dev.set |= PUMP_INTFINFO_HAS_NETWORK;
   }
   env = getenv("DNS");
   if (env && *env) {
     char *s = strdup (env);
     char *t = strtok (s, ":");
     if(inet_aton((t? t : s), &newCfg.dev.dnsServers[0]))
      newCfg.dev.set |= PUMP_NETINFO_HAS_DNS;
   }
   if (!strncmp(newCfg.dev.device, "ctc", 3)) {
     env = getenv("REMIP");
     if (env && *env) {
       if(inet_aton(env, &newCfg.dev.gateway))
	 newCfg.dev.set |= PUMP_NETINFO_HAS_GATEWAY;
     }
   }
   env = getenv("BROADCAST");
   if (env && *env) {
     if(inet_aton(env, &newCfg.dev.broadcast))
       newCfg.dev.set |= PUMP_INTFINFO_HAS_BROADCAST;     
   }
#endif   /* s390 */

#ifdef __STANDALONE__
    if (!newCfg.isDynamic)
#endif	  
    cfg->isDynamic = newCfg.isDynamic;
    memcpy(&cfg->dev,&newCfg.dev,sizeof(newCfg.dev));

    fillInIpInfo(cfg);

#if !defined(__s390__) && !defined(__s390x__)
    if (!(cfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)) {
	if (*c.gw && inet_aton(c.gw, &addr)) {
	    cfg->dev.gateway = addr;
	    cfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
	}
    }

    if (!(cfg->dev.numDns)) {
	if (*c.ns && inet_aton(c.ns, &addr)) {
	    cfg->dev.dnsServers[0] = addr;
	    cfg->dev.numDns = 1;
	}
    }

    newtPopWindow();
#endif
    if (!FL_TESTING(flags)) {
	configureNetwork(cfg);
	findHostAndDomain(cfg, flags);
	writeResolvConf(cfg);
    }

#ifdef __STANDALONE__
    writeResolvConf(cfg);
#endif
    return 0;
}

int configureNetwork(struct networkDeviceConfig * dev) {
#if !defined(__s390__) && !defined(__s390x__)
    pumpSetupInterface(&dev->dev);

    if (dev->dev.set & PUMP_NETINFO_HAS_GATEWAY)
	pumpSetupDefaultGateway(&dev->dev.gateway);

#endif
    return 0;
}

int writeNetInfo(const char * fn, struct networkDeviceConfig * dev,
		 struct knownDevices * kd) {
    FILE * f;
#ifndef __STANDALONE__
    int i;
#endif

#ifndef __STANDALONE__
    for (i = 0; i < kd->numKnown; i++)
	if (!strcmp(kd->known[i].name, dev->dev.device)) break;
#endif
    
    if (!(f = fopen(fn, "w"))) return -1;

    fprintf(f, "DEVICE=%s\n", dev->dev.device);

#ifndef __STANDALONE__
    if (i < kd->numKnown && kd->known[i].code == CODE_PCMCIA)
	fprintf(f, "ONBOOT=no\n");
    else
#endif
	fprintf(f, "ONBOOT=yes\n");

    if (dev->isDynamic) {
	fprintf(f, "BOOTPROTO=dhcp\n");
    } else {
	fprintf(f, "BOOTPROTO=static\n");
	fprintf(f, "IPADDR=%s\n", inet_ntoa(dev->dev.ip));
	fprintf(f, "NETMASK=%s\n", inet_ntoa(dev->dev.netmask));
	if (dev->dev.set & PUMP_NETINFO_HAS_GATEWAY) {
	  fprintf(f, "GATEWAY=%s\n", inet_ntoa(dev->dev.gateway));
	  if (!strncmp(dev->dev.device, "ctc", 3) || \
	      !strncmp(dev->dev.device, "iucv", 4)) 
	    fprintf(f, "REMIP=%s\n", inet_ntoa(dev->dev.gateway));
	}
	if (dev->dev.set & PUMP_INTFINFO_HAS_BROADCAST)
	  fprintf(f, "BROADCAST=%s\n", inet_ntoa(dev->dev.broadcast));    
    }

    if (dev->dev.set & PUMP_NETINFO_HAS_HOSTNAME)
	fprintf(f, "HOSTNAME=%s\n", dev->dev.hostname);
    if (dev->dev.set & PUMP_NETINFO_HAS_DOMAIN)
	fprintf(f, "DOMAIN=%s\n", dev->dev.domain);

    fclose(f);

    return 0;
}

int writeResolvConf(struct networkDeviceConfig * net) {
    char * filename = "/etc/resolv.conf";
    FILE * f;
    int i;
#if defined(__s390__) || defined(__s390x__)
    return 0;
#endif

    if (!(net->dev.set & PUMP_NETINFO_HAS_DOMAIN) && !net->dev.numDns)
    	return LOADER_ERROR;

    f = fopen(filename, "w");
    if (!f) {
	logMessage("Cannot create %s: %s\n", filename, strerror(errno));
	return LOADER_ERROR;
    }

    if (net->dev.set & PUMP_NETINFO_HAS_DOMAIN)
	fprintf(f, "search %s\n", net->dev.domain);

    for (i = 0; i < net->dev.numDns; i++) 
	fprintf(f, "nameserver %s\n", inet_ntoa(net->dev.dnsServers[i]));

    fclose(f);

    res_init();		/* reinit the resolver so DNS changes take affect */

    return 0;
}

int findHostAndDomain(struct networkDeviceConfig * dev, int flags) {
    char * name, * chptr;
    struct hostent * he;

    if (!FL_TESTING(flags)) {
	writeResolvConf(dev);
    }

    if (!(dev->dev.set & PUMP_NETINFO_HAS_HOSTNAME)) {
	winStatus(40, 3, _("Hostname"), 
		  _("Determining host name and domain..."));
	he = gethostbyaddr( (char *) &dev->dev.ip, sizeof (dev->dev.ip), AF_INET);
	name = he ? he->h_name : 0;
	newtPopWindow();

	if (!name) {
	    logMessage("reverse name lookup failed");
	    return 1;
	}

	logMessage("reverse name lookup worked");

	dev->dev.hostname = strdup(name);
	dev->dev.set |= PUMP_NETINFO_HAS_HOSTNAME;
    } else {
        name = dev->dev.hostname;
    }

    if (!(dev->dev.set & PUMP_NETINFO_HAS_DOMAIN)) {
	for (chptr = name; *chptr && (*chptr != '.'); chptr++) ;
	if (*chptr == '.') {
	    if (dev->dev.domain) free(dev->dev.domain);
	    dev->dev.domain = strdup(chptr + 1);
	    dev->dev.set |= PUMP_NETINFO_HAS_DOMAIN;
	}
    }

    return 0;
}

#ifndef __STANDALONE__
int kickstartNetwork(char ** devicePtr, struct networkDeviceConfig * netDev, 
		     char * bootProto, int flags) {
    char ** ksArgv;
    int ksArgc;
    int netSet, rc;
    char * arg, * chptr;
    char * kshostname=NULL;
    poptContext optCon;
    struct in_addr * parseAddress;
    int noDns = 0;
    char * device;
    struct poptOption ksOptions[] = {
	    { "bootproto", '\0', POPT_ARG_STRING, &bootProto, 0 },
	    { "device", '\0', POPT_ARG_STRING, devicePtr, 0 },
	    { "gateway", '\0', POPT_ARG_STRING, NULL, 'g' },
	    { "ip", '\0', POPT_ARG_STRING, NULL, 'i' },
	    { "nameserver", '\0', POPT_ARG_STRING, NULL, 'n' },
	    { "netmask", '\0', POPT_ARG_STRING, NULL, 'm' },
	    { "nodns", '\0', POPT_ARG_NONE, &noDns, 0 },
	    { "hostname", '\0', POPT_ARG_STRING, NULL, 'h'},
	    { 0, 0, 0, 0, 0 }
    };

    if (!bootProto) {
	if (ksGetCommand(KS_CMD_NETWORK, NULL, &ksArgc, &ksArgv)) {
	    /* This is for compatibility with RH 5.0 */
	    ksArgv = alloca(sizeof(*ksArgv) * 1);
	    ksArgv[0] = "network";
	    ksArgc = 1;
	}

	optCon = poptGetContext(NULL, ksArgc, (const char **) ksArgv, ksOptions, 0);
	while ((rc = poptGetNextOpt(optCon)) >= 0) {
	    parseAddress = NULL;
	    netSet = 0;

	    arg = (char *) poptGetOptArg(optCon);

	    switch (rc) {
	      case 'g':
		parseAddress = &netDev->dev.gateway;
		netSet = PUMP_NETINFO_HAS_GATEWAY;
		break;
		    
	      case 'i':
		parseAddress = &netDev->dev.ip;
		netSet = PUMP_INTFINFO_HAS_IP;
		break;
		    
	      case 'n':
		parseAddress = &netDev->dev.dnsServers[netDev->dev.numDns++];
		netSet = PUMP_NETINFO_HAS_DNS;
		break;

	      case 'm':
		parseAddress = &netDev->dev.netmask;
		netSet = PUMP_INTFINFO_HAS_NETMASK;
		break;

	      case 'h':
		if (kshostname)
		    free(kshostname);
		kshostname =  strdup(arg);
		logMessage("netDev->dev.hostname = %s", kshostname);
		break;
	    }

	    if (parseAddress && !inet_aton(arg, parseAddress)) {
		logMessage("bad ip number in network command: %s", arg);
		return -1;
	    }

	    netDev->dev.set |= netSet;
	}

	if (rc < -1) {
	    newtWinMessage(_("kickstart"),  _("OK"),
		       _("bad argument to kickstart network command %s: %s"),
		       poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
		       poptStrerror(rc));
	} else {
	    poptFreeContext(optCon);
	}
    }

    device = *devicePtr;

    if (!bootProto)
	bootProto = "dhcp";

    if (!strcmp(bootProto, "dhcp") || !strcmp(bootProto, "bootp")) {
	logMessage("sending dhcp request through device %s", device);
	winStatus(50, 3, _("Dynamic IP"), 
		  _("Sending request for IP information..."),
		    0);

	chptr = pumpDhcpRun(device, 0, 0, NULL, &netDev->dev, NULL);
	newtPopWindow();
	if (chptr) {
	    logMessage("pump told us: %s", chptr);
	    return -1;
	}
	netDev->isDynamic = 1;
    } else if (!strcmp(bootProto, "static")) {
       strcpy(netDev->dev.device, device);
    } else if (!strcmp(bootProto, "query")) {
	strcpy(netDev->dev.device, device);
	readNetConfig("eth0", netDev, flags);
    } else {
	newtWinMessage(_("kickstart"), _("OK"),
		    _("Bad bootproto %s specified in network command"),
		    bootProto);
	return -1;
    }

    fillInIpInfo(netDev);
    configureNetwork(netDev);

    logMessage("nodns is %d", noDns);

    if (kshostname) {
	logMessage("setting ks specified hostname of %s", kshostname);
	netDev->dev.hostname=strdup(kshostname);
	netDev->dev.set |= PUMP_NETINFO_HAS_HOSTNAME;
    }

    if (!noDns)
	findHostAndDomain(netDev, flags);

    writeResolvConf(netDev);
    
    return 0;
}
#endif

#ifdef __STANDALONE__
int main(int argc, const char **argv) {
    int netSet, rc;
    int x;
    char * bootProto = NULL;
    char * device = NULL;
    char * hostname = NULL;
    char * domain = NULL;
    const char * arg;
    char path[256];
    char roottext[80];
    poptContext optCon;
    struct networkDeviceConfig *netDev;
    struct in_addr * parseAddress;
    struct poptOption Options[] = {
	    POPT_AUTOHELP
	    { "bootproto", '\0', POPT_ARG_STRING, &bootProto, 0,
	      _("Boot protocol to use"), "(dhcp|bootp|none)" },
	    { "gateway", '\0', POPT_ARG_STRING, NULL, 'g',
	      _("Network gateway"), NULL },
	    { "ip", '\0', POPT_ARG_STRING, NULL, 'i',
	      _("IP address"), NULL },
	    { "nameserver", '\0', POPT_ARG_STRING, NULL, 'n',
	      _("Nameserver"), NULL },
	    { "netmask", '\0', POPT_ARG_STRING, NULL, 'm',
	      _("Netmask"), NULL },
	    { "hostname", '\0', POPT_ARG_STRING, &hostname, 0,
	      _("Hostname"), NULL 
	    },
	    { "domain", '\0', POPT_ARG_STRING, &domain, 0,
	      _("Domain name"), NULL
	    },
	    { "device", 'd', POPT_ARG_STRING, &device, 0,
	      _("Network device"), NULL 
	    },
	    { 0, 0, 0, 0, 0 }
    };

	
    netDev = malloc(sizeof(struct networkDeviceConfig));
    memset(netDev,'\0',sizeof(struct networkDeviceConfig));
    optCon = poptGetContext("netconfig", argc, argv, Options, 0);
    while ((rc = poptGetNextOpt(optCon)) >= 0) {
	parseAddress = NULL;
	netSet = 0;

	arg = poptGetOptArg(optCon);

	switch (rc) {
	  case 'g':
	    parseAddress = &netDev->dev.gateway;
	    netSet = PUMP_NETINFO_HAS_GATEWAY;
	    break;
		
	  case 'i':
	    parseAddress = &netDev->dev.ip;
	    netSet = PUMP_INTFINFO_HAS_IP;
	    break;
		
	  case 'n':
	    parseAddress = &netDev->dev.dnsServers[netDev->dev.numDns++];
	    netSet = PUMP_NETINFO_HAS_DNS;
	    break;

	  case 'm':
	    parseAddress = &netDev->dev.netmask;
	    netSet = PUMP_INTFINFO_HAS_NETMASK;
	    break;
	}

	if (!inet_aton(arg, parseAddress)) {
	    logMessage("bad ip number in network command: %s", arg);
	    return -1;
	}

	netDev->dev.set |= netSet;
    }

    if (rc < -1) {
	fprintf(stderr, "%s: %s\n",
		   poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
		   poptStrerror(rc));
    } else {
	poptFreeContext(optCon);
    }
	
    if (netDev->dev.set || 
	(bootProto && (!strcmp(bootProto, "dhcp") || !strcmp(bootProto, "bootp")))) {
	    if (!device) device="eth0";
	    if (bootProto && (!strcmp(bootProto, "dhcp") || !strcmp(bootProto, "bootp")))
		netDev->isDynamic++;
	    strncpy(netDev->dev.device,device,10);
	    if (hostname) {
		    netDev->dev.hostname=strdup(hostname);
		    netDev->dev.set |= PUMP_NETINFO_HAS_HOSTNAME;
	    }
	    if (domain) {
		    netDev->dev.domain=strdup(domain);
		    netDev->dev.set |= PUMP_NETINFO_HAS_DOMAIN;
	    }
	    snprintf(path,256,"/etc/sysconfig/network-scripts/ifcfg-%s",device);
	    writeNetInfo(path,netDev, NULL);
    } else {
	    newtInit();
	    newtCls();
	    newtPushHelpLine(_(" <Tab>/<Alt-Tab> between elements   |   <Space> selects  |   <F12> next screen"));
	    snprintf(roottext,80,_("netconfig %s  (C) 1999 Red Hat, Inc."), VERSION);
	    newtDrawRootText(0, 0, roottext);
	    x=newtWinChoice(_("Network configuration"),_("Yes"),_("No"),
			  _("Would you like to set up networking?"));
	    if (x==2) { 
		    newtFinished();
		    exit(0);
	    }
	    if (!device) device="eth0";
	    strncpy(netDev->dev.device,device,10);
	    if (readNetConfig(device,netDev,0) != LOADER_BACK) {
		    snprintf(path,256,"/etc/sysconfig/network-scripts/ifcfg-%s",device);
		    writeNetInfo(path,netDev, NULL);
	    }
	    newtFinished();
    }
    exit(0);
}
#endif
