/*
 * The new sysinstall program.
 *
 * This is probably the last attempt in the `sysinstall' line, the next
 * generation being slated to essentially a complete rewrite.
 *
 * $FreeBSD: src/release/sysinstall/network.c,v 1.33.2.10 1999/12/17 02:46:34 jkh Exp $
 *
 * Copyright (c) 1995
 *	Jordan Hubbard.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer,
 *    verbatim and that no modifications are made prior to this
 *    point in the file.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

/* These routines deal with getting things off of network media */

#include "sysinstall.h"
#include <signal.h>
#include <termios.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

static Boolean	networkInitialized;
static pid_t	startPPP(Device *devp);

static pid_t	pppPID;

Boolean
mediaInitNetwork(Device *dev)
{
    int i;
    char *rp;
    char *cp, ifconfig[255];
    WINDOW *w;

    if (!RunningAsInit || networkInitialized)
	return TRUE;

    if (isDebug())
	msgDebug("Init routine called for network device %s.\n", dev->name);

    if (!file_readable("/etc/resolv.conf")) {
	if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) {
	    KANJI_MESSAGE("/etc/resolv.conf に書き込めないようです. ネットは使えません.");
	    msgConfirm(KM("Can't seem to write out /etc/resolv.conf.  Net cannot be used."));
	    return FALSE;
	}
    }

    w = savescr();
    dialog_clear_norefresh();

    /* Old PPP process lying around? */
    if (pppPID) {
	KANJI_MESSAGE("以前の PPP プロセス %d を止めています");
	msgConfirm(KM("Killing previous PPP process %d."), pppPID);
	kill(pppPID, SIGTERM);
	pppPID = 0;
    }
    if (!strncmp("ppp", dev->name, 3)) {	/* PPP? */
	if (!(pppPID = startPPP(dev))) {
	    KANJI_MESSAGE("PPP を開始できません! このインストール法は使用できません.");
	    msgConfirm(KM("Unable to start PPP!  This installation method cannot be used."));
	    return FALSE;
	}
	networkInitialized = TRUE;
	return TRUE;
    }
    else if (!strncmp("sl", dev->name, 2)) {	/* SLIP? */
	char *val;
	char attach[256];

	/* Cheesy slip attach */
	snprintf(attach, 256, "slattach -a -h -l -s 9600 %s", dev->devname);
#ifdef PC98
	KANJI_MESSAGE(
	"警告: この版のインストーラの SLIP へのサポートは, 幾分機能の低いもの\n"
	"となっています. これはダイアリングを行なうためのユーティリティに欠け\n"
	"ていることが原因です. もし代わりに PPP が使用できるのであれば, そち\n"
	"らを利用しましょう. SLIP は直接シリアル接続された場合に使用して下さ\n"
	"い. まず, 以下に示す slattach コマンドを編集して下さい (ここでのデ\n"
	"フォルトは, VJ 圧縮, ハードウェアフロー制御, キャリア無視, 9600 ボー\n"
	"の転送レートです). 準備ができたら, [RETURN] を押して実行して下さい.");
	val = msgGetInput(attach, KM(
			  "Warning:  SLIP is rather poorly supported in this revision\n"
			  "of the installation due to the lack of a dialing utility.\n"
			  "If you can use PPP for this instead then you're much better\n"
			  "off doing so, otherwise SLIP works fairly well for *hardwired*\n"
			  "links.  Please edit the following slattach command for\n"
			  "correctness (default here is: VJ compression, Hardware flow-\n"
			  "control, ignore carrier and 9600 baud data rate).  When you're\n"
			  "ready, press [RETURN] to execute it."));
#else
	KANJI_MESSAGE(
	"警告: この版のインストーラの SLIP へのサポートは, 幾分機能の低いもの\n"
	"となっています. これはダイアリングを行なうためのユーティリティに欠け\n"
	"ていることが原因です. もし代わりに PPP が使用できるのであれば, そち\n"
	"らを利用しましょう. SLIP は直接シリアル接続された場合に使用して下さ\n"
	"い. まず, 以下に示す slattach コマンドを編集して下さい (ここでのデ\n"
	"フォルトは, VJ 圧縮, ハードウェアフロー制御, キャリア無視, 9600 ボー\n"
	"の転送レートです). 準備ができたら, [ENTER] を押して実行して下さい.");
	val = msgGetInput(attach, KM(
			  "Warning:  SLIP is rather poorly supported in this revision\n"
			  "of the installation due to the lack of a dialing utility.\n"
			  "If you can use PPP for this instead then you're much better\n"
			  "off doing so, otherwise SLIP works fairly well for *hardwired*\n"
			  "links.  Please edit the following slattach command for\n"
			  "correctness (default here is: VJ compression, Hardware flow-\n"
			  "control, ignore carrier and 9600 baud data rate).  When you're\n"
			  "ready, press [ENTER] to execute it."));
#endif	/* PC98 */
	if (!val) {
	    KANJI_MESSAGE("slattach コマンドが空です. やりなおし!");
	    msgConfirm(KM("slattach command was empty.  Try again!"));
	    restorescr(w);
	    return FALSE;
	}
	else
	    SAFE_STRCPY(attach, val);
	/*
	 * Doing this with vsystem() is actually bogus since we should be storing the pid of slattach
	 * for later killing.  It's just too convenient to call vsystem(), however, rather than
	 * constructing a proper argument for exec() so we punt on doing slip right for now.
	 */
	if (vsystem(attach)) {
	    KANJI_MESSAGE(
	    "slattach が不正ステータスを返しました. コマンドをもう一度確認して再\n"
	    "度この操作を試してみて下さい.");
	    msgConfirm(KM("slattach returned a bad status!  Please verify that\n"
		       "the command is correct and try this operation again."));
	    restorescr(w);
	    return FALSE;
	}
	restorescr(w);
    }

    snprintf(ifconfig, 255, "%s%s", VAR_IFCONFIG, dev->name);
    cp = variable_get(ifconfig);
    if (!cp) {
	KANJI_MESSAGE(
	"デバイス %s が使用可能となっていません. この作業を行なう前にネット\n"
	"ワーク設定メニューでデバイスの初期設定を行なう必要があります.");
	msgConfirm(KM("The %s device is not configured.  You will need to do so\n"
		   "in the Networking configuration menu before proceeding."), dev->name);
	return FALSE;
    }
    else if (!strcmp(cp, "DHCP"))
	goto bail;
    msgDebug("ifconfig %s %s", dev->name, cp);
    i = vsystem("ifconfig %s %s", dev->name, cp);
    if (i) {
	KANJI_MESSAGE(
	"インターフェース %s を初期化できません!\n"
	"このインストール法は使用できません.");
	msgConfirm(KM("Unable to configure the %s interface!\n"
		   "This installation method cannot be used."), dev->name);
	return FALSE;
    }

    rp = variable_get(VAR_GATEWAY);
    if (!rp || *rp == '0') {
	KANJI_MESSAGE(
	"ゲートウェイが設定されていません. ローカルネットワーク以外にアクセス\n"
	"することはできません.");
	msgConfirm(KM("No gateway has been set. You may be unable to access hosts\n"
		   "not on your local network"));
    }
    else {
	/* KANJI_MESSAGE("%s にデフォルト経路を設定しています."); */
	msgDebug("Adding default route to %s.", rp);
	vsystem("route -n add default %s", rp);
    }
