#!/usr/bin/tclsh
###
### Remote controller program
###

set initialize_amsn 1

source amsncore.tcl

proc readsocket { } {
	global sock

	set complete 0
	set response ""

	while { [info exists sock] && $complete == 0 } {
		if { [gets $sock tmp] == -1 } {
			puts "Amsn server closed\n"
			connect "Amsn server closed"
		} elseif { $tmp != "" } {
			append response $tmp
			append response "\n"
			set complete [info complete $response]
			
			if { $complete } {
				set data [lindex $response 0]
				set colour [lindex $response 1]
				puts "\033\[[colorToCode $colour]m"
				puts $data
				puts "\033\[0m"
			} 
		}
	}
    
}

proc colorToCode { colour } {
	switch -- $colour {
	  error {
	       return "0;31"
	  }
	  msgsent {
	  	return "0;34"
	  }
	  msgrcv {
	  	return "0;33"
	  }
	  command {
	  	return "1;30"
	  }
	  event {
	  	return "0;35"
	  }
	  normal {
	  	return 0
	  }
	  default {
	  	return 0
	  }

	}
}

proc writesocket { command } {
    global sock
    set command [string map { \; \\\; \" \\\" \[ \\\[ \] \\\] \: \\\: \\ \\\\ \* \\\* \? \\\?} $command]
    if { $command != "quit" } {
	puts ${sock} $command
	flush $sock
    } 

}

proc authenticate { password } {
    global sock

    puts ${sock} "auth"
    flush $sock
    gets $sock response
    set response [lindex $response 0]

     if { [lindex $response 0] != "auth" } {
	    if { [lindex $response 0] == "wait" } {
		    return "wait"
	    } else {
		    return "fail"
	    }
    } else {
	set hash [::md5::hmac "[lindex $response 1]" "$password"]
	puts $sock "auth2 $hash"
	flush $sock
	gets $sock response	
        set response [lindex $response 0]
	if { "$response" ==  "Authentication successfull" } {
	    return "OK"
	} elseif { "$response" == "Authentication failed" } {
	    return "fail"
	} else {
	    return "disabled"
	}
       
    }

}

proc connect { status } {
    global sockDS stat ip
    
    if { $sockDS == 0 } {
	set stat [catch {socket $ip 63251} sockDS]
	set status "Connected to $ip"
    }

    if { $stat != 0 } {
	puts "Error connecting to server\n$sockDS"
	set sockDS 0
    }  else {
	puts $status
	puts "Account: "
	set account [gets stdin]
	puts "Password for remote access : "
	catch {eval exec stty -echo 0}
	set password [gets stdin]
	catch {eval exec stty echo}
	retreive_port $ip $account $password
    }

}

proc retreive_port { ip account password} {
    global sockDS sock
    puts $sockDS "$account"

    if { [catch { flush $sockDS}] } {
	set sockDS 0
	connect "Disconnected from the DS server" 
	return 0
    }

    set port [gets $sockDS]

    if { "$port" == "invalid" } {
	connect "This Amsn Account is invalid"
	return 0
    }
    if { "$port" == "noexist" } {
	connect "The Amsn profile file doesn't exist or you don't have permissions to read from it"
	return 0
    }
    if { "$port" == "versionerror" } {
	connect "The Amsn profile file has an invalid version" 
	return 0
    }

    if { [catch {socket $ip $port} sock] != 0 } {
	connect "This Amsn Account isn't connected"
	return 0
    } else {
	fconfigure $sock -buffering line
	if { [set auth_response [authenticate "$password"]] == "fail" } {
	    connect "Password incorrect or not set"
	    return 0
	} elseif { $auth_response == "disabled" } {
	    connect "This account doesn't have remote controlling enabled"
	    return 0
	} elseif { $auth_response == "wait" } {
	    connect "Please wait 3 seconds before retrying."
	    return 0
	} else {
	    puts "Connected to port : $port"
	    fileevent $sock readable "readsocket"
	    control
	    return 1
	}	
    }
}
proc readstdin { } {
	global commando
	set commando [gets stdin]
	writesocket $commando
}

proc control { } {
    global sock
    global commando
	fconfigure stdin -blocking false
	fileevent stdin readable "readstdin"
	set goout 1
	while {$goout != "quit"} {
		vwait commando
		
		set goout $commando 
	}
    }

proc main { } {
    global ip
    puts "Enter the IP address of the host : "
    gets stdin ip
    connect "Connected to the server"
}


############################################################
### Look if we are launched from a link
### and set the correct working directory
############################################################

if {[catch {file readlink [info script]} res]!=0} {

   #Error in readlink, so it's not a symbolic link
   set program_dir [file dirname [info script]]

} else {

   #Recursively update $resdir until it's not a link
   set program_dir [file dirname $res]

   while {[catch {file readlink $res} res2]==0} {
      set res $res2

      #Update $program_dir, depending on absolute or relative path
      if { [string range $res2 0 0]=="/" } {
         set program_dir [file dirname $res2]
      } else {
         set program_dir [file join $resdir [file dirname $res2]]
      }

   }
}

source [file join $program_dir migmd5.tcl]

set sockDS 0

main

