/*
 * installx  --  a simple install program for Micro-X
 * Copyright (C) 1991 StarNet Communications Corp.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * StarNet Communications Corp.
 * 550 Lakeside Dr. #3
 * Sunnyvale CA 94086 US
 * http://www.starnet.com
 * x-dos@starnet.com
 */
/*
 *
 * Ask:
 *	1.  R3 or R4
 *	2.  IP address
 *	3.  Netmask
 *	4.  Color or B/W
 *	5.  Monitor resolution
 */

#include <stdlib.h>
#include <stdio.h>
#include <graph.h>
#include <ctype.h>
#include <string.h>
#include <direct.h>
#include <dos.h>
#include <io.h>
#include <process.h>

int r4;
int broadcast = 0;
int color = 1;
int once = 0;
char bw_res, co_res;
int max_res = 3;
int widths[] = { 640, 800, 1024, 1280 };
int heights[] = { 480, 600, 768, 1024 };
char *query = 0;
char myip[32];
char netmask[32];
char nameserver[32];
char gateway[32];
char domainslist[64];
char *configtel;

int valid_ip(char *);
char *default_netmask(void);
void do_install(FILE *);
static FILE *open_pro(void);
#ifdef X_386
void find_res(void);
#define VGA_VERSION	2
struct vga_header {
	unsigned long version;
	unsigned short mono_modes[4];
	unsigned short color_modes[4];
} vga_head;
#endif

