As many of you know, I'm limited to a dialup system at home. (Anyone who wants to donate money to the "give jerith bandwidth" fund is welcome to do so.) I've also got a small home network set up, with a Debian server and a couple of Windows clients for the rest of the family to use. The rest of the family are used to the Windows world and don't take kindly to commandlines. Also, I don't want dial-on-demand with Windows clients randomly phoning home. Thus, some kind of pretty dialup interface was required.

A bit of googling turned up nothing usable and my php was getting rusty, so I wrote this:

<?php

$debug = True;
$bufdebug = True;

include("utils.php");

/* State machine stuff */

function defstate($state)
{
    define($state, $state);
}

// States
defstate("BADSTATE");
defstate("DISCONNECTED");
defstate("CONNECTING");
defstate("CONNECTED");
defstate("FETCHMAIL");

session_start();

$state = setdef($_SESSION["state"], BADSTATE);

if ($state == BADSTATE) {
    if (`grep ppp0 /proc/net/dev`) {
        $state = CONNECTED;
    } else {
        $state = DISCONNECTED;
    }
}

$refreshtime = setdef($_SESSION["refreshtime"], 20);

$action = setdef($_GET["action"], "none");

if ($action == "reset") {
    $state = BADSTATE;
} elseif ($action == "lexmark") {
    exec("sudo /usr/bin/enable LexmarkE232");
}

$time = gettimeofday();
$time = $time["sec"];

function state_BADSTATE()
{
    buf("<h2>Invalid state, resetting.</h2>");
}

function state_CONNECTING()
{
    global $state, $time;
    if (!$dialupfile = $_SESSION["dialupfile"]) {
        // There's no connection in progress, must be an error.
        $state = BADSTATE;
    } else {
        $lines = file($dialupfile);
        if (trim(end($lines)) == "Done.") {
            // We're connected.
            $state = CONNECTED;
            unset($_SESSION["connectfile"]);
            unlink($dialupfile);
            buf("<h2>Connected.</h2>");
        } else {
            // Still trying.  Have we timed out?
            if ($time > $_SESSION["connect time"] + 60) {
                //Timed out.
                $state = DISCONNECTED;
                #$_SESSION["timeout time"] = $time;
                buf("<h2>Timeout.</h2>");
                buf("<ul>");
                buf("\t<li>Is the modem plugged in and switched on?</li>");
                buf("\t<li>Is the telephone line in use?</li>");
                buf("</ul>");
            } else {
                // Still waiting for connect script.
                buf("<h2>Connecting...</h2>");
            }
        }
    }
}

function transition_DISCONNECTED_CONNECTING()
{
    global $state, $time, $refreshtime;

    if (isset($_SESSION["dialupfile"])) {
        unlink($_SESSION["dialupfile"]);
        unset($_SESSION["dialupfile"]);
    }

    $dialupfile = tempnam("/tmp", "dialup");
    $_SESSION["dialupfile"] = $dialupfile;
    $_SESSION["connect time"] = $time;
    exec("sudo do_dialup.sh > $dialupfile 2>&1 &");
    $state = CONNECTING;
}

function transition_CONNECTED_DISCONNECTED()
{
    global $state;
    exec("sudo poff");
    $state = DISCONNECTED;
}

function transition_CONNECTED_FETCHMAIL()
{
    global $state, $time;

    if (isset($_SESSION["mailfile"])) {
        unlink($_SESSION["mailfile"]);
        unset($_SESSION["mailfile"]);
    }

    $mailfile = tempnam("/tmp", "mail");
    $_SESSION["mailfile"] = $mailfile;
    exec("do_mail.sh > $mailfile 2>&1 &");
    $state = FETCHMAIL;
}

function state_CONNECTED()
{
    buf("<h2>Connected.</h2>");
}

function state_FETCHMAIL()
{
    global $state;

    if (!isset($_SESSION["mailfile"])) {
        $state = BADSTATE;
        return;
    }
    buf("<h2>Fetching mail...</h2>");
    buf("<pre>");
    $lines = file($_SESSION["mailfile"]);
    foreach ($lines as $line) {
        buf($line);
    }
    buf("</pre>");
    if (trim(end($lines)) == "Done.") {
        unlink($_SESSION["mailfile"]);
        unset($_SESSION["mailfile"]);
        $state = CONNECTED;
    }
}

do {
    $oldstate = $state;
    switch ($state) {
        case BADSTATE:
            state_BADSTATE();
            $refreshtime = 10;
            break;
        case DISCONNECTED:
            if ($action == "connect") {
                transition_DISCONNECTED_CONNECTING();
            }
            $refreshtime = 60;
            break;
        case CONNECTING:
            state_CONNECTING();
            $refreshtime = 5;
            break;
        case CONNECTED:
            if ($action == "disconnect") {
                transition_CONNECTED_DISCONNECTED();
            } elseif ($action == "fetchmail") {
                transition_CONNECTED_FETCHMAIL();
            } else {
                state_CONNECTED();
            }
            $refreshtime = 20;
            break;
        case FETCHMAIL:
            state_FETCHMAIL();
            $refreshtime = 10;
            break;
    }
} while ($oldstate != $state);

$_SESSION["state"] = $state;
$_SESSION["refreshtime"] = $refreshtime;

$myURI = $_SERVER["PHP_SELF"];

?>

<html><head>
    <title>Dialup control panel</title>
<?php
    echo "\t<meta http-equiv=\"refresh\" content=\"$refreshtime;url=$myURI\" />";
?>
</head>

<body>

<?php
debug($state);

echobuf();
?>

<h2>Actions:</h2>

<ul>
<?php
    echo "\t<li><a href=\"$myURI?action=connect\">Connect</a></li>\n";
    echo "\t<li><a href=\"$myURI?action=disconnect\">Disconnect</a></li>\n";
    echo "\t<li><a href=\"$myURI?action=fetchmail\">Fetch mail</a></li>\n";
    echo "\t<li><a href=\"$myURI?action=lexmark\">Start printer</a></li>\n";
?>
</ul>

<h2>Dialup statistics:</h2>

<?php
if ($stats = network_stats()) {
    echo "<ul>\n";
    echo "  <li><b>Received:</b> " .
    format_bytesize($stats["rx_bytes"]/1024) . "</li>\n";
    echo "  <li><b>Sent:</b> " .
    format_bytesize($stats["tx_bytes"]/1024) . "</li>\n";
    echo "</ul>\n";
} else {
    echo "<p>Disconnected</p>\n";
}
?>

</body></html>

There are a few functions in utils.php that do debug printing, buffering of output and network status discovery which I'll put up if anyone wants to see them. The network stuff is shamelessly stolen from phpSysInfo anyway.

There are a few scripts needed in addition to this one. The various mailgrabbing and dialup/NAT/firewall shell scripts and some sudo configuration. I'd be happy to provide details of those to anyone who asks but I'd rather not clutter this page with them.

There's still a little cleaning up to do and I would like to parse the fetchmail output into a pretty progress indicator (perhaps even a graphical one) but those are projects for another weekend.

One last note: Occasionally the laser printer will get switched off and CUPS will forget that it exists. I thought this script would be a good place to fix that as well, so that's what the "Lexmark" stuff in there is for.