bail:
    if (isDebug())
	msgDebug("Network initialized successfully.\n");
    networkInitialized = TRUE;
    return TRUE;
}

void
mediaShutdownNetwork(Device *dev)
{
    char *cp;

    if (!RunningAsInit || !networkInitialized)
	return;

    msgDebug("Shutdown called for network device %s\n", dev->name);
    /* Not a serial device? */
    if (strncmp("sl", dev->name, 2) && strncmp("ppp", dev->name, 3)) {
	int i;
	char ifconfig[255];

	snprintf(ifconfig, 255, "%s%s", VAR_IFCONFIG, dev->name);
	cp = variable_get(ifconfig);
	if (!cp)
	    return;
	msgDebug("ifconfig %s down", dev->name);
	i = vsystem("ifconfig %s down", dev->name);
	if (i) {
	    KANJI_MESSAGE("警告: インターフェイス %s は正常に終了できません.");
	    msgConfirm(KM("Warning: Unable to down the %s interface properly"), dev->name);
	}
	cp = variable_get(VAR_GATEWAY);
	if (cp) {
	    /* KANJI_MESSAGE("デフォルト経路を削除しています."); */
	    msgDebug("Deleting default route.");
	    vsystem("route -n delete default");
	}
    }
    else if (pppPID) {
	KANJI_MESSAGE("以前の PPPプロセス %d を終了してます.");
	msgConfirm(KM("Killing previous PPP process %d."), pppPID);
	kill(pppPID, SIGTERM);
	pppPID = 0;
    }
    networkInitialized = FALSE;
}