int
main(argc, argv)
int argc;
char **argv;
{
    char buf[BUFSIZ];
    char *cp;
    int i;
    int fflag = 0;
    union REGS regs;
    FILE *pro;

    if (argc > 1 && strcmp(argv[1], "-f"))
	fflag++;
    configtel = getenv("CONFIGTEL");
    if (!configtel) {
	configtel = "..\\ncsa\\config.tel";
    }
    cp = getenv("X11");
    if (!fflag && cp) {
	if (chdir(cp)) {
	    perror(cp);
	    exit(1);
	}
	if (cp[1] == ':') {
	    cp[1] = 0;
	    if (_chdrive((islower(*cp) ? toupper(*cp) : *cp) - 'A' + 1)) {
		perror(cp);
		exit(1);
	    }
	}
	cp = "..\\xbin";
	if (chdir(cp)) {
	    perror(cp);
	    exit(1);
	}
    }
#ifdef X_386
    pro = fopen("..\\lib\\fonts\\misc\\fonts.dir", "r");
    if (pro) {
	if (fgets(buf, sizeof buf, pro) == NULL) {
	    fclose(pro);
	    pro = 0;
	} else
	    fclose(pro);
    }
    if (!pro) {
	printf("Rebuilding font directory files...");
	if (spawnl(P_WAIT, "mkfntdir.exe", "mkfntdir", "..\\lib\\fonts\\misc",
	    "..\\lib\\fonts\\75dpi", "..\\lib\\fonts\\100dpi", NULL)) {
		perror("mkfntdir.exe");
		exit(1);
	}
    }
#endif
    pro = open_pro();
    /* The following two BIOS calls clear the screen. */
    regs.h.ah = 0xf;	/* get video mode */
    int86(0x10, &regs, &regs);
    regs.h.ah = 0;	/* set video mode */
    int86(0x10, &regs, &regs);
    puts("\n\n\t\t\tX Install Program\n");
    puts("Copyright 1991 StarNet Communications Corp.");
    puts("This program comes with ABSOLUTELY NO WARRANTY.  This is free software.");
    puts("X is designed to run with XDM (X Display Manager) from MIT X11 revision 4.");
    puts("The X11 R4 XDM uses the XDMCP protocol to manage an X server, while");
    puts("the X11 R3 XDM must poll the X server.\n");
    puts("(Answer \"3\" to the next question if you will not be using XDM.)\n");
    do {
	fputs("Enter XDM revision (3 or 4): ", stdout);
	gets(buf);
	cp = buf;
	while (*cp && !isdigit(*cp))
	    cp++;
	i = atoi(cp);
    } while (i != 3 && i != 4);
    r4 = i == 4;
    if (r4) {
	putchar('\n');
	puts("This X server can find an X Display Manager in one of two ways:");
	puts("    1.  It can send a query to a specific host that is running");
	puts("        the XDM program, or...");
	puts("    2.  It can send a broadcast message to the network to find");
	puts("        any host that is running XDM.\n");
	do {
	    fputs("Which method should it use? (1 or 2): ", stdout);
	    gets(buf);
	    i = atoi(buf);
	} while (i != 1 && i != 2);
	if (i == 2)
	    broadcast = 1;
	if (i == 1) {
	    puts("\nEnter the IP address (in the dotted notation a.b.c.d) of the host");
	    puts("to which you want to send the XDMCP query.\n");
	    do {
		fputs("Host: ", stdout);
		gets(buf);
	    } while (!valid_ip(buf));
	    query = malloc(strlen(buf) + 1);
	    if (!query) {
		perror("malloc");
		exit(1);
	    }
	    strcpy(query, buf);
	}
    }
    putchar('\n');
#ifdef X_386
    find_res();
#endif
    if (color) {
	do {
	    fputs("Is your monitor (C)olor or (B)lack and white?  ", stdout);
	    gets(buf);
	    if (isupper(buf[0]))
		    buf[0] = (char)tolower(buf[0]);
	} while (buf[0] != 'c' && buf[0] != 'b');
	color = buf[0] == 'c';
	putchar('\n');
    }
    if (color) {
	puts("You will be given the choice of running in mono mode (which is faster)");
	puts("or in color mode (256 simultaneous colors).\n");
    }
#ifdef X_386
    if (vga_head.version == VGA_VERSION) {
	max_res = 1;
	for (i = 0; i < 4; i++)
	    if (vga_head.mono_modes[i] || vga_head.color_modes[i])
		max_res = i + 1;
    }
#endif
    puts("These are the resolutions supported by the X Server and your VGA card.");
    puts("Choose a resolution (i.e. that your monitor supports).");
    for (i = 0; i < max_res; i++) {
	if (i)
	    fputs(", ", stdout);
	printf("%d = %dx%d", i + 1, widths[i], heights[i]);
    }
    putchar('\n');
    do {
	fputs("> ", stdout);
	gets(buf);
    } while (buf[0] < '1' || buf[0] > '0' + max_res);
    bw_res = buf[0];
    co_res = bw_res;
#ifdef X_386
    if (vga_head.version == VGA_VERSION) {
	i = bw_res - '1';
	if (vga_head.mono_modes[i] == 0) {
	    while (i > 1) {
		if (vga_head.mono_modes[i])
		    break;
		i--;
	    }
	    bw_res = '1' + i;
	}
	i = co_res - '1';
	if (vga_head.color_modes[i] == 0) {
	    while (i > 1) {
		if (vga_head.color_modes[i])
		    break;
		i--;
	    }
	    co_res = '1' + i;
	}
    }
#endif
    putchar('\n');
    puts(
"You can run the server in one of two ways:  You can have the server continue\n"
"to run when you log out or you can have the server exit and return you\n"
"to DOS when you log out of your X session.\n");
    do {
	fputs("Do you want to return to DOS when you log out of X? ", stdout);
	gets(buf);
	if (isupper(buf[0]))
		buf[0] = (char)tolower(buf[0]);
    } while (buf[0] != 'y' && buf[0] != 'n');
    once = buf[0] == 'y';

    if (pro && access(configtel, 0) == 0) {
	printf("The CONFIG.TEL file \"%s\" already exists.\n", configtel);
	do {
	    fputs("Overwrite it? ", stdout);
	    gets(buf);
	    if (isupper(buf[0]))
		    buf[0] = (char)tolower(buf[0]);
	} while (buf[0] != 'y' && buf[0] != 'n');
	putchar('\n');
	if (buf[0] == 'n') {
	    fclose(pro);
	    pro = 0;
	}
    }
    if (pro) {
	puts("\nEach station (including X servers) on an IP network must have a unique");
	puts("address.  You will get this address from your network administrator.\n");
	do {
	    fputs("Your IP address: ", stdout);
	    gets(myip);
	} while (!valid_ip(myip));
	puts("\nIf your network is divided into subnets, you need to specify a subnet");
	puts("mask for your network (also called simply a \"netmask\").  If your");
	puts("network is not divided in this way, then you may use the default.\n");
	cp = default_netmask();
	do {
	    printf("The netmask for your network [%s]: ", cp);
	    gets(netmask);
	    if (!netmask[0])
		    strcpy(netmask, cp);
	} while (!valid_ip(netmask));
	putchar('\n');
	puts("If your network has one or more routers that connect it with other");
	puts("networks the network programs need to know the address of a router");
	puts("to send traffic not on the local Ethernet.\n");
	do {
	    fputs("Enter the address for your default router: ", stdout);
	    gets(gateway);
	} while (gateway[0] && !valid_ip(gateway));
	putchar('\n');
	puts("The programs included with the X server, such as tn (telnet) and ftp will");
	puts("use a nameserver to translate a name into an IP address.  If you don't have");
	puts("or don't care to use a nameserver, just enter the IP address of any host");
	puts("on your network in response to the next question.\n");
	do {
	    fputs("Enter the address for your nameserver: ", stdout);
	    gets(nameserver);
	} while (!valid_ip(nameserver));
	fputs("Enter your default domain: ", stdout);
	gets(domainslist);
    }
    do_install(pro);
    return 0;
}

