#!/bin/bash -e

state_file=clip.db

loading=

close() {
	block
	load
}

block() {
	iptables -P INPUT DROP
	iptables -P OUTPUT DROP
	iptables -P FORWARD DROP
	iptables -F
}

open() {
	iptables -P INPUT ACCEPT
	iptables -P OUTPUT ACCEPT
	iptables -P FORWARD ACCEPT
	iptables -F
}

dns() {
	< /etc/resolv.conf \
	sed -n 's/#.*//; s/  *$//; /nameserver [0-9.][0-9.]*/{ s/.* //; p; }' |
	while read IP; do
		accept "$IP"
	done
}

accept() {
	[ "$#" = 1 ]
	iptables -A INPUT  -p all -s "$1" -j ACCEPT
	iptables -A OUTPUT -p all -d "$1" -j ACCEPT
	[ -n "$loading" ] || echo "accept $1" >> "$state_file"
}

drop() {
	[ "$#" = 1 ]
	iptables -D INPUT  -p all -s "$1" -j ACCEPT
	iptables -D OUTPUT -p all -d "$1" -j ACCEPT
	[ -n "$loading" ] || echo "drop $1" >> "$state_file"
}

state() {
	cat "$state_file"
}

help() {
	if [ "$#" = 1 ]; then
		< "$0" sed -n "/^$1()[ ]{/,/^}/p"
	else
		echo "`basename "$0"` [command]"
		< "$0" sed -n 's/()[ ]{//p'
	fi
}

list() {
	iptables -L
}

load() {
	< "$state_file" loading=1 loop
}

clear() {
	> "$state_file"
	block
}

clean() {
	< "$state_file" tac |
	perl -ne '/^- (.*)/ && $drop{$1}++ or /^+ (.*)/ && !$drop{$1}++ && print' |
	tac | replace "$state_file"
}

replace() {
	rm "$1"  # eek?
	cat >"$1"
}

ed() {
	"$EDITOR" "$0"
	exec "$0"
}

loop() {
	while read -e -p ': ' A; do
		eval "$A"
	done
}

index() {
	[ "$#" = 1 ]
	< "$1" perl -ne '
		BEGIN { $c = 0; $space = 1; }
		if (/^\s*$/) { $space = 1; }
		elsif ($space && /^[0-9a-f]{8}( [0-9a-f]{8})?$/) { }
		else { $space = 0; printf "%08x\n", $c; }
		$c += length($_);' > "ix.$1"
}

pos() {
	[ "$#" = 2 ]
	< "ix.$1" perl -ne '
		BEGIN { seek STDIN, (8+1)*shift, 0; }
		print; exit;' "$2"
}

get() {
	[ "$#" = 2 ]
	< "$1" perl -pe '
		BEGIN { seek STDIN, hex(shift), 0; }
		/^\s*$/ && exit;' "$2"
}

put() {
	[ "$#" = 2 ]
	perl -pe '
		BEGIN { open STDOUT, "+<", shift; seek STDOUT, hex(shift), 0; }
		' "$@"
}

erase() {
	[ "$#" = 2 ]
	perl -e '
		open DB, "+<", shift; seek DB, hex(shift), 0;
		while(1) {
			$_ = <DB>; /^\s*$/ && last;
			seek DB, -length($_), 1;
			print DB " " x (length($_)-1);
			seek DB, 1, 1;
		}' "$@"
	# TODO if much space, add a free-list pointer/s in it?
	# what's a sane structure for the free list?
}

move() {
	[ "$#" = 3 ]
	copy "$@"
	erase "$1" "$2"
}

copy() {
	[ "$#" = 3 ]
	get "$1" "$2" | put "$1" "$3"
}

backup() {
	[ "$#" = 1 ]
	cp -a "$1" bak."$1"
}

restore() {
	[ "$#" = 1 ]
	cp -a bak."$1" "$1"
}

squeeze() {
	[ "$#" = 1 ]
	< "$1" perl -ne '
		if (/^\s*$/) { !$space && print "\n"; $space = 1; }
		elsif ($space && /^[0-9a-f]{8}( [0-9a-f]{8})?$/) { }
		else { $space = 0; print; }
		' | replace "$1"
}

test() {
	return
}

if [ -n "$1" ]; then
	"$@"
else
	loop
fi
