#! /usr/bin/tclsh

set BackupPCdNotifyServerPort 899
set Hostfile "/etc/hosts"

proc handle_connection {sock addr port} {
	fileevent $sock readable [list handle_data $sock $addr $port]

	return
}

proc handle_data {sock addr port} {
	if {[eof $sock]} {
		close $sock
		return
	}

	gets $sock line
	set work [split [string trim $line]]
	set cmd [string toupper [lindex $line 0]]
	set arg [join [lrange $line 1 end]]

	switch -- $cmd {
		"HOST" {
			update_host_record $arg $addr
			close $sock
		}
	}

	return
}

proc update_host_record {host addr} {
	set host [string tolower [lindex [split [string trim $host] .] 0]]

	set tmpfile "/tmp/notifyserv-[pid][clock seconds][expr abs([clock clicks])].tmp"
	set bakfile "$::Hostfile.bak"

	set hostsfmtstr {%-23s %s}

	if {$host == ""} {
		return
	}

	catch {
		set fd [open $::Hostfile "r"]
	}
	if {![info exists fd]} {
		return
	}

	catch {
		set ofd [open $tmpfile "w"]
	}
	if {![info exists ofd]} {
		close $fd
		return
	}

	set HostChanged 0
	set FoundHost 0
	while 1 {
		gets $fd line
		if {[eof $fd]} {
			break
		}

		set work [split [string trim [regsub {#.*$} $line {}]] " \t"]
		if {[llength $work] == 0} {
			puts $ofd $line
			continue
		}

		set hf_addr [lindex $work 0]
		set hf_hosts [list]
		foreach hf_host [lrange $work 1 end] {
			set hf_host [string trim $hf_host]
			if {$hf_host == ""} {
				continue
			}

			lappend hf_hosts $hf_host
		}

		if {$hf_addr == $addr} {
			foreach chk_host $hf_hosts {
				if {[string tolower $chk_host] == [string tolower $host]} {
					set FoundHost 1
					break
				}
			}
			if {!$FoundHost} {
				set line [format $hostsfmtstr $addr $host]
				set HostChanged 1
			}
		} else {
			set new_hf_hosts [list]
			foreach chk_host $hf_hosts {
				if {[string tolower $chk_host] == [string tolower $host]} {
					continue
				}
				lappend new_hf_hosts $chk_host
			}

			if {$new_hf_hosts != $hf_hosts} {
				if {[llength $new_hf_hosts] == 0} {
					continue
				}

				set line [format $hostsfmtstr $addr [join $new_hf_hosts]]
				set HostChanged 1
			}
		}

		puts $ofd $line
	}

	if {!$FoundHost} {
		if {!$HostChanged} {
			puts $ofd [format $hostsfmtstr $addr $host]
		}
	}

	close $fd
	close $ofd

	if {$FoundHost} {
		catch {
			file delete -force -- $tmpfile
		}

		return
	}

	catch {
		set hf_attrs [file attributes $::Hostfile]
	}
	catch {
		file delete -force -- $bakfile
	}

	if {[catch {
		file rename -force -- $::Hostfile $bakfile
		file rename -force -- $tmpfile $::Hostfile

		if {[info exists hf_attrs]} {
			eval [list file attributes $::Hostfile] $hf_attrs
		}
	}]} {
		catch {
			file delete -force -- $tmpfile
		}
	}

	return
}

for {set i 0} {$i < 10} {incr i} {
	if {![catch {
		set servfd [socket -server handle_connection $BackupPCdNotifyServerPort]
	} err]} {
		break
	}

	after 1000
}

if {![info exists servfd]} {
	puts $err
	exit 1
}

if {[catch {
	package require Tclx
}]} {
	puts stderr "Error loading the \"Tclx\" package, we cannot become a daemon."
	puts stderr "Running in the foreground."
	puts stderr "$errorInfo"

	vwait forever
} else {
	# Become a daemon
	if {[fork] == 0} {
		if {[fork] == 0} {
			cd /
			vwait forever
		}
	}
}
