#!/usr/bin/perl -w
use strict;
use POSIX qw(setsid);

die "timegmstr broken"
    unless timegmstr(1087973256) eq "2004062306473600";
sub timegmstr {
    my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(shift);
    $year += 1900;
    $mon += 1;
    return sprintf("%04d%02d%02d%02d%02d%02d00", $year, $mon,
                   $mday, $hour, $min, $sec);
}

sub at_cops {
    return `strace -o /dev/shm/dbus.strace -s4096 -f dbus-send --system --print-reply --dest=org.freesmartphone.ogsmd /org/freesmartphone/GSM/Device org.freesmartphone.GSM.Debug.DebugCommand string:AT+COPS?\r\n`;
}

sub cops_ok {
    my ($cops) = @_;
    if ($cops =~ m/\+COPS: 0,[02],"([^"]*)"/) {
	my $oper = $1;
	if (length($oper) > 2) {
	    return 1;
	}
    }
    return 0;
}

sub is_registered {
    for (my $i = 0; $i < 3; $i++) {
	my $cops = at_cops();
	if (cops_ok($cops)) {
	    return 1;
	}
	my $time = timegmstr(time());
	system("cp /dev/shm/dbus.strace /dev/shm/dbus.strace.$time");
	xlog("cops \"$cops\" not ok, saved /dev/shm/dbus.strace.$time");
	sleep(3);
    }

    return 0;
}

sub xlog {
    my ($msg) = @_;
    #print(timegmstr(time()) . " $msg\n");
    system("logger -t gsm-watchdog \"$msg\"");
}

sub dbg {
    my ($msg) = @_;
    #xlog("debug $msg");
}

sub kill_gsm {
    xlog("kill_gsm");
    system("/etc/init.d/ogsmd stop");
    if (`ps -eo cmd | grep gsm0710mux[d]` ne "") {
	xlog("gsm017muxd did not die");
	system("killall -9 gsm0710muxd");
	sleep(2);
	if (`ps -eo cmd | grep gsm0710mux[d]` ne "") {
	    xlog("gsm017muxd did not die with killall");
	    exit(1);
	}
    }
    if (`ps -eo cmd | grep framework[d]` ne "") {
	xlog("frameworkd did not die");
	system("ps -eo pid,cmd | grep bin/framework[d] | sed \"s/[^0-9]//g\" | xargs kill -9");
	sleep(4);
	if (`ps -eo cmd | grep framework[d]` ne "") {
	    xlog("frameworkd did not die even after kill -9!");
	    exit(1);
	}
    }
    if (-e "/tmp/frameworkd.pid") {
	xlog("pid file was not removed");
	system("rm /tmp/frameworkd.pid");
    }
    system("echo 0 > /sys/class/i2c-adapter/i2c-0/0-0073/neo1973-pm-gsm.0/power_on");
    system("echo 0 > /sys/class/i2c-adapter/i2c-0/0-0073/neo1973-pm-gsm.0/flowcontrolled");
    system("kill -9 `cat /home/lindi/.answering-machine/pid`");
}

sub start_gsm {
    xlog("start_gsm");
    system("/etc/init.d/ogsmd start");
}

sub wait_startup {
    xlog("wait_startup");
    for (my $i = 0; $i < 30; $i++) {
	if (-e "/tmp/frameworkd.pid") {
	    xlog("startup ok");
	    return;
	}
	sleep(1);
    }
    xlog("startup failed");
    exit(1);
}

sub pid_file_fresh {
    my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
	$atime, $mtime, $ctime, $blksize, $blocks) = stat("/tmp/frameworkd.pid");
    if (!defined($mtime)) {
	return 0;
    }
    my $age = time() - $mtime;
    dbg("age $age");
    if ($age < 2 * 60) {
	return 1;
    }
    return 0;
}

sub write_pid_file {
    my $pid = $$;
    my $fh;
    open($fh, ">/var/run/gsm-watchdog.pid")
        or die "Can't open pid file /var/run/gsm-watchdog.pid: $!";
    print $fh "$pid\n";
    close $fh;
}

sub daemonize { # stolen from http://perlmonks.thepen.com/41683.html
    chdir '/'               or die "Can't chdir to /: $!";
    open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
    open STDOUT, '>/dev/null'
        or die "Can't write to /dev/null: $!";
    defined(my $pid = fork) or die "Can't fork: $!";
    exit if $pid;
    setsid()                or die "Can't start a new session: $!";
    open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
}

sub main {
    xlog("starting up");
    daemonize();
    write_pid_file();
    xlog("startup done");
    my $prev_reg = 0;
    for (;;) {
	dbg("starting new run");
	my $reg = is_registered();
	if (!$reg) {
	    system("ledctrl --on-time 100 --off-time 1500 gta02-aux:red");
	}
	if ($reg && !$prev_reg) {
	    system("ledctrl --off gta02-aux:red");
	}
	$prev_reg = $reg;
	if (!pid_file_fresh() && !$reg) {
	    xlog("not registered");
	    kill_gsm();
	    start_gsm();
	    wait_startup();
	}
	sleep(2*50);
    }
}

#print(is_registered());
main();

# only complain if we are unregistered for more than 4 minutes