int
valid_ip(str)
char *str;
{
	char *cp = str;
	unsigned int num[4];
	int i;

	if (!*str)
	    return 0;
	for (i = 0; i < 4; i++) {
	    if (!cp) {
		printf("\"%s\" is not a valid IP address.  An IP address must have four\n", str);
		puts("decimal integers separated by periods");
		return 0;
	    }
	    num[i] = atoi(cp);
	    if (num[i] > 255) {
		printf("\"%s\" is not a valid IP address.  Each number in an IP address\n", str);
		puts("must be from 0-255");
		return 0;
	    }
	    while (isdigit(*cp))
		cp++;
	    if (!*cp) {
		cp = 0;
		continue;
	    }
	    if (*cp == '.') {
		cp++;
		continue;
	    }
	    printf("\"%s\" is not a valid IP address.  The character '%c' is\n", str, *cp);
	    puts("illegal in an IP address");
	    return 0;
	}
	sprintf(str, "%u.%u.%u.%u", num[0], num[1], num[2], num[3]);
	return 1;
}

char *
default_netmask()
{
    int i = atoi(myip);

    if ((i & 0x80) == 0)		/* class A */
	return "255.0.0.0";
    else if ((i & 0xc0) == 0x80)	/* class B */
	return "255.255.0.0";
    else if ((i & 0xc0) == 0xc0)	/* class C */
	return "255.255.255.0";
    else				/* class D */
	return "0.0.0.0";	/* ??? */
}

static FILE *
open_pro()
{
    char *cp;
    char profile[64];

    strcpy(profile, configtel);
    cp = strrchr(profile, '.');
    if (cp)
	strcpy(cp, ".pro");
    else
	strcat(profile, ".pro");
    return fopen(profile, "r");
}