/* Start PPP on the 3rd screen */
static pid_t
startPPP(Device *devp)
{
    int fd2, pulse;
    FILE *fp;
    char *val;
    pid_t pid = 0;
    char myaddr[16], provider[16], speed[16], authname[32], authkey[16];
    char phone[16];
    WINDOW *w = savescr();

    /* These are needed to make ppp work */
    Mkdir("/var/log");
    Mkdir("/var/run");
    Mkdir("/var/spool/lock");
    Mkdir("/etc/ppp");

    dialog_clear_norefresh();
    if (!variable_get(VAR_SERIAL_SPEED))
	variable_set2(VAR_SERIAL_SPEED, "115200", 0);
    /* Get any important user values */
    KANJI_MESSAGE(
    "モデムへのボーレートを設定して下さい. ほとんどのモデムは, 回線に対す\n"
    "る速度と別の速度でコンピュータとデータ転送が可能となっているので,\n"
    "この値はモデムが提供する実際の最高速度よりも高く設定することができま\n"
    "す. もし何を設定して良いのかわからない場合は, デフォルトを選択して下\n"
    "さい.");
    val = variable_get_value(VAR_SERIAL_SPEED, KM(
		      "Enter the baud rate for your modem - this can be higher than the actual\n"
		      "maximum data rate since most modems can talk at one speed to the\n"
		      "computer and at another speed to the remote end.\n\n"
		      "If you're not sure what to put here, just select the default."), 0);
    SAFE_STRCPY(speed, (val && *val) ? val : "115200");

    val = variable_get(VAR_GATEWAY);
    SAFE_STRCPY(provider, (val && *val) ? val : "0");

    dialog_clear_norefresh();
    KANJI_MESSAGE(
    "あなたのサービスプロバイダの IP アドレスを入力して下さい. もしそれ\n"
    "がわからない場合, あるいは動的なネゴシエーションを行ないたい場合に\n"
    "は, 0 を入力して下さい.");
    val = msgGetInput(provider, KM("Enter the IP address of your service provider or 0 if you\n"
		      "don't know it and would prefer to negotiate it dynamically."));
    SAFE_STRCPY(provider, (val && *val) ? val : "0");

    if (devp->private && ((DevInfo *)devp->private)->ipaddr[0])
	SAFE_STRCPY(myaddr, ((DevInfo *)devp->private)->ipaddr);
    else
	strcpy(myaddr, "0");

    if (!Fake)
	fp = fopen("/etc/ppp/ppp.linkup", "w");
    else
	fp = fopen("/dev/stderr", "w");
    if (fp != NULL) {
	fprintf(fp, "MYADDR:\n");
	fprintf(fp, " delete ALL\n");
        fprintf(fp, " add 0 0 HISADDR\n");
	fchmod(fileno(fp), 0755);
	fclose(fp);
    }
    if (!Fake)
	fd2 = open("/etc/ppp/ppp.secret", O_CREAT);
    else
	fd2 = -1;
    if (fd2 != -1) {
	fchmod(fd2, 0700);
	close(fd2);
    }
    if (!Fake)
	fp = fopen("/etc/ppp/ppp.conf", "a");
    else
	fp = fopen("/dev/stderr", "w");
    if (!fp) {
	KANJI_MESSAGE("/etc/ppp/ppp.conf をオープンできません!  この機能は使用不能です");
	msgConfirm(KM("Couldn't open /etc/ppp/ppp.conf file!  This isn't going to work"));
	restorescr(w);
	return 0;
    }
    authname[0] = '\0';
    pulse = 0;
    dialog_clear_norefresh();
    KANJI_MESSAGE("ISP は PAP か CHAP ppp ログインをサポートしていますか?");
    if (!dialog_yesno("", KM("Does your ISP support PAP or CHAP ppp logins?"), -1, -1)) {
	KANJI_MESSAGE("プロバイダーのログインに使用する名前を入力してください.");
	val = msgGetInput(NULL, KM("Enter the name you use to login to your provider."));
	SAFE_STRCPY(authname, val);
	dialog_clear_norefresh();
	KANJI_MESSAGE("プロバイダーのログインに使用するパスワードを入力してください.");
	val = msgGetInput(NULL, KM("Enter the password you use to login to your provider."));
	SAFE_STRCPY(authkey, val);
	dialog_clear_norefresh();
	KANJI_MESSAGE("プロバイダーのログイン用の電話番号を入力してください.");
	val = msgGetInput(NULL, KM("Enter the your provider's login phone number."));
	SAFE_STRCPY(phone, val);
	dialog_clear_norefresh();
	KANJI_MESSAGE("電話回線はトーンダイヤルをサポートしていますか?");
	pulse = dialog_yesno("", KM("Does your telephone line support tone dialing?"), -1, -1);
    }
    fprintf(fp, "\ninstall:\n");
    fprintf(fp, " set speed %s\n", speed);
    fprintf(fp, " set device %s\n", devp->devname);
    fprintf(fp, " set ifaddr %s %s\n", myaddr, provider);
    fprintf(fp, " set timeout 0\n");
    fprintf(fp, " set log local phase\n");
    if(authname[0] != '\0'){
	fprintf(fp, " set dial \"ABORT BUSY ABORT NO\\\\sCARRIER TIMEOUT 5 \\\"\\\" AT OK-AT-OK ATE1Q0 OK \\\\dATD%c\\\\T TIMEOUT 40 CONNECT\"\n", pulse ? 'P' : 'T');
	fprintf(fp, " set login\n");
	fprintf(fp, " set authname %s\n", authname);
	fprintf(fp, " set authkey %s\n", authkey);
	fprintf(fp, " set phone %s\n", phone);
    }
    if (fchmod(fileno(fp), 0600) != 0) {
	KANJI_MESSAGE("警告: /etc/ppp/ppp.conf のパーミションの設定に失敗しました!");
	msgConfirm(KM("Warning: Failed to fix permissions on /etc/ppp/ppp.conf !"));
    }
    fclose(fp);

    /* Make the ppp config persistent */
    variable_set2(VAR_PPP_ENABLE, "YES", 0);
    variable_set2(VAR_PPP_PROFILE, "install", 0);

    if (!Fake && !file_readable("/dev/tun0") && mknod("/dev/tun0", 0600 | S_IFCHR, makedev(52, 0))) {
	KANJI_MESSAGE("警告:  デバイス /dev/tun0 がありません. PPP は動きません!");
	msgConfirm(KM("Warning:  No /dev/tun0 device.  PPP will not work!"));
	restorescr(w);
	return 0;
    }

    if (isDebug())
	msgDebug("About to start PPP on device %s @ %s baud.  Provider = %s\n", devp->devname, speed, provider);

    if (!Fake && !(pid = fork())) {
	int i, fd;
	struct termios foo;
	extern int login_tty(int);

	for (i = getdtablesize(); i >= 0; i--)
	    close(i);

	/* We're going over to VTY2 */
	fd = open("/dev/ttyv2", O_RDWR);
	ioctl(0, TIOCSCTTY, &fd);
	dup2(0, 1);
	dup2(0, 2);
	DebugFD = 2;
	if (login_tty(fd) == -1)
	    msgDebug("ppp: Can't set the controlling terminal.\n");
	signal(SIGTTOU, SIG_IGN);
	if (tcgetattr(fd, &foo) != -1) {
	    foo.c_cc[VERASE] = '\010';
	    if (tcsetattr(fd, TCSANOW, &foo) == -1)
		msgDebug("ppp: Unable to set the erase character.\n");
	}
	else
	    msgDebug("ppp: Unable to get the terminal attributes!\n");
	execlp("ppp", "ppp", "install", (char *)NULL);
	msgDebug("PPP process failed to exec!\n");
	exit(1);
    }
    else {
	dialog_clear_norefresh();
#ifdef PC98
	KANJI_MESSAGE(
	"注意: VTY3 上で PPP コマンドが始動しました (GRPH-F3 を打つとこの\n"
	"コマンドの操作を行なうことができます. GRPH-F1 で元に戻ります).\n"
	"PAP か CHAP ログインを使うなら単に \"dial\", を入力します, 他の場合\n"
        "は \"term\" とタイプするだけで, 端末エミュレータが起動し, そこから\n"
	"モデムを操作してサービスプロバイダにダイアルできるはずです. 一旦\n"
	"接続が確立したら, このスクリーンに戻ってリターンを打って下さい.\n\n"
	"完全に接続が確立するまでは絶対に [RETRUN] を押さないこと!");
	msgConfirm(KM("NOTICE: The PPP command is now started on VTY3 (type GRPH-F3 to\n"
           "interact with it, GRPH-F1 to switch back here). If you are using\n"
           "a PAP or CHAP login simply enter \"dial\", otherwise you'll need\n"
           "to use the \"term\" command which starts a terminal emulator\n"
           "which you can use to talk to your modem and dial the service\n"
           "provider.  Once you're connected, come back to this screen and\n"
           "press return.\n\n"
           "DO NOT PRESS [RETURN] HERE UNTIL THE CONNECTION IS FULLY\n"
           "ESTABLISHED!"));
#else
	KANJI_MESSAGE(
	"注意: VTY3 上で PPP コマンドが始動しました (ALT-F3 を打つとこのコ\n"
	"マンドの操作を行なうことができます. ALT-F1 で元に戻ります).\n"
	"PAP か CHAP ログインを使うなら単に \"dial\", を入力します, 他の場合\n"
        "は \"term\" とタイプするだけで, 端末エミュレータが起動し, そこから\n"
	"モデムを操作してサービスプロバイダにダイアルできるはずです. 一旦\n"
	"接続が確立したら, このスクリーンに戻ってリターンを打って下さい.\n\n"
	"完全に接続が確立するまでは絶対に [ENTER] を押さないこと!");
	msgConfirm(KM("NOTICE: The PPP command is now started on VTY3 (type ALT-F3 to\n"
           "interact with it, ALT-F1 to switch back here). If you are using\n"
           "a PAP or CHAP login simply enter \"dial\", otherwise you'll need\n"
           "to use the \"term\" command which starts a terminal emulator\n"
           "which you can use to talk to your modem and dial the service\n"
           "provider.  Once you're connected, come back to this screen and\n"
           "press return.\n\n"
           "DO NOT PRESS [ENTER] HERE UNTIL THE CONNECTION IS FULLY\n"
           "ESTABLISHED!"));
#endif
    }
    restorescr(w);
    return pid;
}