void
do_install(pro)
FILE *pro;
{
    FILE *tel;
    char buf[256];
    char *cp;

    if (pro) {
	puts("Installing the CONFIG.TEL file...");
	tel = fopen(configtel, "w");
	if (!tel) {
	    perror(configtel);
	    exit(1);
	}
	while (fgets(buf, sizeof buf, pro)) {
	    if (buf[0] == '^') {
		if (strncmp(&buf[1], "MYIP", 4) == 0) {
		    fprintf(tel, "myip=%s\n", myip);
		} else if (strncmp(&buf[1], "NETMASK", 7) == 0) {
		    fprintf(tel, "netmask=%s\n", netmask);
		} else if (strncmp(&buf[1], "IOA", 3) == 0) {
		    fprintf(tel, "ioaddr=0x60\n");
		} else if (strncmp(&buf[1], "GATEWAY", 7) == 0) {
		    if (gateway[0]) {
			fprintf(tel, "name=mygateway\n");
			fprintf(tel, "hostip=%s\n", gateway);
			fprintf(tel, "gateway=1\n");
		    }
		} else if (strncmp(&buf[1], "NAMESERVERIP", 12) == 0) {
		    fprintf(tel, "hostip=%s\n", nameserver);
		} else if (strncmp(&buf[1], "DOMAINSLIST", 11) == 0) {
		    fprintf(tel, "domainslist=\"%s\"\n", domainslist);
		}
	    } else
		fputs(buf, tel);
	}
	fclose(tel);
	fclose(pro);
    }
    puts("Creating the X.BAT file...");
    tel = fopen("x.bat", "w");
    if (!tel) {
	perror("x.bat");
	exit(1);
    }
    fputs("@echo off\n", tel);
    fputs("cls\n", tel);
    /* Gross hack: take the current directory, go up one level, then
     * down to LIB.  This will be where the HELO file is. */
    getcwd(buf, sizeof buf - 1);
    buf[sizeof buf - 1] = 0;
    cp = strrchr(buf, '\\');
    *cp = 0;
    fprintf(tel, "type %s\\LIB\\HELO.TXT\n", buf);
#ifndef X_386
    fputs("cf2bf\n", tel);
#endif
    if (color) {
	fprintf(tel, "if \"%%1\" == \"mono\" goto mono\n");
	fprintf(tel, "if \"%%1\" == \"MONO\" goto mono\n");
	fprintf(tel, "if \"%%1\" == \"color\" goto color\n");
	fprintf(tel, "if \"%%1\" == \"COLOR\" goto color\n");
	fprintf(tel, "echo Type \"x mono\"   for mono mode  (faster)\n");
	fprintf(tel, "echo      \"x color\"  for color mode (256 simultaneous colors)\n");
	fprintf(tel, "goto end\n");
	fprintf(tel, ":color\n");
	fputs("sleep 5\n", tel);
#ifdef X_386
	strcpy(buf, "x3c -su -mode ");
#else
	strcpy(buf, "x0c -mode ");
#endif
	cp = buf + strlen(buf);
	*cp++ = co_res;
	if (broadcast) {
		strcpy(cp, " -broadcast");
		cp += strlen(cp);
	}
	if (query) {
		strcpy(cp, " -query ");
		cp += strlen(cp);
		strcat(cp, query);
		cp += strlen(cp);
	}
	if (once) {
		strcpy(cp, " -once");
		cp += strlen(cp);
	}
	*cp = 0;
	fprintf(tel, "%s\n", buf);
	fprintf(tel, "goto end\n");
	fprintf(tel, ":mono\n");
    }
    fputs("sleep 5\n", tel);
#ifdef X_386
    strcpy(buf, "x3m -su -mode ");
#else
    strcpy(buf, "x0m -mode ");
#endif
    cp = buf + strlen(buf);
    *cp++ = bw_res;
    if (broadcast) {
	    strcpy(cp, " -broadcast");
	    cp += strlen(cp);
    }
    if (query) {
	    strcpy(cp, " -query ");
	    cp += strlen(cp);
	    strcat(cp, query);
	    cp += strlen(cp);
    }
    if (once) {
	    strcpy(cp, " -once");
	    cp += strlen(cp);
    }
    *cp = 0;
    fprintf(tel, "%s\n", buf);
    if (color)
	fprintf(tel, ":end\n");
    fclose(tel);
    puts("Installation done.\n");
    if (color)
	puts("Restart your system now.  Then type \"X\" for instructions.\n");
    else
	puts("Restart your system now.  Then type \"X\" to run X\n");
}

#ifdef X_386
void
find_res()
{
	FILE *fp;

	fp = fopen("..\\lib\\vga.drv", "r");
	if (!fp)
		return;
	if (fread(&vga_head, sizeof vga_head, 1, fp) == 1 &&
	    vga_head.version == VGA_VERSION) {
		if (vga_head.color_modes[0] == 0 &&
		    vga_head.color_modes[1] == 0 &&
		    vga_head.color_modes[2] == 0 &&
		    vga_head.color_modes[3] == 0)
			color = 0;
	}
}
#endif
